From f5294a19d7e7756ec2b6ecd7dae4cb2d28c409ba Mon Sep 17 00:00:00 2001 From: Wayne Warthen Date: Tue, 28 Aug 2018 18:55:31 -0700 Subject: [PATCH] Preliminary Support for Interrupt Management API --- Doc/ChangeLog.txt | 1 + ReadMe.txt | 2 +- Source/Apps/Build.cmd | 7 + Source/Apps/IntTest.asm | 519 ++++++++++++++++++++++++++++++++++++++++ Source/Apps/Timer.asm | 2 +- Source/CBIOS/ver.inc | 2 +- Source/HBIOS/API.txt | 102 +++++++- Source/HBIOS/Build.ps1 | 2 +- Source/HBIOS/hbios.asm | 174 +++++++++++++- Source/HBIOS/hbios.inc | 5 + Source/HBIOS/ver.inc | 2 +- 11 files changed, 793 insertions(+), 25 deletions(-) create mode 100644 Source/Apps/IntTest.asm diff --git a/Doc/ChangeLog.txt b/Doc/ChangeLog.txt index 7f3b22c9..2023ab20 100644 --- a/Doc/ChangeLog.txt +++ b/Doc/ChangeLog.txt @@ -14,6 +14,7 @@ Version 2.9.1 - WBW: Added NZCOM distribution files to third slice of hard disk image - WBW: Fixed getnum32 bug in MODE command (found by Phil Summers) - P?S: Added serial support for Zilog Peripherals Baord +- WBW: Added preliminary support for interrupt management API Version 2.9.0 ------------- diff --git a/ReadMe.txt b/ReadMe.txt index 8067f003..e71bee63 100644 --- a/ReadMe.txt +++ b/ReadMe.txt @@ -7,7 +7,7 @@ *********************************************************************** Wayne Warthen (wwarthen@gmail.com) -Version 2.9.1-pre.6, 2018-08-01 +Version 2.9.1-pre.7, 2018-08-28 https://www.retrobrewcomputers.org/ RomWBW is a ROM-based implementation of CP/M-80 2.2 and Z-System for diff --git a/Source/Apps/Build.cmd b/Source/Apps/Build.cmd index b2dea6cf..03acd2bf 100644 --- a/Source/Apps/Build.cmd +++ b/Source/Apps/Build.cmd @@ -20,6 +20,7 @@ call :asm OSLdr || goto :eof call :asm Mode || goto :eof call :asm RTC || goto :eof call :asm Timer || goto :eof +call :asm180 IntTest || goto :eof zx Z80ASM -SYSGEN/F @@ -38,4 +39,10 @@ goto :eof echo. echo Building %1... tasm -t80 -g3 -fFF %1.asm %1.com %1.lst +goto :eof + +:asm180 +echo. +echo Building %1... +tasm -t180 -g3 -fFF %1.asm %1.com %1.lst goto :eof \ No newline at end of file diff --git a/Source/Apps/IntTest.asm b/Source/Apps/IntTest.asm new file mode 100644 index 00000000..06bfa5ed --- /dev/null +++ b/Source/Apps/IntTest.asm @@ -0,0 +1,519 @@ +;=============================================================================== +; INTTEST - Test HBIOS interrupt API functions +; +;=============================================================================== +; +; Author: Wayne Warthen (wwarthen@gmail.com) +;_______________________________________________________________________________ +; +; Usage: +; INTTEST +;_______________________________________________________________________________ +; +;=============================================================================== +; Definitions +;=============================================================================== +; +stksiz .equ $40 ; Working stack size +; +restart .equ $0000 ; CP/M restart vector +bdos .equ $0005 ; BDOS invocation vector +; +bf_sysint .equ $FC ; INT function +; +bf_sysintinfo .equ $00 ; INT INFO subfunction +bf_sysintget .equ $10 ; INT GET subfunction +bf_sysintset .equ $20 ; INT SET subfunction +; +z180_base .equ $40 ; i/o base address for internal z180 registers +z180_tcr .equ z180_base + $10 ; timer control +z180_tmdr0l .equ z180_base + $0C ; timer 0 data lo + +; +;=============================================================================== +; Code Section +;=============================================================================== +; + .org $100 +; + ; setup stack (save old value) + ld (stksav),sp ; save stack + ld sp,stack ; set new stack +; + ; initialization + call init ; initialize + jr nz,exit ; abort if init fails +; + ; process + call process ; do main processing + jr nz,exit ; abort on error +; +exit: ; clean up and return to command processor + call crlf ; formatting + ld sp,(stksav) ; restore stack + ;jp restart ; return to CP/M via restart + ret ; return to CP/M w/o restart +; +; Initialization +; +init: + call crlf ; formatting + ld de,msgban ; point to version message part 1 + call prtstr ; print it +; + ; relocate handler + ld hl,reladr + ld de,$8000 + ld bc,hsiz + ldir +; +initx + ; initialization complete + xor a ; signal success + ret ; return +; +; Process +; +process: +; +; Get info +; + call crlf2 + ld de,msginfo ; message + call prtstr +; + ld b,bf_sysint ; INT function + ld c,bf_sysintinfo ; INFO subfunction + rst 08 + ld a,d + ld (intmod),a ; save int mode + ld a,e + ld (veccnt),a ; save vector count +; + push de + call crlf + ld de,msgmode ; mode + call prtstr + pop de + push de + ld a,d ; interrupt mode + call prtdecb + call crlf + ld de,msgcnt ; count of vectors + call prtstr + pop de + ld a,e + call prtdecb +; +; Done if int mode is 0 +; + ld a,(intmod) + or a + ret z +; +; List vectors +; + call crlf2 + ld de,msglst + call prtstr + ld a,(veccnt) ; get count of vectors + or a + jr z,estidx ; bypass if nothing to list + ld b,a ; make it the loop counter + ld c,0 ; vector entry index +; +lstlp: + push bc + call crlf + ld a,' ' + call prtchr + call prtchr + ld a,c + call prthex + ld a,':' + call prtchr + ld e,c + ld b,bf_sysint + ld c,bf_sysintget + rst 08 + push hl + pop bc + call prthexword + pop bc + inc c + djnz lstlp +; +; Establish interrupt vector index to hook +; +estidx: + ld a,(intmod) + ld c,0 + cp 1 + jr z,setidx + ld c,2 ; assume timer in entry 2 if im2 + cp 2 + jr z,setidx + ret ; neither im1 or im2, bail out +setidx: + ld a,c + ld (vecidx),a +; +; Hook vector +; + call crlf2 + ld de,msghook + call prtstr + call crlf2 + ld a,$ff + ld (count),a ; set counter to max value +; + ld a,(intmod) + cp 1 + jr z,hkim1 + cp 2 + jr z,hkim2 + ret +; +; IM1 specific code +; +hkim1: + ld hl,m1int ; pointer to my interrupt handler + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld a,(vecidx) ; get vector idx + ld e,a ; put in E + di + rst 08 ; do it + ld (chain),hl ; save the chain address + ei ; interrupts back on + jr start +; +; IM2 specific code +; +hkim2: + ld hl,m2stub ; pointer to my interrupt stub + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld a,(vecidx) ; get vector idx + ld e,a ; put in E + di + rst 08 ; do it + ld (chain),hl ; save the chain address + ld (engadr),de ; insert the int routing engine address + ei ; interrupts back on + jr start +; +; Wait for counter to countdown to zero +; +start: + ld a,(count) + ld e,a + call prthex ; print it + ld a,13 + call prtchr +loop: + ld a,(count) ; get current count value + cp e + jr z,loop + push af + call prthex ; print it + ld a,13 + call prtchr + pop af + or a ; set flags + jr z,loop1 ; done + jr loop ; and loop +loop1: +; +; Unhook +; + call crlf2 + ld de,msgunhk + call prtstr + ld hl,(chain) ; original vector + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld a,(vecidx) ; get vector idx + ld e,a ; put in E + di + rst 08 ; do it + ei ; interrupts back on +; + xor a ; signal success + ret ; done +; +; Print character in A without destroying any registers +; +prtchr: + push bc ; save registers + push de + push hl + ld e,a ; character to print in E + ld c,$02 ; BDOS function to output a character + call bdos ; do it + pop hl ; restore registers + pop de + pop bc + ret +; +prtdot: +; + ; shortcut to print a dot preserving all regs + push af ; save af + ld a,'.' ; load dot char + call prtchr ; print it + pop af ; restore af + ret ; done +; +prtcr: +; + ; shortcut to print a dot preserving all regs + push af ; save af + ld a,13 ; load CR value + call prtchr ; print it + pop af ; restore af + ret ; done +; +; Print a zero terminated string at (DE) without destroying any registers +; +prtstr: + push de +; +prtstr1: + ld a,(de) ; get next char + or a + jr z,prtstr2 + call prtchr + inc de + jr prtstr1 +; +prtstr2: + pop de ; restore registers + ret +; +; Print the value in A in hex without destroying any registers +; +prthex: + push af ; save AF + push de ; save DE + call hexascii ; convert value in A to hex chars in DE + ld a,d ; get the high order hex char + call prtchr ; print it + ld a,e ; get the low order hex char + call prtchr ; print it + pop de ; restore DE + pop af ; restore AF + ret ; done +; +; print the hex word value in bc +; +prthexword: + push af + ld a,b + call prthex + ld a,c + call prthex + pop af + ret +; +; print the hex dword value in de:hl +; +prthex32: + push bc + push de + pop bc + call prthexword + push hl + pop bc + call prthexword + pop bc + ret +; +; Convert binary value in A to ascii hex characters in DE +; +hexascii: + ld d,a ; save A in D + call hexconv ; convert low nibble of A to hex + ld e,a ; save it in E + ld a,d ; get original value back + rlca ; rotate high order nibble to low bits + rlca + rlca + rlca + call hexconv ; convert nibble + ld d,a ; save it in D + ret ; done +; +; Convert low nibble of A to ascii hex +; +hexconv: + and $0F ; low nibble only + add a,$90 + daa + adc a,$40 + daa + ret +; +; Print value of A or HL in decimal with leading zero suppression +; Use prtdecb for A or prtdecw for HL +; +prtdecb: + push hl + ld h,0 + ld l,a + call prtdecw ; print it + pop hl + ret +; +prtdecw: + push af + push bc + push de + push hl + call prtdec0 + pop hl + pop de + pop bc + pop af + ret +; +prtdec0: + ld e,'0' + ld bc,-10000 + call prtdec1 + ld bc,-1000 + call prtdec1 + ld bc,-100 + call prtdec1 + ld c,-10 + call prtdec1 + ld e,0 + ld c,-1 +prtdec1: + ld a,'0' - 1 +prtdec2: + inc a + add hl,bc + jr c,prtdec2 + sbc hl,bc + cp e + ret z + ld e,0 + call prtchr + ret +; +; Start a new line +; +crlf2: + call crlf ; two of them +crlf: + push af ; preserve AF + ld a,13 ; + call prtchr ; print it + ld a,10 ; + call prtchr ; print it + pop af ; restore AF + ret +; +; Get the next non-blank character from (HL). +; +nonblank: + ld a,(hl) ; load next character + or a ; string ends with a null + ret z ; if null, return pointing to null + cp ' ' ; check for blank + ret nz ; return if not blank + inc hl ; if blank, increment character pointer + jr nonblank ; and loop +; +; Convert character in A to uppercase +; +ucase: + cp 'a' ; if below 'a' + ret c ; ... do nothing and return + cp 'z' + 1 ; if above 'z' + ret nc ; ... do nothing and return + res 5,a ; clear bit 5 to make lower case -> upper case + ret ; and return +; +; Add the value in A to HL (HL := HL + A) +; +addhl: + add a,l ; A := A + L + ld l,a ; Put result back in L + ret nc ; if no carry, we are done + inc h ; if carry, increment H + ret ; and return +; +; Jump indirect to address in HL +; +jphl: + jp (hl) +; +;=============================================================================== +; Storage Section +;=============================================================================== +; +intmod .db 0 ; active interrupt mode +veccnt .db 0 ; count of ingterrupt vectors +vecidx .db 0 ; vector index to hook +; +stksav .dw 0 ; stack pointer saved at start + .fill stksiz,0 ; stack +stack .equ $ ; stack top +; +; Messages +; +msgban .db "INTTEST v1.0, 27-Aug-2018",13,10 + .db "Copyright (C) 2018, Wayne Warthen, GNU GPL v3",0 +msginfo .db "Interrupt information request...",0 +msgmode .db " Active interrupt mode: ",0 +msgcnt .db " Vector entries in use: ",0 +msglst .db "Interrupt vector address list:",0 +msghook .db "Hooking vector...",0 +msgunhk .db "Unhooking vector...",0 +; +;=============================================================================== +; Interrupt Handler +;=============================================================================== +; +reladr .equ $ ; relocation start adr +; + .org $8000 ; code will run here +; +m1int: + ; count down to zero + ld a,(count) + or a + jr z,m1int1 + dec a + ld (count),a +m1int1: + ; follow the chain... + ld hl,(chain) + jp (hl) +; +m2stub: + push hl + ld hl,m2int + jp $0000 +engadr .equ $ - 2 +; +m2int: + ; count down to zero + ld a,(count) + or a + jr z,m2int1 + dec a + ld (count),a +m2int1: + ; ack/reset z180 timer interrupt + in0 a,(z180_tcr) + in0 a,(z180_tmdr0l) + ret +; +chain .dw $0000 ; chain address +count .db 0 ; counter + +hsiz .equ $ - $8000 ; size of handler to relocate + .end diff --git a/Source/Apps/Timer.asm b/Source/Apps/Timer.asm index 21f7aa13..fa8d737c 100644 --- a/Source/Apps/Timer.asm +++ b/Source/Apps/Timer.asm @@ -1,5 +1,5 @@ ;=============================================================================== -; SIMER - Display system timer value +; TIMER - Display system timer value ; ;=============================================================================== ; diff --git a/Source/CBIOS/ver.inc b/Source/CBIOS/ver.inc index 1f3e0de7..6f33bd5a 100644 --- a/Source/CBIOS/ver.inc +++ b/Source/CBIOS/ver.inc @@ -2,4 +2,4 @@ #DEFINE RMN 9 #DEFINE RUP 1 #DEFINE RTP 0 -#DEFINE BIOSVER "2.9.1-pre.6" +#DEFINE BIOSVER "2.9.1-pre.7" diff --git a/Source/HBIOS/API.txt b/Source/HBIOS/API.txt index 5463890d..781e9aef 100644 --- a/Source/HBIOS/API.txt +++ b/Source/HBIOS/API.txt @@ -2,7 +2,7 @@ HBIOS Management Functions ========================== -RESET: ($F0): +RESET ($F0): B=Function A=Result VER ($F1): @@ -52,7 +52,7 @@ GET ($F8): VDACNT ($40): BC=Function/Subfunction A=Result E=Video Unit Count - + TIMER ($D0): BC=Function/Subfunction A=Result DE:HL=Timer Value (32 bit) @@ -90,17 +90,101 @@ SET ($F9): DE=Boot Volume (Disk Unit/Slice) L=Boot Bank Id -PEEK: ($FA): +PEEK ($FA): B=Function A=Result D=Bank E=Byte Value HL=Address -POKE: ($FB): +POKE ($FB): B=Function A=Result D=Bank E=Byte Value HL=Address +INT ($FC): Interrupt vector management functions + BC=Function/Subfunction A=Result + + Subfunctions: + + INTINF ($00): Query interrupt system information + BC=Function/Subfunction A=Result + D=Interrupt Mode + E=Interrupt Vector Table Size + + Report interrupt interrupt management system information. + + Interrupt Mode: + 0: Interrupts disabled + 1: Z80 Interrupt Mode 1 active + 2: Z80 Interrupt Mode 2 active + + Interrupt Vector Table Size: + If interrupts are disabled, this will be zero. if interrupt mode 1, this + will be the number of entries in the interrupt call list. if interrupt mode + 2, this will be the number of slots in the interrupt vector table. + + INTGET ($10): Get interrupt vector + BC=Function/Subfunction A=Result + E=Interrupt Vector Table Position HL=Interrupt Vector + + Return the Interrupt Vector for the specified Interrupt Vector Table Position. + + INTSET ($20): Set interrupt vector + BC=Function/Subfunction A=Result + HL=Interrupt Vector HL=Previous Vector + E=Interrupt Vector Table Position DE=Interrupt Routing Engine Address + + Set the Interrupt Vector for the specified Interrupt Vector Table Position to the + specified Interrupt Vector. The previous value at the specified table position + will be returned. The Vector Table Position is a zero-based index into the + interrupt vector table and must specify a position less than or equal to the + size of the table. + + The new interrupt vector must point to a proper interrupt handler located in the + top 32K of CPU address space. Note that during interrupt processing, the lower + 32K of CPU address space will contain the RomWBW HBIOS code bank, not the lower + 32K of application TPA. As such, a dynamically installed interrupt handler does + not have access to the lower 32K of TPA and must be careful to avoid modifying + the contents of the lower 32K of memory. Invoking RomWBW HBIOS functions within + an interrupt handler is not supported. The interrupt management framework takes + care of saving and restoring AF, BC, DE, HL, and IY. Any other registers modified + must be saved and restored by the interrupt handler. + + Interrupt handlers are different for IM1 or IM2. + + For IM1: + + The new interrupt handler is responsible for chaining (JP) to the previous vector + if the interrupt is not handled. The interrupt handler must return with ZF set + if interrupt is handled and ZF cleared if not handled. + + For IM2: + + The interrupt handler requires an invocation stub separate from the actual interrupt + handling code. The stub must be: + + PUSH HL + LD HL, + JP + + When calling Set Interrupt Vector, the address of the stub must be provided for the + Interrupt Vector parameter. The address of the Interrupt Routing Engine will be + returned in DE and must be inserted into the stub code as indicated above. In the + case of IM2 mode interrutps, the actual interrupt handler should not chain to the + previous entry. The new interrupt handler must assume all responsibilities for + the specific interrupt slot being occupied. + + If the caller is transient, then the caller must remove the new interrupt handler and + restore the original one prior to termination. This is accomplished by calling this + function with the Interrupt Vector set to the Previous Vector returned in the original + call. + + The caller is responsible for disabling interrupts prior to making an INTSET call and + enabling them afterwards. The caller is responsible for ensuring that a valid interrupt + handler is installed prior to enabling any hardware interrupts associated with the handler. + Also, if the handler is transient, the caller must disable the hardware interrupt(s) + associated with the handler prior to uninstalling it. + ================ Serial Functions ================ @@ -167,7 +251,7 @@ DEVICE ($06): Serial Device Attributes Byte: 7: 0=RS-232, 1=Terminal - + If Terminal, 3-0 is attached Video Unit # ============== @@ -234,18 +318,18 @@ DEVICE ($17) Disk Device Attributes Byte: 7: 1=Floppy, 0=Hard Disk (or similar, e.g. CF, SD, RAM) - + If Floppy: 6-5: Form Factor (0=8", 1=5.25", 2=3.5", 3=Other) 4: Sides (0=SS, 1=DS) 3-2: Density (0=SD, 1=DD, 2=HD, 3=ED) 1-0: Reserved - + If Hard Disk: 6: Removable 5-3: Type (0=Hard, 1=CF, 2=SD, 3=USB, 4=ROM, 5=RAM, 6=RAMF, 7=?) 2-0: Reserved - + Note: IDE value 848Ah in IDENTIFY DEVICE data word 0 indicates CF Card MEDIA ($18): @@ -277,7 +361,7 @@ GEOMETRY ($1B): D:7=LBA Capable E=Sectors BC=Block Size - + Report current media geometry information. If media is unknown, return error (no media) diff --git a/Source/HBIOS/Build.ps1 b/Source/HBIOS/Build.ps1 index 19525ceb..3a2290ad 100644 --- a/Source/HBIOS/Build.ps1 +++ b/Source/HBIOS/Build.ps1 @@ -104,7 +104,7 @@ $ImgFile = "${OutDir}/${RomName}.img" # Final name of IMG image (memory loadable if ($Platform -eq "UNA") {$CBiosFile = '../CBIOS/cbios_una.bin'} else {$CBiosFile = '../CBIOS/cbios_wbw.bin'} # List of RomWBW proprietary apps to imbed in ROM disk. -$RomApps = "assign","fdu","format","mode","osldr","rtc","survey","syscopy","sysgen","talk","timer","xm" +$RomApps = "assign","fdu","format","mode","osldr","rtc","survey","syscopy","sysgen","talk","timer","xm","inttest" "" "Building ${RomName}: ${ROMSize}KB ROM configuration ${Config} for Z${CPUType}..." diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index c79c0356..36916770 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -491,6 +491,25 @@ HBX_IVT: .DW INT_BAD ; .DW INT_BAD ; ; +HBX_IVTCNT .EQU ($ - HBX_IVT) / 2 +; +HBX_ITBL: + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT #ENDIF ; ; INTERRUPT HANDLER STUBS @@ -1465,6 +1484,8 @@ SYS_DISPATCH: JP Z,SYS_PEEK ; $FA DEC A JP Z,SYS_POKE ; $FB + DEC A + JP Z,SYS_INT ; $FC CALL PANIC ; INVALID ; ; SOFT RESET HBIOS, RELEASE HEAP MEMORY NOT USED BY HBIOS @@ -1740,6 +1761,123 @@ SYS_POKE: XOR A RET ; +; INTERRUPT MANAGEMENT FUNCTIONS +; SUBFUNCTION IN C +; +SYS_INT: + LD A,C ; GET REQUESTED SUB-FUNCTION + CP BF_SYSINT_INFO + JR Z,SYS_INTINFO + CP BF_SYSINT_GET + JR Z,SYS_INTGET + CP BF_SYSINT_SET + JR Z,SYS_INTSET + OR $FF ; SIGNAL ERROR + RET +; +; GET INTERRUPT SYSTEM INFORMATION +; RETURN D:=INTERRUPT MODE, E:=INT VEC TABLE SIZE +; +SYS_INTINFO: + LD D,INTMODE ; D := ACTIVE INTERRUPT MODE +#IF (INTMODE == 0) + LD E,0 ; 0 ENTRIES IF INTERRUPTS DISABLED +#ENDIF +#IF (INTMODE == 1) + LD A,(HB_IM1CNT) ; RETURN IM1 CALL LIST SIZE + LD E,A +#ENDIF +#IF (INTMODE == 2) + LD E,HBX_IVTCNT ; RETURN INT VEC TABLE SIZE +#ENDIF + XOR A ; INDICATE SUCCESS + RET ; AND DONE +; +; ROUTINE SHARED BY INT GET/SET. RETURNS ADDRESS OF VECTOR FOR SPECIFIED LIST / TABLE +; POSITION. ZF SET ON RETURN FOR SUCCESS, ELSE ERROR. +; +SYS_INTVECADR: +#IF (INTMODE == 0) + CALL PANIC ; INVALID FOR INT MODE 0 + OR $FF + RET +#ENDIF +#IF (INTMODE == 1) + LD A,(HB_IM1CNT) ; GET CURRENT ENTRY COUNT + INC A ; ALLOW FOR EXTRA ENTRY TO APPEND AT END + LD C,A ; SAVE IN C FOR COMPARE +#ENDIF +#IF (INTMODE == 2) + LD C,HBX_IVTCNT ; GET CURRENT ENTRY COUNT +#ENDIF + LD A,E ; INCOMING INDEX POSITION TO A + CP C ; COMPARE TO VECTOR COUNT + JR C,SYS_INTGET1 ; CONTINUE IF POSITION IN RANGE + CALL PANIC ; ELSE ERROR + OR $FF + RET +SYS_INTGET1: + OR A + RLA ; HL := (A * 2) FOR IM2 +#IF (INTMODE == 1) + RLA ; ... HL := (A * 4) + 1 FOR IM1 + INC A +#ENDIF + LD H,0 + LD L,A +#IF (INTMODE == 1) + LD DE,HB_IM1INT ; DE := START OF CALL LIST +#ENDIF +#IF (INTMODE == 2) + LD DE,HBX_IVT ; DE := START OF VECTOR TABLE +#ENDIF + ADD HL,DE ; HL := ADR OF VECTOR + XOR A ; INDICATE SUCCESS + RET +; +; RETURN THE INTERRUPT VECTOR FOR A SPECIFIED POSITION IN THE INT VECTOR LIST / TABLE +; ENTRY: E=LIST/TABLE POSITION +; RETURN: HL=INTERRUPT VECTOR +; +SYS_INTGET: + CALL SYS_INTVECADR ; GET VECTOR ADDRESS + RET NZ ; BAIL OUT ON ERROR + LD A,(HL) ; DEREF HL TO GET VECTOR + INC HL + LD H,(HL) + LD L,A + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +; SET AN INTERRUPT VECTOR FOR A SPECIFIED POSITION IN THE INT VECTOR LIST / TABLE +; ENTRY: E=LIST/TABLE POSITION, HL=NEW INTERRUPT VECTOR +; RETURN: HL=PREVIOUS INTERRUPT VECTOR, DE=ADR OF INT ROUTING ENGINE FOR IM2 +; +SYS_INTSET: + PUSH HL ; SAVE NEW VECTOR + CALL SYS_INTVECADR ; GET VECTOR ADDRESS + JR Z,SYS_INTSET1 ; CONTINUE IF OK + POP HL ; FIX STACK + RET NZ ; BAIL OUT ON ERROR +SYS_INTSET1: + PUSH HL ; SAVE VECTOR ADDRESS + LD A,(HL) ; DEREF HL TO GET PREV VECTOR + INC HL + LD H,(HL) + LD L,A + EX (SP),HL ; (SP) := PREV VEC, HL := VEC ADR + POP DE ; DE := PREV VEC + POP BC ; BC := NEW VEC + LD (HL),C ; SAVE LSB + INC HL + LD (HL),B ; SAVE MSB + EX DE,HL ; HL := PREV VEC +#IF (INTMODE == 2) + LD DE,HBX_INT ; DE := IM2 INT ROUTING ENGINE +#ENDIF + XOR A ; SIGNAL SUCCESS + RET ; DONE +; ;================================================================================================== ; GLOBAL HBIOS FUNCTIONS ;================================================================================================== @@ -1765,30 +1903,43 @@ CIO_IDLE: ; CALL XXXX ; CALL INT HANDLER ; RET NZ ; RETURN IF HANDLED ; -HB_IM1INT: ; IM1 DEVICE INTERRUPT HANDLER - JP HB_BADINT - RET ; START WITH NO ENTRIES - .FILL 4 * 8,$C9 ; ROOM FOR 8 ENTRIES +; NOTE THAT THE LIST IS INITIALLY FILLED WITH CALLS TO HB_BADINT. +; AS THE TABLE IS POPULATED, THE ADDRESS OF HB_BADINT IS OVERLAID +; WITH THE ADDRESS OF A REAL INTERRUPT HANDLER. +; +; THERE IS ROOM FOR 8 ENTRIES PLUS A FINAL CALL TO HB_BADINT. +; +HB_IM1INT: ; IM1 DEVICE INTERRUPT HANDLER CALL LIST + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ ; ; ROUTINE BELOW IS USED TO ADD A NEW VECTOR TO THE IM1 ; CALL LIST ABOVE. ENTER WITH HL=VECTOR ADDRESS IN HBIOS ; HB_ADDIM1: EX DE,HL ; VECTOR ADDRESS TO DE - LD HL,(HB_IM1P) ; GET PTR FOR NEXT ENTRY - LD (HL),$CD ; "CALL" OPCODE - INC HL ; BUMP PTR + LD HL,(HB_IM1PTR) ; GET PTR FOR NEXT ENTRY + INC HL ; BUMP PTR TO ADDRESS FIELD OF CALL OPCODE LD (HL),E ; ADD VECTOR ADDRESS INC HL ; ... LD (HL),D ; ... INC HL ; BUMP PTR - LD (HL),$C0 ; "RET NZ" OPCODE INC HL ; BUMP PTR - LD (HL),$C9 ; FINAL "RET" OPCODE - LD (HB_IM1P),HL ; SAVE POINTER + LD (HB_IM1PTR),HL ; SAVE UPDATED POINTER + LD HL,HB_IM1CNT ; POINT TO ENTRY COUNT + INC (HL) ; INCREMENT RET ; DONE ; -HB_IM1P .DW HB_IM1INT ; POINTER FOR NEXT IM1 ENTRY +HB_IM1CNT .DB 0 ; NUMBER OF ENTRIES IN CALL LIST +HB_IM1MAX .DB 8 ; MAX ENTRIES IN CALL LIST +HB_IM1PTR .DW HB_IM1INT ; POINTER FOR NEXT IM1 ENTRY ; #ENDIF ; @@ -1843,6 +1994,7 @@ HB_BADINT: PRTS("+++ BAD INT: $") CALL _REGDMP CALL CONTINUE + OR $FF ; SIGNAL INTERRUPT HANDLED RET ; ; COMMON API FUNCTION DISPATCH CODE diff --git a/Source/HBIOS/hbios.inc b/Source/HBIOS/hbios.inc index 9e565e6f..ad64b3b5 100644 --- a/Source/HBIOS/hbios.inc +++ b/Source/HBIOS/hbios.inc @@ -65,6 +65,7 @@ BF_SYSGET .EQU BF_SYS + 8 ; GET HBIOS INFO BF_SYSSET .EQU BF_SYS + 9 ; SET HBIOS PARAMETERS BF_SYSPEEK .EQU BF_SYS + 10 ; GET A BYTE VALUE FROM ALT BANK BF_SYSPOKE .EQU BF_SYS + 11 ; SET A BYTE VALUE IN ALT BANK +BF_SYSINT .EQU BF_SYS + 12 ; MANAGE INTERRUPT VECTORS ; BF_SYSGET_CIOCNT .EQU $00 ; GET CHAR UNIT COUNT BF_SYSGET_DIOCNT .EQU $10 ; GET DISK UNIT COUNT @@ -78,6 +79,10 @@ BF_SYSGET_BNKINFO .EQU $F2 ; GET BANK ASSIGNMENT INFO BF_SYSSET_TIMER .EQU $D0 ; SET TIMER VALUE BF_SYSSET_BOOTINFO .EQU $E0 ; SET BOOT INFORMATION ; +BF_SYSINT_INFO .EQU $00 ; GET INTERRUPT SYSTEM INFO +BF_SYSINT_GET .EQU $10 ; GET INT VECTOR ADDRESS +BF_SYSINT_SET .EQU $20 ; SET INT VECTOR ADDRESS +; ; SERIAL DEVICE IDS ; CIODEV_UART .EQU $00 diff --git a/Source/HBIOS/ver.inc b/Source/HBIOS/ver.inc index 1f3e0de7..6f33bd5a 100644 --- a/Source/HBIOS/ver.inc +++ b/Source/HBIOS/ver.inc @@ -2,4 +2,4 @@ #DEFINE RMN 9 #DEFINE RUP 1 #DEFINE RTP 0 -#DEFINE BIOSVER "2.9.1-pre.6" +#DEFINE BIOSVER "2.9.1-pre.7"