ZX81 interrupts with z88dk, how to install an ISR ?

Any discussions related to the creation of new hardware or software for the ZX80 or ZX81
zx81ultra
Posts: 21
Joined: Thu Feb 13, 2020 4:19 am
Location: Bolivia

Re: ZX81 interrupts with z88dk, how to install an ISR ?

Post by zx81ultra »

olofsen wrote:
Thu Jun 11, 2020 6:49 pm
Just a note that the clock available here viewtopic.php?p=17265#p17265 hooks up an ISR, but I don't remember all details... The address of a C function (although consisting of assembly code) is "poked" to the startup code of the ISR that z88dk installed, at 0x41b4.The source for this alternative ISR may now be found in "lib/target/zx81/classic", but at the time it may have been in "lib". Most likely I inspected the generated P file to find the address to hook to; and in later versions of z88dk this address may have changed. But perhaps this is the difficult way to do this...
As olofsen says, the 0x41b4 might have changed or something else, the following code is not working but it helps me to better understand the logic of an ISR call after the display is refreshed. I hope I'm in the right direction. Any ideas to make this work ?

Code: Select all

/* zcc +zx81 -create-app disp_isr.c */

/* Inspired by RELOGIO By K. Murta http://zx81.eu5.org/toddysofte.html,
   and the z88dk source of gmtime(). 

Also based on olofsen post viewtopic.php?p=17265#p17265
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <input.h>
#include <zx81.h>

extern int d_file @16396;
unsigned char i, isrText[32], *Display; 

void DisplayISR(void)
{
for(i = 0; i < 32; ++i)
	isrText[i] = rand()%64;

memcpy(Display,isrText,32);

#asm
jp 0x02a4  ; return to the main program
#endasm 
}

void hook()
{
#asm
	  ld      hl,_DisplayISR
	  ld      (0x41b4),hl        ; 0x41b4 I guess this address has changed in z88dk ?
	  ld      a,0xc9							
	  ld      (0x412e),a         ; same here ?
#endasm
}

void main(void)
{
Display = (unsigned char *) d_file + 1; 

hook();

while(1);
}

Thank you all for your answers !

hlide
Posts: 4
Joined: Sat Jun 06, 2020 12:55 am

Re: ZX81 interrupts with z88dk, how to install an ISR ?

Post by hlide »

Yes, I expected that float byte to be $FF in most case if nothing else can disturb. Since it is an odd address at the end of a page, it means it will call a routine accross the page I and page I+1. I thought Z88DK can handle mode 1 and mode 2. Is there no im1_init function?

zx81ultra
Posts: 21
Joined: Thu Feb 13, 2020 4:19 am
Location: Bolivia

Re: ZX81 interrupts with z88dk, how to install an ISR ?

Post by zx81ultra »

The z88dk documentation I found about IM1 https://www.z88dk.org/wiki/doku.php?id= ... rupts#im_1says this:
IM 1
Response to a maskable interrupt is to jump to a fixed ISR at address 0×38 that must terminate in “EI;RET” or “EI;RETI” (latter preferred). The best way to accommodate this mode is to include an ISR at address 0×38 in the C startup code. The generic ISR supplied in this library can be used to field this interrupt by placing a JP instruction to the generic ISR at 0×38 in the startup.
I can't find the "generic ISR supplied in this library"

I think the example by olofson (viewtopic.php?p=17265#p17265), does the same directly in the C main program. My test code is based on his example but the hard-coded 0x41b4 address must have changed since then:

Code: Select all

void DisplayISR(void)
{
for(i = 0; i < 32; ++i)
	isrText[i] = rand()%64;

memcpy(Display,isrText,32);

#asm
jp 0x02a4  ; return to the main program
#endasm 
}

void hook()
{
#asm
	  ld      hl,_DisplayISR
	  ld      (0x41b4),hl        ; 0x41b4 I guess this address has changed in z88dk ?
	  ld      a,0xc9							
	  ld      (0x412e),a         ; same here ?
#endasm
}

olofsen
Posts: 175
Joined: Wed Jan 08, 2014 12:29 pm

Re: ZX81 interrupts with z88dk, how to install an ISR ?

Post by olofsen »

So the address may be located by disassembling the P file and looking for the end of the alternative DISPLAY-3:

Code: Select all

4167 ed44      neg     
4169 3c        inc     a
416a 08        ex      af,af'
416b d3fe      out     (0feh),a
416d 2a8b41    ld      hl,(418bh)
4170 23        inc     hl
4171 228b41    ld      (418bh),hl
4174 7c        ld      a,h
4175 b5        or      l
4176 c27d41    jp      nz,417dh
4179 218c41    ld      hl,418ch
417c 34        inc     (hl)
417d c3a402    jp      02a4h
So with my test program and installation of z88dk, the address to hook a function to is 417eh. The other "poke" may be omitted. So the following framework seems to work:

Code: Select all

void fun()
{
#asm
	jp      0x02a4
#endasm
}

void hook()
{
#asm
	ld      hl,_fun
	ld      (0x417e),hl        ; jump to fun instead of 0x02a4
#endasm
}
Last edited by olofsen on Fri Jun 12, 2020 7:49 pm, edited 1 time in total.

User avatar
1024MAK
Posts: 2978
Joined: Mon Sep 26, 2011 10:56 am
Location: Looking forward to summer in Somerset, UK...

Re: ZX81 interrupts with z88dk, how to install an ISR ?

Post by 1024MAK »

There are three maskable interrupt modes on a Z80 CPU.
  • Mode 0 is of no use on a ZX81 (and indeed most computers using the Z80 CPU), as hardware has to feed the CPU with an instruction or a sequence of bytes making up an instruction.
  • Mode 1 is the simplest, but it always jumps to address 0x0038 when an interrupt occurs. But address 0x0038 is in the ROM.
  • Mode 2 is the most flexible and as described above uses the I register and a 8 bit value grabbed from the data bus to form a vector. The intention being that the hardware supplies a byte of data on the data bus when it detects the Z80’s interrupt acknowledge signal. But as the ZX81 does not have any such hardware, the Z80 will read the current value on the data bus. Pull-up resistors will try to pull the bus to 0xFF, but if other hardware is attached via the edge-connector, a different value may be read. Especially if the other hardware was not designed to ignore the Z80’s interrupt acknowledge signal and interprets the bus as a I/O port access.
Despite what the documentation says, you can use a simple RET, you don’t have to use a RETI. To the Z80 CPU both do the same thing, the difference being that the Zilog Z80 specialist peripheral interface chips watch the data bus for the opcode for RETI. If none of these are in use, you don’t have to use RETI.

More details of the Z80 interrupt system are in this document.

Mark

User avatar
1024MAK
Posts: 2978
Joined: Mon Sep 26, 2011 10:56 am
Location: Looking forward to summer in Somerset, UK...

Re: ZX81 interrupts with z88dk, how to install an ISR ?

Post by 1024MAK »

Oh, and one other point, the byte read by the Z80 from the data bus and used to form the vector used for mode 2 can have the least significant bit set to 1 or to 0. Despite what some documentation says, the Z80 can read this and interpret it as a 8 bit byte. So if the least significant bit set to 1, then it will use this when addressing memory to get the interrupt routines address.

Mark

zx81ultra
Posts: 21
Joined: Thu Feb 13, 2020 4:19 am
Location: Bolivia

Re: ZX81 interrupts with z88dk, how to install an ISR ?

Post by zx81ultra »

olofsen wrote:
Fri Jun 12, 2020 7:45 pm
So the address may be located by disassembling the P file and looking for the end of the alternative DISPLAY-3:

Code: Select all

4167 ed44      neg     
4169 3c        inc     a
416a 08        ex      af,af'
416b d3fe      out     (0feh),a
416d 2a8b41    ld      hl,(418bh)
4170 23        inc     hl
4171 228b41    ld      (418bh),hl
4174 7c        ld      a,h
4175 b5        or      l
4176 c27d41    jp      nz,417dh
4179 218c41    ld      hl,418ch
417c 34        inc     (hl)
417d c3a402    jp      02a4h
So with my test program and installation of z88dk, the address to hook a function to is 417eh. The other "poke" may be omitted. So the following framework seems to work:

Code: Select all

void fun()
{
#asm
	jp      0x02a4
#endasm
}

void hook()
{
#asm
	ld      hl,_fun
	ld      (0x417e),hl        ; jump to fun instead of 0x02a4
#endasm
}
The 0x417e address is not working for me. Which P file are you disassembling ? (by the way which tool do you recommend to disassembling)

Thank you !

zx81ultra
Posts: 21
Joined: Thu Feb 13, 2020 4:19 am
Location: Bolivia

Re: ZX81 interrupts with z88dk, how to install an ISR ?

Post by zx81ultra »

Ok it works now !

The address in my case is 0x4179, so the hook code that installs the ISR is now:

Code: Select all

void hook(void)
{
#asm
	  ld      hl,_DisplayISR
	  ld      (0x4179),hl        
#endasm
}
I found the way to identify the correct address examining the crt initialization code located in ../lib/target/zx81/zx81_altint_core.asm section DISPLAY-3 and disassembling a .P file as olofsen post suggested. Maybe the correct way is to place the call to the ISR directly in the asm file ?

Code: Select all

;; DISPLAY-3
L0292:  POP     IY              ; return address to IX register (--IXIY swap).
                                ; will be either L0281 or L028F - see above.
; Modified here to keep IY unchanged

        ld	a,($4028)      ; load C with MARGIN
MTCH_P3:
		add     0             ; more blank lines for fast application code and correct sync
        ld	c,a

        ld   a,($403B)      ; test CDFLAG
        and  128            ; is in FAST mode ?
        jp   z,$2a9         ; if so, jp to DISPLAY-4

        ; jp $29e       ;  this could save 6 bytes, but I'm not sure the display timing won't be correct.. 
                        ;  better to reach the 'out' instruction first
        ld   a,c
        neg
        inc  a
        ex   af,af
        out  ($FE),a
        jp	$2A4
I still have to figure out how much run time is the ISR allowed to before returning the control.

Thanks to everyone that took the time to help !
Attachments
zx81isr.c
(893 Bytes) Downloaded 10 times
zx81isr.P
(2.74 KiB) Downloaded 10 times

hlide
Posts: 4
Joined: Sat Jun 06, 2020 12:55 am

Re: ZX81 interrupts with z88dk, how to install an ISR ?

Post by hlide »

Why all those complications? shouldn't be easy to put a label at the right instruction in ../lib/target/zx81/zx81_altint_core.asm, to make that label global so your #asm block can see it as a label and you only need to write "ld (display3_back_to_rom_isr+1),hl" ?

zx81ultra
Posts: 21
Joined: Thu Feb 13, 2020 4:19 am
Location: Bolivia

Re: ZX81 interrupts with z88dk, how to install an ISR ?

Post by zx81ultra »

hlide wrote:
Sat Jun 13, 2020 2:51 pm
Why all those complications? shouldn't be easy to put a label at the right instruction in ../lib/target/zx81/zx81_altint_core.asm, to make that label global so your #asm block can see it as a label and you only need to write "ld (display3_back_to_rom_isr+1),hl" ?
You are right, I just did it, much easier with a label, thank you.

Post Reply