From 8e97614ffeca1cb6acca5470f9bf74511d472ee3 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 24 Aug 2025 11:10:55 -0500 Subject: [PATCH] dreamcast2: initial --- dreamcast2/Makefile | 30 + dreamcast2/holly/holly.hpp | 166 ++++ dreamcast2/holly/holly_bits.hpp | 635 ++++++++++++ dreamcast2/holly/region_array.cpp | 71 ++ dreamcast2/holly/region_array.hpp | 41 + dreamcast2/holly/region_array_bits.hpp | 22 + dreamcast2/memorymap.hpp | 15 + dreamcast2/reg.hpp | 12 + dreamcast2/regs/block_regs.py | 100 ++ dreamcast2/regs/csv_input.py | 27 + dreamcast2/regs/generate.py | 43 + dreamcast2/regs/holly.py | 18 + dreamcast2/regs/holly/holly.csv | 87 ++ dreamcast2/regs/holly/holly.ods | Bin 0 -> 23503 bytes dreamcast2/regs/holly/holly_bits.csv | 327 ++++++ dreamcast2/regs/holly/holly_bits.ods | Bin 0 -> 24403 bytes dreamcast2/regs/holly/region_array_bits.csv | 10 + dreamcast2/regs/holly/region_array_bits.ods | Bin 0 -> 13089 bytes dreamcast2/regs/holly_bits.py | 286 ++++++ dreamcast2/regs/sh7091.py | 145 +++ dreamcast2/regs/sh7091/sh7091.csv | 126 +++ dreamcast2/regs/sh7091/sh7091.ods | Bin 0 -> 21788 bytes dreamcast2/regs/sh7091/sh7091_bits.csv | 366 +++++++ dreamcast2/regs/sh7091/sh7091_bits.ods | Bin 0 -> 26732 bytes dreamcast2/regs/systembus/systembus.csv | 163 +++ dreamcast2/regs/systembus/systembus.ods | Bin 0 -> 29488 bytes dreamcast2/regs/systembus/systembus_bits.ods | Bin 0 -> 15350 bytes dreamcast2/sh7091/sh7091.hpp | 379 +++++++ dreamcast2/sh7091/sh7091_bits.hpp | 994 +++++++++++++++++++ dreamcast2/sh7091/store_queue_transfer.hpp | 70 ++ dreamcast2/systembus/systembus.hpp | 308 ++++++ 31 files changed, 4441 insertions(+) create mode 100644 dreamcast2/Makefile create mode 100644 dreamcast2/holly/holly.hpp create mode 100644 dreamcast2/holly/holly_bits.hpp create mode 100644 dreamcast2/holly/region_array.cpp create mode 100644 dreamcast2/holly/region_array.hpp create mode 100644 dreamcast2/holly/region_array_bits.hpp create mode 100644 dreamcast2/memorymap.hpp create mode 100644 dreamcast2/reg.hpp create mode 100644 dreamcast2/regs/block_regs.py create mode 100644 dreamcast2/regs/csv_input.py create mode 100644 dreamcast2/regs/generate.py create mode 100644 dreamcast2/regs/holly.py create mode 100644 dreamcast2/regs/holly/holly.csv create mode 100644 dreamcast2/regs/holly/holly.ods create mode 100644 dreamcast2/regs/holly/holly_bits.csv create mode 100644 dreamcast2/regs/holly/holly_bits.ods create mode 100644 dreamcast2/regs/holly/region_array_bits.csv create mode 100644 dreamcast2/regs/holly/region_array_bits.ods create mode 100644 dreamcast2/regs/holly_bits.py create mode 100644 dreamcast2/regs/sh7091.py create mode 100644 dreamcast2/regs/sh7091/sh7091.csv create mode 100644 dreamcast2/regs/sh7091/sh7091.ods create mode 100644 dreamcast2/regs/sh7091/sh7091_bits.csv create mode 100644 dreamcast2/regs/sh7091/sh7091_bits.ods create mode 100644 dreamcast2/regs/systembus/systembus.csv create mode 100644 dreamcast2/regs/systembus/systembus.ods create mode 100644 dreamcast2/regs/systembus/systembus_bits.ods create mode 100644 dreamcast2/sh7091/sh7091.hpp create mode 100644 dreamcast2/sh7091/sh7091_bits.hpp create mode 100644 dreamcast2/sh7091/store_queue_transfer.hpp create mode 100644 dreamcast2/systembus/systembus.hpp diff --git a/dreamcast2/Makefile b/dreamcast2/Makefile new file mode 100644 index 0000000..6f0774a --- /dev/null +++ b/dreamcast2/Makefile @@ -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/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 > $@ diff --git a/dreamcast2/holly/holly.hpp b/dreamcast2/holly/holly.hpp new file mode 100644 index 0000000..25b71ca --- /dev/null +++ b/dreamcast2/holly/holly.hpp @@ -0,0 +1,166 @@ +#pragma once + +#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 */ +}; + +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"); diff --git a/dreamcast2/holly/holly_bits.hpp b/dreamcast2/holly/holly_bits.hpp new file mode 100644 index 0000000..fe6dd75 --- /dev/null +++ b/dreamcast2/holly/holly_bits.hpp @@ -0,0 +1,635 @@ +#pragma once + +#include + +namespace holly { + namespace id { + constexpr uint32_t device_id(uint32_t reg) { return (reg >> 16) & 0xffff; } + constexpr uint32_t vendor_id(uint32_t reg) { return (reg >> 0) & 0xffff; } + } + + namespace revision { + constexpr uint32_t chip_revision(uint32_t reg) { return (reg >> 0) & 0xffff; } + } + + namespace softreset { + constexpr uint32_t sdram_if_soft_reset = 1 << 2; + constexpr uint32_t pipeline_soft_reset = 1 << 1; + constexpr uint32_t ta_soft_reset = 1 << 0; + } + + namespace startrender { + constexpr uint32_t start_render = 1 << 0; + } + + namespace test_select { + constexpr uint32_t diagdb_data(uint32_t reg) { return (reg >> 5) & 0x1f; } + constexpr uint32_t diagda_data(uint32_t reg) { return (reg >> 0) & 0x1f; } + } + + namespace param_base { + constexpr uint32_t base_address(uint32_t num) { return (num & 0xf00000) << 0; } + } + + namespace region_base { + constexpr uint32_t base_address(uint32_t num) { return (num & 0xfffffc) << 0; } + } + + namespace span_sort_cfg { + constexpr uint32_t cache_bypass = 1 << 16; + constexpr uint32_t offset_sort_enable = 1 << 8; + constexpr uint32_t span_sort_enable = 1 << 0; + } + + namespace vo_border_col { + constexpr uint32_t chroma(uint32_t num) { return (num & 0x1) << 24; } + constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } + constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } + constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace fb_r_ctrl { + namespace vclk_div { + constexpr uint32_t pclk_vclk_2 = 0 << 23; + constexpr uint32_t pclk_vclk_1 = 1 << 23; + + constexpr uint32_t bit_mask = 0x1 << 23; + } + + constexpr uint32_t fb_strip_buf_en = 1 << 22; + constexpr uint32_t fb_stripsize(uint32_t num) { return (num & 0x3e) << 16; } + constexpr uint32_t fb_chroma_threshold(uint32_t num) { return (num & 0xff) << 8; } + constexpr uint32_t fb_concat(uint32_t num) { return (num & 0x3) << 4; } + + namespace fb_depth { + constexpr uint32_t xrgb0555 = 0 << 2; + constexpr uint32_t rgb565 = 1 << 2; + constexpr uint32_t rgb888 = 2 << 2; + constexpr uint32_t xrgb0888 = 3 << 2; + + constexpr uint32_t bit_mask = 0x3 << 2; + } + + constexpr uint32_t fb_line_double = 1 << 1; + constexpr uint32_t fb_enable = 1 << 0; + } + + namespace fb_w_ctrl { + constexpr uint32_t fb_alpha_threshold(uint32_t num) { return (num & 0xff) << 16; } + constexpr uint32_t fb_kval(uint32_t num) { return (num & 0xff) << 8; } + constexpr uint32_t fb_dither = 1 << 3; + + namespace fb_packmode { + constexpr uint32_t krgb0555 = 0 << 0; + constexpr uint32_t rgb565 = 1 << 0; + constexpr uint32_t argb4444 = 2 << 0; + constexpr uint32_t argb1555 = 3 << 0; + constexpr uint32_t rgb888 = 4 << 0; + constexpr uint32_t krgb0888 = 5 << 0; + constexpr uint32_t argb8888 = 6 << 0; + + constexpr uint32_t bit_mask = 0x7 << 0; + } + } + + namespace fb_w_linestride { + constexpr uint32_t fb_line_stride(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace fb_r_sof1 { + constexpr uint32_t frame_buffer_read_address_frame_1(uint32_t num) { return (num & 0xfffffc) << 0; } + } + + namespace fb_r_sof2 { + constexpr uint32_t frame_buffer_read_address_frame_2(uint32_t num) { return (num & 0xfffffc) << 0; } + } + + namespace fb_r_size { + constexpr uint32_t fb_modulus(uint32_t num) { return (num & 0x3ff) << 20; } + constexpr uint32_t fb_y_size(uint32_t num) { return (num & 0x3ff) << 10; } + constexpr uint32_t fb_x_size(uint32_t num) { return (num & 0x3ff) << 0; } + } + + namespace fb_w_sof1 { + constexpr uint32_t frame_buffer_write_address_frame_1(uint32_t num) { return (num & 0x1fffffc) << 0; } + } + + namespace fb_w_sof2 { + constexpr uint32_t frame_buffer_write_address_frame_2(uint32_t num) { return (num & 0x1fffffc) << 0; } + } + + namespace fb_x_clip { + constexpr uint32_t fb_x_clip_max(uint32_t num) { return (num & 0x7ff) << 16; } + constexpr uint32_t fb_x_clip_min(uint32_t num) { return (num & 0x7ff) << 0; } + } + + namespace fb_y_clip { + constexpr uint32_t fb_y_clip_max(uint32_t num) { return (num & 0x3ff) << 16; } + constexpr uint32_t fb_y_clip_min(uint32_t num) { return (num & 0x3ff) << 0; } + } + + namespace fpu_shad_scale { + namespace simple_shadow_enable { + constexpr uint32_t parameter_selection_volume_mode = 0 << 8; + constexpr uint32_t intensity_volume_mode = 1 << 8; + + constexpr uint32_t bit_mask = 0x1 << 8; + } + + constexpr uint32_t scale_factor_for_shadows(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace fpu_cull_val { + inline uint32_t culling_comparison_value(float num) { return _i(__builtin_fabsf(num));; } + } + + namespace fpu_param_cfg { + namespace region_header_type { + constexpr uint32_t type_1 = 0 << 21; + constexpr uint32_t type_2 = 1 << 21; + + constexpr uint32_t bit_mask = 0x1 << 21; + } + + constexpr uint32_t tsp_parameter_burst_threshold(uint32_t num) { return (num & 0x3f) << 14; } + constexpr uint32_t isp_parameter_burst_threshold(uint32_t num) { return (num & 0x3f) << 8; } + constexpr uint32_t pointer_burst_size(uint32_t num) { return (num & 0xf) << 4; } + constexpr uint32_t pointer_first_burst_size(uint32_t num) { return (num & 0xf) << 0; } + } + + namespace half_offset { + namespace tsp_texel_sampling_position { + constexpr uint32_t top_left = 1 << 2; + constexpr uint32_t center = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; + } + + namespace tsp_pixel_sampling_position { + constexpr uint32_t top_left = 1 << 1; + constexpr uint32_t center = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; + } + + namespace fpu_pixel_sampling_position { + constexpr uint32_t top_left = 1 << 0; + constexpr uint32_t center = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace fpu_perp_val { + inline uint32_t perpendicular_triangle_compare(float num) { return _i(__builtin_fabsf(num));; } + } + + namespace isp_backgnd_d { + inline uint32_t background_plane_depth(float num) { return _i(num) & 0xfffffff0; } + } + + namespace isp_backgnd_t { + constexpr uint32_t cache_bypass = 1 << 28; + constexpr uint32_t shadow = 1 << 27; + constexpr uint32_t skip(uint32_t num) { return (num & 0x7) << 24; } + constexpr uint32_t tag_address(uint32_t num) { return (num & 0x1fffff) << 3; } + constexpr uint32_t tag_offset(uint32_t num) { return (num & 0x7) << 0; } + } + + namespace isp_feed_cfg { + constexpr uint32_t cache_size_for_translucency(uint32_t num) { return (num & 0x3ff) << 14; } + constexpr uint32_t punch_through_chunk_size(uint32_t num) { return (num & 0x3ff) << 4; } + constexpr uint32_t discard_mode = 1 << 3; + constexpr uint32_t pre_sort_mode = 1 << 0; + } + + namespace sdram_refresh { + constexpr uint32_t refresh_counter_value(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace sdram_arb_cfg { + namespace override_value { + constexpr uint32_t priority_only = 0x0 << 18; + constexpr uint32_t rendered_data = 0x1 << 18; + constexpr uint32_t texture_vq_index = 0x2 << 18; + constexpr uint32_t texture_normal_data_and_vq_codebook = 0x3 << 18; + constexpr uint32_t tile_accelerator_isp_tsp_data = 0x4 << 18; + constexpr uint32_t tile_accelerator_pointers = 0x5 << 18; + constexpr uint32_t sh4 = 0x6 << 18; + constexpr uint32_t tsp_parameters = 0x7 << 18; + constexpr uint32_t tsp_region_data = 0x8 << 18; + constexpr uint32_t isp_pointer_data = 0x9 << 18; + constexpr uint32_t isp_parameters = 0xa << 18; + constexpr uint32_t crt_controller = 0xb << 18; + + constexpr uint32_t bit_mask = 0xf << 18; + } + + namespace arbiter_priority_control { + constexpr uint32_t priority_arbitration_only = 0x0 << 16; + constexpr uint32_t override_value_field = 0x1 << 16; + constexpr uint32_t round_robin_counter = 0x2 << 16; + + constexpr uint32_t bit_mask = 0x3 << 16; + } + + constexpr uint32_t arbiter_crt_page_break_latency_count_value(uint32_t num) { return (num & 0xff) << 8; } + constexpr uint32_t arbiter_page_break_latency_count_value(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace sdram_cfg { + constexpr uint32_t read_command_to_returned_data_delay(uint32_t num) { return (num & 0x7) << 26; } + constexpr uint32_t cas_latency_value(uint32_t num) { return (num & 0x7) << 23; } + constexpr uint32_t activate_to_activate_period(uint32_t num) { return (num & 0x3) << 21; } + constexpr uint32_t read_to_write_period(uint32_t num) { return (num & 0x7) << 18; } + constexpr uint32_t refresh_to_activate_period(uint32_t num) { return (num & 0xf) << 14; } + constexpr uint32_t pre_charge_to_activate_period(uint32_t num) { return (num & 0x3) << 10; } + constexpr uint32_t activate_to_pre_charge_period(uint32_t num) { return (num & 0xf) << 6; } + constexpr uint32_t activate_to_read_write_command_period(uint32_t num) { return (num & 0x3) << 4; } + constexpr uint32_t write_to_pre_charge_period(uint32_t num) { return (num & 0x3) << 2; } + constexpr uint32_t read_to_pre_charge_period(uint32_t num) { return (num & 0x3) << 0; } + } + + namespace fog_col_ram { + constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } + constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } + constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace fog_col_vert { + constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } + constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } + constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace fog_density { + constexpr uint32_t fog_scale_mantissa(uint32_t num) { return (num & 0xff) << 8; } + constexpr uint32_t fog_scale_exponent(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace fog_clamp_max { + constexpr uint32_t alpha(uint32_t num) { return (num & 0xff) << 24; } + constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } + constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } + constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace fog_clamp_min { + constexpr uint32_t alpha(uint32_t num) { return (num & 0xff) << 24; } + constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } + constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } + constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace spg_trigger_pos { + constexpr uint32_t trigger_v_count(uint32_t reg) { return (reg >> 16) & 0x3ff; } + constexpr uint32_t trigger_h_count(uint32_t reg) { return (reg >> 0) & 0x3ff; } + } + + namespace spg_hblank_int { + constexpr uint32_t hblank_in_interrupt(uint32_t reg) { return (reg >> 16) & 0x3ff; } + + namespace hblank_int_mode { + constexpr uint32_t output_equal_line_comp_val = 0x0 << 12; + constexpr uint32_t output_every_line_comp_val = 0x1 << 12; + constexpr uint32_t output_every_line = 0x2 << 12; + + constexpr uint32_t bit_mask = 0x3 << 12; + } + + constexpr uint32_t line_comp_val(uint32_t num) { return (num & 0x3ff) << 0; } + } + + namespace spg_vblank_int { + constexpr uint32_t vblank_out_interrupt_line_number(uint32_t num) { return (num & 0x3ff) << 16; } + constexpr uint32_t vblank_in_interrupt_line_number(uint32_t num) { return (num & 0x3ff) << 0; } + } + + namespace spg_control { + namespace csync_on_h { + constexpr uint32_t hsync = 0 << 9; + constexpr uint32_t csync = 1 << 9; + + constexpr uint32_t bit_mask = 0x1 << 9; + } + + namespace sync_direction { + constexpr uint32_t input = 0 << 8; + constexpr uint32_t output = 1 << 8; + + constexpr uint32_t bit_mask = 0x1 << 8; + } + + constexpr uint32_t pal = 1 << 7; + constexpr uint32_t ntsc = 1 << 6; + constexpr uint32_t force_field2 = 1 << 5; + constexpr uint32_t interlace = 1 << 4; + constexpr uint32_t spg_lock = 1 << 3; + + namespace mcsync_pol { + constexpr uint32_t active_low = 0 << 2; + constexpr uint32_t active_high = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; + } + + namespace mvsync_pol { + constexpr uint32_t active_low = 0 << 1; + constexpr uint32_t active_high = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; + } + + namespace mhsync_pol { + constexpr uint32_t active_low = 0 << 0; + constexpr uint32_t active_high = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace spg_hblank { + constexpr uint32_t hbend(uint32_t num) { return (num & 0x3ff) << 16; } + constexpr uint32_t hbstart(uint32_t num) { return (num & 0x3ff) << 0; } + } + + namespace spg_load { + constexpr uint32_t vcount(uint32_t num) { return (num & 0x3ff) << 16; } + constexpr uint32_t hcount(uint32_t num) { return (num & 0x3ff) << 0; } + } + + namespace spg_vblank { + constexpr uint32_t vbend(uint32_t num) { return (num & 0x3ff) << 16; } + constexpr uint32_t vbstart(uint32_t num) { return (num & 0x3ff) << 0; } + } + + namespace spg_width { + constexpr uint32_t eqwidth(uint32_t num) { return (num & 0x3ff) << 22; } + constexpr uint32_t bpwidth(uint32_t num) { return (num & 0x3ff) << 12; } + constexpr uint32_t vswidth(uint32_t num) { return (num & 0xf) << 8; } + constexpr uint32_t hswidth(uint32_t num) { return (num & 0x7f) << 0; } + } + + namespace text_control { + namespace code_book_endian { + constexpr uint32_t little_endian = 0 << 17; + constexpr uint32_t big_endian = 1 << 17; + + constexpr uint32_t bit_mask = 0x1 << 17; + } + + namespace index_endian { + constexpr uint32_t little_endian = 0 << 16; + constexpr uint32_t big_endian = 1 << 16; + + constexpr uint32_t bit_mask = 0x1 << 16; + } + + constexpr uint32_t bank_bit(uint32_t num) { return (num & 0x1f) << 8; } + constexpr uint32_t stride(uint32_t num) { return (num & 0x1f) << 0; } + } + + namespace vo_control { + constexpr uint32_t pclk_delay_reset = 1 << 21; + constexpr uint32_t pclk_delay(uint32_t num) { return (num & 0x1f) << 16; } + constexpr uint32_t pixel_double = 1 << 8; + + namespace field_mode { + constexpr uint32_t use_field_flag_from_spg = 0x0 << 4; + constexpr uint32_t use_inverse_of_field_flag_from_spg = 0x1 << 4; + constexpr uint32_t field_1_fixed = 0x2 << 4; + constexpr uint32_t field_2_fixed = 0x3 << 4; + constexpr uint32_t field_1_when_the_active_edges_of_hsync_and_vsync_match = 0x4 << 4; + constexpr uint32_t field_2_when_the_active_edges_of_hsync_and_vsync_match = 0x5 << 4; + constexpr uint32_t field_1_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge = 0x6 << 4; + constexpr uint32_t field_2_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge = 0x7 << 4; + constexpr uint32_t inverted_at_the_active_edge_of_vsync = 0x8 << 4; + + constexpr uint32_t bit_mask = 0xf << 4; + } + + constexpr uint32_t blank_video = 1 << 3; + + namespace blank_pol { + constexpr uint32_t active_low = 0 << 2; + constexpr uint32_t active_high = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; + } + + namespace vsync_pol { + constexpr uint32_t active_low = 0 << 1; + constexpr uint32_t active_high = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; + } + + namespace hsync_pol { + constexpr uint32_t active_low = 0 << 0; + constexpr uint32_t active_high = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace vo_startx { + constexpr uint32_t horizontal_start_position(uint32_t num) { return (num & 0x3ff) << 0; } + } + + namespace vo_starty { + constexpr uint32_t vertical_start_position_on_field_2(uint32_t num) { return (num & 0x3ff) << 16; } + constexpr uint32_t vertical_start_position_on_field_1(uint32_t num) { return (num & 0x3ff) << 0; } + } + + namespace scaler_ctl { + namespace field_select { + constexpr uint32_t field_1 = 0 << 18; + constexpr uint32_t field_2 = 1 << 18; + + constexpr uint32_t bit_mask = 0x1 << 18; + } + + constexpr uint32_t interlace = 1 << 17; + constexpr uint32_t horizontal_scaling_enable = 1 << 16; + constexpr uint32_t vertical_scale_factor(uint32_t num) { return (num & 0xffff) << 0; } + } + + namespace pal_ram_ctrl { + namespace pixel_format { + constexpr uint32_t argb1555 = 0 << 0; + constexpr uint32_t rgb565 = 1 << 0; + constexpr uint32_t argb4444 = 2 << 0; + constexpr uint32_t argb8888 = 3 << 0; + + constexpr uint32_t bit_mask = 0x3 << 0; + } + } + + namespace spg_status { + constexpr uint32_t vsync(uint32_t reg) { return (reg >> 13) & 0x1; } + constexpr uint32_t hsync(uint32_t reg) { return (reg >> 12) & 0x1; } + constexpr uint32_t blank(uint32_t reg) { return (reg >> 11) & 0x1; } + constexpr uint32_t fieldnum(uint32_t reg) { return (reg >> 10) & 0x1; } + constexpr uint32_t scanline(uint32_t reg) { return (reg >> 0) & 0x3ff; } + } + + namespace fb_burstctrl { + constexpr uint32_t wr_burst(uint32_t num) { return (num & 0xf) << 16; } + constexpr uint32_t vid_lat(uint32_t num) { return (num & 0x7f) << 8; } + constexpr uint32_t vid_burst(uint32_t num) { return (num & 0x3f) << 0; } + } + + namespace fb_c_sof { + constexpr uint32_t frame_buffer_current_read_address(uint32_t reg) { return (reg >> 0) & 0xffffff; } + } + + namespace y_coeff { + constexpr uint32_t coefficient_1(uint32_t num) { return (num & 0xff) << 8; } + constexpr uint32_t coefficient_0_2(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace pt_alpha_ref { + constexpr uint32_t alpha_reference_for_punch_through(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace fog_table { + constexpr uint32_t fog_table_data(uint32_t num) { return (num & 0xffff) << 0; } + } + + namespace palette_ram { + constexpr uint32_t palette_data(uint32_t num) { return (num & 0xffffffff) << 0; } + } + + namespace ta_ol_base { + constexpr uint32_t base_address(uint32_t num) { return (num & 0xffffe0) << 0; } + } + + namespace ta_isp_base { + constexpr uint32_t base_address(uint32_t num) { return (num & 0xfffffc) << 0; } + } + + namespace ta_ol_limit { + constexpr uint32_t limit_address(uint32_t num) { return (num & 0xffffe0) << 0; } + } + + namespace ta_isp_limit { + constexpr uint32_t limit_address(uint32_t num) { return (num & 0xfffffc) << 0; } + } + + namespace ta_next_opb { + constexpr uint32_t address(uint32_t num) { return (num & 0xffffe0) << 0; } + } + + namespace ta_itp_current { + constexpr uint32_t address(uint32_t reg) { return (reg >> 0) & 0xffffff; } + } + + namespace ta_glob_tile_clip { + constexpr uint32_t tile_y_num(uint32_t num) { return (num & 0xf) << 16; } + constexpr uint32_t tile_x_num(uint32_t num) { return (num & 0x1f) << 0; } + } + + namespace ta_alloc_ctrl { + namespace opb_mode { + constexpr uint32_t increasing_addresses = 0 << 20; + constexpr uint32_t decreasing_addresses = 1 << 20; + + constexpr uint32_t bit_mask = 0x1 << 20; + } + + namespace pt_opb { + constexpr uint32_t no_list = 0 << 16; + constexpr uint32_t _8x4byte = 1 << 16; + constexpr uint32_t _16x4byte = 2 << 16; + constexpr uint32_t _32x4byte = 3 << 16; + + constexpr uint32_t bit_mask = 0x3 << 16; + } + + namespace tm_opb { + constexpr uint32_t no_list = 0 << 12; + constexpr uint32_t _8x4byte = 1 << 12; + constexpr uint32_t _16x4byte = 2 << 12; + constexpr uint32_t _32x4byte = 3 << 12; + + constexpr uint32_t bit_mask = 0x3 << 12; + } + + namespace t_opb { + constexpr uint32_t no_list = 0 << 8; + constexpr uint32_t _8x4byte = 1 << 8; + constexpr uint32_t _16x4byte = 2 << 8; + constexpr uint32_t _32x4byte = 3 << 8; + + constexpr uint32_t bit_mask = 0x3 << 8; + } + + namespace om_opb { + constexpr uint32_t no_list = 0 << 4; + constexpr uint32_t _8x4byte = 1 << 4; + constexpr uint32_t _16x4byte = 2 << 4; + constexpr uint32_t _32x4byte = 3 << 4; + + constexpr uint32_t bit_mask = 0x3 << 4; + } + + namespace o_opb { + constexpr uint32_t no_list = 0 << 0; + constexpr uint32_t _8x4byte = 1 << 0; + constexpr uint32_t _16x4byte = 2 << 0; + constexpr uint32_t _32x4byte = 3 << 0; + + constexpr uint32_t bit_mask = 0x3 << 0; + } + } + + namespace ta_list_init { + constexpr uint32_t list_init = 1 << 31; + } + + namespace ta_yuv_tex_base { + constexpr uint32_t base_address(uint32_t num) { return (num & 0xfffff8) << 0; } + } + + namespace ta_yuv_tex_ctrl { + namespace yuv_form { + constexpr uint32_t yuv420 = 0 << 24; + constexpr uint32_t yuv422 = 1 << 24; + + constexpr uint32_t bit_mask = 0x1 << 24; + } + + namespace yuv_tex { + constexpr uint32_t one_texture = 0 << 16; + constexpr uint32_t multiple_textures = 1 << 16; + + constexpr uint32_t bit_mask = 0x1 << 16; + } + + constexpr uint32_t yuv_v_size(uint32_t num) { return (num & 0x3f) << 8; } + constexpr uint32_t yuv_u_size(uint32_t num) { return (num & 0x3f) << 0; } + } + + namespace ta_yuv_tex_cnt { + constexpr uint32_t yuv_num(uint32_t reg) { return (reg >> 0) & 0x1fff; } + } + + namespace ta_list_cont { + constexpr uint32_t list_cont = 1 << 31; + } + + namespace ta_next_opb_init { + constexpr uint32_t address(uint32_t num) { return (num & 0xffffe0) << 0; } + } + + namespace ta_ol_pointers { + constexpr uint32_t entry(uint32_t reg) { return (reg >> 31) & 0x1; } + constexpr uint32_t sprite(uint32_t reg) { return (reg >> 30) & 0x1; } + constexpr uint32_t triangle(uint32_t reg) { return (reg >> 29) & 0x1; } + constexpr uint32_t number_of_triangles_quads(uint32_t reg) { return (reg >> 25) & 0xf; } + constexpr uint32_t shadow(uint32_t reg) { return (reg >> 24) & 0x1; } + constexpr uint32_t pointer_address(uint32_t reg) { return (reg >> 2) & 0x3fffff; } + constexpr uint32_t skip(uint32_t reg) { return (reg >> 0) & 0x3; } + } + +} diff --git a/dreamcast2/holly/region_array.cpp b/dreamcast2/holly/region_array.cpp new file mode 100644 index 0000000..e2e99f4 --- /dev/null +++ b/dreamcast2/holly/region_array.cpp @@ -0,0 +1,71 @@ +#include "holly/region_array.hpp" +#include "holly/region_array_bits.hpp" + +#incllude "sh7091/store_queue_transfer.hpp" + +namespace holly::region_array { + + void transfer_region_array(const int tile_width, + const int tile_height, + const list_block_size& list_block_size, + const uint32_t region_array_start, + const uint32_t object_list_start); + { + const uint32_t ol_base = object_list_start; + const uint32_t num_tiles = width * height; + region_array_entry region_array[num_tiles]; + + int ix = 0; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + region_array[ix].tile = tile::y_position(y) + | tile::x_position(x); + + if (y == (height - 1) && x == (width - 1)) + region_array[ix].tile |= tile::last_region; + + region_array[ix].list_pointer.opaque = (opb_size.opaque == 0) ? REGION_ARRAY__LIST_POINTER__EMPTY : + (ol_base + (opb_size.opaque * ix) + ); + + region_array[ix].list_pointer.opaque_modifier_volume = (opb_size.opaque_modifier == 0) ? REGION_ARRAY__LIST_POINTER__EMPTY : + (ol_base + num_tiles * ( opb_size.opaque + ) + + (opb_size.opaque_modifier_volume * ix) + ); + + region_array[ix].list_pointer.translucent = (opb_size.translucent == 0) ? REGION_ARRAY__LIST_POINTER__EMPTY : + (ol_base + num_tiles * ( opb_size.opaque + + opb_size.opaque_modifier_volume + ) + + (opb_size.translucent * ix) + ); + region_array[ix].list_pointer.translucent_modifier_volume = (opb_size.translucent_modifier == 0) ? REGION_ARRAY__LIST_POINTER__EMPTY : + (ol_base + num_tiles * ( opb_size.opaque + + opb_size.opaque_modifier_volume + + opb_size.translucent + ) + + (opb_size.translucent_modifier_volume * ix) + ); + region_array[ix].list_pointer.punch_through = (opb_size.punch_through == 0) ? REGION_ARRAY__LIST_POINTER__EMPTY : + (ol_base + num_tiles * ( opb_size.opaque + + opb_size.opaque_modifier_volume + + opb_size.translucent + + opb_size.translucent_modifier_volume + ) + + (opb_size.punch_through * ix) + ); + + ix += 1; + } + } + + system.LMMODE0 = 1; // 32-bit address space + system.LMMODE1 = 1; // 32-bit address space + + void * dst = (void *)(&ta_fifo_texture_memory[region_array_start]); + void * src = (void *)(region_array); + sh7091::store_queue_transfer::copy(dst, src, (sizeof (region_array_entry)) * num_tiles); + } +} diff --git a/dreamcast2/holly/region_array.hpp b/dreamcast2/holly/region_array.hpp new file mode 100644 index 0000000..c596b75 --- /dev/null +++ b/dreamcast2/holly/region_array.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include + +namespace holly { + namespace region_array { + struct region_array_entry { + uint32_t tile; + struct { + uint32_t opaque; + uint32_t opaque_modifier_volume; + uint32_t translucent; + uint32_t translucent_modifier_volume; + uint32_t punch_through; + } list_pointer; + }; + + struct list_block_size { + uint32_t opaque; + uint32_t opaque_modifier_volume; + uint32_t translucent; + uint32_t translucent_modifier_volume; + uint32_t punch_through; + + uint32_t total() const + { + return opaque + + opaque_modifier_volume + + translucent + + translucent_modifier_volume + + punch_through; + } + }; + + void transfer_region_array(const int tile_width, + const int tile_height, + const list_block_size& list_block_size, + const uint32_t region_array_start, + const uint32_t object_list_start); + } +} diff --git a/dreamcast2/holly/region_array_bits.hpp b/dreamcast2/holly/region_array_bits.hpp new file mode 100644 index 0000000..0769699 --- /dev/null +++ b/dreamcast2/holly/region_array_bits.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace holly { + namespace region_array { + namespace tile { + constexpr uint32_t last_region = 1 << 31; + constexpr uint32_t z_clear = 1 << 30; + constexpr uint32_t pre_sort = 1 << 29; + constexpr uint32_t flush_accumulate = 1 << 28; + constexpr uint32_t y_position(uint32_t num) { return (num & 0x3f) << 8; } + constexpr uint32_t x_position(uint32_t num) { return (num & 0x3f) << 2; } + } + + namespace list_pointer { + constexpr uint32_t empty = 1 << 31; + constexpr uint32_t object_list(uint32_t num) { return (num & 0xfffffc) << 0; } + } + + } +} diff --git a/dreamcast2/memorymap.hpp b/dreamcast2/memorymap.hpp new file mode 100644 index 0000000..ed0845f --- /dev/null +++ b/dreamcast2/memorymap.hpp @@ -0,0 +1,15 @@ +#include + +extern volatile uint8_t system_boot_rom[0x200000] __asm("system_boot_rom"); +extern volatile uint8_t aica_wave_memory[0x200000] __asm("aica_wave_memory"); +extern volatile uint8_t texture_memory64[0x800000] __asm("texture_memory64"); +extern volatile uint8_t texture_memory32[0x800000] __asm("texture_memory32"); +extern volatile uint8_t system_memory[0x1000000] __asm("system_memory"); +extern volatile uint8_t ta_fifo_polygon_converter[0x800000] __asm("ta_fifo_polygon_converter"); +extern volatile uint8_t ta_fifo_yuv_converter[0x800000] __asm("ta_fifo_yuv_converter"); +extern volatile uint8_t ta_fifo_texture_memory[0x800000] __asm("ta_fifo_texture_memory"); +extern volatile uint8_t ta_fifo_polygon_converter_mirror[0x800000] __asm("ta_fifo_polygon_converter_mirror"); +extern volatile uint8_t ta_fifo_yuv_converter_mirror[0x800000] __asm("ta_fifo_yuv_converter_mirror"); +extern volatile uint8_t ta_fifo_texture_memory_mirror[0x800000] __asm("ta_fifo_texture_memory_mirror"); +extern volatile uint8_t store_queue[0x4000000] __asm("store_queue"); +extern volatile uint8_t sh7091_oc_d[0x1000] __asm("sh7091_oc_d"); diff --git a/dreamcast2/reg.hpp b/dreamcast2/reg.hpp new file mode 100644 index 0000000..d24bbb1 --- /dev/null +++ b/dreamcast2/reg.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +typedef volatile uint8_t reg8; +typedef volatile uint16_t reg16; +typedef volatile uint32_t reg32; + +static_assert((sizeof (reg8)) == 1); +static_assert((sizeof (reg16)) == 2); +static_assert((sizeof (reg32)) == 4); diff --git a/dreamcast2/regs/block_regs.py b/dreamcast2/regs/block_regs.py new file mode 100644 index 0000000..a189e20 --- /dev/null +++ b/dreamcast2/regs/block_regs.py @@ -0,0 +1,100 @@ +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 headers(): + yield "#pragma once" + yield "" + yield '#include "reg.hpp"' + yield "" diff --git a/dreamcast2/regs/csv_input.py b/dreamcast2/regs/csv_input.py new file mode 100644 index 0000000..e694b84 --- /dev/null +++ b/dreamcast2/regs/csv_input.py @@ -0,0 +1,27 @@ +import csv + +def as_dict(header, row0): + row = [s.strip() for s in row0] + return dict(zip(header, row)) + +def read_input(filename): + with open(filename) as f: + reader = csv.reader(f, delimiter=",", quotechar='"') + header, *rows = reader + + rows = [ + as_dict(header, row) + for row in rows + if "".join(map(str, row)).strip() + ] + + return rows + +def read_input_headerless(filename): + with open(filename) as f: + reader = csv.reader(f, delimiter=",", quotechar='"') + rows = [ + [s.strip() for s in row] + for row in reader + ] + return rows diff --git a/dreamcast2/regs/generate.py b/dreamcast2/regs/generate.py new file mode 100644 index 0000000..c959cb9 --- /dev/null +++ b/dreamcast2/regs/generate.py @@ -0,0 +1,43 @@ +import io + +def should_autonewline(line): + return ( + "static_assert" not in line + and "extern" not in line + and (len(line.split()) < 2 or line.split()[1] != '=') # hacky; meh + ) + +def _render(out, lines): + indent = " " + level = 0 + #namespace = 0 + for l in lines: + if l and (l[0] == "}" or l[0] == ")"): + level -= 2 + #if level < 0: + #assert namespace >= 0 + #namespace -= 1 + #level = 0 + assert level >= 0 + + if len(l) == 0: + out.write("\n") + else: + out.write(indent * level + l + "\n") + + if l and (l[-1] == "{" or l[-1] == "("): + #if l.startswith("namespace"): + # namespace += 1 + #else: + level += 2 + + if level == 0 and l and l[-1] == ";": + if should_autonewline(l): + out.write("\n") + return out + +def renderer(): + out = io.StringIO() + def render(lines): + return _render(out, lines) + return render, out diff --git a/dreamcast2/regs/holly.py b/dreamcast2/regs/holly.py new file mode 100644 index 0000000..35ffcae --- /dev/null +++ b/dreamcast2/regs/holly.py @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..353e47e --- /dev/null +++ b/dreamcast2/regs/holly/holly.csv @@ -0,0 +1,87 @@ +"block","address","size","name","r/w","description" +"holly","0000","4","ID","R","Device ID" +"holly","0004","4","REVISION","R","Revision Number" +"holly","0008","4","SOFTRESET","RW","CORE & TA software reset" +,,,,, +"holly","0014","4","STARTRENDER","RW","Drawing start" +"holly","0018","4","TEST_SELECT","RW","Test (writing this register is prohibited)" +,,,,, +"holly","0020","4","PARAM_BASE","RW","Base address for ISP parameters" +,,,,, +"holly","002c","4","REGION_BASE","RW","Base address for Region Array" +"holly","0030","4","SPAN_SORT_CFG","RW","Span Sorter control" +,,,,, +"holly","0040","4","VO_BORDER_COL","RW","Border area color" +"holly","0044","4","FB_R_CTRL","RW","Frame buffer read control" +"holly","0048","4","FB_W_CTRL","RW","Frame buffer write control" +"holly","004c","4","FB_W_LINESTRIDE","RW","Frame buffer line stride" +"holly","0050","4","FB_R_SOF1","RW","Read start address for field - 1/strip - 1" +"holly","0054","4","FB_R_SOF2","RW","Read start address for field - 2/strip - 2" +,,,,, +"holly","005c","4","FB_R_SIZE","RW","Frame buffer XY size" +"holly","0060","4","FB_W_SOF1","RW","Write start address for field - 1/strip - 1" +"holly","0064","4","FB_W_SOF2","RW","Write start address for field - 2/strip - 2" +"holly","0068","4","FB_X_CLIP","RW","Pixel clip X coordinate" +"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","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","008c","4","ISP_BACKGND_T","RW","Background surface tag" +,,,,, +"holly","0098","4","ISP_FEED_CFG","RW","Translucent polygon sort mode" +,,,,, +"holly","00a0","4","SDRAM_REFRESH","RW","Texture memory refresh counter" +"holly","00a4","4","SDRAM_ARB_CFG","RW","Texture memory arbiter control" +"holly","00a8","4","SDRAM_CFG","RW","Texture memory control" +,,,,, +"holly","00b0","4","FOG_COL_RAM","RW","Color for Look Up table Fog" +"holly","00b4","4","FOG_COL_VERT","RW","Color for vertex Fog" +"holly","00b8","4","FOG_DENSITY","RW","Fog scale value" +"holly","00bc","4","FOG_CLAMP_MAX","RW","Color clamping maximum value" +"holly","00c0","4","FOG_CLAMP_MIN","RW","Color clamping minimum value" +"holly","00c4","4","SPG_TRIGGER_POS","RW","External trigger signal HV counter value" +"holly","00c8","4","SPG_HBLANK_INT","RW","H-blank interrupt control" +"holly","00cc","4","SPG_VBLANK_INT","RW","V-blank interrupt control" +"holly","00d0","4","SPG_CONTROL","RW","Sync pulse generator control" +"holly","00d4","4","SPG_HBLANK","RW","H-blank control" +"holly","00d8","4","SPG_LOAD","RW","HV counter load value" +"holly","00dc","4","SPG_VBLANK","RW","V-blank control" +"holly","00e0","4","SPG_WIDTH","RW","Sync width control" +"holly","00e4","4","TEXT_CONTROL","RW","Texturing control" +"holly","00e8","4","VO_CONTROL","RW","Video output control" +"holly","00ec","4","VO_STARTX","RW","Video output start X position" +"holly","00f0","4","VO_STARTY","RW","Video output start Y position" +"holly","00f4","4","SCALER_CTL","RW","X & Y scaler control" +,,,,, +"holly","0108","4","PAL_RAM_CTRL","RW","Palette RAM control" +"holly","010c","4","SPG_STATUS","R","Sync pulse generator status" +"holly","0110","4","FB_BURSTCTRL","RW","Frame buffer burst control" +"holly","0114","4","FB_C_SOF","R","Current frame buffer start address" +"holly","0118","4","Y_COEFF","RW","Y scaling coefficent" +"holly","011c","4","PT_ALPHA_REF","RW","Alpha value for Punch Through polygon comparison" +,,,,, +"holly","0124","4","TA_OL_BASE","RW","Object List write start address" +"holly","0128","4","TA_ISP_BASE","RW","ISP/TSP Parameter write start address" +"holly","012c","4","TA_OL_LIMIT","RW","Object List write limit address" +"holly","0130","4","TA_ISP_LIMIT","RW","ISP/TSP Parameter limit address" +"holly","0134","4","TA_NEXT_OPB","R","Start address for the Object Pointer Block" +"holly","0138","4","TA_ITP_CURRENT","R","Starting address where the next ISP/TSP Parameters are stored" +"holly","013c","4","TA_GLOB_TILE_CLIP","RW","Global Tile Clip control" +"holly","0140","4","TA_ALLOC_CTRL","RW","Object list control" +"holly","0144","4","TA_LIST_INIT","RW","TA initialization" +"holly","0148","4","TA_YUV_TEX_BASE","RW","YUV422 texture write start address" +"holly","014c","4","TA_YUV_TEX_CTRL","RW","YUV converter control" +"holly","0150","4","TA_YUV_TEX_CNT","R","YUV converter macro block counter value" +,,,,, +"holly","0160","4","TA_LIST_CONT","RW","TA continuation processing" +"holly","0164","4","TA_NEXT_OPB_INIT","RW","Additional OPB starting address" +,,,,, +"holly","0200","512","FOG_TABLE","RW","Look-up table fog data" +,,,,, +"holly","0600","2400","TA_OL_POINTERS","R","TA Object List Pointer data" +,,,,, +"holly","1000","4096","PALETTE_RAM","RW","Palette RAM" diff --git a/dreamcast2/regs/holly/holly.ods b/dreamcast2/regs/holly/holly.ods new file mode 100644 index 0000000000000000000000000000000000000000..5ffe8edefc81fa1dc958637ac8db71b8716ae700 GIT binary patch literal 23503 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

