Help with making a Custom embedded CRT

Discussion about other targets
Post Reply
Neuxsone1984
Member
Posts: 30
Joined: Fri Feb 10, 2017 3:36 pm

Help with making a Custom embedded CRT

Post by Neuxsone1984 »

I started to move from SDCC to the z88dk, while I got the sdcc to make working code to run on my custom built Z-80 system. Found making ROM files for embedded app and custom configurations limited.

I have installed z88dk, made modified versions of the sdcc with the patch. Created a custom CRT asm, opt and cfg based on the embedded_crt and embedded config file.

I think I have everything right, but get this error error 119: don't know what to do with file '/tmp/tmpXXfv6lM9.i'. file extension unsupported.

Also notice in the embedded_crt0.asm has ROM_Start, but no ROM size or end. Also on RAM_Start and RAM_length, is that RAM space to be used in RAM or should it be full RAM size?

Any tips or sites that have good tutorials on setting up this would be nice, maybe in the end I will create the information I find on my site. For setting up custom builds. Making a custom CRT vs changing params in code or ROM/RAM, etc



BTW my system is 8K ROM 0x0000 and 8K RAM 0x2000, right now using a RAM chip in place of ROM/EPROM. one Z80 PIO chip, notes on setting up hardware config for z88dk.

Thanks.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Neuxsone1984 wrote:I started to move from SDCC to the z88dk, while I got the sdcc to make working code to run on my custom built Z-80 system. Found making ROM files for embedded app and custom configurations limited.

I have installed z88dk, made modified versions of the sdcc with the patch. Created a custom CRT asm, opt and cfg based on the embedded_crt and embedded config file.

I think I have everything right, but get this error error 119: don't know what to do with file '/tmp/tmpXXfv6lM9.i'. file extension unsupported.

Also notice in the embedded_crt0.asm has ROM_Start, but no ROM size or end. Also on RAM_Start and RAM_length, is that RAM space to be used in RAM or should it be full RAM size?

Any tips or sites that have good tutorials on setting up this would be nice, maybe in the end I will create the information I find on my site. For setting up custom builds. Making a custom CRT vs changing params in code or ROM/RAM, etc


BTW my system is 8K ROM 0x0000 and 8K RAM 0x2000, right now using a RAM chip in place of ROM/EPROM. one Z80 PIO chip, notes on setting up hardware config for z88dk.
Hi Neuxsone1984,

We recently moved the source code to https://github.com/z88dk/z88dk (and some of the discussion that's usually here has ended up in the issues tab, some of which may be of interest). I mention that because I've been trying to make sure all the pointers to source code have been moved out of sf.net and to github. In particular the sdcc patch ( https://github.com/z88dk/z88dk/blob/mas ... _patch.zip ) that should be applied should be the one from github because it has been updated since the move from sourceforge. If you have used a nightly build or a git clone as linux source tarball you will be up-to-date but otherwise you may want to make sure you have a recent build rather than the last release 1.99B ( https://github.com/z88dk/z88dk#installation ). z88dk is quite active and we've already made a number of changes since then.

That out of the way, you should know there are two c libraries in z88dk currently, called the classic and the new. The new is a rewrite for C11 and it comes with its own build environment (read: crts). Eventually the two will be homogenized but at the moment there is this dichotomy in there.

