
;----------------------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
