Add 'teensytp/' from commit 'be48e888050f18a31e788269c8f47358036a8e3b'
authornotaz <notasas@gmail.com>
Mon, 7 Dec 2015 23:54:13 +0000 (01:54 +0200)
committernotaz <notasas@gmail.com>
Mon, 7 Dec 2015 23:54:13 +0000 (01:54 +0200)
git-subtree-dir: teensytp
git-subtree-mainline: 8d788f3de66aeda55c2518b5e511111face3a82a
git-subtree-split: be48e888050f18a31e788269c8f47358036a8e3b

68 files changed:
.gitignore
hexed/Makefile [new file with mode: 0644]
hexed/font.s [new file with mode: 0644]
hexed/hexed.s [new file with mode: 0644]
hexed/md.ld [new file with mode: 0644]
hexed/pc_transfer.c [new file with mode: 0644]
hexed/readme.txt [new file with mode: 0644]
hexed/sega_gcc.s [new file with mode: 0644]
hexed/transfer.S [new file with mode: 0644]
hexed/transfer.h [new file with mode: 0644]
mdpcjoy/mdpcjoy.c [new file with mode: 0644]
mega-usb/Makefile [new file with mode: 0644]
mega-usb/mega-usb.c [new file with mode: 0644]
megaed-stop-md/Makefile [new file with mode: 0644]
megaed-stop-md/UNLICENSE [new file with mode: 0644]
megaed-stop-md/data.s [new file with mode: 0644]
megaed-stop-md/font.bin [new file with mode: 0644]
megaed-stop-md/main.c [new file with mode: 0644]
megaed-stop-md/maketest.c [new file with mode: 0644]
megaed-stop-md/sega.ld [new file with mode: 0644]
megaed-stop-md/sega_gcc.s [new file with mode: 0644]
megaed-stop/Makefile [new file with mode: 0644]
megaed-stop/UNLICENSE [new file with mode: 0644]
megaed-stop/ed_app.ld [new file with mode: 0644]
megaed-stop/edos.h [new file with mode: 0644]
megaed-stop/main.c [new file with mode: 0644]
megaed-stop/sega_gcc.s [new file with mode: 0644]
megaed-sv/Makefile [new file with mode: 0644]
megaed-sv/asmtools.h [new file with mode: 0644]
megaed-sv/asmtools.s [new file with mode: 0644]
megaed-sv/ed_app.ld [new file with mode: 0644]
megaed-sv/edos.h [new file with mode: 0644]
megaed-sv/main.c [new file with mode: 0644]
megaed-sv/sega_gcc.s [new file with mode: 0644]
mx/linux/Makefile [new file with mode: 0644]
mx/linux/mx_flasher.c [new file with mode: 0644]
mx/linux/sms2mx.c [new file with mode: 0644]
nshtest/Makefile [new file with mode: 0644]
nshtest/md.ld [new file with mode: 0644]
nshtest/sega_gcc.s [new file with mode: 0644]
nshtest/test.s [new file with mode: 0644]
teensytp/.gitignore [new file with mode: 0644]
teensytp/Makefile [moved from Makefile with 100% similarity]
teensytp/host/Makefile [moved from host/Makefile with 100% similarity]
teensytp/host/main.c [moved from host/main.c with 100% similarity]
teensytp/main.c [moved from main.c with 100% similarity]
teensytp/pkts.h [moved from pkts.h with 100% similarity]
teensytp/teensy3/avr_functions.h [moved from teensy3/avr_functions.h with 100% similarity]
teensytp/teensy3/core_pins.h [moved from teensy3/core_pins.h with 100% similarity]
teensytp/teensy3/kinetis.h [moved from teensy3/kinetis.h with 100% similarity]
teensytp/teensy3/mk20dx128.c [moved from teensy3/mk20dx128.c with 100% similarity]
teensytp/teensy3/mk20dx128.h [moved from teensy3/mk20dx128.h with 100% similarity]
teensytp/teensy3/mk20dx128.ld [moved from teensy3/mk20dx128.ld with 100% similarity]
teensytp/teensy3/mk20dx256.ld [moved from teensy3/mk20dx256.ld with 100% similarity]
teensytp/teensy3/nonstd.c [moved from teensy3/nonstd.c with 100% similarity]
teensytp/teensy3/pins_arduino.h [moved from teensy3/pins_arduino.h with 100% similarity]
teensytp/teensy3/pins_teensy.c [moved from teensy3/pins_teensy.c with 100% similarity]
teensytp/teensy3/usb_desc.c [moved from teensy3/usb_desc.c with 100% similarity]
teensytp/teensy3/usb_desc.h [moved from teensy3/usb_desc.h with 100% similarity]
teensytp/teensy3/usb_dev.c [moved from teensy3/usb_dev.c with 100% similarity]
teensytp/teensy3/usb_dev.h [moved from teensy3/usb_dev.h with 100% similarity]
teensytp/teensy3/usb_mem.c [moved from teensy3/usb_mem.c with 100% similarity]
teensytp/teensy3/usb_mem.h [moved from teensy3/usb_mem.h with 100% similarity]
teensytp/teensy3/usb_names.h [moved from teensy3/usb_names.h with 100% similarity]
teensytp/teensy3/usb_rawhid.c [moved from teensy3/usb_rawhid.c with 100% similarity]
teensytp/teensy3/usb_rawhid.h [moved from teensy3/usb_rawhid.h with 100% similarity]
teensytp/teensy3/usb_seremu.c [moved from teensy3/usb_seremu.c with 100% similarity]
teensytp/teensy3/usb_seremu.h [moved from teensy3/usb_seremu.h with 100% similarity]

index 850d10a..5457b76 100644 (file)
@@ -1,6 +1,2 @@
 *.o
