From 5f61aaa4837ac52fe61657bcb57f8ae697799b76 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 24 Aug 2025 22:16:29 -0500 Subject: [PATCH] dreamcast2: add framebuffer_shaded example --- dreamcast2/Makefile | 33 +- dreamcast2/addresses.lds | 32 + dreamcast2/base.mk | 74 ++ dreamcast2/binary.mk | 29 + dreamcast2/common.lds | 58 ++ dreamcast2/debug.lds | 48 ++ dreamcast2/example/example.mk | 9 + dreamcast2/example/framebuffer_shaded.cpp | 36 + dreamcast2/holly/holly.hpp | 323 ++++---- dreamcast2/holly/holly_bits.hpp | 6 +- dreamcast2/main.lds | 10 + dreamcast2/reg.hpp | 2 + dreamcast2/regs.mk | 30 + dreamcast2/regs/block_regs.py | 28 +- dreamcast2/regs/holly.py | 18 - dreamcast2/regs/holly/holly.csv | 6 +- dreamcast2/regs/holly/holly.ods | Bin 23503 -> 32107 bytes .../regs/{holly_bits.py => render_bits.py} | 19 +- dreamcast2/regs/render_block_regs.py | 32 + dreamcast2/regs/render_sh7091.py | 55 ++ dreamcast2/regs/sh7091.py | 145 ---- dreamcast2/regs/systembus/systembus_bits.csv | 67 ++ dreamcast2/runtime.cpp | 59 ++ dreamcast2/sh7091/sh7091.hpp | 715 +++++++++--------- dreamcast2/sh7091/store_queue_transfer.hpp | 12 +- dreamcast2/start.s | 41 + dreamcast2/symbols.lds | 21 + dreamcast2/systembus/systembus.hpp | 599 +++++++-------- dreamcast2/systembus/systembus_bits.hpp | 89 +++ 29 files changed, 1553 insertions(+), 1043 deletions(-) create mode 100644 dreamcast2/addresses.lds create mode 100644 dreamcast2/base.mk create mode 100644 dreamcast2/binary.mk create mode 100644 dreamcast2/common.lds create mode 100644 dreamcast2/debug.lds create mode 100644 dreamcast2/example/example.mk create mode 100644 dreamcast2/example/framebuffer_shaded.cpp create mode 100644 dreamcast2/main.lds create mode 100644 dreamcast2/regs.mk delete mode 100644 dreamcast2/regs/holly.py rename dreamcast2/regs/{holly_bits.py => render_bits.py} (92%) create mode 100644 dreamcast2/regs/render_block_regs.py create mode 100644 dreamcast2/regs/render_sh7091.py delete mode 100644 dreamcast2/regs/sh7091.py create mode 100644 dreamcast2/regs/systembus/systembus_bits.csv create mode 100644 dreamcast2/runtime.cpp create mode 100644 dreamcast2/start.s create mode 100644 dreamcast2/symbols.lds create mode 100644 dreamcast2/systembus/systembus_bits.hpp diff --git a/dreamcast2/Makefile b/dreamcast2/Makefile index 6f0774a..5f4be2d 100644 --- a/dreamcast2/Makefile +++ b/dreamcast2/Makefile @@ -1,30 +1,9 @@ -%.csv: %.ods - libreoffice --headless --convert-to csv:"Text - txt - csv (StarCalc)":44,34,76,,,,true --outdir $(dir $@) $< +include base.mk +OPT = -O2 -# HOLLY +MAKEFILE_PATH := $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST))))) +CFLAGS += -I$(MAKEFILE_PATH) +LIB ?= $(MAKEFILE_PATH) -holly/holly.hpp: regs/holly/holly.csv regs/holly.py - python regs/holly.py $< > $@ - -holly/holly_bits.hpp: regs/holly/holly_bits.csv regs/holly_bits.py - python regs/holly_bits.py $< holly > $@ - -holly/region_array_bits.hpp: regs/holly/region_array_bits.csv regs/holly_bits.py - python regs/holly_bits.py $< holly region_array > $@ - -# SH7091 - -sh7091/sh7091.hpp: regs/sh7091/sh7091.csv regs/sh7091.py - python regs/sh7091.py $< > $@ - -sh7091/sh7091_bits.hpp: regs/sh7091/sh7091_bits.csv regs/holly_bits.py - python regs/holly_bits.py $< sh7091 > $@ - -# SYSTEMBUS - -systembus/systembus.hpp: regs/systembus/systembus.csv regs/holly.py - python regs/holly.py $< > $@ - -systembus/systembus_bits.hpp: regs/systembus/systembus_bits.csv regs/holly_bits.py - python regs/holly_bits.py $< system > $@ +include example/example.mk diff --git a/dreamcast2/addresses.lds b/dreamcast2/addresses.lds new file mode 100644 index 0000000..1cd560c --- /dev/null +++ b/dreamcast2/addresses.lds @@ -0,0 +1,32 @@ +system_boot_rom = 0xa0000000; + +system = 0xa05f6800; +maple_if = 0xa05f6c00; +gdrom_if = 0xa05f7000; +g1_if = 0xa05f7400; +g2_if = 0xa05f7800; +pvr_if = 0xa05f7c00; +holly = 0xa05f8000; +modem = 0xa0600000; +aica_sound = 0xa0700000; +aica_rtc = 0xa0710000; + +system_boot_rom = 0xa0000000; +aica_wave_memory = 0xa0800000; +texture_memory64 = 0xa4000000; +texture_memory32 = 0xa5000000; +system_memory = 0xac000000; +ta_fifo_polygon_converter = 0x10000000; +ta_fifo_yuv_converter = 0x10800000; +ta_fifo_texture_memory = 0x11000000; +ta_fifo_polygon_converter_mirror = 0x12000000; +ta_fifo_yuv_converter_mirror = 0x12800000; +ta_fifo_texture_memory_mirror = 0x13000000; + +store_queue = 0xe0000000; + +sh7091_ic_a = 0xf0000000; +sh7091_ic_d = 0xf1000000; +sh7091_oc_a = 0xf4000000; +sh7091_oc_d = 0xf5000000; +sh7091 = 0xff000000; diff --git a/dreamcast2/base.mk b/dreamcast2/base.mk new file mode 100644 index 0000000..6af92e5 --- /dev/null +++ b/dreamcast2/base.mk @@ -0,0 +1,74 @@ +################################################################################ +# architecture flags +################################################################################ + +AARCH = --isa=sh4 --little + +CARCH ?= -m4-single-only -ml +CFLAGS += -mfsca -mfsrra -funsafe-math-optimizations -ffast-math + +OBJARCH = -O elf32-shl -B sh4 + +TARGET = sh4-none-elf- + +################################################################################ +# architecture-agnostic flags +################################################################################ + +DEBUG = -g -gdwarf-4 + +AFLAGS += --fatal-warnings + +CSTD ?= -std=gnu23 + +CXXSTD ?= -std=c++23 + +CFLAGS += -ffreestanding -nostdlib -fno-builtin +CFLAGS += -falign-functions=4 +CFLAGS += -ffunction-sections -fdata-sections -fshort-enums +CFLAGS += -Wall -Werror -Wfatal-errors -Winline +CFLAGS += -Wno-array-bounds +CFLAGS += -Wno-error=maybe-uninitialized +CFLAGS += -Wno-error=unused-but-set-variable +CFLAGS += -Wno-error=unused-variable +CFLAGS += -Wno-error=unused-function +CFLAGS += -D__dreamcast__ + +CXXFLAGS += -fno-exceptions -fno-non-call-exceptions -fno-rtti -fno-threadsafe-statics + +LDFLAGS += --gc-sections --no-warn-rwx-segment --print-memory-usage --entry=_start --orphan-handling=error + +DEPFLAGS = -MMD -MP + +################################################################################ +# toolchain +################################################################################ + +CC = $(TARGET)gcc +CXX = $(TARGET)g++ +AS = $(TARGET)as +LD = $(TARGET)ld +OBJCOPY = $(TARGET)objcopy +OBJDUMP = $(TARGET)objdump + +################################################################################ +# base rules +################################################################################ + +%.o: %.s + $(AS) $(AARCH) $(AFLAGS) $(DEBUG) $< -o $@ + +%.o: %.c + $(CC) $(CARCH) $(CFLAGS) $(CSTD) $(OPT) $(DEBUG) $(DEPFLAGS) -MF ${<}.d -c $< -o $@ + +%.o: %.cpp + $(CXX) $(CARCH) $(CFLAGS) $(CXXSTD) $(CXXFLAGS) $(OPT) $(DEBUG) $(DEPFLAGS) -MF ${<}.d -c $< -o $@ + +%.elf: + $(LD) $(LDFLAGS) -L $(LIB) -T $(LDSCRIPT) $^ -o $@ + +%.bin: %.elf + $(OBJCOPY) -O binary $< $@ + du -b $@ + +-include $(shell find -type f -name '*.d') diff --git a/dreamcast2/binary.mk b/dreamcast2/binary.mk new file mode 100644 index 0000000..1e6ddc2 --- /dev/null +++ b/dreamcast2/binary.mk @@ -0,0 +1,29 @@ +define BUILD_BINARY_O + $(OBJCOPY) \ + -I binary $(OBJARCH) \ + --rename-section .data=.data.$(basename $@) \ + $< $@ +endef + +makefile_path := $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) +makefile_relative = $(shell realpath --relative-to $(makefile_path) $(1)) +as_obj_binary = _binary_$(subst -,_,$(subst .,_,$(subst /,_,$(subst .h,,$(call makefile_relative,$(1)))))) + +define BUILD_BINARY_H + @echo gen $(call makefile_relative,$@) + @echo '#pragma once' > $@ + @echo '' >> $@ + @echo '#include ' >> $@ + @echo '' >> $@ + @echo '#ifdef __cplusplus' >> $@ + @echo 'extern "C" {' >> $@ + @echo '#endif' >> $@ + @echo '' >> $@ + @echo 'extern uint32_t $(call as_obj_binary,$@)_start __asm("$(call as_obj_binary,$@)_start");' >> $@ + @echo 'extern uint32_t $(call as_obj_binary,$@)_end __asm("$(call as_obj_binary,$@)_end");' >> $@ + @echo 'extern uint32_t $(call as_obj_binary,$@)_size __asm("$(call as_obj_binary,$@)_size");' >> $@ + @echo '' >> $@ + @echo '#ifdef __cplusplus' >> $@ + @echo '}' >> $@ + @echo '#endif' >> $@ +endef diff --git a/dreamcast2/common.lds b/dreamcast2/common.lds new file mode 100644 index 0000000..ad18b42 --- /dev/null +++ b/dreamcast2/common.lds @@ -0,0 +1,58 @@ +SECTIONS +{ + . = ORIGIN(p2ram); + + .text.start : + { + KEEP(*(.text.start)) + *(.text.startup.*) + } > p2ram AT>p1ram + + . = ORIGIN(p1ram) + (. - ORIGIN(p2ram)); + + .text : + { + *(.text.*) + *(.text) + } > p1ram + + .data : + { + *(.data) + *(.data.*) + } > p1ram + + .rodata : + { + *(.rodata) + *(.rodata.*) + } > p1ram + + .ctors ALIGN(4) : + { + KEEP(*(.ctors)) + KEEP(*(.ctors.*)) + } > p1ram + + .text.vbr : + { + __vbr100 = .; + KEEP(*(.vbr.100)) + . = __vbr100 + 0x300; + KEEP(*(.vbr.400)) + . = __vbr100 + 0x500; + KEEP(*(.vbr.600)) + } > p1ram + + .bss ALIGN(32) (NOLOAD) : + { + *(.bss) + *(.bss.*) + *(COMMON) + } > p1ram + + INCLUDE "debug.lds" +} + +INCLUDE "symbols.lds" +INCLUDE "addresses.lds" diff --git a/dreamcast2/debug.lds b/dreamcast2/debug.lds new file mode 100644 index 0000000..71b5eb2 --- /dev/null +++ b/dreamcast2/debug.lds @@ -0,0 +1,48 @@ + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1. */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions. */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2. */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2. */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions. */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3. */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF 5. */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + .debug_sup 0 : { *(.debug_sup) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.rela.*) } diff --git a/dreamcast2/example/example.mk b/dreamcast2/example/example.mk new file mode 100644 index 0000000..1232778 --- /dev/null +++ b/dreamcast2/example/example.mk @@ -0,0 +1,9 @@ +START_OBJ = \ + start.o \ + runtime.o + +FRAMEBUFFER_SHADED_OBJ = \ + example/framebuffer_shaded.o + +example/framebuffer_shaded.elf: LDSCRIPT = $(LIB)/main.lds +example/framebuffer_shaded.elf: $(START_OBJ) $(FRAMEBUFFER_SHADED_OBJ) diff --git a/dreamcast2/example/framebuffer_shaded.cpp b/dreamcast2/example/framebuffer_shaded.cpp new file mode 100644 index 0000000..97364be --- /dev/null +++ b/dreamcast2/example/framebuffer_shaded.cpp @@ -0,0 +1,36 @@ +#include "memorymap.hpp" +#include "holly/holly.hpp" +#include "holly/holly_bits.hpp" + +void main() +{ + volatile uint32_t * framebuffer = (volatile uint32_t * )texture_memory32; + + for (int y = 0; y < 480; y++) { + for (int x = 0; x < 640; x++) { + int red = (y % 255); + int blue = (x % 255); + + framebuffer[y * 640 + x] = (red << 16) | (blue << 0); + } + } + + using holly::holly; + using namespace holly; + + holly.FB_R_CTRL + = fb_r_ctrl::vclk_div::pclk_vclk_1 + | fb_r_ctrl::fb_depth::xrgb0888 + | fb_r_ctrl::fb_enable; + + int fb_y_size = 480 - 1; + int bytes_per_pixel = 4; + int fb_x_size = ((640 * bytes_per_pixel) / 4) - 1; + holly.FB_R_SIZE + = fb_r_size::fb_modulus(1) + | fb_r_size::fb_y_size(fb_y_size) + | fb_r_size::fb_x_size(fb_x_size); + + // the framebuffer is at the start of texture memory (texture memory address 0) + holly.FB_R_SOF1 = 0; +} diff --git a/dreamcast2/holly/holly.hpp b/dreamcast2/holly/holly.hpp index 25b71ca..1e2d03f 100644 --- a/dreamcast2/holly/holly.hpp +++ b/dreamcast2/holly/holly.hpp @@ -2,165 +2,166 @@ #include "reg.hpp" -struct holly_reg { - reg32 ID; /* Device ID */ - reg32 REVISION; /* Revision Number */ - reg32 SOFTRESET; /* CORE & TA software reset */ - reg8 _pad0[8]; - reg32 STARTRENDER; /* Drawing start */ - reg32 TEST_SELECT; /* Test (writing this register is prohibited) */ - reg8 _pad1[4]; - reg32 PARAM_BASE; /* Base address for ISP parameters */ - reg8 _pad2[8]; - reg32 REGION_BASE; /* Base address for Region Array */ - reg32 SPAN_SORT_CFG; /* Span Sorter control */ - reg8 _pad3[12]; - reg32 VO_BORDER_COL; /* Border area color */ - reg32 FB_R_CTRL; /* Frame buffer read control */ - reg32 FB_W_CTRL; /* Frame buffer write control */ - reg32 FB_W_LINESTRIDE; /* Frame buffer line stride */ - reg32 FB_R_SOF1; /* Read start address for field - 1/strip - 1 */ - reg32 FB_R_SOF2; /* Read start address for field - 2/strip - 2 */ - reg8 _pad4[4]; - reg32 FB_R_SIZE; /* Frame buffer XY size */ - reg32 FB_W_SOF1; /* Write start address for field - 1/strip - 1 */ - reg32 FB_W_SOF2; /* Write start address for field - 2/strip - 2 */ - reg32 FB_X_CLIP; /* Pixel clip X coordinate */ - reg32 FB_Y_CLIP; /* Pixel clip Y coordinate */ - reg8 _pad5[4]; - reg32 FPU_SHAD_SCALE; /* Intensity Volume mode */ - reg32 FPU_CULL_VAL; /* Comparison value for culling */ - reg32 FPU_PARAM_CFG; /* Parameter read control */ - reg32 HALF_OFFSET; /* Pixel sampling control */ - reg32 FPU_PERP_VAL; /* Comparison value for perpendicular polygons */ - reg32 ISP_BACKGND_D; /* Background surface depth */ - reg32 ISP_BACKGND_T; /* Background surface tag */ - reg8 _pad6[8]; - reg32 ISP_FEED_CFG; /* Translucent polygon sort mode */ - reg8 _pad7[4]; - reg32 SDRAM_REFRESH; /* Texture memory refresh counter */ - reg32 SDRAM_ARB_CFG; /* Texture memory arbiter control */ - reg32 SDRAM_CFG; /* Texture memory control */ - reg8 _pad8[4]; - reg32 FOG_COL_RAM; /* Color for Look Up table Fog */ - reg32 FOG_COL_VERT; /* Color for vertex Fog */ - reg32 FOG_DENSITY; /* Fog scale value */ - reg32 FOG_CLAMP_MAX; /* Color clamping maximum value */ - reg32 FOG_CLAMP_MIN; /* Color clamping minimum value */ - reg32 SPG_TRIGGER_POS; /* External trigger signal HV counter value */ - reg32 SPG_HBLANK_INT; /* H-blank interrupt control */ - reg32 SPG_VBLANK_INT; /* V-blank interrupt control */ - reg32 SPG_CONTROL; /* Sync pulse generator control */ - reg32 SPG_HBLANK; /* H-blank control */ - reg32 SPG_LOAD; /* HV counter load value */ - reg32 SPG_VBLANK; /* V-blank control */ - reg32 SPG_WIDTH; /* Sync width control */ - reg32 TEXT_CONTROL; /* Texturing control */ - reg32 VO_CONTROL; /* Video output control */ - reg32 VO_STARTX; /* Video output start X position */ - reg32 VO_STARTY; /* Video output start Y position */ - reg32 SCALER_CTL; /* X & Y scaler control */ - reg8 _pad9[16]; - reg32 PAL_RAM_CTRL; /* Palette RAM control */ - reg32 SPG_STATUS; /* Sync pulse generator status */ - reg32 FB_BURSTCTRL; /* Frame buffer burst control */ - reg32 FB_C_SOF; /* Current frame buffer start address */ - reg32 Y_COEFF; /* Y scaling coefficent */ - reg32 PT_ALPHA_REF; /* Alpha value for Punch Through polygon comparison */ - reg8 _pad10[4]; - reg32 TA_OL_BASE; /* Object List write start address */ - reg32 TA_ISP_BASE; /* ISP/TSP Parameter write start address */ - reg32 TA_OL_LIMIT; /* Object List write limit address */ - reg32 TA_ISP_LIMIT; /* ISP/TSP Parameter limit address */ - reg32 TA_NEXT_OPB; /* Start address for the Object Pointer Block */ - reg32 TA_ITP_CURRENT; /* Starting address where the next ISP/TSP Parameters are stored */ - reg32 TA_GLOB_TILE_CLIP; /* Global Tile Clip control */ - reg32 TA_ALLOC_CTRL; /* Object list control */ - reg32 TA_LIST_INIT; /* TA initialization */ - reg32 TA_YUV_TEX_BASE; /* YUV422 texture write start address */ - reg32 TA_YUV_TEX_CTRL; /* YUV converter control */ - reg32 TA_YUV_TEX_CNT; /* YUV converter macro block counter value */ - reg8 _pad11[12]; - reg32 TA_LIST_CONT; /* TA continuation processing */ - reg32 TA_NEXT_OPB_INIT; /* Additional OPB starting address */ - reg8 _pad12[152]; - reg32 FOG_TABLE[128]; /* Look-up table fog data */ - reg8 _pad13[512]; - reg32 TA_OL_POINTERS[600]; /* TA Object List Pointer data */ - reg8 _pad14[160]; - reg32 PALETTE_RAM[1024]; /* Palette RAM */ -}; +namespace holly { + struct holly_reg { + reg32 ID; /* Device ID */ + reg32 REVISION; /* Revision Number */ + reg32 SOFTRESET; /* CORE & TA software reset */ + reg8 _pad0[8]; + reg32 STARTRENDER; /* Drawing start */ + reg32 TEST_SELECT; /* Test (writing this register is prohibited) */ + reg8 _pad1[4]; + reg32 PARAM_BASE; /* Base address for ISP parameters */ + reg8 _pad2[8]; + reg32 REGION_BASE; /* Base address for Region Array */ + reg32 SPAN_SORT_CFG; /* Span Sorter control */ + reg8 _pad3[12]; + reg32 VO_BORDER_COL; /* Border area color */ + reg32 FB_R_CTRL; /* Frame buffer read control */ + reg32 FB_W_CTRL; /* Frame buffer write control */ + reg32 FB_W_LINESTRIDE; /* Frame buffer line stride */ + reg32 FB_R_SOF1; /* Read start address for field - 1/strip - 1 */ + reg32 FB_R_SOF2; /* Read start address for field - 2/strip - 2 */ + reg8 _pad4[4]; + reg32 FB_R_SIZE; /* Frame buffer XY size */ + reg32 FB_W_SOF1; /* Write start address for field - 1/strip - 1 */ + reg32 FB_W_SOF2; /* Write start address for field - 2/strip - 2 */ + reg32 FB_X_CLIP; /* Pixel clip X coordinate */ + reg32 FB_Y_CLIP; /* Pixel clip Y coordinate */ + reg8 _pad5[4]; + reg32 FPU_SHAD_SCALE; /* Intensity Volume mode */ + reg32f FPU_CULL_VAL; /* Comparison value for culling */ + reg32 FPU_PARAM_CFG; /* Parameter read control */ + reg32 HALF_OFFSET; /* Pixel sampling control */ + reg32f FPU_PERP_VAL; /* Comparison value for perpendicular polygons */ + reg32f ISP_BACKGND_D; /* Background surface depth */ + reg32 ISP_BACKGND_T; /* Background surface tag */ + reg8 _pad6[8]; + reg32 ISP_FEED_CFG; /* Translucent polygon sort mode */ + reg8 _pad7[4]; + reg32 SDRAM_REFRESH; /* Texture memory refresh counter */ + reg32 SDRAM_ARB_CFG; /* Texture memory arbiter control */ + reg32 SDRAM_CFG; /* Texture memory control */ + reg8 _pad8[4]; + reg32 FOG_COL_RAM; /* Color for Look Up table Fog */ + reg32 FOG_COL_VERT; /* Color for vertex Fog */ + reg32 FOG_DENSITY; /* Fog scale value */ + reg32 FOG_CLAMP_MAX; /* Color clamping maximum value */ + reg32 FOG_CLAMP_MIN; /* Color clamping minimum value */ + reg32 SPG_TRIGGER_POS; /* External trigger signal HV counter value */ + reg32 SPG_HBLANK_INT; /* H-blank interrupt control */ + reg32 SPG_VBLANK_INT; /* V-blank interrupt control */ + reg32 SPG_CONTROL; /* Sync pulse generator control */ + reg32 SPG_HBLANK; /* H-blank control */ + reg32 SPG_LOAD; /* HV counter load value */ + reg32 SPG_VBLANK; /* V-blank control */ + reg32 SPG_WIDTH; /* Sync width control */ + reg32 TEXT_CONTROL; /* Texturing control */ + reg32 VO_CONTROL; /* Video output control */ + reg32 VO_STARTX; /* Video output start X position */ + reg32 VO_STARTY; /* Video output start Y position */ + reg32 SCALER_CTL; /* X & Y scaler control */ + reg8 _pad9[16]; + reg32 PAL_RAM_CTRL; /* Palette RAM control */ + reg32 SPG_STATUS; /* Sync pulse generator status */ + reg32 FB_BURSTCTRL; /* Frame buffer burst control */ + reg32 FB_C_SOF; /* Current frame buffer start address */ + reg32 Y_COEFF; /* Y scaling coefficent */ + reg32 PT_ALPHA_REF; /* Alpha value for Punch Through polygon comparison */ + reg8 _pad10[4]; + reg32 TA_OL_BASE; /* Object List write start address */ + reg32 TA_ISP_BASE; /* ISP/TSP Parameter write start address */ + reg32 TA_OL_LIMIT; /* Object List write limit address */ + reg32 TA_ISP_LIMIT; /* ISP/TSP Parameter limit address */ + reg32 TA_NEXT_OPB; /* Start address for the Object Pointer Block */ + reg32 TA_ITP_CURRENT; /* Starting address where the next ISP/TSP Parameters are stored */ + reg32 TA_GLOB_TILE_CLIP; /* Global Tile Clip control */ + reg32 TA_ALLOC_CTRL; /* Object list control */ + reg32 TA_LIST_INIT; /* TA initialization */ + reg32 TA_YUV_TEX_BASE; /* YUV422 texture write start address */ + reg32 TA_YUV_TEX_CTRL; /* YUV converter control */ + reg32 TA_YUV_TEX_CNT; /* YUV converter macro block counter value */ + reg8 _pad11[12]; + reg32 TA_LIST_CONT; /* TA continuation processing */ + reg32 TA_NEXT_OPB_INIT; /* Additional OPB starting address */ + reg8 _pad12[152]; + reg32 FOG_TABLE[128]; /* Look-up table fog data */ + reg8 _pad13[512]; + reg32 TA_OL_POINTERS[600]; /* TA Object List Pointer data */ + reg8 _pad14[160]; + reg32 PALETTE_RAM[1024]; /* Palette RAM */ + }; + static_assert((offsetof (struct holly_reg, ID)) == 0x0); + static_assert((offsetof (struct holly_reg, REVISION)) == 0x4); + static_assert((offsetof (struct holly_reg, SOFTRESET)) == 0x8); + static_assert((offsetof (struct holly_reg, STARTRENDER)) == 0x14); + static_assert((offsetof (struct holly_reg, TEST_SELECT)) == 0x18); + static_assert((offsetof (struct holly_reg, PARAM_BASE)) == 0x20); + static_assert((offsetof (struct holly_reg, REGION_BASE)) == 0x2c); + static_assert((offsetof (struct holly_reg, SPAN_SORT_CFG)) == 0x30); + static_assert((offsetof (struct holly_reg, VO_BORDER_COL)) == 0x40); + static_assert((offsetof (struct holly_reg, FB_R_CTRL)) == 0x44); + static_assert((offsetof (struct holly_reg, FB_W_CTRL)) == 0x48); + static_assert((offsetof (struct holly_reg, FB_W_LINESTRIDE)) == 0x4c); + static_assert((offsetof (struct holly_reg, FB_R_SOF1)) == 0x50); + static_assert((offsetof (struct holly_reg, FB_R_SOF2)) == 0x54); + static_assert((offsetof (struct holly_reg, FB_R_SIZE)) == 0x5c); + static_assert((offsetof (struct holly_reg, FB_W_SOF1)) == 0x60); + static_assert((offsetof (struct holly_reg, FB_W_SOF2)) == 0x64); + static_assert((offsetof (struct holly_reg, FB_X_CLIP)) == 0x68); + static_assert((offsetof (struct holly_reg, FB_Y_CLIP)) == 0x6c); + static_assert((offsetof (struct holly_reg, FPU_SHAD_SCALE)) == 0x74); + static_assert((offsetof (struct holly_reg, FPU_CULL_VAL)) == 0x78); + static_assert((offsetof (struct holly_reg, FPU_PARAM_CFG)) == 0x7c); + static_assert((offsetof (struct holly_reg, HALF_OFFSET)) == 0x80); + static_assert((offsetof (struct holly_reg, FPU_PERP_VAL)) == 0x84); + static_assert((offsetof (struct holly_reg, ISP_BACKGND_D)) == 0x88); + static_assert((offsetof (struct holly_reg, ISP_BACKGND_T)) == 0x8c); + static_assert((offsetof (struct holly_reg, ISP_FEED_CFG)) == 0x98); + static_assert((offsetof (struct holly_reg, SDRAM_REFRESH)) == 0xa0); + static_assert((offsetof (struct holly_reg, SDRAM_ARB_CFG)) == 0xa4); + static_assert((offsetof (struct holly_reg, SDRAM_CFG)) == 0xa8); + static_assert((offsetof (struct holly_reg, FOG_COL_RAM)) == 0xb0); + static_assert((offsetof (struct holly_reg, FOG_COL_VERT)) == 0xb4); + static_assert((offsetof (struct holly_reg, FOG_DENSITY)) == 0xb8); + static_assert((offsetof (struct holly_reg, FOG_CLAMP_MAX)) == 0xbc); + static_assert((offsetof (struct holly_reg, FOG_CLAMP_MIN)) == 0xc0); + static_assert((offsetof (struct holly_reg, SPG_TRIGGER_POS)) == 0xc4); + static_assert((offsetof (struct holly_reg, SPG_HBLANK_INT)) == 0xc8); + static_assert((offsetof (struct holly_reg, SPG_VBLANK_INT)) == 0xcc); + static_assert((offsetof (struct holly_reg, SPG_CONTROL)) == 0xd0); + static_assert((offsetof (struct holly_reg, SPG_HBLANK)) == 0xd4); + static_assert((offsetof (struct holly_reg, SPG_LOAD)) == 0xd8); + static_assert((offsetof (struct holly_reg, SPG_VBLANK)) == 0xdc); + static_assert((offsetof (struct holly_reg, SPG_WIDTH)) == 0xe0); + static_assert((offsetof (struct holly_reg, TEXT_CONTROL)) == 0xe4); + static_assert((offsetof (struct holly_reg, VO_CONTROL)) == 0xe8); + static_assert((offsetof (struct holly_reg, VO_STARTX)) == 0xec); + static_assert((offsetof (struct holly_reg, VO_STARTY)) == 0xf0); + static_assert((offsetof (struct holly_reg, SCALER_CTL)) == 0xf4); + static_assert((offsetof (struct holly_reg, PAL_RAM_CTRL)) == 0x108); + static_assert((offsetof (struct holly_reg, SPG_STATUS)) == 0x10c); + static_assert((offsetof (struct holly_reg, FB_BURSTCTRL)) == 0x110); + static_assert((offsetof (struct holly_reg, FB_C_SOF)) == 0x114); + static_assert((offsetof (struct holly_reg, Y_COEFF)) == 0x118); + static_assert((offsetof (struct holly_reg, PT_ALPHA_REF)) == 0x11c); + static_assert((offsetof (struct holly_reg, TA_OL_BASE)) == 0x124); + static_assert((offsetof (struct holly_reg, TA_ISP_BASE)) == 0x128); + static_assert((offsetof (struct holly_reg, TA_OL_LIMIT)) == 0x12c); + static_assert((offsetof (struct holly_reg, TA_ISP_LIMIT)) == 0x130); + static_assert((offsetof (struct holly_reg, TA_NEXT_OPB)) == 0x134); + static_assert((offsetof (struct holly_reg, TA_ITP_CURRENT)) == 0x138); + static_assert((offsetof (struct holly_reg, TA_GLOB_TILE_CLIP)) == 0x13c); + static_assert((offsetof (struct holly_reg, TA_ALLOC_CTRL)) == 0x140); + static_assert((offsetof (struct holly_reg, TA_LIST_INIT)) == 0x144); + static_assert((offsetof (struct holly_reg, TA_YUV_TEX_BASE)) == 0x148); + static_assert((offsetof (struct holly_reg, TA_YUV_TEX_CTRL)) == 0x14c); + static_assert((offsetof (struct holly_reg, TA_YUV_TEX_CNT)) == 0x150); + static_assert((offsetof (struct holly_reg, TA_LIST_CONT)) == 0x160); + static_assert((offsetof (struct holly_reg, TA_NEXT_OPB_INIT)) == 0x164); + static_assert((offsetof (struct holly_reg, FOG_TABLE)) == 0x200); + static_assert((offsetof (struct holly_reg, TA_OL_POINTERS)) == 0x600); + static_assert((offsetof (struct holly_reg, PALETTE_RAM)) == 0x1000); -static_assert((offsetof (struct holly_reg, ID)) == 0x0); -static_assert((offsetof (struct holly_reg, REVISION)) == 0x4); -static_assert((offsetof (struct holly_reg, SOFTRESET)) == 0x8); -static_assert((offsetof (struct holly_reg, STARTRENDER)) == 0x14); -static_assert((offsetof (struct holly_reg, TEST_SELECT)) == 0x18); -static_assert((offsetof (struct holly_reg, PARAM_BASE)) == 0x20); -static_assert((offsetof (struct holly_reg, REGION_BASE)) == 0x2c); -static_assert((offsetof (struct holly_reg, SPAN_SORT_CFG)) == 0x30); -static_assert((offsetof (struct holly_reg, VO_BORDER_COL)) == 0x40); -static_assert((offsetof (struct holly_reg, FB_R_CTRL)) == 0x44); -static_assert((offsetof (struct holly_reg, FB_W_CTRL)) == 0x48); -static_assert((offsetof (struct holly_reg, FB_W_LINESTRIDE)) == 0x4c); -static_assert((offsetof (struct holly_reg, FB_R_SOF1)) == 0x50); -static_assert((offsetof (struct holly_reg, FB_R_SOF2)) == 0x54); -static_assert((offsetof (struct holly_reg, FB_R_SIZE)) == 0x5c); -static_assert((offsetof (struct holly_reg, FB_W_SOF1)) == 0x60); -static_assert((offsetof (struct holly_reg, FB_W_SOF2)) == 0x64); -static_assert((offsetof (struct holly_reg, FB_X_CLIP)) == 0x68); -static_assert((offsetof (struct holly_reg, FB_Y_CLIP)) == 0x6c); -static_assert((offsetof (struct holly_reg, FPU_SHAD_SCALE)) == 0x74); -static_assert((offsetof (struct holly_reg, FPU_CULL_VAL)) == 0x78); -static_assert((offsetof (struct holly_reg, FPU_PARAM_CFG)) == 0x7c); -static_assert((offsetof (struct holly_reg, HALF_OFFSET)) == 0x80); -static_assert((offsetof (struct holly_reg, FPU_PERP_VAL)) == 0x84); -static_assert((offsetof (struct holly_reg, ISP_BACKGND_D)) == 0x88); -static_assert((offsetof (struct holly_reg, ISP_BACKGND_T)) == 0x8c); -static_assert((offsetof (struct holly_reg, ISP_FEED_CFG)) == 0x98); -static_assert((offsetof (struct holly_reg, SDRAM_REFRESH)) == 0xa0); -static_assert((offsetof (struct holly_reg, SDRAM_ARB_CFG)) == 0xa4); -static_assert((offsetof (struct holly_reg, SDRAM_CFG)) == 0xa8); -static_assert((offsetof (struct holly_reg, FOG_COL_RAM)) == 0xb0); -static_assert((offsetof (struct holly_reg, FOG_COL_VERT)) == 0xb4); -static_assert((offsetof (struct holly_reg, FOG_DENSITY)) == 0xb8); -static_assert((offsetof (struct holly_reg, FOG_CLAMP_MAX)) == 0xbc); -static_assert((offsetof (struct holly_reg, FOG_CLAMP_MIN)) == 0xc0); -static_assert((offsetof (struct holly_reg, SPG_TRIGGER_POS)) == 0xc4); -static_assert((offsetof (struct holly_reg, SPG_HBLANK_INT)) == 0xc8); -static_assert((offsetof (struct holly_reg, SPG_VBLANK_INT)) == 0xcc); -static_assert((offsetof (struct holly_reg, SPG_CONTROL)) == 0xd0); -static_assert((offsetof (struct holly_reg, SPG_HBLANK)) == 0xd4); -static_assert((offsetof (struct holly_reg, SPG_LOAD)) == 0xd8); -static_assert((offsetof (struct holly_reg, SPG_VBLANK)) == 0xdc); -static_assert((offsetof (struct holly_reg, SPG_WIDTH)) == 0xe0); -static_assert((offsetof (struct holly_reg, TEXT_CONTROL)) == 0xe4); -static_assert((offsetof (struct holly_reg, VO_CONTROL)) == 0xe8); -static_assert((offsetof (struct holly_reg, VO_STARTX)) == 0xec); -static_assert((offsetof (struct holly_reg, VO_STARTY)) == 0xf0); -static_assert((offsetof (struct holly_reg, SCALER_CTL)) == 0xf4); -static_assert((offsetof (struct holly_reg, PAL_RAM_CTRL)) == 0x108); -static_assert((offsetof (struct holly_reg, SPG_STATUS)) == 0x10c); -static_assert((offsetof (struct holly_reg, FB_BURSTCTRL)) == 0x110); -static_assert((offsetof (struct holly_reg, FB_C_SOF)) == 0x114); -static_assert((offsetof (struct holly_reg, Y_COEFF)) == 0x118); -static_assert((offsetof (struct holly_reg, PT_ALPHA_REF)) == 0x11c); -static_assert((offsetof (struct holly_reg, TA_OL_BASE)) == 0x124); -static_assert((offsetof (struct holly_reg, TA_ISP_BASE)) == 0x128); -static_assert((offsetof (struct holly_reg, TA_OL_LIMIT)) == 0x12c); -static_assert((offsetof (struct holly_reg, TA_ISP_LIMIT)) == 0x130); -static_assert((offsetof (struct holly_reg, TA_NEXT_OPB)) == 0x134); -static_assert((offsetof (struct holly_reg, TA_ITP_CURRENT)) == 0x138); -static_assert((offsetof (struct holly_reg, TA_GLOB_TILE_CLIP)) == 0x13c); -static_assert((offsetof (struct holly_reg, TA_ALLOC_CTRL)) == 0x140); -static_assert((offsetof (struct holly_reg, TA_LIST_INIT)) == 0x144); -static_assert((offsetof (struct holly_reg, TA_YUV_TEX_BASE)) == 0x148); -static_assert((offsetof (struct holly_reg, TA_YUV_TEX_CTRL)) == 0x14c); -static_assert((offsetof (struct holly_reg, TA_YUV_TEX_CNT)) == 0x150); -static_assert((offsetof (struct holly_reg, TA_LIST_CONT)) == 0x160); -static_assert((offsetof (struct holly_reg, TA_NEXT_OPB_INIT)) == 0x164); -static_assert((offsetof (struct holly_reg, FOG_TABLE)) == 0x200); -static_assert((offsetof (struct holly_reg, TA_OL_POINTERS)) == 0x600); -static_assert((offsetof (struct holly_reg, PALETTE_RAM)) == 0x1000); - -extern struct holly_reg holly __asm("holly"); + extern struct holly_reg holly __asm("holly"); +} diff --git a/dreamcast2/holly/holly_bits.hpp b/dreamcast2/holly/holly_bits.hpp index fe6dd75..7fb9a5f 100644 --- a/dreamcast2/holly/holly_bits.hpp +++ b/dreamcast2/holly/holly_bits.hpp @@ -140,7 +140,7 @@ namespace holly { } namespace fpu_cull_val { - inline uint32_t culling_comparison_value(float num) { return _i(__builtin_fabsf(num));; } + inline float culling_comparison_value(float num) { return num; } } namespace fpu_param_cfg { @@ -181,11 +181,11 @@ namespace holly { } namespace fpu_perp_val { - inline uint32_t perpendicular_triangle_compare(float num) { return _i(__builtin_fabsf(num));; } + inline float perpendicular_triangle_compare(float num) { return num; } } namespace isp_backgnd_d { - inline uint32_t background_plane_depth(float num) { return _i(num) & 0xfffffff0; } + inline float background_plane_depth(float num) { return num; } } namespace isp_backgnd_t { diff --git a/dreamcast2/main.lds b/dreamcast2/main.lds new file mode 100644 index 0000000..3583424 --- /dev/null +++ b/dreamcast2/main.lds @@ -0,0 +1,10 @@ +OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") +MEMORY +{ + p1ram : ORIGIN = 0x8c010000, LENGTH = 0xff0000 + p2ram : ORIGIN = 0xac010000, LENGTH = 0xff0000 +} + +INCLUDE "common.lds" + +__stack_end = ORIGIN(p1ram) + LENGTH(p1ram) - 0x4000; diff --git a/dreamcast2/reg.hpp b/dreamcast2/reg.hpp index d24bbb1..df02c2e 100644 --- a/dreamcast2/reg.hpp +++ b/dreamcast2/reg.hpp @@ -6,7 +6,9 @@ typedef volatile uint8_t reg8; typedef volatile uint16_t reg16; typedef volatile uint32_t reg32; +typedef volatile float reg32f; static_assert((sizeof (reg8)) == 1); static_assert((sizeof (reg16)) == 2); static_assert((sizeof (reg32)) == 4); +static_assert((sizeof (reg32f)) == 4); diff --git a/dreamcast2/regs.mk b/dreamcast2/regs.mk new file mode 100644 index 0000000..3d20b89 --- /dev/null +++ b/dreamcast2/regs.mk @@ -0,0 +1,30 @@ +%.csv: %.ods + libreoffice --headless --convert-to csv:"Text - txt - csv (StarCalc)":44,34,76,,,,true --outdir $(dir $@) $< + + +# HOLLY + +holly/holly.hpp: regs/holly/holly.csv regs/render_block_regs.py + python regs/render_block_regs.py $< holly > $@ + +holly/holly_bits.hpp: regs/holly/holly_bits.csv regs/render_bits.py + python regs/render_bits.py $< holly > $@ + +holly/region_array_bits.hpp: regs/holly/region_array_bits.csv regs/render_bits.py + python regs/render_bits.py $< holly region_array > $@ + +# SH7091 + +sh7091/sh7091.hpp: regs/sh7091/sh7091.csv regs/sh7091.py + python regs/sh7091.py $< sh7091 > $@ + +sh7091/sh7091_bits.hpp: regs/sh7091/sh7091_bits.csv regs/render_bits.py + python regs/render_bits.py $< sh7091 > $@ + +# SYSTEMBUS + +systembus/systembus.hpp: regs/systembus/systembus.csv regs/render_block_regs.py + python regs/render_block_regs.py $< systembus > $@ + +systembus/systembus_bits.hpp: regs/systembus/systembus_bits.csv regs/render_bits.py + python regs/render_bits.py $< systembus > $@ diff --git a/dreamcast2/regs/block_regs.py b/dreamcast2/regs/block_regs.py index a189e20..017bcd4 100644 --- a/dreamcast2/regs/block_regs.py +++ b/dreamcast2/regs/block_regs.py @@ -1,21 +1,41 @@ import sys +import string from generate import renderer from csv_input import read_input def size_p(size): return size in {1, 2, 4} -def size_to_type(size): +def size_to_type(size, type=None): if size == 1: + assert type is None return "reg8 " elif size == 2: + assert type is None return "reg16" elif size == 4: - return "reg32" + if type == "f": + return "reg32f" + else: + assert type is None + return "reg32" else: raise NotImplemented(size) +def split_integer(s): + acc = [] + for i, c in enumerate(s): + if c in string.digits: + acc.append(c) + else: + return int("".join(acc), 10), s[i:] + return int("".join(acc), 10), None + +def parse_size_type(s): + size, type = split_integer(s) + return size, type + def new_writer(): first_address = 0 next_address = 0 @@ -50,7 +70,7 @@ def new_writer(): assert _address <= 0xffff offset_address = (_offset << 16) address = offset_address | (_address << 0) - size = int(row["size"], 10) + size, size_type = parse_size_type(row["size"]) name = row["name"] description = row["description"] @@ -73,7 +93,7 @@ def new_writer(): def field(): if size_p(size): assert address % size == 0 - type = size_to_type(size) + type = size_to_type(size, size_type) return f"{type} {name};" else: type = size_to_type(4) diff --git a/dreamcast2/regs/holly.py b/dreamcast2/regs/holly.py deleted file mode 100644 index 35ffcae..0000000 --- a/dreamcast2/regs/holly.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys - -from csv_input import read_input -from generate import renderer -from block_regs import new_writer -from block_regs import headers - -def block(): - yield 'extern struct holly_reg holly __asm("holly");' - -input_file = sys.argv[1] -rows = read_input(input_file) -process = new_writer() -render, out = renderer() -render(headers()) -render(process(rows)) -render(block()) -sys.stdout.write(out.getvalue()) diff --git a/dreamcast2/regs/holly/holly.csv b/dreamcast2/regs/holly/holly.csv index 353e47e..2e0a20e 100644 --- a/dreamcast2/regs/holly/holly.csv +++ b/dreamcast2/regs/holly/holly.csv @@ -25,11 +25,11 @@ "holly","006c","4","FB_Y_CLIP","RW","Pixel clip Y coordinate" ,,,,, "holly","0074","4","FPU_SHAD_SCALE","RW","Intensity Volume mode" -"holly","0078","4","FPU_CULL_VAL","RW","Comparison value for culling" +"holly","0078","4f","FPU_CULL_VAL","RW","Comparison value for culling" "holly","007c","4","FPU_PARAM_CFG","RW","Parameter read control" "holly","0080","4","HALF_OFFSET","RW","Pixel sampling control" -"holly","0084","4","FPU_PERP_VAL","RW","Comparison value for perpendicular polygons" -"holly","0088","4","ISP_BACKGND_D","RW","Background surface depth" +"holly","0084","4f","FPU_PERP_VAL","RW","Comparison value for perpendicular polygons" +"holly","0088","4f","ISP_BACKGND_D","RW","Background surface depth" "holly","008c","4","ISP_BACKGND_T","RW","Background surface tag" ,,,,, "holly","0098","4","ISP_FEED_CFG","RW","Translucent polygon sort mode" diff --git a/dreamcast2/regs/holly/holly.ods b/dreamcast2/regs/holly/holly.ods index 5ffe8edefc81fa1dc958637ac8db71b8716ae700..85942f4450d7403bb53be952d40fa02994e34697 100644 GIT binary patch literal 32107 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 ZdJiivnhquW;@8fc^I+ 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