You are looking at the classic crt in z88dk/lib/embedded_crt0.asm while the new crt is in z88dk/libsrc/_DEVELOPMENT/target/embedded/embedded_crt.asm . For embedded targets, I'd suggest using the new c lib as the new c lib's been written with embedded applications in mind and it allows for flexible customized builds. (I'll have more to say about the classic embedded target below or in the next post).

You can find a somewhat technical introduction to using this target here: https://www.z88dk.org/wiki/doku.php?id= ... t_embedded

In particular the target is described by a compile-time configuration with defaults: https://www.z88dk.org/wiki/doku.php?id= ... figuration

For your target, you would want:

* CRT_ORG_CODE=0 (which it is by default).
* CRT_ORG_DATA=0x2000 where ram starts.
* REGISTER_SP = 0x4000 (0x2000 + 8k).

With ram size precious, you may want to reduce some of the other settings too:

* CRT_STACK_SIZE = 256 This is only used by z88dk if you have 'automatic malloc' enabled. This happens if CLIB_MALLOC_HEAP_SIZE = -1 and this causes the crt to automatically size and place the heap between the end of the BSS section and the bottom of the stack (initial SP - CRT_STACK_SIZE). If this feature is enabled and this number comes out negative at runtime, the program will simply bail rather than start.
* CLIB_MALLOC_HEAP_SIZE = 0 (no malloc heap)
* CLIB_STDIO_HEAP_SIZE = 0 (streams cannot be opened; on an embedded target this applies to memory streams)
* CLIB_FOPEN_MAX = -1 (don't even create the FILE* lists).


I'd put all those into a separate file "zpragma.inc":

#pragma output CRT_ORG_CODE = 0
#pragma output CRT_ORG_DATA = 0x2000
#pragma output REGISTER_SP = 0x4000
#pragma output CRT_STACK_SIZE = 256
#pragma output CLIB_MALLOC_HEAP_SIZE = 0
#pragma output CLIB_FOPEN_MAX = -1


And then, using one of the quick-start compile lines mentioned ( https://www.z88dk.org/wiki/doku.php?id= ... uick_start ) you could compile programs for your specific machine:

zcc +embedded -vn -SO3 -startup=1 -clib=sdcc_iy ?max-allocs-per-node200000 test.c -o test -lm -create-app -pragma-include:zpragma.inc

When CRT_ORG_CODE = 0, z88dk will supply the page zero code (see https://www.z88dk.org/wiki/doku.php?id= ... m1_and_nmi ) and you may want to attach your own code to some restarts or the interrupt. How you can do that is discussed there.

In the new c lib, everything to do with a specific target (aside from .cfg) is in z88dk/libsrc/_DEVELOPMENT/target and for embedded this is https://github.com/z88dk/z88dk/tree/mas ... t/embedded . The crt being used is https://github.com/z88dk/z88dk/blob/mas ... d_crt_0.m4 (or rather the accompanying .asm file but the m4 file is much easier to read. We use an m4 crt so that we can instantiate device drivers on stdin, stdout, stderr, etc using m4 but the embedded target has none of these things). This crt is written to implement all the features and runtime configuration described above but if you want to provide your own you can do that too.

Also note that zcc is very good with being able to mix any sort of input source into an output binary. You can add as many source files on the compile line you like and mix .c, .asm, .asm.m4 (macro expansion for asm), etc as you like.

====

So that's a quick overview of the embedded target in the new c lib. If you want to do your own target you can do that too. The advantage is you can set your own defaults, write your own crt if you want, provide your own drivers and add your own target-specific code to the library.

Quick overview:

1. Select a short unique name for your target. This is going to appear on the compile line as in "zcc +embedded ..." or "zcc +yourname ..." so something short is good. I will call this name "TARGET".

2. In z88dk/lib/config create your "TARGET.cfg" file. Just copy embedded.cfg and replace all instances of "embedded" with "TARGET". Case is sensitive so replace "EMBEDDED" with "TARGET" and "embedded" with "target". This config file sets up compile defaults which you may want to change once you know what is going on but as is, compiles will work as described in https://www.z88dk.org/wiki/doku.php?id= ... t_embedded . The "CRT0" line sets up for the classic lib and I will describe that as well later if dom or stef don't come along but I am a bit short on time atm.

3. In z88dk/libsrc/_DEVELOPMENT/target copy create a new tree "TARGET" that is a copy of the embedded tree there. In your new TARGET tree, you'll have to go through all files and filenames, replacing "embedded" with TARGET.

4. Add your target to the build. In z88dk/libsrc/_DEVELOPMENT, edit "Makefile" to include your target by modifying "TARGET ?= cpm embedded m rc2014 sms z180 zx" to include your target. It seems I should have been more careful with the name :P Also edit "Winmake.bat" by modifying "set alltargets= embedded cpm m rc2014 sms z180 zx " to include your target. Note that this line must have a space at the front and end of the target list.

5. In z88dk/libsrc/_DEVELOPMENT/TARGET edit some basic configuration information.

* In "clib_target_cfg.asm" (and its .bak backup) changed "defc _embedded" to your target name if you haven't already. Edit the cpu clock so that the library can measure time accurately (see things like z80_delay_ms in z80.h). Leave cpuinfo at nmos unless you will only use cmos z80s.

* In "crt_target_defaults.inc" (and its .bak backup) set the default configuration that you want. This is where you put the pragma values discussed above so that you can compile with those values without a special pragma file. There are three sets defined: one for ram model compiles (for programs that are destined for ram) and the other two for rom models which applies more directly to you.

6. Cross fingers and build your target's library. Go to z88dk/libsrc/_DEVELOPMENT and run "make TARGET=target" (non-windows, that's your target's name in lower case there) or "Winmake target" (windows). If all is well, no errors and your target will have libraries in each of the subdirs in z88dk/libsrc/_DEVELOPMENT/lib

Now you're ready to compile a test:

zcc +target -vn -SO3 -startup=1 -clib=sdcc_iy ?max-allocs-per-node200000 test.c -o test -lm -create-app

Further customization can go into changing the memory map (not likely to be needed), adding stdin/stdout/stderr although at 8k rom a full stdio implementation with streams would be a luxury, customizing library option (clib_cfg.asm), adding your own specialized code to the library (library/*.lst), writing your own crt and probably other things :)


One thing that people are sometimes unaware of is that you don't have to use C in z88dk. The assembler in z88dk, coupled with m4 for macros, is very powerful and zcc is perfectly happy to chew on an all-asm project.


More later on the classic lib
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

> I think I have everything right, but get this error error 119: don't know what to do with file '/tmp/tmpXXfv6lM9.i'. file extension unsupported.

I'm not sure what this error is about. The .i file should be a known type (it's a .c file after preprocessing). Try the suggestions above and see if things work.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

I should try to consolidate my thoughts a little better :)

One last thing: there is no sections size enforcement. zcc's output will be "foo_CODE.bin", "foo_DATA.bin" and "foo_BSS.bin" corresponding to the code, data and bss sections. When -create-app is added, the final output binary "foo.bin" will be produced. This "foo.bin" must fit into your 8k rom. The data+bss will go into your ram segment starting at 0x2000. Not included in the ram requirement is the stack which will grown downward from the top.

You'll have to keep an eye on sizes to make sure things will fit into your system.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Note that in:

"zpragma.inc":

#pragma output CRT_ORG_CODE = 0
#pragma output CRT_ORG_DATA = 0x2000
#pragma output REGISTER_SP = 0x4000
#pragma output CRT_STACK_SIZE = 256
#pragma output CLIB_MALLOC_HEAP_SIZE = 0
#pragma output CLIB_FOPEN_MAX = -1

you will need "CLIB_FOPEN_MAX" to be at least 0 if using the sprintf/sscanf families. Maybe it's better to set to zero.
Neuxsone1984
Member
Posts: 30
Joined: Fri Feb 10, 2017 3:36 pm

Post by Neuxsone1984 »

Thanks for the reply, I just now noticed I got an reply to my message after logging in here this evening (sort of expected an e-mail when I got a reply), I going to digest what you have suggested and give it a try. This is an after hours project and I go from days to a week until I get time to go back at it.

And I know the ADHD issue, I go from working on the Z-80 code to the Beaglebone and I using to program and develope the board. To playing with interfacing stuff to the PIO and coding it. Though I hope this will help with the core code stuff, in a base system CRT configuration going. My whole idea of using C is to focus on code app vs. a lot of low level stuff like memory handling variables etc.

I try to drop a note once I have it going.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

And I know the ADHD issue,
It's made much worse by not being able to edit forum posts :D
Thanks for the reply, I just now noticed I got an reply to my message after logging in here this evening (sort of expected an e-mail when I got a reply), I going to digest what you have suggested and give it a try. This is an after hours project and I go from days to a week until I get time to go back at it.
That's fine; let us know if you run into trouble.

In the above I didn't successfully put the entire crt configuration together in one place for compiling with the supplied embedded target.

Create a file "zpragma.inc" containing:

#pragma output CRT_ORG_CODE = 0
#pragma output CRT_ORG_DATA = 0x2000
#pragma output REGISTER_SP = 0x4000
#pragma output CRT_STACK_SIZE = 256
#pragma output CLIB_MALLOC_HEAP_SIZE = 0
#pragma output CLIB_STDIO_HEAP_SIZE = 0

(I left CLIB_FOPEN_MAX at the default 0 rather than -1 so that sprintf/sscanf will work; it costs a few bytes of ram to do so but the cost is very small).

Then to compile for your target:

zcc +embedded -vn -SO3 -clib=sdcc_iy ?max-allocs-per-node200000 test.c -o test -lm -create-app -pragma-include:zpragma.inc

(change -vn to -v to see what zcc is doing, you can drop -lm if float math is not used, see print/scanf configruation to reduce cost of the stdio core - https://www.z88dk.org/wiki/doku.php?id= ... figuration )

You'll see mention of "reducing size from x bytes to y bytes" -- in this compile model, the stored data section is compressed but you need to save at least ~70-80 bytes for this to be a win since the decompressor is about that size. If it's a not a win you can get a smaller compile by adding "-startup=1" to the compile line for an uncompressed data section.

With "-create-app" the output is going to be "test.bin" which should be stored at address 0 in your rom. That's it. The other files "test_CODE.bin" corresponds to the code section, "test_DATA.bin" corresponds to the data section and "test_BSS.bin" corresponds to the bss section. Total ram requirement is DATA+BSS+stack (+heap if you end up enabling malloc).

You also mentioned you replaced your 8k rom with ram so you have a 16k ram target in reality? Then you can use a ram model compile instead:

Change "zpragma.inc" to:

#pragma output CRT_ORG_CODE = 0
#pragma output REGISTER_SP = 0x4000
#pragma output CRT_STACK_SIZE = 256
#pragma output CLIB_MALLOC_HEAP_SIZE = 0
#pragma output CLIB_STDIO_HEAP_SIZE = 0

zcc +embedded -vn -startup=0 -SO3 -clib=sdcc_iy ?max-allocs-per-node200000 test.c -o test -lm -create-app -pragma-include:zpragma.inc

(startup=0 selects ram model). The difference for a ram model is that there is no stored data section so the binary size will be smaller.

The output is "test.bin" which should be loaded to address 0 and jump to address 0 to start.

And then as mentioned you can make your own target if you'd like but trying the embedded target first will let you do things now and get a feel for how things work.
To playing with interfacing stuff to the PIO and coding it. Though I hope this will help with the core code stuff, in a base system CRT configuration going. My whole idea of using C is to focus on code app vs. a lot of low level stuff like memory handling variables etc.
The crt is done for you and it's easy to add your own pio code.

That section I pointed out explains how to add jumps to your own im1 interrupt code or to a restart ( https://www.z88dk.org/wiki/doku.php?id= ... m1_and_nmi ). If you're using im2 mode it's fairly easy to do that too, though that's not completely explained on that page.

One of things that is different from sdcc is that z88dk's front end (zcc) is very flexible. You can list any number of files of various types on the compile line and it will build a coherent binary out of all of it. So, eg, if you have pio code written in asm, you could include it just by adding it to the compile line:

zcc +embedded -vn -SO3 -clib=sdcc_iy ?max-allocs-per-node200000 test.c pio.asm -o test -lm -create-app -pragma-include:zpragma.inc

Just remember to properly assign your asm code and data to sections so that the linker knows where to place that stuff in memory ( https://www.z88dk.org/wiki/doku.php?id= ... y_language )
Neuxsone1984
Member
Posts: 30
Joined: Fri Feb 10, 2017 3:36 pm

Post by Neuxsone1984 »

Just did a test of code that worked under sdcc(with custom crt with my custom irq handling), with the z88dk embedded target and your list of prama changes in the inc file. I need to look into the interrupt handling under the z88dk more, I had been testing im2 mode with the Z80 PIO.

The code ran successfully on my system, as a ROM config, I know RAM config would make a small file size. But at some point the intent is to burn a EPROM for custom projects using my base Z80 hardware.

One error on the compile on a compiler setting "Error: cannot read file "-max-allocs-per-node200000.o", removed this option and compiled ok.

Thanks for your help, I hope to put on my google sites my experiences with creating this system and software used to program it.

FYI here is a overview of the first Z80 board I have built

https://www.youtube.com/watch?v=885C_DJwgrc
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Neuxsone1984 wrote:The code ran successfully on my system, as a ROM config,
Good to hear!
One error on the compile on a compiler setting "Error: cannot read file "-max-allocs-per-node200000.o", removed this option and compiled ok.
A copy and paste of the command line may not work - when I do it, at least, two minuses in a row get translated to some unicode character that fouls up the compile line. It should be "- -max-allocs-per-node200000" with two consecutive minuses instead of one. It's an sdcc option passed straight to zsdcc and, as on regular sdcc, it will lead to much better quality code generation and also much longer compile times. You may also want to try "- -opt-code-size" (two minuses) if code size is an issue. Adding "- -list" will get you asm translation prior to linking stage, "- -c-code-in-asm" will intersperse c statements, "-m" will generate the map file, among other common options.
Thanks for your help, I hope to put on my google sites my experiences with creating this system and software used to program it.
FYI here is a overview of the first Z80 board I have built
https://www.youtube.com/watch?v=885C_DJwgrc
Nice, it's always rewarding when things start to come together.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Some information about the im2 mode has been added to the wiki concerning builds dated Feb 23 or later:
https://www.z88dk.org/wiki/doku.php?id= ... e_routines

Over time I think that will be clarified but to summarize, if you are using z88dk's page zero code (CRT_ORG_CODE=0) then setting CRT_ORG_VECTOR_TABLE=-1 will cause z88dk to build an im2 vector table for you at address 0x100.

A section "code_vector" is created to hold the interrupt vector table. Suppose the vector table is defined in a separate file "interrupt.asm":

Code: Select all

SECTION code_vector

; vector 0
EXTERN _isr_pio
defw _isr_pio

; vector 2
EXTERN _isr_sio
defw _isr_sio
...
Then adding "interrupt.asm" to the compile line along with setting CRT_ORG_CODE_VECTOR=-1 will generate a program with im2 enabled. The crt will also initialize the "I" register to point at that table (I=1) and will enable interrupts just before calling main if CRT_ENABLE_EIDI is suitably set.

zcc +z80 -v -SO3 -clib=sdcc_iy --max-allocs-per-node200000 --opt-code-size test.c interrupt.asm -create-app --list -m -pragma-define:CRT_ORG_VECTOR_TABLE=-1 -pragma-define:CRT_ENABLE_EIDI=0x12

would be an example compile line. Putting those pragmas in a separate pragma.inc file would save some typing.
Post Reply