-*.elf
-*.hex
-.*.swp
-cscope.out
-tags
+*.gen
diff --git a/hexed/Makefile b/hexed/Makefile
new file mode 100644 (file)
index 0000000..55a0e05
--- /dev/null
@@ -0,0 +1,48 @@
+CROSS = m68k-elf-\r
+CC = $(CROSS)gcc\r
+AS = $(CROSS)as\r
+LD = $(CROSS)ld\r
+OBJCOPY = $(CROSS)objcopy\r
+\r
+ASFLAGS += -m68000 --register-prefix-optional --bitwise-or -pic\r
+CPPFLAGS += -Wa,-m68000 -Wa,--register-prefix-optional -Wa,--bitwise-or -Wa,-pic\r
+\r
+TARGET = hexed.bin\r
+OBJS = sega_gcc.o hexed.o transfer.o font.o\r
+\r
+all: $(TARGET)\r
+\r
+$(TARGET): a.out\r
+       $(OBJCOPY) -I elf32-m68k -O binary $^ $@\r
+\r
+a.out: $(OBJS)\r
+       $(LD) -Tmd.ld -Map $(TARGET).map $^\r
+\r
+clean:\r
+       $(RM) $(TARGET) $(OBJS) $(TARGET).map a.out pc_transfer\r
+\r
+\r
+pc_transfer: pc_transfer.c\r
+       gcc -Wall -O2 -ggdb -o $@ $^ -lz\r
+\r
+%.o: %.S\r
+       $(CC) -c -o $@ $^ $(CPPFLAGS)\r
+\r
+%.bin: %.o\r
+       $(OBJCOPY) -I elf32-m68k -O binary $^ $@\r
+\r
+\r
+# ----------- release -----------\r
+ifneq ($(findstring rel,$(MAKECMDGOALS)),)\r
+ifeq ($(VER),)\r
+$(error need VER)\r
+endif\r
+endif\r
+\r
+rel: hexed.bin readme.txt src\r
+       zip -9 -r hexed_r$(VER).zip $^\r
+       rm -rf src\r
+\r
+src: hexed.s font.s sega_gcc.s md.ld Makefile\r
+       mkdir src\r
+       cp $^ src/\r
diff --git a/hexed/font.s b/hexed/font.s
new file mode 100644 (file)
index 0000000..6b3be24
--- /dev/null
@@ -0,0 +1,69 @@
+.text
+.globl font
+
+font:
+       dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+       dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+       dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+       dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+       dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+       dc.b 0x3C,0x42,0x99,0xBD,0xBD,0x99,0x42,0x3C,0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C
+       dc.b 0xFE,0x82,0x8A,0xD2,0xA2,0x82,0xFE,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x00
+       dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00
+       dc.b 0x80,0xC0,0xF0,0xFC,0xF0,0xC0,0x80,0x00,0x01,0x03,0x0F,0x3F,0x0F,0x03,0x01,0x00
+       dc.b 0x18,0x3C,0x7E,0x18,0x7E,0x3C,0x18,0x00,0xEE,0xEE,0xEE,0xCC,0x00,0xCC,0xCC,0x00
+       dc.b 0x00,0x00,0x30,0x68,0x78,0x30,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00
+       dc.b 0x3C,0x66,0x7A,0x7A,0x7E,0x7E,0x3C,0x00,0x0E,0x3E,0x3A,0x22,0x26,0x6E,0xE4,0x40
+       dc.b 0x18,0x3C,0x7E,0x3C,0x3C,0x3C,0x3C,0x00,0x3C,0x3C,0x3C,0x3C,0x7E,0x3C,0x18,0x00
+       dc.b 0x08,0x7C,0x7E,0x7E,0x7C,0x08,0x00,0x00,0x10,0x3E,0x7E,0x7E,0x3E,0x10,0x00,0x00
+       dc.b 0x58,0x2A,0xDC,0xC8,0xDC,0x2A,0x58,0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00
+       dc.b 0x00,0x10,0x10,0x38,0x38,0x7C,0xFE,0x00,0xFE,0x7C,0x38,0x38,0x10,0x10,0x00,0x00
+       dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x18,0x00,0x18,0x18,0x00
+       dc.b 0x6C,0x6C,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7C,0x28,0x7C,0x28,0x00,0x00
+       dc.b 0x10,0x38,0x60,0x38,0x0C,0x78,0x10,0x00,0x40,0xA4,0x48,0x10,0x24,0x4A,0x04,0x00
+       dc.b 0x18,0x34,0x18,0x3A,0x6C,0x66,0x3A,0x00,0x18,0x18,0x20,0x00,0x00,0x00,0x00,0x00
+       dc.b 0x30,0x60,0x60,0x60,0x60,0x60,0x30,0x00,0x0C,0x06,0x06,0x06,0x06,0x06,0x0C,0x00
+       dc.b 0x10,0x54,0x38,0x7C,0x38,0x54,0x10,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00
+       dc.b 0x00,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00
+       dc.b 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00
+       dc.b 0x38,0x4C,0xC6,0xC6,0xC6,0x64,0x38,0x00,0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00
+       dc.b 0x7C,0xC6,0x0E,0x3C,0x78,0xE0,0xFE,0x00,0x7E,0x0C,0x18,0x3C,0x06,0xC6,0x7C,0x00
+       dc.b 0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x00,0xFC,0xC0,0xFC,0x06,0x06,0xC6,0x7C,0x00
+       dc.b 0x3C,0x60,0xC0,0xFC,0xC6,0xC6,0x7C,0x00,0xFE,0xC6,0x0C,0x18,0x30,0x30,0x30,0x00
+       dc.b 0x78,0xC4,0xE4,0x78,0x86,0x86,0x7C,0x00,0x7C,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00
+       dc.b 0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30
+       dc.b 0x1C,0x38,0x70,0xE0,0x70,0x38,0x1C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00
+       dc.b 0x70,0x38,0x1C,0x0E,0x1C,0x38,0x70,0x00,0x7C,0xC6,0xC6,0x1C,0x18,0x00,0x18,0x00
+       dc.b 0x3C,0x42,0x99,0xA1,0xA5,0x99,0x42,0x3C,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00
+       dc.b 0xFC,0xC6,0xC6,0xFC,0xC6,0xC6,0xFC,0x00,0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00
+       dc.b 0xF8,0xCC,0xC6,0xC6,0xC6,0xCC,0xF8,0x00,0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xFE,0x00
+       dc.b 0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xC0,0x00,0x3E,0x60,0xC0,0xCE,0xC6,0x66,0x3E,0x00
+       dc.b 0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x00
+       dc.b 0x06,0x06,0x06,0x06,0xC6,0xC6,0x7C,0x00,0xC6,0xCC,0xD8,0xF0,0xF8,0xDC,0xCE,0x00
+       dc.b 0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00
+       dc.b 0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00
+       dc.b 0xFC,0xC6,0xC6,0xC6,0xFC,0xC0,0xC0,0x00,0x7C,0xC6,0xC6,0xC6,0xDE,0xCC,0x7A,0x00
+       dc.b 0xFC,0xC6,0xC6,0xCE,0xF8,0xDC,0xCE,0x00,0x78,0xCC,0xC0,0x7C,0x06,0xC6,0x7C,0x00
+       dc.b 0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00
+       dc.b 0xC6,0xC6,0xC6,0xEE,0x7C,0x38,0x10,0x00,0xC6,0xC6,0xD6,0xFE,0xFE,0xEE,0xC6,0x00
+       dc.b 0xC6,0xEE,0x3C,0x38,0x7C,0xEE,0xC6,0x00,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00
+       dc.b 0xFE,0x0E,0x1C,0x38,0x70,0xE0,0xFE,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00
+       dc.b 0x60,0x60,0x30,0x18,0x0C,0x06,0x06,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00
+       dc.b 0x18,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF
+       dc.b 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x06,0x3E,0x66,0x66,0x3C,0x00
+       dc.b 0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x00
+       dc.b 0x06,0x3E,0x66,0x66,0x66,0x66,0x3E,0x00,0x00,0x3C,0x66,0x66,0x7E,0x60,0x3C,0x00
+       dc.b 0x1C,0x30,0x78,0x30,0x30,0x30,0x30,0x00,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x3C
+       dc.b 0x60,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x00
+       dc.b 0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x38,0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0x00
+       dc.b 0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0xEC,0xFE,0xFE,0xFE,0xD6,0xC6,0x00
+       dc.b 0x00,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x00
+       dc.b 0x00,0x7C,0x66,0x66,0x66,0x7C,0x60,0x60,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x06
+       dc.b 0x00,0x7E,0x70,0x60,0x60,0x60,0x60,0x00,0x00,0x3C,0x60,0x3C,0x06,0x66,0x3C,0x00
+       dc.b 0x30,0x78,0x30,0x30,0x30,0x30,0x1C,0x00,0x00,0x66,0x66,0x66,0x66,0x6E,0x3E,0x00
+       dc.b 0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0xC6,0xD6,0xFE,0xFE,0x7C,0x6C,0x00
+       dc.b 0x00,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x06,0x3C
+       dc.b 0x00,0x7E,0x0C,0x18,0x30,0x60,0x7E,0x00,0x0E,0x18,0x0C,0x38,0x0C,0x18,0x0E,0x00
+       dc.b 0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x70,0x18,0x30,0x1C,0x30,0x18,0x70,0x00
+       dc.b 0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x10,0x28,0x10,0x54,0xAA,0x44,0x00,0x00
+
diff --git a/hexed/hexed.s b/hexed/hexed.s
new file mode 100644 (file)
index 0000000..ae77a3e
--- /dev/null
@@ -0,0 +1,1660 @@
+###############################################################################
+#
+# Copyright (c) 2009,2011 Gražvydas Ignotas
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the organization nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Assemble with gas
+#   --register-prefix-optional --bitwise-or
+#
+
+.equ USE_VINT,        0
+.equ COPY_TO_EXP,     1
+.equ RELOCATE_TO_RAM, 1
+
+.text
+.globl main
+.globl INT
+.globl VBL
+.globl return_to_main
+
+##################################################
+#                                                #
+#        Register and bitmask definitions        #
+#                                                #
+##################################################
+
+.equ GFXDATA,          0xc00000
+.equ GFXCNTL,          0xc00004
+
+.equ VDP0_E_HBI,       0x10
+.equ VDP0_E_DISPLAY,   0x02 
+.equ VDP0_PLTT_FULL,   0x04 
+
+.equ VDP1_SMS_MODE,    0x80
+.equ VDP1_E_DISPLAY,   0x40
+.equ VDP1_E_VBI,       0x20
+.equ VDP1_E_DMA,       0x10
+.equ VDP1_NTSC,                0x00
+.equ VDP1_PAL,         0x08
+.equ VDP1_MODE5,       0x04
+
+.equ VDP12_STE,                0x08
+.equ VDP12_SCREEN_V224,        0x00
+.equ VDP12_SCREEN_V448,        0x04
+.equ VDP12_PROGRESSIVE,        0x00
+.equ VDP12_INTERLACED, 0x02
+.equ VDP12_SCREEN_H256,        0x00
+.equ VDP12_SCREEN_H320,        0x81
+
+.equ VDP16_MAP_V32,    0x00
+.equ VDP16_MAP_V64,    0x10
+.equ VDP16_MAP_V128,   0x30
+.equ VDP16_MAP_H32,    0x00
+.equ VDP16_MAP_H64,    0x01
+.equ VDP16_MAP_H128,   0x03
+
+.equ MMODE_MAIN,       0
+.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 MMODE_PC,         7
+
+.equ predef_addr_cnt,  ((predef_addrs_end-predef_addrs)/4)
+
+##################################################
+#                                                #
+#                   MACROS                       #
+#                                                #
+##################################################
+
+
+# Write val to VDP register reg
+.macro write_vdp_r_dst reg val dst
+       move.w #((\reg << 8) + 0x8000 + \val),\dst
+.endm
+
+# Write val to VDP register reg, vdp addr in a3
+.macro write_vdp_reg reg val
+       write_vdp_r_dst \reg, \val, (a3)
+.endm
+
+# Set up address in VDP, control port in dst
+.macro VRAM_ADDR adr dst
+       move.l #(0x40000000 | ((\adr & 0x3fff) << 16) | (\adr >> 14)),\dst
+.endm
+
+.macro VSRAM_ADDR adr dst
+       move.l #(0x40000010 | ((\adr & 0x3fff) << 16) | (\adr >> 14)),\dst
+.endm
+
+
+# make VDP word from address adr and store in d0
+.macro XRAM_ADDR_var adr
+       move.l \adr,d0
+       lsl.l #8,d0
+       lsl.l #8,d0
+       rol.l #2,d0
+       lsl.b #2,d0
+       lsr.l #2,d0
+.endm
+
+
+.macro VRAM_ADDR_var adr
+       XRAM_ADDR_var \adr
+       or.l #0x40000000,d0
+.endm
+
+
+.macro CRAM_ADDR_var adr
+       XRAM_ADDR_var \adr
+       or.l #0xc0000000,d0
+.endm
+
+
+# convert tile coords in d0, d1 to nametable addr to a0
+.macro XY2NT
+       lsl.w           #6,d1
+       add.w           d1,d0
+       lsl.w           #1,d0
+       movea.l         #0xe000,a0
+       add.w           d0,a0
+.endm
+
+# check if some d-pad button (and modifier) is pressed
+.macro do_dpad bit op val
+       btst.l          #\bit,d0
+       beq             0f
+       \op             \val,a6
+       bra             dpad_end
+0:
+.endm
+
+# convert a6 to normal addr
+#  destroys d0
+.macro mk_a6_addr reg
+       move.l          a6,\reg
+       moveq.l         #0,d0
+       move.b          \reg,d0
+       lsr.l           #8,\reg
+       add.l           d0,\reg
+.endm
+
+.macro change_mode mode_new mode_back
+       and.w           #0xc0ff,d7
+       or.w            #(\mode_back<<11)|(\mode_new<<8),d7
+.endm
+
+#  destroys a0,d0-d2
+.macro menu_text str x y pal
+       lea             (\str,pc),a0
+       move.l          #\x,d0
+       move.l          #\y,d1
+       move.l          #0x8000|(\pal<<13),d2
+       jsr             print
+.endm
+
+#################################################
+#                                               #
+#                    DATA                       #
+#                                               #
+#################################################
+
+colors:
+       dc.w 0x0000,0x0eee,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
+       dc.w    0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
+       dc.w 0x0000,0x02e2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
+       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:
+
+
+sprite_data:
+       /*         Y        size     link          attr        X */
+       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, 0xa15100
+       dc.l 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:
+       dc.l 0xa15100, 0xa1513f
+safe_addrs_end_32x:
+       dc.l 0xa15180, 0xa153ff
+safe_addrs_end_32x_vdp:
+
+sizeof_bin:
+       dc.l _edata
+
+txt_edit:
+       .ascii  "- edit -\0"
+txt_a_confirm:
+       .ascii  "A-confirm\0"
+txt_about:
+       .ascii  "hexed r2\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_dump:
+       .ascii  "PC Transfer\0"
+txt_dtack:
+       .ascii  "DTACK safety\0"
+txt_transfer_ready:
+       .ascii  "Transfer Ready\0"
+txt_working:
+       .ascii  "PC mode       \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:
+       /* make sure io port 2 is doing inputs */
+       move.b          #0,(0xa1000b).l
+       /* make sure irqs are masked */
+       move.w          #0x2700,sr
+       /* take care of TMSS */
+       move.b          (0xa10000).l,d0
+       andi.b          #0x0f,d0
+       beq             no_tmss
+       move.l          #0x53454741,(0xa14000).l
+       /* want cart, not OS rom if cart pops in */
+       move.w          #1,(0xa14100).l
+       /* touch VDP after TMSS setup? */
+       tst.w           (0xc00004).l
+no_tmss:
+
+       /* want to do early PC transfer (with RAM/VRAM intact and such)?
+        * also give time PC to see start condition */
+       move.l          #0x2000,d0
+0:     dbra            d0,0b
+
+       move.l          #0xa10005,a0
+       btst.b          #5,(a0)
+       bne             no_early_transfer
+move.b #1,(0)
+       move.b          #0x40,(0xa1000b).l      /* port 2 ctrl */
+       move.b          #0x00,(a0)              /* port 2 data - start with TH low */
+       move.l          #0x2000,d0
+0:
+       btst.b          #4,(a0)
+       beq             do_early_transfer
+       dbra            d0,0b
+
+move.b #2,(0)
+       move.b          #0,(0xa1000b).l
+       bra             no_early_transfer       /* timeout */
+
+do_early_transfer:
+move.b #9,(0)
+       bsr             do_transfer
+
+no_early_transfer:
+
+.if COPY_TO_EXP
+       /* copy to expansion device if magic number is set */
+       move.l          #0x400000,a1
+       cmp.w           #0x1234,(a1)
+       bne             0f
+
+       move.l          #0,a0
+       move.l          (sizeof_bin,pc),d0
+       lsr.l           #3,d0
+1:
+       move.l          (a0)+,(a1)+
+       move.l          (a0)+,(a1)+
+       dbra            d0,1b
+0:
+.endif
+
+.if RELOCATE_TO_RAM
+       /* we could be relocated by 32x or something else, adjust start addr */
+       lea             (pc),a0
+       move.l          a0,d0
+       and.l           #0xff0000,d0
+       move.l          d0,a0
+
+       /* copy, assume 8K size */
+       move.l          #0xFF0100,a1
+       move.l          (sizeof_bin,pc),d0
+       lsr.l           #3,d0
+1:
+       move.l          (a0)+,(a1)+
+       move.l          (a0)+,(a1)+
+       dbra            d0,1b
+
+       /* copy test code */
+       lea             (test_code,pc),a0
+       move.l          #0xffc000,a1
+       move.w          #(test_code_end - test_code)/2-1,d0
+1:
+       move.w          (a0)+,(a1)+
+       dbra            d0,1b
+
+       lea             (0f,pc),a0
+       move.l          a0,d0
+       and.l           #0x00ffff,d0
+       add.l           #0xFF0100,d0
+       move.l          d0,a0
+
+       /* patch test code */
+       move.l          #0xffc000,a1
+       add.w           #(test_code_ret_op-test_code+2),a1
+       move.l          a0,(a1)
+
+       jmp             (a0)
+0:
+.endif
+
+       movea.l         #0,a6
+       move.l          #0x8000,d7
+       moveq.l         #0,d6
+
+       /* Init pads */
+       move.b          #0x40,(0xa10009).l
+       move.b          #0x40,(0xa10003).l
+
+       /* Initialize VDP */
+       jsr             init_gfx
+
+       /* Clear h/v scroll */
+       movea.l         #GFXDATA,a0
+       VRAM_ADDR       0x8000,(GFXCNTL)
+       move.l          #0,(a0)
+       VSRAM_ADDR      0,(GFXCNTL)
+       move.l          #0,(a0)
+
+       /* Load color data */
+       movea.l         #0,a0
+       lea             (colors,pc),a1
+       moveq.l         #(colors_end-colors)/2,d0
+       jsr             load_colors
+
+       /* load font patterns */
+       movea.l         #GFXDATA,a0
+       lea             (font,pc),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
+       move.l          #28-1,d4
+lmaploop0:
+       movea.l         a1,a0
+       jsr             load_prepare
+
+       move.l          #64/2-1,d3
+0:     move.l          #0x00000000,(a0)
+       dbra            d3,0b
+
+       add.l           #64*2,a1
+       dbra            d4,lmaploop0
+
+       /* generate B layer map */
+       movea.l         #0xc000,a0
+       jsr             load_prepare
+
+       move.l          #64*28/2-1,d3
+0:     move.l          #0x00000000,(a0)
+       dbra            d3,0b
+
+       /* upload sprite data */
+       movea.l         #0xfc00,a0
+       jsr             load_prepare
+       lea             (sprite_data,pc),a1
+
+       move.l          #(sprite_data_end-sprite_data)/2-1,d3
+0:     move.l          (a1)+,(a0)
+       dbra            d3,0b
+
+.if USE_VINT
+       /* wait for vsync before unmask */
+       jsr             wait_vsync_poll
+
+       /* wait a bit to avoid nested vint */
+       move.w          #20,d0
+0:
+       dbra            d0,0b           /* 10 cycles to go back */
+
+       /* enable and unmask vint */
+       write_vdp_r_dst 1,(VDP1_E_VBI | VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL)
+       move.w          #0x2000,sr
+.endif
+
+##################################################
+
+forever:
+.if USE_VINT
+       jsr             wait_vsync
+.else
+       jsr             wait_vsync_poll
+       jsr             VBL
+.endif
+       bra             forever
+
+
+INT:
+       /* let's hope VRAM is already set up.. */
+       lea             (txt_exc,pc),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-d4/a0-a5,-(a7)
+
+       btst.b          #5,(0xa10005).l
+       bne             no_auto_transfer
+       change_mode     MMODE_PC, MMODE_MAIN
+       write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
+
+no_auto_transfer:
+       moveq.l         #0,d0
+       move.w          d7,d0
+       lsr.w           #6,d0
+       and.w           #0x1c,d0
+       lea             (jumptab,pc,d0),a0
+       jmp             (a0)
+jumptab:
+       /* branch insns here because we want to be position independent */
+       bra             mode_main
+       bra             mode_val_input
+       bra             mode_edit_val   /* edit val in editor */
+       bra             mode_goto
+       bra             mode_start_menu
+       bra             mode_goto_predef
+       bra             mode_jmp_addr
+       bra             mode_transfer
+
+##################### main #######################
+
+mode_main:
+       /* assume we will hang */
+       lea             (txt_dtack_err,pc),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
+       move.l          d0,a1           /* current addr */
+       lsr.b           #3,d1
+       neg.b           d1
+       add.b           #27-1,d1        /* line where the cursor sits */
+       swap            d1
+
+       movea.l         #0xe002,a2
+       move.l          #27-1,d5        /* line counter for dbra */
+       or.l            d1,d5
+
+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_words:
+       move.w          #' ',(a0)
+       move.w          (a1)+,d2
+       jsr             print_hex_preped
+       dbra            d4,draw_words
+
+       move.l          #(' '<<16)|' ',(a0)
+
+       move.l          d5,d0
+       swap            d0
+       cmp.w           d5,d0
+       beq             draw_cursor_word
+
+draw_chars_pre:
+       /* 8 chars */
+       subq.l          #8,a1
+       moveq.l         #8-1,d4
+draw_chars:
+       move.b          (a1)+,d0
+       move.b          d0,d1
+       sub.b           #0x20,d1
+       cmp.b           #0x60,d1
+       blo             0f
+       move.w          #'.',d0
+0:
+       move.w          d0,(a0)
+       dbra            d4,draw_chars
+
+       move.l          #(' '<<16)|' ',(a0)
+
+       add.w           #0x80,a2
+       dbra            d5,draw_row
+
+
+draw_status_bar:
+       /* status bar */
+       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 */
+
+       btst.l          #16+4,d0                /* A - scroll modifier */
+       beq             input_noa
+
+       do_dpad         16+0,  sub.l, #0x0800
+       do_dpad         16+1,  add.l, #0x0800
+       do_dpad         16+10, sub.l, #0xd800
+       do_dpad         16+11, add.l, #0xd800
+input_noa:
+       moveq.l         #0,d1
+       move.w          d7,d1
+       lsr.w           #7,d1
+       lsr.w           #7,d1
+
+       do_dpad         0,  subq.l, #0x0008
+       do_dpad         1,  addq.l, #0x0008
+       do_dpad         10, sub.l, d1
+       do_dpad         11, add.l, d1
+
+dpad_end:
+       /* update addr */
+       move.l          a6,d1
+       cmp.b           #0xf0,d1
+       blo             0f
+       sub.l           #0xd800,a6
+       add.w           #0x00d8,a6
+       bra             1f
+0:
+       cmp.b           #0xd8,d1
+       blo             1f
+       add.l           #0xd800,a6
+       sub.w           #0x00d8,a6
+1:
+
+       /* other btns */
+       moveq.l         #0,d1
+       btst.l          #12,d0                  /* B - switch byte/word mode */
+       beq             input_nob
+       bclr.l          #15,d7
+       add.w           #0x4000,d7              /* changes between 01 10 */
+       move.l          a6,d1
+       and.l           #1,d1
+       sub.l           d1,a6                   /* make even, just in case */
+
+input_nob:
+       btst.l          #13,d0                  /* C - edit selected byte */
+       beq             input_noc
+
+       change_mode     MMODE_EDIT_VAL, MMODE_MAIN
+       write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
+
+input_noc:
+       btst.l          #5,d0                   /* Start - menu */
+       beq             input_nos
+
+       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-d4/a0-a5
+.if USE_VINT
+       rte
+.else
+       rts
+.endif
+
+
+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 */
+       bra             draw_chars_hsafe_pre
+
+draw_cursor_unsafe_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
+
+       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 */
+       bra             draw_chars_hsafe_pre
+
+
+draw_cursor_byte:
+       move.l          a6,d0
+       and.l           #7,d0           /* byte offs */
+       move.w          #0x2002,d3
+
+       move.b          (-8,a1,d0),d2
+       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 */
+
+       bra             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
+       lea             (8*2,a2,d1),a0
+       jsr             load_prepare
+       jsr             print_hex_preped
+
+       move.l          a2,a0
+       add.w           #29*2,a0
+       jsr             load_prepare    /* restore a0 */
+
+       bra             draw_chars_pre
+
+
+#################### hedit #######################
+
+mode_edit_val:
+       btst.l          #7,d6
+       bne             mode_hedit_finish
+
+       /* read val to edit */
+       moveq.l         #0,d5
+       mk_a6_addr      d1
+       move.l          d1,a0
+       btst.l          #15,d7
+       bne             0f
+       move.b          (a0),d5
+       lsl.l           #8,d5
+       or.b            #1,d5
+       bra             1f
+0:
+       move.w          (a0),d5
+       lsl.l           #8,d5
+       or.b            #2,d5
+1:
+
+       change_mode     MMODE_VAL_INPUT, MMODE_EDIT_VAL
+       bra             vbl_end
+
+mode_hedit_finish:
+       /* write the val */
+       mk_a6_addr      d1
+       move.l          d1,a0
+       lsr.l           #8,d5
+
+       btst.l          #15,d7
+       bne             0f
+       move.b          d5,(a0)
+       bra             1f
+0:
+       move.w          d5,(a0)
+1:
+
+       bra             return_to_main
+
+##################### goto #######################
+
+mode_goto:
+       btst.l          #7,d6
+       bne             mode_goto_finish
+
+       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
+       bra             vbl_end
+
+mode_goto_finish:
+       lsr.l           #8,d5
+       move.l          d5,d0
+       move.l          d0,d1
+       and.l           #7,d1
+       and.b           #0xf8,d0
+       lsl.l           #8,d0
+       or.l            d1,d0
+       move.l          d0,a6
+
+       lsr.l           #8,d5
+       swap            d6
+       move.w          d5,d6
+       swap            d6
+
+       bra             return_to_main
+
+################### val edit #####################
+
+mode_val_input:
+       /* frame */
+       movea.l         #0xe000+14*2+11*64*2,a1
+       moveq.l         #6-1,d1
+0:
+       move.w          a1,a0
+       jsr             load_prepare
+       moveq.l         #11-1,d0
+1:
+       move.w          #0,(a0)
+       dbra            d0,1b
+
+       add.w           #64*2,a1
+       dbra            d1,0b
+
+       /* text */
+       lea             (txt_edit,pc),a0
+       move.l          #15,d0
+       move.l          #11,d1
+       move.l          #0xc000,d2
+       jsr             print
+
+       lea             (txt_a_confirm,pc),a0
+       move.l          #15,d0
+       move.l          #15,d1
+       move.l          #0xc000,d2
+       jsr             print
+
+       /* edit field */
+       moveq.l         #0,d0
+       moveq.l         #0,d1
+       moveq.l         #0,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          d5,d2
+       lsr.l           #8,d2
+       add.b           d3,d3
+       or.w            #0x8000,d3
+       jsr             print_hex
+
+       /* current char */
+       moveq.l         #0,d0
+       moveq.l         #0,d1
+
+       and.w           #6,d3
+       move.b          #19,d0
+       move.b          d3,d1
+       lsr.b           #1,d1           /* length in bytes */
+       sub.b           d1,d0
+       move.b          d5,d1
+       lsr.b           #2,d1
+       and.b           #7,d1           /* nibble to edit */
+       add.b           d1,d0
+
+       sub.b           d1,d3
+       sub.b           #1,d3           /* chars to shift out */
+       lsl.b           #2,d3
+       add.b           #8,d3
+       move.l          d5,d2
+       lsr.l           d3,d2
+
+       move.b          #13,d1
+       move.w          #0xa001,d3
+       jsr             print_hex
+
+       /* handle input */
+       jsr             get_input       /* x0cbrldu x1sa00du */
+
+       move.w          d0,d1
+       and.w           #0x0f00,d1
+       beq             ai_no_dpad
+       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          d5,d2
+       lsr.b           #2,d2
+       and.b           #7,d2           /* nibble to edit */
+
+       move.b          d0,d3
+       and.b           #3,d3
+       beq             ai_no_ud
+       moveq.l         #0,d3
+       moveq.l         #0,d4
+       move.b          #0xf,d3
+       move.b          #0x1,d4
+       sub.b           d2,d1
+       lsl.b           #2,d1
+       add.b           #8,d1
+       lsl.l           d1,d3           /* mask */
+       lsl.l           d1,d4           /* what to add/sub */
+       move.l          d5,d1
+       and.l           d3,d1
+       btst.l          #8,d0
+       beq             0f
+       add.l           d4,d1
+       bra             1f
+0:
+       sub.l           d4,d1
+1:
+       and.l           d3,d1
+       eor.l           #0xffffffff,d3
+       and.l           d3,d5
+       or.l            d1,d5
+       bra             vbl_end
+
+ai_no_ud:
+       btst.l          #10,d0
+       bne             0f
+       add.b           #1,d2
+       bra             1f
+0:
+       sub.b           #1,d2
+1:
+       cmp.b           #0,d2
+       bge             0f
+       move.b          d1,d2
+0:
+       cmp.b           d1,d2
+       ble             0f
+       move.b          #0,d2
+0:
+       and.b           #0xe3,d5
+       lsl.b           #2,d2
+       or.b            d2,d5
+       bra             vbl_end
+
+ai_no_dpad:
+       move.w          d0,d1
+       and.w           #0x1020,d1
+       beq             ai_no_sb
+
+       bra             return_to_main
+
+ai_no_sb:
+       btst.l          #4,d0           /* A - confirm */
+       beq             ai_no_input
+       bset.l          #7,d6
+       move.w          d7,d1           /* back to prev mode */
+       and.w           #0x3800,d1
+       lsr.w           #3,d1
+       and.w           #0xc0ff,d7
+       or.w            d1,d7
+
+ai_no_input:
+       bra             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_dump,        13, 14, 0
+       menu_text       txt_dtack,       13, 15, 0
+       menu_text       txt_a_confirm,   13, 17, 2
+
+       /* dtack safety on/off */
+       movea.l         #0xe000+26*2+15*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           #7,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           #7,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          #4,d1
+0:
+       cmp.b           #4,d1
+       ble             0f
+       move.b          #0,d1
+0:
+       and.b           #0xf8,d5
+       or.b            d1,d5
+       bra             vbl_end
+
+msm_no_ud:
+       btst.l          #4,d0           /* A - confirm */
+       beq             msm_no_a
+       move.b          d5,d1
+       and.b           #7,d1
+       bne             0f
+       change_mode     MMODE_GOTO, MMODE_MAIN
+       bsr             start_menu_box
+       bra             vbl_end
+0:
+       cmp.b           #1,d1
+       bne             0f
+       moveq.l         #0,d5
+       change_mode     MMODE_GOTO_PREDEF, MMODE_MAIN
+       bsr             start_menu_box
+       bra             vbl_end
+0:
+       cmp.b           #2,d1
+       bne             0f
+       change_mode     MMODE_JMP_ADDR, MMODE_MAIN
+       bsr             start_menu_box
+       bra             vbl_end
+0:
+       cmp.b           #3,d1
+       bne             0f
+       change_mode     MMODE_PC, MMODE_MAIN
+       bsr             start_menu_box
+       bra             vbl_end
+0:
+       cmp.b           #4,d1
+       bne             0f
+       bchg.l          #4,d6
+       bra             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:
+       bra             vbl_end
+
+start_menu_box:
+       movea.l         #0xe000+10*2+8*64*2,a1
+       move.w          #11-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,pc),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:
+       bra             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,pc),a0
+       move.l          (a0,d0),d5
+       lsl.l           #8,d5
+       bra             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:
+       bra             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
+       bra             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)
+
+mode_transfer:
+       move.b          #0x40,(0xa1000b).l      /* port 2 ctrl */
+       move.b          #0x00,(0xa10005).l      /* port 2 data - start with TH low */
+
+       lea             (txt_transfer_ready,pc),a0
+       move.l          #13,d0
+       move.l          #13,d1
+       move.l          #0x8000,d2
+       jsr             print
+
+wait_tl_low0:
+       move.b          (0xa10005),d0
+       btst.b          #4,d0
+       bne             wait_tl_low0
+
+       menu_text       txt_working, 13, 13, 0
+       bsr             do_transfer
+       bra             return_to_main
+
+# go back to main mode
+return_to_main:
+       bclr.l          #7,d6           /* not edited */
+       change_mode     MMODE_MAIN, MMODE_MAIN
+       write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320),(GFXCNTL)
+       bra             vbl_end
+
+
+#################################################
+#                                               #
+#         Initialize VDP registers              #
+#                                               #
+#################################################
+
+init_gfx:
+       move.l          #GFXCNTL,a3
+       write_vdp_reg   0,(VDP0_E_DISPLAY | VDP0_PLTT_FULL)
+       write_vdp_reg   1,(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 */
+       write_vdp_reg   5,(0xfc00 >>  9)        /* Sprite address */
+       write_vdp_reg   6,0     
+       write_vdp_reg   7,0                     /* Backdrop color */
+       write_vdp_reg   0x0a,1                  /* Lines per hblank interrupt */
+       write_vdp_reg   0x0b,0                  /* 2-cell vertical scrolling */
+       write_vdp_reg   0x0c,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320)
+       write_vdp_reg   0x0d,(0x8000 >> 10)     /* Horizontal scroll address */
+       write_vdp_reg   0x0e,0
+       write_vdp_reg   0x0f,2
+       write_vdp_reg   0x10,(VDP16_MAP_V32 | VDP16_MAP_H64)    /* layer size */
+       write_vdp_reg   0x11,0
+       write_vdp_reg   0x12,0
+       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,pc),a1
+       move.w          #(safe_addrs_end - safe_addrs)/8-1,d2
+       cmp.l           #0x4D415253,(0xa130ec)  /* 'MARS' */
+       bne             no_32x
+       move.w          #(safe_addrs_end_32x - safe_addrs)/8-1,d2
+       move.w          (0xa15100),d0
+       and.w           #3,d0
+       cmp.w           #3,d0                   /* ADEN and nRES */
+       bne             no_32x_vdp
+       btst.b          #7,d0                   /* FM */
+       bne             no_32x_vdp
+       move.w          #(safe_addrs_end_32x_vdp - safe_addrs)/8-1,d2
+no_32x_vdp:
+no_32x:
+
+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
+#  destroys d1,d2
+get_input:
+       move.b          #0x40,(0xa10003)
+       nop
+       nop
+       nop
+       move.b          (0xa10003),d0
+       move.b          #0x00,(0xa10003)
+       lsl.w           #8,d0
+       nop
+       move.b          (0xa10003),d0
+       eor.w           #0xffff,d0
+
+       swap            d7
+       move.w          d7,d1
+       eor.w           d0,d1           /* changed btns */
+       move.w          d0,d7           /* old val */
+       swap            d7
+       and.w           d0,d1           /* what changed now */
+       bne             0f
+
+       addq.b          #1,d6
+       move.b          d6,d2
+       and.b           #0x0f,d2        /* do autorepeat */
+       cmp.b           #9,d2
+       bne             1f
+       move.w          d0,d1
+0:
+       and.b           #0xf0,d6
+1:
+       swap            d0
+       move.w          d1,d0
+       rts
+
+# Prepare to write to VDP RAM @a0
+# sets a0 to VDP data port for convenience
+#  a0: VRAM base
+#  destroys d0
+
+load_prepare:
+       VRAM_ADDR_var   a0
+       move.l          d0,(GFXCNTL).l
+       move.l          #GFXDATA,a0
+       rts
+
+
+# Load color data from ROM
+#  a0: CRAM base
+#  a1: color list address
+#  d0: number of colors to load
+#  destroys d1
+
+load_colors:
+       move.l          d0,d1
+       CRAM_ADDR_var   a0
+       move.l          d0,(GFXCNTL).l
+
+       move.l          #GFXDATA,a0
+       subq.w          #1,d1
+0:
+       move.w          (a1)+,(a0)
+       dbra            d1,0b
+
+       rts
+
+
+# print
+#  a0 - string
+#  d0 - x
+#  d1 - y 
+#  d2 - tile_bits[15:11]
+#  destroys a1
+
+print:
+       move.l          a0,a1
+       XY2NT
+       jsr             load_prepare
+       move.l          d2,d0
+       and.w           #0xf800,d0
+
+_print_loop:
+       move.b          (a1)+,d0
+       beq             _print_end
+
+       move.w          d0,(a0)
+       bra             _print_loop
+
+_print_end:
+       rts
+
+
+# print_hex
+#  d0 - x
+#  d1 - y 
+#  d2 - value
+#  d3 - tile_bits[15:11]|digit_cnt[7:0]
+#  destroys a0, preserves d3
+
+print_hex:
+       XY2NT
+       jsr             load_prepare
+
+print_hex_preped:
+       moveq.l         #0,d0
+       move.b          d3,d0
+       move.l          d0,d1
+       lsl.b           #2,d0
+       ror.l           d0,d2           /* prep value */
+       subq.l          #1,d1           /* count */
+       move.w          d3,d0
+       and.w           #0xf800,d0      /* keep upper bits in d0 */
+
+_print_hex_loop:
+       rol.l           #4,d2
+       move.b          d2,d0
+       and.b           #0xf,d0
+
+       add.b           #'0',d0
+       cmp.b           #'9',d0
+       ble             0f
+       addq.b          #7,d0
+0:
+       move.w          d0,(a0)
+       dbra            d1,_print_hex_loop
+
+       rts
+
+
+# wait vertical sync interrupt
+
+wait_vsync:
+       move.b          d7,d0
+_wait_change:
+       stop            #0x2000
+       cmp.b           d7,d0
+       beq             _wait_change
+       rts
+
+
+# wait vsync start (polling)
+#  destroys a0,d0
+
+wait_vsync_poll:
+       move.l          #GFXCNTL,a0
+0:
+       move.w          (a0),d0
+       and.b           #8,d0
+       nop
+       nop
+       bne             0b
+0:
+       move.w          (a0),d0
+       and.b           #8,d0
+       nop
+       nop
+       beq             0b
+       rts
+
+
+test_code:
+       nop
+
+test_code_ret_op:
+       jmp     0x123456        /* will be patched */
+test_code_end:
+
+#################################################
+#                                               #
+#                 RAM DATA                      #
+#                                               #
+#################################################
+
+.bss
+
+# nothing :)
+
+.end
+
+# vim:filetype=asmM68k
diff --git a/hexed/md.ld b/hexed/md.ld
new file mode 100644 (file)
index 0000000..208bfa7
--- /dev/null
@@ -0,0 +1,122 @@
+OUTPUT_ARCH(m68k)\r
+SEARCH_DIR(.)\r
+/*GROUP(-lbcc -lc -lgcc)*/\r
+__DYNAMIC  =  0;\r
+\r
+/*\r
+ * Setup the memory map of the SEGA Genesis.\r
+ * stack grows down from high memory.\r
+ *\r
+ * The memory map look like this:\r
+ * +--------------------+ <- low memory\r
+ * | .text              |\r
+ * |        _etext      |\r
+ * |        ctor list   | the ctor and dtor lists are for\r
+ * |        dtor list   | C++ support\r
+ * +--------------------+\r
+ * | .data              | initialized data goes here\r
+ * |        _edata      |\r
+ * +--------------------+\r
+ * | .bss               |\r
+ * |        __bss_start | start of bss, cleared by crt0\r
+ * |        _end        | start of heap, used by sbrk()\r
+ * +--------------------+\r
+ * .                    .\r
+ * .                    .\r
+ * .                    .\r
+ * |        __stack     | top of stack\r
+ * +--------------------+\r
+ */\r
+/*\r
+MEMORY\r
+{\r
+  rom     : ORIGIN = 0x00000000, LENGTH = 0x00400000\r
+  ram     : ORIGIN = 0xffff0000, LENGTH = 0x00010000\r
+}\r
+*/\r
+\r
+MEMORY {\r
+       ram : ORIGIN = 0x0, LENGTH = 0xfffffff\r
+}\r
+\r
+/*\r
+ * allocate the stack to be at the top of memory, since the stack\r
+ * grows down\r
+ */\r
+\r
+PROVIDE (__stack = 0x00fffff0);\r
+\r
+PROVIDE (ram = 0xffff0000);\r
+/*\r
+ * Initalize some symbols to be zero so we can reference them in the\r
+ * crt0 without core dumping. These functions are all optional, but\r
+ * we do this so we can have our crt0 always use them if they exist. \r
+ * This is so BSPs work better when using the crt0 installed with gcc.\r
+ * We have to initalize them twice, so we cover a.out (which prepends\r
+ * an underscore) and coff object file formats.\r
+ */\r
+PROVIDE (hardware_init_hook = 0);\r
+PROVIDE (_hardware_init_hook = 0);\r
+PROVIDE (software_init_hook = 0);\r
+PROVIDE (_software_init_hook = 0);\r
+\r
+SECTIONS\r
+{\r
+  .text 0x00000000:\r
+  {\r
+    *(.text)\r
+    . = ALIGN(0x4);\r
+     __CTOR_LIST__ = .;\r
+    LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)\r
+    *(.ctors)\r
+    LONG(0)\r
+    __CTOR_END__ = .;\r
+    __DTOR_LIST__ = .;\r
+    LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)\r
+    *(.dtors)\r
+     LONG(0)\r
+    __DTOR_END__ = .;\r
+    *(.rodata)\r
+    *(.gcc_except_table) \r
+\r
+    __INIT_SECTION__ = . ;\r
+    *(.init)\r
+    SHORT (0x4e75)     /* rts */\r
+\r
+    __FINI_SECTION__ = . ;\r
+    *(.fini)\r
+    SHORT (0x4e75)     /* rts */\r
+\r
+    _etext = .;\r
+    *(.lit)\r
+  } > ram\r
+\r
+  .data BLOCK (0x4) :\r
+  {\r
+    *(.shdata)\r
+    *(.data)\r
+    _edata = .;\r
+  } > ram\r
+\r
+  .bss 0xff0000 :\r
+  {\r
+    __bss_start = . ;\r
+    *(.shbss)\r
+    *(.bss)\r
+    *(COMMON)\r
+    *(.eh_fram)\r
+    *(.eh_frame)\r
+    _end =  ALIGN (0x8);\r
+    __end = _end;\r
+  } > ram\r
+\r
+  .stab 0 (NOLOAD) :\r
+  {\r
+    *(.stab)\r
+  }\r
+\r
+  .stabstr 0 (NOLOAD) :\r
+  {\r
+    *(.stabstr)\r
+  }\r
+}\r
diff --git a/hexed/pc_transfer.c b/hexed/pc_transfer.c
new file mode 100644 (file)
index 0000000..bcfb652
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * Copyright (c) 2011, Gražvydas Ignotas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the organization nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/io.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <zlib.h>
+
+#include "transfer.h"
+
+/*
+ * PC:
+ * BASE+0 ~ data
+ * BASE+1 ~ status:  BAOSEI??
+ *          /BUSY, ACK, PE, SLCT, ERROR, IRQ
+ * BASE+2 ~ control: ??MISIAS
+ *          bidirrectMODE, IRQ_EN, /SLCT_IN, INIT, /AUTO_FD_XT, /STROBE
+ *
+ * SEGA
+ * ?HRL3210
+ * TH, TR, TL, D3, D2, D1, D0
+ *
+ * SEGA      PC
+ * 1 D0  <->  2 D0
+ * 2 D1  <->  3 D1
+ * 3 D2  <->  4 D2
+ * 4 D3  <->  5 D3
+ * 5 +5V
+ * 6 TL  <-- 14 /AUTO_FD_XT
+ * 7 TH  --> 10 ACK
+ * 8 GND --- 21 GND
+ * 9 TR  <-- 17 /SLCT_IN
+ *
+ * start: TH low/high, TL high
+ *
+ * TH low  - lower nibble: MD ready to recv | MD sent to PC
+ * TL low  - lower niblle: sent to MD       | ready to recv from MD
+ * TH high - upper nibble: MD ready to recv | MD sent to PC
+ * TL high - upper nibble: sent             | ready to recv from MD
+ */
+
+#define ACK_TIMEOUT    2000000
+
+#define PORT_DATA      888
+#define PORT_STATUS    889
+#define PORT_CONTROL   890
+
+#define timediff(now, start) \
+       ((now.tv_sec - start.tv_sec) * 1000000 + now.tv_usec - start.tv_usec)
+
+#define PBE2(p) ((*(p) << 8) | *(p+1))
+#define PBE3(p) ((*(p) << 16) | (*(p + 1) << 8) | *(p + 2))
+#define PBE4(p) ((*(p) << 24) | (*(p + 1) << 16) | (*(p + 2) << 8) | *(p + 3))
+
+static void do_exit(const char *msg, const char *where)
+{
+       /* switch TL back to high */
+       outb(0xe0, PORT_CONTROL);
+
+       if (where)
+               fprintf(stderr, "%s: ", where);
+       if (msg)
+               fprintf(stderr, "%s", msg);
+       exit(1);
+}
+
+static void inthandler(int u)
+{
+       do_exit("\n", NULL);
+}
+
+static void wait_th_low(const char *where)
+{
+       struct timeval start, now;
+
+       gettimeofday(&start, NULL);
+
+       while (inb(PORT_STATUS) & 0x40) {
+               gettimeofday(&now, NULL);
+               if (timediff(now, start) > ACK_TIMEOUT)
+                       do_exit("timeout waiting TH low\n", where);
+       }
+}
+
+static void wait_th_high(const char *where)
+{
+       struct timeval start, now;
+
+       gettimeofday(&start, NULL);
+
+       while (!(inb(PORT_STATUS) & 0x40)) {
+               gettimeofday(&now, NULL);
+               if (timediff(now, start) > ACK_TIMEOUT)
+                       do_exit("timeout waiting TH high\n", where);
+       }
+}
+
+static void output_to_input(void)
+{
+       /* TL high, recv mode; also give time
+        * MD to see TL before we lower it in recv_byte */
+       outb(0xe0, PORT_CONTROL);
+       usleep(4*10);                   /* must be at least 12+8+8 M68k cycles, 28/7.67M */
+}
+
+static void input_to_output(void)
+{
+       wait_th_low("input_to_output");
+       outb(0xc0, PORT_CONTROL);       /* TL high, out mode */
+}
+
+static unsigned int recv_byte(void)
+{
+       unsigned int byte;
+
+       outb(0xe2, PORT_CONTROL);       /* TL low */
+
+       wait_th_low("recv_byte");
+
+       byte = inb(PORT_DATA) & 0x0f;
+
+       outb(0xe0, PORT_CONTROL);       /* TL high */
+
+       wait_th_high("recv_byte");
+
+       byte |= inb(PORT_DATA) << 4;
+
+       return byte;
+}
+
+static void recv_bytes(unsigned char *b, size_t count)
+{
+       while (count-- > 0)
+               *b++ = recv_byte();
+}
+
+static void send_byte(unsigned int byte)
+{
+       wait_th_low("recv_bytes");
+
+       outb(byte & 0x0f, PORT_DATA);
+       outb(0xc2, PORT_CONTROL);       /* TL low */
+
+       wait_th_high("recv_bytes");
+
+       outb((byte >> 4) & 0x0f, PORT_DATA);
+       outb(0xc0, PORT_CONTROL);       /* TL high */
+}
+
+static void send_bytes(unsigned char *b, size_t count)
+{
+       while (count-- > 0)
+               send_byte(*b++);
+}
+
+static void send_cmd(unsigned int cmd)
+{
+       send_byte(CMD_PREFIX);
+       send_byte(cmd);
+}
+
+static void usage(const char *argv0)
+{
+       fprintf(stderr, "usage:\n%s <cmd> [args]\n"
+               "\tsend <file> <addr> [size]\n"
+               "\trecv <file> <addr> <size>\n"
+               "\tjump <addr>\n"
+               "\tio {r{8,16,32} <addr>,w{8,16,32} <addr> <data>}*\n"
+               "\tloadstate <picodrive_savestate>\n"
+               "\trecvvram <file>\n", argv0);
+       exit(1);
+}
+
+static unsigned int atoi_or_die(const char *a)
+{
+       char *p = NULL;
+       unsigned int i;
+
+       i = strtoul(a, &p, 0);
+       if (p == NULL || *p != 0) {
+               fprintf(stderr, "atoi: can't convert: %s\n", a);
+               exit(1);
+       }
+
+       return i;
+}
+
+static void checked_gzread(gzFile f, void *data, size_t size)
+{
+       unsigned int ret;
+       ret = gzread(f, data, size);
+       if (ret != size) {
+               fprintf(stderr, "gzread returned %d/%zu\n", ret, size);
+               exit(1);
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       unsigned int addr = 0, size = 0;
+       unsigned int count = 0, i = 0;
+       int ret;
+       unsigned char *data;
+       FILE *file = NULL;
+
+       if (argc < 2)
+               usage(argv[0]);
+
+       data = malloc(0x1000000);
+       if (data == NULL) {
+               fprintf(stderr, "can't alloc %d bytes\n", 0x1000000);
+               return 1;
+       }
+
+       /* parse args, read files.. */
+       if (strcmp(argv[1], "send") == 0)
+       {
+               if (argc != 4 && argc != 5)
+                       usage(argv[0]);
+
+               file = fopen(argv[2], "rb");
+               if (file == NULL) {
+                       fprintf(stderr, "can't open file: %s\n", argv[2]);
+                       return 1;
+               }
+
+               addr = atoi_or_die(argv[3]);
+               if (argv[4] == NULL) {
+                       fseek(file, 0, SEEK_END);
+                       size = ftell(file);
+                       fseek(file, 0, SEEK_SET);
+               }
+               else
+                       size = atoi_or_die(argv[4]);
+
+               ret = fread(data, 1, size, file);
+               if (ret != size) {
+                       fprintf(stderr, "fread returned %d/%d\n", ret, size);
+                       perror(NULL);
+                       return 1;
+               }
+       }
+       else if (strcmp(argv[1], "recv") == 0)
+       {
+               if (argc != 5)
+                       usage(argv[0]);
+
+               file = fopen(argv[2], "wb");
+               if (file == NULL) {
+                       fprintf(stderr, "can't open file: %s\n", argv[2]);
+                       return 1;
+               }
+
+               addr = atoi_or_die(argv[3]);
+               size = atoi_or_die(argv[4]);
+
+               memset(data, 0, size);
+       }
+       else if (strcmp(argv[1], "jump") == 0)
+       {
+               if (argc != 3)
+                       usage(argv[0]);
+
+               addr = atoi_or_die(argv[2]);
+       }
+       else if (strcmp(argv[1], "io") == 0)
+       {
+               unsigned int cmd = 0, value, iosize;
+               unsigned char *p = data;
+
+               for (i = 2; i < argc; ) {
+                       if (argv[i][0] == 'r')
+                               cmd = IOSEQ_R8;
+                       else if (argv[i][0] == 'w')
+                               cmd = IOSEQ_W8;
+                       else
+                               usage(argv[0]);
+
+                       iosize = atoi_or_die(&argv[i][1]);
+                       if (iosize == 32)
+                               cmd += 2;
+                       else if (iosize == 16)
+                               cmd += 1;
+                       else if (iosize != 8)
+                               usage(argv[0]);
+                       *p++ = cmd;
+                       i++;
+
+                       addr = atoi_or_die(argv[i]);
+                       *p++ = addr >> 16;
+                       *p++ = addr >> 8;
+                       *p++ = addr >> 0;
+                       i++;
+
+                       if (cmd == IOSEQ_W8 || cmd == IOSEQ_W16 || cmd == IOSEQ_W32) {
+                               value = atoi_or_die(argv[i]);
+                               switch (iosize) {
+                               case 32:
+                                       *p++ = value >> 24;
+                                       *p++ = value >> 16;
+                               case 16:
+                                       *p++ = value >> 8;
+                               case 8:
+                                       *p++ = value >> 0;
+                               }
+                               i++;
+                       }
+
+                       count++;
+               }
+       }
+       else if (strcmp(argv[1], "loadstate") == 0)
+       {
+               unsigned char chunk;
+               char header[12];
+               gzFile f;
+               int len;
+
+               if (argc != 3)
+                       usage(argv[0]);
+
+               f = gzopen(argv[2], "rb");
+               if (f == NULL) {
+                       perror("gzopen");
+                       return 1;
+               }
+
+               checked_gzread(f, header, sizeof(header));
+               if (strncmp(header, "PicoSEXT", 8) != 0) {
+                       fprintf(stderr, "bad header\n");
+                       return 1;
+               }
+
+               while (!gzeof(file))
+               {
+                       ret = gzread(f, &chunk, 1);
+                       if (ret == 0)
+                               break;
+                       checked_gzread(f, &len, 4);
+                       //printf("%2d %x\n", chunk, len);
+                       switch (chunk) {
+                       case 3: // VRAM
+                               checked_gzread(f, data, len);
+                               size += len;
+                               break;
+                       case 5: // CRAM
+                               checked_gzread(f, data + 0x10000, len);
+                               size += len;
+                               break;
+                       case 6: // VSRAM
+                               checked_gzread(f, data + 0x10080, len);
+                               size += len;
+                               break;
+                       case 8: // video
+                               checked_gzread(f, data + 0x10100, len);
+                               data[size+0] &= ~1;   // no display disable
+                               data[size+1] |= 0x40; // no blanking
+                               size += 0x20;
+                               break;
+                       default:
+                               if (chunk > 64+8) {
+                                       fprintf(stderr, "bad chunk: %d\n", chunk);
+                                       return 1;
+                               }
+                               gzseek(f, len, SEEK_CUR);
+                               break;
+                       }
+               }
+               gzclose(f);
+               if (size != 0x10120) {
+                       fprintf(stderr, "bad final size: %x\n", size);
+                       return 1;
+               }
+               // unbyteswap *RAMs (stored byteswapped)
+               for (i = 0; i < 0x10100; i += 2) {
+                       int tmp = data[i];
+                       data[i] = data[i + 1];
+                       data[i + 1] = tmp;
+               }
+       }
+       else if (strcmp(argv[1], "recvvram") == 0)
+       {
+               if (argc != 3)
+                       usage(argv[0]);
+
+               file = fopen(argv[2], "wb");
+               if (file == NULL) {
+                       fprintf(stderr, "can't open file: %s\n", argv[2]);
+                       return 1;
+               }
+
+               size = 0x10000;
+               memset(data, 0, size);
+       }
+       else
+               usage(argv[0]);
+
+       ret = ioperm(PORT_DATA, 3, 1);
+       if (ret != 0) {
+               perror("ioperm");
+               return 1;
+       }
+
+       signal(SIGINT, inthandler);
+
+       printf("regs: %02x %02x %02x\n",
+               inb(PORT_DATA), inb(PORT_STATUS), inb(PORT_CONTROL));
+
+       /* wait for start condition */
+       if (!(inb(PORT_STATUS) & 0x40))
+               printf("waiting for TH high..\n");
+       while (!(inb(PORT_STATUS) & 0x40))
+               usleep(10000);
+
+       outb(0xe8, PORT_CONTROL);       /* TR low - request for transfer */
+
+       /* wait for request ack */
+       if (inb(PORT_STATUS) & 0x40)
+               printf("waiting for TH low..\n");
+       for (i = 10000; inb(PORT_STATUS) & 0x40; i += 100) {
+               if (i > 100000)
+                       i = 100000;
+               usleep(i);
+       }
+
+       outb(0xe0, PORT_CONTROL);
+
+       if (strcmp(argv[1], "send") == 0)
+       {
+               send_cmd(CMD_PC_SEND);
+               send_byte((addr >> 16) & 0xff);
+               send_byte((addr >>  8) & 0xff);
+               send_byte((addr >>  0) & 0xff);
+               send_byte((size >> 16) & 0xff);
+               send_byte((size >>  8) & 0xff);
+               send_byte((size >>  0) & 0xff);
+
+               for (i = 0; i < size; i++)
+               {
+                       if ((i & 0xff) == 0) {
+                               printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
+                               printf("%06x/%06x", i, size);
+                               fflush(stdout);
+                       }
+
+                       send_byte(data[i]);
+               }
+       }
+       else if (strcmp(argv[1], "recv") == 0)
+       {
+               send_cmd(CMD_PC_RECV);
+               send_byte((addr >> 16) & 0xff);
+               send_byte((addr >>  8) & 0xff);
+               send_byte((addr >>  0) & 0xff);
+               send_byte((size >> 16) & 0xff);
+               send_byte((size >>  8) & 0xff);
+               send_byte((size >>  0) & 0xff);
+               output_to_input();
+
+               for (i = 0; i < size; i++)
+               {
+                       if ((i & 0xff) == 0) {
+                               printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
+                               printf("%06x/%06x", i, size);
+                               fflush(stdout);
+                       }
+
+                       data[i] = recv_byte();
+               }
+
+               fwrite(data, 1, size, file);
+       }
+       else if (strcmp(argv[1], "jump") == 0)
+       {
+               send_cmd(CMD_JUMP);
+               send_byte((addr >> 16) & 0xff);
+               send_byte((addr >>  8) & 0xff);
+               send_byte((addr >>  0) & 0xff);
+       }
+       else if (strcmp(argv[1], "io") == 0)
+       {
+               unsigned char *p = data;
+               unsigned char rdata[4];
+               send_cmd(CMD_IOSEQ);
+               send_byte((count >> 8) & 0xff);
+               send_byte((count >> 0) & 0xff);
+
+               for (; count > 0; count--) {
+                       input_to_output();
+                       send_bytes(p, 4);       /* cmd + addr */
+
+                       switch (p[0]) {
+                       case IOSEQ_R8:
+                               output_to_input();
+                               recv_bytes(rdata, 1);
+                               printf("r8  %06x       %02x\n", PBE3(p + 1), rdata[0]);
+                               p += 4;
+                               break;
+                       case IOSEQ_R16:
+                               output_to_input();
+                               recv_bytes(rdata, 2);
+                               printf("r16 %06x     %04x\n", PBE3(p + 1), PBE2(rdata));
+                               p += 4;
+                               break;
+                       case IOSEQ_R32:
+                               output_to_input();
+                               recv_bytes(rdata, 4);
+                               printf("r32 %06x %08x\n", PBE3(p + 1), PBE4(rdata));
+                               p += 4;
+                               break;
+                       case IOSEQ_W8:
+                               send_bytes(&p[4], 1);
+                               printf("w8  %06x       %02x\n", PBE3(p + 1), p[4]);
+                               p += 5;
+                               break;
+                       case IOSEQ_W16:
+                               send_bytes(&p[4], 2);
+                               printf("w16 %06x     %04x\n", PBE3(p + 1), PBE2(p + 4));
+                               p += 6;
+                               break;
+                       case IOSEQ_W32:
+                               send_bytes(&p[4], 4);
+                               printf("w32 %06x %08x\n", PBE3(p + 1), PBE4(p + 4));
+                               p += 8;
+                               break;
+                       default:
+                               do_exit("error in ioseq data\n", NULL);
+                               break;
+                       }
+               }
+       }
+       else if (strcmp(argv[1], "loadstate") == 0)
+       {
+               send_cmd(CMD_LOADSTATE);
+
+               for (i = 0; i < size; i++)
+               {
+                       if ((i & 0x1f) == 0) {
+                               printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
+                               printf("%06x/%06x", i, size);
+                               fflush(stdout);
+                       }
+
+                       send_byte(data[i]);
+               }
+       }
+       else if (strcmp(argv[1], "recvvram") == 0)
+       {
+               send_cmd(CMD_VRAM_RECV);
+               output_to_input();
+
+               for (i = 0; i < size; i++)
+               {
+                       if ((i & 0xff) == 0) {
+                               printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
+                               printf("%06x/%06x", i, size);
+                               fflush(stdout);
+                       }
+
+                       data[i] = recv_byte();
+               }
+
+               fwrite(data, 1, size, file);
+       }
+
+       if (size != 0) {
+               printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
+               printf("%06x/%06x\n", i, size);
+       }
+       if (file != NULL)
+               fclose(file);
+
+       /* switch TL back to high, disable outputs */
+       outb(0xe0, PORT_CONTROL);
+
+       return 0;
+}
+
diff --git a/hexed/readme.txt b/hexed/readme.txt
new file mode 100644 (file)
index 0000000..cac50e0
--- /dev/null
@@ -0,0 +1,19 @@
+-------------------------------------------------------------------------------\r
+hexed - realtime memory viewer for Genesis/Megadrive\r
+  written by Gražvydas "notaz" Ignotas\r
+-------------------------------------------------------------------------------\r
+\r
+This is rather simple address space viewer for Genesis/Megadrive. It is capable\r
+of displaying 216 bytes of memory simultaneously in a manner similar to some\r
+hex editors for the PC, with refresh of 50/60Hz. It was created for hardware\r
+research purposes.\r
+\r
+Here are the key bindings:\r
+  A + up, A + down    - scroll one line up/down.\r
+  A + left, A + right - scroll one page up/down.\r
+  B     - toggle between byte/word display/edit mode.\r
+  C     - edit highlighted value.\r
+  Start - enter menu.\r
+\r
+\r
+hexed is released under the BSD license (see included source code for details).\r
diff --git a/hexed/sega_gcc.s b/hexed/sega_gcc.s
new file mode 100644 (file)
index 0000000..07a3494
--- /dev/null
@@ -0,0 +1,106 @@
+        dc.l 0x0,0x200\r
+        dc.l INT,INT,INT,INT,INT,INT,INT\r
+        dc.l INT,INT,INT,INT,INT,INT,INT,INT\r
+        dc.l INT,INT,INT,INT,INT,INT,INT,INT\r
+        dc.l INT,INT,INT,HBL,INT,VBL,INT,INT\r
+        dc.l INT,INT,INT,INT,INT,INT,INT,INT\r
+        dc.l INT,INT,INT,INT,INT,INT,INT,INT\r
+        dc.l INT,INT,INT,INT,INT,INT,INT,INT\r
+        dc.l INT,INT,INT,INT,INT,INT,INT\r
+        .ascii "SEGA GENESIS                    "\r
+        .ascii "hexed (c) notaz, 2009-2011                      "\r
+        .ascii "HEXED (C) NOTAZ, 2009-2011                      "\r
+        .ascii "GM 00000000-00"\r
+        .byte 0x00,0x00\r
+        .ascii "JD              "\r
+        .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00\r
+        .byte 0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff\r
+        .ascii "               "\r
+        .ascii "                        "\r
+        .ascii "                         "\r
+        .ascii "JUE             "\r
+\r
+       moveq   #0,%d0\r
+       movea.l %d0,%a7\r
+       move    %a7,%usp\r
+       bra     main\r
+\r
+* INT:\r
+*      rte\r
+\r
+HBL:\r
+       rte\r
+\r
+* VBL:\r
+*      addq.l #1,(vtimer).l\r
+*      rte\r
+\r
+* Standard 32X startup code for MD side at 0x3F0\r
+       .org 0x3F0\r
+\r
+        .word   0x287C,0xFFFF,0xFFC0,0x23FC,0x0000,0x0000,0x00A1,0x5128\r
+        .word   0x46FC,0x2700,0x4BF9,0x00A1,0x0000,0x7001,0x0CAD,0x4D41\r
+        .word   0x5253,0x30EC,0x6600,0x03E6,0x082D,0x0007,0x5101,0x67F8\r
+        .word   0x4AAD,0x0008,0x6710,0x4A6D,0x000C,0x670A,0x082D,0x0000\r
+        .word   0x5101,0x6600,0x03B8,0x102D,0x0001,0x0200,0x000F,0x6706\r
+        .word   0x2B78,0x055A,0x4000,0x7200,0x2C41,0x4E66,0x41F9,0x0000\r
+        .word   0x04D4,0x6100,0x0152,0x6100,0x0176,0x47F9,0x0000,0x04E8\r
+        .word   0x43F9,0x00A0,0x0000,0x45F9,0x00C0,0x0011,0x3E3C,0x0100\r
+        .word   0x7000,0x3B47,0x1100,0x3B47,0x1200,0x012D,0x1100,0x66FA\r
+        .word   0x7425,0x12DB,0x51CA,0xFFFC,0x3B40,0x1200,0x3B40,0x1100\r
+        .word   0x3B47,0x1200,0x149B,0x149B,0x149B,0x149B,0x41F9,0x0000\r
+        .word   0x04C0,0x43F9,0x00FF,0x0000,0x22D8,0x22D8,0x22D8,0x22D8\r
+        .word   0x22D8,0x22D8,0x22D8,0x22D8,0x41F9,0x00FF,0x0000,0x4ED0\r
+        .word   0x1B7C,0x0001,0x5101,0x41F9,0x0000,0x06BC,0xD1FC,0x0088\r
+        .word   0x0000,0x4ED0,0x0404,0x303C,0x076C,0x0000,0x0000,0xFF00\r
+        .word   0x8137,0x0002,0x0100,0x0000,0xAF01,0xD91F,0x1127,0x0021\r
+        .word   0x2600,0xF977,0xEDB0,0xDDE1,0xFDE1,0xED47,0xED4F,0xD1E1\r
+        .word   0xF108,0xD9C1,0xD1E1,0xF1F9,0xF3ED,0x5636,0xE9E9,0x9FBF\r
+        .word   0xDFFF,0x4D41,0x5253,0x2049,0x6E69,0x7469,0x616C,0x2026\r
+        .word   0x2053,0x6563,0x7572,0x6974,0x7920,0x5072,0x6F67,0x7261\r
+        .word   0x6D20,0x2020,0x2020,0x2020,0x2020,0x2043,0x6172,0x7472\r
+        .word   0x6964,0x6765,0x2056,0x6572,0x7369,0x6F6E,0x2020,0x2020\r
+        .word   0x436F,0x7079,0x7269,0x6768,0x7420,0x5345,0x4741,0x2045\r
+        .word   0x4E54,0x4552,0x5052,0x4953,0x4553,0x2C4C,0x5444,0x2E20\r
+        .word   0x3139,0x3934,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020\r
+        .word   0x2020,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020\r
+        .word   0x2020,0x2020,0x2020,0x524F,0x4D20,0x5665,0x7273,0x696F\r
+        .word   0x6E20,0x312E,0x3000,0x48E7,0xC040,0x43F9,0x00C0,0x0004\r
+        .word   0x3011,0x303C,0x8000,0x323C,0x0100,0x3E3C,0x0012,0x1018\r
+        .word   0x3280,0xD041,0x51CF,0xFFF8,0x4CDF,0x0203,0x4E75,0x48E7\r
+        .word   0x81C0,0x41F9,0x0000,0x063E,0x43F9,0x00C0,0x0004,0x3298\r
+        .word   0x3298,0x3298,0x3298,0x3298,0x3298,0x3298,0x2298,0x3341\r
+        .word   0xFFFC,0x3011,0x0800,0x0001,0x66F8,0x3298,0x3298,0x7000\r
+        .word   0x22BC,0xC000,0x0000,0x7E0F,0x3340,0xFFFC,0x3340,0xFFFC\r
+        .word   0x3340,0xFFFC,0x3340,0xFFFC,0x51CF,0xFFEE,0x22BC,0x4000\r
+        .word   0x0010,0x7E09,0x3340,0xFFFC,0x3340,0xFFFC,0x3340,0xFFFC\r
+        .word   0x3340,0xFFFC,0x51CF,0xFFEE,0x4CDF,0x0381,0x4E75,0x8114\r
+        .word   0x8F01,0x93FF,0x94FF,0x9500,0x9600,0x9780,0x4000,0x0080\r
+        .word   0x8104,0x8F02,0x48E7,0xC140,0x43F9,0x00A1,0x5180,0x08A9\r
+        .word   0x0007,0xFF80,0x66F8,0x3E3C,0x00FF,0x7000,0x7200,0x337C\r
+        .word   0x00FF,0x0004,0x3341,0x0006,0x3340,0x0008,0x4E71,0x0829\r
+        .word   0x0001,0x000B,0x66F8,0x0641,0x0100,0x51CF,0xFFE8,0x4CDF\r
+        .word   0x0283,0x4E75,0x48E7,0x8180,0x41F9,0x00A1,0x5200,0x08A8\r
+        .word   0x0007,0xFF00,0x66F8,0x3E3C,0x001F,0x20C0,0x20C0,0x20C0\r
+        .word   0x20C0,0x51CF,0xFFF6,0x4CDF,0x0181,0x4E75,0x41F9,0x00FF\r
+        .word   0x0000,0x3E3C,0x07FF,0x7000,0x20C0,0x20C0,0x20C0,0x20C0\r
+        .word   0x20C0,0x20C0,0x20C0,0x20C0,0x51CF,0xFFEE,0x3B7C,0x0000\r
+        .word   0x1200,0x7E0A,0x51CF,0xFFFE,0x43F9,0x00A1,0x5100,0x7000\r
+        .word   0x2340,0x0020,0x2340,0x0024,0x1B7C,0x0003,0x5101,0x2E79\r
+        .word   0x0088,0x0000,0x0891,0x0007,0x66FA,0x7000,0x3340,0x0002\r
+        .word   0x3340,0x0004,0x3340,0x0006,0x2340,0x0008,0x2340,0x000C\r
+        .word   0x3340,0x0010,0x3340,0x0030,0x3340,0x0032,0x3340,0x0038\r
+        .word   0x3340,0x0080,0x3340,0x0082,0x08A9,0x0000,0x008B,0x66F8\r
+        .word   0x6100,0xFF12,0x08E9,0x0000,0x008B,0x67F8,0x6100,0xFF06\r
+        .word   0x08A9,0x0000,0x008B,0x6100,0xFF3C,0x303C,0x0040,0x2229\r
+        .word   0x0020,0x0C81,0x5351,0x4552,0x6700,0x0092,0x303C,0x0080\r
+        .word   0x2229,0x0020,0x0C81,0x5344,0x4552,0x6700,0x0080,0x21FC\r
+        .word   0x0088,0x02A2,0x0070,0x303C,0x0002,0x7200,0x122D,0x0001\r
+        .word   0x1429,0x0080,0xE14A,0x8242,0x0801,0x000F,0x660A,0x0801\r
+        .word   0x0006,0x6700,0x0058,0x6008,0x0801,0x0006,0x6600,0x004E\r
+        .word   0x7020,0x41F9,0x0088,0x0000,0x3C28,0x018E,0x4A46,0x6700\r
+        .word   0x0010,0x3429,0x0028,0x0C42,0x0000,0x67F6,0xB446,0x662C\r
+        .word   0x7000,0x2340,0x0028,0x2340,0x002C,0x3E14,0x2C7C,0xFFFF\r
+        .word   0xFFC0,0x4CD6,0x7FF9,0x44FC,0x0000,0x6014,0x43F9,0x00A1\r
+        .word   0x5100,0x3340,0x0006,0x303C,0x8000,0x6004,0x44FC,0x0001\r
+\r
diff --git a/hexed/transfer.S b/hexed/transfer.S
new file mode 100644 (file)
index 0000000..ef5bf5d
--- /dev/null
@@ -0,0 +1,447 @@
+###############################################################################
+#
+# Copyright (c) 2011, Gražvydas Ignotas
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the organization nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Assemble with gas
+#   --register-prefix-optional --bitwise-or
+#
+
+#include "transfer.h"
+
+.text
+.globl do_transfer
+
+
+# receive 1 byte to d0
+#  in: a1 - data port
+#  trash: d1
+.macro recv_one_byte is_last=0
+       move.b          #0,(a1)         /* clear TH */
+
+0: /*L_wait_tl_low*/
+       move.b          (a1),d1
+       btst.b          #4,d1
+       bne             0b /*L_wait_tl_low*/
+
+       move.b          #0x40,(a1)      /* set TH */
+       and.b           #0x0f,d1
+
+0: /*L_wait_tl_hi*/
+       move.b          (a1),d0
+       btst.b          #4,d0
+       beq             0b /*L_wait_tl_hi*/
+
+.if !\is_last
+       move.b          #0,(a1)         /* clear TH - ready for next */
+.endif
+       lsl.b           #4,d0
+       or.b            d1,d0
+.endm
+
+# send 1 byte in d0
+#  in: a1 - data port
+#  trash: d1,d2
+.macro send_one_byte
+       move.b          d0,d2
+       and.b           #0x0f,d2
+
+0: /*Lwait_tl_low:*/
+       move.b          (a1),d1
+       btst.b          #4,d1
+       bne             0b /*Lwait_tl_low*/
+
+       move.b          d2,(a1)         /* clears TH and writes data */
+
+       move.b          d0,d2
+       lsr.b           #4,d2
+       bset.b          #6,d2           /* prepare TH */
+
+0: /*wait_tl_hi*/
+       move.b          (a1),d1
+       btst.b          #4,d1
+       beq             0b /*wait_tl_hi1*/
+
+       move.b          d2,(a1)
+.endm
+
+recv_byte:
+       moveq.l         #0,d0
+       recv_one_byte 1
+       rts
+
+# receive 1 16bit word to d0
+#  in: a1 - data port
+#  trash: d1,d2
+recv_word:
+       recv_one_byte
+       move.b          d0,d2
+       recv_one_byte
+       lsl.w           #8,d2
+       move.b          d0,d2
+       move.w          d2,d0
+       rts
+
+# receive address/size to d0 (3 bytes BE)
+#  in: a1 - data port
+#  trash: d1,d2
+recv_ad:
+       moveq.l         #0,d2
+       bsr             recv_byte
+       move.b          d0,d2
+       bsr             recv_byte
+       lsl.l           #8,d2
+       move.b          d0,d2
+       bsr             recv_byte
+       lsl.l           #8,d2
+       move.b          d0,d2
+       move.l          d2,d0
+       rts
+
+# send 1 byte in d0
+#  in: a1 - data port
+#  trash: d1,d2
+send_byte:
+       send_one_byte
+       rts
+
+.macro switch_to_output
+0: /*Lwait_tl_low: PC should switch to rx mode before lowering tl */
+       move.b          (a1),d0
+       btst.b          #4,d0
+       bne             0b /*Lwait_tl_low*/
+
+       move.b          #0x4f,(0xa1000b).l
+       move.b          #0x40,(a1)
+.endm
+
+.equ sat_maxsize, (80*8+0x200) /* sprites+max_align */
+
+# make sure cache is invalidated
+# note: VRAM copy doesn't seem to help here
+# note2: cache is updated as data is written
+#  in: d0 - vdp reg5, a0 = 0xc00000
+#  trash: d1,d2,a2
+invalidate_sprite_cache:
+       move.w          #0x8f02,4(a0)           /* auto increment 2 */
+       lsl.b           #1,d0                   /* upper byte of sat address */
+       move.b          d0,d1
+       lsr.b           #6,d1                   /* 15:14 dst addr */
+       and.b           #0x3f,d0                /* assemble cmd */
+       lsl.w           #8,d0
+       swap            d0
+       move.b          d1,d0
+       move.l          d0,4(a0)
+
+       move.l          #0xffe000,a2
+       move.l          #sat_maxsize/2-1,d2
+0:
+       move.w          (a0),(a2)+
+       dbra            d2,0b
+
+       bset            #30,d0                  /* VRAM write */
+       move.l          d0,4(a0)
+
+       move.l          #0xffe000,a2
+       move.l          #sat_maxsize/2-1,d2
+0:
+       move.w          (a2)+,(a0)
+       dbra            d2,0b
+       rts
+
+
+
+do_transfer:
+       lea             0xa10005,a1
+       move.b          #0x40,(0xa1000b).l      /* ctrl - all inputs except TH */
+       move.b          #0x00,(a1)
+
+       bsr             recv_byte
+       cmp.b           #CMD_PREFIX,d0
+       bne             return
+
+       bsr             recv_byte
+       cmp.b           #CMD_FIRST,d0
+       bcs             return
+       cmp.b           #CMD_LAST+1,d0
+       bcc             return
+       sub.b           #CMD_FIRST,d0
+
+       lsl.w           #2,d0
+       lea             (jumptab,pc,d0),a0
+       jmp             (a0)
+jumptab:
+       bra             pcc_transfer_recv       /* sent to us */
+       bra             pcc_transfer_send       /* recv from us */
+       bra             pcc_jump
+       bra             pcc_io
+       bra             pcc_loadstate
+       bra             pcc_vram_send
+       bra             pcc_test_code
+
+
+/* receive data from PC */
+pcc_transfer_recv:
+       bsr             recv_ad
+       move.l          d0,a0
+       bsr             recv_ad
+       move.l          d0,d3
+
+tr_recv_loop:
+       recv_one_byte
+       move.b          d0,(a0)+
+       subq.l          #1,d3
+       bgt             tr_recv_loop
+       bra             return
+
+
+/* send data to PC */
+pcc_transfer_send:
+       bsr             recv_ad
+       move.l          d0,a0
+       bsr             recv_ad
+       move.l          d0,d3
+
+       switch_to_output
+
+tr_send_loop:
+       move.b          (a0)+,d0
+       send_one_byte
+       subq.l          #1,d3
+       bgt             tr_send_loop
+       bra             return
+
+
+/* call specified location */
+pcc_jump:
+       bsr             recv_ad
+       move.l          d0,a0
+       jsr             (a0)
+       bra             return
+
+
+/* do simple i/o commands */
+pcc_io:
+       moveq.l         #0,d4
+       bsr             recv_byte
+       move.b          d0,d4
+       bsr             recv_byte
+       lsl.l           #8,d4
+       move.b          d0,d4
+
+pcc_io_loop:
+       move.b          #0x40,(0xa1000b).l      /* input mode */
+
+       sub.w           #1,d4
+       bmi             return
+
+       bsr             recv_byte
+       move.b          d0,d3                   /* cmd */
+
+       bsr             recv_ad
+       move.l          d0,a2                   /* addr */
+
+       cmp.b           #IOSEQ_W32, d3
+       beq             pcc_io_w32
+       cmp.b           #IOSEQ_W16, d3
+       beq             pcc_io_w16
+       cmp.b           #IOSEQ_W8, d3
+       bne             pcc_io_rx
+
+pcc_io_w8:
+       bsr             recv_byte
+       move.b          d0,(a2)
+       bra             pcc_io_loop
+
+pcc_io_w16:
+       bsr             recv_byte
+       move.b          d0,d3
+       bsr             recv_byte
+       lsl.w           #8,d3
+       move.b          d0,d3
+       move.w          d3,(a2)
+       bra             pcc_io_loop
+
+pcc_io_w32:
+       bsr             recv_byte
+       move.b          d0,d3
+       bsr             recv_byte
+       lsl.w           #8,d3
+       move.b          d0,d3
+       bsr             recv_byte
+       lsl.l           #8,d3
+       move.b          d0,d3
+       bsr             recv_byte
+       lsl.l           #8,d3
+       move.b          d0,d3
+       move.l          d3,(a2)
+       bra             pcc_io_loop
+
+pcc_io_rx:
+       switch_to_output
+
+       cmp.b           #IOSEQ_R32, d3
+       beq             pcc_io_r32
+       cmp.b           #IOSEQ_R16, d3
+       beq             pcc_io_r16
+       cmp.b           #IOSEQ_R8, d3
+       bne             return
+
+pcc_io_r8:
+       move.b          (a2),d0
+       bsr             send_byte
+       bra             pcc_io_loop
+
+pcc_io_r16:
+       move.w          (a2),d3
+       move.w          d3,d0
+       lsr.w           #8,d0
+       bsr             send_byte
+       move.b          d3,d0
+       bsr             send_byte
+       bra             pcc_io_loop
+
+pcc_io_r32:
+       move.l          (a2),d3
+       move.l          d3,d0
+       swap            d0
+       lsr.l           #8,d0
+       bsr             send_byte
+       move.l          d3,d0
+       swap            d0
+       bsr             send_byte
+       move.w          d3,d0
+       lsr.w           #8,d0
+       bsr             send_byte
+       move.b          d3,d0
+       bsr             send_byte
+       bra             pcc_io_loop
+
+
+/* PicoDrive savestate load */
+pcc_loadstate:
+       /* write VRAM */
+       move.l          #0xc00000,a0
+       move.w          #0x8f02,4(a0)           /* auto increment 2 */
+
+       move.l          #0x40000000,4(a0)
+       move.l          #0x10000/2-1,d3
+tr_do_vram_loop:
+       bsr             recv_word
+       move.w          d0,(a0)
+       dbra            d3, tr_do_vram_loop
+
+       /* write cram */
+       move.l          #0xc0000000,4(a0)
+       move.l          #0x80/2-1,d3
+tr_do_cram_loop:
+       bsr             recv_word
+       move.w          d0,(a0)
+       dbra            d3, tr_do_cram_loop
+
+       /* write vsram */
+       move.l          #0x40000010,4(a0)
+       move.l          #0x80/2-1,d3
+tr_do_vsram_loop:
+       bsr             recv_word
+       move.w          d0,(a0)
+       dbra            d3, tr_do_vsram_loop
+
+       /* recv and write regs */
+       lea             0xffe000,a3
+       move.l          a3,a2
+       moveq.l         #0x20-1,d3
+tr_do_vdpreg_recv_loop:
+       bsr             recv_byte
+       move.b          d0,(a2)+
+       dbra            d3, tr_do_vdpreg_recv_loop
+
+       move.l          a3,a2
+       moveq.l         #0,d3
+tr_do_vdpreg_loop:
+       move.b          d3,d1
+       or.b            #0x80,d1
+       lsl.w           #8,d1
+       move.b          (d3,a2),d1
+       move.w          d1,4(a0)
+       addq.l          #1,d3
+       cmp.b           #0x17,d3        /* FIXME: r23 might cause DMA or.. */
+       bne             0f              /* ..something and hang VDP.. */
+       add.b           #1,d3           /* ..so we skip it */
+0:
+       cmp.b           #0x20,d3
+       blt             tr_do_vdpreg_loop
+
+       moveq.l         #0,d0
+       move.b          5(a3),d0
+       bsr             invalidate_sprite_cache
+
+
+0:     bra             0b
+
+       bra             return
+
+
+pcc_vram_send:
+       /* write VRAM */
+       move.l          #0xc00000,a0
+       move.w          #0x8f02,4(a0)           /* auto increment 2 */
+       move.l          #0,4(a0)                /* VRAM read, addr 0 */
+       move.l          #0x10000/2-1,d4
+
+       switch_to_output
+
+tr_vram_send_loop:
+       move.w          (a0),d3
+       move.w          d3,d0
+       lsr.w           #8,d0
+       bsr             send_byte
+       move.b          d3,d0
+       bsr             send_byte
+       dbra            d4,tr_vram_send_loop
+
+       bra             return
+
+
+
+/* some random code */
+pcc_test_code:
+       bra             return
+
+
+
+return:
+       move.b          #0,(0xa1000b).l /* all inputs */
+       move.l          #0xffe000,a1
+       move.l          d0,(a1)+        /* last state for debug */
+       move.l          d1,(a1)+
+       move.l          d2,(a1)+
+       move.l          d3,(a1)+
+       move.l          a0,(a1)+
+       rts
+#      bra             return_to_main
+
+
+# vim:filetype=asmM68k
diff --git a/hexed/transfer.h b/hexed/transfer.h
new file mode 100644 (file)
index 0000000..118b752
--- /dev/null
@@ -0,0 +1,20 @@
+/* all data is big endian */
+
+#define CMD_PREFIX     0x5a
+#define CMD_PC_SEND    0xc1    /* send to MD:   addr[3], len[3], data[] */
+#define CMD_PC_RECV    0xc2    /* recv from MD: addr[3], len[3], data[] */
+#define CMD_JUMP       0xc3    /* jump to addr: addr[3] */
+#define CMD_IOSEQ      0xc4    /* perform i/o ops: count[2], [type[1], addr[3], data[{0,1,2,4}]]* */
+#define CMD_LOADSTATE  0xc5    /* load PD state: vram[64k], cram[128], vsram[128], vdp[32] */
+#define CMD_VRAM_RECV  0xc6    /* recv from MD: vram[64k] */
+#define CMD_TEST       0xc7    /* test code */
+
+#define CMD_FIRST      CMD_PC_SEND
+#define CMD_LAST       CMD_TEST
+
+#define IOSEQ_R8       0xb0
+#define IOSEQ_R16      0xb1
+#define IOSEQ_R32      0xb2
+#define IOSEQ_W8       0xb3
+#define IOSEQ_W16      0xb4
+#define IOSEQ_W32      0xb5
diff --git a/mdpcjoy/mdpcjoy.c b/mdpcjoy/mdpcjoy.c
new file mode 100644 (file)
index 0000000..8ae6f82
--- /dev/null
@@ -0,0 +1,111 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/input.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/io.h>
+
+int main()
+{
+       int i, ret, fd;
+       int dpad = 0;
+
+       for (i = 0;; i++)
+       {
+               int support = 0;
+               char name[64];
+
+               snprintf(name, sizeof(name), "/dev/input/event%d", i);
+               fd = open(name, O_RDONLY);
+               if (fd == -1)
+                       break;
+
+               /* check supported events */
+               ret = ioctl(fd, EVIOCGBIT(0, sizeof(support)), &support);
+               if (ret == -1) {
+                       printf("ioctl failed on %s\n", name);
+                       goto skip;
+               }
+
+               if (!(support & (1 << EV_KEY)))
+                       goto skip;
+               if (!(support & (1 << EV_ABS)))
+                       goto skip;
+
+               ioctl(fd, EVIOCGNAME(sizeof(name)), name);
+               printf("found \"%s\" (type %08x)\n", name, support);
+               break;
+
+skip:
+               close(fd);
+               fd = -1;
+       }
+
+       if (fd == -1) {
+               printf("no suitable devs\n");
+               return 1;
+       }
+
+       ret = ioperm(888, 3, 1);
+       if (ret != 0) {
+               perror("ioperm");
+               return 1;
+       }
+
+       outb(0xc0, 890);        /* switch to output mode, TL and TR high */
+       outb(0x0f, 888);        /* Dx high */
+
+       while (1)
+       {
+               struct input_event ev;
+               int rd;
+
+               rd = read(fd, &ev, sizeof(ev));
+               if (rd < (int) sizeof(ev)) {
+                       perror("in_evdev: error reading");
+                       return 1;
+               }
+
+               if (ev.type == EV_KEY) {
+                       int val = 0xc0;
+                       if (ev.code & 1) {
+                               if (ev.value)
+                                       val |= 2;
+                               else
+                                       val &= ~2;
+                       } else {
+                               if (ev.value)
+                                       val |= 8;
+                               else
+                                       val &= ~8;
+                       }
+                       outb(val, 890);
+               }
+               else if (ev.type == EV_ABS)
+               {
+                       if (ev.code == ABS_X) {
+                               if (ev.value < 128)
+                                       dpad |= 4;
+                               else if (ev.value > 128)
+                                       dpad |= 8;
+                               else
+                                       dpad &= ~0x0c;
+                       }
+                       if (ev.code == ABS_Y) {
+                               if (ev.value < 128)
+                                       dpad |= 1;
+                               else if (ev.value > 128)
+                                       dpad |= 2;
+                               else
+                                       dpad &= ~3;
+                       }
+                       outb(~dpad & 0x0f, 888);
+               }
+       }
+
+       return 0;
+}
+
diff --git a/mega-usb/Makefile b/mega-usb/Makefile
new file mode 100644 (file)
index 0000000..8d5879e
--- /dev/null
@@ -0,0 +1,9 @@
+CFLAGS += -Wall -ggdb
+ifndef DEBUG
+CFLAGS += -O2
+endif
+
+all: mega-usb
+
+clean:
+       $(RM) mega-usb
diff --git a/mega-usb/mega-usb.c b/mega-usb/mega-usb.c
new file mode 100644 (file)
index 0000000..2649797
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * Tool for USB communication with Mega Everdrive
+ * Copyright (c) 2013,2014 notaz
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be 
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define _BSD_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <arpa/inet.h> // hton
+#include <termios.h>
+#include <unistd.h>
+
+static int setup(int fd)
+{
+       struct termios tty;
+       int ret;
+
+       memset(&tty, 0, sizeof(tty));
+
+       ret = tcgetattr(fd, &tty);
+       if (ret != 0)
+       {
+               perror("tcgetattr");
+               return 1;
+       }
+
+       tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
+                       | INLCR | IGNCR | ICRNL | IXON);
+       tty.c_oflag &= ~OPOST;
+       tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+       tty.c_cflag &= ~(CSIZE | PARENB);
+       tty.c_cflag |= CS8;
+
+       //tty.c_cc[VMIN] = 1;
+       //tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout
+
+       ret = tcsetattr(fd, TCSANOW, &tty);
+       if (ret != 0) {
+               perror("tcsetattr");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int write_to_cart(int fd, const void *data, size_t size)
+{
+       int ret;
+
+       ret = write(fd, data, size);
+       if (ret != size) {
+               fprintf(stderr, "write %d/%zd: ", ret, size);
+               perror("");
+               exit(1);
+               //return -1;
+       }
+
+       return 0;
+}
+
+static int read_from_cart(int fd, void *data, size_t size)
+{
+       size_t got = 0;
+       int ret;
+
+       while (got < size) {
+               ret = read(fd, (char *)data + got, size - got);
+               if (ret <= 0) {
+                       fprintf(stderr, "read %d %zd/%zd: ",
+                               ret, got, size);
+                       perror("");
+                       exit(1);
+                       //return -1;
+               }
+               got += ret;
+       }
+
+       return 0;
+}
+
+#define send_cmd(fd, cmd) \
+       write_to_cart(fd, cmd, strlen(cmd))
+
+static int read_check_byte(int fd, char expect)
+{
+       char r = '0';
+       int ret;
+
+       ret = read_from_cart(fd, &r, 1);
+       if (ret != 0) {
+               fprintf(stderr, "missing response, need '%c'\n", expect);
+               return -1;
+       }
+
+       if (r != expect) {
+               fprintf(stderr, "unexpected response: '%c', need '%c'\n",
+                       r, expect);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int write_with_check(int fd, const void *data, size_t size, char chk)
+{
+       int ret;
+
+       ret = write_to_cart(fd, data, size);
+       if (ret)
+               return ret;
+
+       ret = read_check_byte(fd, chk);
+       if (ret != 0) {
+               if (size < 16)
+                       fprintf(stderr, "data sent: '%16s'\n",
+                               (const char *)data);
+               exit(1);
+               //return -1;
+       }
+
+       return 0;
+}
+
+#define send_cmd_check_k(fd, cmd) \
+       write_with_check(fd, cmd, strlen(cmd), 'k')
+
+static int send_file(int fd, const char *fname, const char *cmd)
+{
+       char buf[0x10000];
+       int retval = -1;
+       FILE *f = NULL;
+       size_t blocksz;
+       size_t size;
+       int blocks;
+       int ret;
+       int i;
+
+       f = fopen(fname, "rb");
+       if (f == NULL) {
+               fprintf(stderr, "fopen %s: ", fname);
+               perror("");
+               return -1;
+       }
+
+       fseek(f, 0, SEEK_END);
+       size = ftell(f);
+       fseek(f, 0, SEEK_SET);
+       if (size > 0xf00000) {
+               fprintf(stderr, "size too large: %zd\n", size);
+               goto out;
+       }
+
+       if (cmd[1] == 'f')
+               blocksz = 1024;
+       else
+               blocksz = sizeof(buf);
+
+       blocks = (size + blocksz - 1) / blocksz;
+
+       send_cmd(fd, cmd);
+       ret = write_with_check(fd, &blocks, 1, 'k');
+       if (ret)
+               return ret;
+
+       // at this point, 'd' will arrive even if we don't
+       // write any more data, what's the point of that?
+       // probably a timeout?
+
+       for (i = 0; i < blocks; i++) {
+               ret = fread(buf, 1, blocksz, f);
+               if (i != blocks - 1 && ret != blocksz) {
+                       fprintf(stderr, "failed to read block %d/%d\n",
+                               i, blocks);
+               }
+               if (ret < blocksz)
+                       memset(buf + ret, 0, blocksz - ret);
+
+               write_to_cart(fd, buf, blocksz);
+       }
+
+       ret = read_check_byte(fd, 'd');
+       if (ret)
+               goto out;
+
+       retval = 0;
+out:
+       if (f != NULL)
+               fclose(f);
+
+       return retval;
+}
+
+static int recv_file(int fd, const char *fname, unsigned int addr,
+       unsigned int size)
+{
+       int retval = -1;
+       char *buf = NULL;
+       FILE *f = NULL;
+       struct {
+               unsigned int addr;
+               unsigned int size;
+       } addr_size;
+       int ret;
+
+       f = fopen(fname, "wb");
+       if (f == NULL) {
+               fprintf(stderr, "fopen %s: ", fname);
+               perror("");
+               return -1;
+       }
+
+       buf = malloc(size);
+       if (buf == NULL) {
+               fprintf(stderr, "OOM?\n");
+               goto out;
+       }
+
+       send_cmd(fd, "*xd");
+
+       addr_size.addr = htonl(addr);
+       addr_size.size = htonl(size);
+       ret = write_with_check(fd, &addr_size, sizeof(addr_size), 'k');
+       if (ret)
+               return ret;
+
+       ret = read_from_cart(fd, buf, size);
+       if (ret)
+               goto out;
+
+       ret = fwrite(buf, 1, size, f);
+       if (ret != size) {
+               fprintf(stderr, "fwrite %d/%d: ", ret, size);
+               perror("");
+               goto out;
+       }
+
+       retval = 0;
+out:
+       if (f != NULL)
+               fclose(f);
+       free(buf);
+
+       return retval;
+}
+
+static void usage(const char *argv0)
+{
+       printf("usage:\n"
+               "%s [-d <ttydevice>] [-f <file>] command(s)\n"
+               "known commands for ED OS:\n"
+               "  *g - upload game\n"
+               "  *w - upload and start OS\n"
+               "  *o - upload and start OS\n"
+               "  *f - upload (and start?) FPGA firmware\n"
+               "  *s - start last ROM (same as pressing start in menu)\n"
+               "  *r<x> - run SDRAM contents as mapper x:\n"
+               "    s - sms, m - md, o - OS app, c - cd BIOS, M - md10m\n"
+               "upload commands must be followed by -f <file>\n"
+               "custom OS commands:\n"
+               "  *xd <addr> <size> <file> - download memory\n"
+               , argv0);
+       exit(1);
+}
+
+static void invarg(int argc, char *argv[], int arg)
+{
+       if (arg < argc)
+               fprintf(stderr, "invalid arg %d: \"%s\"\n", arg, argv[arg]);
+       else
+               fprintf(stderr, "missing required argument %d\n", arg);
+       exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+       const char *portname = "/dev/ttyUSB0";
+       const char *pending_cmd = NULL;
+       int ret = -1;
+       int arg = 1;
+       int fd;
+
+       if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
+               usage(argv[0]);
+
+       if (!strcmp(argv[arg], "-d")) {
+               arg++;
+               if (argv[arg] != NULL)
+                       portname = argv[arg];
+               else
+                       invarg(argc, argv, arg);
+               arg++;
+       }
+
+       fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
+       if (fd < 0) {
+               fprintf(stderr, "open %s: ", portname);
+               perror("");
+               return 1;
+       }
+
+       setup(fd);
+
+       send_cmd_check_k(fd, "    *T");
+
+       for (; arg < argc; arg++) {
+               if (!strcmp(argv[arg], "-f")) {
+                       arg++;
+                       if (argv[arg] == NULL)
+                               invarg(argc, argv, argc);
+                       if (pending_cmd == NULL)
+                               // assume game upload
+                               pending_cmd = "*g";
+
+                       ret = send_file(fd, argv[arg], pending_cmd);
+                       if (ret)
+                               return ret;
+
+                       pending_cmd = NULL;
+                       continue;
+               }
+               if (argv[arg + 1] && !strcmp(argv[arg + 1], "-f")) {
+                       /* we'll avoid sending command if there are
+                        * problems with specified file */
+                       pending_cmd = argv[arg];
+                       continue;
+               }
+               /* custom OS commands */
+               if (!strcmp(argv[arg], "*xd")) {
+                       unsigned int addr, size;
+                       if (arg + 3 >= argc)
+                               invarg(argc, argv, argc);
+                       addr = strtoul(argv[++arg], NULL, 0);
+                       size = strtoul(argv[++arg], NULL, 0);
+                       ret = recv_file(fd, argv[++arg], addr, size);
+                       if (ret)
+                               return ret;
+
+                       continue;
+               }
+
+               /* passthrough */
+               ret = send_cmd_check_k(fd, argv[arg]);
+       }
+
+       return ret;
+}
diff --git a/megaed-stop-md/Makefile b/megaed-stop-md/Makefile
new file mode 100644 (file)
index 0000000..56894ab
--- /dev/null
@@ -0,0 +1,40 @@
+CROSS = m68k-elf-\r
+CC = $(CROSS)gcc\r
+AS = $(CROSS)as\r
+LD = $(CROSS)ld\r
+OBJCOPY = $(CROSS)objcopy\r
+\r
+ASFLAGS += -m68000 --register-prefix-optional --bitwise-or -pic\r
+ASFLAGS_CC += -Wa,-m68000 -Wa,--register-prefix-optional -Wa,--bitwise-or -Wa,-pic\r
+CFLAGS += -Wall -g -O1 -m68000 -fomit-frame-pointer\r
+LDLIBS += $(shell $(CC) -print-file-name=libgcc.a)\r
+\r
+TARGET = megaed_stop_md\r
+OBJS = sega_gcc.o main.o data.o\r
+\r
+all: $(TARGET).bin\r
+\r
+$(TARGET).elf: $(OBJS)\r
+       $(LD) -o $@ -Tsega.ld -Map $(TARGET).map $^ $(LDLIBS)\r
+\r
+clean:\r
+       $(RM) $(TARGET).bin $(OBJS) $(TARGET).elf $(TARGET).map\r
+       $(RM) maketest test.bin\r
+\r
+%.bin: %.elf\r
+       $(OBJCOPY) -I elf32-m68k -O binary $^ $@\r
+\r
+%.o: %.S\r
+       $(CC) -c -o $@ $^ $(ASFLAGS_CC)\r
+\r
+data.s: test.bin\r
+\r
+test.bin:\r
+       gcc -o maketest maketest.c\r
+       ./maketest\r
+\r
+rel: $(TARGET).bin\r
+       mkdir -p /tmp/$(TARGET)/src/\r
+       cp $^ /tmp/$(TARGET)/\r
+       $(MAKE) clean\r
+       cp -a * /tmp/$(TARGET)/src/\r
diff --git a/megaed-stop-md/UNLICENSE b/megaed-stop-md/UNLICENSE
new file mode 100644 (file)
index 0000000..68a49da
--- /dev/null
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
diff --git a/megaed-stop-md/data.s b/megaed-stop-md/data.s
new file mode 100644 (file)
index 0000000..ceac4b8
--- /dev/null
@@ -0,0 +1,17 @@
+.section .rodata
+
+# I don't know why multiple different .align don't work..
+.align 0x8000
+
+.global font_base
+font_base:
+.incbin "font.bin"
+
+.align 0x8000
+.global test_data
+test_data:
+.incbin "test.bin"
+.global test_data_end
+test_data_end:
+
+# vim:filetype=asmM68k:ts=4:sw=4:expandtab
diff --git a/megaed-stop-md/font.bin b/megaed-stop-md/font.bin
new file mode 100644 (file)
index 0000000..c11cc37
Binary files /dev/null and b/megaed-stop-md/font.bin differ
diff --git a/megaed-stop-md/main.c b/megaed-stop-md/main.c
new file mode 100644 (file)
index 0000000..618f3b5
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * This software is released into the public domain.
+ * See UNLICENSE file in top level directory.
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define u8      unsigned char
+#define u16     unsigned short
+#define u32     unsigned int
+
+#define GFX_DATA_PORT    0xC00000
+#define GFX_CTRL_PORT    0xC00004
+
+#define TILE_MEM_END     0xB000
+
+#define FONT_LEN         128
+#define TILE_FONT_BASE   (TILE_MEM_END - FONT_LEN * 32)
+
+/* note: using ED menu's layout here.. */
+#define WPLANE           (TILE_MEM_END + 0x0000)
+#define HSCRL            (TILE_MEM_END + 0x0800)
+#define SLIST            (TILE_MEM_END + 0x0C00)
+#define APLANE           (TILE_MEM_END + 0x1000)
+#define BPLANE           (TILE_MEM_END + 0x3000)
+
+#define read8(a) \
+    *((volatile u8 *) (a))
+#define read16(a) \
+    *((volatile u16 *) (a))
+#define read32(a) \
+    *((volatile u32 *) (a))
+#define write16(a, d) \
+    *((volatile u16 *) (a)) = (d)
+#define write32(a, d) \
+    *((volatile u32 *) (a)) = (d)
+
+#define GFX_WRITE_VRAM_ADDR(adr) \
+    (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00)
+#define GFX_WRITE_VSRAM_ADDR(adr) \
+    (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x10)
+#define GFX_WRITE_CRAM_ADDR(adr) \
+    (((0xC000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00)
+
+#define VDP_setReg(r, v) \
+    write16(GFX_CTRL_PORT, 0x8000 | ((r) << 8) | (v))
+
+enum {
+    VDP_MODE1 = 0x00,
+    VDP_MODE2 = 0x01,
+    VDP_NT_SCROLLA = 0x02,
+    VDP_NT_WIN = 0x03,
+    VDP_NT_SCROLLB = 0x04,
+    VDP_SAT_BASE = 0x05,
+    VDP_BACKDROP = 0x07,
+    VDP_MODE3 = 0x0b,
+    VDP_MODE4 = 0x0c,
+    VDP_HSCROLL = 0x0d,
+    VDP_AUTOINC = 0x0f,
+    VDP_SCROLLSZ = 0x10,
+};
+
+/* cell counts */
+#define LEFT_BORDER 1   /* lame TV */
+#define PLANE_W 64
+#define PLANE_H 32
+#define CSCREEN_H 28
+
+static void VDP_drawTextML(const char *str, u16 plane_base,
+    u16 x, u16 y)
+{
+    const u8 *src = (const u8 *)str;
+    u16 basetile = 0;
+    int max_len = 40 - LEFT_BORDER;
+    int len;
+    u32 addr;
+
+    x += LEFT_BORDER;
+
+    for (len = 0; str[len] && len < max_len; len++)
+        ;
+    if (len > (PLANE_W - x))
+        len = PLANE_W - x;
+
+    addr = plane_base + ((x + (PLANE_W * y)) << 1);
+    write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr));
+
+    while (len-- > 0) {
+        write16(GFX_DATA_PORT,
+            basetile | ((*src++) - 32 + TILE_FONT_BASE / 32));
+    }
+}
+
+static int printf_ypos;
+
+static void printf_line(int x, const char *buf)
+{
+    u32 addr;
+    int i;
+
+    VDP_drawTextML(buf, APLANE, x, printf_ypos++ & (PLANE_H - 1));
+
+    if (printf_ypos >= CSCREEN_H) {
+        /* clear next line */
+        addr = APLANE;
+        addr += (PLANE_W * (printf_ypos & (PLANE_H - 1))) << 1;
+        write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr));
+        for (i = 0; i < 40 / 2; i++)
+            write32(GFX_DATA_PORT, 0);
+
+        /* scroll plane */
+        write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
+        write16(GFX_DATA_PORT, (printf_ypos - CSCREEN_H + 1) * 8);
+    }
+}
+
+#define PRINTF_LEN 40
+
+static int printf(const char *fmt, ...)
+{
+    static const char hexchars[] = "0123456789abcdef";
+    static int printf_xpos;
+    char c, buf[PRINTF_LEN + 11 + 1];
+    const char *s;
+    va_list ap;
+    int ival;
+    u32 uval;
+    int d = 0;
+    int i, j;
+
+    va_start(ap, fmt);
+    for (d = 0; *fmt; ) {
+        int prefix0 = 0;
+        int fwidth = 0;
+
+        c = *fmt++;
+        if (d < PRINTF_LEN)
+            buf[d] = c;
+
+        if (c != '%') {
+            if (c == '\n') {
+                buf[d] = 0;
+                printf_line(printf_xpos, buf);
+                d = 0;
+                printf_xpos = 0;
+                continue;
+            }
+            d++;
+            continue;
+        }
+        if (d >= PRINTF_LEN)
+            continue;
+
+        if (*fmt == '0') {
+            prefix0 = 1;
+            fmt++;
+        }
+
+        while ('1' <= *fmt && *fmt <= '9') {
+            fwidth = fwidth * 10 + *fmt - '0';
+            fmt++;
+        }
+
+        switch (*fmt++) {
+        case '%':
+            d++;
+            break;
+        case 'd':
+        case 'i':
+            ival = va_arg(ap, int);
+            if (ival < 0) {
+                buf[d++] = '-';
+                ival = -ival;
+            }
+            for (i = 1000000000; i >= 10; i /= 10)
+                if (ival >= i)
+                    break;
+            for (; i >= 10; i /= 10) {
+                buf[d++] = '0' + ival / i;
+                ival %= i;
+            }
+            buf[d++] = '0' + ival;
+            break;
+        case 'x':
+            uval = va_arg(ap, int);
+            while (fwidth > 1 && uval < (1 << (fwidth - 1) * 4)) {
+                buf[d++] = prefix0 ? '0' : ' ';
+                fwidth--;
+            }
+            for (j = 1; j < 8 && uval >= (1 << j * 4); j++)
+                ;
+            for (j--; j >= 0; j--)
+                buf[d++] = hexchars[(uval >> j * 4) & 0x0f];
+            break;
+        case 's':
+            s = va_arg(ap, char *);
+            while (*s && d < PRINTF_LEN)
+                buf[d++] = *s++;
+            break;
+        default:
+            // don't handle, for now
+            d++;
+            va_arg(ap, void *);
+            break;
+        }
+    }
+    buf[d] = 0;
+    va_end(ap);
+
+    if (d != 0) {
+        // line without \n
+        VDP_drawTextML(buf, APLANE, printf_xpos,
+            printf_ypos & (PLANE_H - 1));
+        printf_xpos += d;
+    }
+
+    return d; // wrong..
+}
+
+extern u32 font_base[];
+extern u8 test_data[];
+extern u8 test_data_end[];
+
+int main()
+{
+    volatile u32 *vptr;
+    u32 old;
+    u8 bad = 0;
+    u8 *p, val;
+    int i, t, len;
+
+    /* z80 */
+    write16(0xa11100, 0x100);
+    write16(0xa11200, 0);
+
+    /* setup VDP */
+    while (read16(GFX_CTRL_PORT) & 2)
+        ;
+
+    VDP_setReg(VDP_MODE1, 0x04); 
+    VDP_setReg(VDP_MODE2, 0x64); 
+    VDP_setReg(VDP_MODE3, 0x00); 
+    VDP_setReg(VDP_MODE4, 0x81); 
+    VDP_setReg(VDP_NT_SCROLLA, APLANE >> 10); 
+    VDP_setReg(VDP_NT_SCROLLB, BPLANE >> 13); 
+    VDP_setReg(VDP_SAT_BASE, SLIST >> 9); 
+    VDP_setReg(VDP_HSCROLL, HSCRL >> 10); 
+    VDP_setReg(VDP_AUTOINC, 2); 
+    VDP_setReg(VDP_SCROLLSZ, 0x01); 
+    VDP_setReg(VDP_BACKDROP, 0); 
+
+    /* clear name tables */
+    write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(APLANE));
+    for (i = 0; i < PLANE_W * PLANE_H / 2; i++)
+        write32(GFX_DATA_PORT, 0);
+
+    write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(BPLANE));
+    for (i = 0; i < PLANE_W * PLANE_H / 2; i++)
+        write32(GFX_DATA_PORT, 0);
+
+    /* SAT, h. scroll */
+    write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(SLIST));
+    write32(GFX_DATA_PORT, 0);
+
+    write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(HSCRL));
+    write32(GFX_DATA_PORT, 0);
+
+    /* scroll plane vscroll */
+    write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
+    write32(GFX_DATA_PORT, 0);
+    printf_ypos = 0;
+
+    /* load font */
+    write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(TILE_FONT_BASE));
+    for (i = 0; i < FONT_LEN * 32 / 4; i++)
+        write32(GFX_DATA_PORT, font_base[i]);
+
+    /* set colors */
+    write32(GFX_CTRL_PORT, GFX_WRITE_CRAM_ADDR(0));
+    write32(GFX_DATA_PORT, 0);
+    write32(GFX_CTRL_PORT, GFX_WRITE_CRAM_ADDR(15 * 2)); // font
+    write16(GFX_DATA_PORT, 0xeee);
+
+    printf("\n");
+    printf("MD version: %02x\n", read8(0xa10001));
+    printf("ROM witable? ");
+
+    vptr = (void *)0x120;
+    old = *vptr;
+    *vptr ^= ~0;
+    printf(*vptr == old ? "no" : "yes");
+    printf("\n\n");
+
+    p = test_data;
+    len = test_data_end - test_data;
+
+    for (t = 1; ; t++) {
+        printf("executing stop.. ");
+        for (i = 0; i < 5 * 60; i++)
+            asm volatile("stop #0x2000" ::: "cc");
+        printf("done\n");
+
+        printf("checking memory..\n");
+
+        val = 0;
+        for (i = 0; i < len; i++) {
+            if (p[i] != val) {
+                printf("bad: %06x: got %02x, expected %02x\n",
+                       &p[i], p[i], val);
+                bad = 1;
+            }
+            val++;
+        }
+
+        printf("done. Try %d: test ", t);
+        if (bad) {
+            printf("FAILED\n");
+            break;
+        }
+        printf("PASSED\n");
+    }
+
+    write32(GFX_CTRL_PORT, GFX_WRITE_CRAM_ADDR(0));
+    write16(GFX_DATA_PORT, 0x008);
+
+    /* there are not enough STOP opcodes in this world :D */
+    while (1)
+        asm volatile("stop #0x2000" ::: "cc");
+
+    return 0;
+}
+
+// vim:ts=4:sw=4:expandtab
diff --git a/megaed-stop-md/maketest.c b/megaed-stop-md/maketest.c
new file mode 100644 (file)
index 0000000..9ebe038
--- /dev/null
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+int main()
+{
+       FILE *f;
+       int i;
+
+       f = fopen("test.bin", "wb");
+       if (f == NULL)
+               return 1;
+
+       for (i = 0; i < 0x200000 - 0x10000; i++)
+               fwrite(&i, 1, 1, f);
+       fclose(f);
+
+       return 0;
+}
diff --git a/megaed-stop-md/sega.ld b/megaed-stop-md/sega.ld
new file mode 100644 (file)
index 0000000..0921912
--- /dev/null
@@ -0,0 +1,117 @@
+OUTPUT_ARCH(m68k)\r
+SEARCH_DIR(.)\r
+/*GROUP(-lbcc -lc -lgcc)*/\r
+__DYNAMIC  =  0;\r
+\r
+/*\r
+ * Setup the memory map of the SEGA Genesis.\r
+ * stack grows down from high memory.\r
+ *\r
+ * The memory map look like this:\r
+ * +--------------------+ <- low memory\r
+ * | .text              |\r
+ * |        _etext      |\r
+ * |        ctor list   | the ctor and dtor lists are for\r
+ * |        dtor list   | C++ support\r
+ * +--------------------+\r
+ * | .data              | initialized data goes here\r
+ * |        _edata      |\r
+ * +--------------------+\r
+ * | .bss               |\r
+ * |        __bss_start | start of bss, cleared by crt0\r
+ * |        _end        | start of heap, used by sbrk()\r
+ * +--------------------+\r
+ * .                    .\r
+ * .                    .\r
+ * .                    .\r
+ * |        __stack     | top of stack\r
+ * +--------------------+\r
+ */\r
+MEMORY\r
+{\r
+       rom : ORIGIN = 0x00000000, LENGTH = 0x00400000\r
+       ram : ORIGIN = 0x00ff0000, LENGTH = 0x00010000\r
+}\r
+\r
+/*\r
+ * allocate the stack to be at the top of memory, since the stack\r
+ * grows down\r
+ */\r
+\r
+PROVIDE (__stack = 0x00fffff0);\r
+\r
+/*\r
+ * Initalize some symbols to be zero so we can reference them in the\r
+ * crt0 without core dumping. These functions are all optional, but\r
+ * we do this so we can have our crt0 always use them if they exist. \r
+ * This is so BSPs work better when using the crt0 installed with gcc.\r
+ * We have to initalize them twice, so we cover a.out (which prepends\r
+ * an underscore) and coff object file formats.\r
+ */\r
+PROVIDE (hardware_init_hook = 0);\r
+PROVIDE (_hardware_init_hook = 0);\r
+PROVIDE (software_init_hook = 0);\r
+PROVIDE (_software_init_hook = 0);\r
+\r
+SECTIONS\r
+{\r
+  .text 0x00000000:\r
+  {\r
+    *(.text)\r
+    . = ALIGN(0x4);\r
+     __CTOR_LIST__ = .;\r
+    LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)\r
+    *(.ctors)\r
+    LONG(0)\r
+    __CTOR_END__ = .;\r
+    __DTOR_LIST__ = .;\r
+    LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)\r
+    *(.dtors)\r
+     LONG(0)\r
+    __DTOR_END__ = .;\r
+    *(.rodata*)\r
+/*\r
+    *(.gcc_except_table)\r
+\r
+    __INIT_SECTION__ = . ;\r
+    *(.init)\r
+    SHORT (0x4e75)\r
+\r
+    __FINI_SECTION__ = . ;\r
+    *(.fini)\r
+    SHORT (0x4e75)\r
+*/\r
+    _etext = .;\r
+    *(.lit)\r
+  } > rom\r
+\r
+  .data 0xff0000 :\r
+  {\r
+    *(.shdata)\r
+    *(.data)\r
+    _edata = .;\r
+  } > ram\r
+\r
+  /* .bss 0xff0100 : */\r
+  .bss BLOCK (0x4) :\r
+  {\r
+    __bss_start = . ;\r
+    *(.shbss)\r
+    *(.bss)\r
+    *(COMMON)\r
+    *(.eh_fram)\r
+    *(.eh_frame)\r
+    _end =  ALIGN (0x8);\r
+    __end = _end;\r
+  } > ram\r
+\r
+  .stab 0 (NOLOAD) :\r
+  {\r
+    *(.stab)\r
+  }\r
+\r
+  .stabstr 0 (NOLOAD) :\r
+  {\r
+    *(.stabstr)\r
+  }\r
+}\r
diff --git a/megaed-stop-md/sega_gcc.s b/megaed-stop-md/sega_gcc.s
new file mode 100644 (file)
index 0000000..5619334
--- /dev/null
@@ -0,0 +1,41 @@
+    dc.l     0, RST,   exc__, exc__, exc__, exc__, exc__, exc__\r
+    dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__\r
+    dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__\r
+    dc.l exc__, exc__, exc__, exc__, HBL,   exc__, VBL,   exc__\r
+    dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__\r
+    dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__\r
+    dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__\r
+    dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__\r
+\r
+    .ascii "SEGA                            "\r
+    .ascii "MEGA-ED SDRAM vs STOP                           "\r
+    .ascii "MEGA-ED SDRAM vs STOP                           "\r
+    .ascii "GM 00000000-00"\r
+    .byte 0x00,0x00\r
+    .ascii "JD              "\r
+    .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00\r
+    .byte 0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff\r
+    .ascii "               "\r
+    .ascii "                        "\r
+    .ascii "                         "\r
+    .ascii "JUE             "\r
+\r
+RST:\r
+    move.w #0x2700, %sr\r
+\r
+    move.b (0xA10001), %d0\r
+    andi.b #0x0F, %d0\r
+    beq.s 0f\r
+    move.l  #0x53454741, (0xA14000) /* 'SEGA' */\r
+0:\r
+    moveq.l #0, %d0\r
+    movea.l %d0, %a7\r
+    move.l  %a7, %usp\r
+    bra     main\r
+\r
+HBL:\r
+VBL:\r
+exc__:\r
+    rte\r
+\r
+# vim:filetype=asmM68k:ts=4:sw=4:expandtab\r
diff --git a/megaed-stop/Makefile b/megaed-stop/Makefile
new file mode 100644 (file)
index 0000000..fe8f346
--- /dev/null
@@ -0,0 +1,39 @@
+CROSS = m68k-elf-\r
+CC = $(CROSS)gcc\r
+AS = $(CROSS)as\r
+LD = $(CROSS)ld\r
+OBJCOPY = $(CROSS)objcopy\r
+\r
+ASFLAGS += -m68000 --register-prefix-optional --bitwise-or -pic\r
+ASFLAGS_CC += -Wa,-m68000 -Wa,--register-prefix-optional -Wa,--bitwise-or -Wa,-pic\r
+CFLAGS += -Wall -g -O1 -m68000 -fomit-frame-pointer\r
+LDLIBS += $(shell $(CC) -print-file-name=libgcc.a)\r
+\r
+TARGET = megaed_stop\r
+OBJS = sega_gcc.o main.o\r
+\r
+all: $(TARGET).bin\r
+\r
+$(TARGET).elf: $(OBJS)\r
+       $(LD) -o $@ -Ted_app.ld -Map $(TARGET).map $^ $(LDLIBS)\r
+\r
+$(TARGET)_e.bin: $(TARGET).bin\r
+       dd if=/dev/zero of=$@ bs=1M count=1\r
+       dd if=$^ of=$@ bs=1M seek=1\r
+       dd if=$^ of=$@ conv=notrunc\r
+\r
+clean:\r
+       $(RM) $(TARGET).bin $(OBJS) $(TARGET).elf $(TARGET).map\r
+\r
+\r
+%.bin: %.elf\r
+       $(OBJCOPY) -I elf32-m68k -O binary $^ $@\r
+\r
+%.o: %.S\r
+       $(CC) -c -o $@ $^ $(ASFLAGS_CC)\r
+\r
+rel: $(TARGET).bin\r
+       mkdir -p /tmp/$(TARGET)/src/\r
+       cp $^ /tmp/$(TARGET)/\r
+       $(MAKE) clean\r
+       cp -a * /tmp/$(TARGET)/src/\r
diff --git a/megaed-stop/UNLICENSE b/megaed-stop/UNLICENSE
new file mode 100644 (file)
index 0000000..68a49da
--- /dev/null
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
diff --git a/megaed-stop/ed_app.ld b/megaed-stop/ed_app.ld
new file mode 100644 (file)
index 0000000..bd40362
--- /dev/null
@@ -0,0 +1,116 @@
+OUTPUT_ARCH(m68k)\r
+SEARCH_DIR(.)\r
+/*GROUP(-lbcc -lc -lgcc)*/\r
+__DYNAMIC  =  0;\r
+\r
+/*\r
+ * Setup the memory map of the SEGA Genesis.\r
+ * stack grows down from high memory.\r
+ *\r
+ * The memory map look like this:\r
+ * +--------------------+ <- low memory\r
+ * | .text              |\r
+ * |        _etext      |\r
+ * |        ctor list   | the ctor and dtor lists are for\r
+ * |        dtor list   | C++ support\r
+ * +--------------------+\r
+ * | .data              | initialized data goes here\r
+ * |        _edata      |\r
+ * +--------------------+\r
+ * | .bss               |\r
+ * |        __bss_start | start of bss, cleared by crt0\r
+ * |        _end        | start of heap, used by sbrk()\r
+ * +--------------------+\r
+ * .                    .\r
+ * .                    .\r
+ * .                    .\r
+ * |        __stack     | top of stack\r
+ * +--------------------+\r
+ */\r
+MEMORY\r
+{\r
+       rom : ORIGIN = 0x00100000, LENGTH = 0x00300000\r
+       ram : ORIGIN = 0x00ff0100, LENGTH = 0x0000FF00\r
+}\r
+\r
+/*\r
+ * allocate the stack to be at the top of memory, since the stack\r
+ * grows down\r
+ */\r
+\r
+PROVIDE (__stack = 0x00fffff0);\r
+\r
+/*\r
+ * Initalize some symbols to be zero so we can reference them in the\r
+ * crt0 without core dumping. These functions are all optional, but\r
+ * we do this so we can have our crt0 always use them if they exist. \r
+ * This is so BSPs work better when using the crt0 installed with gcc.\r
+ * We have to initalize them twice, so we cover a.out (which prepends\r
+ * an underscore) and coff object file formats.\r
+ */\r
+PROVIDE (hardware_init_hook = 0);\r
+PROVIDE (_hardware_init_hook = 0);\r
+PROVIDE (software_init_hook = 0);\r
+PROVIDE (_software_init_hook = 0);\r
+\r
+SECTIONS\r
+{\r
+  .text 0x00100000:\r
+  {\r
+    *(.text)\r
+    . = ALIGN(0x4);\r
+     __CTOR_LIST__ = .;\r
+    LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)\r
+    *(.ctors)\r
+    LONG(0)\r
+    __CTOR_END__ = .;\r
+    __DTOR_LIST__ = .;\r
+    LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)\r
+    *(.dtors)\r
+     LONG(0)\r
+    __DTOR_END__ = .;\r
+    *(.rodata*)\r
+    *(.gcc_except_table)\r
+\r
+    __INIT_SECTION__ = . ;\r
+    *(.init)\r
+    SHORT (0x4e75)     /* rts */\r
+\r
+    __FINI_SECTION__ = . ;\r
+    *(.fini)\r
+    SHORT (0x4e75)     /* rts */\r
+\r
+    _etext = .;\r
+    *(.lit)\r
+  } > rom\r
+\r
+  .data 0xff0100 :\r
+  {\r
+    *(.shdata)\r
+    *(.data)\r
+    _edata = .;\r
+  } > ram\r
+\r
+  /* .bss 0xff0100 : */\r
+  .bss BLOCK (0x4) :\r
+  {\r
+    __bss_start = . ;\r
+    *(.shbss)\r
+    *(.bss)\r
+    *(COMMON)\r
+    *(.eh_fram)\r
+    *(.eh_frame)\r
+    _end =  ALIGN (0x8);\r
+    __end = _end;\r
+  } > ram\r
+\r
+  .stab 0 (NOLOAD) :\r
+  {\r
+    *(.stab)\r
+  }\r
+\r
+  .stabstr 0 (NOLOAD) :\r
+  {\r
+    *(.stabstr)\r
+  }\r
+}\r
diff --git a/megaed-stop/edos.h b/megaed-stop/edos.h
new file mode 100644 (file)
index 0000000..58025e3
--- /dev/null
@@ -0,0 +1,153 @@
+/* 
+ * File:   edos.h
+ * Author: krik
+ *
+ * Created on 29 ÃŒÃ Ã°Ã² 2012 Ã£., 1:29
+ */
+
+#ifndef _EDOS_H
+#define        _EDOS_H
+
+//#include "segalib.h"
+
+/*
+ * saddr: address in sectors
+ * slen: lenght in sectors
+ * wr_slen: how many sectors will be written
+ * sector size 512 bytes
+ * dma reading of usb and SD available only if data destination located in rom area (0-0x3ffffff). dma reading not available for genesis ram
+ * destination address for dma reading must be aligned to 512b
+ * one mbyte of sdram can be mapped to one of four banks in rom space. osSetMemMap(u16) can be used for mapping configuration.
+ * os code located in last mbyte of sdram and should be mapped in bank 0
+ * user code located in begin of sdram. default mapping 0x210f means that end of sdram (OS) mapped to area 0-0x0fffff, first mbyte of user code mapped to 0x100000-0x1fffff,
+ * memory configuration:
+ * genesis address: 0x000000-0x0fffff, physical sdram address: 0xf00000-0xffffff  OS
+ * genesis address: 0x100000-0x3fffff, physical sdram address: 0x000000-0x2fffff  user code (current application)
+ * 0xff0000-0xff00ff OS dma code
+ * first 256bytes of genesis ram must be reserved for OS
+ * */
+
+
+#define MEM_ERR_SPI_RD_TIMEOUT 120
+
+#define ERR_FILE_TOO_BIG 140
+#define ERR_WRON_OS_SIZE 142
+#define ERR_OS_VERIFY 143
+#define ERR_OS_VERIFY2 144
+#define ERR_BAD_DMA_ADDRESS 145
+#define ERR_MUST_NOT_RET 146
+
+//100 - 119 fat errors
+#define FAT_ERR_NOT_EXIST 100
+#define FAT_ERR_EXIST 101
+#define FAT_ERR_NAME 102
+#define FAT_ERR_OUT_OF_FILE 103
+#define FAT_ERR_BAD_BASE_CLUSTER 104;
+#define FAT_ERR_NO_FRE_SPACE 105
+#define FAT_ERR_NOT_FILE 106
+#define FAT_ERR_FILE_MODE 107
+#define FAT_ERR_ROT_OVERFLOW 108
+#define FAT_ERR_OUT_OF_TABLE 109
+#define FAT_ERR_INIT 110
+#define FAT_LFN_BUFF_OVERFLOW 111
+#define FAT_DISK_NOT_READY 112
+#define FAT_ERR_SIZE 113
+#define FAT_ERR_RESIZE 114
+
+
+#define DISK_ERR_INIT 50
+#define DISK_ERR_RD1 62
+#define DISK_ERR_RD2 63
+
+#define DISK_ERR_WR1 64
+#define DISK_ERR_WR2 65
+#define DISK_ERR_WR3 66
+#define DISK_ERR_WR4 67
+#define DISK_ERR_WR5 68
+
+typedef struct {
+    u32 entry_cluster;
+    u32 size;
+    u32 hdr_sector;
+    u16 hdr_idx;
+    u8 name[256];
+    u16 is_dir;
+} FatFullRecord;
+
+typedef struct {
+    u8(*diskWrite)(u32 saddr, u8 *buff, u16 slen);
+    u8(*diskRead)(u32 saddr, void *buff, u16 slen);//*dst must be alligned to 512bytes and be in range 0x100000-0x3fffff. *dst can be located in genesis ram also, but transfer will be slow in this case
+    u8(*usbReadByte)();//loop inside of function waiting until usbRdReady != 0
+    void (*usbWriteByte)(u8 dat);//loop inside of function waiting until usbWrReady != 0
+    u8(*usbReadDma)(u16 *dst, u16 slen);//*dst must be alligned to 512bytes and be in range 0x100000-0x3fffff
+    u8(*usbReadPio)(u16 *dst, u16 slen);
+    u8(*usbRdReady)(); //return 1 if some data comes from pc
+    u8(*usbWrReady)(); //return 1 usb ready to send byte
+    void (*osSetMemMap)(u16 map); //memoty configuration 4x1Mb
+    u16(*osGetOsVersion)();
+    u16(*osGetFirmVersion)();
+    void (*osGetSerial)(u32 * buff); // 8bytes uniq serial number
+    void (*VDP_setReg)(u8 reg, u8 value);//os vdp functions should be used, otherwise system may hang while udb/sd dma
+    void (*VDP_vintOn)();
+    void (*VDP_vintOff)();
+    void (*memInitDmaCode)();//copy dma routine to genesis ram
+    u8(*fatReadDir)(FatFullRecord * frec);//get next record in current dir
+    void(*fatOpenDir)(u32 entry_cluster);//arg is entry cluster ot dir or 0. zero arg means that need to open root dir
+    u8(*fatOpenFileByeName)(u8 *name, u32 wr_slen);//wr_slen write len, or 0 if reading
+    u8(*fatOpenFile)(FatFullRecord *rec, u32 wr_slen);//wr_slen is write len, or 0 if reading
+    u8(*fatReadFile)(void *dst, u32 slen);
+    u8(*fatWriteFile)(void *src, u32 slen);
+    u8(*fatCreateRecIfNotExist)(u8 *name, u8 is_dir);
+    u8(*fatSkipSectors)(u32 slen);
+} OsRoutine;
+
+
+extern OsRoutine *ed_os;
+void edInit();
+
+
+//stereo dac. 8bit for each channel.
+//any writing to this port enables dac output, any reading from this port disables dac output.
+#define REG_DAC *((volatile u16*) (0xA1300E))
+
+
+//stuff for direct access to usb and spi. not recommended for use. OS function should be used for best compatibility
+#define _SPI_SS 0
+#define _SPI_FULL_SPEED 1
+#define _SPI_SPI16 2
+#define _SPI_AREAD 3
+
+//spi port (sd interface)
+#define SPI_PORT *((volatile u16*) (0xA13000))
+#define SPI_CFG_PORT *((volatile u16*) (0xA13002))
+
+//16bit or 8bit spi mode
+#define SPI16_ON SPI_CFG_PORT |= (1 << _SPI_SPI16)
+#define SPI16_OFF SPI_CFG_PORT &= ~(1 << _SPI_SPI16)
+
+//spi autoread. means that not need to write something to spi port before than read
+#define SPI_AR_ON SPI_CFG_PORT |= (1 << _SPI_AREAD)
+#define SPI_AR_OFF SPI_CFG_PORT &= ~(1 << _SPI_AREAD)
+
+//spi chip select
+#define SPI_SS_OFF SPI_CFG_PORT |= (1 << _SPI_SS)
+#define SPI_SS_ON SPI_CFG_PORT &= ~(1 << _SPI_SS)
+
+//spi speed. low speed need only for sd init
+#define SPI_HI_SPEED_ON SPI_CFG_PORT |= (1 << _SPI_FULL_SPEED)
+#define SPI_HI_SPEED_OFF SPI_CFG_PORT &= ~(1 << _SPI_FULL_SPEED)
+
+//usb-serial port
+#define FIFO_PORT *((volatile u16*) (0xA1300A))
+
+//spi and usb state
+#define STATE_PORT *((volatile u16*) (0xA1300C))
+#define _STATE_SPI_READY 0
+#define _STATE_FIFO_WR_READY 1
+#define _STATE_FIFO_RD_READY 2
+#define IS_FIFO_RD_READY (STATE_PORT & (1 << _STATE_FIFO_RD_READY))
+#define IS_FIFO_WR_READY (STATE_PORT & (1 << _STATE_FIFO_WR_READY))
+
+
+#endif /* _EDOS_H */
+
diff --git a/megaed-stop/main.c b/megaed-stop/main.c
new file mode 100644 (file)
index 0000000..4fbac7a
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * This software is released into the public domain.
+ * See UNLICENSE file in top level directory.
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define u8      unsigned char
+#define u16     unsigned short
+#define u32     unsigned int
+
+#include "edos.h"
+
+#define GFX_DATA_PORT    0xC00000
+#define GFX_CTRL_PORT    0xC00004
+
+#define TILE_MEM_END     0xB000
+
+#define FONT_LEN         128
+#define TILE_FONT_BASE   (TILE_MEM_END / 32  - FONT_LEN)
+
+/* note: using ED menu's layout here.. */
+#define WPLANE           (TILE_MEM_END + 0x0000)
+#define HSCRL            (TILE_MEM_END + 0x0800)
+#define SLIST            (TILE_MEM_END + 0x0C00)
+#define APLANE           (TILE_MEM_END + 0x1000)
+#define BPLANE           (TILE_MEM_END + 0x3000)
+
+#define read8(a) \
+    *((volatile u8 *) (a))
+#define read16(a) \
+    *((volatile u16 *) (a))
+#define read32(a) \
+    *((volatile u32 *) (a))
+#define write16(a, d) \
+    *((volatile u16 *) (a)) = (d)
+#define write32(a, d) \
+    *((volatile u32 *) (a)) = (d)
+
+#define GFX_WRITE_VRAM_ADDR(adr) \
+    (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00)
+#define GFX_WRITE_VSRAM_ADDR(adr) \
+    (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x10)
+
+enum {
+    VDP_MODE1 = 0x00,
+    VDP_MODE2 = 0x01,
+    VDP_BACKDROP = 0x07,
+    VDP_MODE3 = 0x0b,
+    VDP_MODE4 = 0x0c,
+    VDP_AUTOINC = 0x0f,
+    VDP_SCROLLSZ = 0x10,
+};
+
+/* cell counts */
+#define LEFT_BORDER 1   /* lame TV */
+#define PLANE_W 64
+#define PLANE_H 32
+#define CSCREEN_H 28
+
+static void VDP_drawTextML(const char *str, u16 plane_base,
+    u16 x, u16 y)
+{
+    const u8 *src = (const u8 *)str;
+    u16 basetile = 0;
+    int max_len = 40 - LEFT_BORDER;
+    int len;
+    u32 addr;
+
+    x += LEFT_BORDER;
+
+    for (len = 0; str[len] && len < max_len; len++)
+        ;
+    if (len > (PLANE_W - x))
+        len = PLANE_W - x;
+
+    addr = plane_base + ((x + (PLANE_W * y)) << 1);
+    write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr));
+
+    while (len-- > 0) {
+        write16(GFX_DATA_PORT,
+            basetile | ((*src++) - 32 + TILE_FONT_BASE));
+    }
+}
+
+static int printf_ypos;
+
+static void printf_line(int x, const char *buf)
+{
+    u32 addr;
+    int i;
+
+    VDP_drawTextML(buf, APLANE, x, printf_ypos++ & (PLANE_H - 1));
+
+    if (printf_ypos >= CSCREEN_H) {
+        /* clear next line */
+        addr = APLANE;
+        addr += (PLANE_W * (printf_ypos & (PLANE_H - 1))) << 1;
+        write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr));
+        for (i = 0; i < 40 / 2; i++)
+            write32(GFX_DATA_PORT, 0);
+
+        /* scroll plane */
+        write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
+        write16(GFX_DATA_PORT, (printf_ypos - CSCREEN_H + 1) * 8);
+    }
+}
+
+#define PRINTF_LEN 40
+
+static int printf(const char *fmt, ...)
+{
+    static const char hexchars[] = "0123456789abcdef";
+    static int printf_xpos;
+    char c, buf[PRINTF_LEN + 11 + 1];
+    const char *s;
+    va_list ap;
+    int ival;
+    u32 uval;
+    int d = 0;
+    int i, j;
+
+    va_start(ap, fmt);
+    for (d = 0; *fmt; ) {
+        int prefix0 = 0;
+        int fwidth = 0;
+
+        c = *fmt++;
+        if (d < PRINTF_LEN)
+            buf[d] = c;
+
+        if (c != '%') {
+            if (c == '\n') {
+                buf[d] = 0;
+                printf_line(printf_xpos, buf);
+                d = 0;
+                printf_xpos = 0;
+                continue;
+            }
+            d++;
+            continue;
+        }
+        if (d >= PRINTF_LEN)
+            continue;
+
+        if (*fmt == '0') {
+            prefix0 = 1;
+            fmt++;
+        }
+
+        while ('1' <= *fmt && *fmt <= '9') {
+            fwidth = fwidth * 10 + *fmt - '0';
+            fmt++;
+        }
+
+        switch (*fmt++) {
+        case '%':
+            d++;
+            break;
+        case 'd':
+        case 'i':
+            ival = va_arg(ap, int);
+            if (ival < 0) {
+                buf[d++] = '-';
+                ival = -ival;
+            }
+            for (i = 1000000000; i >= 10; i /= 10)
+                if (ival >= i)
+                    break;
+            for (; i >= 10; i /= 10) {
+                buf[d++] = '0' + ival / i;
+                ival %= i;
+            }
+            buf[d++] = '0' + ival;
+            break;
+        case 'x':
+            uval = va_arg(ap, int);
+            while (fwidth > 1 && uval < (1 << (fwidth - 1) * 4)) {
+                buf[d++] = prefix0 ? '0' : ' ';
+                fwidth--;
+            }
+            for (j = 1; j < 8 && uval >= (1 << j * 4); j++)
+                ;
+            for (j--; j >= 0; j--)
+                buf[d++] = hexchars[(uval >> j * 4) & 0x0f];
+            break;
+        case 's':
+            s = va_arg(ap, char *);
+            while (*s && d < PRINTF_LEN)
+                buf[d++] = *s++;
+            break;
+        default:
+            // don't handle, for now
+            d++;
+            va_arg(ap, void *);
+            break;
+        }
+    }
+    buf[d] = 0;
+    va_end(ap);
+
+    if (d != 0) {
+        // line without \n
+        VDP_drawTextML(buf, APLANE, printf_xpos,
+            printf_ypos & (PLANE_H - 1));
+        printf_xpos += d;
+    }
+
+    return d; // wrong..
+}
+
+int main()
+{
+    OsRoutine *ed;
+    u8 seed, bad = 0;
+    u8 *p, val;
+    int i, t, len;
+
+    ed = (OsRoutine *) *(u32 *)0x1A0;
+    ed->memInitDmaCode(); 
+
+    ed->VDP_setReg(VDP_MODE1, 0x04); 
+    ed->VDP_setReg(VDP_MODE2, 0x64); 
+    ed->VDP_setReg(VDP_AUTOINC, 2); 
+    ed->VDP_setReg(VDP_SCROLLSZ, 0x01); 
+
+    /* clear name tables */
+    write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(APLANE));
+    for (i = 0; i < PLANE_W * PLANE_H / 2; i++)
+        write32(GFX_DATA_PORT, 0);
+
+    write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(BPLANE));
+    for (i = 0; i < PLANE_W * PLANE_H / 2; i++)
+        write32(GFX_DATA_PORT, 0);
+
+    /* scroll planes */
+    write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
+    write32(GFX_DATA_PORT, 0);
+
+    /* note: relying on ED menu's font setup here.. */
+
+    printf("\n");
+    printf("MD version: %02x\n", read8(0xa10001));
+    printf("ED os/fw: %d/%d\n\n", ed->osGetOsVersion(),
+           ed->osGetFirmVersion());
+
+    seed = read8(0xC00009);
+    p = (void *)0x200000;
+    len = 0x200000;
+    printf("filling SDRAM, seed=%02x.. ", seed);
+
+    val = seed;
+    for (i = 0; i < len; i++)
+        p[i] = val++;
+
+    printf("done.\n");
+
+    for (t = 1; ; t++) {
+        printf("executing stop.. ");
+        for (i = 0; i < 5 * 60; i++)
+            asm volatile("stop #0x2000");
+        printf("done\n");
+
+        printf("checking memory..\n");
+
+        val = seed;
+        for (i = 0; i < len; i++) {
+            if (p[i] != val) {
+                printf("bad: %06x: got %02x, expected %02x\n",
+                       &p[i], p[i], val);
+                bad = 1;
+            }
+            val++;
+        }
+
+        printf("done. Try %d: test ", t);
+        if (bad) {
+            printf("FAILED\n");
+            break;
+        }
+        printf("PASSED\n");
+    }
+
+    /* there are not enough STOP opcodes in this world :D */
+    while (1)
+        asm volatile("stop #0x2000");
+
+    return 0;
+}
+
+// vim:ts=4:sw=4:expandtab
diff --git a/megaed-stop/sega_gcc.s b/megaed-stop/sega_gcc.s
new file mode 100644 (file)
index 0000000..927da4e
--- /dev/null
@@ -0,0 +1,43 @@
+    dc.l     0, 0x200, exc__, exc__, exc__, exc__, exc__, exc__\r
+    dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__\r
+    dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__\r
+    dc.l exc__, exc__, exc__, exc__, HBL,   exc__, VBL,   exc__\r
+    dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__\r
+    dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__\r
+    dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__\r
+    dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__\r
+\r
+    .ascii "SEGA EVERDRIVE                  "\r
+    .ascii "MEGA-ED SDRAM vs STOP                           "\r
+    .ascii "MEGA-ED SDRAM vs STOP                           "\r
+    .ascii "GM 00000000-00"\r
+    .byte 0x00,0x00\r
+    .ascii "JD              "\r
+    .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00\r
+    .byte 0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff\r
+    .ascii "               "\r
+    .ascii "                        "\r
+    .ascii "                         "\r
+    .ascii "JUE             "\r
+\r
+RST:\r
+       move.w #0x2700, %sr\r
+/* magic ED app init */\r
+       move.w #0x0000, (0xA13006)\r
+       jmp init_ed.l\r
+init_ed:\r
+       move.w #0x210f, (0xA13006)\r
+    move.l #HBL, (0x70)\r
+    move.l #VBL, (0x78)\r
+\r
+       moveq   #0, %d0\r
+       movea.l %d0, %a7\r
+       move    %a7, %usp\r
+       bra     main\r
+\r
+HBL:\r
+VBL:\r
+exc__:\r
+       rte\r
+\r
+# vim:filetype=asmM68k:ts=4:sw=4:expandtab\r
diff --git a/megaed-sv/Makefile b/megaed-sv/Makefile
new file mode 100644 (file)
index 0000000..24f0965
--- /dev/null
@@ -0,0 +1,33 @@
+CROSS = m68k-elf-\r
+CC = $(CROSS)gcc\r
+AS = $(CROSS)as\r
+LD = $(CROSS)ld\r
+OBJCOPY = $(CROSS)objcopy\r
+\r
+ASFLAGS += -m68000 --register-prefix-optional --bitwise-or -pic\r
+ASFLAGS_CC += -Wa,-m68000 -Wa,--register-prefix-optional -Wa,--bitwise-or -Wa,-pic\r
+CFLAGS += -Wall -g -O1 -m68000 -fomit-frame-pointer\r
+LDLIBS += $(shell $(CC) -print-file-name=libgcc.a)\r
+\r
+TARGET = megaedsv\r
+OBJS = sega_gcc.o main.o asmtools.o\r
+\r
+all: $(TARGET).bin\r
+\r
+$(TARGET).elf: $(OBJS)\r
+       $(LD) -o $@ -Ted_app.ld -Map $(TARGET).map $^ $(LDLIBS)\r
+\r
+$(TARGET)_e.bin: $(TARGET).bin\r
+       dd if=/dev/zero of=$@ bs=1M count=1\r
+       dd if=$^ of=$@ bs=1M seek=1\r
+       dd if=$^ of=$@ conv=notrunc\r
+\r
+clean:\r
+       $(RM) $(TARGET).bin $(OBJS) $(TARGET).elf $(TARGET).map\r
+\r
+\r
+%.bin: %.elf\r
+       $(OBJCOPY) -I elf32-m68k -O binary $^ $@\r
+\r
+%.o: %.S\r
+       $(CC) -c -o $@ $^ $(ASFLAGS_CC)\r
diff --git a/megaed-sv/asmtools.h b/megaed-sv/asmtools.h
new file mode 100644 (file)
index 0000000..ff3c42b
--- /dev/null
@@ -0,0 +1,5 @@
+void read_joy_responses(u8 resp[8*5]);
+void test_joy_read_log(u8 *dest, int size, int do_sync);
+void test_joy_read_log_vsync(u8 *dest, int size);
+void test_byte_write(u8 *dest, int size, int seed);
+void run_game(u16 mapper, int tas_sync);
diff --git a/megaed-sv/asmtools.s b/megaed-sv/asmtools.s
new file mode 100644 (file)
index 0000000..dc75b6c
--- /dev/null
@@ -0,0 +1,414 @@
+# Assemble with gas
+#   --register-prefix-optional --bitwise-or
+
+.macro ldarg  arg, stacksz, reg
+    move.l (4 + \arg * 4 + \stacksz)(%sp), \reg
+.endm
+
+
+.global read_joy_responses /* u8 *rbuf */
+read_joy_responses:
+    ldarg       0, 0, a1
+    movem.l     d2-d7, -(sp)
+    movea.l     #0xa10003, a0
+    move.b      #0x40, (6,a0)
+    move.b      #0x40, (a0)
+
+.macro one_test val
+    move.l      #100/12-1, d0
+0:
+    dbra        d0, 0b
+    move.b      \val, d0
+    move.b      d0, (a0)
+    move.b      (a0), d0
+    move.b      (a0), d1
+    move.b      (a0), d2
+    move.b      (a0), d3
+    move.b      (a0), d4
+    move.b      (a0), d5
+    move.b      (a0), d6
+    move.b      (a0), d7
+    move.b      d0, (a1)+
+    move.b      d1, (a1)+
+    move.b      d2, (a1)+
+    move.b      d3, (a1)+
+    move.b      d4, (a1)+
+    move.b      d5, (a1)+
+    move.b      d6, (a1)+
+    move.b      d7, (a1)+
+.endm
+
+       move.w          #0x2700, sr
+    one_test    #0x00
+    one_test    #0x40
+    one_test    #0x00
+    one_test    #0x40
+    one_test    #0x00
+       move.w          #0x2000, sr
+    movem.l     (sp)+, d2-d7
+    rts
+
+
+/* expects:
+ * a0 = #0xa10003
+ * d0 = #0
+ * d1 = #0x40
+ * trashes d2, d3
+ */
+sync_with_teensy:
+0:  /* wait for special code */
+    move.b      d1, (a0)
+    move.b      (a0), d2
+    move.b      d0, (a0)
+    move.b      (a0), d3
+    and.b       #0x3f, d2
+    cmp.b       d2, d3
+    bne         0b
+    cmp.b       #0x25, d2
+    bne         0b
+
+0:  /* wait for special code to end */
+    cmp.b       (a0), d2
+    beq         0b
+
+    move.b      d1, (a0)
+    move.l      #8000000/50/18, d2
+
+0:  /* wait enough for teensy to setup it's stuff */
+    subq.l      #1, d2   /* 8 */
+    bgt.s       0b       /* 10 */
+
+    rts
+
+
+.macro t_nop
+    /*
+     * when communicating with 3.3V teensy:
+     * - no nops: see old value on multiple pins randomly
+     * - 1 nop: only TR often shows old value
+     * - 2 nops: ?
+     */
+    nop
+    nop
+.endm
+
+
+.global test_joy_read_log /* u8 *dest, int size, int do_sync */
+test_joy_read_log:
+    ldarg       0, 0, a1
+    ldarg       1, 0, d0
+    ldarg       2, 0, d1
+    movem.l     d2-d7, -(sp)
+    movea.l     #0xa10003, a0
+    move.l      d0, d7
+    move.l      d1, d6
+
+    moveq.l     #0, d0
+    move.l      #0x40, d1
+    move.b      d1, (6,a0)
+    move.b      d1, (a0)
+
+    tst.l       d6
+    beq.s       2f
+    bsr         sync_with_teensy
+
+2:  /* save data */
+    move.b      d0, (a0)
+    t_nop
+    move.b      (a0), d2
+    move.b      d1, (a0)
+    t_nop
+    move.b      (a0), d3
+    move.b      d0, (a0)
+    t_nop
+    move.b      (a0), d4
+    move.b      d1, (a0)
+    t_nop
+    move.b      (a0), d5
+.if 0
+    /* broken on Mega-ED v9?? */
+    move.b      d2, (a1)+
+    move.b      d3, (a1)+
+    move.b      d4, (a1)+
+    move.b      d5, (a1)+
+.else
+    lsl.w       #8, d2
+    move.b      d3, d2
+    move.w      d2, (a1)+
+    lsl.w       #8, d4
+    move.b      d5, d4
+    move.w      d4, (a1)+
+.endif
+
+    /* delay for teensy, 128 not enough.. */
+    move.l      #256, d2
+0:
+    dbra        d2, 0b
+
+    subq.l      #4, d7
+    bgt.s       2b
+
+    movem.l     (sp)+, d2-d7
+    rts
+
+
+.global test_joy_read_log_vsync /* u8 *dest, int size */
+test_joy_read_log_vsync:
+    ldarg       0, 0, a1
+    ldarg       1, 0, d0
+    movem.l     d2-d7/a2, -(sp)
+    movea.l     #0xa10003, a0
+    movea.l     #0xc00005, a2
+    move.l      d0, d7
+
+    move.l      #0x40, d1
+    moveq.l     #0, d0
+    move.b      d1, (6,a0)
+    move.b      d1, (a0)
+
+    bsr         sync_with_teensy
+
+2:  /* save data */
+    move.b      d0, (a0)
+    move.b      (a0), d2
+    move.b      d1, (a0)
+    move.b      (a0), d3
+    move.b      d2, (a1)+
+    move.b      d3, (a1)+
+
+    /* wait for next vsync */
+    moveq.l     #3, d2
+0:
+    btst        d2, (a2)
+    bne.s       0b
+0:
+    btst        d2, (a2)
+    beq.s       0b
+
+    subq.l      #2, d7
+    bgt.s       2b
+
+    movem.l     (sp)+, d2-d7/a2
+    rts
+
+
+.global test_byte_write /* u8 *dest, int size, int seed */
+test_byte_write:
+    ldarg       0, 0, a0
+    ldarg       1, 0, d0
+    ldarg       2, 0, d1
+    movem.l     d2-d7, -(sp)
+
+    move.l      a0, a1
+    add.l       d0, a1
+    move.l      d1, d7
+0:
+    move.b      d7, d0
+    addq.b      #1, d7
+    move.b      d7, d1
+    addq.b      #1, d7
+    move.b      d7, d2
+    addq.b      #1, d7
+    move.b      d7, d3
+    addq.b      #1, d7
+    move.b      d7, d4
+    addq.b      #1, d7
+    move.b      d7, d5
+    addq.b      #1, d7
+    move.b      d7, d6
+    addq.b      #1, d7
+
+    move.b      d0, (a0)+
+    move.b      d1, (a0)+
+    move.b      d2, (a0)+
+    move.b      d3, (a0)+
+    move.b      d4, (a0)+
+    move.b      d5, (a0)+
+    move.b      d6, (a0)+
+    move.b      d7, (a0)+
+    addq.b      #1, d7
+    cmp.l       a1, a0
+    blt.s       0b
+
+    movem.l     (sp)+, d2-d7
+    rts
+
+
+.global run_game /* u16 mapper, int tas_sync */
+run_game:
+    move.w      #0x2700, sr
+    ldarg       0, 0, d7
+    ldarg       1, 0, d6
+    movea.l     #0xa10000, a6
+    movea.l     #0xc00000, a5
+    movea.l     #0xc00005, a4
+    movea.l     #0xc00004, a3
+    moveq.l     #0x00, d0
+    move.b      #0x40, d1     /* d2 is tmp */
+    move.b      #0xff, d3     /* d4 is temp */
+    moveq.l     #0x00, d5     /* progress cnt */
+    movea.l     d0, a7
+    move.b      d1, (0x09,a6) /* CtrlA */
+    move.b      d0, (0x0b,a6) /* CtrlB */
+    move.b      d0, (0x0d,a6) /* CtrlC */
+    move.b      d0, (0x13,a6) /* S-CtrlA */
+    move.b      d3, (0x0f,a6) /* TxDataA */
+    move.b      d0, (0x19,a6) /* S-CtrlB */
+    move.b      d3, (0x15,a6) /* TxDataB */
+    move.b      d0, (0x1f,a6) /* S-CtrlC */
+    move.b      d3, (0x1b,a6) /* TxDataC */
+
+    move.w      #0xcbaf, (0xA13006) /* some scratch area */
+
+    move.l      #0xff0000, a1
+    move.l      #0x10000/4/4-1, d2
+0:
+    move.l      d0, (a1)+
+    move.l      d0, (a1)+
+    move.l      d0, (a1)+
+    move.l      d0, (a1)+
+    dbra        d2, 0b
+
+    lea         (run_game_r,pc), a0
+    move.l      #0xffff80, a1
+    move.l      #(run_game_r_end - run_game_r)/2-1, d2
+0:
+    move.w      (a0)+, (a1)+
+    dbra        d2, 0b
+
+    tst.l       d6
+    beq.s       sync_hvc
+
+    movea.l     #0xa10003, a0
+    bsr         sync_with_teensy  /* trashes d3 */
+    move.l      d0, (-4,a7)
+
+sync_hvc:
+    addq.l      #1, d6        /* attempt counter */
+
+    /* set up for progress vram write (x,y - tile #) */
+    /* GFX_WRITE_VRAM_ADDR(0xc000 + (x + 64 * y) * 2) */
+    /* d = d5 + '0' - 32 + 0xB000/32 - 128 = d5 + 0x510 */
+    move.l      #(0x40000003 | ((36 + 64*1) << 17)), (a3)
+    add.w       #0x510, d5
+    move.w      d5, (a5)
+    move.w      #('/'+0x4e0), (a5)
+    move.w      #('4'+0x4e0), (a5)
+
+    lea         hexchars, a1
+    move.l      #(0x40000003 | ((31 + 64*2) << 17)), (a3)
+    moveq.l     #8-1, d5
+0:
+    rol.l       #4, d3
+    move.b      d3, d4
+    and.l       #0x0f, d4
+    move.b      (d4,a1), d4
+    add.w       #0x4e0, d4
+    move.w      d4, (a5)
+    dbra        d5, 0b
+
+    movea.l     #0xc00008, a0
+    movea.l     #0x3ff000, a1
+    movea.l     #0xffffe0, a2
+
+    /* wait for active display */
+    moveq.l     #3, d2
+0:
+    btst        d2, (a4)      /* 8 */
+    beq.s       0b            /* 10 */
+0:
+    btst        d2, (a4)
+    bne.s       0b
+
+    /* flood the VDP FIFO */
+.rept 5
+    move.w      d0, (a5)
+.endr
+
+    /* these seem stable for both 50Hz/60Hz */
+    move.l      (a0), (a1)+      /* #0xff07ff09 */
+    move.l      (a0), (a1)+      /* #0xff00ff11 */
+    move.l      (a0), (a1)+      /* #0xff18ff1a */
+    move.l      (a0), (a1)+      /* #0xff21ff23 */
+    move.l      (a0), (a1)+      /* #0xff2aff28 */
+    move.l      (a0), (a1)+      /* #0xff33ff34 */
+    move.l      (a0), (a1)+      /* #0xff3cff3e */
+    move.l      (a0), (a1)+      /* #0xff45ff47 */
+
+    /* as long as exactly 8 or more RAM writes are performed here, */
+    /* after multiple tries RAM refresh somehow eventually syncs */
+    /* after cold boot, only 50Hz syncs to always same values though, */
+    /* so values below are 50Hz */
+    move.l      (a0), (a2)+      /* #0xff4eff4f */
+    move.l      (a0), (a2)+      /* #0xff58ff59 */
+    move.l      (a0), (a2)+      /* #0xff60ff62 */
+    move.l      (a0), (a2)+      /* #0xff69ff6b */
+    move.l      (a0), (a2)+      /* #0xff72ff74 */
+    move.l      (a0), (a2)+      /* #0xff7bff7c */
+    move.l      (a0), (a2)+      /* #0xff83ff85 */
+    move.l      (a0), (a2)+      /* #0xff8eff8f */
+
+    sub.l       #4*8, a1
+    sub.l       #4*8, a2
+
+    moveq.l     #1, d5
+    move.l      (0x00,a1), d3
+    cmp.l       #0xff07ff09, d3
+    bne.w       sync_hvc
+
+    moveq.l     #2, d5
+    move.l      (0x04,a1), d3
+    cmp.l       #0xff00ff11, d3  /* mystery value */
+    bne.w       sync_hvc
+
+    moveq.l     #3, d5
+    move.l      (0x1c,a1), d3
+    cmp.l       #0xff45ff47, d3
+    bne.w       sync_hvc
+
+    btst.b      #6, (0xa10001)
+    bne.s       sync_hvc_50hz
+
+sync_hvc_60hz:
+    /* unable to get stable RAM between cold boots :( */
+    moveq.l     #4, d5
+    move.l      (0x1c,a2), d3
+    cmp.l       #0xff8dff8f, d3  /* unstable */
+    beq.s       sync_hvc_end
+    cmp.l       #0xff8cff8e, d3  /* stable? */
+    beq.s       sync_hvc_end
+    cmp.l       #0xff8eff90, d3
+    beq.s       sync_hvc_end
+    bra.w       sync_hvc
+
+sync_hvc_50hz:
+    moveq.l     #4, d5
+    move.l      (0x1c,a2), d3
+    cmp.l       #0xff8eff8f, d3  /* RAM */
+    bne.w       sync_hvc
+
+sync_hvc_end:
+    movea.l     d0, a0
+    movea.l     #0xA13000, a1
+
+    move.b      d0, (0x09,a6) /* CtrlA */
+    move.b      d1, (0x03,a6)
+
+    jmp         0xffff80
+
+run_game_r:
+    move.w      #0x3210, (0x06,a1) /* 0xA13006 */
+    move.w      d7, (0x10,a1)      /* 0xA13010 */
+    move.w      d0, (a1)           /* 0xA13000 */
+    
+    move.l      (a0)+, a7
+    move.l      (a0),  a0
+
+    jmp         (a0)
+run_game_r_end:
+
+hexchars:
+    dc.b        '0','1','2','3','4','5','6','7'
+    dc.b        '8','9','a','b','c','d','e','f'
+
+# vim:filetype=asmM68k:ts=4:sw=4:expandtab
diff --git a/megaed-sv/ed_app.ld b/megaed-sv/ed_app.ld
new file mode 100644 (file)
index 0000000..bd40362
--- /dev/null
@@ -0,0 +1,116 @@
+OUTPUT_ARCH(m68k)\r
+SEARCH_DIR(.)\r
+/*GROUP(-lbcc -lc -lgcc)*/\r
+__DYNAMIC  =  0;\r
+\r
+/*\r
+ * Setup the memory map of the SEGA Genesis.\r
+ * stack grows down from high memory.\r
+ *\r
+ * The memory map look like this:\r
+ * +--------------------+ <- low memory\r
+ * | .text              |\r
+ * |        _etext      |\r
+ * |        ctor list   | the ctor and dtor lists are for\r
+ * |        dtor list   | C++ support\r
+ * +--------------------+\r
+ * | .data              | initialized data goes here\r
+ * |        _edata      |\r
+ * +--------------------+\r
+ * | .bss               |\r
+ * |        __bss_start | start of bss, cleared by crt0\r
+ * |        _end        | start of heap, used by sbrk()\r
+ * +--------------------+\r
+ * .                    .\r
+ * .                    .\r
+ * .                    .\r
+ * |        __stack     | top of stack\r
+ * +--------------------+\r
+ */\r
+MEMORY\r
+{\r
+       rom : ORIGIN = 0x00100000, LENGTH = 0x00300000\r
+       ram : ORIGIN = 0x00ff0100, LENGTH = 0x0000FF00\r
+}\r
+\r
+/*\r
+ * allocate the stack to be at the top of memory, since the stack\r
+ * grows down\r
+ */\r
+\r
+PROVIDE (__stack = 0x00fffff0);\r
+\r
+/*\r
+ * Initalize some symbols to be zero so we can reference them in the\r
+ * crt0 without core dumping. These functions are all optional, but\r
+ * we do this so we can have our crt0 always use them if they exist. \r
+ * This is so BSPs work better when using the crt0 installed with gcc.\r
+ * We have to initalize them twice, so we cover a.out (which prepends\r
+ * an underscore) and coff object file formats.\r
+ */\r
+PROVIDE (hardware_init_hook = 0);\r
+PROVIDE (_hardware_init_hook = 0);\r
+PROVIDE (software_init_hook = 0);\r
+PROVIDE (_software_init_hook = 0);\r
+\r
+SECTIONS\r
+{\r
+  .text 0x00100000:\r
+  {\r
+    *(.text)\r
+    . = ALIGN(0x4);\r
+     __CTOR_LIST__ = .;\r
+    LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)\r
+    *(.ctors)\r
+    LONG(0)\r
+    __CTOR_END__ = .;\r
+    __DTOR_LIST__ = .;\r
+    LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)\r
+    *(.dtors)\r
+     LONG(0)\r
+    __DTOR_END__ = .;\r
+    *(.rodata*)\r
+    *(.gcc_except_table)\r
+\r
+    __INIT_SECTION__ = . ;\r
+    *(.init)\r
+    SHORT (0x4e75)     /* rts */\r
+\r
+    __FINI_SECTION__ = . ;\r
+    *(.fini)\r
+    SHORT (0x4e75)     /* rts */\r
+\r
+    _etext = .;\r
+    *(.lit)\r
+  } > rom\r
+\r
+  .data 0xff0100 :\r
+  {\r
+    *(.shdata)\r
+    *(.data)\r
+    _edata = .;\r
+  } > ram\r
+\r
+  /* .bss 0xff0100 : */\r
+  .bss BLOCK (0x4) :\r
+  {\r
+    __bss_start = . ;\r
+    *(.shbss)\r
+    *(.bss)\r
+    *(COMMON)\r
+    *(.eh_fram)\r
+    *(.eh_frame)\r
+    _end =  ALIGN (0x8);\r
+    __end = _end;\r
+  } > ram\r
+\r
+  .stab 0 (NOLOAD) :\r
+  {\r
+    *(.stab)\r
+  }\r
+\r
+  .stabstr 0 (NOLOAD) :\r
+  {\r
+    *(.stabstr)\r
+  }\r
+}\r
diff --git a/megaed-sv/edos.h b/megaed-sv/edos.h
new file mode 100644 (file)
index 0000000..58025e3
--- /dev/null
@@ -0,0 +1,153 @@
+/* 
+ * File:   edos.h
+ * Author: krik
+ *
+ * Created on 29 ÃŒÃ Ã°Ã² 2012 Ã£., 1:29
+ */
+
+#ifndef _EDOS_H
+#define        _EDOS_H
+
+//#include "segalib.h"
+
+/*
+ * saddr: address in sectors
+ * slen: lenght in sectors
+ * wr_slen: how many sectors will be written
+ * sector size 512 bytes
+ * dma reading of usb and SD available only if data destination located in rom area (0-0x3ffffff). dma reading not available for genesis ram
+ * destination address for dma reading must be aligned to 512b
+ * one mbyte of sdram can be mapped to one of four banks in rom space. osSetMemMap(u16) can be used for mapping configuration.
+ * os code located in last mbyte of sdram and should be mapped in bank 0
+ * user code located in begin of sdram. default mapping 0x210f means that end of sdram (OS) mapped to area 0-0x0fffff, first mbyte of user code mapped to 0x100000-0x1fffff,
+ * memory configuration:
+ * genesis address: 0x000000-0x0fffff, physical sdram address: 0xf00000-0xffffff  OS
+ * genesis address: 0x100000-0x3fffff, physical sdram address: 0x000000-0x2fffff  user code (current application)
+ * 0xff0000-0xff00ff OS dma code
+ * first 256bytes of genesis ram must be reserved for OS
+ * */
+
+
+#define MEM_ERR_SPI_RD_TIMEOUT 120
+
+#define ERR_FILE_TOO_BIG 140
+#define ERR_WRON_OS_SIZE 142
+#define ERR_OS_VERIFY 143
+#define ERR_OS_VERIFY2 144
+#define ERR_BAD_DMA_ADDRESS 145
+#define ERR_MUST_NOT_RET 146
+
+//100 - 119 fat errors
+#define FAT_ERR_NOT_EXIST 100
+#define FAT_ERR_EXIST 101
+#define FAT_ERR_NAME 102
+#define FAT_ERR_OUT_OF_FILE 103
+#define FAT_ERR_BAD_BASE_CLUSTER 104;
+#define FAT_ERR_NO_FRE_SPACE 105
+#define FAT_ERR_NOT_FILE 106
+#define FAT_ERR_FILE_MODE 107
+#define FAT_ERR_ROT_OVERFLOW 108
+#define FAT_ERR_OUT_OF_TABLE 109
+#define FAT_ERR_INIT 110
+#define FAT_LFN_BUFF_OVERFLOW 111
+#define FAT_DISK_NOT_READY 112
+#define FAT_ERR_SIZE 113
+#define FAT_ERR_RESIZE 114
+
+
+#define DISK_ERR_INIT 50
+#define DISK_ERR_RD1 62
+#define DISK_ERR_RD2 63
+
+#define DISK_ERR_WR1 64
+#define DISK_ERR_WR2 65
+#define DISK_ERR_WR3 66
+#define DISK_ERR_WR4 67
+#define DISK_ERR_WR5 68
+
+typedef struct {
+    u32 entry_cluster;
+    u32 size;
+    u32 hdr_sector;
+    u16 hdr_idx;
+    u8 name[256];
+    u16 is_dir;
+} FatFullRecord;
+
+typedef struct {
+    u8(*diskWrite)(u32 saddr, u8 *buff, u16 slen);
+    u8(*diskRead)(u32 saddr, void *buff, u16 slen);//*dst must be alligned to 512bytes and be in range 0x100000-0x3fffff. *dst can be located in genesis ram also, but transfer will be slow in this case
+    u8(*usbReadByte)();//loop inside of function waiting until usbRdReady != 0
+    void (*usbWriteByte)(u8 dat);//loop inside of function waiting until usbWrReady != 0
+    u8(*usbReadDma)(u16 *dst, u16 slen);//*dst must be alligned to 512bytes and be in range 0x100000-0x3fffff
+    u8(*usbReadPio)(u16 *dst, u16 slen);
+    u8(*usbRdReady)(); //return 1 if some data comes from pc
+    u8(*usbWrReady)(); //return 1 usb ready to send byte
+    void (*osSetMemMap)(u16 map); //memoty configuration 4x1Mb
+    u16(*osGetOsVersion)();
+    u16(*osGetFirmVersion)();
+    void (*osGetSerial)(u32 * buff); // 8bytes uniq serial number
+    void (*VDP_setReg)(u8 reg, u8 value);//os vdp functions should be used, otherwise system may hang while udb/sd dma
+    void (*VDP_vintOn)();
+    void (*VDP_vintOff)();
+    void (*memInitDmaCode)();//copy dma routine to genesis ram
+    u8(*fatReadDir)(FatFullRecord * frec);//get next record in current dir
+    void(*fatOpenDir)(u32 entry_cluster);//arg is entry cluster ot dir or 0. zero arg means that need to open root dir
+    u8(*fatOpenFileByeName)(u8 *name, u32 wr_slen);//wr_slen write len, or 0 if reading
+    u8(*fatOpenFile)(FatFullRecord *rec, u32 wr_slen);//wr_slen is write len, or 0 if reading
+    u8(*fatReadFile)(void *dst, u32 slen);
+    u8(*fatWriteFile)(void *src, u32 slen);
+    u8(*fatCreateRecIfNotExist)(u8 *name, u8 is_dir);
+    u8(*fatSkipSectors)(u32 slen);
+} OsRoutine;
+
+
+extern OsRoutine *ed_os;
+void edInit();
+
+
+//stereo dac. 8bit for each channel.
+//any writing to this port enables dac output, any reading from this port disables dac output.
+#define REG_DAC *((volatile u16*) (0xA1300E))
+
+
+//stuff for direct access to usb and spi. not recommended for use. OS function should be used for best compatibility
+#define _SPI_SS 0
+#define _SPI_FULL_SPEED 1
+#define _SPI_SPI16 2
+#define _SPI_AREAD 3
+
+//spi port (sd interface)
+#define SPI_PORT *((volatile u16*) (0xA13000))
+#define SPI_CFG_PORT *((volatile u16*) (0xA13002))
+
+//16bit or 8bit spi mode
+#define SPI16_ON SPI_CFG_PORT |= (1 << _SPI_SPI16)
+#define SPI16_OFF SPI_CFG_PORT &= ~(1 << _SPI_SPI16)
+
+//spi autoread. means that not need to write something to spi port before than read
+#define SPI_AR_ON SPI_CFG_PORT |= (1 << _SPI_AREAD)
+#define SPI_AR_OFF SPI_CFG_PORT &= ~(1 << _SPI_AREAD)
+
+//spi chip select
+#define SPI_SS_OFF SPI_CFG_PORT |= (1 << _SPI_SS)
+#define SPI_SS_ON SPI_CFG_PORT &= ~(1 << _SPI_SS)
+
+//spi speed. low speed need only for sd init
+#define SPI_HI_SPEED_ON SPI_CFG_PORT |= (1 << _SPI_FULL_SPEED)
+#define SPI_HI_SPEED_OFF SPI_CFG_PORT &= ~(1 << _SPI_FULL_SPEED)
+
+//usb-serial port
+#define FIFO_PORT *((volatile u16*) (0xA1300A))
+
+//spi and usb state
+#define STATE_PORT *((volatile u16*) (0xA1300C))
+#define _STATE_SPI_READY 0
+#define _STATE_FIFO_WR_READY 1
+#define _STATE_FIFO_RD_READY 2
+#define IS_FIFO_RD_READY (STATE_PORT & (1 << _STATE_FIFO_RD_READY))
+#define IS_FIFO_WR_READY (STATE_PORT & (1 << _STATE_FIFO_WR_READY))
+
+
+#endif /* _EDOS_H */
+
diff --git a/megaed-sv/main.c b/megaed-sv/main.c
new file mode 100644 (file)
index 0000000..a0741b6
--- /dev/null
@@ -0,0 +1,696 @@
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define u8      unsigned char
+#define u16     unsigned short
+#define u32     unsigned int
+
+#define noinline __attribute__((noinline))
+#define _packed __attribute__((packed))
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+#include "edos.h"
+#include "asmtools.h"
+
+extern u16 start_hvc;
+
+#define GFX_DATA_PORT    0xC00000
+#define GFX_CTRL_PORT    0xC00004
+
+#define TILE_MEM_END     0xB000
+
+#define FONT_LEN         128
+#define TILE_FONT_BASE   (TILE_MEM_END / 32  - FONT_LEN)
+
+/* note: using ED menu's layout here.. */
+#define WPLANE           (TILE_MEM_END + 0x0000)
+#define HSCRL            (TILE_MEM_END + 0x0800)
+#define SLIST            (TILE_MEM_END + 0x0C00)
+#define APLANE           (TILE_MEM_END + 0x1000)
+#define BPLANE           (TILE_MEM_END + 0x3000)
+
+#define read8(a) \
+    *((volatile u8 *) (a))
+#define read16(a) \
+    *((volatile u16 *) (a))
+#define read32(a) \
+    *((volatile u32 *) (a))
+#define write8(a, d) \
+    *((volatile u8 *) (a)) = (d)
+#define write16(a, d) \
+    *((volatile u16 *) (a)) = (d)
+#define write32(a, d) \
+    *((volatile u32 *) (a)) = (d)
+
+#define GFX_WRITE_VRAM_ADDR(adr) \
+    (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00)
+#define GFX_WRITE_VSRAM_ADDR(adr) \
+    (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x10)
+
+enum {
+    VDP_MODE1 = 0x00,
+    VDP_MODE2 = 0x01,
+    VDP_BACKDROP = 0x07,
+    VDP_MODE3 = 0x0b,
+    VDP_MODE4 = 0x0c,
+    VDP_AUTOINC = 0x0f,
+    VDP_SCROLLSZ = 0x10,
+};
+
+/* cell counts */
+#define LEFT_BORDER 1   /* lame TV */
+#define PLANE_W 64
+#define PLANE_H 32
+#define CSCREEN_H 28
+
+static noinline void VDP_drawTextML(const char *str, u16 plane_base,
+    u16 x, u16 y)
+{
+    const u8 *src = (const u8 *)str;
+    u16 basetile = 0;
+    int max_len = 40 - LEFT_BORDER;
+    int len;
+    u32 addr;
+
+    x += LEFT_BORDER;
+
+    for (len = 0; str[len] && len < max_len; len++)
+        ;
+    if (len > (PLANE_W - x))
+        len = PLANE_W - x;
+
+    addr = plane_base + ((x + (PLANE_W * y)) << 1);
+    write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr));
+
+    while (len-- > 0) {
+        write16(GFX_DATA_PORT,
+            basetile | ((*src++) - 32 + TILE_FONT_BASE));
+    }
+}
+
+static int printf_ypos;
+
+static void printf_line(int x, const char *buf)
+{
+    u32 addr;
+    int i;
+
+    VDP_drawTextML(buf, APLANE, x, printf_ypos++ & (PLANE_H - 1));
+
+    if (printf_ypos >= CSCREEN_H) {
+        /* clear next line */
+        addr = APLANE;
+        addr += (PLANE_W * (printf_ypos & (PLANE_H - 1))) << 1;
+        write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr));
+        for (i = 0; i < 40 / 2; i++)
+            write32(GFX_DATA_PORT, 0);
+
+        /* scroll plane */
+        write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
+        write16(GFX_DATA_PORT, (printf_ypos - CSCREEN_H + 1) * 8);
+    }
+}
+
+#define PRINTF_LEN 40
+
+static noinline int printf(const char *fmt, ...)
+{
+    static const char hexchars[] = "0123456789abcdef";
+    static int printf_xpos;
+    char c, buf[PRINTF_LEN + 11 + 1];
+    const char *s;
+    va_list ap;
+    int ival;
+    u32 uval;
+    int d = 0;
+    int i, j;
+
+    va_start(ap, fmt);
+    for (d = 0; *fmt; ) {
+        int prefix0 = 0;
+        int fwidth = 0;
+
+        c = *fmt++;
+        if (d < PRINTF_LEN)
+            buf[d] = c;
+
+        if (c != '%') {
+            if (c == '\n') {
+                buf[d] = 0;
+                printf_line(printf_xpos, buf);
+                d = 0;
+                printf_xpos = 0;
+                continue;
+            }
+            d++;
+            continue;
+        }
+        if (d >= PRINTF_LEN)
+            continue;
+
+        if (*fmt == '0') {
+            prefix0 = 1;
+            fmt++;
+        }
+
+        while ('1' <= *fmt && *fmt <= '9') {
+            fwidth = fwidth * 10 + *fmt - '0';
+            fmt++;
+        }
+
+        switch (*fmt++) {
+        case '%':
+            d++;
+            break;
+        case 'd':
+        case 'i':
+            ival = va_arg(ap, int);
+            if (ival < 0) {
+                buf[d++] = '-';
+                ival = -ival;
+            }
+            for (i = 1000000000; i >= 10; i /= 10)
+                if (ival >= i)
+                    break;
+            for (; i >= 10; i /= 10) {
+                buf[d++] = '0' + ival / i;
+                ival %= i;
+            }
+            buf[d++] = '0' + ival;
+            break;
+        case 'x':
+            uval = va_arg(ap, int);
+            while (fwidth > 1 && uval < (1 << (fwidth - 1) * 4)) {
+                buf[d++] = prefix0 ? '0' : ' ';
+                fwidth--;
+            }
+            for (j = 1; j < 8 && uval >= (1 << j * 4); j++)
+                ;
+            for (j--; j >= 0; j--)
+                buf[d++] = hexchars[(uval >> j * 4) & 0x0f];
+            break;
+        case 's':
+            s = va_arg(ap, char *);
+            while (*s && d < PRINTF_LEN)
+                buf[d++] = *s++;
+            break;
+        default:
+            // don't handle, for now
+            d++;
+            va_arg(ap, void *);
+            break;
+        }
+    }
+    buf[d] = 0;
+    va_end(ap);
+
+    if (d != 0) {
+        // line without \n
+        VDP_drawTextML(buf, APLANE, printf_xpos,
+            printf_ypos & (PLANE_H - 1));
+        printf_xpos += d;
+    }
+
+    return d; // wrong..
+}
+
+static u8 gethex(char c)
+{
+    if ('0' <= c && c <= '9')
+        return c - '0';
+    if ('a' <= c && c <= 'f')
+        return c - 'a' + 10;
+    if ('A' <= c && c <= 'F')
+        return c - 'A' + 10;
+    return 0;
+}
+
+static const char *exc_names[] = {
+    NULL,
+    NULL,
+    "Bus Error",
+    "Address Error",
+    "Illegal Instruction",
+    "Zero Divide",
+    "CHK Instruction",
+    "TRAPV Instruction",
+    "Privilege Violation",  /*  8  8 */
+    "Trace",
+    "Line 1010 Emulator",
+    "Line 1111 Emulator",
+    NULL,
+    NULL,
+    NULL,
+    "Uninitialized Interrupt",
+    NULL,                   /* 10 16 */
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    "Spurious Interrupt",   /* 18 24 */
+    "l1 irq",
+    "l2 irq",
+    "l3 irq",
+    "l4 irq",
+    "l5 irq",
+    "l6 irq",
+    "l7 irq",
+};
+
+struct exc_frame {
+    u32 dr[8];
+    u32 ar[8];
+    u16 ecxnum; // from handler
+    union {
+        struct {
+            u16 sr;
+            u32 pc;
+        } g _packed;
+        struct {
+            u16 fc;
+            u32 addr;
+            u16 ir;
+            u16 sr;
+            u32 pc;
+        } bae _packed; // bus/address error frame
+    };
+} _packed;
+
+int xtttt(void) { return sizeof(struct exc_frame); }
+
+void exception(const struct exc_frame *f)
+{
+    int i;
+
+    while (read16(GFX_CTRL_PORT) & 2)
+        ;
+    write16(GFX_CTRL_PORT, 0x8000 | (VDP_MODE1 << 8) | 0x04);
+    write16(GFX_CTRL_PORT, 0x8000 | (VDP_MODE2 << 8) | 0x44);
+    /* adjust scroll */
+    write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
+    write16(GFX_DATA_PORT,
+      printf_ypos >= CSCREEN_H ?
+        (printf_ypos - CSCREEN_H + 1) * 8 : 0);
+
+    printf("exception %i ", f->ecxnum);
+    if (f->ecxnum < ARRAY_SIZE(exc_names) && exc_names[f->ecxnum] != NULL)
+        printf("(%s)", exc_names[f->ecxnum]);
+    if (f->ecxnum < 4)
+        printf(" (%s)", (f->bae.fc & 0x10) ? "r" : "w");
+    printf("    \n");
+
+    if (f->ecxnum < 4) {
+        printf("  PC: %08x SR: %04x    \n", f->bae.pc, f->bae.sr);
+        printf("addr: %08x IR: %04x FC: %02x   \n",
+               f->bae.addr, f->bae.ir, f->bae.fc);
+    }
+    else {
+        printf("  PC: %08x SR: %04x    \n", f->g.pc, f->g.sr);
+    }
+    for (i = 0; i < 8; i++)
+        printf("  D%d: %08x A%d: %08x    \n", i, f->dr[i], i, f->ar[i]);
+    printf("                       \n");
+}
+
+void vbl(void)
+{
+}
+
+static int usb_read_while_ready(OsRoutine *ed,
+    void *buf_, unsigned int maxlen)
+{
+    u8 *buf = buf_;
+    unsigned int r = 0;
+
+    while (ed->usbRdReady() && r < maxlen)
+        buf[r++] = ed->usbReadByte();
+
+    return r;
+}
+
+static int usb_read(OsRoutine *ed, void *buf_, unsigned int maxlen)
+{
+    u8 *buf = buf_;
+    unsigned int r = 0;
+
+    while (r < maxlen)
+        buf[r++] = ed->usbReadByte();
+
+    return r;
+}
+
+static int usb_write(OsRoutine *ed, const void *buf_, unsigned int maxlen)
+{
+    const u8 *buf = buf_;
+    unsigned int r = 0;
+
+    while (r < maxlen)
+        ed->usbWriteByte(buf[r++]);
+
+    return r;
+}
+
+/*
+ * TH = 1 : ?1CBRLDU    3-button pad return value (not read)
+ * TH = 0 : ?0SA00DU    3-button pad return value
+ * TH = 1 : ?1CBRLDU    3-button pad return value
+ * TH = 0 : ?0SA0000    D3-0 are forced to '0'
+ * TH = 1 : ?1CBMXYZ    Extra buttons returned in D3-0
+ * TH = 0 : ?0SA1111    D3-0 are forced to '1'
+ */
+static void test_joy_latency(int *min_out, int *max_out)
+{
+    u8 rbuf[8 * 6];
+    int min = 8;
+    int max = 0;
+    int i, v, b, e;
+
+    for (i = 0; i < 64; i++) {
+        read_joy_responses(rbuf);
+
+        for (b = 0; b < 8 * 4; b++) {
+            v = b & 7;
+            e = (b & 0x08) ? 0x0c : 0;
+            if ((rbuf[b] & 0x0c) == e) {
+                if (v < min)
+                    min = v;
+            }
+            else if (v > max)
+                max = v;
+        }
+    }
+
+    /* print out the last test */
+    for (b = 0; b < 8 * 5; b++) {
+        printf(" %02x", rbuf[b]);
+        if ((b & 7) == 7)
+            printf("\n");
+    }
+    printf("\n");
+
+    *min_out = min;
+    *max_out = max;
+}
+
+static int do_test(OsRoutine *ed, u8 b3)
+{
+    int min = 0, max = 0;
+    int i, t, len, seed;
+    u8 *p, v;
+
+    switch (b3)
+    {
+    case '0':
+        printf("reading..\n");
+        test_joy_read_log((void *)0x200000, 0x20000, 1);
+        //test_joy_read_log((void *)0xff0200, 0x0f000, 1);
+        printf("done\n");
+        return 0;
+    case '1':
+        printf("reading w/vsync..\n");
+        test_joy_read_log_vsync((void *)0x200000, 3600 * 2);
+        printf("done\n");
+        return 0;
+    case '2':
+    case '3':
+        printf("3btn_idle test..\n");
+        p = (void *)0x200000;
+        len = 0x20000;
+        test_joy_read_log(p, len, b3 == '3');
+        for (i = 0; i < len; i++) {
+            static const u8 e[2] = { 0x33, 0x7f };
+            v = e[i & 1];
+            if (p[i] != v)
+                printf("%06x: bad: %02x %02x\n", &p[i], p[i], v);
+        }
+        printf("done\n");
+        return 0;
+    case '4':
+        printf("3btn_idle data test..\n");
+        p = (void *)0x200000;
+        len = 0x20000;
+        for (i = 0; i < len; i++) {
+            static const u8 e[2] = { 0x33, 0x7f };
+            v = e[i & 1];
+            if (p[i] != v)
+                printf("%06x: bad: %02x %02x\n", &p[i], p[i], v);
+        }
+        printf("done\n");
+        return 0;
+    case '5':
+        seed = read8(0xC00009);
+        printf("testing, seed=%02x\n", seed);
+        p = (void *)0x200000;
+        len = 0x100000;
+        test_byte_write(p, len, seed);
+        for (t = 0; t < 2; t++) {
+            for (i = 0; i < len; i++) {
+                v = (u8)(i + seed);
+                if (p[i] != v)
+                    printf("%06x: bad: %02x %02x\n", &p[i], p[i], v);
+            }
+            printf("done (%d)\n", t);
+        }
+        return 0;
+    case 'j':
+        test_joy_latency(&min, &max);
+        printf("latency: %d - %d\n\n", min, max);
+        return 0;
+    default:
+        break;
+    }
+
+    return -1;
+}
+
+static int do_custom(OsRoutine *ed, u8 b3)
+{
+    struct {
+        unsigned int addr;
+        unsigned int size;
+    } d;
+
+    switch (b3)
+    {
+    case 'd':
+        usb_read(ed, &d, sizeof(d));
+        ed->usbWriteByte('k');
+        printf("sending %i bytes from %06x..\n", d.size, d.addr);
+        usb_write(ed, (void *)d.addr, d.size);
+        printf("done.\n");
+        return 1;
+    default:
+        break;
+    }
+
+    return -1;
+}
+
+#define MTYPE_OS 0
+#define MTYPE_MD 1
+#define MTYPE_SSF 2
+#define MTYPE_CD 3
+#define MTYPE_SMS 4
+#define MTYPE_10M 5
+#define MTYPE_32X 6
+
+static int do_run(OsRoutine *ed, u8 b3, int tas_sync)
+{
+    u8 mapper = 0;
+
+    switch (b3)
+    {
+    case 's':
+        mapper = MTYPE_SMS | (7 << 4);
+        break;
+    case 'm':
+        mapper = MTYPE_MD;
+        break;
+    case 'o':
+        mapper = MTYPE_OS;
+        break;
+    case 'c':
+        mapper = MTYPE_CD;
+        break;
+    case '3':
+        mapper = MTYPE_32X;
+        break;
+    case 'M':
+        mapper = MTYPE_10M;
+        break;
+    case 'n':
+        // raw numer: hex XX: mtype | x;
+        // x: bits [4-7]: SRAM_ON, SRAM_3M_ON, SNAP_SAVE_ON, MKEY
+        mapper  = gethex(ed->usbReadByte()) << 4;
+        mapper |= gethex(ed->usbReadByte());
+        break;
+    default:
+        return -1;
+    }
+
+    printf("syncing and starting mapper %x..\n", mapper);
+
+    while (read16(GFX_CTRL_PORT) & 2)
+        ;
+    ed->VDP_setReg(VDP_MODE1, 0x04); 
+    ed->VDP_setReg(VDP_MODE2, 0x44); 
+
+    ed->usbWriteByte('k');
+
+    run_game(mapper, tas_sync);
+    /* should not get here.. */
+
+    return -1;
+}
+
+void setup_z80(void)
+{
+    u8 *mem = (u8 *)0xa00000;
+    int i;
+
+    write8(0xa11100, 1);
+    write8(0xa11200, 1);
+
+    while (read8(0xa11100) & 1)
+        ;
+
+    /* must use byte access */
+    for (i = 0x2000; i > 0; i--)
+        *mem++ = 0;
+
+    /* console starts with reset on, busreq off,
+     * gens starts with busreq on, keep that for gmv.. */
+}
+
+int main()
+{
+    OsRoutine *ed;
+    u8 buf[16];
+    int len;
+    int i, d, ret;
+
+    ed = (OsRoutine *) *(u32 *)0x1A0;
+    ed->memInitDmaCode(); 
+
+    /* setup VDP */
+    while (read16(GFX_CTRL_PORT) & 2)
+        ;
+
+    ed->VDP_setReg(VDP_MODE1, 0x04); 
+    ed->VDP_setReg(VDP_MODE2, 0x64); 
+    ed->VDP_setReg(VDP_AUTOINC, 2); 
+    ed->VDP_setReg(VDP_SCROLLSZ, 0x01); 
+
+    /* clear name tables */
+    write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(APLANE));
+    for (i = 0; i < PLANE_W * PLANE_H / 2; i++)
+        write32(GFX_DATA_PORT, 0);
+
+    write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(BPLANE));
+    for (i = 0; i < PLANE_W * PLANE_H / 2; i++)
+        write32(GFX_DATA_PORT, 0);
+
+    /* scroll planes */
+    write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
+    write32(GFX_DATA_PORT, 0);
+
+    /* note: relying on ED menu's font setup here.. */
+
+    printf("\n");
+    printf("version: %02x, hvc: %04x %04x\n",
+           read8(0xa10001), start_hvc, read16(0xc00008));
+    printf("ED os/fw: %d/%d\n\n", ed->osGetOsVersion(),
+           ed->osGetFirmVersion());
+
+    setup_z80();
+
+    for (;;) {
+        if (!ed->usbRdReady()) {
+            /* note: stop corrupts SDRAM */
+            //asm volatile("stop #0x2000");
+            asm volatile(
+                "move.l #1000/10, %0\n"
+                "0: dbra %0, 0b\n" : "=r" (i) :: "cc");
+            continue;
+        }
+
+        buf[0] = ed->usbReadByte();
+        if (buf[0] == ' ')
+            continue;
+        if (buf[0] != '*') {
+            d = 1;
+            goto bad_input;
+        }
+
+        /* note: OS uses Twofgsr */
+        buf[1] = ed->usbReadByte();
+        switch (buf[1]) {
+        case 'T':
+            ed->usbWriteByte('k');
+            break;
+        case 'g':
+            len = ed->usbReadByte() * 128;
+            printf("loading %d bytes.. ", len * 512);
+            ed->usbWriteByte('k');
+            ed->usbReadDma((void *)0x200000, len);
+            ed->usbWriteByte('d');
+            printf("done\n");
+            break;
+        case 'r':
+        case 'R':
+            buf[2] = ed->usbReadByte();
+            ret = do_run(ed, buf[2], buf[1] == 'R');
+            if (ret != 0) {
+                d = 3;
+                goto bad_input;
+            }
+            printf("run returned??\n");
+            break;
+
+        /* custom */
+        case 't':
+            buf[2] = ed->usbReadByte();
+            ret = do_test(ed, buf[2]);
+            if (ret != 0) {
+                d = 3;
+                goto bad_input;
+            }
+            ed->usbWriteByte('k');
+            break;
+        case 'x':
+            buf[2] = ed->usbReadByte();
+            ret = do_custom(ed, buf[2]);
+            if (ret == 1)
+                break;
+            if (ret != 0) {
+                d = 3;
+                goto bad_input;
+            }
+            ed->usbWriteByte('k');
+            break;
+        default:
+            d = 2;
+            goto bad_input;
+        }
+
+        continue;
+
+bad_input:
+        ret = usb_read_while_ready(ed, buf + d, sizeof(buf) - d);
+        buf[d + ret] = 0;
+        printf("bad cmd: %s\n", buf);
+        /* consume all remaining data */
+        while (ed->usbRdReady())
+            usb_read_while_ready(ed, buf, sizeof(buf));
+
+        ed->usbWriteByte('b');
+    }
+
+    return 0;
+}
+
+// vim:ts=4:sw=4:expandtab
diff --git a/megaed-sv/sega_gcc.s b/megaed-sv/sega_gcc.s
new file mode 100644 (file)
index 0000000..897acdf
--- /dev/null
@@ -0,0 +1,222 @@
+exc_tab:\r
+    dc.l     0, 0x200, exc02, exc03, exc04, exc05, exc06, exc07\r
+    dc.l exc08, exc09, exc0a, exc0b, exc0c, exc0d, exc0e, exc0f\r
+    dc.l exc10, exc11, exc12, exc13, exc14, exc15, exc16, exc17\r
+    dc.l exc18, exc19, exc1a, exc1b, HBL,   exc1d, VBL,   exc1f\r
+    dc.l exc20, exc21, exc22, exc23, exc24, exc25, exc26, exc27\r
+    dc.l exc28, exc29, exc2a, exc2b, exc2c, exc2d, exc2e, exc2f\r
+    dc.l exc30, exc31, exc32, exc33, exc34, exc35, exc3e, exc37\r
+    dc.l exc38, exc39, exc3a, exc3b, exc3c, exc3d, exc3e, exc3f\r
+\r
+    .ascii "SEGA EVERDRIVE                  "\r
+    .ascii "MEGA-ED host                                    "\r
+    .ascii "MEGA-ED host                                    "\r
+    .ascii "GM 00000000-00"\r
+    .byte 0x00,0x00\r
+    .ascii "JD              "\r
+    .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00\r
+    .byte 0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff\r
+    .ascii "               "\r
+    .ascii "                        "\r
+    .ascii "                         "\r
+    .ascii "JUE             "\r
+\r
+RST:\r
+       move.w      (0xc00008), start_hvc\r
+       move.w          #0x2700, %sr\r
+/* magic ED app init */\r
+       move.w #0x0000, (0xA13006)\r
+       jmp init_ed.l\r
+init_ed:\r
+/* relocate to bank a, so that other ROMs can be loaded */\r
+       move.w #0x0a0f, (0xA13006)\r
+       movea.l #0x100000, %a0\r
+       movea.l #0x200000, %a1\r
+       move.l #0x100000/4/4-1, %d0\r
+0:\r
+       move.l (a0)+, (a1)+\r
+       move.l (a0)+, (a1)+\r
+       move.l (a0)+, (a1)+\r
+       move.l (a0)+, (a1)+\r
+       dbra %d0, 0b\r
+\r
+       move.w #0x10af, (0xA13006)\r
+\r
+       lea exc_tab, %a0\r
+       adda.l #4*2, %a0\r
+       movea.l #4*2, %a1\r
+       move.l #64-2-1, %d0\r
+0:\r
+       move.l (a0)+, (a1)+\r
+       dbra %d0, 0b\r
+\r
+       moveq   #0, %d0\r
+       movea.l %d0, %a7\r
+       move    %a7, %usp\r
+       move.w  #0x2000, %sr\r
+       bra     main\r
+\r
+HBL:\r
+       rte\r
+\r
+VBL:\r
+       movem.l %d0-%d1/%a0-%a1,-(%sp)\r
+        jsr vbl\r
+       movem.l (%sp)+,%d0-%d1/%a0-%a1\r
+       rte\r
+\r
+pre_exception:\r
+       move.w  #0x2700, %sr\r
+       movem.l %d0-%d7/%a0-%a7,-(%sp)\r
+       move.l %sp, %d0\r
+       move.l %d0,-(%sp)\r
+       jsr exception\r
+0:\r
+       bra 0b\r
+\r
+\r
+* Standard 32X startup code for MD side at 0x3F0\r
+       .org 0x3F0\r
+\r
+        .word   0x287C,0xFFFF,0xFFC0,0x23FC,0x0000,0x0000,0x00A1,0x5128\r
+        .word   0x46FC,0x2700,0x4BF9,0x00A1,0x0000,0x7001,0x0CAD,0x4D41\r
+        .word   0x5253,0x30EC,0x6600,0x03E6,0x082D,0x0007,0x5101,0x67F8\r
+        .word   0x4AAD,0x0008,0x6710,0x4A6D,0x000C,0x670A,0x082D,0x0000\r
+        .word   0x5101,0x6600,0x03B8,0x102D,0x0001,0x0200,0x000F,0x6706\r
+        .word   0x2B78,0x055A,0x4000,0x7200,0x2C41,0x4E66,0x41F9,0x0000\r
+        .word   0x04D4,0x6100,0x0152,0x6100,0x0176,0x47F9,0x0000,0x04E8\r
+        .word   0x43F9,0x00A0,0x0000,0x45F9,0x00C0,0x0011,0x3E3C,0x0100\r
+        .word   0x7000,0x3B47,0x1100,0x3B47,0x1200,0x012D,0x1100,0x66FA\r
+        .word   0x7425,0x12DB,0x51CA,0xFFFC,0x3B40,0x1200,0x3B40,0x1100\r
+        .word   0x3B47,0x1200,0x149B,0x149B,0x149B,0x149B,0x41F9,0x0000\r
+        .word   0x04C0,0x43F9,0x00FF,0x0000,0x22D8,0x22D8,0x22D8,0x22D8\r
+        .word   0x22D8,0x22D8,0x22D8,0x22D8,0x41F9,0x00FF,0x0000,0x4ED0\r
+        .word   0x1B7C,0x0001,0x5101,0x41F9,0x0000,0x06BC,0xD1FC,0x0088\r
+        .word   0x0000,0x4ED0,0x0404,0x303C,0x076C,0x0000,0x0000,0xFF00\r
+        .word   0x8137,0x0002,0x0100,0x0000,0xAF01,0xD91F,0x1127,0x0021\r
+        .word   0x2600,0xF977,0xEDB0,0xDDE1,0xFDE1,0xED47,0xED4F,0xD1E1\r
+        .word   0xF108,0xD9C1,0xD1E1,0xF1F9,0xF3ED,0x5636,0xE9E9,0x9FBF\r
+        .word   0xDFFF,0x4D41,0x5253,0x2049,0x6E69,0x7469,0x616C,0x2026\r
+        .word   0x2053,0x6563,0x7572,0x6974,0x7920,0x5072,0x6F67,0x7261\r
+        .word   0x6D20,0x2020,0x2020,0x2020,0x2020,0x2043,0x6172,0x7472\r
+        .word   0x6964,0x6765,0x2056,0x6572,0x7369,0x6F6E,0x2020,0x2020\r
+        .word   0x436F,0x7079,0x7269,0x6768,0x7420,0x5345,0x4741,0x2045\r
+        .word   0x4E54,0x4552,0x5052,0x4953,0x4553,0x2C4C,0x5444,0x2E20\r
+        .word   0x3139,0x3934,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020\r
+        .word   0x2020,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020\r
+        .word   0x2020,0x2020,0x2020,0x524F,0x4D20,0x5665,0x7273,0x696F\r
+        .word   0x6E20,0x312E,0x3000,0x48E7,0xC040,0x43F9,0x00C0,0x0004\r
+        .word   0x3011,0x303C,0x8000,0x323C,0x0100,0x3E3C,0x0012,0x1018\r
+        .word   0x3280,0xD041,0x51CF,0xFFF8,0x4CDF,0x0203,0x4E75,0x48E7\r
+        .word   0x81C0,0x41F9,0x0000,0x063E,0x43F9,0x00C0,0x0004,0x3298\r
+        .word   0x3298,0x3298,0x3298,0x3298,0x3298,0x3298,0x2298,0x3341\r
+        .word   0xFFFC,0x3011,0x0800,0x0001,0x66F8,0x3298,0x3298,0x7000\r
+        .word   0x22BC,0xC000,0x0000,0x7E0F,0x3340,0xFFFC,0x3340,0xFFFC\r
+        .word   0x3340,0xFFFC,0x3340,0xFFFC,0x51CF,0xFFEE,0x22BC,0x4000\r
+        .word   0x0010,0x7E09,0x3340,0xFFFC,0x3340,0xFFFC,0x3340,0xFFFC\r
+        .word   0x3340,0xFFFC,0x51CF,0xFFEE,0x4CDF,0x0381,0x4E75,0x8114\r
+        .word   0x8F01,0x93FF,0x94FF,0x9500,0x9600,0x9780,0x4000,0x0080\r
+        .word   0x8104,0x8F02,0x48E7,0xC140,0x43F9,0x00A1,0x5180,0x08A9\r
+        .word   0x0007,0xFF80,0x66F8,0x3E3C,0x00FF,0x7000,0x7200,0x337C\r
+        .word   0x00FF,0x0004,0x3341,0x0006,0x3340,0x0008,0x4E71,0x0829\r
+        .word   0x0001,0x000B,0x66F8,0x0641,0x0100,0x51CF,0xFFE8,0x4CDF\r
+        .word   0x0283,0x4E75,0x48E7,0x8180,0x41F9,0x00A1,0x5200,0x08A8\r
+        .word   0x0007,0xFF00,0x66F8,0x3E3C,0x001F,0x20C0,0x20C0,0x20C0\r
+        .word   0x20C0,0x51CF,0xFFF6,0x4CDF,0x0181,0x4E75,0x41F9,0x00FF\r
+        .word   0x0000,0x3E3C,0x07FF,0x7000,0x20C0,0x20C0,0x20C0,0x20C0\r
+        .word   0x20C0,0x20C0,0x20C0,0x20C0,0x51CF,0xFFEE,0x3B7C,0x0000\r
+        .word   0x1200,0x7E0A,0x51CF,0xFFFE,0x43F9,0x00A1,0x5100,0x7000\r
+        .word   0x2340,0x0020,0x2340,0x0024,0x1B7C,0x0003,0x5101,0x2E79\r
+        .word   0x0088,0x0000,0x0891,0x0007,0x66FA,0x7000,0x3340,0x0002\r
+        .word   0x3340,0x0004,0x3340,0x0006,0x2340,0x0008,0x2340,0x000C\r
+        .word   0x3340,0x0010,0x3340,0x0030,0x3340,0x0032,0x3340,0x0038\r
+        .word   0x3340,0x0080,0x3340,0x0082,0x08A9,0x0000,0x008B,0x66F8\r
+        .word   0x6100,0xFF12,0x08E9,0x0000,0x008B,0x67F8,0x6100,0xFF06\r
+        .word   0x08A9,0x0000,0x008B,0x6100,0xFF3C,0x303C,0x0040,0x2229\r
+        .word   0x0020,0x0C81,0x5351,0x4552,0x6700,0x0092,0x303C,0x0080\r
+        .word   0x2229,0x0020,0x0C81,0x5344,0x4552,0x6700,0x0080,0x21FC\r
+        .word   0x0088,0x02A2,0x0070,0x303C,0x0002,0x7200,0x122D,0x0001\r
+        .word   0x1429,0x0080,0xE14A,0x8242,0x0801,0x000F,0x660A,0x0801\r
+        .word   0x0006,0x6700,0x0058,0x6008,0x0801,0x0006,0x6600,0x004E\r
+        .word   0x7020,0x41F9,0x0088,0x0000,0x3C28,0x018E,0x4A46,0x6700\r
+        .word   0x0010,0x3429,0x0028,0x0C42,0x0000,0x67F6,0xB446,0x662C\r
+        .word   0x7000,0x2340,0x0028,0x2340,0x002C,0x3E14,0x2C7C,0xFFFF\r
+        .word   0xFFC0,0x4CD6,0x7FF9,0x44FC,0x0000,0x6014,0x43F9,0x00A1\r
+        .word   0x5100,0x3340,0x0006,0x303C,0x8000,0x6004,0x44FC,0x0001\r
+\r
+.macro exc_stub num\r
+exc\num:\r
+       move.w #0x\num, -(%sp)\r
+       jmp pre_exception\r
+.endm\r
+\r
+exc_stub 02\r
+exc_stub 03\r
+exc_stub 04\r
+exc_stub 05\r
+exc_stub 06\r
+exc_stub 07\r
+exc_stub 08\r
+exc_stub 09\r
+exc_stub 0a\r
+exc_stub 0b\r
+exc_stub 0c\r
+exc_stub 0d\r
+exc_stub 0e\r
+exc_stub 0f\r
+exc_stub 10\r
+exc_stub 11\r
+exc_stub 12\r
+exc_stub 13\r
+exc_stub 14\r
+exc_stub 15\r
+exc_stub 16\r
+exc_stub 17\r
+exc_stub 18\r
+exc_stub 19\r
+exc_stub 1a\r
+exc_stub 1b\r
+# exc_stub 1c\r
+exc_stub 1d\r
+# exc_stub 1e\r
+exc_stub 1f\r
+exc_stub 20\r
+exc_stub 21\r
+exc_stub 22\r
+exc_stub 23\r
+exc_stub 24\r
+exc_stub 25\r
+exc_stub 26\r
+exc_stub 27\r
+exc_stub 28\r
+exc_stub 29\r
+exc_stub 2a\r
+exc_stub 2b\r
+exc_stub 2c\r
+exc_stub 2d\r
+exc_stub 2e\r
+exc_stub 2f\r
+exc_stub 30\r
+exc_stub 31\r
+exc_stub 32\r
+exc_stub 33\r
+exc_stub 34\r
+exc_stub 35\r
+exc_stub 36\r
+exc_stub 37\r
+exc_stub 38\r
+exc_stub 39\r
+exc_stub 3a\r
+exc_stub 3b\r
+exc_stub 3c\r
+exc_stub 3d\r
+exc_stub 3e\r
+exc_stub 3f\r
+\r
+.bss\r
+.align 2\r
+.global start_hvc\r
+start_hvc:\r
+    .word 0\r
+\r
+# vim:filetype=asmM68k:ts=4:sw=4:expandtab\r
diff --git a/mx/linux/Makefile b/mx/linux/Makefile
new file mode 100644 (file)
index 0000000..d97f9fb
--- /dev/null
@@ -0,0 +1,11 @@
+
+CC ?= $(CROSS)gcc
+
+CFLAGS += -Wall -O2 -ggdb -fno-strict-aliasing
+LDLIBS += -lusb
+TARGET = mx_flasher
+
+all: $(TARGET)
+
+clean:
+       $(RM) $(TARGET)
diff --git a/mx/linux/mx_flasher.c b/mx/linux/mx_flasher.c
new file mode 100644 (file)
index 0000000..1bec278
--- /dev/null
@@ -0,0 +1,1232 @@
+/*
+ * Copyright (c) 2009, Gražvydas Ignotas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the organization nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <usb.h>
+
+
+typedef unsigned char  u8;
+typedef unsigned short u16;
+typedef unsigned int   u32;
+#define array_size(x) (sizeof(x) / sizeof(x[0]))
+
+static const struct {
+       unsigned short vendor;
+       unsigned short product;
+       const char *name;
+} g_devices[] = {
+       { 0x03eb, 0x202a, "16MX+U Game Device" },
+       { 0x03eb, 0x202b, "32MX+U Game Device" },
+       { 0x03eb, 0x202c, "16MX+US Game Device" },
+       { 0x03eb, 0x202d, "32MX+UF Game Device" },
+};
+
+#define VERSION                        "0.91"
+
+//#define IO_BLK_SIZE          0x2000  /* 8K - unreliable? */
+#define IO_BLK_SIZE            0x800
+#define IO_RAM_BLK_SIZE                256
+
+#define CMD_ATM_READY          0x22
+#define CMD_SEC_GET_NAME       'G'     /* filename r/w */
+#define CMD_SEC_PUT_NAME       'P'
+#define CMD_SEC_DEVID          'L'     /* read flash device ID */
+#define CMD_SEC_ERASE          'E'
+#define CMD_SEC_READY          'C'     /* is flash ready? */
+#define CMD_SEC_READ           'R'
+#define CMD_SEC_WRITE          'W'
+#define CMD_SEC_RAM_READ       'D'     /* not implemented? */
+#define CMD_SEC_RAM_WRITE      'U'
+#define CMD_SEC_COMPAT         '$'     /* set RAM mode */
+
+/* bus controllers */
+#define CTL_DATA_BUS   0x55
+#define CTL_ADDR_BUS   0xAA
+
+#define W_COUNTER      0xA0
+#define W_CNT_WRITE    0x01
+#define W_CNT_READ     0x00
+
+#define FILENAME_ROM0  0
+#define FILENAME_ROM1  1
+#define FILENAME_RAM   2
+
+/* windows app sets to 0x80 on init
+ * checkboxes use 0x41 0x42 0x43 (?)
+ * r,w Ram/ROM uses 0x23/0x21
+ */
+#define C_MODE_4M_NORAM        0x41    /* RAM always off */
+#define C_MODE_4M_RAM  0x42    /* RAM switched by game */
+#define C_MODE_2M_RAM  0x43
+#define C_RAM_TMP_OFF  0x21
+#define C_RAM_TMP_ON   0x23
+
+typedef struct {
+       u8 magic[4];
+       u8 reserved[8];
+       u8 write_flag;
+       u8 reserved2[2];
+       u8 magic2;
+       u8 mx_cmd;
+       union {                         /* 0x11 */
+               struct {
+                       u8 which_device;
+               } dev_info;
+               struct {
+                       u8 addrb2;      /* most significant (BE) */
+                       u8 addrb1;
+                       u8 addrb0;
+                       u8 param;       /* 64 byte usb packets for i/o */
+                       u8 param2;
+               } rom_rw;
+               struct {
+                       u8 which;
+               } filename, mode;
+               struct {
+                       u8 cmd;
+                       u8 action;
+                       u8 b0;          /* LE */
+                       u8 b1;
+                       u8 b2;
+                       u8 b3;
+               } write_cnt;
+               struct {
+                       u8 which;
+                       u8 dev_id;
+               } rom_id;
+       };
+       u8 pad[8];
+} dev_cmd_t;
+
+typedef struct {
+       u8 firmware_ver[4];
+       u8 bootloader_ver[4];
+       char names[56];
+} dev_info_t;
+
+typedef struct {
+       u32 start_addr;
+       u32 end_addr;
+       u32 page_size;
+} page_table_t;
+
+static const page_table_t p_AM29LV320DB[] =
+{
+       { 0x000000, 0x00ffff, 0x002000 },
+       { 0x010000, 0x3fffff, 0x010000 },
+       { 0x000000, 0x000000, 0x000000 },
+};
+
+static const page_table_t p_AM29LV320DT[] =
+{
+       { 0x000000, 0x3effff, 0x010000 },
+       { 0x3f0000, 0x3fffff, 0x002000 },
+       { 0x000000, 0x000000, 0x000000 },
+};
+
+static const page_table_t p_2x_16[] =
+{
+       { 0x000000, 0x003fff, 0x004000 },
+       { 0x004000, 0x007fff, 0x002000 },
+       { 0x008000, 0x00ffff, 0x008000 },
+       { 0x010000, 0x1fffff, 0x010000 },
+       { 0x200000, 0x203fff, 0x004000 },
+       { 0x204000, 0x207fff, 0x002000 },
+       { 0x208000, 0x20ffff, 0x008000 },
+       { 0x210000, 0x3fffff, 0x010000 },
+       { 0x000000, 0x000000, 0x000000 },
+};
+
+/*****************************************************************************/
+
+static void prepare_cmd(dev_cmd_t *dev_cmd, u8 cmd)
+{
+       memset(dev_cmd, 0, sizeof(*dev_cmd));
+
+       memcpy(dev_cmd->magic, "USBC", 4);
+       dev_cmd->magic2 = 0x67; /* MySCSICommand, EXCOMMAND */
+       dev_cmd->mx_cmd = cmd;
+}
+
+static int write_data(struct usb_dev_handle *dev, void *data, int len)
+{
+       int ret = usb_bulk_write(dev, 0x03, data, len, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "failed to write:\n");
+               fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
+       } else if (ret != len)
+               printf("write_cmd: wrote only %d of %d bytes\n", ret, len);
+       
+       return ret;
+}
+
+static int write_cmd(struct usb_dev_handle *dev, dev_cmd_t *cmd)
+{
+       return write_data(dev, cmd, sizeof(*cmd));
+}
+
+static int read_data(struct usb_dev_handle *dev, void *buff, int size)
+{
+       int ret = usb_bulk_read(dev, 0x82, buff, size, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "failed to read:\n");
+               fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
+       }
+/*
+       else if (ret != size)
+               printf("read_data: read only %d of %d bytes\n", ret, size);
+*/
+       return ret;
+}
+
+static int read_info(struct usb_dev_handle *device, u8 ctl_id, dev_info_t *info)
+{
+       dev_cmd_t cmd;
+       int ret;
+
+       prepare_cmd(&cmd, CMD_ATM_READY);
+       cmd.dev_info.which_device = ctl_id;
+       memset(info, 0, sizeof(*info));
+
+       ret = write_cmd(device, &cmd);
+       if (ret < 0)
+               return ret;
+
+       ret = read_data(device, info, sizeof(*info));
+       if (ret < 0)
+               return ret;
+       
+       return 0;
+}
+
+static void printf_info(dev_info_t *info)
+{
+       printf(" firmware version:   %X.%X.%X%c\n", info->firmware_ver[0],
+               info->firmware_ver[1], info->firmware_ver[2], info->firmware_ver[3]);
+       printf(" bootloader version: %X.%X.%X%c\n", info->bootloader_ver[0],
+               info->bootloader_ver[1], info->bootloader_ver[2], info->bootloader_ver[3]);
+       info->names[sizeof(info->names) - 1] = 0;
+       printf(" device name:        %s\n", info->names);
+}
+
+static void print_progress(u32 done, u32 total)
+{
+       int i, step;
+
+       printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+       printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); /* 20 */
+       printf("\b\b\b\b\b\b");
+       printf("%06x/%06x |", done, total);
+
+       step = total / 20;
+       for (i = step; i <= total; i += step)
+               printf("%c", done >= i ? '=' : '-');
+       printf("| %3d%%", done * 100 / total);
+       fflush(stdout);
+}
+
+static int read_filename(struct usb_dev_handle *dev, char *dst, int len, u8 which)
+{
+       char buff[65];
+       dev_cmd_t cmd;
+       int ret;
+
+       prepare_cmd(&cmd, CMD_SEC_GET_NAME);
+       cmd.filename.which = which;
+       memset(buff, 0, sizeof(buff));
+
+       ret = write_cmd(dev, &cmd);
+       if (ret < 0)
+               return ret;
+
+       ret = read_data(dev, buff, 64);
+       if (ret < 0)
+               return ret;
+
+       strncpy(dst, buff, len);
+       dst[len - 1] = 0;
+
+       return 0;
+}
+
+static int write_filename(struct usb_dev_handle *dev, const char *fname, u8 which)
+{
+       dev_cmd_t cmd;
+       char buff[64];
+       int ret, len;
+
+       len = strlen(fname);
+       if (len > 63)
+               len = 63;
+       strncpy(buff, fname, len);
+       buff[len] = 0;
+
+       prepare_cmd(&cmd, CMD_SEC_PUT_NAME);
+       cmd.filename.which = which;
+
+       ret = write_cmd(dev, &cmd);
+       if (ret < 0)
+               return ret;
+
+       return write_data(dev, buff, len + 1);
+}
+
+static int read_erase_counter(struct usb_dev_handle *dev, u32 *val)
+{
+       dev_info_t dummy_info;
+       dev_cmd_t cmd;
+       u8 buff[4];
+       int ret;
+
+       /* must perform dummy info read here,
+        * or else device hangs after close (firmware bug?) */
+       ret = read_info(dev, CTL_DATA_BUS, &dummy_info);
+       if (ret < 0)
+               return ret;
+
+       prepare_cmd(&cmd, CMD_ATM_READY);
+       cmd.write_cnt.cmd = W_COUNTER;
+       cmd.write_cnt.action = W_CNT_READ;
+
+       ret = write_cmd(dev, &cmd);
+       if (ret < 0)
+               return ret;
+
+       ret = read_data(dev, buff, sizeof(buff));
+       if (ret < 0)
+               return ret;
+
+       *val = *(u32 *)buff;
+       return 0;
+}
+
+static int read_flash_rom_id(struct usb_dev_handle *dev, int is_second, u32 *val)
+{
+       dev_cmd_t cmd;
+       u8 buff[2];
+       int ret;
+
+       prepare_cmd(&cmd, CMD_SEC_DEVID);
+       cmd.rom_id.which = is_second ? 0x10 : 0;
+       cmd.rom_id.dev_id = 0;
+
+       ret = write_cmd(dev, &cmd);
+       if (ret < 0)
+               return ret;
+
+       ret = read_data(dev, buff, sizeof(buff));
+       if (ret < 0)
+               return ret;
+
+       *val = *(u16 *)buff << 16;
+
+       cmd.rom_id.dev_id = 1;
+       ret = write_cmd(dev, &cmd);
+       if (ret < 0)
+               return ret;
+
+       ret = read_data(dev, buff, sizeof(buff));
+       if (ret < 0)
+               return ret;
+       
+       *val |= *(u16 *)buff;
+       return 0;
+}
+
+static const page_table_t *get_page_table(u32 rom_id)
+{
+       switch (rom_id) {
+       case 0x0100F922:
+               return p_AM29LV320DB;
+       case 0x0100F422:
+               return p_AM29LV320DT;
+       case 0x01004922:
+       case 0xC2004922:
+               return p_2x_16;
+       default:
+               fprintf(stderr, "unrecognized ROM id: %08x\n", rom_id);
+       }
+
+       return NULL;
+}
+
+static int get_page_size(const page_table_t *table, u32 addr, u32 *size)
+{
+       const page_table_t *t;
+       
+       for (t = table; t->end_addr != 0; t++) {
+               if (addr >= t->start_addr && addr <= t->end_addr) {
+                       *size = t->page_size;
+                       return 0;
+               }
+       }
+
+       if (addr == t[-1].end_addr + 1)
+               return 1;       /* no more */
+       
+       fprintf(stderr, "get_page_size: failed on addr %06x\n", addr);
+       return -1;
+}
+
+static int set_ram_mode(struct usb_dev_handle *dev, u8 mode)
+{
+       dev_cmd_t cmd;
+       u8 buff[2];
+       int ret;
+
+       prepare_cmd(&cmd, CMD_SEC_COMPAT);
+       cmd.write_flag = 1;
+       cmd.mode.which = mode;
+
+       ret = write_cmd(dev, &cmd);
+       if (ret < 0)
+               goto end;
+
+       ret = read_data(dev, buff, sizeof(buff));
+
+end:
+       if (ret < 0)
+               fprintf(stderr, "warning: failed to set RAM mode\n");
+       return ret;
+}
+
+/* limitations:
+ * - bytes must be multiple of 64
+ * - bytes must be less than 16k
+ * - must perform even number of reads, or dev hangs on exit (firmware bug?) */
+static int rw_dev_block(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes, int mx_cmd)
+{
+       dev_cmd_t cmd;
+       int ret;
+
+       prepare_cmd(&cmd, mx_cmd);
+       if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE)
+               cmd.write_flag = 1;
+       cmd.rom_rw.addrb2 = addr >> (16 + 1);
+       cmd.rom_rw.addrb1 = addr >> (8 + 1);
+       cmd.rom_rw.addrb0 = addr >> 1;
+       cmd.rom_rw.param = bytes / 64;
+       if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE)
+               cmd.rom_rw.param2 = 1; /* ? */
+
+       ret = write_cmd(dev, &cmd);
+       if (ret < 0)
+               return ret;
+
+       bytes &= ~63;
+
+       if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE)
+               ret = write_data(dev, buffer, bytes);
+       else
+               ret = read_data(dev, buffer, bytes);
+       if (ret < 0)
+               return ret;
+
+       if (ret != bytes)
+               fprintf(stderr, "rw_dev_block warning: done only %d/%d bytes\n", ret, bytes);
+
+       return ret;
+}
+
+static int read_write_rom(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes, int is_write)
+{
+       int mx_cmd = is_write ? CMD_SEC_WRITE : CMD_SEC_READ;
+       int total_bytes = bytes;
+       u8 *buff = buffer;
+       u8 dummy[64 * 4];
+       int count, ret;
+
+       if (addr & 1)
+               fprintf(stderr, "read_write_rom: can't handle odd address %06x, "
+                               "LSb will be ignored\n", addr);
+       if (bytes & 63)
+               fprintf(stderr, "read_write_rom: byte count must be multiple of 64, "
+                               "last %d bytes will not be handled\n", bytes & 63);
+
+       set_ram_mode(dev, C_RAM_TMP_OFF);
+
+       printf("%s flash ROM...\n", is_write ? "writing to" : "reading");
+
+       /* do i/o in blocks */
+       for (count = 0; bytes >= IO_BLK_SIZE; count++) {
+               print_progress(buff - (u8 *)buffer, total_bytes);
+
+               ret = rw_dev_block(dev, addr, buff, IO_BLK_SIZE, mx_cmd);
+               if (ret < 0)
+                       return ret;
+               buff += IO_BLK_SIZE;
+               addr += IO_BLK_SIZE;
+               bytes -= IO_BLK_SIZE;
+       }
+       print_progress(buff - (u8 *)buffer, total_bytes);
+
+       ret = 0;
+       if (bytes != 0) {
+               ret = rw_dev_block(dev, addr, buff, bytes, mx_cmd);
+               count++;
+               print_progress(total_bytes, total_bytes);
+       }
+
+       if ((count & 1) && !is_write)
+               /* work around rw_dev_block() limitation 3 (works for reads only?) */
+               rw_dev_block(dev, 0, dummy, sizeof(dummy), 0);
+
+       printf("\n");
+       return ret;
+}
+
+static int read_write_ram(struct usb_dev_handle *dev, void *buffer, int bytes, int is_write)
+{
+       int mx_cmd = is_write ? CMD_SEC_RAM_WRITE : CMD_SEC_READ;
+       int total_bytes = bytes;
+       u8 *buff = buffer;
+       u32 addr = 0x200000;
+       int i, ret = 0;
+
+       if (bytes % IO_RAM_BLK_SIZE)
+               fprintf(stderr, "read_write_ram: byte count must be multiple of %d, "
+                               "last %d bytes will not be handled\n", IO_RAM_BLK_SIZE,
+                               bytes % IO_RAM_BLK_SIZE);
+
+       set_ram_mode(dev, C_RAM_TMP_ON);
+
+       printf("%s RAM...\n", is_write ? "writing to" : "reading");
+
+       /* do i/o in blocks */
+       while (bytes >= IO_RAM_BLK_SIZE) {
+               print_progress(buff - (u8 *)buffer, total_bytes);
+
+               ret = rw_dev_block(dev, addr, buff, IO_RAM_BLK_SIZE, mx_cmd);
+               if (ret < 0)
+                       return ret;
+               buff += IO_RAM_BLK_SIZE;
+               addr += IO_RAM_BLK_SIZE;
+               bytes -= IO_RAM_BLK_SIZE;
+       }
+       print_progress(buff - (u8 *)buffer, total_bytes);
+
+       /* only D0-D7 connected.. */
+       for (i = 0; i < total_bytes; i += 2)
+               ((u8 *)buffer)[i] = 0;
+
+       printf("\n");
+       return ret;
+
+}
+
+static int increment_erase_cnt(struct usb_dev_handle *dev)
+{
+       dev_cmd_t cmd;
+       u8 buff[4];
+       u32 cnt;
+       int ret;
+
+       ret = read_erase_counter(dev, &cnt);
+       if (ret != 0)
+               return ret;
+
+       if (cnt == (u32)-1) {
+               fprintf(stderr, "flash erase counter maxed out!\n");
+               fprintf(stderr, "(wow, did you really erase so many times?)\n");
+               return -1;
+       }
+
+       cnt++;
+
+       prepare_cmd(&cmd, CMD_ATM_READY);
+       cmd.write_cnt.cmd = W_COUNTER;
+       cmd.write_cnt.action = W_CNT_WRITE;
+       cmd.write_cnt.b3 = cnt >> 24;
+       cmd.write_cnt.b2 = cnt >> 16;
+       cmd.write_cnt.b1 = cnt >> 8;
+       cmd.write_cnt.b0 = cnt;
+
+       ret = write_cmd(dev, &cmd);
+       if (ret < 0)
+               return ret;
+
+       ret = read_data(dev, buff, sizeof(buff));
+       if (ret < 0)
+               return ret;
+
+       return cnt;
+}
+
+static int erase_page(struct usb_dev_handle *dev, u32 addr, int whole)
+{
+       dev_cmd_t cmd;
+       u8 buff[5];
+       int i, ret;
+
+       prepare_cmd(&cmd, CMD_SEC_ERASE);
+       cmd.write_flag = 1;
+       cmd.rom_rw.addrb2 = addr >> (16 + 1);
+       cmd.rom_rw.addrb1 = addr >> (8 + 1);
+       cmd.rom_rw.addrb0 = addr >> 1;
+       cmd.rom_rw.param = whole ? 0x10 : 0;
+
+       ret = write_cmd(dev, &cmd);
+       if (ret < 0)
+               return ret;
+
+       ret = read_data(dev, buff, sizeof(buff));
+       if (ret < 0)
+               return ret;
+       
+       prepare_cmd(&cmd, CMD_SEC_READY);
+       cmd.rom_rw.addrb2 = addr >> (16 + 1);
+       cmd.rom_rw.addrb1 = addr >> (8 + 1);
+       cmd.rom_rw.addrb0 = addr >> 1;
+
+       for (i = 0; i < 100; i++) {
+               ret = write_cmd(dev, &cmd);
+               if (ret < 0)
+                       return ret;
+
+               ret = read_data(dev, buff, sizeof(buff));
+               if (ret < 0)
+                       return ret;
+
+               if (ret > 4 && buff[4] == 1)
+                       break;
+
+               usleep((whole ? 600 : 20) * 1000);
+       }
+
+       if (i == 100) {
+               fprintf(stderr, "\ntimeout waiting for erase to complete\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int erase_seq(struct usb_dev_handle *dev, u32 size)
+{
+       const page_table_t *table;
+       u32 addr, page_size = 0;
+       u32 rom0_id, rom1_id;
+       int count, ret;
+
+       ret = read_flash_rom_id(dev, 0, &rom0_id);
+       if (ret < 0)
+               return ret;
+
+       ret = read_flash_rom_id(dev, 1, &rom1_id);
+       if (ret < 0)
+               return ret;
+
+       if (rom0_id != rom1_id)
+               fprintf(stderr, "Warning: flash ROM ids differ: %08x %08x\n",
+                       rom0_id, rom1_id);
+
+       table = get_page_table(rom0_id);
+       if (table == NULL)
+               return -1;
+
+       ret = increment_erase_cnt(dev);
+       if (ret < 0)
+               fprintf(stderr, "warning: coun't increase erase counter\n");
+
+       printf("erasing flash... (erase count=%u)\n", ret);
+
+       for (addr = 0, count = 0; addr < size; addr += page_size, count++) {
+               print_progress(addr, size);
+
+               ret = erase_page(dev, addr, 0);
+               if (ret < 0)
+                       return ret;
+
+               ret = get_page_size(table, addr, &page_size);
+               if (ret != 0)
+                       break;
+       }
+
+       if (count & 1)
+               /* ??? */
+               /* must submit even number of erase commands (fw bug?) */
+               erase_page(dev, 0, 0);
+
+       print_progress(addr, size);
+       printf("\n");
+
+       return ret;
+}
+
+static int erase_all(struct usb_dev_handle *dev, u32 size)
+{
+       int ret;
+
+       ret = increment_erase_cnt(dev);
+       if (ret < 0)
+               fprintf(stderr, "warning: couldn't increase erase counter\n");
+
+       printf("erasing flash0, count=%u ...", ret);
+       fflush(stdout);
+
+       ret = erase_page(dev, 0xaaa, 1);
+       if (ret != 0)
+               return ret;
+
+       if (size > 0x200000) {
+               printf(" done.\n");
+               printf("erasing flash1...");
+               fflush(stdout);
+
+               ret = erase_page(dev, 0x200aaa, 1);
+       }
+
+       printf(" done.\n");
+       return ret;
+}
+
+static int print_device_info(struct usb_dev_handle *dev)
+{
+       u32 counter, rom0_id, rom1_id;
+       dev_info_t info;
+       int ret;
+
+       printf("data bus controller:\n");
+       ret = read_info(dev, CTL_DATA_BUS, &info);
+       if (ret < 0)
+               return ret;
+       printf_info(&info);
+
+       printf("address bus controller:\n");
+       ret = read_info(dev, CTL_ADDR_BUS, &info);
+       if (ret < 0)
+               return ret;
+       printf_info(&info);
+
+       ret = read_erase_counter(dev, &counter);
+       if (ret < 0)
+               return ret;
+       printf("flash erase count:   %u\n", counter);
+
+       ret = read_flash_rom_id(dev, 0, &rom0_id);
+       if (ret < 0)
+               return ret;
+       printf("flash rom0 id:       %08x\n", rom0_id);
+
+       ret = read_flash_rom_id(dev, 1, &rom1_id);
+       if (ret < 0)
+               return ret;
+       printf("flash rom1 id:       %08x\n", rom1_id);
+
+       return 0;
+}
+
+static int print_game_info(struct usb_dev_handle *dev)
+{
+       char fname[65];
+       int ret;
+
+       ret = read_filename(dev, fname, sizeof(fname), FILENAME_ROM0);
+       if (ret < 0)
+               return ret;
+       printf("ROM filename:  %s\n", fname);
+
+       ret = read_filename(dev, fname, sizeof(fname), FILENAME_RAM);
+       if (ret < 0)
+               return ret;
+       printf("SRAM filename: %s\n", fname);
+
+       return 0;
+}
+
+static int read_file(const char *fname, void **buff_out, int *size, int limit)
+{
+       int file_size, ret;
+       void *data;
+       FILE *file;
+
+       file = fopen(fname, "rb");
+       if (file == NULL) {
+               fprintf(stderr, "can't open file: %s\n", fname);
+               return -1;
+       }
+
+       fseek(file, 0, SEEK_END);
+       file_size = ftell(file);
+       fseek(file, 0, SEEK_SET);
+       if (file_size > limit)
+               fprintf(stderr, "warning: input file \"%s\" too large\n", fname);
+       if (file_size < 0) {
+               fprintf(stderr, "bad/empty file: %s\n", fname);
+               goto fail;
+       }
+
+       data = malloc(file_size);
+       if (data == NULL) {
+               fprintf(stderr, "low memory\n");
+               goto fail;
+       }
+
+       ret = fread(data, 1, file_size, file);
+       if (ret != file_size) {
+               fprintf(stderr, "failed to read file: %s", fname);
+               perror("");
+               goto fail;
+       }
+
+       *buff_out = data;
+       *size = file_size;
+       fclose(file);
+       return 0;
+
+fail:
+       fclose(file);
+       return -1;
+}
+
+static int write_file(const char *fname, void *buff, int size)
+{
+       FILE *file;
+       int ret;
+
+       file = fopen(fname, "wb");
+       if (file == NULL) {
+               fprintf(stderr, "can't open for writing: %s\n", fname);
+               return -1;
+       }
+
+       ret = fwrite(buff, 1, size, file);
+       if (ret != size) {
+               fprintf(stderr, "write failed to %s", fname);
+               perror("");
+       } else
+               printf("saved to \"%s\".\n", fname);
+       fclose(file);
+       
+       return 0;
+}
+
+static usb_dev_handle *get_device(void)
+{
+       struct usb_dev_handle *handle;
+       struct usb_device *dev;
+       struct usb_bus *bus;
+       int i, ret;
+
+       ret = usb_find_busses();
+       if (ret <= 0) {
+               fprintf(stderr, "Can't find USB busses\n");
+               return NULL;
+       }
+
+       ret = usb_find_devices();
+       if (ret <= 0) {
+               fprintf(stderr, "Can't find USB devices\n");
+               return NULL;
+       }
+
+       bus = usb_get_busses();
+       for (; bus; bus = bus->next)
+       {
+               for (dev = bus->devices; dev; dev = dev->next)
+               {
+                       for (i = 0; i < array_size(g_devices); i++)
+                       {
+                               if (dev->descriptor.idVendor == g_devices[i].vendor &&
+                                               dev->descriptor.idProduct == g_devices[i].product)
+                                       goto found;
+                       }
+               }
+       }
+
+       fprintf(stderr, "device not found.\n");
+       return NULL;
+
+found:
+       printf("found %s.\n", g_devices[i].name);
+
+       handle = usb_open(dev);
+       if (handle == NULL) {
+               fprintf(stderr, "failed to open device:\n");
+               fprintf(stderr, "%s\n", usb_strerror());
+               return NULL;
+       }
+
+       ret = usb_set_configuration(handle, 1);
+       if (ret != 0) {
+               fprintf(stderr, "couldn't set configuration for /*/bus/usb/%s/%s:\n",
+                       bus->dirname, dev->filename);
+               fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
+               return NULL;
+       }
+
+       ret = usb_claim_interface(handle, 0);
+       if (ret != 0) {
+               fprintf(stderr, "couldn't claim /*/bus/usb/%s/%s:\n",
+                       bus->dirname, dev->filename);
+               fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
+               return NULL;
+       }
+
+       return handle;
+}
+
+static void release_device(struct usb_dev_handle *device)
+{
+       usb_release_interface(device, 0);
+       usb_close(device);
+}
+
+static void usage(const char *app_name)
+{
+       printf("Flasher tool for MX game devices\n"
+               "written by Grazvydas \"notaz\" Ignotas\n");
+       printf("v" VERSION " (" __DATE__ ")\n\n");
+       printf("Usage:\n"
+               "%s [-i] [-g] [-e] [-r [file]] [-w <file>] ...\n"
+               "  -i         print some info about connected device\n"
+               "  -g         print some info about game ROM inside device\n"
+               "  -e[1]      erase whole flash ROM in device, '1' uses different erase method\n"
+               "  -m[1-3]    set MX mode: 2M+RAM, 4M no RAM, 4M+RAM\n"
+               "  -f         skip file check\n"
+               "  -r [file]  copy game image from device to file; can autodetect filename\n"
+               "  -w <file>  write file to device; also does erase\n"
+               "  -sr [file] read save RAM to file\n"
+               "  -sw <file> write save RAM file to device\n"
+               "  -sc        clear save RAM\n"
+               "  -v         with -w or -sw: verify written file\n",
+               app_name);
+}
+
+int main(int argc, char *argv[])
+{
+       char *r_fname = NULL, *w_fname = NULL, *sr_fname = NULL, *sw_fname = NULL;
+       void *r_fdata = NULL, *w_fdata = NULL, *sr_fdata = NULL, *sw_fdata = NULL;
+       int do_read_ram = 0, do_clear_ram = 0, do_verify = 0, do_check = 1;
+       int pr_dev_info = 0, pr_rom_info = 0, do_read = 0, mx_mode = 0;
+       int erase_method = 0, do_erase_size = 0;
+       int w_fsize = 0, sw_fsize = 0;
+       struct usb_dev_handle *device;
+       char fname_buff[65];
+       int i, ret = 0;
+
+       for (i = 1; i < argc; i++)
+       {
+               if (argv[i][0] != '-')
+                       break;
+
+               switch (argv[i][1]) {
+               case 'i':
+                       pr_dev_info = 1;
+                       break;
+               case 'g':
+                       pr_rom_info = 1;
+                       break;
+               case 'e':
+                       do_erase_size = 0x400000;
+                       if (argv[i][2] == '1')
+                               erase_method = 1;
+                       break;
+               case 'f':
+                       do_check = 0;
+                       break;
+               case 'v':
+                       do_verify = 1;
+                       break;
+               case 'm':
+                       mx_mode = argv[i][2];
+                       break;
+               case 'r':
+                       do_read = 1;
+                       if (argv[i+1] && argv[i+1][0] != '-')
+                               r_fname = argv[++i];
+                       break;
+               case 'w':
+                       if (argv[i+1] && argv[i+1][0] != '-')
+                               w_fname = argv[++i];
+                       else
+                               goto breakloop;
+                       break;
+               case 's':
+                       switch (argv[i][2]) {
+                       case 'r':
+                               do_read_ram = 1;
+                               if (argv[i+1] && argv[i+1][0] != '-')
+                                       sr_fname = argv[++i];
+                               break;
+                       case 'w':
+                               if (argv[i+1] && argv[i+1][0] != '-')
+                                       sw_fname = argv[++i];
+                               else
+                                       goto breakloop;
+                               break;
+                       case 'c':
+                               do_clear_ram = 1;
+                               break;
+                       default:
+                               goto breakloop;
+                       }
+                       break;
+               default:
+                       goto breakloop;
+               }
+       }
+
+breakloop:
+       if (i <= 1 || i < argc) {
+               usage(argv[0]);
+               return 1;
+       }
+
+       /* preparations */
+       if (w_fname != NULL) {
+               /* check extension */
+               ret = strlen(w_fname);
+               if (do_check && (w_fname[ret - 4] == '.' || w_fname[ret - 3] == '.' ||
+                               w_fname[ret - 2] == '.') &&
+                               strcasecmp(&w_fname[ret - 4], ".gen") != 0 &&
+                               strcasecmp(&w_fname[ret - 4], ".bin") != 0 &&
+                               strcasecmp(&w_fname[ret - 4], ".32x") != 0) {
+                       fprintf(stderr, "\"%s\" doesn't look like a game ROM, aborting "
+                                       "(use -f to disable this check)\n", w_fname);
+                       return 1;
+               }
+
+               ret = read_file(w_fname, &w_fdata, &w_fsize, 0x400000);
+               if (ret < 0)
+                       return 1;
+
+               /* align size to 64 */
+               ret = (w_fsize + 63) & ~63;
+               if (w_fsize != ret) {
+                       printf("ROM image size is %d, padding to %d\n", w_fsize, ret);
+                       w_fdata = realloc(w_fdata, ret);
+                       if (w_fdata == NULL) {
+                               fprintf(stderr, "low mem\n");
+                               return 1;
+                       }
+                       memset((char *)w_fdata + w_fsize, 0, ret - w_fsize);
+                       w_fsize = ret;
+               }
+
+               if (do_erase_size < w_fsize)
+                       do_erase_size = w_fsize;
+       }
+       if (sw_fname != NULL) {
+               ret = read_file(sw_fname, &sw_fdata, &sw_fsize, 0x8000*2);
+               if (ret < 0)
+                       return 1;
+       }
+       if (sw_fdata != NULL || do_clear_ram) {
+               if (sw_fsize < 0x8000*2) {
+                       sw_fdata = realloc(sw_fdata, 0x8000*2);
+                       if (sw_fdata == NULL) {
+                               fprintf(stderr, "low mem\n");
+                               return 1;
+                       }
+                       memset((u8 *)sw_fdata + sw_fsize, 0, 0x8000*2 - sw_fsize);
+               }
+               sw_fsize = 0x8000*2;
+       }
+       if (w_fname == NULL && sw_fname == NULL && do_verify) {
+               fprintf(stderr, "warning: -w or -sw not specified, -v ignored.\n");
+               do_verify = 0;
+       }
+
+       /* init */
+       usb_init();
+
+       device = get_device();
+       if (device == NULL)
+               return 1;
+
+       /* info */
+       if (pr_dev_info) {
+               ret = print_device_info(device);
+               if (ret < 0)
+                       goto end;
+       }
+
+       if (pr_rom_info) {
+               ret = print_game_info(device);
+               if (ret < 0)
+                       goto end;
+       }
+
+       /* erase */
+       if (do_erase_size != 0) {
+               if (erase_method)
+                       ret = erase_all(device, do_erase_size);
+               else
+                       ret = erase_seq(device, do_erase_size);
+               if (ret < 0)
+                       goto end;
+       }
+
+       /* write flash */
+       if (w_fdata != NULL) {
+               char *p;
+
+               ret = read_write_rom(device, 0, w_fdata, w_fsize, 1);
+               if (ret < 0)
+                       goto end;
+
+               p = strrchr(w_fname, '/');
+               p = (p == NULL) ? w_fname : p + 1;
+
+               ret = write_filename(device, p, FILENAME_ROM0);
+               if (ret < 0)
+                       fprintf(stderr, "warning: failed to save ROM filename\n");
+       }
+
+       /* write ram */
+       if (sw_fdata != NULL) {
+               char *p, *t;
+
+               ret = read_write_ram(device, sw_fdata, sw_fsize, 1);
+               if (ret < 0)
+                       goto end;
+
+               memset(fname_buff, 0, sizeof(fname_buff));
+               p = fname_buff;
+               if (sw_fname != NULL) {
+                       p = strrchr(sw_fname, '/');
+                       p = (p == NULL) ? sw_fname : p + 1;
+               } else if (w_fname != NULL) {
+                       t = strrchr(w_fname, '/');
+                       t = (t == NULL) ? w_fname : t + 1;
+
+                       strncpy(fname_buff, t, sizeof(fname_buff));
+                       fname_buff[sizeof(fname_buff) - 1] = 0;
+                       ret = strlen(fname_buff);
+                       if (ret > 4 && fname_buff[ret - 4] == '.')
+                               strcpy(&fname_buff[ret - 4], ".srm");
+               }
+
+               ret = write_filename(device, p, FILENAME_RAM);
+               if (ret < 0)
+                       fprintf(stderr, "warning: failed to save RAM filename\n");
+       }
+
+       /* set mode */
+       if (mx_mode || w_fsize > 0x200000) {
+               if (mx_mode == 0)
+                       mx_mode = '3';
+               printf("MX mode set to ");
+               switch (mx_mode) {
+               case '1':
+                       printf("2M with RAM.\n");
+                       mx_mode = C_MODE_2M_RAM;
+                       break;
+               case '2':
+                       printf("4M, no RAM.\n");
+                       mx_mode = C_MODE_4M_NORAM;
+                       break;
+               default:
+                       printf("4M with RAM.\n");
+                       mx_mode = C_MODE_4M_RAM;
+                       break;
+               }
+               set_ram_mode(device, mx_mode);
+       }
+
+       /* read flash */
+       if (do_read && r_fname == NULL) {
+               ret = read_filename(device, fname_buff, sizeof(fname_buff), FILENAME_ROM0);
+               if (ret < 0)
+                       return ret;
+               r_fname = fname_buff;
+               if (r_fname[0] == 0)
+                       r_fname = "rom.gen";
+       }
+
+       if (r_fname != NULL || do_verify) {
+               r_fdata = malloc(0x400000);
+               if (r_fdata == NULL) {
+                       fprintf(stderr, "low mem\n");
+                       goto end;
+               }
+
+               ret = read_write_rom(device, 0, r_fdata, 0x400000, 0);
+               if (ret < 0)
+                       goto end;
+       }
+
+       if (r_fname != NULL)
+               write_file(r_fname, r_fdata, 0x400000);
+
+       /* read ram */
+       if (do_read_ram && sr_fname == NULL) {
+               ret = read_filename(device, fname_buff, sizeof(fname_buff), FILENAME_RAM);
+               if (ret < 0)
+                       return ret;
+               sr_fname = fname_buff;
+               if (sr_fname[0] == 0)
+                       sr_fname = "rom.srm";
+       }
+
+       if (sr_fname != NULL || do_verify) {
+               sr_fdata = malloc(0x8000*2);
+               if (sr_fdata == NULL) {
+                       fprintf(stderr, "low mem\n");
+                       goto end;
+               }
+
+               ret = read_write_ram(device, sr_fdata, 0x8000*2, 0);
+               if (ret < 0)
+                       goto end;
+       }
+
+       if (sr_fname != NULL)
+               write_file(sr_fname, sr_fdata, 0x8000*2);
+
+       /* verify */
+       if (do_verify && w_fdata != NULL && r_fdata != NULL) {
+               ret = memcmp(w_fdata, r_fdata, w_fsize);
+               if (ret == 0)
+                       printf("flash verification passed.\n");
+               else
+                       printf("flash verification FAILED!\n");
+       }
+
+       if (do_verify && sw_fdata != NULL && sr_fdata != NULL) {
+               ret = memcmp(sw_fdata, sr_fdata, 0x8000*2);
+               if (ret == 0)
+                       printf("RAM verification passed.\n");
+               else
+                       printf("RAM verification FAILED!\n");
+       }
+
+       printf("all done.\n");
+       ret = 0;
+
+end:
+       if (w_fdata != NULL)
+               free(w_fdata);
+       if (r_fdata != NULL)
+               free(r_fdata);
+
+       release_device(device);
+
+       return ret;
+}
+
diff --git a/mx/linux/sms2mx.c b/mx/linux/sms2mx.c
new file mode 100644 (file)
index 0000000..6b084ea
--- /dev/null
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <string.h>
+
+#define IN_SIZE                0x8000
+#define OUT_SIZE       0x400000
+static unsigned char buff[OUT_SIZE], buff_in[IN_SIZE];
+
+int main(int argc, char *argv[])
+{
+       FILE *fi, *fo;
+       int size, bsize;
+       int i, o;
+
+       if (argc != 3) {
+               fprintf(stderr, "usage:\n%s <sms ROM> <mx img>\n", argv[0]);
+               return 1;
+       }
+
+       fi = fopen(argv[1], "rb");
+       if (fi == NULL) {
+               fprintf(stderr, "can't open: %s\n", argv[1]);
+               return 1;
+       }
+
+       fo = fopen(argv[2], "wb");
+       if (fo == NULL) {
+               fprintf(stderr, "can't open: %s\n", argv[2]);
+               return 1;
+       }
+
+       fseek(fi, 0, SEEK_END);
+       size = ftell(fi);
+       fseek(fi, 0, SEEK_SET);
+
+       if (size > IN_SIZE) {
+               fprintf(stderr, "ROMs > 32k won't work\n");
+               size = IN_SIZE;
+       }
+
+       if (fread(buff_in, 1, size, fi) != size)
+               fprintf(stderr, "failed to read %s\n", argv[1]);
+
+       memset(buff, 0, sizeof(buff));
+
+       for (bsize = 1; bsize < size; bsize <<= 1)
+               ;
+
+       for (i = o = 0; o < sizeof(buff); i = (i + 1) & (bsize - 1), o += 2)
+               buff[o+1] = buff_in[i];
+
+       if (fwrite(buff, 1, OUT_SIZE, fo) != OUT_SIZE)
+               fprintf(stderr, "failed to write to %s\n", argv[2]);
+       fclose(fi);
+       fclose(fo);
+
+       return 0;
+}
+
diff --git a/nshtest/Makefile b/nshtest/Makefile
new file mode 100644 (file)
index 0000000..bfe4a04
--- /dev/null
@@ -0,0 +1,21 @@
+CROSS = m68k-elf-\r
+AS = $(CROSS)as\r
+LD = $(CROSS)ld\r
+OBJCOPY = $(CROSS)objcopy\r
+\r
+ASFLAGS = -m68000 --register-prefix-optional --bitwise-or \r
+\r
+TARGET = nshtest.bin\r
+OBJS = sega_gcc.o test.o\r
+\r
+all : $(TARGET)\r
+\r
+$(TARGET) : a.out\r
+       $(OBJCOPY) -I elf32-m68k -O binary $^ $@\r
+\r
+a.out : $(OBJS)\r
+       $(LD) -Tmd.ld -Map $(TARGET).map $^\r
+\r
+clean:\r
+       $(RM) $(TARGET) $(OBJS) $(TARGET).map a.out\r
+\r
diff --git a/nshtest/md.ld b/nshtest/md.ld
new file mode 100644 (file)
index 0000000..208bfa7
--- /dev/null
@@ -0,0 +1,122 @@
+OUTPUT_ARCH(m68k)\r
+SEARCH_DIR(.)\r
+/*GROUP(-lbcc -lc -lgcc)*/\r
+__DYNAMIC  =  0;\r
+\r
+/*\r
+ * Setup the memory map of the SEGA Genesis.\r
+ * stack grows down from high memory.\r
+ *\r
+ * The memory map look like this:\r
+ * +--------------------+ <- low memory\r
+ * | .text              |\r
+ * |        _etext      |\r
+ * |        ctor list   | the ctor and dtor lists are for\r
+ * |        dtor list   | C++ support\r
+ * +--------------------+\r
+ * | .data              | initialized data goes here\r
+ * |        _edata      |\r
+ * +--------------------+\r
+ * | .bss               |\r
+ * |        __bss_start | start of bss, cleared by crt0\r
+ * |        _end        | start of heap, used by sbrk()\r
+ * +--------------------+\r
+ * .                    .\r
+ * .                    .\r
+ * .                    .\r
+ * |        __stack     | top of stack\r
+ * +--------------------+\r
+ */\r
+/*\r
+MEMORY\r
+{\r
+  rom     : ORIGIN = 0x00000000, LENGTH = 0x00400000\r
+  ram     : ORIGIN = 0xffff0000, LENGTH = 0x00010000\r
+}\r
+*/\r
+\r
+MEMORY {\r
+       ram : ORIGIN = 0x0, LENGTH = 0xfffffff\r
+}\r
+\r
+/*\r
+ * allocate the stack to be at the top of memory, since the stack\r
+ * grows down\r
+ */\r
+\r
+PROVIDE (__stack = 0x00fffff0);\r
+\r
+PROVIDE (ram = 0xffff0000);\r
+/*\r
+ * Initalize some symbols to be zero so we can reference them in the\r
+ * crt0 without core dumping. These functions are all optional, but\r
+ * we do this so we can have our crt0 always use them if they exist. \r
+ * This is so BSPs work better when using the crt0 installed with gcc.\r
+ * We have to initalize them twice, so we cover a.out (which prepends\r
+ * an underscore) and coff object file formats.\r
+ */\r
+PROVIDE (hardware_init_hook = 0);\r
+PROVIDE (_hardware_init_hook = 0);\r
+PROVIDE (software_init_hook = 0);\r
+PROVIDE (_software_init_hook = 0);\r
+\r
+SECTIONS\r
+{\r
+  .text 0x00000000:\r
+  {\r
+    *(.text)\r
+    . = ALIGN(0x4);\r
+     __CTOR_LIST__ = .;\r
+    LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)\r
+    *(.ctors)\r
+    LONG(0)\r
+    __CTOR_END__ = .;\r
+    __DTOR_LIST__ = .;\r
+    LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)\r
+    *(.dtors)\r
+     LONG(0)\r
+    __DTOR_END__ = .;\r
+    *(.rodata)\r
+    *(.gcc_except_table) \r
+\r
+    __INIT_SECTION__ = . ;\r
+    *(.init)\r
+    SHORT (0x4e75)     /* rts */\r
+\r
+    __FINI_SECTION__ = . ;\r
+    *(.fini)\r
+    SHORT (0x4e75)     /* rts */\r
+\r
+    _etext = .;\r
+    *(.lit)\r
+  } > ram\r
+\r
+  .data BLOCK (0x4) :\r
+  {\r
+    *(.shdata)\r
+    *(.data)\r
+    _edata = .;\r
+  } > ram\r
+\r
+  .bss 0xff0000 :\r
+  {\r
+    __bss_start = . ;\r
+    *(.shbss)\r
+    *(.bss)\r
+    *(COMMON)\r
+    *(.eh_fram)\r
+    *(.eh_frame)\r
+    _end =  ALIGN (0x8);\r
+    __end = _end;\r
+  } > ram\r
+\r
+  .stab 0 (NOLOAD) :\r
+  {\r
+    *(.stab)\r
+  }\r
+\r
+  .stabstr 0 (NOLOAD) :\r
+  {\r
+    *(.stabstr)\r
+  }\r
+}\r
diff --git a/nshtest/sega_gcc.s b/nshtest/sega_gcc.s
new file mode 100644 (file)
index 0000000..a295692
--- /dev/null
@@ -0,0 +1,443 @@
+*-------------------------------------------------------\r
+*\r
+*       Sega startup code for the GNU Assembler\r
+*       Translated from:\r
+*       Sega startup code for the Sozobon C compiler\r
+*       Written by Paul W. Lee\r
+*       Modified from Charles Coty's code\r
+*\r
+*-------------------------------------------------------\r
+\r
+        dc.l 0x0,0x200\r
+        dc.l INT,INT,INT,INT,INT,INT,INT\r
+        dc.l INT,INT,INT,INT,INT,INT,INT,INT\r
+        dc.l INT,INT,INT,INT,INT,INT,INT,INT\r
+        dc.l INT,INT,INT,HBL,INT,VBL,INT,INT\r
+        dc.l INT,INT,INT,INT,INT,INT,INT,INT\r
+        dc.l INT,INT,INT,INT,INT,INT,INT,INT\r
+        dc.l INT,INT,INT,INT,INT,INT,INT,INT\r
+        dc.l INT,INT,INT,INT,INT,INT,INT\r
+        .ascii "SEGA GENESIS                    "\r
+        .ascii "notaz's Shadow / Hilight test                   "\r
+        .ascii "NOTAZ'S SHADOW HILIGHT TEST                     "\r
+        .ascii "GM 00000000-00"\r
+        .byte 0xa5,0xfb\r
+        .ascii "JD              "\r
+        .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00\r
+        .byte 0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff\r
+        .ascii "               "\r
+        .ascii "                        "\r
+        .ascii "                         "\r
+        .ascii "JUE             "\r
+*debugee:\r
+*        bra     debugee\r
+        tst.l   0xa10008\r
+       bne     SkipJoyDetect                               \r
+        tst.w   0xa1000c\r
+SkipJoyDetect:\r
+       bne     SkipSetup\r
+        lea     Table,%a5                       \r
+        movem.w (%a5)+,%d5-%d7\r
+        movem.l (%a5)+,%a0-%a4                       \r
+* Check Version Number                      \r
+        move.b  -0x10ff(%a1),%d0\r
+        andi.b  #0x0f,%d0                             \r
+       beq     WrongVersion                                   \r
+* Sega Security Code (SEGA)   \r
+        move.l  #0x53454741,0x2f00(%a1)\r
+WrongVersion:\r
+        move.w  (%a4),%d0\r
+        moveq   #0x00,%d0                                \r
+        movea.l %d0,%a6                                  \r
+        move    %a6,%usp\r
+* Set VDP registers\r
+        moveq   #0x17,%d1\r
+FillLoop:                           \r
+        move.b  (%a5)+,%d5\r
+        move.w  %d5,(%a4)                              \r
+        add.w   %d7,%d5                                 \r
+        dbra    %d1,FillLoop                           \r
+        move.l  (%a5)+,(%a4)                            \r
+        move.w  %d0,(%a3)                                 \r
+        move.w  %d7,(%a1)                                 \r
+        move.w  %d7,(%a2)                                 \r
+L0250:\r
+        btst    %d0,(%a1)\r
+       bne     L0250                                   \r
+* Put initial values into a00000                \r
+        moveq   #0x25,%d2\r
+Filla:                                 \r
+        move.b  (%a5)+,(%a0)+\r
+        dbra    %d2,Filla\r
+        move.w  %d0,(%a2)                                 \r
+        move.w  %d0,(%a1)                                 \r
+        move.w  %d7,(%a2)                                 \r
+L0262:\r
+        move.l  %d0,-(%a6)\r
+        dbra    %d6,L0262                            \r
+        move.l  (%a5)+,(%a4)                              \r
+        move.l  (%a5)+,(%a4)                              \r
+* Put initial values into c00000                  \r
+        moveq   #0x1f,%d3\r
+Filc0:                             \r
+        move.l  %d0,(%a3)\r
+        dbra    %d3,Filc0\r
+        move.l  (%a5)+,(%a4)                              \r
+* Put initial values into c00000                 \r
+        moveq   #0x13,%d4\r
+Fillc1:                            \r
+        move.l  %d0,(%a3)\r
+        dbra    %d4,Fillc1\r
+* Put initial values into c00011                 \r
+        moveq   #0x03,%d5\r
+Fillc2:                            \r
+        move.b  (%a5)+,0x0011(%a3)        \r
+        dbra    %d5,Fillc2                            \r
+        move.w  %d0,(%a2)                                 \r
+        movem.l (%a6),%d0-%d7/%a0-%a6                    \r
+        move    #0x2700,%sr                           \r
+SkipSetup:\r
+       bra     Continue\r
+Table:\r
+        dc.w    0x8000, 0x3fff, 0x0100, 0x00a0, 0x0000, 0x00a1, 0x1100, 0x00a1\r
+        dc.w    0x1200, 0x00c0, 0x0000, 0x00c0, 0x0004, 0x0414, 0x302c, 0x0754\r
+        dc.w    0x0000, 0x0000, 0x0000, 0x812b, 0x0001, 0x0100, 0x00ff, 0xff00                                   \r
+        dc.w    0x0080, 0x4000, 0x0080, 0xaf01, 0xd91f, 0x1127, 0x0021, 0x2600\r
+        dc.w    0xf977, 0xedb0, 0xdde1, 0xfde1, 0xed47, 0xed4f, 0xd1e1, 0xf108                                   \r
+        dc.w    0xd9c1, 0xd1e1, 0xf1f9, 0xf3ed, 0x5636, 0xe9e9, 0x8104, 0x8f01                \r
+        dc.w    0xc000, 0x0000, 0x4000, 0x0010, 0x9fbf, 0xdfff                                \r
+\r
+Continue:\r
+        tst.w    0x00C00004\r
+\r
+* set stack pointer\r
+*        clr.l   %a7\r
+        move.w   #0,%a7\r
+\r
+* user mode\r
+        move.w  #0x2300,%sr\r
+\r
+* clear Genesis RAM\r
+        lea     0xff0000,%a0\r
+        moveq   #0,%d0\r
+clrram: move.w  #0,(%a0)+\r
+        subq.w  #2,%d0\r
+       bne     clrram\r
+\r
+*----------------------------------------------------------        \r
+*\r
+*       Load driver into the Z80 memory\r
+*\r
+*----------------------------------------------------------        \r
+\r
+* halt the Z80\r
+        move.w  #0x100,0xa11100\r
+* reset it\r
+        move.w  #0x100,0xa11200\r
+\r
+        lea     Z80Driver,%a0\r
+        lea     0xa00000,%a1\r
+        move.l  #Z80DriverEnd,%d0\r
+        move.l  #Z80Driver,%d1\r
+        sub.l   %d1,%d0\r
+Z80loop:\r
+        move.b  (%a0)+,(%a1)+\r
+        subq.w  #1,%d0\r
+       bne     Z80loop\r
+\r
+* enable the Z80\r
+        move.w  #0x0,0xa11100\r
+\r
+*----------------------------------------------------------        \r
+        jmp      main\r
+\r
+INT:    \r
+       rte\r
+\r
+HBL:\r
+        /* addq.l   #1,htimer */\r
+       rte\r
+\r
+VBL:\r
+        /* addq.l   #1,vtimer */\r
+        move.l #vtimer,a0\r
+        addq.l #1,(a0)\r
+       rte\r
+\r
+*------------------------------------------------\r
+*\r
+*       Get a random number.  This routine\r
+*       was found in TOS.\r
+*\r
+*       Output\r
+*       ------\r
+*       d0 = random number\r
+*\r
+*------------------------------------------------\r
+\r
+        .globl  random\r
+\r
+random:\r
+                move.l      rand_num,%d0\r
+                tst.l       %d0\r
+                bne         .L1\r
+                moveq       #16,%d1\r
+                lsl.l       %d1,%d0\r
+                or.l        htimer,%d0\r
+                move.l      %d0,rand_num\r
+.L1:\r
+                move.l      #-1153374675,-(%sp)\r
+                move.l      rand_num,-(%sp)\r
+                bsr         lmul\r
+                addq.w      #8,%sp\r
+                addq.l      #1,%d0\r
+                move.l      %d0,rand_num\r
+\r
+                lsr.l       #8,%d0\r
+                and.l       #16777215,%d0\r
+                rts\r
+\r
+\r
+*------------------------------------------------\r
+*\r
+* Copyright (c) 1988 by Sozobon, Limited.  Author: Johann Ruegg\r
+*\r
+* Permission is granted to anyone to use this software for any purpose\r
+* on any computer system, and to redistribute it freely, with the\r
+* following restrictions:\r
+* 1) No charge may be made other than reasonable charges for reproduction.\r
+* 2) Modified versions must be clearly marked as such.\r
+* 3) The authors are not responsible for any harmful consequences\r
+*    of using this software, even if they result from defects in it.\r
+*\r
+*------------------------------------------------\r
+\r
+ldiv:\r
+        move.l  4(%a7),%d0\r
+       bpl     ld1\r
+        neg.l   %d0\r
+ld1:\r
+        move.l  8(%a7),%d1\r
+       bpl     ld2\r
+        neg.l   %d1\r
+        eor.b   #0x80,4(%a7)\r
+ld2:\r
+       bsr     i_ldiv          /* d0 = d0/d1 */\r
+        tst.b   4(%a7)\r
+       bpl     ld3\r
+        neg.l   %d0\r
+ld3:\r
+       rts\r
+\r
+lmul:\r
+        move.l  4(%a7),%d0\r
+       bpl     lm1\r
+        neg.l   %d0\r
+lm1:\r
+        move.l  8(%a7),%d1\r
+       bpl     lm2\r
+        neg.l   %d1\r
+        eor.b   #0x80,4(%a7)\r
+lm2:\r
+       bsr     i_lmul          /* d0 = d0*d1 */\r
+        tst.b   4(%a7)\r
+       bpl     lm3\r
+        neg.l   %d0\r
+lm3:\r
+       rts\r
+\r
+lrem:\r
+        move.l  4(%a7),%d0\r
+       bpl     lr1\r
+        neg.l   %d0\r
+lr1:\r
+        move.l  8(%a7),%d1\r
+       bpl     lr2\r
+        neg.l   %d1\r
+lr2:\r
+       bsr     i_ldiv          /* d1 = d0%d1 */\r
+        move.l  %d1,%d0\r
+        tst.b   4(%a7)\r
+       bpl     lr3\r
+        neg.l   %d0\r
+lr3:\r
+       rts\r
+\r
+ldivu:\r
+        move.l  4(%a7),%d0\r
+        move.l  8(%a7),%d1\r
+       bsr     i_ldiv\r
+       rts\r
+\r
+lmulu:\r
+        move.l  4(%a7),%d0\r
+        move.l  8(%a7),%d1\r
+       bsr     i_lmul\r
+       rts\r
+\r
+lremu:\r
+        move.l  4(%a7),%d0\r
+        move.l  8(%a7),%d1\r
+       bsr     i_ldiv\r
+        move.l  %d1,%d0\r
+       rts\r
+*\r
+* A in d0, B in d1, return A*B in d0\r
+*\r
+i_lmul:\r
+        move.l  %d3,%a2           /* save d3 */\r
+        move.w  %d1,%d2\r
+        mulu    %d0,%d2           /* d2 = Al * Bl */\r
+\r
+        move.l  %d1,%d3\r
+        swap    %d3\r
+        mulu    %d0,%d3           /* d3 = Al * Bh */\r
+\r
+        swap    %d0\r
+        mulu    %d1,%d0           /* d0 = Ah * Bl */\r
+\r
+        add.l   %d3,%d0           /* d0 = (Ah*Bl + Al*Bh) */\r
+        swap    %d0\r
+        clr.w   %d0              /* d0 = (Ah*Bl + Al*Bh) << 16 */\r
+\r
+        add.l   %d2,%d0           /* d0 = A*B */\r
+        move.l  %a2,%d3           /* restore d3 */\r
+       rts\r
+*\r
+*A in d0, B in d1, return A/B in d0, A%B in d1\r
+*\r
+i_ldiv:\r
+        tst.l   %d1\r
+       bne     nz1\r
+\r
+*       divide by zero\r
+*       divu    #0,%d0           /* cause trap */\r
+        move.l  #0x80000000,%d0\r
+        move.l  %d0,%d1\r
+       rts\r
+nz1:\r
+        move.l  %d3,%a2           /* save d3 */\r
+        cmp.l   %d1,%d0\r
+       bhi     norm\r
+       beq     is1\r
+*       A<B, so ret 0, rem A\r
+        move.l  %d0,%d1\r
+        clr.l   %d0\r
+        move.l  %a2,%d3           /* restore d3 */\r
+       rts\r
+*       A==B, so ret 1, rem 0\r
+is1:\r
+        moveq.l #1,%d0\r
+        clr.l   %d1\r
+        move.l  %a2,%d3           /* restore d3 */\r
+       rts\r
+*       A>B and B is not 0\r
+norm:\r
+        cmp.l   #1,%d1\r
+       bne     not1\r
+*       B==1, so ret A, rem 0\r
+        clr.l   %d1\r
+        move.l  %a2,%d3           /* restore d3 */\r
+       rts\r
+*  check for A short (implies B short also)\r
+not1:\r
+        cmp.l   #0xffff,%d0\r
+       bhi     slow\r
+*  A short and B short -- use 'divu'\r
+        divu    %d1,%d0           /* d0 = REM:ANS */\r
+        swap    %d0              /* d0 = ANS:REM */\r
+        clr.l   %d1\r
+        move.w  %d0,%d1           /* d1 = REM */\r
+        clr.w   %d0\r
+        swap    %d0\r
+        move.l  %a2,%d3           /* restore d3 */\r
+       rts\r
+* check for B short\r
+slow:\r
+        cmp.l   #0xffff,%d1\r
+       bhi     slower\r
+* A long and B short -- use special stuff from gnu\r
+        move.l  %d0,%d2\r
+        clr.w   %d2\r
+        swap    %d2\r
+        divu    %d1,%d2           /* d2 = REM:ANS of Ahi/B */\r
+        clr.l   %d3\r
+        move.w  %d2,%d3           /* d3 = Ahi/B */\r
+        swap    %d3\r
+\r
+        move.w  %d0,%d2           /* d2 = REM << 16 + Alo */\r
+        divu    %d1,%d2           /* d2 = REM:ANS of stuff/B */\r
+\r
+        move.l  %d2,%d1\r
+        clr.w   %d1\r
+        swap    %d1              /* d1 = REM */\r
+\r
+        clr.l   %d0\r
+        move.w  %d2,%d0\r
+        add.l   %d3,%d0           /* d0 = ANS */\r
+        move.l  %a2,%d3           /* restore d3 */\r
+       rts\r
+*       A>B, B > 1\r
+slower:\r
+        move.l  #1,%d2\r
+        clr.l   %d3\r
+moreadj:\r
+        cmp.l   %d0,%d1\r
+       bhs     adj\r
+        add.l   %d2,%d2\r
+        add.l   %d1,%d1\r
+       bpl     moreadj\r
+* we shifted B until its >A or sign bit set\r
+* we shifted #1 (d2) along with it\r
+adj:\r
+        cmp.l   %d0,%d1\r
+       bhi     ltuns\r
+        or.l    %d2,%d3\r
+        sub.l   %d1,%d0\r
+ltuns:\r
+        lsr.l   #1,%d1\r
+        lsr.l   #1,%d2\r
+       bne     adj\r
+* d3=answer, d0=rem\r
+        move.l  %d0,%d1\r
+        move.l  %d3,%d0\r
+        move.l  %a2,%d3           /* restore d3 */\r
+       rts\r
+*----------------------------------------------------------        \r
+*\r
+*       Z80 Sound Driver\r
+*\r
+*----------------------------------------------------------        \r
+Z80Driver:\r
+          dc.b  0xc3,0x46,0x00,0x00,0x00,0x00,0x00,0x00\r
+          dc.b  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00\r
+          dc.b  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00\r
+          dc.b  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00\r
+          dc.b  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00\r
+          dc.b  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00\r
+          dc.b  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00\r
+          dc.b  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00\r
+          dc.b  0x00,0x00,0x00,0x00,0x00,0x00,0xf3,0xed\r
+          dc.b  0x56,0x31,0x00,0x20,0x3a,0x39,0x00,0xb7\r
+          dc.b  0xca,0x4c,0x00,0x21,0x3a,0x00,0x11,0x40\r
+          dc.b  0x00,0x01,0x06,0x00,0xed,0xb0,0x3e,0x00\r
+          dc.b  0x32,0x39,0x00,0x3e,0xb4,0x32,0x02,0x40\r
+          dc.b  0x3e,0xc0,0x32,0x03,0x40,0x3e,0x2b,0x32\r
+          dc.b  0x00,0x40,0x3e,0x80,0x32,0x01,0x40,0x3a\r
+          dc.b  0x43,0x00,0x4f,0x3a,0x44,0x00,0x47,0x3e\r
+          dc.b  0x06,0x3d,0xc2,0x81,0x00,0x21,0x00,0x60\r
+          dc.b  0x3a,0x41,0x00,0x07,0x77,0x3a,0x42,0x00\r
+          dc.b  0x77,0x0f,0x77,0x0f,0x77,0x0f,0x77,0x0f\r
+          dc.b  0x77,0x0f,0x77,0x0f,0x77,0x0f,0x77,0x3a\r
+          dc.b  0x40,0x00,0x6f,0x3a,0x41,0x00,0xf6,0x80\r
+          dc.b  0x67,0x3e,0x2a,0x32,0x00,0x40,0x7e,0x32\r
+          dc.b  0x01,0x40,0x21,0x40,0x00,0x7e,0xc6,0x01\r
+          dc.b  0x77,0x23,0x7e,0xce,0x00,0x77,0x23,0x7e\r
+          dc.b  0xce,0x00,0x77,0x3a,0x39,0x00,0xb7,0xc2\r
+          dc.b  0x4c,0x00,0x0b,0x78,0xb1,0xc2,0x7f,0x00\r
+          dc.b  0x3a,0x45,0x00,0xb7,0xca,0x4c,0x00,0x3d\r
+          dc.b  0x3a,0x45,0x00,0x06,0xff,0x0e,0xff,0xc3\r
+          dc.b  0x7f,0x00\r
+Z80DriverEnd:\r
+\r
+\r
diff --git a/nshtest/test.s b/nshtest/test.s
new file mode 100644 (file)
index 0000000..3802920
--- /dev/null
@@ -0,0 +1,443 @@
+##################################################
+#                                                #
+# Assemble with gas                              #
+#   --register-prefix-optional --bitwise-or      #
+#                                                #
+##################################################
+
+.text
+.globl main
+
+##################################################
+#                                                #
+#        Register and bitmask definitions        #
+#                                                #
+##################################################
+
+.equ GFXDATA,          0xc00000
+.equ GFXCNTL,          0xc00004
+
+.equ VDP0_E_HBI,       0x10
+.equ VDP0_E_DISPLAY,   0x02 
+.equ VDP0_PLTT_FULL,   0x04 
+
+.equ VDP1_SMS_MODE,    0x80
+.equ VDP1_E_DISPLAY,   0x40
+.equ VDP1_E_VBI,       0x20
+.equ VDP1_E_DMA,       0x10
+.equ VDP1_NTSC,                0x00
+.equ VDP1_PAL,         0x08
+.equ VDP1_RESERVED,    0x04
+
+.equ VDP12_SPR_SHADOWS,        0x08
+.equ VDP12_SCREEN_V224,        0x00
+.equ VDP12_SCREEN_V448,        0x04
+.equ VDP12_PROGRESSIVE,        0x00
+.equ VDP12_INTERLACED, 0x02
+.equ VDP12_SCREEN_H256,        0x00
+.equ VDP12_SCREEN_H320,        0x81
+
+.equ VDP16_MAP_V32,    0x00
+.equ VDP16_MAP_V64,    0x10
+.equ VDP16_MAP_V128,   0x30
+.equ VDP16_MAP_H32,    0x00
+.equ VDP16_MAP_H64,    0x01
+.equ VDP16_MAP_H128,   0x03
+
+
+
+##################################################
+#                                                #
+#                   MACROS                       #
+#                                                #
+##################################################
+
+
+/* Write val to VDP register reg */
+.macro write_vdp_reg reg val
+       move.w #((\reg << 8) + 0x8000 + \val),(a3)
+.endm
+
+
+/* For immediate addresses */
+.macro VRAM_ADDR reg adr
+       move.l #(((0x4000 + (\adr & 0x3fff)) << 16) + (\adr >> 14)),\reg
+.endm
+
+
+/* For indirect (variable) addresses.
+   Destroys d6-d7. */
+.macro VRAM_ADDR_var reg adr
+       move.l \adr,d6
+       move.l \adr,d7
+       and.w #0x3fff,d6
+       lsr.w #7,d7
+       lsr.w #7,d7
+       add.w #0x4000,d6
+       lsl.l #7,d6
+       lsl.l #7,d6
+       lsl.l #2,d6
+       or.l d7,d6
+       move.l d6,\reg
+.endm
+
+
+.macro CRAM_ADDR reg adr
+       move.l  #(((0xc000 + (\adr & 0x3fff)) << 16) + (\adr >> 14)),\reg
+.endm
+
+
+/* For indirect (variable) addresses */
+.macro CRAM_ADDR_var reg adr
+       move.l \adr,d6
+       move.l \adr,d7
+       and.w #0x3fff,d6
+       lsr.w #7,d7
+       lsr.w #7,d7
+       add.w #0xc000,d6
+       lsl.l #7,d6
+       lsl.l #7,d6
+       lsl.l #2,d6
+       or.l d7,d6
+       move.l d6,\reg
+.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
+
+
+#################################################
+#                                               #
+#                    DATA                       #
+#                                               #
+#################################################
+
+colors:
+       dc.w 0x0040,0x0080,0x000e,0x00e0,0x0e00,0x00ee
+pattern:
+       dc.l 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
+       dc.l 0x22334455,0x22334455,0x22334455,0x22334455,0x22334455,0x22334455,0x22334455,0x22334455
+       /* shadow sprite */
+       dc.l 0x00000fff
+       dc.l 0x0000ffff
+       dc.l 0x00ffffff
+       dc.l 0x00ffffff
+       dc.l 0x0fffffff
+       dc.l 0xffffffff
+       dc.l 0xffffffff
+       dc.l 0xffffffff
+       /* */
+       dc.l 0xffffffff
+       dc.l 0xffffffff
+       dc.l 0xffffffff
+       dc.l 0x0fffffff
+       dc.l 0x00ffffff
+       dc.l 0x00ffffff
+       dc.l 0x0000ffff
+       dc.l 0x00000fff
+       /* */
+       dc.l 0xfff00000
+       dc.l 0xffff0000
+       dc.l 0xffffff00
+       dc.l 0xffffff00
+       dc.l 0xfffffff0
+       dc.l 0xffffffff
+       dc.l 0xffffffff
+       dc.l 0xffffffff
+       /* */
+       dc.l 0xffffffff
+       dc.l 0xffffffff
+       dc.l 0xffffffff
+       dc.l 0xfffffff0
+       dc.l 0xffffff00
+       dc.l 0xffffff00
+       dc.l 0xffff0000
+       dc.l 0xfff00000
+       /* hilight sprite */
+       dc.l 0x00000eee
+       dc.l 0x0000eeee
+       dc.l 0x00eeeeee
+       dc.l 0x00eeeeee
+       dc.l 0x0eeeeeee
+       dc.l 0xeeeeeeee
+       dc.l 0xeeeeeeee
+       dc.l 0xeeeeeeee
+       /* */
+       dc.l 0xeeeeeeee
+       dc.l 0xeeeeeeee
+       dc.l 0xeeeeeeee
+       dc.l 0x0eeeeeee
+       dc.l 0x00eeeeee
+       dc.l 0x00eeeeee
+       dc.l 0x0000eeee
+       dc.l 0x00000eee
+       /* */
+       dc.l 0xeee00000
+       dc.l 0xeeee0000
+       dc.l 0xeeeeee00
+       dc.l 0xeeeeee00
+       dc.l 0xeeeeeee0
+       dc.l 0xeeeeeeee
+       dc.l 0xeeeeeeee
+       dc.l 0xeeeeeeee
+       /* */
+       dc.l 0xeeeeeeee
+       dc.l 0xeeeeeeee
+       dc.l 0xeeeeeeee
+       dc.l 0xeeeeeee0
+       dc.l 0xeeeeee00
+       dc.l 0xeeeeee00
+       dc.l 0xeeee0000
+       dc.l 0xeee00000
+
+
+sprite_data:
+       /*         Y        size     link          attr        X */
+       dc.w  10+128;  dc.b 0x05;  dc.b 1;  dc.w 0x6002;  dc.w 0
+       dc.w  30+128;  dc.b 0x05;  dc.b 2;  dc.w 0x6006;  dc.w 0
+       dc.w  60+128;  dc.b 0x05;  dc.b 3;  dc.w 0xe002;  dc.w 0
+       dc.w  80+128;  dc.b 0x05;  dc.b 4;  dc.w 0xe006;  dc.w 0
+       dc.w 120+128;  dc.b 0x05;  dc.b 5;  dc.w 0x6002;  dc.w 0
+       dc.w 140+128;  dc.b 0x05;  dc.b 6;  dc.w 0x6006;  dc.w 0
+       dc.w 170+128;  dc.b 0x05;  dc.b 7;  dc.w 0xe002;  dc.w 0
+       dc.w 190+128;  dc.b 0x05;  dc.b 0;  dc.w 0xe006;  dc.w 0
+sprite_data_end:
+
+
+##################################################
+#                                                #
+#               MAIN PROGRAM                     #
+#                                                #
+##################################################
+main:
+       /* Initialize VDP */
+       jsr             init_gfx
+
+       /* Load color data */
+       movea.l         #0,a3
+       move.l          #colors,a4
+       moveq.l         #6,d4
+       jsr             load_colors
+
+       /* load patterns */
+       movea.l         #0,a3
+       movea.l         #pattern,a4
+       move.l          #10,d4
+       jsr             load_tiles
+
+       /* generate A layer map */
+       movea.l         #0xe000+10*2,a6
+       move.l          #28-1,d4
+lmaploop0:
+       movea.l         a6,a3
+       jsr             load_prepare
+
+       moveq.l         #6-1,d3
+0:     move.l          #0x00010001,(a3)
+       dbra            d3,0b
+
+       moveq.l         #9-1,d3
+0:     move.l          #0x80018001,(a3)
+       dbra            d3,0b
+
+       add.l           #64*2,a6
+       dbra            d4,lmaploop0
+
+       /* generate B layer map */
+       movea.l         #0xc000+64*14*2,a3
+       jsr             load_prepare
+
+       move.l          #64*14/2-1,d3
+0:     move.l          #0x80008000,(a3)
+       dbra            d3,0b
+
+       /* upload sprite data */
+       movea.l         #0xfc00,a3
+       jsr             load_prepare
+       movea.l         #sprite_data,a0
+
+       move.l          #(sprite_data_end-sprite_data)/2-1,d3
+0:     move.l          (a0)+,(a3)
+       dbra            d3,0b
+
+       jsr             wait_vsync
+
+##################################################
+#                                                #
+#                 MAIN LOOP                      #
+#                                                #
+##################################################
+
+forever:
+       movea.l         #vtimer,a0
+       move.l          (a0),d4
+       and.w           #0x1ff,d4
+       movea.l         #0xfc06,a6
+       moveq.l         #8-1,d5
+
+0:
+       movea.l         a6,a3
+       jsr             load_prepare
+       move.w          d4,(a3)
+       addq.w          #8,a6
+       dbra            d5,0b
+
+       jsr             wait_vsync
+       bra             forever
+       
+
+
+#################################################
+#                                               #
+#         Initialize VDP registers              #
+#                                               #
+#################################################
+
+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   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 */
+       write_vdp_reg   5,(0xfc00 >>  9)        /* Sprite address */
+       write_vdp_reg   6,0     
+       write_vdp_reg   7,1                     /* Border color */
+       write_vdp_reg   10,1                    /* Lines per hblank interrupt */
+       write_vdp_reg   11,0                    /* 2-cell vertical scrolling */
+       write_vdp_reg   12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_SPR_SHADOWS)
+       write_vdp_reg   13,(0x6000 >> 10)       /* Horizontal scroll address */
+       write_vdp_reg   15,2
+       write_vdp_reg   16,(VDP16_MAP_V32 + VDP16_MAP_H64)
+       write_vdp_reg   17,0
+       write_vdp_reg   18,0xff
+       rts
+
+
+
+#################################################
+#                                               #
+#        Load tile data from ROM                #
+#                                               #
+# Parameters:                                   #
+#  a3: VRAM base                                # 
+#  a4: pattern address                          #
+#  d4: number of tiles to load                  #
+#  Destroys a2,d0,d6-d7...                      #
+#                                               #
+#################################################
+
+load_tiles:
+       move.l          #GFXCNTL,a2
+       VRAM_ADDR_var   d0,a3
+       move.l          d0,(a2)
+       lsl             #3,d4
+       
+       move.l          #GFXDATA,a3
+       subq.l          #1,d4
+_copy_tile_data:
+       move.l          (a4)+,(a3)
+       dbra            d4,_copy_tile_data
+
+       rts
+
+
+load_prepare:
+       move.l          #GFXCNTL,a2
+       VRAM_ADDR_var   d0,a3
+       move.l          d0,(a2)
+       move.l          #GFXDATA,a3
+
+       rts
+
+
+#################################################
+#                                               #
+#        Clear one of the screen maps           #
+#                                               #
+# Parameters:                                   #
+#  a0: Map address                              # 
+#  d0: Data to write to each map entry          #
+#                                               #
+#################################################
+
+clear_map:
+       move.l          #GFXCNTL,a4
+       VRAM_ADDR_var   d1,a0
+       move.l          d1,(a4)
+       move.l          #GFXDATA,a3
+       move.w          #1023,d1        /* Loop counter */
+_clear_map_loop:
+       move.w          d0,(a3)
+       move.w          d0,(a3)
+       dbra            d1,_clear_map_loop
+       rts
+       
+
+#################################################
+#                                               #
+#        Load color data from ROM               #
+#                                               #
+# Parameters:                                   #
+#  a3: CRAM base                                # 
+#  a4: color list address                       #
+#  d4: number of colors to load                 #
+#                                               #
+#################################################
+
+load_colors:
+       move.l          #GFXCNTL,a2
+       CRAM_ADDR_var   d0,a3
+       move.l          d0,(a2)
+
+       move.l          #GFXDATA,a3
+       subq.w          #1,d4
+_copy_color_data:
+       move.w          (a4)+,(a3)
+       dbra            d4,_copy_color_data
+
+       rts
+
+
+#################################################
+#                                               #
+#       Wait for next VBlank interrupt          #
+#                                               #
+#################################################
+
+wait_vsync:
+       movea.l         #vtimer,a0
+       move.l          (a0),a1
+_wait_change:
+       stop            #0x2000
+       cmp.l           (a0),a1
+       beq             _wait_change
+       rts
+
+
+#################################################
+#                                               #
+#                 RAM DATA                      #
+#                                               #
+#################################################
+
+.bss
+.globl htimer
+.globl vtimer
+.globl rand_num
+htimer:                .long 0
+vtimer:                .long 0
+rand_num:      .long 0
+scrollx:       .long 0
+
+.end
+
+# vim:filetype=asmM68k
diff --git a/teensytp/.gitignore b/teensytp/.gitignore
new file mode 100644 (file)
index 0000000..850d10a
--- /dev/null
@@ -0,0 +1,6 @@
+*.o
+*.elf
+*.hex
+.*.swp
+cscope.out
+tags
similarity index 100%
rename from Makefile
rename to teensytp/Makefile
similarity index 100%
rename from host/Makefile
rename to teensytp/host/Makefile
similarity index 100%
rename from host/main.c
rename to teensytp/host/main.c
similarity index 100%
rename from main.c
rename to teensytp/main.c
similarity index 100%
rename from pkts.h
rename to teensytp/pkts.h
similarity index 100%
rename from teensy3/kinetis.h
rename to teensytp/teensy3/kinetis.h
similarity index 100%
rename from teensy3/nonstd.c
rename to teensytp/teensy3/nonstd.c
similarity index 100%
rename from teensy3/usb_dev.c
rename to teensytp/teensy3/usb_dev.c
similarity index 100%
rename from teensy3/usb_dev.h
rename to teensytp/teensy3/usb_dev.h
similarity index 100%
rename from teensy3/usb_mem.c
rename to teensytp/teensy3/usb_mem.c
similarity index 100%
rename from teensy3/usb_mem.h
rename to teensytp/teensy3/usb_mem.h