Embedded Z180 Target with Interrupt Vector Table

Discussion about other targets
Post Reply
sponaugle
New member
Posts: 3
Joined: Fri Jul 23, 2021 2:44 am

Embedded Z180 Target with Interrupt Vector Table

Post by sponaugle »

I'm building a rom image for an embedded Z180 target, and I'd like to use the new C Library. I am looking at the Interrupt section of the newlib - embedded documentation at: https://github.com/z88dk/z88dk/wiki/New ... --Embedded

It suggests two critical steps:

(1) Having CRT_ORG_VECTOR_TABLE = -0x100 ( a special flag to put the interrupt vector table at 0x100 in the CRT Page 0)
(2) Including in the compile a section for the interrupt vectors. I did an interrupt.asm file as suggested.

For a sample simple c program, I am using this for test.c:

Code: Select all

#include <stdio.h>
int main()
{
  int q=0;
  for (int i=0; i<100; i++)
  {	
    q = q +i;	
  }	
  return 0;
}
and for the interrupt.asm file:

Code: Select all

section interrupt_vectors
EXTERN l_ret
;defs 0x100 - ASMPC
;defc z180_int_int1  = __crt_org_vector_table + 0x00
defw l_ret
;defc z180_int_int2  = __crt_org_vector_table  + 0x02
defw l_ret
;defc z180_int_prt0  = __crt_org_vector_table  + 0x04
defw l_ret
;defc z180_int_prt1  = __crt_org_vector_table + 0x06
defw l_ret
;defc z180_int_dma0  = __crt_org_vector_table  + 0x08
defw l_ret
;defc z180_int_dma1  = __crt_org_vector_table  + 0x0A
defw l_ret
;defc z180_int_csio  = __crt_org_vector_table  + 0x0C
defw l_ret
;defc z180_int_asci0 = __crt_org_vector_table + 0x0E
defw l_ret
;defc z180_int_asci1 = __crt_org_vector_table + 0x10
defw l_ret
defb $AA,$BB,$CC,$DD
defb $AA,$BB,$CC,$DD
defb $AA,$BB,$CC,$DD
defb $AA,$BB,$CC,$DD

The values at the end of the vector table are just there so I can see where the table ends up at in the final binary.

I compiled these two files with:

Code: Select all

zcc +z180 -clib=new -startup=1 test.c interrupt.asm -create-app -v -pragma-define:CRT_ORG_VECTOR_TABLE=-0x100 -o testrom -pragma-define:CRT_INTERRUPT_MODE=2 -pragma-define:CRT_IO_VECTOR_BASE=0 --list -v
However, the resulting file does not have the interrupt vector table at 0x100.

If I look in the crt_memory_model_z180.inc file:

Code: Select all

SECTION CODE
org __crt_org_code
IF (__crt_org_vector_table = -0x80) || (__crt_org_vector_table = -0x100)
section interrupt_vectors
ENDIF
section code_crt_start
.......
You can see that the interrupt_vector section will be the first section in the resulting binary file.. and sure enough it unfortunately is instead of being at location 0x100.

I looked in the page zero ctr itself (crt_page_zero_z180.inc) , and it has

Code: Select all

IF (__crt_org_vector_table = -0x0100)

; place vector table at address 0x0100

; current address = 0x0069 or 0x0068
; that is 151 bytes to pad, make it count!
followed by 151 bytes of padding code, then

Code: Select all

; address = 0x100

   defs 0x100 - ASMPC

section code_crt_start
I assume this means the interrupt vector needs to be in section code_crt_start? However that would not make sure it goes here since there are other segments that are code_crt_start.

I did quickly try using the +embedded target (using the old c library and targeting the Z80), and it seemed to do the right thing. (the vector table was at 0x100).

I am sure I am missing something here! Anyone have any ideas what I'm missing?

Cheers!

Jeff Sponaugle
sponaugle
New member
Posts: 3
Joined: Fri Jul 23, 2021 2:44 am

Re: Embedded Z180 Target with Interrupt Vector Table

Post by sponaugle »

As an additional note:

If I run the commmand as above, same files, change to the newlib Z80 target (instead of the Z180 target), the code produced looks as expected:

Code: Select all

zcc +z180 -clib=new -startup=1 test.c interrupt.asm -create-app -v -pragma-define:CRT_ORG_VECTOR_TABLE=-0x100 -o testrom -pragma-define:CRT_INTERRUPT_MODE=2 -pragma-define:CRT_IO_VECTOR_BASE=0 --list -v

Code: Select all

C:\z88dk\testfile>z88dk-dis -mz180 testrom.bin  | more
                    di                                      ;[0000] f3
                    im      1                               ;[0001] ed 56
                    jp      $0122                           ;[0003] c3 22 01
                    nop                                     ;[0006] 00
                    nop                                     ;[0007] 00

You can see there the jp to $122 occurs because the IVT is at 0x100, as you would expect.

If you simply change the target back to +z180 you get:

Code: Select all

C:\z88dk\testfile>z88dk-dis -mz180 testrom.bin  | more
                    ld      d,b                             ;[0000] 50
                    nop                                     ;[0001] 00
                    ld      d,b                             ;[0002] 50
                    nop                                     ;[0003] 00
                    ld      d,b                             ;[0004] 50
                    nop                                     ;[0005] 00
                    ld      d,b                             ;[0006] 50
                    nop                                     ;[0007] 00
                    ld      d,b                             ;[0008] 50
                    nop                                     ;[0009] 00
                    ld      d,b                             ;[000a] 50
                    nop                                     ;[000b] 00
                    ld      d,b                             ;[000c] 50
                    nop                                     ;[000d] 00
                    ld      d,b                             ;[000e] 50
                    nop                                     ;[000f] 00
                    ld      d,b                             ;[0010] 50
                    nop                                     ;[0011] 00
                    xor     d                               ;[0012] aa
                    cp      e                               ;[0013] bb
                    call    z,$aadd                         ;[0014] cc dd aa
                    cp      e                               ;[0017] bb
                    call    z,$aadd                         ;[0018] cc dd aa
                    cp      e                               ;[001b] bb
                    call    z,$aadd                         ;[001c] cc dd aa
                    cp      e                               ;[001f] bb
                    call    z,$f5dd                         ;[0020] cc dd f5
