jmp opt and cleanups
[megadrive.git] / hexed / hexed.s
index 23313dc..ca17291 100644 (file)
@@ -7,6 +7,7 @@
 
 .text
 .globl main
+.globl INT
 .globl VBL
 
 ##################################################
@@ -28,7 +29,7 @@
 .equ VDP1_E_DMA,       0x10
 .equ VDP1_NTSC,                0x00
 .equ VDP1_PAL,         0x08
-.equ VDP1_RESERVED,    0x04
+.equ VDP1_MODE5,       0x04
 
 .equ VDP12_STE,                0x08
 .equ VDP12_SCREEN_V224,        0x00
 .equ MMODE_VAL_INPUT,  1
 .equ MMODE_EDIT_VAL,   2
 .equ MMODE_GOTO,       3
+.equ MMODE_START_MENU, 4
+.equ MMODE_GOTO_PREDEF,        5
+.equ MMODE_JMP_ADDR,   6
 
+.equ predef_addr_cnt,  ((predef_addrs_end-predef_addrs)/4)
 
 ##################################################
 #                                                #
 ##################################################
 
 
-/* Write val to VDP register reg */
-.macro write_vdp_reg reg val
-       move.w #((\reg << 8) + 0x8000 + \val),(a3)
+# Write val to VDP register reg
+.macro write_vdp_r_dst reg val dst
+       move.w #((\reg << 8) + 0x8000 + \val),\dst
 .endm
 
-
-/* For immediate addresses */
-.macro VRAM_ADDR reg adr
-       move.l #(((0x4000 + (\adr & 0x3fff)) << 16) + (\adr >> 14)),\reg
+# Write val to VDP register reg, vdp addr in a3
+.macro write_vdp_reg reg val
+       write_vdp_r_dst \reg, \val, (a3)
 .endm
 
-
-.macro CRAM_ADDR reg adr
-       move.l  #(((0xc000 + (\adr & 0x3fff)) << 16) + (\adr >> 14)),\reg
+# Set up address in VDP, control port in dst
+.macro VRAM_ADDR adr dst
+       move.l #(((0x4000 | (\adr & 0x3fff)) << 16) | (\adr >> 14)),\dst
 .endm
 
 
 .endm
 
 
-.macro VSCROLL_ADDR reg adr
-       move.l  #(((0x4000 + (\adr & 0x3fff)) << 16) + ((\adr >> 14) | 0x10)),\reg
-.endm
-
-
-.macro HSCROLL_ADDR reg adr
-       move.l #(((0x4000 + (\adr & 0x3fff)) << 16) + (\adr >> 14)),\reg
-.endm
-
-
 # convert tile coords in d0, d1 to nametable addr to a0
 .macro XY2NT
        lsl.w           #6,d1
        or.w            #(\mode_back<<11)|(\mode_new<<8),d7
 .endm
 
+.macro menu_text str x y pal
+       lea             \str,a0
+       move.l          #\x,d0
+       move.l          #\y,d1
+       move.l          #0x8000|(\pal<<13),d2
+       jsr             print
+.endm
+
 #################################################
 #                                               #
 #                    DATA                       #
@@ -154,6 +156,8 @@ colors:
        dc.w    0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
        dc.w 0x0000,0x0e44,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
        dc.w    0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
+       dc.w 0x0000,0x044e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
+       dc.w    0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
 colors_end:
 
 
@@ -162,23 +166,78 @@ sprite_data:
        dc.w       0;  dc.b 0x05;  dc.b 0;  dc.w 0x6002;  dc.w 0
 sprite_data_end:
 
+predef_addrs:
+       dc.l 0x000000, 0x200000, 0x400000, 0xa00000, 0xa10000
+       dc.l 0xa11100, 0xa12000, 0xa13000, 0xa14000, 0xc00000
+predef_addrs_end:
+
+safe_addrs:
+       dc.l 0x000000, 0x7fffff
+       dc.l 0xe00000, 0xffffff
+       dc.l 0xa00000, 0xa100ff
+       dc.l 0xa11000, 0xa113ff
+       dc.l 0xa12000, 0xa120ff
+       dc.l 0xa13000, 0xa130ff
+safe_addrs_end:
+
 txt_edit:
        .ascii  "- edit -\0"
 txt_a_confirm:
        .ascii  "A-confirm\0"
+txt_about:
+       .ascii  "hexed r1\0"
+txt_goto:
+       .ascii  "Go to address\0"
+txt_goto_predef:
+       .ascii  "Go to (predef)\0"
+txt_jmp_addr:
+       .ascii  "Jump to address\0"
+txt_dtack:
+       .ascii  "DTACK safety\0"
+txt_dtack_err:
+       .ascii  "DTACK err?\0"
+txt_exc:
+       .ascii  "Exception \0"
 
 ##################################################
 #                                                #
 #               MAIN PROGRAM                     #
 #                                                #
 ##################################################
