-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstring.z80
473 lines (443 loc) · 9.96 KB
/
string.z80
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
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
ConvertToUpper:
push hl
ConvertToUpper00:
ld a, (hl)
cp $0
jr z, ConvertToUpper03
cp 'a'
jr z, ConvertToUpper01
jr c, ConvertToUpper02
cp 'z'
jr z, ConvertToUpper01
jr nc, ConvertToUpper02
ConvertToUpper01:
sub a, 32
ld (hl), a
ConvertToUpper02:
inc hl
jr ConvertToUpper00
ConvertToUpper03:
pop hl
ret
PrintStringA:
ld a, (hl)
cp "\0"
ret z
call SERIAL_WRITE_A
inc hl
jr PrintStringA
Print3Strings:
call PrintStringA
ex de, hl
call PrintStringA
ld h, b
ld l, c
jr PrintStringA
ReadLineA:
push hl
ld b, 0
ReadLineA00:
call SERIAL_READ_A
; Check for backspace
cp 0x7F ; Backspace
jr z, ReadLineABackspace
; Check for end of line
cp "\r"
jr z, ReadLineA01
; Check for abort with ctrl-c
cp 0x03 ; Ctrl-C
jr z, ReadLineA02
; If not any of the above cases, we're
; dealing with a "real char".
; Do we have buffer space to handle it?
ld c, a ; Backup char
ld a, b
cp 80
jr z, ReadLineABackspaceEnd
ld a, c ; Restore char
; We have buffer space, so echo the char,
; store it in mem and increment the buffer
; pointer and char count
call SERIAL_WRITE_A
ld (hl), a
inc hl
inc b
jr ReadLineA00
ReadLineABackspace:
; Handle Backspace
; Are we already at cursor?
ld a, 0
cp b
jr z, ReadLineABackspaceEnd
dec hl
dec b
push hl
ld hl, BackSpaceControlSeq
call PrintStringA
pop hl
; Read next char
jr ReadLineA00
ReadLineABackspaceEnd:
ld a, 0x1B
call SERIAL_WRITE_A
ld a, "g"
call SERIAL_WRITE_A
jr ReadLineA00
BackSpaceControlSeq:
defm 0x1B, 0x5B, "D", 0x1B, 0x5B, "P", 0x00
ReadLineA01:
; Handle Enter
call SERIAL_WRITE_A ; Echo the \r
ld a, "\n"
call SERIAL_WRITE_A
; Terminate string
ld (hl), "\0"
pop hl
cp a ; Set zero flag
ret
ReadLineA02:
; Handle Ctrl-C
ld hl, message_buffer
call TerminateLine
ld hl, message_buffer
call PrintStringA
pop hl
or 1 ; Reset zero flag
ret
StrCmp:
ld a, (hl)
cp $0
ret z
ld b, a
ld a, (de)
cp $0
ret z
cp b
ret nz
inc hl
inc de
jr StrCmp
StrictStrCmp:
; Load next chars of each string
ld a, (de)
ld b, a
ld a, (hl)
; Compare
cp b
; Return non-zero if chars don't match
ret nz
; Check for end of both strings
cp "\0"
; Return if strings have ended
ret z
; Otherwise, advance to next chars
inc hl
inc de
jr StrictStrCmp
StrLen:
push hl
ld b, 0
StrLen00:
ld a, (hl)
cp "\0"
jr z, StrLen01
inc hl
inc b
jr StrLen00
StrLen01:
pop hl
ld a, b
ret
StrAddChar:
; Copy char in A to HL and inc
ld (hl), a
inc hl
ret
IsStrDec:
push hl
IsStrDec00:
ld a, (hl)
; Test for end of string
cp "\0"
jr z, IsStrDecTrue
; Fail if < "0"
cp "0"
jr c, IsStrDecFalse
; Continue if <= "9" (< "9"+1)
cp "9"+1
jr c, IsStrDecContinue
cp "9"
; Fall through to fail otherwise
IsStrDecFalse:
or 1 ; Reset zero flag
pop hl
ret
IsStrDecTrue:
cp a ; Set zero flag
pop hl
ret
IsStrDecContinue:
inc hl
jr IsStrDec00
IsStrHex:
push hl
IsStrHex00:
ld a, (hl)
; Test for end of string
cp "\0"
jr z, IsStrHexTrue
; Fail if < "0"
cp "0"
jr c, IsStrHexFalse
; Continue if <= "9" (< "9"+1)
cp "9"+1
jr c, IsStrHexContinue
; Fail if < "A"
cp "0"
jr c, IsStrHexFalse
; Continue if <= "F" (< "F"+1)
cp "F"+1
jr c, IsStrHexContinue
; Fall through to fail otherwise
IsStrHexFalse:
or 1 ; Reset zero flag
pop hl
ret
IsStrHexTrue:
cp a ; Set zero flag
pop hl
ret
IsStrHexContinue:
inc hl
jr IsStrHex00
StrTok:
push hl ; Push start address of string
StrTok00:
ld a, (hl)
cp " "
jr z, StrTok01
cp "\0"
jr z, StrTok02
inc hl
jr StrTok00
StrTok01:
ld (hl), "\0" ; Terminate string
StrTok02:
inc hl ; Advance HL to start of next string
; Put start address of next string in DE
ex de, hl
pop hl ; Pop original string start
ret
SkipWhitespace:
ld a, (hl)
cp ' '
ret nz
inc hl
jr SkipWhitespace
StrStrip:
ld a,(hl)
cp "\0"
jr z, StrStrip01
inc hl
jr StrStrip
StrStrip01:
dec hl
ld a,(hl)
cp " "
jr nz,StrStripEnd
ld (hl),"\0"
jr StrStrip01
StrStripEnd:
inc hl
ret
;;;;;;;;;;;;;;;;;;;;;;;;
Read8bit:
; HL is a pointer to a two-char string
; This is read as an 8 bit hex number
; The number is stored in A
ld a, (hl) ; Copy first char to A
call Hex12 ; Convert first char
add a, a ; Multiply by 16...
add a, a ; ...
add a, a ; ...
add a, a ; ...done!
ld d, a ; Store top 4 bits in D
inc hl ; Advance to next char
ld a, (hl)
call Hex12 ; Convert second char
or d ; Add back top bits
inc hl ; Advance for next guy
ret
Hex12: sub a, '0'
cp 10
ret c
sub a,'A'-'0'-10
ret
Read16bit:
; HL is a pointer to a four-char string
; This is read as a 16 bit hex number
; The number is stored in BC
call Read8bit
ld b, a
call Read8bit
ld c, a
ret
;;;;;;;;;;;;;;;;;;;;;;;;
ReadBCDByte:
; HL is a pointer to a two-char string
; This is read as a decimal number (assumed <=80)
; The number is stored in A in BCD format
ld a, (hl)
inc hl
sub "0"
sla a
sla a
sla a
sla a
ld b, a
ld a, (hl)
inc hl
sub "0"
or b
ret
;;;;;;;;;;;;;;;;;;;;;;;;
TerminateLine:
ld (hl), "\n"
inc hl
ld (hl), "\r"
inc hl
ld (hl), "\0"
ret
;;;;;;;;;;;;;;;;;;;;;;;;
StrfHex:
; Convert byte in A to two-char hex and append to HL
ld c, a ; a = number to convert
call Num1
ld (hl), a
inc hl
ld a, c
call Num2
ld (hl), a
inc hl
ret
Num1: rra
rra
rra
rra
Num2: or $F0
daa
add a, $A0
adc a, $40 ; Ascii hex at this point (0 to F)
ret
;;;;;;;;;;;;;;;;;;;;;;;;
; Binary to decimal stuff
; From https://www.msx.org/forum/development/msx-development/32-bit-long-ascii
; Combined routine for conversion of different sized binary numbers into
; directly printable ASCII(Z)-string
; Input value in registers, number size and -related to that- registers to fill
; is selected by calling the correct entry:
;
; entry inputregister(s) decimal value 0 to:
; B2D8 A 255 (3 digits)
; B2D16 HL 65535 5 "
; B2D24 E:HL 16777215 8 "
; B2D32 DE:HL 4294967295 10 "
; B2D48 BC:DE:HL 281474976710655 15 "
; B2D64 IX:BC:DE:HL 18446744073709551615 20 "
;
; The resulting string is placed into a small buffer attached to this routine,
; this buffer needs no initialization and can be modified as desired.
; The number is aligned to the right, and leading 0's are replaced with spaces.
; On exit HL points to the first digit, (B)C = number of decimals
; This way any re-alignment / postprocessing is made easy.
; Changes: AF,BC,DE,HL,IX
; P.S. some examples below
; by Alwin Henseler
B2D8: LD H,0
LD L,A
B2D16: LD E,0
B2D24: LD D,0
B2D32: LD BC,0
B2D48: LD IX,0 ; zero all non-used bits
B2D64: LD (B2DINV),HL
LD (B2DINV+2),DE
LD (B2DINV+4),BC
LD (B2DINV+6),IX ; place full 64-bit input value in buffer
LD HL,B2DBUF
LD DE,B2DBUF+1
LD (HL)," "
B2DFILC: EQU $-1 ; address of fill-character
LD BC,18
LDIR ; fill 1st 19 bytes of buffer with spaces
LD (B2DEND-1),BC ;set BCD value to "0" & place terminating 0
LD E,1 ; no. of bytes in BCD value
LD HL,B2DINV+8 ; (address MSB input)+1
LD BC,0x0909
XOR A
B2DSKP0: DEC B
JR Z,B2DSIZ ; all 0: continue with postprocessing
DEC HL
OR (HL) ; find first byte <>0
JR Z,B2DSKP0
B2DFND1: DEC C
RLA
JR NC,B2DFND1 ; determine no. of most significant 1-bit
RRA
LD D,A ; byte from binary input value
B2DLUS2: PUSH HL
PUSH BC
B2DLUS1: LD HL,B2DEND-1 ; address LSB of BCD value
LD B,E ; current length of BCD value in bytes
RL D ; highest bit from input value -> carry
B2DLUS0: LD A,(HL)
ADC A,A
DAA
LD (HL),A ; double 1 BCD byte from intermediate result
DEC HL
DJNZ B2DLUS0 ; and go on to double entire BCD value (+carry!)
JR NC,B2DNXT
INC E ; carry at MSB -> BCD value grew 1 byte larger
LD (HL),1 ; initialize new MSB of BCD value
B2DNXT: DEC C
JR NZ,B2DLUS1 ; repeat for remaining bits from 1 input byte
POP BC ; no. of remaining bytes in input value
LD C,8 ; reset bit-counter
POP HL ; pointer to byte from input value
DEC HL
LD D,(HL) ; get next group of 8 bits
DJNZ B2DLUS2 ; and repeat until last byte from input value
B2DSIZ: LD HL,B2DEND ; address of terminating 0
LD C,E ; size of BCD value in bytes
OR A
SBC HL,BC ; calculate address of MSB BCD
LD D,H
LD E,L
SBC HL,BC
EX DE,HL ; HL=address BCD value, DE=start of decimal value
LD B,C ; no. of bytes BCD
SLA C ; no. of bytes decimal (possibly 1 too high)
LD A,"0"
RLD ; shift bits 4-7 of (HL) into bit 0-3 of A
CP "0" ; (HL) was > 9h?
JR NZ,B2DEXPH ; if yes, start with recording high digit
DEC C ; correct number of decimals
INC DE ; correct start address
JR B2DEXPL ; continue with converting low digit
B2DEXP: RLD ; shift high digit (HL) into low digit of A
B2DEXPH: LD (DE),A ; record resulting ASCII-code
INC DE
B2DEXPL: RLD
LD (DE),A
INC DE
INC HL ; next BCD-byte
DJNZ B2DEXP ; and go on to convert each BCD-byte into 2 ASCII
SBC HL,BC ; return with HL pointing to 1st decimal
RET
AppendB2D:
; Append results of B2D to string at HL
ex de, hl ; Get destination into DE
ld hl, B2DBUF
call SkipWhitespace
ldir
ex de, hl ; Get destination into DE
ret