1
0
mirror of https://github.com/livingcomputermuseum/Darkstar.git synced 2026-03-02 10:06:45 +00:00
Files
livingcomputermuseum.Darkstar/D/IOP/Source/IOPKernel.asm,v
2023-09-27 16:17:41 -07:00

39 lines
39 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.23; author freier; state Exp;
branches 1.1.1.1;
next ;
1.1.1.1
date 2001.08.12.22.22.23; author freier; state Exp;
branches ;
next ;
desc
@@
1.1
log
@Initial revision
@
text
@{
----------- Dandelion Processor Program - I/O Processor -----------
DESCRIPTION: Development Kernel
Last modification by Roy RXO : September 27, 1981 4:21 PM
File: IOPKernel.asm
Stored: [Iris]<WMicro>DLion>
Written by Roy RXO .
Dennis DEG : 2-Sep-84 15:25:19, add copyright notice
}
{ Copyright (C) 1981 by Xerox Corporation. All rights reserved.}
; Modification History:
;
; Version 1.0
; - Created (March 30, 1979 3:00 PM)
; - Short RAM test added during cold start (April 27, 1979 4:07 PM)
; - This version for system with reversed Prom data, PPICmds (May 4, 1979 12:02 AM)
; - Upgraded to IOP Rev. B (fixed Prom data, PPICmds) (May 10, 1979 2:36 PM)
; Version 2.0
; - Addition of CP interface functions (October 14, 1979 5:04 PM)
; - Full RAM test during cold start (October 20, 1979 6:04 PM)
; Version 2.1 (November 26, 1979 11:00 PM)
; - Code for CP breakpoints
; Version 2.2 (March 5, 1980 11:24 AM)
; - Update for Rev. F IOP
; - Removal of CPStop code
; - Simplification of ReadTPC code
; - Addition of WriteCPBlock command
; Version 2.3 (May 16, 1980 11:56 AM)
; - New commands: ReadCPBlock, PollIOP, ColdStartCP.
; - MaxCommand generated in-line.
; - Polling for CPAttn removed from Kernel loop.
; - Maintenance panel posting added.
; - Kernel now restores its own SP on entry (Note: incompatibility with old kernel.)
; Version 2.4 (May 16, 1980 11:56 AM)
; - Failure of boot memory test reported.
; - MouseHalt code modified to take care of BurdockCP task.
; - Fixed bug in PutMP.
; - Take out memory test.
; Version 2.5 (November 11, 1980 2:02 PM)
; - HNH for Boot proms.
; - Complemented control store data.
; Version 2.6 (January 6, 1981 3:38 PM)
; - Default boot for Boot button.
; - ORGs taken out.
; - ORGs put back.
; Version 2.7 (January 20, 1981 12:05 PM)
; - new RST asignments, addition of Floppy, RS232 interrupts.
; - bug fixes for interrupts (February 2, 1981 3:53 PM)
; Version numbers dropped, renamed IOPKernel.asm (September 21, 1981 2:50 PM)
; - Changes to fit into new EProm organization (September 21, 1981 2:51 PM)
; RST links removed, no ORGs
; Maintenance Panel Codes:
; Kernel Here - 100.
; Bad command - <command>
; Bad interrupt - 101.
; DEFNITIONS:
get "SysDefs"
get "IOPKernelDefs"
; IMPORTS/EXPORTS:
EXP ColdStart ; For RSTLinksK
EXP KernelStart ; For RSTLinksK
EXP IOPBreakpoint ; For RSTLinksK
EXP BurdockCPInt ; For RSTLinksK
;
; ---------------------------------------------------------------------------
;
; Commands to IOP:
;
; Special:
; Proceed after ColdStart
; 10H -> IOP returns IOPAlive if error, KernelHere if kernel starts correctly.
;
;
; Normal:
; Write IOP memory
; 01H, Addr LSB, Addr MSB, Count, Data bytes ...
;
; Read IOP memory
; 02H, Addr LSB, Addr MSB, Count -> IOP now sends Count bytes
;
; Start IOP
; 03H -> IOP restores state and starts executing user program
;
; Interrupt IOP - Reenter kernel
; 04H
;
; Get IOP configuration
; 05H -> IOP then returns the following data:
; EndOfProm (word, LSB first)
; StartOfRam
; EndOfRam
; TopOfStack
; StartOfRegisters (stored in the following way):
; Flags, AC, C, B, E, D, L, H, PC, SP, RIM
; Start of Breakpoint Return Area
;
; Write CP control store
; 06H, CSAddr low, CSAddr high (4 bits), 6 Data bytes (LSB ... MSB)
;
; Read CP control store
; 07H, CSAddr low, CSAddr high (4 bits) -> IOP returns 6 bytes (LSB ... MSB)
;
; Write TPC
; 08H, TPC address, TPC data low, TPC data high (4 bits)
;
; Read TPC/TC
; 09H, TPC/TC address
; -> IOP returns TPC data low, TC data (4 bits)..TPC data high (4 bits)
;
; Write CP port (defaulted to 1 byte)
; 0AH, Data byte
;
; Read CP port (defaulted to 1 byte)
; 0BH -> IOP returns data byte
;
; Start CP kernel
; 0CH -> IOP clears IOPWait, SwTAddr, clears BootMode in KernelFlags.
;
; Halt CP
; 0DH -> IOP sets IOPWait, then clears IOPWait.
;
; Start CP
; 0EH -> IOP restores CPport state, issues CPExitKernel Command.
;
; Write CP Block
; 0FH, countLow, countHigh, "count" Data bytes
;
; Invalid command (so as not to confuse with ColdStartGo)
; 10H -> Hang at BadCommand
;
; Read CP Block
; 11H, countLow, countHigh
; -> IOP returns "count" Data bytes
;
; Poll IOP: IOP polls certain hardware flags (currently only CPAttn)
; 12H -> IOP returns status (0 = no CPAttn, #0 = CPAttn)
;
; (Cold) Start CP
; 13H -> IOP issues CPExitKernel Command (no CPport restoral)
;
; Invalid command (so as not to confuse with DataForCP)
; 14H -> Hang at BadCommand
;
; Invalid command (so as not to confuse with ColdStartTest)
; 15H -> Hang at BadCommand
;
; Commands to Burdock:
;
;
; IOPAlive: 0FFH - Cold Start acknowledge
; KernelHere: 0FEH - Kernel Start
; IOPBreak: 0FDH - IOP breakpoint
; CPBreak: 0FCH - CP breakpoint
; IOPHalt: 0FBH - Stopped after Burdock halt
; IOPHaltError: 0FAH - Stopped after Burdock halt, but Alto data
; is not DebugIntr
; DataForBurdock: 0F9H - CP data for Burdock
; 0F9H, type, low count, high count, "count" data bytes (LSB, MSB)
; (Code not implemented in the Kernel.)
; BootMemError: 0F8H - Error in boot memory test
;
; Fixed Memory Allocation
;
; Basic RAM usage - see KernelDefs.
;
; Low PROM Area - RST dispatch (see RST.asm, and RSTLinksK.asm)
; Note see page 3-4 of the 8085 manual for details
{*** Removed:
; Restart locations:
org 0000H ;RST 0 - Hardware Reset ONLY
;*** All Interrupts off and masked
RST0:
jmp ColdStart
org 0008H ;RST 1 - Manual Kernel restart
RST1:
jmp KernelStart
org 0010H ;RST 2 - Breakpoint (OpCode D7H)
RST2:
jmp IOPBreakpoint
; org 0018H ;RST 3 - (unused)
; org 0020H ;RST 4 - (unused)
; org 0024H ;RST TRAP - (unused)
; org 0028H ;RST 5 - (unused)
org 002CH ;RST 5.5 - Burdock or CP Interrupt
RST55:
jmp BurdockCPInt
; org 0030H ;RST 6 - (unused)
org 0034H ;RST 6.5 - RS232C Interrupt
RST65:
jmp GoToRS232CIntr
; org 0038H ;RST 7 - (unused)
org 003CH ;RST 7.5 - Floppy Interrupt
RST75:
jmp GoToFloppyIntr
}
;
; COLDSTART code.
;
; System Hardware Initialization after hardware reset
; org 40H ; start at loaction 64D
;
ColdStart:
;
; Initialize Alto PPI for communication with Alto.
mvi a,AltoPPImode ; Port A: mode 1, input
out AltoPPICtrl ; Port B: mode 1, output
mvi a,EnableIntA ; Enable INTE A in
out AltoPPICtrl
mvi a,EnableIntB ; Enable INTE B out
out AltoPPICtrl
; This code sends Cold Start Ack message to Alto without using RAM.
AltoWrite:
mvi a,IOPAlive
out AltoPPIB ; Write data into port B
; Now wait a specified period to determine whether Burdock is there.
; If not, go to the Boot code.
WaitAck:
lxi h,TimeOutConst ; [10] Time-out constant
; Inner loop approximately 49 cycles (~= 17 usec)
; Delay is approx. 17 * TimeOutConst usec.
WaitAckLoop:
in AltoPPIC ; [11] Read Channel B interrupt
ani IntBMask ; [7]
jnz AltoRead ; [7] nz => Burdock took byte
dcx h ; [6]
xra a ; [4]
cmp l ; [4]
jnz WaitAckLoop ; [10]
cmp h ; [4]
jnz WaitAckLoop ; [10]
; Timed out, jump to boot code.
jmp BootGoProm ; Assume push-button boot if no interrupt
; Not a Pushbutton boot, assume Burdock communication.
; Now wait for response from Alto.
AltoRead:
in AltoPPIC ; Read port A interrupt
ani IntAMask
jz AltoRead ; Wait if no interrupt
in AltoPPIA ; Read data from port A
;
; Check the command.
cpi ColdStartGo ; normal proceed from coldstart?
jz EndMemTest ; If so, check the (stack/state area in) RAM
cpi ColdStartTest ; memory test proceed from coldstart?
jz MemTest ; If so, check the (stack/state area in) RAM
jmp AltoWrite ; Didn't recognize command, send ColdStart Ack again
;
; This code tests the whole RAM,
; including the half page where the stack and processor state are kept.
; This is so the stack can be used in the rest of the kernel.
; Note that, the RAM is not used (other than being tested).
; Register usage:
; H,L - memory address
; B,C - byte count
; D - data value
; E - test number
MemTest:
mvi e,0 ; Initialize test number register
NextTest:
inr e ; Next test number
mov a,e
cpi 1 ; Test 1?
jz Test1
cpi 2 ; Test 2?
jz Test2
cpi 3 ; Test 3?
jz Test3
cpi 4 ; Test 4?
jz Test4
; Clear CPDataMode to indicate no memory error.
EndMemTest:
xra a
sta CPDataMode
jmp GoToKernel
;
;
; Test 1: Store all 0's in memory location and read back.
Test1:
mvi d,0
jmp DoTest
; Test 2: Store all 1's in memory location and read back.
Test2:
mvi d,0FFH
jmp DoTest
; Test 3: Store 1's in odd bit positions in memory location and read back.
Test3:
mvi d,55H
jmp DoTest
; Test 4: Store 1's in even bit positions in memory location and read back.
Test4:
mvi d,0AAH
;
; Memory test.
; Tests whole of RAM.
; On entry: D contains the test pattern.
DoTest:
lxi h,StartOfRAM ; Point to start of RAM
lxi b,EndOfRAM-StartOfRAM+1 ; Memory size
StoreLoop:
mov m,d ; Store pattern
inx h
dcx b
xra a ; Clear A
cmp c ; Check low part
jnz StoreLoop
cmp b ; Check high part
jnz StoreLoop
; Now check.
lxi h,StartOfRAM ; Point to start of RAM
lxi b,EndOfRAM-StartOfRAM+1 ; Memory size
CheckLoop:
mov a,m ; Fetch pattern
cmp d ; Same as d?
jnz MemError
inx h
dcx b
xra a ; Clear A
cmp c ; Check low part
jnz CheckLoop
cmp b ; Check high part
jnz CheckLoop
; Test is done with no error. Go to next test.
jmp NextTest
; Error found in test. Go back to cold start acknowledge again.
; Burdock will report IOPWild.
MemError:
;*** jmp AltoWrite
;**** Don't hang after a memory error.
; Store Failure description in memory:
; mem[2000..2001] - address which failed.
; mem[2002] - write pattern
; mem[2003] - read pattern
shld 2000H ; Address
sta 2003H ; Read pattern
mov a,d
sta 2002H ; Write pattern
; Set CPDataMode to indicate a memory error.
xra a
sta CPDataMode
jmp GoToKernel
;*****
;
; Set hardware interrupt mask.
GoToKernel:
mvi a,EnableRST55 ; Enable RST 5.5 interrupt (Burdock, CP interrupts)
sim
; The first time execution is started, the interrupts will be disabled,
; and will have to be explicitly enabled by a program.
; Initialize the kernel stack.
; The kernel stack underflow area (2 slots) will contain the Kernel start address (08H).
; The kernel stack will have one item in it, viz. the kernel start address.
lxi sp,StackStart+StkUndSize ; Initialize stack pointer to underflow area
lxi h,08H ; Address of kernel
push h ; Dummy up stack, underflow area with kernel address
push h
push h
; The kernel stack now has one entry, i.e. kernel address.
; Set KernelFlags to BootMode set, CPInSaveFull, CPOutSaveFull cleared.
mvi a,BootMode
sta KernelFlags
; Ensure that IOPWait = SwTAddr = 1 (should be after hard boot).
mvi a,CPWaitSwT
out CPControl
; Put KernelHere code in Maintenance Panel.
lxi h,KernelHereCode
call PutMP
; START of Kernel
; Kernel start can also be reached by a RST 1 in a program.
;
KernelStart:
push psw
rim
sta SaveRIM
di ; In case interrupts are enabled.
; Check if there was a memory error (indicated by flag in CPDataMode).
lda CPDataMode
mov b,a ; Save Flag
xra a ; Clear CPDataMode for BurdockCPTask
sta CPDataMode
mov a,b
ora a ; Set flags
jm BootError
; No error.
mvi a,KernelHere ; Send greetings to Burdock
; When we reach here, the SaveRIM has already been filled.
; Stack has PC, PSW..A
SaveState:
sta WhyKernel
shld SaveL ; Save Machine State
pop h ; PSW from before
shld SaveFLG
xchg
shld SaveE
mov l,c
mov h,b
shld SaveC
pop h ; PC from stack
shld SavePC
lxi h,0
dad sp
shld SaveSP
; Restore the stack pointer for the kernel stack.
lxi sp,StackStart-2 ; Stack has one item in it
; Tell the Alto why we are here.
NotifyAlto:
lda WhyKernel ;recover reason for kernel
call WriteByte
;
; Check Alto port for command from Burdock.
; Go to CommandDispatch if there is an Alto command (command in A),
; Note: an IOPHalt command (4) while IOP in kernel causes a KernelHere message.
KernelLoop:
in AltoPPIC ; Read port A interrupt
ani IntAMask
jz KernelLoop ; nz => Alto command
in AltoPPIA ; Read data from port A
jmp CommandDispatch
; There was an error in the boot memory test.
BootError:
mvi a,BootMemError
jmp SaveState
;
; Command table is a table of addresses of the starting point of the command code.
CommandTable:
C1: dw WriteIOPmem ; Write IOP memory (command=1)
C2: dw ReadIOPmem ; Read IOP memory (command=2)
C3: dw RestoreState ; Start IOP Command (command=3)
C4: dw KernelLoop ; Noop command (command=4)
C5: dw SendConfiguration ; Send IOP configuration (command=5)
C6: dw WriteCS ; Write CP control store location (command=6)
C7: dw ReadCS ; Read CP control store location (command=7)
C8: dw WriteTPC ; Write a single TPC (command=8)
C9: dw ReadTPC ; Read a single TPC/TC value (command=9)
C10: dw WritePort ; Write CP port (command=0AH)
C11: dw ReadPort ; Read CP port (command=0BH)
C12: dw StartCPKernel ; Start CPKernel (command=0CH)
C13: dw StopCP ; Stop CP execution (force to CPKernel) (command=0DH)
C14: dw StartCP ; Start CP execution (force out CPKernel) (command=0EH)
C15: dw WriteCPBlock ; Write CP Block (command=0FH)
C16: dw BadCommand ; Invalid command (command=10H)
C17: dw ReadCPBlock ; Read CP Block (command=11H)
C18: dw PollIOP ; Poll IOP (command=12H)
C19: dw ColdStartCP ; (Cold) Start CP execution (command=13H)
C20: dw BadCommand ; Invalid command (command=14H)
C21: dw BadCommand ; Invalid command (command=15H)
EndCommandTable:
nop
MaxCommand equ (EndCommandTable-CommandTable)/2
; Dispatch on command: Jump to Contents[CommandTable + 2*(Command-1)]
CommandDispatch:
cpi MaxCommand+1 ; Check for largest command?
jnc BadCommand ; nc => command (in A) > MaxCommand - hang
lxi h,CommandTable-2 ; [H,L] _ CommandTable-2
CheckCommand:
inx h ; [H,L] points to next slot
inx h
dcr a ; Is this the slot?
jnz CheckCommand
; Command found. H,L points to the appropriate table slot.
mov e,m ; Load low part of address into E
inx h
mov d,m ; Load high part of address into D
xchg ; H,L _ D,E
pchl ; Jump to address
; Put BadCommand code in Maintenance Panel.
BadCommand:
lxi h,0 ; Clear H,L
mov l,a ; Put Command in Panel
MPHang:
call PutMP
Hang:
jmp Hang ; If we get a bad command, hang
;
; COMMAND PROCESSING
; Command 1: Write a location in IOP Ram.
WriteIOPmem: ; fill IOP Ram from Alto
call ReadWord ; get address to hl
call ReadByte ; get count
mov b,a
WriteIOPmemLoop:
call ReadByte
mov m,a
inx h
dcr b
jnz WriteIOPmemLoop
jmp KernelLoop
; Command 2: Read a location of IOP memory.
ReadIOPmem: ; Send IOP Ram to Alto
call ReadWord ; get address to hl
call ReadByte ; get count
mov b,a
ReadIOPmemLoop:
mov a,m
call WriteByte
inx h
dcr b
jnz ReadIOPmemLoop
jmp KernelLoop
; Command 3: Restore the state of the CPU before returning to program.
; This code also restores the RST masks,
; and enables interrupts only if the IntEnabled bit was set in SaveRIM.
;
RestoreState:
lhld SaveC
mov b,h
mov c,l ; put bc back
lhld SaveE
xchg ; put de back
lda SaveRIM ; restore RST mask values
mov h,a ; save temporarily in H
ani RSTMasks ; isolate masks
ori EnMaskSet ; OR in EnableMaskSet
sim
; check if interrupts were disabled or not.
mov a,h ; get RIM value again
ani IntEnableBit ; Look at IntEnable bit
jnz RestoreEI ; Non-zero means they were enabled
; interrupts were disabled, restore state without enabling interrupts.
lhld SaveFLG
push h
pop psw ; put ac and psw back
lhld SaveSP
sphl ; put sp back
lhld SavePC
push h ; put return address on stack
lhld SaveL
ret ; back we go (interrupts still disabled)
; interrupts were enabled, restore state and enable interrupts.
RestoreEI:
lhld SaveFLG
push h
pop psw ; put ac and psw back
lhld SaveSP
sphl ; put sp back
lhld SavePC
push h ; put return address on stack
lhld SaveL
ei ; turn interrupts on
ret ; back we go
; Command 4: Re-enter kernel. A Noop directly in the CommandTable.
; Command 5: Send the IOP memory configuration to Burdock.
SendConfiguration:
lxi h,EndOfProm
call WriteWord
lxi h,StartOfRAM
call WriteWord
lxi h,EndOfRAM
call WriteWord
lxi h,Stack
call WriteWord
lxi h,SaveArea
call WriteWord
lxi h,BRArea
call WriteWord
jmp KernelLoop
; Command 6: Write Control Store: Write one location in CP control store.
; First two bytes from Alto are: CS addr low (low 8 bits), CS addr High (high 4 bits).
; Next 6 bytes from Alto are: CS data (least significant first)
; Use TPC (6) for CS addressing.
WriteCS:
call ReadWord ; get CS address address in H,L
xchg ; move to D,E
mvi c,CSTask ; Use special TPC for control store addressing (to C)
call DoWriteTPC ; Write the TPC
mvi c,6 ; Counter for 6 bytes
lxi h,CSBuffer+5 ; Point to LS byte in buffer
GetCSData:
call ReadByte ; get next data byte from Alto
mov m,a ; Store in buffer area
dcx h ; Move pointer up
dcr c
jnz GetCSData ; nz => still more
; Now write the location.
call DoWriteCS ; Write the CS location
jmp KernelLoop
; Subroutine to write the CS location.
; In BootMode the CS location is written.
; In non-BootMode, IOPWait is set, a CS byte is written,
; the CP re-enabled, and a Refresh is requested. Repeated for each byte.
; (Maximum time that IOPWait should be set is 80 340 ns IOP cycles, 92 333 ns cycles.)
; On entry: Assumes that the TPC[6] has been set up correctly.
; CS data is in CSBuffer [0..5], (MSB..LSB).
; All registers are used.
; Register usage:
; H,L - Points to CPControl (memory mapped I/O)
; B,C - Points to CSa-CSe (memory mapped I/O)
; D,E - Points to CSBuffer
DoWriteCS:
lxi h,8000H+CPControl ; Set H,L to point to CPControl (memory mapped I/O)
lxi b,8000H+CSa ; Set B,C to point to CSa-CSe (memory mapped I/O)
lxi d,CSBuffer ; Set D,E to point to CSBuffer
; Check for BootMode.
lda KernelFlags ; Check whether the CP kernel is running (BootMode)
ani BootMode ;
jnz BootDoWriteCS ; BootMode (nz) => no CP control, Refresh
; Not BootMode.
mvi a,6 ; Counter for 6 bytes
DoWriteCSLoop:
sta CSCount ; Use memory for CS byte counter
mvi m,CPWait ; Set IOPWait in CPControl
; CP now in WAIT state.
mvi m,CPWaitSwT ; [10] Set IOPWait, SwTAddr in CPControl
ldax d ; [7] Get byte into A
cma ; [4] Complement for CP with LS240
stax b ; [7] Output CS byte
mvi m,CPWait ; [10] Set IOPWait, clear SwTAddr in CPControl
mvi m,CPEnable ; [10] Clear IOPWait, SwTAddr in CPControl
; CP now out of WAIT state. In wait state for 44 IOP cycles.
mvi a,CPRefresh ; Request refresh
call WriteCPport
NextWriteCS:
inx b ; Point to next CS I/O slot
inx d ; Point to next CS buffer location
lda CSCount ; Decrement CS byte counter
dcr a
jnz DoWriteCSLoop ; nz => still more
ret
; In BootMode. IOPWait is true.
BootDoWriteCS:
mvi a,6 ; Counter for 6 bytes
BootDoWriteCSLoop:
sta CSCount ; Use memory for CS byte counter
ldax d ; Get byte into A
cma ; Complement for CP with LS240
stax b ; Output CS byte
inx b ; Point to next CS I/O slot
inx d ; Point to next CS buffer location
lda CSCount ; Decrement CS byte counter
dcr a
jnz BootDoWriteCSLoop ; nz => still more
ret
; Command 7: Read Control Store: Read one location in control store.
; First two bytes from Alto are: CS addr low (low 8 bits), CS addr High (high 4 bits).
; 6 data bytes returned to Alto, least significant first.
; Use TPC (6) for CS addressing.
ReadCS:
call ReadWord ; get CS address address in H,L
xchg ; move to D,E
mvi c,CSTask ; Use special TPC for control store addressing (to C)
call DoWriteTPC ; Write the TPC
call DoReadCS ; Read the CS location into CSBuffer
; Return the CSData to the Alto
mvi c,6 ; Counter for 6 bytes
lxi h,CSBuffer+5 ; Point to LS byte in buffer
PutCSData:
mov a,m ; Get next data byte from buffer
call WriteByte ; send it to the Alto
dcx h ; Move pointer up
dcr c
jnz PutCSData ; nz => still more
jmp KernelLoop
; Subroutine to read the CS location.
; In BootMode the CS location is read.
; In non-BootMode, IOPWait is set, a CS byte is read,
; the CP re-enabled, and a Refresh is requested. Repeated for each byte.
; (Maximum time that IOPWait should be set is 80 340 ns IOP cycles, 92 333 ns cycles.)
; On entry: Assumes that the TPC[6] has been set up correctly.
; CS data is read into CSBuffer [0..5], (MSB..LSB).
; All registers are used.
; Register usage:
; H,L - Points to CPControl (memory mapped I/O)
; B,C - Points to CS0-CS5 (memory mapped I/O)
; D,E - Points to CSBuffer
DoReadCS:
lxi h,8000H+CPControl ; Set H,L to point to CPControl (memory mapped I/O)
lxi b,8000H+CS0 ; Set B,C to point to CS0-CS5 (memory mapped I/O)
lxi d,CSBuffer ; Set D,E to point to CSBuffer
; Check for BootMode.
lda KernelFlags ; Check whether the CP kernel is running (BootMode)
ani BootMode ;
jnz BootDoReadCS ; BootMode (nz) => no CP control, Refresh
; Not BootMode.
mvi a,6 ; Counter for 6 bytes
DoReadCSLoop:
sta CSCount ; Use memory for CS byte counter
mvi m,CPWait ; Set IOPWait in CPControl
; CP now in WAIT state.
mvi m,CPWaitSwT ; [10] Set IOPWait, SwTAddr in CPControl
ldax b ; [7] Get CS byte into A
stax d ; [7] Store in buffer
mvi m,CPWait ; [10] Set IOPWait, clear SwTAddr in CPControl
mvi m,CPEnable ; [10] Clear IOPWait, SwTAddr in CPControl
; CP now out of WAIT state. In wait state for 44 IOP cycles.
mvi a,CPRefresh ; Request refresh
call WriteCPport
NextReadCS:
inx b ; Point to next CS I/O slot
inx d ; Point to next CS buffer location
lda CSCount ; Decrement CS byte counter
dcr a
jnz DoReadCSLoop ; nz => still more
ret
; In BootMode. IOPWait is true.
BootDoReadCS:
mvi a,6 ; Counter for 6 bytes
BootDoReadCSLoop:
sta CSCount ; Use memory for CS byte counter
ldax b ; Get CS byte into A
stax d ; Store in buffer
inx b ; Point to next CS I/O slot
inx d ; Point to next CS buffer location
lda CSCount ; Decrement CS byte counter
dcr a
jnz BootDoReadCSLoop ; nz => still more
ret
; Command 8: Write TPC.
; First byte from Alto is TPC address, right justified (Task number).
; Next two bytes are: TPC data low (low 8 bits), TPC dataHigh (high 4 bits).
; Conventions: C contains the TPC address (3 bits right-justified)
; DE contains the TPC data (12 bits right-justified)
WriteTPC:
call ReadByte ; get TPC address
mov c,a
call ReadWord ; get TPC data to H,L
xchg ; move to D,E
call DoWriteTPC ; Write the TPC
jmp KernelLoop
; Subroutine to write the TPC.
; In BootMode the TPC is written.
; In non-BootMode, IOPWait is set, TPC is written,
; the CP re-enabled, and a Refresh is requested.
; (Maximum time that IOPWait should be set is 80 340 ns IOP cycles, 92 333 ns cycles.)
; On entry: C contains the TPC address (3 bits right-justified)
; DE contains the TPC data (12 bits right-justified)
; Format of TPCHigh (write): TPCAddr[0:2],,TPCData[0:4]'
; Format of TPCLow (write): don't care,,TPCData[5:11]'
; Compute the values of TPCHigh, TPCLow beforehand so that the
; CP is kept with IOPWait high for a minimum of time.
DoWriteTPC:
call LeftAlignTPCAddr ; Left align 3 bits of address in C
mov a,e ; Move TPC[4] into B for TPCHigh format
ral ; TPC[4] into carry
mov a,d ; get high part
ral ; TPC[4] into B[7]
cma ; complement for port
ani 1FH ; Clear High 3 bits
ora c ; OR in address
; Value in C not needed again.
mov d,a ; Store back in D
mov a,e ; Get low part (E[0] is don't care)
cma ; complement for port
mov e,a ; Store back in E
lxi h,8000H+CPControl ; Set H,L to point to CPControl (memory mapped I/O)
lxi b,8000H+TPCHigh ; Set B,C to point to CPControl (memory mapped I/O)
; Check for BootMode.
lda KernelFlags ; Check whether the CP kernel is running (BootMode)
ani BootMode ;
jnz BootWriteTPC ; BootMode (nz) => no CP control, Refresh
mvi m,CPWait ; Set IOPWait in CPControl
; CP now in WAIT state.
mvi m,CPWaitSwT ; [10] Set IOPWait, SwTAddr in CPControl
mov a,d ; [4] Get high part
stax b ; [7] Output TPCHigh (address, high data)
inx b ; [6] point to TPCLow
mov a,e ; [4] Get low part
stax b ; [7] Output TPCLow (low data)
mvi m,CPWait ; [10] Set IOPWait, clear SwTAddr in CPControl
mvi m,CPEnable ; [10] Clear IOPWait, SwTAddr in CPControl
; CP now out of WAIT state. In wait state for 58 IOP cycles.
mvi a,CPRefresh ; Request refresh
call WriteCPport
ret
; In BootMode. IOPWait is true.
BootWriteTPC:
mov a,d ; Get high part
stax b ; Output TPCHigh (address, high data)
inx b ; point to TPCLow
mov a,e ; Get low part
stax b ; Output TPCLow (low data)
ret
; Command 9: Read TPC/TC.
; First byte from Alto is TPC address, right justified (Task number).
; TPC data returned in two bytes: TPC data low (low 8 bits), TPC (high)/TC (8 bits).
ReadTPC:
call ReadByte ; get TPC address
mov c,a ; TPC address is in C
call DoReadTPC ; Read the TPC (data returned in H,L)
call WriteWord ; Send to Alto
jmp KernelLoop
; Subroutine to read the TPC.
; In BootMode the TPC is read.
; In non-BootMode, IOPWait is set, TPC is read,
; the CP re-enabled, and a Refresh is requested.
; (Maximum time that IOPWait should be set is 80 340 ns IOP cycles, 92 333 ns cycles.)
; On entry:
; TPC address is in C (3 bits right-justified).
; On exit:
; TPC data is in HL (12 bits right-justified).
; Format of bytes with TPCdata (CP Rev. B):
; TPCHigh (read): TC[0:3],,TPCdata[0:3]'
; TPCLow (read): TPCdata[4:11]'
; Have to set TPCAddress before read.
DoReadTPC:
call LeftAlignTPCAddr ; Left align 3 bits of address in C
lxi h,8000H+CPControl ; Set H,L to point to CPControl (memory mapped I/O)
lxi d,8000H+TPCHigh ; Set D,E to point to TPCHigh (memory mapped I/O)
; Check for BootMode.
lda KernelFlags ; Check whether the CP kernel is running (BootMode)
ani BootMode ;
jnz BootReadTPC ; BootMode (nz) => no CP control, Refresh
mov a,c ; TPC address to A
mvi m,CPWait ; Set IOPWait in CPControl
; CP now in WAIT state. A has TPC address.
mvi m,CPWaitSwT ; [10] Set IOPWait, SwTAddr in CPControl
stax d ; [7] Output TPCHigh (address, high data)
ldax d ; [7] Input TPCHigh (TC, high TPC data')
mov b,a ; [4] Store in B
inx d ; [6] point to TPCLow
ldax d ; [7] Input TPCLow (low TPC data')
mov c,a ; [4] Store in C
mvi m,CPWait ; [10] Set IOPWait, clear SwTAddr in CPControl
mvi m,CPEnable ; [10] Clear IOPWait, SwTAddr
; CP now out of WAIT state. In wait state for 65 IOP cycles.
mvi a,CPRefresh ; Request refresh
call WriteCPport
FixTPCData:
mov a,b ; Fix polarity of TPC data high
xri 0FH
mov h,a
mov a,c ; Fix polarity of TPC data low
cma
mov l,a
ret
; In BootMode. IOPWait is true.
BootReadTPC:
mov a,c ; Output TPCHigh (address, high data)
stax d ; Output TPCHigh (address, high data)
ldax d ; Input TPCHigh (TC, high TPC data')
mov b,a ; Store in B
inx d ; point to TPCLow
ldax d ; Input TPCLow (low TPC data')
mov c,a ; Store in C
jmp FixTPCData
; Subroutine to left align TPC address in C.
LeftAlignTPCAddr:
mov a,c
ani 7H ; Clear top bits
rrc
rrc
rrc
mov c,a
ret
; Command A: Write a single byte to CP port. (Use Block transfer command.)
WritePort:
lxi h,1 ; Count of 1
jmp WriteCPBlockLoop ; Jump into block transfer command
; Command B: Read a single byte from CP port. (Use Block transfer command.)
ReadPort:
lxi h,1 ; Count of 1
jmp ReadCPBlockLoop ; Jump into block transfer command
; Command C: Start CPKernel.
; Command to set IOPWait=0, SwTAddr=0, clear BootMode in KernelFlags.
; Used after CPKernel loading.
; At this point IOPWait = SwTAddr = 1.
StartCPKernel:
mvi a,CPWait ; Clear SwTAddr (Set IOPWait) in CPControl
out CPControl
mvi a,CPEnable ; Clear IOPWait, SwTAddr in CPControl
out CPControl
mvi a,NoBootMode ; BootMode=0, CPInSave=0, CPOutSave=0
sta KernelFlags
jmp KernelLoop
; Command D: Stop CP execution.
; Toggle IOPWait in CPControl, in order to cause CP to enter the CPKernel.
; We need to save CPport state here.
StopCP:
mvi a,CPWait ; Set IOPWait (SwTAddr=0) in CPControl
out CPControl
mvi a,CPEnable ; Clear IOPWait (SwTAddr=0) in CPControl
out CPControl
; We now need to save the state of the CPport.
call SaveCPportState
jmp KernelLoop
; Command E: Start CP execution.
; Force the CP to exit the CPkernel.
; Restore the state of the CPport here.
; This involves restoring CPOut, and CPControl.
; CPIn has already been restored by Burdock, IOPCtl will be done by CPKernel.
StartCP:
mvi a,CPExitKernel ; Command to CPKernel to exit CPKernel
call WriteCPport
; Restore the CPport.
lxi h,KernelFlags ; H,L points to KernelFlags
mov a,m ; Check if CPOut needs restoring
ani CPOutSaveFull ; Check CPOutSaveFull flag
jz RestoreCPControl ; z => CPOut was empty
lda CPOutSave ; Retrieve byte
out CPOut ; Put it back into port
RestoreCPControl:
mov a,m ; Check Dma state of port in KernelFlags
ani CPDmaIn ; Mask CPDmaIn
ori CPEnable ; OR in IOPWait=0, SwTAddr=0
mov b,a ; Save in B
out CPControl ; Restore DmaIn (to be done before DmaMode)
mov a,m ; Check DmaMode in KernelFlags
ani IOPAttn+CPDmaMode ; Mask all but IOPAttn, CPDmaMode
ora b ; OR in previous value
out CPControl ; Restore IOPAttn, DmaMode
; Clear out flags in KernelFlags.
EndStartCP:
mvi a,NoBootMode ; BootMode=0, CPInSave=0, CPOutSave=0 in KernelFlags
mov m,a
jmp KernelLoop
; Command 13H: Cold Start CP execution.
; Force the CP to exit the CPkernel.
; This command does not restore the CPport and is to be used when starting a program.
ColdStartCP:
mvi a,CPExitKernel ; Command to CPKernel to exit CPKernel
call WriteCPport
jmp EndStartCP
; Command F: Write a block of bytes to the CP port.
WriteCPBlock:
call ReadWord ; get byte count to H,L
WriteCPBlockLoop:
call ReadByte ; get data byte
call WriteCPport ; send it to port
dcx h ; Decrements byte counter
xra a ; Clear A
cmp l ; Check low part
jnz WriteCPBlockLoop
cmp h ; Check high part
jnz WriteCPBlockLoop
jmp KernelLoop ; Return for next command
; Command 11H: Read a block of bytes from the CP port.
ReadCPBlock:
call ReadWord ; get byte count to H,L
ReadCPBlockLoop:
call ReadCPport ; get data byte
call WriteByte ; send it to Alto
dcx h ; Decrements byte counter
xra a ; Clear A
cmp l ; Check low part
jnz WriteCPBlockLoop
cmp h ; Check high part
jnz WriteCPBlockLoop
jmp KernelLoop ; Return for next command
; Command 12H: Poll certain hardware flags (currently only CPAttn)
PollIOP:
in CPStatus ; Read the CPport status bits
ani CPAttnMask ; CPIn requesting an interrupt?
jz CPAttention ; Zero means CPAttn (active low)
; Return zero for no status.
xra a
call WriteByte ; Send to Alto
jmp KernelLoop ; CP breakpoint
;
; INTERRUPTS.
; IOP breakpoint. We get here from a RST 1
; Interrupts may be enabled or disabled at this point.
IOPBreakpoint:
push psw
rim ; Get status of interrupts
sta SaveRIM ; and save
di ; Disable in case on
mvi a,IOPBreak
jmp SaveState
; RST 5.5 Interrupt.
; The RST 5.5 interrupt can either be from the CPAttn, signifying a CP breakpoint,
; or from the Alto, signifying a mouse halt.
; Check the CPAttn bit first. If both interrupt sources are active the CPAttn will take precedence.
BurdockCPInt:
push psw ; save A, Flags of running program
; Check first for CPAttn, signifying a CP breakpoint.
in CPStatus ; Read the CPport status bits
ani CPAttnMask ; CPIn requesting an interrupt?
jz CPCall ; z => CPAttn (active low)
; Check for Mouse Halt, i.e. check for character from Alto.
in AltoPPIC ; Read port A interrupt
ani IntAMask
jnz BurdockCall ; nz => interrupt true
; Neither CPAttn or MouseHalt. Signify error in MP.
lxi h,ErrorBadIntr
jmp MPHang
; Alto Interrupt (mouse halt)
; Control reaches here as a result of the RST 5.5 hardware interrupt caused by a
; byte being transferred from Burdock to the IOP, while the IOP was not in the kernel.
; There are two modes of occurrence:
; The first is the normal mouse halt.
; The second is to implement the "DataForCP" command, in cooperation with Domino.
; The flag CPDataMode is set when the latter occurs, and an interrupt handler,
; in the BurdockCPTask in Domino is called.
; If it is the normal MouseHalt: Save machine state and check value from Burdock.
; Note: We know that interrupts were enabled and are now disabled.
; On entry: Stack has A, Flags of running program.
BurdockCall:
; push psw ; save A, Flags of running program
lda CPDataMode ; If CPDataMode is true, then data is transparent
ora a ; Set flags
jm DoDominoIntr ; m => call Domino interrupt handler
; We are not in transparent mode. Check byte from the port.
call ReadByte ; Get Burdock byte
cpi DataForCP ; Is it "DataForCP"?
jz GoToBurdockCPIntr ; Start of transparent mode
; Check for mouse halt.
push psw ; save A
rim ; Get status of interrupts
ori IntEnableBit ; Or in IntEnabled bit
sta SaveRIM ; and save
pop psw ; Retrieve Burdock byte
cpi AltoStop ; Is it a mouse halt?
jnz BurdockCallError ; If not, something is wrong
mvi a,IOPHalt ; It is a mouse halt
jmp SaveState
; Incorrect value from Alto, after halt.
BurdockCallError:
mvi a,IOPHaltError ; Error code
jmp SaveState
; We should jump to the Domino interrupt handler in BurdockCPTask.
DoDominoIntr:
call ReadByte ; Get Burdock byte
jmp GoToBurdockCPIntr
; CP breakpoint.
; Control reaches here when the CP hits a breakpoint and the IOP is not in the IOPKernel.
; This is as a result of the RST 5.5 hardware interrupt caused by CPAttn.
; The state of the CPport is saved for later restarting via StartCP.
; Note: that BootMode can never be set here.
; Return to the kernel similarly to Mouse halt or IOP breakpoint (above).
; Note: We know that interrupts were enabled and are now disabled.
; On entry: Stack has A, Flags of running program.
CPCall:
; push psw ; save AC, Flags
rim ; Get status of interrupts
ori IntEnableBit ; Or in IntEnabled bit
sta SaveRIM ; and save
; We now need to save the state of the CPport.
call SaveCPportState
; Enter the IOP Kernel.
mvi a,CPBreak ; It is a CP breakpoint
jmp SaveState
; CP breakpoint.
; Control reaches here when the CP hits a breakpoint and the IOP is in the IOPKernel.
; This is as a result of CPAttn being set, and detected in the Kernel IOPPoll command.
; The state of the CPport is saved for later restarting via StartCP.
CPAttention:
; We now need to save the state of the CPport.
call SaveCPportState
; Enter the IOP Kernel.
mvi a,CPBreak ; It is a CP breakpoint
sta WhyKernel ; Reason for message to Alto
jmp NotifyAlto ; Go tell the Alto (don't save the IOP state)
;
; SUBROUTINES.
; Subroutine to save the state of the CPport whenever the CP halts.
; The CP halts either after encountering a breakpoint, or as a result of a CPStop.
; We can only use the A reg., since the rest of the machine state may not be saved.
; (We could push a register on Stack before using).
SaveCPportState:
; Check the CPport Dma Status in CPControl.
in CPStatus ; Read IOPAttn, DmaMode, DmaIn in CPControl
ani CPDmaMask ; Mask out all but IOPAttn, DmaMode, DmaIn
sta KernelFlags ; Store. Note: CPSave flags, BootMode cleared.
mvi a,CPEnable ; Clear the saved bits in CPControl
out CPControl ; Note: Dma request disabled (DmaMode=0)
; CPDma is now disabled (in case it was previously enabled).
; Set IOPAttn to inform the CP that all CPport activity has ceased.
; The CP is waiting for the positive transition of IOPAttn so that it can
; check the state of the IOPIData (CPOut) register.
; Note that we should wait at least one instruction after the previous output
; to CPControl, in case the last Dma transfer just squeaked through.
mvi a,CPEnable+IOPAttn ; Set IOPAttn to inform the CP
out CPControl
; Check the state of CPIn.
; If CPInIntr is true, then there is a byte in the port which has not been read by the IOP.
in CPStatus
ani CPInIntMask
jz CheckCPAttn ; z => no byte is there.
in CPIn ; Read the byte,
sta CPInSave ; and store it in the save area
lda KernelFlags ; Set CPInSaveFlag in KernelFlags
ori CPInSaveFull
sta KernelFlags ; Store back.
; Now wait for CPAttn to clear.
CheckCPAttn:
in CPStatus ; Read the CPport status bits
ani CPAttnMask ; CPAttn true?
jz CheckCPAttn ; Zero means CPAttn true (active low)
mvi a,CPEnable ; Clear IOPAttn to inform the CP
out CPControl
ret
; CPport data transfer.
; Read abyte from the CP port. Return with byte in A register.
ReadCPport:
in CPStatus ; Read the port interrupt bits
ani CPInIntMask ; CPIn requesting an interrupt?
jz ReadCPport ; Zero means no interrupt
in CPIn ; get data
ret
; Write a byte to the CPport. Byte is in A register.
WriteCPport:
out CPOut ; Output data
WaitCPOutAck:
in CPStatus ; Read the port interrupt bits
ani CPOutIntMask ; CPOut requesting an interrupt, i.e data read?
jz WaitCPOutAck ; Zero means no interrupt
ret
; ReadByte: Read a byte from the Alto. Return with byte in A register.
ReadByte:
in AltoPPIC ; Read port A interrupt
ani IntAMask
jz ReadByte ; z => no interrupt
in AltoPPIA ; Read data from port A
ret
; WriteByte: Send a byte to the Alto. Byte is in A register.
WriteByte:
out AltoPPIB ; Write data into port B
WaitWrAck:
in AltoPPIC ; Read Channel B interrupt
ani IntBMask
jz WaitWrAck ; Wait if no interrupt
ret
; ReadWord - Word from Alto to HL, A lost.
ReadWord:
call ReadByte
mov l,a
call ReadByte
mov h,a
ret
; WriteWord - Word from HL to Alto, A lost.
WriteWord:
mov a,l
call WriteByte
mov a,h
call WriteByte
ret
; Maintenance Panel subroutines.
; Subroutine [DoMiscClock].
; Clocks a bit in the MiscClocks1 register.
; Width of clock pulse is 14 cycles (~5 usec).
; On entry: D contains a mask of the bit(s) to be toggled.
DoMiscClock:
mvi a,0FFH ; Set all high
xra d ; Clear clock bit(s)
out MiscClocks1
xra d ; Toggle bit again
out MiscClocks1
ret
; Subroutine [PutMP].
; Put a number in the maintenance panel.
; Number is put modulo 10,000D.
; On entry: H,L contains the number to be put in the panel.
PutMP:
call ClearMPanel ; Clear the panel
inx h ; Bias so that a value of zero can be used
jmp PutMPCheck
PutMPLoop:
mvi d,IncMPanel ; Mask for IncMPanel clock
call DoMiscClock
PutMPCheck:
xra a ; Clear A
dcx h ; Decrement the count
cmp l ; Check low part for zero
jnz PutMPLoop ; nz => not done yet
cmp h ; Low part is zero, check high part for zero
jnz PutMPLoop ; nz => not done yet
; Done.
ret
; Subroutine [ClearMPanel].
; Clear the maintenance panel, and to disable blanking.
ClearMPanel:
mvi d,ClrMPanel ; Mask for ClrMPanel clock
call DoMiscClock
xra a ; Clear BlankMPanel
out MiscControl1
ret
END
@
1.1.1.1
log
@first add
@
text
@@