+
+# global regs:
+# a6 = page_start[31:8]|cursor_offs[7:0]
+# d7 = old_inputs[31:16]|edit_bytes[15:14]|g_mode_old[13:11]|g_mode[10:8]|irq_cnt[7:0]
+# d6 = edit_word_save[31:15]|edit_done[7]|no_dtack_detect[4]|autorep_cnt[3:0]
+# d5 = main: tmp
+#      edit: edit_word[31:8]|edit_pos[4:2]|byte_cnt[1:0]
+#      menu: sel
+
 .align 2
 
 main:
        /* mask irqs during init */
        move.w          #0x2700,sr
 
+.if 0
+       /* copy */
+       lea             (0,pc),a0
+       move.l          a0,d0
+       swap            d0
+       lsr.l           #4,d0
+       and.b           #0x0f,d0
+       cmp.b           #0,d0
+       bne             0f
+
+       move.w          #8000/2,d0
+       move.l          #0,a0
+       move.l          #0x400000,a1
+1:
+       move.w          (a0)+,(a1)+
+       dbra            d0,1b
+0:
+.endif
+
        movea.l         #0,a6
        move.l          #0x8000,d7
        moveq.l         #0,d6
@@ -196,11 +255,24 @@ main:
        moveq.l         #(colors_end-colors)/2,d0
        jsr             load_colors
 
-       /* load patterns */
-       movea.l         #0,a0
-       movea.l         #font,a1
-       move.l          #128,d0
-       jsr             load_tiles
+       /* load font patterns */
+       lea             GFXDATA,a0
+       lea             font,a1
+       VRAM_ADDR       0,(GFXCNTL)
+       move.w          #128*8,d3
+font_loop:
+       moveq.l         #8-1,d2
+       moveq.l         #0,d1
+       move.b          (a1)+,d0
+0:
+       lsr.b           #1,d0
+       roxl.l          #1,d1
+       ror.l           #5,d1
+       dbra            d2,0b
+
+       rol.l           #1,d1           /* fixup */
+       move.l          d1,(a0)
+       dbra            d3,font_loop
 
        /* generate A layer map */
        movea.l         #0xe000,a1
@@ -233,30 +305,38 @@ lmaploop0:
 0:     move.l          (a1)+,(a0)
        dbra            d3,0b
 
+       /* wait for vsync before unmask */
+       move.l          #GFXCNTL,a3
+0:
+       move.w          (a3),d0
+       and.b           #8,d0
+       nop
+       nop
+       beq             0b
+
         move.w         #0x2000,sr
 
 ##################################################
-#                                                #
-#                 MAIN LOOP                      #
-#                                                #
-##################################################
-
-# global regs:
-# a6 = page_start[31:8]|cursor_offs[7:0]
-# d7 = old_inputs[31:16]|edit_bytes[15:14]|g_mode_old[13:11]|g_mode[10:8]|irq_cnt[7:0]
-# d6 = edit_word[31:8]|edit_done[7]|edit_pos[6:4]|autorep_cnt[3:0]
 
 forever:
-
-
        jsr             wait_vsync
        bra             forever
-       
 
 
+INT:
+       /* let's hope VRAM is already set up.. */
+       lea             txt_exc,a0
+       move.l          #9,d0
+       move.l          #27,d1
+       move.l          #0xe000,d2
+       jsr             print
+       bra             forever
+
+##################################################
+
 VBL:
        addq.b          #1,d7
-       movem.l         d0-d5/a0-a5,-(a7)
+#      movem.l         d0-d4/a0-a5,-(a7)
 
        moveq.l         #0,d0
        move.w          d7,d0
@@ -269,15 +349,22 @@ jumptab:
        dc.l            mode_val_input
        dc.l            mode_edit_val   /* edit val in editor */
        dc.l            mode_goto
-       dc.l            mode_main
-       dc.l            mode_main
-       dc.l            mode_main
+       dc.l            mode_start_menu
+       dc.l            mode_goto_predef
+       dc.l            mode_jmp_addr
        dc.l            mode_main
 
 ##################### main #######################
 
 mode_main:
-       clr.l           d1
+       /* assume we will hang */
+       lea             txt_dtack_err,a0
+       move.l          #9,d0
+       move.l          #27,d1
+       move.l          #0xe000,d2
+       jsr             print
+
+       moveq.l         #0,d1
        move.l          a6,d0
        move.b          d0,d1
        lsr.l           #8,d0
@@ -287,36 +374,190 @@ mode_main:
        add.b           #27-1,d1        /* line where the cursor sits */
        swap            d1
 
