Friday, 15 November 2024

Writing an unencumbered boot and monitor ROM for Freebee

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: