;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;
D O R A D O C o n t r o l P r o g r a m
;
;
B o o t s t r a p C o d e
;
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

;
filed on DoradoBoot.masm
;
E. McCreight
;
last modified May 15, 1981 5:09 PM

.EXPORTLoadDoradoCode,DoIRTableInst
.EXPORTStartDoradoAtInitmap
.EXPORTSetCP~AndDoIRTableInst,SetCPAndDoIRTableInst
.EXPORTSendIMBlockToDorado,SendAHunk
.EXPORTSendViaMIR,IRTable
.EXPORTCPRegToLink#,IMLHRSTK.0Is0#,IMLHRSTK.0Is1#
.EXPORTIMRHBLOCKIs0#,IMRHBLOCKIs1#
.EXPORTReturn#,QFromCPReg#,ALUFM[0]FromQ#
.EXPORTSetHoldTaskSim#
.EXPORTBootBlocks,Boot0Block,Boot1Block

.EXPORTIMAddress,HunksLeft,Hunk,MicroHalf,ExtraBits,ViaCP

.IMPORTInitMap

.IMPORTStdClockSet,StdClockSpeedH,StdClockSpeedL
.IMPORTReadMufflerField,ClockSpeedMufField
.IMPORTInitManifolds,MaxInitManifold,DoIOReset
.IMPORTBoot0Data,Boot0IMLoc,Boot0Length,Boot0Checksum
.IMPORTBoot0BreakpointCount,Boot0BreakpointAddrTable
.IMPORTBoot0GoLoc

.IMPORTBoot1Data,Boot1IMLoc,Boot1Length,Boot1Checksum
.IMPORTBoot1BreakpointCount,Boot1BreakpointAddrTable

.IMPORTClearDMManifold,AllowCBHolds,SetManifold
.IMPORTMicro,CDatum,ToCPRegH,ToCPRegL
.IMPORTSetCPReg~,SetCPReg,DoDoradoMicroInst
.IMPORTSetCPReg0,SetCPReg1
.IMPORTRunDoradoInstructionStream,StopDorado
.IMPORTPacifyWatchdog,Delay
.IMPORTWaitForCPControl,EnableMidas
.IMPORTSetProblem,ClearProblem,CouldntBootDorado

.SHORTMicro,CDatum,ToCPRegH,ToCPRegL

.PREDEFINE "MCS6502PREDEFS.SR"
.GETNOLIST"DoradoIO.mdefs"

.LOCBootData
.SHORTBootData

;
Note: these next two must appear together, because we copy
;
them as a block to the Dorado.

IMAddress:
.BLK2; the address where the data goes,
; high-order byte first

HunksLeft:
.BLK2; number of 17-byte hunks of an IM
;
block left to send, high-order byte first



InitManifoldsLeft:
.BLK1

NoopsToGo:
.BLK1; number of remaining No-ops for reset

Hunk:
.BLK2; address where the Rom data is coming from

ExtraBits:
.BLK1; byte containing 1 bit per 2 bytes of IM
; data

Checksum:
.BLK2; low-order byte first

BreakpointsLeft: .BLK
1

NextBreakpoint:
.BLK2; IM address, high-order byte first

BPAddrTable:
.BLK2; low-order byte first

MicroHalf:
.BLK1; 40 if left half, 41 if right half

ViaCP:
.BLK1;0 if bootstrap loader not yet running in Dorado

;
These parameter blocks describe data blocks to be transferred
;
to the running Dorado processor. They are probably (although
;
not necessarily) located in Rom, and they probably (although
;
not necessarily) consist of packed microinstructions to
;
be put into IM. We allow for several blocks because we
;
may want to re-configure the processor between
;
transfers; for example, to turn on/off parity errors.

.LOCBootBlockTable

BootBlocks:

Boot0Block:
.ADRBoot0Data; in microcomputer memory
Boot0IMLocation:
.ADRBoot0IMLoc; first IM location
Boot0HunkCount:
.ADRBoot0Length; in 17-byte hunks
Boot0RomChecksum:
.ADRBoot0Checksum
Boot0BPCount:
Boot0BreakpointCount
Boot0BPAddrTable:
.ADRBoot0BreakpointAddrTable; two bytes/breakpoint,
;
high-order byte first, in decreasing address order

