Creating my own target

Discussion about other targets
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

obiwanjacobi wrote:It looks like there are jumps to an address that is not in the bin file..?
I must not understand something fundamental...
Do you have multiple bin files being generated? There should only be one non-zero size "helloworld.bin" and "helloworld" should be zero size.
I am under the impression that the helloworld.bin file (compiled from helloworld.c) contains my program to be loaded from address $0000.
Using:
zcc +zalt -clib=sdcc_iy --max-allocs-per-node200000 -m helloworld.c -o helloworld --list

Is that correct?
Yes this is correct and you are right that there should be a single output binary at ORG 0 (if that's what your CRT_ORG_CODE was specified as in your crt configuration file).

Would you mind posting your "target/zalt/crt_target_defaults.inc" and "target/zalt/zalt_crt.asm" files? (target/zalt/zalt_crt.opt should include the asm one)
I have some trouble disassembling the bin file (because I do not know what is code and what may be data) so I could be wrong but...

Is it possible to get a list file or an asm file from the entire compiled source? (not just my part)
Code will be packed at the beginning and any data will come after the code except for string constant which may be interspersed in the code.

The library code is already in a semi-compiled state so there is no associated asm listing except, of course, you can see the source in the source directory.

What you can do is look at the second half of the map file generated which shows symbols in address order. By comparing your memory address and this map file you should be able to figure out where you are in your code or in the library code.

An excerpt from another map file:

Code: Select all

asm_strchrnul                   = 0EBE, G: asm_strchrnul
loop                            = 0EBE, L: asm_strchrnul
asm_strcmp                      = 0EC8, G: asm_strcmp
loop                            = 0EC8, L: asm_strcmp
equal                           = 0ED1, L: asm_strcmp
different                       = 0ED5, L: asm_strcmp
asm_strnlen                     = 0ED9, G: asm_strnlen
notend                          = 0EE6, L: asm_strnlen
asm__memlwr                     = 0EE9, G: asm__memlwr
loop                            = 0EED, L: asm__memlwr
In the first line "G: asm_strchrnul" the G means global (publicly exported symbol) part of the "asm_strchrnul" module. "L" means a local symbol in that module.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Not one "helloworld.bin" but one "helloworld_CODE.bin"
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Unfortunately I have to head out before I can look at this anymore but if your ORG address is 0, the crt is responsible for setting up the z80's restart vectors. In the wiki there is a short note about this at the end of the making crt section and a pointer to the embedded target's crt that generates the restarts if the org address is 0.

Maybe to save some time, do you mind zipping up your target/zalt directory and posting a link someplace?
obiwanjacobi
Member
Posts: 67
Joined: Tue Dec 22, 2015 7:39 am

Post by obiwanjacobi »

I understand the issues you've outlined, but I am just debug-hacking around in the code. Nothing permanent. First I need my hello world! :lol:

Ok for now I can see that two things bit me.

First the TAR__crt_code_org was defined at 32k. Set that to zero and it went a lot better.

Second thing is that you can run a program only once. I know you said that (somewhere) but I did not think about at the right time.

I have this working:

Code: Select all

void main(void)
{
        __asm
                
                ld a, '@'
                out ($20), a
                
                halt
                
        __endasm;        
}
I also switched to sdcc in the meantime, because I though it worked better. But I'm sure when its all working the other compiler (clib=new) will work fine.

I'll look at your other post in a bit. :)
obiwanjacobi
Member
Posts: 67
Joined: Tue Dec 22, 2015 7:39 am

Post by obiwanjacobi »

I have a full 64k or ram, so wherever the SP is pointing that should be fine (for now).

This also works:

Code: Select all

#include<stdio.h>

void main(void)
{
        char buffer[30];
        sprintf(buffer, "Hello World!");
   
        __asm
                
                ld a, '@'
                out ($20), a
                
                halt
                
        __endasm;
}
But I have no clue how to check the content of buffer. I can read any address in memory. I have tried probing the end of memory ($FFFF) but could see any recognizable text.

Thanks for the responses so far. I understand that this is also a burden on you (write out the same stuff over and over again! :lol: )
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

if your ORG address is 0, the crt is responsible for setting up the z80's restart vectors. In the wiki there is a short note about this at the end of the making crt section and a pointer to the embedded target's crt that generates the restarts if the org address is 0.
I understand the issues you've outlined, but I am just debug-hacking around in the code.
What I'm thinking about is your device is generating interrupts (maskable or non-maskable) and is jumping into space to service them. If interrupts are not occurring then this isn't a problem.
I have a full 64k or ram, so wherever the SP is pointing that should be fine (for now).
I want to make sure SP is not pointing into the program. Note that a cpu reset does not load a known value into SP! Maybe a "di; ld sp,0" at the start of the crt could rule these things out?
This also works:

Code: Select all

#include<stdio.h>

void main(void)
{
        char buffer[30];
        sprintf(buffer, "Hello World!");
   
        __asm
                
                ld a, '@'
                out ($20), a
                
                halt
                
        __endasm;
}
But I have no clue how to check the content of buffer. I can read any address in memory. I have tried probing the end of memory ($FFFF) but could see any recognizable text.
Try making 'buffer' a global variable instead so that it is assigned a fixed address. Then you can find its location from the map file. Locals are created on the stack (as you know since you were hunting for it at the end of memory) so it's not known exactly where they are. If you can't find it at the end of memory, it could be SP is not pointing there. sprintf() is going to exercise all the same code as printf() except for the driver.

Just to check, when you compile this test program with:

zcc +zalt -vn -SO3 -clib=sdcc_iy --max-allocs-per-node200000 helloworld.c -o helloworld -m --list

You get the following files generated:

hw (should be zero size, this catches stuff not assigned to sections)
hw.lst (list file contains "hw.c" translated to asm)
hw.map (map file lists all label values)
hw.reloc (should be zero size, this is the relocation data associated with file "hw")
hw_CODE.bin (this is your output binary to be loaded at address 0)
hw_CODE.reloc (this is the relocation data for "hw_CODE.bin")

There should be no other binaries generated. (If your user program deliberately creates new sections or the RAM model is not properly specified in the crt configuration you may get additional binaries generated, separate DATA and BSS binaries in the latter case).
First the TAR__crt_code_org was defined at 32k. Set that to zero and it went a lot better.
Ok well that will make a big difference :D

The crt configuration should be something like this:

Code: Select all

   defc TAR__crt_org_code              = 0     ;; org 0
   defc TAR__crt_org_data              = 0     ;; data section appends to code section
   defc TAR__crt_org_bss               = 0     ;; bss section appends to data section

   defc TAR__crt_model                 = 0     ;; ram model means no initialization of bss or data
   
   defc TAR__register_sp               = 0     ;; specify sp=0 but the crt must do it so it won't happen on its own
   defc TAR__crt_stack_size            = 256   ;; indicate stack size, only used if heap is automatically sized by c lib
      
   defc TAR__crt_initialize_bss        = 0     ;; set to one if you want the bss section to be zeroed by the crt when ram model is active
   
   defc TAR__crt_enable_commandline    = 0
   defc TAR__crt_enable_restart        = 0
   defc TAR__crt_enable_close          = 1
   
   defc TAR__crt_enable_rst            = 0
   defc TAR__crt_enable_nmi            = 0
   
   ; clib defaults
   
   defc TAR__clib_exit_stack_size      = 0     ;; set to max number of exit functions you want to be able to register
   defc TAR__clib_quickexit_stack_size = 0
   
   defc TAR__clib_malloc_heap_size     = 0    ;; 0 = no heap, set to -1 if you want c lib to create heap between end of BSS and bottom of stack
   defc TAR__clib_stdio_heap_size      = 0     ;; increase if you want to create memstreams
   
   defc TAR__clib_balloc_table_size    = 0
   
   defc TAR__clib_fopen_max            = 0
   defc TAR__clib_open_max             = 0
Second thing is that you can run a program only once. I know you said that (somewhere) but I did not think about at the right time.
That's right the ram model will not initialize the bss and data sections before calling main, which means they will only have their correct initial values on the first run. If your program does not depend on initialized data this won't be a problem. Less obvious is the c library may have static data about. For example, if a FILE being written to generates an error, the FILE will still be in an error state at the start of the next run. You may be able to sort out some of these problems by directing the c library to zero the bss section (set TAR__crt_initialize_bss = 1 above).

With these short test programs, there shouldn't be an issue with restarting. Setting the SP to a known value in the crt will ensure SP doesn't creep downward in memory should you hit reset in the middle of program execution.
Thanks for the responses so far. I understand that this is also a burden on you (write out the same stuff over and over again! :lol: )
It's no trouble - I don't mind answering a few questions :)

