// DDTapeInit.bcpl - Dual Density Tape Low Level Driver Initialization
//
// Dual Density Tape Low Level Initialization
// Last modified by Tim Diebert, March 3, 1981 2:16 PM
// Copyright Xerox, 1980
//


get "DDTapes.d"

external
[

// Procedures from the User Program or the ALTO Context package
Block

// Procedures from the ALTO Operating System
Allocate
CallSwat
DisableInterrupts
EnableInterrupts
Free
SetEndCode
StartIO
sysZone
Zero

// Procedures from the ALTO Interrupt Package
InitializeInterrupt
FindInterruptMask

// Procedures from the ALTO LoadRam Package
LoadRam

// Procedures from the ALTO Timer Package
InitializeTimer
SetTimer
TimerHasExpired

]

static
[
DDTapeDispSaveData1
DDTapeDispSaveData2
DDTapeDispSaveData3
DDTapeDispSavervDCBStart
DDTapeVertIntMask
DDTapeVertIntChannel
]


//---------------------------------------------------------------------------------
let InitializeDDTape() = valof
//---------------------------------------------------------------------------------
[
if LoadRam( DDTapeImage ,true) ne 0 do
[
CallSwat("LoadRam(DDTapeImage ,true) failed.")
resultis false
]

// Set up TapeOpened block
TapeOpened = Allocate(sysZone, MaxUnitNum + 1, true)
unless TapeOpened do
[
CallSwat("*NSystem Error unable to allocate space for TapeOpened")
resultis false
]
Zero(TapeOpened, MaxUnitNum + 1)
InitializeTimer()

// Allocate some space for the VDDTCB
let vtape = Allocate(sysZone, lVDDTCB, true, true)
unless vtape do
[
CallSwat("*nSystem Error: Unable to allocate space for VDDTCB")
resultis 0
]

// Allocate a DDTCB in order to perform a reset on the hardware
Zero(vtape, lDDTCB)
vtape>>VDDTCB.Unit = 0
vtape>>VDDTCB.Command = #37
vtape>>VDDTCB.opDensity = PE
vtape>>DDTCB.Opcode = NoOp
@DDTCBStart=vtape
StartIO(TapeResetOp)

// DO the reset
let Timer = nil
SetTimer(lv Timer, 8)
until TimerHasExpired(lv Timer) do Block()

StartIO(TapeNormalOp)

// DO the reset
let Timer = nil
SetTimer(lv Timer, 8)
until TimerHasExpired(lv Timer) do Block()

StartIO(TapeNormalOp)

// DO the reset
let Timer = nil
SetTimer(lv Timer, 8)
until TimerHasExpired(lv Timer) do Block()

StartIO(TapeNormalOp)

// DO the reset
let Timer = nil
SetTimer(lv Timer, 8)
until TimerHasExpired(lv Timer) do Block()

// Make things right with the world again
Free(sysZone, vtape)

// Get Channel available mask
DDTapeVertIntMask = FindInterruptMask(1)

// Check validity of mask
DDTapeVertIntMask = MakeOneBit(DDTapeVertIntMask)
if (DDTapeVertIntMask & @IntActive) ne 0 then CallSwat("Interrupt In Use")

// Discover interrupt channel number
let DDTapeVertIntChannel = 0
while ((1 lshift DDTapeVertIntChannel) & DDTapeVertIntMask) eq 0 do
[
DDTapeVertIntChannel = DDTapeVertIntChannel + 1
]

// Save off the old stuff
DDTapeDispSaveData1 = IntVec!DDTapeVertIntChannel
DDTapeDispSaveData2 = DCBInterupt
DDTapeDispSaveData3 = rv IntActive
DDTapeDispSavervDCBStart = rv DCBStart

// Set up new interupt
DisableInterrupts()
IntVec!DDTapeVertIntChannel = DDTapeVertIntCode
@IntActive = @IntActive % DDTapeVertIntMask
@DCBInterupt = @DCBInterupt % DDTapeVertIntMask
EnableInterrupts()

resultis true
]

//---------------------------------------------------------------
and MakeOneBit(mask) = valof
//---------------------------------------------------------------
//From mask, make legal one-bit mask sensing only highest order bit
[
if mask eq 0 then CallSwat("Interrupt Mask Zero")
let i = 0
while (mask𘚠) eq 0 do
[
mask = mask lshift 1
i = i+1
]
mask = (#100000 rshift i)
if mask eq #100000 then CallSwat("Interrupt Chan Zero")
resultis mask
]