-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcore.s
372 lines (343 loc) · 13.3 KB
/
core.s
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
; -----------------------------------------------------------------------------
; main loop
STRT: jsr CRLF
; print current drive and prompt
lda FA
jsr WRTWO
; lda STATUS
; jsr WRTWO
msg prompt
; read one line of input into BUF
ldx #0
SMOVE: stx CHRPNT
jsr CHRIN
tay
lda STATUS
beq @ok1
jsr CLRCHN
lda #0
sta STATUS
@ok1: ldx CHRPNT
tya
sta BUF,X
inx
CPX #ENDIN-BUF ; error if buffer is full
BCS ERROR
cmp #10 ; convert lf to cr
bne @sm1
lda #13
@sm1: cmp #13 ; keep reading until CR
bne SMOVE
LDA #0 ; null-terminate input buffer
STA BUF-1,X ; (replacing the CR)
stx COUNT
dec COUNT
; execute BUF
STRT2:
jsr translate
LDA #0
STA CHRPNT
; stx COUNT
; dec COUNT
lda COUNT
beq STRT ; repeat if buffer is empty
ST1: JSR GETCHR ; get a character from the buffer
BEQ STRT ; start over if buffer is empty
CMP #$20 ; skip leading spaces
BEQ ST1
S0: LDX #KEYTOP-KEYW ; loop through valid command characters
S1: CMP KEYW,X ; see if input character matches
BEQ S2 ; command matched, dispatch it
DEX ; no match, check next command
BPL S1 ; keep trying until we've checked them all
; then fall through to error handler
; -----------------------------------------------------------------------------
; handle error
ERROR:
LDY #MSG3-MSGBAS ; display "?" to indicate error and go to new line
JSR SNDMSG
JSR CLRCHN
JMP STRT ; back to main loop
; -----------------------------------------------------------------------------
; dispatch command
S2:
CPX #KEYTOP-KEYW-3 ; last 3 commands in table are load/save/validate
BCS LSV ; which are handled by the same subroutine
CPX #KEYTOP-KEYW-7 ; next 4 commands are base conversions
BCS CNVLNK ; which are handled by the same subroutine
TXA ; remaining commands dispatch through vector table
ASL A ; multiply index of command by 2
TAX ; since table contains 2-byte addresses
LDA KADDR+1,X ; push address from vector table onto stack
PHA ; so that the RTS from GETPAR will jump there
LDA KADDR,X
PHA
; JMP GETPAR ; get the first parameter for the command
RTS
LSV: STA SAVY ; handle load/save/validate
JMP LD
CNVLNK: JMP CONVRT ; handle base conversion
; -----------------------------------------------------------------------------
; read parameters
RDPAR: DEC CHRPNT ; back up one char
GETPAR: JSR RDVAL ; read the value
BCS GTERR ; carry set indicates error
JSR GOTCHR ; check previous character
BNE CKTERM ; if it's not null, check if it's a valid separator
DEC CHRPNT ; back up one char
LDA DIGCNT ; get number of digits read
BNE GETGOT ; found some digits
BEQ GTNIL ; didn't find any digits
CKTERM: CMP #$20 ; space or comma are valid separators
BEQ GETGOT ; anything else is an error
CMP #','
BEQ GETGOT
GTERR: PLA ; encountered error
PLA ; get rid of command vector pushed on stack
JMP ERROR ; handle error
GTNIL: SEC ; set carry to indicate no parameter found
.BYTE $24 ; BIT ZP opcode consumes next byte (CLC)
GETGOT: CLC ; clear carry to indicate paremeter returned
LDA DIGCNT ; return number of digits in A
RTS ; return to address pushed from vector table
; -----------------------------------------------------------------------------
; read a value in the specified base
RDVAL: LDA #0 ; clear temp
STA TMP0
STA TMP0+1
STA DIGCNT ; clear digit counter
TXA ; save X and Y
PHA
TYA
PHA
RDVMOR: JSR GETCHR ; get next character from input buffer
BEQ RDNILK ; null at end of buffer
CMP #$20 ; skip spaces
BEQ RDVMOR
LDX #3 ; check numeric base [$+&%]
GNMODE: CMP HIKEY,X
BEQ GOTMOD ; got a match, set up base
DEX
BPL GNMODE ; check next base
INX ; default to hex
DEC CHRPNT ; back up one character
GOTMOD: LDY MODTAB,X ; get base value
LDA LENTAB,X ; get bits per digit
STA NUMBIT ; store bits per digit
NUDIG: JSR GETCHR ; get next char in A
RDNILK: BEQ RDNIL ; end of number if no more characters
SEC
SBC #$30 ; subtract ascii value of 0 to get numeric value
BCC RDNIL ; end of number if character was less than 0
CMP #$0A
BCC DIGMOR ; not a hex digit if less than A
SBC #$07 ; 7 chars between ascii 9 and A, so subtract 7
CMP #$10 ; end of number if char is greater than F
BCS RDNIL
DIGMOR: STA INDIG ; store the digit
CPY INDIG ; compare base with the digit
BCC RDERR ; error if the digit >= the base
BEQ RDERR
INC DIGCNT ; increment the number of digits
CPY #10
BNE NODECM ; skip the next part if not using base 10
LDX #1
DECLP1: LDA TMP0,X ; stash the previous 16-bit value for later use
STA STASH,X
DEX
BPL DECLP1
NODECM: LDX NUMBIT ; number of bits to shift
TIMES2: ASL TMP0 ; shift 16-bit value by specified number of bits
ROL TMP0+1
BCS RDERR ; error if we overflowed 16 bits
DEX
BNE TIMES2 ; shift remaining bits
CPY #10
BNE NODEC2 ; skip the next part if not using base 10
ASL STASH ; shift the previous 16-bit value one bit left
ROL STASH+1
BCS RDERR ; error if we overflowed 16 bits
LDA STASH ; add shifted previous value to current value
ADC TMP0
STA TMP0
LDA STASH+1
ADC TMP0+1
STA TMP0+1
BCS RDERR ; error if we overflowed 16 bits
NODEC2: CLC
LDA INDIG ; load current digit
ADC TMP0 ; add current digit to low byte
STA TMP0 ; and store result back in low byte
TXA ; A=0
ADC TMP0+1 ; add carry to high byte
STA TMP0+1 ; and store result back in high byte
BCC NUDIG ; get next digit if we didn't overflow
RDERR: SEC ; set carry to indicate error
.BYTE $24 ; BIT ZP opcode consumes next byte (CLC)
RDNIL: CLC ; clear carry to indicate success
STY NUMBIT ; save base of number
PLA ; restore X and Y
TAY
PLA
TAX
LDA DIGCNT ; return number of digits in A
RTS
; -----------------------------------------------------------------------------
; copy TMP0 to TMP2
COPY12: LDA TMP0 ; low byte
STA TMP2
LDA TMP0+1 ; high byte
STA TMP2+1
RTS
; -----------------------------------------------------------------------------
; copy TMP0 to PC
COPY1P: BCS CPY1PX ; do nothing if parameter is empty
LDA TMP0 ; copy low byte
LDY TMP0+1 ; copy high byte
STA PCL
STY PCH
CPY1PX: RTS
; -----------------------------------------------------------------------------
; convert base [$+&%]
CONVRT: JSR RDPAR ; read a parameter
CONVRT1:
JSR FRESH ; output character
LDA #'"'
JSR CHROUT
LDA TMP0
JSR CHROUT
LDA TMP1
JSR CHROUT
LDA #'"'
JSR CHROUT
JSR FRESH ; next line and clear
LDA #'$' ; output $ sigil for hex
JSR CHROUT
LDA TMP0 ; load the 16-bit value entered
LDX TMP0+1
JSR WRADDR ; print it in 4 hex digits
JSR FRESH
LDA #'+' ; output + sigil for decimal
JSR CHROUT
JSR CVTDEC ; convert to BCD using hardware mode
LDA #0 ; clear digit counter
LDX #6 ; max digits + 1
LDY #3 ; bits per digit - 1
JSR NMPRNT ; print result without leading zeros
JSR FRESH ; next line and clear
LDA #'&' ; print & sigil for octal
JSR CHROUT
LDA #0 ; clear digit counter
LDX #8 ; max digits + 1
LDY #2 ; bits per digit - 1
JSR PRINUM ; output number
JSR FRESH ; next line and clear
LDA #'%' ; print % sigil for binary
JSR CHROUT
LDA #0 ; clear digit counter
LDX #$18 ; max digits + 1
LDY #0 ; bits per digit - 1
JSR PRINUM ; output number
JSR FRESH ; next line and clear
LDA #'#' ; print % sigil for binary
JSR CHROUT
lda TMP0 ; 1st charaster
and #$1F
ora #$40
jsr CHROUT
lda TMP1 ; 2nd character
and #$03
sta T1
lda TMP0
asl
rol T1
asl
rol T1
asl
rol T1
lda T1
ldx TMP1 ;
cpx #$c6
beq @cvt3 ; it is a number
ora #$40
jsr CHROUT
lda TMP1 ; 3rd character
bmi @cvt5
@cvt4: ; it is a letter
lsr
lsr
and #$1f
ora #$40
bne @cvt9 ; allways
@cvt5: ; it is a digit
lsr
lsr
@cvt3:
and #$0f
ora #$30
@cvt9:
jsr CHROUT
JMP STRT ; back to mainloop
; -----------------------------------------------------------------------------
; convert binary to BCD
CVTDEC: JSR COPY12 ; copy value from TMP0 to TMP2
LDA #0
LDX #2 ; clear 3 bytes in work buffer
DECML1: STA U0AA0,X
DEX
BPL DECML1
LDY #16 ; 16 bits in input
PHP ; save status register
SEI ; make sure no interrupts occur with BCD enabled
SED
DECML2: ASL TMP2 ; rotate bytes out of input low byte
ROL TMP2+1 ; .. into high byte and carry bit
LDX #2 ; process 3 bytes
DECDBL: LDA U0AA0,X ; load current value of byte
ADC U0AA0,X ; add it to itself plus the carry bit
STA U0AA0,X ; store it back in the same location
DEX ; decrement byte counter
BPL DECDBL ; loop until all bytes processed
DEY ; decrement bit counter
BNE DECML2 ; loop until all bits processed
PLP ; restore processor status
RTS
; load the input value and fall through to print it
PRINUM: PHA ; save accumulator
LDA TMP0 ; copy input low byte to work buffer
STA U0AA0+2
LDA TMP0+1 ; copy input high byte to work buffer
STA U0AA0+1
LDA #0 ; clear overflow byte in work buffer
STA U0AA0
PLA ; restore accumulator
; print number in specified base without leading zeros
NMPRNT:
JSR NMFORMAT
RTS
NMFORMAT:
STA DIGCNT ; number of digits in accumulator
STY NUMBIT ; bits per digit passed in Y register
DIGOUT: LDY NUMBIT ; get bits to process
LDA #0 ; clear accumulator
ROLBIT: ASL U0AA0+2 ; shift bits out of low byte
ROL U0AA0+1 ; ... into high byte
ROL U0AA0 ; ... into overflow byte
ROL A ; ... into accumulator
DEY ; decrement bit counter
BPL ROLBIT ; loop until all bits processed
TAY ; check whether accumulator is 0
BNE NZERO ; if not, print it
CPX #1 ; have we output the max number of digits?
BEQ NZERO ; if not, print it
LDY DIGCNT ; how many digits have we output?
BEQ ZERSUP ; skip output if digit is 0
NZERO: INC DIGCNT ; increment digit counter
ORA #$30 ; add numeric value to ascii '0' to get ascii char
STA $100,X
JSR CHROUT ; output character
ZERSUP: DEX ; decrement number of leading zeros
BNE DIGOUT ; next digit
RTS
MODTAB: .BYTE $10,$0A,$08,02 ; modulo number systems
LENTAB: .BYTE $04,$03,$03,$01 ; bits per digit