z88dk / z88dk

The development kit for over a hundred z80 family machines - c compiler, assembler, linker, libraries.
https://www.z88dk.org
Other
914 stars 174 forks source link

symbol '_stdout' not defined #562

Closed akalulyadurov closed 6 years ago

akalulyadurov commented 6 years ago

I make the file test2.c for RC2014 Mini and get an error "symbol '_stdout' not defined". If I choose to "zcc +rc2014" then I haven't that error but printf("qwerty"); doesn't work and print nothing. Somebody help me please.

test2.c

include "rc2014.h"

include

pragma output REGISTER_SP = -1

pragma output CLIB_MALLOC_HEAP_SIZE = 0

pragma output CRT_ENABLE_RESTART = 0

pragma output CRT_ON_EXIT = 0×10004

void main() { printf("qwerty"); }

some part of Makefile

pigfx: $(MAKE) -C ../pigfx/

$(APP_NAME).bin: $(APP_NAME).c pigfx cp ../init_ram/rc2014init.asm crt_preamble.asm zcc +embedded -v -m -clib=new -startup=0 -pragma-define:CRT_INCLUDE_PREAMBLE=1 -pragma-define:CRT_ORG_CODE=$(mem_org_decimal) -pragma-define:CRT_ORG_BSS=-1 -pragma-define:CRT_INITIALIZE_BSS=1 -I../pigfx/ -I../init_ram/ -I"c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\target\z80" -I"c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\target\rc2014" -l../pigfx/pigfx.lib -lrc2014.lib -lz80.lib -create-app -o $(APP_NAME) $(APP_NAME).c rm crt_preamble.asm

%.hex : %.bin cp $< aux_INIT.bin appmake +hex --org $(mem_org) -b aux_INIT.bin -o $@ rm aux_INIT.bin

make log:

c:\TASKS\RC2014-master\ROMs\test2>make

Compiling test2 with ram memory model " Memory ORG: 0x8080"

make -C ../pigfx/ make[1]: Entering directory 'c:/TASKS/RC2014-master/ROMs/pigfx' make[1]: Nothing to be done for 'all'. make[1]: Leaving directory 'c:/TASKS/RC2014-master/ROMs/pigfx' cp ../init_ram/rc2014init.asm crt_preamble.asm zcc +embedded -v -m -clib=new -startup=0 -pragma-define:CRT_INCLUDE_PREAMBLE=1 -pragma-define:CRT_ORG_CODE=32896 -pragma-define:CRT_ORG_BSS=-1 -pragma -define:CRT_INITIALIZE_BSS=1 -I../pigfx/ -I../init_ram/ -I"c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\target\z80" -I"c:\z88dk\lib\config\....\ libsrc_DEVELOPMENT\target\rc2014" -l../pigfx/pigfx.lib -lrc2014.lib -lz80.lib -create-app -o test2 test2.c

PROCESSING test2.c ucpp -I"../pigfx/" -I"../init_ram/" -I"c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\target\z80" -I"c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\ target\rc2014" -iquote"." -DZ88DK -DEMBEDDED -DEMBEDDED -D__EMBEDDED_Z80 -DZ80 -DZ80 -DSCCZ80 -isystem"c:\z88dk\lib\config\....\include_D EVELOPMENT\sccz80" -DSCCZ80 -DSMALL_C -DSCCZ80 "test2.c" "c:/tmp\zccD1C12.i2" zpragma -sccz80 < "c:/tmp\zccD1C12.i2" > "c:/tmp\zccD1C12.i" sccz80 -ext=opt -mz80 -standard-escape-chars "c:/tmp\zccD1C12.i" copt "c:\z88dk\lib\config\....\/lib/z80rules.9" < "c:/tmp\zccD1C12.opt" > "c:/tmp\zccD1C12.op1" copt "c:\z88dk\lib\config\....\/lib/z80rules.2" < "c:/tmp\zccD1C12.op1" > "c:/tmp\zccD1C12.opt" copt "c:\z88dk\lib\config\....\/lib/z80rules.1" < "c:/tmp\zccD1C12.opt" > "c:/tmp\zccD1C12.asm" type "c:/tmp\zccD1C12.asm" >> "c:/tmp\zccD1C12.tmp" type "c:/tmp\zccD1C12.tmp" >> "c:/tmp\zccD1C12.asm" z80asm -DSCCZ80 -I"c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\target\z80" -s --cpu=z80 -I"c:\z88dk\lib\config\....\/lib" "c:/tmp\zccD1C12.a sm"

