mirror of
https://github.com/livingcomputermuseum/Darkstar.git
synced 2026-03-02 10:06:45 +00:00
39 lines
39 KiB
Plaintext
39 lines
39 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.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
|
||
@@
|