-       movea.l         #0xe004,a2
+       movea.l         #0xe002,a2
        move.l          #27-1,d5        /* line counter for dbra */
        or.l            d1,d5
 
-draw_column:
+draw_row:
        move.l          a2,a0
        jsr             load_prepare
 
+       btst.l          #15,d7
+       beq             0f
+       move.w          #' ',(a0)
+0:
        /* addr */
        move.l          a1,d2
        moveq.l         #6,d3
        jsr             print_hex_preped
 
+       btst.l          #4,d6
+       bne             draw_row_safe
+
+       bsr             get_safety_mask
+       cmp.b           #0xf,d0
+       beq             draw_row_safe
+
+# unsafe or partially safe
+draw_row_hsafe:
+       move.l          d0,d4
+       swap            d4              /* mask in upper word */
+       btst.l          #15,d7
+       bne             draw_row_hsafe_words_pre
+
+draw_row_hsafe_bytes_pre:
+       /* 8 bytes */
+       moveq.l         #2,d3
+       move.w          #3,d4
+
+draw_row_hsafe_bytes:
+       move.w          #' ',(a0)
+       move.b          d4,d0
+       add.b           #16,d0
+       btst.l          d0,d4
+       bne             0f
+       move.l          #'?'|('?'<<16),(a0)
+       move.w          #' ',(a0)
+       move.l          #'?'|('?'<<16),(a0)
+       bra             1f
+0:
+       move.b          (0,a1),d2
+       jsr             print_hex_preped
+       move.w          #' ',(a0)
+       move.b          (1,a1),d2
+       jsr             print_hex_preped
+1:
+       addq.l          #2,a1
+       dbra            d4,draw_row_hsafe_bytes
+
+       move.w          #' ',(a0)
+
+       move.l          d5,d0
+       swap            d0
+       cmp.w           d5,d0
+       beq             draw_cursor_unsafe_byte
+       bra             draw_chars_hsafe_pre
+
+draw_row_hsafe_words_pre:
+       /* 4 shorts */
+       moveq.l         #4,d3
+       move.w          #3,d4
+
+draw_row_hsafe_words:
+       move.w          #' ',(a0)
+       move.b          d4,d0
+       add.b           #16,d0
+       btst.l          d0,d4
+       bne             0f
+       move.l          #'?'|('?'<<16),(a0)
+       move.l          #'?'|('?'<<16),(a0)
+       bra             1f
+0:
+       move.w          (a1),d2
+       jsr             print_hex_preped
+1:
+       addq.l          #2,a1
+       dbra            d4,draw_row_hsafe_words
+
+       move.l          #(' '<<16)|' ',(a0)
+
+       move.l          d5,d0
+       swap            d0
+       cmp.w           d5,d0
+       beq             draw_cursor_unsafe_word
+
+draw_chars_hsafe_pre:
+       subq.l          #8,a1
+       move.w          #3,d4
+       moveq.l         #0,d0
+
+draw_chars_hsafe:
+       move.b          d4,d0
+       add.b           #16,d0
+       btst.l          d0,d4
+       bne             0f
+       move.l          #'?'|('?'<<16),(a0)
+       bra             draw_chars_hsafe_next
+0:
+       btst.l          #15,d7          /* must perform correct read type */
+       bne             0f              /* doing byte reads on security reg hangs */
+       move.b          (0,a1),d0
+       lsl.l           #8,d0
+       move.b          (1,a1),d0
+       bra             1f
+0:
+       move.w          (a1),d0
+1:
+       ror.l           #8,d0
+       move.b          d0,d1
+       sub.b           #0x20,d1
+       cmp.b           #0x60,d1
+       blo             0f
+       move.b          #'.',d0
+0:
+       move.w          d0,(a0)
+
+       move.b          #0,d0
+       rol.l           #8,d0
+       move.b          d0,d1
+       sub.b           #0x20,d1
+       cmp.b           #0x60,d1
+       blo             0f
+       move.b          #'.',d0
+0:
+       move.w          d0,(a0)
+
+draw_chars_hsafe_next:
+       addq.l          #2,a1
+       dbra            d4,draw_chars_hsafe
+
+       move.l          #(' '<<16)|' ',(a0)
+       add.w           #0x80,a2
+       dbra            d5,draw_row
+       bra             draw_status_bar
+
+
+# normal draw
+draw_row_safe:
+       btst.l          #15,d7
+       bne             draw_row_words
+
+draw_row_bytes:
+       /* 8 bytes */
+       moveq.l         #2,d3
+       moveq.l         #8-1,d4
+draw_bytes:
+       move.w          #' ',(a0)
+       move.b          (a1)+,d2
+       jsr             print_hex_preped
+       dbra            d4,draw_bytes
+
+       move.w          #' ',(a0)
+
+       move.l          d5,d0
+       swap            d0
+       cmp.w           d5,d0
+       beq             draw_cursor_byte
+       bra             draw_chars_pre
+
+draw_row_words:
        /* 4 shorts */
        moveq.l         #4,d3
        moveq.l         #4-1,d4