Boot1Block:
.ADRBoot1Data
.ADRBoot1IMLoc
.ADRBoot1Length
.ADRBoot1Checksum
Boot1BreakpointCount
.ADRBoot1BreakpointAddrTable

.LOCBootCode

;
This is a set of Dorado microinstructions that are
;
jammed into IM and executed for their side effects.
;
Each is 5 bytes long and conforms to the format
;
in DoDoradoMicroInst:

;
0:RSTK.0,P015,JCN.7,P1631,0,0,0,0
;
1:RSTK.1,RSTK.2,RSTK.3,ALUF.0,BLOCK,FF.0,FF.1,FF.2
;
2:ALUF.1,ALUF.2,ALUF.3,BSEL.0,FF.3,FF.4,FF.5,FF.6
;
3:BSEL.1,BSEL.2,LC.0,LC.1,FF.7,JCN.0,JCN.1,JCN.2
;
4:LC.2,ASEL.0,ASEL.1,ASEL.2,JCN.3,JCN.4,JCN.5,JCN.6

.RDX2

IRTable:
;
General note: these are hand-coded and should be thoroughly
;
checked for accuracy. Make sure never to select BSEL=MD (0)
;
because that can cause holds.


Nop#:
;
Nop;
;
RSTK[0],ALUF[0],BSEL[1],LC[0],ASEL[4],FF[77],JCN[201]
01↑6.+(11↑4.)
0000↑4.+0001
0000↑4.+1111
0100↑4.+1100
0100↑4.+0000

IFUReset#:
;
IFUReset;
;
RSTK[0],ALUF[0],BSEL[1],LC[0],ASEL[4],FF[136],JCN[201]
01↑6.+(10↑4.)
0000↑4.+0010
0000↑4.+1111
0100↑4.+0100
0100↑4.+0000

CPRegToLink#:
;
B←RWCPReg,LocalJump[1];
;
RSTK[0],ALUF[17],BSEL[0],LC[0],ASEL[4],FF[176],JCN[201]
00↑6.+(11↑4.)
0001↑4.+0011
1110↑4.+1111
0000↑4.+0100
0100↑4.+0000

IMLHRSTK.0Is0#:
;
IMLHR0’POK←RWCPReg;
;
RSTK[1],ALUF[17],BSEL[0],LC[0],ASEL[4],FF[176],JCN[177]
01↑6.+(10↑4.)
0011↑4.+0011
1110↑4.+1111
0000↑4.+0011
0100↑4.+1111

IMLHRSTK.0Is1#:
;
IMLHR0POK←RWCPReg;
;
RSTK[3],ALUF[17],BSEL[0],LC[0],ASEL[4],FF[176],JCN[177]
00↑6.+(10↑4.)
0111↑4.+0011
1110↑4.+1111
0000↑4.+0011
0100↑4.+1111

CPRegToIM#:
IMRHBLOCKIs0#:
;
IMRHB’POK←RWCPReg;
;
RSTK[0],ALUF[17],BSEL[0],LC[0],ASEL[4],FF[176],JCN[177]
00↑6.+(10↑4.)
0001↑4.+0011
1110↑4.+1111
0000↑4.+0011
0100↑4.+1111

IMRHBLOCKIs1#:
;
IMRHBPOK←RWCPReg;
;
RSTK[2],ALUF[17],BSEL[0],LC[0],ASEL[4],FF[176],JCN[177]
01↑6.+(10↑4.)
0101↑4.+0011
1110↑4.+1111
0000↑4.+0011
0100↑4.+1111

Return#:
;
TaskingOff,Return;
;
RSTK[0],ALUF[17],BSEL[1],LC[0],ASEL[4],FF[142],JCN[107]
01↑6.+(10↑4.)
0001↑4.+0011
1110↑4.+0001
0100↑4.+0010
0100↑4.+0011

