Assembly Listing?
Assembly Listing?
I'm using z88dk/sdcc with the following basic command line
zcc +embedded -vn -SO3 -startup=0 -clib=sdcc_iy --max-allocs-per-node200000 -o testembed.bin -notemp testembed.c
what do i have to add to get an assembly listing?
Also, does the crt get assembled each time so i could see it in the listing?
Also, my output seems to end up in testembed_code.bin, does that make sense? And I don't think i get that file if i don't use -notemp
zcc +embedded -vn -SO3 -startup=0 -clib=sdcc_iy --max-allocs-per-node200000 -o testembed.bin -notemp testembed.c
what do i have to add to get an assembly listing?
Also, does the crt get assembled each time so i could see it in the listing?
Also, my output seems to end up in testembed_code.bin, does that make sense? And I don't think i get that file if i don't use -notemp
Last edited by bill2009 on Wed Jan 06, 2016 3:14 pm, edited 1 time in total.
You can add '-a' to stop after the asm listing is generated:bill2009 wrote:I'm using z88dk/sdcc with the following basic command line
zcc +embedded -vn -SO3 -startup=0 -clib=sdcc_iy --max-allocs-per-node200000 -o testembed.bin -notemp testembed.c
what do i have to add to get an assembly listing?
zcc +embedded -vn -a -SO3 -clib=sdcc_iy --max-allocs-per-node200000 testembed.c
"-startup=0" selects the crt to use so it's irrelevant in the C translation but you can leave it there no harm done.
"-o testembed.bin" will rename the generated asm file so you probably want to leave that out.
"-notemp" is discussed below.
The output will be the single file "testembed.opt" containing the translated C after all optimizations and translations have been applied.
"-O2" is implied in this compile line meaning sdcc's output is translated to Zilog form and a few code transformations are applied. If you drop it to "-O1" sdcc's calls to its primitives will not be changed to callee (this will negatively impact on code size). If you drop to "-O0" the output filename will change to "test.asm" (.asm meaning no -O applied) and this will be in asz80 form (sdcc's assembler).
If you drop the peephole level "-SO3" to "-SO1" the peephole rules applied will be sdcc's original set. If you drop to "-SO0" no peephole rules will be applied.
You can also add "--fverbose-asm" to see what peephole rules have been applied in the output asm:
zcc +embedded -vn -a -SO3 -clib=sdcc_iy --max-allocs-per-node200000 testembed.c --fverbose-asm
In the output comments will appear indicating where peephole rules were applied and comments at the top of each function will indicate if the code might be improved with higher "--max-allocs-per-node" setting.
An example:
Code: Select all
; ---------------------------------
; Function main
; ---------------------------------
; Register assignment is optimal.
; Stack space usage: 0 bytes.
It does -- it gets assembled from raw state in the last linking step so that it can gather the final defined options from the "zcc_opt.def" file that is generated when other files are compiled.Also, does the crt get assembled each time so i could see it in the listing?
Seeing it in the listing.. I think we missed a trick here. What you see in the listing is a thoroughly unhelpful INCLUDE that includes the actual crt. I'll try further to find a way to see the crt after options have been applied but at the moment it looks like you have to look at it in a disassembler after the binary is built . The crt will be right at the beginning of the output binary.
It should be "testembed_CODE.bin". The binaries have a section name appended to the output filename corresponding to all code/data assigned to that section. The crts set up a memory map that consists of three major blocks: CODE, DATA, BSS and in the ram model the DATA and BSS sections are just appended to CODE so the output is a single binary corresponding to everything in the CODE section, including DATA and BSS.Also, my output seems to end up in testembed_code.bin, does that make sense? And I don't think i get that file if i don't use -notemp
If you have a disjoint memory map where you might want some stuff in a different location, the means to do that is to create a new section and assign an ORG to it. Then when the project is compiled the output will be *_CODE.bin and *_NAME.bin corresponding to the two different sections defined with their own ORG. You can see we prefer to output to raw binaries rather than ihx; ihx would bundle separate regions into a single file.
Just so it's clear: "testembed_CODE.bin" is the name of your binary output and you place that at the ORG address and execute from the ORG address to run the binary. If you didn't change your ORG address, this address is 0, otherwise you can change the ORG address by adding "#pragma output CRT_ORG_CODE = ????" to your embedtest.c source file where "????" is the address in decimal. It doesn't matter where -- you can stick it at the top, eg.
To generate a listing file this is what I used:
zcc +embedded -vn -SO3 -startup=0 -clib=sdcc_iy -Ca--list -notemp --max-allocs-per-node200000 test.c -o test
"-notemp" is necessary otherwise the listing file is left in the temp dir.
"test.lst" is the listing file corresponding to "test.c"
"crt0.asm" and "crt0.opt" are the crts. As you can see, they only consist of INCLUDEs which don't help at all.
"test.c" go through these steps which all appear because of "-notemp":
test.i is test.c after the preprocessor is applied
test.i2 is test.i after zpragma is applied. this is the input to sdcc
test.asm is sdcc's output after peephole step
test.op1 is sdcc's output translated to Zilog and z80asm directives
test.opt is test.op1 after sdcc's calls to its primitives are changed to callee linkage
test_CODE.bin is the output binary
test_CODE.reloc contains relocation information if the binary needs to be patched to a new address
"test" is the binary contents of the unnamed section. This should be empty. Anything in this file indicates something was not assigned to a section and exists outside the memory map.
That's probably much more information than you need to know
I prefer the asm output file but if you want to see the output bytes a listing file is necessary. I can see that we need to copy the listing file out of the temp dir so that "-notemp" is unnecessary and we need to provide a way to see the final crt listing. z80asm is being actively developed so these usage issues do still crop up when someone tries something a little bit different. I'll add these two to the to-do list.
zcc +embedded -vn -SO3 -startup=0 -clib=sdcc_iy -Ca--list -notemp --max-allocs-per-node200000 test.c -o test
"-notemp" is necessary otherwise the listing file is left in the temp dir.
"test.lst" is the listing file corresponding to "test.c"
"crt0.asm" and "crt0.opt" are the crts. As you can see, they only consist of INCLUDEs which don't help at all.
"test.c" go through these steps which all appear because of "-notemp":
test.i is test.c after the preprocessor is applied
test.i2 is test.i after zpragma is applied. this is the input to sdcc
test.asm is sdcc's output after peephole step
test.op1 is sdcc's output translated to Zilog and z80asm directives
test.opt is test.op1 after sdcc's calls to its primitives are changed to callee linkage
test_CODE.bin is the output binary
test_CODE.reloc contains relocation information if the binary needs to be patched to a new address
"test" is the binary contents of the unnamed section. This should be empty. Anything in this file indicates something was not assigned to a section and exists outside the memory map.
That's probably much more information than you need to know
I prefer the asm output file but if you want to see the output bytes a listing file is necessary. I can see that we need to copy the listing file out of the temp dir so that "-notemp" is unnecessary and we need to provide a way to see the final crt listing. z80asm is being actively developed so these usage issues do still crop up when someone tries something a little bit different. I'll add these two to the to-do list.
It turns out it was fairly easy to do the list files so zcc has been updated and a new zcc binary will be in the Jan 7 nightly build. Just copy the zcc binary from z88dk/bin to your own z88dk/bin. I personally prefer the asm output with -a option but the list files will include the crt which is different.
If you are using windows, this is my compiled zcc.exe if you don't want to wait:
https://drive.google.com/file/d/0B6XhJJ ... sp=sharing
zcc +embedded -vn -SO3 -startup=0 -clib=sdcc_iy --list --max-allocs-per-node200000 test.c -o test
The new "--list" option will generate list files for all input source files including the crt.
At the stage that the list files are generated, addresses have not yet been patched by the linker. For example in a simple test compile something like this was generated in the list file:
Notice the call to printf is calling address 0. This is because printf's address has not been resolved at the assemble stage when the list file is created.
For crt0.lst, the entire asm source listing is present, including IFDEF blocks that are present for implementing options. These options have already been processed at the list file stage so you can see what is actually present by looking at whether output is generated for asm statements.
Here's a brief example from a crt0.lst file:
What happens at program termination depends on crt options. The program might loop forever if there is no host present, the crt may restart the program or the program may exit to a host.
In the above you can see that three instructions are generated corresponding to "halt; jr ASMPC". This is an infinite loop so the crt is set up to halt the program on exit. The other options do not generate code.
If you are using windows, this is my compiled zcc.exe if you don't want to wait:
https://drive.google.com/file/d/0B6XhJJ ... sp=sharing
zcc +embedded -vn -SO3 -startup=0 -clib=sdcc_iy --list --max-allocs-per-node200000 test.c -o test
The new "--list" option will generate list files for all input source files including the crt.
At the stage that the list files are generated, addresses have not yet been patched by the linker. For example in a simple test compile something like this was generated in the list file:
Code: Select all
328 0000 _main:
329 0000 21 0E 00 ld hl,___str_0
330 0003 E5 push hl
331 0004 21 00 00 ld hl,_buffer
332 0007 E5 push hl
333 0008 CD 00 00 call _printf
334 000B F1 pop af
335 000C F1 pop af
336 000D C9 ret
For crt0.lst, the entire asm source listing is present, including IFDEF blocks that are present for implementing options. These options have already been processed at the list file stage so you can see what is actually present by looking at whether output is generated for asm statements.
Here's a brief example from a crt0.lst file:
Code: Select all
616 0000 ; terminate
617 0000
618 0000 IF __crt_enable_restart
619 0000
620 0000 ; restart the program
621 0000
622 0000 IF __register_sp = -1
623 0000
624 0000 ; restore sp
625 0000
626 0000 ld sp,(__sp)
627 0000
628 0000 ENDIF
629 0000
630 0000 IF __crt_org_code = 0
631 0000
632 0000 di
633 0000
634 0000 ENDIF
635 0000
636 0000 jp __Restart
637 0000
638 0000 ELSE
639 0000
640 0000 ; exit program
641 0000
642 0000 E1 pop hl ; hl = return status
643 0001
644 0001 IF __crt_org_code = 0
645 0001
646 0001 76 halt ; some tools like to see this
647 0002 18 FE jr ASMPC ; loop forever
648 0004
649 0004 ELSE
650 0004
651 0004 ld sp,(__sp)
652 0004 ret ; return to host
653 0004
654 0004 ENDIF
655 0004
656 0004 ENDIF
In the above you can see that three instructions are generated corresponding to "halt; jr ASMPC". This is an infinite loop so the crt is set up to halt the program on exit. The other options do not generate code.
Ok, thanks again. I was able to see the crt assembly by running the compile with -v and reissung the second z80asm with --list
z80asm --list -a -m -Mo -oto -Lc:\z88dk\Lib\Config\\..\..\\libsrc\_DEVELOPMENT\lib\sdcc_iy -iembedded -D__SDCC -D__SDCC_IY -Ic:\z88dk\Lib\Config\\..\..\\libsrc\_DEVELOPMENT\target\embedded crt0.opt testembed.o
I'm currently puzzling through it but there may just be too much sophistication going on here for my simple mind and target.
I started poking at z88dk because SDCC required me to explicitly locate my code and data and it does runtime initialization of globals. I'm beginning to think z88dk is too steep a hill to climb for the benefit in my limited case. Clearly it's an excellent piece of work but it may just be too heavy duty for me in this instance.
I do thank you for the fast and effective response though. Much appreciated.
Actually, one more question. Would it be possible to have a CRT that did absolutely nothing other than jump to or call main?
z80asm --list -a -m -Mo -oto -Lc:\z88dk\Lib\Config\\..\..\\libsrc\_DEVELOPMENT\lib\sdcc_iy -iembedded -D__SDCC -D__SDCC_IY -Ic:\z88dk\Lib\Config\\..\..\\libsrc\_DEVELOPMENT\target\embedded crt0.opt testembed.o
I'm currently puzzling through it but there may just be too much sophistication going on here for my simple mind and target.
I started poking at z88dk because SDCC required me to explicitly locate my code and data and it does runtime initialization of globals. I'm beginning to think z88dk is too steep a hill to climb for the benefit in my limited case. Clearly it's an excellent piece of work but it may just be too heavy duty for me in this instance.
I do thank you for the fast and effective response though. Much appreciated.
Actually, one more question. Would it be possible to have a CRT that did absolutely nothing other than jump to or call main?
Last edited by bill2009 on Wed Jan 06, 2016 10:12 pm, edited 1 time in total.
Most of the time, especially for embedded targets, the crt comes down to a couple dozen bytes or less. It's just that z88dk tries to be a complete C implementation which means we have to deal with streamed i/o and device instantiation, among other things. sdcc is much more minimal in terms of its crts and libraries, only implementing just enough to support simple embedded systems. There are no streams, eg, the entire scanf side is missing, etc. So the crts look very simple in comparison But we make sure crt options are able to pare down to the minimum required; the embedded target's crt is written to be suitable for very simple devices.bill2009 wrote:I'm currently puzzling through it but there may just be too much sophistication going on here for my simple mind and target.
I find it much easier to look at the m4 macro defining the embedded target crt to understand what is going on. That was written by a human -- what is seen after that is the result of macro expansion.
z88dk/libsrc/_DEVELOPMENT/target/embedded/startup/embedded_crt_rom.m4
(there is only one crt for the embedded target and it is generated from this)
http://z88dk.cvs.sourceforge.net/viewvc ... iew=markup
The base directory for the includes is
z88dk/libsrc/_DEVELOPMENT/target/embedded/
Lines 11-17 settle on the final crt options. The C library defines defaults, the target can override those and finally pragmas embedded in the C source override those. crt options are things like code org, data org, bss org, heap size and so on.
Lines 19-23 define the memory map. The supplied memory map creates the standard CODE/DATA/BSS sections.
Lines 25-30 define some global symbols. These are things internal to the c lib as well as defines for IOCTLs and error numbers.
Lines 32-43 instantiate drivers and define FILE streams (stdin, stdout, stderr) and what file descriptors device drivers are assigned to. The embedded target doesn't have any drivers so there is just a begin and end with nothing in between.
Line 45 and up is the first actual startup code belonging to the crt. There are two cases for the embedded target that complicate the reading somewhat. If the code org is 0, the crt inserts the z80 restarts. Otherwise the restarts are not inserted. If your org is away from 0, the startup code then looks like this:
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; STARTUP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SECTION CODE
PUBLIC __Start, __Exit
EXTERN _main
__Start:
; set stack address
IF (__register_sp = -1) || (__crt_enable_restart = 0)
; save current sp if sp not supplied or returning to host
ld (__sp),sp
ENDIF
__Restart:
IF __register_sp != -1
; crt supplies sp
ld sp,__register_sp
ENDIF
; commandline
IF __crt_enable_commandline = 1
ld hl,0
push hl ; argv[argc] = NULL
add hl,sp
push hl ; argv[0] = ""
dec hl
dec hl ; hl = argv
ld bc,1 ; bc = argc = 1
IF __SDCC | __SDCC_IX | __SDCC_IY
push hl ; argv
push bc ; argc
ELSE
push bc ; argc
push hl ; argv
ENDIF
ENDIF
; initialize data section
include "../clib_init_data.inc"
; initialize bss section
include "../clib_init_bss.inc"
SECTION code_crt_init ; user and library initialization
SECTION code_crt_main
; call user program
call _main ; hl = return status
; run exit stack
IF __clib_exit_stack_size > 0
EXTERN asm_exit
jp asm_exit ; exit function jumps to __Exit
ENDIF
__Exit:
IF __crt_enable_restart = 0
; returning to host
push hl ; save return status
ENDIF
SECTION code_crt_exit ; user and library cleanup
SECTION code_crt_return
; close files
include "../clib_close.inc"
; terminate
IF __crt_enable_restart
; restart the program
IF __register_sp = -1
; restore sp
ld sp,(__sp)
ENDIF
IF __crt_org_code = 0
di
ENDIF
jp __Restart
ELSE
; exit program
pop hl ; hl = return status
IF __crt_org_code = 0
halt ; some tools like to see this
jr ASMPC ; loop forever
ELSE
ld sp,(__sp)
ret ; return to host
ENDIF
ENDIF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; RUNTIME VARS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IF (__register_sp = -1) || (__crt_enable_restart = 0)
SECTION BSS_UNINITIALIZED
__sp: defw 0
ENDIF
include "../clib_variables.inc"
include "clib_target_variables.inc"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CLIB STUBS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
include "../clib_stubs.inc"
If the stack pointer must be saved, it is saved in the special BSS_UNINITIALIZED section that is separate but adjacent to BSS. This prevents the stored SP value from being zeroed when the BSS section is initialized.
The variables and stubs are c lib quantities like initialization of the heap and things that are not implemented yet but need a name defined to allow compilation to complete.
What's controlling which crt options are defined are your program's pragmas and the defaults defined in:
z88dk/libsrc/_DEVELOPMENT/target/embedded/crt_target_defaults.inc
http://z88dk.cvs.sourceforge.net/viewvc ... iew=markup
You're using startup=0 which sets __CRTDEF=0 so the active crt options are between lines 18 and 51. These crt options are discussed in the wiki:
http://www.z88dk.org/wiki/doku.php?id=t ... figuration
The minimal crt will result by turning most things off so these changes to those defaults is what I would add to my main.c:
Code: Select all
#pragma output CRT_ORG_CODE = 32768 // away from address 0 means no restarts
#pragma output CRT_ENABLE_CLOSE = 0 // don't close files on exit as there aren't any
#pragma output CLIB_EXIT_STACK_SIZE = 0 // no functions can be registered with atexit()
#pragma output CLIB_MALLOC_HEAP_SIZE = 0 // no heap
#pragma output CLIB_STDIO_HEAP_SIZE = 0 // no stdio heap means no files can be created
Code: Select all
__Start:
ld (__sp),sp
__Restart:
ld sp,0x0000
call _main
__Exit:
push hl
pop hl
ld sp,(__sp)
ret
If you are looking for a way to add stdin, stdout, stderr let me know. The easiest target to follow would be cp/m for that but it's best if I just give an example implementation for the sort of i/o device you are using.
It will look a little daunting at first but I promise it's fairly straightforward. There's nothing wrong with using sdcc but if you use it through z88dk, sdcc's output is improbed, sometimes substantiallyI'm beginning to think z88dk is too steep a hill to climb for the benefit in my limited case. Clearly it's an excellent piece of work but it may just be too heavy duty for me in this instance.
Yes when I'm back online later tonight I'll give you a boiler plate crt which you can modify with your own startup code.bill2009 wrote:Actually, one more question. Would it be possible to have a CRT that did absolutely nothing other than jump to or call main?
The embedded crt does give you a pretty small crt as noted in the last post. With regard to that one you may still want to change the location of the stack (#pragma output REGISTER_SP = ???) if the top of memory is occupied. If you need a heap, change the malloc heap size to something larger than 14 bytes and one will be created in the BSS section. If you set that to -1 (the default), the heap will automatically occupy the space between the end of BSS and the bottom of the stack (the default assumption is the stack size is 512 bytes). However if the computed heap size turns out to be negative, the program will exit without any indication. Memstreams are fairly new but in case you need to create them, you must have some bytes allocated to the stdio heap and the malloc heap; the former is used to create FILE*s.
I think the best way to make a custom crt is to make a new one for the embedded target. If you start adding i/o streams, a new target should be started.
A zip file containing all modified files described below:
https://drive.google.com/file/d/0B6XhJJ ... sp=sharing
First I created a crt.m4 named "embedded_crt_99.m4" inside z88dk/libsrc/_DEVELOPMENT/target/embedded/startup
The 99 is just some out of the way number.
embedded_crt_99.m4
Most of the pragmas will still be active and you will still be able to automatically create a heap, eg, if you add the necessary pragma to your source code.
The crt code begins at "__Start" above. I've placed a "nop" there so that I can control the name of the output file. Without it there is no code generated until after "SECTION code_crt_main" so the first non-empty section will be "code_crt_main" which means the name of the output file would be "test_code_crt_main.bin". With the nop there the first non-empty section is "CODE" and the output name will be "test_CODE.bin". If you add something underneath the CODE section you can get rid of the nop. A better solution would be to put a short library function in there that is always used.
Next you can insert optional code to initialize the stack pointer. As noted in the comments, if __register_sp is -1, the user is indicating that the stack pointer should not be changed. You're the user so you can decide if you want to pay attention to the __register_sp pragma.
Initialization of the data and bss sections follow. In the RAM model, neither is done and this inserts no code.
"SECTION code_crt_init" is a point for the user or library to insert initialization code. If a heap is present, the c library will insert heap initialization code here.
Next main is called. You can launch main however you want but the crt code shown will be consistent with how C programs are supposed to behave.
After main returns, exit() is called if exit functions can be registered (__clib_exit_stack_size > 0).
The label "_Exit" is the point that exit() jumps to after calling the exit functions. It should be present even if __clib_exit_stack_size = 0.
At this point HL holds the return value. You can choose to save it or ignore it. The code saves it.
"SECTION code_crt_exit" is a point for the user or library to insert exit code. Destructors, eg.
There are no files so the close file include does nothing.
Then you have to decide what to do with a program exit. The code here just loops forever.
Second I expanded the embedded_crt_99.m4 macro into an asm file "embedded_crt_99.asm"
This is done by running m4 on it:
m4 embedded_crt_99.m4 > embedded_crt_99.asm
If your using something other than windows you probably have this already. Otherwise it's easy to install: http://www.z88dk.org/wiki/doku.php?id=temp:front#m4
If you don't want to install m4 you can copy the embedded_crt_99.asm file I included in the zip. The asm file contains the crt used in the compile so if you want to edit the crt embedded_crt_99.asm is what needs to be changed.
Third, one directory up in z88dk/libsrc/_DEVELOPMENT/target/embedded I edited "embedded_crt.asm" to add a startup=99 option and to make startup=99 the default.
You can copy the entire file from the zip but these are the relevant edits:
This makes startup=99 the default. When you compile with zcc +embedded you no longer have to add "-startup=99" to get your crt selected.
At the end of the file this was added to define what happens when "-startup=99" appears on the compile line. We load up "embedded_crt_99.asm", we select the normal memory map (__MMAP=0) defining CODE/DATA/BSS sections, and we choose new crt options indicated by __CRTDEF=99.
Fourth, new crt options are defined in z88dk/libsrc/_DEVELOPMENT/target/embedded/crt_target_defaults.inc under __CRTDEF=99
Again you can copy the relevant file from the zip.
The change adds this to the file:
When your crt is selected, these will be the crt options active. You can still override them with pragmas in the C source.
After these changes are made, a compile like this:
zcc +embedded -vn -SO3 -clib=sdcc_iy --max-allocs-per-node200000 test.c -o test
will choose -startup=99 and your crt by default. You can still access the built-in crts by specifying a startup value of 0, 1, or 2.
Let me know if things work out.
A zip file containing all modified files described below:
https://drive.google.com/file/d/0B6XhJJ ... sp=sharing
First I created a crt.m4 named "embedded_crt_99.m4" inside z88dk/libsrc/_DEVELOPMENT/target/embedded/startup
The 99 is just some out of the way number.
embedded_crt_99.m4
Code: Select all
dnl############################################################
dnl## EMBEDDED_CRT_99.M4 - STANDALONE TARGET ##
dnl############################################################
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; embedded standalone target ;;
;; generated by target/embedded/startup/embedded_crt_99.m4 ;;
;; ;;
;; flat 64k address space ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CRT AND CLIB CONFIGURATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
include "../crt_defaults.inc"
include "crt_target_defaults.inc"
include "../crt_rules.inc"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SET UP MEMORY MODEL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
include "memory_model.inc"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GLOBAL SYMBOLS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
include "../clib_constants.inc"
include "clib_target_constants.inc"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INSTANTIATE DRIVERS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The embedded target has no device drivers so it cannot
; instantiate FILEs.
; It can use sprint/sscanf + family and it can create
; memstreams in the default configuration.
include(../../clib_instantiate_begin.m4)
include(../../clib_instantiate_end.m4)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; STARTUP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SECTION CODE
PUBLIC __Start, __Exit
EXTERN _main
__Start:
nop
; set stack address (optional)
; IF __register_sp != -1
;
; ld sp,__register_sp
;
; ENDIF
; initialize data section
include "../clib_init_data.inc"
; initialize bss section
include "../clib_init_bss.inc"
SECTION code_crt_init ; user and library initialization
SECTION code_crt_main
; call user program
call _main ; hl = return status
; run exit stack
IF __clib_exit_stack_size > 0
EXTERN asm_exit
jp asm_exit ; exit function jumps to __Exit
ENDIF
__Exit:
; hl = return status
push hl
SECTION code_crt_exit ; user and library cleanup
SECTION code_crt_return
; close files
include "../clib_close.inc"
pop hl ; hl = return status
jr ASMPC ; infinite loop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; RUNTIME VARS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SECTION BSS_UNINITIALIZED
; place any uninitialized data here (eg saved stack pointer)
; bss and data section initialization will not touch it
include "../clib_variables.inc"
include "clib_target_variables.inc"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CLIB STUBS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
include "../clib_stubs.inc"
The crt code begins at "__Start" above. I've placed a "nop" there so that I can control the name of the output file. Without it there is no code generated until after "SECTION code_crt_main" so the first non-empty section will be "code_crt_main" which means the name of the output file would be "test_code_crt_main.bin". With the nop there the first non-empty section is "CODE" and the output name will be "test_CODE.bin". If you add something underneath the CODE section you can get rid of the nop. A better solution would be to put a short library function in there that is always used.
Next you can insert optional code to initialize the stack pointer. As noted in the comments, if __register_sp is -1, the user is indicating that the stack pointer should not be changed. You're the user so you can decide if you want to pay attention to the __register_sp pragma.
Initialization of the data and bss sections follow. In the RAM model, neither is done and this inserts no code.
"SECTION code_crt_init" is a point for the user or library to insert initialization code. If a heap is present, the c library will insert heap initialization code here.
Next main is called. You can launch main however you want but the crt code shown will be consistent with how C programs are supposed to behave.
After main returns, exit() is called if exit functions can be registered (__clib_exit_stack_size > 0).
The label "_Exit" is the point that exit() jumps to after calling the exit functions. It should be present even if __clib_exit_stack_size = 0.
At this point HL holds the return value. You can choose to save it or ignore it. The code saves it.
"SECTION code_crt_exit" is a point for the user or library to insert exit code. Destructors, eg.
There are no files so the close file include does nothing.
Then you have to decide what to do with a program exit. The code here just loops forever.
Second I expanded the embedded_crt_99.m4 macro into an asm file "embedded_crt_99.asm"
This is done by running m4 on it:
m4 embedded_crt_99.m4 > embedded_crt_99.asm
If your using something other than windows you probably have this already. Otherwise it's easy to install: http://www.z88dk.org/wiki/doku.php?id=temp:front#m4
If you don't want to install m4 you can copy the embedded_crt_99.asm file I included in the zip. The asm file contains the crt used in the compile so if you want to edit the crt embedded_crt_99.asm is what needs to be changed.
Third, one directory up in z88dk/libsrc/_DEVELOPMENT/target/embedded I edited "embedded_crt.asm" to add a startup=99 option and to make startup=99 the default.
You can copy the entire file from the zip but these are the relevant edits:
Code: Select all
IFNDEF startup
; startup undefined so select a default
defc startup = 99
ENDIF
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; custom crt ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IF startup = 99
; custom crt
IFNDEF __CRTDEF
defc __CRTDEF = 99
ENDIF
IFNDEF __MMAP
defc __MMAP = 0
ENDIF
INCLUDE "startup/embedded_crt_99.asm"
ENDIF
Fourth, new crt options are defined in z88dk/libsrc/_DEVELOPMENT/target/embedded/crt_target_defaults.inc under __CRTDEF=99
Again you can copy the relevant file from the zip.
The change adds this to the file:
Code: Select all
IF __CRTDEF = 99
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; custom crt ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
defc TAR__crt_org_code = 32768 ;; code origin is 32768
defc TAR__crt_org_data = 0 ;; data section appends to code
defc TAR__crt_org_bss = 0 ;; bss section appends to data
defc TAR__crt_model = 0 ;; ram model
defc TAR__register_sp = 0 ;; initial stack pointer set to 0 (this is ignored in the crt written)
defc TAR__crt_stack_size = 512 ;; stack size is 512 bytes (only used if the heap is automatically initialized)
defc TAR__crt_initialize_bss = 0 ;; do not initialize bss section to zero (it's zero already in the binary generated for the ram model)
defc TAR__crt_enable_commandline = 0 ;; no command line needed (ignored in the crt written)
defc TAR__crt_enable_restart = 0 ;; not restarting the program on exit (ignored in the crt written)
defc TAR__crt_enable_close = 0 ;; do not close files on exit
defc TAR__crt_enable_rst = 0 ;; no z80 restarts implemented by user (ignored in crt written)
defc TAR__crt_enable_nmi = 0 ;; nmi not implemented by user (ignored in crt written)
; clib defaults
defc TAR__clib_exit_stack_size = 0
defc TAR__clib_quickexit_stack_size = 0
defc TAR__clib_malloc_heap_size = 0
defc TAR__clib_stdio_heap_size = 0
defc TAR__clib_balloc_table_size = 0
defc TAR__clib_fopen_max = 0
defc TAR__clib_open_max = 0
ENDIF
After these changes are made, a compile like this:
zcc +embedded -vn -SO3 -clib=sdcc_iy --max-allocs-per-node200000 test.c -o test
will choose -startup=99 and your crt by default. You can still access the built-in crts by specifying a startup value of 0, 1, or 2.
Let me know if things work out.
Glad to hear it worked.
Another option you might need is "-m" which will create a map file listing values of all labels first in alphabetical order then in address order (there is a top half and a bottom half).
If you need to sprintf floats using %aefg, they have to be enabled. They are disabled by default so a non-float printf core is available for compiles. You can enable that or otherwise customize the library by editing the clib_cfg.asm file in target/embedded. There is some description of that in http://www.z88dk.org/wiki/doku.php?id=t ... figuration . Documentation for the meaning of the customizations is in the clib_cfg.asm file itself.
I've started documentation on creating a new target and writing drivers but it may take a couple of days to complete: http://www.z88dk.org/wiki/doku.php?id=t ... g_a_target
Another option you might need is "-m" which will create a map file listing values of all labels first in alphabetical order then in address order (there is a top half and a bottom half).
If you need to sprintf floats using %aefg, they have to be enabled. They are disabled by default so a non-float printf core is available for compiles. You can enable that or otherwise customize the library by editing the clib_cfg.asm file in target/embedded. There is some description of that in http://www.z88dk.org/wiki/doku.php?id=t ... figuration . Documentation for the meaning of the customizations is in the clib_cfg.asm file itself.
I've started documentation on creating a new target and writing drivers but it may take a couple of days to complete: http://www.z88dk.org/wiki/doku.php?id=t ... g_a_target
Ok. This probably warrants its own thread but I'm following along with the new target instructions. I have the .cfg and the directory structure done and i've changed all the "temp" references to my target name "zmc". I'm at the stage now where it's looking for zmc.lib and not finding it. I've looked around for anything like embedded.lib that i could copy but no sign of any .lib files. Eagerly awaiting next steps....
(in case the .lib referrence is caused by some error of mine, the failing command is below)
z80asm -a -m -Mo -oa.bin -Lh:\apps\z88dk\Lib\Config\\..\..\/libsrc/_DEVELOPMENT/lib/sdcc_iy -izmc -D__SDCC -D__SDCC_IY -Ih:\apps\z88dk\Lib\Config\\..\..\/libsrc/_DEVELOPMENT/target/zmc --list C:\Users\Bill\AppData\Local\Temp\s3suk_1.opt C:\Users\Bill\AppData\Local\Temp\s3suk_.o
Error: cannot read file 'zmc.lib'
1 errors occurred during assembly
(in case the .lib referrence is caused by some error of mine, the failing command is below)
z80asm -a -m -Mo -oa.bin -Lh:\apps\z88dk\Lib\Config\\..\..\/libsrc/_DEVELOPMENT/lib/sdcc_iy -izmc -D__SDCC -D__SDCC_IY -Ih:\apps\z88dk\Lib\Config\\..\..\/libsrc/_DEVELOPMENT/target/zmc --list C:\Users\Bill\AppData\Local\Temp\s3suk_1.opt C:\Users\Bill\AppData\Local\Temp\s3suk_.o
Error: cannot read file 'zmc.lib'
1 errors occurred during assembly
The bit for building the library is not there yet but it's easy to add.bill2009 wrote:Ok. This probably warrants its own thread but I'm following along with the new target instructions. I have the .cfg and the directory structure done and i've changed all the "temp" references to my target name "zmc". I'm at the stage now where it's looking for zmc.lib and not finding it. I've looked around for anything like embedded.lib that i could copy but no sign of any .lib files. Eagerly awaiting next steps....
In z88dk/libsrc/_DEVELOPMENT, Winmake.bat and Makefile are responsible for building the z80 libraries. You just have to add "zmc" to the build lists.
In Winmake.bat (in Windows you'll have to edit it by right clicking and choosing "send to" + your text editor) change this line:
Code: Select all
set alltargets= embedded cpm m zx
Code: Select all
set alltargets= embedded cpm m zmc zx
In the Makefile change this line:
Code: Select all
TARGET ?= embedded zx m cpm
Code: Select all
TARGET ?= embedded zmc zx m cpm
Winmake zmc (windows)
make TARGET=zmc (non-windows)
There shouldn't be any errros. Three libraries are built and should appear as "zmc.lib" in z88dk/libsrc/_DEVELOPMENT/lib/sccz80, lib/sdcc_ix, lib/sdcc_iy.
The other thing that has to be done is to make the crt. This will be the same as in already discussed above and after that is done there should be a functioning target. The next steps would be adding any target-specific code and writing device drivers.
I have a functioning Target! I tried it with the default CRT and it worked but i copied the embedded_CRT_99 to zmc_CRT_99 and fiddled target_defaults.inc and zmc_crt.asm to make this the default and i'm now getting the simpler crt.
I did have to remove the @sound line from the three .lst files - as you note it needs some defines which i don't have.
So to use printf I need a driver?
I did have to remove the @sound line from the three .lst files - as you note it needs some defines which i don't have.
So to use printf I need a driver?
Last edited by bill2009 on Sun Jan 10, 2016 6:58 pm, edited 1 time in total.
I was just working on the wiki now and was going to let you know that sound has to be excluded from the library if some defines are missing, otherwise the library will fail to build. So I will be changing the download zip to exclude sound from the example target.
But yes to get printf to work you'll need to write a driver. I'll skip the crt discussion in the wiki for now and jump to the driver so maybe it can have something substantive there today. What's your output device like and do you have an input one as well? For output is it a serial device (like a physical terminal or simply rs232) or is it bitmapped? If you have an input device you can think about console functionality otherwise it can be a simpler output driver.
Nice! You can assign CRT numbers as you like -- there is some method behind the crt number assignments for the zx and cpm targets that are linked to the stdin/stdout drivers which you can choose to adopt or not.bill2009 wrote:I have a functioning Target! I tried it with the default CRT and it worked but i copied the embedded_CRT_99 to zmc_CRT_99 and fiddled target_defaults.inc and zmc_crt.asm to make this the default and i'm now getting the simpler crt.
So to use printf I need a driver?
But yes to get printf to work you'll need to write a driver. I'll skip the crt discussion in the wiki for now and jump to the driver so maybe it can have something substantive there today. What's your output device like and do you have an input one as well? For output is it a serial device (like a physical terminal or simply rs232) or is it bitmapped? If you have an input device you can think about console functionality otherwise it can be a simpler output driver.
The console I/O is bit-bang serial I have routines in ROM that do the tricky bits. I just need to call them with the character in A and they return the same way. for example the simplest putchar is shown below. I did it in assembly because I need to get the char from L to A before calling
void putchar(unsigned char) __z88dk_fastcall;
__asm
_putchar::
ld a,l //for z88dk declared as fastcall
call 0x0FE9
ret
__endasm;
void putchar(unsigned char) __z88dk_fastcall;
__asm
_putchar::
ld a,l //for z88dk declared as fastcall
call 0x0FE9
ret
__endasm;
Device drivers are going to take a lot of explaining so it may take me several days :-/
Instead I will supply a driver for you and explain some of the parts.
A zip file containing a serial output driver can be downloaded here:
https://drive.google.com/open?id=0B6XhJ ... lpETmwyajg
The zip file contains a "driver" directory. That's the same driver directory as your target's : z88dk/libsrc/_DEVELOPMENT/target/zmc/driver
You can copy the files in there.
zmc/driver/driver.lst lists all the device driver related source files
zmc/driver/character contains character oriented device drivers
Inside this last directory are files associated with the new driver called "zmc_00_output_bbserial". I'm really bad at names but the "00_output" part is supposed to help distinguish what part of the library the code is derived from. "bbserial" stands for bit-bang serial.
zmc_00_output_bbserial.lst lists all the source files making up the driver
zmc_00_output_bbserial.m4 is an m4 macro that will instantiate the driver in your crt. Instantiation means it will statically declare the data structures required in ram
zmc_00_output_bbserial.asm is the actual driver.
If you look at the driver code there are a lot of comments and then this:
This driver inherits from "character_00_output" which you can find in the z88dk/libsrc/_DEVELOPMENT/drivers hierarchy if you care to look. What the driver is doing is intercepting one message "OCHAR_MSG_PUTC" which is requesting that you output a char. All other messages are forwarded to the base class.
The "zmc_00_output_bbserial_ochar_msg_putc" function is your putchar code and it is implemented in the subdirectory "zmc_00_output_bbserial".
If you go in there you will see how this "putchar" is implemented:
Pay attention to the allowed register use. If the code at 0x0fe9 alters any other registers (including the EXX set!) you will have to push&pop them. Carry must be reset to indicate succes before return. If there is an error you can generate an errno by exiting via one of the error functions that sets carry flag in z88dk/libsrc/_DEVELOPMENT/error . If the carry flag is set, HL=0 to indicate error and -1 for EOF (closed serial port I guess?). Returning with the carry flag set will place the driver in an error state that won't accept further output unless clearerr() is run.
This driver is an ascii stream that does CR/LF conversion. On the C side "\n" will be turned into "\r\n" on the output stream.
Turning that off is under program control with "ioctl(1, IOCTL_OCHAR_CRLF, 0);" -- the last '0' is actually on=1 or off=0. But it can also be turned off by default in the macro (I elected to turn it on).
You can also make a binary stream so that no text CR./LF is considered. If you back up to the top:
You can intercept the message "OCHAR_MSG_PUTC_BIN" instead of "OCHAR_MSG_PUTC" and this will deactivate the text stream stuff.
You don't have to modify anything I've done. The next thing to do is add the driver.lst file to your libraries.
In target/zmc/library, add "@target/zmc/driver/driver.lst" to each of the list files.
Next you need to modify your crt to instantiate the output driver on stdout.
Edit the m4 crt file "target/zmc/startup/zmc_crt_0.m4" (or whatever you have called it)
Where it used to say this:
replace with this:
The paths are relative to the startup directory where m4 is run from.
The comments at the beginning list the available drivers. Then the drivers are instantiated between the "begin" and "end" macros. The file descriptors assigned will begin at 0 and count upward which is why the first driver instantiated is an absent one (to skip fd=0=stdin) and then second is the output driver just added. You don't have to add stderr but I put it in there as a dup of stdout.
With the m4 crt edited, create the crt by running m4 on it:
m4 zmc_crt_0.m4 > zmc_crt_0.asm
Now go up to z88dk/libsrc/_DEVELOPMENT and rebuild your library with "Winmake zmc" or "make TARGET=zmc".
One that's done, printf should be working. Let me know if you have any problems with this!
Instead I will supply a driver for you and explain some of the parts.
A zip file containing a serial output driver can be downloaded here:
https://drive.google.com/open?id=0B6XhJ ... lpETmwyajg
The zip file contains a "driver" directory. That's the same driver directory as your target's : z88dk/libsrc/_DEVELOPMENT/target/zmc/driver
You can copy the files in there.
zmc/driver/driver.lst lists all the device driver related source files
zmc/driver/character contains character oriented device drivers
Inside this last directory are files associated with the new driver called "zmc_00_output_bbserial". I'm really bad at names but the "00_output" part is supposed to help distinguish what part of the library the code is derived from. "bbserial" stands for bit-bang serial.
zmc_00_output_bbserial.lst lists all the source files making up the driver
zmc_00_output_bbserial.m4 is an m4 macro that will instantiate the driver in your crt. Instantiation means it will statically declare the data structures required in ram
zmc_00_output_bbserial.asm is the actual driver.
If you look at the driver code there are a lot of comments and then this:
Code: Select all
SECTION code_driver
SECTION code_driver_character_output
PUBLIC zmc_00_output_bbserial
EXTERN OCHAR_MSG_PUTC
EXTERN zmc_00_output_bbserial_ochar_msg_putc, character_00_output
zmc_00_output_bbserial:
cp OCHAR_MSG_PUTC
jp z, zmc_00_output_bbserial_ochar_msg_putc
jp character_00_output ; forward to library
The "zmc_00_output_bbserial_ochar_msg_putc" function is your putchar code and it is implemented in the subdirectory "zmc_00_output_bbserial".
If you go in there you will see how this "putchar" is implemented:
Code: Select all
SECTION code_driver
SECTION code_driver_character_output
PUBLIC zmc_00_output_bbserial_ochar_msg_putc
zmc_00_output_bbserial_ochar_msg_putc:
; enter : c = char
; exit : carry set if error
; can use : af, bc, de, hl, af'
ld a,c
call 0x0fe9
or a
ret
This driver is an ascii stream that does CR/LF conversion. On the C side "\n" will be turned into "\r\n" on the output stream.
Turning that off is under program control with "ioctl(1, IOCTL_OCHAR_CRLF, 0);" -- the last '0' is actually on=1 or off=0. But it can also be turned off by default in the macro (I elected to turn it on).
You can also make a binary stream so that no text CR./LF is considered. If you back up to the top:
Code: Select all
zmc_00_output_bbserial:
cp OCHAR_MSG_PUTC
jp z, zmc_00_output_bbserial_ochar_msg_putc
jp character_00_output ; forward to library
You don't have to modify anything I've done. The next thing to do is add the driver.lst file to your libraries.
In target/zmc/library, add "@target/zmc/driver/driver.lst" to each of the list files.
Next you need to modify your crt to instantiate the output driver on stdout.
Edit the m4 crt file "target/zmc/startup/zmc_crt_0.m4" (or whatever you have called it)
Where it used to say this:
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INSTANTIATE DRIVERS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
include(../../clib_instantiate_begin.m4)
include(../../clib_instantiate_end.m4)
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INSTANTIATE DRIVERS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
dnl
dnl############################################################
dnl## LIST OF AVAILABLE DRIVERS WITH STATIC INSTANTIATORS #####
dnl############################################################
dnl
dnl
dnl## output streams
dnl
dnl#include(../driver/character/zmc_00_output_bbserial.m4)
dnl
dnl## file dup
dnl
dnl#include(../../m4_file_dup.m4)dnl
dnl
dnl## empty fd slot
dnl
dnl#include(../../m4_file_absent.m4)dnl
dnl
dnl############################################################
dnl## INSTANTIATE DRIVERS #####################################
dnl############################################################
dnl
include(../../clib_instantiate_begin.m4)
;; fd=0, stdin
include(../../m4_file_absent.m4)
m4_file_absent
;; fd=1, stdout
include(../driver/character/zmc_00_output_bbserial.m4)
m4_zmc_00_output_bbserial(_stdout, 0x0010)
;; fd=2, stderr
include(../../m4_file_dup.m4)
m4_file_dup(_stderr, 0x80, __i_fcntl_fdstruct_1)
include(../../clib_instantiate_end.m4)
The comments at the beginning list the available drivers. Then the drivers are instantiated between the "begin" and "end" macros. The file descriptors assigned will begin at 0 and count upward which is why the first driver instantiated is an absent one (to skip fd=0=stdin) and then second is the output driver just added. You don't have to add stderr but I put it in there as a dup of stdout.
With the m4 crt edited, create the crt by running m4 on it:
m4 zmc_crt_0.m4 > zmc_crt_0.asm
Now go up to z88dk/libsrc/_DEVELOPMENT and rebuild your library with "Winmake zmc" or "make TARGET=zmc".
One that's done, printf should be working. Let me know if you have any problems with this!
Holy cr*p I guess they will! I really appreciate all the work you're going to here. I'm sure the overall explanation will be valuable for others as well.alvin wrote:Device drivers are going to take a lot of explaining
**I got a "You need permission" error on the google drive access.** Can you allow me access?
I've checked and my low-level code saves any regs that it uses so I should be ok so far.
I created the link again:bill2009 wrote:**I got a "You need permission" error on the google drive access.** Can you allow me access?
https://drive.google.com/file/d/0B6XhJJ ... sp=sharing
Anyone who has the link should be able to download or at least that's what it tells me
None of us like to write documentation but if you don't people are unaware of what's in there. z88dk is plagued by a lack of documentation just about everywhere. It's a but of a pain but it's something that has to be done too.
I think I followed the instructions and everything seemed ok until I tried to compile something with printf()
ld ix,(_stdout)
The line that gives the error is, not surprisingly:C:\Users\Bill\Desktop\olduinoZ\z88dk>zcc +zmc testprintf.c
1 file(s) copied.
1 file(s) copied.
1 file(s) copied.
Error at file 'stdio/z80/asm_vprintf_unlocked.asm' line 48: symbol '_stdout' not defined
1 errors occurred during assembly
Key to filenames:
C:\Users\Bill\AppData\Local\Temp\s4o4o_.o = testprintf.c
Error at file 'stdio/z80/asm_vprintf_unlocked.asm' line 48: symbol '_stdout' not defined
ld ix,(_stdout)
Make sure you are using a crt that has had stdout added. If you're using the 99 one you mentioned you have to do the device instantiation into the 99 m4 one and then create the crt with "m4 zmc_crt_99.m4 > zmc_crt_99.asm"bill2009 wrote:Error at file 'stdio/z80/asm_vprintf_unlocked.asm' line 48: symbol '_stdout' not defined
The line that gives the error is, not surprisingly:
ld ix,(_stdout)
In the m4 file this is the part that declares stdout:
Code: Select all
;; fd=1, stdout
include(../driver/character/zmc_00_output_bbserial.m4)
m4_zmc_00_output_bbserial(_stdout, 0x0010)
The m4_zmc_00_output_bbserial macro is defined in zmc/driver/character:
Code: Select all
.....
; FILE *
PUBLIC $1
$1: defw __i_stdio_file_`'__I_STDIO_NUM_FILE + 2
.....
But I think maybe you are compiling use a crt.asm that hasn't had the driver instantiated. Maybe forgetting to run m4 to make it again or creating a crt.asm that isn't used in your compile (crt_0 instead of crt_99)?
And that did it! Thanks again
[img]http://olduino.files.wordpress.com/2016 ... printf.jpg[\img]
[img]http://olduino.files.wordpress.com/2016 ... printf.jpg[\img]
Last edited by bill2009 on Mon Jan 11, 2016 8:55 pm, edited 1 time in total.