;-------------------------------------------------------------------------------------------------------- ;- ;- Name: tzfs_bank3.asm ;- Created: July 2019 ;- Author(s): Philip Smart ;- Description: Sharp MZ series tzfs (tranZPUter Filing System). ;- Bank 3 - F000:FFFF - ;- ;- This assembly language program is a branch from the original RFS written for the ;- MZ80A_RFS upgrade board. It is adapted to work within the similar yet different ;- environment of the tranZPUter SW which has a large RAM capacity (512K) and an ;- I/O processor in the K64F/ZPU. ;- ;- Credits: ;- Copyright: (c) 2018-2023 Philip Smart ;- ;- History: May 2020 - Branch taken from RFS v2.0 and adapted for the tranZPUter SW. ;- Jul 2021 - Updated to add configurable tape read/write for MZ80K,80B and 800 series ;- machines. ;- Feb 2023 - TZFS now running on FusionX. Small changes to ensure compatibility. ;- ;-------------------------------------------------------------------------------------------------------- ;- This source file is free software: you can redistribute it and-or modify ;- it under the terms of the GNU General Public License as published ;- by the Free Software Foundation, either version 3 of the License, or ;- (at your option) any later version. ;- ;- This source file is distributed in the hope that it will be useful, ;- but WITHOUT ANY WARRANTY; without even the implied warranty of ;- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;- GNU General Public License for more details. ;- ;- You should have received a copy of the GNU General Public License ;- along with this program. If not, see . ;-------------------------------------------------------------------------------------------------------- ;============================================================ ; ; TZFS BANK 3 - Utilities and additional commands. ; ;============================================================ ORG BANKRAMADDR ;------------------------------------------------------------------------------- ; START OF UTILITY METHODS ;------------------------------------------------------------------------------- ; Method to skip white space whilst locating a comma. Once found, advance to the next first non-white space character. ; Outputs: ; Z = No comma - either comma found but no following characters or no comma found. ; NZ = comma found, DE points to next non-white character. SKIPCOMMA: LD A,(DE) ; Scan the parameter buffer for a comma. INC DE CP ' ' JR Z,SKIPCOMMA CP 000H RET Z ; End of string, no comma found. CP ',' JR NZ,SKIPCOMMA SKIPCOM2: LD A,(DE) ; Comma found now advance to first non-white char. CP 000H ; End of string? RET Z CP ' ' ; Non comma found, return success. RET NZ INC DE ; Whitespace so advance to next char. JR SKIPCOM2 ; Method to validate a model code, the single character should be one of: ; 0, K = MZ-80K ; 1, C = MZ-80C ; 2, 1 = MZ-1200 ; 3, A = MZ-80A ; 4, 7 = MZ-700 ; 5, 8 = MZ-800 ; 6, B = MZ-80B ; 7, 2 = MZ-2000 ; 8, O = Original memory load, original machine configuration, ie. MZ-800 as an MZ-800.. ; 9, o = Original memory load, alternative mode, ie. MZ-700 on MZ-800 host.. ; Outputs: ; C = Binary model number 0..7 ; Z = Model code valid. ; NZ = Invalid code. CHECKMODEL: LD C,MODE_MZ80K CP 'K' ; MZ-80K RET Z ; 0 INC C CP 'C' ; MZ-80C RET Z ; 1 INC C CP '1' ; MZ-1200 RET Z ; 2 INC C CP 'A' ; MZ-80A RET Z ; 3 INC C CP '7' ; MZ-700 RET Z ; 4 INC C CP '8' ; MZ-800 RET Z ; 5 INC C CP 'B' ; MZ-80B RET Z ; 6 INC C CP '2' ; MZ-2000 RET Z ; 7 INC C CP 'O' ; Original host, ie. MZ-800 as an MZ-800 RET Z ; 8 INC C CP 'S' ; Original host, alternative mode, ie. MZ-700 mode on MZ-800 host. RET ; 9? ; Get optional machine model code. Format is: CMD[,][machine model code] ; Outputs: ; A = Model number. GETMODEL: CALL SKIPCOMMA JR Z,READMODEL ; No comma found so no parameter, read default model from CPLD. LD A,(DE) ; Get code CALL CHECKMODEL LD A,C JR NZ,READMODEL RET READMODEL: IN A,(CPLDINFO) ; Get the model number from the underlying hardware. AND 007H ; Mask in the relevant bits, A = Model number. RET ; ; Pallet Reg. & Border Reg. set ; PLT0~3 Black ; Border Black ; ; output: BC = 6CFH, A = 0 ; PLTST: PUSH HL LD BC,05F0H ; C=port (Pallet Write), B=count LD HL,PLTDT ; Data OTIR XOR A LD BC,06CFH ; Border Black OUT (C),A ; Send to port. POP HL RET ; Initialization table for Palette ; PLTDT: DB 0,10H,20H,30H,40H ;------------------------------------------------------------------------------- ; END OF UTILITY METHODS ;------------------------------------------------------------------------------- ;------------------------------------------------------------------------------- ; START OF ADDITIONAL TZFS COMMAND METHODS ;------------------------------------------------------------------------------- ; ; Memory correction ; command 'M' ; MCORX: CALL READ4HEX ; correction address RET C MCORX1: CALL NLPHL ; corr. adr. print CALL SPHEX ; ACC ASCII display CALL PRNTS ; space print LD DE,BUFER ; Input the data. CALL GETL LD A,(DE) CP 01Bh ; If . pressed, exit. RET Z PUSH HL POP BC CALL HLHEX ; If the existing address is no longer hex, reset. HLASCII(DE). If it is hex, take as the address to store data into. JR C,MCRX3 ; Line is corrupted as the address is no longer in Hex, reset. INC DE INC DE INC DE INC DE INC DE ; CALL _2HEX ; Get value entered. JR C,MCORX1 ; Not hex, reset. CP (HL) ; Not same as memory, reset. JR NZ,MCORX1 INC DE ; LD A,(DE) ; Check if no data just CR, if so, move onto next address. CP 00Dh ; not correction JR Z,MCRX2 CALL _2HEX ; Get the new entered data. ACCHL(ASCII) JR C,MCORX1 ; New data not hex, reset. LD (HL),A ; data correct so store. MCRX2: INC HL JR MCORX1 MCRX3: LD H,B ; memory address LD L,C JR MCORX1 ; Dump method when called interbank as HL cannot be passed. ; ; BC = Start ; DE = End DUMPBC: PUSH BC POP HL JR DUMP ; Command line utility to dump memory. ; Get start and optional end addresses from the command line, ie. XXXX[XXXX] ; Paging is implemented, 23 lines at a time, pressing U goes back 100H, pressing D scrolls down 100H ; DUMPX: CALL HLHEX ; Get start address if present into HL JR NC,DUMPX1 LD DE,(DUMPADDR) ; Setup default start and end. JR DUMPX2 DUMPX1: INC DE INC DE INC DE INC DE PUSH HL CALL HLHEX ; Get end address if present into HL POP DE ; DE = Start address JR NC,DUMPX4 ; Both present? Then display. DUMPX2: LD A,(SCRNMODE) BIT 0,A LD HL,000A0h ; Make up an end address based on 160 bytes from start for 40 column mode. JR Z,DUMPX3 LD HL,00140h ; Make up an end address based on 320 bytes from start for 80 column mode. DUMPX3: ADD HL,DE DUMPX4: EX DE,HL ; ; HL = Start ; DE = End DUMP: LD A,23 DUMP0: LD (TMPCNT),A LD A,(SCRNMODE) ; Configure output according to screen mode, 40/80 chars. BIT 0,A JR NZ,DUMP1 LD B,008H ; 40 Char, output 23 lines of 40 char. LD C,017H JR DUMP2 DUMP1: LD B,010h ; 80 Char, output 23 lines of 80 char. LD C,02Fh DUMP2: CALL NLPHL DUMP3: CALL SPHEX INC HL PUSH AF LD A,(DSPXY) ADD A,C LD (DSPXY),A POP AF CP 020h JR NC,DUMP4 LD A,02Eh DUMP4: CALL ?ADCN CALL PRNT3 LD A,(DSPXY) INC C SUB C LD (DSPXY),A DEC C DEC C DEC C PUSH HL SBC HL,DE POP HL JR NC,DUMP9 DUMP5: DJNZ DUMP3 LD A,(TMPCNT) DEC A JR NZ,DUMP0 DUMP6: CALL GETKY ; Pause, X to quit, D to go down a block, U to go up a block. OR A JR Z,DUMP6 CP 'D' JR NZ,DUMP7 LD A,8 JR DUMP0 DUMP7: CP 'U' JR NZ,DUMP8 PUSH DE LD DE,00100H OR A SBC HL,DE POP DE LD A,8 JR DUMP0 DUMP8: CP 'X' JR Z,DUMP9 JR DUMP DUMP9: LD (DUMPADDR),HL ; Store last address so we can just press D for next page, CALL NL RET ;------------------------------------------------------------------------------- ; END OF ADDITIONAL TZFS COMMAND METHODS ;------------------------------------------------------------------------------- ;------------------------------------------------------------------------------- ; START OF TIMER TEST FUNCTIONALITY ;------------------------------------------------------------------------------- ; Test the 8253 Timer, configure it as per the monitor and display the read back values. TIMERTST: CALL NL LD DE,MSG_TIMERTST CALL MSG CALL NL LD DE,MSG_TIMERVAL CALL MSG LD A,01h LD DE,8000h CALL TIMERTST1 NDE: JP NDE JP ST1X TIMERTST1: DI PUSH BC PUSH DE PUSH HL LD (AMPM),A LD A,0F0H LD (TIMFG),A ABCD: LD HL,0A8C0H XOR A SBC HL,DE PUSH HL INC HL EX DE,HL LD HL,CONTF ; Control Register LD (HL),0B0H ; 10110000 Control Counter 2 10, Write 2 bytes 11, 000 Interrupt on Terminal Count, 0 16 bit binary LD (HL),074H ; 01110100 Control Counter 1 01, Write 2 bytes 11, 010 Rate Generator, 0 16 bit binary LD (HL),030H ; 00110100 Control Counter 1 01, Write 2 bytes 11, 010 interrupt on Terminal Count, 0 16 bit binary LD HL,CONT2 ; Counter 2 LD (HL),E LD (HL),D LD HL,CONT1 ; Counter 1 LD (HL),00AH LD (HL),000H LD HL,CONT0 ; Counter 0 LD (HL),00CH LD (HL),0C0H ; LD HL,CONT2 ; Counter 2 ; LD C,(HL) ; LD A,(HL) ; CP D ; JP NZ,L0323H ; LD A,C ; CP E ; JP Z,CDEF ; L0323H: PUSH AF PUSH BC PUSH DE PUSH HL ; LD HL,CONTF ; Control Register LD (HL),080H LD HL,CONT2 ; Counter 2 LD C,(HL) LD A,(HL) CALL PRTHX LD A,C CALL PRTHX ; CALL PRNTS ; LD HL,CONTF ; Control Register LD (HL),040H LD HL,CONT1 ; Counter 1 LD C,(HL) LD A,(HL) CALL PRTHX LD A,C CALL PRTHX ; CALL PRNTS ; LD HL,CONTF ; Control Register LD (HL),000H LD HL,CONT0 ; Counter 0 LD C,(HL) LD A,(HL) CALL PRTHX LD A,C CALL PRTHX ; LD A,0C4h ; Move cursor left. LD E,0Eh ; 4 times. L0330: CALL DPCT DEC E JR NZ,L0330 ; ; LD C,20 ;L0324: CALL DLY12 ; DEC C ; JR NZ,L0324 ; POP HL POP DE POP BC POP AF ; LD HL,CONT2 ; Counter 2 LD C,(HL) LD A,(HL) CP D JP NZ,L0323H LD A,C CP E JP NZ,L0323H ; ; PUSH AF PUSH BC PUSH DE PUSH HL CALL NL CALL NL CALL NL LD DE,MSG_TIMERVAL2 CALL MSG POP HL POP DE POP BC POP AF ; CDEF: POP DE LD HL,CONT1 LD (HL),00CH LD (HL),07BH INC HL L0336H: PUSH AF PUSH BC PUSH DE PUSH HL ; LD HL,CONTF ; Control Register LD (HL),080H LD HL,CONT2 ; Counter 2 LD C,(HL) LD A,(HL) CALL PRTHX LD A,C CALL PRTHX ; CALL PRNTS CALL DLY1SEC ; LD HL,CONTF ; Control Register LD (HL),040H LD HL,CONT1 ; Counter 1 LD C,(HL) LD A,(HL) CALL PRTHX LD A,C CALL PRTHX ; CALL PRNTS CALL DLY1SEC ; LD HL,CONTF ; Control Register LD (HL),000H LD HL,CONT0 ; Counter 0 LD C,(HL) LD A,(HL) CALL PRTHX LD A,C CALL PRTHX ; CALL DLY1SEC ; LD A,0C4h ; Move cursor left. LD E,0Eh ; 4 times. L0340: CALL DPCT DEC E JR NZ,L0340 ; POP HL POP DE POP BC POP AF LD HL,CONT2 ; Counter 2 LD C,(HL) LD A,(HL) CP D JR NZ,L0336H LD A,C CP E JR NZ,L0336H CALL NL LD DE,MSG_TIMERVAL3 CALL MSG POP HL POP DE POP BC EI RET ;------------------------------------------------------------------------------- ; END OF TIMER TEST FUNCTIONALITY ;------------------------------------------------------------------------------- ;------------------------------------------------------------------------------- ; START OF PRINTER CMDLINE TOOLS FUNCTIONALITY ;------------------------------------------------------------------------------- PTESTX: LD A,(DE) CP '&' ; plotter test JR NZ,PTST1X PTST0X: INC DE LD A,(DE) CP 'L' ; 40 in 1 line JR Z,.LPTX CP 'S' ; 80 in 1 line JR Z,..LPTX CP 'C' ; Pen change JR Z,PENX CP 'G' ; Graph mode JR Z,PLOTX CP 'T' ; Test JR Z,PTRNX ; PTST1X: CALL PMSGX ST1X2: RET .LPTX: LD DE,LLPT ; 01-09-09-0B-0D JR PTST1X ..LPTX: LD DE,SLPT ; 01-09-09-09-0D JR PTST1X PTRNX: LD A,004h ; Test pattern JR LE999 PLOTX: LD A,002h ; Graph mode LE999: CALL LPRNTX JR PTST0X PENX: LD A,01Dh ; 1 change code (text mode) JR LE999 ; ; ; 1 char print to $LPT ; ; in: ACC print data ; ; LPRNTX: LD C,000h ; RDAX test LD B,A ; print data store CALL RDAX LD A,B OUT (0FFh),A ; data out LD A,080h ; RDP high OUT (0FEh),A LD C,001h ; RDA test CALL RDAX XOR A ; RDP low OUT (0FEh),A RET ; ; $LPT msg. ; in: DE data low address ; 0D msg. end ; PMSGX: PUSH DE PUSH BC PUSH AF PMSGX1: LD A,(DE) ; ACC = data CALL LPRNTX LD A,(DE) INC DE CP 00Dh ; end ? JR NZ,PMSGX1 POP AF POP BC POP DE RET ; ; RDA check ; ; BRKEY in to monitor return ; in: C RDA code ; RDAX: IN A,(0FEh) AND 00Dh CP C RET Z CALL BRKEY JR NZ,RDAX LD SP,ATRB JR ST1X2 ; 40 CHA. IN 1 LINE CODE (DATA) LLPT: DB 01H ; TEXT MODE DB 09H DB 09H DB 0BH DB 0DH ; 80 CHA. 1 LINE CODE (DATA) SLPT: DB 01H ; TEXT MODE DB 09H DB 09H DB 09H DB 0DH ;------------------------------------------------------------------------------- ; END OF PRINTER CMDLINE TOOLS FUNCTIONALITY ;------------------------------------------------------------------------------- ;------------------------------------------------------------------------------- ; START OF ADDITIONAL CMT CONTROLLER FUNCTIONALITY ;------------------------------------------------------------------------------- ; Method to setup the delay loop count to set the half-wave period of the sampling, short and long CMT pulses. ; To allow the user to compensate for tape stretch or drive belt wear, a compensation value can be added/subtracted ; from the precise time values. ; ; Opcode timings: ; CALL - 17 T-states time from caller into function. ; LD - 7 T-states no longer used, hard coded value. ; LD A,(nn) - 13 T-states time to load up the configurable loop count ; DEC - 4 T-states time to dec A ; JP cc - 10 T-states time to test and loop for next iteration ; NOP - 4 T-states additional delay for fine tuning. ; RET - 10 T-states time to return to caller. ; ; Example: ; 17 + 7 + ((4+10)*x) + 12 + 10 = 564 * 1/3546000 = 159uS + (7 + 13 * (1/3546000)) = 164.5uS ; (66 + (14 * x)) / 3540000 = delay ; MZ-700 - x = ((delay * 3540000) - 66) / 14 ; MZ-80A - x = ((delay * 2000000) - 66) / 14 CMTSETDLY: IF BUILD_MZ700+BUILD_MZ1500 > 0 PUSH BC ; Store the compensation value in B to be added into fixed delay value. LD A,(CMTDLYCOMP) LD B,A ; LD A,(HWMODEL) ; Get the machine model we are conforming to. CP 5 ; MZ-800 has its own timing. JR Z,CMTSETDLY0 CP 6 ; MZ-80B uses 1800 baud settings JR Z,CMTSETDLY1 CP 7 ; MZ-2000 uses 1800 baud settings JR Z,CMTSETDLY1 ; ; K Series LD A,86 ; Remainder of the machines use a 1200 baud setting, ADD A,B LD (CMTSAMPLECNT),A ; 368uS sample point. LD A,56 ; ADD A,B LD (CMTDLY1CNTM),A ; 240us LD A,62 ; ADD A,B LD (CMTDLY1CNTS),A ; + 264uS = 504uS LD A,113 ADD A,B LD (CMTDLY2CNTM),A ; 464uS LD A,120 ADD A,B LD (CMTDLY2CNTS),A ; + 494uS = 958uS JR CMTDLYEXIT ; MZ-800 CMTSETDLY0: LD A,89 ; 379uS sample point ADD A,B LD (CMTSAMPLECNT),A LD A,56 ; 240uS ADD A,B LD (CMTDLY1CNTM),A LD A,66 ; + 278uS = 518uS ADD A,B LD (CMTDLY1CNTS),A LD A,114 ; 470uS ADD A,B LD (CMTDLY2CNTM),A ; LD A,120 ; + 494uS = 964uS ADD A,B LD (CMTDLY2CNTS),A ; JR CMTDLYEXIT ; B Series CMTSETDLY1: LD A,52 ; 255uS sample point. ADD A,B LD (CMTSAMPLECNT),A LD A,37 ; 166.75uS ADD A,B LD (CMTDLY1CNTM),A LD A,37 ; + 166uS = 332.75uS ADD A,B LD (CMTDLY1CNTS),A LD A,80 ; 333uS ADD A,B LD (CMTDLY2CNTM),A ; LD A,80 ; + 334uS = 667uS ADD A,B LD (CMTDLY2CNTS),A ; JR CMTDLYEXIT ENDIF ; The values below are for an MZ-80A running at 2MHz under the FusionX board. ; If TZFS runs on more platforms then a table will be the best method forward. IF BUILD_MZ80A > 0 PUSH BC ; Store the compensation value in B to be added into fixed delay value. LD A,(CMTDLYCOMP) LD B,A ; LD A,(HWMODEL) ; Get the machine model we are conforming to. CP 5 ; MZ-800 has its own timing. JR Z,CMTSETDLY0 CP 6 ; MZ-80B uses 1800 baud settings JR Z,CMTSETDLY1 CP 7 ; MZ-2000 uses 1800 baud settings JR Z,CMTSETDLY1 ; ; K Series LD A,47 ; Remainder of the machines use a 1200 baud setting, ADD A,B LD (CMTSAMPLECNT),A ; 368uS sample point. LD A,30 ; ADD A,B LD (CMTDLY1CNTM),A ; 240us LD A,33 ; ADD A,B LD (CMTDLY1CNTS),A ; + 264uS = 504uS LD A,62 ADD A,B LD (CMTDLY2CNTM),A ; 464uS LD A,66 ADD A,B LD (CMTDLY2CNTS),A ; + 494uS = 958uS JR CMTDLYEXIT ; MZ-800 CMTSETDLY0: LD A,49 ; 379uS sample point ADD A,B LD (CMTSAMPLECNT),A LD A,30 ; 240uS ADD A,B LD (CMTDLY1CNTM),A LD A,35 ; + 278uS = 518uS ADD A,B LD (CMTDLY1CNTS),A LD A,62 ; 470uS ADD A,B LD (CMTDLY2CNTM),A ; LD A,66 ; + 494uS = 964uS ADD A,B LD (CMTDLY2CNTS),A ; JR CMTDLYEXIT ; B Series CMTSETDLY1: LD A,32 ; 255uS sample point. ADD A,B LD (CMTSAMPLECNT),A LD A,19 ; 166.75uS ADD A,B LD (CMTDLY1CNTM),A LD A,19 ; + 166uS = 332.75uS ADD A,B LD (CMTDLY1CNTS),A LD A,43 ; 333uS ADD A,B LD (CMTDLY2CNTM),A ; LD A,43 ; + 334uS = 667uS ADD A,B LD (CMTDLY2CNTS),A ; JR CMTDLYEXIT ENDIF CMTDLYEXIT: POP BC RET ;READ INFORMATION ; CF=1:ERROR RDITZFS: DI CALL CMTSETDLY ; Setup the delay loop counters according to machine model being used. LD D,04H LD BC,0080H LD HL,IBUFE RD1: CALL MOTOR JR C,STPEIR CALL TMARK JR C,STPEIR CALL RTAPETZFS JR C,STPEIR JR EIRTN ;RET2S: BIT 3,D ; JR Z,EIRTN STPEIR: CALL BRKEY ; Double check reason for exit, was it a break key? LD A,01H JR NC,STPEIR1 LD A,02H STPEIR1: LD (RESULT),A ; Store result for later use. SCF ; Indicate error condition. EIRTN: CALL MSTOP EI RET ;READ DATA RDDTZFS: DI CALL CMTSETDLY ; Setup the delay loop counters according to machine model being used. LD D,08H LD BC,(SIZE) JR RD1 ; ;READ TAPE ; BC=SIZE ; DE=LOAD ADDRESS RTAPETZFS: PUSH DE PUSH BC PUSH HL LD H,02H RTP2: CALL SPDIN JR C,TRTN1 ;BREAK JR Z,RTP2 LD D,H LD HL,0000H LD (SUMDT),HL POP HL POP BC PUSH BC PUSH HL RTP3: CALL RBYTE JR C,TRTN1 LD (HL),A INC HL DEC BC LD A,B OR C JR NZ,RTP3 LD HL,(SUMDT) CALL RBYTE JR C,TRTN1 LD E,A CALL RBYTE JR C,TRTN1 CP L JR NZ,RTP5 LD A,E CP H JR Z,TRTN1 RTP5: DEC D JR Z,RTP6 LD H,D JR RTP2 RTP6: SCF TRTN1: POP HL POP BC POP DE RET ;--------------------------------------------------------------------------------------------------------------------- ; The FDC controller uses it's busy/wait signal as a ROM address line input, this ; causes a jump in the code dependent on the signal status. It gets around the 2MHz Z80 not being quick ; enough to process the signal by polling. ALIGN_NOPS FDCJMP1 ORG FDCJMP1 FDCJMPL3: JP (IX) ;--------------------------------------------------------------------------------------------------------------------- ; EDGE (TAPE DATA EDGE DETECT) ; BC=KEYPB (E001H) ; DE=CSTR (E002H) ; EXIT CF=0 OK CF=1 BREAK EDGE: LD A,0F8H ; BREAK KEY IN (88H WOULD BE BETTER!!) LD (KEYPA),A NOP EDG1: LD A,(KEYPB) AND 81H ; SHIFT & BREAK JR NZ,L060E SCF RET L060E: LD A,(KEYPC) AND 20H JR NZ,EDG1 ; CSTR D5 = 0 EDG2: LD A,(KEYPB) ; 13 AND 81H ; 7 JR NZ,L061A ; 12 if condition met, 7 if not SCF RET L061A: LD A,(KEYPC) ; 13 AND 20H ; 7 JR Z,EDG2 ; CSTR D5 = 1 12/7 RET ; 10 ; 1 BYTE READ ; DATA=A ; SUMDT STORE RBYTE: PUSH HL LD HL,0800H ; 8 BITS RBY1: CALL SPDIN JR C,RBY3 ;BREAK JR Z,RBY2 ;BIT=0 PUSH HL LD HL,(SUMDT) ;CHECKSUM INC HL LD (SUMDT),HL POP HL SCF RBY2: RL L DEC H JR NZ,RBY1 CALL EDGE LD A,L RBY3: POP HL RET ;TAPE MARK DETECT ; E=L:INFORMATION ; E=S:DATA TMARK: PUSH HL LD HL,1414H BIT 3,D JR NZ,TM0 ADD HL,HL TM0: LD (TMCNT),HL TM1: LD HL,(TMCNT) TM2: CALL SPDIN JR C,RBY3 JR Z,TM1 DEC H JR NZ,TM2 TM3: CALL SPDIN JR C,RBY3 JR NZ,TM1 DEC L JR NZ,TM3 CALL EDGE JR RBY3 ;READ 1 BIT SPDIN: CALL EDGE ;WAIT ON HIGH RET C ;BREAK ; LD A,(nn) - 13 T-states ; DEC - 4 T-states ; JP cc - 10 T-states ; LD A,(nn) - 13 T-states ; K Series = 368uS ; B Series = 255uS ; 800 = 379uS ; 74 (time from edge detection to here) + 13 + ((4+10)*x) + 13 = 798 * 1/3580000 = 178uS LD A,(CMTSAMPLECNT) SPDIN_1: DEC A JP NZ,SPDIN_1 LD A,(KEYPC) ;READ BIT AND 020H RET ; DELAY FOR SHORT PULSE - MARK ; ; CALL - 17 T-states ; LD - 7 T-states ; LD A,(nn) - 13 T-states ; DEC - 4 T-states ; JP cc - 10 T-states ; NOP - 4 T-states ; RET - 10 T-states ; 17 + 13 + ((4+10)*37) + 12 + 10 = 564 * 1/3546000 = 159uS + (7 + 13 * (1/3546000)) = 164.5uS DLYSHORTM: LD A,(CMTDLY1CNTM) ; LD A,37 DLYSHORT_1: DEC A JP NZ,DLYSHORT_1 NOP NOP RET ; DELAY FOR SHORT PULSE - SPACE ; ; CALL - 17 T-states ; LD - 7 T-states ; LD A,(nn) - 13 T-states ; DEC - 4 T-states ; JP cc - 10 T-states ; NOP - 4 T-states ; RET - 10 T-states ; 17 + 13 + ((4+10)*37) + 12 + 10 = 564 * 1/3546000 = 159uS + (7 + 13 * (1/3546000)) = 164.5uS DLYSHORTS: LD A,(CMTDLY1CNTS) ; LD A,37 DLYSHORT_2: DEC A JP NZ,DLYSHORT_2 NOP NOP RET ; DELAY FOR LONG PULSE - MARK ; ; CALL - 17 T-states ; LD - 7 T-states ; LD A,(nn) - 13 T-states ; DEC - 4 T-states ; JP cc - 10 T-states ; NOP - 4 T-states ; RET - 10 T-states ; LD - 7 T-states ; LD (nn),A - 13 T-states ; 17 + 13 + ((4+10)*80) + 8 + 10 = 560 * 1/3546000 = 327.6uS + (7 + 13 * (1/3546000)) = 333.2uS DLYLONGM: LD A,(CMTDLY2CNTM) ; LD A,80 DLYLONG_1: DEC A JP NZ,DLYLONG_1 NOP NOP RET ; DELAY FOR LONG PULSE - SPACE ; ; CALL - 17 T-states ; LD - 7 T-states ; LD A,(nn) - 13 T-states ; DEC - 4 T-states ; JP cc - 10 T-states ; NOP - 4 T-states ; RET - 10 T-states ; LD - 7 T-states ; LD (nn),A - 13 T-states ; 17 + 13 + ((4+10)*80) + 8 + 10 = 560 * 1/3546000 = 327.6uS + (7 + 13 * (1/3546000)) = 333.2uS DLYLONGS: LD A,(CMTDLY2CNTS) ; LD A,80 DLYLONG_2: DEC A JP NZ,DLYLONG_2 NOP NOP RET ; Method to create a delay of 1 Second. DLY1SEC: PUSH BC LD BC,1000 DLY1S_1: CALL DLY1MSEC DEC BC LD A,B OR C JR NZ,DLY1S_1 POP BC RET ; Method to create a delay of 1mSec, from caller point of call to next instruction after call. DLY1MSEC: LD A, 249 DLY1MS_1: DEC A JP NZ,DLY1MS_1 NOP NOP RET ; SHORT AND LONG PULSE FOR 1 BIT WRITE ; SHORTTZFS: PUSH AF ; 12 LD A,03H ; 9 LD (CSTPT),A ; E003H PC3=1:16 CALL DLYSHORTM LD A,02H ; 9 LD (CSTPT),A ; E003H PC3=0:16 CALL DLYSHORTS POP AF ; 11 RET ; 11 ; LONGTZFS: PUSH AF ; 11 LD A,03H ; 9 LD (CSTPT),A ; 16 CALL DLYLONGM LD A,02H ; 9 LD (CSTPT),A ; 16 CALL DLYLONGS POP AF ; 11 RET ; 11 ; GAP + TAPEMARK ; E =@L@ LONG GAP ; =@s@ SHORT GAP GAPTZFS: PUSH BC PUSH DE LD A,(HWMODEL) ; Get model so we can set the header pulse count. CP 6 JR Z,GAPTZFS_0 CP 7 JR Z,GAPTZFS_0 LD BC,55F0H ; K Series machines have 22000 lead in short pulses. JR GAPTZFS_00 GAPTZFS_0: LD BC,2710H ; 10,000 short pulses for 1800 baud cassettes GAPTZFS_00: LD A,E LD DE,2828H CP 0CCH ; "L" JP Z,GAPTZFS_1 LD BC,2AF8H LD DE,1414H GAPTZFS_1: CALL SHORTTZFS ; Write out the number of short pulses as the start. DEC BC LD A,B OR C JR NZ,GAPTZFS_1 GAPTZFS_2: CALL LONGTZFS ; Write out the Tape Mark Long pulses DEC D JR NZ,GAPTZFS_2 GAPTZFS_3: CALL SHORTTZFS ; Write out the Tape Mark Short pulses DEC E JR NZ,GAPTZFS_3 CALL LONGTZFS POP DE POP BC RET ; ; Method to write the tape header block. ; WRITZFS: DI PUSH DE PUSH BC PUSH HL CALL CMTSETDLY ; Setup the delay loop counters according to machine model being used. LD D,0D7H LD E,0CCH LD HL,IBUFE LD BC,00080H WRITZFS_0: CALL CKSUM CALL MOTOR JR C,WRITZFS_2 LD A,E CP 0CCH JR NZ,WRITZFS_1 ; PUSH HL PUSH DE PUSH BC LD DE,MSGCMTWRITE LD BC,NAME CALL ?PRINTMSG POP BC POP DE POP HL ; WRITZFS_1: CALL GAPTZFS CALL WTAPETZFS WRITZFS_2: POP HL POP BC POP DE CALL MSTOP PUSH AF LD A,(TIMFG) CP 0F0H JR NZ,WRITZFS_3 EI WRITZFS_3: POP AF RET ; Method to write the tape data block. ; EXIT CF=0 : OK ; =1 : BREAK WRDTZFS: DI PUSH DE PUSH BC PUSH HL CALL CMTSETDLY ; Setup the delay loop counters according to machine model being used. LD D,0D7H ; "W" LD E,53H ; "S" L047D: LD BC,(SIZE) ; WRITE DATA BYTE SIZE LD HL,(DTADR) ; WRITE DATA ADDRESS LD A,B OR C JR Z,RET1 JR WRITZFS_0 ; TAPE WRITE ; BC=BYTE SIZE ; HL=DATA LOW ADDRESS ; EXIT CF=0 : OK ; =1 : BREAK WTAPETZFS: PUSH DE PUSH BC PUSH HL LD D,02H LD A,0F8H ; 88H WOULD BE BETTER!! LD (KEYPA),A ; E000H WTAP1: LD A,(HL) CALL WBYTE ; 1 BYTE WRITE LD A,(KEYPB) ; E001H AND 81H ; SHIFT & BREAK JP NZ,WTAP2 LD A,02H ; BREAK IN CODE SCF JR WTAP3 WTAP2: INC HL DEC BC LD A,B OR C JP NZ,WTAP1 LD HL,(SUMDT) ; SUM DATA SET LD A,H CALL WBYTE LD A,L CALL WBYTE CALL LONGTZFS DEC D JP NZ,L04C2 OR A JP WTAP3 L04C2: LD B,0 L04C4: CALL SHORTTZFS DEC B JP NZ,L04C4 POP HL POP BC PUSH BC PUSH HL JP WTAP1 WTAP3: RET1: POP HL POP BC POP DE RET ; 1 BYTE WRITE WBYTE: PUSH BC LD B,8 CALL LONGTZFS WBY1: RLCA CALL C,LONGTZFS CALL NC,SHORTTZFS DEC B JP NZ,WBY1 POP BC RET ;------------------------------------------------------------------------------- ; END OF ADDITIONAL CMT CONTROLLER FUNCTIONALITY ;------------------------------------------------------------------------------- ;--------------------------------------------------------------------------------------------------------------------- ; The FDC controller uses it's busy/wait signal as a ROM address line input, this ; causes a jump in the code dependent on the signal status. It gets around the 2MHz Z80 not being quick ; enough to process the signal by polling. ALIGN_NOPS FDCJMP2 ORG FDCJMP2 FDCJMPH3: JP (IY) ;--------------------------------------------------------------------------------------------------------------------- ;------------------------------------------------------------------------------- ; START OF ADDITIONAL TZFS COMMAND METHODS ;------------------------------------------------------------------------------- ; Cmd tool to Fill memory. ; Read cmd line the start address, end address and byte to initialise with, if one not present, use 00H ; FILL: CALL READ4HEX JR C,FILLERR PUSH HL CALL READ4HEX JR C,FILLERR LD (TMPADR),DE POP DE ; DE = Start addr OR A SBC HL,DE ; HL - DE = Count PUSH HL POP BC ; Count of bytes to fill JR C,FILLERR ; Overflow, End > Start JR Z,FILLERR ; Nothing to do, Start = End PUSH DE LD DE,(TMPADR) CALL _2HEX ; Get optional byte to use for fill, default to 00H JR NC,FILL1 LD A,000H FILL1: POP HL LD (HL),A PUSH HL POP DE INC DE LDIR ; Copy (HL) -> (DE) filling memory with same byte. RET FILLERR: LD DE,MSGNOPARAM CALL ?PRINTMSG RET ; Tape Compensation Setup. ; Set a value which is added to or subtracted from the tape delay timing. ; This compensation value is to allow for old stretched tapes or machines with warped/stretched drive bands. ; TAPECOMP: LD A,(DE) ; Test the first character, if minus then set bit 0 in B for later use. CP '-' LD A,0 JR NZ,TAPECOMP1 INC DE ; Skip over minus. INC A ; Set bit 0 to indicate negative number. TAPECOMP1: LD B,A CALL ConvertStringToNumber ; Convert the input into compensation value. JP NZ,BADNUMERR LD A,L CP 080H ; Numbers > 127 are illegal. JP NC,BADNUMERR BIT 0,B JR Z,TAPECOMP2 NEG TAPECOMP2: LD (CMTDLYCOMP),A ; Store compensation value to be used by delay calculations. RET ; Copy - Source, Destination, Size. COPYM: CALL READ4HEX ; Start address JR C,COPYMERR LD (TMPADR),HL CALL READ4HEX JR C,COPYMERR LD (TMPCNT),HL CALL READ4HEX JR C,COPYMERR PUSH HL POP BC LD HL,(TMPCNT) LD DE,(TMPADR) LDIR COPYMERR: RET ; Write to I/O port. 16bit address to BC, 8bit value to A. WRITEIO: CALL READ4HEX ; Get 16bit I/O port. JR C,WRITEIOER PUSH HL ; Swap to BC so B=15:8, C=7:0 POP BC CALL _2HEX ; Get 8 bit data. OUT (C),A ; Write 8 bit data to 16bit port. WRITEIOER: RET ; Read 16bit I/O port value. READIO: CALL READ4HEX ; Get 16bit I/O port. JR C,READIOER PUSH HL ; Swap to BC so B=15:8, C=7:0 POP BC IN A,(C) ; Get 8bit value from 16bit I/O port. CALL PRTHX ; Print. CALL NL READIOER: RET ; FusionX doesnt yet have the video capabilities, so no need to build in the logic. SETVMODE: IF BUILD_FUSIONX = 0 ; Method to set the video mode. ; Param: 0 - Enable FPGA and set to MZ-80K mode. ; 1 - Enable FPGA and set to MZ-80C mode. ; 2 - Enable FPGA and set to MZ-1200 mode. ; 3 - Enable FPGA and set to MZ-80A mode (base mode on MZ-80A hardware). ; 4 - Enable FPGA and set to MZ-700 mode (base mode on MZ-700 hardware). ; 5 - Enable FPGA and set to MZ-1500 mode. ; 6 - Enable FPGA and set to MZ-800 mode. ; 7 - Enable FPGA and set to MZ-80B mode. ; 8 - Enable FPGA and set to MZ-2000 mode. ; 9 - Enable FPGA and set to MZ-2200 mode. ; 10 - Enable FPGA and set to MZ-2500 mode. ; O - Turn off FPGA Video, turn on mainboard video. IN A,(CPLDINFO) ; Get configuration of hardware. BIT 3,A JP Z,NOFPGAERR ; No hardware so cannot change mode. PUSH DE ; Preserve DE in case no number given. POP BC CALL ConvertStringToNumber ; Convert the input into 0 (disable) or frequency in KHz. JR NZ,SETVMODEOFF LD A,H CP 0 JP NZ,BADNUMERR ; Check that the given mode is in range 0 - 7. LD A,L CP 10 JP NC,BADNUMERR ; SETVMODE0: IN A,(CPLDCFG) OR MODE_VIDEO_FPGA ; Set the tranZPUter CPLD hardware to enable the FPGA video mode. OUT (CPLDCFG),A ; IN A,(VMCTRL) ; Get current setting. AND 0F0H ; Clear old mode setting. OR L ; Add in new setting. OUT (VMCTRL),A RLC L ; Shift mode to position for SCRNMODE storage. RLC L RLC L RLC L LD A,(SCRNMODE) ; Repeat for the screen mode variable, used when resetting or changing display settings. AND 007H ; Clear video mode setting. OR L ; Add in new setting. SET 2, A ; Set flag to indicate video mode override - ie, dont use base machine mode. SETVMODECLR: SET 1, A ; Ensure flag set so on restart the FPGA video mode is selected. LD (SCRNMODE),A LD A, 016H ; Clear the screen so we start from a known position. CALL PRNT LD A,071H ; Blue background and white characters. LD HL,ARAM CALL CLR8 RET SETVMODEOFF: LD A,(DE) CP 'O' JR Z,SETVMODE1 CP 'o' JP NZ,BADNUMERR SETVMODE1: LD A,(SCRNMODE) ; Disable flag to enable FPGA on restart. RES 1,A LD (SCRNMODE),A IN A,(CPLDCFG) AND ~MODE_VIDEO_FPGA ; Set the tranZPUter CPLD hardware to disable the FPGA video mode. OUT (CPLDCFG),A RET ENDIF ; Method to set the VGA output mode of the external display. SETVGAMODE: IF BUILD_FUSIONX = 0 IN A,(CPLDINFO) ; Get configuration of hardware. BIT 3,A JP Z,NOFPGAERR ; No hardware so cannot change mode. CALL ConvertStringToNumber ; Convert the input into 0-3, 0 = off, 1 = 640x480, 2=1024x768, 3=800x600. JP NZ,BADNUMERR LD A,H CP 0 JP NZ,BADNUMERR ; Check that the given mode is in range 0 - 15. LD A,L CP 15 JP NC,BADNUMERR ; ; RRC L ; RRC L ; Value to top 2 bits ready to be applied to VGA mode register. ; SETVGAMODE1: IN A,(CPLDCFG) OR MODE_VIDEO_FPGA ; Set the tranZPUter CPLD hardware to enable the FPGA video mode. OUT (CPLDCFG),A ; LD A, L ; Add in new setting. OUT (VMVGAMODE),A LD (SCRNMODE2), A JP SETVMODECLR ENDIF ; Method to set the VGA border colour on the external display. SETVBORDER: IF BUILD_FUSIONX = 0 IN A,(CPLDINFO) ; Get configuration of hardware. BIT 3,A JP Z,NOFPGAERR ; No hardware so cannot change mode. CALL ConvertStringToNumber ; Convert the input into 0 - 7, bit 2 = Red, 1 = Green, 0 = Blue. JP NZ,BADNUMERR LD A,H CP 0 JP NZ,BADNUMERR ; Check that the given mode is in range 0 - 7. LD A,L CP 7 JP NC,BADNUMERR ; IN A,(CPLDCFG) OR MODE_VIDEO_FPGA ; Set the tranZPUter CPLD hardware to enable the FPGA video mode. OUT (CPLDCFG),A ; LD A,L OUT (VMVGATTR),A RET ENDIF ; BUILD_FUSIONX ; Method to enable/disable the alternate CPU frequency and change it's values. ; SETFREQ: IF BUILD_FUSIONX = 0 CALL ConvertStringToNumber ; Convert the input into 0 (disable) or frequency in KHz. JP NZ,BADNUMERR LD (TZSVC_CPU_FREQ),HL ; Set the required frequency in the service structure. LD A,H CP L JR NZ,SETFREQ1 LD A, TZSVC_CMD_CPU_BASEFREQ ; Switch to the base frequency. JR SETFREQ2 SETFREQ1: LD A, TZSVC_CMD_CPU_ALTFREQ ; Switch to the alternate frequency. SETFREQ2: CALL SVC_CMD OR A JP NZ,SETFREQERR LD A,H CP L RET Z ; If we are disabling the alternate cpu frequency (ie. = 0) exit. LD A, TZSVC_CMD_CPU_CHGFREQ ; Switch to the base frequency. CALL SVC_CMD OR A JP NZ,SETFREQERR RET ENDIF ; BUILD_FUSIONX ; FusionX doesnt have the soft CPU capabilities, so no need to build in the logic. SETT80: IF BUILD_FUSIONX = 0 ; Method to configure the hardware to use the T80 CPU instantiated in the FPGA. ; IN A,(CPUINFO) LD C,A AND CPUMODE_IS_SOFT_MASK CP CPUMODE_IS_SOFT_AVAIL JP NZ,SOFTCPUERR LD A,C AND CPUMODE_IS_T80 JP Z,NOT80ERR ;LD L,VMMODE_VGA_640x480 ; Enable VGA mode for a better display. ;CALL SETVGAMODE1 LD A, TZSVC_CMD_CPU_SETT80 ; We need to ask the K64F to switch to the T80 as it may involve loading of ROMS. CALL SVC_CMD OR A JP NZ,SETT80ERR RET ENDIF ; BUILD_FUSIONX ; Method to configure the hardware to use the original Z80 CPU installed on the tranZPUter board. ; SETZ80: IF BUILD_FUSIONX = 0 IN A,(CPUINFO) AND CPUMODE_IS_SOFT_MASK CP CPUMODE_IS_SOFT_AVAIL JP NZ,SOFTCPUERR CALL SETVMODE1 ; Turn off VGA mode, return to default MZ video. LD A, TZSVC_CMD_CPU_SETZ80 CALL SVC_CMD OR A JP NZ,SETZ80ERR RET ENDIF ; BUILD_FUSIONX ; Method to configure the hardware to use the ZPU Evolution CPU instantiated in the FPGA. ; SETZPUEVO: IF BUILD_FUSIONX = 0 IN A,(CPUINFO) LD C,A AND CPUMODE_IS_SOFT_MASK CP CPUMODE_IS_SOFT_AVAIL JP NZ,SOFTCPUERR LD A,C AND CPUMODE_IS_ZPU_EVO JP Z,NOZPUERR LD L,VMMODE_VGA_640x480 ; Enable VGA mode for a better display. CALL SETVGAMODE1 LD A, TZSVC_CMD_CPU_SETZPUEVO ; We need to ask the K64F to switch to the ZPU Evo as it may involve loading of ROMS. CALL SVC_CMD OR A JP NZ,SETZPUERR HALT ; ZPU will take over so stop the Z80 from further processing. ENDIF ; BUILD_FUSIONX ;---------------------------------------------- ; Hardware Emulation Mode Activation Routines. ;---------------------------------------------- SETMZ80K: IF BUILD_FUSIONX = 0 LD D, TZSVC_CMD_EMU_SETMZ80K ; We need to ask the K64F to switch to the Sharp MZ80K emulation as it involves loading ROMS. JR SETEMUMZ ENDIF ; BUILD_FUSIONX SETMZ80C: IF BUILD_FUSIONX = 0 LD D, TZSVC_CMD_EMU_SETMZ80C JR SETEMUMZ ENDIF ; BUILD_FUSIONX SETMZ1200: IF BUILD_FUSIONX = 0 LD D, TZSVC_CMD_EMU_SETMZ1200 JR SETEMUMZ ENDIF ; BUILD_FUSIONX SETMZ80A: IF BUILD_FUSIONX = 0 LD D, TZSVC_CMD_EMU_SETMZ80A JR SETEMUMZ ENDIF ; BUILD_FUSIONX SETMZ700: IF BUILD_FUSIONX = 0 LD D, TZSVC_CMD_EMU_SETMZ700 JR SETEMUMZ ENDIF ; BUILD_FUSIONX SETMZ1500: IF BUILD_FUSIONX = 0 LD D, TZSVC_CMD_EMU_SETMZ1500 JR SETEMUMZ ENDIF ; BUILD_FUSIONX SETMZ800: IF BUILD_FUSIONX = 0 LD D, TZSVC_CMD_EMU_SETMZ800 JR SETEMUMZ ENDIF ; BUILD_FUSIONX SETMZ80B: IF BUILD_FUSIONX = 0 LD D, TZSVC_CMD_EMU_SETMZ80B JR SETEMUMZ ENDIF ; BUILD_FUSIONX SETMZ2000: IF BUILD_FUSIONX = 0 LD D, TZSVC_CMD_EMU_SETMZ2000 JR SETEMUMZ ENDIF ; BUILD_FUSIONX SETMZ2200: IF BUILD_FUSIONX = 0 LD D, TZSVC_CMD_EMU_SETMZ2200 JR SETEMUMZ ENDIF ; BUILD_FUSIONX SETMZ2500: IF BUILD_FUSIONX = 0 LD D, TZSVC_CMD_EMU_SETMZ2500 JR SETEMUMZ ENDIF ; BUILD_FUSIONX ; ; General function to determine if the emulator MZ hardware is present and activate it. Activation requires making a request to the ; I/O processor as it needs to load up the correct BIOS etc prior to activating the emulation. ; SETEMUMZ: IF BUILD_FUSIONX = 0 IN A,(CPUINFO) ; Verify that the FPGA has emuMZ capabilities. LD C,A AND CPUMODE_IS_SOFT_MASK CP CPUMODE_IS_SOFT_AVAIL JR NZ,SOFTCPUERR LD A,C AND CPUMODE_IS_EMU_MZ JR Z,NOEMUERR LD L,VMMODE_VGA_640x480 ; Enable VGA mode for a better display. CALL SETVGAMODE1 ; PUSH DE ; Setup the initial video mode based on the required emulation. LD A,D SUB TZSVC_CMD_EMU_SETMZ80K LD L,A LD H,0 CALL SETVMODE0 POP DE ; LD A, D ; Load up the required emulation mode. CALL SVC_CMD OR A JR NZ,SETT80ERR HALT ENDIF ; BUILD_FUSIONX ; Simple routine to clear screen or attributes. CLR8: LD BC,00800H PUSH DE LD D,A CLR8_1: LD (HL),D INC HL DEC BC LD A,B OR C JR NZ,CLR8_1 POP DE RET ; ; Message addresses are in Bank2. ; NOFPGAERR: IF BUILD_FUSIONX = 0 LD DE,MSGNOFPGA JR BADNUM2 ENDIF ; BUILD_FUSIONX SETT80ERR: IF BUILD_FUSIONX = 0 LD DE,MSGT80ERR JR BADNUM2 ENDIF ; BUILD_FUSIONX SETZ80ERR: IF BUILD_FUSIONX = 0 LD DE,MSGZ80ERR JR BADNUM2 ENDIF ; BUILD_FUSIONX SETZPUERR: IF BUILD_FUSIONX = 0 LD DE,MSGZPUERR JR BADNUM2 ENDIF ; BUILD_FUSIONX SOFTCPUERR: IF BUILD_FUSIONX = 0 LD DE,MSGNOSOFTCPU JR BADNUM2 ENDIF ; BUILD_FUSIONX NOT80ERR: IF BUILD_FUSIONX = 0 LD DE,MSGNOT80CPU JR BADNUM2 ENDIF ; BUILD_FUSIONX NOZPUERR: IF BUILD_FUSIONX = 0 LD DE,MSGNOZPUCPU JR BADNUM2 ENDIF ; BUILD_FUSIONX NOEMUERR: IF BUILD_FUSIONX = 0 LD DE,MSGNOEMU JR BADNUM2 ENDIF ; BUILD_FUSIONX SETFREQERR: LD DE,MSGFREQERR JR BADNUM2 BADNUMERR: LD DE,MSGBADNUM BADNUM2: CALL ?PRINTMSG RET ;------------------------------------------------------------------------------- ; END OF ADDITIONAL TZFS COMMAND METHODS ;------------------------------------------------------------------------------- ; Ensure we fill the entire 4K by padding with FF's. ; ALIGN_NOPS 10000H