QFromCPReg#:
;
Q←RWCPReg;
;
RSTK[0],ALUF[17],BSEL[3],LC[0],ASEL[4],FF[176],JCN[201]
00↑6.+(11↑4.)
0001↑4.+0011
1110↑4.+1111
1100↑4.+0100
0100↑4.+0000

TFromCPReg#:
; requires ALUFM[0]=B
;
T←RWCPReg;
;
RSTK[0],ALUF[0],BSEL[0],LC[1],ASEL[4],FF[176],JCN[201]
01↑6.+(11↑4.)
0000↑4.+0011
0000↑4.+1111
0000↑4.+0100
1100↑4.+0000

ALUFM[0]FromQ#:
;
ALUFMEM←Q,ALUF[0];
;
RSTK[0],ALUF[0],BSEL[3],LC[0],ASEL[4],FF[262],JCN[201]
00↑6.+(11↑4.)
0000↑4.+0101
0000↑4.+1001
1100↑4.+0100
0100↑4.+0000

SetMcr#:
;
LoadMcr[T,T];
;
RSTK[0],ALUF[0],BSEL[2],LC[0],ASEL[6],FF[126],JCN[201]
00↑6.+(11↑4.)
0000↑4.+0010
0000↑4.+1011
1000↑4.+0100
0110↑4.+0000

SetHoldTaskSim#:
;
HoldSim←RWCPReg (more or less);
;
RSTK[0],ALUF[17],BSEL[2],LC[0],ASEL[4],FF[176],JCN[201]
01↑6.+(11↑4.)
0001↑4.+0011
1110↑4.+1111
1000↑4.+0100
0100↑4.+0000

.RDX16

;
Routine to run the Boot0 code block in the Dorado, and then
;
hand it the Boot1 code block in CPReg byte by byte.

LoadDoradoCode:

;
Prevent Midas from taking over the machine during a bootstrap
;
operation, assuming that Midas is obeying standard politeness
;
conventions.

JSRWaitForCPControl
JSRStopDorado

;
Check whether the clock speed is faster than the standard
;
startup clock speed. If so, slow it down.

LDYI7
LDXIClockSpeedMufField
JSRReadMufflerField
CMPIStdClockSet
BEQClockSpeedOK
BCCClockSpeedOK

;
Set the standard clock speed

LDXIStdClockSpeedH
JSRSetManifold
LDXIStdClockSpeedL
JSRSetManifold

;
Wait for the clock to settle.

LDXI2.
JSRDelay

;
At this point all the power supplies are on and the
;
voltages and currents are within acceptable limits.
;
Initialize all manifold registers, clear IO reset.

ClockSpeedOK:
LDXIInitManifolds
LDAIMaxInitManifold
STAInitManifoldsLeft

SetupManifoldLoop:
JSRSetManifold
INX
INX; two bytes per manifold entry
DECInitManifoldsLeft
BPLSetupManifoldLoop

JSRPrepareProcessor

;
Set up ALUFM[0] with a 25o, which is the logical
;
function B.

LDXI25o
LDAIQFromCPReg#-IRTable
JSRSetCPAndDoIRTableInst
LDAIALUFM[0]FromQ#-IRTable
JSRDoIRTableInst

;
Do an IFU reset to stop the IFU from polluting the MAR mux.

LDAIIFUReset#-IRTable
JSRDoIRTableInst

;
Enter the Boot0 loader into the IM

LDXIBoot0Block-BootBlocks
LDAI0; Dorado not running loader
JSRSendIMBlockToDorado

;
Make sure there is no "ACK" in the Dorado-to-micro
;
manifold communication register.

LDXIClearDMManifold
JSRSetManifold

;
Put into Link the address of the first instruction in the Boot0
;
microcode.

LDYIBoot0GoLoc,#HighAddrByte
LDXIBoot0GoLoc,#LowAddrByte
LDAICPRegToLink#-IRTable
JSRSetCP~AndDoIRTableInst

;
Put a 1 in CPReg[0] to synchronize microcomputer-microprocessor
;
CPReg communications.

