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
85 .equ predef_addr_cnt, ((predef_addrs_end-predef_addrs)/4)
87 ##################################################
91 ##################################################
94 # Write val to VDP register reg
95 .macro write_vdp_r_dst reg val dst
96 move.w #((\reg << 8) + 0x8000 + \val),\dst
99 # Write val to VDP register reg, vdp addr in a3
100 .macro write_vdp_reg reg val
101 write_vdp_r_dst \reg, \val, (a3)
104 # Set up address in VDP, control port in dst
105 .macro VRAM_ADDR adr dst
106 move.l #(0x40000000 | ((\adr & 0x3fff) << 16) | (\adr >> 14)),\dst
109 .macro VSRAM_ADDR adr dst
110 move.l #(0x40000010 | ((\adr & 0x3fff) << 16) | (\adr >> 14)),\dst
114 # make VDP word from address adr and store in d0
115 .macro XRAM_ADDR_var adr
125 .macro VRAM_ADDR_var adr
131 .macro CRAM_ADDR_var adr
137 # convert tile coords in d0, d1 to nametable addr to a0
146 # check if some d-pad button (and modifier) is pressed
147 .macro do_dpad bit op val
155 # convert a6 to normal addr
157 .macro mk_a6_addr reg
165 .macro change_mode mode_new mode_back
167 or.w #(\mode_back<<11)|(\mode_new<<8),d7
171 .macro menu_text str x y pal
175 move.l #0x8000|(\pal<<13),d2
179 #################################################
183 #################################################
186 dc.w 0x0000,0x0eee,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
187 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
188 dc.w 0x0000,0x02e2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
189 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
190 dc.w 0x0000,0x0e44,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
191 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
192 dc.w 0x0000,0x044e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
193 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
198 /* Y size link attr X */
199 dc.w 0; dc.b 0x05; dc.b 0; dc.w 0x6002; dc.w 0
203 dc.l 0x000000, 0x200000, 0x400000, 0xa00000, 0xa10000
204 dc.l 0xa11100, 0xa12000, 0xa13000, 0xa14000, 0xc00000
208 dc.l 0x000000, 0x7fffff
209 dc.l 0xe00000, 0xffffff
210 dc.l 0xa00000, 0xa100ff
211 dc.l 0xa11000, 0xa113ff
212 dc.l 0xa12000, 0xa120ff
213 dc.l 0xa13000, 0xa130ff
217 dc.l 0x000000 /* 1 for recv */
230 .ascii "Go to address\0"
232 .ascii "Go to (predef)\0"
234 .ascii "Jump to address\0"
238 .ascii "DTACK safety\0"
240 .ascii "Ready to send\0"
242 .ascii "Ready to recv\0"
244 .ascii "Working.. \0"
246 .ascii "DTACK err?\0"
248 .ascii "Exception \0"
250 ##################################################
254 ##################################################
257 # a6 = page_start[31:8]|cursor_offs[7:0]
258 # d7 = old_inputs[31:16]|edit_bytes[15:14]|g_mode_old[13:11]|g_mode[10:8]|irq_cnt[7:0]
259 # d6 = edit_word_save[31:15]|edit_done[7]|no_dtack_detect[4]|autorep_cnt[3:0]
261 # edit: edit_word[31:8]|edit_pos[4:2]|byte_cnt[1:0]
267 /* mask irqs during init */
271 /* copy to expansion device if magic number is set */
277 move.w #0x2000/8-1,d0
286 /* copy, assume 8K size */
289 move.w #0x2000/8-1,d0
306 move.b #0x40,(0xa10009).l
307 move.b #0x40,(0xa10003).l
312 /* Clear h/v scroll */
314 VRAM_ADDR 0x8000,(GFXCNTL)
316 VSRAM_ADDR 0,(GFXCNTL)
319 /* Load color data */
322 moveq.l #(colors_end-colors)/2,d0
325 /* load font patterns */
328 VRAM_ADDR 0,(GFXCNTL)
340 rol.l #1,d1 /* fixup */
344 /* generate A layer map */
352 0: move.l #0x00000000,(a0)
358 /* generate B layer map */
363 0: move.l #0x00000000,(a0)
366 /* upload sprite data */
369 lea (sprite_data,pc),a1
371 move.l #(sprite_data_end-sprite_data)/2-1,d3
376 /* wait for vsync before unmask */
379 /* wait a bit to avoid nested vint */
382 dbra d0,0b /* 10 cycles to go back */
384 /* enable and unmask vint */
385 write_vdp_r_dst 1,(VDP1_E_VBI | VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL)
389 ##################################################
402 /* let's hope VRAM is already set up.. */
410 ##################################################
414 # movem.l d0-d4/a0-a5,-(a7)
420 lea (jumptab,pc,d0),a0
425 bra mode_edit_val /* edit val in editor */
432 ##################### main #######################
435 /* assume we will hang */
436 lea (txt_dtack_err,pc),a0
446 move.l d0,a1 /* current addr */
449 add.b #27-1,d1 /* line where the cursor sits */
453 move.l #27-1,d5 /* line counter for dbra */
476 # unsafe or partially safe
479 swap d4 /* mask in upper word */
481 bne draw_row_hsafe_words_pre
483 draw_row_hsafe_bytes_pre:
488 draw_row_hsafe_bytes:
494 move.l #'?'|('?'<<16),(a0)
496 move.l #'?'|('?'<<16),(a0)
506 dbra d4,draw_row_hsafe_bytes
513 beq draw_cursor_unsafe_byte
514 bra draw_chars_hsafe_pre
516 draw_row_hsafe_words_pre:
521 draw_row_hsafe_words:
527 move.l #'?'|('?'<<16),(a0)
528 move.l #'?'|('?'<<16),(a0)
535 dbra d4,draw_row_hsafe_words
537 move.l #(' '<<16)|' ',(a0)
542 beq draw_cursor_unsafe_word
544 draw_chars_hsafe_pre:
554 move.l #'?'|('?'<<16),(a0)
555 bra draw_chars_hsafe_next
557 btst.l #15,d7 /* must perform correct read type */
558 bne 0f /* doing byte reads on security reg hangs */
585 draw_chars_hsafe_next:
587 dbra d4,draw_chars_hsafe
589 move.l #(' '<<16)|' ',(a0)
628 move.l #(' '<<16)|' ',(a0)
650 move.l #(' '<<16)|' ',(a0)
672 move.l #' '|(' '<<16),(a0)
673 move.l #' '|(' '<<16),(a0)
678 jsr get_input /* x0cbrldu x1sa00du */
680 btst.l #16+4,d0 /* A - scroll modifier */
683 do_dpad 16+0, sub, #0x0800
684 do_dpad 16+1, add, #0x0800
685 do_dpad 16+10, sub, #0xd800
686 do_dpad 16+11, add, #0xd800
693 do_dpad 0, subq, #0x0008
694 do_dpad 1, addq, #0x0008
715 btst.l #12,d0 /* B - switch byte/word mode */
718 add.w #0x4000,d7 /* changes between 01 10 */
721 sub.l d1,a6 /* make even, just in case */
724 btst.l #13,d0 /* C - edit selected byte */
727 change_mode MMODE_EDIT_VAL, MMODE_MAIN
728 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
731 btst.l #5,d0 /* Start - menu */
735 change_mode MMODE_START_MENU, MMODE_MAIN
736 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
740 # movem.l (a7)+,d0-d4/a0-a5
748 draw_cursor_unsafe_byte:
750 and.l #7,d0 /* byte offs */
753 add.b d1,d0 /* d0 *= 3 (chars) */
757 move.l #(0x2000|'?'|((0x2000|'?')<<16)),(a0)
761 jsr load_prepare /* restore a0 */
762 bra draw_chars_hsafe_pre
764 draw_cursor_unsafe_word:
766 and.l #7,d0 /* byte offs */
768 lsr.b #1,d1 /* which word */
771 add.b d2,d1 /* num of chars to skip */
776 move.l #(0x2000|'?'|((0x2000|'?')<<16)),d0
782 jsr load_prepare /* restore a0 */
783 bra draw_chars_hsafe_pre
788 and.l #7,d0 /* byte offs */
794 add.b d1,d0 /* d0 *= 3 (chars) */
802 jsr load_prepare /* restore a0 */
808 and.l #7,d0 /* byte offs */
810 lsr.b #1,d1 /* which word */
813 add.b d2,d1 /* num of chars to skip */
824 jsr load_prepare /* restore a0 */
829 #################### hedit #######################
833 bne mode_hedit_finish
835 /* read val to edit */
851 change_mode MMODE_VAL_INPUT, MMODE_EDIT_VAL
870 ##################### goto #######################
881 or.b #3,d5 /* 3 bytes */
883 change_mode MMODE_VAL_INPUT, MMODE_GOTO
903 ################### val edit #####################
907 movea.l #0xe000+14*2+11*64*2,a1
927 lea (txt_a_confirm,pc),a0
938 and.b #3,d3 /* edit field bytes */
956 lsr.b #1,d1 /* length in bytes */
960 and.b #7,d1 /* nibble to edit */
964 sub.b #1,d3 /* chars to shift out */
975 jsr get_input /* x0cbrldu x1sa00du */
982 add.b d1,d1 /* nibble count */
983 sub.b #1,d1 /* max n.t.e. val */
986 and.b #7,d2 /* nibble to edit */
998 lsl.l d1,d3 /* mask */
999 lsl.l d1,d4 /* what to add/sub */
1010 eor.l #0xffffffff,d3
1044 btst.l #4,d0 /* A - confirm */
1047 move.w d7,d1 /* back to prev mode */
1057 ################### start menu ###################
1064 menu_text txt_about, 13, 9, 1
1065 menu_text txt_goto, 13, 11, 0
1066 menu_text txt_goto_predef, 13, 12, 0
1067 menu_text txt_jmp_addr, 13, 13, 0
1068 menu_text txt_dump, 13, 14, 0
1069 menu_text txt_dtack, 13, 15, 0
1070 menu_text txt_a_confirm, 13, 17, 2
1072 /* dtack safety on/off */
1073 movea.l #0xe000+26*2+15*64*2,a0
1075 move.w #0x8000|'O',(a0)
1078 move.w #0x8000|'N',(a0)
1081 move.w #0x8000|'F',(a0)
1082 move.w #0x8000|'F',(a0)
1086 movea.l #0xe000+11*2+11*64*2,a0
1096 jsr get_input /* x0cbrldu x1sa00du */
1105 or.b #1,d2 /* up -1, down 1 */
1120 btst.l #4,d0 /* A - confirm */
1125 change_mode MMODE_GOTO, MMODE_MAIN
1132 change_mode MMODE_GOTO_PREDEF, MMODE_MAIN
1138 change_mode MMODE_JMP_ADDR, MMODE_MAIN
1144 change_mode MMODE_DUMP, MMODE_MAIN
1164 movea.l #0xe000+10*2+8*64*2,a1
1178 ################### goto predef ##################
1182 movea.l #0xe000+14*2+8*64*2,a1
1183 move.l #predef_addr_cnt+2-1,d1
1195 /* draw addresses */
1196 movea.l #0xe000+17*2+9*64*2,a1
1197 lea (predef_addrs,pc),a2
1198 move.w #predef_addr_cnt-1,d4
1204 jsr print_hex_preped
1209 movea.l #0xe000+15*2+9*64*2,a0
1218 jsr get_input /* x0cbrldu x1sa00du */
1225 or.b #1,d2 /* up -1, down 1 */
1229 move.b #predef_addr_cnt-1,d5
1231 cmp.b #predef_addr_cnt-1,d5
1238 btst.l #4,d0 /* A - confirm */
1243 lea (predef_addrs,pc),a0
1246 bra mode_goto_finish
1257 ##################### jmp ########################
1264 or.b #3,d5 /* 3 bytes */
1266 change_mode MMODE_VAL_INPUT, MMODE_JMP_ADDR
1271 write_vdp_r_dst 1,(VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL) /* disable vint */
1275 ################### transfer #####################
1278 move.b #0x40,(0xa1000b).l
1279 move.b #0x40,(0xa10005).l
1281 move.l (transfer_mode,pc),d0
1284 lea (txt_ready_send,pc),a0
1287 lea (txt_ready_recv,pc),a0
1295 move.b (0xa10005),d0
1299 menu_text txt_working, 13, 13, 0
1302 move.l (transfer_addr,pc),a0
1303 move.l (transfer_len,pc),d2
1305 move.l (transfer_mode,pc),d0
1310 move.b #0x4f,(0xa1000b).l
1321 move.b d1,(a1) /* clears TH and writes data */
1325 bset.b #6,d1 /* prepare TH */
1336 move.b #0,(0xa1000b).l
1340 move.b #0,(a1) /* clear TH */
1348 move.b #0x40,(a1) /* set TH */
1357 move.b #0,(a1) /* clear TH */
1365 move.b #0,(0xa1000b).l
1369 # go back to main mode
1371 bclr.l #7,d6 /* not edited */
1372 change_mode MMODE_MAIN, MMODE_MAIN
1373 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320),(GFXCNTL)
1377 #################################################
1379 # Initialize VDP registers #
1381 #################################################
1385 write_vdp_reg 0,(VDP0_E_DISPLAY | VDP0_PLTT_FULL)
1386 write_vdp_reg 1,(VDP1_E_DISPLAY | VDP1_MODE5)
1387 write_vdp_reg 2,(0xe000 >> 10) /* Screen map a adress */
1388 write_vdp_reg 3,(0xe000 >> 10) /* Window address */
1389 write_vdp_reg 4,(0xc000 >> 13) /* Screen map b address */
1390 write_vdp_reg 5,(0xfc00 >> 9) /* Sprite address */
1392 write_vdp_reg 7,0 /* Backdrop color */
1393 write_vdp_reg 0x0a,1 /* Lines per hblank interrupt */
1394 write_vdp_reg 0x0b,0 /* 2-cell vertical scrolling */
1395 write_vdp_reg 0x0c,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320)
1396 write_vdp_reg 0x0d,(0x8000 >> 10) /* Horizontal scroll address */
1397 write_vdp_reg 0x0e,0
1398 write_vdp_reg 0x0f,2
1399 write_vdp_reg 0x10,(VDP16_MAP_V32 | VDP16_MAP_H64) /* layer size */
1400 write_vdp_reg 0x11,0
1401 write_vdp_reg 0x12,0
1405 # get mask of bits representing safe words
1406 # a1 - address to check
1407 # destroys d0-d2, strips upper bits from a1
1412 lea (safe_addrs,pc),a1
1413 move.w #(safe_addrs_end - safe_addrs)/8-1,d2
1435 /* check for VDP address */
1440 bne addr_unsafe /* not vdp */
1449 blt addr_hsafe_3 /* data port */
1451 blt addr_safe /* below PSG */
1453 bge addr_safe /* above PSG */
1456 moveq.l #0,d0 /* skip line */
1460 moveq.l #3,d0 /* skip 2 words */
1470 # read single phase from controller
1475 move.b #0x40,(0xa10003)
1479 move.b (0xa10003),d0
1480 move.b #0x00,(0xa10003)
1483 move.b (0xa10003),d0
1488 eor.w d0,d1 /* changed btns */
1489 move.w d0,d7 /* old val */
1491 and.w d0,d1 /* what changed now */
1496 and.b #0x0f,d2 /* do autorepeat */
1507 # Prepare to write to VDP RAM @a0
1508 # sets a0 to VDP data port for convenience
1514 move.l d0,(GFXCNTL).l
1519 # Load color data from ROM
1521 # a1: color list address
1522 # d0: number of colors to load
1528 move.l d0,(GFXCNTL).l
1543 # d2 - tile_bits[15:11]
1568 # d3 - tile_bits[15:11]|digit_cnt[7:0]
1569 # destroys a0, preserves d3
1580 ror.l d0,d2 /* prep value */
1581 subq.l #1,d1 /* count */
1583 and.w #0xf800,d0 /* keep upper bits in d0 */
1596 dbra d1,_print_hex_loop
1601 # wait vertical sync interrupt
1612 # wait vsync start (polling)
1632 #################################################
1636 #################################################
1644 # vim:filetype=asmM68k