-draw_shorts:
+draw_words:
        move.w          #' ',(a0)
        move.w          (a1)+,d2
        jsr             print_hex_preped
-       dbra            d4,draw_shorts
+       dbra            d4,draw_words
+
+       move.l          #(' '<<16)|' ',(a0)
 
        move.l          d5,d0
        swap            d0
        cmp.w           d5,d0
-       beq             draw_cursor
+       beq             draw_cursor_word
 
 draw_chars_pre:
-       move.l          #(' '<<16)|' ',(a0)
-
        /* 8 chars */
        subq.l          #8,a1
        moveq.l         #8-1,d4
@@ -331,16 +572,33 @@ draw_chars:
        move.w          d0,(a0)
        dbra            d4,draw_chars
 
+       move.l          #(' '<<16)|' ',(a0)
+
        add.w           #0x80,a2
-       dbra            d5,draw_column
+       dbra            d5,draw_row
+
 
+draw_status_bar:
        /* status bar */
-       movea.l         #0xe004+64*2*27,a0
+       move.l          a2,a0
        jsr             load_prepare
+
+       btst.l          #15,d7
+       beq             0f
+       move.w          #' ',(a0)
+0:
        mk_a6_addr      d2
        move.l          #0x4006,d3
        jsr             print_hex_preped
 
+       /* clear error */
+       moveq.l         #5-1,d0
+0:
+       move.l          #' '|(' '<<16),(a0)
+       move.l          #' '|(' '<<16),(a0)
+       dbra            d0,0b
+
+
        /* handle input */
        jsr             get_input               /* x0cbrldu x1sa00du */
 
@@ -392,22 +650,39 @@ input_nob:
        beq             input_noc
 
        change_mode     MMODE_EDIT_VAL, MMODE_MAIN
-       write_vdp_reg   12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE)
+       write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
 
 input_noc:
-       btst.l          #5,d0                   /* Start - goto */
+       btst.l          #5,d0                   /* Start - menu */
        beq             input_nos
 
-       change_mode     MMODE_GOTO, MMODE_MAIN
-       write_vdp_reg   12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE)
+       moveq.l         #0,d5
+       change_mode     MMODE_START_MENU, MMODE_MAIN
+       write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
 
 input_nos:
 vbl_end:
-       movem.l         (a7)+,d0-d5/a0-a5
+#      movem.l         (a7)+,d0-d4/a0-a5
        rte
 
 
-draw_cursor:
+draw_cursor_unsafe_byte:
+       move.l          a6,d0
+       and.l           #7,d0           /* byte offs */
+       move.b          d0,d1
+       add.b           d0,d0
+       add.b           d1,d0           /* d0 *= 3 (chars) */
+       add.b           d0,d0
+       lea             (7*2,a2,d0),a0
+       jsr             load_prepare
+       move.l          #(0x2000|'?'|((0x2000|'?')<<16)),(a0)
+
+       move.l          a2,a0
+       add.w           #31*2,a0
+       jsr             load_prepare    /* restore a0 */
+       jmp             draw_chars_hsafe_pre
+
+draw_cursor_unsafe_word:
        move.l          a6,d0
        and.l           #7,d0           /* byte offs */
        move.l          d0,d1
@@ -415,29 +690,58 @@ draw_cursor:
        move.b          d1,d2
        lsl.b           #2,d2
        add.b           d2,d1           /* num of chars to skip */
-       lsl.b           #1,d1
-       move.w          #0x2004,d3
+       add.b           d1,d1
+
+       lea             (8*2,a2,d1),a0
+       jsr             load_prepare
+       move.l          #(0x2000|'?'|((0x2000|'?')<<16)),d0
+       move.l          d0,(a0)
+       move.l          d0,(a0)
+
+       move.l          a2,a0
+       add.w           #29*2,a0
+       jsr             load_prepare    /* restore a0 */
+       jmp             draw_chars_hsafe_pre
 
-       btst.l          #15,d7
-       bne             draw_cursor_word
 
 draw_cursor_byte:
+       move.l          a6,d0
+       and.l           #7,d0           /* byte offs */
+       move.w          #0x2002,d3
+
        move.b          (-8,a1,d0),d2