LDAI0
STAToCPRegL
LDAI80
STAToCPRegH
JSRSetCPReg; force a 1 in CPReg[0] to synchronize comm

;
Allow CB holds

LDXIAllowCBHolds
JSRSetManifold

;
Start the Boot0 loader running in the Dorado.

LDAIReturn#,#HighAddrByte
STAMicro+1
LDAIReturn#,#LowAddrByte
STAMicro
JSRRunDoradoInstructionStream

;
Send the Boot0 loader a block of code for it to load into IM.

LDXIBoot1Block-BootBlocks
LDAI1; Dorado now running loader
JSRSendIMBlockToDorado

LDAICouldntBootDorado
JSRClearProblem

;
Now see if Dorado has sent us an "ACK", as it were,
;
for the whole block.

LDYI65.; give the Dorado about 250 ms to complete init
LDXI0

WaitForACK:
LDAMiscByte
ANDI0f
CMPI01; "ACK"
BEQHeSentACK

DEX; 15 us inner loop
BNE WaitForACK

DEY
BNEWaitForACK

LDAICouldntBootDorado
JSRSetProblem; we failed. Notify user.

;
Now let Midas have access to the Dorado once again.

HeSentACK:
JMPEnableMidas

;
Routine to re-start the Dorado at IM location InitMap.

StartDoradoAtInitmap:
JSRWaitForCPControl

JSRPrepareProcessor

;
Put into Link the address of the InitMap.

LDYIInitMap,#HighAddrByte
LDXIInitMap,#LowAddrByte
LDAICPRegToLink#-IRTable
JSRSetCP~AndDoIRTableInst

;
Start the Dorado running at InitMap.

LDAIReturn#,#HighAddrByte
STAMicro+1
LDAIReturn#,#LowAddrByte
STAMicro
JSRRunDoradoInstructionStream

JMPEnableMidas

;
Subroutine to get the Dorado’s attention and get it reset.

PrepareProcessor:
JSRStopDorado

LDXIDoIOReset
JSRSetManifold

;
Do a lot of microinstructions to clear out the cobwebs. Those
;
microinstructions clear out the hold and task simulator.

LDAI40.
STANoopsToGo

DoYetAnotherNoop:
LDXI0
LDYI0
LDAISetHoldTaskSim#-IRTable
JSRSetCPAndDoIRTableInst
DECNoopsToGo
BNEDoYetAnotherNoop

;
Clear out MCR to DisHold, NoWakeups.

LDXI103o
LDYI0
LDAITFromCPReg#-IRTable
JSRSetCPAndDoIRTableInst
LDAISetMcr#-IRTable
JSRDoIRTableInst

;
Turn off tasking

LDAIReturn#-IRTable
JSRDoIRTableInst

RTS

;
Routine to do an IRTable instruction, perhaps setting
;
the CP register first. The offset
;
is in A.

SetCP~AndDoIRTableInst:
STXToCPRegL
STYToCPRegH
PHA
JSRWaitForCPControl
JSRSetCPReg~
PLA
JMPDoIRTableInstAndNop

SetCPAndDoIRTableInst:
STXToCPRegL
STYToCPRegH
PHA
JSRWaitForCPControl
JSRSetCPReg
PLA

DoIRTableInstAndNop:
; the Nop holds CPReg constant through T3 of
; the previous instruction
JSRDoIRTableInst
LDAINop#-IRTable
JMPBasicDoIRTableInst



DoIRTableInst:
JSRWaitForCPControl

BasicDoIRTableInst:
CLC
ADCIIRTable,#LowAddrByte
STAMicro
LDAI0
ADCIIRTable,#HighAddrByte
STAMicro+1
JSRDoDoradoMicroInst
JMPEnableMidas


;
Routine to pass the Dorado a block of microinstructions.
;
X indexes a table of pointers (to first bytes) and lengths
;
(in hunks). A is zero if we must load IM by manually executing
;
instructions in MIR, and non-zero if we can send stuff
;
to an executing Dorado program through CPReg.

SendIMBlockToDorado:
STAViaCP

