;----------------------EIO Board Z80 EPROM------------------- ; 0000 di ;Reset Starts here 0001 jp 07f7h ;Go to ResetEntry 0004 ld h,h 0005 djnz 00h 0007 nop ;---ClockInit - Initiallise Clock Device 0008 xor a ;Clear Clock Message Flag 0009 ld (680fh),a 000c ret ;And Return ;---XClock - Clock Request Handler 000d ld hl,680fh ;CLK.Msg - Point to clock message flag 0010 set 1,(hl) ;Set NAK bit 0012 jp 0b31h ;Go to PERQEnable, and continue ;---LowPriClock - Send NAK for RTC messages 0015 ld c,0ah ;DevClock - Clock Device 0017 ld hl,680fh ;CLK.Msg - Look at clock message flag 001a bit 1,(hl) ;Has NAK bit been set? 001c jp nz,0ad6h ;Yes, Goto SendNAK and return 001f ret ;No, just return 0020 jp 0140h ;Dummy vector points here - goto DummyISR ;------GPIBInit - Initialise GPIB System 0023 xor a ;Clear GPIB.Msg Flag 0024 ld (680eh),a 0027 out (00h),a ;Clear GPIB Int Mask 0 Register - Disable int 0029 out (7bh),a ;Clear system controller latch, Not a controller 002b ret ;Exit ;------XGPIB - GPIB Message Handler 002c ld hl,680eh ;Point to GPIB.Msg Flag 002f set 1,(hl) ;Set NAK bit 0031 jp 0b31h ;Goto PERQEnable and exit ;------LowPriGPIB - Send NAK for any GPIB Messages that nothing else takes 0034 ld c,07h ;DevGPIB - GPIB Device 0036 ld hl,680eh ;Get GPIB.Msg - GPIB Message Flag 0039 bit 1,(hl) ;Have we got a message to NAK? 003b jp nz,0ad6h ;Yes, Goto SendNAK and return 003e ret ;No, Just exit ;------GPIB.Task - Dummy Task for GPIB Handler 003f ld hl,6806h ;GPIB.Sem - GPIB Task Semaphore 0042 call 0ce8h ;Call Wait - Wait on it for a long time 0045 jr f8h ;Back to GPIB.Task ;-----LowPriTask - Low Priority task 0047 call 0034h ;LowPriGPIB - GPIB Messages 004a call 00b0h ;LowPriRSA - RS232 port A Messages 004d call 00dfh ;LowPriRSB - RS232 port B Messages 0050 call 0cafh ;LowPriSpeech - Speech Messages 0053 call 0e8ah ;LowPriZ80 - Z80 Task 0056 call 0d44h ;CPUGive - Try and give up CPU to another task 0059 call 0034h ;LowPriGPIB - GPIB Messages (again) 005c call 0083h ;LowPriPointer - Pointer Messages 005f call 028eh ;LowPriFloppy - Floppy Task 0062 call 0926h ;LowPriKB - Keyboard Task 0065 call 0015h ;LowPriClock - Clock Messages 0068 call 0d44h ;CPUGIve - Try and give up CPU (again) 006b jp 0047h ;Back to LowPriTask to try again ;PointerInit 006e xor a ;Clear Pointer.Msg Message flag 006f ld (6810h),a 0072 ld a,03h ;Select SIO Register 3, Channel B 0074 out (13h),a 0076 ld a,00h ;Disable Receiver 0078 out (13h),a 007a ret ;Exit ;---XPointer - Pointer Request Handler 007b ld hl,6810h ;Pointer.Msg message flag 007e set 1,(hl) ;Set NAK bit 0080 jp 0b31h ;Goto PERQ.Enable and exit ;---LowPriPointer - NAK unwanted pointer messages 0083 ld hl,6810h ;Look at Pointer.Msg flag 0086 ld c,0bh ;DevPointer - Pointer device 0088 bit 1,(hl) ;Is the NAK bit set? 008a jp nz,0ad6h ;Yes, Goto SendNAK and exit 008d ret ;No, exit anyway 008e jp 0140h 0091 jp 0140h 0094 jp 0140h ;---RSAInit - Initialise RS232 port A 0097 xor a ;Clear RSA.Msg Message Flag 0098 ld (6809h),a 009b ld hl,00a5h ;Point to RSA.InitTbl Initialisation table 009e ld b,03h ;Size of RSA.InitTbl 00a0 ld c,12h ;SIO A Control A port 00a2 otir ;Send initialisation values 00a4 ret ;Exit ;---RSA.InitTbl - Initialisation values for RS232 port A 00a5 defb 18h ;Channel Reset 00a6 defb 01h ;Select Register 1 00a7 defb 00h ;Disable Interrupts ;---XRSA - RS232 port A Message Handler 00a8 ld hl,6809h ;Get RSA.Msg - RSA Message Flag 00ab set 1,(hl) ;Set NAK bit 00ad jp 0b31h ;Goto PERQEnable and continue ;LowPriRSA - Send NAK for any unwanted RSA Messages 00b0 ld c,04h ;DevRSA - RS232 port A device 00b2 ld hl,6809h ;RSA.Msg - RSA message flag 00b5 bit 1,(hl) ;Is the NAK bit set? 00b7 jp nz,0ad6h ;Yes, Goto SendNAK and exit 00ba ret ;No, just exit ;----RSATask - RS232 port A Dummy Task 00bb ld hl,6801h ;RSA.Sem - RSA Task Semaphore 00be call 0ce8h ;Call Wait, and wait on it 00c1 jr f8h ;Go back to RSATask and try again 00c3 jp 0140h ;---RSBInit - Initialise RS232 port B 00c6 xor a ;Clear RSB.Msg Message Flag 00c7 ld (680ah),a 00ca ld hl,00d4h ;Point to RSB.InitTbl Initialisation table 00cd ld b,03h ;Size of RSB.InitTbl 00cf ld c,42h ;SIO B Control port A 00d1 otir ;Send RSB.InitTbl to SIO 00d3 ret ;Exit ;RSB.InitTbl - RS232 port B Initialisation Table 00d4 defb 18h ;Channel Reset 00d5 defb 01h ;Select Register 1 00d6 defb 00h ;Disable Interrupts ;----XRSB - RS232 port B Message handler 00d7 ld hl,680ah ;Point to RSB.Msg Message Flag 00da set 1,(hl) ;Set NAK bit 00dc jp 0b31h ;Goto PERQEnable and exit ;---LowPriRSB - Send NAK for unwanted RSB Messages 00df ld c,05h ;DevRSB - RS232 port B device 00e1 ld hl,680ah ;RSB.Msg - look at RSB Message flag 00e4 bit 1,(hl) ;Is the NAK bit set? 00e6 jp nz,0ad6h ;Yes, Goto SendNAK and exit 00e9 ret ;No, Exit ;---RSBTask - Dummy Task for RS232 port B 00ea ld hl,6802h ;RSB.Sem - RSB task semaphore 00ed call 0ce8h ;Call Wait and Wait on it 00f0 jr f8h ;Go back to RSBTask 00f2 rst 38h 00f3 rst 38h 00f4 rst 38h 00f5 rst 38h 00f6 rst 38h 00f7 rst 38h 00f8 rst 38h 00f9 rst 38h 00fa rst 38h 00fb rst 38h 00fc rst 38h 00fd rst 38h 00fe rst 38h 00ff rst 38h 0100 rst 38h 0101 rst 38h 0102 rst 38h 0103 rst 38h 0104 rst 38h 0105 rst 38h 0106 rst 38h 0107 rst 38h 0108 rst 38h 0109 rst 38h 010a rst 38h 010b rst 38h 010c rst 38h 010d rst 38h 010e rst 38h 010f rst 38h 0110 defw 020eh ;End DMA Interrupt vector 0112 defw 0c81h ;PERQ Output Interrupt vector 0114 defw 09eah ;PERQ Interrupt vector 0116 defw 0655h ;Floppy Interrupt vector 0118 defw 0020h ;Dummy Interrupt vector 011a defw 01beh ;EOP Interrupt vector 011c defw ffffh 011e defw ffffh 0120 sub e 0121 inc c 0122 sub e 0123 inc c 0124 adc a,(hl) 0125 nop 0126 sub c 0127 nop 0128 sub h 0129 nop 012a sub h 012b nop 012c sub h 012d nop 012e sub h 012f nop ;---Keyboard Interrupt Vectors 0130 defw 099dh ;Keyboard Tx ISR 0132 defw 09b0h ;Keyboard status ISR 0134 defw 0972h ;Keyboard Rx ISR 0136 defw 09bbh ;Keyboard Error ISR 0138 jp c300h 013b nop 013c jp c300h 013f nop ;DummyISR - Dummy Interrupt service routine 0140 ei ;Reenable interrupts 0141 reti ;Exit ;---DMAInit - Initialise DMA system 0143 out (3dh),a ;Master clear DMA controller 0145 in a,(38h) ;Read DMA status port 0147 ld a,60h ;Active low Dreq, Dack, extended write 0149 out (38h),a ;Send to DMA command register 014b ld a,e5h ;Load response memory, 1 byte, level 5 014d out (61h),a ;Send to Interrupt controller command port 014f ld a,1ah ;Interrupt vector for channel 5 (EOP Interrupt) 0151 out (60h),a ;Send to data port 0153 ld a,e0h ;Load response memory, 1 byte, level 0 0155 out (61h),a ;Send to command port 0157 ld a,10h ;Interrupt vector for channel 0 (End DMA Int) 0159 out (60h),a ;Send to data port 015b ld a,10h ;Clear IRR and IMR 015d out (61h),a ;Send to command port 015f xor a ;Clear the DMA request flags in RAM for 0160 ld (6868h),a ;Channel 1 (GPIB) 0163 ld (686ch),a ;Channel 2 (SIO) 0166 ret ;Exit ;-----DMAtoMem - set up DMA to Memory 0167 ld l,a ;Save DMA Channel number in L 0168 dec bc ;Decrement Count since 8237 does one more ;transfer than the count value 0169 ld h,c ;Save C in H 016a sla a ;Multiply Channel by 2 - 2 registers/channel 016c add a,30h ;A now contains address register port 016e ld c,a ;Into C 016f out (3ch),a ;Select low byte to DMA (data doesn't matter) 0171 out (c),e ;Send low byte of address 0173 out (c),d ;Send high byte of address 0175 inc c ;C now points to word count register 0176 out (3ch),a ;Select low byte of word count 0178 out (c),h ;Send low byte of word count 017a out (c),b ;Send high byte of word count 017c ld a,44h ;Single mode ! Increment ! Write 017e or l ;Or in the Channel number 017f out (3bh),a ;Write to the DMA Mode register 0181 ld a,l ;Get Channel number back into A 0182 or 00h ;Set flags 0184 out (3ah),a ;Clear mask bit 0186 ld c,h ;Restore BC as count 0187 inc bc 0188 ret ;Exit ;-------DMAtoDEV - set up DMA from Memory 0189 ld l,a ;Save DMA Channel in L 018a dec bc ;Decrement count to avoid 'feature' of 8237 018b ld h,c ;Save C in H 018c sla a ;Multiply channel by 2 - there are 2 registers 018e add a,30h ;A now points to DMA Address register port 0190 ld c,a ;And now, so does C 0191 out (3ch),a ;Select low byte of the address 0193 out (c),e ;Write low address byte 0195 out (c),d ;Write high address byte 0197 inc c ;Point to word count port 0198 out (3ch),a ;Select low byte of word count 019a out (c),h ;Write low byte of word count 019c out (c),b ;And high byte 019e ld a,48h ;Single mode ! Increment ! read 01a0 or l ;OR in the channel number 01a1 out (3bh),a ;Send it to the DMA Mode register 01a3 ld a,l ;Get the channel number back in A 01a4 or 00h ;Set flags 01a6 out (3ah),a ;Clear mask bit 01a8 ld c,h ;Restore word count 01a9 inc bc 01aa ret ;Exit ;---DMASignal - raise signal if DMA transfer not complete (?) ;Enter with channel number in A 01ab ld h,a ;Save Channel number 01ac call 01f3h ;Call ReadDMAStatus to get byte count 01af ld a,b ;Test if byte count is 0 01b0 or c 01b1 jr z,0ah ;It is - goto DMASigExit 01b3 ld c,h ;put channel number in BC 01b4 ld b,00h 01b6 ld hl,6855h ;Base address of DMA semaphores 01b9 add hl,bc ;Point to correct semaphore for this channel 01ba call 0d04h ;Call Signal to raise signal ;---DMASigExit 01bd ret ;Exit ;---EOP ISR - Interrupt service routine for EOP interrupt 01be exx ;Save registers 01bf ex af,af' 01c0 in a,(38h) ;Read DMA channel status 01c2 push af ;Save it 01c3 bit 1,a ;Has channel 1 reached terminal count? 01c5 jr z,0bh ;No, goto NextChan2 01c7 ld a,01h ;Channel 1 (GPIB) 01c9 call 0219h ;Call StartNext to start next transfer 01cc ld hl,6856h ;Point to channel 1 semaphore 01cf call 0d04h ;Call signal to raise it, and fall to NextChan2 ;---NextChan2 01d2 pop af ;Restore channel number 01d3 push af ;Save it again 01d4 bit 2,a ;Has channel 2 reached terminal count? 01d6 jr z,0bh ;No, goto NextChan3 01d8 ld a,02h ;Channel 2 (SIO) 01da call 0219h ;Call startnext and start next transfer 01dd ld hl,6857h ;Point to channel 2 semaphore 01e0 call 0d04h ;Call signal to raise it, and fall to NextChan3 ;---NextChan3 01e3 pop af ;Restore channel number 01e4 bit 3,a ;has channel 3 (PERQ) reached terminal count? 01e6 jr z,06h ;No, goto EOPISR.Exit 01e8 ld hl,6858h ;Point to channel 3 semaphore 01eb call 0d04h ;Call signal to raise it, fall into EOPISR.Exit ;---EOPISR.Exit 01ee exx ;Restore registers 01ef ex af,af' 01f0 ei ;Reenable interrupts 01f1 reti ;Exit ;ReadDMAStatus - Enter with DMA channel in A ;Exit - DE = current DMA address ; BC = #bytes still to transfer 01f3 or 04h ;Set channel mask bit 01f5 out (3ah),a ;Write to mask register 01f7 and fbh ;Restore channel number 01f9 sla a ;Double it - there are 2 registers/channel 01fb add a,30h ;A now points to channel address port 01fd ld c,a ;Now, so does C 01fe out (3ch),a ;Clear byte flip-flop - low byte next 0200 in e,(c) ;Read low byte of address 0202 in d,(c) ;And high byte 0204 inc c ;Point to word count register 0205 out (3ch),a ;Clear byte flip-flop - low byte next 0207 in a,(c) ;Read low byte of count 0209 in b,(c) ;Read high byte of count 020b ld c,a ;BC now contains count from DMA chip 020c inc bc ;Intel chip does one more transfer than the ;count specifies. BC is now true count 020d ret ;Exit ;EndDMAISR - End of DMA interrupt service routine ;This is a dummy. If it is called, it simply masks the interrupt and exits 020e exx ;Save Registers 020f ex af,af' 0210 ld a,38h ;Set IMR bit 0 - mask end DMA interrupt 0212 out (61h),a ;Write to Interrupt controller command port 0214 exx ;Restore registers 0215 ex af,af' 0216 ei ;Reenable Interrupts 0217 reti ;Exit ;---StartNext - start next DMA transfer on channels 1,2 ;--Based on parameters stored in RAM. So, a task can set up the next transfer ;--While this one is running ;-- Channels 1(GPIB) and 2(SIO) ;--Count 6867h 686bh ;--Address 6869h 686dh ; Top 2 bits of the count word are the transfer flag (bit 7) - set if another ; DMA transfer is pending and direction (bit 6) - set if to memory. This limits ; the maximum block length to 16K bytes. 0219 cp 01h ;Is this for channel 1 (GPIB) 021b jr nz,13h ;No, goto StartNext.SIO 021d ld hl,6868h ;Look at GPIB count/flag word 0220 bit 7,(hl) ;Is a new transfer queued? 0222 ret z ;Exit if not 0223 res 7,(hl) ;Clear start flag bit 0225 ld bc,(6867h) ;Get byte count into BC 0229 ld de,(6869h) ;And address into DE 022d jp 0243h ;Go to StartNextDMA ;---StartNext.SIO 0230 cp 02h ;Is this for channel 2 (SIO)? 0232 ret nz ;Exit if not 0233 ld hl,686ch ;Look at SIO count/flag word 0236 bit 7,(hl) ;Is a new SIO transfer queued? 0238 ret z ;Exit if not 0239 res 7,(hl) ;Clear it 023b ld bc,(686bh) ;Get byte count in BC 023f ld de,(686dh) ;and address in DE, fall into StartNextDMA ;---StartNextDMA 0243 bit 6,b ;Test direction bit 0245 jp z,0189h ;Clear, goto DMAtoDev and exit 0248 res 6,b ;Set, clear it 024a jp 0167h ;Goto DMAtoMem and exit ;---Start of Floppy Module ;---FloppyInit - Initialise floppy device 024d ld a,00h ;Clear 024f ld (6834h),a ;FloppyCtrl.Sem - FDC semaphore 0252 ld (680ch),a ;Floppy.Msg - task message flags 0255 ld (6854h),a ;Floppy.Atn - Attention flag 0258 ld (683dh),a ;PERQ Floppy command byte 025b ld (684ch),a ;ResultClass - #bytes returned from FDC code 025e ld a,00h ;Clear 0260 ld (6843h),a ;DiskCmdTable instruction byte 0263 call 078bh ;Call DiskReadStatus - Get FDC Status 0266 ld hl,7adch ;Address of First sector buffer 0269 ld (6863h),hl ;Store it in SecBuff1 026c ld hl,7bdch ;Address of Second Sector buffer 026f ld (6865h),hl ;Store it in SecBuff2 0272 ld a,e3h ;Load response, 1 byte, level 3 0274 out (61h),a ;Send to interrupt controller command port 0276 ld a,16h ;Interrupt vector for channel 3 (Floppy Int) 0278 out (60h),a ;Send to data port 027a ret ;exit ;---XFloppy - Floppy Device Handler 027b ld a,(6826h) ;Get (PERQIBuff+2) - PERQ Command code 027e cp 0ch ;Is id CMD.IOSense? 0280 ld hl,6804h ;Point to Floppy.Sem - Task Semaphore 0283 jp nz,0d04h ;It wasn't, so exit via Signal and wake up ;Floppy.Task 0286 ld hl,680ch ;Point to Floppy.Msg Flag Byte 0289 set 2,(hl) ;Set Status request flag 028b jp 0b31h ;Exit via PERQEnable ;---LowPriFloppy - Low priority floppy task 028e ld c,03h ;DevFlop - Floppy Device 0290 xor a 0291 ld hl,6854h ;Look at DiskCommand Attention Flag 0294 cp (hl) ;Is it set? 0295 call nz,0aa4h ;Yes, call SendAttn and send Atten message 0298 ld hl,680ch ;Point to Floppy.Msg Flag byte 029b ld a,(hl) ;Read flags 029c and 07h ;Only bottom 3 bits used 029e ret z ;Exit if no flags set 029f ld c,03h ;DevFlop - Floppy Device 02a1 bit 0,a ;Is the Ack Flag set? 02a3 jp nz,0addh ;Yes, Exit via SendAck 02a6 bit 1,a ;Is the NAK Flag set? 02a8 jp nz,0ad6h ;Yes, Exit via SendNAK 02ab bit 2,a ;Is the Status Request flag set? 02ad ret z ;Exit if not 02ae res 2,(hl) ;It was. Now clear Status Request flag 02b0 ld hl,6800h ;Point to PERQOCmd - Perq output semaphore 02b3 call 0ce8h ;Wait for Fifo to be free 02b6 ld a,0ah ;10 bytes in message 02b8 ld (6815h),a ;Store in output buffer 02bb ld a,03h ;DevFlop - floppy device 02bd ld (6816h),a ;Store in output buffer 02c0 ld a,07h ;Status message code 02c2 ld (6817h),a ;Store in output buffer 02c5 ld bc,0008h ;8 bytes FDC Status 02c8 ld hl,684ch ;Point to Disk results buffer 02cb ld de,6818h ;Point to next address in output buffer 02ce ldir ;Copy FDC results into output buffer 02d0 jp 0a89h ;Exit via SendPERQ and send message ;---FloppyTask - handle the Floppy Disk System ;---Start by initializing the FDC 02d3 ld a,1ah ;EOT Value 02d5 ld (6835h),a ;Store in DskParam.EOT 02d8 ld a,07h ;Gap Length 02da ld (6836h),a ;Store in DskParam.GPL 02dd ld a,00h ;Sector Size 02df ld (6837h),a ;Store in DiskParam.Size 02e2 ld a,00h ;MT/MF/Skip Flags 02e4 ld (6838h),a ;Store in DiskParam.Flag 02e7 ld hl,683dh ;Point to Disk Command byte 02ea ld (hl),15h ;Specify Command 02ec inc hl ;Point to parameters 02ed ld (hl),03h ;Step Rate 02ef inc hl ;Point to next 02f0 ld (hl),0fh ;Head Unload delay 02f2 inc hl ;Point to Next 02f3 ld (hl),24h ;Head load delay 02f5 call 0697h ;Call DiskExecute - do the command 02f8 jp c,0312h ;Go if error to FloppyTask.Loop 02fb ld hl,683dh ;Point to command code 02fe ld (hl),17h ;Recalibrate command 0300 inc hl ;Point to parameter 0301 xor a ;Unit 0 0302 ld (hl),a ;Store in the parameter table 0303 ld (6839h),a ;Clear cylinder address 0306 call 0697h ;Call DiskExecute 0309 jp c,0312h ;Go if error to FloppyTask.Loop 030c ld hl,6834h ;Point to FloppyCtrl.Sem - Controller Semaphore 030f call 0ce8h ;Call Wait - Wait for command to finish ;---FloppyTask.Loop 0312 ld hl,6804h ;Point to Floppy.Sem - Task Semaphore 0315 call 0ce8h ;Wait for a command ;---FloppyTask.Execute - Execute command in PERQ input buffer 0318 ld de,683dh ;Point to floppy command buffer 031b ld hl,6826h ;Point to PERQIBuff+2 - Perq Command 031e ld bc,0006h ;Maximum of 6 bytes in any floppy command 0321 ldir ;Transfer the PERQ command into the floppy ;Command buffer 0323 call 0b31h ;Call PERQEnable, and reenable input port 0326 ld hl,683dh ;Point to the Floppy command buffer 0329 ld a,(hl) ;Get the command code 032a inc hl ;Point to parameters 032b call 0330h ;Call ExecPerqFlop, and perform the command 032e jr e2h ;Go back to FloppyTask.Loop for the next ;command ;---ExecPerqFlop - Execute Perq Floppy Command 0330 cp 08h ;Seek Command? 0332 jp z,04d3h ;Yes, Goto PerqSeek 0335 cp 10h ;Read Data Command? 0337 jp z,03f3h ;Yes, Goto PerqReadFlop 033a cp 11h ;Write Data Command? 033c jp z,0459h ;Yes, Goto PerqWriteFlop 033f cp 17h ;Recalibrate Command? 0341 jp z,04d8h ;Yes, Goto PerqRecalib 0344 cp 18h ;Sense Status Command? 0346 jp z,04fah ;Yes, Goto PerqFlopStat 0349 cp 15h ;Specify Command? 034b jp z,04f1h ;Yes, Goto PerqSpec 034e cp 16h ;Format Track Command? 0350 jp z,0518h ;Yes, Goto PerqFormatTrk 0353 cp 09h ;Set Parameters Command? 0355 jp z,03d6h ;Yes, Goto PerqSetParams 0358 cp 12h ;Read ID command? 035a jp z,0506h ;Yes, Goto PerqRdID 035d cp 13h ;Read Deleted Data Command? 035f jp z,03f3h ;Yes, Goto PerqReadFlop 0362 cp 14h ;Write Deleted Data Command? 0364 jp z,0459h ;Yes, Goto PerqWriteFlop 0367 cp 0ah ;Boot Command? 0369 jp z,056ch ;Yes, Goto PerqBoot 036c cp 0bh ;Initialise command? 036e jp z,0550h ;Yes, Goto PerqFlopInit ;---FloppyNAK 0371 ld hl,680ch ;Point to Floppy.Msg Flag byte 0374 ld c,03h ;DevFlop - Floppy Device 0376 jp 0ad6h ;Exit via SendNAK ;---FloppyAck 0379 ld hl,680ch ;Point to Floppy.Msg Flag Byte 037c ld c,03h ;DevFlop - Floppy Device 037e jp 0addh ;Exit via SendAck ;---FlopPendingNAK - Set NAK flag for floppy device 0381 ld hl,680ch ;Point to Floppy.Msg - flag byte 0384 set 1,(hl) ;Set NAK bit 0386 pop hl ;Clean up stack - drop return address 0387 jp 0318h ;Goto FloppyTask.Execute ;---GetFlopParams - Get parameters for a read/write command 038a inc hl ;Point to second parameter - Sector Number 038b ld a,(hl) ;Get it 038c ld (683ah),a ;Save in disk parameter block 038f inc hl ;Point to 3rd parameter (Word) Byte count 0390 ld c,(hl) ;Get it into BC 0391 inc hl 0392 ld b,(hl) 0393 ld (683bh),bc ;Save it in the parameter block 0397 ret ;Exit ;---FlopBytesLeft - Returns how many bytes to transfer ;---On exit, BC contains the # bytes to transfer from the next sector ;--- HL contains the # bytes left after that 0398 ld a,(6837h) ;Read sector size code 039b ld bc,0080h ;128 bytes/sector 039e or a ;Clear Carry 039f jr z,15h ;If sector code was 0, goto FlopBytesLeft1 03a1 ld bc,0100h ;256 bytes/sector 03a4 dec a 03a5 jr z,0fh ;If sector code was 1, goto FlopBytesLeft1 03a7 ld bc,0200h ;512 bytes/sector 03aa dec a 03ab jr z,09h ;If sector code was 2, goto FlopBytesLeft1 03ad ld bc,0400h ;1024 bytes/sector 03b0 dec a 03b1 jr z,03h ;If sector code was 3, goto FlopBytesLeft1 03b3 ld bc,0080h ;Default to 128 bytes/sector ;---FlopBytesLeft1 03b6 ld hl,(683bh) ;Read current byte count 03b9 or a ;Clear Carry 03ba sbc hl,bc ;Subtract sector size from byte count 03bc ret nc ;Exit if +ve - at least one more to go ;(BC contains sector size) 03bd add hl,bc ;Restore byte count 03be ld b,h ;transfer remainder to BC 03bf ld c,l 03c0 xor a ;Clear HL - no more bytes after this transfer 03c1 ld l,a 03c2 ld h,a 03c3 ret ;Exit ;CheckFlopRWResult - Check result from FDC ;Carry set if error 03c4 ld hl,684ch ;Point to DiskResultClass 03c7 ld a,(hl) ;Read value 03c8 or a ;Is it 0 (No bytes returned) 03c9 scf ;Set carry flag (for error) 03ca ret z ;And exit if so 03cb cp 02h ;Is is 2 (1 byte returned) 03cd scf ;Set carry flag and 03ce ret z ;Exit if so 03cf inc hl ;Point to Result.ST0 03d0 ld a,(hl) ;Get value 03d1 and c0h ;Look at interrupt code 03d3 ret z ;Exit if 0 (normal completion) 03d4 scf ;Set carry (error) flag 03d5 ret ;Exit ;---PerqSetParams - Set Disk Parameters 03d6 ld b,(hl) ;Get EOT Value 03d7 inc hl ;Point to next byte 03d8 ld c,(hl) ;Get Gap Length 03d9 inc hl ;Point to next byte 03da ld a,(hl) ;Get Sector Size from PERQ 03db inc hl ;Point to next byte 03dc cp 02h ;Test Sector Size 03de jr nc,91h ;Exit via FloppyNAK if sector size too big 03e0 ld (6837h),a ;Store sector size in paramter block 03e3 ld a,(hl) ;Get Density flags 03e4 and e0h ;Only top 3 bits used 03e6 ld (6838h),a ;Store in parameter block 03e9 ld hl,6835h ;Point to EOT address 03ec ld (hl),b ;Save EOT Value 03ed ld hl,6836h ;Point to Gap Length 03f0 ld (hl),c ;Save Gap Length 03f1 jr 86h ;Exit via FloppyAck ;---PerqReadFlop - Read floppy disk and transfer it to the PERQ 03f3 call 038ah ;Call GetFlopParams 03f6 ld a,c ;Test if Byte cound is 0 03f7 or b 03f8 jp z,0379h ;If it is, Exit via FloppyAck 03fb call 0448h ;Call PerqReadCmd to start transfer 03fe jr c,45h ;If Error, Goto FlopReadNAK ;---PerqRdFLoop 0400 ld de,(6863h) ;Swap the pointers to the sector buffers 0404 ld hl,(6865h) 0407 ld (6863h),hl 040a ld (6865h),de 040e ld hl,6834h ;Point to FloppyCtrl.Sem - FDC Semaphore 0411 call 0ce8h ;Call Wait - wait for transfer to complete 0414 call 03c4h 0417 jr c,2ch ;Goto FlopReadNAK if error 0419 ld hl,683ah ;Point to current sector parameter 041c inc (hl) ;Increment it 041d call 0398h ;Call FlopBytesLeft to find how many more bytes ;to transfer 0420 push bc ;Save size 0421 ld (683bh),hl ;Store #bytes left in parameter block 0424 ld a,l ;Test to see if it was 0 0425 or h 0426 call nz,0448h ;No, Call PerqRdCommand to start next transfer 0429 pop bc ;Restore Size 042a jr c,19h ;If error, goto FlopReadNAK 042c ld hl,6804h ;Point to Floppy.Sem - task Semaphore 042f ld de,(6865h) ;Pointer to buffer that's just been loaded 0433 ld a,03h ;DevFlop - Floppy Device 0435 call 0bbah ;Call SendBlkData and send the buffer to the ;PERQ 0438 jp c,0381h ;If Error, exit via FlopPendingNAK 043b ld hl,(683bh) ;Get remaining byte count 043e ld a,h ;test if it's 0 043f or l 0440 jr nz,beh ;No, goto PerqRdFLoop 0442 jp 0379h ;All done. Exit via FloppyAck ;---FlopReadNAK 0445 jp 0371h ;Exit via FloppyNAK ;---PerqRdCmd - Set up DMA and execute an FDC Read command 0448 call 0398h ;Call FlopBytesLeft - determine size of this ;Transfer 044b ld de,(6863h) ;Pointer to sector buffer 044f ld a,00h ;Use DMA Channel 0 0451 di ;Do not disturb 0452 call 0167h ;Call DMAtoMem - Set up transfer 0455 ei ;Reenable interrupts 0456 jp 0697h ;Exit via DiskExecute to do the command ;---PerqWriteFlop - Write a sector to the floppy from the PERQ 0459 call 038ah ;Call GetFlopParams - get sector/byte count 045c ld a,c ;Test if byte count is 0 045d or b 045e jp z,0379h ;Exit if so - nothing to do 0461 call 04b6h ;Call FlopGetBlk and get block from PERQ 0464 jr c,4ah ;If error, Goto FlopWrPNAK and exit ;---FlopWrLoop 0466 ld a,b ;Test if block size is 0 0467 or c 0468 jr z,3dh ;Exit if so via FlopWrAck 046a ld de,(6863h) ;Swap the pointers to the sector buffers 046e ld hl,(6865h) 0471 ld (6863h),hl 0474 ld (6865h),de 0478 push bc ;Save byte count 0479 call 04c5h ;Call PerqWrCmd and write the sector 047c pop bc ;Restore the byte count 047d jr c,34h ;Goto FlopWrNAK if error 047f ld hl,683ah ;Point to sector address 0482 inc (hl) ;Increment sector 0483 ld hl,(683bh) ;Point to byte count 0486 or a ;Clear carry 0487 sbc hl,bc ;Subtract size of this sector 0489 ld (683bh),hl ;Store back in byte count 048c ld a,h ;Is the remaining byte count 0? 048d or l 048e call nz,04b6h ;No, call FlopGetBlk and get some data 0491 jr c,17h ;If error, Exit via FlopWaitNAK 0493 push bc ;Save byte count 0494 ld hl,6834h ;Point to FloppyCtrl.Sem - FDC Semaphore 0497 call 0ce8h ;Call Wait - wait for Write to finish 049a call 03c4h ;Call CheckFlopRWResult - Check FDC return 049d pop bc ;Restore byte count 049e jr c,13h ;If error, goto FlopWrNAK and exit 04a0 ld hl,(683bh) ;Point to remaining byte count 04a3 ld a,h ;Test if it's 0 04a4 or l 04a5 jr nz,bfh ;Go back to FlopWrLoop for more if not, else... ;---FlopWrAck 04a7 jp 0379h ;Exit via FloppyAck ;---FlopWaitNAK 04aa ld hl,6834h ;Point to FloppyCtrl.Sem 04ad call 0ce8h ;Call Wait - Wait for FDC to finish and ;Fall into FlopWrPNAK ;---FlopWrPNAK 04b0 jp 0381h ;Exit via FlopPendingNAK ;---FlopWrNAK 04b3 jp 0371h ;Exit via FloppyNAK ;---FlopGetBlk - Get a block from the PERQ 04b6 call 0398h ;Call FlopBytesLeft to determine size 04b9 ld de,(6863h) ;Pointer to 1st sector buffer 04bd ld a,03h ;DevFlop - Floppy Device 04bf ld hl,6804h ;Pointer to Floppy.Sem - Task Semaphore 04c2 jp 0b40h ;Goto GetBlkData and read in block ;---PerqWrCmd - Set up DMA and perform write command 04c5 ld de,(6865h) ;Pointer to current sector buffer 04c9 ld a,00h ;DMA Channel 0 04cb di ;Do not disturb 04cc call 0189h ;Call DMAToDev and set up transfer 04cf ei ;Reenable interrupts 04d0 jp 0697h ;Exit via DiskExecute and perform command ;---PerqSeek - Set Floppy Cylinder 04d3 ld a,(683fh) ;Get Second PERQ Parameter (1st is Unit) 04d6 jr 01h ;Goto DoSeek ;---PerqRecalib - Recalibrate Floppy disk head position 04d8 xor a ;Clear cylinder address and fall into DoSeek ;---DoSeek - Perform a head movement 04d9 ld (6839h),a ;Store new cylinder address in the parameter ;block 04dc call 0697h ;Call DiskExecute and perform the command 04df jp c,0371h ;Exit via FloppyNAK if error 04e2 ld hl,6834h ;Point to FloppyCtrl.Sem - FDC Semaphore 04e5 call 0ce8h ;Call Wait - wait for device to finish 04e8 call 03c4h ;Call CheckFlopRWResult - Check result code 04eb jp c,0371h ;Exit via FloppyNAK if error 04ee jp 0379h ;OK, Exit via FloppyAck ;---PerqSpec - Specify Disk parameters 04f1 call 0697h ;Call DiskExecute to perform the command 04f4 jp c,0371h ;Error? Yes, Exit via FloppyNAK 04f7 jp 0379h ;No, Exit via FloppyAck ;---PerqFlopStat - Report disk status 04fa call 0697h ;Call DiskExecute and do the command 04fd jp c,0371h ;Exit via FloppyNAK if error 0500 ld hl,680ch ;Point to Floppy.Msg Flag byte 0503 set 2,(hl) ;Set Status Request Flag 0505 ret ;Exit ;---PerqRdID - Read ID marker 0506 call 0697h ;Call DiskExecute and do the command 0509 jp c,0371h ;Exit via FloppyNAK if error 050c ld hl,6834h ;Point to FloppyCtrl.Sem - FDC Semaphore 050f call 0ce8h ;Call Wait - Wait for FDC to finish 0512 ld hl,680ch ;Point to Floppy.Msg Flag byte 0515 set 2,(hl) ;Set Status Request Flag 0517 ret ;Exit ;---PerqFormatTrk - Format a Floppy disk track 0518 ld b,00h ;Clear B 051a ld hl,683fh ;Read 1st Parameter (sectors/track) 051d ld c,(hl) ;Get it 051e sla c ;Multiply by 4 - 4 bytes for each sector 0520 sla c ;Header 0522 ld de,(6863h) ;Point to 1st sector buffer 0526 ld a,03h ;DevFlop - Floppy Device 0528 ld hl,6804h ;Floppy.Sem - Task Semaphore 052b call 0b40h ;Call GetBlkData and read data from PERQ 052e jp c,0381h ;Exit via FloppyPendingNAK if error 0531 ld de,(6863h) ;Point to 1st sector buffer 0535 ld a,00h ;DMA Channel 0 0537 di ;Do Not Disturb 0538 call 0189h ;Call DMAToDev and set up transfer 053b ei ;Reenable Interrupts 053c call 0697h ;Call DiskExecute and perform command 053f ld hl,6834h ;Point to FloppyCtrl.Sem - FDC Semaphore 0542 call 0ce8h ;Call Wait - Wait for FDC to Finish 0545 call 03c4h ;Call CheckFlopRWResult - Did it complete OK? 0548 jr c,03h ;Go if Error to FormatNAK 054a jp 0379h ;Exit via FloppyAck ;---FormatNAK 054d jp 0371h ;Exit via FloppyNAK ;---PerqFlopInit - Initialise Floppy 0550 ld a,00h ;Clear 0552 ld (6834h),a ;FloppyCtrl.Sem - FDC Semaphore 0555 ld (680ch),a ;Floppy.Msg - Flag byte 0558 ld (6854h),a ;Attention Flag 055b ld (683dh),a ;Perq disk command 055e ld (684ch),a ;Result Class Code 0561 ld a,00h ;Clear 0563 ld (6843h),a ;FDC Command in command table 0566 call 078bh ;Call DiskReadStatus to report FDC Status 0569 jp 0379h ;Exit via FloppyAck ;PerqBoot - Transfer boot block to PERQ 056c ld a,1ah ;EOT Value 056e ld (6835h),a ;Save in parameter block 0571 ld a,07h ;Gap Length 0573 ld (6836h),a ;Save in parameter block 0576 ld a,00h ;Sector Size (128 bytes) 0578 ld (6837h),a ;Save in parameter block 057b ld a,00h ;FDC Flags (Single Density) 057d ld (6838h),a ;Save in parameter block 0580 ld hl,683dh ;Point to disk command block 0583 ld (hl),15h ;Specify command 0585 inc hl ;Point to next byte 0586 ld (hl),03h ;Step rate 0588 inc hl ;Point to next byte 0589 ld (hl),0fh ;Unload time 058b inc hl ;Point to next byte 058c ld (hl),24h ;Load delay 058e call 0697h ;Call DiskExecute and perform the command 0591 jp c,0371h ;If error, exit via FloppyNAK 0594 ld hl,683dh ;Point to disk command block 0597 ld (hl),17h ;Recalibrate command 0599 inc hl ;Point to next byte 059a xor a ;Select Unit 0 059b ld (hl),a ;Store in command block 059c ld (6839h),a ;Clear cylinder address 059f call 0697h ;Call DiskExecute and recalibrate 05a2 jp c,0371h ;If error, exit via FloppyNAK 05a5 ld hl,6834h ;Point to FloppyCtrl.Sem - FDC Semaphore 05a8 call 0ce8h ;Call Wait - Wait for command to finish 05ab ld a,01h ;Sector 1, Cylinder 1 05ad ld (683ah),a ;Store in command block 05b0 ld (6839h),a 05b3 xor a ;Select unit 0, head 0 05b4 ld (683eh),a ;Store in command block 05b7 call 0612h ;CallBootRead and read in sector 05ba jr c,53h ;Goto BootNAK if Error 05bc ld hl,6834h ;Point to FloppyCtrl.Sem - FDC Semaphore 05bf call 0ce8h ;Call Wait and wait for FDC to finish 05c2 call 03c4h ;Call CheckFlopRWResult to test for errors 05c5 jr c,48h ;Goto BootNAK if Error 05c7 ld hl,(6863h) ;Point to first sector buffer 05ca ld a,(hl) ;Get 1st byte 05cb cp 55h ;Is is 01010101 ? 05cd jr nz,40h ;Goto BootNAK if not 05cf inc hl ;Point to next byte 05d0 ld a,(hl) ;Get it 05d1 cp aah ;Is is 10101010 ? 05d3 jr nz,3ah ;Goto BootNAK if error 05d5 call 0645h ;Call NextSector - Set up parameters for next ;Sector 05d8 call 0612h ;Call BootRead and read it in 05db jr c,32h ;Goto BootNAK if error ;---BootLoop 05dd ld de,(6863h) ;Exchange sector buffer pointers 05e1 ld hl,(6865h) 05e4 ld (6863h),hl 05e7 ld (6865h),de 05eb ld hl,6834h ;Point to FloppyCtrl.Sem - FDC Semaphore 05ee call 0ce8h ;Wait until transfer has completed 05f1 call 03c4h ;Call CheckFlopRWResult - Check for errors 05f4 jr c,19h ;Goto BootNAK if Error 05f6 call 0645h ;Call NextSector - Set up Next sector address 05f9 call 0612h ;Call BootRead and read it in 05fc jr c,11h ;Goto BootNAK if error 05fe ld hl,6804h ;Point to Floppy.Sem - Task Semaphore 0601 ld bc,0080h ;128 bytes to transfer 0604 ld de,(6865h) ;Pointer to second sector buffer 0608 ld a,03h ;DevFlop - Floppy Device 060a call 0c2bh ;Call SendBootData and transfer last sector ;to the PERQ 060d jr ceh ;Go back to BootLoop for next sector ;---BootNAK 060f jp 0371h ;Exit via FloppyNAK ;---BootRead - Read in Boot Sector 0612 ld a,(683ah) ;Read Sector number 0615 cp 01h ;Sector 1? 0617 jr nz,16h ;No, Goto BootNoSeek 0619 ld a,(683eh) ;Read Unit/Head parameter 061c bit 2,a ;Is it head 0? 061e jr nz,0fh ;Goto BootNoSeek if not 0620 ld hl,683dh ;Point to Disk parameter block 0623 ld (hl),08h ;Store Seek Command 0625 call 0697h ;Call DiskExecute and Seek 0628 ret c ;Exit if error 0629 ld hl,6834h ;Point to FloppyCtrl.Sem - FDC Semaphore 062c call 0ce8h ;Call Wait - Wait for Seek to finish ;---BootNoSeek 062f ld bc,0080h ;128 bytes to transfer 0632 ld de,(6863h) ;Pointer to 1st sector buffer 0636 ld a,00h ;DMA Channel 0 0638 di ;Do Not Disturb 0639 call 0167h ;Call DMAtoMem and set up trnasfer 063c ei ;Reenable Interrupts 063d ld hl,683dh ;Point to Disk parameter block 0640 ld (hl),10h ;Read Data Command 0642 jp 0697h ;Exit via DiskExecute and read in sector ;---NextSector - Update FDC parameters for the next sector 0645 ld hl,683ah ;Point to Sector address 0648 inc (hl) ;Increment it 0649 ld a,(6835h) ;Get the EOT (sectors/track) value 064c cp (hl) ;After EOT? 064d ret nc ;Return if not 064e ld (hl),01h ;Sector 1 0650 ld hl,6839h ;Point to Cylinder address 0653 inc (hl) ;Increment cylinder position 0654 ret ;Exit ;FloppISR - Floppy Disk Interrupt service routine 0655 exx ;Save registers 0656 ex af,af' 0657 ld hl,6843h ;Point to DiskCmdTable 065a ld a,(hl) ;Read Disk Controller command 065b and 1fh ;Mask out MT,MF,SK flags 065d jr z,1fh ;If zero, goto DiskIntNoCmd 065f cp 0fh ;Was it a seek command? 0661 jr z,04h ;Go if so to DiskIntNoStat 0663 cp 07h ;Was it Recalibrate? 0665 jr nz,07h ;No, Goto DiskIntStat ;---DiskIntNoStat ;--Seek and recalibrate have no result phase, so give them one 0667 ld (hl),08h ;Store Sense Interrupt command in DiskCmdTable 0669 ld b,01h ;1 byte in command 066b call 076ah ;Call DiskCommand ;---DiskIntStat 066e call 078bh ;Call DiskReadStatus and read FDC status 0671 ld hl,6834h ;Point to FloppyCtrl.Sem - FDC Semaphore 0674 call 0d04h ;Call Signal and wake up anything waiting 0677 ld a,00h ;Clear DiskCmdTable (1st byte - Instruction) 0679 ld (6843h),a ;Next time we get a DiskIntNoCmd 067c jr 14h ;Goto FloppISR.Exit ;---DiskIntNoCmd 067e ld (hl),08h ;Sense Interrupt Status Command 0680 ld b,01h ;1 byte long 0682 call 076ah ;Call DiskCommand 0685 ld a,00h ;Clear Intstruction byte in DiskCmdTbl 0687 ld (6843h),a 068a call 078bh ;Call DiskReadStatus 068d ld hl,6854h ;Point to Attention flag 0690 set 0,(hl) ;Set it ;---FloppISR.Exit 0692 exx ;Restore Registers 0693 ex af,af' 0694 ei ;Reenable interrupts 0695 reti ;Exit ;DiskExecute - Execute disk command specified by parameter block 0697 ld hl,6843h ;Point to DiskCmdTable 069a ld a,(683dh) ;Read PERQ Disk Command 069d cp 10h ;Read Data Command 069f jr z,2ch ;Goto DiskReadData 06a1 cp 11h ;Write data Commnd 06a3 jr z,30h ;Goto DiskWriteData 06a5 cp 08h ;Seek Command 06a7 jp z,075ah ;Goto DiskSeek 06aa cp 17h ;Recalibrate command 06ac jp z,070fh ;DiskRecalib 06af cp 13h ;Read Deleted Data command 06b1 jr z,1eh ;Goto DiskReadDel 06b3 cp 14h ;Write Deleted data command 06b5 jr z,22h ;Goto DiskWriteDel 06b7 cp 12h ;Read ID command 06b9 jp z,06e8h ;Goto DiskReadID 06bc cp 15h ;Specify Command 06be jp z,072bh ;Goto DiskSpecify 06c1 cp 16h ;Format track command 06c3 jp z,06f2h ;Goto DiskFormatTrk 06c6 cp 18h ;Sense Drive Status Command 06c8 jp z,071bh ;Goto DiskSenseDr 06cb scf 06cc ret ;------------------------------- ;---Disk Command routines ;---All entered with HL pointing to DiskCmdTable at 6843h ;------------------------------- ;---DiskReadData - Read Data 06cd ld b,06h ;Read data command 06cf jr 0ch ;Goto DiskDataCommand ;---DiskReadDel - Read Deleted Data 06d1 ld b,0ch ;Read deleted data command 06d3 jr 08h ;Goto DiskDataCommand ;---DiskWriteData - Write Data 06d5 ld b,05h ;Write data command 06d7 jr 04h ;Goto DiskDataCommand ;---DiskWriteDel - Write Deleted Data 06d9 ld b,09h ;Write deleted data command 06db jr 00h ;Goto DiskDataCommand ;---DiskDataCommand - Perform a data transfer command 06dd call 07c3h ;Call DiskCmdUnit - Set up command bytes 06e0 call 07cfh ;Call DiskCmdParams - Set up parameters 06e3 ld b,09h ;9 bytes for the command 06e5 jp 076ah ;Exit via DiskCommand ;---DiskReadID - Execute Read ID Command 06e8 ld b,0ah ;ReadID Command code 06ea call 07c3h ;Call DiskCmdUnit - Set up command bytes 06ed ld b,02h ;2 bytes in command 06ef jp 076ah ;Exit via DiskCommand ;---DiskFormatTrk - Format a track 06f2 ld b,0dh ;Format Track Command - CHECK THIS!!! 06f4 call 07c3h ;Call DiskCmdUnit - Set up first 2 bytes 06f7 ld a,(6837h) ;Get sector size 06fa ld (hl),a ;Store it in DiskCmdTable 06fb inc hl ;Point to next byte 06fc ld a,(683fh) ;Get sectors/track 06ff ld (hl),a ;Store it in DiskCmdTable 0700 inc hl ;Point to next byte 0701 ld a,(6841h) ;Read GAP3 length 0704 ld (hl),a ;Store it in DiskCmdTable 0705 inc hl ;Point to next byte 0706 ld a,(6840h) ;Get filler byte 0709 ld (hl),a ;Store in DiskCmdTable 070a ld b,06h ;6 bytes in command 070c jp 076ah ;Exit via DiskCommand ;---DiskRecalib - Recalibrate head on current drive 070f ld (hl),07h ;Recalibrate command code 0711 inc hl ;Point to next byte of DiskCmdTable 0712 ld a,(683eh) ;Get unit/head parameter 0715 ld (hl),a ;Store it in DiskCmdTable 0716 ld b,02h ;2 bytes in command 0718 jp 076ah ;Exit via DiskCommand ;---DiskSenseDr - Sense Drive Status 071b ld (hl),04h ;Sense Drive Status Command 071d inc hl ;Point to next byte of DiskCmdTable 071e ld a,(683eh) ;Get unit/head parameter 0721 ld (hl),a ;Save in DiskCmdTable 0722 ld b,02h ;2 bytes in command 0724 call 076ah ;Call DiskCommand 0727 ret c ;Exit if error 0728 jp 078bh ;No Error, exit via DiskReadStatus ;---DiskSpecify - Specify disk characteristics 072b ld (hl),03h ;Specify command code 072d inc hl ;Point to next byte of DiskCmdTable 072e ld a,(683eh) ;Get step rate value 0731 cp 10h ;Is it too big 0733 jr nc,23h ;Go if so to DskSpecError 0735 neg ;Invert it (Intel feature!) 0737 sla a ;Get it into the high nybble 0739 sla a 073b sla a 073d sla a 073f ld b,a ;Save step rate in B 0740 ld a,(683fh) ;Get head unload time 0743 cp 10h ;Is it too big? 0745 jr nc,11h ;If so, goto DskSpecError 0747 or b ;Merge in the step rate 0748 ld (hl),a ;Store in DskCmdTable 0749 inc hl ;Point to next byte 074a ld a,(6840h) ;Get Head load time 074d cp 80h ;Is it too big? 074f jr nc,07h ;If so, goto DskSpecError 0751 sla a ;Shift Head load time into top 7 bits 0753 ld (hl),a ;Store in DskCmdTable 0754 ld b,03h ;3 bytes in command 0756 jr 12h ;Exit via DiskCommand ;---DskSpecError 0758 scf ;Set carry flag on error 0759 ret ;Exit ;---DiskSeek - Seek to a track 075a ld (hl),0fh ;Seek Command byte 075c inc hl ;Point to next byte of DiskCmdTable 075d ld a,(683eh) ;Unit/head select flags 0760 ld (hl),a ;Store in DiskCmdTable 0761 inc hl ;Point to next byte 0762 ld a,(6839h) ;Cylinder address 0765 ld (hl),a ;Store in DiskCmdTable 0766 ld b,03h ;3 bytes in command 0768 jr 00h ;Goto DiskCommand ;---DiskCommand - Write disk command bytes to the disk controller ;---6843h (DiskCmdTbl) is the start of the disk command table ;---B = #bytes to send ;---Carry set on exit if error 076a ld hl,6843h ;Point to DiskCmdTbl ;---DskSendNext 076d ld c,ffh ;Retry count for testing if ready ;---CmdTestRQM 076f in a,(20h) ;Read disk controller status register 0771 bit 7,a ;Check the RQM (Request for Master) bit 0773 jr nz,05h ;Go if set to SendDskCmd - OK to send 0775 dec c ;Decrement retry count 0776 jr nz,f7h ;Not given up - back to CmdTestRQM 0778 scf ;There is an error - set carry 0779 ret ;Exit ;---SendDskCmd 077a bit 6,a ;Look at DIO (Data Input/Output) Bit 077c jr nz,08h ;Go if set to DskSendError-this should not occur 077e ld a,(hl) ;Read byte from command table 077f inc hl ;Point to next byte in command table 0780 out (21h),a ;Write this byte to the FDC Chip 0782 djnz e9h ;Decrement counter (B), and goto DskSendNext 0784 or a ;No error - clear carry 0785 ret ;Exit ;---DskSendError 0786 call 078bh ;Call DskReadStatus to get FDC Status 0789 scf ;Set carry - there was an error 078a ret ;Exit ;---DiskReadStatus - Read status from FDC Chip ;---FDC result bytes are stored in Diskresult. ;---Carry set on exit if there was an error 078b ld hl,684dh ;Point to DiskResult for storing result table 078e ld b,00h ;Counter of #bytes read ;---DskGetNxt 0790 ld c,ffh ;Retry counter ;---StatTestRQM 0792 in a,(20h) ;Read disk controller status register 0794 bit 7,a ;Test RQM bit 0796 jr nz,05h ;Go if set to DskStatNxt 0798 dec c ;Decrement retry count 0799 jr nz,f7h ;Given up? If not, back to StatTestRQM 079b scf ;Controller timed out - Set carry for error 079c ret ;Exit ;---DskStatNxt 079d bit 6,a ;Test DIO bit 079f jr z,07h ;Goto DskStatExit if no more to read 07a1 in a,(21h) ;Read next result byte from FDC 07a3 ld (hl),a ;Store it in the RAM result table 07a4 inc hl ;Point to next location 07a5 inc b ;Increment counter 07a6 jr e8h ;Go back to DskGetNxt to get next byte ;---DskStatExit 07a8 ld a,b ;A now contains the #of result bytes read 07a9 ld b,03h ;And B is a code for the result type 07ab cp 07h ;Did we get 7 bytes? (B=3) 07ad jr z,0eh ;Yes, goto QuitDskStat 07af ld b,02h ;No 07b1 cp 01h ;Did we get one byte (B=2) 07b3 jr z,08h ;Yes, goto QuitDskStat 07b5 ld b,01h ;No 07b7 cp 02h ;Did we get 2 bytes (B=1) 07b9 jr z,02h ;Yes, goto QuitDskStat 07bb ld b,00h ;No, B=0 ;---QuitDskStat 07bd ld a,b ;Copy Result class into A 07be ld (684ch),a ;Save in DskResultClass 07c1 or a ;No error, clear carry 07c2 ret ;Exit ;DskCmdUnit - Set up command and unit/head select words ;On Entry, HL pointrs to DiskCmdTable at 6843h ;B contains command byte(except for MT/MF/SK flags) 07c3 ld a,(6838h) ;Get MT/MF/SK flags 07c6 or b ;Combine with command byte 07c7 ld (hl),a ;Store in DiskCmdTable 07c8 inc hl ;Point to next byte of DiskCmdTable 07c9 ld a,(683eh) ;Read unit/head select flags 07cc ld (hl),a ;Store in DiskCmdTable 07cd inc hl ;Point to next byte 07ce ret ;Exit ;DskCmdParams - Set up parameters for a disk command ;On Entry, HL points to DiskCmdTable+2 (6845h) 07cf ld a,(6839h) ;Get Cylinder address 07d2 ld (hl),a ;Store in DiskCmdTable 07d3 inc hl ;Point to next byte 07d4 ld a,(683eh) ;Get Unit/head flags 07d7 sra a ;Shift right twice - Head flag is now LSB 07d9 sra a 07db and 01h ;Mask out other bits 07dd ld (hl),a ;Save head address in DiskCmdTable 07de inc hl ;Point to next byte 07df ld a,(683ah) ;Get Sector Address 07e2 ld (hl),a ;Save in DiskCmdTable 07e3 inc hl ;Point to next byte 07e4 ld a,(6837h) ;Get sector size 07e7 ld (hl),a ;Save in DiskCmdTable 07e8 inc hl ;Point to next byte 07e9 ld a,(6835h) ;Get EOT sector number 07ec ld (hl),a ;Save in DiskCmdTable 07ed inc hl ;Point to next byte 07ee ld a,(6836h) ;Get Gap Length 07f1 ld (hl),a ;Save in DiskCmdTable 07f2 inc hl ;Point to next byte 07f3 ld (hl),80h ;DTL (data length) = 128 bytes 07f5 inc hl ;Point to next byte 07f6 ret ;Exit ;----End of Disk Module ;----ResetEntry - Enter here after a reset 07f7 di ;Turn off interrupts 07f8 ld sp,7b5ch ;Set up Stack Pointer 07fb xor a ;Clear 07fc ld (6801h),a ;RSA.Sem - RS232 port A semaphore 07ff ld (6802h),a ;RSB.Sem - RS232 port B semaphore 0802 ld (6803h),a ;Speech.Sem - Speech Semaphore 0805 ld (6804h),a ;Floppy.Sem - Floppy Semaphore 0808 ld (6805h),a 080b ld (6806h),a ;GPIB.Sem - GPIB Task Semaphore 080e ld (6807h),a 0811 ld (6808h),a ;Z80.Sem - Z80 Device Semaphore 0814 ld (6834h),a ;FloppyCtrl.Sem - FDC Semaphore 0817 ld (6858h),a ;DMAPERQ - PERQ DMA semaphore 081a ld (6856h),a ;DMAGPIB - GPIB DMA semaphore 081d ld (6857h),a ;DMASIO - SIO DMA semaphore 0820 ld (6855h),a ;DMAFlop - Floppy disk DMA Semaphore 0823 inc a ;A now contains one 0824 ld (6800h),a ;Set PERQ Output Semaphore 0827 ld (6859h),a 082a ld (685ah),a ;And PERQDMABusy Semaphore ;Set up Interrupt Controller 082d ld a,00h ;Reset Interrupt controller 082f out (61h),a ;Send to Interrupt controller command port 0831 ld a,90h ;Load mode register - active high IREQ ;Active low Init, Interupt mode ;Individual vector, fixed priortiy 0833 out (61h),a ;Send to command port 0835 ld a,c0h ;Select autoclear register 0837 out (61h),a ;Send to command port 0839 ld a,ffh ;Set all autoclear bits 083b out (60h),a ;Send to data port ;Call Device initialisation routines 083d call 0e72h ;Z80Init - Z80 Device 0840 call 09c8h ;PERQInit - PERQ I/O 0843 call 08bfh ;KBInit - keyboard 0846 call 0143h ;DMAInit - DMA Controller 0849 call 024dh ;FloppyInit - Floppy Drive 084c call 0008h ;ClockInit - Clock 084f call 0097h ;RSAInit - RS232 port A 0852 call 00c6h ;RSBInit - RS232 port B 0855 call 0c96h ;SpeechInit - Speech System 0858 call 0023h ;GPIBInit - GPIB 085b call 006eh ;PointerInit - Kriz Tablet 085e call 0cc2h ;InitTCB - Set up Task Table ;Now start creating tasks 0861 ld a,01h ;LowPri.Task 0863 ld bc,0047h 0866 ld hl,6a04h 0869 call 0dabh 086c ld a,05h ;Floppy.Task 086e ld bc,02d3h 0871 ld hl,6a28h 0874 call 0dabh 0877 ld a,05h ;RSA.Task 0879 ld bc,00bbh 087c ld hl,6a4ch 087f call 0dabh 0882 ld a,05h ;RSB.Task 0884 ld bc,00eah 0887 ld hl,6a70h 088a call 0dabh 088d ld a,05h ;GPIB.Task 088f ld bc,003fh 0892 ld hl,6a94h 0895 call 0dabh 0898 ld a,05h ;Z80.Task 089a ld bc,0ec1h 089d ld hl,6ab8h 08a0 call 0dabh 08a3 ld a,05h ;SpeechTask 08a5 ld bc,0cbah 08a8 ld hl,6adch 08ab call 0dabh 08ae ld a,a1h 08b0 out (61h),a 08b2 ld a,01h ;Set I register to 1 08b4 ld i,a ;So Interrupt vectors must be in 01xxh 08b6 im 2 ;Set interrupt mode 2 - vectored 08b8 ld ix,(699eh) ;CurrTCB - a pointer into the task list 08bc jp 0d5bh ;Jump to Despatch and set the first task ;running ;----Start of Keyboard Module ;----KBInit - Initialise Keyboard device 08bf xor a ;Clear 08c0 ld (6973h),a ;Keyboard Circular buffer pointers 08c3 ld (6974h),a 08c6 ld hl,680dh ;Point to KB.Msg - Keyboard Message flag 08c9 ld (hl),a ;Clear it 08ca set 5,(hl) ;And set Keyboard enable bit 08cc ld a,76h ;Counter 1 ! Load both ! Square Wave 08ce out (57h),a ;Send to CTC B Mode port 08d0 ld a,41h ;341h -> 300 baud 08d2 out (55h),a ;Send low byte to counter 1 CTC B 08d4 ld a,03h ;And High Byte 08d6 out (55h),a 08d8 in a,(41h) ;Read SIO B Data B to flush it 08da in a,(41h) 08dc in a,(41h) 08de ld hl,08e8h ;Pointer to KB.InitTbl - Keyboard init Table 08e1 ld b,0ch ;Length of table - 12 bytes 08e3 ld c,43h ;SIO B Control B port 08e5 otir ;Send KB.InitTbl to SIO B 08e7 ret ;Exit ;KB.InitTbl - Keyboard SIO Initialisation table 08e8 defb 18h ;Channel Reset 08e9 defb 04h ;Register 4 08ea defb 48h ;*16 Clock, 1.5stop, no parity 08eb defb 03h ;Register 3 08ec defb e1h ;Rx 8 bit, auto enable, Rx Enable 08ed defb 05h ;Register 5 08ee defb e0h ;Tx 8 bit, DTR 08ef defb 01h ;Register 1 08f0 defb 1ch ;Rx Int on all chars, status affects vector 08f1 defb 02h ;Register 2 08f2 defb 30h ;Interrupt vector 08f3 defb 00h ;Register 0 ;-----XKB - Keyboard Request Handler 08f4 ld hl,680dh ;Point to KB.Msg Status flag 08f7 ld a,(6826h) ;Get command byte from PERQIBuff+2 08fa cp 09h ;Is it CMDSet? 08fc jr z,12h ;Go if so to KB.Set 08fe cp 0ch ;Is it CMDIOSense? 0900 jr z,09h ;Yes, goto KB.Sense 0902 cp 0bh ;Is it CMDReset? 0904 jr nz,1bh ;No, goto KB.ExitNAK 0906 call 08bfh ;Call KB.Init to Initialise Keyboard 0909 jr 11h ;Exit via KB.ExitAck ;---KB.Sense 090b set 2,(hl) ;Set Status request bit 090d jp 0b31h ;Exit via PERQEnable to release port ;---KB.Set 0910 ld a,(6827h) ;Read byte from PERQIBuff+3 0913 or a ;Is it 0? 0914 jr z,04h ;Go if so to KB.Disable 0916 set 5,(hl) ;Set keyboard enable bit 0918 jr 02h ;Goto KB.ExitAck ;---KB.Disable 091a res 5,(hl) ;Clear Keyboard Enable bit and fall into ;KB.ExitAck ;---KB.ExitAck 091c set 0,(hl) ;Set Ack flag bit 091e jp 0b31h ;Exit via PERQEnable to release port ;---KB.ExitNAK 0921 set 1,(hl) ;Set NAK flag bit 0923 jp 0b31h ;Exit via PERQEnable to release port ;---LowPriKB - Low Priority Keyboard task 0926 ld c,08h ;DevKB - Keyboard device 0928 ld hl,6973h ;Pointer to keyboard circular buffer 092b call 0b04h ;Call Senddata to send any characters in the ;Keyboard buffer 092e ld hl,680dh ;Point to KB.Msg status byte 0931 ld a,(hl) ;Read it into A 0932 and 07h ;lower 3 bits contain message requests 0934 ret z ;Exit if none 0935 ld c,08h ;DevKB - keyboard device 0937 bit 0,a ;Look at Ack flag 0939 jp nz,0addh ;if it's set, exit via SendAck 093c bit 1,a ;Look at NAK flag 093e jp nz,0ad6h ;If set, exit via SendNAK 0941 bit 2,a ;Look at status request flag 0943 ret z ;Exit if it's not set 0944 res 2,(hl) ;Clear status request flag 0946 ld hl,6800h ;PERQOCmd - PERQ Output Semaphore 0949 call 0ce8h ;Call Wait and wait for PERQ output port ;to be available 094c ld a,04h ;4 bytes in status message 094e ld (6815h),a ;Write it into PERQOBuff 0951 ld a,08h ;DevKB - Keyboard device 0953 ld (6816h),a ;Write it into PERQOBuff+1 0956 ld a,07h ;Status Message code 0958 ld (6817h),a ;Write it into PERQOBuff+2 095b ld hl,680dh ;Get KB.Msg status flags 095e xor a ;Clear A 095f bit 4,(hl) ;Is the Buffer full bit set? 0961 jr z,01h ;Go if not to KB.BuffOK 0963 inc a ;Buffer is full, so set A=1 ;---KB.BuffOK 0964 ld (6819h),a ;Write buffer status into PERQOBuff+4 0967 res 4,(hl) ;Clear buffer full flag 0969 ld a,(hl) ;Read KB.Msg status byte 096a and 20h ;Look at bit 5 - Keyboard enable 096c ld (6818h),a ;Write it into PERQOBuff+3 096f jp 0a89h ;Exit via SendPERQ to send status to PERQ ;---KBRx.ISR ;Keyboard Rx ISR - Read a character from the keyboard SIO and store it in ;the circular buffer 0972 exx ;Save Registers 0973 ex af,af' 0974 in a,(41h) ;Read character from SIO B data B port 0976 ld hl,680dh ;Point to KB.Msg Status byte 0979 bit 5,(hl) ;Is the keyboard enabled? 097b jr z,1bh ;Go if not to KB.ISRExit 097d cpl ;Flip bits - for some reason the keyboard ;Output is inverted 097e ld d,a ;Save character in D 097f ld hl,6973h ;Pointer to keyboard circular buffer 0982 call 0e04h ;Call BufCmp to check if there's room 0985 cp 1eh ;Are there more than 30 bytes? 0987 jr c,07h ;Go if not to KB.Save 0989 ld hl,680dh ;Point to KB.Msg status byte 098c set 4,(hl) ;Set Buffer full flag 098e jr 08h ;and go to KB.ISRExit ;---KB.Save 0990 xor a ;A=0 0991 call 0df3h ;Call WrQueue and save it 0994 ld a,d ;A=KB Character 0995 call 0df3h ;Into the queue, and fall into KB.ISRExit ;---KB.ISRExit 0998 exx ;Restore Registers 0999 ex af,af' 099a ei ;Enable Interrupts 099b reti ;and Exit ;----KBTx.ISR ;----KB Tx Interrupt handler ;----This should never be called - the Keyboard is an Input-only device 099d exx ;Save registers 099e ex af,af' 099f ld a,05h ;Register 5 09a1 out (43h),a ;Send to SIO B Control B port 09a3 ld a,00h ;Disable transmitter 09a5 out (43h),a 09a7 ld a,28h ;Reset pending Tx interrupt 09a9 out (43h),a 09ab exx ;Restore registers 09ac ex af,af' 09ad ei ;Enable interrupts 09ae reti ;and Exit ;---KBStat.ISR ;Keyboard status ISR - should never be called - Handshake lines are tied active 09b0 exx ;Save registers 09b1 ex af,af' 09b2 ld a,10h ;Reset Status Interrupt 09b4 out (43h),a ;Send to SIO B Control B port 09b6 exx ;Restore Registers 09b7 ex af,af' 09b8 ei ;Enable Interrupts 09b9 reti ;and Exit ;---KBErr.ISR ;---Keyboard Error ISR 09bb exx ;Save registers 09bc ex af,af' 09bd ld a,30h ;Reset Error 09bf out (43h),a ;Send to SIO B Control B 09c1 in a,(41h) ;Read and drop input character 09c3 exx ;Restore Registers 09c4 ex af,af' 09c5 ei ;Enable Interrupts 09c6 reti ;and Exit ;--------End of Keyboard Module--------------- ;---Start of PERQ Module----- ; ;------------------------PERQInit-------------------- 09c8 ld a,e1h ;I.WrRes ! I.Byl ! I.PERQI 09ca out (61h),a ;INTCSR - Enable Writing response memory 09cc ld a,14h ;Low byte of PERQ Input Interrupt vector 09ce out (60h),a ;Send it to the Controller 09d0 ld a,19h ;I.CIMRIRR ! I.PERQI ! I.Single 09d2 out (61h),a ;INTCSR - Clear IMR and IFR for PERQ Input 09d4 ld a,e2h ;IWrRes ! I.Byl ! I.PERQO 09d6 out (61h),a ;INTCSR - Enable Writing response memory 09d8 ld a,12h ;Low Byte of PERQ Output vector 09da out (60h),a ;Send it to the Controller 09dc ld a,1ah ;I.CIMRIRR ! I.PERQO ! I.Single 09de out (61h),a ;Clear IMR and IFR for PERQ Output 09e0 ld a,00h ;PI_Empty - PERQ Input State 09e2 ld (6812h),a ;Store in PI.State 09e5 ld a,01h ;Set Ready Flag 09e7 out (78h),a ;IOD Output Ready 09e9 ret ;Exit ;------PERQ Input Interrupt Handler----------- ;------PERQI.ISR------------------------------ 09ea exx ;Save Registers 09eb ex af,af' 09ec ld a,(6812h) ;Read PI.State 09ef dec a 09f0 jr z,33h ;Go if state = 1 and save data 09f2 dec a 09f3 jr z,11h ;Go if State =2 and save count ;----WaitSom 09f5 in a,(72h) ;PERQ.STS - read FIFO Status 09f7 bit 6,a ;Look for data in input fifo 09f9 jr nz,4bh ;Got to IH.Exit and leave if no more chars 09fb in a,(70h) ;Read Character from PERQ Input Port 09fd cp aah ;Compare with packet start (SOM) character 09ff jr nz,f4h ;Go back to WaitSOM if not 0a01 ld a,02h ;Set state to PI_Count 0a03 ld (6812h),a ;Set PI.State and fall into next state ;---SaveCount 0a06 in a,(72h) ;Look for data in input FIFO 0a08 bit 6,a 0a0a jr nz,3ah ;Goto IH.Exit if none 0a0c in a,(70h) ;Read in the Character 0a0e or a ;Test if count is 0 0a0f jr z,3ah ;Go if count was 0 0a11 cp 0fh ;Compare with Maxlength+1 0a13 jr nc,3dh ;Goto CountOVF if too long ;---CountOK 0a15 ld hl,6824h ;Load pointer with PERQIBuff - Start of Input ;Buffer 0a18 ld (hl),a ;Store Count 0a19 inc hl ;Increment buffer address 0a1a ld (6813h),hl ;Store it in PI.Addr 0a1d ld (6833h),a ;Store Count in PI.Remain 0a20 ld a,01h ;PI.Data State 0a22 ld (6812h),a ;Store it in PI.State and fall into next state ;---SaveData 0a25 in a,(72h) 0a27 bit 6,a ;Look for data in Input FIFO 0a29 jr nz,1bh ;Goto IH.Exit if none 0a2b in a,(70h) ;Get the Character 0a2d ld hl,(6813h) ;Load HL with PI.Addr - Buffer Pointer 0a30 ld (hl),a ;Save the Character 0a31 inc hl ;Increment the address pointer 0a32 ld (6813h),hl ;And save it back in PI.Addr 0a35 ld hl,6833h ;Get PI.Remain - Character Counter 0a38 dec (hl) ;And decrement it 0a39 jr nz,eah ;Go back to SaveData to get next character ;---PI.Remain got to 0. Complete packet received 0a3b call 0b2ch ;Call PERQDisable, and disable input ints 0a3e ld a,00h ;Set PI.State to PI_Empty 0a40 ld (6812h),a 0a43 call 0a56h ;Call ExaminePacket and sort out what to do ;------IH.Exit - Exit Handler 0a46 exx ;Restore Registers 0a47 ex af,af' 0a48 ei 0a49 reti ;And leave ;---CountZero - Error if count was 0 0a4b ld a,00h ;Set State to PI_Empty 0a4d ld (6812h),a 0a50 jr a3h ;Go back to WaitSom for more ;---CountOvf 0a52 ld a,0eh ;Load A with Max Size 0a54 jr bfh ;And go back to CountOK ;------ExaminePacket - Dispatch on Device Code 0a56 ld a,(6825h) ;Read First data byte of packet 0a59 cp 03h ;DevFloppy - for floppy? 0a5b jp z,027bh ;yes, Goto XFloppy 0a5e cp 04h ;DevRSA - 1st Serial 0a60 jp z,00a8h ;yes, Goto XRSA 0a63 cp 05h ;DevRSB - 2nd Serial 0a65 jp z,00d7h ;yes. Goto XRSB 0a68 cp 06h ;DevSpeech - Speech Output 0a6a jp z,0ca7h ;yes, Goto XSpeech 0a6d cp 07h ;DevGPIB - GPIB Port 0a6f jp z,002ch ;yes, Goto XGPIB 0a72 cp 08h ;DevKB - Keyboard 0a74 jp z,08f4h ;yes, Goto XKB 0a77 cp 0ah ;DevClock - RTC Device 0a79 jp z,000dh ;yes, Goto XClock 0a7c cp 0bh ;DevPointer - Kriz Tablet 0a7e jp z,007bh ;yes, Goto Xpointer 0a81 cp 0fh ;DevZ80 - Z80 Device 0a83 jp z,0e77h ;yes, Goto XZ80 0a86 jp 0b31h ;Unknown device - ignore it, and goto ;PerqEnable ;--------SendPERQ - Output PERQOBuff to PERQ 0a89 ld hl,6815h ;Load HL with PERQOBuff - Start Address of ;Buffer 0a8c ld b,(hl) ;Get Message Byte Count 0a8d inc b ;Total Message Length 0a8e ld c,71h ;PERQ Output FIFO Port 0a90 call 0c8ch ;Call FIFOWait - wait for space in FIFO 0a93 ld a,aah ;Load A with SOM byte 0a95 out (c),a ;And Output it ;---CheckBusy - Start of output loop 0a97 call 0c8ch ;Call FIFOWait 0a9a outi ;Send Next Byte 0a9c jr nz,f9h ;Back to CheckBusy to send another character 0a9e ld hl,6800h ;Ld HL with PERQO.Cmd - Port semaphore 0aa1 jp 0d04h ;Goto Signal ;--------SendAttn----Send Pending Attention Message 0aa4 di ;Don't Disturb me 0aa5 ld a,(hl) ;Get Attention Mask 0aa6 ld (hl),00h ;And Clear it 0aa8 ei ;OK to interrupt now 0aa9 or a ;Does it need Attention 0aaa ret z ;Exit if not 0aab ld b,a ;Save Attention reason in B 0aac ld hl,6800h ;Get PERQO.Cmd Output Semaphore 0aaf call 0ce8h ;Call Wait - wait for output buffer 0ab2 call 0c8ch ;Call FIFOWait - wait for space in FIFO 0ab5 ld a,aah ;SOM start character 0ab7 out (71h),a ;Write to PERQ Output FIFO 0ab9 call 0c8ch ;Wait for space in FIFO 0abc ld a,03h ;Length of Atten Message 0abe out (71h),a ;Send it 0ac0 call 0c8ch 0ac3 ld a,c ;Device to send ack for 0ac4 out (71h),a ;Send it 0ac6 call 0c8ch 0ac9 ld a,06h ;CmdAttn - Attenion packet code 0acb out (71h),a ;Send it 0acd call 0c8ch 0ad0 ld a,b ;Reason that we saved earlier 0ad1 out (71h),a ;Send it 0ad3 jp 0d04h ;Goto Signal ;--------SendNak--- Send NAK for device in C. Flag byte (HL) 0ad6 res 1,(hl) ;Clear NAK Pending Flag 0ad8 ld b,05h ;NAK Code 0ada jp 0ae1h ;Goto SendAN - common entry for ACK/NAK ;--------SendAck--- Send ACK for device in C 0add res 0,(hl) ;Clear Ack Pending Flag 0adf ld b,04h ;ACK Code ;And fall into SendAN ;---SendAN 0ae1 ld hl,6800h ;Get PERQO.Cmd - PERQ Output semaphore 0ae4 call 0ce8h ;Wait for PERQ output port 0ae7 call 0c8ch ;Wait for space in the FIFO 0aea ld a,aah ;Send SOM byte 0aec out (71h),a 0aee call 0c8ch 0af1 ld a,02h ;Length of ACK/NAK 0af3 out (71h),a 0af5 call 0c8ch 0af8 ld a,c ;Send Device Code 0af9 out (71h),a 0afb call 0c8ch 0afe ld a,b ;Send ACK or NAK 0aff out (71h),a 0b01 jp 0d04h ;Goto Signal, Release Port, Return ;----------SendData --- Send data from queue buffer ;--- C - Device Code ;--- HL - Address of Queue 0b04 call 0e04h ;BufCmp - Compare buffer pointers 0b07 and feh ;Mask out LSB - send only even # bytes 0b09 ret z ;Exit if no data in buffer 0b0a cp 0ch ;Can't have more than 12 characters in message 0b0c jr c,02h ;Goto Enough if OK 0b0e ld a,0ch ;Otherwise force length to be 12 0b10 ex de,hl ;Save buffer pointer 0b11 ld b,a ;And Count 0b12 ld hl,6800h ;Get PERQO.Cmd - Output Semaphore 0b15 call 0ce8h ;Call Wait - Wait for Port 0b18 ld a,b ;Get Count back again 0b19 add a,02h ;Include the 2 command bytes 0b1b ld hl,6815h ;Point to the output buffer - PERQOBuff 0b1e ld (hl),a ;And save the count 0b1f inc hl ;Point to device byte in buffer 0b20 ld (hl),c ;Save device code 0b21 inc hl ;Point to Command byte in buffer 0b22 ld (hl),03h ;CmdData - it's a data message 0b24 inc hl ;Point to message area 0b25 ex de,hl ;Put Pointer in DE, Buffer in HL 0b26 call 0e18h ;Call BlockGet and copy bytes 0b29 jp 0a89h ;Goto SendPERQ and send data packet ;-----PEQDisable - disable PERQ input interrupts 0b2c ld a,39h ;I.Single ! I.PERQI ! I.SIMR 0b2e out (61h),a ;Set PERQ Input mask register bit 0b30 ret ;Exit ;-----PERQEnable 0b31 in a,(72h) ;Read PERQ.STS port to check status of FIFO 0b33 bit 6,a ;Test if data in input FIFO 0b35 jr nz,04h ;Go if none 0b37 ld a,59h ;I.Single ! I.PERQI ! I.SIRR 0b39 out (61h),a ;Force Fifo Interrupt 0b3b ld a,29h ;I.Single ! I.PEQI ! I.CIMR 0b3d out (61h),a ;Clear PERQ input mask register bit 0b3f ret ;Exit ;------GetBlkData --- Send request for data block to PERQ ;---Wait for response, and if it's a BLKData command, store ;---Data in buffer, and reenable input interrupts ;---Otherwise return command code and don't enable interrupts ; In Out ;---A - Device Code Command Code ;--BC - length of data req Length of data received ;--DE - Address of Buffer ;--HL - Address of Semaphore ;-- Carry Set if NOT BLKData ; 0b40 push hl ;Save input semaphore address 0b41 push af ;And Device Code 0b42 ld hl,685ah ;PERQDMABusy - PERQ DMA semaphore 0b45 call 0ce8h ;Call Wait - Wait for DMA Channel to free 0b48 ld hl,6800h ;PERQOC.Cmd - PERQ Output semaphore 0b4b call 0ce8h ;Call Wait - Wait for port to be available 0b4e call 0c8ch ;Call FiFoWait - wait for space in fifo 0b51 ld a,aah ;SOM 0b53 out (71h),a ;Send it to PERQ 0b55 call 0c8ch ;Wait for space 0b58 ld a,04h ;Length of Reqdata command 0b5a out (71h),a ;Send it 0b5c call 0c8ch 0b5f pop af ;Restore device code 0b60 out (71h),a ;Send it 0b62 call 0c8ch 0b65 ld a,01h ;CmdReqData - Request Data Command 0b67 out (71h),a ;Send it 0b69 call 0c8ch 0b6c ld a,c ;Low Order Byte of Length 0b6d out (71h),a ;Send it 0b6f call 0c8ch 0b72 ld a,b ;High Order Byte of Length 0b73 out (71h),a ;Send it 0b75 push bc ;Save Byte Count 0b76 push de ;Data Buffer Address 0b77 ld hl,6800h ;PERQOCmd - PERQ Output Semaphore 0b7a call 0d04h ;Call Signal - release output port 0b7d pop de ;Restore Address 0b7e pop bc ;And Count 0b7f pop hl ;And Semaphore address 0b80 call 0ce8h ;Call Wait - Wait for Comamnd from PERQ 0b83 push de ;Save buffer address 0b84 push hl ;And Semaphore Address 0b85 ld a,(6826h) ;PI.Command - Command byte in input buffer 0b88 cp 02h ;Is it CmdBlkData? 0b8a scf ;Set carry for possible error exit 0b8b jr nz,20h ;Go if not BlkData to GetBlkExit 0b8d ld hl,6827h ;HL Points to 1st count byte 0b90 ld c,(hl) ;Read count into BC 0b91 inc hl 0b92 ld b,(hl) 0b93 xor a ;Clear PERQ DMA Direction bit - from PERQ 0b94 out (7ah),a 0b96 out (74h),a ;Flush PERQ DMA FIFO 0b98 ld a,03h ;D.PERQ - PERQ DMA Channel 0b9a di ;Do Not Disturb 0b9b call 0167h ;Call DMAtoMem - Start DMA from PERQ 0b9e ei ;OK again 0b9f out (73h),a ;FDMAStart - force 1st PERQ DMA request 0ba1 call 0b31h ;Call PERQEnable - enable perq interrupt req 0ba4 ld hl,6858h ;DMAPERQ - Perq DMA semaphore 0ba7 call 0ce8h ;Call Wait - Wait for DMA to finish 0baa ld a,02h ;Set command to CmdBlkData 0bac or a ;Clear Carry ;GetBlkExit 0bad push af ;Save Command and carry flag 0bae push bc ;Save byte count 0baf ld hl,685ah ;Get PERQDMABusy - Dma semaphore 0bb2 call 0d04h ;Call Signal - Release DMA Channel 0bb5 pop bc ;Restore Byte Count 0bb6 pop af ;And command 0bb7 pop hl ;Restore other registers 0bb8 pop de 0bb9 ret ;Exit ;---------SendBlkData --- Send block of data to PERQ ;---A - Device Code ;--BC - Length of Block ;--DE - Address of Buffer ;--HL - Address of semaphore ;----- 0bba push hl ;Save semaphore address 0bbb push af ;Save Device Code 0bbc ld hl,685ah ;PERQDMABusy - DMA Semaphore 0bbf call 0ce8h ;Call Wait - Wait for free DMA Channel 0bc2 ld hl,6800h ;PERQO.Cmd - PERQ Output Semaphore 0bc5 call 0ce8h ;Wait for port to be free 0bc8 call 0c8ch ;Call FiFoWait - Wait for space in output FIFO 0bcb ld a,aah ;SOM 0bcd out (71h),a ;Send it to PERQ 0bcf call 0c8ch 0bd2 ld a,04h ;Length of Blkdata command 0bd4 out (71h),a ;Send it 0bd6 call 0c8ch 0bd9 pop af ;Device Code 0bda out (71h),a ;Send it 0bdc call 0c8ch 0bdf ld a,02h ;CmdBlkData - Block Data Command 0be1 out (71h),a ;Send it 0be3 call 0c8ch 0be6 ld a,c ;Low byte of length 0be7 out (71h),a ;Send it 0be9 call 0c8ch 0bec ld a,b ;High byte of length 0bed out (71h),a ;Send it 0bef push bc ;Save length 0bf0 push de ;Save Buffer Address 0bf1 ld hl,6800h ;PERQO.Cmd - Perq output port semaphore 0bf4 call 0d04h ;Call Signal and release port 0bf7 pop de ;Restore buffer address 0bf8 pop bc ;And Length 0bf9 pop hl ;Get semaphore address 0bfa call 0ce8h ;Call Wait - wait for Ack 0bfd ld a,(6826h) ;Command byte in buffer 0c00 cp 04h ;Is it a CMDAck? 0c02 scf ;Set carry for possible error 0c03 jr nz,1dh ;Go if not CMDAck to SendExit 0c05 call 0b31h ;Call PERQEnable and enable interrupts 0c08 ld a,01h ;DMA Direction - 1 is to PERQ 0c0a out (7ah),a ;Set it 0c0c out (74h),a ;Flush FIFO 0c0e ld a,03h ;D.PERQ - PERQ DMA Channel 0c10 di ;Do Not Disturb 0c11 call 0189h ;DMAtoDEV - set up DMA 0c14 ei 0c15 ld hl,6858h ;DMAPERQ - Perq DMA Semaphore 0c18 call 0ce8h ;Wait for DMA to finish 0c1b ld a,c ;Get low byte of byte count 0c1c and 07h ;Test to see if multiple of 8 0c1e jr z,02h ;It was, OK 0c20 out (73h),a ;PDMAStart - Force last bytes to PERQ ;--SendExit 0c22 push af ;Save A and Carry 0c23 ld hl,685ah ;PERQDMABusy semaphore 0c26 call 0d04h ;Call Signal - release DMA Channel 0c29 pop af ;Restore 0c2a ret ;Exit ;-----SendBootData------------Send data via fifos, not DMA ;--- Otherwise similar to SendBlkData 0c2b push hl ;Save semaphore address 0c2c push af ;Save Device Code 0c2d ld hl,6800h ;PERQO.cmd - Perq output semaphore 0c30 call 0ce8h ;Call Wait - Wait for port to be free 0c33 call 0c8ch ;Call FiFoWait - Wait for space in FIFO 0c36 ld a,aah ;SOM 0c38 out (71h),a ;Send it to PERQ 0c3a call 0c8ch 0c3d ld a,04h ;Length of BlkData command 0c3f out (71h),a ;Send it 0c41 call 0c8ch 0c44 pop af ;Device Code 0c45 out (71h),a ;Send it 0c47 call 0c8ch 0c4a ld a,02h ;CmdBlkData Command Byte 0c4c out (71h),a ;Send it 0c4e call 0c8ch 0c51 ld a,c ;Low byte of count 0c52 out (71h),a ;Send it 0c54 call 0c8ch 0c57 ld a,b ;High Byte of Count 0c58 out (71h),a ;Send it 0c5a pop hl ;Semaphore address 0c5b ex de,hl ;Buffer address into HL 0c5c xor a ;Clear A 0c5d cp c ;Any bytes in this page? 0c5e ld d,b ;Page Count 0c5f ld b,c ;#Bytes in Page 0c60 ld c,71h ;PERQ Output FIFO Port 0c62 jr z,07h ;Goto SendPage if no bytes in 1st page ;---SendWait 0c64 call 0c8ch ;Call FiFoWait and wait for space in fifo 0c67 outi ;Send a byte to the PERQ 0c69 jr nz,f9h ;Go back to SendWait to send next byte ;---SendPage 0c6b ld a,d ;Copy page counter 0c6c or a ;Test if 0 0c6d jr z,0ah ;Go if no more pages to send to SendDone ;---SendAgain 0c6f call 0c8ch ;Call FiFoWait and wait for space 0c72 outi ;Send a byte to the PERQ 0c74 jr nz,f9h ;Repeat while more bytes to send 0c76 dec d ;Decrement page counter 0c77 jr nz,f6h ;Send another page if not 0 ;---SendDone 0c79 ld hl,6800h ;PERQO.Cmd - PERQ Output Semaphore 0c7c call 0d04h ;Call Signal and release port 0c7f xor a ;Clear Carry bit (and A) 0c80 ret ;Exit ;---PERQ Output Interrupt Service Routine ;---Dummy Routine which simply mackes the interrupt and ignores it 0c81 exx ;Save Registers 0c82 ex af,af' 0c83 ld a,3ah ;I.PERQO ! I.Single ! I.SIMR 0c85 out (61h),a ;Set mask bit for PERQ output interrupt 0c87 exx ;Restore Registers 0c88 ex af,af' 0c89 ei 0c8a reti ;Exit ;-------FIFOWait - Wait for FIFO to be non-full 0c8c in a,(72h) ;PERQ.Sts - Get PERQ Status 0c8e bit 7,a ;Look at Fifo to PERQ Flag 0c90 ret nz ;Return if there's space 0c91 jr f9h ;Jump Back to FIFOWait and Try again. ;----End of PERQ module 0c93 jp 0140h ;---SpeechInit - Initialise Speech System 0c96 xor a ;Clear Speech.Msg Message Flag 0c97 ld (680bh),a 0c9a ld hl,0ca4h ;Point to Sp.InitTbl - Speech Initialisation ;Table 0c9d ld b,03h ;Length of Sp.InitTbl 0c9f ld c,13h ;SIO A Control Port B 0ca1 otir ;Sent Sp.InitTbl to SIO 0ca3 ret ;Exit ;---Sp.InitTbl - Speech SIO Initialisation Table 0ca4 defb 18h ;Channel Reset 0ca5 defb 01h ;Point to Register 1 0ca6 defb 00h ;Disable Interrupts ;---XSpeech - Speech Message Handler 0ca7 ld hl,680bh ;Point to Speech.MSG message flag 0caa set 1,(hl) ;Set NAK flag 0cac jp 0b31h ;Goto PERQEnable and exit ;---LowPriSpeech - Send NAK for unwanted Speech Messages 0caf ld c,06h ;DevSpeech - Speech Device 0cb1 ld hl,680bh ;Point to Speech.Msg Flag 0cb4 bit 1,(hl) ;Is the NAK bit set? 0cb6 jp nz,0ad6h ;Yes, Goto SendNAK and exit 0cb9 ret ;No, Just exit ;---Speech.Task - Dummy task for speech system 0cba ld hl,6803h ;Speech.Sem - Speech Task Semaphore 0cbd call 0ce8h ;Call Wait, and wait on it 0cc0 jr f8h ;Go back to SpeechTask ;-----Start of Task Control Module ;--- ;Format of a TCB ;TCB+0 - State ;TCB+1 - Priority ;TCB+2 - Stack Pointer (word) ;TCB+4 - Semaphore address (word) ;TCB+6 - Pointer to next TCB ; ;-----InitTCB - Sets up the TCB Data Structure as Circular Linked List 0cc2 ld a,03h ;TskDead - just to fill in task state 0cc4 ld hl,69a0h ;TCBBase - Load pointer to start of TCB Array 0cc7 ld (699eh),hl ;CurrTCB - Store pointer to provide entry into ;list 0cca ld de,0008h ;TCBSize - Provide pointer for stepping through 0ccd ld b,08h ;NTCBS - Total number of TCBs ;---TCBLoop 0ccf push hl ;Transfer address of last TCB into IX 0cd0 pop ix 0cd2 add hl,de ;Point to next TCB with HL 0cd3 ld (ix+06h),l ;Save Pointer to next TCB 0cd6 ld (ix+07h),h 0cd9 ld (ix+00h),a ;Set Task State 0cdc djnz f1h ;Go back to TCBLoop to set up next TCB 0cde ld hl,69a0h ;Pointer to 1st TCB again, so we can make the ;List circular 0ce1 ld (ix+06h),l ;Save it in the pointer field of the last TCB 0ce4 ld (ix+07h),h 0ce7 ret ;Exit ;----Wait - Wait on semaphore ;If semaphore non-zero, decrement it and continue ;Else suspend the process 0ce8 di ;Do Not Disturb 0ce9 dec (hl) ;Decrement Semaphore 0cea jp p,0d02h ;It was non zero - go to Wait1 0ced ld ix,(699eh) ;IX points to CurrTCB - Current TCB 0cf1 ld a,02h ;TskWait 0cf3 ld (ix+00h),a ;is stored in the Task State 0cf6 ld (ix+04h),l ;Save Semaphore value 0cf9 ld (ix+05h),h 0cfc call 0d44h ;Call CPUGive and try next task 0cff jp 0ce8h ;Go back to Wait ;---Wait1 0d02 ei ;Restore State 0d03 ret ;And Exit ;-----Signal - Signal on semaphore ;Increments as semaphore count ;Wakes up any tasks waiting on that semaphore ; 0d04 ld c,00h ;C is used as a flag to store the interrupt ;Status 0d06 ld a,r ;This sets the Parity flag to IFF2 0d08 jp po,0d0dh ;Go if interrupts were off to DoSignal 0d0b inc c ;Otherwise set the flag 0d0c di ;And turn off interrupts so we are not ;disturbed 0d0d ld a,(hl) ;Get semaphore value 0d0e or a ;Test to see if it's 0 0d0f jp p,0d3eh ;It isn't, so nobody's waiting ;Goto NoWaiting 0d12 push ix ;Save IX 0d14 ld ix,(699eh) ;CurrTCB - Pointer to Current TCB 0d18 ld b,07h ;Number of TCBs not counting this one ;We are certainly not waiting! ;---SIGLOOP 0d1a ld d,(ix+07h) ;Get pointer to next TCB 0d1d ld e,(ix+06h) 0d20 push de ;And copy it into IX 0d21 pop ix 0d23 ld a,(de) ;Get Task State 0d24 cp 02h ;Compare with TSKWait - is this task waiting 0d26 jr nz,12h ;No, Goto SIGNEXT and look at next task 0d28 ld a,(ix+04h) ;Get low byte of task semaphore 0d2b cp l ;Compare it with this semaphore 0d2c jr nz,0ch ;Not the same, so go to SIGNEXT 0d2e ld a,(ix+05h) ;Now compare the high bytes of the semaphore 0d31 cp h 0d32 jr nz,06h ;Not the same, goto SIGNEXT 0d34 ld a,01h ;We've found a task - set state to TskRun 0d36 ld (de),a ;Store it 0d37 inc (hl) ;Increment Semaphore 0d38 jr z,02h ;Exit if it's 0 ;---SIGNEXT 0d3a djnz deh ;Decrement counter (B), and go back to SIGLOOP 0d3c pop ix ;Restore IX and fall into exit routine ;---NoWaiting 0d3e inc (hl) ;Increment semaphore 0d3f ld a,c ;Now look at the interrupt state flag 0d40 or a 0d41 ret z ;Return if interrupts were off 0d42 ei ;Otherwise turn them back on 0d43 ret ;And Exit ;-----CPUGive --- Save state of this process, and start next process ;---No reason why this can't be the caller! 0d44 di ;Do Not Disturb 0d45 push iy ;Save all CPU Registers 0d47 push ix 0d49 push hl 0d4a push de 0d4b push bc 0d4c push af 0d4d ld hl,0000h ;Get Stack Pointer into HL 0d50 add hl,sp 0d51 ld ix,(699eh) ;CurrTCB - Get pointer to this TCB 0d55 ld (ix+02h),l ;Save Stack Pointer in TCB 0d58 ld (ix+03h),h ;---Despatch 0d5b ld b,08h ;Total Number of TCBs 0d5d ld c,00h ;Register to store highest priority ;---PRILoop 0d5f ld a,(ix+00h) ;Look at task state 0d62 cp 01h ;Is it TskRun? 0d64 jr nz,0ah ;No, so ignore it and goto DespNxt 0d66 ld a,(ix+01h) ;Get Priority from TCB 0d69 cp c ;Compare it with 'Best So Far' 0d6a jr c,04h ;Lower, so ignore it and got to DespNxt 0d6c push ix ;HL is now a pointer to the highest priority 0d6e pop hl ;TCB 0d6f ld c,a ;And C is the new max priority ;---DespNxt 0d70 ld d,(ix+07h) ;Trace pointer to next TCB 0d73 ld e,(ix+06h) 0d76 push de ;And put it in IX 0d77 pop ix 0d79 djnz e4h ;Go back to PRILoop to try again 0d7b ld a,c ;Now, C should be non-zero 0d7c or a ;Check it 0d7d jr z,18h ;Goto PANIC if no TCBs found 0d7f ld (699eh),hl ;Save TCB Pointer in CurrTCB 0d82 ld ix,(699eh) ;Get it into IX 0d86 ld l,(ix+02h) ;Restore stack pointer from this TCB 0d89 ld h,(ix+03h) 0d8c ld sp,hl 0d8d pop af ;Restore registers from that task's stack 0d8e pop bc 0d8f pop de 0d90 pop hl 0d91 pop ix 0d93 pop iy 0d95 ei ;Turn on interrupts again 0d96 ret ;Exit ;---PANIC 0d97 halt ;Something really wrong with TCB - Stop ;------SNOOZE - set process priority to 1, and call CPUGIVE. 0d98 ld a,01h ;New priority 0d9a ld ix,(699eh) ;CurrTCB - pointer to this TCB 0d9e ld b,(ix+01h) ;Get old priority 0da1 ld (ix+01h),a ;And set new one 0da4 call 0d44h ;Call CPUGive to try a new task 0da7 ld (ix+01h),b ;Restore old process priority 0daa ret ;Exit ;-------NEWTASK - create a new TCB ;---HL contains initial stack pointer, BC contains PC for new task ;---A contains priority 0dab push af ;Save registers 0dac push bc 0dad ld ix,(699eh) ;CurrTCB - as a pointer into TCB List 0db1 ld b,08h ;TCB Count ;---FindFree 0db3 ld a,(ix+00h) ;Read TskState - Task State 0db6 cp 03h ;Is it TskDead? 0db8 jr nz,1bh ;No, so goto FindNext and try the next one 0dba pop bc ;Restore Registers 0dbb pop af 0dbc ld (ix+01h),a ;Set Priority in TCB 0dbf dec hl ;Save 'PC' onto new task stack 0dc0 ld (hl),b 0dc1 dec hl 0dc2 ld (hl),c 0dc3 ld bc,000ch ;Number of bytes of registers saved on task ;Stack Frame 0dc6 or a ;Clear Carry 0dc7 sbc hl,bc ;Build Dummy stack frame by decremanting HL 0dc9 ld (ix+03h),h ;Store HL(=Stack Pointer) into TCB 0dcc ld (ix+02h),l 0dcf ld a,01h ;TskRun - set task state 0dd1 ld (ix+00h),a ;Store it in TCB 0dd4 ret ;Exit ;---FindNext 0dd5 ld d,(ix+07h) ;Follow pointer to next TCB 0dd8 ld e,(ix+06h) 0ddb push de ;Copy it into IX 0ddc pop ix 0dde djnz d3h ;Go back to FindFree and try again 0de0 pop bc ;Only get here if no available TCBs 0de1 pop af ;Restore Registers 0de2 ret ;And Exit ;----------End of Task Control Module--------------- ;----------Start of Circular Buffer Module---------- ;--A circular buffer consists of ; 1 byte Write pointer (0-31) ; 1 byte Read pointer (0-31) ; 32 byte data area ;On entry, HL -> Write pointer (and hence entire buffer structure) ;---RdQueue - Read 1 byte from a circular buffer ;---Entry : HL->circular buffer ;---Exit : A = byte 0de3 inc hl ;Point to Read pointer 0de4 ld c,(hl) ;Get read pointer into C 0de5 ld b,00h ;and BC 0de7 push hl ;Save address of read pointer 0de8 inc c ;Point to current read location in buffer 0de9 add hl,bc 0dea ld b,(hl) ;Get character into B 0deb pop hl ;Restore address of read pointer 0dec ld a,c ;Copy updated read pointer into A 0ded and 1fh ;Only 32 locations in the buffer 0def ld (hl),a ;Save updated read pointer in buffer structure 0df0 dec hl ;Point to start of circular buffer again 0df1 ld a,b ;Transfer byte read into A 0df2 ret ;Exit ;----WrQueue - Write a character into a circular buffer ;---HL -> circular buffer ;---A = character 0df3 ld c,(hl) ;Get buffer write pointer into C 0df4 ld b,00h ;And into BC 0df6 inc c ;Point to next location in the buffer 0df7 inc hl ;Point to start of buffer -1 0df8 push hl ;Save it 0df9 add hl,bc ;Point to next available location 0dfa ld (hl),a ;Save byte in circular buffer 0dfb pop hl ;Restore buffer pointer 0dfc ld a,c ;Copy write pointer into A 0dfd and 1fh ;Only lower 5 bits (32 bytes in buffer) used 0dff cp (hl) ;Compare with read pointer 0e00 dec hl ;Point to write pointer again 0e01 ret z ;Exit if buffer is full 0e02 ld (hl),a ;Save new write pointer 0e03 ret ;and Exit ;---BufCmp - Compare Circular buffer pointers ;--- hl points to buffer pointers 0e04 ld a,(hl) ;Read first buffer pointer 0e05 inc hl 0e06 sub (hl) ;Subtract the second 0e07 dec hl ;Restore pointer 0e08 and 1fh ;Only 5 bits significant 0e0a ret ;Exit ;BlockPut - Write block to circular buffer ;B = #bytes ;DE -> Block to copy ;HL -> Circular Buffer 0e0b ld a,b ;Check if byte count is 0 0e0c or a 0e0d ret z ;Exit if so ;---NextPut 0e0e push bc ;Save byte count 0e0f ld a,(de) ;Read byte from input block 0e10 call 0df3h ;Call WrQueue to write byte 0e13 inc de ;Point to next byte of input block 0e14 pop bc ;Restore byte count 0e15 djnz f7h ;Decrement count and go back to NextPut 0e17 ret ;All done, Exit ;---BlockGet - Read block from circular buffer ;B=byte count ;DE -> Output block ;HL -> Circular buffer 0e18 ld a,b ;Check if byte count is 0 0e19 or a 0e1a ret z ;Exit if it is 0e1b inc hl ;Point to read pointer ;---NextGet 0e1c push bc ;Save byte count 0e1d ld c,(hl) ;Get read pointer 0e1e ld b,00h ;Into BC 0e20 inc c ;Point to next location to read 0e21 push hl ;Save pointer to circular buffer 0e22 add hl,bc ;HL -> next byte 0e23 ld a,(hl) ;Read a byte from the circular buffer 0e24 ld (de),a ;Save in output block 0e25 pop hl ;Restore pointer to read pointer 0e26 ld a,c ;Copy updated read pointer into A 0e27 and 1fh ;Only 32 bytes in the buffer 0e29 ld (hl),a ;Save new read pointer 0e2a inc de ;Point to next word of the output block 0e2b pop bc ;Restore byte count 0e2c djnz eeh ;Go back to NExtGet for another byte 0e2e ret ;All done, so exit ;---InitCircBuff - Initiallise circular buffer ;---On Entry, HL points to a circular buffer ;--- DE to the block to load ;--- B = character count to copy 0e2f di ;Do not disturb me! 0e30 ld c,(hl) ;Save write pointer 0e31 push bc ;Save write pointer and character count ;---InitCircBuf.Loop 0e32 ld a,(de) ;Read next byte from source block 0e33 call 0df3h ;Call WrQueue, and save it in the buffer 0e36 inc de ;Point to next source byte 0e37 pop bc ;Restore count and write pointer 0e38 djnz f7h ;Decrement count, go back to InitCircBuff.Loop 0e3a ld b,(hl) ;Done. Get new write pointer into B 0e3b ld (hl),c ;Restore original write pointer 0e3c ei ;Reenable interrupts 0e3d ret ;Exit ;---DespatchTable - go to a routine specified by C ;--- On entry, TOS contains the address of the despatch table ;--- and C the routine number to execute 0e3e pop hl ;Get address of despatch table 0e3f ld b,00h ;BC contains the routine number 0e41 add hl,bc ;Make HL point to routine's entry point 0e42 add hl,bc ;There are 2 bytes for an address. 0e43 ld e,(hl) ;Get routine address low byte into E 0e44 inc hl ;Point to high byte 0e45 ld d,(hl) ;get it into D 0e46 ex de,hl ;Routine start address now in HL 0e47 jp (hl) ;Goto routine. ;---NextChunk - calculate size of next transfer ;---Enter with HL = # bytes to transfer ;--- BC = Max transfer size ;---Exit with HL = #bytes left after this transfer ;--- BC = this transfer size 0e48 or a ;Clear carry 0e49 sbc hl,bc ;Subtact max size from total 0e4b jr nc,06h ;Goto NextChunk.Exit if +ve 0e4d add hl,bc ;-ve, So originally HL < BC. Now restore HL 0e4e ld b,h ;Transfer into BC - this can be done in 0e4f ld c,l ;One go 0e50 xor a ;Clear #bytes left 0e51 ld l,a 0e52 ld h,a ;And fall into NextChunk.Exit ;---NextChunk.Exit 0e53 ret ;Exit ;---WaitForEnable - Wait for enable bit (5) of (HL) to be clear 0e54 or a ;Clear carry 0e55 bit 5,(hl) ;Test Enable bit 0e57 ret z ;Exit if clear 0e58 call 0d98h ;Call Snooze to let this task sleep 0e5b jp 0e54h ;Go Back to WaitForEnable and try again ;---SendCirc - Transfer Circular buffer to PERQ 0e5e ld b,03h ;Load counter ;---SendCircLoop 0e60 call 0e04h ;Call BufCmp 0e63 or a ;Clear Carry 0e64 ret z ;Exit if Pointers the same 0e65 push bc ;Save Count 0e66 push hl ;Save Circular buffer pointer 0e67 call 0b04h ;Call SendData and transfer buffer to PERQ 0e6a pop hl ;Restore Circular bufer pointer 0e6b call 0d98h ;Call Snooze and let this task sleep 0e6e pop bc ;Restore count 0e6f djnz efh ;Decrement counter and go back to SendCircLoop 0e71 ret ;Exit ;----Z80Init -- Initialise Z80 memory transfer 0e72 xor a ;Clear Z80.Msg - Message Flag 0e73 ld (6811h),a 0e76 ret ;Exit ;----XZ80 - Z80 device message handler 0e77 ld hl,6808h ;Point to Z80.Sem - Z80 Task Semaphore 0e7a ld a,(6826h) ;Get Function code - PERQIBuff+2 0e7d cp 0ch ;Is it CmdIOSense? 0e7f jp nz,0d04h ;No, exit via signal, and wake up Z80Task ;which is waiting on Z80.Sem 0e82 ld hl,6811h ;Yes, point to Z80.Msg - Message flag 0e85 set 2,(hl) ;Set Status Req bit 0e87 jp 0b31h ;Exit via PERQEnable ;----LowPriZ80 - Low Priority Z80 Task 0e8a ld hl,6811h ;Point to Z80.Msg - Message Flag 0e8d ld a,(hl) ;Read it 0e8e and 07h ;Mask out unused bits 0e90 ret z ;Exit if all clear 0e91 ld c,0fh ;DevZ80 - Z80 device 0e93 bit 0,a ;Is the Ack bit set? 0e95 jp nz,0addh ;Yes, SendAck and exit 0e98 bit 1,a ;Is the NAK bit set? 0e9a jp nz,0ad6h ;Yes, SendNAK and exit 0e9d bit 2,a ;Is the IOSense bit set? 0e9f ret z ;No, Exit 0ea0 res 2,(hl) ;Yes, clear it 0ea2 ld hl,6800h ;PERQOCmd - PERQ Output FIFO Semaphore 0ea5 call 0ce8h ;Call Wait - Wait for FIFO to be free 0ea8 ld hl,6815h ;Point to PERQOBuff - PERQ Output Buffer 0eab ld a,04h ;Message length - 4 bytes 0ead ld (hl),a ;Store in buffer 0eae inc hl 0eaf ld a,0fh ;DevZ80 - Z80 Device 0eb1 ld (hl),a ;Store it 0eb2 inc hl 0eb3 ld a,07h ;Function code 0eb5 ld (hl),a ;Store it 0eb6 inc hl 0eb7 ld a,10h ;Minor version 16 0eb9 ld (hl),a ;Store it 0eba inc hl 0ebb ld a,64h ;Major Version 100 0ebd ld (hl),a ;Store it 0ebe jp 0a89h ;Exit via SendPERQ and send message. ;Z80Task - Z80 Device Task 0ec1 ld hl,6808h ;Z80.Sem - Z80 Task Semaphore 0ec4 call 0ce8h ;Call Wait - Wait for message to be received ;---Z80Decode - Decode Z80 Message 0ec7 ld hl,6826h ;Point to PERQIBuff+2 - Command code 0eca ld a,(hl) ;Read Command Code 0ecb cp 0eh ;Is it 0eh (ReadHiVol) 0ecd jr z,24h ;Yes, goto ReadZ80Mem 0ecf cp 0fh ;Is it 0fh (WriteHiVol) 0ed1 jr z,43h ;Yes - goto WriteZ80Mem 0ed3 cp 0dh ;Is it 0dh (WriteRegs) 0ed5 jr z,62h ;Yes, goto GoZ80 0ed7 call 0b31h ;call PERQEnable to release port 0eda ld hl,6811h ;Point to Z80.Msg 0edd ld c,0fh ;DevZ80 - Z80 Device 0edf call 0ad6h ;call SendNAK - message not recognised 0ee2 jp 0ec1h ;Back to Z80Task and wait for another message ;---Z80Ack - Acknowledge Z80 messages 0ee5 call 0b31h ;call PERQEnable to release port ;---Z80Ack1 - Acknowldge Z80 Message without releasing port 0ee8 ld hl,6811h ;Point to Z80.Msg 0eeb ld c,0fh ;DevZ80 - Z80 Device 0eed call 0addh ;Call SendAck and acknowledge message 0ef0 jp 0ec1h ;Back to Z80Task ;---ReadZ80mem - Read bytes from the Z80 memory 0ef3 ld de,(6827h) ;Read address from PERQIbuff+3 0ef7 ld bc,(6829h) ;Block length from PERQIbuff+5 0efb call 0b31h ;Call PERQEnable and release port 0efe ld a,b ;Test if length is 0 0eff or c 0f00 ld hl,6808h ;Z80.Sem - Z80 task semaphore 0f03 ld a,0fh ;DevZ80 - Z80 device 0f05 call nz,0bbah ;Call SendBlkData if length non-zero, and read ;Block to PERQ 0f08 jp nc,0ee8h ;Send Ack if no Error, goto Z80Ack1 and exit 0f0b ld hl,6811h ;Point to Z80.Msg if error occured 0f0e ld c,0fh ;DevZ80 - Z80Device 0f10 call 0ad6h ;Call SendNAK 0f13 jp 0ec7h ;Back to Z80Decode to look at next message ;---WriteZ80Mem 0f16 ld de,(6827h) ;Address of block from PERQIBuff+3 0f1a ld bc,(6829h) ;Length of block from PERQIBuff+5 0f1e call 0b31h ;Call PERQENable and release port 0f21 ld a,b ;Test if block length is 0 0f22 or c 0f23 ld hl,6808h ;Point to Z80.Sem - Z80 task Semaphore 0f26 ld a,0fh ;DevZ80 - Z80 Device 0f28 call nz,0b40h ;Call GetBlkData, and read block from PERQ 0f2b jp nc,0ee8h ;Send Ack if no error - goto Z80Ack1 and exit 0f2e ld hl,6811h ;Point to Z80.Msg if error occured 0f31 ld c,0fh ;DevZ80 - Z80 Device code 0f33 call 0ad6h ;Call SendNAK 0f36 jp 0ec7h ;Back to Z80Decode to look at next message ;--GoZ80----Cause Z80 to execute from a User-supplied address 0f39 ld hl,(6827h) ;Start address from PERQIBuff+3 0f3c push hl ;Save it 0f3d call 0b31h ;Call PERQEnable and release port 0f40 ld hl,6811h ;Point to Z80.Msg 0f43 ld c,0fh ;DevZ80 - Z80 Device 0f45 call 0addh ;call SendAck and acknowledge message 0f48 pop hl ;Restore address 0f49 call 0f4fh ;Effective call (hl) - call to jp (hl) 0f4c jp 0ec1h ;When user routine returns, back to Z80Task 0f4f jp (hl) ;Go to User routine with a suitable return ;on the stack ;------------------------End of EIO ROM--------------------------- 0f50 rst 38h 0f51 rst 38h 0f52 rst 38h 0f53 rst 38h 0f54 rst 38h 0f55 rst 38h 0f56 rst 38h 0f57 rst 38h 0f58 rst 38h 0f59 rst 38h 0f5a rst 38h 0f5b rst 38h 0f5c rst 38h 0f5d rst 38h 0f5e rst 38h 0f5f rst 38h 0f60 rst 38h 0f61 rst 38h 0f62 rst 38h 0f63 rst 38h 0f64 rst 38h 0f65 rst 38h 0f66 rst 38h 0f67 rst 38h 0f68 rst 38h 0f69 rst 38h 0f6a rst 38h 0f6b rst 38h 0f6c rst 38h 0f6d rst 38h 0f6e rst 38h 0f6f rst 38h 0f70 rst 38h 0f71 rst 38h 0f72 rst 38h 0f73 rst 38h 0f74 rst 38h 0f75 rst 38h 0f76 rst 38h 0f77 rst 38h 0f78 rst 38h 0f79 rst 38h 0f7a rst 38h 0f7b rst 38h 0f7c rst 38h 0f7d rst 38h 0f7e rst 38h 0f7f rst 38h 0f80 rst 38h 0f81 rst 38h 0f82 rst 38h 0f83 rst 38h 0f84 rst 38h 0f85 rst 38h 0f86 rst 38h 0f87 rst 38h 0f88 rst 38h 0f89 rst 38h 0f8a rst 38h 0f8b rst 38h 0f8c rst 38h 0f8d rst 38h 0f8e rst 38h 0f8f rst 38h 0f90 rst 38h 0f91 rst 38h 0f92 rst 38h 0f93 rst 38h 0f94 rst 38h 0f95 rst 38h 0f96 rst 38h 0f97 rst 38h 0f98 rst 38h 0f99 rst 38h 0f9a rst 38h 0f9b rst 38h 0f9c rst 38h 0f9d rst 38h 0f9e rst 38h 0f9f rst 38h 0fa0 rst 38h 0fa1 rst 38h 0fa2 rst 38h 0fa3 rst 38h 0fa4 rst 38h 0fa5 rst 38h 0fa6 rst 38h 0fa7 rst 38h 0fa8 rst 38h 0fa9 rst 38h 0faa rst 38h 0fab rst 38h 0fac rst 38h 0fad rst 38h 0fae rst 38h 0faf rst 38h 0fb0 rst 38h 0fb1 rst 38h 0fb2 rst 38h 0fb3 rst 38h 0fb4 rst 38h 0fb5 rst 38h 0fb6 rst 38h 0fb7 rst 38h 0fb8 rst 38h 0fb9 rst 38h 0fba rst 38h 0fbb rst 38h 0fbc rst 38h 0fbd rst 38h 0fbe rst 38h 0fbf rst 38h 0fc0 rst 38h 0fc1 rst 38h 0fc2 rst 38h 0fc3 rst 38h 0fc4 rst 38h 0fc5 rst 38h 0fc6 rst 38h 0fc7 rst 38h 0fc8 rst 38h 0fc9 rst 38h 0fca rst 38h 0fcb rst 38h 0fcc rst 38h 0fcd rst 38h 0fce rst 38h 0fcf rst 38h 0fd0 rst 38h 0fd1 rst 38h 0fd2 rst 38h 0fd3 rst 38h 0fd4 rst 38h 0fd5 rst 38h 0fd6 rst 38h 0fd7 rst 38h 0fd8 rst 38h 0fd9 rst 38h 0fda rst 38h 0fdb rst 38h 0fdc rst 38h 0fdd rst 38h 0fde rst 38h 0fdf rst 38h 0fe0 rst 38h 0fe1 rst 38h 0fe2 rst 38h 0fe3 rst 38h 0fe4 rst 38h 0fe5 rst 38h 0fe6 rst 38h 0fe7 rst 38h 0fe8 rst 38h 0fe9 rst 38h 0fea rst 38h 0feb rst 38h 0fec rst 38h 0fed rst 38h 0fee rst 38h 0fef rst 38h 0ff0 rst 38h 0ff1 rst 38h 0ff2 rst 38h 0ff3 rst 38h 0ff4 rst 38h 0ff5 rst 38h 0ff6 rst 38h 0ff7 rst 38h 0ff8 rst 38h 0ff9 rst 38h 0ffa rst 38h 0ffb rst 38h 0ffc rst 38h 0ffd rst 38h 0ffe rst 38h 0fff rst 38h