-       and.b           #1,d0
-       lsl.b           #2,d0
-       add.b           d0,d1
-       subq.b          #2,d3
-       bra             0f
+       move.b          d0,d1
+       add.b           d0,d0
+       add.b           d1,d0           /* d0 *= 3 (chars) */
+       add.b           d0,d0
+       lea             (7*2,a2,d0),a0
+       jsr             load_prepare
+       jsr             print_hex_preped
+
+       move.l          a2,a0
+       add.w           #31*2,a0
+       jsr             load_prepare    /* restore a0 */
+
+       jmp             draw_chars_pre
 
 draw_cursor_word:
+       move.l          a6,d0
+       and.l           #7,d0           /* byte offs */
+       move.l          d0,d1
+       lsr.b           #1,d1           /* which word */
+       move.b          d1,d2
+       lsl.b           #2,d2
+       add.b           d2,d1           /* num of chars to skip */
+       add.b           d1,d1
+       move.w          #0x2004,d3
+
        move.w          (-8,a1,d0),d2
-0:
-       lea             (7*2,a2,d1),a0
+       lea             (8*2,a2,d1),a0
        jsr             load_prepare
        jsr             print_hex_preped
 
        move.l          a2,a0
-       add.w           #26*2,a0
+       add.w           #29*2,a0
        jsr             load_prepare    /* restore a0 */
 
        jmp             draw_chars_pre
@@ -450,21 +754,21 @@ mode_edit_val:
        bne             mode_hedit_finish
 
        /* read val to edit */
+       moveq.l         #0,d5
        mk_a6_addr      d1
        move.l          d1,a0
-       moveq.l         #0,d0
        btst.l          #15,d7
        bne             0f
-       move.b          (a0),d0
+       move.b          (a0),d5
+       lsl.l           #8,d5
+       or.b            #1,d5
        bra             1f
 0:
-       move.w          (a0),d0
+       move.w          (a0),d5
+       lsl.l           #8,d5
+       or.b            #2,d5
 1:
-       lsl.l           #8,d0
-       and.l           #0xff,d6
-       or.l            d0,d6
 
-       and.b           #0x0f,d6        /* not done, reset pos */
        change_mode     MMODE_VAL_INPUT, MMODE_EDIT_VAL
        jmp             vbl_end
 
@@ -472,18 +776,16 @@ mode_hedit_finish:
        /* write the val */
        mk_a6_addr      d1
        move.l          d1,a0
-       move.l          d6,d0
-       lsr.l           #8,d0
+       lsr.l           #8,d5
 
        btst.l          #15,d7
        bne             0f
-       move.b          d0,(a0)
+       move.b          d5,(a0)
        bra             1f
 0:
-       move.w          d0,(a0)
+       move.w          d5,(a0)
 1:
 
-       and.l           #0xf,d6         /* forget val and pos */
        bra             return_to_main
 
 ##################### goto #######################
@@ -492,14 +794,19 @@ mode_goto:
        btst.l          #7,d6
        bne             mode_goto_finish
 
-       or.w            #0xc000,d7      /* 3 bytes */
+       moveq.l         #0,d5
+       swap            d6
+       move.w          d6,d5
+       swap            d6
+       swap            d5
+       or.b            #3,d5           /* 3 bytes */
        bclr.l          #7,d6
        change_mode     MMODE_VAL_INPUT, MMODE_GOTO
        jmp             vbl_end
 
 mode_goto_finish:
-       move.l          d6,d0
-       lsr.l           #8,d0
+       lsr.l           #8,d5
+       move.l          d5,d0
        move.l          d0,d1
        and.l           #7,d1
        and.b           #0xf8,d0
@@ -507,8 +814,11 @@ mode_goto_finish:
        or.l            d1,d0
        move.l          d0,a6
 
-       and.w           #0x3fff,d7
-       or.w            #0x8000,d7      /* back to 2 bytes */
+       lsr.l           #8,d5
+       swap            d6
+       move.w          d5,d6
+       swap            d6
+
        bra             return_to_main
 
 ################### val edit #####################
@@ -545,14 +855,13 @@ mode_val_input:
        moveq.l         #0,d0
        moveq.l         #0,d1
        moveq.l         #0,d3
-       move.w          d7,d3
-       lsr.w           #7,d3
-       lsr.w           #7,d3
+       move.b          d5,d3
+       and.b           #3,d3           /* edit field bytes */
 
        move.b          #19,d0
        sub.b           d3,d0
        move.b          #13,d1
-       move.l          d6,d2
+       move.l          d5,d2
        lsr.l           #8,d2
        add.b           d3,d3
        or.w            #0x8000,d3
@@ -567,8 +876,8 @@ mode_val_input:
        move.b          d3,d1
        lsr.b           #1,d1           /* length in bytes */
        sub.b           d1,d0
-       move.b          d6,d1
-       lsr.b           #4,d1
+       move.b          d5,d1
+       lsr.b           #2,d1
        and.b           #7,d1           /* nibble to edit */
        add.b           d1,d0
 
