4

I'm familiar with the C programming language and z80 assembly and I have made a simple z80 "computer" with just the cpu with 32k of ram, 32k of rom, and an 8255 pia for io control. I have gotten the 8255 to bling an LED with my system through an assembly language subroutine.

So the question is: If there is the SDCC(Small Device C compiler) that can compile a C program into assembly for various small CPUs including the z80, How do you create a C program if there are no stdio libraries or any libraries of any kind because of how custom this system is. Am i forced to use assembly first then make and call a function as an ASM routine? Am I misunderstanding some sort of key idea? Im quite confused on how this works. I cant just printf() on a system with no output. Not to mention printf() is under the assumption that a terminal is connected of some kind.

Rob
  • 14,746
  • 28
  • 47
  • 65
  • 3
    Any line of code that you are worry about? In general C language doesn't require any headers – Yaroslav Stetsyk Nov 24 '20 at 20:23
  • 1
    If you don't have a standard library, but you want to use any of the features that it would normally provide, then you have to write those functions yourself - either in C or assembly, your choice. – Nate Eldredge Nov 24 '20 at 20:25
  • 2
    Per [C11 clause 4](http://port70.net/~nsz/c/c11/n1570.html#4) a *freestanding implementation* is limited to the headers ``, ``, ``, ``, ``, ``, ``, ``, and ``. – pmg Nov 24 '20 at 20:33
  • *"Am i forced to use assembly first then make and call a function as an ASM routine?"* Yes. Given that you have an LED blinking, you're most of the way there. To run C code, you need to point the stack pointer at the high address of a block of RAM (2K is probably a good size). Then you need to call `main`. In assembly, it's probably `_main`. Your C code should not return from `main` or call `exit`. And then there's maybe 200 other things that you'll need to get right before this will work. For example, clearing the BSS, and copying initialized DATA from ROM to RAM. – user3386109 Nov 24 '20 at 20:33
  • Why would you want to call `printf` if there is no screen to print to? – TonyK Nov 24 '20 at 21:03
  • 4
    Headers are not libraries. – Clifford Nov 24 '20 at 21:03
  • 1
    @TonyK `printf` outputs to the `stdout` stream - that need not be a "screen". Most often in small embedded systems it is implemented on a UART so a terminal or more likely terminal emulator running on a PC is the "display". – Clifford Nov 24 '20 at 21:13

2 Answers2

5

You would write a platform specific I/O library that utilises whatever I/O capability your platform has available. On many embedded systems a minimal standard I/O is implemented on a UART serial port so your "console" can be a terminal emulator on a host PC.

Your I/O API need not be as sophisticated as the standard library's stdio. It also need not be written in assembler, register-level access of memory-mapped peripherals is possible (in fact normal) in C - it is a systems level language after all.

All that said, SDCC already includes a standard library subset that includes a subset stdio. So it is not clear why you think you lack that support. You do have to provide low level platform specific support, but to support printf you need only implement putchar() to emit a character on your chosen stdout device. For unbuffered serial output that is rather trivial. A more sophisticated implementation might use interrupt driven, buffered serial output. The porting of the library is described in the SDCC manual.

Clifford
  • 88,407
  • 13
  • 85
  • 165
1

You are right. An assembly routine contains the actual entry point, where memory initialization is done, and that routine then calls main().

sdcc/device/lib/z80/crt0.s contains the default startup code provided by SDCC.

If your system needs more stuff to be done than that provides, refer to section 3.12.3 of the SDCC manual on how to supply your own.

As for printf(), you just need to supply putchar() somehow. If it's simply an out instruction to some device, you can just chuck it in the crt0.s as well, like this:

    .area   _CODE
init:
    call    0x01B0 ; ROM_CLEAR_SCREEN    
    ;; Initialise global variables
    call    gsinit
    call    _main
_exit:
    call    0x0200 ; ROM_GET_KEY
    jr      z, _exit
    call    0x01B0 ; ROM_CLEAR_SCREEN
    ret
_putchar:
    ld      hl, #2
    add     hl, sp
    ld      a, (hl)
    out     (0xBC), a
    ld      hl, #0
    ret
Stefan Paul Noack
  • 3,654
  • 1
  • 27
  • 38