That is the interrupt table from the interrupt.asm right at the begining of the ROM image.

In looking at the Z80 vs the Z180 crt files:

crt_page_zero_z80.inc:

Code: Select all

; address = 0x0000
   di
   im 1
   jp __Start
; address = 0x0008
while the crt_page_zero_z180.inc:

Code: Select all

SECTION code_crt_start

; address = 0x0000
; must decide if this is a power on reset or a trap

   push af
   ld a,__IO_BASE_ADDRESS

   jp __Test_Trap

   PUBLIC l_retn
That first 'SECTION code_crt_start' seems odd, as that would prevent this code from coming before the IVT.

I removed that single line (the SECTION code_crt_start) in crt_page_zero_z180.inc, and executed the same zcc command from above targeting +z180, and it fixed the problem.

Looking at the output binary:

Code: Select all

C:\z88dk\testfile>z88dk-dis -mz180 testrom.bin  | more
                    push    af                              ;[0000] f5
                    ld      a,$00                           ;[0001] 3e 00
                    jp      $0122                           ;[0003] c3 22 01
                    retn                                    ;[0006] ed 45
We can see the __Startup is now at 0x122. And at 0x100:

Code: Select all

push    ix                              ;[00fb] dd e5
                    pop     bc                              ;[00fd] c1
                    add     hl,bc                           ;[00fe] 09
                    ret                                     ;[00ff] c9

                    ld      l,$00                           ;[0100] 2e 00
                    ld      l,$00                           ;[0102] 2e 00
                    ld      l,$00                           ;[0104] 2e 00
                    ld      l,$00                           ;[0106] 2e 00
                    ld      l,$00                           ;[0108] 2e 00
                    ld      l,$00                           ;[010a] 2e 00
                    ld      l,$00                           ;[010c] 2e 00
                    ld      l,$00                           ;[010e] 2e 00
                    ld      l,$00                           ;[0110] 2e 00
                    xor     d                               ;[0112] aa
                    cp      e                               ;[0113] bb
                    call    z,$aadd                         ;[0114] cc dd aa
                    cp      e                               ;[0117] bb
                    call    z,$aadd                         ;[0118] cc dd aa
                    cp      e                               ;[011b] bb
                    call    z,$aadd                         ;[011c] cc dd aa
                    cp      e                               ;[011f] bb
                    call    z,$eddd                         ;[0120] cc dd
Of course this leaves me wondering why the SECTION code_crt_start is there in the first place, as it was certainly added at some point during the development of the Z180 newlib support.

Any ideas?
User avatar
feilipu
Member
Posts: 45
Joined: Tue Nov 15, 2016 5:02 am

Re: Embedded Z180 Target with Interrupt Vector Table

Post by feilipu »

Hi Jeff,
not sure about the history of this.
But here's the discussion https://github.com/z88dk/z88dk/commit/9 ... t-53911407 to your comment, and commit removing the offending line. https://github.com/z88dk/z88dk/commit/7 ... 21efe734a8.
Cheers, Phillip
User avatar
feilipu
Member
Posts: 45
Joined: Tue Nov 15, 2016 5:02 am

Re: Embedded Z180 Target with Interrupt Vector Table

Post by feilipu »

Hi Jeff,

a follow up question on the "why" to locating the vector table at 0x0100?

For background to the question, 0x0100 is typically used as the application starting address and is paged. Usually a page or small amount of high memory (in COMMON_1) would be kept for the vector table and stubs for the support coded located in the lowest BANK. Different applications then go into BANK, with Page0 contents replicated into each BANK. (CBAR/CBR/BBR settings).

This is a graphic representation of what I believe is done typically. This arrangement was copied from CP/M-3, RomWBW (see Section 4), and FUZIX provides a fixed COMMON and BANK for Z180 too.
User avatar
feilipu
Member
Posts: 45
Joined: Tue Nov 15, 2016 5:02 am

Re: Embedded Z180 Target with Interrupt Vector Table

Post by feilipu »

feilipu wrote: Mon Jul 26, 2021 1:45 am For background to the question, 0x0100 is typically used as the application starting address and is paged. Usually a page or small amount of high memory (in COMMON_1) would be kept for the vector table and stubs for the support coded located in the lowest BANK.
Sorry, I didn't say why this is usually done. It is because the low memory of a Z180 system is usually ROM, so the that the Z180 can boot from physical 0x00000. and the vector table is something that you want to be able to change as needed during run time, so it is usually located in RAM and hence in high memory. Z88DK can/will automatically copy the ROM stored initial table up to a high memory location of your choice during the CRT0 process.
sponaugle
New member
Posts: 3
Joined: Fri Jul 23, 2021 2:44 am

Re: Embedded Z180 Target with Interrupt Vector Table

Post by sponaugle »

Good point Philip... I was doing the table at 0x0100 in part because it was supported and in part because I had an application that didn't need it in RAM. However it makes sense that with the use of memory bank the layout you suggested having the table in RAM works well. Either way at least it is valuable to have the option work correctly in case someone does have a very specific use case. Thanks for all of the awesome work you have put into this project.
Post Reply