;SPECTRAVIDEO SVI-738 X'PRESS CP/M V2.2 BIOS DISASSEMBLY Jun 09 2002 ;Disassembled and commented by Luis C. Grosso ; ;Explanation of IOBYTE ; LST: is currently 02 hex or [10 ] binary, or LPT: ; PUN: is currently 00 hex or [ 00 ] binary, or UP1: ; RDR: is currently 00 hex or [ 00 ] binary, or UR1: ; CON: is currently 01 hex or [ 01] binary, or CRT: ; ----------- ;where, for the following devices: ; IN OUT ; Device LST: PUN: RDR: CON: CON: ; ---------------------------------------- ; 00 assigns UC1: UP1: UR1: KBD: UC1: ; 01 assigns CRT: UP1: UR1: KBD: CRT: ; 10 assigns LPT: UP1: UR1: UR1: LST: ; 11 assigns UP1: UP1: UR1: KBD: UC1: ORG 0E200H LE200: JP LE543 ;BOOT - cold boot entry point LE203: JP LE5CD ;WBOOT - warm boot entry point LE206: JP LE6F6 ;CONST - console status routine LE209: JP LE732 ;CONIN - console input LE20C: JP LE884 ;CONOUT - console output LE20F: JP LEADA ;LIST - list device output LE212: JP LEB60 ;PUNCH - punch device output (always UP1:) LE215: JP LEB62 ;READER - reader device input (always UR1:) LE218: JP LEB6C ;HOME - home drive LE21B: JP LEB76 ;SELDSK - select disk LE21E: JP LEBE0 ;SETTRK - set track LE221: JP LEBE6 ;SETSEC - set sector LE224: JP LEBEC ;SETDMA - set DMA address LE227: JP LEBF5 ;READ - read from the disk LE22A: JP LEC21 ;WRITE - write to the disk LE22D: JP LEB51 ;LISTST - list device status LE230: JP LEBF1 ;SECTRAN- sector translation LE233: DEFW LE251 ;address of disk parameter header for disk 00 LE235: DEFW LE2E1 ;address of disk parameter block for disk 06 LE237: DEFW LE39B ;address of function key definition table LE239: DEFB 14H ;??? LE23A: DEFW LE200 ;address of BIOS start LE23C: DEFB 00H ;terminal type 00=VT-52 01=ADM-3A LE23D: DEFB 00H ;debug flag 00=not debugging (update BDOS and RST 38) LE23E: DEFB 00H ;printing pending jobs flag 00=no job LE23F: DEFB 0FFH ;CENTRONICS printer status 0FF=not busy LE240: DEFW 1900H ;printer queue input pointer LE242: DEFW 1900H ;printer queue output pointer LE244: DEFB 00H ;copy of the drive control register LE245: DEFS 12 ;unused locations ; disk parameter header for disk 00 (SVI-738) ;DPBAS0 LE251: DEFW 0000H ;TRANS DEFW 0000H DEFW 0000H DEFW 0000H DEFW LFEDE ;DIRBF DEFW LE2F0 ;DPBLK0 DEFW LF938 ;CHK00 DEFW LFA18 ;ALL00 ; disk parameter header for disk 01 (SVI-738 SSDD) ;DPBAS1 LE261: DEFW 0000H ;TRANS DEFW 0000H DEFW 0000H DEFW 0000H DEFW LFEDE ;DIRBF DEFW LE2F0 ;DPBLK0 DEFW LF958 ;CHK01 DEFW LFA31 ;ALL01 ; disk parameter header for disk 06 (XEROX 820 II SSDD) ;DPBAS6 LE271: DEFW 0000H ;TRANS DEFW 0000H DEFW 0000H DEFW 0000H DEFW LFEDE ;DIRBF DEFW LE2E1 ;DPBLK6 DEFW LF978 ;CHK02 DEFW LFA4A ;ALL02 ; disk parameter header for disk 02 (OSBORNE 1 SSDD) ;DPBAS2 LE281: DEFW 0000H ;TRANS DEFW 0000H DEFW 0000H DEFW 0000H DEFW LFEDE ;DIRBF DEFW LE2FF ;DPBLK2 DEFW LF988 ;CHK03 DEFW LFA5F ;ALL03 ; disk parameter header for disk 03 (KAYPRO 2 SSDD) ;DPBAS3 LE291: DEFW 0000H ;TRANS DEFW 0000H DEFW 0000H DEFW 0000H DEFW LFEDE ;DIRBF DEFW LE30E ;DPBLK3 DEFW LF998 ;CHK04 DEFW LFA77 ;ALL04 ; disk parameter header for disk 04 (BONDWELL 12 SSDD) ;DPBAS4 LE2A1: DEFW 0000H ;TRANS DEFW 0000H DEFW 0000H DEFW 0000H DEFW LFEDE ;DIRBF DEFW LE31D ;DPBLK4 DEFW LF9A8 ;CHK05 DEFW LFA90 ;ALL05 ; disk parameter header for disk 05 (XEROX 512 DSDD) ;DPBAS5 LE2B1: DEFW 0000H ;TRANS DEFW 0000H DEFW 0000H DEFW 0000H DEFW LFEDE ;DIRBF DEFW LE32C ;DPBLK5 DEFW LF9D8 ;CHK06 DEFW LFAB0 ;ALL06 ; disk parameter header for disk 07 (SVI-328 DSDD) ;DPBAS7 LE2C1: DEFW 0000H ;TRANS DEFW 0000H DEFW 0000H DEFW 0000H DEFW LFEDE ;DIRBF DEFW LE33B ;DPBLK7 DEFW LF9C8 ;CHK07 DEFW LFA9B ;ALL07 ; disk parameter header for disk 08 (BONDWELL 14 DSDD) ;DPBAS8 LE2D1: DEFW 0000H ;TRANS DEFW 0000H DEFW 0000H DEFW 0000H DEFW LFEDE ;DIRBF DEFW LE34A ;DPBLK8 DEFW LF9F8 ;CHK08 DEFW LFAC6 ;ALL08 ; disk parameter block for disk 06 (XEROX 820 II SSDD) ;DPBLK6 LE2E1: DEFW 0022H ;34 SPT 128 byte logical sectors per track DEFB 03H ;3 BSH block shift factor DEFB 07H ;7 BLM block mask DEFB 00H ;0 EXM null mask DEFW 009CH ;156 DSM disk size in blocks-1 DEFW 003FH ;63 DRM directory max entries DEFB 0C0H ;192 AL0 dir. alloc. mask 0 DEFB 00H ;0 AL1 dir. alloc. mask 1 DEFW 0010H ;16 CKS dir. check size DEFW 0003H ;3 OFF track offset ; disk parameter block for disk 00 - 01 (SVI-738 SSDD) ;DPBLK0 LE2F0: DEFW 0024H ;36 SPT 128 byte logical sectors per track DEFB 04H ;4 BSH block shift factor DEFB 0FH ;15 BLM block mask DEFB 01H ;1 EXM null mask DEFW 00ACH ;172 DSM disk size in blocks - 1 DEFW 003FH ;63 DRM directory max entries DEFB 80H ;128 AL0 dir. alloc. mask 0 DEFB 00H ;0 AL1 dir. alloc. mask 1 DEFW 0010H ;16 CKS dir. check size DEFW 0003H ;3 OFF track offset ; disk parameter block for disk 02 (OSBORNE 1 SSDD) ;DPBLK2 LE2FF: DEFW 0028H ;40 SPT DEFB 03H ;3 BSH DEFB 07H ;7 BLM DEFB 00H ;0 EXM DEFW 00B8H ;184 DSM DEFW 003FH ;63 DRM DEFB 0C0H ;192 AL0 DEFB 00H ;0 AL1 DEFW 0010H ;16 CKS DEFW 0003H ;3 OFF ; disk parameter block for disk 03 (KAYPRO 2 SSDD) ;DPBLK3 LE30E: DEFW 0028H ;40 SPT DEFB 03H ;3 BSH DEFB 07H ;7 BLM DEFB 00H ;0 EXM DEFW 00C2H ;194 DSM DEFW 003FH ;63 DRM DEFB 0C0H ;192 AL0 DEFB 00H ;0 AL1 DEFW 0010H ;16 CKS DEFW 0001H ;1 OFF ; disk parameter block for disk 04 (BONDWELL 12 SSDD) ;DPBLK4 LE31D: DEFW 0024H ;36 SPT DEFB 04H ;4 BSH DEFB 0FH ;15 BLM DEFB 01H ;1 EXM DEFW 0054H ;84 DSM DEFW 007FH ;127 DRM DEFB 0C0H ;192 AL0 DEFB 00H ;0 AL1 DEFW 0020H ;32 CKS DEFW 0002H ;2 OFF ; disk parameter block for disk 05 (XEROX 512 DSDD) ;DPBLK5 LE32C: DEFW 0024H ;36 SPT DEFB 04H ;4 BSH DEFB 0FH ;15 BLM DEFB 01H ;1 EXM DEFW 00AAH ;170 DSM DEFW 007FH ;127 DRM DEFB 0C0H ;192 AL0 DEFB 00H ;0 AL1 DEFW 0020H ;32 CKS DEFW 0002H ;2 OFF ; disk parameter block for disk 07 (SVI-328 DSDD) ;DPBLK7 LE33B: DEFW 0022H ;34 SPT DEFB 04H ;4 BSH DEFB 0FH ;15 BLM DEFB 01H ;1 EXM DEFW 00A2H ;162 DSM DEFW 003FH ;63 DRM DEFB 80H ;128 AL0 DEFB 00H ;0 AL1 DEFW 0010H ;16 CKS DEFW 0003H ;3 OFF ; disk parameter block for disk 08 (BONDWELL 14 DSDD) ;DPBLK8 LE34A: DEFW 0024H ;36 SPT DEFB 04H ;4 BSH DEFB 0FH ;15 BLM DEFB 01H ;1 EXM DEFW 00AEH ;174 DSM DEFW 007FH ;127 DRM DEFB 0C0H ;192 AL0 DEFB 00H ;0 AL1 DEFW 0020H ;32 CKS DEFW 0002H ;2 OFF LE359: DEFS 31 ;unused locations ; patches for the 'DIR' command (40/80 col display) ; the zero flag is set every 2, or 4 directory entries LE378: PUSH DE ;push it like in the CCP PUSH BC ;save BC CALL LE38C ;B=1 or 3 AND B ;set ZF if B=x0B or 00B POP BC ;retrieve BC JP LD0B3 ;end of patch ; the zero flag is set for the 2nd, or 4th entry, so that an extra ; space is not printed (40 or 80 col display) LE382: PUSH AF ;push it like in the CCP PUSH BC ;save BC CALL LE38C ;B=1 or 3 CP B ;ZF set on 2nd or 4th entry POP BC ;retrieve BC JP LD0E8 ;end of patch ; return B=1 for 40 col display, else B=3 LE38C: PUSH AF ;save A LD A,(L0003) ;get IOBYTE AND 03H ;isolate CON: bits CP 01H ;is CRT: active? (40 col) JR Z,LE398 ;jump if yes, else.. LD A,03H ;A=3 LE398: LD B,A ;pass it to B POP AF ;retrieve A RET ;and ret ; unshifted function keys definition data table ; F1 LE39B: DEFB 'DIR',0DH DEFB 00H,00H,00H,00H DEFB 00H,00H,00H,00H DEFB 00H,00H,00H,00H ; F2 LE3AB: DEFB 'STAT CON:=UC1:',0DH DEFB 00H ; F3 LE3BB: DEFB 'STAT' DEFB 00H,00H,00H,00H DEFB 00H,00H,00H,00H DEFB 00H,00H,00H,00H ; F4 LE3CB: DEFB 'EDITFKEY',0DH DEFB 00H,00H,00H,00H DEFB 00H,00H,00H ; F5 LE3DB: DEFB 'FILECOPY',0DH DEFB 00H,00H,00H,00H DEFB 00H,00H,00H ; shifted function keys definition data table ; shifted F1 LE3EB: DEFB 'DIR A:',0DH DEFB 00H,00H,00H,00H DEFB 00H,00H,00H,00H DEFB 00H ; shifted F2 LE3FB: DEFB 'STAT CON:=CRT:',0DH DEFB 00H ; shifted F3 LE40B: DEFB 'STAT *.*',0DH DEFB 00H,00H,00H,00H DEFB 00H,00H,00H ; shifted F4 LE41B: DEFB 'FORMAT',0DH DEFB 00H,00H,00H,00H DEFB 00H,00H,00H,00H DEFB 00H ; shifted F5 LE42B: DEFB 'SYSGEN',0DH DEFB 00H,00H,00H,00H DEFB 00H,00H,00H,00H DEFB 00H ; interrupt handling routine (rst 38H) ; put the SP in a safe place and push main registers LE43B: LD (LF087),SP ;save the SP LD SP,LF0BB ;give it a new value PUSH AF ;save the PUSH BC ;main PUSH DE ;registers PUSH HL ; finish any VDP command in process and reset its interrupt flag IN A,(99H) ;prepare for VDP access ; decrease console bell volume (if it is on) LD A,(LF0BC) ;beeper counter OR A ;is the beeper on? JR Z,LE45B ;skip if not DEC A ;decrement volume LD (LF0BC),A ;store in variable LD A,08H ;select reg 8 OUT (0A0H),A ;channel A volume LD A,(LF0BC) ;get vol from variable OUT (0A1H),A ;out to PSG data register ; this is the typematic interrupt counter ; it is decremented each int until it reaches zero LE45B: LD A,(LF083) ;get the counter value OR A ;is it zero? JR Z,LE465 ;if yes, then do nothing with it DEC A ;else decrement it LD (LF083),A ;store back into variable ; if the drive is active, then skip the motor timing routine LE465: LD A,(LFFFB) ;drive activity flag OR A ;is any drive active? JR NZ,LE481 ;jump if so ; decrement drive idle timer, if zero then turn motor off LD A,(LFFFC) ;get count to turn drive off OR A ;is it zero? JR Z,LE481 ;if yes then jr LE481 DEC A ;dec counter JR NZ,LE47E ;jump if not zero CALL LF049 ;enable disk slot CALL LEF9B ;turn off drive motor CALL LF05A ;disable disk slot XOR A ;A=0 LE47E: LD (LFFFC),A ;store in variable ; scan the kryboard, and display the function key definitions LE481: CALL LE7E8 ;scan kbd and display key definitions OR A ;is a key depressed? LD (LF080),A ;copy k state flag into var JR NZ,LE495 ;jump if a key is pressed LD HL,LF06A ;copy the secondary table LD DE,LF074 ;to a tertiary one (shift LD BC,000AH ;keys included) LDIR ;using LDIR LE495: LD A,(LF0BE) ;get the shift state flag OR A ;is shift depressed? JR NZ,LE4A8 ;jump if it is LD A,(LF0BD) ;shift kept pressed flag OR A ;is shift kept released? JR Z,LE4A8 ;jump if it is XOR A ;signal 'kept released' LD (LF0BD),A ;into variable CALL LF58A ;display key definitions ; check the state of the caps lock key and act accordingly LE4A8: LD A,(LF081) ;all shift keys state AND 08H ;leave only CAPS JR Z,LE4BD ;jump if not pressed LD A,(LF082) ;get the caps kept down flag AND 08H ;mask off unwanted bits JR NZ,LE4BD ;jump if kept down LD A,(LF0C1) ;get CAPS LOCK STATE CPL ;toggle it LD (LF0C1),A ;store back in variable LE4BD: LD A,(LF0C1) ;get caps lock state OR A ;is signaling 'off' JR NZ,LE4C9 ;jump if not IN A,(0AAH) ;PPI port C OR 40H ;turn caps led off JR LE4CD ;continue there LE4C9: IN A,(0AAH) ;PPI port C AND 0BFH ;turn caps led on LE4CD: OUT (0AAH),A ;out to PPI LD A,(LF081) ;get all shift k state LD (LF082),A ;copy to caps kept down ; process any pending job in the printer queue LE4D5: LD A,(LE23E) ;printing job in queue flag OR A ;is there a pending job? JP Z,LE528 ;jump if not LD B,00H ;256 retries LE4DE: IN A,(90H) ;centronics state port RRCA ;move the bit 1 RRCA ;(printer bust) to CF CCF ;CF=0 if printer busy SBC A,A ;A=0 if printer busy JR NZ,LE4EB ;jump if not busy DJNZ LE4DE ;retry one more time JP LE528 ;leave the job for next int LE4EB: LD A,0FFH ;signal 'printer free' LD (LE23F),A ;into variable LD HL,(LE242) ;get queue out pointer NOP ;time delay LD A,L ;get lo byte OUT (99H),A ;out to VDP reg LD A,H ;get high byte RES 6,A ;prepere to read OUT (99H),A ;out to VDP EX (SP),HL ;little EX (SP),HL ;time delay IN A,(98H) ;get byte from queue PUSH AF ;push it OUT (91H),A ;out to the printer XOR A ;active strobe line OUT (90H),A ;out to strobe port DEC A ;release the strobe line OUT (90H),A ;out to same port INC HL ;inc queue out pointer LD A,H ;check if the CP HIGH L39FF ;printer queue out JR NZ,LE517 ;pointer reached LD A,L ;39FFH CP LOW L39FF ;if not JR NZ,LE517 ;then jump, else LD HL,L1900 ;make the pointer = 1900H LE517: LD (LE242),HL ;copy it to the variable CALL LEB43 ;compare in and out pointers LD (LE23E),A ;if equal, signal 'job done' POP AF ;retrieve the just printed chr LD C,A ;copy it to C SUB 20H ;was it a control chr? JR C,LE528 ;jump if not JR LE4D5 ;else process next chr ; set the VRAM access register to the range 0000H-4000H LE528: LD A,00H ;value for the 0-4000H range OUT (99H),A ;send it to VDP LD A,8EH ;register 0E OUT (99H),A ;out to VDP ; retrieve the previously saved registers, the SP, enable ints and RETI POP HL ;retrieve POP DE ;the main POP BC ;registers POP AF LD SP,(LF087) ;and the SP itself EI ;allow ints RETI ;ret from interrupt ; initial PSG regiter data LE53B: DEFB 00H ;reg 0 (fine freq channel A) \ DEFB 80H ;128 | DEFB 01H ;reg 1 (frequency channel A) > 875 hz DEFB 00H ;0*256 / DEFB 07H ;reg 7 (mixer control) DEFB 0FEH ;activate channel A only DEFB 08H ;reg 8 (volume channel A) DEFB 00H ;silence ; Cold boot -- entered from CP/M bootstrap loader. ;BOOT LE543: DI ;disable ints XOR A ;signal 'update BDOS LD (LE23D),A ;entry point' in PSP DEC A ;A = 0FFH OUT (52H),A ;??? LD SP,LCBFE ;put the SP here LD A,55H ;set all RAM OUT (0A8H),A ;mem slt reg PPI port A LD A,0FFH ;disk slot LD (LFFFA),A ;(bits 2 & 3) LD A,55H ;signal 'all ram' LD (LFFFD),A ;into variable LD A,81H ;initial IOBYTE value LD (LFFF0),A ;put into variable IN A,(0AAH) ;PPI port C kbd & cass OR 40H ;turn off CAPS led OUT (0AAH),A ;keyboard and cassette LD A,(LFFFD) ;all ram, again OUT (0A8H),A ;PPI port A ; initialize the psg registers for the console beeper ; on channel A at about 875 Hz LD B,04H ;four registers LD HL,LE53B ;table start LE571: LD A,(HL) ;get reg addr from table OUT (0A0H),A ;PSG reg select INC HL ;inc pointer LD A,(HL) ;get register value OUT (0A1H),A ;PSG data write INC HL ;increment pointer DJNZ LE571 ;process next value ; initialise the VDP and enable disk slot CALL LF54D ;initialise the VDP CALL LF049 ;enable disk slot ; check for the presence of a second disk drive LD A,02H ;select drive 1 LD (L7FBC),A ;drive select port CALL LF03E ;wait until fdc is free LD A,00H ;'restore' command LD (L7FB8),A ;FDC command port EX (SP),HL ;little EX (SP),HL ;time delay LD HL,0000H ;65536 retries LE593: LD A,(L7FB8) ;FDC status port RRA ;move bit 0 into CF JR NC,LE5A2 ;jump if not busy DEC HL ;dec the retry counter LD A,L ;check if OR H ;it is zero JR NZ,LE593 ;if not, try again LD A,20H ;sign drive 1 not present JR LE5A4 ;jump to LE5A4 LE5A2: LD A,00H ;signal drive 1 present LE5A4: LD (LF0CA),A ;put the result in variable ; turn off all drives and disable disk slot (page in all ram) XOR A ;turn all drives off LD (L7FBC),A ;drive select port CALL LF05A ;disable disk slot ; load the CCP and BDOS and set the IOBYTE initial value CALL LE619 ;read CCP and BDOS from disk LD A,(LFFF0) ;get initial IOBYTE LD (L0003),A ;put it into the true IOBYTE ; display the copyright message and set default drive/user LD C,09H ;print string LD DE,LF0F1 ;copyright message CALL L0005 ;BDOS LD A,00H ;set A: and user 0 LD (L0004),A ;as current disk ; initialise RS232, pass the default drive to C and jump to CCP PUSH AF ;save current disk CALL LE5DB ;initialise RS232 POP AF ;retrieve current disk LD C,A ;pass it to C JP LCC00 ;jump to CCP ; Warm boot -- entered by jumping to location 0000H. ;WBOOT LE5CD: DI ;no ints allowed LD SP,LCBFE ;put the SP in a safe place CALL LE619 ;read CCP and BDOS from disk LD A,(L0004) ;pass the actual disk and LD C,A ;user to C JP LCC00 ;jump to CCP ; set the serial interface to 300 8 O 2 LE5DB: LD A,0FFH ;disable all kind of ints OUT (82H),A ;RS232 int mask register LD A,36H ;timer 0 ctl (rx clock) OUT (87H),A ;8253 ctl port LD HL,0180H ;constant for 4800 baud LD A,L ;send low byte OUT (84H),A ;to timer 0 LD A,H ;send high byte OUT (84H),A ;to timer 0 LD A,76H ;timer 1 ctl (tx clock) OUT (87H),A ;8253 ctl port LD A,L ;send low byte OUT (85H),A ;to timer 1 LD A,H ;and high byte OUT (85H),A ;to timer 1 LD A,0B0H ;timer 2 ctl (utl timer) OUT (87H),A ;8253 ctl port XOR A ;make sure the 8251 OUT (81H),A ;is in command mode OUT (81H),A ;sync mode OUT (81H),A ;dummy write OUT (81H),A ;dummy write OUT (81H),A ;dummy write INC A ;A=1 OUT (88H),A ;modem enable LD A,40H ;software reset OUT (81H),A ;8251 command reg LD A,0DEH ;8 O 2 1/16 OUT (81H),A ;8251 command reg LD A,10H ;reset error flags OUT (81H),A ;8251 command reg LD A,27H ;set dtr tx and rx OUT (81H),A ;8251 command reg RET ;ret ; load the CCP and BDOS into memory LE619: LD A,(LE23D) ;is the RST 38 entry OR A ;point to be updated? JR NZ,LE62D ;skip if not LD A,0C3H ;put a JP opcode LD (0038H),A ;in the RST 38 location LD HL,LE43B ;int handling routine address LD (0039H),HL ;put it as a JP argument LD (0038H),A ;and the opcode again LE62D: LD A,(LF0DE) ;get hstwrt OR A ;is a write job pending? JR Z,LE63A ;skip if not CALL LED9E ;finish it XOR A ;signal 'not writing' LD (LF0DE),A ;into the variable LE63A: LD A,0BH ;11 sectors to read LD (LF0EA),A ;put in variable LD A,01H ;from track 1 LD (LF0DA),A ;hsttrk host trk nmbr LD A,07H ;sector 7 LD (LF0D9),A ;hstsec host sec nmbr CALL LF049 ;enable disk slot LD A,(LF0D7) ;get current host disk PUSH AF ;push it LD A,(LF0CA) ;check if a 2nd drive OR A ;is present JR NZ,LE678 ;if not then jr E678 ; check for a 2nd drive presence but discard the result LD A,0D0H ;forced interrupt LD (L7FB8),A ;fdc command register LD A,02H ;select drive 1 LD (L7FBC),A ;drive ctrl register CALL LF03E ;wait till fdc is not busy LD A,00H ;restore LD (L7FB8),A ;fdc command register EX (SP),HL ;little EX (SP),HL ;time delay LD HL,0000H ;65536 retries LE66D: LD A,(L7FB8) ;fdc status register RRA ;move bit 0 to carry JR NC,LE678 ;jump if not busy DEC HL ;decrement the retry counter LD A,L ;check if OR H ;it is zero JR NZ,LE66D ;if not then retry LE678: XOR A ;present or not the 2nd drive LD (LF0D7),A ;this var is always set to zero (host drive 0) ; read the system sectors to 0CC00H CALL LEF3E ;activate the drive CALL LEFA7 ;move head to track 00 CALL LF05A ;disable disk slot XOR A ;signal track 00 LD (LF0F0),A ;for drive 1 LD (LF0EF),A ;and drive 0 LD DE,LCC00 ;destination address (CCP) LE68F: PUSH DE ;save dest address CALL LEE8D ;read host sect into buffer POP DE ;retrieve destination address LD HL,(LF0CE) ;host disk buffer LD BC,0200H ;512 bytes LDIR ;copy the code to destination place LD A,(LF0EA) ;decrement the DEC A ;'sectors to read' LD (LF0EA),A ;counter JR Z,LE6BE ;jump if no more sectors LD A,(LF0D9) ;get host sector INC A ;increment it LD (LF0D9),A ;back to variable CP 09H ;was it the ninth sector? JR NZ,LE68F ;if not then process next LD A,00H ;else point to first one LD (LF0D9),A ;put it into variable LD A,(LF0DA) ;and increment INC A ;the track number LD (LF0DA),A ;put into variable JR LE68F ;process next sector ; once the system tracks are loaded, some pointers are updated and the ; internal command 'DIR' is patched for 40/80 column display LE6BE: POP AF ;pop current host disk LD (LF0D7),A ;put into variable LD A,0C3H ;put a jp opcode LD (0000H),A ;at PSP warm boot entry LD (0005H),A ;at PSP bdos entry LD (0D0B0H),A ;patch the 'DIR' command to LD (0D0E5H),A ;handle 40/80 col correctly LD HL,LE203 ;BIOS warm start address LD (0001H),HL ;put in PSP LD A,(LE23D) ;is the BDOS entry OR A ;to be updated? JR NZ,LE6E2 ;skip if not LD HL,LD406 ;BDOS entry point LD (0006H),HL ;put in PSP LE6E2: LD HL,LE378 ;address of first patch LD (0D0B1H),HL ;poke it into CCP LD HL,LE382 ;address of the 2nd patch LD (0D0E6H),HL ;poke it into CCP XOR A ;A=00 LD (LF0DD),A ;clear the host active flag LD (LF0DF),A ;unaloct'd record counter RET ;ret ; Console status -- returns A = 0FFH if there is a ; console keyboard character waiting ;CONST LE6F6: LD A,I ;get the int status PUSH AF ;save the flag DI ;disable interrupts CALL LE700 ;execute CONST routine JP LEC33 ;restore int status LE700: LD A,(L0003) ;get IOBYTE AND 03H ;isolate CON: bits CP 02H ;is it UR1: JP Z,LE72A ;if yes check RS232 LD A,(LF084) ;functn in process flag OR A ;is a functn in process? JR NZ,LE727 ;if yes signal key available LD A,(LF080) ;kstate flag OR A ;is a key being pressed? JR Z,LE723 ;jump if not CALL LE857 ;decode the key position CP 0FFH ;is any key value available? JR NZ,LE727 ;jump if yes LD A,(LF083) ;get the typematic counter OR A ;is it zero? JR Z,LE727 ;if yes, signal key available LE723: LD A,00H ;signal 'no key available' JR LE729 ;ret LE727: LD A,0FFH ;signal 'key available to be read' LE729: RET ;ret ; check if there is a received byte available LE72A: IN A,(81H) ;8251 command port AND 02H ;RX ready bit JR NZ,LE727 ;signal 'byte received' JR LE723 ;or 'not received' ; Console input -- returns the next console keyboard ; character in A ;CONIN LE732: LD A,I ;get the int status PUSH AF ;save the flag DI ;disable interrupts CALL LE73C ;exec the CONIN routine JP LEC33 ;restore int status LE73C: LD A,(L0003) ;get IOBYTE AND 03H ;isolate CON: bits CP 02H ;is it UR1: JP Z,LEB62 ;goto READER (UR1:) LD A,(LF084) ;is any function key OR A ;in process? JP NZ,LE7CD ;jump if yes LE74D: EI ;enable ints to NOP ;allow the keyboard NOP ;scan DI ;disable ints CALL LE84B ;check for key depression OR A ;is a key depressed? JR Z,LE74D ;loop back if not CALL LE857 ;decode the key position CP 0FFH ;is any key decoded? JR NZ,LE781 ;jump if yes LD A,(LF083) ;get the typematic counter OR A ;is it zero? JR NZ,LE74D ;loop back if not LD A,06H ;set to 120 ms key repet LD (LF083),A ;the typematic counter ; decode the key position (row * 8 + col) LD HL,LF06A-1 ;secondary keyboard table -1 LD C,0AH ;ten elements LE76E: INC HL ;increment pointer DEC C ;decrement counter LD A,(HL) ;get row data OR A ;is any key depressed? JR Z,LE76E ;loop back if not SLA C ;multiply the SLA C ;row value SLA C ;by eight LE77A: RR A ;search for a set bit JR C,LE787 ;jump if found INC C ;increment key value JR LE77A ;loop back LE781: LD C,A ;key position to C LD A,28H ;40 ints initial delay LD (LF083),A ;typematic counter LE787: LD A,(LF081) ;get the all shift key state AND 03H ;leave only shift & ctrl JR Z,LE7B5 ;jump if none pressed AND 02H ;leave only ctrl JR Z,LE794 ;jump if not pressed (shift) ADD A,4EH ;add ctrl offset -2 LE794: ADD A,50H ;add shift offset LE796: ADD A,C ;add key position to A LD B,00H ;high byte = 00 LD C,A ;key position to C LD HL,LF169 ;key table start ADD HL,BC ;add position to table start LD A,(HL) ;get key ascii value LD (LF07E),A ;store in variable LD HL,LF06A ;secondary table LD DE,LF074 ;tertiary table LD BC,000AH ;ten elements LDIR ;copy the table LD A,(LF07E) ;get key value CP 80H ;has its bit 7 set? JR NC,LE7D2 ;jump if yes RET ;else ret LE7B5: LD A,(LF0C1) ;caps lock state OR A ;is it off? JR Z,LE796 ;jump if yes (unshifted) LD A,C ;key position to A JP LF259 ;process capsed keys ; treat the non alphabetic keys as unshifted LE7BF: CP 16H ;this is 'A' JR C,LE7CA ;unsifted if less than CP 30H ;this is 'Z'+1 JR NC,LE7CA ;unshifted if greater or equal LE7C7: XOR A ;make A=0 JR LE794 ;process as shifted LE7CA: XOR A ;make A=0 JR LE796 ;process as unshifted LE7CD: LD HL,(LF085) ;get function table pointer JR LE7DD ;process next byte ; a function key was obtained from table LE7D2: ADD A,A ;multiply ADD A,A ;the key value ADD A,A ;by 16 dec ADD A,A ;bit 7 is lost LD C,A ;copy result in C LD B,00H ;high byte = 0 LD HL,LE39B ;function key definition table ADD HL,BC ;access the proper function LE7DD: LD C,(HL) ;get byte from function table INC HL ;increment pointer LD A,(HL) ;get the next byte as a flag LD (LF085),HL ;save pointer into variable LD (LF084),A ;put the 'flag' into variable LD A,C ;copy current byte to A RET ;ret ; scan the keyboard three times if no key chaged state, else do it ; for more times, leave the result in a 10 element table at LF060 LE7E8: LD A,03H ;scan 3 times to avoid key bounces JR LE7EF ;jr to keyboard scaning routine LE7EC: LD (HL),A ;update secondary table LD A,04H ;four more scannings LE7EF: LD (LF07F),A ;update keyboard scan counter LE7F2: LD HL,LF060 ;keyboard row state table LD C,09H ;ten kbd rows to scan IN A,(0AAH) ;get current kbd row,etc PUSH AF ;save it LE7FA: IN A,(0AAH) ;get kbd row sel, led... AND 0F0H ;mask off kbd row OR C ;add current row OUT (0AAH),A ;select it NOP ;little NOP ;time delay IN A,(0A9H) ;get kbd column CPL ;complement byte LD (HL),A ;store in table INC HL ;inc table pointer DEC C ;one row less to scan JP P,LE7FA ;loop till 9 rows done POP AF ;get previous state OUT (0AAH),A ;out back to register ; compare both tables for key state changes LD DE,LF060 ;kbd row primary table LD HL,LF06A ;kbd row secondary table LD B,0AH ;ten elements LE817: LD A,(DE) ;get byte from primary table CP (HL) ;compare with secondary JP NZ,LE7EC ;if not equal scan kbd 4 more times INC HL ;inc secondary table pointer INC DE ;inc primary table pointer DJNZ LE817 ;loop till ten rows processed ; check if all the keyboard scanings were completed LD A,(LF07F) ;get the kbd scan counter DEC A ;decrement it LD (LF07F),A ;and save back into variable JR NZ,LE7F2 ;jump if not zero ; if SHIFT is pressed then refresh the key definition messages LD A,(LF063) ;get row 6 AND 01H ;leave only SHIFT state LD (LF0BE),A ;save into variable JR Z,LE840 ;jump if not pressed LD A,(LF0BD) ;SHIFT kept down flag OR A ;is shift kept down? JR NZ,LE840 ;if yes then skip INC A ;signal 'SHIFT kept down' LD (LF0BD),A ;save back into variable CALL LF58A ;display key definitions LE840: LD A,(LF06D) ;secondary table row 6 LD (LF081),A ;put it into a variable AND 0E0H ;mask off shift keys LD (LF06D),A ;store back in table ; scan the secondary table for a key depressed, if found, A <> 0 LE84B: LD HL,LF06A ;keyboard row secondary table LD B,0AH ;ten elements LE850: LD A,(HL) ;get byte from table OR A ;is a key depressed? RET NZ ;jump if so with A <> 0 INC HL ;inc table pointer DJNZ LE850 ;process next table element RET ;ret with A = 0 (no key) ; decode the key position (row * 8 + col) LE857: LD HL,LF06A ;kbd row secondary table LD DE,LF074 ;kbd row tertiary table LD C,09H ;ten elements LE85F: LD A,(DE) ;get row data XOR (HL) ;if all bits are equal JR Z,LE866 ;then no key depressed AND (HL) ;was it a key release? JR NZ,LE877 ;jump if not LE866: INC HL ;increnent INC DE ;both pointers DEC C ;dec row counter JP P,LE85F ;jp back if not under zero DEC HL ;decrement pointers DEC DE ;to compensate LD BC,000AH ;ten table elements LDDR ;copy to tertiary table LD C,0FFH ;signal 'no key pressed' LE875: LD A,C ;into A and C registers RET ;ret ; multiply row by 8 and add the column position (key bit set) LE877: SLA C ;multiply SLA C ;the row value SLA C ;by eight LE87D: RR A ;look for a set bit JR C,LE875 ;copy C to A and ret INC C ;inc key value JR LE87D ;loop back to find a bit set ; Console output -- outputs the character in C to ; the console device ;CONOUT LE884: LD A,I ;get the int status PUSH AF ;save the flag DI ;disable ints LD (LF087),SP ;save the SP in a var LD SP,LF0BB ;give to SP a new value CALL LE899 ;execute CONOUT LD SP,(LF087) ;retrieve SP JP LEC33 ;restore int status LE899: LD A,(L0003) ;get IOBYTE AND 03H ;isolate CON: bits CP 01H ;is it CRT:? JP Z,LE8AB ;jump if yes CP 02H ;is it LST:? JP Z,LEAE3 ;jump if yes LE8A8: JP LF263 ;it is 00 or 03 (UC1:) ; CRT: 40 column display LE8AB: LD A,(LF0C5) ;is the 40 col display OR A ;initialized? JR Z,LE8B8 ;skip if yes CALL LF54D ;initialize the 40 col display XOR A ;signal '40 col init'd' LD (LF0C5),A ;into variable LE8B8: LD A,01H ;signal '80 col not init'd' LD (LF0C6),A ;into variable CALL LEA52 ;calculate vram address LD DE,04000H ;signal 'write to vram' ADD HL,DE ;add the flag LD A,L ;get vram addr lo OUT (99H),A ;out to vdp LD A,H ;get high byte OUT (99H),A ;out to vdp LD A,(LF0C4) ;get chr under the cursor EX (SP),HL ;little EX (SP),HL ;time delay OUT (98H),A ;print the chr LD A,(LF0BF) ;escape in process flag OR A ;escape seq in process? JP NZ,LEA6F ;jump if yes LD A,C ;get the byte to be printed CP 20H ;'SPACE' JR C,LE90F ;jump if a ctrl code CALL LEA3F ;print the character CALL LE9F4 ;update coordinates LE8E3: XOR A ;A=0 LD (LF0BF),A ;no esc seq in process LD (LF0C0),A ;no ESC Y argument LE8EA: CALL LEA52 ;calc new vram address LD DE,0000H ;signal 'read from vram' ADD HL,DE ;add the flag LD A,L ;get vram address lo OUT (99H),A ;out to vdp LD A,H ;get vram address hi OUT (99H),A ;out to vdp EX (SP),HL ;little EX (SP),HL ;time delay IN A,(98H) ;get the new chr under cursor LD (LF0C4),A ;put into variable LD DE,4000H ;signal 'write to vram' ADD HL,DE ;add the flag LD A,L ;get vram address hi OUT (99H),A ;out to vdp LD A,H ;get vram address lo OUT (99H),A ;out to vdp LD A,0DBH ;cursor character EX (SP),HL ;little EX (SP),HL ;time delay OUT (98H),A ;print the cursor RET ;ret ; process the 40 col control codes LE90F: CP 07H ;is it BELL? JP Z,LE946 ;jump if yes CP 08H ;is it BACK SPACE? JR Z,LE951 ;jump if yes CP 09H ;is it TAB? JR Z,LE95B ;jump if yes CP 0AH ;is it LINE FEED? JR Z,LE967 ;jump if yes CP 0BH ;is it HOME JR Z,LE979 ;jump if yes CP 0CH ;is it CLS? JR Z,LE985 ;jump if yes CP 0DH ;is it ENTER? JR Z,LE97E ;jump if yes CP 1BH ;is it ESC? JR Z,LE9A3 ;jump if yes CP 1CH ;is it CURSOR RIGHT? JP Z,LE9CC ;jump if yes CP 1DH ;is it CURSOR LEFT? JP Z,LE9C2 ;jump if yes CP 1EH ;is it CURSOR UP? JP Z,LE9AB ;jump if yes CP 1FH ;is it CURSOR DOWN? JP Z,LE9B5 ;jump if yes JR LE8EA ;if none, prnt crsr ; bell ^g ; ring the console bell print the cursor and ret LE946: CALL LE94B ;ring the console bell JR LE8E3 ;prnt the crsr and ret ; ring the bell (off within 16 interrupts) LE94B: LD A,10H ;set initial bell vol & int cnt LD (LF0BC),A ;ring the bell RET ; backspace ^h ; calculate coords after backspace and print a space LE951: CALL LE9DA ;update coords LD C,20H ;SPACE CALL LEA3F ;print it JR LE9D7 ;print cursor and ret ; tab ^i ; move col to a position multiple of 8 LE95B: CALL LE9F4 ;update coordinates LD A,(LF0C2) ;column + 32 AND 07H ;leave only bits 2,1&0 JR NZ,LE95B ;loop back until bits=0 JR LE9D7 ;print cursor and ret ; line feed ^j ; increment line position and make a scroll if necesary LE967: LD A,(LF0C3) ;line +32 CP 37H ;is it line 23? JR NZ,LE973 ;jump if not CALL LEA18 ;screoll up JR LE9D7 ;print csr and ret ; increment line position update variable print cursor and ret LE973: INC A ;increment line LD (LF0C3),A ;put into variable JR LE9D7 ;print crsr and ret ; home ^k ; move the print position to the upper left corner LE979: LD A,20H ;line 0 LD (LF0C3),A ;put into variable ; enter ^m ; move the cursor to column 0 LE97E: LD A,20H ;column 0 LD (LF0C2),A ;put into variable JR LE9D7 ;print crsr and ret ; cls ^l ; clear the screen move the print position to home LE985: CALL LE98A ;clear the screen JR LE979 ;home the cursor and ret ; fill 1000dec bytes with 20h's (spaces) from 0000H in vram (cls) LE98A: LD DE,4000H ;vram address + write flag LD BC,03E8H ;1000 in decimal LE990: LD A,E ;start address lo OUT (99H),A ;out to VDP LD A,D ;start address hi OUT (99H),A ;out to VDP LD A,20H ;'SPACE' EX (SP),HL ;little EX (SP),HL ;time delay OUT (98H),A ;vpoke the 'space' INC DE ;increment pointer DEC BC ;decrement counter LD A,B ;check if counter OR C ;reaches zero JR NZ,LE990 ;if not then loop back RET ;else return ; escape LE9A3: LD A,01H ;ESC seq in process LD (LF0BF),A ;put into variable JP LE8EA ;print cursor and ret ; cursor up LE9AB: LD A,(LF0C3) ;line position +32 CP 20H ;is it line 0? JR Z,LE9D7 ;if yes do nothing DEC A ;decrement line JR LE9BD ;update variable print cursor ; cursor down LE9B5: LD A,(LF0C3) ;line position +32 CP 37H ;is it line 23? JR Z,LE9D7 ;if yes do nothing INC A ;increment line LE9BD: LD (LF0C3),A ;put into variable JR LE9D7 ;print crsr and ret ; cursor left LE9C2: LD A,(LF0C2) ;column position +32 CP 20H ;is it col 0? JR Z,LE9D7 ;if yes do nothing DEC A ;decrement column JR LE9D4 ;upd var print crsr ; cursor right LE9CC: LD A,(LF0C2) ;column position +32 CP 46H ;is it col 38? JR Z,LE9D7 ;if yes then do nothing INC A ;increment column LE9D4: LD (LF0C2),A ;put into variable LE9D7: JP LE8E3 ;print crsr and ret ; calculate mew coordinates after a backspace character LE9DA: LD A,(LF0C2) ;column position +32 CP 20H ;is it col 0? JR Z,LE9E4 ;jump if yes DEC A ;decremrnt column JR LE9F0 ;update var and ret LE9E4: LD A,(LF0C3) ;line position +32 CP 20H ;is it line 0? RET Z ;if yes then do nothing DEC A ;decrement line position LD (LF0C3),A ;put into variable LD A,46H ;point to column 38 LE9F0: LD (LF0C2),A ;put into variable RET ; update line and column position and make a scroll if necesary LE9F4: LD A,(LF0C2) ;column position + 32 CP 46H ;is it col 38? JR Z,LE9FE ;jump if yes INC A ;increment column JR LEA0B ;continue in LEA0B LE9FE: LD A,(LF0C3) ;line position + 32 CP 37H ;is it line 23? JR Z,LEA0F ;jump if yes INC A ;increment line LD (LF0C3),A ;put into variable LD A,20H ;point to column 0 LEA0B: LD (LF0C2),A ;put into variable RET ;ret ; make a scroll and point to col 0 LEA0F: CALL LEA18 ;scroll up LD A,20H ;point to column 0 LD (LF0C2),A ;put into variable RET ;ret ; scroll up one line the 40 col screen LEA18: LD HL,00028H ;41th chr addr + rd flag LD DE,04000H ;vram start + wr flag LD BC,003C0H ;960 characters (40x24) LEA21: LD A,L ;pass the address of OUT (99H),A ;the character LD A,H ;to be read OUT (99H),A ;to the VDP EX (SP),HL ;little EX (SP),HL ;time delay IN A,(98H) ;vpeek the character PUSH AF ;push it LD A,E ;pass the address of OUT (99H),A ;the character LD A,D ;to be write OUT (99H),A ;to the VDP POP AF ;pop the character EX (SP),HL ;little EX (SP),HL ;time delay OUT (98H),A ;vpoke the character INC HL ;increment the read ptr INC DE ;and the write ptr DEC BC ;dec the byte count LD A,B ;check if the OR C ;byte count is zero JR NZ,LEA21 ;loop back if not RET ;else ret ; print the character in C on the 40 col screen LEA3F: CALL LEA52 ;calculate vram address LD DE,04000H ;signal write to vram ADD HL,DE ;add the flag LD A,L ;get vram address lo OUT (99H),A ;out to vdp LD A,H ;get vram address hi OUT (99H),A ;out to vdp LD A,C ;get the chr to print EX (SP),HL ;little EX (SP),HL ;time delay OUT (98H),A ;print it RET ;ret ; given the coordinates calculate vram address (40 col) LEA52: LD A,(LF0C3) ;line position + 32 SUB 20H ;substract the offset LD HL,0000H ;initial vram address LD DE,0028H ;40 columns CP 00H ;is it line 0? JR Z,LEA65 ;jump if yes LEA61: ADD HL,DE ;add 40 for each line DEC A ;decrement line couter JR NZ,LEA61 ;loop until A=0 LEA65: LD A,(LF0C2) ;column position + 31 SUB 1FH ;substract the offset LD E,A ;pass the result to E LD D,00H ;high byte = 0 ADD HL,DE ;add the column RET ;ret ; process the ESCAPE sequences LEA6F: LD A,(LF0C0) ;esc argument number CP 01H ;is it first argument? JP Z,LEAAF ;jump if yes CP 02H ;is it second argument? JP Z,LEAC7 ;jump if yes LD A,C ;get the character CP 'j' ;ESC j = cls JP Z,LE985 ;clear the screen CP 'E' ;ESC E = cls JP Z,LE985 ;clear the screen CP 'Y' ;ESC Y = set line,col JP Z,LEAA8 ;set line and col CP 'A' ;ESC A = cursor up JP Z,LE9AB ;move crsr one line up CP 'B' ;ESC B = cursor down JP Z,LE9B5 ;move crsr one line down CP 'C' ;ESC C = cursor right JP Z,LE9CC ;move crsr one col right CP 'D' ;ESC D = cursor left JP Z,LE9C2 ;move crsr one col left CP 'H' ;ESC H = home JP Z,LE979 ;crsr to up left corner JP LE8E3 ;if none then ret ; process ESC Y set line and colunm ; signal first argument, print cursor and ret LEAA8: LD A,01H ;signal '1st argument' LD (LF0C0),A ;into variable JR LEAC4 ;print crsr and ret ; process first argument of ESC Y (40 col) LEAAF: LD A,C ;get the character CP 20H ;is it line 0? JR NC,LEAB6 ;jump if gr or eq LD A,20H ;signal 'line 0' LEAB6: CP 38H ;is it line 24? JR C,LEABC ;jump if less LD A,37H ;signal line 23 LEABC: LD (LF0C3),A ;put into variable LD A,02H ;signal '2nd argument' LD (LF0C0),A ;into the variable LEAC4: JP LE8EA ;print crsr and ret ; process second argument of ESC Y (40 col) LEAC7: LD A,C ;get the character CP 20H ;is it col 0? JR NC,LEACE ;jump if greater or equal LD A,20H ;signal col 0 LEACE: CP 47H ;is it col 39? JR C,LEAD4 ;jump if less LD A,46H ;signal 'col 38' LEAD4: LD (LF0C2),A ;put into variable JP LE8E3 ;end of esc sequence ; List output -- outputs the character in C to the ; list device ;LIST LEADA: LD A,I ;get the IFF state PUSH AF ;push the int flag CALL LEAE3 ;exec the LIST routine JP LEC33 ;restore the INT status LEAE3: LD A,(L0003) ;get iobyte AND 0C0H ;isolate the LST: bits JP Z,LF263 ;if UC1: jump to 80 col CP 40H ;is it CRT:? JP Z,LE8AB ;if yes jump to 40 col CP 0C0H ;is it UP1:? JP Z,LEB37 ;out to RS232 interface ; LST: output the byte in C to the printer queue in VRAM ; pending interrupt processing LEAF5: PUSH BC ;save BC EI ;enable interrupts NOP ;to process any pending NOP ;printer job DI ;disable ints POP BC ;retrieve BC ; check printer status flag and wait until the printer is free LEAFB: LD A,(LE23F) ;get printer status OR A ;is it busy? JR Z,LEAF5 ;jump back if yes LD A,0FFH ;signal 'pending job' LD (LE23E),A ;in the variable LD HL,(LE240) ;get queue input ptr ; vpoke the character in C into the printer queue buffer NOP ;just a nop LD A,L ;queue pointer lo OUT (99H),A ;out to the VDP LD A,H ;queue pointer hi SET 6,A ;signal 'write operation' OUT (99H),A ;out to the VDP LD A,C ;byte to lprint to A EX (SP),HL ;time EX (SP),HL ;delay OUT (98H),A ;vpoke the byte INC HL ;increment pointer LD A,H ;pointer hi to A CP HIGH L39FF ;has it reached 39XX? JR NZ,LEB25 ;skip if not LD A,L ;pointer lo to A CP LOW L39FF ;has it reached 39FF? JR NZ,LEB25 ;skip if not LD HL,L1900 ;make the pointer = 1900H LEB25: LD (LE240),HL ;poke into variable CALL LEB43 ;compare in and out pointers LD (LE23F),A ;if equal signal printer busy LD A,00H ;select status reg 00 OUT (99H),A ;out to VDP LD A,8EH ;register 15 OUT (99H),A ;out to VDP RET ;ret ; output the byte in C to the RS232 interface with bit 7 reset LEB37: IN A,(81H) ;8251 status port AND 01H ;TX ready bit JR Z,LEB37 ;loop until tx is ready LD A,C ;byte to be TXed -> A RES 7,A ;reset bit 7 OUT (80H),A ;xmit the byte RET ;ret ; compare both printer queue pointers ; A=0 if both pointers are equal LEB43: LD HL,(LE240) ;get the input pointer LD B,H ;copy it LD C,L ;to BC LD HL,(LE242) ;get the output pointer OR A ;reset the carry flag SBC HL,BC ;substract both pointers LD A,H ;check if OR L ;the result is zero RET ;ret ; Returns A = 0FFH if the list device can accept ; another output character ;LISTST LEB51: LD A,(L0003) ;get IOBYTE AND 0C0H ;leave only LST: CP 80H ;is centronics active? JR Z,LEB5C ;jump if yes XOR A ;else signal 'not ready' RET ;ret LEB5C: LD A,(LE23F) ;get printer status RET ;ret ; the punch output always point to the RS232 interface (UP1:) ;PUNCH LEB60: JR LEB37 ;out to RS232 ; the reader input always point to the RS232 interface (UR1:) ;READER LEB62: CALL LE72A ;is a byte available? JR Z,LEB62 ;if not then wait IN A,(80H) ;else get the byte RES 7,A ;reset bit 7 RET ;and ret ; Homes the currently selected disk to track 0 ;HOME LEB6C: LD A,(LF0DE) ;write pending flag OR A ;check for pending write JR NZ,LEB75 ; LD (LF0DD),A ;clear host active flag LEB75: RET ; select disk given by register C ; in a memory wasting way ;SELDSK LEB76: LD A,C ;disk number to A LD (LF0D1),A ;and to the variable LD A,(LF0D7) ;three CP C ;useless JR Z,LEB80 ;instructions LEB80: LD A,(LF0D1) ;retrieve dsk number LD C,A ;put it back to C OR A ;is it 00 JR NZ,LEB8F ;jump if not LD HL,LE251 ;DPH for disk 00 LEB8A: LD A,C ;copy the valid disk LD (LF0D3),A ;number into variable RET ;ret LEB8F: LD A,C ;disk number to A CP 01H ;is it 01? JR NZ,LEB9D ;jump if not LD HL,LE261 ;DPH for disk 01 JR LEB8A ;update var and ret LD (LF0D3),A ;two useless RET ;instructions LEB9D: CP 02H ;is it 02? JR NZ,LEBA6 ;jump if not LD HL,LE281 ;DPH for disk 02 JR LEB8A ;update var and ret LEBA6: CP 03H ;is it 03? JR NZ,LEBAF ;jump if not LD HL,LE291 ;DPH for disk 03 JR LEB8A ;update var and ret LEBAF: CP 04H ;is it 04? JR NZ,LEBB8 ;jump if not LD HL,LE2A1 ;DPH for disk 04 JR LEB8A ;update var and ret LEBB8: CP 05H ;is it 05? JR NZ,LEBC1 ;jump if not LD HL,LE2B1 ;DPH for disk 05 JR LEB8A ;update var and ret LEBC1: CP 06H ;is it 06? JR NZ,LEBCA ;jump if not LD HL,LE271 ;DPH for disk 06 JR LEB8A ;update var and ret LEBCA: CP 07H ;is it 07? JR NZ,LEBD3 ;jump if not LD HL,LE2C1 ;DPH for disk 07 JR LEB8A ;update var and ret LEBD3: CP 08H ;is it 08? JR NZ,LEBDC ;jump if not LD HL,LE2D1 ;DPH for disk 08 JR LEB8A ;update var and ret LEBDC: LD HL,L0000 ;signal 'invalid disk' RET ;ret ; set track address for subsequent read/write given by BC ;SETTRK LEBE0: LD H,B ;transfer the track LD L,C ;number to HL LD (LF0D4),HL ;then to the variable RET ;ret ; set sector address for subsequent read/write given by C ;SETSEC LEBE6: INC BC ;xlate logical to LD A,C ;phisical sector LD (LF0D6),A ;store into variable RET ;ret ;set disk DMA address given by BC ;SETDMA LEBEC: LD (LF0E8),BC ;copy BC to the RET ;transfer address ; translate the sector given by BC just incrementing it ; the phisical is returned in HL ;SECTRAN LEBF1: LD H,B ;pass the logical LD L,C ;sector to HL INC HL ;convert to phisical RET ;ret ; Reads the previously specified track and sector from ; the selected disk into the DMA address ;READ LEBF5: LD A,I ;get the int status PUSH AF ;save the flag DI ;disable interrupts LD (LF087),SP ;save SP in a variable LD SP,LF0BB ;give a new value to SP CALL LEC0A ;execute READ LD SP,(LF087) ;restore SP JP LEC33 ;restore int status LEC0A: CALL LED54 ;modify disk parameters XOR A ;A=00 LD (LF0DF),A ;unaloc'd record cnt LD A,01H ;signal 'read' LD (LF0E6),A ;readop LD (LF0E5),A ;rsflag LD A,02H ;write to unaloc LD (LF0E7),A ;wrtype JP LECAC ;rwoper ; Writes the previously specified track and sector onto ; the specified disk from the DMA address ;WRITE LEC21: LD A,I ;get the int status PUSH AF ;push the flag DI ;disable interrupts LD (LF087),SP ;save SP in a variable LD SP,LF0BB ;give the SP a new value CALL LEC40 ;exec the WRITE routine LD SP,(LF087) ;retrieve the SP ; restore the interrupt status LEC33: EI ;enable ints LD (LF0C8),A ;save the A content POP AF ;retrieve int state LD A,(LF0C8) ;retrieve the A reg JP PE,LEC3F ;ret if ints were enab DI ;else disable ints LEC3F: RET ;ret ; perform the write operation LEC40: CALL LED54 ;modify disk parameters XOR A ;not a read operation LD (LF0E6),A ;readop LD A,C ;write type supplied by BDOS LD (LF0E7),A ;wrtype CP 02H ;write unalocated? JR NZ,LEC68 ;check for unalloc LD A,00H ;block size/128 LEC50: EQU $-1 ;blocksize/128 (cpm sectors per block) LD (LF0DF),A ;set a counter LD A,(LF0D3) ;copy current disk number sekdsk LD (LF0E0),A ;to the unallocated variable unadsk LD HL,(LF0D4) ;copy current track number sektrk LD (LF0E1),HL ;to the unallocated variable unatrk LD A,(LF0D6) ;seksec DEC A DEC A LD (LF0E3),A ;unasec ; Check if this is not the first write to an unallocated ; allocation block -- if it is, the unallocated record count ; has just been set to the number of 128-byte sectors in the ; allocation block. ; ;CHKUNA ;check for write to unallocated sector LEC68: LD A,(LF0DF) ;get the unallocated rec count unacnt OR A ;any unaloc'd remain? JR Z,LECA4 ;skip if not ; more unallocated records remain DEC A ;decrement unacnt LD (LF0DF),A ;store in variable LD A,(LF0D3) ;seek disk number LD HL,LF0E0 ;unadsk CP (HL) ;same disk? JR NZ,LECA4 ;skip if not ; disks are the same LD HL,LF0E1 ;unatrk CALL LED48 ;same trk? sektrk=unatrk? JR NZ,LECA4 ;skip if not ; tracks are the same LD A,(LF0D6) ;seksec DEC A DEC A LD HL,LF0E3 ;unasec CP (HL) ;same sector? JR NZ,LECA4 ;skip if not ; match, move to next sector for future reference INC (HL) ;inc unasec LD A,(HL) ;end of track? CP 00H LEC91: EQU $-1 ;number of 128 byte cpm sectors per track JR C,LEC9D ;skip if no overflow ; overflow to next track LD (HL),00H ;unasec = 0 LD HL,(LF0E1) ;get unatrk INC HL ;increment it LD (LF0E1),HL ;store back in variable ;NOOVF: ;match found, mark as unnecessary read LEC9D: XOR A ;zero to accumulator LD (LF0E5),A ;rsflag = 0 (read not needed) JP LECAC ;RWOPER perform the write ;ALLOC: ;not an unallocated record, requires pre-read LECA4: XOR A ;0 to A LD (LF0DF),A ;unacnt = 0 INC A ;1 to A LD (LF0E5),A ;rsflag = 1 (read needed) ;RWOPER ;enter here to perform the read/write LECAC: XOR A ;signal no errors (yet) LD (LF0E4),A ;in the error flag LD A,(LF0D6) ;seek sector number DEC A DEC A PUSH BC LD B,00H LECB7: EQU $-1 ;log2(cpm sectors per host sector) LECB8: OR A ;clear carry RRA ;divide by two DJNZ LECB8 ; POP BC LD (LF0DC),A ;host sector to seek (sekhst) LD HL,LF0DD ;hstact LD A,(HL) ;get host active flag LD (HL),01H ;always signal 'in activity' OR A ;was it already active? JR Z,LECEA ;fill host if not ; ; host disk active, same as seek disk? LD A,(LF0D3) ;current seek disk (sekdsk) LD HL,LF0D7 ;current host disk (hstdsk) CP (HL) ;same disk? JR NZ,LECE3 ;skip if not ; ; same disk, same track? LD HL,LF0DA ;current host track (hsttrk) CALL LED48 ;sektrk = hssttrk ? JR NZ,LECE3 ;skip if not ; ; same disk, same track, same sector? LD A,(LF0DC) ;sekhst LD HL,LF0D9 ;hstsec CP (HL) ;same sector? JR Z,LED07 ;skip if match ;NOMATCH ;proper disk, but not correct sector LECE3: LD A,(LF0DE) ;hstwrt OR A ;host written? CALL NZ,LED9E ;if not, then write to disk ;may have to fill the host buffer FILHST: LECEA: LD A,(LF0D3) ;sekdsk LD (LF0D7),A ;hstdsk LD HL,(LF0D4) ;settrk LD (LF0DA),HL LD A,(LF0DC) LD (LF0D9),A ;hstsec LD A,(LF0E5) OR A ;is it necesary to read? CALL NZ,LEE8D ;read the host sector XOR A ;signal 'not writing' LD (LF0DE),A ;in the variable ;MATCH ;copy data to or from buffer LED07: LD A,(LF0D6) ;seksec DEC A DEC A AND 00H LED0D: EQU $-1 ;sector mask LD L,A LD H,00H ADD HL,HL ;*2 ADD HL,HL ;*4 ADD HL,HL ;*8 ADD HL,HL ;*16 ADD HL,HL ;*32 ADD HL,HL ;*64 ADD HL,HL ;*128 LD DE,(LF0CE) ;host buffer ADD HL,DE LD DE,(LF0E8) ;get the transfer address LD BC,0080H ;length of move 128 bytes LD A,(LF0E6) ;readop OR A ;read? JR NZ,LED30 ;skip if read LD A,01H ;signal write LD (LF0DE),A ;in hstwrt EX DE,HL ;exchange pointers LED30: LDIR ;move data LD A,(LF0E7) ;wrtype CP 01H ;write to directory? LD A,(LF0E4) ;in case of errors RET NZ ;no further processing OR A RET NZ XOR A ;signal writing finished LD (LF0DE),A ;in hstwrt CALL LED9E ;writehst LD A,(LF0E4) ;error flag to A RET ; Utility subroutine for 16-bit compare ; In: HL = unatrk or hsttrk, compare with sektrk ;Out: ZF set if equal LED48: EX DE,HL ;pass HL to DE LD HL,LF0D4 ;sektrk variable LD A,(DE) ;low byte compare CP (HL) ;same? RET NZ ;ret if not INC DE ;low byte equal INC HL ;test high bytes LD A,(DE) ;high byte compare CP (HL) ;same? RET ;ret with ZF set or not ; modify some parameters in the disk routines according to drive type LED54: PUSH AF ;save PUSH DE ;registers PUSH HL ;in the stack LD A,(LF0D3) ;get the disk number ADD A,A ;multiply ADD A,A ;by four LD E,A ;pass it to E LD D,00H ;high part = 0 LD HL,LED7A ;table start ADD HL,DE ;calc table acess LD A,(HL) ;get blocksize/128 LD (LEC50),A ;store in variable INC HL ;inc table pointer LD A,(HL) ;get the CPM sect/track LD (LEC91),A ;store in variable INC HL ;inc table pointer LD A,(HL) ;get sector mask LD (LED0D),A ;store in variable INC HL ;inc table pointer LD A,(HL) ;get log2(cpmsect/hostsect) LD (LECB7),A ;store in variable POP HL ;retrieve registers POP DE POP AF RET ;ret ; parameters table for the disk routines ; disk 00 SVI 738 SS DD LED7A: DEFB 10H ;16 cpm sectors per block DEFB 24H ;36 128 byte cpm sectors per track DEFB 03H ;03 sector mask (2 bits) DEFB 02H ;2^02H = 4 cpm sectors per host sector ; disk 01 SVI 738 SS DD LED7E: DEFB 10H ;16 cpm sectors per block DEFB 24H ;36 128 byte cpm sectors per track DEFB 03H ;03 sector mask (2 bits) DEFB 02H ;2^02H = 4 cpm sectprs per host sector ; disk 02 OSBOURNE 1 SS DD LED82: DEFB 08H ;08 cpm sectors per block DEFB 28H ;40 128 byte cpm sectors per track DEFB 07H ;07 sector mask (3 bits) DEFB 03H ;2^03H = 8 cpm sectors per host sector ; disk 03 KAYPRO 2 SS DD LED86: DEFB 08H ;08 cpm sectors per track DEFB 28H ;40 128 byte cpm sectors per track DEFB 03H ;03 sector mask (2 bits) DEFB 02H ;2^02H = 4 cpm sectors per host sector ; disk 04 BONDWELL 12 SS DD LED8A: DEFB 10H ;16 cpm sectors per track DEFB 24H ;36 128 byte cpm sectors per track DEFB 01H ;01 sector mask (1 bit) DEFB 01H ;2^01H = 2 cpm sectors per host sector ; disk 05 XEROX 512 DS DD LED8E: DEFB 10H ;16 cpm sectors per track DEFB 24H ;36 128 byte cpm sectors per track DEFB 01H ;01 sector mask (1 bit) DEFB 01H ;2^01H = 2 cpm sectors per host sector ; disk 06 XEROX 820II SS DD LED92: DEFB 08H ;08 cpm sectors per track DEFB 22H ;34 128 byte cpm sectors per track DEFB 01H ;01 sector mask (1 bit) DEFB 01H ;2^01H = 2 cpm sectors per host sector ; disk 07 SVI 328 DS DD LED96: DEFB 10H ;16 cpm sectors per track DEFB 22H ;34 128 byte cpm sectors per track DEFB 01H ;01 sector mask (1 bit) DEFB 01H ;2^01H = 2 cpm sectors per host sector ; disk 08 BONDWELL 14 SS DD LED9A: DEFB 10H ;16 cpm sectors per track DEFB 24H ;36 128 byte cpm sectors per track DEFB 01H ;01 sector mask (1 bit) DEFB 01H ;2^01H = 2 cpm sectors per host sector ; performs the phisical write to the host disk ;WRITEHST LED9E: LD A,(LF0D7) ;useless instruction LD A,01H ;signal 'drive is active' LD (LFFFB),A ;into variable CALL LF049 ;enable disk slot CALL LEF3E ;activate the drive LD A,(LFFFC) ;get cnt to turn drive off OR A ;is the drive stopped? JR NZ,LEDB8 ;skip if not LD HL,9C40H ;wait for motor spin up CALL LEFBA ;time delay (10000) LEDB8: LD A,14H ;20 decimal LD (LF0D0),A ;retries counter LEDBD: LD A,(LF0DA) ;hsttrk host track CALL LEFCF ;position the head LD HL,LFADE ;host sec buffer address LD (LF0CE),HL ;put into variable CALL LEF29 ;get hst sect offset LD A,(LF0D9) ;host sector ADD A,B ;add offset LD (L7FBA),A ;FDC sector register LD A,0A0H ;write sector LD (L7FB8),A ;FDC command port LD BC,L7FBC ;data request port LD HL,(LF0CE) ;host data buffer LD DE,0000H ;65536 attempts LEDE1: LD A,(BC) ;get data request info ADD A,A ;bit 6 to SF JP P,LEDF4 ;jump if ready to accept data DEC E ;decrement counter lo JP NZ,LEDE1 ;try again if not zero DEC D ;decrement counter hi JP NZ,LEDE1 ;try again if not zero CALL LEF9B ;turn drive motor off JP LEF0C ;finish with error LEDF4: LD DE,L7FBB ;FDC data register JP LEE01 ;skip to LEE01 LEDFA: LD A,(BC) ;get data request info ADD A,A ;bit 6 to SF, bit 7 to CF JR C,LEE07 ;jump if command finished JP M,LEDFA ;loop back if not ready LEE01: LD A,(HL) ;get byte from buffer LD (DE),A ;out to FDC INC HL ;inc pointer JP LEDFA ;process next byte LEE07: LD A,(L7FB8) ;FDC status register BIT 0,A ;is the FDC still busy? JR NZ,LEE07 ;jump back if yes AND 7CH ;leave only the error bits JP Z,LEE20 ;jump if no error LD B,A ;copy error bits to B LD A,(LF0D0) ;get the retries counter DEC A ;decrement it LD (LF0D0),A ;back to variable JR NZ,LEDBD ;try again if not zero JP LEF0C ;finish with error ; verify the sector just writen to disk LEE20: LD A,14H ;20 decimal LD (LEE8B),A ;retries during verification LEE25: LD A,(LF0DA) ;hsttrk CALL LEFCF ;position the head LD HL,LFADE ;host sector buffer address LD (LF0CE),HL ;put into variable CALL LEF29 ;get host sect offset LD A,(LF0D9) ;host sector ADD A,B ;add offset LD (L7FBA),A ;FDC sector register LD A,80H ;read sector LD (L7FB8),A ;FDC command register LD BC,L7FBC ;data request port LD HL,(LF0CE) ;host sector pointer LD DE,0000H ;timeout counter LEE49: LD A,(BC) ;get drq status ADD A,A ;bit 6 to SF JP P,LEE5C ;jump if byte ready DEC E ;dec timeout counter lo JP NZ,LEE49 ;loop back if not zero DEC D ;dec timeout counter hi JP NZ,LEE49 ;loop back if not zero CALL LEF9B ;turn drive motor off JP LEF0C ;finish with error LEE5C: LD DE,L7FBB ;FDC data register JP LEE69 ;skip to LEE69 LEE62: LD A,(BC) ;get drq status ADD A,A ;bit 7 to CF bit 6 to SF JR C,LEE72 ;command completed JP M,LEE62 ;byte still not available LEE69: LD A,(DE) ;get byte from FDC CP (HL) ;compare with stored byte JP NZ,LEE88 ;jump on verify error INC HL ;increment pointer JP LEE62 ;process next byte LEE72: LD A,(L7FB8) ;FDC status register BIT 0,A ;is the FDC still busy? JR NZ,LEE72 ;jump back if yes AND 1CH ;leave only the error bits JP Z,LEF13 ;jump if no error LD B,A ;save the error code LD A,(LEE8B) ;get the retries counter DEC A ;decrement it LD (LEE8B),A ;put it back into variable JR NZ,LEE25 ;retry if not zero LEE88: JP LEDBD ;verify error (retry?) LEE8B: DEFB 00H ;retry counter during verification LEE8C: DEFB 00H ;unused location ; read the host sector into the buffer ;READHST LEE8D: LD A,(LF0D7) ;useless instruction LD A,01H ;signal 'drive is active' LD (LFFFB),A ;in the flag CALL LF049 ;enable disk slot CALL LEF3E ;activate the drive LD A,(LFFFC) ;get count to turn drive off OR A ;is it stopped? JR NZ,LEEA7 ;skip delay if not LD HL,9C40H ;10000 decimal CALL LEFBA ;time delay LEEA7: LD A,14H ;20 decimal LD (LF0D0),A ;retries counter LEEAC: LD A,(LF0DA) ;hsttrk CALL LEFCF ;position the head LD HL,LFADE ;host buffer address LD (LF0CE),HL ;put into variable CALL LEF29 ;get host sector offset LD A,(LF0D9) ;host sector ADD A,B ;add offset LD (L7FBA),A ;FDC sector register LD A,80H ;read sector LD (L7FB8),A ;FDC command register LD BC,L7FBC ;data request port LD HL,(LF0CE) ;host sector pointer LD DE,0000H ;timeout counter LEED0: LD A,(BC) ;get drq status ADD A,A ;bit 6 to SF JP P,LEEE3 ;jump if byte ready DEC E ;dec timeout lo JP NZ,LEED0 ;loop back if not zero DEC D ;dec timeout hi JP NZ,LEED0 ;loop back if not zero CALL LEF9B ;turn drive motor off JP LEF0C ;finish with error LEEE3: LD DE,L7FBB ;fdc data register JP LEEF0 ;skip to LEEF0 LEEE9: LD A,(BC) ;get drq status ADD A,A ;bit 7 to CF bit 6 to SF JR C,LEEF6 ;command completed JP M,LEEE9 ;byte still not ready LEEF0: LD A,(DE) ;get byte from fdc LD (HL),A ;store in buffer INC HL ;increment pointer JP LEEE9 ;process next byte LEEF6: LD A,(L7FB8) ;FDC status register BIT 0,A ;command still going? JR NZ,LEEF6 ;wait until it finishes AND 1CH ;leave bits 4,3 and 2 JP Z,LEF13 ;jump if no error LD B,A ;save the error code LD A,(LF0D0) ;get the retries counter DEC A ;decrement it LD (LF0D0),A ;store back JR NZ,LEEAC ;retry if not zero LEF0C: LD A,01H ;signal 'error' LD (LF0E4),A ;in the flag JR LEF18 ;continue there LEF13: LD A,00H ;signal 'no error' LD (LF0E4),A ;in the flag LEF18: LD A,78H ;120 interrupts LD (LFFFC),A ;to turn drive mot off LD A,00H ;signal 'drive inactive' LD (LFFFB),A ;into variable CALL LF05A ;disable disk slot LD A,(LF0E4) ;error flag to A RET ;ret ; obtain the host sector offset (first sector number) LEF29: LD HL,LEF35 ;table address LD B,00H ;make B=0 LD A,(LF0D7) ;get host disk number LD C,A ;transfer to C ADD HL,BC ;calculate address in table LD B,(HL) ;get byte RET ;ret ; first host sector number LEF35: DEFB 01H ;disk 0 SVI 738 SSDD DEFB 01H ;disk 1 SVI 738 SSDD DEFB 01H ;disk 2 OSBORNE 1 SSDD DEFB 00H ;disk 3 KAYPRO 2 SSDD DEFB 00H ;disk 4 BONDWELL 12 SSDD DEFB 00H ;disk 5 XEROX 512 DSDD DEFB 01H ;disk 6 XEROX 820II SSDD DEFB 01H ;disk 7 SVI 328 DSDD DEFB 00H ;disk 8 DONDWELL 14 DSDD ; activate the correct drive LEF3E: LD A,(LF0CA) ;check if a second OR A ;drive is present LD A,(LF0D7) ;get current host disk JR NZ,LEF4A ;jump if not present OR A ;is it drive 0? JR NZ,LEF5B ;jump if not LEF4A: LD B,A ;current hst dsk to B LD A,(LF0C9) ; CP B LD A,B LD (LF0C9),A JR LEF55 ;a useless instruction LEF55: AND 0FCH ;mask off ds0 & ds1 OR 01H ;select drive 0 JR LEF62 ;continue there LEF5B: LD A,(LE244) ;get actual drv ctl value AND 0FCH ;mask off ds0 & ds1 OR 02H ;select drive 1 LEF62: OR 08H ;turn motor on LD (L7FBC),A ;drive ctl register LD (LE244),A ;copy of drive ctl reg LD A,(LF0CA) ;check for a second OR A ;drive present JR NZ,LEF9A ;jump if not present LD A,(LF0D8) ;get last host disk LD B,A ;copy to B LD A,(LF0D7) ;get current host disk CP B ;was there a drive change? JR Z,LEF9A ;jump if not LD (LF0D8),A ;make last dsk = cur dsk CP 00H ;is it drive 0? JR Z,LEF8E ;jump if yes LD A,(L7FB9) ;FDC track register LD (LF0EF),A ;save trk reg for drv 0 LD A,(LF0F0) ;get trk reg for drv 1 LD (L7FB9),A ;FDC track register RET LEF8E: LD A,(L7FB9) ;FDC track register LD (LF0F0),A ;save trk reg for drive 1 LD A,(LF0EF) ;get trk reg for drv 0 LD (L7FB9),A ;FDC track register LEF9A: RET ; turn all drive motors off LEF9B: LD A,00H ;all drives off LD (L7FBC),A ;drive control reg LD (LE244),A ;copy of drive ctl reg LD (LFFFC),A ;signal 'motor is off' RET ; move drive head to track 00 LEFA7: LD A,00H ;restore LD (L7FB8),A ;FDC command register CALL LF037 ;little time delay CALL LF03E ;wait until fdc is not busy LD A,(L7FB8) ;FDC status register BIT 2,A ;is the head at trk 00? JR Z,LEFA7 ;if not, repeat the command LEFB9: RET ;ret ; time delay, value in HL LEFBA: DEC HL ;decrement counter DI ;disable ints NOP ;and lose a little DI ;time in the meantime LD A,H ;check if the OR L ;counter is zero JR NZ,LEFBA ;loop back if not RET ;ret ; move drive head one step in LEFC3: LD A,54H ;step in LD (L7FB8),A ;FDC command register CALL LF037 ;little time delay CALL LF03E ;wait until fdc is not busy RET ; compute the disk type and head number LEFCF: LD C,A ;host track to C LD A,(LF0D7) ;hstdsk CP 02H JP C,LEFF1 ;disk 0 and 1 CP 08H JR Z,LEFF1 ;disk 8 LD A,C ;host track to A CP 28H ;track 40 JR C,LEFF1 ;jump if less than LD A,(LE244) ;copy of drive select port OR 04H ;select side 1 LD (L7FBC),A ;drive select port LD (LE244),A ;copy of drive select port LD A,C ;host track to A SUB 28H ;substract 40 JR LF007 ;continue there LEFF1: LD A,(LE244) ;copy of drive select port AND 0FBH ;select side 0 LD (L7FBC),A ;drive select port LD (LE244),A ;copy of drive select port LD A,C ;host track to A JR LF007 ;continue there ; apparently orphaned code LEFFF: CALL LEFA7 ;move head to track 00 CALL LEFC3 ;step in JR LF00D ; position the head on the desired track LF007: LD B,A ;host track to B LD A,(L7FB9) ;FDC track register CP B ;is the head already positioned? RET Z ;if yes then ret LF00D: LD A,B ;host track to A OR A ;is trk 00 being requested? JR Z,LF032 ;jump if yes LD (L7FBB),A ;FDC data register LD A,14H ;seek LD (L7FB8),A ;FDC command register CALL LF037 ;little time delay CALL LF03E ;wait until fdc is not busy LF01F: LD A,(L7FB8) ;FDC status register BIT 0,A ;command still in execution? JR NZ,LF01F ;loop back if yes BIT 4,A ;check the rec not found bit LD A,C ;host track to A JR NZ,LEFCF ;if error then try again LF02B: LD HL,04B0H ;1200 CALL LEFBA ;time delay RET ;ret ; move the r/w head to track 00 wait a little and ret LF032: CALL LEFA7 ;move head to track 00 JR LF02B ;delay and ret ; little time delay LF037: NOP NOP NOP NOP NOP NOP RET ; wait until the disk controller is not busy LF03E: CALL LF037 ;time delay LF041: LD A,(L7FB8) ;status port BIT 0,A ;is the FD1793 busy? JR NZ,LF041 ;if yes then wait RET ;else ret ; enable disk slot in page 1 LF049: LD A,(LFFFA) ;disk slot (bit 2 & 3) AND 0CH ;leave only page 1 LD B,A ;store it in B IN A,(0A8H) ;get the main slt reg LD (LF0ED),A ;save it AND 0F3H ;mask off page 1 OR B ;add disk slot OUT (0A8H),A ;out to main slt reg RET ;ret ; page out the disk slot LF05A: LD A,(LF0ED) ;retrieve main slt reg OUT (0A8H),A ;out to PPI port A RET ;ret ; primary keyboard row state table ; each depressed key is represented by a set bit LF060: DEFB 00H ;row 9 DEFB 00H ;row 8 DEFB 00H ;row 7 LF063: DEFB 00H ;row 6 DEFB 00H ;row 5 DEFB 00H ;row 4 DEFB 00H ;row 3 DEFB 00H ;row 2 DEFB 00H ;row 1 DEFB 00H ;row 0 ; secondary keyboard row state table ; each depressed key is represented by a set bit LF06A: DEFB 00H ;row 9 DEFB 00H ;row 8 DEFB 00H ;row 7 LF06D: DEFB 00H ;row 6 DEFB 00H ;row 5 DEFB 00H ;row 4 DEFB 00H ;row 3 DEFB 00H ;row 2 DEFB 00H ;row 1 DEFB 00H ;row 0 ; tertiary keyboard row state table ; each depressed key is represented by a set bit LF074: DEFB 00H ;row 9 DEFB 00H ;row 8 DEFB 00H ;row 7 DEFB 00H ;row 6 DEFB 00H ;row 5 DEFB 00H ;row 4 DEFB 00H ;row 3 DEFB 00H ;row 2 DEFB 00H ;row 1 DEFB 00H ;row 0 LF07E: DEFB 00H ;ASCII value read from keyboard LF07F: DEFB 00H ;keyboard scan counter LF080: DEFB 00H ;key state flag 00 = no key depressed LF081: DEFB 00H ;all shift keys state LF082: DEFB 00H ;CAPS kept down flag 08 = kept down LF083: DEFB 00H ;typematic counter LF084: DEFB 00H ;function key in process flag 00=no function LF085: DEFW 0000H ;function key definition pointer LF087: DEFW 0000H ;saved SP LF089: DEFS 50 ;space reserved for the machine stack LF0BB: DEFB 00H ;internal machine stack (end) LF0BC: DEFB 00H ;console bell volume and flag 00=off LF0BD: DEFB 00H ;SHIFT kept down flag 01=kept down LF0BE: DEFB 00H ;SHIFT state flag 01=SHIFT pressed LF0BF: DEFB 00H ;40 col ESC sequence in process flag 00=no seq LF0C0: DEFB 00H ;ESC Y argument number (40 col) LF0C1: DEFB 00H ;CAPS LOCK state 00 = CAPS off LF0C2: DEFB 20H ;column position +32 (40 col) LF0C3: DEFB 20H ;line position +32 (40 col) LF0C4: DEFB 20H ;character under the cursor in 40 col LF0C5: DEFB 00H ;40 colunm initialisation flag 00 = display initialised LF0C6: DEFB 01H ;80 column initialisation flag 00 = display initialised LF0C7: DEFB 07H ;unused location LF0C8: DEFB 00H ;temporal place to store the A register LF0C9: DEFB 00H ;unused location LF0CA: DEFB 00H ;flag 00 = drive 1 present, 20 = absent LF0CB: DEFS 3 ;unused locations LF0CE: DEFW 0FADEH ;address of the host sector buffer LF0D0: DEFB 00H ;disk retries counter LF0D1: DEFB 00H ;disk number (valid or not) LF0D2: DEFB 00H ;unused location LF0D3: DEFB 00H ;valid disk number LF0D4: DEFW 0000H ;track to seek sektrk LF0D6: DEFB 00H ;sector to seek seksec LF0D7: DEFB 00H ;current host disk hstdsk LF0D8: DEFB 00H ;last host disk accessed LF0D9: DEFB 00H ;host sector number hstsec LF0DA: DEFW 0000H ;host track number hsttrk LF0DC: DEFB 00H ;host sector to seek sekhst LF0DD: DEFB 00H ;host active flag 00=inactive hstact LF0DE: DEFB 00H ;host writen flag 00=not writing hstwrt LF0DF: DEFB 00H ;unalloc rec counter LF0E0: DEFB 00H ;last unalocated disk unadsk LF0E1: DEFW 0000H ;unalocated track unatrk LF0E3: DEFB 00H ;unalocated sector unasec LF0E4: DEFB 00H ;error flag 00 = no error LF0E5: DEFB 00H ;read sector flag 01= read needed LF0E6: DEFB 00H ;readop 1 if read, 0 if write LF0E7: DEFB 00H ;write operation type LF0E8: DEFW 0000H ;disk transfer address LF0EA: DEFB 00H ;host sectors to read LF0EB: DEFB 00H ;two unused LF0EC: DEFB 00H ;locations LF0ED: DEFB 00H ;main slot register temporal value LF0EE: DEFB 00H ;unused location LF0EF: DEFB 00H ;track register for drive 0 LF0F0: DEFB 00H ;track register for drive 1 etc ; the initial copyright message LF0F1: DEFB 0CH ;ctrl L -> CLS DEFB 'SPECTRAVIDEO CP/M-80 Revision 2.28' DEFB 0DH,0AH DEFB 'for X',27H,'PRESS ( release 2.3 )' DEFB 0DH,0AH DEFB 'Spanish keyboard' DEFB 0DH,0AH DEFB 'Copyright (c) by Digital Research' DEFB 0DH,0AH,'$' ; key decode tables ; unshifted keys LF169: DEFB 30H,31H,32H,33H,34H,35H,36H,37H ;'01234567' DEFB 38H,39H,2DH,3DH,5CH,5BH,5DH,60H ;'89-=\[]¤' DEFB 27H,3BH,2CH,2EH,2FH,20H,61H,62H ;'';,./ ab' DEFB 63H,64H,65H,66H,67H,68H,69H,6AH ;'cdefghij' DEFB 6BH,6CH,6DH,6EH,6FH,70H,71H,72H ;'klmnopqr' DEFB 73H,74H,75H,76H,77H,78H,79H,7AH ;'stuvwxyz' DEFB 20H,20H,20H,20H,20H,80H,81H,82H ;' f1,f2,f3' DEFB 83H,84H,1BH,09H,20H,08H,20H,0DH ;'f4,f5,ESC,TAB, ,BS, ,ENTER' DEFB 20H,0BH,20H,7FH,13H,05H,18H,04H ;'SP,HM, ,DEL,LE,UP,DO,RI ; apparently unused key values LF1B1: DEFB 2BH,2DH,2AH,2FH,20H,20H,20H,20H ;'+-*/ ' ; shifted keys LF1B9: DEFB 29H,21H,40H,23H,24H,25H,5EH,26H ;')!@#$%^&' DEFB 2AH,28H,5FH,2BH,7CH,7BH,7DH,7EH ;'*(_+|{}¥' DEFB 22H,3AH,3CH,3EH,3FH,20H,41H,42H ;'":<>? AB' DEFB 43H,44H,45H,46H,47H,48H,49H,4AH ;'CDEFGHIJ' DEFB 4BH,4CH,4DH,4EH,4FH,50H,51H,52H ;'KLMNOPQR' DEFB 53H,54H,55H,56H,57H,58H,59H,5AH ;'STUVWXYZ' DEFB 20H,20H,20H,20H,20H,85H,86H,87H ;' f6,f7,f8' DEFB 88H,89H,1BH,09H,20H,08H,20H,0DH ;'f9,f10,ESC,TAB, ,BS, ,ENTER' DEFB 20H,0CH,20H,7FH,13H,05H,18H,04H ;'SP,???, ,DEL,LE,UP,DO,RI ; apparently unused key values LF201: DEFB 2BH,2DH,2AH,2FH,20H,20H,20H,20H ;'+-*/ ' ; ctrled key values LF209: DEFB 30H,31H,32H,33H,34H,35H,36H,37H ;'01234567' DEFB 38H,39H,2DH,3DH,5CH,5BH,5DH,60H ;'89-=\[]¤' DEFB 27H,3BH,2CH,2EH,2FH,20H,01H,02H ;'';,./ ^A^B DEFB 03H,04H,05H,06H,07H,08H,09H,0AH ;'^C^D^E^F^G^H^I^J' DEFB 0BH,0CH,0DH,0EH,0FH,10H,11H,12H ;'^K^L^M^N^O^P^Q^R' DEFB 13H,14H,15H,16H,17H,18H,19H,1AH ;'^S^T^U^V^W^X^Y^Z' DEFB 20H,20H,20H,20H,20H,80H,81H,82H ;' f1,f2,f3' DEFB 83H,84H,1BH,09H,20H,08H,20H,0DH ;'f4,f5,ESC,TAB, ,BS, ,ENTER' DEFB 20H,0BH,20H,7FH,13H,05H,18H,04H ;'SP,HM, ,DEL,LE,UP,DO,RI' ; apparently unused key values LF251: DEFB 2BH,2DH,2AH,2FH,20H,20H,20H,20H ;'+-*/ ' ; process capsed keys (caps lock on) LF259: CP 0FH ;is it '¤'? JR Z,LF260 ;jump if yes JP LE7BF ;else jump to LE7BF LF260: JP LE7C7 ;process the '¤' ; UC1: 80 colunn display LF263: PUSH IY ;save both PUSH IX ;index registers LD A,(LF0C6) ;is the 80 col OR A ;display initialized? JR Z,LF274 ;skip if yes CALL LF4DE ;initialize 80 col display XOR A ;signal '80 col init'd' LD (LF0C6),A ;into variable LF274: LD A,01H ;signal '40 col not init'd' LD (LF0C5),A ;into variable LD A,(LF8D2) ;esc seq in process flag OR A ;esc seq in process? JP NZ,LF2A6 ;jump if yes LD A,C ;get the chr to print CP 20H ;'SPACE' JR C,LF2C8 ;jp if it's a ctrl chr LD A,(LF8DC) ;discard character flag OR A ;has it to be discarded? JR NZ,LF2A0 ;jump if yes CALL LF4C9 ;print the character CALL LF3BE ;upd line and column LF291: CALL LF5BC ;print the cursor LF294: XOR A ;A=0 LD (LF8D2),A ;no esc seq in process LD (LF8D3),A ;no ESC Y argument LF29B: POP IX ;retrieve POP IY ;the index registers RET ;ret ; only one character has to be discarded LF2A0: XOR A ;signal 'no more discards' LD (LF8DC),A ;into variable JR LF29B ;pop regs and ret ; process the escape sequences for the 80 col display LF2A6: LD B,11H ;17 elements in table LD IX,LF3E2 ;chars after esc VT-52 LD A,(LE23C) ;get the terminal type OR A ;is it VT-52? JR Z,LF2B8 ;jump if yes LD B,08H ;8 elements in table LD IX,LF4B1 ;chars after esc ADM-3A LF2B8: LD A,(LF8D3) ;ESC Y or = argument CP 01H ;is it the 1st argument? JP Z,LF448 ;jump if yes (line) CP 02H ;is it the 2nd argument? JP Z,LF460 ;jump if yes (column) LD A,C ;get the character JR LF2DB ;exec the appropriate routine ; process the 80 col control characters LF2C8: LD B,0CH ;12 elements LD IX,LF2F7 ;ctl chrs for VT-52 LD A,(LE23C) ;get the termtype var OR A ;is it VT-52? LD A,C ;get the character JR Z,LF2DB ;jump if VT-52 LD B,0BH ;11 elements in table LD IX,LF490 ;ctl chars for ADM-3A LF2DB: CP (IX+00H) ;is the char in table? JR Z,LF2F0 ;jump if yes INC IX ;increment the INC IX ;table pointer INC IX ;three times DJNZ LF2DB ;process next tab elememt LD A,(LF8D2) ;esc sequence flag OR A ;esc seq in process? JR Z,LF29B ;ret if not JR LF291 ;print crsr and ret LF2F0: LD L,(IX+01H) ;get the routine address LD H,(IX+02H) ;from table JP (HL) ;execute the routine ; control character routines table for VT-52 terminal LF2F7: DEFB 07H ;^G BELL DEFW LF31B ;ring the console bell DEFB 08H ;^H BACK SPACE DEFW LF321 ;move cursor to the left deleting char DEFB 09H ;^I TAB DEFW LF336 ;advance to the next tab position DEFB 0AH ;^J line feed DEFW LF342 ;line feed DEFB 0BH ;^K home DEFW LF359 ;move the cusor to the home position DEFB 0CH ;^L cls DEFW LF365 ;clear the screen DEFB 0DH ;^M enter DEFW LF35E ;cursor to column 0 DEFB 1BH ;ESC DEFW LF36A ;process the escape sequences DEFB 1CH ;^\ DEFW LF393 ;cursor right DEFB 1DH ;^] DEFW LF389 ;cursor left DEFB 1EH ;ctrl ^ DEFW LF372 ;cursor up DEFB 1FH ;^_ DEFW LF37C ;cursor down ; ^G BELL ring the console bell LF31B: CALL LE94B ;ring the bell JP LF294 ;pop regs and ret ; ^H back space LF321: CALL LF82C ;uninv char under the cursor CALL LF3A4 ;move crsr to the left LD C,20H ;a space CALL LF4C9 ;print the character CALL LF5BC ;print the cursor XOR A ;signal 'uninvert char' LD (LF8DD),A ;into the variable JP LF294 ;pop regs and ret ; ^I tab LF336: CALL LF3BE ;update line and column LD A,(LF8D5) ;get the column position AND 07H ;leave only bits 2,1 & 0 JR NZ,LF336 ;move to next tab posit. JR LF39E ;uninv char and print crsr ; line feed LF342: CALL LF82C ;uninv char under the cursor LD A,(LF8D6) ;line position +32 CP 37H ;is it line 23? JR NZ,LF352 ;skip if not CALL LF5FC ;scroll up the 80 col screen JP LF291 ;print cursor and ret ; not in the last line, so only update the line position LF352: INC A ;increment line LD (LF8D6),A ;put into variable JP LF291 ;prnt crsr and ret ; move the cursor to the home position LF359: LD A,20H ;signal 'line 0' LD (LF8D6),A ;into the variable ; move the cursor to column 0 LF35E: LD A,20H ;and 'column 0' LD (LF8D5),A ;into the other variab JR LF39E ;uninv char and print crsr ; clear the 80 col screen and home the cursor LF365: CALL LF677 ;clear the 80 col screen JR LF359 ;home the cursor ; signal ESC sequence in process LF36A: LD A,01H ;esc seq in process LD (LF8D2),A ;put into var JP LF29B ;pop regs and ret ; cursor up LF372: LD A,(LF8D6) ;line position +32 CP 20H ;is it line 0? JR Z,LF39E ;skip if yes DEC A ;decrement line JR LF384 ;update line and... ; cursor down LF37C: LD A,(LF8D6) ;line position +32 CP 37H ;is it line 23? JR Z,LF39E ;skip if yes INC A ;increment line LF384: LD (LF8D6),A ;put into variable JR LF39E ;uninv chr and print crsr ; cursor left LF389: LD A,(LF8D5) ;column position +32 CP 20H ;is it col 0? JR Z,LF39E ;skip if yes DEC A ;decrement column JR LF39B ;update column and... ; cursor right LF393: LD A,(LF8D5) ;column position +32 CP 6FH ;is it col 79? JR Z,LF39E ;skip if yes INC A ;increment column LF39B: LD (LF8D5),A ;put into variable LF39E: CALL LF82C ;uninv char under the cursor JP LF291 ;print crsr and ret ; move the current print position one character to the left LF3A4: LD A,(LF8D5) ;column position +32 CP 20H ;is at column 0? JR Z,LF3AE ;jump if yes, else.. DEC A ;decrement column JR LF3BA ;update variable and ret ; if at the first column, move to column 79 of the previous line LF3AE: LD A,(LF8D6) ;line position +32 CP 20H ;is at line 0? RET Z ;ret if yes, else.. DEC A ;decrement line LD (LF8D6),A ;update the variable LD A,6FH ;point to col 79 LF3BA: LD (LF8D5),A ;store in variable RET ;and ret ; update line and column position, and meke a scroll if necesary LF3BE: LD A,(LF8D5) ;column position +32 CP 6FH ;is it col 79? JR Z,LF3C8 ;skip if yes INC A ;increment column JR LF3D5 ;update var and ret LF3C8: LD A,(LF8D6) ;line position +32 CP 37H ;is it line 23? JR Z,LF3D9 ;scroll if yes INC A ;icrement line LD (LF8D6),A ;update variable LD A,20H ;point to col 0 LF3D5: LD (LF8D5),A ;update variable RET ;ret ; scroll the 80 column screen and set the print position to the first col LF3D9: CALL LF5FC ;scroll up the 80 col screen LD A,20H ;point to col 0 LD (LF8D5),A ;put into variable RET ;ret ; control characters after ESCAPE table for VT-52 LF3E2: DEFB 6AH ;ESC j cls DEFW LF365 ;clear the screen DEFB 45H ;ESC E DEFW LF365 ;clear the screen DEFB 4BH ;ESC K DEFW LF415 ;clear to end of line DEFB 4AH ;ESC J DEFW LF436 ;clear to end of screen DEFB 6CH ;ESC l DEFW LF43B ;clear line DEFB 4CH ;ESC L DEFW LF486 ;insert line DEFB 4DH ;ESC M DEFW LF48B ;delete line DEFB 59H ;ESC Y DEFW LF441 ;signal first argument (set line,cal) DEFB 41H ;ESC A DEFW LF372 ;cursor up DEFB 42H ;ESC B DEFW LF37C ;cursor down DEFB 43H ;ESC C DEFW LF393 ;cursor right DEFB 44H ;ESC D DEFW LF389 ;cursor left DEFB 48H ;ESC H DEFW LF359 ;move the cursor to the home position DEFB 70H ;ESC p DEFW LF473 ;set inverse video DEFB 71H ;ESC q DEFW LF477 ;set normal video DEFB 78H ;ESC x DEFW LF47F ;discard the next character DEFB 79H ;ESC y DEFW LF47F ;discard the next character ; clear to the end of line LF415: LD A,(LF8D5) ;get the column +32 PUSH AF ;push it LD C,20H ;a space LF41B: CALL LF4C9 ;print it LD A,(LF8D5) ;get the column INC A ;increment it CP 70H ;is it col 80? LD (LF8D5),A ;update the variable JR NZ,LF41B ;if not, print another space POP AF ;retrieve the original col LD (LF8D5),A ;restore the column variable CALL LF836 ;uninvert to end of line XOR A ;signal 'uninvert char' LD (LF8DD),A ;into the variable JR LF43E ;print cursor and ret ; clear to the end of screen LF436: CALL LF68E ;clear to end of screen JR LF43E ;print cursor and ret ; clear line LF43B: CALL LF6B1 ;clear the current line LF43E: JP LF291 ;print cursor and ret ; signal first argument retrieve regs and ret LF441: LD A,01H ;signal first argument LD (LF8D3),A ;into variable JR LF45D ;retrieve regs and ret ; process ESC Y (VT-52) or ESC = (ADM-3A) first argument (line) LF448: LD A,C ;copy the chr to A CP 20H ;is it line 0? JR NC,LF44F ;jp if great or equal LD A,20H ;signal 'line 0' LF44F: CP 38H ;is it line 23+1? JR C,LF455 ;jp if less LD A,37H ;signal 'line 23' LF455: LD (LF8D6),A ;put into the variable LD A,02H ;signal '2nd argument' LD (LF8D3),A ;into the variable LF45D: JP LF29B ;retrieve regs and ret ; process ESC Y (VT-52) or ESC = (ADM-3A) second argument (column) LF460: LD A,C ;copy the character to A CP 20H ;is it col 0? JR NC,LF467 ;jp if greater or eq LD A,20H ;signal 'col 0' LF467: CP 70H ;is it col 79+1 JR C,LF46D ;jump if less than LD A,6FH ;signal 'col 79' LF46D: LD (LF8D5),A ;into the variable JP LF39E ;uninv char and print cursor ; activate 'inverse video' LF473: LD A,01H ;signal 'inv video' JR LF479 ;update the variable ; activate 'normal video' LF477: LD A,00H ;signal 'normal video' LF479: LD (LF8D4),A ;into the variable JP LF294 ;upd vars retr regist ; discard the next character LF47F: LD A,01H ;signal 'discard nxt chr' LD (LF8DC),A ;into variable JR LF43E ;print cursor and ret ; insert line LF486: CALL LF6CD ;insert a line JR LF43E ;print cursor and ret ; delete line LF48B: CALL LF76B ;delete line (80 column) JR LF43E ;print cursor and ret ; control characters address table for ADM-3A terminal LF490: DEFB 07H ;ctrl G DEFW LF31B ;ring the console bell DEFB 08H ;CTRL H DEFW LF389 ;cursor left DEFB 0AH ;ctrl J DEFW LF342 ;line feed DEFB 0BH ;ctrl K DEFW LF372 ;cursor up DEFB 0CH ;ctrl L DEFW LF393 ;cursor right DEFB 0DH ;ctrl M DEFW LF35E ;carriage return DEFB 1BH ;escape DEFW LF36A ;process escape sequences DEFB 05H ;ctrl E DEFW LF372 ;cursor up DEFB 18H ;ctrl X DEFW LF37C ;cursor down DEFB 13H ;ctrl S DEFW LF389 ;cursor left DEFB 04H ;ctrl D DEFW LF393 ;cursor right ; control character table after ESCAPE for ADM-3A terminal LF4B1: DEFB 2AH ;ESC * DEFW LF365 ;clear the screen DEFB 49H ;ESC I DEFW LF473 ;set the inverse video flag DEFB 4EH ;ESC N DEFW LF477 ;reset the inverse video flag DEFB 54H ;ESC T DEFW LF415 ;clear to end of line DEFB 59H ;ESC Y DEFW LF436 ;clear to end of screen DEFB 3DH ;ESC = DEFW LF441 ;signal first argument (set line,col) DEFB 52H ;ESC R DEFW LF48B ;delete line DEFB 45H ;ESC E DEFW LF486 ;insert line ; print the character in C in the 80 col screen LF4C9: CALL LF750 ;calculate vram address LD DE,L1000 ;start of display file ADD HL,DE ;add to the calc'ed addr LD A,C ;get the byte to print CALL LF5D7 ;vpoke it LD A,(LF8D4) ;get the inv video flag OR A ;is it normal video? JR NZ,LF4DD ;ret if not CALL LF7B1 ;else uninvert the chr LF4DD: RET ;ret ; initialize the 80 column display LF4DE: XOR A ;signal to uninvert the char LD (LF8DD),A ;into the variable ; read initial vdp reg values from table LD B,14H ;20 values (10 registers) LD HL,LF539 ;table with vdp reg data LF4E7: LD A,(HL) ;get byte from table OUT (99H),A ;out to vdp INC HL ;increment pointer DJNZ LF4E7 ;process next value ; program the vertical freq and the screen height LD A,(LF8E7) ;get the mode reg 3 SET 7,A ;signal (212 pixel height) OUT (99H),A ;out to VDP LD A,89H ;register 9 OUT (99H),A ;out to vdp ; clear the screen and print the cursor CALL LF677 ;clear the 80 col screen CALL LF5BC ;print the cursor ; clear the bottom two lines LD A,20H ;a space LD HL,L1000+07D0H ;start of the 25th line LD BC,00A0H ;160 chars (2 lines) CALL LF5E6 ;repetitive vpoke ; invert video in the bottom line LD A,0FFH ;all bits set (inverse video) LD HL,L0000+00FAH ;the 25th line in blink file LD BC,000AH ;1 line in the blink file CALL LF5E6 ;repetitive vpoke ; draw the five white boxes for the function keys in the blink file LD B,05H ;five 'function boxes' LD A,0FEH ;15 inv chars plus 1 uninv char boxes JR LF51B ;skip the initial inc LF51A: INC HL ;point to LF51B: INC HL ;the next box PUSH BC ;push the counter CALL LF5D7 ;vpoke POP BC ;pop the counter DJNZ LF51A ;draw next box ; clear the 26th line in the blink file XOR A ;all bits reset (normal video) LD HL,L0000+0104H ;the 26th line in blink file LD BC,000AH ;1 line in the blink file CALL LF5E6 ;repetitive vpoke ; display the function keys, enable the screen and ret CALL LF58A ;display the function keys LD A,70H ;enable screen and vdp ints OUT (99H),A ;out to VDP LD A,81H ;reg 1 (mode register 1) OUT (99H),A ;out to VDP RET ;ret ; vdp register values for the 80 column display LF539: DEFB 04H ;set M4 mode bit DEFB 80H ;reg 0 (mode register 0) DEFB 10H ;set M1 mode and disable screen DEFB 81H ;reg 1 (mode register 1) DEFB 07H ;set name table base address at 1000H DEFB 82H ;reg 2 (name table base address) DEFB 01H ;set the chr generator at 0800H DEFB 84H ;reg 4 (pattern generator base address) DEFB 07H ;set the blink table base address at 0000H DEFB 83H ;reg 3 (blink table base address lo) DEFB 00H ;set the blink table address high byte to zero DEFB 8AH ;reg 10 (blink table base address hi) DEFB 00H ;set the vram address high bits to 0 DEFB 8EH ;reg 14 (VRAM address select high bits) DEFB 0F1H ;ink white, paper black DEFB 87H ;reg 7 (colour register) DEFB 1FH ;ink black, paper white DEFB 8CH ;reg 12 (inverse text colour) DEFB 0F0H ;always on DEFB 8DH ;reg 13 (blinking period) ; initialize the VDP for screen 0 40 columns, ; background dark blue, foreground white LF54D: LD HL,LF582 ;table start LD B,08H ;eight values LF552: LD A,(HL) ;get data from table OUT (99H),A ;send to VDP INC HL ;increment pointer DJNZ LF552 ;process next element ; enable BIOS and BASIC rom in the 0000H-7FFFH area IN A,(0A8H) ;get the primary slot register LD B,A ;save it in B LD A,50H ;put slot 0 in pages 0 & 1 OUT (0A8H),A ;out to PPI port A ; check the interrupt frequency in the ID byte and store the ; proper value in the VDP reg 9 LD A,(L002B) ;get the ID byte BIT 7,A ;test the int freq flag LD A,00H ;value for 60hz JR Z,LF56A ;jump if 60hz LD A,02H ;value for 50hz LF56A: LD (LF8E7),A ;save it in variable OUT (99H),A ;and send it to LD A,89H ;the VDP reg 9 OUT (99H),A ;(mode reg 2) ; restore the previous saved memory configuration LD A,B ;retrieve primary slot reg config OUT (0A8H),A ;out to PPi port A ; clear the screen and enable the screen output CALL LE98A ;clear the screen (cls) LD A,70H ;enable the screen output OUT (99H),A ;VDP ctl reg LD A,81H ;reg 1 (mode reg 1) OUT (99H),A ;VDP ctl reg RET ;ret ; initial VDP register data LF582: DEFB 10H ;set M1 mode and disable screen DEFB 81H ;reg 01 (mode reg 1) DEFB 00H ;reset M3, M4 and M5 bits DEFB 80H ;reg 00 (mode reg 0) DEFB 0F4H ;ink white, paper dark blue DEFB 87H ;reg 07 (colour register) DEFB 00H ;address 0000 in VRAM DEFB 82H ;reg 02 (name table base address) ; display the unshifted key definitions if A=0 ; else display the shifted ones LF58A: LD HL,(LE237) ;get the key definition table addr OR A ;is shift unpressed? JR Z,LF594 ;jump if so LD BC,0050H ;offset to shifted messages ADD HL,BC ;add to table begining LF594: EX DE,HL ;move result to DE LD C,05H ;5 function keys to display LD HL,L1000+07D1H ;address in VRAM LF59A: LD B,0EH ;14 chrs to print PUSH HL ;save VRAM pointer PUSH DE ;and table pointer LF59E: LD A,(DE) ;get byte from table CP 14H ;any character below JP P,LF5A6 ;14H is interpreted as LD A,20H ;a SPACE at printing time LF5A6: CALL LF5D7 ;vpoke chr in VRAM INC HL ;inc VRAM pointer INC DE ;and table pointer DJNZ LF59E ;process next character POP DE ;retrieve the table ptr POP HL ;and the VRAM pointer PUSH BC ;save number of functions to print LD BC,0010H ;offset to next definition ADD HL,BC ;point to next key def EX DE,HL ;move new ptr to DE ADD HL,BC ;add offset to VRAM ptr EX DE,HL ;VRAM addr to DE tbl ptr to HL POP BC ;retrieve functions counter DEC C ;one function less to print JR NZ,LF59A ;jump to process next key definition RET ;ret ; print the cursor by vpoking into the blink file LF5BC: CALL LF87C ;get blink addr and mask LD (LF8DE),A ;put blink mask LD (LF8DF),HL ;and blink addr in var OR D ;the vpeeked blink byte CALL LF5D7 ;vpoke chr in vram RET ;ret ; vpeek in A the address pointed by HL LF5CA: LD A,L ;get address lo byte OUT (99H),A ;out to vdp LD A,H ;get address hi byte RES 6,A ;signal 'read from vram' OUT (99H),A ;out to vdp EX (SP),HL ;little EX (SP),HL ;time delay IN A,(98H) ;perform the vpeek RET ;ret ; vpoke A in the vram address pointed by HL LF5D7: PUSH AF ;save the byte LD A,L ;get lo byte OUT (99H),A ;out to VDP LD A,H ;get hi byte SET 6,A ;prepare to write OUT (99H),A ;out to VDP POP AF ;retrieve byte EX (SP),HL ;little EX (SP),HL ;time delay OUT (98H),A ;vpoke the byte RET ;ret ; vpoke A BC times from the address pointed by HL LF5E6: PUSH BC ;save the counter SET 6,H ;signal 'vram write' LD C,99H ;vdp access port OUT (C),L ;send address lo OUT (C),H ;and address hi POP BC ;get the counter EX (SP),HL ;little EX (SP),HL ;time delay LF5F2: OUT (98H),A ;perform the vpoke LD D,A ;save data byte in D DEC BC ;decrement counter LD A,C ;check if OR B ;it reached zero LD A,D ;retrieve data byte JR NZ,LF5F2 ;loop back if not RET ;else ret ; scroll up the 80 column screen LF5FC: LD HL,0050H ;offset to line 1 begin LD DE,L1000 ;start of display file ADD HL,DE ;HL=start of line 1 LD DE,L1000 ;start of display file LD BC,0780H ;1920 chars to scroll LD A,50H ;80 columns LD (LF8E1),A ;store in variable CALL LF619 ;scroll up display file CALL LF7DC ;scroll up blink file XOR A ;signal 'uninvert char' LD (LF8DD),A ;into the variable RET ;ret ; scroll up routine (80 col) LF619: SET 6,D ;signal 'write to vram' LD (LF8E5),DE ;line for write