From e17fee85e94dcceb44f3c64369ab86847d08a3d6 Mon Sep 17 00:00:00 2001 From: Wayne Warthen Date: Mon, 22 Feb 2021 14:18:01 -0800 Subject: [PATCH] Add Z180 Invalid Opcode Handler --- Source/CBIOS/cbios.asm | 52 +++++++++++--------- Source/CPM3/bioskrnl.asm | 5 +- Source/HBIOS/Config/RCZ280_nat_zz.asm | 2 +- Source/HBIOS/dbgmon.asm | 6 +-- Source/HBIOS/hbios.asm | 68 +++++++++++++++++++++++++- Source/HBIOS/hbios.inc | 1 + Source/HBIOS/romldr.asm | 16 ++++++ Source/Images/Common/TDLBASIC.COM | Bin 0 -> 14848 bytes Source/ver.inc | 2 +- Source/ver.lib | 2 +- 10 files changed, 124 insertions(+), 30 deletions(-) create mode 100644 Source/Images/Common/TDLBASIC.COM diff --git a/Source/CBIOS/cbios.asm b/Source/CBIOS/cbios.asm index 4af347ef..34d8647d 100644 --- a/Source/CBIOS/cbios.asm +++ b/Source/CBIOS/cbios.asm @@ -350,33 +350,41 @@ REBOOT: ; ;__________________________________________________________________________________________________ WBOOT: - LD SP,STACK ; STACK FOR INITIALIZATION +; +#IFDEF PLTWBW + ; GIVE HBIOS A CHANCE TO DIAGNOSE ISSUES, PRIMARILY + ; THE OCCURRENCE OF A Z180 INVALID OPCODE TRAP + POP HL ; SAVE PC FOR DIAGNOSIS + LD SP,STACK ; STACK FOR INITIALIZATION + LD BC,$F003 ; HBIOS USER RESET FUNCTION + RST 08 ; DO IT +#ENDIF ; #IFDEF PLTUNA ; RESTORE COMMAND PROCESSOR FROM UNA BIOS CACHE - LD BC,$01FB ; UNA FUNC = SET BANK - LD DE,(BNKBIOS) ; UBIOS_PAGE (SEE PAGES.INC) - RST 08 ; DO IT - PUSH DE ; SAVE PREVIOUS BANK - - LD HL,(CCPBUF) ; ADDRESS OF CCP BUF IN BIOS MEM - LD DE,CCP_LOC ; ADDRESS IN HI MEM OF CCP - LD BC,CCP_SIZ ; SIZE OF CCP - LDIR ; DO IT - - LD BC,$01FB ; UNA FUNC = SET BANK - POP DE ; RECOVER OPERATING BANK - RST 08 ; DO IT + LD BC,$01FB ; UNA FUNC = SET BANK + LD DE,(BNKBIOS) ; UBIOS_PAGE (SEE PAGES.INC) + RST 08 ; DO IT + PUSH DE ; SAVE PREVIOUS BANK + + LD HL,(CCPBUF) ; ADDRESS OF CCP BUF IN BIOS MEM + LD DE,CCP_LOC ; ADDRESS IN HI MEM OF CCP + LD BC,CCP_SIZ ; SIZE OF CCP + LDIR ; DO IT + + LD BC,$01FB ; UNA FUNC = SET BANK + POP DE ; RECOVER OPERATING BANK + RST 08 ; DO IT #ELSE ; RESTORE COMMAND PROCESSOR FROM CACHE IN HB BANK - LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY - LD DE,(BNKBIOS) ; D = DEST (USER BANK), E = SRC (BIOS BANK) - LD HL,CCP_SIZ ; HL = COPY LEN = SIZE OF COMMAND PROCESSOR - RST 08 ; DO IT - LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY - LD HL,(CCPBUF) ; COPY FROM FIXED LOCATION IN HB BANK - LD DE,CCP_LOC ; TO CCP LOCATION IN USR BANK - RST 08 ; DO IT + LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY + LD DE,(BNKBIOS) ; D = DEST (USER BANK), E = SRC (BIOS BANK) + LD HL,CCP_SIZ ; HL = COPY LEN = SIZE OF COMMAND PROCESSOR + RST 08 ; DO IT + LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY + LD HL,(CCPBUF) ; COPY FROM FIXED LOCATION IN HB BANK + LD DE,CCP_LOC ; TO CCP LOCATION IN USR BANK + RST 08 ; DO IT #ENDIF ; ; SOME APPLICATIONS STEAL THE BDOS SERIAL NUMBER STORAGE diff --git a/Source/CPM3/bioskrnl.asm b/Source/CPM3/bioskrnl.asm index bd21c783..85effacf 100644 --- a/Source/CPM3/bioskrnl.asm +++ b/Source/CPM3/bioskrnl.asm @@ -172,7 +172,10 @@ boot$1: ; Entry for system restarts. wboot: - lxi sp,boot$stack + pop h ; WBW: save PC for diagnosis + lxi sp,boot$stack ; reset stack + lxi b,0F003H ; WBW: HBIOS user reset func + rst 1 ; WBW: do it call set$jumps ; initialize page zero call ?rlccp ; reload CCP jmp ccp ; then reset jmp vectors and exit to ccp diff --git a/Source/HBIOS/Config/RCZ280_nat_zz.asm b/Source/HBIOS/Config/RCZ280_nat_zz.asm index d9f325c4..e74f9d28 100644 --- a/Source/HBIOS/Config/RCZ280_nat_zz.asm +++ b/Source/HBIOS/Config/RCZ280_nat_zz.asm @@ -29,4 +29,4 @@ RAMLOC .SET 23 ; START OF RAM AS POWER OF 2 (2^N) IN PHYSICAL ADDRESS SPACE RAMBIAS .SET (1 << (RAMLOC - 10)) ; OFFSET OF START OF RAM IN PHYSICAL ADDRESS SPACE ; -Z2U0HFC .SET FALSE ; Z2U 0: ENABLE HARDWARE FLOW CONTROL +Z2U0HFC .SET TRUE ; Z2U 0: ENABLE HARDWARE FLOW CONTROL diff --git a/Source/HBIOS/dbgmon.asm b/Source/HBIOS/dbgmon.asm index 73691701..5aacfe6c 100644 --- a/Source/HBIOS/dbgmon.asm +++ b/Source/HBIOS/dbgmon.asm @@ -120,9 +120,9 @@ SERIALCMDLOOP: ;_____________________________________________________________________________ ; INITIALIZE: - LD A,$C3 ; JP OPCODE - LD (0),A ; STORE AT $0000 - LD (1),HL ; STORE AT $0001 + ;LD A,$C3 ; JP OPCODE + ;LD (0),A ; STORE AT $0000 + ;LD (1),HL ; STORE AT $0001 #IF (BIOS == BIOS_UNA) ; INSTALL UNA INVOCATION VECTOR FOR RST 08 diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index abbfac72..c5bc7e68 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -201,7 +201,7 @@ RTCDEF .EQU 0 ; ALLOWS DRIVERS TO SET BITS #IF (INTMODE == 1) JP INT_IM1 ; JP TO INTERRUPT HANDLER IN HI MEM #ELSE - RETI ; RETURN W/ INTS DISABLED + RET ; RETURN W/ INTS DISABLED #ENDIF .FILL (066H - $),0FFH ; NMI RETN @@ -2908,6 +2908,8 @@ SYS_RESET: JR Z,SYS_RESWARM CP BF_SYSRES_COLD JR Z,SYS_RESCOLD + CP BF_SYSRES_USER + JR Z,SYS_RESUSER CALL SYSCHK LD A,ERR_NOFUNC OR A ; SIGNAL ERROR @@ -2916,8 +2918,15 @@ SYS_RESET: ; SOFT RESET HBIOS, RELEASE HEAP MEMORY NOT USED BY HBIOS ; SYS_RESINT: +; + ; RESET THE HEAP LD HL,(HEAPCURB) ; GET HBIOS HEAP THRESHOLD LD (CB_HEAPTOP),HL ; RESTORE HEAP TOP +; + ; MAKE SURE THE PROPER RESET VECTOR IS AT ADDRESS $0000 + LD HL,$0040 ; USER RESET CODE STUB + LD ($0001),HL ; OPERAND OF JP AT $0000 +; XOR A RET ; @@ -2946,6 +2955,63 @@ SYS_RESCOLD: LD IX,0 ; ADDRESS ZERO CALL HB_BNKCALL ; DOES NOT RETURN ; +; HOOK CALLED WHEN A USERLAND RESET IS INVOKED, TYPICALLY VIA A JUMP +; TO LOGICAL CPU ADDRESS $0000 +; +SYS_RESUSER: +; +#IF (CPUFAM == CPU_Z180) +; + IN0 A,(Z180_ITC) ; GET ITC REGISTER + BIT 7,A ; TRAP BIT SET? + JR Z,SYS_RESUSER9 ; IF NOT, SKIP AHEAD +; + ; HANDLE INVALID OPCODE + DEC HL ; BACK UP TO OPCODE START + BIT 6,A ; CHECK UFO BIT (2 BYTE OPCODE) + JR Z,SYS_RESUSER1 ; IF NOT, ALL SET + DEC HL ; OTHERWISE, BACK UP 1 MORE BYTE +; +SYS_RESUSER1: + RES 7,A ; CLEAR THE TRAP BIT + OUT0 (Z180_ITC),A ; SAVE IT +; + CALL PRTSTRD ; PRINT ERROR TAG + .TEXT "\r\n\r\n+++ BAD OPCODE @$" + CALL PRTHEXWORDHL ; PRINT ADDRESS + PRTS("H:$") ; FORMATTING +; + LD B,8 ; SHOW 8 BYTES +SYS_RESUSER2: + PUSH BC ; SAVE BC + PUSH HL ; SAVE HL + LD A,(HB_INVBNK) ; GET BYTE FROM INVOKING BANK + LD D,A ; PUT IN D + CALL SYS_PEEK ; PEEK TO GET BYTE VALUE + LD A,E ; PUT IN A + CALL PC_SPACE ; FORMATTING + CALL PRTHEXBYTE ; DISPLAY BYTE + POP HL ; RECOVER HL + POP BC ; RECOVER BC + INC HL ; NEXT BYTE + DJNZ SYS_RESUSER2 ; LOOP TIL DONE + CALL NEWLINE ; FORMATTING +; +#ENDIF +; +SYS_RESUSER9: + ;; NOTIFY USER + ;CALL PRTSTRD + ;.TEXT "\r\n*** USER RESET ***\r\n$" +; + ;; EXIT VIA USER RESET VECTOR (IF SET) + ;LD HL,(HB_RESVEC) ; GET USER RESET VECTOR + ;LD A,H ; CHECK IF IT + ;OR L ; ... HAS BEEN SET + ;JP Z,SYS_RESWARM ; IF NOT, JUST WARM START +; + RET ; ELSE RETURN WITH USER RESET VECTOR IN HL +; ; GET THE CURRENT HBIOS VERSION ; ON INPUT, C=0 ; RETURNS VERSION IN DE AS BCD diff --git a/Source/HBIOS/hbios.inc b/Source/HBIOS/hbios.inc index bdee24ed..ecb01a9f 100644 --- a/Source/HBIOS/hbios.inc +++ b/Source/HBIOS/hbios.inc @@ -90,6 +90,7 @@ BF_SYSINT .EQU BF_SYS + 12 ; MANAGE INTERRUPT VECTORS BF_SYSRES_INT .EQU $00 ; RESET HBIOS INTERNAL BF_SYSRES_WARM .EQU $01 ; WARM START (RESTART BOOT LOADER) BF_SYSRES_COLD .EQU $02 ; COLD START +BF_SYSRES_USER .EQU $03 ; USER RESET REQUEST ; BF_SYSGET_CIOCNT .EQU $00 ; GET CHAR UNIT COUNT BF_SYSGET_CIOFN .EQU $01 ; GET CIO UNIT FN/DATA ADR diff --git a/Source/HBIOS/romldr.asm b/Source/HBIOS/romldr.asm index 17783fa4..f8f9954b 100644 --- a/Source/HBIOS/romldr.asm +++ b/Source/HBIOS/romldr.asm @@ -83,6 +83,20 @@ bid_cur .equ -1 ; used below to indicate current bank #else ret ; return w/ ints disabled #endif +; +#if (BIOS == BIOS_WBW) + .fill ($40 - $),$FF + ; After initial bootup, it is conventional for a jp 0 to + ; cause a warm start of the system. If there is no OS running + ; then this bit of code will suffice. After bootup, the + ; jp instruction at $0 is modified to point here. + pop hl ; save PC in case needed for ... + ld bc,$F003 ; HBIOS user reset function + call HB_INVOKE ; do it + ld bc,$F001 ; HBIOS warm start function + call HB_INVOKE ; do it +#endif +; .fill ($66 - $) retn ; nmi ; @@ -147,6 +161,8 @@ start1: ld de,0 ; put it in user page zero ld bc,$100 ; full page ldir ; do it + ld hl,$0040 ; adr of user reset code + ld (1),hl ; save at $0000 ; ; Page zero in user bank is ready for interrupts now. ; diff --git a/Source/Images/Common/TDLBASIC.COM b/Source/Images/Common/TDLBASIC.COM new file mode 100644 index 0000000000000000000000000000000000000000..ebaec5268991f83eeff295e378f8a72c71f79855 GIT binary patch literal 14848 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 fd&f;{Z(