Let's see if some of these things improve the result. I think setting SP to zero in the CRT will be one important thing to do.
obiwanjacobi
Member
Posts: 67
Joined: Tue Dec 22, 2015 7:39 am

Post by obiwanjacobi »

hw (should be zero size, this catches stuff not assigned to sections)
hw.lst (list file contains "hw.c" translated to asm)
hw.map (map file lists all label values)
hw.reloc (should be zero size, this is the relocation data associated with file "hw")
hw_CODE.bin (this is your output binary to be loaded at address 0)
hw_CODE.reloc (this is the relocation data for "hw_CODE.bin")
Yes, and also crt0.lst and hw.asm and an empty zcc_opt.def

My commands:

Code: Select all

zcc +zalt -clib=sdcc_iy --max-allocs-per-node200000 -m helloworld.c -o helloworld.asm -a
zcc +zalt -clib=sdcc_iy --max-allocs-per-node200000 -m helloworld.c -o helloworld --list
I have made sure the INT and NMI are tied high and I have changed the crt.asm to read:

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; STARTUP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SECTION CODE

PUBLIC __Start, __Exit

EXTERN _main

__Start:

        di
   ; nop

   ; set stack address
   ; (optional)
    ld sp, $FFFF

   ; parse command line
   ; (optional)
Compiled the libraries and the code with the buffer var global and I could see text at the memory location.

