-
Notifications
You must be signed in to change notification settings - Fork 1
/
monitor.asm
521 lines (450 loc) · 12.9 KB
/
monitor.asm
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
;
;-------------------------------------------------------------------------------
; Writen for zasm assembler:
; https://k1.spdns.de/Develop/Projects/zasm/Distributions/
#target rom
; Constants
CPU_FREQ equ 8000000 ; 8MHz (4000000 = 4MHz)
; OLDROM: 0x80 Map 1st page of ram to high 32kB, ROM bank 0 to low
; NEWROM: 0xA0 Bank 2 to high 32kB, ROM Bank 0 to low
; OLD: 0x8B Map 1st page of ram to high 32kB, RAM Bank 3 to low (ROM emulation loader)
; 0xAB RAM Bank 2 to high 32kB, RAM Bank 3 to low (ROM emulation loader)
; (RAM BANK 0 and RAM BANK 1 for use of program
MONITOR_BANK equ 0xAB ; NEWROM + emu loader
COLS equ 40 ; Number of columns
#if COLS == 80
DISP_MODE equ 0x03 ; 03h 80 column bold, 02h 40 column bold
#else
DISP_MODE equ 0x02
#endif
; Delay constant for DELAY_MS
; Delay calculation:
; 35 + 65*(B-1) + 60 + 20 cycles
; B = (CYCLES - 115)/65 + 1
; 4000 cycles @4MHz, B = 60.7 + 1 = 62
; 8000 cycles @8MHz, B = 121.3 + 1 = 122
; 16000 cycles @16Mhz, B= 244.4 + 1 = 245
MSDELAY equ 1+ (((CPU_FREQ / 1000) - 115) / 65)
#data _RAM,0xF800,0x800 ; Limit to top 2kB of RAM
; Space for bank copying routines in memory
RAM_BANKCOPY DS BANKCOPYLEN
RAM_BANKPEEK DS BANKPEEKLEN
RAM_BANKPOKE DS BANKPOKELEN
MON_FS DS FSLEN ; FS stuct for monitor use
LBUFLEN equ 80
LBUF: DS LBUFLEN+1 ; Line buffer (space for null)
CURADDR: DS 2 ; Current address
; Program settable mode flags
MODEBASE:
DISPDEV DS 1 ; Current display device
DISPMODE DS 1 ; Display line mode
INDEV: DS 1 ; Current input device
MODELEN equ . - MODEBASE ; Number of mode flags
HDROWL DS 1 ; Row length for hexdump
#include "macros.asm" ; Assembler macros
#code _ROM,0x0000,0x8000
;===============================================================================
;===============================================================================
; Reset Vectors
RESET:
LD A, MONITOR_BANK ; Monitor bank setup
OUT (PORT_BANK), A ; Bank switch
JP START
; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
; This code must be preset in every bank that is to be loaded in the low slot
ORG 0x08 ; RST $08 -- BIOS call
LD A, MONITOR_BANK ; Load monitor bank setup
OUT (PORT_BANK), A ; Bank switch
; We're now in the monitor ROM
JP BIOS
BIOSRET:
LD A, (CURBANK) ; DON't CALL RST $10, it's the first byte of address CURBANK
OUT (PORT_BANK), A
RET
BIOSSTART:
LD A, (CURBANK) ; DON't CALL RST $18
OUT (PORT_BANK), A
JP 0x0100
; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ORG 0x20 ; RST $20
JP START
ORG 0x28 ; RST $28
JP START
ORG 0x30 ; RST $30
JP START
ORG 0x38 ; RST $38 / Int vector
JP INT
ORG 0x66 ; NMI vector
JP NMI
ORG 0x80 ; Entry point
;===============================================================================
;===============================================================================
; Program Entry Point
START:
#local
; First thing we need to do is set up the bank switch register to map
; some RAM. By default we have the low 32kB of ROM in both 32kB banks.
LD A, MONITOR_BANK
OUT (PORT_BANK), A
LD SP, 0x0000 ; Set stack to top of RAM
; Init 8255
LD A, 0xC1 ; Mode 2 on Port A (and ctrl on port C), C (low) input
; Port B mode 0 output
OUT (PIO_CTRL), A
LD A, 0
OUT (PIO_B),A ; Clear port B
;CALL LCDINIT
;LD HL, STR_LCDBANNER
;CALL LCDPUTS
CALL DELAY_MS
CALL SERIAL_INIT
LD A, 0
CALL SERIAL_WRITE ; Write a null to clear out the buffer
CALL DISP_INIT
; Setup mode flags
LD B, MODELEN
LD HL, MODEVALS
LD IX, MODEBASE
MODELOOP:
LD A, (HL)
LD (IX), A
INC HL
INC IX
DJNZ MODELOOP
CALL UPDATE_HDROWL
DOBANNER:
LD A, 0x81 ; 80 col graphics for banner
CALL DISP_LMODE
LD B, 80*3 ; 3 lines of graphic data
LD HL, STR_GRAPHIC_BANNER
GRAPHBNR:
LD A,(HL)
CALL DISP_WRITE_ESC
INC HL
DJNZ GRAPHBNR
LD A, (DISPMODE)
CALL DISP_LMODE
LD HL, STR_BANNER
CALL PRINT
; Copy bank code into memory
LD HL, BANKCOPY
LD DE, RAM_BANKCOPY
LD BC, BANKCOPYLEN+BANKPEEKLEN+BANKPOKELEN
LDIR
CALL CF_DETECT
JR NZ, DRVPRES
LD HL, STR_NODRIVE
CALL PRINTN
JR CMD_LOOP
DRVPRES:
CALL CF_INIT
LD HL, STR_DRIVE
CALL PRINTN
CALL FAT_INIT
WARM::
LD SP, 0x0000 ; Reset stack on warm restart
CALL PRINTNL
; Reset display
LD A, (DISPMODE)
CALL DISP_LMODE ; Make sure our mode is correct
LD A, 02h ; Set cursor
CALL DISP_WRITE
LD A, '_' ; Underscore cursor
CALL DISP_WRITE
CALL UPDATE_HDROWL
CMD_LOOP:
CALL DISP_PROMPT ; Display prompt + cur addr
CALL GET_LINE ; Read in user input
CALL PARSE_LINE ; Parse line and do actions
JR CMD_LOOP
HALT:
LD A, 0x80
OUT (PORT_LCD), A
JP HALT
#endlocal
;-----------------------------------------------------------------------
UPDATE_HDROWL:
#local
LD A, (DISPMODE)
AND 1
JR Z, COL80
LD A, 16
LD (HDROWL), A ; 16 bytes in a hex dump if 80 col
RET
COL80:
LD A, 8
LD (HDROWL), A ; 8 bytes for 40 col
RET
#endlocal
;-----------------------------------------------------------------------
; Get a line of user input into LBUF
;-----------------------------------------------------------------------
GET_LINE:
#local
LD HL, LBUF
LD B, LBUFLEN
CLR:
LD (HL), 0
INC HL
DJNZ CLR
LD HL, LBUF
LD C, LBUFLEN
LINEL:
CALL KBD_GETKEY ; Get a character
CALL TO_UPPER ; Uppercase only
LD B, A ; Save charaacter
CP $08 ; BKSP
JR NZ, NOBKSP
BKSP:
LD A, LBUFLEN
CP C
JR Z, IGNORE ; Don't backspace if at beginning of line
DEC HL
INC C
LD A, B ; Restore character (BKSP)
CALL PRINTCH
LD A, ' '
CALL PRINTCH ; Space
LD A, $08 ; BKSP again
JR NOSTORE
NOBKSP:
CP $0A ; NEWLINE
JR Z, DONE
XOR A ; Clear A
CP C ; Check if we have space to store
JR Z, IGNORE ; Ignore character if so
LD A, B ; Restore character
LD (HL), A ; Store into buffer
INC HL
DEC C
NOSTORE:
CALL PRINTCH ; Echo character back
IGNORE:
JR LINEL
DONE: LD A, $0D ; CR
CALL PRINTCH
LD A, $0A ; NL
CALL PRINTCH
LD (HL), 0 ; Add trailing null terminator
RET
#endlocal
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; Parse line and handle commands
;-----------------------------------------------------------------------
PARSE_LINE:
#local
LD HL, LBUF
CALL SKIPWHITE ; Skip leading whitespace to be nice
LD IX, CMDSTBL
LOOP:
PUSH HL ; Save start of user str
LD A, (IX) ; Check if at end of table
AND A
JR Z, NOMATCH ; End of table, no match found
CMP:
LD A, (IX)
AND A
JR Z, MATCH ; End of string in table, matched
CP (HL)
INC IX \ INC HL
JR Z, CMP ; While we match continue comparing
; String doesn't match, advance to next entry
ADVLOOP:
LD A, (IX)
INC IX
AND A
JR NZ, ADVLOOP ; Advance to null terminator
INC IX \ INC IX ; Skip over address
POP HL ; Restore start of user string
JR LOOP ; Keep looping
MATCH: ; Commands matched and we're on the null terminator of the cmd
NOMATCH:; And the user string is pointing just after the matched string
POP BC ; Trash saved HL
DEC HL ; We're pointed one too far
INC IX ; Pointing at address of command
LD BC, (IX) ; Command to run
PUSH BC ; Push into return address
RET ; Jump into table, index into string in HL
#endlocal
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; Display the prompt
; '$ABCD> '
DISP_PROMPT:
LD A, '$'
CALL PRINTCH
LD BC, (CURADDR)
CALL PRINTWORD ; Print current address
LD HL, STR_PROMPTEND
JP PRINT ; Tail call
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; BANK COPYING ROUTINES
;-----------------------------------------------------------------------
; DO NOT DIRECTLY USE, USE RAM_BANKCOPY
; Copy data from monitor bank to other bank
;
; A - target bank (Only LOW 4 bits matter)
; BC - # of bytes to copy (Must be < (32kB - DE)
; HL - This addr (should be in high bank)
; DE - Destination addr (assuming destination is in low bank)
;;
;
; If HL is in low bank, and DE is in high bank, then this should
; work as a copy from banked memory to kernel memory
BANKCOPY:
.phase RAM_BANKCOPY
AND $0F ; Make sure bank doesn't contain data for upper
OR $A0 ; Make sure upper contains our MONITOR RAM address
OUT (PORT_BANK), A ; Bank Switch!
; Now perform the copy
LDIR
LD A, MONITOR_BANK ; Swap back to monitor configuration
OUT (PORT_BANK), A ; Bank switch!
RET
BANKCOPYLEN equ .-RAM_BANKCOPY
.dephase
;---------------------------------------
; DO NOT DIRECTLY USE, USE RAM_BANKPEEK
; Read a byte at an address in the specified bank
; B - target bank (Both bits matter, if HL >= 0x8000 then we'll use the upper bits)
; HL - target address
; Byte in C
BANKPEEK:
#local
.phase RAM_BANKPEEK
LD A, H ; Check high byte of address
AND $80 ; Check if we want the upper bank
JR Z, LOWER ; High bit not set, use lower bank
; Addr is in the upper bank
LD A, H
AND $7F ; Change address to lower
LD H, A
LD A, B
RRA
RRA
RRA
RRA ; Move desired bank to low 4 bits
LD B, A
LOWER:
LD A, B
AND $0F
OR $A0 ; Or with Monitor RAM bank (we're here!)
OUT (PORT_BANK), A ; Bank Switch!
LD A, (HL) ; Read byte
LD C, A ; Save in C
LD A, MONITOR_BANK ; Swap back to Monitors bank setup
OUT (PORT_BANK), A ; Bank Switch!
RET
#endlocal
BANKPEEKLEN equ .-RAM_BANKPEEK
.dephase
;---------------------------------------
; DO NOT DIRECTLY USE, USE RAM_BANKPOKE
; Write a byte at an address in the specified bank
; B - target bank (Both bits matter, if HL >= 0x8000 then we'll use the upper bits)
; HL - target address
; C - byte to write
BANKPOKE:
#local
.phase RAM_BANKPOKE
PUSH HL
LD A, H
AND $80 ; Check if we want the upper bank
JR Z, LOWER
; Addr is in the upper bank
LD A, H
AND $7F ; Change address to lower
LD H, A
LD A, B
RRA
RRA
RRA
RRA ; Move desired bank to low 4 bits
LD B, A
LOWER:
LD A, B
AND $0F
OR $A0 ; Or with Monitor RAM bank (we're here!)
OUT (PORT_BANK), A ; Bank Switch!
LD (HL), C ; Write byte to memory
LD A, MONITOR_BANK ; Swap back to Monitors bank setup
OUT (PORT_BANK), A ; Bank Switch!
POP HL
RET
#endlocal
BANKPOKELEN equ .-RAM_BANKPOKE
.dephase
;-----------------------------------------------------------------------
#include "lcd.asm" ; LCD Routines
#include "delay.asm" ; Delay/sleep routines
#include "cf.asm" ; CF card routines
#include "serial.asm" ; Serial routines
#include "kbd.asm" ; Keyboard routines
#include "int.asm" ; Interrupt routines
#include "parse.asm" ; String parsing routines
#include "print.asm" ; Console printing routines
#include "disass.asm" ; Dissassembler
#include "fatv3.asm" ; FAT filesystem and user filesystem commands
#include "util.asm" ; Utility functions
#include "math.asm" ; Math helper routines
#include "display.asm" ; AVR NTSC display routines
#include "bios.asm" ; BIOS call routines for userspace
#include "teensy.asm" ; Commands to talk with the Teensy peripheral
#include "commands.asm" ; Monitor interactive commands
#include "ioports.asm" ; Port numbers of system devices
;===============================================================================
; Static Data
;===============================================================================
STR_LCDBANNER:
.ascii "Chartreuse Z80 Booted",0
STR_BANNER:
.ascii "Chartreuse Z80 Monitor v0.3.4",10,13
.ascii "========================================",10,13,0
STR_NL:
.ascii 10,13,0
STR_PROMPTEND:
.ascii '> ',0
STR_COLONSEP:
.ascii ': ',0
STR_NODRIVE:
.ascii "No IDE drive detected",0
STR_DRIVE:
.ascii "IDE drive detected",0
STR_VOLLBL:
.ascii "Volume Label: ",0
STR_VOLID:
.ascii "Volume ID: ",0
STR_NOFILE:
.ascii "No such file",0
STR_NOPROG:
.ascii "No such program",0
STR_PREJUMP:
.ascii "Long Jumping to program.",0
STR_HOSTFAIL:
.ascii "Host failure while loading",0
STR_CHKFAIL:
.ascii "Checksum failure",0
; 3 lines of 80 columns (240b) of graphics mode data
STR_GRAPHIC_BANNER:
DB $00,$00,$00,$00,$00,$00,$00,$00,$fa,$e4,$40,$00,$00,$00,$00,$00
DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
DB $80,$10,$e0,$84,$78,$04,$e0,$fe,$ff,$55,$00,$00,$a0,$0c,$10,$54
DB $a8,$a0,$0c,$50,$58,$a4,$08,$5c,$a0,$0c,$50,$58,$0c,$a8,$00,$54
DB $58,$0c,$a0,$0c,$04,$00,$08,$8c,$14,$98,$64,$a0,$0c,$50,$22,$66
DB $66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
DB $02,$2d,$9b,$f6,$e4,$be,$ff,$c7,$40,$2b,$d0,$00,$0a,$30,$04,$17
DB $2b,$2a,$03,$15,$17,$25,$00,$15,$2a,$0b,$10,$27,$31,$0a,$30,$05
DB $32,$19,$0a,$33,$10,$00,$28,$31,$10,$25,$1a,$0a,$30,$05,$22,$26
DB $26,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
MODEVALS:
DB 0 ; Display device
DB DISP_MODE ; Display mode
DB 0 ; Input device
MONITOR_SIZE equ . ; Monitor starts at 0