z88dk - RC2014 - IM 1 - RST38 - how tell c-compiler vector?

107 views
Skip to first unread message

Tom Tom

unread,
Aug 17, 2021, 9:50:48 AM8/17/21
to RC2014-Z80
Hi guys,

I use z88dk for mixed c and asm - it works pretty well (subtype=basic, standard SC-108).

But now I want to use my own RST 38 routine - to be honest, I am no expert with c compiler.

In SCM the RST38 points to vector table $FE15. In $FE15 there is a JP to $0155 with RETI.

So how do I tell the compiler, that the vector at $FE15 should point to MY c function at runtime? After a reset SCM rewrites the vector table anyway.

Any idea? Thank you.


Phillip Stevens

unread,
Aug 17, 2021, 11:28:32 AM8/17/21
to RC2014-Z80
I use z88dk for mixed c and asm - it works pretty well (subtype=basic, standard SC-108).

But now I want to use my own RST 38 routine - to be honest, I am no expert with c compiler.

In SCM the RST38 points to vector table $FE15. In $FE15 there is a JP to $0155 with RETI.
So how do I tell the compiler, that the vector at $FE15 should point to MY c function at runtime?
 
I’ll have to think of a proper answer, but it is late.

If you were using the NASCOM BASIC, it would be easy to take one of these defined locations, and just set it to the address of your routine. For SCM there would be a similar location, you’re saying $FE16 & $FE17, that needs to be loaded with address of your function. In assembler it looks like:

.MY_FUNCTION_LABEL
; my stuff
    RET

._main
; stuff
LD HL,MY_FUNCTION_LABEL
LD ($FE16),HL
; more stuff

In C you take the address of my_function(), and store it in $FE16.

Cheers, Phillip

Tom Tom

unread,
Aug 17, 2021, 12:05:03 PM8/17/21
to RC2014-Z80
Hi phillip, thanks for your idea.

The compiler should write a vector to MY_func in $FE16 & $FE17. But how do I tell the compiler or how do I know, where the MY_func in C is located after linking?

With:

#pragma output crt_enable_rst = 0x80  - I tell the compiler that he should handle the vector in $0038

void z80_rst_38h(void) __critical __interrupt(0)  - the vector to this function is in $0038


BUT $0038 is ROM. 

So I thought - OK, lets tell the compiler, that he should not write in $0038 ($0039 & $003A) but in $FE15 ($FE16 & $FE17).

Am I on the wrong way?

Cheers Thomas

Tom Tom

unread,
Aug 17, 2021, 12:53:41 PM8/17/21
to RC2014-Z80
.... I found something...."crt_org_vector_table" ... in rc2014 subtype=basic config in the listing. maybe I can deal with this compiler directive? but how ...I have no clue

Phillip Stevens

unread,
Aug 17, 2021, 10:13:38 PM8/17/21
to RC2014-Z80
Thomas wrote:
Hi Phillip, thanks for your idea.
The compiler should write a vector to MY_func in $FE16 & $FE17. 
But how do I tell the compiler or how do I know, where the MY_func in C is located after linking?
With:

#pragma output crt_enable_rst = 0x80  - I tell the compiler that he should handle the vector in $0038
void z80_rst_38h(void) __critical __interrupt(0)  - the vector to this function is in $0038

BUT $0038 is ROM. 
So I thought - OK, lets tell the compiler, that he should not write in $0038 ($0039 & $003A) but in $FE15 ($FE16 & $FE17).

Am I on the wrong way?
Cheers Thomas

Hi Thomas,
with the subtypes in z88dk, there are two that are designed to run on "bare metal" as a ROM, and others that rely on a base of some type.

The "acia" and the "sio" subtype run from bare metal, and configure interrupt vectors and provide serial ports, by writing Page 0 of the ROM, etc.

The "basic", "cpm", and "hbios" subtypes run from their underlying platforms, and these subtypes have no inherent knowledge of the vectors, as they don't configure the Page 0 ROM.
You can read this setting from the TAR__crt_org_vector_table being 0 and TAR__crt_org_code being non zero.