PROCESSING c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\target\z80\z80_crt.asm.m4 m4 -I "c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\target\z80" -I "c:\z88dk\lib\config\....\/src/m4" --define=__STARTUP=0 < "c:\z88dk\lib\conf ig\....\libsrc_DEVELOPMENT\target\z80\z80_crt.asm.m4" > "c:/tmp\zccD1C13" type "c:/tmp\zccD1C13" >> "c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\target\z80\z80_crt.asm" type "c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\target\z80\z80_crt.asm" >> "c:/tmp\zccD1C13.asm" type "c:/tmp\zccD1C13.asm" >> "c:/tmp\zccD1C13.tmp" type "c:/tmp\zccD1C13.tmp" >> "c:/tmp\zccD1C13.asm" WILL ACT AS CRT

GENERATING OUTPUT

PROCESSING CRT z80asm -D__SCCZ80 -I"c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\target\z80" -s --cpu=z80 -I"c:\z88dk\lib\config\....\/lib" -I"c:\z88dk\lib\co nfig\....\libsrc_DEVELOPMENT\target\z80" "c:/tmp\zccD1C13.asm"

z80asm --cpu=z80 -b -d -o"test2" -m -s -L. -L"c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\lib\sccz80" -D__SCCZ80 -I"c:\z88dk\lib\config\.... \libsrc_DEVELOPMENT\target\z80" -i../pigfx/pigfx.lib -irc2014.lib -iz80.lib -iz80 "c:/tmp\zccD1C13.o" "c:/tmp\zccD1C12.o" Error at file 'stdio/z80/asm_vprintf_unlocked.asm' line 48: symbol '_stdout' not defined 1 errors occurred during assembly Errors in source file c:\z88dk\lib\config\....\libsrc_DEVELOPMENT\target\z80\z80_crt.asm: Error at file 'stdio/z80/asm_vprintf_unlocked.asm' line 48: symbol '_stdout' not defined buildrules_ram.mk:7: recipe for target 'test2.bin' failed make: *** [test2.bin] Error 1

aralbrec commented 6 years ago

"_stdout" can't be found if the crt doesn't define the stream. That's the case for the embedded target that you tried. The embedded target is meant to work on any z80 machine but because it's generic there is no device specific io so no stdout is defined by the tools.

The rc2014 target is configured with a few different compile types which have been made easy to use with subtypes. The subtypes choose which crt to use (startup value) and these define how the compile will be done. The acia type is intended to be a rom compile for address 0 so that you can replace the basic rom; stdout and stdin are using drivers for the acia supplied by @feilipu . The basic_dcio subtype is the one that works with the basic rom by sending character io through the nascom rom. This one is the only one that does line editing properly because this is the one where the right terminal comm was found but the changes have not been propagated to the other types yet.

test.c

#include <stdio.h>

void main()
{
printf("qwerty\n");   // you may need a \n for the terminal software on the pc
}

zpragma.inc

#pragma printf = ""
#pragma output CLIB_MALLOC_HEAP_SIZE = 0
#pragma output CLIB_STDIO_HEAP_SIZE = 0

I usually prefer to keep the pragmas in a separate file as above so that everything is in one place. If you are defining some in a makefile then you can add those to the compile line as you were doing. The default pragma values for basic compiles are here and the meanings of most of them are defined here. The special printf pragma lists all % converters to include in the compile; in this case they have all been eliminated since none are used and this reduces the size of printf.

To get a compile using basic_dcio using this test program:

sccz80 as c compiler zcc +rc2014 -vn -subtype=basic_dcio -clib=new test.c -o test -pragma-include:zpragma.inc -create-app

zsdcc as c compiler zcc +rc2014 -vn -subtype=basic_dcio -clib=sdcc_iy -SO3 --max-allocs-per-node200000 test.c -o test -pragma-include:zpragma.inc -create-app

In both cases the "-create-app" is going to generate the raw binaries as well as the ihex file. If you want to keep that separate in your makefile you can get rid of the create-app.

I noticed that you are adding a "rc2014init.asm" as crt preamble. The preamble is really meant to replace the library's page zero code if the org is 0x0 or to put a signature in front of the code if some system requires that. You can do what you did but there is a cleaner way to add initialization code.

