; Utility.asm. Assembly language utility routines
; undid change January 6, 1985 4:28 PM by Bill van Melle
; changed SmallPosP/Neg December 14, 1984 2:11 PM by Bill van Melle
; added 2 args to DspRate July 20, 1983 2:09 PM by Bill van Melle
; added SDP December 9, 1982 6:11 PM by Bill van Melle
; removed DoBitBlt July 21, 1982 6:55 PM by Bill van Melle
; added DspRate June 25, 1982 2:50 PM by Bill van Melle
; Last change July 21, 1981 12:38 PM by Beau Sheil
; Tone change March 17, 1981 6:35 PM by Beau Sheil
; Last change February 4, 1981 10:46 PM by Beau Sheil
; Chord change November 18, 1980 10:30 AM by Beau Sheil
; Previous last change November 11, 1980 5:36 PM by Beau Sheil
.ENT VP, VP2, Bytes2, EqNIL, EmAddr, EmUnbox
.ENT MkSmallPos, MkSmallNeg, Smallp, SmallUnbox, SmallNegUnbox
.ENT UCase, ReadClock, TimeSince
.ENT MachineType, Version, Serial, DspRateInstr, DskPartInstr
; procedures used
.EXTN RAIDCode
; statics used
.EXTD RMSK, lvVPtr, VPtr0, VPtr1
.EXTN EmulatorSpace
; new opcodes defined
.DUSR SWAT = #77400 ; For where one shouldnt go
.DUSR DSPRT = #61027 ; changes display rate
.DUSR SDP = #61037 ; sets/returns default partition
.SREL
VP: .vp
VP2: .vp2
Bytes2: .by2
EqNIL: .eqn
EmAddr: .ea
EmUnbox: .emunb
MkSmallPos: .msp
MkSmallNeg: .msn
Smallp: .smp
SmallUnbox: .smunb
SmallNegUnbox: .smnunb
UCase: .uc
ReadClock: .rclk
TimeSince: .tme
MachineType: .mt
Version: .vers
Serial: .ser
DspRateInstr: .dpr
DskPartInstr: .dskp
.NREL
; VP(lvAddr) -> virtual page in ac0
.vp: sta 3,1,2
mov 0,3
lda 0,0,3
lda 1,1,3
jmp vp
; VP2(vahi, valo) -> virtual page in ac0
.vp2: sta 3,1,2
vp: lda 3,RMSK
ands 3,0
lda 3,LMSK
ands 3,1
add 1,0
lda 3,1,2
jmp 1,3
LMSK: 177400
; Bytes2(hibyte, lobyte) -> word {hibyte,lobyte} in ac0
.by2: sta 3,1,2
lda 3,RMSK
ands 3,0
and 3,1
add 1,0
lda 3,1,2
jmp 1,3
; Smallp(lvN) -> whether lvN is a SMALLP
.smp: sta 3,1,2
mov 0,3
lda 0,0,3
lda 1, .smallp
sub# 0,1,snr
jmp .true
lda 1, .smalln
sub# 0,1,snr
jmp .true
jmp .false ; .true and .false restore ac3
; EmUnbox(lvN) unbox if emulator pointer, otherwise error
.emunb: sta 3,1,2
mov 0,3 ; ac3 ← arg
lda 0,0,3 ; ac0 ← hiloc(arg)
lda 1,@.es ; ac1 ← Emulator hi
sub# 0,1,szr ; test ac1=ac2
jmp .notem
lda 0,1,3 ; ac0 ← loloc(arg)
lda 3,1,2
jmp 1,3
.notem: mov 3, 1 ; original arg
.notem2:
jsr .emerr ; get addr of error msg into ac3
.TXTM B
.TXT "Not a short pointer"
.emerr: mov 3, 0 ; addr of error msg
jsrii .raid
2
lda 1, .smallp ; random safe garbage
jmp .notem2
; SmallNegUnbox(lvN) unbox if smallnegp, otherwise error
.smnunb: lda 1, .smalln
jmp .smun2
; SmallUnbox(lvN) unbox if smallposp, otherwise error
.smunb: lda 1, .smallp
.smun2: sta 3,1,2
mov 0,3
lda 0,0,3
sub# 0,1,szr
jmp .notsm
lda 0,1,3
lda 3,1,2
jmp 1,3
.notsm: mov 3, 1 ; original arg
.smerr2:
jsr .smerr ; get addr of error msg into ac3
.TXTM B
.TXT "Not a small posp"
.smerr: mov 3, 0 ; addr of error msg
jsrii .raid
2
lda 1, .smallp ; random safe garbage
jmp .smerr2
; SWAT ; cant return
.raid: RAIDCode
.smallp: 16 ;hi order word of small positive numbers
.smalln: 17 ;hi order word of small negative numbers
.es: EmulatorSpace
; EmAddr(n) ; makes an emulator ptr of n
.ea: lda 1,@.es
jmp .ms
; MkSmallNeg(n) ;n is treated as UNSIGNED
.msn: lda 1,.smalln
jmp .ms
; MkSmallPos(n)
.msp: lda 1,.smallp
.ms: sta 0,VPtr1
sta 1,VPtr0
lda 0,lvVPtr
jmp 1,3
; EqNIL(ptr) - NIL is <0><0> by definition
.eqn: sta 3,1,2
mov 0,3
lda 0,0,3
mov 0,0,szr
jmp .false
lda 0,1,3
mov 0,0,szr
.false: sub 0,0,skp ; false is 0
.true: adc 0,0 ; true is -1
lda 3,1,2
jmp 1,3
; UCase(cc) ;returns Upper Case version of character code
.uc: lda 1,.uca ;range check
adcz# 0,1 szc ;skip if ac0 ge 'a
jmp 1,3 ;other characters are OK
lda 1,.ucz
adcz# 1,0 szc ;skip if ac0 le 'z
jmp 1,3 ;other characters are OK
lda 1,.uc0
and 1,0 ;turn off high bit
jmp 1,3
.uc0: #337 ; select only low order byte, turn off bit 2
.uca: "a
.ucz: "z
; ReadClock(ptr) Reads ucode clock into ptr!0 and ptr!1
.rclk: sta 3,1,2
mov 0,3
RCLK
sta 0,0,3
sta 1,1,3
lda 3,1,2
jmp 1,3
; TimeSince(ptr) -> time in msec since time in ptr!0 and ptr!1
.tme: sta 3,1,2
mov 0,3
RCLK ; AC0/1 ← current time
; sta 0, savAC0 ; *** Strictly for debugging ***
; sta 1, savAC1 ; *** Strictly for debugging ***
sta 2, savAC2
lda 2,0,3 ; AC2/3 ← start time
lda 3,1,3
subz 3,1 szc ;
sub 2,0 skp ; AC0/1 ← AC0/1 - AC2/3
adc 2,0 ;
lda 2, msc1
div ; convert to msec
SWAT ; interval too long
lda 2, msc2
subz# 2,0 szc
inc 1,1 ; round up
mov 1,0
lda 2, savAC2
lda 3,1,2
jmp 1,3
;savAC0: 0 ; *** Strictly for debugging ***
;savAC1: 0 ; *** Strictly for debugging ***
savAC2: 0
msc1: 1681. ; 1msec / .595 usec
msc2: 840. ; half the above
; MachineType() = Version() rshift 12 = Dorado or Dolphin
.mt: VERS
lda 1, hi4
and 1, 0
60004 ; cycle4 - moves [0:3] -> [12:15]
jmp 1,3
hi4: 170000 ; selects bits [0:3]
; Version()
.vers: VERS
jmp 1,3
; Serial() returns the Alto Serial number
.ser: sub 0,0
SIO
lda 1, RMSK ; we want the right 8 bits only
and 1, 0
jmp 1,3
; DspRateInstr(ac0, ac1, ac2) returns old rate
.dpr: sta 2, dspsaveac2
lda 2, 3,2 ; load correct ac2
DSPRT
lda 2, dspsaveac2
jmp 1,3
dspsaveac2: 0
; DskPartInstr(newpart) returns old part
.dskp: SDP
jmp 1,3
; The following are arithmetic routines used ONLY by RAID number printing
; They are here for convenience as I dont want to use a whole file for them
.ENT Divide, Negate
.SREL
Divide: DIVD
Negate: NEGTE
.NREL
; NEGATE (VEC)
NEGTE: STA 3,1,2
MOV 0,3
LDA 0,0,3
LDA 1,1,3
NEG 1,1,SNR
NEG 0,0,SKP
COM 0,0
STA 0,0,3
STA 1,1,3
MOV 3,0
LDA 3,1,2
JMP 1,3
; DIVIDE(a2, b) -> r, leaves q in a
DIVD: STA 3,1,2
STA 2,TEMP
MOV 0,3
MOV 1,2
SUB 0,0
LDA 1,0,3
DIV
JMP .+1
STA 1,0,3 ; Q0
LDA 1,1,3
DIV
JMP .+1
STA 1,1,3 ; Q1
LDA 2,TEMP
LDA 3,1,2
JMP 1,3
TEMP: 0
.END