@@ -576,7 +885,7 @@ mode_val_input:
        sub.b           #1,d3           /* chars to shift out */
        lsl.b           #2,d3
        add.b           #8,d3
-       move.l          d6,d2
+       move.l          d5,d2
        lsr.l           d3,d2
 
        move.b          #13,d1
@@ -589,13 +898,12 @@ mode_val_input:
        move.w          d0,d1
        and.w           #0x0f00,d1
        beq             ai_no_dpad
-       move.w          d7,d1
-       lsr.w           #7,d1
-       lsr.w           #7,d1
+       move.b          d5,d1
+       and.b           #3,d1
        add.b           d1,d1           /* nibble count */
        sub.b           #1,d1           /* max n.t.e. val */
-       move.b          d6,d2
-       lsr.b           #4,d2
+       move.b          d5,d2
+       lsr.b           #2,d2
        and.b           #7,d2           /* nibble to edit */
 
        move.b          d0,d3
@@ -610,7 +918,7 @@ mode_val_input:
        add.b           #8,d1
        lsl.l           d1,d3           /* mask */
        lsl.l           d1,d4           /* what to add/sub */
-       move.l          d6,d1
+       move.l          d5,d1
        and.l           d3,d1
        btst.l          #8,d0
        beq             0f
@@ -621,8 +929,8 @@ mode_val_input:
 1:
        and.l           d3,d1
        eor.l           #0xffffffff,d3
-       and.l           d3,d6
-       or.l            d1,d6
+       and.l           d3,d5
+       or.l            d1,d5
        jmp             vbl_end
 
 ai_no_ud:
@@ -641,9 +949,9 @@ ai_no_ud:
        ble             0f
        move.b          #0,d2
 0:
-       and.b           #0x8f,d6
-       lsl.b           #4,d2
-       or.b            d2,d6
+       and.b           #0xe3,d5
+       lsl.b           #2,d2
+       or.b            d2,d5
        jmp             vbl_end
 
 ai_no_dpad:
@@ -651,14 +959,13 @@ ai_no_dpad:
        and.w           #0x1020,d1
        beq             ai_no_sb
 
-       and.l           #0xf,d6         /* forget val and pos */
        bra             return_to_main
 
 ai_no_sb:
-       btst.l          #4,d0
+       btst.l          #4,d0           /* A - confirm */
        beq             ai_no_input
        bset.l          #7,d6
-       move.w          d7,d1
+       move.w          d7,d1           /* back to prev mode */
        and.w           #0x3800,d1
        lsr.w           #3,d1
        and.w           #0xc0ff,d7
@@ -668,11 +975,223 @@ ai_no_input:
        jmp             vbl_end
 
 
