-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmonitor.z80
655 lines (613 loc) · 11.5 KB
/
monitor.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
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; MONITOR COMMAND LINE INTERFACE
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Monitor:
; Backup stack pointer
ld (mon_stack_backup), SP
ld sp, mon_stack+1
; Save all registers
push af
push bc
push de
push hl
ex af, af'
exx
push af
push bc
push de
push hl
ex af, af'
exx
push ix
push iy
MonitorStart:
ld hl, monwelcomestr
call PrintStringA
call Registers
call Stack
MonitorLoop:
; Infinite loop of read, parse, dispatch
ld hl, monpromptstr
call PrintStringA
ld hl, mon_linebuf
call ReadLineA
jr nz, MonitorLoop ; User stopped input using Ctrl-C
ld hl, mon_linebuf
ld a, (hl)
cp "\0"
jr z, MonitorLoop
call MonitorHandleLine
jr MonitorLoop
MonitorExit:
pop iy
pop ix
ex af, af'
exx
pop hl
pop de
pop bc
pop af
ex af, af'
exx
pop hl
pop de
pop bc
pop af
; Restore original stack pointer
ld SP, (mon_stack_backup)
ret
monwelcomestr:
defm "*** MONITOR\r\n\0"
monpromptstr:
defm "$ \0"
MonitorHandleLine:
ld bc, mon_argc
ld de, mon_dispatch_table
call HandleCommandLine
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; COMMAND DISPATCH
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command strings
cfloadstr: defm "CFLOAD\0"
cfsavestr: defm "CFSAVE\0"
continuestr: defm "CONTINUE\0"
bankstr: defm "BANK\0"
dumpstr: defm "DUMP\0"
instr: defm "IN\0"
helpstr: defm "HELP\0"
jumpstr: defm "JUMP\0"
memcpystr: defm "MEMCPY\0"
memedstr: defm "MEMED\0"
regstr: defm "REGISTERS\0"
stackstr: defm "STACK\0"
outstr: defm "OUT\0"
pushstr: defm "PUSH\0"
popstr: defm "POP\0"
nullstr: defm "\0"
; Table linking command strings to function entry points
mon_dispatch_table:
defw cfloadstr, CfLoad
defw cfsavestr, CfSave
defw continuestr, Continue
defw bankstr, Bank
defw dumpstr, Dump
defw instr, In
defw helpstr, Help
defw jumpstr, Jump
defw memcpystr, Memcpy
defw memedstr, Memed
defw outstr, Out
defw pushstr, Push
defw popstr, Pop
defw regstr, Registers
defw resetstr, Reset
defw stackstr, Stack
defw nullstr, What
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; MONITOR COMMANDS
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Bank:
ld a, (mon_argc)
cp 0
jr z, BankGet
cp 1
jr z, BankSet
;; Argc error
ld hl, bankstr
ld de, ExpectsExactlyOneArgStr
ld bc, BankArgsStr
jp Print3Strings
BankArgsStr:
defm "(mem bank).\r\n\0"
BankGet:
call GetMemBank
ld hl, message_buffer
call StrfHex
call TerminateLine
ld hl, message_buffer
call PrintStringA
ret
BankSet:
ld hl, (mon_argv)
call ValidateValue
ret nz
call Read8bit
call SetMemBank
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CfLoad:
; Check argument count
ld a, (mon_argc)
cp 3
jr z, CfLoad00
;; Argc error
ld hl, cfloadstr
ld de, ExpectsExactlyThreeArgsStr
ld bc, CfLoadArgStr
jp Print3Strings
CfLoad00:
; Validate address
ld hl, (mon_argv)
call ValidateAddress
ret nz
; Validate LBA
ld hl, (mon_argv+2)
call ValidateSector
ret nz
; Validate sector count
ld hl, (mon_argv+4)
call ValidateValue
ret nz
; Parse address
ld hl, (mon_argv)
call Read16bit
push bc
; Parse LBA
ld hl, (mon_argv+2)
call Read16bit
push bc
call Read16bit
push bc
; Parse sector count
ld hl, (mon_argv+4)
call Read8bit
; Put everything in appropriate registers
pop bc
pop de
pop hl
; Do it
call CF_READ
ret
ExpectsExactlyThreeArgsStr:
defm " expects exactly three args \r\n\0"
CfLoadArgStr:
defm "(mem address, start sector, sector count)\r\n\0"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CfSave:
; Check argument count
ld a, (mon_argc)
cp 3
jr z, CfSave00
;; Argc error
ld hl, cfsavestr
ld de, ExpectsExactlyThreeArgsStr
ld bc, CfSaveArgStr
jp Print3Strings
CfSave00:
; Validate sector
ld hl, (mon_argv)
call ValidateSector
ret nz
; Validate address
ld hl, (mon_argv+2)
call ValidateAddress
ret nz
; Validate value
ld hl, (mon_argv+4)
call ValidateValue
ret nz
; Parse LBA
ld hl, (mon_argv)
call Read16bit
push bc
call Read16bit
push bc
; Parse mem address
ld hl, (mon_argv+2)
call Read16bit
push bc
; Parse sector count
ld hl, (mon_argv+4)
call Read8bit
; Put everything in appropriate registers
pop hl
pop bc
pop de
; Do it
call CF_WRITE
ret
CfSaveArgStr:
defm "(start sector, mem address, sector count)\r\n\0"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Continue:
; Pop the return address which leads back to the monitor loop
pop hl ; Break out of Dispatch
pop hl ; Break out of HandleCommandLine
pop hl ; Break out of MonitorHandleLine
; Break out of monitor loop
jp MonitorExit
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Dump:
; Check argument count
ld a, (mon_argc)
cp 1
jr z, Dump00
;; Argc error
ld hl, dumpstr
OneMemAddressArgcError:
ld de, ExpectsExactlyOneArgStr
ld bc, AddressStr
jp Print3Strings
Dump00:
ld hl, (mon_argv)
call ValidateAddress
jr z, Dump01
ret
Dump01:
call Read16bit ; Read address into BC
ld d, b
ld e, c
DumpPreOuter:
ld b, 16 ; We dump 16 rows
DumpOuter:
push bc ; Store row counter
ld hl, mon_linebuf
ld b, 16 ; We dump 16 columns
push de ; Store mem pointer at start of row
DumpInner:
; Print address
ld a, d
call StrfHex
ld a, e
call StrfHex
ld (hl), "\t"
inc hl
; Print out hex version of data
DumpInner2:
ld a, (de) ; Read from DE to A
inc de
call StrfHex
ld (hl), " "
inc hl
djnz DumpInner2
;; Print Separator between hex and ASCII
ld (hl), "\t"
inc hl
;; Now rewind our memory pointer to do the ascii bit
pop de
; Print out ascii version of data
ld b, 16 ; We dump 16 columns
DumpInner3:
ld a, (de) ; Read from DE to A
inc de
cp 32
jr z, HandlePrintable
jr c, HandleNonprintable
cp 127
jr z, HandlePrintable
jr c, HandlePrintable
HandleNonprintable:
ld a, "." ; Clobber unprintable char with dot
HandlePrintable:
ld (hl), a
; Continue loop
inc hl
djnz DumpInner3
;; Now termiate this line
call TerminateLine
ld hl, mon_linebuf
call PrintStringA
pop bc ; Retrieve row counter
djnz DumpOuter
;; Ask to continue
Dump04:
ld hl, DumpContinueStr
call PrintStringA
call SERIAL_READ_A
push af
call ClearLeft
pop af
cp " "
jr z, DumpPreOuter ; Continue
cp 0x03
ret z ; End
jr Dump04 ; Ask again
DumpContinueStr:
defm "(press SPACE to continue, Ctrl-C to end)\0"
ClearLeft:
ld hl, ClearLeftCode
call PrintStringA
ret
ClearLeftCode:
defm 0x1B, 0x5b
defm "1K\r\0"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
In:
ld a, (mon_argc)
cp 1
jr z, In00
;; Argc error
ld hl, instr
ld de, ExpectsExactlyOneArgStr
ld bc, InArgsStr
jp Print3Strings
InArgsStr:
defm "(port)\r\n\0"
In00:
ld hl, (mon_argv)
call Read8bit
ld c, a
in a, (c)
ld hl, mon_linebuf ; Point to start of output
call StrfHex ; Write hex string
call TerminateLine ; Add \n\r\0
ld hl, mon_linebuf ; Print output
call PrintStringA
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Help:
ld hl, helpmessage
call PrintStringA
ret
helpmessage: defm "Monitor commands:\n\r"
defm "BANK PG Bank switch top 32KB\n\r"
defm "CFLOAD ADDR SECT NSECS: Read sectors from CF\n\r"
defm "CFSAVE SECT ADDR NSECS: Write sectors to CF\n\r"
defm "CONTINUE: Resume program execution\n\r"
defm "DUMP ADDR: Hexdump 256 bytes of memory\n\r"
defm "IN PORT: Read byte from I/O port\n\r"
defm "JUMP ADDR: Jump to address\n\r"
defm "MEMCPY DEST SRC NBYTES: Copy memory\n\r"
defm "MEMED ADDR: Edit memory\n\r"
defm "OUT PORT VAL: Write byte to I/O port\n\r"
defm "POP: Pop from stack\n\r"
defm "PUSH VAL: Push to stack\n\r"
defm "REGISTERS: Register dump\n\r"
defm "STACK: Stack trace\n\r"
defm "\0"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Jump:
ld a, (mon_argc)
cp 1
jr z, Jump00
;; Argc error
ld hl, jumpstr
jp OneMemAddressArgcError
Jump00:
ld hl, (mon_argv)
call ValidateAddress
jr z, Jump01
ret
Jump01:
call Read16bit
ld h, b
ld l, c
jp (hl)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Memcpy:
ld a, (mon_argc)
cp 3
jr z, Memcpy00
;; Argc error
ld hl, memcpystr
ld de, ExpectsExactlyThreeArgsStr
ld bc, MemcpyArgStr
jp Print3Strings
MemcpyArgStr:
defm "(dest address, src address, 4 digit byte count).\r\n\0"
Memcpy00:
; Validate, parse and push destination
ld hl, (mon_argv)
call ValidateAddress
ret nz
call Read16bit
push bc
; Validate, parse and push source
ld hl, (mon_argv+2)
call ValidateAddress
jr z, Memcpy01
pop bc
ret
Memcpy01:
call Read16bit
push bc
; Validate, parse and push count
ld hl, (mon_argv+4)
call ValidateAddress
jr z, Memcpy02
pop bc
pop bc
ret
Memcpy02:
call Read16bit
pop hl
pop de
ldir
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Memed:
ld a, (mon_argc)
cp 1
jr z, Memed00
;; Argc error
ld hl, memedstr
jp OneMemAddressArgcError
ret
Memed00:
; Validate, parse and push destination
ld hl, (mon_argv)
call ValidateAddress
ret nz
call Read16bit
ld d, b
ld e, c
Memed01:
ld hl, mon_linebuf
ld a, d
call StrfHex
ld a, e
call StrfHex
ld (hl), "\t"
inc hl
ld a, (de)
call StrfHex
ld (hl), " "
inc hl
ld (hl), "\0"
ld hl, mon_linebuf
call PrintStringA
call ReadLineA
ret nz ; User hit Ctrl-C
ld a, (hl)
cp "\0"
jr z, Memed02
call ConvertToUpper
call ValidateValue
jr nz, Memed01
push de
call Read8bit
pop de
ld (de), a
Memed02:
inc de
jr Memed01
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Registers:
ld hl, reg_labels
call PrintStringA
ld de, mon_stack
ld b, 8
call RegisterPrint
ld hl, alt_reg_labels
call PrintStringA
ld b, 8
call RegisterPrint
ld hl, i_reg_labels
call PrintStringA
ld b, 4
call RegisterPrint
ret
RegisterPrint:
ld hl, mon_linebuf
RegisterPrintLoop:
ld a, (de)
dec de
call StrfHex
ld (hl), " "
inc hl
djnz RegisterPrintLoop
call TerminateLine
ld hl, mon_linebuf
call PrintStringA
ret
reg_labels:
defm "A F B C D E H L\r\n\0"
alt_reg_labels:
defm "A' F' B' C' D' E' H' L'\r\n\0"
i_reg_labels:
defm "IX IY\r\n\0"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Out:
ld a, (mon_argc)
cp 2
jr z, OutValidate
;; Argc error
ld hl, outstr
ld de, ExpectsExactlyTwoArgsStr
ld bc, OutArgsStr
jp Print3Strings
OutArgsStr:
defm "(port, value).\r\n\0"
OutValidate:
ld hl, (mon_argv)
call ValidateValue
ret nz
ld hl, (mon_argv+2)
call ValidateValue
ret nz
ld hl, (mon_argv)
call Read8bit
ld c, a
push bc
ld hl, (mon_argv+2)
call Read8bit
pop bc
out (c), a
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Stack:
ld de, (mon_stack_backup)
ld b, 8
StackLoop:
push bc
ld hl, mon_linebuf
inc de
ld a, d
call StrfHex
ld a, e
call StrfHex
ld (hl), "\t"
inc hl
ld a, (de)
call StrfHex
dec de
ld a, (de)
inc de
inc de
call StrfHex
call TerminateLine
ld hl, mon_linebuf
call PrintStringA
pop bc
djnz StackLoop
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
What:
ld hl, whatstr
call PrintStringA
ret
whatstr: defm "What?\n\r\0"
Push:
ld a, (mon_argc)
cp 1
jr z, Push00
;; Argc error
ld hl, pushstr
jp OneMemAddressArgcError
Push00:
ld hl, (mon_argv)
call ValidateAddress
ret nz
call Read16bit ; Value to push in BC
ld hl, (mon_stack_backup) ; Get app stack in HL
ld (mon_stack_backup), sp ; Put mon stack in mem
ld sp, hl ; Activate app stack
push bc ; Push
jr PopRestoreStacks
Pop:
ld hl, (mon_stack_backup) ; Get app stack in HL
ld (mon_stack_backup), sp ; Put mon stack in mem
ld sp, hl ; Activate app stack
pop de ; Pop
PopRestoreStacks:
ld hl, (mon_stack_backup) ; Get mon stack back in HL
ld (mon_stack_backup), sp ; Put new app stack in mem
ld sp, hl ; Reactivate mon stack
ret