If you look at one of the crts you will see that a special section is defined "code_crt_init" that sits right before _main is called. You can put code there simply by assigning to this section.

So your code might look like this:

rc2014init.asm

SECTION code_crt_init

ld hl,100
ld bc,50
.....
;; no ret here, let the code fall through

By doing that, the linker will insert your code at that point in the crt so your initialization will run before main is called.

Then you just add it to your compile line like any other source file:

sccz80 as c compiler zcc +rc2014 -vn -subtype=basic_dcio -clib=new test.c rc2014init.asm -o test -pragma-include:zpragma.inc -create-app

Let me know if you get something that works. It's been a while since I looked at the rc2014 so I can't quite remember how things should run.

akalulyadurov commented 6 years ago

Thanks a lot for a detailed comment. I flashed HexLoadr to ROM and loaded my test C program to RAM as written in 'https://github.com/RC2014Z80/RC2014/tree/master/ROMs/HexLoadr' and it is working well. I used that compile string: zcc +rc2014 -v -subtype=basic_dcio -clib=new $(APP_NAME).c -o $(APP_NAME) -pragma-include:zpragma.inc -create-app

But after using '-subtype=acia' parameter and flashing to ROM my test program I got nothing printed to stdout.

aralbrec commented 6 years ago

A compile using subtype=acia:

zcc +rc2014 -v -subtype=acia -clib=new $(APP_NAME).c -o $(APP_NAME) -pragma-include:zpragma.inc -create-app

You may have to change where the stack and ram is located for this compile. The defaults for the acia compile are here.

In particular,

   defc TAR__crt_org_code              = 0
   defc TAR__crt_org_data              = 0x8000
   defc TAR__crt_org_bss               = -1

has code generated for address 0 (crt_org_code = 0). When this is the case the library provides the z80's page zero code, meaning all the restarts and the interrupt routine at 0x38. If you are including a preamble, this would replace this page zero code so don't do that if you want a smooth compile without making changes.

The start of ram is set by crt_org_data to 0x8000. If your ram starts someplace else you will have to change this with something like #pragma output CRT_ORG_DATA = 0x4000.

The bss section follows data in ram and will be output as a separate binary (-1) so that the tools can properly attach a copy of the data section to the code.

   defc TAR__register_sp               = 0

This places the stack at the top of ram. If you don't have ram extending to 0xffff, you should change this as well with another pragma #pragma output REGISTER_SP = 0x8000. Point at one byte past the address of the top of ram (the z80 decrements sp before writing values to the stack).

The following you shouldn't have to change.

   defc TAR__crt_enable_restart        = 0x80

This is informing the library that you are providing an im1 interrupt routine named "_z80_rst_38h" that will be jumped to from address 0x38. This feature is implemented in the page zero code the library provides.

The library provides a weak default for _z80_rst_38h that causes it to jump to the acia interrupt routine that processes the tx and rx for the stdin and stdout streams.

I'm providing some insight into how this compile model works; the main issue I think you're likely having is making sure the data section is placed at the start of ram and making sure the stack pointer is pointing at the top of ram.

feilipu commented 6 years ago

The RC2014 Mini is essentially the classic RC2014. This means that it has 32kB of RAM, starting at 0x8000. The ROM is located from 0x0000 to 0x1FFF.

As there are a number of buffers for the ACIA and other BASIC storage locations in place, starting at 0x8000 we've set the default location for the start of the data section to 0x9000. There are actually quite a few bytes of free space available before this location, so the stack is set to start at 0x9000 (z80 is decrement before push) and grow down from there.

If you are not burning an entire ROM, but rather are using the facilities of the HexLoadr ROM to support your programming, then the default sub-type info for -subtype=basic (being the default subtype) looks like this, below. I've added an explanation below, but the general explanation is also very important to understand.

I strongly recommend using the HexLoadr code while you're developing. It is much faster to upload a new program using Intel HEX, rather than burning a new ROM each time.

   defc TAR__crt_org_code              = 0x9000    ; the linker places your code from here
   defc TAR__crt_org_data              = 0    ; then your data follows as part of the code binary 
   defc TAR__crt_org_bss               = -1   ; then the bss follows, but is in a separate (to be discarded) binary.

   defc TAR__register_sp               = 0x9000    ; the SP is set to this location
   defc TAR__crt_stack_size            = 256    ; this is only used where SP is above bss, for heap calculation

   defc TAR__crt_initialize_bss        = 1    ; yes, we need to initialise the bss (since it was discarded)

   defc TAR__crt_include_preamble      = 0    ; we don't need a preamble, because the HexLoadr has done this

   defc TAR__crt_org_vector_table      = 0    ; similarly we don't need a vector table
   defc TAR__crt_interrupt_mode        = -1    ; and we don't change the interrupt mode