+################### start menu ###################
+
+mode_start_menu:
+       /* frame */
+       bsr             start_menu_box
+
+       /* text */
+       menu_text       txt_about,       13,  9, 1
+       menu_text       txt_goto,        13, 11, 0
+       menu_text       txt_goto_predef, 13, 12, 0
+       menu_text       txt_jmp_addr,    13, 13, 0
+       menu_text       txt_dtack,       13, 14, 0
+       menu_text       txt_a_confirm,   13, 16, 2
+
+       /* dtack safety on/off */
+       movea.l         #0xe000+26*2+14*64*2,a0
+       jsr             load_prepare
+       move.w          #0x8000|'O',(a0)
+       btst.l          #4,d6
+       bne             0f
+       move.w          #0x8000|'N',(a0)
+       bra             1f
+0:
+       move.w          #0x8000|'F',(a0)
+       move.w          #0x8000|'F',(a0)
+1:
+
+       /* cursor */
+       movea.l         #0xe000+11*2+11*64*2,a0
+       moveq.l         #0,d0
+       move.b          d5,d0
+       and.b           #3,d0
+       lsl.w           #7,d0
+       add.w           d0,a0
+       jsr             load_prepare
+       move.w          #'>',(a0)
+
+       /* input */
+       jsr             get_input       /* x0cbrldu x1sa00du */
+
+       move.w          d0,d1
+       and.w           #3,d1
+       beq             msm_no_ud
+       move.b          d5,d1
+       and.b           #3,d1
+       btst.l          #0,d0
+       sne             d2
+       or.b            #1,d2           /* up -1, down 1 */
+       add.b           d2,d1
+       cmp.b           #0,d1
+       bge             0f
+       move.b          #3,d1
+0:
+       cmp.b           #3,d1
+       ble             0f
+       move.b          #0,d1
+0:
+       and.b           #0xfc,d5
+       or.b            d1,d5
+       jmp             vbl_end
+
+msm_no_ud:
+       btst.l          #4,d0           /* A - confirm */
+       beq             msm_no_a
+       move.b          d5,d1
+       and.b           #3,d1
+       bne             0f
+       change_mode     MMODE_GOTO, MMODE_MAIN
+       bsr             start_menu_box
+       jmp             vbl_end
+0:
+       cmp.b           #1,d1
+       bne             0f
+       moveq.l         #0,d5
+       change_mode     MMODE_GOTO_PREDEF, MMODE_MAIN
+       bsr             start_menu_box
+       jmp             vbl_end
+0:
+       cmp.b           #2,d1
+       bne             0f
+       change_mode     MMODE_JMP_ADDR, MMODE_MAIN
+       bsr             start_menu_box
+       jmp             vbl_end
+0:
+       cmp.b           #3,d1
+       bne             0f
+       bchg.l          #4,d6
+       jmp             vbl_end
+0:
+
+msm_no_a:
+       move.w          d0,d1
+       and.w           #0x3000,d1
+       beq             msm_no_bc
+       bra             return_to_main
+
+msm_no_bc:
+       jmp             vbl_end
+
+start_menu_box:
+       movea.l         #0xe000+10*2+8*64*2,a1
+       move.w          #10-1,d1
+0:
+       move.w          a1,a0
+       jsr             load_prepare
+       move.w          #20-1,d0
+1:
+       move.w          #0,(a0)
+       dbra            d0,1b
+
+       add.w           #64*2,a1
+       dbra            d1,0b
+       rts
+
+################### goto predef ##################
+
+mode_goto_predef:
+       /* frame */
+       movea.l         #0xe000+14*2+8*64*2,a1
+       move.l          #predef_addr_cnt+2-1,d1
+0:
+       move.w          a1,a0
+       jsr             load_prepare
+       moveq.l         #10-1,d0
+1:
+       move.w          #0,(a0)
+       dbra            d0,1b
+
+       add.w           #64*2,a1
+       dbra            d1,0b
+
+       /* draw addresses */
+       movea.l         #0xe000+17*2+9*64*2,a1
+       lea             predef_addrs,a2
+       move.w          #predef_addr_cnt-1,d4
+       move.l          #0x8006,d3
+mgp_da_loop:
+       move.w          a1,a0
+       jsr             load_prepare
+       move.l          (a2)+,d2
+       jsr             print_hex_preped
+       add.w           #64*2,a1
+       dbra            d4,mgp_da_loop
+
+       /* cursor */
+       movea.l         #0xe000+15*2+9*64*2,a0
+       moveq.l         #0,d0
+       move.b          d5,d0
+       lsl.w           #7,d0
+       add.w           d0,a0
+       jsr             load_prepare
+       move.w          #'>',(a0)
+
+       /* input */
+       jsr             get_input       /* x0cbrldu x1sa00du */
+
+       move.w          d0,d1
+       and.w           #3,d1
+       beq             mgp_no_ud
+       btst.l          #0,d0
+       sne             d2
+       or.b            #1,d2           /* up -1, down 1 */
+       add.b           d2,d5
+       cmp.b           #0,d5
+       bge             0f
+       move.b          #predef_addr_cnt-1,d5
+0:
+       cmp.b           #predef_addr_cnt-1,d5
+       ble             0f
+       move.b          #0,d5
+0:
+       jmp             vbl_end
+
+mgp_no_ud:
+       btst.l          #4,d0           /* A - confirm */
+       beq             mgp_no_a
+       moveq.l         #0,d0
+       move.b          d5,d0
+       lsl.w           #2,d0
+       lea             predef_addrs,a0
+       move.l          (a0,d0),d5
+       lsl.l           #8,d5
+       jmp             mode_goto_finish
+
+mgp_no_a:
+       move.w          d0,d1
+       and.w           #0x3000,d1
+       beq             mgp_no_bc
+       bra             return_to_main
+
+mgp_no_bc:
+       jmp             vbl_end
+
+##################### jmp ########################
+
+mode_jmp_addr:
+       btst.l          #7,d6
+       bne             mode_jmp_finish
+
+       moveq.l         #0,d5
+       or.b            #3,d5           /* 3 bytes */
+       bclr.l          #7,d6
+       change_mode     MMODE_VAL_INPUT, MMODE_JMP_ADDR
+       jmp             vbl_end
+
+mode_jmp_finish:
+       lsr.l           #8,d5
+       write_vdp_r_dst 1,(VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL)       /* disable vint */
+       move.l          d5,a0
+       jmp             (a0)
+
+
 # go back to main mode
 return_to_main:
-       bclr.l          #7,d6
+       bclr.l          #7,d6           /* not edited */
        change_mode     MMODE_MAIN, MMODE_MAIN
