One of the more irritating features of working with Microbee stuff is that much of the software is copyright, so I can't distribute it with Freebee unless I get the permission of the copyright holder.
Even worse, much of the recently developed software has been built on disassembled versions of copyright software, so also can't be distributed.
The solution to this is to just go back to first principles and write stuff from scratch. In principle it should be possible to write a CP/M boot ROM and a basic ROM that's compatible but doesn't share the code, in much the same way as with PC clone BIOS ROMs.
This is a big job, but like eating an elephant the trick is to do it one bite at a time and just write code that can be useful. I'm not a programmer, so this is also a learning experience for me.
So let's start with my boot ROM, which until recently just loaded fonts and then dropped into (proprietary) basic. A monitor is a super useful tool in ot's own right for debugging, but as well as that it needs routines for keyboard input, screen output, tape IO, serial IO, etc., which can potentially be repurposed for more ambitious works.
After a week or so of work I have a couple of cool things happening. Firstly a splash screen and boot menu:
And secondly the beginnings of my monitor.
A little more work has a routine that when given an address, displays 32 bytes before and 224 bytes after the address, for a total of 256 bytes. You can move around the memory using the up (back 16 bytes), down (forward 16 bytes), left (back one byte) and right (forward one byte) keys. You can also enter an address using E XXXX where the address is a 4 digit hex number, and the display jumps to that.
I need to generalise input, as the whole checking every keystroke thing is getting bloody tedious. I think a routine to allow entry of a line of text, terminated with a CR character would be just what the doctor ordered. Then I need to parse the text input to determine what to do, and figure out what commands I want the monitor to recognise.
I also need to keep track of what memory is banked in where. There's plenty of space in the bottom right of the screen where I could display current PCG bank, status of boot bit, status or ROMRD bit, status of colouren bit... Then of course I need commands to actually change these, plus (in the case of the boot bit) a way to survive that, as the ROM that's being used for the monitor gets paged out of existance when I deassert boot. Perhaps I could LDIR a short routine to video RAM to do the bank swap, pull the data needed from RAM, and swap back.
Also using PCG bank zero for my scratch and stack isn't so great. Perhaps I could move these to PCG bank 15.
This is seriously good fun though. I'm learning so much about Z80 assembler doing this.
And, totally experimental, here's a copy and paste of my source code. Wonder if this works:
; ========================================================================
; FreeBee Boot Rom
; Version 0.1 17 November 2024
; ========================================================================
; Copyleft 2024 S.Jackson. All wrongs reserved
; ========================================================================
; Hardware Constants - memory organisation
vdu: equ 0f000h ; Start of video memory
screen: equ vdu ; Screen RAM
pcg: equ vdu + 0800h ; PCG RAM
colour: equ pcg ; Colour RAM
charram: equ vdu ; Character RAM
; Boot / Character RAM enable port - used for memory paging
bootromport: equ 0bh ; Bit 7 set boot ROM at 0000h
; Bit 7 reset RAM at 0000h
charramport: equ bootromport ; Bit 0 set char RAM at F000h
; and keyboard enable
; Bit 0 reset screen RAM at f000h
; Premium graphics port - used for Premium enable and PCG page.
premiumport: equ 1ch ; Premium LV register
; Colour enable port
colourport: equ 08h ; Bit 6 set colour RAM at F800h
; Bit 6 reset PCG RAM at F800h
; Boot / Character RAM enable bit definitions
bootbit: equ 1 << 7 ; bit 7
charrambit: equ 1 << 0 ; bit 0
colourbit: equ 1 << 6 ; bit 6
; Speed select port. Reading from the port with A = 02h enables fast speed
speedport: equ 09h
speedbit: equ 1 << 1 ; bit 1
; Foreground colours
red: equ 01h
green: equ 02h
yellow: equ 03h
blue: equ 04h
pink: equ 05h
cyan: equ 06h
white: equ 07h
; 6545 CRT Controller ports
crtc: equ 0ch
crtcaddr: equ crtc
crtcstatus: equ crtc
crtcdata: equ crtc + 1
; 6545 register definitions
hortotal: equ 0 ; Horizontal total - 1
hordisplay: equ 1 ; Horizontal displayed
horsync: equ 2 ; Horizontal sync position
syncwidth: equ 3 ; Sync widths
vertotal: equ 4 ; Vertical total -1
vertotal_adj: equ 5 ; Vertical total adjust
verdisplay: equ 6 ; Vertical displayed
versync: equ 7 ; Vertical sync position
crtcmode: equ 8 ; Mode control
scanlines: equ 9 ; Scan lines per character
cursstart: equ 10 ; Cursor start & cursor mode
cursend: equ 11 ; Cursor end
dispstarthigh: equ 12 ; Display start address high
dispstartlow: equ 13 ; Display start address low
cursposhigh: equ 14 ; Cursor position high
cursposlow: equ 15 ; Cursor position low
lpenhigh: equ 16 ; Light pen high
lpenlow: equ 17 ; Light pen low
updatehigh: equ 18 ; Update address high
updatelow: equ 19 ; Update address low
dummy: equ 31 ; Dummy location
; CRTC status bit definitions
crtcretrace: equ 5 ; Bit 5 set display in retrace
crtclpenfull: equ 6 ; Bit 6 set key pressed
crtcupdaterdy: equ 7 ; Bit 7
; ASCII constants
space: equ 020h
; 16 bytes of scratch RAM - note this will live in the top of PCG memory
scratch: equ 0fff0h
; Stack - stack lives in the top of PCG memory under scratch. It's
; really important that we don't try to do stack operations
; while colour RAM is paged in - as this pages out the stack!
stack: equ 0ffefh
;#########################################################################
org 0 ; Start at reset vector
RST_VECTOR:
; Jump to start of code
jp cold_boot
defs 066h-$, 0ffh
NMI_VECTOR:
; Jump to start of code. DRAM coreboards assert NMI for reboot
; so this accounts for that.
jp cold_boot
defs 0100h-$, 0ffh
cold_boot: di ; Disable interrupts
ld sp, stack ; Initialise stack pointer
xor a
out (premiumport), a ; Initialise Premium LV latch
ld a, bootbit | charrambit
out (charramport), a ; Enable char RAM at 0f000h
ld a, dispstarthigh
out (crtcaddr), a
ld a, 20h
out (crtcdata), a ; Enable small char RAM
ld hl, char5x7
ld de, charram
ld bc, 0800h
ldir ; Copy small font to char RAM
ld a, dispstarthigh
out (crtcaddr), a
xor a
out (crtcdata), a ; Enable large char RAM
ld hl, char7x12
ld de, charram
ld bc, 0800h
ldir ; Copy large font to char RAM
ld a,bootbit
out (charramport),a ; Enable screen RAM at 0f000h
ld c, green
call clrscr ; Clear Screen
ld hl, crtc80x24 + 15 ; Initialise CRTC for 80 x 24
call initcrtc
ld hl, freebeepcg
ld de, pcg
ld bc, freebeepcgend - freebeepcg
ldir ; Load freebee logo into PCG
ld hl, freebeeline1
ld de, screen + 80 * 8 + 30
ld c, red
call printtext ; Display freebee logo line 1
ld hl, freebeeline2
ld de, screen + 80 * 9 + 30
ld c, red
call printtext ; Display freebee logo line 2
ld hl, freebeeline3
ld de, screen + 80 * 10 + 30
ld c, red
call printtext ; Display freebee logo line 3
ld hl, text1
ld de, screen + 80 * 23 + 0
ld c, green
call printtext ; Display "Open Source" etc.
ld c, green
colourloop: xor a
out (colourport), a ; enable PCG RAM at 0f800h
ld b, 25 ; wait for 500msec
longdelay: call vsyncwait
djnz longdelay
ld a, colourbit
out (colourport), a ; enable colour RAM at 0f800h
ld ix, colour + 80 * 9 + 30
ld b, 20
colourloop1: ld (ix - 80), c
ld (ix + 0), c
ld (ix + 80), c
inc ix
djnz colourloop1
inc c
ld a, c
cp 8
jr nz, colourloop
xor a
out (colourport), a ; enable PCG RAM at 0f800h
ld hl, menu1
ld de, screen + 80 * 14 + 20
ld c, yellow
call printtext ; Display menu line 1
ld hl, menu2
ld de, screen + 80 * 15 + 20
ld c, yellow
call printtext ; Display menu line 2
goslow: xor a
spdcall: call speed
doagain: ld b, 250 ; check keyboard for 5 seconds
longdelay2: call checkkey
jr nz, keypressed
call vsyncwait
next: djnz longdelay2
leave: ld c, green
call clrscr
jp exitboot
keypressed: cp 002h ; 'B' key - boot
jr z, leave
cp 006h ; 'F' key - fast
jr z, gofast
cp 013h ; 'S' key - slow
jr z, goslow
cp 00dh ; 'M' key - monitor
jr z, moncall
jr next
gofast: ld a, 1
jr spdcall
moncall: call monitor
ld hl, freebeepcg
ld de, pcg
ld bc, freebeepcgend - freebeepcg
ldir ; Load freebee logo into PCG
ld hl, freebeeline1
ld de, screen + 80 * 8 + 30
ld c, white
call printtext ; Display freebee logo line 1
ld hl, freebeeline2
ld de, screen + 80 * 9 + 30
ld c, white
call printtext ; Display freebee logo line 2
ld hl, freebeeline3
ld de, screen + 80 * 10 + 30
ld c, white
call printtext ; Display freebee logo line 3
ld hl, text1
ld de, screen + 80 * 23 + 0
ld c, green
call printtext ; Display "Open Source" etc.
ld c, green
ld hl, menu1
ld de, screen + 80 * 14 + 20
ld c, yellow
call printtext ; Display menu line 1
ld hl, menu2
ld de, screen + 80 * 15 + 20
ld c, yellow
call printtext ; Display menu line 2
jr doagain
;#########################################################################
; Print text - Prints a text string
; On entry HL points to the start of the null terminated text string
; DE points to the screen insertion point
; C contains the colour for the string
; Destroys A,F
;#########################################################################
printtext: push hl
push de
push hl
push de
ld a, d ; add 0800h to de to point
add 08h ; into colour RAM
ld d, a
ld a, colourbit
out (colourport), a ; enable colour RAM at 0f800h
.printloop1: ld a, (hl)
cp 0
jr z, .printdone1
ld a, c
ld (de), a
inc hl
inc de
jr .printloop1
.printdone1: xor a
out (colourport), a ; enable PCG RAM at 0f800h
pop de
pop hl
.printloop2: ld a, (hl)
cp 0
jr z, .printdone2
ld (de), a
inc hl
inc de
jr .printloop2
.printdone2: pop de
pop hl
ret
;#########################################################################
; Init CRTC - Initialises the CRT Controller
; On entry HL points to last entry of initialisation table
; Destroys A,F
;#########################################################################
initcrtc: push bc
ld b, 16
.loop: ld a, b
dec a
out (crtcaddr), a
ld a, (hl)
out (crtcdata), a
dec hl
djnz .loop
pop bc
ret
;#########################################################################
; Speed - Changes CPU speed
; On entry A contains speed value - Z slow, NZ fast
; Destroys A,F
;#########################################################################
speed: cp 0
jr z, .slow
ld a, speedbit
.slow: in a, (speedport)
ret
;#########################################################################
; VSYNC wait - waits for the next VSYNC period
; If one is ongoing at entry, it waits for the next.
; Destroys A,F
;#########################################################################
vsyncwait: in a, (crtcstatus)
bit crtcretrace, a
jr nz, vsyncwait
.vsyncwait1: in a, (crtcstatus)
bit crtcretrace, a
jr z, .vsyncwait1
ret
;#########################################################################
; Clear screen - fills 80 x 24 screen with space char and sets colour
; On entry C contains colour byte to initialise colour RAM with
; Destroys A,F
; Entry and exit with screen RAM at 0f000h, PCG RAM at 0f800h
;#########################################################################
clrscr: push hl ; save hl
ld (scratch), sp ; save stack pointer
ld a,colourbit
out (colourport),a ; enable colour RAM at 0f800h
ld sp, colour + 1920 ; clear colour RAM
ld h, c
ld l, c
ld b, 240 ; do the loop 240 times
.loop1: push hl ; write 8 values each loop
push hl ; for a total of 1920 bytes
push hl
push hl
djnz .loop1
xor a
out (colourport),a ; restore PCG RAM at 0f800h
ld sp, screen + 1920 ; clear screen RAM
ld hl, (space << 8) + space
ld b, 240 ; do the loop 240 times
.loop2: push hl ; write 8 values each loop
push hl ; for a total of 1920 bytes
push hl
push hl
djnz .loop2
ld sp, (scratch) ; restore stack pointer
pop hl
ret
;#########################################################################
; Check for key press - tests CRTC status for LPEN strobe
; Destroys A,F
; Returns key in A, with Z flag reset if key pressed
; Z flag set if no key press detected
;#########################################################################
checkkey: in a, (crtcstatus)
bit crtclpenfull, a ; test LPEN bit
ret z ; return if no key
call vsyncwait ; debounce delay 20ms
in a, (crtcstatus)
bit crtclpenfull, a ; test LPEN bit
ret z ; return if no key
push bc
ld a, lpenhigh
out (crtcaddr), a
in a, (crtcdata)
and 00000011b ; mask unused bits
rla
rla
rla
rla
ld b, a
ld a, lpenlow
out (crtcaddr), a
in a, (crtcdata)
and 11110000b ; mask unused bits
rra
rra
rra
rra
or b
pop bc
ret nz ; @ key is 00 - Z flag set
inc a ; clear the Z flag
ld a, 00h ; and restore @ result
ret
;#########################################################################
; Keycode to ASCII conversion
; Destroys A,F
; Accepts eight bit keycode data in A
; On return, A has the ASCII representation of that data
; Destroys AF
;#########################################################################
keylookup: defb 040h, 041h, 042h, 043h, 044h, 045h, 046h, 047h
defb 048h, 049h, 04ah, 04bh, 04ch, 04dh, 04eh, 04fh
defb 050h, 051h, 052h, 053h, 054h, 055h, 056h, 057h
defb 058h, 059h, 05ah, 05bh, 05ch, 05dh, 05eh, 07fh
defb 030h, 031h, 032h, 033h, 034h, 035h, 036h, 037h
defb 038h, 039h, 03ah, 03bh, 02ch, 02dh, 02eh, 02fh
defb 027h, 008h, 009h, 00ah, 00dh, 000h, 000h, 020h
key2ascii: cp 038h
jr c, .lookup
xor a ; not in our table, return 00h
ret
.lookup: push hl
push de
ld b, 00h
ld c, a
ld hl, keylookup
add hl, bc
ld a, (hl)
pop de
pop hl
ret
;#########################################################################
; Binary to ASCII conversion
; Destroys A,F
; Accepts eight bit binary data in A
; On return, BC has an ASCII representation of that data
; Destroys AF
;#########################################################################
bin2ascii: ld b, a ; save input
and 00fh ; mask lower bits
add "0"
cp ":"
jr c, .next
add "A" - ":" ; account for A..F
.next: ld c, a ; store result
ld a, b ; restore upper digit
and 0f0h ; mask
rra ; where's the barrel shifter?
rra
rra
rra
add "0"
cp ":"
jr c, .next2
add "A" - ":"
.next2: ld b, a
ret
;#########################################################################
; Boot Data area
;#########################################################################
; CRTC initialisation tables
crtc64x16: defb 06bh, 040h, 051h, 037h, 012h, 009h, 010h, 011h
defb 048h, 00fh, 02fh, 00fh, 000h, 000h, 000h, 000h
crtc80x24: defb 06bh, 050h, 058h, 037h, 01bh, 005h, 018h, 01ah
defb 048h, 00ah, 02ah, 00ah, 020h, 000h, 000h, 000h
; freebee logo PCG data - 60 pcg characters used - 20 char wide and 3 high
freebeepcg: defb 000h, 000h, 000h, 001h, 003h, 007h, 007h, 00fh
defb 00fh, 00fh, 00fh, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 07fh, 0f8h, 0f0h, 0f0h, 0e0h, 0e0h
defb 0e0h, 0e0h, 0e0h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 0fch, 07fh, 03fh, 03fh, 01fh, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 080h, 080h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 00fh, 007h, 007h, 007h, 007h, 007h
defb 007h, 007h, 007h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 0f0h, 0f0h, 0f0h, 0f0h, 0f0h, 0f0h
defb 0f0h, 0f0h, 0f0h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 03fh, 03fh, 00fh, 00fh, 00fh, 00fh, 00fh, 00fh
defb 00fh, 00fh, 00fh, 000h, 000h, 000h, 000h, 000h
defb 0f8h, 0f8h, 0e0h, 0e0h, 0e0h, 0e0h, 0e0h, 0e0h
defb 0e0h, 0e0h, 0e0h, 000h, 000h, 000h, 000h, 000h
defb 07fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh
defb 03fh, 03fh, 03fh, 000h, 000h, 000h, 000h, 000h
defb 081h, 09fh, 0ffh, 0e1h, 0c0h, 080h, 080h, 080h
defb 080h, 080h, 080h, 000h, 000h, 000h, 000h, 000h
defb 0c0h, 0f0h, 0f9h, 0f3h, 0e7h, 00fh, 00fh, 01fh
defb 01fh, 01fh, 00fh, 000h, 000h, 000h, 000h, 000h
defb 01fh, 0ffh, 0f8h, 0e0h, 0e0h, 0c0h, 0c0h, 0c0h
defb 0ffh, 0c0h, 0e0h, 000h, 000h, 000h, 000h, 000h
defb 0c0h, 0f8h, 0fch, 03eh, 03fh, 01fh, 01fh, 01fh
defb 0ffh, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 001h, 003h, 087h, 087h, 0cfh
defb 0cfh, 00fh, 007h, 000h, 000h, 000h, 000h, 000h
defb 00fh, 07fh, 0fch, 0f0h, 0f0h, 0e0h, 0e0h, 0e0h
defb 0ffh, 0e0h, 0f0h, 000h, 000h, 000h, 000h, 000h
defb 0e0h, 0fch, 07eh, 01fh, 01fh, 00fh, 00fh, 00fh
defb 0ffh, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 007h, 007h, 007h, 007h, 087h, 0c7h, 0c7h, 0e7h
defb 0e7h, 007h, 007h, 000h, 000h, 000h, 000h, 000h
defb 0f7h, 0ffh, 0feh, 0f8h, 0f8h, 0f0h, 0f0h, 0f0h
defb 0f0h, 0f0h, 0f0h, 000h, 000h, 000h, 000h, 000h
defb 0f0h, 0feh, 03fh, 00fh, 00fh, 007h, 007h, 007h
defb 007h, 007h, 007h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 080h, 0c0h, 0e1h, 0e1h, 0f3h
defb 0f3h, 0f3h, 0e1h, 000h, 000h, 000h, 000h, 000h
defb 003h, 01fh, 03fh, 07ch, 0fch, 0f8h, 0f8h, 0f8h
defb 0ffh, 0f8h, 0fch, 000h, 000h, 000h, 000h, 000h
defb 0f8h, 0ffh, 01fh, 007h, 007h, 003h, 003h, 003h
defb 0ffh, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 080h, 0c0h, 0e0h, 0f0h, 0f0h, 0f9h
defb 0f9h, 001h, 000h, 000h, 000h, 000h, 000h, 000h
defb 001h, 00fh, 01fh, 03eh, 07eh, 0fch, 0fch, 0fch
defb 0ffh, 0fch, 0feh, 000h, 000h, 000h, 000h, 000h
defb 0fch, 0ffh, 08fh, 003h, 003h, 001h, 001h, 001h
defb 0ffh, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 080h, 0c0h, 0e0h, 0f0h, 0f8h, 0f8h, 0fch
defb 0fch, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 00fh, 00fh, 00fh, 00fh, 00fh, 01fh, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 0e0h, 0e0h, 0e0h, 0e0h, 0e0h, 0f0h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 03fh, 03fh, 03fh, 03fh, 03fh, 07fh, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 080h, 080h, 080h, 080h, 080h, 0c0h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 00fh, 007h, 003h, 001h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 0e0h, 0f0h, 0f8h, 0ffh, 0ffh, 01fh, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 001h, 003h, 00eh, 0fch, 0f8h, 0c0h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 087h, 003h, 001h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 0f0h, 0f8h, 0fch, 0ffh, 07fh, 00fh, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 001h, 007h, 0feh, 0fch, 0e0h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 0c7h, 087h, 007h, 007h, 007h, 004h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 0f0h, 0f8h, 0f8h, 0feh, 03fh, 007h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 007h, 00fh, 00fh, 03fh, 0feh, 0f0h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 0e1h, 0c0h, 080h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 0fch, 0feh, 07fh, 03fh, 01fh, 003h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 001h, 0ffh, 0ffh, 0f8h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 030h, 060h, 0c0h, 080h, 000h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 0feh, 07fh, 03fh, 01fh, 00fh, 001h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 000h, 000h, 080h, 0ffh, 0ffh, 0fch, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
defb 018h, 030h, 0e0h, 0c0h, 080h, 000h, 000h, 000h
defb 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
freebeepcgend:
freebeeline1: defb 080h, 081h, 082h, 083h, 084h, 085h, 086h, 087h
defb 088h, 089h, 08ah, 08bh, 08ch, 08dh, 08eh, 08fh
defb 090h, 091h, 092h, 093h, 0
freebeeline2: defb 094h, 095h, 096h, 097h, 098h, 099h, 09ah, 09bh
defb 09ch, 09dh, 09eh, 09fh, 0a0h, 0a1h, 0a2h, 0a3h
defb 0a4h, 0a5h, 0a6h, 0a7h, 0
freebeeline3: defb 0a8h, 0a9h, 0aah, 0abh, 0ach, 0adh, 0aeh, 0afh
defb 0b0h, 0b1h, 0b2h, 0b3h, 0b4h, 0b5h, 0b6h, 0b7h
defb 0b8h, 0b9h, 0bah, 0bbh, 0
text1: defb "Open Source Hardware "
defb " https://www.suzyj.net", 0
menu1: defb "< M > monitor < F > 6.750 MHz clock", 0
menu2: defb "< B > boot < S > 3.375 MHz clock", 0
;#########################################################################
; Padding to take us to 06000h - start of a 4K monitor
;#########################################################################
defs 06000h-$, 0ffh
;#########################################################################
; Monitor - a tool for viewing and editing memory
;#########################################################################
monitor: jp moninit
moninit: ld c, green
call clrscr
ld hl, montitle
ld de, screen + 0 * 80 + 26
ld c, cyan
call printtext
ld de, screen + 80 * 20 + 0
ld a, '>'
ld h, d
ld l, e
ld (hl), a
ld hl, 0100h ; memory source address
monloop1: call printhex256
call showcursor
monloop2: call checkkey
jr z, monloop2
checkup: cp 038h ; 'UP' key - 10h
jr nz, checkdn
ld de, 0010h
and a
sbc hl, de
jr waitkeyup
checkdn: cp 03ah ; 'DN' key + 10h
jr nz, checkleft
ld de, 0010h
add hl, de
jr waitkeyup
checkleft: cp 03bh ; 'Left' key - 1h
jr nz, checkright
dec hl
jr waitkeyup
checkright: cp 03eh ; 'Right' key + 1h
jr nz, checke
inc hl
jr waitkeyup
checke: cp 005h
jr nz, checkesc
call enteraddr
jr waitkeyup
checkesc: cp 030h ; 'Right' key + 1h
jr nz, monloop2
ld c, green
call clrscr
ret
waitkeyup: ld b, 20
waitkeyup1: call vsyncwait
djnz waitnext ; key repeat
jr monloop1
waitnext: call checkkey
jr nz, waitkeyup1
call vsyncwait ; debounce delay 20ms
call checkkey
jr nz, waitkeyup1
jr monloop1
;#########################################################################
; Enter address - allows us to enter an address in hex, that we move to
; On entry HL points to the current address
; On exit HL points to the address entered
; Destroys A,F
;#########################################################################
clearentry: defb " ", 000h
enteraddr: push de
push bc
push hl
ld hl, clearentry
ld de, screen + 80 * 20 + 2
ld c, green
call printtext
pop hl
ld b, h
ld c, l
enteraddr1: call vsyncwait
call checkkey
jr nz, enteraddr1
call vsyncwait ; debounce delay
call checkkey
jr nz, enteraddr1
ld de, screen + 80 * 20 + 2
ld a, 'E'
ld h, d
ld l, e
ld (hl), a
inc hl
ld a, ' '
ld (hl), a
ld d, h
ld e, l
enterloop1: call checkkey
jr z, enterloop1
call keytohex ; 0-9, A-F ?
jr nz, enterloop1
inc de
call displayhex
sla a
sla a
sla a
sla a
ld b, a
ld (scratch), a
call waitkeyrelease
enterloop2: call checkkey
jr z, enterloop2
call keytohex ; 0-9, A-F ?
jr nz, enterloop2
inc de
call displayhex
or b
ld b, a
ld (scratch), a
call waitkeyrelease
enterloop3: call checkkey
jr z, enterloop3
call keytohex ; 0-9, A-F ?
jr nz, enterloop3
inc de
call displayhex
sla a
sla a
sla a
sla a
ld c, a
ld (scratch), a
call waitkeyrelease
enterloop4: call checkkey
jr z, enterloop4
call keytohex ; 0-9, A-F ?
jr nz, enterloop4
inc de
call displayhex
or c
ld c, a
ld (scratch), a
call waitkeyrelease
ld h, b
ld l, c
ld (scratch), hl
pop bc
pop de
ret
;#########################################################################
; Display hex - Displays a single hex digit
; On entry A contains a binary value in the lower nibble
; DE points to the screen insertion point
; Preserves A, F
;#########################################################################
displayhex: push af
push bc
call bin2ascii
ld a, c
ld (de), a
pop bc
pop af
ret
;#########################################################################
; Wait key release - Waits for the current keypress to be released
; preserves everything
;#########################################################################
waitkeyrelease: push af
waitkeynext: call vsyncwait
call checkkey
jr nz, waitkeynext
call vsyncwait ; debounce delay 20ms
call checkkey
jr nz, waitkeynext
pop af
ret
;#########################################################################
; Key to hex - converts a keycode to a hex digit
; On entry A contains the keycode
; Hex digit is returned in A
; Z flag set if keycode in 0..9, A..F
; Destroys A, F
;#########################################################################
keytohex: cp 0 ; check for @
jr nz, .keytohex1
.keytohex3: cp 0ffh ; reset the z flag
ret
.keytohex1: cp 007h ; check for A..F
jr nc, .keytohex2
add 009h
cp a ; set the z flag
ret
.keytohex2: sub 020h
cp 00ah ; check for 0..9
jr nc, .keytohex3
cp a ; set the z flag
ret
;#########################################################################
; Print hex 256 - Prints a page of data around the current address
; On entry HL points to the current address
; Destroys A,F
;#########################################################################
printhex256: push hl
push de
push bc
; we want to start our page 2 lines above the current address.
ld a, l
and 0f0h
ld l, a
ld de, 0020h
and a
sbc hl, de
ld de, screen + 2 * 80 + 0 ; screen destination
ld b, 16
.hex256loop: ld c, green
call printhex16
push bc
ld bc, 0010h
add hl, bc
push hl
ld bc, 0050h
ld h, d
ld l, e
add hl, bc
ld d, h
ld e, l
pop hl
pop bc
djnz .hex256loop
pop bc
pop de
pop hl
ret
;#########################################################################
; Show Cursor - highlights the byte being pointed to
; On entry HL points to the current address
; Destroys A,F
;#########################################################################
curslookup: defb 000h, 003h, 006h, 009h, 00dh, 010h, 013h, 016h
defb 01ah, 01dh, 020h, 023h, 027h, 02ah, 02dh, 030h
showcursor: push hl
push bc
ld a, colourbit
out (colourport), a ; enable colour RAM at 0f800h
ld de, colour + 4 * 80 + 7 ; screen destination
ld a, l
and 0fh
ld b, 00h
ld c, a
ld hl, curslookup
add hl, bc
ld a, (hl)
ld l, a
ld h, 0
add hl, de
ld (hl), 020h
inc hl
ld (hl), 020h
xor a
out (colourport), a ; enable PCG RAM at 0f800h
pop bc
pop hl
ret
;#########################################################################
; Print hex 16 - Prints Source address, followed by 16 bytes in hex
; On entry HL points to the source address
; DE points to the screen insertion point
; C contains the colour for the displayed bytes
; Destroys A,F
;#########################################################################
printhex16: push hl
push de
; initialise colours for line
push bc
push de
ld a, d ; add 0800h to de to point
add 08h ; into colour RAM
ld d, a
ld a, colourbit
out (colourport), a ; enable colour RAM at 0f800h
ld b, 76 ; the line is 76 chars wide
ld a, c
.hex16loop1: ld (de), a
inc de
djnz .hex16loop1
xor a
out (colourport), a ; enable PCG RAM at 0f800h
pop de
; print source address
ld a, h
call bin2ascii
ld a, b
ld (de), a
inc de
ld a, c
ld (de), a
inc de
ld a, l
call bin2ascii
ld a, b
ld (de), a
inc de
ld a, c
ld (de), a
inc de
; print divider character
ld a, space
ld (de), a
inc de
ld a, 07ch
ld (de), a ; | char
inc de
ld a, space
ld (de), a
inc de
; print 16 values
push hl
ld b, 4
.hex16loop2: push bc
ld a, (hl)
call bin2ascii
ld a, b
ld (de), a
inc de
ld a, c
ld (de), a
inc de
ld a, space
ld (de), a
inc de
inc hl
ld a, (hl)
call bin2ascii
ld a, b
ld (de), a
inc de
ld a, c
ld (de), a
inc de
ld a, space
ld (de), a
inc de
inc hl
ld a, (hl)
call bin2ascii
ld a, b
ld (de), a
inc de
ld a, c
ld (de), a
inc de
ld a, space
ld (de), a
inc de
inc hl
ld a, (hl)
call bin2ascii
ld a, b
ld (de), a
inc de
ld a, c
ld (de), a
inc de
ld a, space
ld (de), a
inc de
ld (de), a
inc de
inc hl
pop bc
djnz .hex16loop2
pop hl
; print divider character
dec de
ld a, 07ch
ld (de), a ; | char
inc de
ld a, space
ld (de), a
inc de
; print 16 values as straight ASCII
ld bc, 0010h
ldir
pop bc
pop de
pop hl
ret
;#########################################################################
; Monitor data area
;#########################################################################
montitle: defb "Freebee Monitor Version 0.1", 000h
;#########################################################################
; Padding to take us to 07000h - 4K - 3 bytes for fonts and exitboot
; code which is exactly 3 bytes
;#########################################################################
defs 07000h-$, 0ffh
;#########################################################################
; Character data - taken from Motorola MCM66740 and MCM6674 character ROMs
;#########################################################################
char7x12: incbin "MCM66740charrom7x12.bin"
char5x7: incbin "MCM6674charrom5x7truncated.bin"
; Note three bytes truncated from end of last char for exit code.
; These are not displayed as the character cell is 8 x 11
;#########################################################################
; End of boot code - page boot ROM out for Basic execution
;#########################################################################
exitboot: xor a
out (bootromport), a
;#########################################################################
; Note Basic code is copyright Microbee so is not included
;#########################################################################
basic: incbin "Microbee_Basic_522e.bin"
end
No comments:
Post a Comment