diff --git a/.gitignore b/.gitignore index fca0722..8b34d90 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ *.pyc .#* res/ +gen/ diff --git a/Makefile b/Makefile index ea88ccd..f8bded4 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CFLAGS = -Isaturn OPT ?= -Og LIB = ./saturn -SRC = main.o input.o +SRC = main.o input.o gen/maps.o DEP = $(patsubst %.o,%.d,$(SRC)) res = $(subst pokered/,res/,$(patsubst %.$(1),%.$(1).o,$(wildcard $(2)*.$(1)))) @@ -21,11 +21,24 @@ all: main.cue include $(LIB)/common.mk -include $(DEP) -define COPY_BINARY +define LINK_BINARY @mkdir -p $(dir $@) - cp -a $< $@ + ln -sf $(shell realpath --relative-to="$(dir $@)" $<) $@ endef +GEN_PYTHON_SOURCE = $(wildcard tools/source/*.py) $(wildcard tools/generate/*.py) + +define RUN_GENERATE + @mkdir -p ./gen + PYTHONPATH=./tools python -m generate ./pokered ./gen ./res +endef + +gen/%.cpp: $(GEN_PYTHON_SOURCE) + $(RUN_GENERATE) + +gen/%.hpp: $(GEN_PYTHON_SOURCE) + $(RUN_GENERATE) + generated: $(GENERATED) res/%.2bpp: pokered/%.png @@ -39,7 +52,7 @@ res/%.2bpp: pokered/%.png $(BUILD_BINARY_O) res/%.blk: pokered/%.blk - $(COPY_BINARY) + $(LINK_BINARY) %.blk.h: $(BUILD_BINARY_H) @@ -48,7 +61,7 @@ res/%.blk: pokered/%.blk $(BUILD_BINARY_O) res/%.bst: pokered/%.bst - $(COPY_BINARY) + $(LINK_BINARY) %.bst.h: $(BUILD_BINARY_H) diff --git a/main.cpp b/main.cpp index 6102a12..eb732e3 100644 --- a/main.cpp +++ b/main.cpp @@ -9,9 +9,10 @@ #include "common/vdp2_func.hpp" #include "common/intback.hpp" -#include "test.cpp" #include "input.hpp" +#include "gen/maps.hpp" + constexpr inline uint16_t rgb15(int32_t r, int32_t g, int32_t b) { return ((b & 31) << 10) | ((g & 31) << 5) | ((r & 31) << 0); @@ -100,6 +101,7 @@ enum tileset_t::tileset load_tileset(enum tileset_t::tileset tileset) return tileset; } +// fixme: remove hack #include "map.hpp" void render() @@ -109,11 +111,12 @@ void render() if (map.tileset != state.tileset) state.tileset = load_tileset(map.tileset); - uint32_t height = map.height > 16 ? 16 : map.height; - uint32_t width = map.width > 16 ? 16 : map.width; - for (uint32_t map_y = 0; map_y < height; map_y++) { - for (uint32_t map_x = 0; map_x < width; map_x++) { - const uint8_t block = map.blocks.start[map.width * map_y + map_x]; + for (uint32_t map_y = 0; map_y < 16; map_y++) { + for (uint32_t map_x = 0; map_x < 16; map_x++) { + const uint8_t block = + (map_x < map.width && map_y < map.height) + ? map.blocks.start[map.width * map_y + map_x] + : 0; render_block(state.base_pattern, tilesets[map.tileset], map_x, @@ -136,23 +139,39 @@ void update() } } -static int count = 0; - extern "C" void v_blank_in_int(void) __attribute__ ((interrupt_handler)); void v_blank_in_int() { - if (++count > 60) { - count = 0; - state.map_ix++; - if (state.map_ix >= map_ix_last) - state.map_ix = 0; - } scu.reg.IST &= ~(IST__V_BLANK_IN); scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN); + sh2.reg.FRC.H = 0; + sh2.reg.FRC.L = 0; + sh2.reg.FTCSR = 0; // clear flags + render(); update(); + + // wait at least 300us, as specified in the SMPC manual. + // It appears reading FRC.H is mandatory and *must* occur before FRC.L on real + // hardware. + while ((sh2.reg.FTCSR & FTCSR__OVF) == 0 && sh2.reg.FRC.H == 0 && sh2.reg.FRC.L < 63); + + // on real hardware, SF contains uninitialized garbage bits other than the + // lsb. + while ((smpc.reg.SF & 1) != 0); + + smpc.reg.SF = 0; + + smpc.reg.IREG[0].val = INTBACK__IREG0__STATUS_DISABLE; + smpc.reg.IREG[1].val = ( INTBACK__IREG1__PERIPHERAL_DATA_ENABLE + | INTBACK__IREG1__PORT2_15BYTE + | INTBACK__IREG1__PORT1_15BYTE + ); + smpc.reg.IREG[2].val = INTBACK__IREG2__MAGIC; + + smpc.reg.COMREG = COMREG__INTBACK; } extern "C" @@ -210,6 +229,10 @@ void main() vdp2.reg.CYCB0 = 0xffff'ffff; vdp2.reg.CYCB1 = 0x4fff'ffff; + // free-running timer + sh2.reg.TCR = TCR__CKS__INTERNAL_DIV128; + sh2.reg.FTCSR = 0; + // initialize smpc smpc.reg.DDR1 = 0; // INPUT smpc.reg.DDR2 = 0; // INPUT @@ -221,4 +244,6 @@ void main() scu.reg.IST = 0; scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN); + + state.map_ix = map_t::celadon_city; } diff --git a/tools/generate/__main__.py b/tools/generate/__main__.py index b5c67a0..6ea9f34 100644 --- a/tools/generate/__main__.py +++ b/tools/generate/__main__.py @@ -1,6 +1,7 @@ from pathlib import Path from pprint import pprint import io +import sys from parse import parse @@ -12,7 +13,7 @@ def sorted_map_headers(): def includes(): for map_header in sorted_map_headers(): block_path = parse.maps_blocks_list[map_header.blocks()] - yield f'#include "res/{block_path}.h"' + yield f'#include "../res/{block_path}.h"' for tileset_name in sorted(parse.tileset_constants_list): tileset_index = parse.tileset_constants_list[tileset_name] tileset_header = parse.tileset_headers_list[tileset_index] @@ -20,8 +21,8 @@ def includes(): blockset_path = parse.gfx_tilesets_list[tileset_header.blockset()] gfx_path = parse.gfx_tilesets_list[tileset_header.gfx()] - yield f'#include "res/{blockset_path}.h"' - yield f'#include "res/{gfx_path}.h"' + yield f'#include "../res/{blockset_path}.h"' + yield f'#include "../res/{gfx_path}.h"' yield "" def struct_start_size_t(): @@ -98,6 +99,9 @@ def blockset_tileset(name: str): "}," ] +def tilesets_header(): + yield "extern const tileset_t tilesets[];" + def tilesets(): yield "const tileset_t tilesets[] = {" for tileset in sorted(parse.tileset_constants_list): @@ -118,6 +122,9 @@ def map(map_header): "},", ] +def maps_header(): + yield "extern const map_t maps[];" + def maps(): yield "const map_t maps[] = {" for map_header in sorted_map_headers(): @@ -147,24 +154,42 @@ def renderer(): return _render(out, lines) return render, out -def generate(): - #pprint(parse.maps_blocks_list) - #pprint(parse.map_headers) - #pprint(parse.tileset_constants_list) - #pprint(parse.tileset_headers_list) - #pprint(parse.gfx_tilesets_list) +def generate_maps_header(): render, out = renderer() - render(includes()) render(struct_start_size_t()) render(struct_tileset_t()) render(struct_map_t()) + render(tilesets_header()); + render(maps_header()); + return out + +def include_maps_header(): + yield '#include "maps.hpp"' + yield "" + +def generate_maps_source(): + render, out = renderer() + render(include_maps_header()) render(tilesets()) render(maps()) + return out - print(out.getvalue(), end='') +def generate(base_path): + files = [ + (generate_maps_header, "maps.hpp"), + (generate_maps_source, "maps.cpp"), + ] -generate() + for func, filename in files: + path = base_path / filename + with open(path, 'w') as f: + f.write(func().getvalue()) + print(path) + +# sys.argv[1] is secretly used in parse +base_path = Path(sys.argv[2]) +generate(base_path) """ map_headers[0].tileset == 'OVERWORLD' diff --git a/tools/parse/map_header.py b/tools/parse/map_header.py index c1d3fcb..e053a40 100644 --- a/tools/parse/map_header.py +++ b/tools/parse/map_header.py @@ -80,5 +80,7 @@ def parse(path): def parse_all(prefix): base_path = prefix / 'data/maps/headers' - paths = (p for p in base_path.iterdir() if p.is_file()) + paths = [p for p in base_path.iterdir() if p.is_file()] + from pprint import pprint + pprint(paths) return [parse(path) for path in paths]