-       write_vdp_reg   12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320)
+       write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320),(GFXCNTL)
        jmp             vbl_end
 
 
@@ -685,7 +1204,7 @@ return_to_main:
 init_gfx:
        move.l          #GFXCNTL,a3
        write_vdp_reg   0,(VDP0_E_DISPLAY | VDP0_PLTT_FULL)
-       write_vdp_reg   1,(VDP1_E_VBI | VDP1_E_DISPLAY | VDP1_E_DMA | VDP1_RESERVED)
+       write_vdp_reg   1,(VDP1_E_VBI | VDP1_E_DISPLAY | VDP1_MODE5)
        write_vdp_reg   2,(0xe000 >> 10)        /* Screen map a adress */
        write_vdp_reg   3,(0xe000 >> 10)        /* Window address */
        write_vdp_reg   4,(0xc000 >> 13)        /* Screen map b address */
@@ -703,6 +1222,71 @@ init_gfx:
        rts
 
 
+# get mask of bits representing safe words
+#  a1 - address to check
+#  destroys d0-d2, strips upper bits from a1
+get_safety_mask:
+       move.l          a1,d1
+       lsl.l           #8,d1
+       lsr.l           #8,d1
+       lea             safe_addrs,a1
+       move.w          #(safe_addrs_end - safe_addrs)/8-1,d2
+0:
+       move.l          (a1)+,d0
+       cmp.l           d0,d1
+       blt             1f
+       move.l          (a1),d0
+       cmp.l           d0,d1
+       ble             addr_safe
+1:
+       addq.l          #4,a1
+       dbra            d2,0b
+
+       move.l          d1,a1
+
+       moveq.l         #0x0c,d0
+       cmp.l           #0xa14000,d1
+       beq             gsm_rts
+
+       moveq.l         #0x08,d0
+       cmp.l           #0xa14100,d1
+       beq             gsm_rts
+
+       /* check for VDP address */
+       move.l          d1,d0
+       swap            d0
+       and.b           #0xe0,d0
+       cmp.b           #0xc0,d0
+       bne             addr_unsafe     /* not vdp */
+
+       move.l          d1,d0
+       and.l           #0x0700e0,d0
+       bne             addr_unsafe
+
+       move.l          d1,d0
+       and.b           #0x1f,d0
+       cmp.b           #0x04,d0
+       blt             addr_hsafe_3    /* data port */
+       cmp.b           #0x10,d0
+       blt             addr_safe       /* below PSG */
+       cmp.b           #0x18,d0
+       bge             addr_safe       /* above PSG */
+
+addr_unsafe:
+       moveq.l         #0,d0           /* skip line */
+       rts
+
+addr_hsafe_3:
+       moveq.l         #3,d0           /* skip 2 words */
+       rts
+
+addr_safe:
+       move.l          d1,a1
+       moveq.l         #0xf,d0
+gsm_rts:
+       rts
+
+
 # read single phase from controller
 #  #a0 - addr
 #  d0 - result
@@ -729,38 +1313,17 @@ get_input:
 
        addq.b          #1,d6
        move.b          d6,d2
-       and.b           #7,d2           /* do autorepeat every 8 frames */
-       cmp.b           #7,d2
+       and.b           #0x0f,d2        /* do autorepeat */
+       cmp.b           #9,d2
        bne             1f
        move.w          d0,d1
 0:
-       and.b           #0xf8,d6
+       and.b           #0xf0,d6
 1:
        swap            d0
        move.w          d1,d0
        rts
 
-# Load tile data from ROM
-#  a0: VRAM base
-#  a1: pattern address
-#  d0: number of tiles to load
-#  destroys d1
-
-load_tiles:
-       move.l          d0,d1
-       VRAM_ADDR_var   a0
-       move.l          d0,(GFXCNTL).l
-       
-       move.l          #GFXDATA,a0
-       lsl.w           #3,d1
-       subq.l          #1,d1
-0:
-       move.l          (a1)+,(a0)
-       dbra            d1,0b
-
-       rts
-
-
 # Prepare to write to VDP RAM @a0
 # sets a0 to VDP data port for convenience
 #  a0: VRAM base
@@ -822,7 +1385,7 @@ _print_end:
 #  d0 - x
 #  d1 - y 
 #  d2 - value
-#  d3 - digit_cnt[0:7]|tile_bits[11:15]
+#  d3 - tile_bits[15:11]|digit_cnt[7:0]
 #  destroys a0, preserves d3
 
 print_hex:
@@ -855,11 +1418,7 @@ _print_hex_loop:
        rts
 
 
-#################################################
-#                                               #
-#       Wait for next VBlank interrupt          #
-#                                               #
-#################################################
+# wait vertical sync
 
 wait_vsync:
        move.b          d7,d0