Next tried printf and that now also works! :lol: :cool:

Pfew, we're there.

Thanks so much for your help!
obiwanjacobi
Member
Posts: 67
Joined: Tue Dec 22, 2015 7:39 am

Post by obiwanjacobi »

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

Post by alvin »

Looks good!

If you try the input stream, let us know if that works too. A binary input stream will treat \r as an independent character so when doing scanf or getline you may sometimes have an extra \r show up if you're sending \r\n line terminations.

If you're hooking up a PC terminal to the input stream and can therefore send editable text, you may want to try compiling some of the test programs in _DEVELOPMENT/EXAMPLES. Backgammon, eliza (that simple computer shrink from the 70s), umchess (one of the smallest chess programs), sudoku (solver), startrek (requires floats in printf and probably a library rebuild) might be popular choices.
obiwanjacobi
Member
Posts: 67
Joined: Tue Dec 22, 2015 7:39 am

Post by obiwanjacobi »

Yes I am trying input now. Unfortunately I have hit some snags.

I want to insert a page 0 into the crt startup asm to handle all RST calls and NMI. But I cannot get it to stick...
I have looked at the zx target, but I don't get how that works. I have tried some copied code but the 'defs 0x0008 - ASMPC' generates an error with a very big number what probably means that location is not at 0x0008. I have tried to put an org before it but that doesn't seem to work ...

I am calling it for today (so no hurry in answering back). Perhaps I see it with a fresh mind...
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

