;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;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: .BLK1
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