JZCdEC9*ELMFMO(`mYa6b@@cl~f*DQL%rq9uq! z-CjdQ=|cmO2!cY`emSCRAYysZ=tfH7FVUn)+&dtyso_*1^a5z>xN6CLi9_$hd%3A8 z3T*Tt%4n#e+k?JDi2?(@r2>gelxYmSpDR}*bT$?_s8IzdDJlh>g)m&`MZXpYf8y4a zV0VKUiv}%Z6ufZFh{|))oD--G@1Hl`})emwz}MzK3J?%Z)6^i*ht#w@Nhn zJ-e{KQ>iY{!`o-f{Ebepm-;aOy9OGQS+PKL&aigB}GI_Wq&7Z><{YCs+kmrBr+2Jb#_tXFE z%Nk<4j1=3Mmi%2#&PmIQlK4tPQwRJpxsFuyu*)F!GIl3096y#@S zeY`nvHYKyho$UVvi8}Z;k$o#R^38^{XKr7q&L;sX{VhW0FXtyma+Yu2K@c@X!OJM< zc@PhZ(=@%+$ov#@UHf77lMqnVoDDR$P_UjhgOXFiI^9r$$&}wro}wW!PJBMq@sVTY zLiL+o25$@s^;%(py~|E=$tooiO3yK-64q}L(-VOJv;^E_fle3?v=L5d`)9?>1hjdNmRxkvydAm(bn@kZ5Y}E-tO=DId7CtFgUom2`{n~(zqaK zg-=I<23GY-RSI&%JlPB=EuIOIB6s!!$@2P(zOo`|NuBlvsm8@|1-K|gvCL@B&m4NVZ2zYNF61wR5E?9q%cOByK+5FcN4g72brrV#DXEuay4kgVvdv z9H&21V^wd3^-v9l1e*k#_ukjyokMHLy5_0@gn#R$IX&;Le?OG{I^q%_`nnD~#b|r< z#CyYkSANWR)y-V9`k76+FR+SPx1c6RvUT?68L0(W_uNn)U6VcObl}QldfL*a({P@p z=I$w%kOlLs*8tQJ>GBy0&_;kcIq2+OD zvF>n})Yw^;Qp*6UP>3Y$Z}!3;?fwkR>!$_l;{?AGg^QJV%Hf~a*CD$)mwyp2rSH;ZNFSTX zG0nd>k$+#NNLgCd)8mAI_~-rSv|ZK0)z-+)(9*`4)#cw+76&`?2t@@+6hwl5xEYGH zl$bIE#Haj^cLM(7;1D9<8|Tc&mzkoRsyHMhBoY!5Ha0dPAt5CtB_ksv2gk?Ju7Ieh zsI084ii(Pkj*hXhv5k$5v$M08mlqHSjEag%Oiawo%q%P{tf;7HXlUr@=;-h7|Jc>% z=H^ycS9f=JPfkv5Zf@S*-ah(ye}AX6rvX7gkU>a`39EXnoau!b?UrMTm)>tsKfL#J za^#t9o@NZx^T=$Sbx50Nh4druJD9;Q?t9}FRD7c>8f$=;7iaY&j@o{kLqqk=cNt{z zYu_a+8#il zfr_)QUYGWi4*#s(oc!2n(zxVfniL*E2J9dP6BrF~({H&m(j;+FnbW*RPH+z>pd>nm zL3e+G*P^;X{xUvLfQqM<6&FlPC4&;>J}_qEgcL777cSQK1Xv_@2}Lsf)D|+rshb*? z<4tuZJqZQrue=EoC70gu{`DG)iN0FOH)`dfTsezMa)KQUnAH2y1eRgxT$f^c-~+D^ z6DD{WK!&3&K)+5cVUgCXyHf>QNd`v;ejnHdL#~Bo$}zL%i`Sl;NwI-eFT3G_(Oa<< zEFfl5XZFQ5!B16b`EiQr`I3bw~6^Oo&pd0w$+c}{0-a9ew)Y`f3-Vnd~Ih9WX^u&2a)1 zXn``7`4Jsk0R#?Ywn(38zdgIujY2P;!nNMnBz*d|O({+Y8H^WF&g_(fqj_yh$N^TK znTV$N8%!#fC(jRl$0uP30QFTBYhlCXnaUcm)e+}ou3&5H(*}``c^@=c;{t4Ga zt=p!V&u^g&S*AeE!7xUH&B0lbmtwk}%)%wiKoJqdlM+)DoQ4A}AX(@+gq`LtO-IMr za&8G{sJt+N=)p@yC)h~v>R!m#SOjx^_PnGzcIoF!7*@I2aTC=xBs+N2mLfW!Z^N z8lY+GY%`L!KtoKU!|%R=wu4p!sv`6baycgMv*Dkd9OnIW1@56Gy5%!>RFhK4%1mQnXSuZx}oZ#a~@&3rqFJC`FES()1m&Refk@~!zXZ>e8@z- zOpo6>G~-0M1k{Skjw9mrX{Zz2xMdLo<5ffA3L3`MC-SV`DTzBlbeZ6Fo}tlaYz9ns z`t;V%$kdkT_)R|*$91#*WRK>#CVSYZ)5Mox9 z7oC~}LpVuv;0PlK8j9|0e#<>tfN2+2-Jx7m4?Ee#vX$43;rRUL5n}m|YBM=FXA_!S zdrw^As-cUh*?Hyj17!=2N3U%0RI3V)IAJ8CEHVKsRBul7q}4on#@RU*JbRATCRBbj zbfEL_LT)hn68cMkMw2^~Q?6Dzib!ilqC1WLydmt3U>AsK?Os?Qga-v`5iH5Y3Wr1J zo9G9x7n+?N6K8SQNSw#Gqu)w40POW1%2cOu0|@f`7&xQqI~L|42+~qV)b}d=&5-|- z`&-{a8rbRBefc1ne_CIAHrH14NWo$PssesoDHMUl zR7VXZOy~36lfS|gnr-BmpC947l0n|A9&?WFGvn2f(*pPa3yAXT%HflRc!c{}XClu& zRvdXRSx%^j_+AswE9T)FS|KgoE+qN68^vj{LAf>WQL1}E;zMMu0!T{+RR5%;0j9DtvN)Ul#^-(?OR59%T!a96d#6Gnv9 z1gzL{2Mdcv(^pqG@1=$Zpw(B`UP=CfRlyRS5+0{ppQ#GfOeB7K!ZQd)d#hBV>8*hG2R5Hs z8$LwwX;-I*k@Y=cfw-jjoy&M>%Vp$616yr&@yQsLpfSU*!MJyM?~cZoBtEgo{gY;a zapc~Aa^#?3jC1rurmgV-mE*YV9$i1cBY2ewYQN8jlRG)*Odb4{y~`0uSrknPdsRlGs(Sd$8QO($7D9${%o- zWqHcS(Sf;8yypqH{Lz3X_311)zrq7WM8gDpMF{&n`d~p~6;WRycK;M2XW<&KiR4iE z4cZsBAC4q}4IxI%gD*)*LP)w*EWD%0Hys58I8#Q}Z}{SIOqOcFP<$DN2wa4(3`>|Y z&B66#8Clg<^^JNzo5c(9kXzbG8^&)w(*i8C<-0c*;CCAII6a}lUUbQpp3WfPiXO48 zEg*03NJ`3?KzYB`kn}QEixIAp4*01q{z@*SGe1=2qsT%AaIC6Aa76P$5 z(YNftVT!RjBBHtZX3HI054rf?QHTsF%EZ!FT7;vt2h%CGyKk3LIUJF>+=8Zu_kCOJ zX2uoY9bYZ$pAIp+*nx{R$od1u)&~*VOFS^Jtj(dGsM|Eu(!*ukkduP;r_Xk2?d^e%?g1zc{roc%k`>%)|JgF-PbNy6LIjmTOM(xI zenwg#yaAkVD1Mfer~nYIYIRH!3o!Hm5UDW-kB5LVjecG#lNaP=z@iE27^?Mhp4~ zQloIhD<83A9u5y*f{KZz4{HgTI5MnSB!+urCA1~xM%0i>cT-F`^IEd(6a_i2LjHtT zuMv!L5M=WJf+1X;VMY9pq&R{1C>jc^rJ!fs@u~N)U6VzTBR09&|K-dCZTbj zA0+e;CaUcToE#rXRrM<4yV2W}KUvOA{l5JP>fmiINdNJ)Erc4f8#CW~UffN|9mJs&W%}p0j7>@-Ug%YO9&w zn&G(K+V&TVWWx|w84VRG1nqvIDePpV5lw=ZFIwkB*F20KzN;P_^O5^WWmBpp)bD$_ z({OhBeRVnk?t-77lNyag&oJYAOaVQY$6W06H_2G{Q|XMuV(M7wV4sfh-*_vVC4*zS zs)n}}DEaCX{Zn$@D^qWrBFey2W`fQLeF|iwJ{(LH~fc_ zfCwi%6H%d!HsD)$`hp2tbMdTf6^0N29$NJN>32#OHI$r~jiJ6~U#owV*RbI>X$vIn z(-ijLBY!dzksJu#%usx3xfcb;tk}qdotmVIaasQ64$>;zAoXEx?^lWg;aGh>q2!DM zQ(5%wgt#IP%0c~zL#-uS@*%+^KcG+x($cSXr2-@B_EAIt4yRgx0;%Fu5(&hskKU=c zJo=M4J!DBb#~V<-qSx5a3tiK4dPJe{DN|S;U{OGemYbm9F9<4mow457=i9~*c0#fx&C=K*rnYUGO*qBkq3QS*#zR(u{j(9LLMo`unk*# zOi^~00TNU7RX?=T1PQKm6{xAQC5^|`sOI)yu9UZN4W76o&73~NqFrxsH3R3)R0=KZ z^1t|gAL`#zV4EmByX+>k0Jvq+)-LWArQEF7L$=I#j@PYNf=63}=U>Xv+F}Zhb!j4L zUN)p)r{pK23p{0~wlTBGnnPl=!vNY1c|*f)+c6KncTb~S+A4>jQ|BcmoOBr2=oNVGf3_a@5C`k3e7Te?vHeD>6T~ zks=`-ZX%Vj*cvh&(Ck1WE>#-s} z^ZkqSd_Vz-f8l}uJB0oparEEO^IviFe?q7yv&hBF)(0h;xllVe)}g$KrORlr*CJ6B zHPWs&vIWEz;O7TVVm+hFVg$)q{q=Dy;&E7{Z`g1CI<;OCMJry=HIkOu>1?wa%`P>E zDSkb+|1pKu=k0TQ4~lStNV>&HbYe3uz`6@447+_RqN(PDH*?cLr+gN8t>rSzaJ=6eFcsT17sYV@hjwm;)8Ez<{# z{8v?1Vy5wwcH?PQi4)6s>oGc{~6MID{XjmO+LRCb(p6*Uptq zYAW}MyzYScfM%mcUTOf#dhW{ibN-1H*u!GN2^%u`PIJ4s1mvu4TeutSXYn{Y7V#q> z|MOFzbs>tpx^*4YnsOZ+Wi!_S4VEbI_tx=TljkyB27()sti}N2(?h!z0l?kUd-?SS z7I}om<`Z9TupKE(09ycj6}->ZnUo<_75FcBox0l1>|BYnCw5w`(Bg~4S?@h0ce=g} zom=)#E)S!kfXR7W!Omn<==}1L;N(d$Xv5R|-bAhnl!$M=-R960BAerFrVfycQG^GOB|nPBNpKO8bD)%54K{ z!TN;?J3hJv7C6gT^?X&J=Uc{Ktn*v1&dF-5;zOix&t@9JACULeQHj&MZ1|)^cJ+V9 z2>-#i{|yiRg%LiAkNAo)yWa%gr3Soza!QtOC|6`UjQU!v`SW|Xsm_~A>mS_Tw_F~%bmat{2`1J; z9gd^sxQQu0iw+z9hk9jw`^08u_pIm4f73;qQG$KqxR`k`<9KK7TdZpU9G0D8PU^0y z1c|P%rWDg8cHGHEC^BUO53hzII(33;)r@AF)GCMRnxD$nYi^5Mx;tTOid=2!&XzQ0 zw-ACMHHwHZ|MHnTD^TLMhD=R)$a`3`doVYj7zN8HTM*;ak=&P!C%5bmJtv^(=>mC- zycjpiMiS;ZJrvSEAI+Kw39Lj`idLSi2$PwNG}a5IZ)+EiqH?REuYL(>N6O-lyv&2+ zKo-cnU-K{!IhrK^%qy3o3S)D5aKg(u54ib{nDZ>B7$OCix|9-QK(g{2+$^D?h$8sQ z*5$BS|1qCmcHZ?x$d|PS)9@*%UXlJK=)|!0JrSUgeBiRc4UeOB6)&ToCb6)#g_l-K zy}15?aUxAl;#1*YLfYO9i{@(C*2lqU4X%A#_7xH!kqst@U$i3&N!luI_7zaxQtykv zK5_lhWB9$~oIbd^8nl~@F(@{}smA4@9)M^(B^pB-?UhA0pbw1^v@sOp3zE+k?=P>He*6UO9oVx{Bzvb@Mk-sDJs}^07 zhuzgoB9Xc9X(ojW-ud0v24NPF&dc)u$w(P|WTa->PDdHLVDekOcpPGS+GKq7FYlv# zxk&OKIe(1+c|Qf(;dhQUjL#KX)Q>nZ{W=^M{lkpi#6Ss9lZXO&XT35T0h+L;Ofzt* z0b+O@SboOUTc<}kf4l0plOQd-sWX|gG$DHbejaplHx@gk(LYaXR%w$hfO&7L5ycZ z9e#`kIS>l!jld8PM|JC^h9-RM(7Dj!Dv3ZH8O_qfcypNqSD3vY9l|j_kB3*mEH{D_i-`7-a(HncJXCnis{6;~p%%Z*2*S%T4k3*&KWQNmZ+d1>XJ7})_>oG`dOV=o{aj3w)UomqP zQp7vMekSTAfyRi1B4dq&cp^(G{Vld7noz&z$%yhoa6_l8reB|xnZ*`Ci;9#cz2qWC z#Bw)2)_o$v#>$jY2lm&Y5Gj?~fP|KifaVR1Y#wqS6nEHd0i7iK14Q&mtxnf1BDGD{ zZvUPn>pvjjUH!|N_`Gj{pdRW^3EZuG+00Je&7pQPZ*wZ@bh`!B5|xijRg7;Uefr9owE?3g+fn=8R@?_=fau z9(J#f+Ac>KPA3OcC)}ZSEa+8EThdJcS;v8ZPYRee^1mcz_C#@hc`TTsm}pzHSmD7q z{vj@L6(ylfkgrG-%UZmtr^Fhz+ia4?1m)U)XZ!3}-Zy9od$Gz4?(*Kh2|?Z%`dR0$ z{tG$#n6C+s||2Jm%@2LN; z(EmU9T9W*R1Z87=reQ2M#MPj4*9|lUz2k!+auHrI%D#jlpaD#UzG^3FWLVX;r?l^e z89mjT<1F+{90u8!wmE-U3y&cX$V~C(ovh;Y5MDcNh1of^fyrYb636O~m_2qT=#(T} z)}fI5xBwu{9ovLqL&_}t1^+^dSFQ@Bsbh4PcVeiTGh2)3uR}!&WxpedO9B<~uLQB- zZ&{%tW9<&u@<|n%iSt|ZAAsl27MBAYzN{PBD$5a8E5J+lM-X<7&KtSb;xuO#4cxbYp9EvO& z&P|Q&{N#2D0uu*8lnRXFllM9B+vv*4dUcQ*ss3aZ)D!(+2^Vv)vjM z>_0iXl0zZ6Kt9;hZN(n2K#AzZ*+=93R`^Yr!ELPqfU3ZFX*0DckW)zXT@F1jVcXi- z8+m}<2)@FjjZtDoPD@K2e?rrz1QxA=8)sX^H$Owx&9H8MIg|Z+NFu$of7~zvYbsRv zF@KIbniF8TJGgtcWgAIE3i=yk3^og)xJoCXn|0xFb}6X899Q1OErzWgwV57hB7)X0 ziYdlY#_dVOi#Ue}Kr)A*zZ9H;^Y=;Gz1$D_B$q%VHXG&Bi6rs&X8i@EdHw-{2Xz)t zZBR&Z#|AODqiXFQ&lRyLq-bzK>`Iu!-j}q$cdZ_fb74d+`)aiMt?7paBqoEAeoJqs z4dXc&h%Jscz~SU`dGz@0-y{=sYT#m6Q$5g0(LC=Ku9H?08~F6}2!?cB3#!^46?~*O zobJ`$J4e9$ceb`tsTb$_AK1RDt~M7qt%Kj`ueOmAdhr>)i!zd?dT%7cx{7~Fc^qgS z3MfJ1X(2J#F(x6A7#d9CJ7-!Mdq{iu{7a~To0Ujhh0Q}VtU-Rhq!RJNwm(iCwhp{i zHZuhLTLy>MQt`xe$CKPe<;(L|j{$D5**==LZFbo5H28oa;F6MdneuO7OQnq0cC#i! zeANACJjW_#7Mkk*JcODV7IQxqkq=L$#|Jp@=rRYUdyxPF(arUJoL@$8xZtedIPmJT zEp-s`8f=crl{o2dAglBnGKtzhBJ3xZ#+(bTO0MC!swdQGe{^8=(z*IC>trSi_ zz}lM_380ybGw$HvAwEuL$H-_nxU%4gHP&UrQ~#g8*4g18&Z`pIG9H3<*LWZ|Ir=(w z{{+S*I?0MF)!`h7fbeA0& z9jimkJxG}x8*8wU;_&Ekj5rTt^YBPin09{?LZ@Fh)|I=%Lgz|{f8~RZbG!bEOLyLX@nC8smUKkFGKFRBE3=|4aenLO-&~@2*JG3h zI9I|%;3}{^+kdZ^(1B&`A_DSU;w8G2$~S!M%QHV}XhH@2kZLo0sV$Ti27?AF!W2es zVC8bc2vXl`=; z8MC#p8EoIFeIjUHjSGDK8*^$(VF&?%Rr1eWfIVGS_pz-Qnv2mJfQY>bnBwPU0>d7* z`s~&RpgMt1BSTB{JmeuPdo%1n`5a^;Dt!_Gua^bl=p+dvi{?hOe?kThkFQvI?k9Vn zMQ4`VHIO^EK>`EEwWu~0@H=gq>x(JoBwtoeXm1-%o5bFKC&qt>^Wf%&ieLRd$$l(60Q=*Hf8YM+|I9ga?ws@9&->23 z_kHejpXI}2)Kk15y(X&{Z_;g{G}#z@cXN~L$;ek2Qv5`P$=A&u7$FHZET#`vn&xbO zosoT;dL+8@!o6^MCq}|7bg=&e<54xoz>Y7h=@C4yfUYXpn{U4nT&T0w5YI9qGgn-H zRG3DiZF%nfyIE10-Km&?>QdOs-EM$}=D*qnGSoZdGj*N*0%*{>dbh= zc#@?f4{H(EqL^PlIng(+KGRcT;jk#y8l2{7w-I=BEfNO~+ zBW*6?d2RdFNP|kpF_!PFlIw~BxB6|DB$yz0zjKh^xOJhSr z4_w|GvH$f@PA%Yno7}T)Dt#qJW(N(ZXijU7lY>j+OHb5K+{A+R{(%dYf+GsjOoSlT zwyqLxGXs=#4=ULv)25i7VG4!0YU=^6&gI-NMwj znj<;UN=Ccg=%yyg->g~NoUD}QtrDnV#V-z@;klbU48F^0Wa;NlE|q5jFCj@UHM`LF z%f@`&IE<7%=Q0j{pkGGmOWKYV(A(T1=Q*lcAW~a#tCjd*BU}KFrrBdT=j#pX7Kzu~ znhIFf!rtjd7$LmvZjoC&Bo{cE1ebv_2G1Z2t6@_oqw|3mvbf79yp|4#2iQQ8aE6EN zIM-8HgXIsPWnwY>pC1cC^VJ$Buxi)}I@EGIcZ&_492YOoca+C)s}7BAHbsT-8|=Q4 zL$ET{IW!%>jm!A06pVYTs~5>#Lz`bslE9K{JnY0$|FAUmf6w| zOh0F>$eC(et+p;0drT>-X`Uy_21K)tUbjU7uDhas;75OkXreXNF~ zz?ba1XdrcbaR{}(o2Gnr4pgB0QoDU!$!O@)FXXWyZ0vQp~HZ+l?`j<%O7-~!l9CLk9iH)i17@I+fxb>$R7e@LNQXid4TuHw#x zp1Q|{{?L3S4I(})gT43dD;mqA(N*VB>r@@R7@^1DFF%FX#AzR7Bz)6jL{6^x68eDk zRnX(~wvDn3Y}nyk^%#dEOe7r!cbi^bf%Jmc7UhxS=26&%Cfuqit09q`87Wr8p2Nzw zmmoukyU`1{#6diBNpf$%K(00tT|mxk`@|ARZBNQoAmW|meH?OmtWtsOsLs>Nz!Osx zlmae-&AVhoMr&`gY4mE!RUNFt#V&x%D0YWDR$+>gWU^gZLSsXFfe{^EYpyRBnNzq( zBYIql9J|0$`A(xt#PyhO z|AhNZUFs(@c=yjB2_o06X6(FeRHwt|ygaw7zCWUUOCiiva9j!AZZsvho}oOoRp^&x8XDCru{ zNDbj8?@LLbEwD;lWQssxc=LdfTkefOT>ZO|U?;CLCMghcPSrV0`J>0Z717$SFER&} zx1uhDq&s}OoXL4&A)!=;fA|KexR;M_KWH3h^R+xSA<^UPICcE@`E7tndBD$@4oqY81hZ}P;n%FF`L<<@NKeO-kMm* zn_xa$;iqe94B|**eF7gRsTtrz6?GLKFK*mGsojEO2nxO*h1C>wAjXgT0*&jo=yW(% zpFxUfwJykridEY)pfL~EZi-AJrLo$HG6Q>+q^DAC`rQj8Ox^9m*@`H$8@xB}`=0R< zX#!;ExM~~qRrb~CtuE7(`!IRzi^!1Yudv| zJqhlEBT}lupeXuTS{(axl8=Pd6tBrePdJo?g7s0Nl@`7cY25TR;G zEVp;4ZhWPvvkNjtHbU@lM0JS9W&J4;aXh@`K3$XsG089@v9ISyLp#8ReUd=FD6~rG zFE~QV%9NoGcHn=$tL?l7BuQwTd^|okI^oKh6`yY5x2CaORWk9^+rjbHQVvk^)1rYF zSx5PNteJ^fsu|7VphFWA#|sgBak+4Zok&xeLnHW&448LsB?zL z9L9wCuF;2V|A`V8yy5u~F%iju>+mkp;ku>T&r6diL^xvXPJP22A}w)wFTFp#=7(jW zr7K>lx=~x>g>eGS9P*WnteD5jE06>Mt_u|5a*H=nQ978oKGv%MlymUytu$VEIP)k&uX0pPwMKt3H+rj`Matb5n^V!QQrI%F|J?+lFsqP| zyBa?~Yc09id`k~iMYqLX7ByIE8h#YHd6{BSsP@bkJ^*@=$0oQ2)8kSO2^)dqN1^umNKxQ-CG zhF}(!Ck2PUD?pNXIMEb-NXNH*IH;Y1w)gkTkcGWWU*R}tnLYjjxN9~5oWd}I!&VrX z_SJz*@NmwE!|y-FlMt2zOsr8j&{w`BkjLIXFkb>f63NR89HarDix!eZtLEoKRa?F* z69qme_oMs?p&|^mHJglZQ%~i~A91o>vxF3VeFR$XfCt2l<*jesP1rwRIJ=QvTnt4d%gMzc)~40aqO7b29C z^gWH7%G3>^`Ws7QtFj_GA90c_3cDE~;&9mTyf8oclc=xI|@tT=~=&^qUz4<@(ObCM45Co1a2u^CHZ&uTAr*%cmV2%ul=k2TVo zriCn=;zHZL_Xu^L4PEgD5lqakx9q2Xa?20LtTnhY1*Q;QBUj&qB*mX;N@{+nk~YPG zw(V&e+@(HAFJO?0;(nmK4}RhL=I5agJQ7%ZH_+A3N`C@51}-7PQo4m_6*v>RUUxx6 ze06f|482VxvZ#u-aS>b!N~R^`fD-$Q>MVqBE9DG2dAhYD;%@Qm$Q_`b|R zx^l?cc(jO*a`h%7XiZgxJFUymhdd?+*Bhd6`7Pi%Vf)azFEoQpNn7u%(LXDJt(-ri z0$(OpNMi9lfDr$8e@I6yb6Q`G8&w6;v7Ox@3U2>`m`Ut)^6Miu%Y;Nww{t}?ZH1Go z(;!88-Uc_lLSxDLvtv1+ZCAOX+zU87>Nt&D*M)SfFzub+l*9!HF(S?80fIAC@f3G( zX=oE*ql<&K?Tt4(FS2?B7f>w`+5(Jtt{^x``sb;zk#AOefSg{SsqT?=KPMW@rh5^* zX@avz(UWwVmxdufWOKVJYD2`eAsyW?I5c?mgN}w4^Kl6-j<;1p~vv5gW+!VXW zE3eU&Ma!BWV;GS?Mb?jibaY^pwMV;WYTyB}HtermWgWL>nPY~?%7n;F#Kz|}!E_H* z4U%(#`Rqxd2sh(-vvGC7`PGUOu@-$mau~a%ZG;-c%LhpkN#!E7`m7xhpK~9~$e58a z)N9t<>;tY}m`~N9Kb^w2+*tDtu^(lqs%1XQcI)Qnw(=WD(e*s56vt80OOLvmrx0Uv z!J0Y!C19leYX+*dQvCtZ4dqhro9zGKZ-ZdKsRw+6Reo+Q zm@AlBsf*S29FCG@r{PuUkfcTXKEMGX=PmxgjC7cZ@RXPmU!u`Ctci$psO*pKTL>(4 zHJg6q)?gL@4<@tBJ2t1MUsdpoJu#cn8UyW0WL|vA^EGo{*&`;tjtmm#?p` zZW9d=7L@Vw628W9+oCRsXm}-mdj=epKrN@!Z-IwG=PhyDc0JE2 z)ys8q^~3JBv6mwG_n>pTnQSCu@Am?_c!e54rr`m*+isO(gma=S0<3-rp;t7!iYzl) z#MhNO8S0+4ugcXE%xj1P%IhC=Ms9PV6%r3jd`Dw#pK_=fjwzujOgTFu>w$Mx75Hn&+W49D`^whfd>Fdl?nn)RBVa%$)MZQgK4^iz{^TirUcR7Zq zaB||R!}`2IOXxZ8i~+)vlKWsC4~?#-kw&4KefZxQCE38M3^mP9is~9^iT{_G6QqTB zl6vye>%+{Ns|u0zRafTB zp@M)uxZ^VHfFr^L33z&;o$X&=!nXkWzpIdrmCPkL6^Gu)L{!R(D@RB(W9d6TQZ^)HlMPuIZ z?im_Y1Cf}enXdO@4atPzIvo6zmhG`uB@=U5PYskq#!NGzb@x8q(_vS<*30~5e@^p8 zOnqm!G^10ftXx!3=p=JFLBbNBMKE*mnQ#2>;3A z`xEIG5$*33wcF+JJ7NqX{a1H@tiHb%@vol0lb~)>*zQOoSltMcOaCCW{b#S=$!xX> zQg;Ni=MTEne|G%6qJO)daz}buerLYOr!+Kh@Z$n19dnEAU;hDH?kS1@ literal 0 HcmV?d00001 diff --git a/dreamcast2/regs/holly/holly_bits.csv b/dreamcast2/regs/holly/holly_bits.csv new file mode 100644 index 0000000..e9ad7ce --- /dev/null +++ b/dreamcast2/regs/holly/holly_bits.csv @@ -0,0 +1,327 @@ +"register_name","enum_name","bits","bit_name","value","mask","description",,,,, +"ID",,"31-16","device_id",,,,,,,, +"ID",,"15-0","vendor_id",,,,,,,, +,,,,,,,,,,, +"REVISION",,"15-0","chip_revision",,,,,,,, +,,,,,,,,,,, +"SOFTRESET",,2,"sdram_if_soft_reset",1,,,,,,, +"SOFTRESET",,1,"pipeline_soft_reset",1,,,,,,, +"SOFTRESET",,0,"ta_soft_reset",1,,,,,,, +,,,,,,,,,,, +"STARTRENDER",,0,"start_render",1,,,,,,, +,,,,,,,,,,, +"TEST_SELECT",,"9-5","diagdb_data",,,,,,,, +"TEST_SELECT",,"4-0","diagda_data",,,,,,,, +,,,,,,,,,,, +"PARAM_BASE",,"23-0","base_address",,"0xf00000",,,,,, +,,,,,,,,,,, +"REGION_BASE",,"23-0","base_address",,"0xfffffc",,,,,, +,,,,,,,,,,, +"SPAN_SORT_CFG",,16,"cache_bypass",1,,,,,,, +"SPAN_SORT_CFG",,8,"offset_sort_enable",1,,,,,,, +"SPAN_SORT_CFG",,0,"span_sort_enable",1,,,,,,, +,,,,,,,,,,, +"VO_BORDER_COL",,24,"chroma",,"0b1",,,,,, +"VO_BORDER_COL",,"23-16","red",,"0xff",,,,,, +"VO_BORDER_COL",,"15-8","green",,"0xff",,,,,, +"VO_BORDER_COL",,"7-0","blue",,"0xff",,,,,, +,,,,,,,,,,, +"FB_R_CTRL","vclk_div",23,"pclk_vclk_2",0,,,,,,, +"FB_R_CTRL","vclk_div",23,"pclk_vclk_1",1,,,,,,, +"FB_R_CTRL",,22,"fb_strip_buf_en",1,,,,,,, +"FB_R_CTRL",,"21-16","fb_stripsize",,"0b111_110","In units of 16 lines, in multiples of 32 lines. 0x02 is 32 lines, 0x04 is 64 lines, 0x03 is an illegal value",,,,, +"FB_R_CTRL",,"15-8","fb_chroma_threshold",,"0xff",,,,,, +"FB_R_CTRL",,"6-4","fb_concat",,"0b11",,,,,, +"FB_R_CTRL","fb_depth","3-2","xrgb0555",0,,,,,,, +"FB_R_CTRL","fb_depth","3-2","rgb565",1,,,,,,, +"FB_R_CTRL","fb_depth","3-2","rgb888",2,,,,,,, +"FB_R_CTRL","fb_depth","3-2","xrgb0888",3,,,,,,, +"FB_R_CTRL",,1,"fb_line_double",1,,,,,,, +"FB_R_CTRL",,0,"fb_enable",1,,,,,,, +,,,,,,,,,,, +"FB_W_CTRL",,"23-16","fb_alpha_threshold",,"0xff",,,,,, +"FB_W_CTRL",,"15-8","fb_kval",,"0xff",,,,,, +"FB_W_CTRL",,3,"fb_dither",1,,,,,,, +"FB_W_CTRL","fb_packmode","2-0","krgb0555",0,,,,,,, +"FB_W_CTRL","fb_packmode","2-0","rgb565",1,,,,,,, +"FB_W_CTRL","fb_packmode","2-0","argb4444",2,,,,,,, +"FB_W_CTRL","fb_packmode","2-0","argb1555",3,,,,,,, +"FB_W_CTRL","fb_packmode","2-0","rgb888",4,,,,,,, +"FB_W_CTRL","fb_packmode","2-0","krgb0888",5,,,,,,, +"FB_W_CTRL","fb_packmode","2-0","argb8888",6,,,,,,, +,,,,,,,,,,, +"FB_W_LINESTRIDE",,"8-0","fb_line_stride",,"0xff","In 8-byte units",,,,, +,,,,,,,,,,, +"FB_R_SOF1",,"23-0","frame_buffer_read_address_frame_1",,"0xfffffc",,,,,, +,,,,,,,,,,, +"FB_R_SOF2",,"23-0","frame_buffer_read_address_frame_2",,"0xfffffc",,,,,, +,,,,,,,,,,, +"FB_R_SIZE",,"29-20","fb_modulus",,"0x3ff","In 4-byte units",,,,, +"FB_R_SIZE",,"19-10","fb_y_size",,"0x3ff",,,,,, +"FB_R_SIZE",,"9-0","fb_x_size",,"0x3ff",,,,,, +,,,,,,,,,,, +"FB_W_SOF1",,"24-0","frame_buffer_write_address_frame_1",,"0x1fffffc",,,,,, +,,,,,,,,,,, +"FB_W_SOF2",,"24-0","frame_buffer_write_address_frame_2",,"0x1fffffc",,,,,, +,,,,,,,,,,, +"FB_X_CLIP",,"26-16","fb_x_clip_max",,"0x7ff",,,,,, +"FB_X_CLIP",,"10-0","fb_x_clip_min",,"0x7ff",,,,,, +,,,,,,,,,,, +"FB_Y_CLIP",,"25-16","fb_y_clip_max",,"0x3ff",,,,,, +"FB_Y_CLIP",,"9-0","fb_y_clip_min",,"0x3ff",,,,,, +,,,,,,,,,,, +"FPU_SHAD_SCALE","simple_shadow_enable",8,"parameter_selection_volume_mode",0,,,,,,, +"FPU_SHAD_SCALE","simple_shadow_enable",8,"intensity_volume_mode",1,,,,,,, +"FPU_SHAD_SCALE",,"7-0","scale_factor_for_shadows",,"0xff",,,,,, +,,,,,,,,,,, +"FPU_CULL_VAL",,"30-0","culling_comparison_value",,"float_0_8_23",,,,,, +,,,,,,,,,,, +"FPU_PARAM_CFG","region_header_type",21,"type_1",0,,,,,,, +"FPU_PARAM_CFG","region_header_type",21,"type_2",1,,,,,,, +"FPU_PARAM_CFG",,"19-14","tsp_parameter_burst_threshold",,"0x3f",,,,,, +"FPU_PARAM_CFG",,"13-8","isp_parameter_burst_threshold",,"0x3f",,,,,, +"FPU_PARAM_CFG",,"7-4","pointer_burst_size",,"0xf",,,,,, +"FPU_PARAM_CFG",,"3-0","pointer_first_burst_size",,"0xf",,,,,, +,,,,,,,,,,, +"HALF_OFFSET","tsp_texel_sampling_position",2,"top_left",1,,,,,,, +"HALF_OFFSET","tsp_texel_sampling_position",2,"center",1,,,,,,, +"HALF_OFFSET","tsp_pixel_sampling_position",1,"top_left",1,,,,,,, +"HALF_OFFSET","tsp_pixel_sampling_position",1,"center",1,,,,,,, +"HALF_OFFSET","fpu_pixel_sampling_position",0,"top_left",1,,,,,,, +"HALF_OFFSET","fpu_pixel_sampling_position",0,"center",1,,,,,,, +,,,,,,,,,,, +"FPU_PERP_VAL",,"30-0","perpendicular_triangle_compare",,"float_0_8_23",,,,,, +,,,,,,,,,,, +"ISP_BACKGND_D",,"31-4","background_plane_depth",,"float_1_8_19",,,,,, +,,,,,,,,,,, +"ISP_BACKGND_T",,28,"cache_bypass",1,,,,,,, +"ISP_BACKGND_T",,27,"shadow",1,,,,,,, +"ISP_BACKGND_T",,"26-24","skip",,"0b111",,,,,, +"ISP_BACKGND_T",,"23-3","tag_address",,"0x1fffff","In 32-bit units",,,,, +"ISP_BACKGND_T",,"2-0","tag_offset",,"0b111",,,,,, +,,,,,,,,,,, +"ISP_FEED_CFG",,"23-14","cache_size_for_translucency",,"0x3ff","Must be between 0x020 and 0x200",,,,, +"ISP_FEED_CFG",,"13-4","punch_through_chunk_size",,"0x3ff","Must be between 0x020 and 0x200, must be larger than cache_size_for_translucency",,,,, +"ISP_FEED_CFG",,3,"discard_mode",1,,,,,,, +"ISP_FEED_CFG",,0,"pre_sort_mode",1,,,,,,, +,,,,,,,,,,, +"SDRAM_REFRESH",,"7-0","refresh_counter_value",,"0xff",,,,,, +,,,,,,,,,,, +"SDRAM_ARB_CFG","override_value","21-18","priority_only","0x0",,,,,,, +"SDRAM_ARB_CFG","override_value","21-18","rendered_data","0x1",,,,,,, +"SDRAM_ARB_CFG","override_value","21-18","texture_vq_index","0x2",,,,,,, +"SDRAM_ARB_CFG","override_value","21-18","texture_normal_data_and_vq_codebook","0x3",,,,,,, +"SDRAM_ARB_CFG","override_value","21-18","tile_accelerator_isp_tsp_data","0x4",,,,,,, +"SDRAM_ARB_CFG","override_value","21-18","tile_accelerator_pointers","0x5",,,,,,, +"SDRAM_ARB_CFG","override_value","21-18","sh4","0x6",,,,,,, +"SDRAM_ARB_CFG","override_value","21-18","tsp_parameters","0x7",,,,,,, +"SDRAM_ARB_CFG","override_value","21-18","tsp_region_data","0x8",,,,,,, +"SDRAM_ARB_CFG","override_value","21-18","isp_pointer_data","0x9",,,,,,, +"SDRAM_ARB_CFG","override_value","21-18","isp_parameters","0xa",,,,,,, +"SDRAM_ARB_CFG","override_value","21-18","crt_controller","0xb",,,,,,, +"SDRAM_ARB_CFG","arbiter_priority_control","17-16","priority_arbitration_only","0x0",,,,,,, +"SDRAM_ARB_CFG","arbiter_priority_control","17-16","override_value_field","0x1",,,,,,, +"SDRAM_ARB_CFG","arbiter_priority_control","17-16","round_robin_counter","0x2",,,,,,, +"SDRAM_ARB_CFG",,"15-8","arbiter_crt_page_break_latency_count_value",,"0xff",,,,,, +"SDRAM_ARB_CFG",,"7-0","arbiter_page_break_latency_count_value",,"0xff",,,,,, +,,,,,,,,,,, +"SDRAM_CFG",,"28-26","read_command_to_returned_data_delay",,"0b111",,,,,, +"SDRAM_CFG",,"25-23","cas_latency_value",,"0b111",,,,,, +"SDRAM_CFG",,"22-21","activate_to_activate_period",,"0b11",,,,,, +"SDRAM_CFG",,"20-18","read_to_write_period",,"0b111",,,,,, +"SDRAM_CFG",,"17-14","refresh_to_activate_period",,"0b1111",,,,,, +"SDRAM_CFG",,"11-10","pre_charge_to_activate_period",,"0b11",,,,,, +"SDRAM_CFG",,"9-6","activate_to_pre_charge_period",,"0b1111",,,,,, +"SDRAM_CFG",,"5-4","activate_to_read_write_command_period",,"0b11",,,,,, +"SDRAM_CFG",,"3-2","write_to_pre_charge_period",,"0b11",,,,,, +"SDRAM_CFG",,"1-0","read_to_pre_charge_period",,"0b11",,,,,, +,,,,,,,,,,, +"FOG_COL_RAM",,"23-16","red",,"0xff",,,,,, +"FOG_COL_RAM",,"15-8","green",,"0xff",,,,,, +"FOG_COL_RAM",,"7-0","blue",,"0xff",,,,,, +,,,,,,,,,,, +"FOG_COL_VERT",,"23-16","red",,"0xff",,,,,, +"FOG_COL_VERT",,"15-8","green",,"0xff",,,,,, +"FOG_COL_VERT",,"7-0","blue",,"0xff",,,,,, +,,,,,,,,,,, +"FOG_DENSITY",,"15-8","fog_scale_mantissa",,"0xff",,,,,, +"FOG_DENSITY",,"7-0","fog_scale_exponent",,"0xff",,,,,, +,,,,,,,,,,, +"FOG_CLAMP_MAX",,"31-24","alpha",,"0xff",,,,,, +"FOG_CLAMP_MAX",,"23-16","red",,"0xff",,,,,, +"FOG_CLAMP_MAX",,"15-8","green",,"0xff",,,,,, +"FOG_CLAMP_MAX",,"7-0","blue",,"0xff",,,,,, +,,,,,,,,,,, +"FOG_CLAMP_MIN",,"31-24","alpha",,"0xff",,,,,, +"FOG_CLAMP_MIN",,"23-16","red",,"0xff",,,,,, +"FOG_CLAMP_MIN",,"15-8","green",,"0xff",,,,,, +"FOG_CLAMP_MIN",,"7-0","blue",,"0xff",,,,,, +,,,,,,,,,,, +"SPG_TRIGGER_POS",,"25-16","trigger_v_count",,,,,,,, +"SPG_TRIGGER_POS",,"9-0","trigger_h_count",,,,,,,, +,,,,,,,,,,, +"SPG_HBLANK_INT",,"25-16","hblank_in_interrupt",,,,,,,, +"SPG_HBLANK_INT","hblank_int_mode","13-12","output_equal_line_comp_val","0x0",,,,,,, +"SPG_HBLANK_INT","hblank_int_mode","13-12","output_every_line_comp_val","0x1",,,,,,, +"SPG_HBLANK_INT","hblank_int_mode","13-12","output_every_line","0x2",,,,,,, +"SPG_HBLANK_INT",,"9-0","line_comp_val",,"0x3ff",,,,,, +,,,,,,,,,,, +"SPG_VBLANK_INT",,"25-16","vblank_out_interrupt_line_number",,"0x3ff",,,,,, +"SPG_VBLANK_INT",,"9-0","vblank_in_interrupt_line_number",,"0x3ff",,,,,, +,,,,,,,,,,, +"SPG_CONTROL","csync_on_h",9,"hsync",0,,,,,,, +"SPG_CONTROL","csync_on_h",9,"csync",1,,,,,,, +"SPG_CONTROL","sync_direction",8,"input",0,,,,,,, +"SPG_CONTROL","sync_direction",8,"output",1,,,,,,, +"SPG_CONTROL",,7,"pal",1,,,,,,, +"SPG_CONTROL",,6,"ntsc",1,,,,,,, +"SPG_CONTROL",,5,"force_field2",1,,,,,,, +"SPG_CONTROL",,4,"interlace",1,,,,,,, +"SPG_CONTROL",,3,"spg_lock",1,,,,,,, +"SPG_CONTROL","mcsync_pol",2,"active_low",0,,,,,,, +"SPG_CONTROL","mcsync_pol",2,"active_high",1,,,,,,, +"SPG_CONTROL","mvsync_pol",1,"active_low",0,,,,,,, +"SPG_CONTROL","mvsync_pol",1,"active_high",1,,,,,,, +"SPG_CONTROL","mhsync_pol",0,"active_low",0,,,,,,, +"SPG_CONTROL","mhsync_pol",0,"active_high",1,,,,,,, +,,,,,,,,,,, +"SPG_HBLANK",,"25-16","hbend",,"0x3ff",,,,,, +"SPG_HBLANK",,"9-0","hbstart",,"0x3ff",,,,,, +,,,,,,,,,,, +"SPG_LOAD",,"25-16","vcount",,"0x3ff",,,,,, +"SPG_LOAD",,"9-0","hcount",,"0x3ff",,,,,, +,,,,,,,,,,, +"SPG_VBLANK",,"25-16","vbend",,"0x3ff",,,,,, +"SPG_VBLANK",,"9-0","vbstart",,"0x3ff",,,,,, +,,,,,,,,,,, +"SPG_WIDTH",,"31-22","eqwidth",,"0x3ff",,,,,, +"SPG_WIDTH",,"21-12","bpwidth",,"0x3ff",,,,,, +"SPG_WIDTH",,"11-8","vswidth",,"0b1111",,,,,, +"SPG_WIDTH",,"6-0","hswidth",,"0x7f",,,,,, +,,,,,,,,,,, +"TEXT_CONTROL","code_book_endian",17,"little_endian",0,,,,,,, +"TEXT_CONTROL","code_book_endian",17,"big_endian",1,,,,,,, +"TEXT_CONTROL","index_endian",16,"little_endian",0,,,,,,, +"TEXT_CONTROL","index_endian",16,"big_endian",1,,,,,,, +"TEXT_CONTROL",,"12-8","bank_bit",,"0x1f",,,,,, +"TEXT_CONTROL",,"4-0","stride",,"0x1f",,,,,, +,,,,,,,,,,, +"VO_CONTROL",,21,"pclk_delay_reset",1,,,,,,, +"VO_CONTROL",,"20-16","pclk_delay",,"0b11111",,,,,, +"VO_CONTROL",,8,"pixel_double",1,,,,,,, +"VO_CONTROL","field_mode","7-4","use_field_flag_from_spg","0x0",,,,,,, +"VO_CONTROL","field_mode","7-4","use_inverse_of_field_flag_from_spg","0x1",,,,,,, +"VO_CONTROL","field_mode","7-4","field_1_fixed","0x2",,,,,,, +"VO_CONTROL","field_mode","7-4","field_2_fixed","0x3",,,,,,, +"VO_CONTROL","field_mode","7-4","field_1_when_the_active_edges_of_hsync_and_vsync_match","0x4",,,,,,, +"VO_CONTROL","field_mode","7-4","field_2_when_the_active_edges_of_hsync_and_vsync_match","0x5",,,,,,, +"VO_CONTROL","field_mode","7-4","field_1_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge","0x6",,,,,,, +"VO_CONTROL","field_mode","7-4","field_2_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge","0x7",,,,,,, +"VO_CONTROL","field_mode","7-4","inverted_at_the_active_edge_of_vsync","0x8",,,,,,, +"VO_CONTROL",,3,"blank_video",1,,,,,,, +"VO_CONTROL","blank_pol",2,"active_low",0,,,,,,, +"VO_CONTROL","blank_pol",2,"active_high",1,,,,,,, +"VO_CONTROL","vsync_pol",1,"active_low",0,,,,,,, +"VO_CONTROL","vsync_pol",1,"active_high",1,,,,,,, +"VO_CONTROL","hsync_pol",0,"active_low",0,,,,,,, +"VO_CONTROL","hsync_pol",0,"active_high",1,,,,,,, +,,,,,,,,,,, +"VO_STARTX",,"9-0","horizontal_start_position",,"0x3ff",,,,,, +,,,,,,,,,,, +"VO_STARTY",,"25-16","vertical_start_position_on_field_2",,"0x3ff",,,,,, +"VO_STARTY",,"9-0","vertical_start_position_on_field_1",,"0x3ff",,,,,, +,,,,,,,,,,, +"SCALER_CTL","field_select",18,"field_1",0,,,,,,, +"SCALER_CTL","field_select",18,"field_2",1,,,,,,, +"SCALER_CTL",,17,"interlace",1,,,,,,, +"SCALER_CTL",,16,"horizontal_scaling_enable",1,,,,,,, +"SCALER_CTL",,"15-0","vertical_scale_factor",,"0xffff",,,,,, +,,,,,,,,,,, +"PAL_RAM_CTRL","pixel_format","1-0","argb1555",0,,,,,,, +"PAL_RAM_CTRL","pixel_format","1-0","rgb565",1,,,,,,, +"PAL_RAM_CTRL","pixel_format","1-0","argb4444",2,,,,,,, +"PAL_RAM_CTRL","pixel_format","1-0","argb8888",3,,,,,,, +,,,,,,,,,,, +"SPG_STATUS",,13,"vsync",,,,,,,, +"SPG_STATUS",,12,"hsync",,,,,,,, +"SPG_STATUS",,11,"blank",,,,,,,, +"SPG_STATUS",,10,"fieldnum",,,,,,,, +"SPG_STATUS",,"9-0","scanline",,,,,,,, +,,,,,,,,,,, +"FB_BURSTCTRL",,"19-16","wr_burst",,"0b1111",,,,,, +"FB_BURSTCTRL",,"14-8","vid_lat",,"0x7f",,,,,, +"FB_BURSTCTRL",,"5-0","vid_burst",,"0x3f",,,,,," >" +,,,,,,,,,,, +"FB_C_SOF",,"23-0","frame_buffer_current_read_address",,,,,,,, +,,,,,,,,,,, +"Y_COEFF",,"15-8","coefficient_1",,"0xff",,,,,, +"Y_COEFF",,"7-0","coefficient_0_2",,"0xff",,,,,, +,,,,,,,,,,, +"PT_ALPHA_REF",,"7-0","alpha_reference_for_punch_through",,"0xff",,,,,, +,,,,,,,,,,, +"FOG_TABLE",,"15-0","fog_table_data",,"0xffff",,,,,, +,,,,,,,,,,, +"PALETTE_RAM",,"31-0","palette_data",,"0xffff_ffff",,,,,, +,,,,,,,,,,, +"TA_OL_BASE",,"23-0","base_address",,"0xffffe0","in 32-byte units",,,,, +,,,,,,,,,,, +"TA_ISP_BASE",,"23-0","base_address",,"0xfffffc","in 4-byte units",,,,, +,,,,,,,,,,, +"TA_OL_LIMIT",,"23-0","limit_address",,"0xffffe0","in 32-byte units",,,,, +,,,,,,,,,,, +"TA_ISP_LIMIT",,"23-0","limit_address",,"0xfffffc","in 4-byte units",,,,, +,,,,,,,,,,, +"TA_NEXT_OPB",,"23-0","address",,"0xffffe0","in 32-byte units",,,,, +,,,,,,,,,,, +"TA_ITP_CURRENT",,"23-0","address",,,,,,,, +,,,,,,,,,,, +"TA_GLOB_TILE_CLIP",,"19-16","tile_y_num",,"0xf",,,,,, +"TA_GLOB_TILE_CLIP",,"5-0","tile_x_num",,"0x1f",,,,,, +,,,,,,,,,,, +"TA_ALLOC_CTRL","opb_mode",20,"increasing_addresses",0,,,,,,, +"TA_ALLOC_CTRL","opb_mode",20,"decreasing_addresses",1,,,,,,, +"TA_ALLOC_CTRL","pt_opb","17-16","no_list",0,,,,,,, +"TA_ALLOC_CTRL","pt_opb","17-16","8x4byte",1,,,,,,, +"TA_ALLOC_CTRL","pt_opb","17-16","16x4byte",2,,,,,,, +"TA_ALLOC_CTRL","pt_opb","17-16","32x4byte",3,,,,,,, +"TA_ALLOC_CTRL","tm_opb","13-12","no_list",0,,,,,,, +"TA_ALLOC_CTRL","tm_opb","13-12","8x4byte",1,,,,,,, +"TA_ALLOC_CTRL","tm_opb","13-12","16x4byte",2,,,,,,, +"TA_ALLOC_CTRL","tm_opb","13-12","32x4byte",3,,,,,,, +"TA_ALLOC_CTRL","t_opb","9-8","no_list",0,,,,,,, +"TA_ALLOC_CTRL","t_opb","9-8","8x4byte",1,,,,,,, +"TA_ALLOC_CTRL","t_opb","9-8","16x4byte",2,,,,,,, +"TA_ALLOC_CTRL","t_opb","9-8","32x4byte",3,,,,,,, +"TA_ALLOC_CTRL","om_opb","5-4","no_list",0,,,,,,, +"TA_ALLOC_CTRL","om_opb","5-4","8x4byte",1,,,,,,, +"TA_ALLOC_CTRL","om_opb","5-4","16x4byte",2,,,,,,, +"TA_ALLOC_CTRL","om_opb","5-4","32x4byte",3,,,,,,, +"TA_ALLOC_CTRL","o_opb","1-0","no_list",0,,,,,,, +"TA_ALLOC_CTRL","o_opb","1-0","8x4byte",1,,,,,,, +"TA_ALLOC_CTRL","o_opb","1-0","16x4byte",2,,,,,,, +"TA_ALLOC_CTRL","o_opb","1-0","32x4byte",3,,,,,,, +,,,,,,,,,,, +"TA_LIST_INIT",,31,"list_init",1,,,,,,, +,,,,,,,,,,, +"TA_YUV_TEX_BASE",,"23-0","base_address",,"0xfffff8","in 8-byte units",,,,, +,,,,,,,,,,, +"TA_YUV_TEX_CTRL","yuv_form",24,"yuv420",0,,,,,,, +"TA_YUV_TEX_CTRL","yuv_form",24,"yuv422",1,,,,,,, +"TA_YUV_TEX_CTRL","yuv_tex",16,"one_texture",0,,,,,,, +"TA_YUV_TEX_CTRL","yuv_tex",16,"multiple_textures",1,,,,,,, +"TA_YUV_TEX_CTRL",,"13-8","yuv_v_size",,"0x3f",,,,,, +"TA_YUV_TEX_CTRL",,"5-0","yuv_u_size",,"0x3f",,,,,, +,,,,,,,,,,, +"TA_YUV_TEX_CNT",,"12-0","yuv_num",,,,,,,, +,,,,,,,,,,, +"TA_LIST_CONT",,31,"list_cont",1,,,,,,, +,,,,,,,,,,, +"TA_NEXT_OPB_INIT",,"23-0","address",,"0xffffe0","in 32-byte units",,,,, +,,,,,,,,,,, +"TA_OL_POINTERS",,31,"entry",,,,,,,, +"TA_OL_POINTERS",,30,"sprite",,,,,,,, +"TA_OL_POINTERS",,29,"triangle",,,,,,,, +"TA_OL_POINTERS",,"28-25","number_of_triangles_quads",,,,,,,, +"TA_OL_POINTERS",,24,"shadow",,,,,,,, +"TA_OL_POINTERS",,"23-2","pointer_address",,,,,,,, +"TA_OL_POINTERS",,"1-0","skip",,,,,,,, diff --git a/dreamcast2/regs/holly/holly_bits.ods b/dreamcast2/regs/holly/holly_bits.ods new file mode 100644 index 0000000000000000000000000000000000000000..4705d53b0336eaaa970e5fdbb2efeb6dfb1c3474 GIT binary patch literal 24403 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 literal 0 HcmV?d00001 diff --git a/dreamcast2/regs/holly_bits.py b/dreamcast2/regs/holly_bits.py new file mode 100644 index 0000000..890d3ae --- /dev/null +++ b/dreamcast2/regs/holly_bits.py @@ -0,0 +1,286 @@ +import sys +from collections import defaultdict +from pprint import pprint +from dataclasses import dataclass +from typing import Union + +from csv_input import read_input +from generate import renderer + +def aggregate_registers(d): + aggregated = defaultdict(list) + for row in d: + #assert row["register_name"] != "" + aggregated[row["register_name"]].append(row) + return dict(aggregated) + +def parse_bit_number(s): + assert '-' not in s, s + assert ',' not in s, s + return int(s, 10) + +def parse_bit_set(s, split_char, maxsplit): + #assert len(list(c for c in s if c == split_char)) == 1, s + split = list(map(parse_bit_number, s.split(split_char, maxsplit=maxsplit))) + for i in range(len(split) - 1): + left = split[i] + right = split[i+1] + assert left > right, (left, right) + return split + +def parse_bit_range(s): + if '-' in s: + left, right = parse_bit_set(s, '-', 1) + return set(range(right, left+1)) + elif ',' in s: + bits = parse_bit_set(s, ',', -1) + return set(bits) + else: + num = parse_bit_number(s) + return set([num]) + +def aggregate_enums(aggregated_rows): + non_enum = [] + enum_aggregated = defaultdict(list) + all_bits = set() + enum_bits = dict() + + def assert_unique_ordered(bits, row): + nonlocal all_bits + assert all(bit not in all_bits for bit in bits), (bits, row) + assert max(all_bits, default=32) > max(bits), (all_bits, bits) + all_bits |= bits + + for row in aggregated_rows: + bits = parse_bit_range(row["bits"]) + assert row["bit_name"] != "", row + if row["enum_name"] == "": + assert_unique_ordered(bits, row) + non_enum.append(row) + else: + if row["enum_name"] not in enum_bits: + assert_unique_ordered(bits, row) + non_enum.append(row["enum_name"]) + else: + assert enum_bits[row["enum_name"]] == bits, row + + enum_bits[row["enum_name"]] = bits + enum_aggregated[row["enum_name"]].append(row) + + return non_enum, dict(enum_aggregated) + +@dataclass +class enum: + name: str + defs: list[dict] + +@dataclass +class register: + block: Union[None, str] + name: str + defs: list[Union[dict, enum]] + +def aggregate_all_enums(aggregated): + out = [] + for register_name, rows in aggregated.items(): + non_enum, enum_aggregated = aggregate_enums(rows) + def resolve(row_or_string): + if type(row_or_string) == str: + return enum(row_or_string, + enum_aggregated[row_or_string]) + elif type(row_or_string) == dict: + return row_or_string + else: + assert False, (row_or_string, type(row_or_string)) + + defs = [resolve(aggregate) for aggregate in non_enum] + if 'block' in rows[0]: + blocks = set(row['block'] for row in rows) + assert len(blocks) == 1, blocks + block_name = next(iter(blocks)) + out.append( + register(block_name, register_name, defs)) + else: + out.append( + register(None, register_name, defs)) + return out + +''' + register(name='SCALER_CTL', + defs=[enum(name='field_select', + defs=[{'bit_name': 'field_1', + 'bits': '18', + 'description': '', + 'enum_name': 'field_select', + 'mask': '', + 'register_name': 'SCALER_CTL', + 'value': '0'}, + {...}]), + {'bit_name': 'interlace', + 'bits': '17', + 'description': '', + 'enum_name': '', + 'mask': '', + 'register_name': 'SCALER_CTL', + 'value': '1'}, + {...}, + ...]), +''' + +def mask_from_bits(bits): + mask = 0 + for b in bits: + mask |= 1 << b + mask >>= min(bits) + return mask + +def parse_value(value): + return eval(value) + +def escape(bit_name): + if bit_name[0] in {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}: + return '_' + bit_name + else: + return bit_name + +def render_read_only(bit_def): + assert bit_def["value"] == "" + assert bit_def["mask"] == "" + bits = parse_bit_range(bit_def["bits"]) + mask_value = mask_from_bits(bits) + yield ( + f"constexpr uint32_t {escape(bit_def['bit_name'])}(uint32_t reg) {{ " + f"return (reg >> {min(bits)}) & {hex(mask_value)};" + " }" + ) + +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)};" + " }" + ) + else: + assert mask.startswith("0x") or mask.startswith("0b") or mask[0] in set(range(0, 9+1)), mask + mask_value = eval(mask) + assert mask_value & mask_from_bits(bits) == mask_value, (mask_value, mask_from_bits(bits)) + + yield ( + f"constexpr uint32_t {escape(bit_def['bit_name'])}(uint32_t num) {{ " + f"return (num & {hex(mask_value)}) << {min(bits)};" + " }" + ) + +def render_value(bit_def): + assert bit_def["mask"] == "" + bits = parse_bit_range(bit_def["bits"]) + assert parse_value(bit_def["value"]) <= mask_from_bits(bits), (bit_def["value"], mask_from_bits(bits), bits) + bit_ix = min(bits) + yield f"constexpr uint32_t {escape(bit_def['bit_name'])} = {bit_def['value']} << {bit_ix};" + +def render_defs(bit_def): + if bit_def["value"] != "": + yield from render_value(bit_def) + elif bit_def["mask"] != "": + yield from render_mask(bit_def) + else: + yield from render_read_only(bit_def) + +def render_enum_mask(enum_def): + all_bits = set(bit_def["bits"] for bit_def in enum_def.defs) + assert len(all_bits) == 1 + assert all(bit_def["bit_name"] != "bit_mask" for bit_def in enum_def.defs), bit_def + _bits = next(iter(all_bits)) + bits = parse_bit_range(_bits) + mask_value = mask_from_bits(bits) + bit_ix = min(bits) + yield "" + yield f"constexpr uint32_t bit_mask = {hex(mask_value)} << {bit_ix};" + +def render_enum(enum_def): + yield f"namespace {enum_def.name.lower()} {{" + for bit_def in enum_def.defs: + yield from render_defs(bit_def) + yield from render_enum_mask(enum_def) + yield "}" + +def render_register(register): + if register.name != "": + yield f"namespace {register.name.lower()} {{" + + last = None + for ix, bit_def in enumerate(register.defs): + if type(bit_def) is enum: + if ix != 0: + yield "" + yield from render_enum(bit_def) + else: + if ix != 0 and type(last) is enum: + yield "" + yield from render_defs(bit_def) + last = bit_def + + if register.name != "": + yield "}" + yield "" + +def render_registers_inner(registers): + last_block = None + for register in registers: + if register.block != last_block: + assert register.block is not None + if last_block is not None: + yield '}' # end of previous namespace + yield "" + yield f'namespace {register.block.lower()} {{' + if register.block is None: + assert last_block is None + last_block = register.block + + yield from render_register(register) + + if last_block is not None: + yield '}' # end of block namespace + +def render_registers(registers, file_namespaces): + if file_namespaces: + yield f"namespace {file_namespaces[0]} {{" + yield from render_registers(registers, file_namespaces[1:]) + yield '}' # end of file namespace + else: + yield from render_registers_inner(registers) + +def header(): + yield "#pragma once" + yield "" + yield "#include " + yield "" + +if __name__ == "__main__": + d = read_input(sys.argv[1]) + file_namespaces = sys.argv[2:] + aggregated = aggregate_registers(d) + registers = aggregate_all_enums(aggregated) + render, out = renderer() + render(header()) + render(render_registers(registers, file_namespaces)) + sys.stdout.write(out.getvalue()) diff --git a/dreamcast2/regs/sh7091.py b/dreamcast2/regs/sh7091.py new file mode 100644 index 0000000..b93e545 --- /dev/null +++ b/dreamcast2/regs/sh7091.py @@ -0,0 +1,145 @@ +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/sh7091/sh7091.csv b/dreamcast2/regs/sh7091/sh7091.csv new file mode 100644 index 0000000..c5e7eae --- /dev/null +++ b/dreamcast2/regs/sh7091/sh7091.csv @@ -0,0 +1,126 @@ +"block","offset","address","size","name","r/w","description" +"CCN","00","0000",4,"PTEH","RW","Page table entry high register" +"CCN","00","0004",4,"PTEL","RW","Page table entry low register" +"CCN","00","0008",4,"TTB","RW","Translation table base register" +"CCN","00","000c",4,"TEA","RW","TLB exception address register" +"CCN","00","0010",4,"MMUCR","RW","MMU control register" +"CCN","00","0014",1,"BASRA","RW","Break ASID register A" +"CCN","00","0018",1,"BASRB","RW","Break ASID register B" +"CCN","00","001c",4,"CCR","RW","Cache control register" +"CCN","00","0020",4,"TRA","RW","TRAPA exception register" +"CCN","00","0024",4,"EXPEVT","RW","Exception event register" +"CCN","00","0028",4,"INTEVT","RW","Interrupt event register" +"CCN","00","0034",4,"PTEA","RW","Page table entry assistance register" +"CCN","00","0038",4,"QACR0","RW","Queue address control register 0" +"CCN","00","003c",4,"QACR1","RW","Queue address control register 1" +,,,,,, +"UBC","20","0000",4,"BARA","RW","Break address register A" +"UBC","20","0004",1,"BAMRA","RW","Break address mask register A" +"UBC","20","0008",2,"BBRA","RW","Break bus cycle register A" +"UBC","20","000c",4,"BARB","RW","Break address register B" +"UBC","20","0010",1,"BAMRB","RW","Break address mask register B" +"UBC","20","0014",2,"BBRB","RW","Break bus cycle register B" +"UBC","20","0018",4,"BDRB","RW","Break data register B" +"UBC","20","001c",4,"BDMRB","RW","Break data mask register B" +"UBC","20","0020",2,"BRCR","RW","Break control register" +,,,,,, +"BSC","80","0000",4,"BCR1","RW","Bus control register 1" +"BSC","80","0004",2,"BCR2","RW","Bus control register 2" +"BSC","80","0008",4,"WCR1","RW","Wait state control register 1" +"BSC","80","000c",4,"WCR2","RW","Wait state control register 2" +"BSC","80","0010",4,"WCR3","RW","Wait state control register 3" +"BSC","80","0014",4,"MCR","RW","Memory control register" +"BSC","80","0018",2,"PCR","RW","PCMCIA control register" +"BSC","80","001c",2,"RTCSR","RW","Refresh timer control/status register" +"BSC","80","0020",2,"RTCNT","RW","Refresh timer counter" +"BSC","80","0024",2,"RTCOR","RW","Refresh timer constant counter" +"BSC","80","0028",2,"RFCR","RW","Refresh count register" +"BSC","80","002c",4,"PCTRA","RW","Port control register A" +"BSC","80","0030",2,"PDTRA","RW","Port data register A" +"BSC","80","0040",4,"PCTRB","RW","Port control register B" +"BSC","80","0044",2,"PDTRB","RW","Port data register B" +"BSC","80","0048",2,"GPIOIC","RW","GPIO interrupt control register" +"BSC","90","0000",65536,"SDMR2","W","Synchronous DRAM mode registers" +"BSC","94","0000",65536,"SDMR3","W","Synchronous DRAM mode registers" +,,,,,, +"DMAC","a0","0000",4,"SAR0","RW","DMA source address register 0" +"DMAC","a0","0004",4,"DAR0","RW","DMA destination address register 0" +"DMAC","a0","0008",4,"DMATCR0","RW","DMA transfer count register 0" +"DMAC","a0","000c",4,"CHCR0","RW","DMA control register 0" +"DMAC","a0","0010",4,"SAR1","RW","DMA source address register 1" +"DMAC","a0","0014",4,"DAR1","RW","DMA destination address register 1" +"DMAC","a0","0018",4,"DMATCR1","RW","DMA transfer count register 1" +"DMAC","a0","001c",4,"CHCR1","RW","DMA control register 1" +"DMAC","a0","0020",4,"SAR2","RW","DMA source address register 2" +"DMAC","a0","0024",4,"DAR2","RW","DMA destination address register 2" +"DMAC","a0","0028",4,"DMATCR2","RW","DMA transfer count register 2" +"DMAC","a0","002c",4,"CHCR2","RW","DMA control register 2" +"DMAC","a0","0030",4,"SAR3","RW","DMA source address register 3" +"DMAC","a0","0034",4,"DAR3","RW","DMA destination address register 3" +"DMAC","a0","0038",4,"DMATCR3","RW","DMA transfer count register 3" +"DMAC","a0","003c",4,"CHCR3","RW","DMA control register 3" +"DMAC","a0","0040",4,"DMAOR","RW","DMA operation register" +,,,,,, +"CPG","c0","0000",2,"FRQCR","RW","Frequency control register" +"CPG","c0","0004",1,"STBCR","RW","Standby control register" +"CPG","c0","0008",2,"WTCNT","RW","Watchdog timer counter" +"CPG","c0","000c",2,"WTCSR","RW","Watchdog timer control/status register" +"CPG","c0","0010",1,"STBCR2","RW","Standby control register 2" +,,,,,, +"RTC","c8","0000",1,"R64CNT","R","64 Hz counter" +"RTC","c8","0004",1,"RSECCNT","RW","Second counter" +"RTC","c8","0008",1,"RMINCNT","RW","Minute counter" +"RTC","c8","000c",1,"RHRCNT","RW","Hour counter" +"RTC","c8","0010",1,"RWKCNT","RW","Day-of-week counter" +"RTC","c8","0014",1,"RDAYCNT","RW","Day counter" +"RTC","c8","0018",1,"RMONCNT","RW","Month counter" +"RTC","c8","001c",2,"RYRCNT","RW","Year counter" +"RTC","c8","0020",1,"RSECAR","RW","Second alarm register" +"RTC","c8","0024",1,"RMINAR","RW","Minute alarm register" +"RTC","c8","0028",1,"RHRAR","RW","Hour alarm register" +"RTC","c8","002c",1,"RWKAR","RW","Day-of-week alarm register" +"RTC","c8","0030",1,"RDAYAR","RW","Day alarm register" +"RTC","c8","0034",1,"RMONAR","RW","Month alarm register" +"RTC","c8","0038",1,"RCR1","RW","RTC control register 1" +"RTC","c8","003c",1,"RCR2","RW","RTC control register 2" +,,,,,, +"INTC","d0","0000",2,"ICR","RW","Interrupt control register" +"INTC","d0","0004",2,"IPRA","RW","Interrupt priority register A" +"INTC","d0","0008",2,"IPRB","RW","Interrupt priority register B" +"INTC","d0","000c",2,"IPRC","RW","Interrupt priority register C" +,,,,,, +"TMU","d8","0000",1,"TOCR","RW","Timer output control register" +"TMU","d8","0004",1,"TSTR","RW","Timer start register" +"TMU","d8","0008",4,"TCOR0","RW","Timer constant register 0" +"TMU","d8","000c",4,"TCNT0","RW","Timer counter 0" +"TMU","d8","0010",2,"TCR0","RW","Timer control register 0" +"TMU","d8","0014",4,"TCOR1","RW","Timer constant register 1" +"TMU","d8","0018",4,"TCNT1","RW","Timer counter 1" +"TMU","d8","001c",2,"TCR1","RW","Timer control register 1" +"TMU","d8","0020",4,"TCOR2","RW","Timer constant register 2" +"TMU","d8","0024",4,"TCNT2","RW","Timer counter 2" +"TMU","d8","0028",2,"TCR2","RW","Timer control register 2" +"TMU","d8","002c",4,"TCPR2","R","Timer input capture register 2" +,,,,,, +"SCI","e0","0000",1,"SCSMR1","RW","Serial mode register 1" +"SCI","e0","0004",1,"SCBRR1","RW","Bit rate register 1" +"SCI","e0","0008",1,"SCSCR1","RW","Serial control register 1" +"SCI","e0","000c",1,"SCTDR1","RW","Transmit data register 1" +"SCI","e0","0010",1,"SCSSR1","RW","Serial status register 1" +"SCI","e0","0014",1,"SCRDR1","R","Receive data register 1" +"SCI","e0","0018",1,"SCSCMR1","RW","Smart card mode register 1" +"SCI","e0","001c",1,"SCSPTR1","RW","Serial port register" +,,,,,, +"SCIF","e8","0000",2,"SCSMR2","RW","Serial mode register 2" +"SCIF","e8","0004",1,"SCBRR2","RW","Bit rate register 2" +"SCIF","e8","0008",2,"SCSCR2","RW","Serial control register 2" +"SCIF","e8","000c",1,"SCFTDR2","W","Transmit FIFO data register 2" +"SCIF","e8","0010",2,"SCFSR2","RW","Serial status register 2" +"SCIF","e8","0014",1,"SCFRDR2","R","Receive FIFO data register 2" +"SCIF","e8","0018",2,"SCFCR2","RW","FIFO control register" +"SCIF","e8","001c",2,"SCFDR2","R","FIFO data count register" +"SCIF","e8","0020",2,"SCSPTR2","RW","Serial port register 2" +"SCIF","e8","0024",2,"SCLSR2","RW","Line status register 2" +,,,,,, +"UDI","f0","0000",2,"SDIR","R","Instruction register" +"UDI","f0","0008",4,"SDDR","R","Data register" diff --git a/dreamcast2/regs/sh7091/sh7091.ods b/dreamcast2/regs/sh7091/sh7091.ods new file mode 100644 index 0000000000000000000000000000000000000000..34cb24c27ea9c531dea697efdc6d343185a6888c GIT binary patch literal 21788 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 literal 0 HcmV?d00001 diff --git a/dreamcast2/regs/systembus/systembus.csv b/dreamcast2/regs/systembus/systembus.csv new file mode 100644 index 0000000..6e8983e --- /dev/null +++ b/dreamcast2/regs/systembus/systembus.csv @@ -0,0 +1,163 @@ +"block","address","size","name","r/w","description" +"SYSTEMBUS","000","4","C2DSTAT","RW","CH2-DMA destination address" +"SYSTEMBUS","004","4","C2DLEN","RW","CH2-DMA length" +"SYSTEMBUS","008","4","C2DST","RW","CH2-DMA start" +,,,,, +"SYSTEMBUS","010","4","SDSTAW","RW","Sort-DMA start link table address" +"SYSTEMBUS","014","4","SDBAAW","RW","Sort-DMA link base address" +"SYSTEMBUS","018","4","SDWLT","RW","Sort-DMA link address bit width" +"SYSTEMBUS","01c","4","SDLAS","RW","Sort-DMA link address shift control" +"SYSTEMBUS","020","4","SDST","RW","Sort-DMA start" +,,,,, +"SYSTEMBUS","040","4","DBREQM","RW","DBREQ# signal mask control" +"SYSTEMBUS","044","4","BAVLWC","RW","BAVL# signal wait count" +"SYSTEMBUS","048","4","C2DPYRC","RW","DMA (TA/Root Bus) priority count" +"SYSTEMBUS","04c","4","DMAXL","RW","CH2-DMA maximum burst length" +,,,,, +"SYSTEMBUS","080","4","TFREM","R","TA FIFO remaining amount" +"SYSTEMBUS","084","4","LMMODE0","RW","Via TA texture memory bus select 0" +"SYSTEMBUS","088","4","LMMODE1","RW","Via TA texture memory bus select 1" +"SYSTEMBUS","08c","4","FFST","R","FIFO status" +"SYSTEMBUS","090","4","SFRES","W","System reset" +,,,,, +"SYSTEMBUS","09c","4","SBREV","R","System bus revision number" +"SYSTEMBUS","0a0","4","RBSPLT","RW","SH4 Root Bus split enable" +,,,,, +"SYSTEMBUS","100","4","ISTNRM","RW","Normal interrupt status" +"SYSTEMBUS","104","4","ISTEXT","R","External interrupt status" +"SYSTEMBUS","108","4","ISTERR","RW","Error interrupt status" +,,,,, +"SYSTEMBUS","110","4","IML2NRM","RW","Level 2 normal interrupt mask" +"SYSTEMBUS","114","4","IML2EXT","RW","Level 2 external interrupt mask" +"SYSTEMBUS","118","4","IML2ERR","RW","Level 2 error interrupt mask" +,,,,, +"SYSTEMBUS","120","4","IML4NRM","RW","Level 4 normal interrupt mask" +"SYSTEMBUS","124","4","IML4EXT","RW","Level 4 external interrupt mask" +"SYSTEMBUS","128","4","IML4ERR","RW","Level 4 error interrupt mask" +,,,,, +"SYSTEMBUS","130","4","IML6NRM","RW","Level 6 normal interrupt mask" +"SYSTEMBUS","134","4","IML6EXT","RW","Level 6 external interrupt mask" +"SYSTEMBUS","138","4","IML6ERR","RW","Level 6 error interrupt mask" +,,,,, +"SYSTEMBUS","140","4","PDTNRM","RW","Normal interrupt PVR-DMA startup mask" +"SYSTEMBUS","144","4","PDTEXT","RW","External interrupt PVR-DMA startup mask" +,,,,, +"SYSTEMBUS","150","4","G2DTNRM","RW","Normal interrupt G2-DMA startup mask" +"SYSTEMBUS","154","4","G2DTEXT","RW","External interrupt G2-DMA startup mask" +,,,,, +"MAPLE_IF","04","4","MDSTAR","RW","Maple-DMA command table address" +,,,,, +"MAPLE_IF","10","4","MDTSEL","RW","Maple-DMA trigger select" +"MAPLE_IF","14","4","MDEN","RW","Maple-DMA enable" +"MAPLE_IF","18","4","MDST","RW","Maple-DMA start" +,,,,, +"MAPLE_IF","80","4","MSYS","RW","Maple system control" +"MAPLE_IF","84","4","MST","R","Maple status" +"MAPLE_IF","88","4","MSHTCL","W","Maple-DMA hard trigger clear" +"MAPLE_IF","8c","4","MDAPRO","W","Maple-DMA address range" +,,,,, +"MAPLE_IF","e8","4","MMSEL","RW","Maple MSP selection" +,,,,, +"MAPLE_IF","f4","4","MTXDAD","R","Maple TXD address counter" +"MAPLE_IF","f8","4","MRXDAD","R","Maple RXD address counter" +"MAPLE_IF","fc","4","MRXDBD","R","Maple RXD address base" +,,,,, +"G1_IF","04","4","GDSTAR","RW","GD-DMA start address" +"G1_IF","08","4","GDLEN","RW","GD-DMA length" +"G1_IF","0c","4","GDDIR","RW","GD-DMA direction" +,,,,, +"G1_IF","14","4","GDEN","RW","GD-DMA enable" +"G1_IF","18","4","GDST","RW","GD-DMA start" +,,,,, +"G1_IF","80","4","G1RRC","W","System ROM read access timing" +"G1_IF","84","4","G1RWC","W","System ROM write access timing" +"G1_IF","88","4","G1FRC","W","Flash ROM read access timing" +"G1_IF","8c","4","G1FWC","W","Flash ROM write access timing" +"G1_IF","90","4","G1CRC","W","GD PIO read access timing" +"G1_IF","94","4","G1CWC","W","GD PIO write access timing" +,,,,, +"G1_IF","a0","4","G1GDRC","W","GD-DMA read access timing" +"G1_IF","a4","4","G1GDWC","W","GD-DMA write access timing" +,,,,, +"G1_IF","b0","4","G1SYSM","R","System mode" +"G1_IF","b4","4","G1CRDYC","W","G1IORDY signal control" +"G1_IF","b8","4","GDAPRO","W","GD-DMA address range" +,,,,, +"G1_IF","e4","4","GDUNLOCK","W","(undocumented unlock register)" +"G1_IF","f4","4","GDSTARD","R","GD-DMA address count (on Root Bus)" +"G1_IF","f8","4","GDLEND","R","GD-DMA transfer counter" +,,,,, +"G2_IF","00","4","ADSTAG","RW","ACIA:G2-DMA G2 start address" +"G2_IF","04","4","ADSTAR","RW","ACIA:G2-DMA system memory start address" +"G2_IF","08","4","ADLEN","RW","ACIA:G2-DMA length" +"G2_IF","0c","4","ADDIR","RW","ACIA:G2-DMA direction" +"G2_IF","10","4","ADTSEL","RW","ACIA:G2-DMA trigger select" +"G2_IF","14","4","ADEN","RW","ACIA:G2-DMA enable" +"G2_IF","18","4","ADST","RW","ACIA:G2-DMA start" +"G2_IF","1c","4","ADSUSP","RW","ACIA:G2-DMA suspend" +,,,,, +"G2_IF","20","4","E1STAG","RW","Ext1:G2-DMA start address" +"G2_IF","24","4","E1STAR","RW","Ext1:G2-DMA system memory start address" +"G2_IF","28","4","E1LEN","RW","Ext1:G2-DMA length" +"G2_IF","2c","4","E1DIR","RW","Ext1:G2-DMA direction" +"G2_IF","30","4","E1TSEL","RW","Ext1:G2-DMA trigger select" +"G2_IF","34","4","E1EN","RW","Ext1:G2-DMA enable" +"G2_IF","38","4","E1ST","RW","Ext1:G2-DMA start" +"G2_IF","3c","4","E1SUSP","RW","Ext1:G2-DMA suspend" +,,,,, +"G2_IF","40","4","E2STAG","RW","Ext2:G2-DMA start address" +"G2_IF","44","4","E2STAR","RW","Ext2:G2-DMA system memory start address" +"G2_IF","48","4","E2LEN","RW","Ext2:G2-DMA length" +"G2_IF","4c","4","E2DIR","RW","Ext2:G2-DMA direction" +"G2_IF","50","4","E2TSEL","RW","Ext2:G2-DMA trigger select" +"G2_IF","54","4","E2EN","RW","Ext2:G2-DMA enable" +"G2_IF","58","4","E2ST","RW","Ext2:G2-DMA start" +"G2_IF","5c","4","E2SUSP","RW","Ext2:G2-DMA suspend" +,,,,, +"G2_IF","60","4","DDSTAG","RW","Dev:G2-DMA start address" +"G2_IF","64","4","DDSTAR","RW","Dev:G2-DMA system memory start address" +"G2_IF","68","4","DDLEN","RW","Dev:G2-DMA length" +"G2_IF","6c","4","DDDIR","RW","Dev:G2-DMA direction" +"G2_IF","70","4","DDTSEL","RW","Dev:G2-DMA trigger select" +"G2_IF","74","4","DDEN","RW","Dev:G2-DMA enable" +"G2_IF","78","4","DDST","RW","Dev:G2-DMA start" +"G2_IF","7c","4","DDSUSP","RW","Dev:G2-DMA suspend" +,,,,, +"G2_IF","80","4","G2ID","R","G2 bus version" +,,,,, +"G2_IF","90","4","G2DSTO","RW","G2/DS timeout" +"G2_IF","94","4","G2TRTO","RW","G2/TR timeout" +"G2_IF","98","4","G2MDMTO","RW","Modem unit wait timeout" +"G2_IF","9c","4","G2MDMW","RW","Modem unit wait time" +,,,,, +"G2_IF","bc","4","G2APRO","W","G2-DMA address range" +,,,,, +"G2_IF","c0","4","ADSTAGD","R","AICA-DMA address counter (on AICA)" +"G2_IF","c4","4","ADSTARD","R","AICA-DMA address counter (on root bus)" +"G2_IF","c8","4","ADLEND","R","AICA-DMA transfer counter" +,,,,, +"G2_IF","d0","4","E1STAGD","R","Ext-DMA1 address counter (on Ext)" +"G2_IF","d4","4","E1STARD","R","Ext-DMA1 address counter (on root bus)" +"G2_IF","d8","4","E1LEND","R","Ext-DMA1 transfer counter" +,,,,, +"G2_IF","e0","4","E2STAGD","R","Ext-DMA2 address counter (on Ext)" +"G2_IF","e4","4","E2STARD","R","Ext-DMA2 address counter (on root bus)" +"G2_IF","e8","4","E2LEND","R","Ext-DMA2 transfer counter" +,,,,, +"G2_IF","f0","4","DDSTAGD","R","Dev-DMA address counter (on Dev)" +"G2_IF","f4","4","DDSTARD","R","Dev-DMA address counter (on root bus)" +"G2_IF","f8","4","DDLEND","R","Dev-DMA transfer counter" +,,,,, +"PVR_IF","00","4","PDSTAP","RW","PVR-DMA start address" +"PVR_IF","04","4","PDSTAR","RW","PVR-DMA system memory start address" +"PVR_IF","08","4","PDLEN","RW","PVR-DMA length" +"PVR_IF","0c","4","PDDIR","RW","PVR-DMA direction" +"PVR_IF","10","4","PDTSEL","RW","PVR-DMA trigger select" +"PVR_IF","14","4","PDEN","RW","PVR-DMA enable" +"PVR_IF","18","4","PDST","RW","PVR-DMA start" +,,,,, +"PVR_IF","80","4","PDAPRO","W","PVR-DMA address range" +,,,,, +"PVR_IF","f0","4","PDSTAPD","R","PVR-DMA address counter (on Ext)" +"PVR_IF","f4","4","PDSTARD","R","PVR-DMA address counter (on root bus)" +"PVR_IF","f8","4","PDLEND","R","PVR-DMA transfer counter" diff --git a/dreamcast2/regs/systembus/systembus.ods b/dreamcast2/regs/systembus/systembus.ods new file mode 100644 index 0000000000000000000000000000000000000000..a98930bce9c357b4f7ba07651d6c25ed8326f01e GIT binary patch literal 29488 zcmb5U1yEGs`!ldoC@Cr3y|DDsAu1(Zy8_b9O0yvS zuK)M@zcb&=@B4rAo@dU?nKS2p`o8b$x}Kw}fsOMN3kx3$i%})V?1P&`i~trE*1sF` z3d`Nq-O)GD%hA@$%gxo^*4Ne3L(t#DLBP`%;tCP)^m6oY@U-`Hcl7WTfOz>h+B!g7 z936di|6g@ts`)<`4dzL~)5FQt+0W;{YJ-RfVyyk_Y<&d(zpd#0gO!)3m!H=^)BnMa z;Xm2=cslzyLLmQhi~p&gPHvvIzK;L5{e<}1`uhFD~Xi z2r*9(-#|Ag*B0MAV#2!GI$-Hb309?Lo!g(u51b|#VSQ5U79e$dd8#w! z6V!4!N}~4UX|JDVkpiLUfzaJ2mTdgBI2eR5lLp7)SbV}w3roQ*_x;lbz-I*e$4m~( z7FUFNHPdGrqRV~X@xX5X#r0!xsVGtTfP?MNHIWhwuf33Vhb|230)M`q$_H%szr)^U z>RqSTIIi1v<@(SAgjwLiD}>d8O|NUddaZN`y)$#8(n~$9-va-Et`ZdPnu4OuOSK*> zU;JwFT_!5HI=;*8LoPA!j{fat{Y<9+DFuh_``Fm;+3`|GdyZE^f7pLSt7gT1{k2v$ zv0gC4ro=GyZIZ^(`ihai@Ix`T_~WdN;F=$mE>B26PaZH(j%du>$kxlpuu+4O>N{zf$F=@sl~f|dc{yGlQ;s&MnxnfhBC}4xkkwx?ZdS-r6uh8dSiOQYBTH8cvUOfFEr@?sE$HG$N)QO&|3S$PnobRu{lXrE;$6P7)Q}l8*(@e zNmDZ4AJme3oGQ_q>q36hFWSV+{htJMr9MzkyaL4t%7)z*L?_(SOs73k zM(0%}g50tvY{F$aZ*A?|AZC{AJV`5NP_X${+j2>EcFIpNjek`=T+a=pL0IvLu~!?= zu&k$^5R7kkuCa2v7O?V(A!d^bnH`86MinW}>asqk7tQW-G^^IAq5P>B!a6SNpyuN* zPvJ~D=`rqZ`0|}H1)EZd%454g;Myns!l%S0kkr{{=HJ?+HFj|9GLD$YWXuZ6 zpK0`ymQ6;bDnPTpzvdSzyt%AtYNTx|LGJKqZu8uP^i@vBd8hSP7(TOhQI}f=YrdcK z)b4uE!<$}d8kFL64$@Y+JuV|Di4IiPD?2xrlA|tWT+zjliUmQuW5@bvjnaXZ;b+mn#<^M z6hoDpGPxxC$^k*kNuXUOiARup~kYH03sB0?^1c+H9I$rl~ ziC&cryFY&9{@8k9%QUo~{)D_?RqJe8w7zjMxVO1NI)%A0+ZYcWkW(%;64N=Cm}jlS z!rVZBFu?yYfU>;4%ON4Uj31cv&4RO_9jFs^e|TV&tD%e<~P=*oLBwf zhqi>H`yZTcNN>OCkjRbmR;_j^m=n?u62hV=iPl4cUrp7hhdP*!S;f|9B3Zn9Kdb?L z%ljUr)$_l)<-qScdSPomeFVZ)CX3RNCyVlm`w^Jp#XZ=sYVm@gc$SAQ&rs{lEGKaY z^JDUZ;alKBl2_sj7Mc{cxLhly*bk&%%+q4_v1&=b)M8cm@_XJn3adX*NwR;y^;s#R z+kTQp`8jUU4|_5>e`t?XM%D>Y)=$B{M3#7a~=qZG_&}aFM+b zBCY*JeS^_D-naumXJ7-vTx22hIbH0rzne z2%E=XRC6cfr!Dhn2ORs35O_DG^YmaNTS@-{Vp;L%_vj(on!(#bX?8r!WzmgiqAsGv-Htg>@{7h4sG?_kRLw#2B#VZtLOdXp2_Dfa}7uVn|VpUlO~GHx@mAlXWVs z)5+R9EAFjI+~1UdPrwu}?~2|Cp_3R}BXBa&^Fu3-{LsY`Uf+ill9hcoW8dEqx*`+q7EgsyncVSPn^Z z2|BP3@|*5EUS>g4Ea`w!{H8)$u=7JAxw%FEhlGGMKy3VXrpEz3alUNNcFsPa~f z#-hU~N9*#U}ELeV96at&_vuiUlq;Fg_*18jlG(A%<; z&!3gw&sd>VyvUhZ#D<>x<+?>6{A1t#c#|AS{5|n8E4q*)M_&$Dl>KXk3;Vly({q6} z{=JBl?p;kTOGu=)GRG~!ZxBmHJ%r;JCPv)3jGw_w=^A9)$JMJTS8RJS{}xw<3P@UxSzMj}adH3o2E@_V*VV)M zzo^VU&^!Pt{`76W_2ee1nyIoYXAP8#Ydm9Bz3GH9e^)`P@QuA!BkUGuLi=-C^P|n` zOaNNx;ZRF}*fo>DooVD>8$4Q-R14#TZtgT})eyR8BHh*E&E9XUE{l&Ba2ewhNl_2b z>ts*72Mfu32xSt732LuX;}R{%MD@$xu~~6Fi|iD*k&J(4CRo*zXQ>nI7(hjnwCm`| zs%ThiynTAva(VpnXa6jlkx|v|G}=&oclZa6)H+|Tg+XcxNbGH9Zo=!~U!Zhu`zn-4 zkwnc4gpa9bk9YmN#(BUe9Ab(&hH4M49|F9|n^(lWm$5TE3y9m+ekF!L8W8crY~?hx zLVetZf}&z+p@rdc_|4NJeuikD#7ED`Qrst0w)g7WMMEAH9Xs%%mOqcDri`yKM?I5N zWPe9Q<2Dt3y6?$t$p(nxm-#N76A(cn)@GxR%M-82lJGWW8pk(6hh8;0F63mHKDrMx4>DADcSUYA;YsiQ2=qT(bpYe9{YIi6_wv8A zR!Q$1aHaWM&8vy6sEzZJRZiH}_qoFON!mlV%Q(9~55CZ!j?bP7rq@+zsN$EjBb|lR z7}a%;B1gzXvQEY?4#S?@Fi|?n(Wib8#=Ci3=PD4**k_PnudSQ?)S%gtV>|&2pKg3r zp-m8OOaDez(3qF3$4@uc?{{>ICg82GQkxtJxG^-wDo^sD1w= zm)9EKfmJP0nFRFSpY%jr$Kd5)kWb=z>_Vb!)J??fNbca798PAh%X3PeC28`xb^qpX*pJ7x zeHGskOT~XcTy{Zmei1El(EN_i9rN2Dr?|G?x4wj=eyywbXk*r4beYfXzo!iV*zXM9 zS6&pj8dtD3xe3!FIuf39-Z&&84zAKFNE$1nSx`|S1h7z`t?p8F9yB2(4Dw~EajODfP=3RWG=K9rqZubbvMY+~qvYhns z+t!;sR0!J7D#F|bZ(ofe2&do)bRB1Dv^%klOG`75w*7S3;~+g`PtOU`bB0~WL2hGP z+Pf54yx%r_VfV{SJ@rR0ebi)kJ8$6fsslVkv%%WUa1Mm=)RVH%_nOlpkO8?uO_B!BB^EfO3z7-pFvTWNmk&QiWsMYw3yy2UR7BM zV>tmsd0|6k2_sc$ppuBC8o*Lr!d6qvR$Izh@0FUGx{{`$roNe>rh=)ShOx1Utd5P6 zv8#%Ouc3vbp0$^zeUQ05*w`t+PEXF(P~FZ{)74PU%~TO=p=EDw1Tk0kwNeM!0RwC_ z-Z&eBTwNXA{hYl+d_7zPy&`_~PK?^0ygv@7+v3dRxW>*hhx=CI>sD zhIz+D1Z9M~WqtB5_~=m>=U1K_+>rS;CMG5-E+r;8D=8*CIUz1H?tNBDTyk=9%9pJ4 zjP%ru?Ci9ptc)+&*;yYlpdWMVQ?rUv@+vd)O5=)J(hIB7%37cqAIfr58?qxR3o=@Z zVjD|RJ4zEfE0Q~_vntBVORC|;bzRl9B9P4FhGZLlxbV zO|nZ`<^@>barjrHQWfvF6R`&cVT<{?Y006Tg2>&CiVXFH8+0 zk;rc|8{ZJSeRHTm#QN~B_2J)pgG)yZ^xpmD*8TOLv$Hew`QOv)yQ}k)zZZXRug~u8?l6vUe}9jP^uQ3BXIN^Aa)xi_ z_j5^14IP*6NsBs(6gd4IRKofF8MVLMh?|LS6P zHV#`f=UVEbZ9Me#c5t^0UMgp({ZoRcMxM+@+3K&$b^27Qwl+%NHjUr?R%h06ztKx} zKM2}9YqNI$HL2E?J^0+;sfVpEcF}hsN0n;x zAA7JWv_FTg6Nnh|PTMbsysNkx=`>JC=#7f}<>x^CE4wWB4bF;wyI5eXIdi+`)9%9c zXlk1ltNf&Tf_C+&AFxvoXXp$wcXZfaUhmi*wdIC@!BoT|0jX6V4Eg$RV3_l}qeooA z(Ta<>UdaT*(N0z$E#t%%WSaJI8e26et{i1vU$9f8Q-`Pon-Hf6b7x2(Ds7px={Ev! z?H(3IbX)X~1Vv@4+!fS_=SldpiFc}w^Lei;=uEt{=Wrx2NqytrZaoEP8} zV9A?I;!of(4>>iz7YcomlEW}wBCBw;lAQ6i{cVB~qgQcetxj@%mU`4IdPQn*UB))x zq&{V&v%b*ex)C6 z??$t&$A!3>xW0yPvFnsT$}Bd81&^crv)q@^1I}eVXG0tMp1uK(zmI0a=>G(i^0MQ9 zN$R<%6p{(5;R&>+f}9bbvX&FLv+>{{6q8h@5=0*;p4>Hk;qz;Xk!WTdSn=IL!ACgX z5jfz{$aP;ej=aO7{BGfjZ=3Psq5%Bjy9<(j@e+DO5nGDaNCQYn`^?5C_Q52K;N6`)r%S%Vi9 z!**g9&gRTEh?du57E41n4_3U(Joqz>Z20s5oOP6A!tL{dSwK^v{ZPp#o38;}d2y}* z2*b?{l5DBl6s#}n7aSqUlTt?1MNk=SXGDvp^XqoG?uN&5vjdqi{aJ`FZ=qRl8bzZj z2jE|EM7GA0J;4kRGGmdCV?wb*NABnw`!@2oejB1PPoROW=)poU2Y zo#%l}{v%G&0;g3&Ne$+rGx0i`%SYGR_Z@@E<#jD_jC6M??7DC?Q+wY>&&1tQ0|i4y z^1&L8WedOazPFX?WvDj*(fB_HL1ch z&(teg3Z&@`D2d)vCf z{Btb8Q#SEs^>vKfx|}$A9!#$>Y<8T|>7rFyvT(ih!smtxdGLl*Q)-E0_%-VgjB$?s zy1xA9&j+S|1Ki`%uwHH5uM%*AjZ4G!Xm%w8Lq%UZN-U(E6b!)kQ=zJU39h-76 zljg<=PIhp3KBCU@J_Z^CwNXI?-Q7m6lt@pVK$~BzK2ZAl?yn8#symDes#v`gMl7iYk4MgTWx6cjRn=a(LR0-@o0|!bWwc-@etX_zKgfRhqX_&<)6TE+&9msM z=OvtamHk}J0p*qJ-{Iqp6AU`LyT#)V++sOg?&J$#(D&l|K~$$6kRFW5eGA=j3$%t0e2Dx4mi5QI=C6kVj!l zo;L5oP(;NxaHsD}LMg^6n32`Q()vcY_J`0)R#=x*l!W4vuYma3M~~6)c_`yXYR%le z(A$YmZC>G(t!R5%2-baIZy2u|K6Km8C%!y_^xN4FM1RHQljlOYW_<7pv$y71pmb4l z+sK+yZcYk9`JRd^cA`t1y$N|=myjMOH#-tLfB^qn@j#+LfzB2E*~X2T9AYSs2#&!Z zfwaWE#%Nz}5A!&Wf7B8?WW;o}1P&RjaCL|>%_CbtFow@;-f3DHQR#1gJ5jvJ)#?7G z2BNjXiJr5doq2pTd$AJ|tpsz}sdzp|SXGlKL-qj7wqwnz5VvPj zBsns(x<;=Zg{%;qMxPT~9*W9-+#2J#6S0IG6@L4aja8M2hJSn7A^Pct-UvVw&)^F} zf>8y$h2lBTpJK`$QJ$mrXkyXPoBjA94o@bjuxs6h2jDOR#&^MT697+27u^=^48dcG z1r2iJ>F1AA!ttf0c3E$EZLDf3wSjq4lhcvADYj?QS8<&-JAPI$Z6aN+8{8JSChQLD z^T)oucSkDS4^K@)b9!AB2mDo-7&~zMIgFyzSIyIS&q4>_esrT=g~M@^5|<^}~GiCz03`L{$nXn|+%r`4Rb|2<4gg zP{PqY($ya;*i-1!o%9cnvuVZ2^;YDDD~L-h|qB?Jjvt$T$Wqr zcqxISs%V;=UN5}5k*dX{k5a`KVAR-0g3~?REtIy8kjPYR^M|(+#3ItcE0vlja+R?< z#Qmh-&DBichZXmBxmc;r*iI8L4XWQ(}&)KH}C@>*vYT zmuQ%H29ac<)DdCsb-6NM*WYP=?C}u=wI79&4yAUG*-=dsEDwLU>Sm-L{ zwcBX!%MbO0LUN^C{I;UhCl7M^hH>|2iclqdE@^Ej(o(C3_mZOB9jXs~=UtwdsZakKwf<$9D<$(IqQ7>ajpl`r;eQ-z*! zXM!EOUlvbLLg?b`Rjtn^#EEiJg7%z|eAjDC>deeu;_<3MsZz-%^ZPCbT-`f1-$av( z?wgbL__K^x(Vx zg^0|$3xA+_-s4esNxAHXH`ZVW-<3x8^woPooIOXr!aQ+=cNz<_dr-p{}<4=u+P%?(h62{V$9D*=Jg`e0xE z@7Nn51)5+bSTQ%eCZT*Lt7%hVAv7OYiJ#!1?XVdjkm{dvIa{mX7gdI(w1_MS~1P-V1qW*)yh zLScbjSC$jB*pxg+c(DVl{Y+MYo_3k1|DIn_OVahJ3nK_Pma+WO#I!;^Gw)D_NX4GG zZH1_wIIz;{z*@pd;A0%cka z>rc8nOqcXEA)iub3`Ml4KPwNbt$IwQ{CmR&t_ltWxtGjjah$rRHybYOU-VJSp7;FW^hN%NCOr5B^kfD&uUrY&lUCFkj08k@JEMr_a4rb#{e-|GwBl@W zW^of0LiOVkNN#x4?4F$Q4BcXdH2ltF z$-pkCN`PQSlDuEgL)OVr3)UM0^z5sBdv+L|L*cV~0i^0JWs3ZHbl6E*ps7*`my_3W zuk0=U|A~@9*hUf{{9`mmAI$ z0j2xVtKm=CbXA_(1~A42g?^NUX^A!YQ-{SH9i<1TFt1hmWw62TbW0H5k2|O<(D8E2 zNt?ZE2`5u8O)8P_AY_=wJvdB&xloD~1~r}uqLGP@nE^6r;ub;eqoKKM6ut))>XmS& z+WtE23cqKii1)1U*Er=#z(;UBP;T7T%^ul%U>F@k`YUJE3V!(GpK6=b(6qfEZbcd{ zBDglGwymcw==PZo3_B4h^KMbQVt`uJ8nU`{>9CRK@LQj<(yv(+_W7idM;{y{zFmoS zRfol5rcZ71O8=_n@g(n}Ub3i0r^###@Lu&Z?s95y*uw?;$Xg#>l!Piw%D-ArfM?!C z2_{pxcy|!wN^t%*_NXO*!Eop2xS9#W_$*06YOl*Uv-oh5;SI?n7yeyxbAblCwcHiu z?vCowpc$;SssoCLj@3LNMtVki@a54Ja)R#MtjS;_Znzj>V;#ZOzHk)hu)K8vB1aZ> z9o-w2#hHSX)P9w{&vYWmwDje%3W(8J3l`>Ef_S-K2?&B|9JS=?qoVY@kK2t2t^|4E zOcV)Ls9a+!aNg2|Bg{X@L#fiQZVv2ThM=lNw{|d8`VF!^0_|ISqYz?eK#107g^iRs1wS?eXlf`KZAzAzLg% z27|<_s<8M}V0IVcRh{O50XPyW%Bdif6yz6qK{$8-x1wi}1xeMSiF3KA8yLC})kGlo zXQu-C;5|43AytUjfm3k>CIJm<(X}>CPVVb2hq>hqdf?SReKuM!SSO-?DLzem8?*Ud z>b>I*f&m_ASNa8DJdRrG6i759`L-YvSiB1fIsh?rFFaDf&TNkglBxZ<1K%>e@$@sz zZPn@H^Ev|tH{IJJUAibjNtTtwqM3OdM{=R$o72jUPDnN-*_i*_f$EFf%=RG!r=V zWuq9uSBjv(0gbjF0fUP$mfzhv5!Eo{d>*jM(g1aB;Dz(+4UBsENQNh9qs!$)ALaUZ zhE5P47zlf1kahtitt&#%(}X6ZA+z8`h>w9F{x`6cOzNv51T=@G-aU~rwMU*~=ovj1 zx>LOpZQsl7)`$%ka5&(UOymd(OEA{%MD)#xS)rz#YS932t>0vScO`o15Bd$a&2mo8 z1xE(%W(lGbc}3D(-{g?H0#{}{pK#9aI=q}zclDW|`~tBdVhV)yEjKp<%@Z2F1?09Me_+1S^ z2NFUC#XL=~aXbQ^E_$}8bP|=t!K9(who8_5!nxvQJ@}AO|3{MR3qzm zmJVn%5Fvazk@TUo(yBdT-_nSM1?QFb7zB2S<8B&>z{&w$%Ov z%>Zwd9@{p{r`3IA21(cX;56IYy=8O;9B{86g^O`TPTb6@T&IBDH;So0bvyW^i6DV% z#<^n8@v-$087Xp-dB(UuwkE%WM`Cw^ivkg=FAFsqY3&~8k$ha2+YhaMfKv0+ZOJlTEEBg7>44^GY>)6bSWZeNBI%bTFTc7%^86G+9%fpZaJt;jAx)KP{m$7n zUZ9p5=o{GvtPHDsnfuZevDG70sM)z_|{V=jZndCUQ^GA z55R!Q8vY`g5klB{7%y*}v;?_^c6*1iK!1_t_bc%h!c3&kFfRN~z5o$YgT7#e`@ckH z>7&|wohA3fK6-8erw_uYlEFibVgV!ta)#+)Q-8w9D8CsT&J1-`feI1YPvre^=k!q< z+)ki<{-`Akjh|9Gd7JyAwrnIGHP9=0J^;WgZ0=+QJeR2Sc~I|DtG z$Eedt&dGJ*JEpfoD8WfC8m1saH?dv)-IGP5>&7b$oqP@U_B-? zr{SN{RWbas_HF4zT7GnmI8J!0LHwi(oLDT~!gmn9CA*iF7&kLtqwp=NQ4AG2=8nl3 zM@E=*VO0C9w$Yz{6DXDXI#Jdr#$BRVsq!smWd`A5_dhV9{zMmCPseuFL06mzW@J8y z1k$_KpnphOmm!ofz%TfHTy?`If1kIsVLR@5+QC%rqZ#%47SD;ERG=Glk+U?x#fUq~ z7T`}D(5t~1Aodn;`DD@p47tDsbrCofbp$?C=>I|6)BH_p$8**&@QJ&73iuTw9uy}~ z35O%+pKkzTXWB)7V1na^17=|Z6!X|$_%}4pty|U@-xs?L>F8$v5%^Y>uo!_swGlv> zV!<4s+zWQsfjy`M5Q&O_>8C?Pk@Lj+!fZ4eW$s(yyes>*9qXnv65|#kacK5m2v>lz zhr*|63$T}2Jb9!AO0KyLk@=7yQd#SbZ?$0?;>pV-U~vSaOCEYhGvm^&0es1oui ze!}!nJeRD8fDc#TmEmj+U9sLE#z*+}nxO;kJjcX7$ieNT{0zaRR|BUdh-3NQ=$9s#=j$z1}*fft{?;2dpR1bB{{m?qes|9DD>-#v z0p~qoXGgNLR#0I&{);;Nux&5rCJvS#&-B3&{P3+mU5M@58Z|HaRh zYX0I_dRO%C_;R62>56-A1|{DSj%~dRsf(VOcR3{lli&qOOa0=pH(IUw2c8AW=mW}1 zx}B^O2fO(o6fM9kV5dMA;h}q86Y7V{tN2c|F(C|7y4r^G)qIAdIlqFO)0Z9kG0N3Lp=&AuqZnF; z;ew-~Z(xPI4Mh*s3UI`AJ!%1*k&$lU^^e;Sw;3kf&F~E%M2vvtd?x6R-F6!SGjbt; z=+6Y_m~qf!m>{+M07V8^i?mZ%@H~uUVl{)TA)>rVD&kKC+CQKZ!N(anVFBKuDH0`w zUU}7EqMa6ALIyaO9aHP=KmErn807A?20!3M(qRT63in9Jkr%6yyDc5x#xPBIG@jt} zT^K4%bp(F!8T!dRo)zBD7po1C|D*w0>_F1-S)pFMK3nz2rn?<8f=+&rqXh^F3>z&bP$S<(v z5JPnha8pN-uBr+)&-@|aks#|L=4E8~MC`9a;0_&ma7pDBK~J&nZrG!C$WIqovy~y- z&_2f|o6K$E@a zKivH9e*x&`Y9J0mahZg#cI-Ag@GhLP6kySvGvj~%dahK9t@?==b8?iN)$nA+2iBtf zVv$)rX~^fs_BnjU_7>y8Fv~4qY`zo~fA)GFu7`t??Gr<&mmvPh)t!w5#vk9BO!NSP zM1D)r##!2zJ@6d+NdDr}dr?{~zSjfmW3**=A%CFkCuNb8p)>ZSPV24w7~uA(t)l;p z@1G~zR;b|WD&Ypx_@p3MI;!9qf%Z|2P5v1$|DrhH*SKm?g3l~Quf-eW<6jbgeMb1y zuBVu-COna3;_J<+{2TX;kBNX2z&4QnNA=26kx6{aqE#Z>M?WBgJSD%I zi`DO}U>jr)O;|~3V$>3PvS+bKx&fZKw<6c^vv9*%zRwkh2{EG?G&yHIJD}SlD6}kQ z^KDn+e7}H@b-qdCG=$~K$5#K)epUe4{-~NlI0pk`N5NX%zBMX?a4Qkf=WJ}RZO%EE z&w=?WMi>%G<5e$@x5t@9?#rN|pRu0Km3TPq@NWP8pUb*zt|tKly;-mOp*CX88^C3J zatMs12np1k<*xqe;D5lqX&+JkMm_2vRz-vpT$E`f+0RvJ!nSt9G<8p z{>IN3npYBR)9Ca%hvQ@Fi+v*936oqD=IG&%+Li_QBn$&3EVBr$z-cRR1Vh6y@bd{< z)eI=!UH;P!d~Etiqa7ab@aEM@(m?p@ba|X1OjgR+h`vhvBq-D+rBF*c#;(FUf)9FZ zC99yI+T*&?2>z%4%&r6GY$z!Xvuv)A7|axUv^@VqH1ojg4YEt#yYA4}B_ z!?zScjP%Uc?=9t3eN8=QX_&o|{=vbiF9Xfj0`P=I1)XTuIJEj5LmeNvldkOTg{e>3 zBEU!3jC*D1zWWW__*On2I`xT|dghAgJ@9mvrsuGju2=$@h0$b2;2xBffJgaP%afe% z@fvhd8b-XCq(l0<{E}omw9*6{c3W%Q;&UIfZ%Nl;D=<*^xqV)3<>IOgOwfpbCMd^V z{*y$QQ30Z+N_Y#n38c3*dy)?(Nh5&N#n>VfrC~VGp9-+|c_rsZ!ic78yqE@@8{y=^ z`kRBustNKCEO{5`LFG-iAwb1JoHH^*5tPfV4^E$@Im{$-#^lri9b6B5eemOkGC)O_ ziID(^q~m+dGiY@!dk3`}srz;nj=m8|od}i9U|!RxmpuBr*%mn4Tr0Q~A%}5V*c16b z74TS4Ty-M&)z=)d2CPQDC^op2Le&1yQS+%S+KTs?N)0-Y)1t~TkB#jUgPu#AU%Hbh zEr`<4h$5G5FKbpN(KaVd^?Z>zCqG`&4Ewi_CO)|jEFcpC6C|9uY8iVX|5Xe*Kgbm+ ztzC)EvURwZ!B1OV4h-cKz*H=;b(@uCpf^q~ENUIdPoigN{KRb_*6kbd1guh={1KO( z?T=V5>51HWjAjd?kPouZMG?u#{L%*(hXRyevuu3eD?va5c^^4A#L-n;i1^Dff#OB6 zh&~k3*yk4Nkc!7dpTmlUnLY?AXh@#^X|QlXbXUE`BO%s0KKPrluV9o7ipy}EwAIGn z-F=0e-(f}0>&Mpz4fLN3d|R#(ST^lub?Hhk^gq!>oxUIgDMxbjw?CRj9Z1D-yH+Xz?>OC`8`l-3mA~PF*5(Rm;^3%CW{V!XYk|Y=2AX*NC9Ro5EQ7v zYk0cgJnv0%ufl!9RVqkL31hQ|2b*i zBrr+egbSCQw6?T{l2u6uCO2Qpoq%+uZ(4CDlu%cr)vz_42Lb;S60w?r=B` zs4K1<0pl-1233#cfEVfEV%z`D0tV$_%nw_gMHT=-tvdSP!IOolnWmgMV$304PxMeE zz|Ke+)Lj$ATKAZs`N09QH<10e(e%)+33Bk)MK+WR_wAe%yygHSru?FYH=hIPM`vjY zMOJAUeWMtjIoI@@sDUhpCiL_g9vPEI6SCRB6Fn^lAXt23{$eW%zbJi4cq);UAawQR%B4? z3Oou!u^p-}26!>qTIcxO3Om-1pYYqB4T+?VnPRp$wnY$Y6H_e(l(~rAX=zxgwm&gq zxR(078ShCK0`jKhcWw_r9@32#CaY;HK6l18=U(MRWt6Iw z^oYJyNN>##-K2t#0Sr*ukQx9AlP3W1JIJMd#Bx>tap$o4qYi0|pg}mg%Ba^?7uTX= z5P^Ov%)Mq))Vj$h@rL$IOR&kzLk76u1e>Lj=ZvI^CuTJ<7&teD@tXnaYc^{)r4MYp zJs<2|h|q{QF{z-!u=fosaO=}2=c++ogbNG|>4iuc)l=B?L*IQH+A1vPn?2c9CL%7H z&fvJ{VQqV=Gj&*_dzG+$EdUh*Y>AzvL8iBl!7&Gzb1h4Kq|fG2kx zbHVQS3*BzaFXr3(%`QsBc-VFS5is=>DDSkXFsL+!(!P_%JAVGB4T?E48_}TA zrjY+#)vro*K6=a?J=1Pd3xA=-S&J63Fc;j^u`!-9SEy2;N<5yGy|RhSt#`NBdoXSY zFtKks1}^*5(yiOI9{d2u+bqn3`4{bU$08GViH#fo(5XEY`l|2F7eteuB6{dFi?Zwf za18}kpv4y=6AydU0R2OXte61$Wd=7EqeQA;M*Y9~`s%o`L3br6v5?yleFx$k|w_rA~l&HjVgANH)-GiPScn(z9~ zT4F6T_(>YwiMWTK4%w^{F73QxLxM>+gY#^Phy_SG47}E$Z}L0NYqlUE@Ua>yr+f!y zkMB-Xv-iJh5&Th;-G>Z+cVidPCJtD)4j7nzO+{_EVHF@$(p;c}hA(zRQ|_ok#5 zm}~$B#$c6}e=i7ZA`jC?N>bV~FR@zJn4Rlp0p2GG*J>}yi|}0KN(@Vp+ZKZ>U#Lyg zoBxy6R!h+$vR|U&ZhNnrjW`E_^41MM8V14(m>7oUMi0aRe$hVJlhumB(qu}lc0 z8L4x?;4ISRB00n5#_2=mRZxuODh_@fxok-un$fiTbOsJ=09#GJb5A?pLoJV3>fr0c zl?q!DG_zYxqSFM4b?s7CbUsWTrR%yU0O6({+`jEHGG|$%7&2E4K_;`l_239~JB+qA0 z$UDj7y}*yI`Nl)FOn9+=!~HG{u5?Xx=5*oaME9a<$@-@TxV-RFriiMW9rnBe)69k( z9O$ax#$ek4mDjOHy70wKutT_o3osJ#<)TZVf8eRv^neioxMTrCGjRQX>~`*x&>moi zVX}DR$IN_Z1np4|wbXX;vU??+&n|b=4GGcATX1P_U;T9H5a&*2H}*0307dO-kP4F; zxy__2Xr-XzC)xEIE)^~SS}+g(&Ys-8X^f z>wGFb{LwMcfGn{{U{D(ytrhk3nlv^oW6(cyVeZ&xWOM3fXR9HvXAc8nx0ZJ~M*wP@4tK~fI`&fQF0uFf+$|laHYl2-{1PvJ{ezHd< zLxJgb6uKESsG|RTXTsq@0hz-%M-huy>kkF)2pJDA489TX5(a(l4tKK7mm%@?!dR2L z@eKgb+c~Jme&fxb(%L!j{X(UJI1p+$+$#A^Kmk+;31J*l>VmL+nHfc-Y})mZxaC|g zCBzK*s;{Mqu6K#X!dx=Yg0Whx5X|maIq9<#2rX67=Q8abXw^QP0h+wi4%>71np(t6 z{|rEeHKVoV?p|=~Y9FnC%I4yI?Ljt9?3-#;u#e|AtxQ!p2aJ>dp?&hvI%$Uf+d7k^Wu2qE^IF?L|s{< zmghM^gs%4G`DY`}p_H$F1{5l26>n5Q9gvVjQl!lbzRFts!}2*tR!=4jD%Fd^&;%x% ze(1Mks$=Q8CNf-NJ6)Z6+@>Z>gWGU9Y)YUT-a+cqR=B8bve4<}C!{W{YsIV$i>gXPH3Y0O=Ecx9z+0j8qF9224iUBIp_VB_?Jw5UP5< zfE)K{4AO;LLN(?#%{x4i$73VGK6z?tmX`)}XODU{LhplwxA#cpKteErnck-KAy5XGQoQ+q%vrkR9p;5=pL|H8pj9+MN9oI6;+XIm zCK+XALiEfuCVIC`gONO&&{#N^_~eDX{%X+1z<#NWtdFNQTf7<=QEA z9}7bbX4SbMgUw2A79)p>{&Lg$6+^KA1>SR&Hrm1$G=EYGD&}^+DTS7p+sxRzCo7sb zLfM1HYBnlQz-O(rEcW*bx@x%8kl=FSH~@{=@)=u3*QUY8Ja5UHq)rsqL&3d(fk_4? zA&06B>v%a7BPRh7cv=3aCvFW`*4`XbYiE^6bB05kt(Nvw$Stz(XDp8r-~LZyVX-VN z@`dTKDKF?%23*6ptd!?j&&;i5v%y*QF7P>A3{MjuASa!fQ)cV}w3z?w}Az-I$IClD+%eRpFp}+is zvUweV#;;NbHPvd1O3%zUvV}$MW|J06=`9 zg;*);yW|GRqXHZR7>}|S*)pZ#C`2%CClv~GD&hANWwvuG?v6J#bb%OD#z+U-#R(}b z?M%C8SkHhLN&%bTwA|0}m#Z+B{?ulC-UkxIXIpERYju%T_w7z}tpNgq8vG&Y^=20CTYwYAD}yLGF~QAd|CNrQ$P=W~Q}pD_-1en8w|FF& z2dnOdXP_(v#4H67^)TE|Lm8W>2d}JnP9M|&2|*TvJZesKt$a$O^-!nX09PikndV`^ zBg1+=aJPDBWG);{w}Qd^!w?buyNF*VW^$-_6pCTImxx>&FQIq(AUGt1x?)y{P8(?} zh-vJy-)=$CBGB5|`dxs0rYNA$Dv`Y%fP|nf)K}p^*h^=>6#PjC-E?uXG{)StJzcp> z$#<=^oXy{CGntWxm|1?0Pw@F@a;xtOz%Ah?yA>n}SQOBpF#re`DYVV;o|xjUu-gYu zuYprXAg$fJpw8#8DIRNByV{=JtPDB%^y#ae?bbL`db?Une8(}(qjw}CSw8nrzn!H$G*&70>hF#2ZvhHIwwNR5gFnCc{+-_NBJzTP`#+~c05R|6p-ngA=zGg^tZzK50u2RdHfeWLsuZbn`uaaU4RP(B@j1wM?wFXUF=s>H886B$%+q5&R>NJ+COAl(>fJC2IY>4zvYy215GLW|2Z=`U$0IV0 zB~;|XQR%d{8mwT$CT94+R8(aKu?bXhHUTDO6e)owe&iuXZla}@_Ah115k_~S6yJl! zre1z92{BsdqVxHY1+RC82_J*qf5y9pk{RHfTNPH|ZjnnV8}hDiEKo8kij+(nD|dx3 z#`jVH1j-Xv{v6r%zu78GSh%TKtuW&)(Jo92xhc1Hs)#UAA99R#8m7+$&dfdt$L{KK z#5V@x+*6E-%CZ4E8SmcySc14tl3mLErXozs1fUmVP(1~>8llloYqjeoUS|z;Y81K9 zwmCi_kQMCh9XQgVjPxk{rL}e@M61dEM&WCU;7VBzT(7vIA`|S;zl>OL;h0cjFKM=X zHP9^oM&+-BF@OW`r_Ksxz<>E)wbvs7kZe#+k6MiUc&u^M*AtEOqxXXK2@h7e`p^$z`Nc6onddC zooVz^N0J_{brNvEh-Tk9-IJ|fGBVWK$n?Cp5VLT9_ukFY?N;?8;mK1?9Bi{KxIx2* z;|EH*E9Lx8_|5Ka>4=}Uj*#*0d_54I+$ElgWD4nxg)$qbd{t9UzY5l^n7gEgT-OR! zmaiKY)T(s@3n@#_91_hZ!?dz5q%h)P(`&f4M=%wQrAUy)nyoZ;f`k3AbGR6(>Kg72 zKU5{XZ!-}9!l0`feFn6N||p{_3(LCo7C?; z&C}^~!?RD>$*=1yNMG4xz>fW(Engi^U^?S$vu>4KEEErmZGUxsqWsl54bB_25>Y^n z*Uk~PUydAuS-jdMbb{$~j)>X-B*&EyFe~B5rFys$X_s7U`*X`UX8-EIE7 zda?2=Zil;D?~P2P?xwe#7X5;Ez6SGpbz+BT9>~Z&E&P@!qk16+SVq(~Vi=R7+_WU# z_|t5j@%G@348C32brnj+q2`ba;@bj8ho#F!pS5&ewIoEWp;8*Y=j)YKE~FX@gl|SsFri@-1L5iMflR#M zc;8R6+_5kqo(;tO(*Mc?A@OLW%9C(EqU+WFngc3XAkQfir!sj5P%TZssT8$7@!6Dg*R1zflDv4^p3TVmo7@X9zbMt$yDMS~` zmPfR5Prn;{I$Mh((b2RVe%=^9uT_9Pl@~9qs&a90vE`P9B8Kgh#h@%CJBYMi8c@XY zLpC*uKe*6`!C044YUIQqFsYJc)dhom(st-|ezLP)U6im1k4tPy#Pu5r5xHzSIs^3B zWxr#e&&fZUqyyxNAjP>hA% z4x%%;%wh<9=|_!H$L8QG6@c|^;0ZQ30bl<0P57zr-w`jR_#i6;fyV2)+%4%!>h z#|EhNCG8m9?vZ-V*|~5+S)n-j&)n*Xi{v*si{;D9cN~X8PQ(W%tc4qkhCU1TQOC#sJ0&JQhrv_6#pi80E3|V399NKcYuP3BCej792md1a+Rp zwzbh~&#+l%y=^K|As%N9Z9Y6!41IFqr%}$2G6#c~l|+?C+i&?Gq0jfx7$Gwxss3Y5 z%3%T(IiDA5xARWwtJ(BE4ZGTx4-f52f$Ar&8daPi{cGwp-*VROIQNjg_!NT9hlviQ z)Z<9BN%x&RoT1c}vR#>90bTOW8)NXNDBU|Ms_Y+2v+dv1HpQ`P(f+tvlx*~;l&=Wk$$Rw@-nL!@)Z_UPXePcb(FN?0|y0LRh zIl&^qTxkJ|9d;EvElMvUiji?5w*S?$s0f^cR;*KzMJgU z2--^{Vc@$RubPyybhwT*Ot!@~|6-0~P!;s~_7WDfZD{OWmxTBOIN&5D58Ln{Ubp{ZPh~SfEYO`+oD7xFFakV!txAvbz%V`20n@9TVMx z0So&Al}mZ1Idf51F52Vz+OvkCH&`m^B-=~WQVtN{wBYRHJX@nc0?5to2O+27BJW%{ zT^y{IlbUmKT-dqt5j4U}BQ%lqV7y5x;c>&OeTEQHFgQtwIs?YZaTk`t#nRxR8yMjcMJ}Q(ZG(&_66pq#r4N3@a|3grNGOzm;OtnX$vQb? zty|o_fH=m&-i`0$U?FEJeU`k8#=B!?^<01#8B-XyeZ&_M`y>Ru-KM+!Gm;PvWuv)^ zeqlnqE)*)rDjx1i>0GA>s>yk4Vu-5n2h;xf|NQ-T#{Inlb>Rn<5((f?F;oV{`rw{( zA*b5*y&uZlYq76~Cr^GuJe{=tVT!4e%a=^&GOp-aZr8F~3VI@R>0 zq|z~>4blW+NH5C!dN_XmQABW4t-JIq8vbZls^~^2nc18-idF>CG)L3 zTaiL!Bs%!P!Ck;w|=Sltw{D$9%D%X)5e)~B2CpU;2$Hxr~ zrFAZhhI2|g=We#2+XG;Iua?yC2fB!>Z|BxcOijNgRR<~sJ%(t#r;HA;FE}En;7jG# zwJf;wH_6N+sD0ZhMp275Yu8AMh;sPcC!)hnTxE!)>79`W>ItAIR{@$G7_9qkP_unjBX8v{c0s$|ib}$iQ_qCX{lA@$lK&33M+b+oV zZYV7TRNVmu;3Ac=gp?mmyAoMy54t2^zSzbFYPy%b6Py-!8u7yohhKPFh2Mby26ss& zT);x$0Y>nIEDJ>T4ZqcXKV)Q~>3Z>wL*I$mnJykrFQ;X;E-G?iOV!j;k#TS1Y|F+?Io;O!b-c742f_{O@H0H#{_3m!TYwD_mK|&-z z5@z;BhQ0n4kIXEe1Tm_bvYACm1f4uz684QYQl1tnr-pQIk*~i4y4nl+#>N53?gz24 z;_k2q{f!b)VipF~+q?=#)S;bI4b{t#O-EKn)UL0%dg*YgF!C1?Gl1VQ>8`B;e`rq> zuAVGRVzBmjc@#$;(_yHWi_{Tc#PoZGtN(&&lfMP^e&fLgR=9Euups$?S=V}5m7&>c z>hDu=sTH;k4-cZj=2g4RxX=`vJPiv{bu81gthRP=w z9u`Nz_t7%yvCf7IerKuk!m}QdeA5R?l|Hy%_x)1bI!&*m`ybdHOTLxzn(DayzL~FG z-J%NY+!(B{?nnz0%CU>o>;VTW2=B$@-W7`Ic>TM_NFv}VSutf{=J#^qtpDpe67YWr z`zrjU^%<_%8Lw}9B}djyj)-OH_c4Mjv@|1&h#cXk`O65VxIQ2+KoR)V6qmPXHc+>`iH%#h~x=6nb6p^k=b zR_>w50k|S$dhn;~sQ>1s^C8gb`sQD3?)~orUA>d6X`T7{vESaAszN*z7XL8eEr0y; z=^3RkOaAy0f}-TxnyDyZyYH*{&++K4wp5W!^*ew5;0#_!OWX~LjPO`nuUqrTI%^bi zEs!Kib0M*2$!Xd;d%V$;1N!}>D|haj*X4@SEHtF5tqyJ7xKYR2gCcO!J>_Ibz_T} zy%}TOycLD67iK@PRAYAW$+<}mY9aLZeRJ62hF9tid6I^ zKlqrLFPv=+#Wb993g0|>y`$A7octp(bilsy4IOr?!NqsY&bt(xl-D&bLl64xwW8dh zfgJHEYJARmR1@G77Z6uS0O^xb=0~+^A776j+h2~LT*>c0LsR+sG>_~O32a2VM)Y@QUv?X1Ybt1}L zH!eA}jZSjSV%Vt=5D)rb@B+ODM-^sIoa2Y>FR?D87!%njOVIY(q!zEr((SQf5yfT8EQ&dr=jdJC#z1U2BKf)qK0gZk{XT zvcYvVx!^*7NgNrZE5mG75y7XE$9Vdu2d;Xn)IS1#{ak_)a_Y_mbWMPr@F6$G>F!jA26fffAKTWlREJp&6Cl=s5Z}vXDF3hc9>>nBIJ6WiU3c zC*FZ?W`EI>9{x#?BdUJbw76Dt@*d)!%1QElBqMsx8<)nf`W@G4C4&QNReNjEk^f+~ zz+@}|=3dS4E1|i{*!HxBp{}mb;vOxLTRuaduZ|f^dJD{*=NIjf`%7()3ikFYj*HHw zjLJ~>^y;ccg?dV+Ul%Z>+Q z`14&>4v3WV>xdz%orRtGvs!!E`Puf{5CN$%`wTZk(i2M>afcpUU0Tlul2udtVMpO% zsLhwQ@gU@b9MT-E&$6d*XNGds>YNXyhGEDpDmi%p-_|fnK6nykP?jQ*CQj`54N+PP z2`lSqV>x$0OikT3yjAqK#&Vk&3H<2~f|UYq<&K$$*3YI_W(TFxe8&2T7v#Kdh#VYUB@9q<%~_i5eNt8Q<`EUq_*KPHa%Z{j#`vLW!=wR3r$DZfZ(J|LZ8XW{EecMP@{0A1Co3Uha(ax@B zE32ogT2wzp!v=BayS}CvvK~h02j1#fnA`PoZ$`QH8l%xCxg4mzD_+!Pea8B$Rl!&9 ziH6Li>q(S*m!()sm_^29v3br~wPJD9~ zl6Jd$T!fq!fRea8T_vSXWH7qoHaFNHG+?evtmvs7zMZ3e{!BttODYfPF{)F}#!i|!!o&yH zYah*ag=<+^TETBI1BP^$X+%U4jW+LX$&L?9%xD+p9twRjq@DL?hQ;oiOBQf+e?!Xm zNcT*c?tBCrNB10$LfS$bLSrcghvKR+(-*s;yUioz|M8FfO+P!-k2=XbB09;^o+rrb z$WPSPfXCK8=-l95H=)2CX&%6<3DrP6TtoTmSp6NYX582OV3;bA@5uOe6++jWU=0L| z_;FX}qOi}%BO8Ql)!I~i$tlD9MWdWqqr81c&-lo75&MtcNR)dz@g@s9|J=J>JIxtG zL%n=><@wVF*+x*;L&WWcuC~g&V^>vp*@_=mIa2D0_p5S$%O}THwv3`nXhxheBiYIj z>a{R$e$zQ5XX$35{gnZfLfZ9+xgIPJbHidJ&0RwU<}#%E!*!kON5{9XOVsJP)D^R} z_=w5S?1uC(j-#yUH*FK9+{oI5d$SHGagwb>=k+(TB;IWs5}Q^Nj~hA`EGghPiv94M zqzKz36~5667V^4||45Sm=G0f%IYyY^5Za@|FLRV9H!nR64Kb4yMx({i?ytlUWLZ$H zKGr-a{7|9ZfBd@3+m0?%{FzWx7o`vXI=XMG#SGIjT|f_l;a2_T#^DvT@yO2Wt^sOX zIExi~qX@cD^JhwSGNL?1qom(l*=Yy^oPWe3hO80dYIkl23sFYzy8}rn|oj&d< z2qs9tkF;3aj<;?8piI}}m}H#o<&ZYo>GAM)B}lNuWTSJ! zG8GQ^#YQIUBVji=GC$g*!_4LsH)N-{MoT=`=*(-+Hg7rh4W2ZK3!($72-aEZ_4+Pn zC$!^dbDS{?JN0A>I8Ef0VS64F3rfGjU)RwIb@eG|1*cWf>}?1T{NM|;hK(c>u8~*r zZNxX-yzi?$ri-a4!Z3B`xP8Uq2pZ5|)~s)eWzDt5@ZS-BLvuv>=}E@i?2)wccTNHm zbGS)GD9sS|Wen0W$z+~Z)MyFgCw1a-N_L@{lRZ9n#7bBy%^Y??SF7NfdY}tWal?_M z%c=#2m|G+^ZLZkRXx7*Ff)U0;W)9H~9p4YF=NU7f>GasXqrIqJZjJqLv#W{RWc*Qd zI8UuN?^pE*w~~_hhIQz(wdAQ5*l`bcp;fzbt@U(+lzrnm$w`tZSnwz!TbcCQWrOKx zW2%Va6zP!q;G5F->7iT&?*S|LaH-(o6nLruA(3oI>)gw5r?B-gB395Bc(! zR)r*Ykj;mbaZ8s z)_d(1!<3KmhKucK#2k--+ubuHVF^@mFPlFzob*338>3=vv3a@J znpubS7wO_>g#zrmJOL)FV+zwAN3Hwon}}8vg3C>Ql5;~VKt#k6aJR@$GGO=xXia1D z*^Pn8-!{c}U;(UI$sFvVZdAoJ_A|&(TYN=CO3T)3T)AI=2|CEhHYSj6dDSnKMsol`(E`%C?T2pGUbSs6O4Xv1-^1-Xq=q~#>4vA~Z?kkE}Dzr)Vy_G{%#9xLA3Xet; znqD!l^I4Kw(d|OPu_(O1v>nf9W7WtC`eWNxzT)trntRWMIMZFc zGwl+{8}|FPGK$0d+FW!l!WpCSS5$4ns-b8ssN0P^VkiHq&&P2?Bl)4w%Nr?{^9T^A z)LcTp`5P3%dIQ|lnMu&he}h63R(*x@88WG$JrU4No&7)Z5We#dpq*^WawtbaIut7p z$^g+)>Voz>xWgQ3lds+rK4;%hv8wiGg39c(BG_B9a*u1BQ<*RjTwXPzTz&XJRISlE zm|5DtMOd2i6mt&AsfC#?r!x44+}o~83WDxd(MY>fp}o0Bye<0pgXp@+4f9aZxQKga z8rk845US&t+sDxpX7PlPhU z#Rf%Q^alaHzHA5mUhHE`K1___EY1I7KNA8=h6XN++Z1FVrh?0lb zHLeksSeLpI^i7RjYP2a*=hXU|q6b#$h}o%?EZ`bN#EldEenWTlBp@n8{y8rpaxlTU z@|a92@rn?2qM%-%ijW+jnVx(jSBvy_?ci%p4IC7_#kt=R7g>w^n#4vx;7>*b0#_g+ z5hDD1*t&bj;&=Kph}}O+{eI#PC(OU^m4WQPhpGE}-M>pAAl%1B`<;S->_4UaHEi9# z%efB-_dB%!+5aQwZ(;2IUDCaC>EG!Z$o^B(@340NF6Hm-y2mB{Ddn$W?*3iQ-`fTG zFLM4K_U_*$-3Pw=owELmr2i8J@85;}y^|LHi?H8e@%~-P-#h6E(*NzGzlO>CL(ZR| z&R?Ul+&laJo#X*Izr*JJIfVZ#_t$VF_i-tHr)vNk`d=6hh~VDFICI2k-SC8g@ua6k#?@=-SEctI9&wp3>34jj&&HwqIQvPi3UtzI(#PN4x(fSws n@t-38`W?B)&wi&&?Z2UE3eqTm?{)+PJm4|}V7Q7e_jmsf0YL}W literal 0 HcmV?d00001 diff --git a/dreamcast2/regs/systembus/systembus_bits.ods b/dreamcast2/regs/systembus/systembus_bits.ods new file mode 100644 index 0000000000000000000000000000000000000000..20fade0d86f11ac5fa4d47f909f599bc3e233a54 GIT binary patch literal 15350 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 qyFlR|D1S`UKU +#include + +#include "type.hpp" + +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 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); + +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 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); + +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 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); + +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"); diff --git a/dreamcast2/sh7091/sh7091_bits.hpp b/dreamcast2/sh7091/sh7091_bits.hpp new file mode 100644 index 0000000..f6ac2c4 --- /dev/null +++ b/dreamcast2/sh7091/sh7091_bits.hpp @@ -0,0 +1,994 @@ +#pragma once + +#include + +namespace sh7091 { + namespace ccn { + namespace pteh { + constexpr uint32_t VPN(uint32_t reg) { return (reg >> 10) & 0x3fffff; } + constexpr uint32_t ASID(uint32_t reg) { return (reg >> 0) & 0xff; } + } + + namespace ptel { + constexpr uint32_t PPN(uint32_t reg) { return (reg >> 10) & 0x7ffff; } + + namespace v { + constexpr uint32_t invalid = 0 << 8; + constexpr uint32_t valid = 1 << 8; + + constexpr uint32_t bit_mask = 0x1 << 8; + } + + namespace sz { + constexpr uint32_t _1_kbyte_page = 0b0000 << 4; + constexpr uint32_t _4_kbyte_page = 0b0001 << 4; + constexpr uint32_t _64_kbyte_page = 0b1000 << 4; + constexpr uint32_t _1_mbyte_page = 0b1001 << 4; + + constexpr uint32_t bit_mask = 0x9 << 4; + } + + namespace pr { + constexpr uint32_t read_only_in_privileged_mode = 0b00 << 5; + constexpr uint32_t read_write_in_privileged_mode = 0b01 << 5; + constexpr uint32_t read_only_in_privileged_and_user_mode = 0b10 << 5; + constexpr uint32_t read_write_in_privileged_and_user_mode = 0b11 << 5; + + constexpr uint32_t bit_mask = 0x3 << 5; + } + + namespace c { + constexpr uint32_t not_cacheable = 0 << 3; + constexpr uint32_t cacheable = 1 << 3; + + constexpr uint32_t bit_mask = 0x1 << 3; + } + + namespace d { + constexpr uint32_t write_has_not_been_performed = 0 << 2; + constexpr uint32_t write_has_been_performed = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; + } + + namespace sh { + constexpr uint32_t pages_are_shared_by_processes = 0 << 1; + constexpr uint32_t pages_are_not_shared_by_processes = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; + } + + namespace wt { + constexpr uint32_t copy_back_mode = 0 << 0; + constexpr uint32_t write_through_mode = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace mmucr { + constexpr uint32_t LRUI(uint32_t reg) { return (reg >> 26) & 0x3f; } + constexpr uint32_t URB(uint32_t reg) { return (reg >> 18) & 0x3f; } + constexpr uint32_t URC(uint32_t reg) { return (reg >> 10) & 0x3f; } + + namespace sqmd { + constexpr uint32_t user_privileged_access_possible = 0 << 9; + constexpr uint32_t privileged_access_possible = 1 << 9; + + constexpr uint32_t bit_mask = 0x1 << 9; + } + + namespace sv { + constexpr uint32_t multiple_virtual_memory_mode = 0 << 8; + constexpr uint32_t single_virtual_memory_mode = 1 << 8; + + constexpr uint32_t bit_mask = 0x1 << 8; + } + + namespace ti { + constexpr uint32_t invalidate_all_utlb_itlb_bits = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; + } + + namespace at { + constexpr uint32_t mmu_disabled = 0 << 0; + constexpr uint32_t mmu_enabled = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace basra { + constexpr uint32_t basa(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace basrb { + constexpr uint32_t basa(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace ccr { + namespace iix { + constexpr uint32_t address_bits_12_5_used_for_ic_entry_selection = 0 << 15; + constexpr uint32_t address_bits_25_and_11_5_used_for_ic_entry_selection = 1 << 15; + + constexpr uint32_t bit_mask = 0x1 << 15; + } + + namespace ici { + constexpr uint32_t clear_v_bits_of_all_ic_entries = 1 << 11; + + constexpr uint32_t bit_mask = 0x1 << 11; + } + + namespace ice { + constexpr uint32_t ic_not_used = 0 << 8; + constexpr uint32_t ic_used = 1 << 8; + + constexpr uint32_t bit_mask = 0x1 << 8; + } + + namespace oix { + constexpr uint32_t address_bits_13_5_used_for_oc_entry_selection = 0 << 7; + constexpr uint32_t address_bits_25_and_12_5_used_for_oc_entry_selection = 1 << 7; + + constexpr uint32_t bit_mask = 0x1 << 7; + } + + namespace ora { + constexpr uint32_t _16_kbytes_used_as_cache = 0 << 5; + constexpr uint32_t _8_kbytes_used_as_cache_8_kbytes_used_as_ram = 1 << 5; + + constexpr uint32_t bit_mask = 0x1 << 5; + } + + namespace oci { + constexpr uint32_t clear_v_and_u_bits_of_all_oc_entries = 1 << 3; + + constexpr uint32_t bit_mask = 0x1 << 3; + } + + namespace cb { + constexpr uint32_t write_through_mode = 0 << 2; + constexpr uint32_t copy_back_mode = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; + } + + namespace wt { + constexpr uint32_t copy_back_mode = 0 << 1; + constexpr uint32_t write_through_mode = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; + } + + namespace oce { + constexpr uint32_t oc_not_used = 0 << 0; + constexpr uint32_t oc_used = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace tra { + constexpr uint32_t imm(uint32_t reg) { return (reg >> 2) & 0xff; } + } + + namespace expevt { + constexpr uint32_t exception_code(uint32_t reg) { return (reg >> 0) & 0xfff; } + } + + namespace intevt { + constexpr uint32_t exception_code(uint32_t reg) { return (reg >> 0) & 0xfff; } + } + + namespace ptea { + namespace tc { + constexpr uint32_t area_5_is_used = 0 << 3; + constexpr uint32_t area_6_is_used = 1 << 3; + + constexpr uint32_t bit_mask = 0x1 << 3; + } + + namespace sa { + constexpr uint32_t undefined = 0b000 << 0; + constexpr uint32_t variable_size_io_space = 0b001 << 0; + constexpr uint32_t _8_bit_io_space = 0b010 << 0; + constexpr uint32_t _16_bit_io_space = 0b011 << 0; + constexpr uint32_t _8_bit_common_memory_space = 0b100 << 0; + constexpr uint32_t _16_bit_common_memory_space = 0b101 << 0; + constexpr uint32_t _8_bit_attribute_memory_space = 0b110 << 0; + constexpr uint32_t _16_bit_attribute_memory_space = 0b111 << 0; + + constexpr uint32_t bit_mask = 0x7 << 0; + } + } + + namespace qacr0 { + constexpr uint32_t area(uint32_t num) { return (num & 0x7) << 2; } + } + + namespace qacr1 { + constexpr uint32_t area(uint32_t num) { return (num & 0x7) << 2; } + } + + } + + namespace dmac { + namespace dmatcr { + constexpr uint32_t transfer_count(uint32_t num) { return (num & 0xffffff) << 0; } + } + + namespace chcr { + namespace ssa { + constexpr uint32_t reserved_in_pcmcia_access = 0b000 << 29; + constexpr uint32_t dynamic_bus_sizing_io_space = 0b001 << 29; + constexpr uint32_t _8_bit_io_space = 0b010 << 29; + constexpr uint32_t _16_bit_io_space = 0b011 << 29; + constexpr uint32_t _8_bit_common_memory_space = 0b100 << 29; + constexpr uint32_t _16_bit_common_memory_space = 0b101 << 29; + constexpr uint32_t _8_bit_attribute_memory_space = 0b110 << 29; + constexpr uint32_t _16_bit_attribute_memory_space = 0b111 << 29; + + constexpr uint32_t bit_mask = 0x7 << 29; + } + + namespace stc { + constexpr uint32_t c5_space_wait_cycle_selection = 0 << 28; + constexpr uint32_t c6_space_wait_cycle_selection = 1 << 28; + + constexpr uint32_t bit_mask = 0x1 << 28; + } + + namespace dsa { + constexpr uint32_t reserved_in_pcmcia_access = 0b000 << 25; + constexpr uint32_t dynamic_bus_sizing_io_space = 0b001 << 25; + constexpr uint32_t _8_bit_io_space = 0b010 << 25; + constexpr uint32_t _16_bit_io_space = 0b011 << 25; + constexpr uint32_t _8_bit_common_memory_space = 0b100 << 25; + constexpr uint32_t _16_bit_common_memory_space = 0b101 << 25; + constexpr uint32_t _8_bit_attribute_memory_space = 0b110 << 25; + constexpr uint32_t _16_bit_attribute_memory_space = 0b111 << 25; + + constexpr uint32_t bit_mask = 0x7 << 25; + } + + namespace dtc { + constexpr uint32_t c5_space_wait_cycle_selection = 0 << 24; + constexpr uint32_t c6_space_wait_cycle_selection = 1 << 24; + + constexpr uint32_t bit_mask = 0x1 << 24; + } + + namespace ds { + constexpr uint32_t low_level_detection = 0 << 19; + constexpr uint32_t falling_edge_detection = 1 << 19; + + constexpr uint32_t bit_mask = 0x1 << 19; + } + + namespace rl { + constexpr uint32_t drak_is_an_active_high = 0 << 18; + constexpr uint32_t drak_is_an_active_low = 1 << 18; + + constexpr uint32_t bit_mask = 0x1 << 18; + } + + namespace am { + constexpr uint32_t dack_is_output_in_read_cycle = 0 << 17; + constexpr uint32_t dack_is_output_in_write_cycle = 1 << 17; + + constexpr uint32_t bit_mask = 0x1 << 17; + } + + namespace al { + constexpr uint32_t active_high_output = 0 << 16; + constexpr uint32_t active_low_output = 1 << 16; + + constexpr uint32_t bit_mask = 0x1 << 16; + } + + namespace dm { + constexpr uint32_t destination_address_fixed = 0b00 << 14; + constexpr uint32_t destination_address_incremented = 0b01 << 14; + constexpr uint32_t destination_address_decremented = 0b10 << 14; + + constexpr uint32_t bit_mask = 0x3 << 14; + } + + namespace sm { + constexpr uint32_t source_address_fixed = 0b00 << 12; + constexpr uint32_t source_address_incremented = 0b01 << 12; + constexpr uint32_t source_address_decremented = 0b10 << 12; + + constexpr uint32_t bit_mask = 0x3 << 12; + } + + namespace rs { + constexpr uint32_t resource_select(uint32_t num) { return (num & 0xf) << 8; } + + constexpr uint32_t bit_mask = 0xf << 8; + } + + namespace tm { + constexpr uint32_t cycle_steal_mode = 0 << 7; + constexpr uint32_t cycle_burst_mode = 1 << 7; + + constexpr uint32_t bit_mask = 0x1 << 7; + } + + namespace ts { + constexpr uint32_t _64_bit = 0b000 << 4; + constexpr uint32_t _8_bit = 0b001 << 4; + constexpr uint32_t _16_bit = 0b010 << 4; + constexpr uint32_t _32_bit = 0b011 << 4; + constexpr uint32_t _32_byte = 0b100 << 4; + + constexpr uint32_t bit_mask = 0x7 << 4; + } + + namespace ie { + constexpr uint32_t interrupt_request_not_generated = 0 << 2; + constexpr uint32_t interrupt_request_generated = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; + } + + namespace te { + constexpr uint32_t transfers_not_completed = 0 << 1; + constexpr uint32_t transfers_completed = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; + } + + namespace de { + constexpr uint32_t channel_operation_disabled = 0 << 0; + constexpr uint32_t channel_operation_enabled = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace dmaor { + namespace ddt { + constexpr uint32_t normal_dma_mode = 0 << 15; + constexpr uint32_t on_demand_data_transfer_mode = 1 << 15; + + constexpr uint32_t bit_mask = 0x1 << 15; + } + + namespace pr { + constexpr uint32_t ch0_ch1_ch2_ch3 = 0b00 << 8; + constexpr uint32_t ch0_ch2_ch3_ch1 = 0b01 << 8; + constexpr uint32_t ch2_ch0_ch1_ch3 = 0b10 << 8; + constexpr uint32_t round_robin = 0b11 << 8; + + constexpr uint32_t bit_mask = 0x3 << 8; + } + + namespace ae { + constexpr uint32_t no_address_error__dma_transfer_enabled = 0 << 2; + constexpr uint32_t address_error__dma_transfer_disabled = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; + } + + namespace nmif { + constexpr uint32_t no_nmi__dma_transfer_enabled = 0 << 1; + constexpr uint32_t nmi__dma_transfer_disabled = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; + } + + namespace dme { + constexpr uint32_t operation_disabled_on_all_channels = 0 << 0; + constexpr uint32_t operation_enabled_on_all_channels = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + } + + namespace intc { + namespace icr { + namespace nmil { + constexpr uint32_t pin_input_level_is_low = 0 << 15; + constexpr uint32_t pin_input_level_is_high = 1 << 15; + + constexpr uint32_t bit_mask = 0x1 << 15; + } + + namespace mai { + constexpr uint32_t interrupts_enabled_while_nmi_pin_is_low = 0 << 14; + constexpr uint32_t interrupts_disabled_while_nmi_pin_is_low = 1 << 14; + + constexpr uint32_t bit_mask = 0x1 << 14; + } + + namespace nmib { + constexpr uint32_t interrupt_requests_witheld = 0 << 9; + constexpr uint32_t interrupt_requests_detected = 1 << 9; + + constexpr uint32_t bit_mask = 0x1 << 9; + } + + namespace nmie { + constexpr uint32_t interrupt_on_falling_edge_of_nmi = 0 << 8; + constexpr uint32_t interrupt_on_rising_edge_of_nmi = 1 << 8; + + constexpr uint32_t bit_mask = 0x1 << 8; + } + + namespace irlm { + constexpr uint32_t level_encoded_interrupt_requests = 0 << 7; + constexpr uint32_t independent_interrupt_request = 1 << 7; + + constexpr uint32_t bit_mask = 0x1 << 7; + } + } + + namespace ipra { + constexpr uint32_t TMU0(uint32_t num) { return (num & 0xf) << 12; } + constexpr uint32_t TMU1(uint32_t num) { return (num & 0xf) << 8; } + constexpr uint32_t TMU2(uint32_t num) { return (num & 0xf) << 4; } + constexpr uint32_t RTC(uint32_t num) { return (num & 0xf) << 0; } + } + + namespace iprb { + constexpr uint32_t WDT(uint32_t num) { return (num & 0xf) << 12; } + constexpr uint32_t REF(uint32_t num) { return (num & 0xf) << 8; } + constexpr uint32_t SCI1(uint32_t num) { return (num & 0xf) << 4; } + } + + namespace iprc { + constexpr uint32_t GPIO(uint32_t num) { return (num & 0xf) << 12; } + constexpr uint32_t DMAC(uint32_t num) { return (num & 0xf) << 8; } + constexpr uint32_t SCIF(uint32_t num) { return (num & 0xf) << 4; } + constexpr uint32_t UDI(uint32_t num) { return (num & 0xf) << 0; } + } + + } + + namespace tmu { + namespace tocr { + namespace tcoe { + constexpr uint32_t tclk_is_external_clock_or_input_capture = 0 << 0; + constexpr uint32_t tclk_is_on_chip_rtc = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace tstr { + namespace str2 { + constexpr uint32_t counter_start = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; + } + + namespace str1 { + constexpr uint32_t counter_start = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; + } + + namespace str0 { + constexpr uint32_t counter_start = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace tcr0 { + constexpr uint32_t UNF = 1 << 8; + constexpr uint32_t UNIE = 1 << 5; + + namespace ckeg { + constexpr uint32_t rising = 0b00 << 3; + constexpr uint32_t falling = 0b01 << 3; + constexpr uint32_t rising_falling = 0b10 << 3; + + constexpr uint32_t bit_mask = 0x3 << 3; + } + + namespace tpsc { + constexpr uint32_t p_phi_4 = 0b000 << 0; + constexpr uint32_t p_phi_16 = 0b001 << 0; + constexpr uint32_t p_phi_64 = 0b010 << 0; + constexpr uint32_t p_phi_256 = 0b011 << 0; + constexpr uint32_t p_phi_1024 = 0b100 << 0; + constexpr uint32_t rtc_output = 0b110 << 0; + constexpr uint32_t external = 0b111 << 0; + + constexpr uint32_t bit_mask = 0x7 << 0; + } + } + + namespace tcr1 { + constexpr uint32_t UNF = 1 << 8; + constexpr uint32_t UNIE = 1 << 5; + + namespace ckeg { + constexpr uint32_t rising = 0b00 << 3; + constexpr uint32_t falling = 0b01 << 3; + constexpr uint32_t rising_falling = 0b10 << 3; + + constexpr uint32_t bit_mask = 0x3 << 3; + } + + namespace tpsc { + constexpr uint32_t p_phi_4 = 0b000 << 0; + constexpr uint32_t p_phi_16 = 0b001 << 0; + constexpr uint32_t p_phi_64 = 0b010 << 0; + constexpr uint32_t p_phi_256 = 0b011 << 0; + constexpr uint32_t p_phi_1024 = 0b100 << 0; + constexpr uint32_t rtc_output = 0b110 << 0; + constexpr uint32_t external = 0b111 << 0; + + constexpr uint32_t bit_mask = 0x7 << 0; + } + } + + namespace tcr2 { + constexpr uint32_t ICPF = 1 << 9; + constexpr uint32_t UNF = 1 << 8; + + namespace icpe { + constexpr uint32_t disabled = 0b00 << 6; + constexpr uint32_t enabled = 0b10 << 6; + constexpr uint32_t enabled_with_interrupts = 0b11 << 6; + + constexpr uint32_t bit_mask = 0x3 << 6; + } + + constexpr uint32_t UNIE = 1 << 5; + + namespace ckeg { + constexpr uint32_t rising = 0b00 << 3; + constexpr uint32_t falling = 0b01 << 3; + constexpr uint32_t rising_falling = 0b10 << 3; + + constexpr uint32_t bit_mask = 0x3 << 3; + } + + namespace tpsc { + constexpr uint32_t p_phi_4 = 0b000 << 0; + constexpr uint32_t p_phi_16 = 0b001 << 0; + constexpr uint32_t p_phi_64 = 0b010 << 0; + constexpr uint32_t p_phi_256 = 0b011 << 0; + constexpr uint32_t p_phi_1024 = 0b100 << 0; + constexpr uint32_t rtc_output = 0b110 << 0; + constexpr uint32_t external = 0b111 << 0; + + constexpr uint32_t bit_mask = 0x7 << 0; + } + } + + } + + namespace scif { + namespace scsmr2 { + namespace chr { + constexpr uint32_t _8_bit_data = 0 << 6; + constexpr uint32_t _7_bit_data = 1 << 6; + + constexpr uint32_t bit_mask = 0x1 << 6; + } + + namespace pe { + constexpr uint32_t parity_disabled = 0 << 5; + constexpr uint32_t parity_enabled = 1 << 5; + + constexpr uint32_t bit_mask = 0x1 << 5; + } + + namespace oe { + constexpr uint32_t even_parity = 0 << 4; + constexpr uint32_t odd_parity = 1 << 4; + + constexpr uint32_t bit_mask = 0x1 << 4; + } + + namespace stop { + constexpr uint32_t _1_stop_bit = 0 << 3; + constexpr uint32_t _2_stop_bits = 1 << 3; + + constexpr uint32_t bit_mask = 0x1 << 3; + } + + namespace cks { + constexpr uint32_t p_phi_clock = 0b00 << 0; + constexpr uint32_t p_phi_4_clock = 0b01 << 0; + constexpr uint32_t p_phi_16_clock = 0b10 << 0; + constexpr uint32_t p_phi_64_clock = 0b11 << 0; + + constexpr uint32_t bit_mask = 0x3 << 0; + } + } + + namespace scscr2 { + namespace tie { + constexpr uint32_t transmit_fifo_data_empty_interrupt_disabled = 0 << 7; + constexpr uint32_t transmit_fifo_data_empty_interrupt_enabled = 1 << 7; + + constexpr uint32_t bit_mask = 0x1 << 7; + } + + namespace rie { + constexpr uint32_t request_disabled = 0 << 6; + constexpr uint32_t request_enabled = 1 << 6; + + constexpr uint32_t bit_mask = 0x1 << 6; + } + + namespace te { + constexpr uint32_t transmission_disabled = 0 << 5; + constexpr uint32_t transmission_enabled = 1 << 5; + + constexpr uint32_t bit_mask = 0x1 << 5; + } + + namespace re { + constexpr uint32_t reception_disabled = 0 << 4; + constexpr uint32_t reception_enabled = 1 << 4; + + constexpr uint32_t bit_mask = 0x1 << 4; + } + + namespace reie { + constexpr uint32_t requests_disabled = 0 << 3; + constexpr uint32_t requests_enabled = 1 << 3; + + constexpr uint32_t bit_mask = 0x1 << 3; + } + + namespace cke1 { + constexpr uint32_t sck2_pin_functions_as_input_pin = 0 << 1; + constexpr uint32_t sck2_pin_functions_as_clock_input = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; + } + } + + namespace scfsr2 { + namespace per3_0 { + constexpr uint32_t number_of_parity_errors(uint32_t reg) { return (reg >> 12) & 0xf; } + + constexpr uint32_t bit_mask = 0xf << 12; + } + + namespace fer3_0 { + constexpr uint32_t number_of_framing_errors(uint32_t reg) { return (reg >> 8) & 0xf; } + + constexpr uint32_t bit_mask = 0xf << 8; + } + + namespace er { + constexpr uint32_t no_framing_error_or_parity_error = 0 << 7; + constexpr uint32_t framing_error_or_parity_error = 1 << 7; + + constexpr uint32_t bit_mask = 0x1 << 7; + } + + namespace tend { + constexpr uint32_t transmission_in_progress = 0 << 6; + constexpr uint32_t transmission_has_ended = 1 << 6; + + constexpr uint32_t bit_mask = 0x1 << 6; + } + + namespace tdfe { + constexpr uint32_t transmit_data_bytes_does_exceed_trigger = 0 << 5; + constexpr uint32_t transmit_data_bytes_does_not_exceed_trigger = 1 << 5; + + constexpr uint32_t bit_mask = 0x1 << 5; + } + + namespace brk { + constexpr uint32_t break_not_received = 0 << 4; + constexpr uint32_t break_received = 1 << 4; + + constexpr uint32_t bit_mask = 0x1 << 4; + } + + namespace fer { + constexpr uint32_t no_framing_error = 0 << 3; + constexpr uint32_t framing_error = 1 << 3; + + constexpr uint32_t bit_mask = 0x1 << 3; + } + + namespace per { + constexpr uint32_t parity_error = 0 << 2; + constexpr uint32_t no_parity_error = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; + } + + namespace rdf { + constexpr uint32_t receive_data_bytes_less_than_receive_trigger = 0 << 1; + constexpr uint32_t receive_data_bytes_greater_than_or_equal_receive_trigger = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; + } + + namespace dr { + constexpr uint32_t reception_is_in_progress = 0 << 0; + constexpr uint32_t no_further_data_has_arrived = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace scfcr2 { + namespace rtrg { + constexpr uint32_t trigger_on_1_byte = 0b00 << 6; + constexpr uint32_t trigger_on_4_bytes = 0b01 << 6; + constexpr uint32_t trigger_on_8_bytes = 0b10 << 6; + constexpr uint32_t trigger_on_14_byte = 0b11 << 6; + + constexpr uint32_t bit_mask = 0x3 << 6; + } + + namespace ttrg { + constexpr uint32_t trigger_on_8_bytes = 0b00 << 4; + constexpr uint32_t trigger_on_4_bytes = 0b01 << 4; + constexpr uint32_t trigger_on_2_bytes = 0b10 << 4; + constexpr uint32_t trigger_on_1_bytes = 0b11 << 4; + + constexpr uint32_t bit_mask = 0x3 << 4; + } + + namespace mce { + constexpr uint32_t modem_signals_disabled = 0 << 3; + constexpr uint32_t modem_signals_enabled = 1 << 3; + + constexpr uint32_t bit_mask = 0x1 << 3; + } + + namespace tfrst { + constexpr uint32_t reset_operation_disabled = 0 << 2; + constexpr uint32_t reset_operation_enabled = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; + } + + namespace rfrst { + constexpr uint32_t reset_operation_disabled = 0 << 1; + constexpr uint32_t reset_operation_enabled = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; + } + + namespace loop { + constexpr uint32_t loopback_test_disabled = 0 << 0; + constexpr uint32_t loopback_test_enabled = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace scfdr2 { + constexpr uint32_t transmit_data_bytes(uint32_t reg) { return (reg >> 8) & 0x1f; } + constexpr uint32_t receive_data_bytes(uint32_t reg) { return (reg >> 0) & 0x1f; } + } + + namespace scsptr2 { + namespace rtsio { + constexpr uint32_t rtsdt_not_output_to_rts2 = 0 << 7; + constexpr uint32_t rtsdt_output_to_rts2 = 1 << 7; + + constexpr uint32_t bit_mask = 0x1 << 7; + } + + namespace rtsdt { + constexpr uint32_t input_output_data_is_low_level = 0 << 6; + constexpr uint32_t input_output_data_is_high_level = 1 << 6; + + constexpr uint32_t bit_mask = 0x1 << 6; + } + + namespace ctsio { + constexpr uint32_t ctsdt_is_not_output_to_cts2 = 0 << 5; + constexpr uint32_t ctsdt_is_output_to_cts2 = 1 << 5; + + constexpr uint32_t bit_mask = 0x1 << 5; + } + + namespace ctsdt { + constexpr uint32_t input_output_data_is_low_level = 0 << 4; + constexpr uint32_t input_output_data_is_high_level = 1 << 4; + + constexpr uint32_t bit_mask = 0x1 << 4; + } + + namespace spb2io { + constexpr uint32_t spb2dt_is_not_output_to_txd2 = 0 << 1; + constexpr uint32_t spb2dt_is_output_to_txd2 = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; + } + + namespace spb2dt { + constexpr uint32_t input_output_data_is_low_level = 0 << 0; + constexpr uint32_t input_output_data_is_high_level = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace sclsr2 { + namespace orer { + constexpr uint32_t overrun_error_occured = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + } + + namespace sh { + namespace sr { + constexpr uint32_t md = 1 << 30; + constexpr uint32_t rb = 1 << 29; + constexpr uint32_t bl = 1 << 28; + constexpr uint32_t fd = 1 << 15; + constexpr uint32_t m = 1 << 9; + constexpr uint32_t q = 1 << 8; + constexpr uint32_t imask(uint32_t num) { return (num & 0xf) << 4; } + constexpr uint32_t s = 1 << 1; + constexpr uint32_t t = 1 << 0; + } + + namespace fpscr { + constexpr uint32_t fr = 1 << 21; + constexpr uint32_t sz = 1 << 20; + constexpr uint32_t pr = 1 << 19; + constexpr uint32_t dn = 1 << 18; + + namespace cause { + constexpr uint32_t fpu_error = 0b100000 << 12; + constexpr uint32_t invalid_operation = 0b010000 << 12; + constexpr uint32_t division_by_zero = 0b001000 << 12; + constexpr uint32_t overflow = 0b000100 << 12; + constexpr uint32_t underflow = 0b000010 << 12; + constexpr uint32_t inexact = 0b000001 << 12; + + constexpr uint32_t bit_mask = 0x3f << 12; + } + + namespace enabled { + constexpr uint32_t invalid_operation = 0b10000 << 7; + constexpr uint32_t division_by_zero = 0b01000 << 7; + constexpr uint32_t overflow = 0b00100 << 7; + constexpr uint32_t underflow = 0b00010 << 7; + constexpr uint32_t inexact = 0b00001 << 7; + + constexpr uint32_t bit_mask = 0x1f << 7; + } + + namespace flag { + constexpr uint32_t invalid_operation = 0b10000 << 2; + constexpr uint32_t division_by_zero = 0b01000 << 2; + constexpr uint32_t overflow = 0b00100 << 2; + constexpr uint32_t underflow = 0b00010 << 2; + constexpr uint32_t inexact = 0b00001 << 2; + + constexpr uint32_t bit_mask = 0x1f << 2; + } + + namespace rm { + constexpr uint32_t round_to_nearest = 0b00 << 0; + constexpr uint32_t round_to_zero = 0b01 << 0; + + constexpr uint32_t bit_mask = 0x3 << 0; + } + } + + } + + namespace ubc { + namespace bamra { + namespace bama { + constexpr uint32_t all_bara_bits_are_included_in_break_conditions = 0b0000 << 0; + constexpr uint32_t lower_10_bits_of_bara_are_not_included_in_break_conditions = 0b0001 << 0; + constexpr uint32_t lower_12_bits_of_bara_are_not_included_in_break_conditions = 0b0010 << 0; + constexpr uint32_t all_bara_bits_are_not_included_in_break_conditions = 0b0011 << 0; + constexpr uint32_t lower_16_bits_of_bara_are_not_included_in_break_conditions = 0b1000 << 0; + constexpr uint32_t lower_20_bits_of_bara_are_not_included_in_break_conditions = 0b1001 << 0; + + constexpr uint32_t bit_mask = 0xb << 0; + } + + namespace basma { + constexpr uint32_t all_basra_bits_are_included_in_break_conditions = 0 << 2; + constexpr uint32_t no_basra_bits_are_included_in_break_conditions = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; + } + } + + namespace bbra { + namespace sza { + constexpr uint32_t operand_size_is_not_included_in_break_conditions = 0b00 << 0; + constexpr uint32_t byte_access_is_used_as_break_condition = 0b01 << 0; + constexpr uint32_t word_access_is_used_as_break_condition = 0b10 << 0; + constexpr uint32_t longword_access_is_used_as_break_condition = 0b11 << 0; + constexpr uint32_t quadword_access_is_used_as_break_condition = 0b1000000 << 0; + + constexpr uint32_t bit_mask = 0x43 << 0; + } + + namespace ida { + constexpr uint32_t condition_comparison_is_not_performed = 0b00 << 4; + constexpr uint32_t instruction_access_cycle_is_used_as_break_condition = 0b01 << 4; + constexpr uint32_t operand_access_cycle_is_used_as_break_condition = 0b10 << 4; + constexpr uint32_t instruction_access_cycle_or_operand_access_cycle_is_used_as_break_condition = 0b11 << 4; + + constexpr uint32_t bit_mask = 0x3 << 4; + } + + namespace rwa { + constexpr uint32_t condition_comparison_is_not_performed = 0b00 << 2; + constexpr uint32_t read_cycle_is_used_as_break_condition = 0b01 << 2; + constexpr uint32_t write_cycle_is_used_as_break_condition = 0b10 << 2; + constexpr uint32_t read_cycle_or_write_cycle_is_used_as_break_condition = 0b11 << 2; + + constexpr uint32_t bit_mask = 0x3 << 2; + } + } + + namespace brcr { + namespace cmfa { + constexpr uint32_t channel_a_break_condition_is_not_matched = 0 << 15; + constexpr uint32_t channel_a_break_condition_match_has_occured = 1 << 15; + + constexpr uint32_t bit_mask = 0x1 << 15; + } + + namespace cmfb { + constexpr uint32_t channel_b_break_condition_is_not_matched = 0 << 14; + constexpr uint32_t channel_b_break_condition_match_has_occured = 1 << 14; + + constexpr uint32_t bit_mask = 0x1 << 14; + } + + namespace pcba { + constexpr uint32_t channel_a_pc_break_is_effected_before_instruction_execution = 0 << 10; + constexpr uint32_t channel_a_pc_break_is_effected_after_instruction_execution = 1 << 10; + + constexpr uint32_t bit_mask = 0x1 << 10; + } + + namespace dbeb { + constexpr uint32_t data_bus_condition_is_not_included_in_channel_b_conditions = 0 << 7; + constexpr uint32_t data_bus_condition_is_included_in_channel_b_conditions = 1 << 7; + + constexpr uint32_t bit_mask = 0x1 << 7; + } + + namespace pcbb { + constexpr uint32_t channel_b_pc_break_is_effected_before_instruction_execution = 0 << 6; + constexpr uint32_t channel_b_pc_break_is_effected_after_instruction_execution = 1 << 6; + + constexpr uint32_t bit_mask = 0x1 << 6; + } + + namespace seq { + constexpr uint32_t channel_a_and_b_comparison_are_performed_as_independent_condition = 0 << 3; + constexpr uint32_t channel_a_and_b_comparison_are_performed_as_sequential_condition = 1 << 3; + + constexpr uint32_t bit_mask = 0x1 << 3; + } + + namespace ubde { + constexpr uint32_t user_break_debug_function_is_not_used = 0 << 0; + constexpr uint32_t user_break_debug_function_is_used = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + } +} diff --git a/dreamcast2/sh7091/store_queue_transfer.hpp b/dreamcast2/sh7091/store_queue_transfer.hpp new file mode 100644 index 0000000..9c3a25b --- /dev/null +++ b/dreamcast2/sh7091/store_queue_transfer.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include "sh7091/sh7091.hpp" +#include "memorymap.hpp" + +namespace sh7091 { + namespace store_queue_transfer { + + static inline void copy(void * out_addr, + const void * src, + int length) + { + uint32_t out = reinterpret_cast(out_addr); + sh7091.CCN.QACR0 = ((out >> 24) & 0b11100); + sh7091.CCN.QACR1 = ((out >> 24) & 0b11100); + + volatile uint32_t * base = &store_queue[(out & 0x03ffffe0)]; + const uint32_t * src32 = reinterpret_cast(src); + + length = (length + 31) & ~31; // round up to nearest multiple of 32 + while (length > 0) { + base[0] = src32[0]; + base[1] = src32[1]; + base[2] = src32[2]; + base[3] = src32[3]; + base[4] = src32[4]; + base[5] = src32[5]; + base[6] = src32[6]; + base[7] = src32[7]; + asm volatile ("pref @%0" + : // output + : "r" (&base[0]) // input + : "memory"); + length -= 32; + base += 8; + src32 += 8; + } + } + + + static inline void zeroize(void * out_addr, + int length, + const uint32_t value) + { + uint32_t out = reinterpret_cast(out_addr); + sh7091.CCN.QACR0 = ((out >> 24) & 0b11100); + sh7091.CCN.QACR1 = ((out >> 24) & 0b11100); + + volatile uint32_t * base = &store_queue[(out & 0x03ffffe0)]; + + length = (length + 31) & ~31; // round up to nearest multiple of 32 + while (length > 0) { + base[0] = value; + base[1] = value; + base[2] = value; + base[3] = value; + base[4] = value; + base[5] = value; + base[6] = value; + base[7] = value; + asm volatile ("pref @%0" + : // output + : "r" (&base[0]) // input + : "memory"); + length -= 32; + base += 8; + } + } + } +} diff --git a/dreamcast2/systembus/systembus.hpp b/dreamcast2/systembus/systembus.hpp new file mode 100644 index 0000000..efbc170 --- /dev/null +++ b/dreamcast2/systembus/systembus.hpp @@ -0,0 +1,308 @@ +#pragma once + +#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 */ +}; + +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 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); + +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");