diff --git a/.gitignore b/.gitignore index a1e7a31..762b381 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,12 @@ *.pyc __pycache__ -.~* \ No newline at end of file +.~* +*.BIN +*.bin +*.elf +*.d +*.iso +*.cdi +*.o +scramble +cdi4dc \ No newline at end of file diff --git a/ABSTRACT.TXT b/ABSTRACT.TXT new file mode 100644 index 0000000..af14975 --- /dev/null +++ b/ABSTRACT.TXT @@ -0,0 +1 @@ +abstract diff --git a/BIBLIOGR.TXT b/BIBLIOGR.TXT new file mode 100644 index 0000000..d8dfacf --- /dev/null +++ b/BIBLIOGR.TXT @@ -0,0 +1 @@ +bibliography diff --git a/COPYRIGH.TXT b/COPYRIGH.TXT new file mode 100644 index 0000000..73129b4 --- /dev/null +++ b/COPYRIGH.TXT @@ -0,0 +1 @@ +Copyright(c) SEGA ENTERPRISES, LTD. 1998 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..31ea6a8 --- /dev/null +++ b/Makefile @@ -0,0 +1 @@ +include common.mk diff --git a/common.mk b/common.mk new file mode 100644 index 0000000..c8a9a72 --- /dev/null +++ b/common.mk @@ -0,0 +1,112 @@ +LIB ?= . +OPT ?= -Og +DEBUG ?= -g -gdwarf-4 +GENERATED ?= + +AARCH = --isa=sh4 --little +AFLAGS = --fatal-warnings + +CARCH = -m4-single-only -ml +CFLAGS += -falign-functions=4 -ffunction-sections -fdata-sections -fshort-enums -ffreestanding -nostdlib +CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable +DEPFLAGS = -MMD -E +# --print-gc-sections +LDFLAGS = --gc-sections --no-warn-rwx-segment --print-memory-usage --entry=_start --orphan-handling=error +CXXFLAGS = -std=c++20 -fno-exceptions -fno-non-call-exceptions -fno-rtti -fno-threadsafe-statics + +TARGET = sh4-none-elf- +CC = $(TARGET)gcc +CXX = $(TARGET)g++ +AS = $(TARGET)as +LD = $(TARGET)ld +OBJCOPY = $(TARGET)objcopy +OBJDUMP = $(TARGET)objdump + +IP_OBJ = \ + systemid.o \ + toc.o \ + sg/sg_sec.o \ + sg/sg_arejp.o \ + sg/sg_areus.o \ + sg/sg_areec.o \ + sg/sg_are00.o \ + sg/sg_are01.o \ + sg/sg_are02.o \ + sg/sg_are03.o \ + sg/sg_are04.o \ + sg/sg_ini.o \ + sg/aip.o + +all: main.elf + +%.o: %.obj + $(OBJCOPY) -g \ + --rename-section IP=.text.$* \ + $< $@ + +%.o: %.s + $(AS) $(AARCH) $(AFLAGS) $(DEBUG) $< -o $@ + +%.c.d: | $(GENERATED) + $(CC) $(CARCH) $(CFLAGS) $(OPT) $(DEBUG) $(DEPFLAGS) -c $(basename $@) -MF $@ -o /dev/null + +%.o: %.c %.c.d + $(CC) $(CARCH) $(CFLAGS) $(OPT) $(DEBUG) -c $< -o $@ + +main.elf: main.o + $(LD) $(LDFLAGS) -T $(LIB)/main.lds $^ -o $@ + +%.bin: %.elf + $(OBJCOPY) -O binary $< $@ + +ip.elf: $(IP_OBJ) + $(LD) --print-memory-usage -T $(LIB)/ip.lds $^ -o $@ + +audio.pcm: + sox \ + --rate 44100 \ + --encoding signed-integer \ + --bits 16 \ + --channels 2 \ + --endian little \ + --null \ + $@.raw \ + synth 1 sin 440 vol -10dB + mv $@.raw $@ + +1ST_READ.BIN: main.bin + ./scramble main.bin 1ST_READ.BIN + +%.iso: 1ST_READ.BIN ip.bin + mkisofs \ + -C 0,11702 \ + -sysid "SEGA SEGAKATANA" \ + -volid "SAMPLE_GAME_TITLE" \ + -volset "SAMPLE_GAME_TITLE" \ + -publisher "SEGA ENTERPRISES, LTD." \ + -preparer "CRI CD CRAFT VER.2.27" \ + -copyright "COPYRIGH.TXT" \ + -abstract "ABSTRACT.TXT" \ + -biblio "BIBLIOGR.TXT" \ + -sectype data \ + -G ip.bin \ + -o $@ \ + -graft-points \ + /=./1ST_READ.BIN \ + /=./COPYRIGH.TXT \ + /=./ABSTRACT.TXT \ + /=./BIBLIOGR.TXT + +%.cdi: %.iso + ./cdi4dc $< $@ >/dev/null + +.SUFFIXES: +.INTERMEDIATE: +.SECONDARY: +.PHONY: all clean + +%: RCS/%,v +%: RCS/% +%: %,v +%: s.% +%: SCCS/s.% diff --git a/ip.lds b/ip.lds new file mode 100644 index 0000000..e3803a4 --- /dev/null +++ b/ip.lds @@ -0,0 +1,56 @@ +OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") + +MEMORY +{ + systemid (arx) : ORIGIN = 0x8c008000, LENGTH = 0x100 + toc (arx) : ORIGIN = 0x8c008100, LENGTH = 0x200 + sg_sec (arx) : ORIGIN = 0x8c008300, LENGTH = 0x3400 + sg_are (arx) : ORIGIN = 0x8c00b700, LENGTH = 0x100 + sg_ini (arx) : ORIGIN = 0x8c00b800, LENGTH = 0x2800 + aip (arx) : ORIGIN = 0x8c00e000, LENGTH = 0x2000 +} + +SECTIONS +{ + .text.systemid : + { + KEEP(*(.text.systemid)) + } > systemid + + .text.toc : + { + KEEP(*(.text.toc)) + } > toc + + .text.sg_sec : + { + KEEP(*(.text.sg_sec)) + } > sg_sec + + .text.sg_are : + { + KEEP(*(.text.sg_arejp)) + KEEP(*(.text.sg_areus)) + KEEP(*(.text.sg_areec)) + KEEP(*(.text.sg_are00)) + KEEP(*(.text.sg_are01)) + KEEP(*(.text.sg_are02)) + KEEP(*(.text.sg_are03)) + KEEP(*(.text.sg_are04)) + } > sg_are + + .text.sg_ini : + { + KEEP(*(.text.sg_ini)) + } > sg_ini + + .text.aip : + { + KEEP(*(.text.aip)) + } > aip + + /DISCARD/ : + { + *(*) + } +} diff --git a/main.c b/main.c new file mode 100644 index 0000000..4a44c65 --- /dev/null +++ b/main.c @@ -0,0 +1,53 @@ +#include + +volatile uint8_t * SCFTDR2 = (volatile uint8_t *)0xFFE8000C; + +volatile uint32_t * SOFT_RESET = (volatile uint32_t *)0xa05f8008; +volatile uint32_t * STARTRENDER = (volatile uint32_t *)0xa05f8014; +volatile uint32_t * VO_CONTROL = (volatile uint32_t *)0xa05f80e8; +volatile uint32_t * VO_BORDER_COL = (volatile uint32_t *)0xa05f8040; + +volatile uint32_t * FB_R_SOF1 = (volatile uint32_t *)0xa05f8050; + +volatile uint32_t * RAM = (volatile uint32_t *)0xa5000000; + +volatile uint32_t * SPG_STATUS = (volatile uint32_t *)0xa05f810; + +void start() +{ + *SCFTDR2 = 'H'; + *SCFTDR2 = 'e'; + *SCFTDR2 = 'l'; + *SCFTDR2 = 'l'; + *SCFTDR2 = '3'; + + *SOFT_RESET = 0b111; + *SOFT_RESET = 0b000; + + *VO_CONTROL |= 1 << 3; + *VO_BORDER_COL = 31; + + for (int i = 0; i < (2*1024*1024 + 1024 * 2 + 512 + 4) / 4; i++) { + RAM[i] = 0x1; + } + + while (1) { + } +} + +/* + { + DM_640x480, + 640, 480, + VID_INTERLACE, // flags + CT_VGA, // cable type + 0, // pixel mode + 0x20C, 0x359, // scanlines, clocks per scanline + 0xAC, 0x28, // bitmap x, bitmap y + 0x15, 0x104, // first scanline interrupt, second scanline interrupt + 0x7E, 0x345, // border x start, border x stop + 0x24, 0x204, // border y start, border y stop + 0, 1, // current framebuffer, number of framebuffers + { 0, 0, 0, 0 } // offset to framebuffers + }, +*/ diff --git a/main.lds b/main.lds new file mode 100644 index 0000000..17bce10 --- /dev/null +++ b/main.lds @@ -0,0 +1,53 @@ +OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") +MEMORY +{ + ram : ORIGIN = 0x8c010000, LENGTH = 1M +} +SECTIONS +{ + . = 0x8c010000; + + .text ALIGN(4) : SUBALIGN(4) + { + KEEP(*(.text.start)) + *(.text) + *(.text.*) + } > ram + + .data ALIGN(4) : SUBALIGN(4) + { + *(.data) + *(.data.*) + } > ram + + .rodata ALIGN(4) : SUBALIGN(4) + { + *(.rodata) + *(.rodata.*) + } > ram + + .ctors ALIGN(4) : SUBALIGN(4) + { + KEEP(*(.ctors)) + KEEP(*(.ctors.*)) + } > ram + + .bss ALIGN(4) (NOLOAD) : SUBALIGN(4) + { + *(.bss) + *(.bss.*) + } > ram + + /DISCARD/ : + { + *(.debug*) + *(.comment*) + *(.rela*) + } + + __bss_link_start = ADDR(.bss); + __bss_link_end = ADDR(.bss) + SIZEOF(.bss); + + __ctors_link_start = ADDR(.ctors); + __ctors_link_end = ADDR(.ctors) + SIZEOF(.ctors); +} diff --git a/scramble.c b/scramble.c new file mode 100644 index 0000000..56069b1 --- /dev/null +++ b/scramble.c @@ -0,0 +1,259 @@ +#include +#include + +#define MAXCHUNK (2048*1024) + +static unsigned int seed; + +void my_srand(unsigned int n) +{ + seed = n & 0xffff; +} + +unsigned int my_rand() +{ + seed = (seed * 2109 + 9273) & 0x7fff; + return (seed + 0xc000) & 0xffff; +} + +void load(FILE *fh, unsigned char *ptr, unsigned long sz) +{ + if(fread(ptr, 1, sz, fh) != sz) + { + fprintf(stderr, "Read error!\n"); + exit(1); + } +} + +void load_chunk(FILE *fh, unsigned char *ptr, unsigned long sz) +{ + static int idx[MAXCHUNK/32]; + int i; + + /* Convert chunk size to number of slices */ + sz /= 32; + + /* Initialize index table with unity, + so that each slice gets loaded exactly once */ + for(i = 0; i < sz; i++) + idx[i] = i; + + for(i = sz-1; i >= 0; --i) + { + /* Select a replacement index */ + int x = (my_rand() * i) >> 16; + + /* Swap */ + int tmp = idx[i]; + idx[i] = idx[x]; + idx[x] = tmp; + + /* Load resulting slice */ + load(fh, ptr+32*idx[i], 32); + } +} + +void load_file(FILE *fh, unsigned char *ptr, unsigned long filesz) +{ + unsigned long chunksz; + + my_srand(filesz); + + /* Descramble 2 meg blocks for as long as possible, then + gradually reduce the window down to 32 bytes (1 slice) */ + for(chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1) + while(filesz >= chunksz) + { + load_chunk(fh, ptr, chunksz); + filesz -= chunksz; + ptr += chunksz; + } + + /* Load final incomplete slice */ + if(filesz) + load(fh, ptr, filesz); +} + +void read_file(char *filename, unsigned char **ptr, unsigned long *sz) +{ + FILE *fh = fopen(filename, "rb"); + if(fh == NULL) + { + fprintf(stderr, "Can't open \"%s\".\n", filename); + exit(1); + } + if(fseek(fh, 0, SEEK_END)<0) + { + fprintf(stderr, "Seek error.\n"); + exit(1); + } + *sz = ftell(fh); + *ptr = malloc(*sz); + if( *ptr == NULL ) + { + fprintf(stderr, "Out of memory.\n"); + exit(1); + } + if(fseek(fh, 0, SEEK_SET)<0) + { + fprintf(stderr, "Seek error.\n"); + exit(1); + } + load_file(fh, *ptr, *sz); + fclose(fh); +} + +void save(FILE *fh, unsigned char *ptr, unsigned long sz) +{ + if(fwrite(ptr, 1, sz, fh) != sz) + { + fprintf(stderr, "Write error!\n"); + exit(1); + } +} + +void save_chunk(FILE *fh, unsigned char *ptr, unsigned long sz) +{ + static int idx[MAXCHUNK/32]; + int i; + + /* Convert chunk size to number of slices */ + sz /= 32; + + /* Initialize index table with unity, + so that each slice gets saved exactly once */ + for(i = 0; i < sz; i++) + idx[i] = i; + + for(i = sz-1; i >= 0; --i) + { + /* Select a replacement index */ + int x = (my_rand() * i) >> 16; + + /* Swap */ + int tmp = idx[i]; + idx[i] = idx[x]; + idx[x] = tmp; + + /* Save resulting slice */ + save(fh, ptr+32*idx[i], 32); + } +} + +void save_file(FILE *fh, unsigned char *ptr, unsigned long filesz) +{ + unsigned long chunksz; + + my_srand(filesz); + + /* Descramble 2 meg blocks for as long as possible, then + gradually reduce the window down to 32 bytes (1 slice) */ + for(chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1) + while(filesz >= chunksz) + { + save_chunk(fh, ptr, chunksz); + filesz -= chunksz; + ptr += chunksz; + } + + /* Save final incomplete slice */ + if(filesz) + save(fh, ptr, filesz); +} + +void write_file(char *filename, unsigned char *ptr, unsigned long sz) +{ + FILE *fh = fopen(filename, "wb"); + if(fh == NULL) + { + fprintf(stderr, "Can't open \"%s\".\n", filename); + exit(1); + } + save_file(fh, ptr, sz); + fclose(fh); +} + +void descramble(char *src, char *dst) +{ + unsigned char *ptr = NULL; + unsigned long sz = 0; + FILE *fh; + + read_file(src, &ptr, &sz); + + fh = fopen(dst, "wb"); + if(fh == NULL) + { + fprintf(stderr, "Can't open \"%s\".\n", dst); + exit(1); + } + if( fwrite(ptr, 1, sz, fh) != sz ) + { + fprintf(stderr, "Write error.\n"); + exit(1); + } + fclose(fh); + free(ptr); +} + +void scramble(char *src, char *dst) +{ + unsigned char *ptr = NULL; + unsigned long sz = 0; + FILE *fh; + + fh = fopen(src, "rb"); + if(fh == NULL) + { + fprintf(stderr, "Can't open \"%s\".\n", src); + exit(1); + } + if(fseek(fh, 0, SEEK_END)<0) + { + fprintf(stderr, "Seek error.\n"); + exit(1); + } + sz = ftell(fh); + ptr = malloc(sz); + if( ptr == NULL ) + { + fprintf(stderr, "Out of memory.\n"); + exit(1); + } + if(fseek(fh, 0, SEEK_SET)<0) + { + fprintf(stderr, "Seek error.\n"); + exit(1); + } + if( fread(ptr, 1, sz, fh) != sz ) + { + fprintf(stderr, "Read error.\n"); + exit(1); + } + fclose(fh); + + write_file(dst, ptr, sz); + + free(ptr); +} + +int main(int argc, char *argv[]) +{ + int opt = 0; + + if(argc > 1 && !strcmp(argv[1], "-d")) + opt ++; + + if(argc != 3+opt) + { + fprintf(stderr, "Usage: %s [-d] from to\n", argv[0]); + exit(1); + } + + if(opt) + descramble(argv[2], argv[3]); + else + scramble(argv[1], argv[2]); + + return 0; +} diff --git a/sg/aip.obj b/sg/aip.obj new file mode 100644 index 0000000..b3b37cf Binary files /dev/null and b/sg/aip.obj differ diff --git a/sg/sg_are00.obj b/sg/sg_are00.obj new file mode 100644 index 0000000..9def46a Binary files /dev/null and b/sg/sg_are00.obj differ diff --git a/sg/sg_are01.obj b/sg/sg_are01.obj new file mode 100644 index 0000000..7ee9c78 Binary files /dev/null and b/sg/sg_are01.obj differ diff --git a/sg/sg_are02.obj b/sg/sg_are02.obj new file mode 100644 index 0000000..624c188 Binary files /dev/null and b/sg/sg_are02.obj differ diff --git a/sg/sg_are03.obj b/sg/sg_are03.obj new file mode 100644 index 0000000..927c201 Binary files /dev/null and b/sg/sg_are03.obj differ diff --git a/sg/sg_are04.obj b/sg/sg_are04.obj new file mode 100644 index 0000000..d07299c Binary files /dev/null and b/sg/sg_are04.obj differ diff --git a/sg/sg_are05.obj b/sg/sg_are05.obj new file mode 100644 index 0000000..c82d170 Binary files /dev/null and b/sg/sg_are05.obj differ diff --git a/sg/sg_are06.obj b/sg/sg_are06.obj new file mode 100644 index 0000000..d21b75b Binary files /dev/null and b/sg/sg_are06.obj differ diff --git a/sg/sg_areec.obj b/sg/sg_areec.obj new file mode 100644 index 0000000..af4d738 Binary files /dev/null and b/sg/sg_areec.obj differ diff --git a/sg/sg_arejp.obj b/sg/sg_arejp.obj new file mode 100644 index 0000000..4524f97 Binary files /dev/null and b/sg/sg_arejp.obj differ diff --git a/sg/sg_areus.obj b/sg/sg_areus.obj new file mode 100644 index 0000000..17929e8 Binary files /dev/null and b/sg/sg_areus.obj differ diff --git a/sg/sg_ini.obj b/sg/sg_ini.obj new file mode 100644 index 0000000..988551e Binary files /dev/null and b/sg/sg_ini.obj differ diff --git a/sg/sg_sec.obj b/sg/sg_sec.obj new file mode 100644 index 0000000..5941098 Binary files /dev/null and b/sg/sg_sec.obj differ diff --git a/sg/strt2.obj b/sg/strt2.obj new file mode 100644 index 0000000..52d04b2 Binary files /dev/null and b/sg/strt2.obj differ diff --git a/sg/zero.obj b/sg/zero.obj new file mode 100644 index 0000000..fa9e498 Binary files /dev/null and b/sg/zero.obj differ diff --git a/systemid.s b/systemid.s new file mode 100644 index 0000000..b8dc97c --- /dev/null +++ b/systemid.s @@ -0,0 +1,52 @@ + /* +<-------B------> + +1100 0000 0000 0000 1000 0001 0000 + +0000 0000 0000 0000 0000 0000 0000 +^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^ ^ +|||| |||| |||| |||| |||| | | +|||| |||| |||| |||| |||| | +----- Uses Windows CE +|||| |||| |||| |||| |||| | +|||| |||| |||| |||| |||| +----- VGA box support +|||| |||| |||| |||| |||| +|||| |||| |||| |||| |||+----- Other expansions +|||| |||| |||| |||| ||+----- Puru Puru pack +|||| |||| |||| |||| |+----- Mike device +|||| |||| |||| |||| +----- Memory card +|||| |||| |||| |||+------ Start + A + B + Directions +|||| |||| |||| ||+------ C button +|||| |||| |||| |+------ D button +|||| |||| |||| +------ X button +|||| |||| |||+------- Y button +|||| |||| ||+------- Z button +|||| |||| |+------- Expanded direction buttons +|||| |||| +------- Analog R trigger +|||| |||+-------- Analog L trigger +|||| ||+-------- Analog horizontal controller +|||| |+-------- Analog vertical controller +|||| +-------- Expanded analog horizontal +|||+--------- Expanded analog vertical +||+--------- Gun +|+--------- Keyboard ++--------- Mouse + */ + + .section .text.systemid + + .ascii "SEGA SEGAKATANA " /* H/W identifier */ + .ascii "SEGA ENTERPRISES" /* H/W Vendor ID */ + .ascii "39F1 " /* Media ID */ + .ascii "GD-ROM1/1 " /* Media information */ + .ascii "JUE " /* Compatible Area Symbol */ + .ascii "C000810 " /* Compatible peripherals */ + .ascii "HDR-0900 " /* Product number */ + .ascii "V0.000" /* Version number */ + .ascii "19980901" /* Release date */ + .ascii " " /* Reserved */ + .ascii "1ST_READ.BIN" + .ascii " " /* Reserved */ + .ascii "SEGA LC-KAISYAID" /* Maker identifier */ + .ascii "SAMPLE GAME " /* Game title */ + .fill (96-16),1,0x20 /* Game title */ + .fill 32,1,0x20 /* Reserved */ diff --git a/toc.s b/toc.s new file mode 100644 index 0000000..06e8c0e --- /dev/null +++ b/toc.s @@ -0,0 +1,4 @@ + .section .text.toc + + .fill (101*4),1,0xff + .fill (27 *4),1,0x00