// PupTimeInit.bcpl

// Last modified March 4, 1979  2:33 AM by Boggs

get "pup0.decl"
get "pup1.decl"
get "PupTimeServ.decl"

external
[
// outgoing procedures
CreateTimeServ; DestroyTimeServ
SetTimeCorrection; SetTimeZone; SetTimeDST

// incoming procedures
TimeServ; TimeServCtx
Allocate; Free; Zero; MoveBlock
InitializeContext; Enqueue; Unqueue

// incoming statics
@ts; @ms
]

compileif alto then [ external [ ReadCalendar ] ]

//----------------------------------------------------------------------------
let CreateTimeServ() be
//----------------------------------------------------------------------------
[
ts = Allocate(ms>>MS.zone, lenTS); Zero(ts, lenTS)
ts>>TS.stats.version = timeStatsVersion
ts>>TS.ctx = InitializeContext(Allocate(ms>>MS.zone, 20), 20, TimeServCtx)
Enqueue(ms>>MS.ctxQ, ts>>TS.ctx)
compileif alto then [ ReadCalendar(lv ts>>TS.altoClk) ]
ts>>TS.dontKnowTime = nova  // assume Alto calendar clock is correct
]

//----------------------------------------------------------------------------
and DestroyTimeServ() be
//----------------------------------------------------------------------------
[
Unqueue(ms>>MS.ctxQ, ts>>TS.ctx)
Free(ms>>MS.zone, ts>>TS.ctx)
Free(ms>>MS.zone, ts)
]

//----------------------------------------------------------------------------
and SetTimeCorrection(seconds, sign) be
//----------------------------------------------------------------------------
[
ts>>TS.doCorrect = true
ts>>TS.corrSign = sign
MoveBlock(lv ts>>TS.correction, table [ 1; 20864 ], 2) // 86400 seconds/day
Divide32x16(lv ts>>TS.correction, seconds)
MoveBlock(lv ts>>TS.corrCount, lv ts>>TS.correction, 2)
ts>>TS.stats.correction = sign? seconds, -seconds
]

//----------------------------------------------------------------------------
and SetTimeZone(zoneS, zoneH, zoneM) be
//----------------------------------------------------------------------------
[
ts>>TS.timeParams.zoneS = zoneS
ts>>TS.timeParams.zoneH = zoneH
ts>>TS.timeParams.zoneM = zoneM
]

//----------------------------------------------------------------------------
and SetTimeDST(beginDST, endDST) be
//----------------------------------------------------------------------------
[
ts>>TS.timeParams.beginDST = beginDST
ts>>TS.timeParams.endDST = endDST
]

//----------------------------------------------------------------------------
and Divide32x16(lvNumber, divisor) = valof
//----------------------------------------------------------------------------
// Unsigned divide the 32-bit number at @lvNumber,
// put the quotient back in @lvNumber, and return the remainder.
[
manifest div = alto? 61021b, 73101b

(table
   [
    #55001	// sta 3 1 2
   #155000	// mov 2 3	// save stack pointer
   #102400	// mkzero 0 0
    #27404	// lda 1 @4 3	// get high dividend
    #31405	// lda 2 5 3	// get divisor
   div		// div		// ac0 ← remainder, ac1 ← quotient
      #401	//  nop
    #47404	// sta 1 @4 3	// store high quotient
    #11404	// isz 4 3
    #27404	// lda 1 @4 3	// get low dividend
   div		// div		// ac0 ← remainder, ac1 ← quotient
      #401	//  nop
    #47404	// sta 1 @4 3	// store low quotient
   #171000	// mov 3 2	// restore stack pointer
    #35001	// lda 3 1 2
     #1401	// jmp 1 3
   ])()
]