With these defaults the HEX code will be generated to be loaded at 0x9000.

Normal HexLoadr Usage

  1. Select the preferred origin .ORG for your arbitrary program (this defaults to 0x9000 and this is correct for the RC2014 Mini), and assemble a HEX file using your preferred compiler / assembler (z88dk naturally).

  2. Start your 32k RAM RC2014 Mini with the Memory top? set to 36863 (0x8FFF) or lower. This leaves space for your program from 0x9000 through to 0xFFFF. Adjust this if needed to suit your individual needs.

  3. Reset the RC2014 and type H when offered the (C|W|H) option when booting. HexLoadr: will wait for Intel HEX formatted data on the ACIA serial interface.

  4. Using a serial terminal, upload the HEX file for your arbitrary program that you prepared in Step 1, using the Linux cat utility or similar. If desired the python slowprint.py program can also be used for this purpose. python slowprint.py > /dev/ttyUSB0 < myprogram.hex or cat > /dev/ttyUSB0 < myprogram.hex.

  5. When HexLoadr has finished, and you are back at the Basic ok prompt, use the DOKE command relocate the address for the Basic USR(x) command to point to .ORG of your arbitrary program. For the RC2014 the USR(x) jump address is located at 0x8224. If your arbitrary program is located at 0x9000 then the Basic command is DOKE &h8224, &h9000, for example.

  6. Start your program by typing PRINT USR(0), or other variant if you have a parameter to pass to your program.

akalulyadurov commented 6 years ago

Hi Phillip

thanks for your recommendations, it is very important for me. But I have understood the general explanation of HexLoadr and successfully experimented it. I also checked execution of my program 'test_ram_scm.c' flashed to RAM under the Small Computer Monitor ( https://smallcomputercentral.wordpress.com/projects/small-computer-monitor). I was convinced a 'rc2014_getc' and 'rc2014_putc' functions is working well.

I am interesting in -subtype=acia option for communicate through ACIA with RC2014 mini when my program 'test_rom.c' in ROM.

Could you advise me how to use input/output functions in my 'test_rom.c'? It is about 'acia_putc' and 'acia_getc' functions as I guess. I'd like to write my own monitor program in c. The example in RC2014-master\ROMs\buildrules.mk doesn't work for me.

Akal

feilipu commented 6 years ago

You can try with the password example, or basically any other example in the same directory, using this command line.

zcc +rc2014 -subtype=acia -clib=sdcc_iy -SO3 -v -m --list --max-allocs-per-node200000 password.c -o password -create-app

or, the equivalent for each of the other examples.

You can use the --list and -m options to generate an assembly list from the c file, and a map file respectively.

The command will generate all of the relevant files to get an Intel Hex file password.ihx starting from 0x0000 which should just work. The default configuration is...

   defc TAR__crt_org_code              = 0    ; the program starts here in ROM, so a preamble is generated including jump vectors.
   defc TAR__crt_org_data              = 0x8000    ; the data starts here in RAM
   defc TAR__crt_org_bss               = -1    ; the bss is in a separate binary file (to be discarded)

   defc TAR__crt_model                 = 2    ; the CRT model is 2

   defc TAR__register_sp               = 0    ; the stack pointer is set to top of RAM 
   defc TAR__crt_stack_size            = 256    ; this stack size is allowed for when calculating the heap size

   defc TAR__crt_initialize_bss        = 1    ; since we discarded the bss binary, we need to initialise the bss region

   defc TAR__crt_include_preamble      = 0    ; use the standard z80 preamble

   defc TAR__crt_org_vector_table      = 0    ; don't use a vector table
   defc TAR__crt_interrupt_mode        = -1   ; don't change the interrupt mode

Could you advise me how to use input/output functions in my 'test_rom.c'?

Your normal printf() and scanf() C functions work as normal. z88dk handles the I/O using the ACIA interface.

aralbrec commented 6 years ago

continued in #588