obiwanjacobi wrote:I want to insert a page 0 into the crt startup asm to handle all RST calls and NMI. But I cannot get it to stick...
I have looked at the zx target, but I don't get how that works. I have tried some copied code but the 'defs 0x0008 - ASMPC' generates an error with a very big number what probably means that location is not at 0x0008. I have tried to put an org before it but that doesn't seem to work ...
Yes the big number is probably a negative 32-bit number meaning the PC has already advanced past 0x0008 at the point of the defs. You may have too much code between the restarts. There are only eight bytes between restarts so there isn't space for much more than a jump.

A section can only have one ORG address that defines where it is placed in memory -- it's not possible to hop to a different address in the section by adding another ORG. That's why the defs are being used to insert padding to get to a new known address.

The CODE, DATA and BSS sections already have ORGs assigned by the memory model included at the beginning of your crt ( http://z88dk.cvs.sourceforge.net/viewvc ... iew=markup )

And those ORG addresses are controlled by your crt configuration. Eg the CODE org is controlled by your TAR__crt_org_code variable and this could be overridden by a pragma in the C source code:

Code: Select all

#pragma output CRT_ORG_CODE = 32768   // move org to 32768

#include <stdio.h>

void main(void)
{
   printf("Hello World\n");
}
I want to insert a page 0 into the crt startup asm to handle all RST calls and NMI. But I cannot get it to stick...
I suspect you've got too much code before address 8 so that the defs is producing a large negative number.

Here's how a CRT that accommodates a zero page might look like. I put the zero page in conditional assembly because, as shown above, it's possible for the user program to change the ORG address away from zero. It may make sense to be able to use the same CRT to compile for address 0 and addresses other than 0.

zalt_crt_0.m4

Code: Select all

dnl############################################################
dnl##           ZALT_CRT_0.M4 - EXAMPLE TARGET               ##
dnl############################################################
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                  zalt standalone target                   ;;
;;      generated by target/temp/startup/zalt_crt_0.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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
dnl
dnl############################################################
dnl## LIST OF AVAILABLE DRIVERS WITH STATIC INSTANTIATORS #####
dnl############################################################
dnl
dnl
dnl## output streams
dnl
dnl#include(../driver/character/zalt_00_output_sysctrl.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/zalt_00_output_sysctrl.m4)
m4_zalt_00_output_sysctrl(_stdout, 0x0010)

;; fd=2, stderr

include(../../m4_file_dup.m4)
m4_file_dup(_stderr, 0x80, __i_fcntl_fdstruct_1)

include(../../clib_instantiate_end.m4)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; STARTUP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SECTION CODE

PUBLIC __Start, __Exit

EXTERN _main

;**************************************************************
IF __crt_org_code = 0
;**************************************************************

;; IF ORG IS ZERO CREATE THE ZERO PAGE

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; rst and im1 entry ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

   ; address = 0x0000
   
   jr __Start

   defs 0x0008 - ASMPC
   
   ; address = 0x0008
   
IF (__crt_enable_rst & $02)

   EXTERN _z80_rst_08h
   jp _z80_rst_08h

ELSE

   ret

ENDIF

   defs 0x0010 - ASMPC

   ; address = 0x0010

IF (__crt_enable_rst & $04)

   EXTERN _z80_rst_10h
   jp _z80_rst_10h

ELSE

   ret

ENDIF

   defs 0x0018 - ASMPC

   ; address = 0x0018
   
IF (__crt_enable_rst & $08)

   EXTERN _z80_rst_18h
   jp _z80_rst_18h

ELSE

   ret

ENDIF

   defs 0x0020 - ASMPC

   ; address = 0x0020

IF (__crt_enable_rst & $10)

   EXTERN _z80_rst_20h
   jp _z80_rst_20h

ELSE

   ret

ENDIF

   defs 0x0028 - ASMPC

   ; address = 0x0028

IF (__crt_enable_rst & $20)

   EXTERN _z80_rst_28h
   jp _z80_rst_28h

ELSE

   ret

ENDIF

   defs 0x0030 - ASMPC

   ; address = 0x0030

IF (__crt_enable_rst & $40)

   EXTERN _z80_rst_30h
   jp _z80_rst_30h

ELSE

   ret

ENDIF

   defs 0x0038 - ASMPC

   ; address = 0x0038
   ; im 1 isr

IF (__crt_enable_rst & $80)

   EXTERN _z80_rst_38h
   jp _z80_rst_38h

ELSE

   ei
   reti

ENDIF

   defs 0x0066 - ASMPC

   ; address = 0x0066
   ; nmi isr

IF __crt_enable_nmi

   EXTERN _z80_nmi
   jp _z80_nmi

ELSE

   retn

ENDIF

;**************************************************************
ENDIF
;**************************************************************

__Start:

   di

   ; set stack address
   ; (optional)

   ld sp,0xffff

   ; parse command line
   ; (optional)

   ; 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 registered exit() functions

   IF __clib_exit_stack_size > 0
   
      EXTERN asm_exit
      jp asm_exit              ; exit function jumps to __Exit
   
   ENDIF

__Exit:

   ; abort(), exit(), quickexit() can be called from anywhere
   ; so the stack may be unbalanced here

   ; 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

   ; exit program

   jr ASMPC                    ; infinite loop (ASMPC means current address)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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"
If you compare this with the embedded target's crt ( http://z88dk.cvs.sourceforge.net/viewvc ... iew=markup ) you'll see that in the embedded case we tried to fill the gaps between the restarts (and especially between the im1 isr and nmi isr) with common library code and part of the crt's __Start code.

Anyway you can write the zero page as you see fit -- just remember to jump to start at address 0.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

The conditional code testing __crt_enable_restart allows the user program to indicate which restart functions it will implement.

So a program like this:

Code: Select all

#pragma output CRT_ENABLE_RESTART = 130   // $82 (I believe pragmas have to be decimal constants unfortunately)

#include <stdio.h>

void main(void)
{
   printf("Hello World\n");
}
is indicating that the program will implement RST$08 and RST$38 (im1 isr). It must provide two functions that the crt's page zero code will jump to called "_z80_rst_08h" and "_z80_rst_38h". The leading underscore means you could implement these functions in C as long as care is taken in the case of rst$38 to save registers. However it's going to be more natural to implement them in assembly language. To do that I would create a new asm file holding the implementation:

restarts.asm

Code: Select all

SECTION code_crt_common   ;; or other suitable section - this section appears right after your crt code

PUBLIC _z80_rst_08h

_z80_rst_08h:

   ;; insert rst $08 code here
   ret

PUBLIC _z80_rst_38h

_z80_rst_38h:

   push af
   push bc
   push de
   push hl

   ;; insert im 1 isr here

   pop hl
   pop de 
   pop bc
   pop af

   ei
   reti
Then to compile your program:

zcc +zalt -vn -SO3 -clib=sdcc_iy --max-allocs-per-node200000 hw.c restarts.asm -o hw --list -m
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

That's CRT_ENABLE_RST not CRT_ENABLE_RESTART in the C code above. CRT_ENABLE_RESTART is for something else!

Code: Select all

#pragma output CRT_ENABLE_RST = 130   // $82 (I believe pragmas have to be decimal constants unfortunately)

#include <stdio.h>

void main(void)
{
   printf("Hello World\n");
}
obiwanjacobi
Member
Posts: 67
Joined: Tue Dec 22, 2015 7:39 am

Post by obiwanjacobi »

Yeah that is basically the code I have tried to copy (never copy code you don't understand ;-) ). I have also tried to put it in section code_crt_init instead of section CODE or code_crt_main. In the (default) memory model (inc) that is the first section mentioned.

Could I make a separate section (with an org) for each address and put the up front in the memory model. Wouldn't the linker take care of the rest?
(I am at work now so I cannot try it right now)
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

obiwanjacobi wrote:Yeah that is basically the code I have tried to copy (never copy code you don't understand ;-) ). I have also tried to put it in section code_crt_init instead of section CODE or code_crt_main. In the (default) memory model (inc) that is the first section mentioned.
That's going to be the wrong place :)

The memory map begins like this:

Code: Select all

SECTION CODE
org __crt_org_code

section code_crt_init
section code_crt_main
section code_crt_exit
section code_crt_return
section code_crt_common
...
The first section is "CODE" and anything in that section will be placed starting at "org __crt_org_code". The following sections will append to CODE until another org is found (maybe DATA or BSS). The crt is divided into pieces so that the library (or user) can insert code into the crt.

If you look again at a typical crt:

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; STARTUP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SECTION CODE

PUBLIC __Start, __Exit

EXTERN _main

__Start:

   ; set stack address
   ; (optional)

   ; parse command line
   ; (optional)

   ; 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 registered exit() functions

   IF __clib_exit_stack_size > 0
   
      EXTERN asm_exit
      jp asm_exit              ; exit function jumps to __Exit
   
   ENDIF

__Exit:

   ; abort(), exit(), quickexit() can be called from anywhere
   ; so the stack may be unbalanced here

   ; 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

   ; exit program

   jr ASMPC                    ; infinite loop (ASMPC means current address)
The crt starts by putting stuff into section "CODE" and this is what will be at the beginning of the output binary (and this is where your restarts and whatnot should be too). Then the next section is opened "code_crt_init" which is empty. But the library may insert code here to initialize the heap among other things. It's a place where initialization code can be wedged in just before main is called by source code elsewhere. Section "code_crt_main" defines the section that follows "code_crt_init" and is where main is called. "code_crt_exit" is a place to wedge in destructor code and the following "code_crt_return" defines the section that follows it. Of course the crt doesn't actually sequence these sections -- it's already been done in the memory map; the sections are listed in the crt in proper order so that it's clear how things are fitted together.
Could I make a separate section (with an org) for each address and put the up front in the memory model. Wouldn't the linker take care of the rest?
(I am at work now so I cannot try it right now)
The linker will generate a separate binary for each section with its own org address. So you could create sections with new orgs but then the output would be several binary files which you would then have to manually stick together. If you're thinking of one section per rst, you'll get a rst8 binary, rst16 binary, rst24 binary.... which you would then have to stitch together. "appmake" is able to take these binaries and insert them into a larger output binary at an indicated offset but this would be a really hard way to do things when the alternative is to put stuff at the beginning of section CODE where the address is known to be 0 and then use defs to offset forward to the right locations.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

These conditional RSTs are really meant for a generic embedded target. In your case you're probably looking at defining the restarts and not necessarily leaving it open to the user program to fill them in.

Another way to structure the crt might be like this:

Code: Select all

dnl############################################################
dnl##           ZALT_CRT_0.M4 - EXAMPLE TARGET               ##
dnl############################################################
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                  zalt standalone target                   ;;
;;      generated by target/temp/startup/zalt_crt_0.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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
dnl
dnl############################################################
dnl## LIST OF AVAILABLE DRIVERS WITH STATIC INSTANTIATORS #####
dnl############################################################
dnl
dnl
dnl## output streams
dnl
dnl#include(../driver/character/zalt_00_output_sysctrl.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/zalt_00_output_sysctrl.m4)
m4_zalt_00_output_sysctrl(_stdout, 0x0010)

;; fd=2, stderr

include(../../m4_file_dup.m4)
m4_file_dup(_stderr, 0x80, __i_fcntl_fdstruct_1)

include(../../clib_instantiate_end.m4)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; BIOS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

IF __crt_org_code = 0

SECTION CODE
include "bios.asm"

ENDIF

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; STARTUP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SECTION CODE

PUBLIC __Start, __Exit

EXTERN _main

__Start:

   di

   ; set stack address
   ; (optional)

   ld sp,0xffff

   ; parse command line
   ; (optional)

   ; 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 registered exit() functions

   IF __clib_exit_stack_size > 0
   
      EXTERN asm_exit
      jp asm_exit              ; exit function jumps to __Exit
   
   ENDIF

__Exit:

   ; abort(), exit(), quickexit() can be called from anywhere
   ; so the stack may be unbalanced here

   ; 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

   ; exit program

   jr ASMPC                    ; infinite loop (ASMPC means current address)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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"
"bios.asm" will be included at address 0 when the org address is 0. You could keep it in target/zalt/bios.asm or you could have it in your local work directory -- I think that will be searched for includes.

bios.asm

Code: Select all

SECTION CODE

; org 0

jp __Start   ;  start C program
defs 0x008 - ASMPC

; org 0x08

rst_08h:
   ret

defs 0x10 - ASMPC

; org 0x10

rst_10h:
   ret

defs 0x18 - ASMPC

; org 0x18

rst_18h:
   ret

defs 0x20 - ASMPC

; org 0x20

rst_20h:
   ret

defs 0x28 - ASMPC

; org 0x28

rst_28h:
   ret

defs 0x30 - ASMPC

; org 0x30

rst_30h:
   ret

defs 0x38 - ASMPC

; org 0x38
; im 1 ISR

rst_38h:
   ei
   reti

defs 0x66 - ASMPC

; org 0x66
; nmi isr

nmi:
   retn

; can add more bios code here if needed
You could still allow some or all of the restarts to be user-definable by adding that conditional code stuff with __crt_enable_rst as needed.

The gaps between the restarts is only 8 bytes so there isn't much room to do anything except jp someplace but there is a larger gap between the im1 isr and the nmi isr which may be large enough to fit some or all of your im 1 isr routine or something else.
obiwanjacobi
Member
Posts: 67
Joined: Tue Dec 22, 2015 7:39 am

Post by obiwanjacobi »

alvin wrote:The crt starts by putting stuff into section "CODE" and this is what will be at the beginning of the output binary (and this is where your restarts and whatnot should be too).
I knew that :D

Anyway I have the code in place at the right addresses. I trap every RST (except RST0) and NMI with a halt instruction (I can detect easily in hardware) after I've output a unique character (1-8). So now I can easily detect if it flies of in an interrupt or something.

I have run some more tests but it looks like I might also be having some sort of hardware fault. So I need to sort that out first. Not sure yet what is going on exactly. "I'll be back" :cool:

Thanks!
obiwanjacobi
Member
Posts: 67
Joined: Tue Dec 22, 2015 7:39 am

Post by obiwanjacobi »

(you posted again while I was writing mine)
Yes, using includes will probably be my final setup, but for now I'd just put the temp code in the file as you've shown before.
obiwanjacobi
Member
Posts: 67
Joined: Tue Dec 22, 2015 7:39 am

Post by obiwanjacobi »

I had indeed two nasty hardware problems. I hope once my PCBs are in it will become more stable ;-) (part is on a bread board still)

Anyway I have the input (stdin) working also and can echo back typed text. I will post new threads if new questions come up.
Thanks a lot for help and patience.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

obiwanjacobi wrote:Anyway I have the input (stdin) working also and can echo back typed text. I will post new threads if new questions come up.
Thanks a lot for help and patience.
Great I'm glad to hear the sw end is working. Yeah at 20MHz, you'll probably start seeing weird things if part of the circuit is still on a breadboard.
obiwanjacobi
Member
Posts: 67
Joined: Tue Dec 22, 2015 7:39 am

Post by obiwanjacobi »

Nah, it is currently running at 1.5 MHz max. I can even slow it down to a couple of Hz - then you can really see what is going on - but it takes forever.
Post Reply