1 ###############################################################################
3 # Copyright (c) 2009, GraÅžvydas Ignotas
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions are met:
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above copyright
11 # notice, this list of conditions and the following disclaimer in the
12 # documentation and/or other materials provided with the distribution.
13 # * Neither the name of the organization nor the
14 # names of its contributors may be used to endorse or promote products
15 # derived from this software without specific prior written permission.
17 # THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
18 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 # DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
21 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 # --register-prefix-optional --bitwise-or
33 .equ RELOCATE_TO_RAM, 0
40 ##################################################
42 # Register and bitmask definitions #
44 ##################################################
46 .equ GFXDATA, 0xc00000
47 .equ GFXCNTL, 0xc00004
50 .equ VDP0_E_DISPLAY, 0x02
51 .equ VDP0_PLTT_FULL, 0x04
53 .equ VDP1_SMS_MODE, 0x80
54 .equ VDP1_E_DISPLAY, 0x40
62 .equ VDP12_SCREEN_V224, 0x00
63 .equ VDP12_SCREEN_V448, 0x04
64 .equ VDP12_PROGRESSIVE, 0x00
65 .equ VDP12_INTERLACED, 0x02
66 .equ VDP12_SCREEN_H256, 0x00
67 .equ VDP12_SCREEN_H320, 0x81
69 .equ VDP16_MAP_V32, 0x00
70 .equ VDP16_MAP_V64, 0x10
71 .equ VDP16_MAP_V128, 0x30
72 .equ VDP16_MAP_H32, 0x00
73 .equ VDP16_MAP_H64, 0x01
74 .equ VDP16_MAP_H128, 0x03
77 .equ MMODE_VAL_INPUT, 1
78 .equ MMODE_EDIT_VAL, 2
80 .equ MMODE_START_MENU, 4
81 .equ MMODE_GOTO_PREDEF, 5
82 .equ MMODE_JMP_ADDR, 6
84 .equ predef_addr_cnt, ((predef_addrs_end-predef_addrs)/4)
86 ##################################################
90 ##################################################
93 # Write val to VDP register reg
94 .macro write_vdp_r_dst reg val dst
95 move.w #((\reg << 8) + 0x8000 + \val),\dst
98 # Write val to VDP register reg, vdp addr in a3
99 .macro write_vdp_reg reg val
100 write_vdp_r_dst \reg, \val, (a3)
103 # Set up address in VDP, control port in dst
104 .macro VRAM_ADDR adr dst
105 move.l #(((0x4000 | (\adr & 0x3fff)) << 16) | (\adr >> 14)),\dst
109 # make VDP word from address adr and store in d0
110 .macro XRAM_ADDR_var adr
120 .macro VRAM_ADDR_var adr
126 .macro CRAM_ADDR_var adr
132 # convert tile coords in d0, d1 to nametable addr to a0
141 # check if some d-pad button (and modifier) is pressed
142 .macro do_dpad bit op val
150 # convert a6 to normal addr
152 .macro mk_a6_addr reg
160 .macro change_mode mode_new mode_back
162 or.w #(\mode_back<<11)|(\mode_new<<8),d7
165 .macro menu_text str x y pal
169 move.l #0x8000|(\pal<<13),d2
173 #################################################
177 #################################################
180 dc.w 0x0000,0x0eee,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
181 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
182 dc.w 0x0000,0x02e2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
183 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
184 dc.w 0x0000,0x0e44,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
185 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
186 dc.w 0x0000,0x044e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
187 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
192 /* Y size link attr X */
193 dc.w 0; dc.b 0x05; dc.b 0; dc.w 0x6002; dc.w 0
197 dc.l 0x000000, 0x200000, 0x400000, 0xa00000, 0xa10000
198 dc.l 0xa11100, 0xa12000, 0xa13000, 0xa14000, 0xc00000
202 dc.l 0x000000, 0x7fffff
203 dc.l 0xe00000, 0xffffff
204 dc.l 0xa00000, 0xa100ff
205 dc.l 0xa11000, 0xa113ff
206 dc.l 0xa12000, 0xa120ff
207 dc.l 0xa13000, 0xa130ff
217 .ascii "Go to address\0"
219 .ascii "Go to (predef)\0"
221 .ascii "Jump to address\0"
223 .ascii "DTACK safety\0"
225 .ascii "DTACK err?\0"
227 .ascii "Exception \0"
229 ##################################################
233 ##################################################
236 # a6 = page_start[31:8]|cursor_offs[7:0]
237 # d7 = old_inputs[31:16]|edit_bytes[15:14]|g_mode_old[13:11]|g_mode[10:8]|irq_cnt[7:0]
238 # d6 = edit_word_save[31:15]|edit_done[7]|no_dtack_detect[4]|autorep_cnt[3:0]
240 # edit: edit_word[31:8]|edit_pos[4:2]|byte_cnt[1:0]
246 /* mask irqs during init */
258 /* copy, assume 8K size */
259 move.w #0x2000/8-1,d0
278 move.b #0x40,(0xa10009).l
279 move.b #0x40,(0xa10003).l
284 /* Load color data */
287 moveq.l #(colors_end-colors)/2,d0
290 /* load font patterns */
293 VRAM_ADDR 0,(GFXCNTL)
305 rol.l #1,d1 /* fixup */
309 /* generate A layer map */
317 0: move.l #0x00000000,(a0)
323 /* generate B layer map */
328 0: move.l #0x00000000,(a0)
331 /* upload sprite data */
334 lea (sprite_data,pc),a1
336 move.l #(sprite_data_end-sprite_data)/2-1,d3
341 /* wait for vsync before unmask */
344 /* wait a bit to avoid nested vint */
347 dbra d0,0b /* 10 cycles to go back */
349 /* enable and unmask vint */
350 write_vdp_r_dst 1,(VDP1_E_VBI | VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL)
354 ##################################################
367 /* let's hope VRAM is already set up.. */
375 ##################################################
379 # movem.l d0-d4/a0-a5,-(a7)
385 lea (jumptab,pc,d0),a0
390 bra mode_edit_val /* edit val in editor */
397 ##################### main #######################
400 /* assume we will hang */
401 lea (txt_dtack_err,pc),a0
411 move.l d0,a1 /* current addr */
414 add.b #27-1,d1 /* line where the cursor sits */
418 move.l #27-1,d5 /* line counter for dbra */
441 # unsafe or partially safe
444 swap d4 /* mask in upper word */
446 bne draw_row_hsafe_words_pre
448 draw_row_hsafe_bytes_pre:
453 draw_row_hsafe_bytes:
459 move.l #'?'|('?'<<16),(a0)
461 move.l #'?'|('?'<<16),(a0)
471 dbra d4,draw_row_hsafe_bytes
478 beq draw_cursor_unsafe_byte
479 bra draw_chars_hsafe_pre
481 draw_row_hsafe_words_pre:
486 draw_row_hsafe_words:
492 move.l #'?'|('?'<<16),(a0)
493 move.l #'?'|('?'<<16),(a0)
500 dbra d4,draw_row_hsafe_words
502 move.l #(' '<<16)|' ',(a0)
507 beq draw_cursor_unsafe_word
509 draw_chars_hsafe_pre:
519 move.l #'?'|('?'<<16),(a0)
520 bra draw_chars_hsafe_next
522 btst.l #15,d7 /* must perform correct read type */
523 bne 0f /* doing byte reads on security reg hangs */
550 draw_chars_hsafe_next:
552 dbra d4,draw_chars_hsafe
554 move.l #(' '<<16)|' ',(a0)
593 move.l #(' '<<16)|' ',(a0)
615 move.l #(' '<<16)|' ',(a0)
637 move.l #' '|(' '<<16),(a0)
638 move.l #' '|(' '<<16),(a0)
643 jsr get_input /* x0cbrldu x1sa00du */
645 btst.l #16+4,d0 /* A - scroll modifier */
648 do_dpad 16+0, sub, #0x0800
649 do_dpad 16+1, add, #0x0800
650 do_dpad 16+10, sub, #0xd800
651 do_dpad 16+11, add, #0xd800
658 do_dpad 0, subq, #0x0008
659 do_dpad 1, addq, #0x0008
680 btst.l #12,d0 /* B - switch byte/word mode */
683 add.w #0x4000,d7 /* changes between 01 10 */
686 sub.l d1,a6 /* make even, just in case */
689 btst.l #13,d0 /* C - edit selected byte */
692 change_mode MMODE_EDIT_VAL, MMODE_MAIN
693 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
696 btst.l #5,d0 /* Start - menu */
700 change_mode MMODE_START_MENU, MMODE_MAIN
701 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
705 # movem.l (a7)+,d0-d4/a0-a5
713 draw_cursor_unsafe_byte:
715 and.l #7,d0 /* byte offs */
718 add.b d1,d0 /* d0 *= 3 (chars) */
722 move.l #(0x2000|'?'|((0x2000|'?')<<16)),(a0)
726 jsr load_prepare /* restore a0 */
727 bra draw_chars_hsafe_pre
729 draw_cursor_unsafe_word:
731 and.l #7,d0 /* byte offs */
733 lsr.b #1,d1 /* which word */
736 add.b d2,d1 /* num of chars to skip */
741 move.l #(0x2000|'?'|((0x2000|'?')<<16)),d0
747 jsr load_prepare /* restore a0 */
748 bra draw_chars_hsafe_pre
753 and.l #7,d0 /* byte offs */
759 add.b d1,d0 /* d0 *= 3 (chars) */
767 jsr load_prepare /* restore a0 */
773 and.l #7,d0 /* byte offs */
775 lsr.b #1,d1 /* which word */
778 add.b d2,d1 /* num of chars to skip */
789 jsr load_prepare /* restore a0 */
794 #################### hedit #######################
798 bne mode_hedit_finish
800 /* read val to edit */
816 change_mode MMODE_VAL_INPUT, MMODE_EDIT_VAL
835 ##################### goto #######################
846 or.b #3,d5 /* 3 bytes */
848 change_mode MMODE_VAL_INPUT, MMODE_GOTO
868 ################### val edit #####################
872 movea.l #0xe000+14*2+11*64*2,a1
892 lea (txt_a_confirm,pc),a0
903 and.b #3,d3 /* edit field bytes */
921 lsr.b #1,d1 /* length in bytes */
925 and.b #7,d1 /* nibble to edit */
929 sub.b #1,d3 /* chars to shift out */
940 jsr get_input /* x0cbrldu x1sa00du */
947 add.b d1,d1 /* nibble count */
948 sub.b #1,d1 /* max n.t.e. val */
951 and.b #7,d2 /* nibble to edit */
963 lsl.l d1,d3 /* mask */
964 lsl.l d1,d4 /* what to add/sub */
1009 btst.l #4,d0 /* A - confirm */
1012 move.w d7,d1 /* back to prev mode */
1022 ################### start menu ###################
1029 menu_text txt_about, 13, 9, 1
1030 menu_text txt_goto, 13, 11, 0
1031 menu_text txt_goto_predef, 13, 12, 0
1032 menu_text txt_jmp_addr, 13, 13, 0
1033 menu_text txt_dtack, 13, 14, 0
1034 menu_text txt_a_confirm, 13, 16, 2
1036 /* dtack safety on/off */
1037 movea.l #0xe000+26*2+14*64*2,a0
1039 move.w #0x8000|'O',(a0)
1042 move.w #0x8000|'N',(a0)
1045 move.w #0x8000|'F',(a0)
1046 move.w #0x8000|'F',(a0)
1050 movea.l #0xe000+11*2+11*64*2,a0
1060 jsr get_input /* x0cbrldu x1sa00du */
1069 or.b #1,d2 /* up -1, down 1 */
1084 btst.l #4,d0 /* A - confirm */
1089 change_mode MMODE_GOTO, MMODE_MAIN
1096 change_mode MMODE_GOTO_PREDEF, MMODE_MAIN
1102 change_mode MMODE_JMP_ADDR, MMODE_MAIN
1122 movea.l #0xe000+10*2+8*64*2,a1
1136 ################### goto predef ##################
1140 movea.l #0xe000+14*2+8*64*2,a1
1141 move.l #predef_addr_cnt+2-1,d1
1153 /* draw addresses */
1154 movea.l #0xe000+17*2+9*64*2,a1
1155 lea (predef_addrs,pc),a2
1156 move.w #predef_addr_cnt-1,d4
1162 jsr print_hex_preped
1167 movea.l #0xe000+15*2+9*64*2,a0
1176 jsr get_input /* x0cbrldu x1sa00du */
1183 or.b #1,d2 /* up -1, down 1 */
1187 move.b #predef_addr_cnt-1,d5
1189 cmp.b #predef_addr_cnt-1,d5
1196 btst.l #4,d0 /* A - confirm */
1201 lea (predef_addrs,pc),a0
1204 bra mode_goto_finish
1215 ##################### jmp ########################
1222 or.b #3,d5 /* 3 bytes */
1224 change_mode MMODE_VAL_INPUT, MMODE_JMP_ADDR
1229 write_vdp_r_dst 1,(VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL) /* disable vint */
1234 # go back to main mode
1236 bclr.l #7,d6 /* not edited */
1237 change_mode MMODE_MAIN, MMODE_MAIN
1238 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320),(GFXCNTL)
1242 #################################################
1244 # Initialize VDP registers #
1246 #################################################
1250 write_vdp_reg 0,(VDP0_E_DISPLAY | VDP0_PLTT_FULL)
1251 write_vdp_reg 1,(VDP1_E_DISPLAY | VDP1_MODE5)
1252 write_vdp_reg 2,(0xe000 >> 10) /* Screen map a adress */
1253 write_vdp_reg 3,(0xe000 >> 10) /* Window address */
1254 write_vdp_reg 4,(0xc000 >> 13) /* Screen map b address */
1255 write_vdp_reg 5,(0xfc00 >> 9) /* Sprite address */
1257 write_vdp_reg 7,0 /* Backdrop color */
1258 write_vdp_reg 10,1 /* Lines per hblank interrupt */
1259 write_vdp_reg 11,0 /* 2-cell vertical scrolling */
1260 write_vdp_reg 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320)
1261 write_vdp_reg 13,(0x8000 >> 10) /* Horizontal scroll address */
1263 write_vdp_reg 16,(VDP16_MAP_V32 | VDP16_MAP_H64) /* layer size */
1265 write_vdp_reg 18,0xff
1269 # get mask of bits representing safe words
1270 # a1 - address to check
1271 # destroys d0-d2, strips upper bits from a1
1276 lea (safe_addrs,pc),a1
1277 move.w #(safe_addrs_end - safe_addrs)/8-1,d2
1299 /* check for VDP address */
1304 bne addr_unsafe /* not vdp */
1313 blt addr_hsafe_3 /* data port */
1315 blt addr_safe /* below PSG */
1317 bge addr_safe /* above PSG */
1320 moveq.l #0,d0 /* skip line */
1324 moveq.l #3,d0 /* skip 2 words */
1334 # read single phase from controller
1339 move.b #0x40,(0xa10003)
1343 move.b (0xa10003),d0
1344 move.b #0x00,(0xa10003)
1347 move.b (0xa10003),d0
1352 eor.w d0,d1 /* changed btns */
1353 move.w d0,d7 /* old val */
1355 and.w d0,d1 /* what changed now */
1360 and.b #0x0f,d2 /* do autorepeat */
1371 # Prepare to write to VDP RAM @a0
1372 # sets a0 to VDP data port for convenience
1378 move.l d0,(GFXCNTL).l
1383 # Load color data from ROM
1385 # a1: color list address
1386 # d0: number of colors to load
1392 move.l d0,(GFXCNTL).l
1407 # d2 - tile_bits[15:11]
1432 # d3 - tile_bits[15:11]|digit_cnt[7:0]
1433 # destroys a0, preserves d3
1444 ror.l d0,d2 /* prep value */
1445 subq.l #1,d1 /* count */
1447 and.w #0xf800,d0 /* keep upper bits in d0 */
1460 dbra d1,_print_hex_loop
1465 # wait vertical sync interrupt
1476 # wait vsync start (polling)
1496 #################################################
1500 #################################################
1508 # vim:filetype=asmM68k