JZCdEC9*ELMFMO(`mYa6b@@cl~f*DQL%rq9uq! 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 diff --git a/dreamcast2/regs/holly_bits.py b/dreamcast2/regs/render_bits.py similarity index 92% rename from dreamcast2/regs/holly_bits.py rename to dreamcast2/regs/render_bits.py index 890d3ae..883704b 100644 --- a/dreamcast2/regs/holly_bits.py +++ b/dreamcast2/regs/render_bits.py @@ -154,29 +154,14 @@ def render_read_only(bit_def): " }" ) -def render_float_mask(mask): - if mask == "float_0_8_23": - return "_i(__builtin_fabsf(num));" - elif mask == "float_1_8_23": - return "_i(num)" - else: - assert mask.startswith("float_") - mask = mask.removeprefix("float_") - sign, exponent, fraction = map(int, mask.split('_')) - assert exponent == 8, exponent - assert sign == 1 - bit_length = (sign + exponent + fraction) - mask = (2 ** bit_length - 1) << (32 - bit_length) - return f"_i(num) & {hex(mask)}" - def render_mask(bit_def): assert bit_def["value"] == "" mask = bit_def["mask"] bits = parse_bit_range(bit_def["bits"]) if mask.startswith("float_"): yield ( - f"inline uint32_t {escape(bit_def['bit_name'])}(float num) {{ " - f"return {render_float_mask(mask)};" + f"inline float {escape(bit_def['bit_name'])}(float num) {{ " + f"return num;" " }" ) else: diff --git a/dreamcast2/regs/render_block_regs.py b/dreamcast2/regs/render_block_regs.py new file mode 100644 index 0000000..bd5b6e2 --- /dev/null +++ b/dreamcast2/regs/render_block_regs.py @@ -0,0 +1,32 @@ +import sys + +from csv_input import read_input +from generate import renderer +from block_regs import new_writer +from block_regs import headers + +def blocks(rows): + blocks = [] + for row in rows: + block = row["block"] + if block not in blocks: + blocks.append(block) + + for block in blocks: + yield f'extern struct {block.lower()}_reg {block.lower()} __asm("{block.lower()}");' + +def namespace(namespace_name, rows): + yield f"namespace {namespace_name} {{" + yield from process(rows) + yield from blocks(rows) + yield "}" + +if __name__ == "__main__": + input_file = sys.argv[1] + namespace_name = sys.argv[2] + rows = read_input(input_file) + process = new_writer() + render, out = renderer() + render(headers()) + render(namespace(namespace_name, rows)) + sys.stdout.write(out.getvalue()) diff --git a/dreamcast2/regs/render_sh7091.py b/dreamcast2/regs/render_sh7091.py new file mode 100644 index 0000000..43bdd40 --- /dev/null +++ b/dreamcast2/regs/render_sh7091.py @@ -0,0 +1,55 @@ +import sys + +from generate import renderer +from csv_input import read_input +from block_regs import new_writer +from block_regs import headers +from block_regs import size_to_type + +def blocks(rows): + stack = [] + last_block = None + for row in rows: + block = row["block"] + if last_block != block: + offset = int(row["offset"], 16) + stack.append((block, offset)) + last_block = block + + yield "struct sh7091_reg {" + last_offset = 0 + last_block = None + reserved_num = 0 + for block, offset in stack: + if offset != last_offset: + assert last_block is not None + type = size_to_type(1) + raw_pad = (offset - last_offset) << 16 + yield f"{type} _pad{reserved_num}[{hex(raw_pad)} - (sizeof (struct {last_block.lower()}_reg))];" + reserved_num += 1 + yield f"struct {block.lower()}_reg {block};" + last_offset = offset + last_block = block + yield "};" + + for block, offset in stack: + yield f"static_assert((offsetof (struct sh7091_reg, {block})) == {hex(offset << 16)});" + + yield "" + yield 'extern struct sh7091_reg sh7091 __asm("sh7091");' + +def namespace(namespace_name, rows): + yield f"namespace {namespace_name} {{" + yield from process(rows) + yield from blocks(rows) + yield "}" + +if __name__ == "__main__": + input_file = sys.argv[1] + namespace_name = sys.argv[2] + rows = read_input(input_file) + process = new_writer() + render, out = renderer() + render(headers()) + render(namespace(namespace_name, rows)) + sys.stdout.write(out.getvalue()) diff --git a/dreamcast2/regs/sh7091.py b/dreamcast2/regs/sh7091.py deleted file mode 100644 index b93e545..0000000 --- a/dreamcast2/regs/sh7091.py +++ /dev/null @@ -1,145 +0,0 @@ -import sys - -from generate import renderer -from csv_input import read_input - -def size_p(size): - return size in {1, 2, 4} - -def size_to_type(size): - if size == 1: - return "reg8 " - elif size == 2: - return "reg16" - elif size == 4: - return "reg32" - else: - raise NotImplemented(size) - -def new_writer(): - first_address = 0 - next_address = 0 - last_block = None - size_total = 0 - reserved_num = 0 - stack = [] - - def terminate(): - nonlocal last_block - nonlocal stack - - if last_block is not None: - yield "};" - for address, name in stack: - yield f"static_assert((offsetof (struct {last_block.lower()}_reg, {name})) == {hex(address - first_address)});" - yield "" - stack = [] - - def process_row(row): - nonlocal first_address - nonlocal next_address - nonlocal last_block - nonlocal reserved_num - nonlocal size_total - nonlocal stack - - block = row["block"] - _offset = int(row["offset"], 16) if "offset" in row else 0 - _address = int(row["address"], 16) - assert _offset <= 0xff - assert _address <= 0xffff - offset_address = (_offset << 16) - address = offset_address | (_address << 0) - size = int(row["size"], 10) - name = row["name"] - description = row["description"] - - if block != last_block: - yield from terminate() - first_address = offset_address - next_address = offset_address - size_total = 0 - reserved_num = 0 - yield f"struct {block.lower()}_reg {{" - - assert address >= next_address, row - if address > next_address: - padding = address - next_address - type = size_to_type(1) - yield f"{type} _pad{reserved_num}[{padding}];" - reserved_num += 1 - size_total += padding - - def field(): - if size_p(size): - assert address % size == 0 - type = size_to_type(size) - return f"{type} {name};" - else: - type = size_to_type(4) - return f"{type} {name}[{size // 4}];" - - yield field().ljust(27) + f"/* {description} */" - - stack.append((address, name)) - next_address = address + size - last_block = block - size_total += size - - def process(rows): - for row in rows: - yield from process_row(row) - yield from terminate() - - return process - -def blocks(rows): - stack = [] - last_block = None - for row in rows: - block = row["block"] - if last_block != block: - offset = int(row["offset"], 16) - stack.append((block, offset)) - last_block = block - - yield "struct sh7091_reg {" - last_offset = 0 - last_block = None - reserved_num = 0 - for block, offset in stack: - if offset != last_offset: - assert last_block is not None - type = size_to_type(1) - raw_pad = (offset - last_offset) << 16 - yield f"{type} _pad{reserved_num}[{hex(raw_pad)} - (sizeof (struct {last_block.lower()}_reg))];" - reserved_num += 1 - yield f"struct {block.lower()}_reg {block};" - last_offset = offset - last_block = block - yield "};" - - for block, offset in stack: - yield f"static_assert((offsetof (struct sh7091_reg, {block})) == {hex(offset << 16)});" - - yield "" - yield 'extern struct sh7091_reg sh7091 __asm("sh7091");' - -def headers(): - yield "#pragma once" - yield "" - yield "#include " - yield "#include " - yield "" - yield '#include "type.hpp"' - yield "" - -if __name__ == "__main__": - input_file = sys.argv[1] - rows = read_input(input_file) - process = new_writer() - render, out = renderer() - render(headers()) - render(process(rows)) - render(blocks(rows)) - sys.stdout.write(out.getvalue()) diff --git a/dreamcast2/regs/systembus/systembus_bits.csv b/dreamcast2/regs/systembus/systembus_bits.csv new file mode 100644 index 0000000..310596b --- /dev/null +++ b/dreamcast2/regs/systembus/systembus_bits.csv @@ -0,0 +1,67 @@ +"register_name","enum_name","bits","bit_name","value","mask","description" +"C2DSTAT",,"31-0","texture_memory_start_address",,"0x13ffffe0", +"C2DLEN",,"23-0","transfer_length",,"0xffffe0", +"C2DST",,"0","start","1",, +,,,,,, +"ISTNRM",,"21","end_of_transferring_punch_through_list","1",, +"ISTNRM",,"20","end_of_dma_sort_dma","1",, +"ISTNRM",,"19","end_of_dma_ch2_dma","1",, +"ISTNRM",,"18","end_of_dma_dev_dma","1",, +"ISTNRM",,"17","end_of_dma_ext_dma2","1",, +"ISTNRM",,"16","end_of_dma_ext_dma1","1",, +"ISTNRM",,"15","end_of_dma_aica_dma","1",, +"ISTNRM",,"14","end_of_dma_gd_dma","1",, +"ISTNRM",,"13","maple_v_blank_over","1",, +"ISTNRM",,"12","end_of_dma_maple_dma","1",, +"ISTNRM",,"11","end_of_dma_pvr_dma","1",, +"ISTNRM",,"10","end_of_transferring_translucent_modifier_volume_list","1",, +"ISTNRM",,"9","end_of_transferring_translucent_list","1",, +"ISTNRM",,"8","end_of_transferring_opaque_modifier_volume_list","1",, +"ISTNRM",,"7","end_of_transferring_opaque_list","1",, +"ISTNRM",,"6","end_of_transferring_yuv","1",, +"ISTNRM",,"5","h_blank_in","1",, +"ISTNRM",,"4","v_blank_out","1",, +"ISTNRM",,"3","v_blank_in","1",, +"ISTNRM",,"2","end_of_render_tsp","1",, +"ISTNRM",,"1","end_of_render_isp","1",, +"ISTNRM",,"0","end_of_render_video","1",, +,,,,,, +"ISTERR",,"31","sh4__if_access_inhibited_area","1",, +"ISTERR",,"28","ddt__if_sort_dma_command_error","1",, +"ISTERR",,"27","g2__time_out_in_cpu_access","1",, +"ISTERR",,"26","g2__dev_dma_time_out","1",, +"ISTERR",,"25","g2__ext_dma2_time_out","1",, +"ISTERR",,"24","g2__ext_dma1_time_out","1",, +"ISTERR",,"23","g2__aica_dma_time_out","1",, +"ISTERR",,"22","g2__dev_dma_over_run","1",, +"ISTERR",,"21","g2__ext_dma2_over_run","1",, +"ISTERR",,"20","g2__ext_dma1_over_run","1",, +"ISTERR",,"19","g2__aica_dma_over_run","1",, +"ISTERR",,"18","g2__dev_dma_illegal_address_set","1",, +"ISTERR",,"17","g2__ext_dma2_illegal_address_set","1",, +"ISTERR",,"16","g2__ext_dma1_illegal_address_set","1",, +"ISTERR",,"15","g2__aica_dma_illegal_address_set","1",, +"ISTERR",,"14","g1__rom_flash_access_at_gd_dma","1",, +"ISTERR",,"13","g1__gd_dma_over_run","1",, +"ISTERR",,"12","g1__illegal_address_set","1",, +"ISTERR",,"11","maple__illegal_command","1",, +"ISTERR",,"10","maple__write_fifo_over_flow","1",, +"ISTERR",,"9","maple__dma_over_run","1",, +"ISTERR",,"8","maple__illegal_address_set","1",, +"ISTERR",,"7","pvrif__dma_over_run","1",, +"ISTERR",,"6","pvrif__illegal_address_set","1",, +"ISTERR",,"5","ta__fifo_overflow","1",, +"ISTERR",,"4","ta__illegal_parameter","1",, +"ISTERR",,"3","ta__object_list_pointer_overflow","1",, +"ISTERR",,"2","ta__isp_tsp_parameter_overflow","1",, +"ISTERR",,"1","render__hazard_processing_of_strip_buffer","1",, +"ISTERR",,"0","render__isp_out_of_cache","1",, +,,,,,, +"FFST",,"5","holly_cpu_if_block_internal_write_buffer",,, +"FFST",,"4","holly_g2_if_block_internal_write_buffer",,, +"FFST",,"0","aica_internal_write_buffer",,, +,,,,,, +"ISTEXT",,3,"external_device",1,, +"ISTEXT",,2,"modem",1,, +"ISTEXT",,1,"aica",1,, +"ISTEXT",,0,"gdrom",1,, diff --git a/dreamcast2/runtime.cpp b/dreamcast2/runtime.cpp new file mode 100644 index 0000000..327bf23 --- /dev/null +++ b/dreamcast2/runtime.cpp @@ -0,0 +1,59 @@ +#include + +#include "sh7091/store_queue_transfer.hpp" + +extern uint32_t __text_link_start __asm("__text_link_start"); +extern uint32_t __text_link_end __asm("__text_link_end"); +extern uint32_t __text_load_start __asm("__text_load_start"); + +extern uint32_t __data_link_start __asm("__data_link_start"); +extern uint32_t __data_link_end __asm("__data_link_end"); +extern uint32_t __data_load_start __asm("__data_load_start"); + +extern uint32_t __rodata_link_start __asm("__rodata_link_start"); +extern uint32_t __rodata_link_end __asm("__rodata_link_end"); +extern uint32_t __rodata_load_start __asm("__rodata_load_start"); + +extern uint32_t __ctors_link_start __asm("__ctors_link_start"); +extern uint32_t __ctors_link_end __asm("__ctors_link_end"); + +extern uint32_t __bss_link_start __asm("__bss_link_start"); +extern uint32_t __bss_link_end __asm("__bss_link_end"); + +extern void main(); + +typedef void(init_t)(void); + +void runtime_init() +__attribute__((section(".text.start.runtime_init"))); + +void runtime_init() +{ + // relocate text (if necessary) + //copy(&__text_link_start, &__text_link_end, &__text_load_start); + + // relocate data (if necessary) + //copy(&__data_link_start, &__data_link_end, &__data_load_start); + + // relocate rodata (if necessary) + //copy(&__rodata_link_start, &__rodata_link_end, &__rodata_load_start); + + // clear BSS + uint32_t * bss_start = &__bss_link_start; + uint32_t * bss_end = &__bss_link_end; + int bss_length = bss_end - bss_start; + sh7091::store_queue_transfer::zeroize(bss_start, bss_length, 0); + + // call ctors + uint32_t * ctors_start = &__ctors_link_start; + uint32_t * ctors_end = &__ctors_link_end; + while (ctors_start < ctors_end) { + ((init_t *)(*ctors_start++))(); + } +} + +extern "C" +void foo() +{ + runtime_init(); +} diff --git a/dreamcast2/sh7091/sh7091.hpp b/dreamcast2/sh7091/sh7091.hpp index 1e640e2..ef71499 100644 --- a/dreamcast2/sh7091/sh7091.hpp +++ b/dreamcast2/sh7091/sh7091.hpp @@ -1,379 +1,366 @@ #pragma once -#include -#include +#include "reg.hpp" -#include "type.hpp" +namespace sh7091 { + struct ccn_reg { + reg32 PTEH; /* Page table entry high register */ + reg32 PTEL; /* Page table entry low register */ + reg32 TTB; /* Translation table base register */ + reg32 TEA; /* TLB exception address register */ + reg32 MMUCR; /* MMU control register */ + reg8 BASRA; /* Break ASID register A */ + reg8 _pad0[3]; + reg8 BASRB; /* Break ASID register B */ + reg8 _pad1[3]; + reg32 CCR; /* Cache control register */ + reg32 TRA; /* TRAPA exception register */ + reg32 EXPEVT; /* Exception event register */ + reg32 INTEVT; /* Interrupt event register */ + reg8 _pad2[8]; + reg32 PTEA; /* Page table entry assistance register */ + reg32 QACR0; /* Queue address control register 0 */ + reg32 QACR1; /* Queue address control register 1 */ + }; + static_assert((offsetof (struct ccn_reg, PTEH)) == 0x0); + static_assert((offsetof (struct ccn_reg, PTEL)) == 0x4); + static_assert((offsetof (struct ccn_reg, TTB)) == 0x8); + static_assert((offsetof (struct ccn_reg, TEA)) == 0xc); + static_assert((offsetof (struct ccn_reg, MMUCR)) == 0x10); + static_assert((offsetof (struct ccn_reg, BASRA)) == 0x14); + static_assert((offsetof (struct ccn_reg, BASRB)) == 0x18); + static_assert((offsetof (struct ccn_reg, CCR)) == 0x1c); + static_assert((offsetof (struct ccn_reg, TRA)) == 0x20); + static_assert((offsetof (struct ccn_reg, EXPEVT)) == 0x24); + static_assert((offsetof (struct ccn_reg, INTEVT)) == 0x28); + static_assert((offsetof (struct ccn_reg, PTEA)) == 0x34); + static_assert((offsetof (struct ccn_reg, QACR0)) == 0x38); + static_assert((offsetof (struct ccn_reg, QACR1)) == 0x3c); -struct ccn_reg { - reg32 PTEH; /* Page table entry high register */ - reg32 PTEL; /* Page table entry low register */ - reg32 TTB; /* Translation table base register */ - reg32 TEA; /* TLB exception address register */ - reg32 MMUCR; /* MMU control register */ - reg8 BASRA; /* Break ASID register A */ - reg8 _pad0[3]; - reg8 BASRB; /* Break ASID register B */ - reg8 _pad1[3]; - reg32 CCR; /* Cache control register */ - reg32 TRA; /* TRAPA exception register */ - reg32 EXPEVT; /* Exception event register */ - reg32 INTEVT; /* Interrupt event register */ - reg8 _pad2[8]; - reg32 PTEA; /* Page table entry assistance register */ - reg32 QACR0; /* Queue address control register 0 */ - reg32 QACR1; /* Queue address control register 1 */ -}; + struct ubc_reg { + reg32 BARA; /* Break address register A */ + reg8 BAMRA; /* Break address mask register A */ + reg8 _pad0[3]; + reg16 BBRA; /* Break bus cycle register A */ + reg8 _pad1[2]; + reg32 BARB; /* Break address register B */ + reg8 BAMRB; /* Break address mask register B */ + reg8 _pad2[3]; + reg16 BBRB; /* Break bus cycle register B */ + reg8 _pad3[2]; + reg32 BDRB; /* Break data register B */ + reg32 BDMRB; /* Break data mask register B */ + reg16 BRCR; /* Break control register */ + }; + static_assert((offsetof (struct ubc_reg, BARA)) == 0x0); + static_assert((offsetof (struct ubc_reg, BAMRA)) == 0x4); + static_assert((offsetof (struct ubc_reg, BBRA)) == 0x8); + static_assert((offsetof (struct ubc_reg, BARB)) == 0xc); + static_assert((offsetof (struct ubc_reg, BAMRB)) == 0x10); + static_assert((offsetof (struct ubc_reg, BBRB)) == 0x14); + static_assert((offsetof (struct ubc_reg, BDRB)) == 0x18); + static_assert((offsetof (struct ubc_reg, BDMRB)) == 0x1c); + static_assert((offsetof (struct ubc_reg, BRCR)) == 0x20); -static_assert((offsetof (struct ccn_reg, PTEH)) == 0x0); -static_assert((offsetof (struct ccn_reg, PTEL)) == 0x4); -static_assert((offsetof (struct ccn_reg, TTB)) == 0x8); -static_assert((offsetof (struct ccn_reg, TEA)) == 0xc); -static_assert((offsetof (struct ccn_reg, MMUCR)) == 0x10); -static_assert((offsetof (struct ccn_reg, BASRA)) == 0x14); -static_assert((offsetof (struct ccn_reg, BASRB)) == 0x18); -static_assert((offsetof (struct ccn_reg, CCR)) == 0x1c); -static_assert((offsetof (struct ccn_reg, TRA)) == 0x20); -static_assert((offsetof (struct ccn_reg, EXPEVT)) == 0x24); -static_assert((offsetof (struct ccn_reg, INTEVT)) == 0x28); -static_assert((offsetof (struct ccn_reg, PTEA)) == 0x34); -static_assert((offsetof (struct ccn_reg, QACR0)) == 0x38); -static_assert((offsetof (struct ccn_reg, QACR1)) == 0x3c); + struct bsc_reg { + reg32 BCR1; /* Bus control register 1 */ + reg16 BCR2; /* Bus control register 2 */ + reg8 _pad0[2]; + reg32 WCR1; /* Wait state control register 1 */ + reg32 WCR2; /* Wait state control register 2 */ + reg32 WCR3; /* Wait state control register 3 */ + reg32 MCR; /* Memory control register */ + reg16 PCR; /* PCMCIA control register */ + reg8 _pad1[2]; + reg16 RTCSR; /* Refresh timer control/status register */ + reg8 _pad2[2]; + reg16 RTCNT; /* Refresh timer counter */ + reg8 _pad3[2]; + reg16 RTCOR; /* Refresh timer constant counter */ + reg8 _pad4[2]; + reg16 RFCR; /* Refresh count register */ + reg8 _pad5[2]; + reg32 PCTRA; /* Port control register A */ + reg16 PDTRA; /* Port data register A */ + reg8 _pad6[14]; + reg32 PCTRB; /* Port control register B */ + reg16 PDTRB; /* Port data register B */ + reg8 _pad7[2]; + reg16 GPIOIC; /* GPIO interrupt control register */ + reg8 _pad8[1048502]; + reg32 SDMR2[16384]; /* Synchronous DRAM mode registers */ + reg8 _pad9[196608]; + reg32 SDMR3[16384]; /* Synchronous DRAM mode registers */ + }; + static_assert((offsetof (struct bsc_reg, BCR1)) == 0x0); + static_assert((offsetof (struct bsc_reg, BCR2)) == 0x4); + static_assert((offsetof (struct bsc_reg, WCR1)) == 0x8); + static_assert((offsetof (struct bsc_reg, WCR2)) == 0xc); + static_assert((offsetof (struct bsc_reg, WCR3)) == 0x10); + static_assert((offsetof (struct bsc_reg, MCR)) == 0x14); + static_assert((offsetof (struct bsc_reg, PCR)) == 0x18); + static_assert((offsetof (struct bsc_reg, RTCSR)) == 0x1c); + static_assert((offsetof (struct bsc_reg, RTCNT)) == 0x20); + static_assert((offsetof (struct bsc_reg, RTCOR)) == 0x24); + static_assert((offsetof (struct bsc_reg, RFCR)) == 0x28); + static_assert((offsetof (struct bsc_reg, PCTRA)) == 0x2c); + static_assert((offsetof (struct bsc_reg, PDTRA)) == 0x30); + static_assert((offsetof (struct bsc_reg, PCTRB)) == 0x40); + static_assert((offsetof (struct bsc_reg, PDTRB)) == 0x44); + static_assert((offsetof (struct bsc_reg, GPIOIC)) == 0x48); + static_assert((offsetof (struct bsc_reg, SDMR2)) == 0x100000); + static_assert((offsetof (struct bsc_reg, SDMR3)) == 0x140000); -struct ubc_reg { - reg32 BARA; /* Break address register A */ - reg8 BAMRA; /* Break address mask register A */ - reg8 _pad0[3]; - reg16 BBRA; /* Break bus cycle register A */ - reg8 _pad1[2]; - reg32 BARB; /* Break address register B */ - reg8 BAMRB; /* Break address mask register B */ - reg8 _pad2[3]; - reg16 BBRB; /* Break bus cycle register B */ - reg8 _pad3[2]; - reg32 BDRB; /* Break data register B */ - reg32 BDMRB; /* Break data mask register B */ - reg16 BRCR; /* Break control register */ -}; + struct dmac_reg { + reg32 SAR0; /* DMA source address register 0 */ + reg32 DAR0; /* DMA destination address register 0 */ + reg32 DMATCR0; /* DMA transfer count register 0 */ + reg32 CHCR0; /* DMA control register 0 */ + reg32 SAR1; /* DMA source address register 1 */ + reg32 DAR1; /* DMA destination address register 1 */ + reg32 DMATCR1; /* DMA transfer count register 1 */ + reg32 CHCR1; /* DMA control register 1 */ + reg32 SAR2; /* DMA source address register 2 */ + reg32 DAR2; /* DMA destination address register 2 */ + reg32 DMATCR2; /* DMA transfer count register 2 */ + reg32 CHCR2; /* DMA control register 2 */ + reg32 SAR3; /* DMA source address register 3 */ + reg32 DAR3; /* DMA destination address register 3 */ + reg32 DMATCR3; /* DMA transfer count register 3 */ + reg32 CHCR3; /* DMA control register 3 */ + reg32 DMAOR; /* DMA operation register */ + }; + static_assert((offsetof (struct dmac_reg, SAR0)) == 0x0); + static_assert((offsetof (struct dmac_reg, DAR0)) == 0x4); + static_assert((offsetof (struct dmac_reg, DMATCR0)) == 0x8); + static_assert((offsetof (struct dmac_reg, CHCR0)) == 0xc); + static_assert((offsetof (struct dmac_reg, SAR1)) == 0x10); + static_assert((offsetof (struct dmac_reg, DAR1)) == 0x14); + static_assert((offsetof (struct dmac_reg, DMATCR1)) == 0x18); + static_assert((offsetof (struct dmac_reg, CHCR1)) == 0x1c); + static_assert((offsetof (struct dmac_reg, SAR2)) == 0x20); + static_assert((offsetof (struct dmac_reg, DAR2)) == 0x24); + static_assert((offsetof (struct dmac_reg, DMATCR2)) == 0x28); + static_assert((offsetof (struct dmac_reg, CHCR2)) == 0x2c); + static_assert((offsetof (struct dmac_reg, SAR3)) == 0x30); + static_assert((offsetof (struct dmac_reg, DAR3)) == 0x34); + static_assert((offsetof (struct dmac_reg, DMATCR3)) == 0x38); + static_assert((offsetof (struct dmac_reg, CHCR3)) == 0x3c); + static_assert((offsetof (struct dmac_reg, DMAOR)) == 0x40); -static_assert((offsetof (struct ubc_reg, BARA)) == 0x0); -static_assert((offsetof (struct ubc_reg, BAMRA)) == 0x4); -static_assert((offsetof (struct ubc_reg, BBRA)) == 0x8); -static_assert((offsetof (struct ubc_reg, BARB)) == 0xc); -static_assert((offsetof (struct ubc_reg, BAMRB)) == 0x10); -static_assert((offsetof (struct ubc_reg, BBRB)) == 0x14); -static_assert((offsetof (struct ubc_reg, BDRB)) == 0x18); -static_assert((offsetof (struct ubc_reg, BDMRB)) == 0x1c); -static_assert((offsetof (struct ubc_reg, BRCR)) == 0x20); + struct cpg_reg { + reg16 FRQCR; /* Frequency control register */ + reg8 _pad0[2]; + reg8 STBCR; /* Standby control register */ + reg8 _pad1[3]; + reg16 WTCNT; /* Watchdog timer counter */ + reg8 _pad2[2]; + reg16 WTCSR; /* Watchdog timer control/status register */ + reg8 _pad3[2]; + reg8 STBCR2; /* Standby control register 2 */ + }; + static_assert((offsetof (struct cpg_reg, FRQCR)) == 0x0); + static_assert((offsetof (struct cpg_reg, STBCR)) == 0x4); + static_assert((offsetof (struct cpg_reg, WTCNT)) == 0x8); + static_assert((offsetof (struct cpg_reg, WTCSR)) == 0xc); + static_assert((offsetof (struct cpg_reg, STBCR2)) == 0x10); -struct bsc_reg { - reg32 BCR1; /* Bus control register 1 */ - reg16 BCR2; /* Bus control register 2 */ - reg8 _pad0[2]; - reg32 WCR1; /* Wait state control register 1 */ - reg32 WCR2; /* Wait state control register 2 */ - reg32 WCR3; /* Wait state control register 3 */ - reg32 MCR; /* Memory control register */ - reg16 PCR; /* PCMCIA control register */ - reg8 _pad1[2]; - reg16 RTCSR; /* Refresh timer control/status register */ - reg8 _pad2[2]; - reg16 RTCNT; /* Refresh timer counter */ - reg8 _pad3[2]; - reg16 RTCOR; /* Refresh timer constant counter */ - reg8 _pad4[2]; - reg16 RFCR; /* Refresh count register */ - reg8 _pad5[2]; - reg32 PCTRA; /* Port control register A */ - reg16 PDTRA; /* Port data register A */ - reg8 _pad6[14]; - reg32 PCTRB; /* Port control register B */ - reg16 PDTRB; /* Port data register B */ - reg8 _pad7[2]; - reg16 GPIOIC; /* GPIO interrupt control register */ - reg8 _pad8[1048502]; - reg32 SDMR2[16384]; /* Synchronous DRAM mode registers */ - reg8 _pad9[196608]; - reg32 SDMR3[16384]; /* Synchronous DRAM mode registers */ -}; + struct rtc_reg { + reg8 R64CNT; /* 64 Hz counter */ + reg8 _pad0[3]; + reg8 RSECCNT; /* Second counter */ + reg8 _pad1[3]; + reg8 RMINCNT; /* Minute counter */ + reg8 _pad2[3]; + reg8 RHRCNT; /* Hour counter */ + reg8 _pad3[3]; + reg8 RWKCNT; /* Day-of-week counter */ + reg8 _pad4[3]; + reg8 RDAYCNT; /* Day counter */ + reg8 _pad5[3]; + reg8 RMONCNT; /* Month counter */ + reg8 _pad6[3]; + reg16 RYRCNT; /* Year counter */ + reg8 _pad7[2]; + reg8 RSECAR; /* Second alarm register */ + reg8 _pad8[3]; + reg8 RMINAR; /* Minute alarm register */ + reg8 _pad9[3]; + reg8 RHRAR; /* Hour alarm register */ + reg8 _pad10[3]; + reg8 RWKAR; /* Day-of-week alarm register */ + reg8 _pad11[3]; + reg8 RDAYAR; /* Day alarm register */ + reg8 _pad12[3]; + reg8 RMONAR; /* Month alarm register */ + reg8 _pad13[3]; + reg8 RCR1; /* RTC control register 1 */ + reg8 _pad14[3]; + reg8 RCR2; /* RTC control register 2 */ + }; + static_assert((offsetof (struct rtc_reg, R64CNT)) == 0x0); + static_assert((offsetof (struct rtc_reg, RSECCNT)) == 0x4); + static_assert((offsetof (struct rtc_reg, RMINCNT)) == 0x8); + static_assert((offsetof (struct rtc_reg, RHRCNT)) == 0xc); + static_assert((offsetof (struct rtc_reg, RWKCNT)) == 0x10); + static_assert((offsetof (struct rtc_reg, RDAYCNT)) == 0x14); + static_assert((offsetof (struct rtc_reg, RMONCNT)) == 0x18); + static_assert((offsetof (struct rtc_reg, RYRCNT)) == 0x1c); + static_assert((offsetof (struct rtc_reg, RSECAR)) == 0x20); + static_assert((offsetof (struct rtc_reg, RMINAR)) == 0x24); + static_assert((offsetof (struct rtc_reg, RHRAR)) == 0x28); + static_assert((offsetof (struct rtc_reg, RWKAR)) == 0x2c); + static_assert((offsetof (struct rtc_reg, RDAYAR)) == 0x30); + static_assert((offsetof (struct rtc_reg, RMONAR)) == 0x34); + static_assert((offsetof (struct rtc_reg, RCR1)) == 0x38); + static_assert((offsetof (struct rtc_reg, RCR2)) == 0x3c); -static_assert((offsetof (struct bsc_reg, BCR1)) == 0x0); -static_assert((offsetof (struct bsc_reg, BCR2)) == 0x4); -static_assert((offsetof (struct bsc_reg, WCR1)) == 0x8); -static_assert((offsetof (struct bsc_reg, WCR2)) == 0xc); -static_assert((offsetof (struct bsc_reg, WCR3)) == 0x10); -static_assert((offsetof (struct bsc_reg, MCR)) == 0x14); -static_assert((offsetof (struct bsc_reg, PCR)) == 0x18); -static_assert((offsetof (struct bsc_reg, RTCSR)) == 0x1c); -static_assert((offsetof (struct bsc_reg, RTCNT)) == 0x20); -static_assert((offsetof (struct bsc_reg, RTCOR)) == 0x24); -static_assert((offsetof (struct bsc_reg, RFCR)) == 0x28); -static_assert((offsetof (struct bsc_reg, PCTRA)) == 0x2c); -static_assert((offsetof (struct bsc_reg, PDTRA)) == 0x30); -static_assert((offsetof (struct bsc_reg, PCTRB)) == 0x40); -static_assert((offsetof (struct bsc_reg, PDTRB)) == 0x44); -static_assert((offsetof (struct bsc_reg, GPIOIC)) == 0x48); -static_assert((offsetof (struct bsc_reg, SDMR2)) == 0x100000); -static_assert((offsetof (struct bsc_reg, SDMR3)) == 0x140000); + struct intc_reg { + reg16 ICR; /* Interrupt control register */ + reg8 _pad0[2]; + reg16 IPRA; /* Interrupt priority register A */ + reg8 _pad1[2]; + reg16 IPRB; /* Interrupt priority register B */ + reg8 _pad2[2]; + reg16 IPRC; /* Interrupt priority register C */ + }; + static_assert((offsetof (struct intc_reg, ICR)) == 0x0); + static_assert((offsetof (struct intc_reg, IPRA)) == 0x4); + static_assert((offsetof (struct intc_reg, IPRB)) == 0x8); + static_assert((offsetof (struct intc_reg, IPRC)) == 0xc); -struct dmac_reg { - reg32 SAR0; /* DMA source address register 0 */ - reg32 DAR0; /* DMA destination address register 0 */ - reg32 DMATCR0; /* DMA transfer count register 0 */ - reg32 CHCR0; /* DMA control register 0 */ - reg32 SAR1; /* DMA source address register 1 */ - reg32 DAR1; /* DMA destination address register 1 */ - reg32 DMATCR1; /* DMA transfer count register 1 */ - reg32 CHCR1; /* DMA control register 1 */ - reg32 SAR2; /* DMA source address register 2 */ - reg32 DAR2; /* DMA destination address register 2 */ - reg32 DMATCR2; /* DMA transfer count register 2 */ - reg32 CHCR2; /* DMA control register 2 */ - reg32 SAR3; /* DMA source address register 3 */ - reg32 DAR3; /* DMA destination address register 3 */ - reg32 DMATCR3; /* DMA transfer count register 3 */ - reg32 CHCR3; /* DMA control register 3 */ - reg32 DMAOR; /* DMA operation register */ -}; + struct tmu_reg { + reg8 TOCR; /* Timer output control register */ + reg8 _pad0[3]; + reg8 TSTR; /* Timer start register */ + reg8 _pad1[3]; + reg32 TCOR0; /* Timer constant register 0 */ + reg32 TCNT0; /* Timer counter 0 */ + reg16 TCR0; /* Timer control register 0 */ + reg8 _pad2[2]; + reg32 TCOR1; /* Timer constant register 1 */ + reg32 TCNT1; /* Timer counter 1 */ + reg16 TCR1; /* Timer control register 1 */ + reg8 _pad3[2]; + reg32 TCOR2; /* Timer constant register 2 */ + reg32 TCNT2; /* Timer counter 2 */ + reg16 TCR2; /* Timer control register 2 */ + reg8 _pad4[2]; + reg32 TCPR2; /* Timer input capture register 2 */ + }; + static_assert((offsetof (struct tmu_reg, TOCR)) == 0x0); + static_assert((offsetof (struct tmu_reg, TSTR)) == 0x4); + static_assert((offsetof (struct tmu_reg, TCOR0)) == 0x8); + static_assert((offsetof (struct tmu_reg, TCNT0)) == 0xc); + static_assert((offsetof (struct tmu_reg, TCR0)) == 0x10); + static_assert((offsetof (struct tmu_reg, TCOR1)) == 0x14); + static_assert((offsetof (struct tmu_reg, TCNT1)) == 0x18); + static_assert((offsetof (struct tmu_reg, TCR1)) == 0x1c); + static_assert((offsetof (struct tmu_reg, TCOR2)) == 0x20); + static_assert((offsetof (struct tmu_reg, TCNT2)) == 0x24); + static_assert((offsetof (struct tmu_reg, TCR2)) == 0x28); + static_assert((offsetof (struct tmu_reg, TCPR2)) == 0x2c); -static_assert((offsetof (struct dmac_reg, SAR0)) == 0x0); -static_assert((offsetof (struct dmac_reg, DAR0)) == 0x4); -static_assert((offsetof (struct dmac_reg, DMATCR0)) == 0x8); -static_assert((offsetof (struct dmac_reg, CHCR0)) == 0xc); -static_assert((offsetof (struct dmac_reg, SAR1)) == 0x10); -static_assert((offsetof (struct dmac_reg, DAR1)) == 0x14); -static_assert((offsetof (struct dmac_reg, DMATCR1)) == 0x18); -static_assert((offsetof (struct dmac_reg, CHCR1)) == 0x1c); -static_assert((offsetof (struct dmac_reg, SAR2)) == 0x20); -static_assert((offsetof (struct dmac_reg, DAR2)) == 0x24); -static_assert((offsetof (struct dmac_reg, DMATCR2)) == 0x28); -static_assert((offsetof (struct dmac_reg, CHCR2)) == 0x2c); -static_assert((offsetof (struct dmac_reg, SAR3)) == 0x30); -static_assert((offsetof (struct dmac_reg, DAR3)) == 0x34); -static_assert((offsetof (struct dmac_reg, DMATCR3)) == 0x38); -static_assert((offsetof (struct dmac_reg, CHCR3)) == 0x3c); -static_assert((offsetof (struct dmac_reg, DMAOR)) == 0x40); + struct sci_reg { + reg8 SCSMR1; /* Serial mode register 1 */ + reg8 _pad0[3]; + reg8 SCBRR1; /* Bit rate register 1 */ + reg8 _pad1[3]; + reg8 SCSCR1; /* Serial control register 1 */ + reg8 _pad2[3]; + reg8 SCTDR1; /* Transmit data register 1 */ + reg8 _pad3[3]; + reg8 SCSSR1; /* Serial status register 1 */ + reg8 _pad4[3]; + reg8 SCRDR1; /* Receive data register 1 */ + reg8 _pad5[3]; + reg8 SCSCMR1; /* Smart card mode register 1 */ + reg8 _pad6[3]; + reg8 SCSPTR1; /* Serial port register */ + }; + static_assert((offsetof (struct sci_reg, SCSMR1)) == 0x0); + static_assert((offsetof (struct sci_reg, SCBRR1)) == 0x4); + static_assert((offsetof (struct sci_reg, SCSCR1)) == 0x8); + static_assert((offsetof (struct sci_reg, SCTDR1)) == 0xc); + static_assert((offsetof (struct sci_reg, SCSSR1)) == 0x10); + static_assert((offsetof (struct sci_reg, SCRDR1)) == 0x14); + static_assert((offsetof (struct sci_reg, SCSCMR1)) == 0x18); + static_assert((offsetof (struct sci_reg, SCSPTR1)) == 0x1c); -struct cpg_reg { - reg16 FRQCR; /* Frequency control register */ - reg8 _pad0[2]; - reg8 STBCR; /* Standby control register */ - reg8 _pad1[3]; - reg16 WTCNT; /* Watchdog timer counter */ - reg8 _pad2[2]; - reg16 WTCSR; /* Watchdog timer control/status register */ - reg8 _pad3[2]; - reg8 STBCR2; /* Standby control register 2 */ -}; + struct scif_reg { + reg16 SCSMR2; /* Serial mode register 2 */ + reg8 _pad0[2]; + reg8 SCBRR2; /* Bit rate register 2 */ + reg8 _pad1[3]; + reg16 SCSCR2; /* Serial control register 2 */ + reg8 _pad2[2]; + reg8 SCFTDR2; /* Transmit FIFO data register 2 */ + reg8 _pad3[3]; + reg16 SCFSR2; /* Serial status register 2 */ + reg8 _pad4[2]; + reg8 SCFRDR2; /* Receive FIFO data register 2 */ + reg8 _pad5[3]; + reg16 SCFCR2; /* FIFO control register */ + reg8 _pad6[2]; + reg16 SCFDR2; /* FIFO data count register */ + reg8 _pad7[2]; + reg16 SCSPTR2; /* Serial port register 2 */ + reg8 _pad8[2]; + reg16 SCLSR2; /* Line status register 2 */ + }; + static_assert((offsetof (struct scif_reg, SCSMR2)) == 0x0); + static_assert((offsetof (struct scif_reg, SCBRR2)) == 0x4); + static_assert((offsetof (struct scif_reg, SCSCR2)) == 0x8); + static_assert((offsetof (struct scif_reg, SCFTDR2)) == 0xc); + static_assert((offsetof (struct scif_reg, SCFSR2)) == 0x10); + static_assert((offsetof (struct scif_reg, SCFRDR2)) == 0x14); + static_assert((offsetof (struct scif_reg, SCFCR2)) == 0x18); + static_assert((offsetof (struct scif_reg, SCFDR2)) == 0x1c); + static_assert((offsetof (struct scif_reg, SCSPTR2)) == 0x20); + static_assert((offsetof (struct scif_reg, SCLSR2)) == 0x24); -static_assert((offsetof (struct cpg_reg, FRQCR)) == 0x0); -static_assert((offsetof (struct cpg_reg, STBCR)) == 0x4); -static_assert((offsetof (struct cpg_reg, WTCNT)) == 0x8); -static_assert((offsetof (struct cpg_reg, WTCSR)) == 0xc); -static_assert((offsetof (struct cpg_reg, STBCR2)) == 0x10); + struct udi_reg { + reg16 SDIR; /* Instruction register */ + reg8 _pad0[6]; + reg32 SDDR; /* Data register */ + }; + static_assert((offsetof (struct udi_reg, SDIR)) == 0x0); + static_assert((offsetof (struct udi_reg, SDDR)) == 0x8); -struct rtc_reg { - reg8 R64CNT; /* 64 Hz counter */ - reg8 _pad0[3]; - reg8 RSECCNT; /* Second counter */ - reg8 _pad1[3]; - reg8 RMINCNT; /* Minute counter */ - reg8 _pad2[3]; - reg8 RHRCNT; /* Hour counter */ - reg8 _pad3[3]; - reg8 RWKCNT; /* Day-of-week counter */ - reg8 _pad4[3]; - reg8 RDAYCNT; /* Day counter */ - reg8 _pad5[3]; - reg8 RMONCNT; /* Month counter */ - reg8 _pad6[3]; - reg16 RYRCNT; /* Year counter */ - reg8 _pad7[2]; - reg8 RSECAR; /* Second alarm register */ - reg8 _pad8[3]; - reg8 RMINAR; /* Minute alarm register */ - reg8 _pad9[3]; - reg8 RHRAR; /* Hour alarm register */ - reg8 _pad10[3]; - reg8 RWKAR; /* Day-of-week alarm register */ - reg8 _pad11[3]; - reg8 RDAYAR; /* Day alarm register */ - reg8 _pad12[3]; - reg8 RMONAR; /* Month alarm register */ - reg8 _pad13[3]; - reg8 RCR1; /* RTC control register 1 */ - reg8 _pad14[3]; - reg8 RCR2; /* RTC control register 2 */ -}; + struct sh7091_reg { + struct ccn_reg CCN; + reg8 _pad0[0x200000 - (sizeof (struct ccn_reg))]; + struct ubc_reg UBC; + reg8 _pad1[0x600000 - (sizeof (struct ubc_reg))]; + struct bsc_reg BSC; + reg8 _pad2[0x200000 - (sizeof (struct bsc_reg))]; + struct dmac_reg DMAC; + reg8 _pad3[0x200000 - (sizeof (struct dmac_reg))]; + struct cpg_reg CPG; + reg8 _pad4[0x80000 - (sizeof (struct cpg_reg))]; + struct rtc_reg RTC; + reg8 _pad5[0x80000 - (sizeof (struct rtc_reg))]; + struct intc_reg INTC; + reg8 _pad6[0x80000 - (sizeof (struct intc_reg))]; + struct tmu_reg TMU; + reg8 _pad7[0x80000 - (sizeof (struct tmu_reg))]; + struct sci_reg SCI; + reg8 _pad8[0x80000 - (sizeof (struct sci_reg))]; + struct scif_reg SCIF; + reg8 _pad9[0x80000 - (sizeof (struct scif_reg))]; + struct udi_reg UDI; + }; + static_assert((offsetof (struct sh7091_reg, CCN)) == 0x0); + static_assert((offsetof (struct sh7091_reg, UBC)) == 0x200000); + static_assert((offsetof (struct sh7091_reg, BSC)) == 0x800000); + static_assert((offsetof (struct sh7091_reg, DMAC)) == 0xa00000); + static_assert((offsetof (struct sh7091_reg, CPG)) == 0xc00000); + static_assert((offsetof (struct sh7091_reg, RTC)) == 0xc80000); + static_assert((offsetof (struct sh7091_reg, INTC)) == 0xd00000); + static_assert((offsetof (struct sh7091_reg, TMU)) == 0xd80000); + static_assert((offsetof (struct sh7091_reg, SCI)) == 0xe00000); + static_assert((offsetof (struct sh7091_reg, SCIF)) == 0xe80000); + static_assert((offsetof (struct sh7091_reg, UDI)) == 0xf00000); -static_assert((offsetof (struct rtc_reg, R64CNT)) == 0x0); -static_assert((offsetof (struct rtc_reg, RSECCNT)) == 0x4); -static_assert((offsetof (struct rtc_reg, RMINCNT)) == 0x8); -static_assert((offsetof (struct rtc_reg, RHRCNT)) == 0xc); -static_assert((offsetof (struct rtc_reg, RWKCNT)) == 0x10); -static_assert((offsetof (struct rtc_reg, RDAYCNT)) == 0x14); -static_assert((offsetof (struct rtc_reg, RMONCNT)) == 0x18); -static_assert((offsetof (struct rtc_reg, RYRCNT)) == 0x1c); -static_assert((offsetof (struct rtc_reg, RSECAR)) == 0x20); -static_assert((offsetof (struct rtc_reg, RMINAR)) == 0x24); -static_assert((offsetof (struct rtc_reg, RHRAR)) == 0x28); -static_assert((offsetof (struct rtc_reg, RWKAR)) == 0x2c); -static_assert((offsetof (struct rtc_reg, RDAYAR)) == 0x30); -static_assert((offsetof (struct rtc_reg, RMONAR)) == 0x34); -static_assert((offsetof (struct rtc_reg, RCR1)) == 0x38); -static_assert((offsetof (struct rtc_reg, RCR2)) == 0x3c); - -struct intc_reg { - reg16 ICR; /* Interrupt control register */ - reg8 _pad0[2]; - reg16 IPRA; /* Interrupt priority register A */ - reg8 _pad1[2]; - reg16 IPRB; /* Interrupt priority register B */ - reg8 _pad2[2]; - reg16 IPRC; /* Interrupt priority register C */ -}; - -static_assert((offsetof (struct intc_reg, ICR)) == 0x0); -static_assert((offsetof (struct intc_reg, IPRA)) == 0x4); -static_assert((offsetof (struct intc_reg, IPRB)) == 0x8); -static_assert((offsetof (struct intc_reg, IPRC)) == 0xc); - -struct tmu_reg { - reg8 TOCR; /* Timer output control register */ - reg8 _pad0[3]; - reg8 TSTR; /* Timer start register */ - reg8 _pad1[3]; - reg32 TCOR0; /* Timer constant register 0 */ - reg32 TCNT0; /* Timer counter 0 */ - reg16 TCR0; /* Timer control register 0 */ - reg8 _pad2[2]; - reg32 TCOR1; /* Timer constant register 1 */ - reg32 TCNT1; /* Timer counter 1 */ - reg16 TCR1; /* Timer control register 1 */ - reg8 _pad3[2]; - reg32 TCOR2; /* Timer constant register 2 */ - reg32 TCNT2; /* Timer counter 2 */ - reg16 TCR2; /* Timer control register 2 */ - reg8 _pad4[2]; - reg32 TCPR2; /* Timer input capture register 2 */ -}; - -static_assert((offsetof (struct tmu_reg, TOCR)) == 0x0); -static_assert((offsetof (struct tmu_reg, TSTR)) == 0x4); -static_assert((offsetof (struct tmu_reg, TCOR0)) == 0x8); -static_assert((offsetof (struct tmu_reg, TCNT0)) == 0xc); -static_assert((offsetof (struct tmu_reg, TCR0)) == 0x10); -static_assert((offsetof (struct tmu_reg, TCOR1)) == 0x14); -static_assert((offsetof (struct tmu_reg, TCNT1)) == 0x18); -static_assert((offsetof (struct tmu_reg, TCR1)) == 0x1c); -static_assert((offsetof (struct tmu_reg, TCOR2)) == 0x20); -static_assert((offsetof (struct tmu_reg, TCNT2)) == 0x24); -static_assert((offsetof (struct tmu_reg, TCR2)) == 0x28); -static_assert((offsetof (struct tmu_reg, TCPR2)) == 0x2c); - -struct sci_reg { - reg8 SCSMR1; /* Serial mode register 1 */ - reg8 _pad0[3]; - reg8 SCBRR1; /* Bit rate register 1 */ - reg8 _pad1[3]; - reg8 SCSCR1; /* Serial control register 1 */ - reg8 _pad2[3]; - reg8 SCTDR1; /* Transmit data register 1 */ - reg8 _pad3[3]; - reg8 SCSSR1; /* Serial status register 1 */ - reg8 _pad4[3]; - reg8 SCRDR1; /* Receive data register 1 */ - reg8 _pad5[3]; - reg8 SCSCMR1; /* Smart card mode register 1 */ - reg8 _pad6[3]; - reg8 SCSPTR1; /* Serial port register */ -}; - -static_assert((offsetof (struct sci_reg, SCSMR1)) == 0x0); -static_assert((offsetof (struct sci_reg, SCBRR1)) == 0x4); -static_assert((offsetof (struct sci_reg, SCSCR1)) == 0x8); -static_assert((offsetof (struct sci_reg, SCTDR1)) == 0xc); -static_assert((offsetof (struct sci_reg, SCSSR1)) == 0x10); -static_assert((offsetof (struct sci_reg, SCRDR1)) == 0x14); -static_assert((offsetof (struct sci_reg, SCSCMR1)) == 0x18); -static_assert((offsetof (struct sci_reg, SCSPTR1)) == 0x1c); - -struct scif_reg { - reg16 SCSMR2; /* Serial mode register 2 */ - reg8 _pad0[2]; - reg8 SCBRR2; /* Bit rate register 2 */ - reg8 _pad1[3]; - reg16 SCSCR2; /* Serial control register 2 */ - reg8 _pad2[2]; - reg8 SCFTDR2; /* Transmit FIFO data register 2 */ - reg8 _pad3[3]; - reg16 SCFSR2; /* Serial status register 2 */ - reg8 _pad4[2]; - reg8 SCFRDR2; /* Receive FIFO data register 2 */ - reg8 _pad5[3]; - reg16 SCFCR2; /* FIFO control register */ - reg8 _pad6[2]; - reg16 SCFDR2; /* FIFO data count register */ - reg8 _pad7[2]; - reg16 SCSPTR2; /* Serial port register 2 */ - reg8 _pad8[2]; - reg16 SCLSR2; /* Line status register 2 */ -}; - -static_assert((offsetof (struct scif_reg, SCSMR2)) == 0x0); -static_assert((offsetof (struct scif_reg, SCBRR2)) == 0x4); -static_assert((offsetof (struct scif_reg, SCSCR2)) == 0x8); -static_assert((offsetof (struct scif_reg, SCFTDR2)) == 0xc); -static_assert((offsetof (struct scif_reg, SCFSR2)) == 0x10); -static_assert((offsetof (struct scif_reg, SCFRDR2)) == 0x14); -static_assert((offsetof (struct scif_reg, SCFCR2)) == 0x18); -static_assert((offsetof (struct scif_reg, SCFDR2)) == 0x1c); -static_assert((offsetof (struct scif_reg, SCSPTR2)) == 0x20); -static_assert((offsetof (struct scif_reg, SCLSR2)) == 0x24); - -struct udi_reg { - reg16 SDIR; /* Instruction register */ - reg8 _pad0[6]; - reg32 SDDR; /* Data register */ -}; - -static_assert((offsetof (struct udi_reg, SDIR)) == 0x0); -static_assert((offsetof (struct udi_reg, SDDR)) == 0x8); - -struct sh7091_reg { - struct ccn_reg CCN; - reg8 _pad0[0x200000 - (sizeof (struct ccn_reg))]; - struct ubc_reg UBC; - reg8 _pad1[0x600000 - (sizeof (struct ubc_reg))]; - struct bsc_reg BSC; - reg8 _pad2[0x200000 - (sizeof (struct bsc_reg))]; - struct dmac_reg DMAC; - reg8 _pad3[0x200000 - (sizeof (struct dmac_reg))]; - struct cpg_reg CPG; - reg8 _pad4[0x80000 - (sizeof (struct cpg_reg))]; - struct rtc_reg RTC; - reg8 _pad5[0x80000 - (sizeof (struct rtc_reg))]; - struct intc_reg INTC; - reg8 _pad6[0x80000 - (sizeof (struct intc_reg))]; - struct tmu_reg TMU; - reg8 _pad7[0x80000 - (sizeof (struct tmu_reg))]; - struct sci_reg SCI; - reg8 _pad8[0x80000 - (sizeof (struct sci_reg))]; - struct scif_reg SCIF; - reg8 _pad9[0x80000 - (sizeof (struct scif_reg))]; - struct udi_reg UDI; -}; - -static_assert((offsetof (struct sh7091_reg, CCN)) == 0x0); -static_assert((offsetof (struct sh7091_reg, UBC)) == 0x200000); -static_assert((offsetof (struct sh7091_reg, BSC)) == 0x800000); -static_assert((offsetof (struct sh7091_reg, DMAC)) == 0xa00000); -static_assert((offsetof (struct sh7091_reg, CPG)) == 0xc00000); -static_assert((offsetof (struct sh7091_reg, RTC)) == 0xc80000); -static_assert((offsetof (struct sh7091_reg, INTC)) == 0xd00000); -static_assert((offsetof (struct sh7091_reg, TMU)) == 0xd80000); -static_assert((offsetof (struct sh7091_reg, SCI)) == 0xe00000); -static_assert((offsetof (struct sh7091_reg, SCIF)) == 0xe80000); -static_assert((offsetof (struct sh7091_reg, UDI)) == 0xf00000); - -extern struct sh7091_reg sh7091 __asm("sh7091"); + extern struct sh7091_reg sh7091 __asm("sh7091"); +} diff --git a/dreamcast2/sh7091/store_queue_transfer.hpp b/dreamcast2/sh7091/store_queue_transfer.hpp index 9c3a25b..6f8e205 100644 --- a/dreamcast2/sh7091/store_queue_transfer.hpp +++ b/dreamcast2/sh7091/store_queue_transfer.hpp @@ -6,6 +6,10 @@ namespace sh7091 { namespace store_queue_transfer { + static inline void copy(void * out_addr, + const void * src, + int length) __attribute__((always_inline)); + static inline void copy(void * out_addr, const void * src, int length) @@ -14,7 +18,7 @@ namespace sh7091 { sh7091.CCN.QACR0 = ((out >> 24) & 0b11100); sh7091.CCN.QACR1 = ((out >> 24) & 0b11100); - volatile uint32_t * base = &store_queue[(out & 0x03ffffe0)]; + volatile uint32_t * base = (volatile uint32_t *)&store_queue[(out & 0x03ffffe0)]; const uint32_t * src32 = reinterpret_cast(src); length = (length + 31) & ~31; // round up to nearest multiple of 32 @@ -38,6 +42,10 @@ namespace sh7091 { } + static inline void zeroize(void * out_addr, + int length, + const uint32_t value) __attribute__((always_inline)); + static inline void zeroize(void * out_addr, int length, const uint32_t value) @@ -46,7 +54,7 @@ namespace sh7091 { sh7091.CCN.QACR0 = ((out >> 24) & 0b11100); sh7091.CCN.QACR1 = ((out >> 24) & 0b11100); - volatile uint32_t * base = &store_queue[(out & 0x03ffffe0)]; + volatile uint32_t * base = (volatile uint32_t *)&store_queue[(out & 0x03ffffe0)]; length = (length + 31) & ~31; // round up to nearest multiple of 32 while (length > 0) { diff --git a/dreamcast2/start.s b/dreamcast2/start.s new file mode 100644 index 0000000..a5e32ff --- /dev/null +++ b/dreamcast2/start.s @@ -0,0 +1,41 @@ + .section .text.start + .global _start +_start: + /* set stack pointer */ + mov.l stack_end_ptr,r15 + + /* mask all interrupts */ + mov.l imask_all,r0 + mov.l zero_rb,r2 + stc sr,r1 + or r1,r0 + and r0,r2 + ldc r2,sr + + /* save pr */ + sts.l pr,@-r15 + + /* jump to runtime_init */ + mov.l runtime_init_ptr,r0 + jsr @r0 + nop + + /* restore pr */ + lds.l @r15+,pr + + /* jump to main */ + mov.l main_ptr,r0 + jmp @r0 + nop + + .align 4 +stack_end_ptr: + .long __stack_end +imask_all: + .long 0xf0 +zero_rb: + .long ~(1 << 29) +runtime_init_ptr: + .long __Z12runtime_initv +main_ptr: + .long _main diff --git a/dreamcast2/symbols.lds b/dreamcast2/symbols.lds new file mode 100644 index 0000000..3c1faa6 --- /dev/null +++ b/dreamcast2/symbols.lds @@ -0,0 +1,21 @@ +__text_link_start = ADDR(.text); +__text_link_end = ADDR(.text) + SIZEOF(.text); +__text_load_start = LOADADDR(.text); + +__data_link_start = ADDR(.data); +__data_link_end = ADDR(.data) + SIZEOF(.data); +__data_load_start = LOADADDR(.data); + +__rodata_link_start = ADDR(.rodata); +__rodata_link_end = ADDR(.rodata) + SIZEOF(.rodata); +__rodata_load_start = LOADADDR(.rodata); + +__ctors_link_start = ADDR(.ctors); +__ctors_link_end = ADDR(.ctors) + SIZEOF(.ctors); + +__bss_link_start = ADDR(.bss); +__bss_link_end = ADDR(.bss) + SIZEOF(.bss); + +__vbr_link_start = ADDR(.text.vbr); +__vbr_link_end = ADDR(.text.vbr) + SIZEOF(.text.vbr); +__vbr_load_end = LOADADDR(.text.vbr); diff --git a/dreamcast2/systembus/systembus.hpp b/dreamcast2/systembus/systembus.hpp index efbc170..6805f6c 100644 --- a/dreamcast2/systembus/systembus.hpp +++ b/dreamcast2/systembus/systembus.hpp @@ -2,307 +2,308 @@ #include "reg.hpp" -struct systembus_reg { - reg32 C2DSTAT; /* CH2-DMA destination address */ - reg32 C2DLEN; /* CH2-DMA length */ - reg32 C2DST; /* CH2-DMA start */ - reg8 _pad0[4]; - reg32 SDSTAW; /* Sort-DMA start link table address */ - reg32 SDBAAW; /* Sort-DMA link base address */ - reg32 SDWLT; /* Sort-DMA link address bit width */ - reg32 SDLAS; /* Sort-DMA link address shift control */ - reg32 SDST; /* Sort-DMA start */ - reg8 _pad1[28]; - reg32 DBREQM; /* DBREQ# signal mask control */ - reg32 BAVLWC; /* BAVL# signal wait count */ - reg32 C2DPYRC; /* DMA (TA/Root Bus) priority count */ - reg32 DMAXL; /* CH2-DMA maximum burst length */ - reg8 _pad2[48]; - reg32 TFREM; /* TA FIFO remaining amount */ - reg32 LMMODE0; /* Via TA texture memory bus select 0 */ - reg32 LMMODE1; /* Via TA texture memory bus select 1 */ - reg32 FFST; /* FIFO status */ - reg32 SFRES; /* System reset */ - reg8 _pad3[8]; - reg32 SBREV; /* System bus revision number */ - reg32 RBSPLT; /* SH4 Root Bus split enable */ - reg8 _pad4[92]; - reg32 ISTNRM; /* Normal interrupt status */ - reg32 ISTEXT; /* External interrupt status */ - reg32 ISTERR; /* Error interrupt status */ - reg8 _pad5[4]; - reg32 IML2NRM; /* Level 2 normal interrupt mask */ - reg32 IML2EXT; /* Level 2 external interrupt mask */ - reg32 IML2ERR; /* Level 2 error interrupt mask */ - reg8 _pad6[4]; - reg32 IML4NRM; /* Level 4 normal interrupt mask */ - reg32 IML4EXT; /* Level 4 external interrupt mask */ - reg32 IML4ERR; /* Level 4 error interrupt mask */ - reg8 _pad7[4]; - reg32 IML6NRM; /* Level 6 normal interrupt mask */ - reg32 IML6EXT; /* Level 6 external interrupt mask */ - reg32 IML6ERR; /* Level 6 error interrupt mask */ - reg8 _pad8[4]; - reg32 PDTNRM; /* Normal interrupt PVR-DMA startup mask */ - reg32 PDTEXT; /* External interrupt PVR-DMA startup mask */ - reg8 _pad9[8]; - reg32 G2DTNRM; /* Normal interrupt G2-DMA startup mask */ - reg32 G2DTEXT; /* External interrupt G2-DMA startup mask */ -}; +namespace systembus { + struct systembus_reg { + reg32 C2DSTAT; /* CH2-DMA destination address */ + reg32 C2DLEN; /* CH2-DMA length */ + reg32 C2DST; /* CH2-DMA start */ + reg8 _pad0[4]; + reg32 SDSTAW; /* Sort-DMA start link table address */ + reg32 SDBAAW; /* Sort-DMA link base address */ + reg32 SDWLT; /* Sort-DMA link address bit width */ + reg32 SDLAS; /* Sort-DMA link address shift control */ + reg32 SDST; /* Sort-DMA start */ + reg8 _pad1[28]; + reg32 DBREQM; /* DBREQ# signal mask control */ + reg32 BAVLWC; /* BAVL# signal wait count */ + reg32 C2DPYRC; /* DMA (TA/Root Bus) priority count */ + reg32 DMAXL; /* CH2-DMA maximum burst length */ + reg8 _pad2[48]; + reg32 TFREM; /* TA FIFO remaining amount */ + reg32 LMMODE0; /* Via TA texture memory bus select 0 */ + reg32 LMMODE1; /* Via TA texture memory bus select 1 */ + reg32 FFST; /* FIFO status */ + reg32 SFRES; /* System reset */ + reg8 _pad3[8]; + reg32 SBREV; /* System bus revision number */ + reg32 RBSPLT; /* SH4 Root Bus split enable */ + reg8 _pad4[92]; + reg32 ISTNRM; /* Normal interrupt status */ + reg32 ISTEXT; /* External interrupt status */ + reg32 ISTERR; /* Error interrupt status */ + reg8 _pad5[4]; + reg32 IML2NRM; /* Level 2 normal interrupt mask */ + reg32 IML2EXT; /* Level 2 external interrupt mask */ + reg32 IML2ERR; /* Level 2 error interrupt mask */ + reg8 _pad6[4]; + reg32 IML4NRM; /* Level 4 normal interrupt mask */ + reg32 IML4EXT; /* Level 4 external interrupt mask */ + reg32 IML4ERR; /* Level 4 error interrupt mask */ + reg8 _pad7[4]; + reg32 IML6NRM; /* Level 6 normal interrupt mask */ + reg32 IML6EXT; /* Level 6 external interrupt mask */ + reg32 IML6ERR; /* Level 6 error interrupt mask */ + reg8 _pad8[4]; + reg32 PDTNRM; /* Normal interrupt PVR-DMA startup mask */ + reg32 PDTEXT; /* External interrupt PVR-DMA startup mask */ + reg8 _pad9[8]; + reg32 G2DTNRM; /* Normal interrupt G2-DMA startup mask */ + reg32 G2DTEXT; /* External interrupt G2-DMA startup mask */ + }; + static_assert((offsetof (struct systembus_reg, C2DSTAT)) == 0x0); + static_assert((offsetof (struct systembus_reg, C2DLEN)) == 0x4); + static_assert((offsetof (struct systembus_reg, C2DST)) == 0x8); + static_assert((offsetof (struct systembus_reg, SDSTAW)) == 0x10); + static_assert((offsetof (struct systembus_reg, SDBAAW)) == 0x14); + static_assert((offsetof (struct systembus_reg, SDWLT)) == 0x18); + static_assert((offsetof (struct systembus_reg, SDLAS)) == 0x1c); + static_assert((offsetof (struct systembus_reg, SDST)) == 0x20); + static_assert((offsetof (struct systembus_reg, DBREQM)) == 0x40); + static_assert((offsetof (struct systembus_reg, BAVLWC)) == 0x44); + static_assert((offsetof (struct systembus_reg, C2DPYRC)) == 0x48); + static_assert((offsetof (struct systembus_reg, DMAXL)) == 0x4c); + static_assert((offsetof (struct systembus_reg, TFREM)) == 0x80); + static_assert((offsetof (struct systembus_reg, LMMODE0)) == 0x84); + static_assert((offsetof (struct systembus_reg, LMMODE1)) == 0x88); + static_assert((offsetof (struct systembus_reg, FFST)) == 0x8c); + static_assert((offsetof (struct systembus_reg, SFRES)) == 0x90); + static_assert((offsetof (struct systembus_reg, SBREV)) == 0x9c); + static_assert((offsetof (struct systembus_reg, RBSPLT)) == 0xa0); + static_assert((offsetof (struct systembus_reg, ISTNRM)) == 0x100); + static_assert((offsetof (struct systembus_reg, ISTEXT)) == 0x104); + static_assert((offsetof (struct systembus_reg, ISTERR)) == 0x108); + static_assert((offsetof (struct systembus_reg, IML2NRM)) == 0x110); + static_assert((offsetof (struct systembus_reg, IML2EXT)) == 0x114); + static_assert((offsetof (struct systembus_reg, IML2ERR)) == 0x118); + static_assert((offsetof (struct systembus_reg, IML4NRM)) == 0x120); + static_assert((offsetof (struct systembus_reg, IML4EXT)) == 0x124); + static_assert((offsetof (struct systembus_reg, IML4ERR)) == 0x128); + static_assert((offsetof (struct systembus_reg, IML6NRM)) == 0x130); + static_assert((offsetof (struct systembus_reg, IML6EXT)) == 0x134); + static_assert((offsetof (struct systembus_reg, IML6ERR)) == 0x138); + static_assert((offsetof (struct systembus_reg, PDTNRM)) == 0x140); + static_assert((offsetof (struct systembus_reg, PDTEXT)) == 0x144); + static_assert((offsetof (struct systembus_reg, G2DTNRM)) == 0x150); + static_assert((offsetof (struct systembus_reg, G2DTEXT)) == 0x154); -static_assert((offsetof (struct systembus_reg, C2DSTAT)) == 0x0); -static_assert((offsetof (struct systembus_reg, C2DLEN)) == 0x4); -static_assert((offsetof (struct systembus_reg, C2DST)) == 0x8); -static_assert((offsetof (struct systembus_reg, SDSTAW)) == 0x10); -static_assert((offsetof (struct systembus_reg, SDBAAW)) == 0x14); -static_assert((offsetof (struct systembus_reg, SDWLT)) == 0x18); -static_assert((offsetof (struct systembus_reg, SDLAS)) == 0x1c); -static_assert((offsetof (struct systembus_reg, SDST)) == 0x20); -static_assert((offsetof (struct systembus_reg, DBREQM)) == 0x40); -static_assert((offsetof (struct systembus_reg, BAVLWC)) == 0x44); -static_assert((offsetof (struct systembus_reg, C2DPYRC)) == 0x48); -static_assert((offsetof (struct systembus_reg, DMAXL)) == 0x4c); -static_assert((offsetof (struct systembus_reg, TFREM)) == 0x80); -static_assert((offsetof (struct systembus_reg, LMMODE0)) == 0x84); -static_assert((offsetof (struct systembus_reg, LMMODE1)) == 0x88); -static_assert((offsetof (struct systembus_reg, FFST)) == 0x8c); -static_assert((offsetof (struct systembus_reg, SFRES)) == 0x90); -static_assert((offsetof (struct systembus_reg, SBREV)) == 0x9c); -static_assert((offsetof (struct systembus_reg, RBSPLT)) == 0xa0); -static_assert((offsetof (struct systembus_reg, ISTNRM)) == 0x100); -static_assert((offsetof (struct systembus_reg, ISTEXT)) == 0x104); -static_assert((offsetof (struct systembus_reg, ISTERR)) == 0x108); -static_assert((offsetof (struct systembus_reg, IML2NRM)) == 0x110); -static_assert((offsetof (struct systembus_reg, IML2EXT)) == 0x114); -static_assert((offsetof (struct systembus_reg, IML2ERR)) == 0x118); -static_assert((offsetof (struct systembus_reg, IML4NRM)) == 0x120); -static_assert((offsetof (struct systembus_reg, IML4EXT)) == 0x124); -static_assert((offsetof (struct systembus_reg, IML4ERR)) == 0x128); -static_assert((offsetof (struct systembus_reg, IML6NRM)) == 0x130); -static_assert((offsetof (struct systembus_reg, IML6EXT)) == 0x134); -static_assert((offsetof (struct systembus_reg, IML6ERR)) == 0x138); -static_assert((offsetof (struct systembus_reg, PDTNRM)) == 0x140); -static_assert((offsetof (struct systembus_reg, PDTEXT)) == 0x144); -static_assert((offsetof (struct systembus_reg, G2DTNRM)) == 0x150); -static_assert((offsetof (struct systembus_reg, G2DTEXT)) == 0x154); + struct maple_if_reg { + reg8 _pad0[4]; + reg32 MDSTAR; /* Maple-DMA command table address */ + reg8 _pad1[8]; + reg32 MDTSEL; /* Maple-DMA trigger select */ + reg32 MDEN; /* Maple-DMA enable */ + reg32 MDST; /* Maple-DMA start */ + reg8 _pad2[100]; + reg32 MSYS; /* Maple system control */ + reg32 MST; /* Maple status */ + reg32 MSHTCL; /* Maple-DMA hard trigger clear */ + reg32 MDAPRO; /* Maple-DMA address range */ + reg8 _pad3[88]; + reg32 MMSEL; /* Maple MSP selection */ + reg8 _pad4[8]; + reg32 MTXDAD; /* Maple TXD address counter */ + reg32 MRXDAD; /* Maple RXD address counter */ + reg32 MRXDBD; /* Maple RXD address base */ + }; + static_assert((offsetof (struct maple_if_reg, MDSTAR)) == 0x4); + static_assert((offsetof (struct maple_if_reg, MDTSEL)) == 0x10); + static_assert((offsetof (struct maple_if_reg, MDEN)) == 0x14); + static_assert((offsetof (struct maple_if_reg, MDST)) == 0x18); + static_assert((offsetof (struct maple_if_reg, MSYS)) == 0x80); + static_assert((offsetof (struct maple_if_reg, MST)) == 0x84); + static_assert((offsetof (struct maple_if_reg, MSHTCL)) == 0x88); + static_assert((offsetof (struct maple_if_reg, MDAPRO)) == 0x8c); + static_assert((offsetof (struct maple_if_reg, MMSEL)) == 0xe8); + static_assert((offsetof (struct maple_if_reg, MTXDAD)) == 0xf4); + static_assert((offsetof (struct maple_if_reg, MRXDAD)) == 0xf8); + static_assert((offsetof (struct maple_if_reg, MRXDBD)) == 0xfc); -struct maple_if_reg { - reg8 _pad0[4]; - reg32 MDSTAR; /* Maple-DMA command table address */ - reg8 _pad1[8]; - reg32 MDTSEL; /* Maple-DMA trigger select */ - reg32 MDEN; /* Maple-DMA enable */ - reg32 MDST; /* Maple-DMA start */ - reg8 _pad2[100]; - reg32 MSYS; /* Maple system control */ - reg32 MST; /* Maple status */ - reg32 MSHTCL; /* Maple-DMA hard trigger clear */ - reg32 MDAPRO; /* Maple-DMA address range */ - reg8 _pad3[88]; - reg32 MMSEL; /* Maple MSP selection */ - reg8 _pad4[8]; - reg32 MTXDAD; /* Maple TXD address counter */ - reg32 MRXDAD; /* Maple RXD address counter */ - reg32 MRXDBD; /* Maple RXD address base */ -}; + struct g1_if_reg { + reg8 _pad0[4]; + reg32 GDSTAR; /* GD-DMA start address */ + reg32 GDLEN; /* GD-DMA length */ + reg32 GDDIR; /* GD-DMA direction */ + reg8 _pad1[4]; + reg32 GDEN; /* GD-DMA enable */ + reg32 GDST; /* GD-DMA start */ + reg8 _pad2[100]; + reg32 G1RRC; /* System ROM read access timing */ + reg32 G1RWC; /* System ROM write access timing */ + reg32 G1FRC; /* Flash ROM read access timing */ + reg32 G1FWC; /* Flash ROM write access timing */ + reg32 G1CRC; /* GD PIO read access timing */ + reg32 G1CWC; /* GD PIO write access timing */ + reg8 _pad3[8]; + reg32 G1GDRC; /* GD-DMA read access timing */ + reg32 G1GDWC; /* GD-DMA write access timing */ + reg8 _pad4[8]; + reg32 G1SYSM; /* System mode */ + reg32 G1CRDYC; /* G1IORDY signal control */ + reg32 GDAPRO; /* GD-DMA address range */ + reg8 _pad5[40]; + reg32 GDUNLOCK; /* (undocumented unlock register) */ + reg8 _pad6[12]; + reg32 GDSTARD; /* GD-DMA address count (on Root Bus) */ + reg32 GDLEND; /* GD-DMA transfer counter */ + }; + static_assert((offsetof (struct g1_if_reg, GDSTAR)) == 0x4); + static_assert((offsetof (struct g1_if_reg, GDLEN)) == 0x8); + static_assert((offsetof (struct g1_if_reg, GDDIR)) == 0xc); + static_assert((offsetof (struct g1_if_reg, GDEN)) == 0x14); + static_assert((offsetof (struct g1_if_reg, GDST)) == 0x18); + static_assert((offsetof (struct g1_if_reg, G1RRC)) == 0x80); + static_assert((offsetof (struct g1_if_reg, G1RWC)) == 0x84); + static_assert((offsetof (struct g1_if_reg, G1FRC)) == 0x88); + static_assert((offsetof (struct g1_if_reg, G1FWC)) == 0x8c); + static_assert((offsetof (struct g1_if_reg, G1CRC)) == 0x90); + static_assert((offsetof (struct g1_if_reg, G1CWC)) == 0x94); + static_assert((offsetof (struct g1_if_reg, G1GDRC)) == 0xa0); + static_assert((offsetof (struct g1_if_reg, G1GDWC)) == 0xa4); + static_assert((offsetof (struct g1_if_reg, G1SYSM)) == 0xb0); + static_assert((offsetof (struct g1_if_reg, G1CRDYC)) == 0xb4); + static_assert((offsetof (struct g1_if_reg, GDAPRO)) == 0xb8); + static_assert((offsetof (struct g1_if_reg, GDUNLOCK)) == 0xe4); + static_assert((offsetof (struct g1_if_reg, GDSTARD)) == 0xf4); + static_assert((offsetof (struct g1_if_reg, GDLEND)) == 0xf8); -static_assert((offsetof (struct maple_if_reg, MDSTAR)) == 0x4); -static_assert((offsetof (struct maple_if_reg, MDTSEL)) == 0x10); -static_assert((offsetof (struct maple_if_reg, MDEN)) == 0x14); -static_assert((offsetof (struct maple_if_reg, MDST)) == 0x18); -static_assert((offsetof (struct maple_if_reg, MSYS)) == 0x80); -static_assert((offsetof (struct maple_if_reg, MST)) == 0x84); -static_assert((offsetof (struct maple_if_reg, MSHTCL)) == 0x88); -static_assert((offsetof (struct maple_if_reg, MDAPRO)) == 0x8c); -static_assert((offsetof (struct maple_if_reg, MMSEL)) == 0xe8); -static_assert((offsetof (struct maple_if_reg, MTXDAD)) == 0xf4); -static_assert((offsetof (struct maple_if_reg, MRXDAD)) == 0xf8); -static_assert((offsetof (struct maple_if_reg, MRXDBD)) == 0xfc); + struct g2_if_reg { + reg32 ADSTAG; /* ACIA:G2-DMA G2 start address */ + reg32 ADSTAR; /* ACIA:G2-DMA system memory start address */ + reg32 ADLEN; /* ACIA:G2-DMA length */ + reg32 ADDIR; /* ACIA:G2-DMA direction */ + reg32 ADTSEL; /* ACIA:G2-DMA trigger select */ + reg32 ADEN; /* ACIA:G2-DMA enable */ + reg32 ADST; /* ACIA:G2-DMA start */ + reg32 ADSUSP; /* ACIA:G2-DMA suspend */ + reg32 E1STAG; /* Ext1:G2-DMA start address */ + reg32 E1STAR; /* Ext1:G2-DMA system memory start address */ + reg32 E1LEN; /* Ext1:G2-DMA length */ + reg32 E1DIR; /* Ext1:G2-DMA direction */ + reg32 E1TSEL; /* Ext1:G2-DMA trigger select */ + reg32 E1EN; /* Ext1:G2-DMA enable */ + reg32 E1ST; /* Ext1:G2-DMA start */ + reg32 E1SUSP; /* Ext1:G2-DMA suspend */ + reg32 E2STAG; /* Ext2:G2-DMA start address */ + reg32 E2STAR; /* Ext2:G2-DMA system memory start address */ + reg32 E2LEN; /* Ext2:G2-DMA length */ + reg32 E2DIR; /* Ext2:G2-DMA direction */ + reg32 E2TSEL; /* Ext2:G2-DMA trigger select */ + reg32 E2EN; /* Ext2:G2-DMA enable */ + reg32 E2ST; /* Ext2:G2-DMA start */ + reg32 E2SUSP; /* Ext2:G2-DMA suspend */ + reg32 DDSTAG; /* Dev:G2-DMA start address */ + reg32 DDSTAR; /* Dev:G2-DMA system memory start address */ + reg32 DDLEN; /* Dev:G2-DMA length */ + reg32 DDDIR; /* Dev:G2-DMA direction */ + reg32 DDTSEL; /* Dev:G2-DMA trigger select */ + reg32 DDEN; /* Dev:G2-DMA enable */ + reg32 DDST; /* Dev:G2-DMA start */ + reg32 DDSUSP; /* Dev:G2-DMA suspend */ + reg32 G2ID; /* G2 bus version */ + reg8 _pad0[12]; + reg32 G2DSTO; /* G2/DS timeout */ + reg32 G2TRTO; /* G2/TR timeout */ + reg32 G2MDMTO; /* Modem unit wait timeout */ + reg32 G2MDMW; /* Modem unit wait time */ + reg8 _pad1[28]; + reg32 G2APRO; /* G2-DMA address range */ + reg32 ADSTAGD; /* AICA-DMA address counter (on AICA) */ + reg32 ADSTARD; /* AICA-DMA address counter (on root bus) */ + reg32 ADLEND; /* AICA-DMA transfer counter */ + reg8 _pad2[4]; + reg32 E1STAGD; /* Ext-DMA1 address counter (on Ext) */ + reg32 E1STARD; /* Ext-DMA1 address counter (on root bus) */ + reg32 E1LEND; /* Ext-DMA1 transfer counter */ + reg8 _pad3[4]; + reg32 E2STAGD; /* Ext-DMA2 address counter (on Ext) */ + reg32 E2STARD; /* Ext-DMA2 address counter (on root bus) */ + reg32 E2LEND; /* Ext-DMA2 transfer counter */ + reg8 _pad4[4]; + reg32 DDSTAGD; /* Dev-DMA address counter (on Dev) */ + reg32 DDSTARD; /* Dev-DMA address counter (on root bus) */ + reg32 DDLEND; /* Dev-DMA transfer counter */ + }; + static_assert((offsetof (struct g2_if_reg, ADSTAG)) == 0x0); + static_assert((offsetof (struct g2_if_reg, ADSTAR)) == 0x4); + static_assert((offsetof (struct g2_if_reg, ADLEN)) == 0x8); + static_assert((offsetof (struct g2_if_reg, ADDIR)) == 0xc); + static_assert((offsetof (struct g2_if_reg, ADTSEL)) == 0x10); + static_assert((offsetof (struct g2_if_reg, ADEN)) == 0x14); + static_assert((offsetof (struct g2_if_reg, ADST)) == 0x18); + static_assert((offsetof (struct g2_if_reg, ADSUSP)) == 0x1c); + static_assert((offsetof (struct g2_if_reg, E1STAG)) == 0x20); + static_assert((offsetof (struct g2_if_reg, E1STAR)) == 0x24); + static_assert((offsetof (struct g2_if_reg, E1LEN)) == 0x28); + static_assert((offsetof (struct g2_if_reg, E1DIR)) == 0x2c); + static_assert((offsetof (struct g2_if_reg, E1TSEL)) == 0x30); + static_assert((offsetof (struct g2_if_reg, E1EN)) == 0x34); + static_assert((offsetof (struct g2_if_reg, E1ST)) == 0x38); + static_assert((offsetof (struct g2_if_reg, E1SUSP)) == 0x3c); + static_assert((offsetof (struct g2_if_reg, E2STAG)) == 0x40); + static_assert((offsetof (struct g2_if_reg, E2STAR)) == 0x44); + static_assert((offsetof (struct g2_if_reg, E2LEN)) == 0x48); + static_assert((offsetof (struct g2_if_reg, E2DIR)) == 0x4c); + static_assert((offsetof (struct g2_if_reg, E2TSEL)) == 0x50); + static_assert((offsetof (struct g2_if_reg, E2EN)) == 0x54); + static_assert((offsetof (struct g2_if_reg, E2ST)) == 0x58); + static_assert((offsetof (struct g2_if_reg, E2SUSP)) == 0x5c); + static_assert((offsetof (struct g2_if_reg, DDSTAG)) == 0x60); + static_assert((offsetof (struct g2_if_reg, DDSTAR)) == 0x64); + static_assert((offsetof (struct g2_if_reg, DDLEN)) == 0x68); + static_assert((offsetof (struct g2_if_reg, DDDIR)) == 0x6c); + static_assert((offsetof (struct g2_if_reg, DDTSEL)) == 0x70); + static_assert((offsetof (struct g2_if_reg, DDEN)) == 0x74); + static_assert((offsetof (struct g2_if_reg, DDST)) == 0x78); + static_assert((offsetof (struct g2_if_reg, DDSUSP)) == 0x7c); + static_assert((offsetof (struct g2_if_reg, G2ID)) == 0x80); + static_assert((offsetof (struct g2_if_reg, G2DSTO)) == 0x90); + static_assert((offsetof (struct g2_if_reg, G2TRTO)) == 0x94); + static_assert((offsetof (struct g2_if_reg, G2MDMTO)) == 0x98); + static_assert((offsetof (struct g2_if_reg, G2MDMW)) == 0x9c); + static_assert((offsetof (struct g2_if_reg, G2APRO)) == 0xbc); + static_assert((offsetof (struct g2_if_reg, ADSTAGD)) == 0xc0); + static_assert((offsetof (struct g2_if_reg, ADSTARD)) == 0xc4); + static_assert((offsetof (struct g2_if_reg, ADLEND)) == 0xc8); + static_assert((offsetof (struct g2_if_reg, E1STAGD)) == 0xd0); + static_assert((offsetof (struct g2_if_reg, E1STARD)) == 0xd4); + static_assert((offsetof (struct g2_if_reg, E1LEND)) == 0xd8); + static_assert((offsetof (struct g2_if_reg, E2STAGD)) == 0xe0); + static_assert((offsetof (struct g2_if_reg, E2STARD)) == 0xe4); + static_assert((offsetof (struct g2_if_reg, E2LEND)) == 0xe8); + static_assert((offsetof (struct g2_if_reg, DDSTAGD)) == 0xf0); + static_assert((offsetof (struct g2_if_reg, DDSTARD)) == 0xf4); + static_assert((offsetof (struct g2_if_reg, DDLEND)) == 0xf8); -struct g1_if_reg { - reg8 _pad0[4]; - reg32 GDSTAR; /* GD-DMA start address */ - reg32 GDLEN; /* GD-DMA length */ - reg32 GDDIR; /* GD-DMA direction */ - reg8 _pad1[4]; - reg32 GDEN; /* GD-DMA enable */ - reg32 GDST; /* GD-DMA start */ - reg8 _pad2[100]; - reg32 G1RRC; /* System ROM read access timing */ - reg32 G1RWC; /* System ROM write access timing */ - reg32 G1FRC; /* Flash ROM read access timing */ - reg32 G1FWC; /* Flash ROM write access timing */ - reg32 G1CRC; /* GD PIO read access timing */ - reg32 G1CWC; /* GD PIO write access timing */ - reg8 _pad3[8]; - reg32 G1GDRC; /* GD-DMA read access timing */ - reg32 G1GDWC; /* GD-DMA write access timing */ - reg8 _pad4[8]; - reg32 G1SYSM; /* System mode */ - reg32 G1CRDYC; /* G1IORDY signal control */ - reg32 GDAPRO; /* GD-DMA address range */ - reg8 _pad5[40]; - reg32 GDUNLOCK; /* (undocumented unlock register) */ - reg8 _pad6[12]; - reg32 GDSTARD; /* GD-DMA address count (on Root Bus) */ - reg32 GDLEND; /* GD-DMA transfer counter */ -}; + struct pvr_if_reg { + reg32 PDSTAP; /* PVR-DMA start address */ + reg32 PDSTAR; /* PVR-DMA system memory start address */ + reg32 PDLEN; /* PVR-DMA length */ + reg32 PDDIR; /* PVR-DMA direction */ + reg32 PDTSEL; /* PVR-DMA trigger select */ + reg32 PDEN; /* PVR-DMA enable */ + reg32 PDST; /* PVR-DMA start */ + reg8 _pad0[100]; + reg32 PDAPRO; /* PVR-DMA address range */ + reg8 _pad1[108]; + reg32 PDSTAPD; /* PVR-DMA address counter (on Ext) */ + reg32 PDSTARD; /* PVR-DMA address counter (on root bus) */ + reg32 PDLEND; /* PVR-DMA transfer counter */ + }; + static_assert((offsetof (struct pvr_if_reg, PDSTAP)) == 0x0); + static_assert((offsetof (struct pvr_if_reg, PDSTAR)) == 0x4); + static_assert((offsetof (struct pvr_if_reg, PDLEN)) == 0x8); + static_assert((offsetof (struct pvr_if_reg, PDDIR)) == 0xc); + static_assert((offsetof (struct pvr_if_reg, PDTSEL)) == 0x10); + static_assert((offsetof (struct pvr_if_reg, PDEN)) == 0x14); + static_assert((offsetof (struct pvr_if_reg, PDST)) == 0x18); + static_assert((offsetof (struct pvr_if_reg, PDAPRO)) == 0x80); + static_assert((offsetof (struct pvr_if_reg, PDSTAPD)) == 0xf0); + static_assert((offsetof (struct pvr_if_reg, PDSTARD)) == 0xf4); + static_assert((offsetof (struct pvr_if_reg, PDLEND)) == 0xf8); -static_assert((offsetof (struct g1_if_reg, GDSTAR)) == 0x4); -static_assert((offsetof (struct g1_if_reg, GDLEN)) == 0x8); -static_assert((offsetof (struct g1_if_reg, GDDIR)) == 0xc); -static_assert((offsetof (struct g1_if_reg, GDEN)) == 0x14); -static_assert((offsetof (struct g1_if_reg, GDST)) == 0x18); -static_assert((offsetof (struct g1_if_reg, G1RRC)) == 0x80); -static_assert((offsetof (struct g1_if_reg, G1RWC)) == 0x84); -static_assert((offsetof (struct g1_if_reg, G1FRC)) == 0x88); -static_assert((offsetof (struct g1_if_reg, G1FWC)) == 0x8c); -static_assert((offsetof (struct g1_if_reg, G1CRC)) == 0x90); -static_assert((offsetof (struct g1_if_reg, G1CWC)) == 0x94); -static_assert((offsetof (struct g1_if_reg, G1GDRC)) == 0xa0); -static_assert((offsetof (struct g1_if_reg, G1GDWC)) == 0xa4); -static_assert((offsetof (struct g1_if_reg, G1SYSM)) == 0xb0); -static_assert((offsetof (struct g1_if_reg, G1CRDYC)) == 0xb4); -static_assert((offsetof (struct g1_if_reg, GDAPRO)) == 0xb8); -static_assert((offsetof (struct g1_if_reg, GDUNLOCK)) == 0xe4); -static_assert((offsetof (struct g1_if_reg, GDSTARD)) == 0xf4); -static_assert((offsetof (struct g1_if_reg, GDLEND)) == 0xf8); - -struct g2_if_reg { - reg32 ADSTAG; /* ACIA:G2-DMA G2 start address */ - reg32 ADSTAR; /* ACIA:G2-DMA system memory start address */ - reg32 ADLEN; /* ACIA:G2-DMA length */ - reg32 ADDIR; /* ACIA:G2-DMA direction */ - reg32 ADTSEL; /* ACIA:G2-DMA trigger select */ - reg32 ADEN; /* ACIA:G2-DMA enable */ - reg32 ADST; /* ACIA:G2-DMA start */ - reg32 ADSUSP; /* ACIA:G2-DMA suspend */ - reg32 E1STAG; /* Ext1:G2-DMA start address */ - reg32 E1STAR; /* Ext1:G2-DMA system memory start address */ - reg32 E1LEN; /* Ext1:G2-DMA length */ - reg32 E1DIR; /* Ext1:G2-DMA direction */ - reg32 E1TSEL; /* Ext1:G2-DMA trigger select */ - reg32 E1EN; /* Ext1:G2-DMA enable */ - reg32 E1ST; /* Ext1:G2-DMA start */ - reg32 E1SUSP; /* Ext1:G2-DMA suspend */ - reg32 E2STAG; /* Ext2:G2-DMA start address */ - reg32 E2STAR; /* Ext2:G2-DMA system memory start address */ - reg32 E2LEN; /* Ext2:G2-DMA length */ - reg32 E2DIR; /* Ext2:G2-DMA direction */ - reg32 E2TSEL; /* Ext2:G2-DMA trigger select */ - reg32 E2EN; /* Ext2:G2-DMA enable */ - reg32 E2ST; /* Ext2:G2-DMA start */ - reg32 E2SUSP; /* Ext2:G2-DMA suspend */ - reg32 DDSTAG; /* Dev:G2-DMA start address */ - reg32 DDSTAR; /* Dev:G2-DMA system memory start address */ - reg32 DDLEN; /* Dev:G2-DMA length */ - reg32 DDDIR; /* Dev:G2-DMA direction */ - reg32 DDTSEL; /* Dev:G2-DMA trigger select */ - reg32 DDEN; /* Dev:G2-DMA enable */ - reg32 DDST; /* Dev:G2-DMA start */ - reg32 DDSUSP; /* Dev:G2-DMA suspend */ - reg32 G2ID; /* G2 bus version */ - reg8 _pad0[12]; - reg32 G2DSTO; /* G2/DS timeout */ - reg32 G2TRTO; /* G2/TR timeout */ - reg32 G2MDMTO; /* Modem unit wait timeout */ - reg32 G2MDMW; /* Modem unit wait time */ - reg8 _pad1[28]; - reg32 G2APRO; /* G2-DMA address range */ - reg32 ADSTAGD; /* AICA-DMA address counter (on AICA) */ - reg32 ADSTARD; /* AICA-DMA address counter (on root bus) */ - reg32 ADLEND; /* AICA-DMA transfer counter */ - reg8 _pad2[4]; - reg32 E1STAGD; /* Ext-DMA1 address counter (on Ext) */ - reg32 E1STARD; /* Ext-DMA1 address counter (on root bus) */ - reg32 E1LEND; /* Ext-DMA1 transfer counter */ - reg8 _pad3[4]; - reg32 E2STAGD; /* Ext-DMA2 address counter (on Ext) */ - reg32 E2STARD; /* Ext-DMA2 address counter (on root bus) */ - reg32 E2LEND; /* Ext-DMA2 transfer counter */ - reg8 _pad4[4]; - reg32 DDSTAGD; /* Dev-DMA address counter (on Dev) */ - reg32 DDSTARD; /* Dev-DMA address counter (on root bus) */ - reg32 DDLEND; /* Dev-DMA transfer counter */ -}; - -static_assert((offsetof (struct g2_if_reg, ADSTAG)) == 0x0); -static_assert((offsetof (struct g2_if_reg, ADSTAR)) == 0x4); -static_assert((offsetof (struct g2_if_reg, ADLEN)) == 0x8); -static_assert((offsetof (struct g2_if_reg, ADDIR)) == 0xc); -static_assert((offsetof (struct g2_if_reg, ADTSEL)) == 0x10); -static_assert((offsetof (struct g2_if_reg, ADEN)) == 0x14); -static_assert((offsetof (struct g2_if_reg, ADST)) == 0x18); -static_assert((offsetof (struct g2_if_reg, ADSUSP)) == 0x1c); -static_assert((offsetof (struct g2_if_reg, E1STAG)) == 0x20); -static_assert((offsetof (struct g2_if_reg, E1STAR)) == 0x24); -static_assert((offsetof (struct g2_if_reg, E1LEN)) == 0x28); -static_assert((offsetof (struct g2_if_reg, E1DIR)) == 0x2c); -static_assert((offsetof (struct g2_if_reg, E1TSEL)) == 0x30); -static_assert((offsetof (struct g2_if_reg, E1EN)) == 0x34); -static_assert((offsetof (struct g2_if_reg, E1ST)) == 0x38); -static_assert((offsetof (struct g2_if_reg, E1SUSP)) == 0x3c); -static_assert((offsetof (struct g2_if_reg, E2STAG)) == 0x40); -static_assert((offsetof (struct g2_if_reg, E2STAR)) == 0x44); -static_assert((offsetof (struct g2_if_reg, E2LEN)) == 0x48); -static_assert((offsetof (struct g2_if_reg, E2DIR)) == 0x4c); -static_assert((offsetof (struct g2_if_reg, E2TSEL)) == 0x50); -static_assert((offsetof (struct g2_if_reg, E2EN)) == 0x54); -static_assert((offsetof (struct g2_if_reg, E2ST)) == 0x58); -static_assert((offsetof (struct g2_if_reg, E2SUSP)) == 0x5c); -static_assert((offsetof (struct g2_if_reg, DDSTAG)) == 0x60); -static_assert((offsetof (struct g2_if_reg, DDSTAR)) == 0x64); -static_assert((offsetof (struct g2_if_reg, DDLEN)) == 0x68); -static_assert((offsetof (struct g2_if_reg, DDDIR)) == 0x6c); -static_assert((offsetof (struct g2_if_reg, DDTSEL)) == 0x70); -static_assert((offsetof (struct g2_if_reg, DDEN)) == 0x74); -static_assert((offsetof (struct g2_if_reg, DDST)) == 0x78); -static_assert((offsetof (struct g2_if_reg, DDSUSP)) == 0x7c); -static_assert((offsetof (struct g2_if_reg, G2ID)) == 0x80); -static_assert((offsetof (struct g2_if_reg, G2DSTO)) == 0x90); -static_assert((offsetof (struct g2_if_reg, G2TRTO)) == 0x94); -static_assert((offsetof (struct g2_if_reg, G2MDMTO)) == 0x98); -static_assert((offsetof (struct g2_if_reg, G2MDMW)) == 0x9c); -static_assert((offsetof (struct g2_if_reg, G2APRO)) == 0xbc); -static_assert((offsetof (struct g2_if_reg, ADSTAGD)) == 0xc0); -static_assert((offsetof (struct g2_if_reg, ADSTARD)) == 0xc4); -static_assert((offsetof (struct g2_if_reg, ADLEND)) == 0xc8); -static_assert((offsetof (struct g2_if_reg, E1STAGD)) == 0xd0); -static_assert((offsetof (struct g2_if_reg, E1STARD)) == 0xd4); -static_assert((offsetof (struct g2_if_reg, E1LEND)) == 0xd8); -static_assert((offsetof (struct g2_if_reg, E2STAGD)) == 0xe0); -static_assert((offsetof (struct g2_if_reg, E2STARD)) == 0xe4); -static_assert((offsetof (struct g2_if_reg, E2LEND)) == 0xe8); -static_assert((offsetof (struct g2_if_reg, DDSTAGD)) == 0xf0); -static_assert((offsetof (struct g2_if_reg, DDSTARD)) == 0xf4); -static_assert((offsetof (struct g2_if_reg, DDLEND)) == 0xf8); - -struct pvr_if_reg { - reg32 PDSTAP; /* PVR-DMA start address */ - reg32 PDSTAR; /* PVR-DMA system memory start address */ - reg32 PDLEN; /* PVR-DMA length */ - reg32 PDDIR; /* PVR-DMA direction */ - reg32 PDTSEL; /* PVR-DMA trigger select */ - reg32 PDEN; /* PVR-DMA enable */ - reg32 PDST; /* PVR-DMA start */ - reg8 _pad0[100]; - reg32 PDAPRO; /* PVR-DMA address range */ - reg8 _pad1[108]; - reg32 PDSTAPD; /* PVR-DMA address counter (on Ext) */ - reg32 PDSTARD; /* PVR-DMA address counter (on root bus) */ - reg32 PDLEND; /* PVR-DMA transfer counter */ -}; - -static_assert((offsetof (struct pvr_if_reg, PDSTAP)) == 0x0); -static_assert((offsetof (struct pvr_if_reg, PDSTAR)) == 0x4); -static_assert((offsetof (struct pvr_if_reg, PDLEN)) == 0x8); -static_assert((offsetof (struct pvr_if_reg, PDDIR)) == 0xc); -static_assert((offsetof (struct pvr_if_reg, PDTSEL)) == 0x10); -static_assert((offsetof (struct pvr_if_reg, PDEN)) == 0x14); -static_assert((offsetof (struct pvr_if_reg, PDST)) == 0x18); -static_assert((offsetof (struct pvr_if_reg, PDAPRO)) == 0x80); -static_assert((offsetof (struct pvr_if_reg, PDSTAPD)) == 0xf0); -static_assert((offsetof (struct pvr_if_reg, PDSTARD)) == 0xf4); -static_assert((offsetof (struct pvr_if_reg, PDLEND)) == 0xf8); - -extern struct holly_reg holly __asm("holly"); + extern struct systembus_reg systembus __asm("systembus"); + extern struct maple_if_reg maple_if __asm("maple_if"); + extern struct g1_if_reg g1_if __asm("g1_if"); + extern struct g2_if_reg g2_if __asm("g2_if"); + extern struct pvr_if_reg pvr_if __asm("pvr_if"); +} diff --git a/dreamcast2/systembus/systembus_bits.hpp b/dreamcast2/systembus/systembus_bits.hpp new file mode 100644 index 0000000..95ace0c --- /dev/null +++ b/dreamcast2/systembus/systembus_bits.hpp @@ -0,0 +1,89 @@ +#pragma once + +#include + +namespace systembus { + namespace c2dstat { + constexpr uint32_t texture_memory_start_address(uint32_t num) { return (num & 0x13ffffe0) << 0; } + } + + namespace c2dlen { + constexpr uint32_t transfer_length(uint32_t num) { return (num & 0xffffe0) << 0; } + } + + namespace c2dst { + constexpr uint32_t start = 1 << 0; + } + + namespace istnrm { + constexpr uint32_t end_of_transferring_punch_through_list = 1 << 21; + constexpr uint32_t end_of_dma_sort_dma = 1 << 20; + constexpr uint32_t end_of_dma_ch2_dma = 1 << 19; + constexpr uint32_t end_of_dma_dev_dma = 1 << 18; + constexpr uint32_t end_of_dma_ext_dma2 = 1 << 17; + constexpr uint32_t end_of_dma_ext_dma1 = 1 << 16; + constexpr uint32_t end_of_dma_aica_dma = 1 << 15; + constexpr uint32_t end_of_dma_gd_dma = 1 << 14; + constexpr uint32_t maple_v_blank_over = 1 << 13; + constexpr uint32_t end_of_dma_maple_dma = 1 << 12; + constexpr uint32_t end_of_dma_pvr_dma = 1 << 11; + constexpr uint32_t end_of_transferring_translucent_modifier_volume_list = 1 << 10; + constexpr uint32_t end_of_transferring_translucent_list = 1 << 9; + constexpr uint32_t end_of_transferring_opaque_modifier_volume_list = 1 << 8; + constexpr uint32_t end_of_transferring_opaque_list = 1 << 7; + constexpr uint32_t end_of_transferring_yuv = 1 << 6; + constexpr uint32_t h_blank_in = 1 << 5; + constexpr uint32_t v_blank_out = 1 << 4; + constexpr uint32_t v_blank_in = 1 << 3; + constexpr uint32_t end_of_render_tsp = 1 << 2; + constexpr uint32_t end_of_render_isp = 1 << 1; + constexpr uint32_t end_of_render_video = 1 << 0; + } + + namespace isterr { + constexpr uint32_t sh4__if_access_inhibited_area = 1 << 31; + constexpr uint32_t ddt__if_sort_dma_command_error = 1 << 28; + constexpr uint32_t g2__time_out_in_cpu_access = 1 << 27; + constexpr uint32_t g2__dev_dma_time_out = 1 << 26; + constexpr uint32_t g2__ext_dma2_time_out = 1 << 25; + constexpr uint32_t g2__ext_dma1_time_out = 1 << 24; + constexpr uint32_t g2__aica_dma_time_out = 1 << 23; + constexpr uint32_t g2__dev_dma_over_run = 1 << 22; + constexpr uint32_t g2__ext_dma2_over_run = 1 << 21; + constexpr uint32_t g2__ext_dma1_over_run = 1 << 20; + constexpr uint32_t g2__aica_dma_over_run = 1 << 19; + constexpr uint32_t g2__dev_dma_illegal_address_set = 1 << 18; + constexpr uint32_t g2__ext_dma2_illegal_address_set = 1 << 17; + constexpr uint32_t g2__ext_dma1_illegal_address_set = 1 << 16; + constexpr uint32_t g2__aica_dma_illegal_address_set = 1 << 15; + constexpr uint32_t g1__rom_flash_access_at_gd_dma = 1 << 14; + constexpr uint32_t g1__gd_dma_over_run = 1 << 13; + constexpr uint32_t g1__illegal_address_set = 1 << 12; + constexpr uint32_t maple__illegal_command = 1 << 11; + constexpr uint32_t maple__write_fifo_over_flow = 1 << 10; + constexpr uint32_t maple__dma_over_run = 1 << 9; + constexpr uint32_t maple__illegal_address_set = 1 << 8; + constexpr uint32_t pvrif__dma_over_run = 1 << 7; + constexpr uint32_t pvrif__illegal_address_set = 1 << 6; + constexpr uint32_t ta__fifo_overflow = 1 << 5; + constexpr uint32_t ta__illegal_parameter = 1 << 4; + constexpr uint32_t ta__object_list_pointer_overflow = 1 << 3; + constexpr uint32_t ta__isp_tsp_parameter_overflow = 1 << 2; + constexpr uint32_t render__hazard_processing_of_strip_buffer = 1 << 1; + constexpr uint32_t render__isp_out_of_cache = 1 << 0; + } + + namespace ffst { + constexpr uint32_t holly_cpu_if_block_internal_write_buffer(uint32_t reg) { return (reg >> 5) & 0x1; } + constexpr uint32_t holly_g2_if_block_internal_write_buffer(uint32_t reg) { return (reg >> 4) & 0x1; } + constexpr uint32_t aica_internal_write_buffer(uint32_t reg) { return (reg >> 0) & 0x1; } + } + + namespace istext { + constexpr uint32_t external_device = 1 << 3; + constexpr uint32_t modem = 1 << 2; + constexpr uint32_t aica = 1 << 1; + constexpr uint32_t gdrom = 1 << 0; + } + +}