LDAXBoot0IMLocation; low-order byte
STAIMAddress+1
LDAXBoot0IMLocation+1; high-order byte
STAIMAddress
LDAXBoot0HunkCount; low-order byte
STAHunksLeft+1
LDAXBoot0HunkCount+1; high-order byte
STAHunksLeft
LDAXBoot0RomChecksum; low-order byte
STAChecksum
LDAXBoot0RomChecksum+1; high-order byte
STAChecksum+1
LDAX Boot0BPCount
STABreakpointsLeft
LDAXBoot0BPAddrTable; low-order byte
STABPAddrTable
LDAXBoot0BPAddrTable+1; high-order byte
STABPAddrTable+1
JSRSetupNextBreakpoint

LDAViaCP; don’t send a count if nobody’s listening
BEQFinishSendIMBlockSetup

;
First tell the Dorado where the hunks go, how many are
;
coming.

LDAIIMAddress,#HighAddrByte
STAHunk+1
LDAIIMAddress,#LowAddrByte
STAHunk

LDYI0
STYExtraBits
LDAI40
STAMicroHalf
JSRSendAHalfMicroInstruction; IMAddress
JSRSendAHalfMicroInstruction; HunksLeft

FinishSendIMBlockSetup:
LDAXBoot0Block
STAHunk
LDAXBoot0Block+1
STAHunk+1

SendAnotherHunk:
JSRSendAHunk
JSRPacifyWatchdog

LDAHunk
CLC
ADCI17.
STAHunk
BCCNoMicroCarry
INCHunk+1

NoMicroCarry:
DECHunksLeft+1
BNESendAnotherHunk

DECHunksLeft
BPLSendAnotherHunk

LDAViaCP; don’t send a checksum if nobody’s listening
BEQFinishSendIMBlock

LDAChecksum
SEC; good parity
JSRSetCPReg1; set low-order byte of parity word
LDAChecksum+1
JSRSetCPReg0; high-order byte signals that CPReg is good

FinishSendIMBlock:
RTS


SetupNextBreakpoint:
TYA
PHA
LDYBreakpointsLeft
DEY
TYA
ASLA; 2 bytes/entry
TAY
LDA@YBPAddrTable; high-order address byte
STANextBreakpoint
INY
LDA@YBPAddrTable; low-order address byte
STANextBreakpoint+1
PLA
TAY
RTS

;
A hunk is a
;
sequence of 17 bytes containing four microinstructions
;
packed as follows, from high- to low-order bit in each byte:

;
Byte 0: 0RSTK.0, 0BLOCK, 1RSTK.0, 1BLOCK,
;
2RSTK.0, 2BLOCK, 3RSTK.0, 3BLOCK
;
Byte 1:0RSTK.1, 0RSTK.2, 0RSTK.3, 0ALUF.0,
;
0ALUF.1, 0ALUF.2, 0ALUF.3, 0BSEL.0
;
Byte 2: 0BSEL.1, 0BSEL.2, 0LC.0, 0LC.1,
;
0LC.2, 0ASEL.0, 0ASEL.1, 0ASEL.2
;
Byte 3:0FF.0, 0FF1, 0FF.2, 0FF.3,
;
0FF.4, 0FF.5, 0FF.6, 0FF.7
;
Byte 4:0JCN.0, 0JCN.1, 0JCN.2, 0JCN.3,
;
0JCN.4, 0JCN.5, 0JCN.6, 0JCN.7
;
...
;
...
;
Byte 14:3RSTK.1, 3RSTK.2, 3RSTK.3, 3ALUF.0,
;
3ALUF.1, 3ALUF.2, 3ALUF.3, 3BSEL.0
;
Byte 15: 3BSEL.1, 3BSEL.2, 3LC.0, 3LC.1,
;
3LC.2, 3ASEL.0, 3ASEL.1, 3ASEL.2
;
Byte 16:3FF.0, 3FF1, 3FF.2, 3FF.3,
;
3FF.4, 3FF.5, 3FF.6, 3FF.7
;
Byte 17:3JCN.0, 3JCN.1, 3JCN.2, 3JCN.3,
;
3JCN.4, 3JCN.5, 3JCN.6, 3JCN.7

;
We assume without checking that the Dorado will take the
;
data as fast as we slap it into the CP register. The
;
presence of new data is signalled by a change in
;
the high-order bit of the CP register. The Dorado will
;
have a minimum of 25 usec from a change in the high-order bit
;
of CPReg until the data in the low-order
;
byte of CPReg goes away. Data will be sent at about
;
200 usec per microinstruction.

SendAHunk:
LDAViaCP
BEQDontGetCPControlYet

JSRWaitForCPControl

DontGetCPControlYet:
LDYI0
LDA@YHunk; pick up the first byte
INY
STAExtraBits

SendAnotherInstruction:
LDAI40; left half
STAMicroHalf

LDAIMAddress+1; low-order byte
CMPNextBreakpoint+1
BNEUseMicroHalf
LDAIMAddress; high-order byte
CMPNextBreakpoint
BNEUseMicroHalf
LDABreakpointsLeft; is it really real?
BEQUseMicroHalf

LDAI2; set a breakpoint
ORAMicroHalf
STAMicroHalf

UseMicroHalf:
JSRSendAHalfMicroInstruction

LDAMicroHalf
ORAI1; right half
STAMicroHalf
JSRSendAHalfMicroInstruction

LDAMicroHalf
ANDI2; set a breakpoint?
BEQNotThisInstruction

DECBreakpointsLeft
JSRSetupNextBreakpoint

NotThisInstruction:
INCIMAddress+1
BNEDontStepHighIMAddress
INCIMAddress

DontStepHighIMAddress:
CPYI17.; 2 us
BNESendAnotherInstruction; 3 us

LDAViaCP
BEQDontReturnCPControl
JSREnableMidas

DontReturnCPControl:
RTS

SendAHalfMicroInstruction:
LDAViaCP
BEQSendViaMIR

LDA@Y Hunk; 5 us
INY; 2 us
STAMCPBusH; 4 us
LDAI80+ABMux1; good parity; 2 us
STAMCPBusL; 4 us
INCMCPBusL; strobe it into CPReg low-order bits; 5 us
DECMCPBusL; 5 us

LDAI0; 2 us
STAMCPBusH; 4 us
LDAIABMux0; 2 us
STAMCPBusL; 4 us
INCMCPBusL; strobe it into CPReg high-order bits; 5 us
DECMCPBusL; 5 us

LDA@Y Hunk; 5 us
INY; 2 us
STAMCPBusH; 4 us
LDAI80+ABMux1; good parity; 2 us
STAMCPBusL; 4 us
INCMCPBusL; strobe it into CPReg low-order bits; 5 us
DECMCPBusL; 5 us

LDAMicroHalf; 3 us
ASLExtraBits; 5 us
ROLA; 2 us
STAMCPBusH; 4 us
LDAIABMux0; 2 us
STAMCPBusL; 4 us
INCMCPBusL; strobe it into CPReg high-order bits; 5 us
DECMCPBusL; 5 us

RTS

IMStoreTable:
IMLHRSTK.0Is0#-IRTable; 0instructions in IRTable that do
IMLHRSTK.0Is1#-IRTable; 1useful stores into IM
IMRHBLOCKIs0#-IRTable; 2
IMRHBLOCKIs1#-IRTable; 3

;
This stores in IM by executing instructions out of MIR,
;
one at a time. We don’t bother to set breakpoints here.

SendViaMIR:
TYA
PHA
LDXIMAddress+1; low-order IM address byte
LDYIMAddress; high-order IM address byte
LDAICPRegToLink#-IRTable
JSRSetCP~AndDoIRTableInst

PLA
TAY
LDA@YHunk
INY
STAToCPRegH
LDA@YHunk
INY
STAToCPRegL
TYA
PHA
JSRSetCPReg~

LDAMicroHalf
ANDI1
ASLExtraBits
ROLA
TAX
LDAXIMStoreTable
JSRDoIRTableInst; CPReg can change before T3

PLA
TAY
RTS

.END