mirror of
https://github.com/livingcomputermuseum/Darkstar.git
synced 2026-03-06 11:34:33 +00:00
39 lines
12 KiB
Plaintext
39 lines
12 KiB
Plaintext
head 1.1;
|
||
branch 1.1.1;
|
||
access ;
|
||
symbols start:1.1.1.1 Xerox:1.1.1;
|
||
locks ; strict;
|
||
comment @;; @;
|
||
|
||
|
||
1.1
|
||
date 2001.08.12.22.22.20; author freier; state Exp;
|
||
branches 1.1.1.1;
|
||
next ;
|
||
|
||
1.1.1.1
|
||
date 2001.08.12.22.22.20; author freier; state Exp;
|
||
branches ;
|
||
next ;
|
||
|
||
|
||
desc
|
||
@@
|
||
|
||
|
||
|
||
1.1
|
||
log
|
||
@Initial revision
|
||
@
|
||
text
|
||
@{ File: [Iris]<WMicro>DLion>CPSubs.asm
|
||
|
||
Modification History:
|
||
Last Change by Dennis DEG 1-Sep-84 17:05:19 Add copyright notice.
|
||
Jim JXF April 29, 1982 1:10 PM
|
||
Rewritten by Jim JXF to move page mapping and page crossing into the CP microcode (March 10, 1982 7:31 AM)
|
||
Created by Roy RXO (May 13, 1980 3:37 PM)}
|
||
|
||
{ Copyright (C) 1980, 1982, 1983 by Xerox Corporation. All rights reserved.}
|
||
|
||
|
||
; DEFINITION FILES:
|
||
|
||
get "SysDefs"
|
||
get "CommonDefs"
|
||
|
||
IMP ErrorReport ;From Common
|
||
IMP PortBusyFlag ;From BookKeepingTask
|
||
IMP ReadDmaCompletion ;From DmaSubs
|
||
IMP StartCPDmaChannel ;From DmaSubs
|
||
|
||
EXP ByteToWord
|
||
EXP CheckCPDMAComplete
|
||
EXP Copy
|
||
EXP DoNakedNotify
|
||
EXP LastPCB ;***DEBUGGING
|
||
EXP ReadCPbuffer
|
||
EXP StartCPReadDMA
|
||
EXP StartCPWriteDMA
|
||
EXP WordToByte
|
||
EXP WriteCPbuffer
|
||
|
||
|
||
|
||
{NOTES:
|
||
|
||
These are the subroutines which handle transfers through the CP-IOP port. Clients using the port should use them to carry out any transfers. The client should first check PortBusyFlag to be sure the CP port is not busy. The flag is set whenever the CP DMA channel is started, and it is reset whenever the CP DMA channel completes.
|
||
|
||
For most operations, a pointer to a CP port control block (PCB) is passed as a parameter. The PCB contains the information needed to carry out the transfer, viz. The CP Address, the number of bytes to be transferred, and the IOP address. The CP address is always virtual.
|
||
|
||
CP Port Control Block Format:
|
||
byte 0,1, 2: CP buffer pointer (low bytes first),
|
||
byte 3: Not used
|
||
byte 4,5: CP Buffer Size (in bytes),
|
||
byte 6,7: IOP buffer pointer.
|
||
|
||
NOTE: the last two words of the PortControlBlock are the same as the DmaControlBlock.
|
||
|
||
The following are the subroutines available to clients:
|
||
Transfer subroutines:
|
||
- ReadCPbuffer [HL: POINTER to CPPortControlBlock]
|
||
- WriteCPbuffer [HL: POINTER to CPPortControlBlock]
|
||
- StartCPReadDMA [HL: POINTER to CPPortControlBlock]
|
||
- StartCPWriteDMA [HL: POINTER to CPPortControlBlock]
|
||
- CheckCPDMAComplete [] RETURNS [ConditionCode: DMAComplete]
|
||
Naked notify:
|
||
- DoNakedNotify [HL: NakedNotifyMask]
|
||
Utility subroutines:
|
||
- WordToByte [HL: word] RETURNS [HL: word]
|
||
- ByteToWord [HL: word] RETURNS [HL: word]
|
||
- Copy [HL: POINTER to Source, D,E: POINTER to Destination, C: count]
|
||
}
|
||
|
||
{The following PCB is used to send a NakedNotify. We send the CPAddress just as if it were a normal transfer command.}
|
||
NotifyPCB:
|
||
DW 0
|
||
DW 0
|
||
NotifyMask:
|
||
DS 2
|
||
LastPCB:
|
||
DW 0 ;***DEBUGGING
|
||
;
|
||
ReadCPbuffer:
|
||
{Read from CP main memory.
|
||
On entry: HL = Pointer to CPport Control Block}
|
||
|
||
MVI A,CPReadCmd
|
||
CALL InitCPCmd ;Initialize the CP port for reads (send address, count)
|
||
{On return, count is in D,E and HL points to count high of the PCB}
|
||
INX H ;HL points to low IOP address
|
||
MOV A,M ;Get low IOP address
|
||
INX H ;HL points to high IOP address
|
||
MOV H,M
|
||
MOV L,A ;HL contains IOP address
|
||
{Now do the actual data transfer. The bytes coming from the port are stored directly in memory. The bytes come from the port high byte, low byte.}
|
||
|
||
ReadCPLoop:
|
||
IN CPStatus ;Read the port interrupt bits
|
||
ANI CPInIntMask ;CPIn requesting an interrupt?
|
||
CZ ReadCPByteNotThere ;z => no interrupt
|
||
IN CPIn ;get data
|
||
STA HighByte
|
||
IN CPStatus ;Read the port interrupt bits
|
||
ANI CPInIntMask ;CPIn requesting an interrupt?
|
||
CZ ReadCPByteNotThere ;z => no interrupt
|
||
IN CPIn ;get data
|
||
MOV M,A ;Store low byte
|
||
INX H ;Point to high byte
|
||
DB opMVIM ;Store HighByte
|
||
HighByte:
|
||
DB 0
|
||
INX H ;Point to next byte
|
||
DCX D ;Check for end of buffer
|
||
DCX D ;decrement 2 for 2 bytes
|
||
MOV A,D
|
||
ORA E ;Test high and low for zero
|
||
JNZ ReadCPLoop
|
||
RET
|
||
WriteCPbuffer:
|
||
{Write into CP main memory.
|
||
On entry: HL = Pointer to CPport Control Block}
|
||
MVI A,CPWriteCmd
|
||
CALL InitCPCmd ;Initialize the CP port for writes (send address, count)
|
||
; On return, count is in D,E and HL points to count high of the PCB
|
||
|
||
INX H ;HL points to low IOP address
|
||
MOV A,M ;Get low IOP address
|
||
INX H ;HL points to high IOP address
|
||
MOV H,M
|
||
MOV L,A ;HL contains the IOP address
|
||
|
||
{The bytes coming from the memory are stored directly into the port. The bytes must be sent high byte, low byte.}
|
||
|
||
WriteCPLoop:
|
||
MOV A,M ;Get low byte
|
||
PUSH PSW ;Save low byte in Stack
|
||
INX H ;Point to high byte
|
||
MOV A,M ;Get high byte
|
||
OUT CPOut ;Output data
|
||
IN CPStatus ;Read the port interrupt bits
|
||
ANI CPOutIntMask ;data read?
|
||
CZ WriteCPByteNotThere ;Zero means no interrupt
|
||
POP PSW ;Get low byte in A
|
||
OUT CPOut ;Output data
|
||
IN CPStatus ;Read the port interrupt bits
|
||
ANI CPOutIntMask ;data read?
|
||
CZ WriteCPByteNotThere ;Zero means no interrupt
|
||
INX H ;Point to next byte
|
||
DCX D ;Check for end of buffer
|
||
DCX D ;decrement 2 for 2 bytes
|
||
MOV A,D ;Check high and low for zero
|
||
ORA E
|
||
JNZ WriteCPLoop
|
||
RET
|
||
|
||
StartCPReadDMA:
|
||
{Start the DMA controller reading a buffer from CP main memory to IOP memory. The address in CP main memory is a virtual address. The Client will wait for the CP Dma completion.
|
||
On entry: HL = Pointer to CPport Control Block}
|
||
|
||
MVI A,CPReadCmd ;Write command
|
||
CALL InitCPCmd ;Initialize the CP port for reads
|
||
|
||
{On return, count is in D,E and HL points to count high of PCB}
|
||
DCX H ;Point to Dma Control Block
|
||
MVI A,DmaFuncWrite ;Dma write
|
||
CALL StartCPDmaChannel
|
||
|
||
{Dma is now programmed and enabled. Start Dma going. At this point IOPWait, and SwTAddr are cleared.}
|
||
MVI a,CPEnable+CPDmaIn
|
||
OUT CPControl ;Set DmaIn (Clear IOPWait, clear SwTAddr, DmaMode)
|
||
MVI a,CPEnable+CPDmaIn+CPDmaMode
|
||
OUT CPControl ;Set DmaMode (set DmaIn, clear IOPWait, SwTAddr)
|
||
STA PortBusyFlag
|
||
RET
|
||
|
||
StartCPWriteDMA:
|
||
{Start the DMA controller writing a buffer to CP main memory from IOP memory. The address in CP main memory is a virtual address. The Client will wait for the CP Dma completion.
|
||
On entry: HL = Pointer to CPport Control Block}
|
||
|
||
MVI A,CPWriteCmd ;Write command
|
||
CALL InitCPCmd ;Initialize the CP port for writes
|
||
|
||
{On return, count is in D,E and HL points to count high of PCB}
|
||
DCX H ;Point to Dma Control Block
|
||
MVI A,DmaFuncRead ;Dma read
|
||
CALL StartCPDmaChannel
|
||
|
||
{Dma is now programmed and enabled. Start Dma going. At this point IOPWait, and SwTAddr are cleared.}
|
||
MVI a,CPEnable+CPDmaMode
|
||
OUT CPControl ;Set DmaMode (clear IOPWait, SwTAddr, DmaIn)
|
||
STA PortBusyFlag
|
||
RET
|
||
|
||
CheckCPDmaComplete:
|
||
{Check for the CP DMA channel completion. If the channel has completed, clear the DMA channel, and CP Dma hardware.
|
||
On exit, condition code is set:
|
||
zero => channel is not complete
|
||
# Zero => channel has completed, DMA channel has been cleared.}
|
||
|
||
IN CPStatus ;Check for completion in CPStatus register
|
||
ANI CPDmaCompMask
|
||
RZ ;z => channel has not completed
|
||
|
||
MVI E,CPChannelMask ;Check internal completion.
|
||
CALL ReadDmaCompletion ; Get completion
|
||
JZ NoCPDmaComplete ;nz => Completed
|
||
|
||
CPDmaCompleted:
|
||
{The CP channel completed correctly. The Dma controller hardware is disabled, and ReadDmaCompletion will clear the channel in DmaActive. Thus, don't CALL ClearDmaChannel. Clear the external Dma completion bit, and clear DmaMode. We also clear PortBusyFlag here.}
|
||
XRA A
|
||
STA PortBusyFlag
|
||
OUT CPDmaClr ;Clear CPDmaComplete bit
|
||
MVI A,CPEnable
|
||
OUT CPControl ;Clear DmaMode (clear Wait, SwTAddr, DmaIn)
|
||
ORA A ;Set condition code for completed
|
||
RET
|
||
|
||
|
||
NoCPDmaComplete:
|
||
{The Dma channel did not internally complete. This indicates a fatal error.}
|
||
LXI h,ErrorNoCPDmaComplete ;ERROR: Internal CP Dma channel did not complete
|
||
JMP ErrorReport
|
||
|
||
DoNakedNotify:
|
||
{On entry: HL = Notify mask.}
|
||
|
||
SHLD NotifyMask ;Save mask in NotifyPCB
|
||
LXI H,NotifyPCB ;Point to NotifyPCB
|
||
MVI A,CPNotifyCmd
|
||
{Fall through to InitCPCmd}
|
||
;
|
||
InitCPCmd:
|
||
{Initialize CP port for reads or writes.
|
||
On entry:
|
||
A = command to microcode
|
||
HL = Pointer to CPport Control Block
|
||
Format of initialize:
|
||
low address, middle address, high address, low count, high count, Command.
|
||
On Exit:
|
||
HL = pointer to count high of CP port Control Block
|
||
DE contains count in bytes or NakedNotify mask}
|
||
|
||
PUSH PSW ;Save command in A
|
||
SHLD LastPCB ;***DEBUGGING
|
||
MOV A,M ;Address byte 3
|
||
OUT CPOut ;Output data
|
||
IN CPStatus ;Read the port interrupt bits
|
||
ANI CPOutIntMask ;data read?
|
||
CZ WriteCPByteNotThere ;Zero means no interrupt
|
||
INX H
|
||
MOV A,M ;Address byte 2
|
||
OUT CPOut ;Output data
|
||
IN CPStatus ;Read the port interrupt bits
|
||
ANI CPOutIntMask ;data read?
|
||
CZ WriteCPByteNotThere ;Zero means no interrupt
|
||
INX H
|
||
MOV a,M ;High part address (address byte 1)
|
||
OUT CPOut ;Output data
|
||
IN CPStatus ;Read the port interrupt bits
|
||
ANI CPOutIntMask ;CPOut requesting an interrupt, i.e data read?
|
||
CZ WriteCPByteNotThere ;Zero means no interrupt
|
||
INX H ;Point to byte not used
|
||
INX H ;Point to count low
|
||
MOV A,M ;Low part count
|
||
MOV E,A ;DE will contain count on return
|
||
OUT CPOut ;Output data
|
||
IN CPStatus ;Read the port interrupt bits
|
||
ANI CPOutIntMask ;CPOut requesting an interrupt, i.e data read?
|
||
CZ WriteCPByteNotThere ;Zero means no interrupt
|
||
INX H ;Point to count high
|
||
MOV A,M ;D,E contains count
|
||
MOV D,A
|
||
OUT CPOut ;Output data
|
||
IN CPStatus ;Read the port interrupt bits
|
||
ANI CPOutIntMask ;CPOut requesting an interrupt, i.e data read?
|
||
CZ WriteCPByteNotThere ;Zero means no interrupt
|
||
POP PSW ;A ¬ command
|
||
OUT CPOut ;Output data
|
||
IN CPStatus ;Read the port interrupt bits
|
||
ANI CPOutIntMask ;CPOut requesting an interrupt, i.e data read?
|
||
CZ WriteCPByteNotThere ;Zero means no interrupt
|
||
RET
|
||
|
||
WriteCPByteNotThere:
|
||
{WriteCP byte is not there. Check for timeout.}
|
||
CMA ;A ¬ FF
|
||
UpdateWriteTimeout:
|
||
STA WriteTimeout
|
||
IN CPStatus ;Read the port interrupt bits
|
||
ANI CPOutIntMask ;CPOut requesting an interrupt, i.e data read?
|
||
RNZ
|
||
|
||
DB opMVIA ;A ¬ WriteTimeout
|
||
WriteTimeout:
|
||
DB 0FFH
|
||
DCR A
|
||
JNZ UpdateWriteTimeout
|
||
|
||
WritePortTimeOut:
|
||
LXI h,ErrorWriteCPPortDead ;Set up error code for read timeout
|
||
JMP PortTimeOut
|
||
|
||
|
||
ReadCPByteNotThere:
|
||
{ReadCP byte is not there. Check for timeout.}
|
||
CMA ;A ¬ FF
|
||
UpdateReadTimeout:
|
||
STA ReadTimeout
|
||
IN CPStatus ;Read the port interrupt bits
|
||
ANI CPInIntMask ;CPIn requesting an interrupt?
|
||
RNZ
|
||
|
||
DB opMVIA ;A ¬ ReadTimeout
|
||
ReadTimeout:
|
||
DB 0
|
||
DCR A
|
||
JNZ UpdateReadTimeout
|
||
|
||
ReadPortTimeOut:
|
||
LXI H,ErrorReadCPPortDead ;Set up error code for read timeout
|
||
|
||
PortTimeOut:
|
||
{We have a timeout. Check for CP parity error first.}
|
||
IN MiscInput1
|
||
ANI CSParityMask
|
||
JNZ ErrorReport ;z => (active low) it was
|
||
LXI h,ErrorCSParity ;ERROR: CS parity error
|
||
JMP ErrorReport
|
||
;
|
||
ByteToWord:
|
||
{Convert value in HL (byte count) to word count. i.e. long shift right by 1.}
|
||
XRA A ;Clear carry
|
||
MOV A,H ;High part
|
||
RAR ;shift high part right, low bit into carry
|
||
MOV H,A
|
||
MOV A,L ;Low part
|
||
RAR ;shift low part right, shift in high bit
|
||
MOV L,A
|
||
RET
|
||
|
||
WordToByte:
|
||
{Convert value in HL (word count) to byte count. i.e. long shift left by 1.}
|
||
XRA A ;Clear carry
|
||
MOV A,L ;Low part
|
||
RAL ;shift low part, high bit into carry
|
||
MOV L,A
|
||
MOV A,H ;High part
|
||
RAL ;shift high part, shift in low bit
|
||
MOV H,A
|
||
RET
|
||
|
||
Copy:
|
||
{On entry:
|
||
HL = Source address
|
||
DE = Destination address
|
||
A = Count (in bytes). Count=0 => 256.
|
||
On exit:
|
||
HL = Next Source address after copy
|
||
DE = Next Destination address after copy}
|
||
|
||
STA CopyCount
|
||
MOV A,M ;Get source byte
|
||
STAX D ;Store away in destination
|
||
INX H ;Increment pointers
|
||
INX D
|
||
DB opMVIA ;A ¬ CopyCount
|
||
CopyCount:
|
||
DB 0
|
||
DCR A ;Check count
|
||
JNZ Copy
|
||
RET
|
||
|
||
END CPSubs
|
||
@
|
||
|
||
|
||
1.1.1.1
|
||
log
|
||
@first add
|
||
@
|
||
text
|
||
@@
|