1
0
mirror of https://github.com/UzixLS/zx-sizif-xxs.git synced 2025-07-19 07:11:28 +03:00

new magic rom with menu

This commit is contained in:
UzixLS
2021-06-17 22:00:59 +03:00
parent ec1805f092
commit 1435f856b3
12 changed files with 2527 additions and 270 deletions

3
.gitignore vendored
View File

@ -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.*/

View File

@ -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 \

View File

@ -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

30
rom_src/config.asm Normal file
View File

@ -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

425
rom_src/draw.asm Normal file
View File

@ -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

961
rom_src/font.asm Normal file
View File

@ -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 --####--

183
rom_src/input.asm Normal file
View File

@ -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

View File

@ -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

66
rom_src/main_test.asm Normal file
View File

@ -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

157
rom_src/menu.asm Normal file
View File

@ -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

235
rom_src/menu_structure.asm Normal file
View File

@ -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

102
rom_src/strings.asm Normal file
View File

@ -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: