1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
;;; Subroutine: print_mmss
;;; Print the 3-byte jiffy count at cloksav as minute/seconds/centisec.
;;;
;;; Will print up to 10 characters using printchr. Normally it's only 8,
;;; because normally, the number of minutes is less than 100, even if
;;; the user unwisely enters a 5-digit particle count.
;;;
;;; Uses the floating point ROM routines, because it's easier to code
;;; this way (or so I thought!), and we don't need speed here.
;;;
;;; Caller must define cloksav (3 bytes) and fptmp (6 bytes).
;;; These don't absolutely have to be in zero page, but
;;; it's nice if they are.
;;;
print_mmss:
ldx #0 ; low byte of 256 (0)
stx FR0
inx
stx FR0+1 ; high byte of 256 (1)
jsr IFP ; FR0 now FP 256.0
jsr FMOVE ; FR1 = FR0 (both are 256.0)
jsr FMUL ; FR0 = FR0 * FR1 (65536.0) (and FR1 is now garbage, but...)
jsr FMOVE ; FR1 = FR0 (didn't need it anyway)
; cloksav is 3 bytes, MSB-first (like RTCLOK).
; first, convert the highest byte to jiffies:
ldx #0
stx FR0+1
lda cloksav
sta FR0
jsr IFP ; FR0 now cloksav in FP, FR1 = 65536.0
jsr FMUL ; FR0 = FR0 * FR1
jsr FMOVE ; FR1 = FR0, aka the high byte of cloksav in jiffies
; next, convert low 2 bytes of cloksav to FP...
lda cloksav+1
sta FR0+1
lda cloksav+2
sta FR0
jsr IFP ; ...ok, now:
jsr FADD ; add the high bytes in jiffies, result in FR0 again
; at this point, FR0 holds the 24-bit jiffy count, converted to FP.
; copy to fptmp before dividing (we need it later).
ldx #<fptmp
ldy #>fptmp
jsr FST0R
; 3600 NTSC jiffies or 3000 PAL jiffies = 1 minute, so divide.
jsr load_jpm_fr1
jsr FDIV ; FR0 = FR0 / FR1 (and FR1 is now garbage)
; FR0 is now minutes elapsed (e.g. 1.5, for 90 sec). Only print the
; integer part...
; FP ROM has no equivalent to trunc(). You might think you could call
; FPI followed by IFP, but FPI rounds up (e.g. 1.5 comes out as 2,
; not 1). But it's not hard to do:
lda FR0 ; exponent
beq truncdone
and #$4f ; ignore sign
sec
sbc #$3f ; A gets either 1 or 2
tax
lda #0
truncloop:
sta FR0+1,x
inx
cpx #5
bne truncloop
truncdone:
; print digits in FR0
; don't use FASC, easier to do it this way.
; here we use the first byte of FR1 as a temp.
lda FR0
and #$03
sta FR1
inc FR1
ldx #0
floop:
lda FR0+1,x
jsr printhex
inx
cpx FR1
bcc floop
floopdone:
; done printing minutes, let's have the separator
lda #':'
jsr printchr
; we don't have a modulus or remainder operation in the ROM, so
; handroll one here.
; multiplication and division trash FR1, which is annoying.
jsr load_jpm_fr1
jsr FMUL
jsr FMOVE
; reload original jiffy count into FR0
ldx #<fptmp
ldy #>fptmp
jsr FLD0R
; subtract FR1. FR0 ends up with jiffies modulo jiffies-per-sec.
jsr FSUB
; load 0.6 into FR1 so we can divide by it.
; result will be number of centisec (e.g. 1050 for 10.5 sec).
jsr zero_fr1
lda #$3f
sta FR1
lda #$60
sta FR1+1
jsr FDIV
; *now* we can actually make use of FPI's rounding!
jsr FPI
jsr IFP
; FR0 has division result, which is centiseconds.
; if the exponent is 0, we're OK. otherwise, shift down
; one byte so we print 00 for the seconds.
; again, avoid FASC.
lda FR0
and #$0f
bne twodigits
lda FR0+1
sta FR0+2
lda #0
sta FR0+1
twodigits:
lda FR0+1
jsr printhex
lda #'.'
jsr printchr
lda FR0+2
jmp printhex
; load jiffies-per-minute into FR1. needs done twice so
; it's a subroutine.
; floating point constants:
; 3600.0 is $41,$36,$00,$00,$00,$00
; 3000.0 is $41,$30,$00,$00,$00,$00
load_jpm_fr1:
jsr zero_fr1
lda #$41 ; excess-64 base-100 exponent and sign (bit 7 = 0 means positive)
sta FR1
ldx #$36 ; 1st mantissa BCD byte, NTSC
lda PAL ; ask the GTIA what TV standard we're using
and #$0e
bne ntsc
ldx #$30 ; 1st mantissa BCD byte, PAL
ntsc:
stx FR1+1
rts
;;; Subroutine: zero_fr1. Zeroes out all 6 bytes of FR1. Counterpart
;;; to the OS's ZFR0.
;;; Note: ZF1 does *not* just clear out FR1, it uses the X reg as an 8-bit
;;; pointer (to zero page only).
zero_fr1:
ldx #FR1
jmp ZF1
|