diff --git a/Makefile b/Makefile index 3087e77..b68a393 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,67 @@ -BUILDDIR=.build -_BIN= rom_monitor.bin ram_monitor.bin MONITOR.COM -BIN = $(patsubst %,$(BUILDDIR)/%,$(_BIN)) +# BUILDDIR=.build +# _BIN= rom_monitor.bin ram_monitor.bin MONITOR.COM +# BIN = $(patsubst %,$(BUILDDIR)/%,$(_BIN)) +# +# .PHONY: all clean +# +# all: $(BUILDDIR) $(BIN) +# +# $(BUILDDIR)/%.bin: src/%.z80 | $(BUILDDIR) +# @zasm -w -i $< -o $@ +# +# $(BUILDDIR)/%.COM: src/%.z80 | $(BUILDDIR) +# @zasm -w -i $< -o $@ +# +# $(BUILDDIR): +# @mkdir $(BUILDDIR) +# +# clean: +# @rm -df $(BUILDDIR)/*.bin $(BUILDDIR)/*.COM $(BUILDDIR)/*.lst .build + +AS = sdasz80 +LD = sdldz80 +OBJCOPY = sdobjcopy + +BUILD = .build + +TARGET_ROM = rom_monitor +TARGET_COM = MONITOR + +ASFLAGS = -plosff + +SRC_ROM = \ +src/monitor.s \ +src/rom.s +SRC_COM = \ +src/monitor.s \ +src/cpm.s + +OBJ_ROM = $(addprefix $(BUILD)/, $(notdir $(SRC_ROM:.s=.rel))) +OBJ_COM = $(addprefix $(BUILD)/, $(notdir $(SRC_COM:.s=.rel))) +vpath %.s $(sort $(dir $(SRC_ROM))) +vpath %.s $(sort $(dir $(SRC_COM))) .PHONY: all clean -all: $(BUILDDIR) $(BIN) +all: $(BUILD) $(BUILD)/$(TARGET_ROM).bin $(BUILD)/$(TARGET_COM).COM -$(BUILDDIR)/%.bin: src/%.z80 | $(BUILDDIR) - @zasm -w -i $< -o $@ +$(BUILD)/%.rel: %.s Makefile | $(BUILD) + $(AS) $(ASFLAGS) $@ $< -$(BUILDDIR)/%.COM: src/%.z80 | $(BUILDDIR) - @zasm -w -i $< -o $@ +$(BUILD)/$(TARGET_ROM).ihx: $(OBJ_ROM) + $(LD) -im1 $@ $(OBJ_ROM) -b BOOT=0x0000 -$(BUILDDIR): - @mkdir $(BUILDDIR) +$(BUILD)/$(TARGET_COM).ihx: $(OBJ_COM) + $(LD) -im1 $@ $(OBJ_COM) -b BOOT=0x0100 -b MAIN=0xE200 + +%.bin: %.ihx + $(OBJCOPY) -I ihex -O binary $< $@ + +%.COM: %.ihx + $(OBJCOPY) -I ihex -O binary $< $@ + +$(BUILD): + mkdir $@ clean: - @rm -df $(BUILDDIR)/*.bin $(BUILDDIR)/*.COM $(BUILDDIR)/*.lst .build + rm -fr $(BUILD) diff --git a/src/cpm.s b/src/cpm.s new file mode 100644 index 0000000..fc44fa9 --- /dev/null +++ b/src/cpm.s @@ -0,0 +1,25 @@ +bios .equ 0x0000 +main .equ 0xE200 + +.globl monitor_start +.globl s_MAIN +.globl end + +.area BOOT + ld hl, #origin ; Start of code to transfer + ld bc, #end-main+1 ; Size of code transfer + ld de, #s_MAIN ; Target of transfer + ldir ; Z80 transfer instruction + jp monitor_start + +origin: + +.area MAIN +system_jump: + jp bios + +system_string: + .str /system\0/ + +.area PARSE_TABLE + .dw system_string, system_jump diff --git a/src/monitor.s b/src/monitor.s new file mode 100644 index 0000000..b4daf01 --- /dev/null +++ b/src/monitor.s @@ -0,0 +1,756 @@ +; Variables +current_location .equ 0x1000 +line_count .equ 0x1002 +byte_count .equ 0x1003 +value_pointer .equ 0x1004 +current_value .equ 0x1006 +; Buffer up to stack +buffer .equ 0x1008 + +.area BOOT +.area MAIN +; Puts a single char (byte value) on serial output +; Call with char to send in A register. Uses B register +write_char: + ld b, a +write_char_loop: + in a, (0x03) ; Check if OK to send + and #0x01 + jp z, write_char_loop + + ld a, b + out (0x02), a ; Send the char + + ret + +; Subroutine to write a zero-terminated string to serial output +; Pass address of string in HL register +; No error checking +write_string:: + in a, (0x03) ; Check if OK to send + and #0x01 + jp z, write_string + + ld a, (hl) ; Get char from string + and a ; Check if 0 + ret z ; Yes, finished + out (0x02), a ; No, write char to output + inc hl ; Next char in string + jp write_string + +; Binary loader. Receive a binary file, place in memory. +; Address of load passed in HL, length of load (= file length) in BC +bload: + in a, (0x1F) ; Check if char is available + and #0x01 + jp z,bload + + in a, (0x1E) ; Read char + ld (hl), a ; Write char to memory + inc hl + dec bc ; Decrement counter + ld a, b ; Need to test BC this way because + or c ; dec rp instruction does not change flags + jp nz, bload + + ret + +; Binary dump to port. Send a stream of binary data from memory to serial output +; Address of dump passed in HL, length of dump in BC +bdump: + in a, (0x03) ; Check if OK to send + and #0x01 + jp z, bdump + + ld a, (hl) ; Load from memory + out (0x02), a + inc hl + dec bc ; Decrement counter + ld a, b ; Need to test BC this way because + or c ; dec rp instruction does not change flags + jp nz, bdump + + ret + +; Subroutine to get a string from serial input, place in buffer. +; Buffer address passed in HL reg. +; Uses A,BC,DE,HL registers (including calls to other subroutines). +; Line entry ends by hitting return key. Return char not included in string (replaced by zero). +; Backspace editing OK. No error checking. +get_line: + ld c, #0x00 ; Line position + ld a, h ; Put original buffer address in de + ld d, a ; after this don't need to preserve hl + ld a, l ; subroutines called don't use de + ld e, a +get_line_next_char: + in a, (0x1F) ; Check if char is available + and #0x01 + jp z, get_line_next_char + + in a, (0x1E) ; Read char + cp #0x0D ; Check if return + ret z + + cp #0x7F ; Check if backspace (VT102 keys) + jp z, get_line_backspace + + cp #0x08 ; Check if backspace (ANSI keys) + jp z, get_line_backspace + + call write_char ; Display the char + ld (de), a ; Store char in buffer + inc de + inc c + ld a, #0x00 ; leaves a zero-terminated string in buffer + ld (de), a + jp get_line_next_char + +get_line_backspace: + ld a, c ; Check current position in line + cp #0x00 ; At beginning of line? + jp z, get_line_next_char ; yes, ignore backspace, get next char + + dec de ; No, erase char from buffer + dec c ; Back up one + ld a, #0x00 ; Put a zero in buffer where the last char was + ld (de), a + ld hl, #erase_char_string ; ANSI sequence to delete one char from line + call write_string ; Transmits sequence to backspace and erase char + jp get_line_next_char + +; Creates a two-char hex string from the byte value passed in register A +; Location to place string passed in HL +; String is zero-terminated, stored in 3 locations starting at HL +; Also uses registers b,d, and e +byte_to_hex_string: + ld b, a ; Store original byte + srl a ; Shift right 4 times, putting + srl a ; high nybble in low-nybble spot + srl a ; and zeros in high-nybble spot + srl a + ld d, #0x00 ; Prepare for 16-bit addition + ld e, a ; de contains offset + push hl ; Temporarily store string target address + ld hl, #hex_char_table ; Use char table to get high-nybble character + add hl, de ; Add offset to start of table + ld a, (hl) ; Get char + pop hl ; Get string target address + ld (hl), a ; Store first char of string + inc hl ; Point to next string target address + ld a, b ; Get original byte back from reg b + and #0x0F ; Mask off high-nybble + ld e, a ; d still has 000h, now de has offset + push hl ; Temp store string target address + ld hl, #hex_char_table ; Start of table + add hl, de ; Add offset + ld a, (hl) ; Get char + pop hl ; Get string target address + ld (hl), a ; Store second char of string + inc hl ; Point to third location + ld a, #0x00 ; Zero to terminate string + ld (hl), a ; Store the zero + ret ; Done + +; Converts a single ASCII hex char to a nybble value +; Pass char in reg A. Letter numerals must be upper case. +; Return nybble value in low-order reg A with zeros in high-order nybble if no error. +; Return 0ffh in reg A if error (char not a valid hex numeral). +; Also uses b, c, and hl registers. +hex_char_to_nybble: + ld hl, #hex_char_table + ld b, #0x0f ; No. of valid characters in table - 1. + ld c, #0x00 ; Will be nybble value +hex_to_nybble_loop: + cp (hl) ; Character match here? + jp z, hex_to_nybble_ok ; match found, exit + dec b ; No match, check if at end of table + jp m, hex_to_nybble_err ; Table limit exceded, exit with error + inc c ; Still inside table, continue search + inc hl + jp hex_to_nybble_loop +hex_to_nybble_ok: + ld a, c ; Put nybble value in a + ret +hex_to_nybble_err: + ld a, #0xFF ; Error value + ret + +; Converts a hex character pair to a byte value +; Called with location of high-order char in HL +; If no error carry flag clear, returns with byte value in register A, and +; HL pointing to next mem location after char pair. +; If error (non-hex char) carry flag set, HL pointing to invalid char +hex_to_byte: + ld a, (hl) ; Location of character pair + push hl ; Store hl (hex_char_to_nybble uses it) + call hex_char_to_nybble + pop hl ; Returns with nybble value in a reg, or 0ffh if error + cp #0xFF ; Non-hex character? + jp z, hex_to_byte_err ; Yes, exit with error + sla a ; No, move low order nybble to high side + sla a + sla a + sla a + ld d, a ; Store high-nybble + inc hl ; Get next character of the pair + ld a, (hl) + push hl ; Store hl + call hex_char_to_nybble + pop hl + cp #0xFF ; Non-hex character? + jp z, hex_to_byte_err ; Yes, exit with error + or d ; No, combine with high-nybble + inc hl ; Point to next memory location after char pair + scf + ccf ; No-error exit (carry = 0) + ret +hex_to_byte_err: + scf ; Error, carry flag set + ret + +hex_char_table: + .ascii /0123456789ABCDEF/ ; ASCII hex table + +; Subroutine to get a two-byte address from serial input. +; Returns with address value in HL +; Uses locations in RAM for buffer and variables +address_entry: + ld hl, #buffer ; Location for entered string + call get_line ; Returns with address string in buffer + ld hl, #buffer ; Location of stored address entry string + call hex_to_byte ; Will get high-order byte first + jp c, address_entry_error ; If error, jump + ld (current_location+1), a ; Store high-order byte, little-endian + ld hl, #buffer+2 ; Point to low-order hex char pair + call hex_to_byte ; Get low-order byte + jp c, address_entry_error ; Jump if error + ld (current_location), a ; Store low-order byte in lower memory + ld hl, (current_location) ; Put memory address in hl + ret +address_entry_error: + ld hl, #address_error_msg + call write_string + jp address_entry + +; Subroutine to get a decimal string, return a word value +; Calls decimal_string_to_word subroutine +decimal_entry: + ld hl, #buffer + call get_line ; Returns with DE pointing to terminating zero + ld hl, #buffer + call decimal_string_to_word + ret nc ; No error, return with word in hl + ld hl, #decimal_error_msg ; Error, try again + call write_string + jp decimal_entry + +; Subroutine to convert a decimal string to a word value +; Call with address of string in HL, pointer to end of string in DE +; Carry flag set if error (non-decimal char) +; Carry flag clear, word value in HL if no error. +decimal_string_to_word: + ld b, d + ld c, e ; Use BC as string pointer + ld (current_location), hl ; Store addr. of start of buffer in RAM word variable + ld hl, #0x00 ; Starting value zero + ld (current_value), hl + ld hl, #decimal_place_value ; Pointer to values + ld (value_pointer), hl +decimal_next_char: + dec bc ; Next char in string (moving right to left) + ld hl,(current_location) ; Check if at end of decimal string + scf ; Get ready to subtract de from buffer addr. + ccf ; Set carry to zero (clear) + sbc hl, bc ; Keep going if bc > or = hl (buffer address) + jp c, decimal_continue ; Borrow means bc > hl + jp z, decimal_continue ; z means bc = hl + ld hl, (current_value) ; Return if de < buffer address (no borrow) + scf ; Get value back from RAM variable + ccf + ret ; Return with carry clear, value in hl +decimal_continue: + ld a, (bc) ; Next char in string (right to left) + sub #0x30 ; ASCII value of zero char + jp m, decimal_error ; Error if char value less than 030h + cp #0x0A ; Error if byte value > or = 10 decimal + jp p, decimal_error ; a reg now has value of decimal numeral + ld hl, (value_pointer) ; Get value to add an put in de + ld e, (hl) ; Little-endian (low byte in low memory) + inc hl + ld d, (hl) + inc hl ; hl now points to next value + ld (value_pointer), hl + ld hl, (current_value) ; Get back current value +decimal_add: + dec a ; Add loop to increase total value + jp m, decimal_add_done ; End of multiplication + add hl, de + jp decimal_add +decimal_add_done: + ld (current_value), hl + jp decimal_next_char +decimal_error: + scf + ret + jp decimal_add + +decimal_place_value: + .dw 1,10,100,1000,10000 + +; Memory dump +; Displays a 256-byte block of memory in 16-byte rows. +; Called with address of start of block in HL +memory_dump: + ld (current_location), hl ; Store address of block to be displayed + ld a, #0x00 + ld (byte_count), a ; Initialize byte count + ld (line_count), a ; Initialize line count + jp dump_new_line +dump_next_byte: + ld hl, (current_location) ; Get byte address from storage, + ld a, (hl) ; Get byte to be converted to string + inc hl ; Increment address and + ld (current_location), hl ; Store back + ld hl, #buffer ; Location to store string + call byte_to_hex_string ; Convert + ld hl, #buffer ; Display string + call write_string + ld a, (byte_count) ; Next byte + inc a + jp z, dump_done ; Stop when 256 bytes displayed + ld (byte_count),a ; Not finished yet, store + ld a, (line_count) ; End of line (16 characters)? + cp #0x0f ; Yes, start new line + jp z, dump_new_line + inc a ; No, increment line count + ld (line_count), a + ld a, #0x20 ; Print space + call write_char + jp dump_next_byte ; Continue +dump_new_line: + ld a, #0x00 ; Reset line count to zero + ld (line_count), a + call write_newline + ld hl, (current_location) ; Location of start of line + ld a, h ; High byte of address + ld hl, #buffer + call byte_to_hex_string ; Convert + ld hl, #buffer + call write_string ; Write high byte + ld hl, (current_location) + ld a, l ; Low byte of address + ld hl, #buffer + call byte_to_hex_string ; Convert + ld hl, #buffer + call write_string ; Write low byte + ld a, #0x20 ; Space + call write_char + jp dump_next_byte ; Now write 16 bytes +dump_done: + ld a, #0x00 + ld hl, #buffer + ld (hl), a ; Clear buffer of last string + call write_newline + ret +; +;Memory load +;Loads RAM memory with bytes entered as hex characters +;Called with address to start loading in HL +;Displays entered data in 16-byte rows. +memory_load: + ld (current_location), hl + ld hl, #data_entry_msg + call write_string + jp load_new_line +load_next_char: + call get_char + cp #0x0D ; Return? + jp z, load_done ; Yes, quit + ld (buffer), a + call get_char + cp #0x0D ; Return? + jp z, load_done ; Yes, quit + ld (buffer+1), a + ld hl, #buffer + call hex_to_byte + jp c, load_data_entry_error ; Non-hex character + ld hl, (current_location) ; Get byte address from storage, + ld (hl), a ; Store byte + inc hl ; Increment address and + ld (current_location), hl ; Store back + ld a, (buffer) + call write_char + ld a, (buffer+1) + call write_char + ld a, (line_count) ; End of line (16 characters)? + cp #0x0F ; Yes, start new line + jp z, load_new_line + inc a ; No, increment line count + ld (line_count), a + ld a, #0x20 ; Print space + call write_char + jp load_next_char ; Continue +load_new_line: + ld a, #0x00 ; Reset line count to zero + ld (line_count), a + call write_newline + jp load_next_char ; Continue +load_data_entry_error: + call write_newline + ld hl, #data_error_msg + call write_string + ret +load_done: + call write_newline + ret + +; Get one ASCII character from the serial port. +; Returns with char in A reg. No error checking. +get_char: + in a, (0x1F) ; Get status + and #0x01 ; Check RxRDY bit + jp z, get_char ; Not ready, loop + in a, (0x1E) ; Get char + ret + +; Subroutine to start a new line +write_newline: + ld a, #0x0D ; ASCII carriage return character + call write_char + ld a, #0x0A ; New line (line feed) character + call write_char + ret + +; Subroutine to read one disk sector (128 bytes) +; Address to place data passed in HL +; LBA bits 0 to 7 passed in C, bits 8 to 15 passed in B +; LBA bits 16 to 23 passed in E +disk_read:: + ld a, c + out (0x0B), a ; lba bits 0 - 7 + ld a, b + out (0x0C), a ; lba bits 8 - 15 + ld a, e + out (0x0D), a ; lba bits 16 - 23 + ld a, #0x20 ; Read sector command + out (0x0F), a +rd_wait_for_DRQ_set: + in a, (0x0F) ; Read status + and #0x08 ; DRQ bit + jp z, rd_wait_for_DRQ_set ; Loop until bit set +read_loop: + in a, (0x08) ; Get data + ld (hl), a + inc hl + in a, (0x0f) ; Check status + and #0x08 ; DRQ bit + jp nz, read_loop ; Loop until cleared + ret + +; Subroutine to write one disk sector (128 bytes) +; Address of data to write to disk passed in HL +; LBA bits 0 to 7 passed in C, bits 8 to 15 passed in B +; LBA bits 16 to 23 passed in E +disk_write: + ld a, c + out (0x0b), a ; lba bits 0 - 7 + ld a, b + out (0x0c), a ; lba bits 8 - 15 + ld a, e + out (0x0d), a ; lba bits 16 - 23 + ld a, #0x30 ; Write sector command + out (0x0f), a +wr_wait_for_DRQ_set: + in a, (0x0f) ; Read status + and #0x08 ; DRQ bit + jp z, wr_wait_for_DRQ_set ; Loop until bit set +write_loop: + ld a, (hl) + out (0x08), a ; Write data + inc hl + in a, (0x0f) ; Read status + and #0x08 ; Check DRQ bit + jp nz, write_loop ;write until bit cleared + ret + +; Strings used in subroutines +length_entry_string: + .str /Enter length of file to load (decimal): \0/ +dump_entry_string: + .str /Enter no. of bytes to dump (decimal): \0/ +LBA_entry_string: + .str /Enter LBA (decimal, 0 to 65535): \0/ +erase_char_string: ;ANSI sequence for backspace, erase to end of line. + .db #0x08 + .db #0x1B + .str /[K\0/ +address_entry_msg: + .str /Enter 4-digit hex address (use upper-case A through F): \0/ +address_error_msg: + .str /\r\nError: invalid hex character, try again: \0/ +data_entry_msg: + .str /Enter hex bytes, hit return when finished.\r\n\0/ +data_error_msg: + .str /Error: invalid hex byte.\r\n\0/ +decimal_error_msg: + .str /\r\nError: invalid decimal number, try again: \0/ + +; Simple monitor program for CPUville Z80 computer with serial interface. +monitor_start:: + call write_newline ; Routine program return here to avoid re-initialization of port + ld a, #0x03e ; Cursor symbol + call write_char + ld hl, #buffer + call get_line ; Get monitor input string (command) + call write_newline + call parse ; Interprets command, returns with address to jump to in HL + jp (hl) + +; Parses an input line stored in buffer for available commands as described in parse table. +; Returns with address of jump to action for the command in HL +parse: + ld bc, #parse_table ; bc is pointer to parse_table +parse_start: + ld a, (bc) ; Get pointer to match string from parse table + ld e, a + inc bc + ld a, (bc) + ld d, a ; de will is pointer to strings for matching + ld a, (de) ; Get first char from match string + or #0x00 ; Zero? + jp z, parser_exit ; Yes, exit no_match + ld hl, #buffer ; No, parse input string +match_loop: + cp (hl) ; Compare buffer char with match string char + jp nz, no_match ; No match, go to next match string + or #0x00 ; End of strings (zero)? + jp z, parser_exit ; Yes, matching string found + inc de ; Match so far, point to next char in match string + ld a, (de) ; Get next character from match string + inc hl ; And point to next char in input string + jp match_loop ; Check for match +no_match: + inc bc ; Skip over jump target to + inc bc + inc bc ; Get address of next matching string + jp parse_start +parser_exit: + inc bc ; Skip to address of jump for match + ld a, (bc) + ld l, a + inc bc + ld a,(bc) + ld h, a ; Returns with jump address in hl + ret + +; Actions to be taken on match +; +; Memory dump program +; Input 4-digit hexadecimal address +; Calls memory_dump subroutine +dump_jump: + ld hl, #dump_message ; Display greeting + call write_string + ld hl, #address_entry_msg ; Get ready to get address + call write_string + call address_entry ; Returns with address in HL + call write_newline + call memory_dump + jp monitor_start + +; Hex loader, displays formatted input +load_jump: + ld hl, #load_message ; Display greeting + call write_string ; Get address to load + ld hl, #address_entry_msg ; Get ready to get address + call write_string + call address_entry + call write_newline + call memory_load + jp monitor_start + +; Jump and run do the same thing: get an address and jump to it. +run_jump: + ld hl, #run_message ; Display greeting + call write_string + ld hl, #address_entry_msg ; Get ready to get address + call write_string + call address_entry + jp (hl) + +; Help and ? do the same thing, display the available commands +help_jump: + ld hl, #help_message + call write_string + ld bc, #parse_table ; Table with pointers to command strings +help_loop: + ld a, (bc) ; Displays the strings for matching commands, + ld l, a ; Getting the string addresses from the + inc bc ; Parse table + ld a, (bc) ; Pass address of string to hl through a reg + ld h, a + ld a, (hl) ; hl now points to start of match string + or #0x00 ; Exit if no_match string + jp z, help_done + push bc ; Write_char uses b register + ld a, #0x20 ; Space char + call write_char + pop bc + call write_string ; Writes match string + inc bc ; Pass over jump address in table + inc bc + inc bc + jp help_loop +help_done: + jp monitor_start + +; Binary file load. Need both address to load and length of file +bload_jump: + ld hl, #bload_message + call write_string + ld hl, #address_entry_msg + call write_string + call address_entry + call write_newline + push hl + ld hl, #length_entry_string + call write_string + call decimal_entry + ld b, h + ld c, l + ld hl, #bload_ready_message + call write_string + pop hl + call bload + jp monitor_start + +; Binary memory dump. Need address of start of dump and no. bytes +bdump_jump: + ld hl, #bdump_message + call write_string + ld hl, #address_entry_msg + call write_string + call address_entry + call write_newline + push hl + ld hl, #dump_entry_string + call write_string + call decimal_entry + ld b, h + ld c, l + ld hl, #bdump_ready_message + call write_string + call get_char + pop hl + call bdump + jp monitor_start +; Disk read. Need memory address to place data, LBA of sector to read +diskrd_jump: + ld hl, #diskrd_message + call write_string + ld hl, #address_entry_msg + call write_string + call address_entry + call write_newline + push hl + ld hl, #LBA_entry_string + call write_string + call decimal_entry + ld b, h + ld c, l + ld e, #0x00 + pop hl + call disk_read + jp monitor_start +diskwr_jump: + ld hl, #diskwr_message + call write_string + ld hl, #address_entry_msg + call write_string + call address_entry + call write_newline + push hl + ld hl, #LBA_entry_string + call write_string + call decimal_entry + ld b, h + ld c, l + ld e, #0x00 + pop hl + call disk_write + jp monitor_start + +; Prints message for no match to entered command +no_match_jump: + ld hl, #no_match_message + call write_string + ld hl, #buffer + call write_string + jp monitor_start + +; Monitor data structures: +no_match_message: + .str /? \0/ +help_message: + .str /Commands implemented:\r\n\0/ +dump_message: + .str /Displays a 256-byte block of memory.\r\n\0/ +load_message: + .str /Enter hex bytes starting at memory location.\r\n\0/ +run_message: + .str /Will jump to (execute) program at address entered.\r\n\0/ +bload_message: + .str /Loads a binary file into memory.\r\n\0/ +bload_ready_message: + .str /\r\nReady to receive, start transfer.\0/ +bdump_message: + .str /Dumps binary data from memory to serial port.\r\n\0/ +bdump_ready_message: + .str /\r\nReady to send, hit any key to start.\0/ +diskrd_message: + .str /Reads one sector from disk to memory.\r\n\0/ +diskwr_message: + .str /Writes one sector from memory to disk.\r\n\0/ + +; Strings for matching: +dump_string: + .str /dump\0/ +load_string: + .str /load\0/ +jump_string: + .str /jump\0/ +run_string: + .str /run\0/ +question_string: + .str /?\0/ +help_string: + .str /help\0/ +bload_string: + .str /bload\0/ +bdump_string: + .str /bdump\0/ +diskrd_string: + .str /diskrd\0/ +diskwr_string: + .str /diskwr\0/ +no_match_string: + .dw #0x00 + +;Table for matching strings to jumps +.area PARSE_TABLE +parse_table: + .dw dump_string, dump_jump + .dw load_string, load_jump + .dw jump_string, run_jump + .dw run_string, run_jump + .dw question_string, help_jump + .dw help_string, help_jump + .dw bload_string, bload_jump + .dw bdump_string, bdump_jump + .dw diskrd_string, diskrd_jump + .dw diskwr_string, diskwr_jump +.area PARSE_TABLE_END + .dw no_match_string, no_match_jump + +end:: diff --git a/src/rom.s b/src/rom.s new file mode 100644 index 0000000..38ef76a --- /dev/null +++ b/src/rom.s @@ -0,0 +1,49 @@ +stack .equ 0x10ff +bootloader .equ 0x1100 + +.globl disk_read +.globl write_string +.globl monitor_start + +.area BOOT +start: + ld sp, #stack + call initialize + ld hl, #monitor_message + call write_string + jp monitor_start + +monitor_message: + .db #0x1B + .str /[2J/ + .db #0x1B + .str /[H\r\nROM Ver. 9\r\n\0/ + +; Clear out bufferend input +initialize: +initialize_loop_1: + in a, (0x1E) ; Read char from keyboard + in a, (0x1F) ; Check if there is another char + and #0x01 + jp nz, initialize_loop_1 +; Wait for GPU be ready +initialize_loop_2: + in a, (0x03) ; If GPU is not ready value is 0xFF + and #0x02 + jp nz, initialize_loop_2 + + ret + +.area MAIN +boot_jump: + ld hl, #bootloader ; Set destination + ld bc, #0x0000 ; Set lba of bootloader + ld e, #0x00 + call disk_read + jp bootloader + +boot_string: + .str /boot\0/ + +.area PARSE_TABLE + .dw boot_string, boot_jump