The "basic" subtype relies on the simple serial interface of RST8, RST10, and RST18 calls for interface to the serial device, and what happens after that it doesn't care about.
That's why all both the BASIC ROMs and the SCM work with this same subtype. You only need to adjust the stack location, and optionally the start of code for SCM.

The #pragma output setting won't help here, because we don't have access to write to the Page 0 ROM in SCM or in BASIC.

So you will have to fill out the RST vectors manually, and I know that the NASCOM BASIC in the RC2014 repo has a re-writeable Jump Table for  the RST vectors originating at 0x8000.

Here you take the address of your function, and write it into the vector address which is offset from the VECTOR_BASE which is set here as 0x8000.
Just write the required vector or address of your function into the table, and you're good to go.

The Grant Searle NASCOM BASIC doesn't do this and the RST vectors are hard coded to ROM, so don't even bother.

The SCM uses a different method, with an API to call in assembly to write the table. The manual talks about #09.
So you can write a little assembly function that you can call from C to fill the address using the API.

I'm sure that the vector table will be somewhere sensible, and you could write to it directly, but I can't see the location from a quick scan of the manual. Sorry.
It might be the $FE16 word that you found. And if it is then you can use the same method as above, by writing directly to it.

I can do a little C for you if that is helpful?

Cheers, Phillip
 

Phillip Stevens

unread,
Aug 18, 2021, 12:48:35 AM8/18/21
to RC2014-Z80
Thomas wrote:
Hi Phillip, thanks for your idea.
The compiler should write a vector to MY_func in $FE16 & $FE17. 
But how do I tell the compiler or how do I know, where the MY_func in C is located after linking?

I'm sure that the vector table will be somewhere sensible, and you could write to it directly, but I can't see the location from a quick scan of the manual. Sorry.
It might be the $FE16 word that you found. And if it is then you can use the same method as above, by writing directly to it.

I can do a little C for you if that is helpful?

To save a cycle...

#include <cpu.h>

// For using the SCM
#pragma output CRT_ORG_CODE = 0x8000
#pragma output CRT_REGISTER_SP = 0xFC00

// read and debug: zcc +rc2014 -subtype=basic -v --list -m -SO1 --c-code-in-asm --fverbose-asm --max-allocs-per-node10000 simple.c -o simple -create-app
// run: zcc +rc2014 -subtype=basic -v --list -m -SO3 --max-allocs-per-node200000 simple.c -o simple -create-app

void my_interrupt_handler(void);

int main(void)
{
  uint16_t volatile * const interrupt_vector = (uint16_t *) 0xFE16;
  * interrupt_vector = (uint16_t) my_interrupt_handler;

  return 0;
}

void my_interrupt_handler(void)
{
    uint8_t i = 0;
}

compiles to...

290   0000  01 08 00    ld bc,_my_interrupt_handler
293   0003  ED 43 16 FE ld (0xfe16), bc

Which is what you need. Provided of course that you have the right address for your handler.
Good luck,
Phillip

Tom Tom

unread,
Aug 18, 2021, 5:18:41 AM8/18/21
to RC2014-Z80
Phillip - you are my man - thank you! This I was looking for!!

in main() I had to run first "quick&dirty" (later I will put this in asm init-routine )

__asm
IM 1
ei
__endasm;

but then it worked!!

Like you wrote in your post before I already tried to change the RST38 vector with API and RST30, or directly to $FE16, - both in asm no problem.

But as I mentioned before, I use mixed c and asm in separate files. So some c func() I export to asm ... works fine from c to asm, 
but I had no clue how I should tell c to "hook" a function to a specific address(vector).

This is I was looking for:
uint16_t volatile * const interrupt_vector = (uint16_t *) 0xFE16;
* interrupt_vector = (uint16_t) my_interrupt_handler;

Thank you, this helped me a lot !

Cheers Thomas






Reply all
Reply to author
Forward
0 new messages