From 1435f856b357e9567f8ac62073ff913fd4df0513 Mon Sep 17 00:00:00 2001 From: UzixLS Date: Thu, 17 Jun 2021 22:00:59 +0300 Subject: [PATCH] new magic rom with menu --- .gitignore | 3 + rom/Makefile | 2 +- rom_src/Makefile | 16 +- rom_src/config.asm | 30 ++ rom_src/draw.asm | 425 ++++++++++++++++ rom_src/font.asm | 961 +++++++++++++++++++++++++++++++++++++ rom_src/input.asm | 183 +++++++ rom_src/main.asm | 617 +++++++++++++----------- rom_src/main_test.asm | 66 +++ rom_src/menu.asm | 157 ++++++ rom_src/menu_structure.asm | 235 +++++++++ rom_src/strings.asm | 102 ++++ 12 files changed, 2527 insertions(+), 270 deletions(-) create mode 100644 rom_src/config.asm create mode 100644 rom_src/draw.asm create mode 100644 rom_src/font.asm create mode 100644 rom_src/input.asm create mode 100644 rom_src/main_test.asm create mode 100644 rom_src/menu.asm create mode 100644 rom_src/menu_structure.asm create mode 100644 rom_src/strings.asm diff --git a/.gitignore b/.gitignore index e8df3bb..237e2e2 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,7 @@ fpga/tb.*/ rom/sizif*.rom rom/sizif*.hex rom_src/*.bin +rom_src/*.hex +rom_src/*.map +rom_src/*.sna rom_src.*/ diff --git a/rom/Makefile b/rom/Makefile index 001fa5e..95ff91c 100644 --- a/rom/Makefile +++ b/rom/Makefile @@ -1,7 +1,7 @@ all: cat 128-0.rom \ 128-1.rom \ - ../rom_src/rom1.bin \ + ../rom_src/main.bin \ ESXMMC.BIN ESXMMC.BIN \ dvmen3e0.rom \ dvmen3e1.rom \ diff --git a/rom_src/Makefile b/rom_src/Makefile index d73cd86..95e089d 100644 --- a/rom_src/Makefile +++ b/rom_src/Makefile @@ -1,8 +1,20 @@ export PATH:=/cygdrive/c/Hwdev/sjasmplus/:/cygdrive/c/Dev/srec/:${PATH} +SJOPTS='-DSIZIFXXS' + +.PHONY: all clean .FORCE +.FORCE: + all: main.bin -%.bin: %.asm - sjasmplus $< +clean: + rm -f *.bin *.mem *.hex *.map *.sna + +%.bin: %.asm .FORCE + sjasmplus ${SJOPTS} $< %.mem: %.bin srec_cat $< -binary -o $@ -vmem 8 +%.hex: %.bin + srec_cat $< -binary -o $@ -intel + +test: main_test.bin diff --git a/rom_src/config.asm b/rom_src/config.asm new file mode 100644 index 0000000..f96a854 --- /dev/null +++ b/rom_src/config.asm @@ -0,0 +1,30 @@ +MENU_ENTER_DELAY EQU 40 ; 400ms +MENU_LEAVE_DELAY EQU 2 ; 20ms +MENU_HOLDCHECK_DELAY EQU 7 + +MENU_WIDTH EQU 20 +MENU_HEIGHT EQU MENU_ITEMS+2 + +MENU_HEADER_ATTR EQU #47 +MENU_BODY_ATTR EQU #78 +MENU_SELECT_ATTR EQU #68 + +INPUT_REPEAT EQU 2 +INPUT_REPEAT_FIRST EQU 11 +INPUT_BEEP_DELAY EQU 255 + + + STRUCT CFG_T +_reserv0 DB 0 +_reserv1 DB 0 +timings DB 0 +clock DB 0 +panning DB 1 +plus3 DB 0 +rom48 DB 0 +joystick DB 0 +ram DB 0 +divmmc DB 1 + ENDS + +CFG_DEFAULT CFG_T diff --git a/rom_src/draw.asm b/rom_src/draw.asm new file mode 100644 index 0000000..861f3a6 --- /dev/null +++ b/rom_src/draw.asm @@ -0,0 +1,425 @@ +; IN - B = pixel row (0..191) +; IN - C = character column (0..31) +; OUT - HL = screen address +; OUT - DE = garbage +; OUT - AF = garbage +coords_to_pixel_address: + ld h, 0 + ld l, b ; hl = row + add hl, hl ; hl = row number * 2 + ld de, screen_map ; de = screen map + add hl, de ; de = screen_map + (row * 2) + ld a, (hl) ; implements ld hl, (hl) + inc hl + ld h, (hl) + ld l, a ; hl = address of first pixel in screen map + ld d, 0 + ld e, c ; de = X (character based) + add hl, de ; hl = screen addr + 32 + ret ; return screen_map[pixel_row] + +screen_map: + .defw #4000, #4100, #4200, #4300 + .defw #4400, #4500, #4600, #4700 + .defw #4020, #4120, #4220, #4320 + .defw #4420, #4520, #4620, #4720 + .defw #4040, #4140, #4240, #4340 + .defw #4440, #4540, #4640, #4740 + .defw #4060, #4160, #4260, #4360 + .defw #4460, #4560, #4660, #4760 + .defw #4080, #4180, #4280, #4380 + .defw #4480, #4580, #4680, #4780 + .defw #40A0, #41A0, #42A0, #43A0 + .defw #44A0, #45A0, #46A0, #47A0 + .defw #40C0, #41C0, #42C0, #43C0 + .defw #44C0, #45C0, #46C0, #47C0 + .defw #40E0, #41E0, #42E0, #43E0 + .defw #44E0, #45E0, #46E0, #47E0 + .defw #4800, #4900, #4A00, #4B00 + .defw #4C00, #4D00, #4E00, #4F00 + .defw #4820, #4920, #4A20, #4B20 + .defw #4C20, #4D20, #4E20, #4F20 + .defw #4840, #4940, #4A40, #4B40 + .defw #4C40, #4D40, #4E40, #4F40 + .defw #4860, #4960, #4A60, #4B60 + .defw #4C60, #4D60, #4E60, #4F60 + .defw #4880, #4980, #4A80, #4B80 + .defw #4C80, #4D80, #4E80, #4F80 + .defw #48A0, #49A0, #4AA0, #4BA0 + .defw #4CA0, #4DA0, #4EA0, #4FA0 + .defw #48C0, #49C0, #4AC0, #4BC0 + .defw #4CC0, #4DC0, #4EC0, #4FC0 + .defw #48E0, #49E0, #4AE0, #4BE0 + .defw #4CE0, #4DE0, #4EE0, #4FE0 + .defw #5000, #5100, #5200, #5300 + .defw #5400, #5500, #5600, #5700 + .defw #5020, #5120, #5220, #5320 + .defw #5420, #5520, #5620, #5720 + .defw #5040, #5140, #5240, #5340 + .defw #5440, #5540, #5640, #5740 + .defw #5060, #5160, #5260, #5360 + .defw #5460, #5560, #5660, #5760 + .defw #5080, #5180, #5280, #5380 + .defw #5480, #5580, #5680, #5780 + .defw #50A0, #51A0, #52A0, #53A0 + .defw #54A0, #55A0, #56A0, #57A0 + .defw #50C0, #51C0, #52C0, #53C0 + .defw #54C0, #55C0, #56C0, #57C0 + .defw #50E0, #51E0, #52E0, #53E0 + .defw #54E0, #55E0, #56E0, #57E0 + + +; IN - B = pixel row (0..191) +; IN - C = character column (0..31) +; OUT - HL = screen address +; OUT - AF = garbage +coords_to_attribute_address_pixelrow: + ; attribute address - 010110vv vvvhhhhh + ld a, b ; A = { v4, v3, v2, v1, v0, x, x, x } + rlca ; A = { v2, v1, v0, x, x, x, v4, v3 } + rlca ; ... + jr .do_work +; IN - B = character row (0..23) +; IN - C = character column (0..31) +; OUT - HL = screen address +; OUT - A = garbage +!coords_to_attribute_address: + ; attribute address - 010110vv vvvhhhhh + ld a, b ; A = { 0, 0, 0, v4, v3, v2, v1, v0 } + rrca ; A = { v2, v1, v0, 0, 0, 0, v4, v3 } + rrca ; ... + rrca ; ... +.do_work: + ld h, a ; save A temporary + and a, #E0 ; A = { v2, v1, v0, 0, 0, 0 ,0 ,0 } + or c ; A = { v2, v1, v0, h4, h3, h2, h1, h0 } + ld l, a ; + ld a, h ; restore A = { v2, v1, v0, x, x, x, v4, v3 } + and a, #03 ; A = { 000000, v4, v3 } + or a, #58 ; A = { 010110, v4, v3 } + ld h, a ; HL = attribute address + ret + + +; print one characters at specified coordinate +; IN - A = ascii code +; IN - B = row (0..191) +; IN - C = column (0..31) +; OUT - AF = garbage +; OUT - B = garbage +; OUT - DE = garbage +; OUT - HL = garbage +; OUT - IX = garbage +print_char: + sub 32 ; A = A - 32 (offset of first printable ASCII code) + ld ix, 0 ; IX = character index in font + ld d, 0 ; .. + ld e, a ; .. + add ix, de ; .. + add ix, ix ; ix *= 8 (8 bytes per character in font) + add ix, ix ; ... + add ix, ix ; ... + ld de, font ; ix = &font + character index + add ix, de ; ... + xor a ; A = 0 (row counter) +.loop: + push af + call coords_to_pixel_address ; HL = screen address + ld a, (ix) ; A = pixel data + ld (hl), a ; draw pixel data to screen + pop af ; restore A = row counter + inc b ; row += 1 + inc ix ; next line in character + inc a ; if (++A >= 8) - exit + and a, 7 ; ... + jr nz, .loop ; ... + ret + + +; print null-terminated string +; IN - B - row +; IN - C - column +; IN - HL - string +; OUT - C - last printed column +; OUT - HL - pointer to string 0 byte +; OUT - AF - garbage +; OUT - B = garbage +; OUT - DE - garbage +; OUT - IX = garbage +print_string: + ld a, (hl) ; A = *string + or a ; if (A == 0) - exit + jr z, .return ; ... + push bc + push hl + call print_char + pop hl + pop bc + inc hl ; string++ + inc c ; column++ + jr print_string +.return: + ret + + +; print null-terminated string reverse +; IN - B - row +; IN - C - column +; IN - HL - string +; OUT - C - last printed column +; OUT - HL - pointer to string 0 byte +; OUT - AF - garbage +; OUT - B = garbage +; OUT - DE - garbage +; OUT - IX = garbage +print_string_rev: + ld a, (hl) ; A = *string + or a ; if (A == 0) - exit + jr z, .return ; ... + push bc + push hl + call print_char + pop hl + pop bc + dec hl ; string-- + dec c ; column-- + jr print_string_rev +.return: + ret + + +; IN - B - start row (0..23) +; IN - C - start column (0..31) +; IN - D - rows +; IN - E - columns +; OUT - B - end row +; OUT - D - garbage +; OUT - E - garbage +; OUT - AF - garbage +draw_box: + push bc + push de +.draw_header: + call coords_to_attribute_address ; HL = attribute address + ld a, e ; A = columns +.draw_header_column: + or a ; if (columns == 0) - goto next row + jr z, .draw_body ; ... + ld (hl), MENU_HEADER_ATTR ; set attribute + inc hl ; next column attribute address + dec a ; columns = columns - 1; + jr .draw_header_column + +.draw_body: + inc b ; current_row += 1 + dec d ; rows -= 1 + jr z, .draw_body_end ; if (rows == 0) - exit + call coords_to_attribute_address ; HL = attribute address + ld a, e ; A = columns +.draw_body_column: + or a ; if (columns == 0) - goto next row + jr z, .draw_body ; ... + ld (hl), MENU_BODY_ATTR ; set attribute + inc hl ; next column attribute address + dec a ; columns = columns - 1; + jr .draw_body_column + +.draw_body_end: + pop de + pop bc + push bc + push de + sla b ; current_row = current_row_pixel_address + sla b ; ... + sla b ; ... + sla d ; rows = rows_pixels + sla d ; ... + sla d ; ... + dec d ; rows_pixels -= 1 (fill be filled later by frame) +.fill: + push de + push de + call coords_to_pixel_address + pop de +.fill_line: + ld (hl), 0 ; clear pixels + inc hl ; column++ + dec e ; columns-- + jr nz, .fill_line ; if (columns == 0) - goto next row + pop de + inc b ; row++ + dec d ; rows-- + jr nz, .fill ; if (rows == 0) - exit + +.fill_end: + pop de + pop bc + inc b ; current_row += 1 + sla b ; current_row = current_row_pixel_address + sla b ; ... + sla b ; ... + dec d ; rows -= 1 + sla d ; rows = rows_pixels + sla d ; ... + sla d ; ... +.draw_frame_lr: + push de + call coords_to_pixel_address ; HL = pixel_address + pop de + push de + ld (hl), #80 ; draw left frame line + ld d, 0 + add hl, de ; pixel_address += columns + dec hl + ld (hl), #01 ; draw right frame line + pop de + inc b ; current_row_pixel += 1 + dec d ; rows -= 1 + jr nz, .draw_frame_lr ; if (rows == 0) - exit + +.draw_frame_low: + ld (hl), #ff ; draw low frame line starting from right corner + dec hl ; pixel_address -= one column + dec e ; columns -= 1 + jr nz, .draw_frame_low + +.return: + ret + + +; IN - B - start row (0..191) +; IN - C - start column (0..31) +; IN - E - columns +; IN - HL - menu addr +; OUT - AF - garbage +; OUT - BC - garbage +; OUT - DE - garbage +; OUT - HL - garbage +; OUT - IX - garbage +draw_menu: + ld a, c ; column_to_print_value = start_column + columns - 3 + add a, e ; ... + sub 3 ; ... + ld e, a ; ... + push hl ; IX = menu first item addr + pop ix ; ... +.line_loop: + ld l, (ix+0) ; HL = menu_t.textaddr + ld h, (ix+1) ; ... + ld a, h ; if (HL == 0) - exit + or l ; ... + jr z, .return ; ... + push bc + push de + push ix + call print_string ; print menu item text + pop ix + pop de + pop bc +.print_val: + push de ; will be restored in .skip_val + ld l, (ix+2) ; HL = menu_t.value_cb_addr + ld h, (ix+3) ; ... + ld a, h ; if (HL == 0) - skip value print + or l ; ... + jr z, .skip_val ; ... + push ix + push bc + call .value_cb ; HL = value text addr. AF, BC, IX may be changed + pop bc + dec sp + dec sp + ld c, e ; column = column_to_print_value + call print_string_rev ; print value text + pop bc + pop ix +.skip_val: + ld a, b ; row += 8 + add a, 8 ; ... + ld b, a ; ... + ld de, MENU_T ; IX = IX + sizeof(menu_t) + add ix, de ; ... + pop de ; restore E - columns + jr .line_loop +.return: + ret + +.value_cb: + jp (hl) + + +; IN - B - row (0..24) +; IN - C - start column (0..31) +; IN - D - attribute byte to use +; IN - E - columns +; OUT - AF - garbage +; OUT - B - garbage +; OUT - E - garbage +; OUT - HL - garbage +draw_menu_item_line: + call coords_to_attribute_address ; HL = attribute address +.loop: + ld a, e ; if (columns == 0) - exit + or a ; ... + jr z, .return ; ... + ld (hl), d ; write attribute + inc hl ; column++ + dec e ; columns-- + jr .loop +.return: + ret + + +; IN - B - start row (0..191) +; IN - C - start column (0..31) +; IN - E - color cycle (0..4) +; OUT - AF - garbage +; OUT - BC - garbage +; OUT - DE - garbage +; OUT - HL - garbage +; OUT - IX - garbage +draw_logo: + call coords_to_attribute_address_pixelrow ; HL = attribute address + ld ix, logo_colors ; IX = logo_colors[color_cycle] + ld d, 0 ; ... + add ix, de ; ... +.set_colors: + ld a, (ix+0) + and #c7 + ld (hl), a + inc hl + ld a, (ix+1) + ld (hl), a + inc hl + ld a, (ix+2) + ld (hl), a + inc hl + ld a, (ix+3) + ld (hl), a + inc hl + ld a, (ix+4) + and #f8 + ld (hl), a + inc hl +.set_pixels: + ld ix, logo + ld e, 8 ; rows +.set_pixels_loop_row: + ld d, 5 ; columns + push de + call coords_to_pixel_address ; HL = pixel address + pop de + inc b ; row++ + ld a, (ix) ; A = logo_pixel_data[row] + inc ix +.set_pixels_loop_column: + ld (hl), a ; update screen + inc hl + dec d ; columns-- + jr nz, .set_pixels_loop_column + dec e ; rows-- + jr nz, .set_pixels_loop_row + ret + +logo: DB #00, #01, #03, #07, #0F, #1F, #3F, #7F +logo_colors: DB #5A, #56, #74, #65, #6B, #5A, #56, #74, #65 diff --git a/rom_src/font.asm b/rom_src/font.asm new file mode 100644 index 0000000..c3390e5 --- /dev/null +++ b/rom_src/font.asm @@ -0,0 +1,961 @@ +font: + +font_space: + DG -------- + DG -------- + DG -------- + DG -------- + DG -------- + DG -------- + DG -------- + DG -------- + +font_exclamation_mark: + DG -------- + DG ---#---- + DG ---#---- + DG ---#---- + DG ---#---- + DG -------- + DG ---#---- + DG -------- + +font_quotation_mark: + DG -------- + DG --#--#-- + DG --#--#-- + DG -------- + DG -------- + DG -------- + DG -------- + DG -------- + +font_number_sign: + DG -------- + DG --#--#-- + DG -######- + DG --#--#-- + DG --#--#-- + DG -######- + DG --#--#-- + DG -------- + +font_dollar_sign: + DG -------- + DG ---#---- + DG -#####-- + DG -#-#---- + DG -#####-- + DG ---#-#-- + DG -#####-- + DG ---#---- + +font_percent_sign: + DG -------- + DG -##---#- + DG -##--#-- + DG ----#--- + DG ---#---- + DG --#--##- + DG -#---##- + DG -------- + +font_ampersand: + DG -------- + DG ---#---- + DG --#-#--- + DG ---#---- + DG --#-#-#- + DG -#---#-- + DG --###-#- + DG -------- + +font_apostrophe: + DG -------- + DG ----#--- + DG ---#---- + DG -------- + DG -------- + DG -------- + DG -------- + DG -------- + +font_left_parenthesis: + DG -------- + DG ----#--- + DG ---#---- + DG ---#---- + DG ---#---- + DG ---#---- + DG ----#--- + DG -------- + +font_right_parenthesis: + DG -------- + DG ---#---- + DG ----#--- + DG ----#--- + DG ----#--- + DG ----#--- + DG ---#---- + DG -------- + +font_asterisk: + DG -------- + DG --#-#--- + DG ---#---- + DG -#####-- + DG ---#---- + DG --#-#--- + DG -------- + DG -------- + +font_plus_sign: + DG -------- + DG -------- + DG ---#---- + DG ---#---- + DG -#####-- + DG ---#---- + DG ---#---- + DG -------- + +font_comma: + DG -------- + DG -------- + DG -------- + DG -------- + DG -------- + DG ----#--- + DG ----#--- + DG ---#---- + +font_hyphen_minus: + DG -------- + DG -------- + DG -------- + DG -#####-- + DG -------- + DG -------- + DG -------- + DG -------- + +font_full_stop: + DG -------- + DG -------- + DG -------- + DG -------- + DG -------- + DG ---##--- + DG ---##--- + DG -------- + +font_solidus: + DG -------- + DG ------#- + DG -----#-- + DG ----#--- + DG ---#---- + DG --#----- + DG -#------ + DG -------- + +font_digit_zero: + DG -------- + DG --####-- + DG -#---##- + DG -#--#-#- + DG -#-#--#- + DG -##---#- + DG --####-- + DG -------- + +font_digit_one: + DG -------- + DG --##---- + DG -#-#---- + DG ---#---- + DG ---#---- + DG ---#---- + DG -#####-- + DG -------- + +font_digit_two: + DG -------- + DG --####-- + DG -#----#- + DG ------#- + DG --####-- + DG -#------ + DG -######- + DG -------- + +font_digit_three: + DG -------- + DG --####-- + DG -#----#- + DG ----##-- + DG ------#- + DG -#----#- + DG --####-- + DG -------- + +font_digit_four: + DG -------- + DG ----#--- + DG ---##--- + DG --#-#--- + DG -#--#--- + DG -######- + DG ----#--- + DG -------- + +font_digit_five: + DG -------- + DG -######- + DG -#------ + DG -#####-- + DG ------#- + DG -#----#- + DG --####-- + DG -------- + +font_digit_six: + DG -------- + DG --####-- + DG -#------ + DG -#####-- + DG -#----#- + DG -#----#- + DG --####-- + DG -------- + +font_digit_seven: + DG -------- + DG -######- + DG ------#- + DG -----#-- + DG ----#--- + DG ---#---- + DG ---#---- + DG -------- + +font_digit_eight: + DG -------- + DG --####-- + DG -#----#- + DG --####-- + DG -#----#- + DG -#----#- + DG --####-- + DG -------- + +font_digit_nine: + DG -------- + DG --####-- + DG -#----#- + DG -#----#- + DG --#####- + DG ------#- + DG --####-- + DG -------- + +font_colon: + DG -------- + DG -------- + DG ---#---- + DG -------- + DG -------- + DG ---#---- + DG -------- + DG -------- + +font_semicolon: + DG -------- + DG ----#--- + DG -------- + DG -------- + DG ----#--- + DG ----#--- + DG ---#---- + DG -------- + +font_less_than_sign: + DG -------- + DG ----#--- + DG ---#---- + DG --#----- + DG ---#---- + DG ----#--- + DG -------- + DG -------- + +font_equals_sign: + DG -------- + DG -------- + DG -#####-- + DG -------- + DG -#####-- + DG -------- + DG -------- + DG -------- + +font_greater_than_sign: + DG -------- + DG --#----- + DG ---#---- + DG ----#--- + DG ---#---- + DG --#----- + DG -------- + DG -------- + +font_question_mark: + DG -------- + DG --####-- + DG -#----#- + DG -----#-- + DG ----#--- + DG -------- + DG ----#--- + DG -------- + +font_commercial_at: + DG -------- + DG --####-- + DG -#--#-#- + DG -#-#-##- + DG -#-####- + DG -#------ + DG --####-- + DG -------- + +font_latin_capital_letter_a: + DG -------- + DG --####-- + DG -#----#- + DG -#----#- + DG -######- + DG -#----#- + DG -#----#- + DG -------- + +font_latin_capital_letter_b: + DG -------- + DG -#####-- + DG -#----#- + DG -#####-- + DG -#----#- + DG -#----#- + DG -#####-- + DG -------- + +font_latin_capital_letter_c: + DG -------- + DG --####-- + DG -#----#- + DG -#------ + DG -#------ + DG -#----#- + DG --####-- + DG -------- + +font_latin_capital_letter_d: + DG -------- + DG -####--- + DG -#---#-- + DG -#----#- + DG -#----#- + DG -#---#-- + DG -####--- + DG -------- + +font_latin_capital_letter_e: + DG -------- + DG -######- + DG -#------ + DG -#####-- + DG -#------ + DG -#------ + DG -######- + DG -------- + +font_latin_capital_letter_f: + DG -------- + DG -######- + DG -#------ + DG -#####-- + DG -#------ + DG -#------ + DG -#------ + DG -------- + +font_latin_capital_letter_g: + DG -------- + DG --####-- + DG -#----#- + DG -#------ + DG -#--###- + DG -#----#- + DG --####-- + DG -------- + +font_latin_capital_letter_h: + DG -------- + DG -#----#- + DG -#----#- + DG -######- + DG -#----#- + DG -#----#- + DG -#----#- + DG -------- + +font_latin_capital_letter_i: + DG -------- + DG -#####-- + DG ---#---- + DG ---#---- + DG ---#---- + DG ---#---- + DG -#####-- + DG -------- + +font_latin_capital_letter_j: + DG -------- + DG ------#- + DG ------#- + DG ------#- + DG -#----#- + DG -#----#- + DG --####-- + DG -------- + +font_latin_capital_letter_k: + DG -------- + DG -#---#-- + DG -#--#--- + DG -###---- + DG -#--#--- + DG -#---#-- + DG -#----#- + DG -------- + +font_latin_capital_letter_l: + DG -------- + DG -#------ + DG -#------ + DG -#------ + DG -#------ + DG -#------ + DG -######- + DG -------- + +font_latin_capital_letter_m: + DG -------- + DG -#----#- + DG -##--##- + DG -#-##-#- + DG -#----#- + DG -#----#- + DG -#----#- + DG -------- + +font_latin_capital_letter_n: + DG -------- + DG -#----#- + DG -##---#- + DG -#-#--#- + DG -#--#-#- + DG -#---##- + DG -#----#- + DG -------- + +font_latin_capital_letter_o: + DG -------- + DG --####-- + DG -#----#- + DG -#----#- + DG -#----#- + DG -#----#- + DG --####-- + DG -------- + +font_latin_capital_letter_p: + DG -------- + DG -#####-- + DG -#----#- + DG -#----#- + DG -#####-- + DG -#------ + DG -#------ + DG -------- + +font_latin_capital_letter_q: + DG -------- + DG --####-- + DG -#----#- + DG -#----#- + DG -#-#--#- + DG -#--#-#- + DG --####-- + DG -------- + +font_latin_capital_letter_r: + DG -------- + DG -#####-- + DG -#----#- + DG -#----#- + DG -#####-- + DG -#---#-- + DG -#----#- + DG -------- + +font_latin_capital_letter_s: + DG -------- + DG --####-- + DG -#------ + DG --####-- + DG ------#- + DG -#----#- + DG --####-- + DG -------- + +font_latin_capital_letter_t: + DG -------- + DG #######- + DG ---#---- + DG ---#---- + DG ---#---- + DG ---#---- + DG ---#---- + DG -------- + +font_latin_capital_letter_u: + DG -------- + DG -#----#- + DG -#----#- + DG -#----#- + DG -#----#- + DG -#----#- + DG --####-- + DG -------- + +font_latin_capital_letter_v: + DG -------- + DG -#----#- + DG -#----#- + DG -#----#- + DG -#----#- + DG --#--#-- + DG ---##--- + DG -------- + +font_latin_capital_letter_w: + DG -------- + DG -#----#- + DG -#----#- + DG -#----#- + DG -#----#- + DG -#-##-#- + DG --#--#-- + DG -------- + +font_latin_capital_letter_x: + DG -------- + DG -#----#- + DG --#--#-- + DG ---##--- + DG ---##--- + DG --#--#-- + DG -#----#- + DG -------- + +font_latin_capital_letter_y: + DG -------- + DG #-----#- + DG -#---#-- + DG --#-#--- + DG ---#---- + DG ---#---- + DG ---#---- + DG -------- + +font_latin_capital_letter_z: + DG -------- + DG -######- + DG -----#-- + DG ----#--- + DG ---#---- + DG --#----- + DG -######- + DG -------- + +font_left_square_bracket: + DG -------- + DG --###--- + DG --#----- + DG --#----- + DG --#----- + DG --#----- + DG --###--- + DG -------- + +font_reverse_solidus: + DG -------- + DG -#------ + DG --#----- + DG ---#---- + DG ----#--- + DG -----#-- + DG ------#- + DG -------- + +font_right_square_bracket: + DG -------- + DG --###--- + DG ----#--- + DG ----#--- + DG ----#--- + DG ----#--- + DG --###--- + DG -------- + +font_circumflex_accent: + DG -------- + DG ---#---- + DG --###--- + DG -#-#-#-- + DG ---#---- + DG ---#---- + DG ---#---- + DG -------- + +font_low_line: + DG -------- + DG -------- + DG -------- + DG -------- + DG -------- + DG -------- + DG -------- + DG ######## + +font_grave_accent: + DG -------- + DG ---###-- + DG --#---#- + DG -####--- + DG --#----- + DG --#----- + DG -######- + DG -------- + +font_latin_small_letter_a: + DG -------- + DG -------- + DG --###--- + DG -----#-- + DG --####-- + DG -#---#-- + DG --####-- + DG -------- + +font_latin_small_letter_b: + DG -#------ + DG -#------ + DG -####--- + DG -#---#-- + DG -#---#-- + DG -#---#-- + DG -####--- + DG -------- + +font_latin_small_letter_c: + DG -------- + DG -------- + DG --###--- + DG -#------ + DG -#------ + DG -#------ + DG --###--- + DG -------- + +font_latin_small_letter_d: + DG -----#-- + DG -----#-- + DG --####-- + DG -#---#-- + DG -#---#-- + DG -#---#-- + DG --####-- + DG -------- + +font_latin_small_letter_e: + DG -------- + DG -------- + DG --###--- + DG -#---#-- + DG -####--- + DG -#------ + DG --####-- + DG -------- + +font_latin_small_letter_f: + DG -------- + DG ---##--- + DG --#----- + DG -###---- + DG --#----- + DG --#----- + DG --#----- + DG -------- + +font_latin_small_letter_g: + DG -------- + DG -------- + DG --####-- + DG -#---#-- + DG -#---#-- + DG --####-- + DG -----#-- + DG --###--- + +font_latin_small_letter_h: + DG -#------ + DG -#------ + DG -####--- + DG -#---#-- + DG -#---#-- + DG -#---#-- + DG -#---#-- + DG -------- + +font_latin_small_letter_i: + DG -------- + DG ---#---- + DG -------- + DG --##---- + DG ---#---- + DG ---#---- + DG --###--- + DG -------- + +font_latin_small_letter_j: + DG -----#-- + DG -------- + DG -----#-- + DG -----#-- + DG -----#-- + DG --#--#-- + DG ---##--- + DG -------- + +font_latin_small_letter_k: + DG -------- + DG --#----- + DG --#-#--- + DG --##---- + DG --##---- + DG --#-#--- + DG --#--#-- + DG -------- + +font_latin_small_letter_l: + DG -------- + DG ---#---- + DG ---#---- + DG ---#---- + DG ---#---- + DG ---#---- + DG ----##-- + DG -------- + +font_latin_small_letter_m: + DG -------- + DG -------- + DG -##-#--- + DG -#-#-#-- + DG -#-#-#-- + DG -#-#-#-- + DG -#-#-#-- + DG -------- + +font_latin_small_letter_n: + DG -------- + DG -------- + DG -####--- + DG -#---#-- + DG -#---#-- + DG -#---#-- + DG -#---#-- + DG -------- + +font_latin_small_letter_o: + DG -------- + DG -------- + DG --###--- + DG -#---#-- + DG -#---#-- + DG -#---#-- + DG --###--- + DG -------- + +font_latin_small_letter_p: + DG -------- + DG -------- + DG -####--- + DG -#---#-- + DG -#---#-- + DG -####--- + DG -#------ + DG -#------ + +font_latin_small_letter_q: + DG -------- + DG -------- + DG --####-- + DG -#---#-- + DG -#---#-- + DG --####-- + DG -----#-- + DG -----##- + +font_latin_small_letter_r: + DG -------- + DG -------- + DG --###--- + DG -#------ + DG -#------ + DG -#------ + DG -#------ + DG -------- + +font_latin_small_letter_s: + DG -------- + DG -------- + DG --###--- + DG -#------ + DG --###--- + DG -----#-- + DG -####--- + DG -------- + +font_latin_small_letter_t: + DG -------- + DG ---#---- + DG --###--- + DG ---#---- + DG ---#---- + DG ---#---- + DG ----##-- + DG -------- + +font_latin_small_letter_u: + DG -------- + DG -------- + DG -#---#-- + DG -#---#-- + DG -#---#-- + DG -#---#-- + DG --###--- + DG -------- + +font_latin_small_letter_v: + DG -------- + DG -------- + DG -#---#-- + DG -#---#-- + DG --#-#--- + DG --#-#--- + DG ---#---- + DG -------- + +font_latin_small_letter_w: + DG -------- + DG -------- + DG -#-#-#-- + DG -#-#-#-- + DG -#-#-#-- + DG -#-#-#-- + DG --#-#--- + DG -------- + +font_latin_small_letter_x: + DG -------- + DG -------- + DG -#---#-- + DG --#-#--- + DG ---#---- + DG --#-#--- + DG -#---#-- + DG -------- + +font_latin_small_letter_y: + DG -------- + DG -------- + DG -#---#-- + DG -#---#-- + DG -#---#-- + DG --####-- + DG -----#-- + DG --###--- + +font_latin_small_letter_z: + DG -------- + DG -------- + DG -#####-- + DG ----#--- + DG ---#---- + DG --#----- + DG -#####-- + DG -------- + +font_left_curly_bracket: + DG ---###-- + DG ---#---- + DG ---#---- + DG -##----- + DG ---#---- + DG ---#---- + DG ---###-- + DG -------- + +font_vertical_line: + DG ---#---- + DG ---#---- + DG ---#---- + DG ---#---- + DG ---#---- + DG ---#---- + DG ---#---- + DG ---#---- + +font_right_curly_bracket: + DG -###---- + DG ---#---- + DG ---#---- + DG ----##-- + DG ---#---- + DG ---#---- + DG -###---- + DG -------- + +font_tilde: + DG -------- + DG -------- + DG -------- + DG ---#-#-- + DG --#-#--- + DG -------- + DG -------- + DG -------- + +font_delete: + DG --####-- + DG -#----#- + DG #--##--# + DG #-#----# + DG #-#----# + DG #--##--# + DG -#----#- + DG --####-- diff --git a/rom_src/input.asm b/rom_src/input.asm new file mode 100644 index 0000000..ef15fdd --- /dev/null +++ b/rom_src/input.asm @@ -0,0 +1,183 @@ +; OUT - A - 0 - no key, 32 - exit, 16 - action, 8 - up, 4 - down, 2 - left, 1 - right +input_key_get: + ld a, (var_input_key) + ret + + +; OUT - B - {0, action, up, down, left, right} +; OUT - AF - garbage +; OUT - C - garbage +input_read: + ld b, 0 +.kempston: + ld a, #ff ; read kempston + in a, (#1f) ; ... + bit 7, a ; detect presence by 7th bit + jr nz, .enter ; ... + and #1f ; mask useless bits + ld b, a ; ... +.enter: + ld a, #bf ; read keys + in a, (#fe) ; ... + bit 0, a ; handle Enter (ACTION) key + jr nz, .qwert ; ... + set 4, b ; ... + ret +.qwert: + ld a, #fb ; read keys + in a, (#fe) ; ... + bit 0, a ; handle Q (UP) key + jr nz, .asdfg ; ... + set 3, b ; ... + ret +.asdfg: + ld a, #fd ; read keys + in a, (#fe) ; ... + bit 0, a ; handle A (DOWN) key + jr nz, .poiuy ; ... + set 2, b ; ... + ret +.poiuy: + ld a, #df ; read keys + in a, (#fe) ; ... + bit 0, a ; handle P (RIGHT) key + jr nz, .poiuy1 ; ... + set 0, b ; ... + ret +.poiuy1: + bit 1, a ; handle O (LEFT) key + jr nz, .cszxcv ; ... + set 1, b ; ... + ret +.cszxcv: + ld a, #fe ; read keys + in a, (#fe) ; ... + bit 0, a ; handle CS key. if pressed - assume cursor key. else - assume sinclair joystick + jr z, .space_break ; ... +.space: + ld a, #7f ; read keys + in a, (#fe) ; ... + bit 0, a ; handle Space (ACTION) key + jr nz, .sinclair_09876 ; ... + set 4, b ; ... + ret +.sinclair_09876: + ld a, #ef ; read keys + in a, (#fe) ; ... + bit 0, a ; handle 0 (ACTION) key + jr nz, .sinclair_09876_9 ; ... + set 4, b ; ... + ret +.sinclair_09876_9: + bit 1, a ; handle 9 (UP) key + jr nz, .sinclair_09876_8 ; ... + set 3, b ; ... + ret +.sinclair_09876_8: + bit 2, a ; handle 8 (DOWN) key + jr nz, .sinclair_09876_7 ; ... + set 2, b ; ... + ret +.sinclair_09876_7: + bit 3, a ; handle 7 (RIGHT) key + jr nz, .sinclair_09876_6 ; ... + set 0, b ; ... + ret +.sinclair_09876_6: + bit 4, a ; handle 6 (LEFT) key + jr nz, .return ; ... + set 1, b ; ... + ret +.space_break: + ld a, #7f ; read keys + in a, (#fe) ; ... + bit 0, a ; handle Space (EXIT) key + jr nz, .cursor_09876_7 ; ... + set 5, b ; ... + ret +.cursor_09876_7: + ld a, #ef ; read keys + in a, (#fe) ; ... + bit 3, a ; handle 7 (UP) key + jr nz, .cursor_09876_6 ; ... + set 3, b ; ... + ret +.cursor_09876_6: + bit 4, a ; handle 6 (DOWN) key + jr nz, .cursor_09876_8 ; ... + set 2, b ; ... + ret +.cursor_09876_8: + bit 2, a ; handle 8 (RIGHT) key + jr nz, .cursor_12345_5 ; ... + set 0, b ; ... + ret +.cursor_12345_5: + ld a, #f7 ; read keys + in a, (#fe) ; ... + bit 4, a ; handle 5 (LEFT) key + jr nz, .return ; ... + set 1, b ; ... + ret +.return: + ret + + +; IN - A - current pressed key +; OUT - AF - garbage +; OUT - BC - garbage +input_beep: + or a + jr z, .return + IFDEF TEST_BUILD + ld a, #10 ; blink border + out (#fe), a ; ... + ENDIF + xor a ; blink border + ld bc, #01ff ; ... + out (c), a ; ... + ld b, INPUT_BEEP_DELAY +.loop: + djnz .loop + ld a, 1 ; blink border back + ld bc, #01ff ; ... + out (c), a ; ... +.return: + ret + + +; OUT - B - current pressed key mask +; OUT - AF - garbage +; OUT - C - garbage +input_process: + call input_read ; read keys + ld a, (var_input_key_last) ; + cp b ; if (current_pressed_key == last_pressed_key) {input_key = current_pressed_key; timer = X} + jr z, .repeat ; ... + ld a, b ; + ld (var_input_key), a ; input_key = current_pressed_key + ld (var_input_key_last), a ; last_pressed_ley = current_pressed_key + call input_beep + ld a, INPUT_REPEAT_FIRST ; timer = INPUT_REPEAT_FIRST + ld (var_input_key_hold_timer), a ; ... + ret +.repeat: + ld a, (var_input_key_hold_timer) ; ... + dec a ; timer-- + jr nz, .repeat_wait ; if (timer == 0) input_key = current_pressed_key + ld a, (var_input_key_last) ; ... + ld (var_input_key), a ; ... + call input_beep + ld a, INPUT_REPEAT ; timer = INPUT_REPEAT + ld (var_input_key_hold_timer), a ; ... + ret +.repeat_wait: + ld (var_input_key_hold_timer), a ; timer-- + xor a ; input_key = none + ld (var_input_key), a ; ... + ret + + +;var_input_key: DB 0 +;var_input_key_last: DB 0 +;var_input_key_hold_timer: DB 0 diff --git a/rom_src/main.asm b/rom_src/main.asm index 99c68eb..74e699f 100644 --- a/rom_src/main.asm +++ b/rom_src/main.asm @@ -1,16 +1,21 @@ -; Sizif-512 Service ROM. -; Running while magic (NMI) button hold and changes CPLD configuration register by keypresses. -; If no keypress was registered - jump to default NMI handler. Otherwise - exit NMI. DEVICE ZXSPECTRUM48 - OPT --syntax=m + OPT --syntax=F + +app_begin: +; Startup handler + ORG #0000 + jp startup_handler ; NMI handler ORG #0066 - jp nmi_enter + jp nmi_handler ; INT IM1 handler ORG #0038 - ld hl, #0038 ; set jump address for exit_nmi routine + push bc + ld bc, #0038 + ld (var_int_vector), bc + pop bc ret ; INT IM2 handler @@ -18,296 +23,374 @@ ret ; INT IM2 vector table - ORG #0F00 + ORG #0600 .257 db #01 ; by Z80 user manual int vector is I * 256 + (D & 0xFE) ; but by other references and by T80/A-Z80 implementation int vector is I * 256 + D ; so we just play safe and use symmetric int handler address and vector table with one extra byte -; Main program -nmi_enter: - ld (Saved_sp_value), sp + +startup_handler: + ld ix, #5800 ; draw 4 rygb boxes on left top corner to indicate boot + ld (ix+0), #D2 ; r + ld (ix+1), #F6 ; y + ld (ix+2), #E4 ; g + ld (ix+3), #C9 ; b + call init_variables + call init_cpld + ld hl, 0 + jp exit_with_jp + + +nmi_handler: + ld (var_sp_reg), sp ld sp, Stack_top push af push hl - ld a, #01 ; show magic border - out (#ff), a ; ... - xor a ; reset variables to initial state - ld (Magic_leave_cnt), a ; ... - ld (Key_was_pressed_flag), a ; ... - ld (Reset_flag), a ; ... - -loop: - call key_checker - call check_magic_hold ; return A - or a ; check leave flag - jp nz, exit_nmi ; yes? - jr loop - -; check all functional keys and change zx configuration depending on pressed keys -; input parameters: none -; output parameters: none -key_checker: - push af -key_1: ; timings <= pentagon - ld a, #f7 ; read 0-5 keys - in a, (#fe) ; ... - bit 0, a - jr nz, key_2 - ld a, #20 - out (#ff), a - jp key_checker_pressed -key_2: ; timings <= 128 - bit 1, a - jr nz, key_3 - ld a, #21 - out (#ff), a - jp key_checker_pressed -key_3: ; turbo <= 48 - bit 2, a - jr nz, key_4 - ld a, #23 - out (#ff), a - jp key_checker_pressed -key_4: ; turbo <= none - bit 3, a - jr nz, key_5 - ld a, #30 - out (#ff), a - jp key_checker_pressed -key_5: ; turbo <= 7 - bit 4, a - jr nz, key_6 - ld a, #31 - out (#ff), a - jp key_checker_pressed -key_6: ; turbo <= 14 - ld a, #ef ; read 6-0 keys - in a, (#fe) ; ... - bit 4, a - jr nz, key_7 - ld a, #33 - out (#ff), a - jp key_checker_pressed -key_7: ; ay_abc <= 1 - bit 3, a - jr nz, key_8 - ld a, #41 - out (#ff), a - jp key_checker_pressed -key_8: ; ay_abc <= 0 - bit 2, a - jr nz, key_9 - ld a, #40 - out (#ff), a - jp key_checker_pressed -key_9: ; ay_mono <= 1 - bit 1, a - jr nz, key_U - ld a, #42 - out (#ff), a - jp key_checker_pressed -key_U: ; joystick_sinclair <= 0 - ld a, #df ; read Y-P keys - in a, (#fe) ; ... - bit 3, a - jr nz, key_I - ld a, #70 - out (#ff), a - jp key_checker_pressed -key_I: ; joystick_sinclair <= 1 - bit 2, a - jr nz, key_O - ld a, #71 - out (#ff), a - jp key_checker_pressed -key_O: ; extlock <= 0 - bit 1, a - jr nz, key_P - ld a, #10 - out (#ff), a - jp key_checker_pressed -key_P: ; extlock <= 1 - bit 0, a - jr nz, key_Q - ld a, #11 - out (#ff), a - jp key_checker_pressed -key_Q: ; rom_alt48 <= 0 - ld a, #fb ; read Q-T keys - in a, (#fe) ; ... - bit 0, a - jr nz, key_W - ld a, #60 - out (#ff), a - jp key_checker_pressed -key_W: ; rom_alt48 <= 1 - bit 1, a - jr nz, key_E - ld a, #61 - out (#ff), a - jp key_checker_pressed -key_E: ; rom_plus3 <= 0 - bit 2, a - jr nz, key_R - ld a, #50 - out (#ff), a - jp key_checker_pressed -key_R: ; rom_plus3 <= 1 - bit 3, a - jr nz, Key_Space - ld a, #51 - out (#ff), a - jp key_checker_pressed -Key_Space: ; jump to #00 on exit - ld a, #7f ; read B-Space keys - in a, (#fe) ; ... - bit 0, a - jr nz, key_checker_done - ld a, #01 - ld (Reset_flag), a - jp key_checker_pressed -key_checker_pressed: - ld a, #01 - ld (Key_was_pressed_flag), a - call beep -key_checker_done: - pop af - ret - -; check magic keys is still holding. if no - debounce and set leave flag then -; input parameters: none -; output parameters: A != 0 - leave, A == 0 - do not leave -check_magic_hold: - push af - ld a, #ff ; read magic key state in bit 7 of #FE port - in a, (#fe) ; ... - bit 7, a ; check key is hold - ld a, #00 - jr z, check_magic_hold_l1 ; yes? - ld a, (Magic_leave_cnt) - inc a - jp nz, check_magic_hold_l1 ; check is counter overflow? - pop af ; yes? set A=1 and exit - ld a, #01 - ret -check_magic_hold_l1: - ld (Magic_leave_cnt), a - pop af - xor a ; counter didn't overflow - ret - -; do beep and flash border -; input parameters: none -; output parameters: none -beep: - push af push bc - push de - ld de, #10 ; set total length -beep_length: - ld bc, #30 ; set beeper toggling period -beep_period0: - dec bc ; check it is time to toggle beeper - ld a, b ; ... - or c ; ... - jr nz, beep_period0 ; no? - ld a, #00 ; yes? doing beep - out (#ff), a ; ... - ld bc, #20 ; set beeper toggling period -beep_period1: - dec bc ; check it is time to toggle beeper - ld a, b ; ... - or c ; ... - jr nz, beep_period1 ; no? - ld a, #01 ; yes? doing beep - out (#ff), a ; ... - dec de ; check whether time is over - ld a, d ; ... - or e ; ... - jr nz, beep_length ; no? - pop de - pop bc - pop af - ret - -; read non-magic im2 table and returns im2 handler address -; input parameters: A - im2 table address hight byte -; output parameters: HL - handler address -get_im2_handler: - push af - ld h, a ; hl = im2 table address - ld l, #ff ; hl = im2 table address - ld a, #2a ; 2a - ld hl, (nn) - ld (Readout_vector-2), a ; ... - ld (Readout_vector-1), hl ; hl was set earlier by im2 table address - ld a, #c9 ; c9 - ret - ld (Readout_vector+1), a ; ... - call Readout_vector-2 ; hl contains default im2 handler address now - pop af - ret - -exit_nmi: - xor a ; disable border + ld a, #01 ; show magic border out (#ff), a ; ... - ld a, (Reset_flag) ; should we jump to #0000 at exit? - or a ; ... - ld hl, #0000 ; ... - jp nz, exit_with_jp ; yes? - ld a, (Key_was_pressed_flag) ; was key pressed? - or a ; ... - ld hl, #0066 ; ... - jp z, exit_with_jp ; no? jump to default nmi handler - ld a, i ; save interrupt table address - push af - call get_im2_handler ; hl = im2 handler address - ld a, #0f ; set our interrupt table address (#0Fxx) - ld i, a ; ... - ei ; determine im1 or im2 - halt ; ... also sync execution flow with int for safety - pop af - ld i, a ; restore default interrupt table address - jp po, exit_with_ret ; check int was enabled by default. no? just do retn + xor a + ld (var_magic_enter_cnt), a + ld (var_magic_leave_cnt), a +.loop: + call check_magic_delay + call check_magic_hold ; A == 1 if we are entering menu, A == 2 if we are leaving to... + bit 0, a ; ...default nmi handler, A == 0 otherwise + jp nz, main ; ... + bit 1, a ; ... + jr z, .loop ; ... +.leave: + xor a ; disable border + ld bc, #01ff ; ... + out (c), a ; ... + ld hl, #0066 ; jump to default nmi handler + jp exit_with_jp ; ... + +; IN - HL - jump address exit_with_jp: - ld (Exit_vector-1), hl ; hl argument is jump address + ld (Exit_vector-1), hl ld a, #c3 ; c3 - jp ld (Exit_vector-2), a + pop bc pop hl pop af - ld sp, (Saved_sp_value) + ld sp, (var_sp_reg) jp Exit_vector-2 exit_with_ret: ld hl, #45ed ; ed45 - retn; reverse bytes order ld (Exit_vector-1), hl + pop bc pop hl pop af - ld sp, (Saved_sp_value) + ld sp, (var_sp_reg) jp Exit_vector-1 + +init_variables: + ld hl, cfg_initialized ; if (cfg_initialized == "magic word") {restore cfg} else {default cfg} + ld a, #B1 ; ... + cpi ; ... hl++ + jr nz, .init_default ; ... + ld a, #5B ; ... + cpi ; ... hl++ + jr nz, .init_default ; ... + ld a, #00 ; ... + cpi ; ... hl++ + jr nz, .init_default ; ... + ld a, #B5 ; ... + cpi ; ... hl++ + jr nz, .init_default ; ... + jr .restore ; ... +.init_default: + ld bc, CFG_T ; cfg_saved = cfg_default + ld de, cfg_saved ; ... + ld hl, CFG_DEFAULT ; ... + ldir ; ... +.restore: + ld bc, CFG_T ; cfg = cfg_saved + ld de, cfg ; ... + ld hl, cfg_saved ; ... + ldir ; ... +.save_magic: + ld hl, #5BB1 ; cfg_initialized = "magic word" + ld (cfg_initialized+0), hl ; ... + ld hl, #B500 ; ... + ld (cfg_initialized+2), hl ; ... + ret + +save_variables: + ld bc, CFG_T ; cfg_saved = cfg + ld de, cfg_saved ; ... + ld hl, cfg ; ... + ldir ; ... + ret + + +init_cpld: + ld a, (cfg.ram) ; if ram == 48K - run basic48 + cp 1 ; ... + jr nz, .do_load ; ... + ld a, #10 ; ... + ld bc, #7ffd ; ... + out (c), a ; ... +.do_load: + ld b, CFG_T ; B = registers count + ld c, #ff ; + ld hl, cfg+CFG_T-1 ; HL = &cfg[registers count-1] + otdr ; do { b--; out(bc, *hl); hl--; } while(b) + ret + + +; OUT - A = 1 if we are entering menu, A = 2 if we are leaving menu, A = 0 otherwise +; OUT - F - garbage +check_magic_hold: + ld a, #ff ; read magic key state in bit 7 of #FE port + in a, (#fe) ; ... + bit 7, a ; check key is hold + jr z, .is_hold ; yes? +.not_hold: + ld a, (var_magic_leave_cnt) ; leave_counter++ + inc a ; ... + ld (var_magic_leave_cnt), a ; ... + cp MENU_LEAVE_DELAY ; if (counter == MENU_LEAVE_DELAY) - return 2 + jr nz, .return0 ; ... + ld a, 2 + ret +.is_hold: + ld a, (var_magic_enter_cnt) ; enter_counter++ + inc a ; ... + ld (var_magic_enter_cnt), a ; ... + cp MENU_ENTER_DELAY ; if (counter == MENU_ENTER_DELAY) - return 1 + jr nz, .return0 ; ... + ld a, 1 + ret +.return0: + xor a + ret + + +; OUT - AF - garbage +; OUT - BC - garbage +check_magic_delay: + ld c, MENU_HOLDCHECK_DELAY + ld a, (cfg.clock) + or a + jr z, .loop + ld c, MENU_HOLDCHECK_DELAY*2 + dec a + jr z, .loop + ld c, MENU_HOLDCHECK_DELAY*4 +.loop: + ld a, c +.loop_outer: + ld b, 255 ; ~1ms cycle at 3.5MHz +.loop_inner: ; ... + djnz .loop_inner ; 13 T-states + dec a + jr nz, .loop_outer + ret + + +; read non-magic im2 table and returns im2 handler address +; IN - A - im2 table address hight byte +; OUT - HL - handler address +; OUT - AF - garbage +get_im2_handler: + ld h, a ; HL = im2 table address + ld l, #ff ; HL = im2 table address + ld a, #2a ; 2a - ld hl, (nn) + ld (Readout_vector-2), a ; ... + ld (Readout_vector-1), hl ; HL was set earlier by im2 table address + ld a, #c9 ; c9 - ret + ld (Readout_vector+1), a ; ... + call Readout_vector-2 ; HL = default im2 handler address + ret + + +save: +.save_ay: + ld hl, var_save_ay ; + ld e, #fe ; select first AY chip in TurboSound +.save_ay0: ; ... + ld bc, #fffd ; ... + out (c), e ; ... + ld d, 16 ; register_number=16 +.save_ay1: + dec d ; register_number-- + ld b, #ff ; select register number + out (c), d ; ... + in a, (c) ; read register + ld (hl), a ; save to ram + ld b, #bf ; set register to 0 + xor a ; ... + out (c), a ; ... + inc hl ; ram++ + or d ; register_number == 0? + jr nz, .save_ay1 + inc e ; next ay chip + jr nz, .save_ay0 ; is there more chips? +.save_screen: + ld bc, 6912 + ld de, var_save_screen + ld hl, #4000 + ldir +.save_ulaplus: + ld bc, #bf3b ; set ulaplus address = mode register + ld a, #40 ; ... + out (c), a ; ... + ld bc, #ff3b ; save mode register value + in a, (c) ; ... + ld (var_save_ulaplus), a ; ... + xor a ; disable ulaplus + out (c), a ; ... + ret + + +restore: +.restore_ulaplus: + ld bc, #bf3b ; set ulaplus address = mode register + ld a, #40 ; ... + out (c), a ; ... + ld bc, #ff3b ; restore mode register value + ld a, (var_save_ulaplus) ; ... + out (c), a ; ... +.restore_screen: + ld bc, 6912 + ld de, #4000 + ld hl, var_save_screen + ldir +.restore_ay: + ld hl, var_save_ay ; + ld e, #fe ; select first AY chip in TurboSound +.restore_ay0: ; ... + ld bc, #fffd ; ... + out (c), e ; ... + ld d, 16 ; register_number=16 +.restore_ay1: + dec d ; register_number-- + ld b, #ff ; select register number + out (c), d ; ... + ld b, #bf ; restore register + ld a, (hl) ; ... + out (c), a ; ... + inc hl ; ram++ + xor a ; register_number == 0? + or d ; ... + jr nz, .restore_ay1 ; + inc e ; next ay chip + jr nz, .restore_ay0 ; is there more chips? +.restore_ret: + ret + + +; Main program +main: + push de + push ix + push iy + + ld a, i ; save I reg and IFF2 + push af ; ... + ld a, #06 ; set our interrupt table address (#06xx) + ld i, a ; ... + + xor a + ld (var_exit_flag), a + ld (var_input_key), a + ld (var_input_key_last), a + ld (var_input_key_hold_timer), a + ld (var_menu_current_item), a + ld (var_menu_animate_cnt), a + + call save + call menu_init + +.loop: + ei + halt + call input_process ; B = 32 if exit key pressed + bit 5, b + jr nz, .wait_for_keys_release + + call menu_process + ld a, (var_exit_flag) + or a + jr z, .loop + +.wait_for_keys_release: + ei + halt + call input_process ; B = 0 if no keys pressed + xor a + or b + jr nz, .wait_for_keys_release + +.leave: + call restore + pop af ; A = I + push af ; + call get_im2_handler ; HL = default im2 handler address + ld (var_int_vector), hl + xor a ; disable border + ld bc, #01ff ; ... + out (c), a ; ... + pop af + pop iy + pop ix + pop de + ei ; wait for int just for safety + halt ; ... + ld i, a ; restore default interrupt table address + jp po, exit_with_ret ; check int was enabled by default. no? just do retn + ld hl, (var_int_vector) ; ... + jp exit_with_jp ; yes? goto default int handler + + +; Includes + include config.asm + include draw.asm + include input.asm + include menu.asm + include menu_structure.asm + include font.asm + include strings.asm + +app_end: + ; Magic vectors - ORG #F000 -Exit_vector: - nop - ORG #F008 -Readout_vector: - nop +Exit_vector EQU #F000 +Readout_vector EQU #F008 ; Variables - ORG #FC00 -Reset_flag: - db 0 -Key_was_pressed_flag: - db 0 -Magic_leave_cnt: - db 0 -Saved_sp_value: - dw 0 -Stack_bottom: + ORG #D500 +var_save_screen: .6912 DB 0 + ORG #F020 +var_save_ay: .32 DB 0 +var_save_ulaplus: DB 0 +var_sp_reg: DW 0 +var_int_vector: DW 0 +var_magic_enter_cnt: DB 0 +var_magic_leave_cnt: DB 0 +var_exit_flag: DB 0 +var_input_key: DB 0 +var_input_key_last: DB 0 +var_input_key_hold_timer: DB 0 +var_menu_current_item: DB 0 +var_menu_animate_cnt: DB 0 + +cfg CFG_T +cfg_saved CFG_T +cfg_initialized: DB #B1, #5B, #00, #B5 + ORG #FFBE Stack_top: ORG #FFC0 Ulaplus_pallete: - .64 db 0 + .64 DB 0 - SAVEBIN "rom1.bin",0,16384 + + DISPLAY "Application size: ",/D,app_end-app_begin + CSPECTMAP "main.map" + SAVEBIN "main.bin",0,16384 diff --git a/rom_src/main_test.asm b/rom_src/main_test.asm new file mode 100644 index 0000000..8c57ddc --- /dev/null +++ b/rom_src/main_test.asm @@ -0,0 +1,66 @@ + DEVICE ZXSPECTRUM48 + OPT --syntax=F + DEFINE TEST_BUILD + + org #4000 + ;INCBIN "EXOLON.SCR",0 + + org #7070 +int_handler: + ei + reti + + org #7E00 +; INT IM2 vector table + .257 db #70 ; by Z80 user manual int vector is I * 256 + (D & 0xFE) + ; but by other references and by T80/A-Z80 implementation int vector is I * 256 + D + ; so we just play safe and use symmetric int handler address and vector table with one extra byte + + org #8000 +app_begin: + di + call menu_init + + ld a, #7e ; set our interrupt table address (#7Fxx) + ld i, a ; ... + im 2 + ei +.loop: + halt + call input_process + call menu_process + ld a, #01 + out #fe, a + jr .loop + + +save_variables: + ret + + +includes: + include config.asm + include draw.asm + include input.asm + include menu.asm + include menu_structure.asm + include font.asm + include strings.asm + +variables: +var_exit_flag: DB 0 +var_input_key: DB 0 +var_input_key_last: DB 0 +var_input_key_hold_timer: DB 0 +var_menu_current_item: DB 0 +var_menu_animate_cnt: DB 0 + +cfg CFG_T +cfg_saved CFG_T +cfg_initialized: DB #B1, #5B, #00, #B5 + + + DISPLAY "Application size: ",/D,$-app_begin + CSPECTMAP "main_test.map" + SAVESNA "main_test.sna",app_begin + SAVEBIN "main_test.bin",#8000,#4000 diff --git a/rom_src/menu.asm b/rom_src/menu.asm new file mode 100644 index 0000000..8ff2db9 --- /dev/null +++ b/rom_src/menu.asm @@ -0,0 +1,157 @@ +menu_init: + ld b, (24/2)-(MENU_HEIGHT/2) + ld c, (32/2)-(MENU_WIDTH/2) + ld d, MENU_HEIGHT + ld e, MENU_WIDTH + call draw_box + + ld hl, str_sizif + ld b, ((24/2)-(MENU_HEIGHT/2))*8 + ld c, (32/2)-(MENU_WIDTH/2) + call print_string + + ld b, ((24/2)-(MENU_HEIGHT/2))*8 + ld c, (32/2)-(MENU_WIDTH/2)+MENU_WIDTH-6 + ld e, 0 + call draw_logo + + call menu_draw_menu + + xor a + ld d, MENU_SELECT_ATTR + call menu_draw_selected_item + ret + + +menu_process: + ;call menu_animate_logo + ;call menu_handle_updown + ;call menu_handle_action_left_right + + +menu_animate_logo: + ld a, (var_menu_animate_cnt) ; + inc a ; cnt++ (only cnt[7:5] used as color offset) + cp #a0 ; if (cnt[7:5] == 5) cnt = 0 - because valid offsets 0..4 + jr nz, .animate ; ... + xor a ; ... +.animate: ; + ld (var_menu_animate_cnt), a ; + and a, #1F ; if (cnt[7:5] was not changed) - exit + jr nz, .return ; ... + ld a, (var_menu_animate_cnt) ; + srl a ; cnt[7:5] -> cnt[2:0] + srl a ; ... + srl a ; ... + srl a ; ... + srl a ; ... + ld e, a ; reverse animation direction (from left to right) + ld a, 4 ; ... + sub e ; ... + ld e, a ; ... + ld b, ((24/2)-(MENU_HEIGHT/2))*8 ; draw logo + ld c, (32/2)-(MENU_WIDTH/2)+MENU_WIDTH-6 ; ... + call draw_logo ; ... +.return: + ; ret ; pass to menu_handle_updown + + +; OUT - A - pressed key +; OUT - BC - garbage +; OUT - DE - garbage +; OUT - HL - garbage +menu_handle_updown: + call input_key_get ; A = current_pressed_key +.down: ; + bit 2, a ; down? + jr z, .up ; ... + ld a, (var_menu_current_item) ; + ld d, MENU_BODY_ATTR ; fill selected item with background color + call menu_draw_selected_item ; ... + cp a, MENU_ITEMS-1 ; if (current_item == max) current_item = 0 + jr nz, .down_increment ; ... + ld a, 255 ; ... +.down_increment ; ... + inc a ; current_item++ + jr .return_save ; +.up: ; + bit 3, a ; up? + jr z, .return ; ... + ld a, (var_menu_current_item) ; + ld d, MENU_BODY_ATTR ; fill selected item with background color + call menu_draw_selected_item ; ... + or a ; if (current_item == 0) current_item = max + jr nz, .up_decrement ; ... + ld a, MENU_ITEMS ; ... +.up_decrement ; ... + dec a ; current_item-- +.return_save: ; + ld (var_menu_current_item), a ; ... + ld d, MENU_SELECT_ATTR ; highlight selected item + call menu_draw_selected_item ; ... + xor a +.return: + ;ret ; pass to menu_handle_action_left_right + + +; IN - A - pressed key +; OUT - D - pressed key +; OUT - AF - garbage +; OUT - BC - garbage +; OUT - HL - garbage +; OUT - IX - garbage +menu_handle_action_left_right: + ld d, a + and #13 ; action/left/right? + jr z, .return + ld a, d + ld a, (var_menu_current_item) ; A = selected item index + sla a ; A*8 (one menu entry - 8 bytes) + sla a ; ... + sla a ; ... + ld ix, menu ; IX = &menu + ld c, a ; IX = menu[index] + ld b, 0 ; ... + add ix, bc ; ... + ld l, (ix+4) ; HL = menu[index].callback + ld h, (ix+5) ; ... + ld a, h ; if (HL == 0) - exit + or l ; ... + jr z, .return ; ... + call .callback ; call menu[index].callback(), D is pressed key + call menu_draw_menu ; update menu if something changed +.return: + ret + +.callback: + jp (hl) ; AF, BC, HL, IX may be changed + + +; IN - A - selected menu item number +; IN - D - attribute +; OUT - BC - garbage +; OUT - E - garbage +; OUT - HL - garbage +menu_draw_selected_item: + push af + ld b, (24/2)-(MENU_HEIGHT/2)+1 + add b + ld b, a + ld c, (32/2)-(MENU_WIDTH/2) + ld e, MENU_WIDTH + call draw_menu_item_line + pop af + ret + + +menu_draw_menu: + ld b, ((24/2)-(MENU_HEIGHT/2))*8+8 + ld c, (32/2)-(MENU_WIDTH/2)+1 + ld e, MENU_WIDTH + ld hl, menu + call draw_menu + ret + + +;var_menu_current_item: DB 0 +;var_menu_animate_cnt: DB 0 diff --git a/rom_src/menu_structure.asm b/rom_src/menu_structure.asm new file mode 100644 index 0000000..d3982cf --- /dev/null +++ b/rom_src/menu_structure.asm @@ -0,0 +1,235 @@ + STRUCT MENU_T +text_addr DW +value_cb_addr DW +callback DW +reserved DW + ENDS + +menu: + MENU_T str_timings menu_timings_value_cb menu_timins_cb + MENU_T str_cpu menu_clock_value_cb menu_clock_cb + MENU_T str_panning menu_panning_value_cb menu_panning_cb + MENU_T str_joystick menu_joystick_value_cb menu_joystick_cb + MENU_T str_ram menu_ram_value_cb menu_ram_cb + MENU_T str_rom48 menu_rom48_value_cb menu_rom48_cb + MENU_T str_plus3 menu_plus3_value_cb menu_plus3_cb + MENU_T str_divmmc menu_divmmc_value_cb menu_divmmc_cb + MENU_T str_save 0 menu_save_reboot_cb + MENU_T str_exit 0 menu_exit_cb + MENU_T 0 +MENU_ITEMS EQU ($-menu)/MENU_T-1 + + +menu_timings_value_cb: + ld ix, .values_table + ld a, (cfg.timings) + jp menu_value_get +.values_table: + DW str_timings_pentagon_end-2 + DW str_timings_48_end-2 + DW str_timings_128_end-2 + +menu_clock_value_cb: + ld ix, .values_table + ld a, (cfg.clock) + jp menu_value_get +.values_table: + DW str_cpu_35_end-2 + DW str_cpu_7_end-2 + DW str_cpu_14_end-2 + +menu_panning_value_cb: + ld ix, .values_table + ld a, (cfg.panning) + jp menu_value_get +.values_table: + DW str_panning_acb_end-2 + DW str_panning_abc_end-2 + DW str_panning_mono_end-2 + +menu_joystick_value_cb: + ld ix, .values_table + ld a, (cfg.joystick) + jp menu_value_get +.values_table: + DW str_joystick_kempston_end-2 + DW str_joystick_sinclair_end-2 + +menu_ram_value_cb: + ld ix, .values_table + ld a, (cfg.ram) + or a + jr nz, .less_than_512K + ld a, (cfg.divmmc) ; 256K with divmmc + or a ; ... + jr z, .is_512K ; ... + ld a, 3 ; ... + jp menu_value_get +.is_512K: + xor a +.less_than_512K: + jp menu_value_get +.values_table: + DW str_ram_512_end-2 + DW str_ram_48_end-2 + DW str_ram_128_end-2 + DW str_ram_256_end-2 + +menu_rom48_value_cb: + ld ix, .values_table + ld a, (cfg.rom48) + jp menu_value_get +.values_table: + DW str_rom48_default_end-2 + DW str_rom48_alt_end-2 + +menu_plus3_value_cb: + ld ix, .values_table + ld a, (cfg.plus3) + jp menu_value_get +.values_table: + DW str_off_end-2 + DW str_on_end-2 + +menu_divmmc_value_cb: + ld ix, .values_table + ld a, (cfg.divmmc) + jp menu_value_get +.values_table: + DW str_off_end-2 + DW str_on_end-2 + +menu_value_get: + sla a + ld c, a + ld b, 0 + add ix, bc + ld l, (ix+0) + ld h, (ix+1) + ret + + +menu_timins_cb: + ld a, (cfg.timings) + ld c, 2 + call menu_handle_press + ld (cfg.timings), a + ld bc, #02ff + out (c), a + ret + +menu_clock_cb: + ld a, (cfg.clock) + ld c, 2 + call menu_handle_press + ld (cfg.clock), a + ld bc, #03ff + out (c), a + ret + +menu_panning_cb: + ld a, (cfg.panning) + ld c, 2 + call menu_handle_press + ld (cfg.panning), a + ld bc, #04ff + out (c), a + ret + +menu_joystick_cb: + ld a, (cfg.joystick) + ld c, 1 + call menu_handle_press + ld (cfg.joystick), a + ld bc, #07ff + out (c), a + ret + +menu_ram_cb: + ld a, (cfg.ram) + ld c, 2 + call menu_handle_press + ld (cfg.ram), a + ld bc, #08ff + out (c), a + ret + +menu_rom48_cb: + ld a, (cfg.rom48) + ld c, 1 + call menu_handle_press + ld (cfg.rom48), a + ld bc, #06ff + out (c), a + ret + +menu_plus3_cb: + ld a, (cfg.plus3) + ld c, 1 + call menu_handle_press + ld (cfg.plus3), a + ld bc, #05ff + out (c), a + ret + +menu_divmmc_cb: + ld a, (cfg.divmmc) + ld c, 1 + call menu_handle_press + ld (cfg.divmmc), a + ld bc, #09ff + out (c), a + ret + +menu_save_reboot_cb: + call save_variables + ld a, 1 + ld bc, #00ff + out (c), a + ret + +menu_exit_cb: + ld a, 1 + ld (var_exit_flag), a + ret + + +; IN - A - variable to change +; IN - C - max value +; IN - D - pressed key +; OUT - A - new variable value +menu_handle_press: + bit 4, d ; action? + jr nz, .increment + bit 0, d ; right? + jr nz, .increment + bit 1, d ; left? + jr nz, .decrement + ret +.increment: + cp c ; if (value == max) value = 0 + jr z, .increment_roll ; ... + inc a ; else value++ + ret +.increment_roll: + xor a ; value = 0 + ret +.decrement: + or a ; if (value == 0) value = max + jr z, .decrement_roll ; ... + dec a ; else value-- + ret +.decrement_roll: + ld a, c ; value = max + ret + + +;var_initialized: DB #B1, #5B, #00, #B5 +;var_timings: DB 0 +;var_clock: DB 0 +;var_panning: DB 1 +;var_joystick: DB 0 +;var_ram: DB 0 +;var_rom48: DB 0 +;var_plus3: DB 0 +;var_divmmc: DB 0 diff --git a/rom_src/strings.asm b/rom_src/strings.asm new file mode 100644 index 0000000..7922454 --- /dev/null +++ b/rom_src/strings.asm @@ -0,0 +1,102 @@ + DB 0 + + IFDEF SIZIFXXS +str_sizif: DB "SIZIF-XXS",0 +str_sizif_end: + ENDIF + + IFDEF SIZIF512 +str_sizif: DB "SIZIF-512",0 +str_sizif_end: + ENDIF + +str_save: DB "Save & reset",0 +str_save_end: + +str_exit: DB "Exit",0 +str_exit_end: + +str_on: DB " ON",0 +str_on_end: + +str_off: DB "OFF",0 +str_off_end: + +str_timings: DB "Timings",0 +str_timings_end: + +str_timings_pentagon: DB "Pentagon",0 +str_timings_pentagon_end: + +str_timings_128: DB " 128",0 +str_timings_128_end: + +str_timings_48: DB " 48",0 +str_timings_48_end: + +str_cpu: DB "CPU freq",0 +str_cpu_end: + +str_cpu_35: DB "3.5MHz",0 +str_cpu_35_end: + +str_cpu_7: DB " 7MHz",0 +str_cpu_7_end: + +str_cpu_14: DB " 14MHz",0 +str_cpu_14_end: + +str_panning: DB "Panning",0 +str_panning_end: + +str_panning_abc: DB " ABC",0 +str_panning_abc_end: + +str_panning_acb: DB " ACB",0 +str_panning_acb_end: + +str_panning_mono: DB "Mono",0 +str_panning_mono_end: + +str_joystick: DB "Joystick",0 +str_joystick_end: + +str_joystick_kempston: DB "Kempston",0 +str_joystick_kempston_end: + +str_joystick_sinclair: DB "Sinclair",0 +str_joystick_sinclair_end: + +str_rom48: DB "48K ROM",0 +str_rom48_end: + +str_rom48_default: DB "Default",0 +str_rom48_default_end: + +str_rom48_alt: DB " Alt",0 +str_rom48_alt_end: + +str_plus3: DB "+3",0 +str_plus3_end: + +str_featurelock: DB "Features",0 +str_featurelock_end: + +str_divmmc: DB "DivMMC",0 +str_divmmc_end: + +str_ram: DB "RAM",0 +str_ram_end: + +str_ram_48: DB " 48K",0 +str_ram_48_end: + +str_ram_128: DB "128K",0 +str_ram_128_end: + +str_ram_256: DB "256K",0 +str_ram_256_end: + +str_ram_512: DB "512K",0 +str_ram_512_end: +