From 18c906133cae41fc9e34a8da37957c0cc31a6f0c Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Tue, 26 Aug 2025 16:45:42 -0500 Subject: [PATCH] dreamcast2: add triangle_ta --- dreamcast2/example/example.mk | 8 +- dreamcast2/example/triangle_core.cpp | 4 +- dreamcast2/example/triangle_ta.cpp | 287 ++++++++++ dreamcast2/holly/core/object_list_bits.hpp | 18 +- dreamcast2/holly/core/parameter.hpp | 2 + dreamcast2/holly/core/parameter_bits.hpp | 10 +- dreamcast2/holly/core/region_array_bits.hpp | 6 +- dreamcast2/holly/holly_bits.hpp | 248 ++++----- dreamcast2/holly/ta/global_parameter.hpp | 240 ++++++++ dreamcast2/holly/ta/parameter_bits.hpp | 78 +++ dreamcast2/holly/ta/vertex_parameter.hpp | 512 ++++++++++++++++++ dreamcast2/memorymap.hpp | 2 + dreamcast2/regs.mk | 17 +- dreamcast2/regs/generic_sparse_struct.py | 126 +++++ dreamcast2/regs/holly/ta/global_parameter.ods | Bin 0 -> 21537 bytes dreamcast2/regs/holly/ta/parameter_bits.ods | Bin 0 -> 24788 bytes dreamcast2/regs/holly/ta/vertex_parameter.ods | Bin 0 -> 16833 bytes dreamcast2/regs/render_bits.py | 4 +- dreamcast2/regs/render_ta_parameter_struct.py | 68 +++ dreamcast2/regs/sh7091/sh7091_bits.ods | Bin 26732 -> 28268 bytes dreamcast2/sh7091/pref.hpp | 14 + dreamcast2/sh7091/sh7091_bits.hpp | 62 +-- dreamcast2/sh7091/store_queue_transfer.hpp | 11 +- dreamcast2/systembus/systembus_bits.hpp | 10 +- tools/ftdi_transfer.cpp | 43 ++ 25 files changed, 1576 insertions(+), 194 deletions(-) create mode 100644 dreamcast2/example/triangle_ta.cpp create mode 100644 dreamcast2/holly/ta/global_parameter.hpp create mode 100644 dreamcast2/holly/ta/parameter_bits.hpp create mode 100644 dreamcast2/holly/ta/vertex_parameter.hpp create mode 100644 dreamcast2/regs/generic_sparse_struct.py create mode 100644 dreamcast2/regs/holly/ta/global_parameter.ods create mode 100644 dreamcast2/regs/holly/ta/parameter_bits.ods create mode 100644 dreamcast2/regs/holly/ta/vertex_parameter.ods create mode 100644 dreamcast2/regs/render_ta_parameter_struct.py create mode 100644 dreamcast2/sh7091/pref.hpp diff --git a/dreamcast2/example/example.mk b/dreamcast2/example/example.mk index 0934c88..fa6234d 100644 --- a/dreamcast2/example/example.mk +++ b/dreamcast2/example/example.mk @@ -9,8 +9,14 @@ example/framebuffer_shaded.elf: LDSCRIPT = $(LIB)/main.lds example/framebuffer_shaded.elf: $(START_OBJ) $(FRAMEBUFFER_SHADED_OBJ) TRIANGLE_CORE_OBJ = \ - holly/core/region_array.o \ example/triangle_core.o example/triangle_core.elf: LDSCRIPT = $(LIB)/main.lds example/triangle_core.elf: $(START_OBJ) $(TRIANGLE_CORE_OBJ) + + +TRIANGLE_TA_OBJ = \ + example/triangle_ta.o + +example/triangle_ta.elf: LDSCRIPT = $(LIB)/main.lds +example/triangle_ta.elf: $(START_OBJ) $(TRIANGLE_TA_OBJ) diff --git a/dreamcast2/example/triangle_core.cpp b/dreamcast2/example/triangle_core.cpp index b9cc291..daaddb2 100644 --- a/dreamcast2/example/triangle_core.cpp +++ b/dreamcast2/example/triangle_core.cpp @@ -135,8 +135,8 @@ void main() using polygon = holly::core::parameter::isp_tsp_parameter<3>; - uint32_t triangle_offset = (sizeof (polygon)) * 0; - uint32_t background_offset = (sizeof (polygon)) * 1; + uint32_t background_offset = (sizeof (polygon)) * 0; + uint32_t triangle_offset = (sizeof (polygon)) * 1; transfer_object_list(object_list_start, triangle_offset); diff --git a/dreamcast2/example/triangle_ta.cpp b/dreamcast2/example/triangle_ta.cpp new file mode 100644 index 0000000..4e1f227 --- /dev/null +++ b/dreamcast2/example/triangle_ta.cpp @@ -0,0 +1,287 @@ +#include "memorymap.hpp" + +#include "holly/core/object_list_bits.hpp" +#include "holly/core/region_array.hpp" +#include "holly/core/region_array_bits.hpp" +#include "holly/core/parameter_bits.hpp" +#include "holly/core/parameter.hpp" +#include "holly/ta/global_parameter.hpp" +#include "holly/ta/vertex_parameter.hpp" +#include "holly/ta/parameter_bits.hpp" +#include "holly/holly.hpp" +#include "holly/holly_bits.hpp" + +#include "sh7091/sh7091.hpp" +#include "sh7091/pref.hpp" + +void transfer_background_polygon(uint32_t isp_tsp_parameter_start) +{ + using namespace holly::core::parameter; + + using parameter = isp_tsp_parameter<3>; + + volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start]; + + polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always + | isp_tsp_instruction_word::culling_mode::no_culling; + + polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one + | tsp_instruction_word::dst_alpha_instr::zero + | tsp_instruction_word::fog_control::no_fog; + + polygon->texture_control_word = 0; + + polygon->vertex[0].x = 0.0f; + polygon->vertex[0].y = 0.0f; + polygon->vertex[0].z = 0.00001f; + polygon->vertex[0].base_color = 0xff00ff; + + polygon->vertex[1].x = 32.0f; + polygon->vertex[1].y = 0.0f; + polygon->vertex[1].z = 0.00001f; + polygon->vertex[1].base_color = 0xff00ff; + + polygon->vertex[2].x = 32.0f; + polygon->vertex[2].y = 32.0f; + polygon->vertex[2].z = 0.00001f; + polygon->vertex[2].base_color = 0xff00ff; +} + +void transfer_ta_triangle() +{ + using namespace sh7091; + using sh7091::sh7091; + + sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(ta_fifo_polygon_converter); + sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(ta_fifo_polygon_converter); + + uint32_t store_queue_ix = 0; + + using namespace holly::core::parameter; + using namespace holly::ta; + using namespace holly::ta::parameter; + + // + // TA polygon global transfer + // + + volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix]; + store_queue_ix += (sizeof (global_parameter::polygon_type_0)); + + polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume + | parameter_control_word::list_type::opaque + | parameter_control_word::col_type::packed_color + | parameter_control_word::gouraud; + + polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always + | isp_tsp_instruction_word::culling_mode::no_culling; + + + polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one + | tsp_instruction_word::dst_alpha_instr::zero + | tsp_instruction_word::fog_control::no_fog; + + pref(polygon); + + // + // TA polygon vertex transfer + // + + volatile vertex_parameter::polygon_type_0 * vertex = (volatile vertex_parameter::polygon_type_0 *)&store_queue[store_queue_ix]; + store_queue_ix += (sizeof (vertex_parameter::polygon_type_0)) * 3; + + // bottom left + vertex[0].parameter_control_word = parameter_control_word::para_type::vertex_parameter; + vertex[0].x = 1.0f; + vertex[0].y = 29.0f; + vertex[0].z = 0.1f; + vertex[0].base_color = 0xff0000; // red + + // start store queue transfer of `vertex[0]` to the TA + pref(&vertex[0]); + + // top center + vertex[1].parameter_control_word = parameter_control_word::para_type::vertex_parameter; + vertex[1].x = 16.0f; + vertex[1].y = 3.0f; + vertex[1].z = 0.1f; + vertex[1].base_color = 0x00ff00; // green + + // start store queue transfer of `vertex[1]` to the TA + pref(&vertex[1]); + + // bottom right + vertex[2].parameter_control_word = parameter_control_word::para_type::vertex_parameter + | parameter_control_word::end_of_strip; + vertex[2].x = 31.0f; + vertex[2].y = 29.0f; + vertex[2].z = 0.1f; + vertex[2].base_color = 0x0000ff; // blue + + // start store queue transfer of `params[2]` to the TA + pref(&vertex[2]); + + // + // TA "end of list" global transfer + // + volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix]; + store_queue_ix += (sizeof (global_parameter::end_of_list)); + + end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list; + + // start store queue transfer of `end_of_list` to the TA + pref(end_of_list); +} + +void transfer_region_array(uint32_t region_array_start, + uint32_t opaque_list_pointer) +{ + using namespace holly::core::region_array; + /* + Create a minimal region array with a single entry: + - one tile at tile coordinate (0, 0) with one opaque list pointer + */ + + /* + Holly reads the region array from "32-bit" texture memory address space, + so the region array is correspondingly written from "32-bit" address space. + */ + volatile region_array_entry * region_array = (volatile region_array_entry *)&texture_memory32[region_array_start]; + + region_array[0].tile + = tile::last_region + | tile::y_position(0) + | tile::x_position(0); + + /* + list pointers are offsets relative to the beginning of "32-bit" texture memory. + + each list type uses different rasterization steps, "opaque" being the fastest and most efficient. + */ + region_array[0].list_pointer.opaque = list_pointer::object_list(opaque_list_pointer); + region_array[0].list_pointer.opaque_modifier_volume = list_pointer::empty; + region_array[0].list_pointer.translucent = list_pointer::empty; + region_array[0].list_pointer.translucent_modifier_volume = list_pointer::empty; + region_array[0].list_pointer.punch_through = list_pointer::empty; +} + +void main() +{ + /* + a very simple memory map: + + the ordering within texture memory is not significant, and could be + anything + */ + uint32_t framebuffer_start = 0x200000; // intentionally the same address that the boot rom used to draw the SEGA logo + uint32_t isp_tsp_parameter_start = 0x400000; + uint32_t region_array_start = 0x500000; + uint32_t object_list_start = 0x100000; + + transfer_region_array(region_array_start, + object_list_start); + + transfer_background_polygon(isp_tsp_parameter_start); + + ////////////////////////////////////////////////////////////////////////////// + // configure the TA + ////////////////////////////////////////////////////////////////////////////// + + const int tile_y_num = 1; + const int tile_x_num = 1; + + using namespace holly; + using holly::holly; + + // TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written + // to. + // + // This can also be used to implement "windowing", as long as the desired + // window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA + // control parameter can also ~equivalently be used as many times as desired + // within a single TA initialization to produce an identical effect. + // + // See DCDBSysArc990907E.pdf page 183. + holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1) + | ta_glob_tile_clip::tile_x_num(tile_x_num - 1); + + // While CORE supports arbitrary-length object lists, the TA uses "object + // pointer blocks" as a memory allocation strategy. These fixed-length blocks + // can still have infinite length via "object pointer block links". This + // mechanism is illustrated in DCDBSysArc990907E.pdf page 188. + holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses + | ta_alloc_ctrl::o_opb::_8x4byte; + + // While building object lists, the TA contains an internal index (exposed as + // the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be + // stored at. The initial value of this index is TA_ISP_BASE. + + // reserve space in ISP/TSP parameters for the background parameter + using polygon = holly::core::parameter::isp_tsp_parameter<3>; + uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1; + + holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset; + holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x100000; + + // Similarly, the TA also contains, for up to 600 tiles, an internal index for + // the next address that an object list entry will be stored for each + // tile. These internal indicies are partially exposed via the read-only + // TA_OL_POINTERS. + holly.TA_OL_BASE = object_list_start; + + // TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385: + // + // > Because the TA may automatically store data in the address that is + // > specified by this register, it must not be used for other data. For + // > example, the address specified here must not be the same as the address + // > in the TA_ISP_BASE register. + holly.TA_OL_LIMIT = object_list_start + 0x100000 - 32; + + holly.TA_LIST_INIT = ta_list_init::list_init; + + // dummy TA_LIST_INIT read; DCDBSysArc990907E.pdf in multiple places says this + // step is required. + (void)holly.TA_LIST_INIT; + + ////////////////////////////////////////////////////////////////////////////// + // transfer triangles to texture memory via the TA polygon converter FIFO + ////////////////////////////////////////////////////////////////////////////// + + transfer_ta_triangle(); + + ////////////////////////////////////////////////////////////////////////////// + // configure CORE + ////////////////////////////////////////////////////////////////////////////// + + // REGION_BASE is the (texture memory-relative) address of the region array. + holly.REGION_BASE = region_array_start; + + // PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters. + // Anything that references an ISP/TSP parameter does so relative to this + // address (and not relative to the beginning of texture memory). + holly.PARAM_BASE = isp_tsp_parameter_start; + + // Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE + // SKIP is related to the size of each vertex + uint32_t background_offset = 0; + + holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4) + | isp_backgnd_t::tag_offset(0) + | isp_backgnd_t::skip(1); + + // FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that + // will be written to when a tile is rendered/flushed. + holly.FB_W_SOF1 = framebuffer_start; + + // start the actual render--the rendering process begins by interpreting the + // region array + holly.STARTRENDER = 1; + + // without waiting for rendering to actually complete, immediately display the + // framebuffer. + holly.FB_R_SOF1 = framebuffer_start; + + // return from main; this will effectively jump back to the serial loader + + while (1); +} diff --git a/dreamcast2/holly/core/object_list_bits.hpp b/dreamcast2/holly/core/object_list_bits.hpp index 78256a5..8e9b23d 100644 --- a/dreamcast2/holly/core/object_list_bits.hpp +++ b/dreamcast2/holly/core/object_list_bits.hpp @@ -25,27 +25,27 @@ namespace holly::core::object_list { } constexpr uint32_t shadow = 1 << 24; - constexpr uint32_t skip(uint32_t num) { return (num & 0x7) << 21; } - constexpr uint32_t start(uint32_t num) { return (num & 0x1fffff) << 0; } + constexpr inline uint32_t skip(uint32_t num) { return (num & 0x7) << 21; } + constexpr inline uint32_t start(uint32_t num) { return (num & 0x1fffff) << 0; } } namespace triangle_array { - constexpr uint32_t number_of_triangles(uint32_t num) { return (num & 0xf) << 25; } + constexpr inline uint32_t number_of_triangles(uint32_t num) { return (num & 0xf) << 25; } constexpr uint32_t shadow = 1 << 24; - constexpr uint32_t skip(uint32_t num) { return (num & 0x7) << 21; } - constexpr uint32_t start(uint32_t num) { return (num & 0x1fffff) << 0; } + constexpr inline uint32_t skip(uint32_t num) { return (num & 0x7) << 21; } + constexpr inline uint32_t start(uint32_t num) { return (num & 0x1fffff) << 0; } } namespace quad_array { - constexpr uint32_t number_of_quads(uint32_t num) { return (num & 0xf) << 25; } + constexpr inline uint32_t number_of_quads(uint32_t num) { return (num & 0xf) << 25; } constexpr uint32_t shadow = 1 << 24; - constexpr uint32_t skip(uint32_t num) { return (num & 0x7) << 21; } - constexpr uint32_t start(uint32_t num) { return (num & 0x1fffff) << 0; } + constexpr inline uint32_t skip(uint32_t num) { return (num & 0x7) << 21; } + constexpr inline uint32_t start(uint32_t num) { return (num & 0x1fffff) << 0; } } namespace object_pointer_block_link { constexpr uint32_t end_of_list = 1 << 28; - constexpr uint32_t next_pointer_block(uint32_t num) { return (num & 0xfffffc) << 0; } + constexpr inline uint32_t next_pointer_block(uint32_t num) { return (num & 0xfffffc) << 0; } } } diff --git a/dreamcast2/holly/core/parameter.hpp b/dreamcast2/holly/core/parameter.hpp index 0601125..2b7cf0a 100644 --- a/dreamcast2/holly/core/parameter.hpp +++ b/dreamcast2/holly/core/parameter.hpp @@ -1,3 +1,5 @@ +#pragma once + #include namespace holly::core::parameter { diff --git a/dreamcast2/holly/core/parameter_bits.hpp b/dreamcast2/holly/core/parameter_bits.hpp index aa10f08..f788ec5 100644 --- a/dreamcast2/holly/core/parameter_bits.hpp +++ b/dreamcast2/holly/core/parameter_bits.hpp @@ -125,7 +125,7 @@ namespace holly::core::parameter { } constexpr uint32_t super_sample_texture = 1 << 12; - constexpr uint32_t mip_map_d_adjust(uint32_t num) { return (num & 0xf) << 8; } + constexpr inline uint32_t mip_map_d_adjust(uint32_t num) { return (num & 0xf) << 8; } namespace texture_shading_instruction { constexpr uint32_t decal = 0 << 6; @@ -186,10 +186,10 @@ namespace holly::core::parameter { constexpr uint32_t bit_mask = 0x1 << 26; } - constexpr uint32_t palette_selector4(uint32_t num) { return (num & 0x3f) << 21; } - constexpr uint32_t palette_selector8(uint32_t num) { return (num & 0x3) << 25; } - constexpr uint32_t stride_select(uint32_t reg) { return (reg >> 25) & 0x1; } - constexpr uint32_t texture_address(uint32_t num) { return (num & 0x1fffff) << 0; } + constexpr inline uint32_t palette_selector4(uint32_t num) { return (num & 0x3f) << 21; } + constexpr inline uint32_t palette_selector8(uint32_t num) { return (num & 0x3) << 25; } + constexpr inline uint32_t stride_select(uint32_t reg) { return (reg >> 25) & 0x1; } + constexpr inline uint32_t texture_address(uint32_t num) { return (num & 0x1fffff) << 0; } } } diff --git a/dreamcast2/holly/core/region_array_bits.hpp b/dreamcast2/holly/core/region_array_bits.hpp index 0082289..4d83a77 100644 --- a/dreamcast2/holly/core/region_array_bits.hpp +++ b/dreamcast2/holly/core/region_array_bits.hpp @@ -8,13 +8,13 @@ namespace holly::core::region_array { 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; } + constexpr inline uint32_t y_position(uint32_t num) { return (num & 0x3f) << 8; } + constexpr inline 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; } + constexpr inline uint32_t object_list(uint32_t num) { return (num & 0xfffffc) << 0; } } } diff --git a/dreamcast2/holly/holly_bits.hpp b/dreamcast2/holly/holly_bits.hpp index 7fb9a5f..b4b674b 100644 --- a/dreamcast2/holly/holly_bits.hpp +++ b/dreamcast2/holly/holly_bits.hpp @@ -4,12 +4,12 @@ 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; } + constexpr inline uint32_t device_id(uint32_t reg) { return (reg >> 16) & 0xffff; } + constexpr inline 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; } + constexpr inline uint32_t chip_revision(uint32_t reg) { return (reg >> 0) & 0xffff; } } namespace softreset { @@ -23,16 +23,16 @@ namespace holly { } 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; } + constexpr inline uint32_t diagdb_data(uint32_t reg) { return (reg >> 5) & 0x1f; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline uint32_t base_address(uint32_t num) { return (num & 0xfffffc) << 0; } } namespace span_sort_cfg { @@ -42,10 +42,10 @@ namespace holly { } 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; } + constexpr inline uint32_t chroma(uint32_t num) { return (num & 0x1) << 24; } + constexpr inline uint32_t red(uint32_t num) { return (num & 0xff) << 16; } + constexpr inline uint32_t green(uint32_t num) { return (num & 0xff) << 8; } + constexpr inline uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } } namespace fb_r_ctrl { @@ -57,9 +57,9 @@ namespace holly { } 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; } + constexpr inline uint32_t fb_stripsize(uint32_t num) { return (num & 0x3e) << 16; } + constexpr inline uint32_t fb_chroma_threshold(uint32_t num) { return (num & 0xff) << 8; } + constexpr inline uint32_t fb_concat(uint32_t num) { return (num & 0x3) << 4; } namespace fb_depth { constexpr uint32_t xrgb0555 = 0 << 2; @@ -75,8 +75,8 @@ namespace holly { } 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 inline uint32_t fb_alpha_threshold(uint32_t num) { return (num & 0xff) << 16; } + constexpr inline uint32_t fb_kval(uint32_t num) { return (num & 0xff) << 8; } constexpr uint32_t fb_dither = 1 << 3; namespace fb_packmode { @@ -93,39 +93,39 @@ namespace holly { } namespace fb_w_linestride { - constexpr uint32_t fb_line_stride(uint32_t num) { return (num & 0xff) << 0; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline uint32_t fb_modulus(uint32_t num) { return (num & 0x3ff) << 20; } + constexpr inline uint32_t fb_y_size(uint32_t num) { return (num & 0x3ff) << 10; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline uint32_t fb_x_clip_max(uint32_t num) { return (num & 0x7ff) << 16; } + constexpr inline 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; } + constexpr inline uint32_t fb_y_clip_max(uint32_t num) { return (num & 0x3ff) << 16; } + constexpr inline uint32_t fb_y_clip_min(uint32_t num) { return (num & 0x3ff) << 0; } } namespace fpu_shad_scale { @@ -136,7 +136,7 @@ namespace holly { constexpr uint32_t bit_mask = 0x1 << 8; } - constexpr uint32_t scale_factor_for_shadows(uint32_t num) { return (num & 0xff) << 0; } + constexpr inline uint32_t scale_factor_for_shadows(uint32_t num) { return (num & 0xff) << 0; } } namespace fpu_cull_val { @@ -151,10 +151,10 @@ namespace holly { 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; } + constexpr inline uint32_t tsp_parameter_burst_threshold(uint32_t num) { return (num & 0x3f) << 14; } + constexpr inline uint32_t isp_parameter_burst_threshold(uint32_t num) { return (num & 0x3f) << 8; } + constexpr inline uint32_t pointer_burst_size(uint32_t num) { return (num & 0xf) << 4; } + constexpr inline uint32_t pointer_first_burst_size(uint32_t num) { return (num & 0xf) << 0; } } namespace half_offset { @@ -191,20 +191,20 @@ namespace holly { 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; } + constexpr inline uint32_t skip(uint32_t num) { return (num & 0x7) << 24; } + constexpr inline uint32_t tag_address(uint32_t num) { return (num & 0x1fffff) << 3; } + constexpr inline 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 inline uint32_t cache_size_for_translucency(uint32_t num) { return (num & 0x3ff) << 14; } + constexpr inline 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; } + constexpr inline uint32_t refresh_counter_value(uint32_t num) { return (num & 0xff) << 0; } } namespace sdram_arb_cfg { @@ -233,61 +233,61 @@ namespace holly { 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; } + constexpr inline uint32_t arbiter_crt_page_break_latency_count_value(uint32_t num) { return (num & 0xff) << 8; } + constexpr inline 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; } + constexpr inline uint32_t read_command_to_returned_data_delay(uint32_t num) { return (num & 0x7) << 26; } + constexpr inline uint32_t cas_latency_value(uint32_t num) { return (num & 0x7) << 23; } + constexpr inline uint32_t activate_to_activate_period(uint32_t num) { return (num & 0x3) << 21; } + constexpr inline uint32_t read_to_write_period(uint32_t num) { return (num & 0x7) << 18; } + constexpr inline uint32_t refresh_to_activate_period(uint32_t num) { return (num & 0xf) << 14; } + constexpr inline uint32_t pre_charge_to_activate_period(uint32_t num) { return (num & 0x3) << 10; } + constexpr inline uint32_t activate_to_pre_charge_period(uint32_t num) { return (num & 0xf) << 6; } + constexpr inline uint32_t activate_to_read_write_command_period(uint32_t num) { return (num & 0x3) << 4; } + constexpr inline uint32_t write_to_pre_charge_period(uint32_t num) { return (num & 0x3) << 2; } + constexpr inline 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; } + constexpr inline uint32_t red(uint32_t num) { return (num & 0xff) << 16; } + constexpr inline uint32_t green(uint32_t num) { return (num & 0xff) << 8; } + constexpr inline 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; } + constexpr inline uint32_t red(uint32_t num) { return (num & 0xff) << 16; } + constexpr inline uint32_t green(uint32_t num) { return (num & 0xff) << 8; } + constexpr inline 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; } + constexpr inline uint32_t fog_scale_mantissa(uint32_t num) { return (num & 0xff) << 8; } + constexpr inline 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; } + constexpr inline uint32_t alpha(uint32_t num) { return (num & 0xff) << 24; } + constexpr inline uint32_t red(uint32_t num) { return (num & 0xff) << 16; } + constexpr inline uint32_t green(uint32_t num) { return (num & 0xff) << 8; } + constexpr inline 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; } + constexpr inline uint32_t alpha(uint32_t num) { return (num & 0xff) << 24; } + constexpr inline uint32_t red(uint32_t num) { return (num & 0xff) << 16; } + constexpr inline uint32_t green(uint32_t num) { return (num & 0xff) << 8; } + constexpr inline 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; } + constexpr inline uint32_t trigger_v_count(uint32_t reg) { return (reg >> 16) & 0x3ff; } + constexpr inline 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; } + constexpr inline 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; @@ -297,12 +297,12 @@ namespace holly { constexpr uint32_t bit_mask = 0x3 << 12; } - constexpr uint32_t line_comp_val(uint32_t num) { return (num & 0x3ff) << 0; } + constexpr inline 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; } + constexpr inline uint32_t vblank_out_interrupt_line_number(uint32_t num) { return (num & 0x3ff) << 16; } + constexpr inline uint32_t vblank_in_interrupt_line_number(uint32_t num) { return (num & 0x3ff) << 0; } } namespace spg_control { @@ -349,25 +349,25 @@ namespace holly { } 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; } + constexpr inline uint32_t hbend(uint32_t num) { return (num & 0x3ff) << 16; } + constexpr inline 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; } + constexpr inline uint32_t vcount(uint32_t num) { return (num & 0x3ff) << 16; } + constexpr inline 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; } + constexpr inline uint32_t vbend(uint32_t num) { return (num & 0x3ff) << 16; } + constexpr inline 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; } + constexpr inline uint32_t eqwidth(uint32_t num) { return (num & 0x3ff) << 22; } + constexpr inline uint32_t bpwidth(uint32_t num) { return (num & 0x3ff) << 12; } + constexpr inline uint32_t vswidth(uint32_t num) { return (num & 0xf) << 8; } + constexpr inline uint32_t hswidth(uint32_t num) { return (num & 0x7f) << 0; } } namespace text_control { @@ -385,13 +385,13 @@ namespace holly { 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; } + constexpr inline uint32_t bank_bit(uint32_t num) { return (num & 0x1f) << 8; } + constexpr inline 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 inline uint32_t pclk_delay(uint32_t num) { return (num & 0x1f) << 16; } constexpr uint32_t pixel_double = 1 << 8; namespace field_mode { @@ -433,12 +433,12 @@ namespace holly { } namespace vo_startx { - constexpr uint32_t horizontal_start_position(uint32_t num) { return (num & 0x3ff) << 0; } + constexpr inline 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; } + constexpr inline uint32_t vertical_start_position_on_field_2(uint32_t num) { return (num & 0x3ff) << 16; } + constexpr inline uint32_t vertical_start_position_on_field_1(uint32_t num) { return (num & 0x3ff) << 0; } } namespace scaler_ctl { @@ -451,7 +451,7 @@ namespace holly { 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; } + constexpr inline uint32_t vertical_scale_factor(uint32_t num) { return (num & 0xffff) << 0; } } namespace pal_ram_ctrl { @@ -466,67 +466,67 @@ namespace holly { } 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; } + constexpr inline uint32_t vsync(uint32_t reg) { return (reg >> 13) & 0x1; } + constexpr inline uint32_t hsync(uint32_t reg) { return (reg >> 12) & 0x1; } + constexpr inline uint32_t blank(uint32_t reg) { return (reg >> 11) & 0x1; } + constexpr inline uint32_t fieldnum(uint32_t reg) { return (reg >> 10) & 0x1; } + constexpr inline 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; } + constexpr inline uint32_t wr_burst(uint32_t num) { return (num & 0xf) << 16; } + constexpr inline uint32_t vid_lat(uint32_t num) { return (num & 0x7f) << 8; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline uint32_t coefficient_1(uint32_t num) { return (num & 0xff) << 8; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline 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; } + constexpr inline uint32_t tile_y_num(uint32_t num) { return (num & 0xf) << 16; } + constexpr inline uint32_t tile_x_num(uint32_t num) { return (num & 0x1f) << 0; } } namespace ta_alloc_ctrl { @@ -588,7 +588,7 @@ namespace holly { } namespace ta_yuv_tex_base { - constexpr uint32_t base_address(uint32_t num) { return (num & 0xfffff8) << 0; } + constexpr inline uint32_t base_address(uint32_t num) { return (num & 0xfffff8) << 0; } } namespace ta_yuv_tex_ctrl { @@ -606,12 +606,12 @@ namespace holly { 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; } + constexpr inline uint32_t yuv_v_size(uint32_t num) { return (num & 0x3f) << 8; } + constexpr inline 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; } + constexpr inline uint32_t yuv_num(uint32_t reg) { return (reg >> 0) & 0x1fff; } } namespace ta_list_cont { @@ -619,17 +619,17 @@ namespace holly { } namespace ta_next_opb_init { - constexpr uint32_t address(uint32_t num) { return (num & 0xffffe0) << 0; } + constexpr inline 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; } + constexpr inline uint32_t entry(uint32_t reg) { return (reg >> 31) & 0x1; } + constexpr inline uint32_t sprite(uint32_t reg) { return (reg >> 30) & 0x1; } + constexpr inline uint32_t triangle(uint32_t reg) { return (reg >> 29) & 0x1; } + constexpr inline uint32_t number_of_triangles_quads(uint32_t reg) { return (reg >> 25) & 0xf; } + constexpr inline uint32_t shadow(uint32_t reg) { return (reg >> 24) & 0x1; } + constexpr inline uint32_t pointer_address(uint32_t reg) { return (reg >> 2) & 0x3fffff; } + constexpr inline uint32_t skip(uint32_t reg) { return (reg >> 0) & 0x3; } } } diff --git a/dreamcast2/holly/ta/global_parameter.hpp b/dreamcast2/holly/ta/global_parameter.hpp new file mode 100644 index 0000000..0cfe0cb --- /dev/null +++ b/dreamcast2/holly/ta/global_parameter.hpp @@ -0,0 +1,240 @@ +#pragma once + +#include +#include + +namespace holly::ta::global_parameter { + struct end_of_list { + uint32_t parameter_control_word; + uint32_t _res0; + uint32_t _res1; + uint32_t _res2; + uint32_t _res3; + uint32_t _res4; + uint32_t _res5; + uint32_t _res6; + }; + static_assert((sizeof (end_of_list)) == 32); + static_assert((offsetof (struct end_of_list, parameter_control_word)) == 0x00); + static_assert((offsetof (struct end_of_list, _res0)) == 0x04); + static_assert((offsetof (struct end_of_list, _res1)) == 0x08); + static_assert((offsetof (struct end_of_list, _res2)) == 0x0c); + static_assert((offsetof (struct end_of_list, _res3)) == 0x10); + static_assert((offsetof (struct end_of_list, _res4)) == 0x14); + static_assert((offsetof (struct end_of_list, _res5)) == 0x18); + static_assert((offsetof (struct end_of_list, _res6)) == 0x1c); + + struct user_tile_clip { + uint32_t parameter_control_word; + uint32_t _res0; + uint32_t _res1; + uint32_t _res2; + uint32_t user_clip_x_min; + uint32_t user_clip_y_min; + uint32_t user_clip_x_max; + uint32_t user_clip_y_max; + }; + static_assert((sizeof (user_tile_clip)) == 32); + static_assert((offsetof (struct user_tile_clip, parameter_control_word)) == 0x00); + static_assert((offsetof (struct user_tile_clip, _res0)) == 0x04); + static_assert((offsetof (struct user_tile_clip, _res1)) == 0x08); + static_assert((offsetof (struct user_tile_clip, _res2)) == 0x0c); + static_assert((offsetof (struct user_tile_clip, user_clip_x_min)) == 0x10); + static_assert((offsetof (struct user_tile_clip, user_clip_y_min)) == 0x14); + static_assert((offsetof (struct user_tile_clip, user_clip_x_max)) == 0x18); + static_assert((offsetof (struct user_tile_clip, user_clip_y_max)) == 0x1c); + + struct object_list_set { + uint32_t parameter_control_word; + uint32_t object_pointer; + uint32_t _res0; + uint32_t _res1; + uint32_t bounding_box_x_min; + uint32_t bounding_box_y_min; + uint32_t bounding_box_x_max; + uint32_t bounding_box_y_max; + }; + static_assert((sizeof (object_list_set)) == 32); + static_assert((offsetof (struct object_list_set, parameter_control_word)) == 0x00); + static_assert((offsetof (struct object_list_set, object_pointer)) == 0x04); + static_assert((offsetof (struct object_list_set, _res0)) == 0x08); + static_assert((offsetof (struct object_list_set, _res1)) == 0x0c); + static_assert((offsetof (struct object_list_set, bounding_box_x_min)) == 0x10); + static_assert((offsetof (struct object_list_set, bounding_box_y_min)) == 0x14); + static_assert((offsetof (struct object_list_set, bounding_box_x_max)) == 0x18); + static_assert((offsetof (struct object_list_set, bounding_box_y_max)) == 0x1c); + + struct polygon_type_0 { + uint32_t parameter_control_word; + uint32_t isp_tsp_instruction_word; + uint32_t tsp_instruction_word; + uint32_t texture_control_word; + uint32_t _res0; + uint32_t _res1; + uint32_t data_size_for_sort_dma; + uint32_t next_address_for_sort_dma; + }; + static_assert((sizeof (polygon_type_0)) == 32); + static_assert((offsetof (struct polygon_type_0, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_0, isp_tsp_instruction_word)) == 0x04); + static_assert((offsetof (struct polygon_type_0, tsp_instruction_word)) == 0x08); + static_assert((offsetof (struct polygon_type_0, texture_control_word)) == 0x0c); + static_assert((offsetof (struct polygon_type_0, _res0)) == 0x10); + static_assert((offsetof (struct polygon_type_0, _res1)) == 0x14); + static_assert((offsetof (struct polygon_type_0, data_size_for_sort_dma)) == 0x18); + static_assert((offsetof (struct polygon_type_0, next_address_for_sort_dma)) == 0x1c); + + struct polygon_type_1 { + uint32_t parameter_control_word; + uint32_t isp_tsp_instruction_word; + uint32_t tsp_instruction_word; + uint32_t texture_control_word; + float face_color_alpha; + float face_color_r; + float face_color_g; + float face_color_b; + }; + static_assert((sizeof (polygon_type_1)) == 32); + static_assert((offsetof (struct polygon_type_1, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_1, isp_tsp_instruction_word)) == 0x04); + static_assert((offsetof (struct polygon_type_1, tsp_instruction_word)) == 0x08); + static_assert((offsetof (struct polygon_type_1, texture_control_word)) == 0x0c); + static_assert((offsetof (struct polygon_type_1, face_color_alpha)) == 0x10); + static_assert((offsetof (struct polygon_type_1, face_color_r)) == 0x14); + static_assert((offsetof (struct polygon_type_1, face_color_g)) == 0x18); + static_assert((offsetof (struct polygon_type_1, face_color_b)) == 0x1c); + + struct polygon_type_2 { + uint32_t parameter_control_word; + uint32_t isp_tsp_instruction_word; + uint32_t tsp_instruction_word; + uint32_t texture_control_word; + uint32_t _res0; + uint32_t _res1; + uint32_t data_size_for_sort_dma; + uint32_t next_address_for_sort_dma; + float face_color_alpha; + float face_color_r; + float face_color_g; + float face_color_b; + float face_offset_color_alpha; + float face_offset_color_r; + float face_offset_color_g; + float face_offset_color_b; + }; + static_assert((sizeof (polygon_type_2)) == 64); + static_assert((offsetof (struct polygon_type_2, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_2, isp_tsp_instruction_word)) == 0x04); + static_assert((offsetof (struct polygon_type_2, tsp_instruction_word)) == 0x08); + static_assert((offsetof (struct polygon_type_2, texture_control_word)) == 0x0c); + static_assert((offsetof (struct polygon_type_2, _res0)) == 0x10); + static_assert((offsetof (struct polygon_type_2, _res1)) == 0x14); + static_assert((offsetof (struct polygon_type_2, data_size_for_sort_dma)) == 0x18); + static_assert((offsetof (struct polygon_type_2, next_address_for_sort_dma)) == 0x1c); + static_assert((offsetof (struct polygon_type_2, face_color_alpha)) == 0x20); + static_assert((offsetof (struct polygon_type_2, face_color_r)) == 0x24); + static_assert((offsetof (struct polygon_type_2, face_color_g)) == 0x28); + static_assert((offsetof (struct polygon_type_2, face_color_b)) == 0x2c); + static_assert((offsetof (struct polygon_type_2, face_offset_color_alpha)) == 0x30); + static_assert((offsetof (struct polygon_type_2, face_offset_color_r)) == 0x34); + static_assert((offsetof (struct polygon_type_2, face_offset_color_g)) == 0x38); + static_assert((offsetof (struct polygon_type_2, face_offset_color_b)) == 0x3c); + + struct polygon_type_3 { + uint32_t parameter_control_word; + uint32_t isp_tsp_instruction_word; + uint32_t tsp_instruction_word_0; + uint32_t texture_control_word_0; + uint32_t tsp_instruction_word_1; + uint32_t texture_control_word_1; + uint32_t data_size_for_sort_dma; + uint32_t next_address_for_sort_dma; + }; + static_assert((sizeof (polygon_type_3)) == 32); + static_assert((offsetof (struct polygon_type_3, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_3, isp_tsp_instruction_word)) == 0x04); + static_assert((offsetof (struct polygon_type_3, tsp_instruction_word_0)) == 0x08); + static_assert((offsetof (struct polygon_type_3, texture_control_word_0)) == 0x0c); + static_assert((offsetof (struct polygon_type_3, tsp_instruction_word_1)) == 0x10); + static_assert((offsetof (struct polygon_type_3, texture_control_word_1)) == 0x14); + static_assert((offsetof (struct polygon_type_3, data_size_for_sort_dma)) == 0x18); + static_assert((offsetof (struct polygon_type_3, next_address_for_sort_dma)) == 0x1c); + + struct polygon_type_4 { + uint32_t parameter_control_word; + uint32_t isp_tsp_instruction_word; + uint32_t tsp_instruction_word_0; + uint32_t texture_control_word_0; + uint32_t tsp_instruction_word_1; + uint32_t texture_control_word_1; + uint32_t data_size_for_sort_dma; + uint32_t next_address_for_sort_dma; + float face_color_alpha_0; + float face_color_r_0; + float face_color_g_0; + float face_color_b_0; + float face_color_alpha_1; + float face_color_r_1; + float face_color_g_1; + float face_color_b_1; + }; + static_assert((sizeof (polygon_type_4)) == 64); + static_assert((offsetof (struct polygon_type_4, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_4, isp_tsp_instruction_word)) == 0x04); + static_assert((offsetof (struct polygon_type_4, tsp_instruction_word_0)) == 0x08); + static_assert((offsetof (struct polygon_type_4, texture_control_word_0)) == 0x0c); + static_assert((offsetof (struct polygon_type_4, tsp_instruction_word_1)) == 0x10); + static_assert((offsetof (struct polygon_type_4, texture_control_word_1)) == 0x14); + static_assert((offsetof (struct polygon_type_4, data_size_for_sort_dma)) == 0x18); + static_assert((offsetof (struct polygon_type_4, next_address_for_sort_dma)) == 0x1c); + static_assert((offsetof (struct polygon_type_4, face_color_alpha_0)) == 0x20); + static_assert((offsetof (struct polygon_type_4, face_color_r_0)) == 0x24); + static_assert((offsetof (struct polygon_type_4, face_color_g_0)) == 0x28); + static_assert((offsetof (struct polygon_type_4, face_color_b_0)) == 0x2c); + static_assert((offsetof (struct polygon_type_4, face_color_alpha_1)) == 0x30); + static_assert((offsetof (struct polygon_type_4, face_color_r_1)) == 0x34); + static_assert((offsetof (struct polygon_type_4, face_color_g_1)) == 0x38); + static_assert((offsetof (struct polygon_type_4, face_color_b_1)) == 0x3c); + + struct sprite { + uint32_t parameter_control_word; + uint32_t isp_tsp_instruction_word; + uint32_t tsp_instruction_word; + uint32_t texture_control_word; + uint32_t base_color; + uint32_t offset_color; + uint32_t data_size_for_sort_dma; + uint32_t next_address_for_sort_dma; + }; + static_assert((sizeof (sprite)) == 32); + static_assert((offsetof (struct sprite, parameter_control_word)) == 0x00); + static_assert((offsetof (struct sprite, isp_tsp_instruction_word)) == 0x04); + static_assert((offsetof (struct sprite, tsp_instruction_word)) == 0x08); + static_assert((offsetof (struct sprite, texture_control_word)) == 0x0c); + static_assert((offsetof (struct sprite, base_color)) == 0x10); + static_assert((offsetof (struct sprite, offset_color)) == 0x14); + static_assert((offsetof (struct sprite, data_size_for_sort_dma)) == 0x18); + static_assert((offsetof (struct sprite, next_address_for_sort_dma)) == 0x1c); + + struct modifier_volume { + uint32_t parameter_control_word; + uint32_t isp_tsp_instruction_word; + uint32_t _res0; + uint32_t _res1; + uint32_t _res2; + uint32_t _res3; + uint32_t _res4; + uint32_t _res5; + }; + static_assert((sizeof (modifier_volume)) == 32); + static_assert((offsetof (struct modifier_volume, parameter_control_word)) == 0x00); + static_assert((offsetof (struct modifier_volume, isp_tsp_instruction_word)) == 0x04); + static_assert((offsetof (struct modifier_volume, _res0)) == 0x08); + static_assert((offsetof (struct modifier_volume, _res1)) == 0x0c); + static_assert((offsetof (struct modifier_volume, _res2)) == 0x10); + static_assert((offsetof (struct modifier_volume, _res3)) == 0x14); + static_assert((offsetof (struct modifier_volume, _res4)) == 0x18); + static_assert((offsetof (struct modifier_volume, _res5)) == 0x1c); + +} + diff --git a/dreamcast2/holly/ta/parameter_bits.hpp b/dreamcast2/holly/ta/parameter_bits.hpp new file mode 100644 index 0000000..7449806 --- /dev/null +++ b/dreamcast2/holly/ta/parameter_bits.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include + +namespace holly::ta::parameter { + namespace parameter_control_word { + namespace para_type { + constexpr uint32_t end_of_list = 0 << 29; + constexpr uint32_t user_tile_clip = 1 << 29; + constexpr uint32_t object_list_set = 2 << 29; + constexpr uint32_t polygon_or_modifier_volume = 4 << 29; + constexpr uint32_t sprite = 5 << 29; + constexpr uint32_t vertex_parameter = 7 << 29; + + constexpr uint32_t bit_mask = 0x7 << 29; + } + + constexpr uint32_t end_of_strip = 1 << 28; + + namespace list_type { + constexpr uint32_t opaque = 0 << 24; + constexpr uint32_t opaque_modifier_volume = 1 << 24; + constexpr uint32_t translucent = 2 << 24; + constexpr uint32_t translucent_modifier_volume = 3 << 24; + constexpr uint32_t punch_through = 4 << 24; + + constexpr uint32_t bit_mask = 0x7 << 24; + } + + constexpr uint32_t group_en = 1 << 23; + + namespace strip_len { + constexpr uint32_t _1_strip = 0 << 18; + constexpr uint32_t _2_strip = 1 << 18; + constexpr uint32_t _4_strip = 2 << 18; + constexpr uint32_t _6_strip = 3 << 18; + + constexpr uint32_t bit_mask = 0x3 << 18; + } + + namespace user_clip { + constexpr uint32_t disabled = 0 << 16; + constexpr uint32_t inside_enable = 2 << 16; + constexpr uint32_t outside_enable = 3 << 16; + + constexpr uint32_t bit_mask = 0x3 << 16; + } + + namespace polygon_volume { + constexpr uint32_t no_volume = 0b00 << 6; + constexpr uint32_t intensity_volume = 0b10 << 6; + constexpr uint32_t two_volumes = 0b11 << 6; + + constexpr uint32_t bit_mask = 0x3 << 6; + } + + namespace modifier_volume { + constexpr uint32_t last_in_volume = 0b01 << 6; + + constexpr uint32_t bit_mask = 0x3 << 6; + } + + namespace col_type { + constexpr uint32_t packed_color = 0 << 4; + constexpr uint32_t floating_color = 1 << 4; + constexpr uint32_t intensity_mode_1 = 2 << 4; + constexpr uint32_t intensity_mode_2 = 3 << 4; + + constexpr uint32_t bit_mask = 0x3 << 4; + } + + constexpr uint32_t texture = 1 << 3; + constexpr uint32_t offset = 1 << 2; + constexpr uint32_t gouraud = 1 << 1; + constexpr uint32_t _16bit_uv = 1 << 0; + } + +} diff --git a/dreamcast2/holly/ta/vertex_parameter.hpp b/dreamcast2/holly/ta/vertex_parameter.hpp new file mode 100644 index 0000000..a86dc47 --- /dev/null +++ b/dreamcast2/holly/ta/vertex_parameter.hpp @@ -0,0 +1,512 @@ +#pragma once + +#include +#include + +namespace holly::ta::vertex_parameter { + struct polygon_type_0 { + uint32_t parameter_control_word; + float x; + float y; + float z; + uint32_t _res0; + uint32_t _res1; + uint32_t base_color; + uint32_t _res2; + }; + static_assert((sizeof (polygon_type_0)) == 32); + static_assert((offsetof (struct polygon_type_0, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_0, x)) == 0x04); + static_assert((offsetof (struct polygon_type_0, y)) == 0x08); + static_assert((offsetof (struct polygon_type_0, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_0, _res0)) == 0x10); + static_assert((offsetof (struct polygon_type_0, _res1)) == 0x14); + static_assert((offsetof (struct polygon_type_0, base_color)) == 0x18); + static_assert((offsetof (struct polygon_type_0, _res2)) == 0x1c); + + struct polygon_type_1 { + uint32_t parameter_control_word; + float x; + float y; + float z; + float base_color_alpha; + float base_color_r; + float base_color_g; + float base_color_b; + }; + static_assert((sizeof (polygon_type_1)) == 32); + static_assert((offsetof (struct polygon_type_1, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_1, x)) == 0x04); + static_assert((offsetof (struct polygon_type_1, y)) == 0x08); + static_assert((offsetof (struct polygon_type_1, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_1, base_color_alpha)) == 0x10); + static_assert((offsetof (struct polygon_type_1, base_color_r)) == 0x14); + static_assert((offsetof (struct polygon_type_1, base_color_g)) == 0x18); + static_assert((offsetof (struct polygon_type_1, base_color_b)) == 0x1c); + + struct polygon_type_2 { + uint32_t parameter_control_word; + float x; + float y; + float z; + uint32_t _res0; + uint32_t _res1; + float base_intensity; + uint32_t _res2; + }; + static_assert((sizeof (polygon_type_2)) == 32); + static_assert((offsetof (struct polygon_type_2, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_2, x)) == 0x04); + static_assert((offsetof (struct polygon_type_2, y)) == 0x08); + static_assert((offsetof (struct polygon_type_2, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_2, _res0)) == 0x10); + static_assert((offsetof (struct polygon_type_2, _res1)) == 0x14); + static_assert((offsetof (struct polygon_type_2, base_intensity)) == 0x18); + static_assert((offsetof (struct polygon_type_2, _res2)) == 0x1c); + + struct polygon_type_3 { + uint32_t parameter_control_word; + float x; + float y; + float z; + float u; + float v; + uint32_t base_color; + uint32_t offset_color; + }; + static_assert((sizeof (polygon_type_3)) == 32); + static_assert((offsetof (struct polygon_type_3, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_3, x)) == 0x04); + static_assert((offsetof (struct polygon_type_3, y)) == 0x08); + static_assert((offsetof (struct polygon_type_3, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_3, u)) == 0x10); + static_assert((offsetof (struct polygon_type_3, v)) == 0x14); + static_assert((offsetof (struct polygon_type_3, base_color)) == 0x18); + static_assert((offsetof (struct polygon_type_3, offset_color)) == 0x1c); + + struct polygon_type_4 { + uint32_t parameter_control_word; + float x; + float y; + float z; + uint32_t u_v; + uint32_t _res0; + uint32_t base_color; + uint32_t offset_color; + }; + static_assert((sizeof (polygon_type_4)) == 32); + static_assert((offsetof (struct polygon_type_4, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_4, x)) == 0x04); + static_assert((offsetof (struct polygon_type_4, y)) == 0x08); + static_assert((offsetof (struct polygon_type_4, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_4, u_v)) == 0x10); + static_assert((offsetof (struct polygon_type_4, _res0)) == 0x14); + static_assert((offsetof (struct polygon_type_4, base_color)) == 0x18); + static_assert((offsetof (struct polygon_type_4, offset_color)) == 0x1c); + + struct polygon_type_5 { + uint32_t parameter_control_word; + float x; + float y; + float z; + float u; + float v; + uint32_t _res0; + uint32_t _res1; + float base_color_alpha; + float base_color_r; + float base_color_g; + float base_color_b; + float offset_color_alpha; + float offset_color_r; + float offset_color_g; + float offset_color_b; + }; + static_assert((sizeof (polygon_type_5)) == 64); + static_assert((offsetof (struct polygon_type_5, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_5, x)) == 0x04); + static_assert((offsetof (struct polygon_type_5, y)) == 0x08); + static_assert((offsetof (struct polygon_type_5, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_5, u)) == 0x10); + static_assert((offsetof (struct polygon_type_5, v)) == 0x14); + static_assert((offsetof (struct polygon_type_5, _res0)) == 0x18); + static_assert((offsetof (struct polygon_type_5, _res1)) == 0x1c); + static_assert((offsetof (struct polygon_type_5, base_color_alpha)) == 0x20); + static_assert((offsetof (struct polygon_type_5, base_color_r)) == 0x24); + static_assert((offsetof (struct polygon_type_5, base_color_g)) == 0x28); + static_assert((offsetof (struct polygon_type_5, base_color_b)) == 0x2c); + static_assert((offsetof (struct polygon_type_5, offset_color_alpha)) == 0x30); + static_assert((offsetof (struct polygon_type_5, offset_color_r)) == 0x34); + static_assert((offsetof (struct polygon_type_5, offset_color_g)) == 0x38); + static_assert((offsetof (struct polygon_type_5, offset_color_b)) == 0x3c); + + struct polygon_type_6 { + uint32_t parameter_control_word; + float x; + float y; + float z; + uint32_t u_v; + uint32_t _res0; + uint32_t _res1; + uint32_t _res2; + float base_color_alpha; + float base_color_r; + float base_color_g; + float base_color_b; + float offset_color_alpha; + float offset_color_r; + float offset_color_g; + float offset_color_b; + }; + static_assert((sizeof (polygon_type_6)) == 64); + static_assert((offsetof (struct polygon_type_6, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_6, x)) == 0x04); + static_assert((offsetof (struct polygon_type_6, y)) == 0x08); + static_assert((offsetof (struct polygon_type_6, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_6, u_v)) == 0x10); + static_assert((offsetof (struct polygon_type_6, _res0)) == 0x14); + static_assert((offsetof (struct polygon_type_6, _res1)) == 0x18); + static_assert((offsetof (struct polygon_type_6, _res2)) == 0x1c); + static_assert((offsetof (struct polygon_type_6, base_color_alpha)) == 0x20); + static_assert((offsetof (struct polygon_type_6, base_color_r)) == 0x24); + static_assert((offsetof (struct polygon_type_6, base_color_g)) == 0x28); + static_assert((offsetof (struct polygon_type_6, base_color_b)) == 0x2c); + static_assert((offsetof (struct polygon_type_6, offset_color_alpha)) == 0x30); + static_assert((offsetof (struct polygon_type_6, offset_color_r)) == 0x34); + static_assert((offsetof (struct polygon_type_6, offset_color_g)) == 0x38); + static_assert((offsetof (struct polygon_type_6, offset_color_b)) == 0x3c); + + struct polygon_type_7 { + uint32_t parameter_control_word; + float x; + float y; + float z; + float u; + float v; + float base_intensity; + float offset_intensity; + }; + static_assert((sizeof (polygon_type_7)) == 32); + static_assert((offsetof (struct polygon_type_7, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_7, x)) == 0x04); + static_assert((offsetof (struct polygon_type_7, y)) == 0x08); + static_assert((offsetof (struct polygon_type_7, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_7, u)) == 0x10); + static_assert((offsetof (struct polygon_type_7, v)) == 0x14); + static_assert((offsetof (struct polygon_type_7, base_intensity)) == 0x18); + static_assert((offsetof (struct polygon_type_7, offset_intensity)) == 0x1c); + + struct polygon_type_8 { + uint32_t parameter_control_word; + float x; + float y; + float z; + uint32_t u_v; + uint32_t _res0; + float base_intensity; + float offset_intensity; + }; + static_assert((sizeof (polygon_type_8)) == 32); + static_assert((offsetof (struct polygon_type_8, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_8, x)) == 0x04); + static_assert((offsetof (struct polygon_type_8, y)) == 0x08); + static_assert((offsetof (struct polygon_type_8, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_8, u_v)) == 0x10); + static_assert((offsetof (struct polygon_type_8, _res0)) == 0x14); + static_assert((offsetof (struct polygon_type_8, base_intensity)) == 0x18); + static_assert((offsetof (struct polygon_type_8, offset_intensity)) == 0x1c); + + struct polygon_type_9 { + uint32_t parameter_control_word; + float x; + float y; + float z; + uint32_t base_color_0; + uint32_t base_color_1; + uint32_t _res0; + uint32_t _res1; + }; + static_assert((sizeof (polygon_type_9)) == 32); + static_assert((offsetof (struct polygon_type_9, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_9, x)) == 0x04); + static_assert((offsetof (struct polygon_type_9, y)) == 0x08); + static_assert((offsetof (struct polygon_type_9, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_9, base_color_0)) == 0x10); + static_assert((offsetof (struct polygon_type_9, base_color_1)) == 0x14); + static_assert((offsetof (struct polygon_type_9, _res0)) == 0x18); + static_assert((offsetof (struct polygon_type_9, _res1)) == 0x1c); + + struct polygon_type_10 { + uint32_t parameter_control_word; + float x; + float y; + float z; + uint32_t base_intensity_0; + uint32_t base_intensity_1; + uint32_t _res0; + uint32_t _res1; + }; + static_assert((sizeof (polygon_type_10)) == 32); + static_assert((offsetof (struct polygon_type_10, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_10, x)) == 0x04); + static_assert((offsetof (struct polygon_type_10, y)) == 0x08); + static_assert((offsetof (struct polygon_type_10, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_10, base_intensity_0)) == 0x10); + static_assert((offsetof (struct polygon_type_10, base_intensity_1)) == 0x14); + static_assert((offsetof (struct polygon_type_10, _res0)) == 0x18); + static_assert((offsetof (struct polygon_type_10, _res1)) == 0x1c); + + struct polygon_type_11 { + uint32_t parameter_control_word; + float x; + float y; + float z; + float u_0; + float v_0; + uint32_t base_color_0; + uint32_t offset_color_0; + float u_1; + float v_1; + uint32_t base_color_1; + uint32_t offset_color_1; + uint32_t _res0; + uint32_t _res1; + uint32_t _res2; + uint32_t _res3; + }; + static_assert((sizeof (polygon_type_11)) == 64); + static_assert((offsetof (struct polygon_type_11, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_11, x)) == 0x04); + static_assert((offsetof (struct polygon_type_11, y)) == 0x08); + static_assert((offsetof (struct polygon_type_11, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_11, u_0)) == 0x10); + static_assert((offsetof (struct polygon_type_11, v_0)) == 0x14); + static_assert((offsetof (struct polygon_type_11, base_color_0)) == 0x18); + static_assert((offsetof (struct polygon_type_11, offset_color_0)) == 0x1c); + static_assert((offsetof (struct polygon_type_11, u_1)) == 0x20); + static_assert((offsetof (struct polygon_type_11, v_1)) == 0x24); + static_assert((offsetof (struct polygon_type_11, base_color_1)) == 0x28); + static_assert((offsetof (struct polygon_type_11, offset_color_1)) == 0x2c); + static_assert((offsetof (struct polygon_type_11, _res0)) == 0x30); + static_assert((offsetof (struct polygon_type_11, _res1)) == 0x34); + static_assert((offsetof (struct polygon_type_11, _res2)) == 0x38); + static_assert((offsetof (struct polygon_type_11, _res3)) == 0x3c); + + struct polygon_type_12 { + uint32_t parameter_control_word; + float x; + float y; + float z; + uint32_t u_v_0; + uint32_t _res0; + uint32_t base_color_0; + uint32_t offset_color_0; + uint32_t u_v_1; + uint32_t _res1; + uint32_t base_color_1; + uint32_t offset_color_1; + uint32_t _res2; + uint32_t _res3; + uint32_t _res4; + uint32_t _res5; + }; + static_assert((sizeof (polygon_type_12)) == 64); + static_assert((offsetof (struct polygon_type_12, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_12, x)) == 0x04); + static_assert((offsetof (struct polygon_type_12, y)) == 0x08); + static_assert((offsetof (struct polygon_type_12, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_12, u_v_0)) == 0x10); + static_assert((offsetof (struct polygon_type_12, _res0)) == 0x14); + static_assert((offsetof (struct polygon_type_12, base_color_0)) == 0x18); + static_assert((offsetof (struct polygon_type_12, offset_color_0)) == 0x1c); + static_assert((offsetof (struct polygon_type_12, u_v_1)) == 0x20); + static_assert((offsetof (struct polygon_type_12, _res1)) == 0x24); + static_assert((offsetof (struct polygon_type_12, base_color_1)) == 0x28); + static_assert((offsetof (struct polygon_type_12, offset_color_1)) == 0x2c); + static_assert((offsetof (struct polygon_type_12, _res2)) == 0x30); + static_assert((offsetof (struct polygon_type_12, _res3)) == 0x34); + static_assert((offsetof (struct polygon_type_12, _res4)) == 0x38); + static_assert((offsetof (struct polygon_type_12, _res5)) == 0x3c); + + struct polygon_type_13 { + uint32_t parameter_control_word; + float x; + float y; + float z; + float u_0; + float v_0; + uint32_t base_intensity_0; + float offset_intensity_0; + float u_1; + float v_1; + uint32_t base_intensity_1; + float offset_intensity_1; + uint32_t _res0; + uint32_t _res1; + uint32_t _res2; + uint32_t _res3; + }; + static_assert((sizeof (polygon_type_13)) == 64); + static_assert((offsetof (struct polygon_type_13, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_13, x)) == 0x04); + static_assert((offsetof (struct polygon_type_13, y)) == 0x08); + static_assert((offsetof (struct polygon_type_13, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_13, u_0)) == 0x10); + static_assert((offsetof (struct polygon_type_13, v_0)) == 0x14); + static_assert((offsetof (struct polygon_type_13, base_intensity_0)) == 0x18); + static_assert((offsetof (struct polygon_type_13, offset_intensity_0)) == 0x1c); + static_assert((offsetof (struct polygon_type_13, u_1)) == 0x20); + static_assert((offsetof (struct polygon_type_13, v_1)) == 0x24); + static_assert((offsetof (struct polygon_type_13, base_intensity_1)) == 0x28); + static_assert((offsetof (struct polygon_type_13, offset_intensity_1)) == 0x2c); + static_assert((offsetof (struct polygon_type_13, _res0)) == 0x30); + static_assert((offsetof (struct polygon_type_13, _res1)) == 0x34); + static_assert((offsetof (struct polygon_type_13, _res2)) == 0x38); + static_assert((offsetof (struct polygon_type_13, _res3)) == 0x3c); + + struct polygon_type_14 { + uint32_t parameter_control_word; + float x; + float y; + float z; + uint32_t u_v_0; + uint32_t _res0; + uint32_t base_intensity_0; + float offset_intensity_0; + uint32_t u_v_1; + uint32_t _res1; + uint32_t base_intensity_1; + float offset_intensity_1; + uint32_t _res2; + uint32_t _res3; + uint32_t _res4; + uint32_t _res5; + }; + static_assert((sizeof (polygon_type_14)) == 64); + static_assert((offsetof (struct polygon_type_14, parameter_control_word)) == 0x00); + static_assert((offsetof (struct polygon_type_14, x)) == 0x04); + static_assert((offsetof (struct polygon_type_14, y)) == 0x08); + static_assert((offsetof (struct polygon_type_14, z)) == 0x0c); + static_assert((offsetof (struct polygon_type_14, u_v_0)) == 0x10); + static_assert((offsetof (struct polygon_type_14, _res0)) == 0x14); + static_assert((offsetof (struct polygon_type_14, base_intensity_0)) == 0x18); + static_assert((offsetof (struct polygon_type_14, offset_intensity_0)) == 0x1c); + static_assert((offsetof (struct polygon_type_14, u_v_1)) == 0x20); + static_assert((offsetof (struct polygon_type_14, _res1)) == 0x24); + static_assert((offsetof (struct polygon_type_14, base_intensity_1)) == 0x28); + static_assert((offsetof (struct polygon_type_14, offset_intensity_1)) == 0x2c); + static_assert((offsetof (struct polygon_type_14, _res2)) == 0x30); + static_assert((offsetof (struct polygon_type_14, _res3)) == 0x34); + static_assert((offsetof (struct polygon_type_14, _res4)) == 0x38); + static_assert((offsetof (struct polygon_type_14, _res5)) == 0x3c); + + struct sprite_type_0 { + uint32_t parameter_control_word; + float a_x; + float a_y; + float a_z; + float b_x; + float b_y; + float b_z; + float c_x; + float c_y; + float c_z; + float d_x; + float d_y; + uint32_t _res0; + uint32_t _res1; + uint32_t _res2; + uint32_t _res3; + }; + static_assert((sizeof (sprite_type_0)) == 64); + static_assert((offsetof (struct sprite_type_0, parameter_control_word)) == 0x00); + static_assert((offsetof (struct sprite_type_0, a_x)) == 0x04); + static_assert((offsetof (struct sprite_type_0, a_y)) == 0x08); + static_assert((offsetof (struct sprite_type_0, a_z)) == 0x0c); + static_assert((offsetof (struct sprite_type_0, b_x)) == 0x10); + static_assert((offsetof (struct sprite_type_0, b_y)) == 0x14); + static_assert((offsetof (struct sprite_type_0, b_z)) == 0x18); + static_assert((offsetof (struct sprite_type_0, c_x)) == 0x1c); + static_assert((offsetof (struct sprite_type_0, c_y)) == 0x20); + static_assert((offsetof (struct sprite_type_0, c_z)) == 0x24); + static_assert((offsetof (struct sprite_type_0, d_x)) == 0x28); + static_assert((offsetof (struct sprite_type_0, d_y)) == 0x2c); + static_assert((offsetof (struct sprite_type_0, _res0)) == 0x30); + static_assert((offsetof (struct sprite_type_0, _res1)) == 0x34); + static_assert((offsetof (struct sprite_type_0, _res2)) == 0x38); + static_assert((offsetof (struct sprite_type_0, _res3)) == 0x3c); + + struct sprite_type_1 { + uint32_t parameter_control_word; + float a_x; + float a_y; + float a_z; + float b_x; + float b_y; + float b_z; + float c_x; + float c_y; + float c_z; + float d_x; + float d_y; + uint32_t _res0; + uint32_t a_u_a_v; + uint32_t b_u_b_v; + uint32_t c_u_c_v; + }; + static_assert((sizeof (sprite_type_1)) == 64); + static_assert((offsetof (struct sprite_type_1, parameter_control_word)) == 0x00); + static_assert((offsetof (struct sprite_type_1, a_x)) == 0x04); + static_assert((offsetof (struct sprite_type_1, a_y)) == 0x08); + static_assert((offsetof (struct sprite_type_1, a_z)) == 0x0c); + static_assert((offsetof (struct sprite_type_1, b_x)) == 0x10); + static_assert((offsetof (struct sprite_type_1, b_y)) == 0x14); + static_assert((offsetof (struct sprite_type_1, b_z)) == 0x18); + static_assert((offsetof (struct sprite_type_1, c_x)) == 0x1c); + static_assert((offsetof (struct sprite_type_1, c_y)) == 0x20); + static_assert((offsetof (struct sprite_type_1, c_z)) == 0x24); + static_assert((offsetof (struct sprite_type_1, d_x)) == 0x28); + static_assert((offsetof (struct sprite_type_1, d_y)) == 0x2c); + static_assert((offsetof (struct sprite_type_1, _res0)) == 0x30); + static_assert((offsetof (struct sprite_type_1, a_u_a_v)) == 0x34); + static_assert((offsetof (struct sprite_type_1, b_u_b_v)) == 0x38); + static_assert((offsetof (struct sprite_type_1, c_u_c_v)) == 0x3c); + + struct modifier_volume { + uint32_t parameter_control_word; + float a_x; + float a_y; + float a_z; + float b_x; + float b_y; + float b_z; + float c_x; + float c_y; + float c_z; + uint32_t _res0; + uint32_t _res1; + uint32_t _res2; + uint32_t _res3; + uint32_t _res4; + uint32_t _res5; + }; + static_assert((sizeof (modifier_volume)) == 64); + static_assert((offsetof (struct modifier_volume, parameter_control_word)) == 0x00); + static_assert((offsetof (struct modifier_volume, a_x)) == 0x04); + static_assert((offsetof (struct modifier_volume, a_y)) == 0x08); + static_assert((offsetof (struct modifier_volume, a_z)) == 0x0c); + static_assert((offsetof (struct modifier_volume, b_x)) == 0x10); + static_assert((offsetof (struct modifier_volume, b_y)) == 0x14); + static_assert((offsetof (struct modifier_volume, b_z)) == 0x18); + static_assert((offsetof (struct modifier_volume, c_x)) == 0x1c); + static_assert((offsetof (struct modifier_volume, c_y)) == 0x20); + static_assert((offsetof (struct modifier_volume, c_z)) == 0x24); + static_assert((offsetof (struct modifier_volume, _res0)) == 0x28); + static_assert((offsetof (struct modifier_volume, _res1)) == 0x2c); + static_assert((offsetof (struct modifier_volume, _res2)) == 0x30); + static_assert((offsetof (struct modifier_volume, _res3)) == 0x34); + static_assert((offsetof (struct modifier_volume, _res4)) == 0x38); + static_assert((offsetof (struct modifier_volume, _res5)) == 0x3c); + +} + diff --git a/dreamcast2/memorymap.hpp b/dreamcast2/memorymap.hpp index a9d5f90..06cb6b4 100644 --- a/dreamcast2/memorymap.hpp +++ b/dreamcast2/memorymap.hpp @@ -1,3 +1,5 @@ +#pragma once + #include extern volatile uint8_t system_boot_rom[0x200000] __asm("system_boot_rom") __attribute__((aligned(32))); diff --git a/dreamcast2/regs.mk b/dreamcast2/regs.mk index 395539c..ac70528 100644 --- a/dreamcast2/regs.mk +++ b/dreamcast2/regs.mk @@ -13,16 +13,25 @@ holly/holly_bits.hpp: regs/holly/holly_bits.csv regs/render_bits.py holly/core/region_array_bits.hpp: regs/holly/core/region_array_bits.csv regs/render_bits.py python regs/render_bits.py $< holly::core::region_array > $@ -holly/core/object_list_bits.hpp:regs/holly/core/object_list_bits.csv regs/render_bits.py +holly/core/object_list_bits.hpp: regs/holly/core/object_list_bits.csv regs/render_bits.py python regs/render_bits.py $< holly::core::object_list > $@ -holly/core/parameter_bits.hpp:regs/holly/core/parameter_bits.csv regs/render_bits.py +holly/core/parameter_bits.hpp: regs/holly/core/parameter_bits.csv regs/render_bits.py python regs/render_bits.py $< holly::core::parameter > $@ +holly/ta/parameter_bits.hpp: regs/holly/ta/parameter_bits.csv regs/render_bits.py + python regs/render_bits.py $< holly::ta::parameter > $@ + +holly/ta/global_parameter.hpp: regs/holly/ta/global_parameter.csv regs/render_ta_parameter_struct.py + python regs/render_ta_parameter_struct.py $< holly::ta::global_parameter > $@ + +holly/ta/vertex_parameter.hpp: regs/holly/ta/vertex_parameter.csv regs/render_ta_parameter_struct.py + python regs/render_ta_parameter_struct.py $< holly::ta::vertex_parameter > $@ + # SH7091 -sh7091/sh7091.hpp: regs/sh7091/sh7091.csv regs/sh7091.py - python regs/sh7091.py $< sh7091 > $@ +sh7091/sh7091.hpp: regs/sh7091/sh7091.csv regs/render_sh7091.py + python regs/render_sh7091.py $< sh7091 > $@ sh7091/sh7091_bits.hpp: regs/sh7091/sh7091_bits.csv regs/render_bits.py python regs/render_bits.py $< sh7091 > $@ diff --git a/dreamcast2/regs/generic_sparse_struct.py b/dreamcast2/regs/generic_sparse_struct.py new file mode 100644 index 0000000..4f34bed --- /dev/null +++ b/dreamcast2/regs/generic_sparse_struct.py @@ -0,0 +1,126 @@ +from dataclasses import dataclass + +class EndOfInput(Exception): + pass + +def next_row(ix, rows, advance): + if ix >= len(rows): + raise EndOfInput + + if advance: + while rows[ix][0] == "": + ix += 1 + if ix >= len(rows): + raise EndOfInput + row = rows[ix] + ix += 1 + return ix, row + +@dataclass +class FieldDeclaration: + offset: int + name: str + default: int + array_length: str + +@dataclass +class StructDeclaration: + name: str + fields: list[FieldDeclaration] + size: int + +def parse_type_declaration(ix, rows, expected_offset, expected_sizes): + ix, row = next_row(ix, rows, advance=True) + assert len(row) in {2, 3}, row + struct_name, *empty = row + assert all(e == "" for e in empty) + fields = [] + last_offset = 0 - expected_offset + res_ix = 0 + + def terminate(): + size = last_offset + expected_offset + assert size in expected_sizes, size + return ix, StructDeclaration( + struct_name, + fields, + size + ) + + seen_names = set() + + while True: + try: + ix, row = next_row(ix, rows, advance=False) + except EndOfInput: + return terminate() + if row[0] == "": + return terminate() + else: + default = None + if len(row) == 2: + _offset, name = row + elif len(row) == 3: + _offset, name, _default = row + if _default.strip() != "": + default = int(_default, 16) + else: + assert False, row + offset = int(_offset, 16) + assert offset == last_offset + expected_offset, (hex(offset), hex(last_offset)) + last_offset = offset + if name == "": + name = f"_res{res_ix}" + res_ix += 1 + + if fields and fields[-1].name == name: + assert offset == fields[-1].offset + (fields[-1].array_length * expected_offset) + fields[-1].array_length += 1 + else: + assert name not in seen_names, row + seen_names.add(name) + fields.append(FieldDeclaration(offset, name, default, 1)) + +def parse(rows, expected_offset, expected_sizes): + ix = 0 + declarations = [] + while True: + try: + ix, declaration = parse_type_declaration(ix, rows, expected_offset, expected_sizes) + except EndOfInput: + break + declarations.append(declaration) + + return declarations + +def render_static_assertions(declaration): + yield f"static_assert((sizeof ({declaration.name})) == {declaration.size});" + for field in declaration.fields: + yield f"static_assert((offsetof (struct {declaration.name}, {field.name})) == 0x{field.offset:02x});" + +def render_declaration(declaration, get_type): + yield f"struct {declaration.name} {{" + + for field in declaration.fields: + type = get_type(field.name) + if field.array_length == 1: + yield f"{type} {field.name};" + else: + yield f"{type} {field.name}[{field.array_length}];" + + yield "};" # struct {declaration.name} + yield from render_static_assertions(declaration) + +def render_declarations(namespace, declarations, get_type): + yield f"namespace {namespace} {{" + for declaration in declarations: + yield from render_declaration(declaration, get_type) + yield "" + yield "}" + +def headers(): + yield "#pragma once" + yield "" + yield "#include " + yield "#include " + yield "" diff --git a/dreamcast2/regs/holly/ta/global_parameter.ods b/dreamcast2/regs/holly/ta/global_parameter.ods new file mode 100644 index 0000000000000000000000000000000000000000..5de39907813d9d5caaa3f5314213dc5cc0a9fb1a GIT binary patch literal 21537 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 NKMtVNF}=Qf^nXhgm=pj2 literal 0 HcmV?d00001 diff --git a/dreamcast2/regs/holly/ta/vertex_parameter.ods b/dreamcast2/regs/holly/ta/vertex_parameter.ods new file mode 100644 index 0000000000000000000000000000000000000000..d766222ce42934be1e3114e130fb42dffd712a9b GIT binary patch literal 16833 zcmbWfcUV))_CJgu(gmamNEZ;0-lPi%NbevZM0zhuFQEuhrHM)}(tGGgOXw)Qha$cA z8VI4}4W940=iK|d=l=1|dh%o@d(WDgHM3`b)|$1Vp^R~t6b%g<4XrP$`qc*qkw`8y zG_>0f>L)ZuTSrSbZx>5b7Z(Rxb5l24XD4nCCkrlTQ&(G8E@u}@CktnDcSlPnH!fF~ zcb29Wt~QpIZW{l_6UF9V=@BX?>+ED@YwiB-H#b*4Zc}q}O9x9-(fJ+sKi8!DFEwo) zO|30mxn*qK98FzZ|3_u2|5Dk_+1bIx)XCD}f7JVL-F12AZ2ivC)z!@Oe|7iae`(Rm z!P(T!@_*I(Z~b(2Gj((S|Iym*`2Kev|66M=&MxjQsQGmNA5!^mW4o>LS8LeV*uR$( zN(lc-_^6ztsgtdhrK=m)I}59UgaM~u9-@!~@eh`RQ_s0EG2cDuZLrI16%2ia$$gyi zU>+Qkpr@Hzyq!6|QZCQG5L1)7XZq+zR8?V{j(|BEbMH%=+AR*zCa#9OS<#uPIu5!N znj^d5yiE2+PbYQ}z}F9)!uSqD)!9$HQclFxn;F|Cp1pmE-(3@fjYAtPV+&jLqY@ch z#<9}Zblb^_^FF7Sh?)~E%BsROt41Ktuau{r@-d{eBuP-AuW> z937&y`ff$ne9jS<%JDQ#fdnsnTvk2a$2M=Cv1eYRzFWQy=i=%fx=?RY`6$4YK8QhZ-pos-8s&!q)Rxt`c<8eDuacc=VPM>~%S(}qbCbPCW zcbS4-<49e5@?+}3=(7x2ocG@38ISAEEi~Mg(**RiJJQ^As&Q#xX(?1N8)-;Gjns}P zo}|G(+6#xnzqzd8s}ZvqsGd94^d^k1LE@RGZvvwBEf3%3s& z)0x4+Y<_Bym2+J7@vw-3>~w1rQEu8@W%D5Pc4A+J#{;{E`JuQ&+BaJC3Cw#FyN98 zPJH(UVH=5B*I3xHmow!OD3QNI|6d}z44Z6VSR3zr;3Ul3n$ z@EwQn)02yJCnQfF6>X~mWm$ORgd&(`mqq~qF=2G;H|_WY(`hh1rZh)i>x)lcV$lc} z%5y5}SG6!1{dWnS?_JZzN-SX=T~#7`4x~gqubnd`eTk|K7LO{qn+29DJ;aIaPaxKI zJ$7j?%lkR-ozG)#!p^;# zY7Se(GXObJ+w*7uI>VW>F?!yyk?o8X953bx%ulYyhi{)$b^CnFv9`xQI5?QwwIM5h zkD*F92a#+>4j3JVi%6FWL`i_l)*!D-a5Hcyi!hGro&3M!pUJsZSduIq<`LIK>Sf?R zm~(q}yoq=|Rh~LoR|#t*9*e@DT4(Z*G_D zrNDpmYEw7bSvEl@)FAGlL45VB^NUzBrCwj(B!6F7obq4^!5fy*sUfISIURuY^}RD9 zylT6Zbn@*+wiX=fSau%}i71xZDoMzEj#!*rSE=T780bZz;-=~vZr zlO(XUAI>JgRp?Id3%Z{t9QwyEUK#_|cCt&@;SIcG?M}SynaKo0{dVz>ULov6oW<+< zE`svbIFlU2dkqc;Nh_H~ykaU^z)a-^W4%IkCc>nkSDYW#Yst4&yKM#5s*WsppiQw~ z`=2g;TX6XJfu!jAPF?NEdSr@V6VJBPmw9@~`zQ76NtCgR{YgDEnZDnAe14FWMEYLX zr}mg5n*hF$=7Z~gbQ-_S>r)`anni(<3Ug__5{aoCg0SM|;@&;?NU1v-OzT^CV8 zQaZ6=eT-9MU9PUo66`S2*yDN`gdDh0@r6{rqUkRoA5&60z~JYoVsjSvuH|8&KTIo4w>zwch_Nn5m`)hPd)GZ47$nNq{KaiQiI?7~qR!>ss_V?s zt^IRaYVdPv*$)AmCN86=?fOB^*WnFSE!1GV<=wk>7mt+p>snU9wD|jK%1+~Y?}AgC znl829C4|ZAMoyTR<>zMT`u`y3^5Oy5%w8O(ldXHT7cIxUbR()9E`m<-tqq(^?p`$a zwg1>He=UlW>RRyYk=0WI*u3I|+7n1CJV;5Vj_sJuu=?J}>x=Z4@ccXtQ6I$H;{7&e z-A75d0o8LK27qKI6YpKGPvbltIbTs(`3B~Euao#{;5eIxS$PoR&@1aI%xC_MPjQ`B z@72$Ze9Wz+k`E1z)u~8V%@X=k2^L_ju7p(5H7C03L_c$9Qng}xuD2~|`YY--w`oI< z&_R!v9#ri4$Nb->O|&-C38Pkyc-*#m*Ss2{XPbeJsa8~yV_C*jzQEM8VtWoe?fp$v zGsZ7ptx6Fsqq0)2{Q?%TkJTfvg+* ze7D0j%x92$W`MIrr}|CX4me$GXfN9StCqb#G=|5dr2R@+K8az=(ba24ez4X#eds3Gzo~G?WYZ72 zf`gZUnUka4WTd9bDl@pIHSfe%kfYf|t*M%0YeYqS7FT~5_a`md3RFP?H>zTzJK2Zb zzH%ka>|70pACCsoz5h+yjdVWtVQe&}Gjrx&-9p-$vgekq@*9^Mjia$IUyRmk97g;> z`UfPeA^5~w9JsrWb{|=aos+F~VTt`go-mJ?7@k&t>!S#oreTv))d^wifG8|L>Q)FA z05FM72nLsqz@*>^t7!SXeMMN4nOW0l;heFp0-NY1Dg(4tU=|e{+kE#FmvBuuOB0}7 zmz<^f2kEQl9Ii8F5oe8fi`^AK7eLSnWV_nmv$<>ICZC5EeM^!!Hm5OF1GiUisnN&g zg~CJeb~kdW4+ohxBb;^RB&Lv;RK@Mwe~?KFpfmMjg}bp9PF?v*-G0U~V@O%>Z))-| z()XRc_UcI=-875+{s{RkRn7KAO7WtyIbfr~CV)mjh2l3sSxp<+KclToXs{-6CxO&b zxv%h9`YC>se%OFMF2wzCL|AF`^)A!v5P`-;EauI^@nbAyZJBdk&Va9Oii#;wds4So zZe$hmNTgoORL*vjNKH-G?kWbSkVs+UXlTEux|$StPVk#l3#19yXr*Vcg7O3NiSpQT zv+iuEqW{47KMJNleyB<7PEYuoVs{j1-JDJj9h3@eaDVpv=x<3ziBt(zU9u zo^Td=oKwXPzqd=y_Cj6g8!G($71&)+lQlDE?iI(yC7mc@VBeCfnk||sn(3g~t1%p=Q|fJ2t&IBFSU0}B$Lh1>kJG*OekM?8 zEa}7_1{<`lS=jQgeHLbpWB)%Y9#q88!bFj~r0w(K=fyXkS`)m!0gNi!ug)?_54H@? zayPC;Xd8|xYo zs;ZH@cUJl4vC_Iy1iE66V!$<=T^ppACS<&ESFzJ~KiX4)wkR!QVSTD8=re;>+QpdS zs&7TO;`_+m{s82@rOR?A2rR~I8)^1k9Fm10IWvH(XOyxp5KFtzSM8aDKhZ z)A<$i2ZPbEm!i_ESCf{h)wGq6ZW&OJ1F>s<5vt?F^O*SDz^65N0BNUyum3j%S+J;>Hc!l&qL6wA<6+dPKzY)O?qnk$OiDB`=k##xZ= zBk02Y+{w_XAv)N;Wnq|Cy-Kp>m>*@O+mdIY{kT!@^r~(4f!1S1G>$q;)%Rk~#X1Tb zd3T$B`B@K{Sj`Wsj2^MEz^%Th(aT7snMY{^{lbo!V6HTCcO_8W6sH`LRDW$^czj1J zRu)%T#+&S8s)O4Tr>YF4aA;u6{YZ2uBRi{;+e>L#&-)?|`<_;EakF4Ot~UTa!YTh@ zmH?0y74fC=A=1ri*NEN}}?y}`fu^}^KN)_@?uF+!nOLO(+)U4#~3} zI6dO+-zUs}9R2h}6Pap5gQQUG^)9Q4Sx-6>he`?mHXxm#R9F{n>=t9D3t^ z5pBjAvR-4sjMh1lL?WJ=&ukkHCf~8X)qnTNFMOfe6k;8_bnfuuKy7*OU>bPk&${cS zfpcF6&b)L;Kiyksm(L#4?PnYeHl6!uYD~~d6~*V`(S`2@-h)* z;`7Dv9xr%sKg1pJ;tF%_i?U>?mChZxlqX%oh;qhRjOpwbCa!@5tPepSA@pmX>a- z@1^tdE0|JF%LVoD@-TV%*2qTnwy+Wo@QS@cejmoFn@Q}ro}qSR8a;pVjC?iOjc}p#|ylK&X7UKgUf7>rqz_^KOerGR(N? zF^~N6ciQmB(F`O7z6&jJl=<_QjrpJTRkEpmghKn9o}3gd+_3}9|Ezy)=1chQ6SkxZ zhJQ=RYVEUOA>EWpoiv+HkPodA-6RWU_D_em;tB{KZY%*30eo%6B0{ZTP^<~b;2PeT z%>z!gm{VqpDd#V|8}_ey6{l^j=5i~@qKJ9Zu7}JvGg=A~R^~=#8(KM}vyn#6UF3%H zzn0`sN3H4$%HEgJd3Dd|V)XcI_GKY*Gi`5ZzrypaV928ir57;K4tym=S?I8ngxgc^ znX8E+pAWB7790q^$%6)mhSWROvnbi96NbaV_!cc>#6}FQ_;pHLa-a8tw{1)DflPBk zgrl-8>!AEe0qauBGBVw$A#8hscT+PJWa+>=O?=$NSj&R;UCL6LNetP_>tKd)jHPX? zYYK%&O&Zr%=Jxw`RQ9sPFR1k%2O0q;0`4}b^z$-*~zkJXKGe70i3Y>98P5|p`Qdagv~fxMjA z2Hd_a2j9q>oZUl1yJ7iXTK=tF%GJ`%&DP2K_xp0saKUxv8IeB(!noqu4tnI66mp+o zpiL0UleD^z7$rVKPx)aO`?zNqax*Dp@xbo9urjGBS)92p&sl$GPCaw-wcjhurc4T*KIpQ?rePZ zt_4N%dLxGcTBCh4S15h`SR=QBr?&ZY`j^GyqfrAY5|16&vl#W2Gqz&67H@xl6ZK4| zFvjJR*1KXSPicPH2@Gye!%j9&?EpPOB`P$tS4c(y$AbFk4v&kLr~$(&DM2Utmu9Y2 z4e1Y?+lZ3%V?9}F)p{}&w*ZJ=NF&!emRRe7%86;LmpS5($UHismqJuv)R0dzM zo)7R5B8*o`y?GEsaI@qc@9Jr%%)LE-&Nrsf%5-{*2UNk&keqq0Pt3=C=n@%dFU0)q za-LwOnS3Jh4P&fL3EYQ^SdxAUa6N^QD%oI^fEcvhY@Y+ub8wTUnV7NSM+>_P8@@%t zOWOOrqpv(a`~VIevbxB&4TSu}+y#GRW=D7ag0Ud_`Yny4DXW};KfP0}UzJ>oj5$vs z5ggBqhxzlBz6aVS2FVDQ-S(3`I%e}$@;K5v)0p4N-y!?Aln7!^zwA|CL za*?56?qB`o_wz%gQURxU+g;j1CvdkEb8$x zITi>%c;+MzWq#*!gD@WYZS>`<-CF>>-78nLXZw6*^!6(lrvdpjZr1JIF_sO_rEowM zb-bA(@JfZEkb6@#M)7{i!dsy?qZp;NZ0*}AlvZ~n`JTOL&r$6m9X0ZXw|zRT zRIn6krPs+yU@w0i?2m7?crIxDX`G)>_0tLY+4{Ij)%`mhm!baQz~>YBi}jy(6tE}L zRkWcqhEI!s<`hcsEpy$$Pv_^%ibdDza04d?XU}c;h!+@16x%Zc>fXU-9)o;n$T>r!&);51pHO4<3_i#?)h!Ykwv(MlC-5?9U}7Rvf8 z2@-hNF3C>%BkXaZcReQ6Ki`G*TUGz`IN@122!Z53e_zMA2RLOA&`t?Hom@|IF9l`S z$dZi#xpe`UwVqR0q3znX*G+V6<5B+LkxQ)GT}m+HI?UlNY7=7obC>$_Fh-TNt%?x! z>+R>(=B{Jo?r7#@YU|+2?e=Gu%f-n$LPJe~0GH|(_7f<+e4&Mgb_am^3}B-S%4jiN z;g_f{D-9JLIdpV%JUl!S5)x`^Y9=No4h{}}ett1AFguMZrjCw|zP`S(v9a0N*_D-*ot>T2)6<)q z8&o?;B$5XaKa7S(kEZxSTE}ZzcS*yjL7Ofdej^bC0AGD=L zH$cc?UnyMG1-4tf3JHYYJOK~54Qq4bEzK?Mj4$}S5k`hO?KY&rZ+fAZvmHzotzz()?1a#CV~j%NVW@ z$Z&t!OBJAS1d>?B(=hP+QAR8-q^F0cHY@s|mAh3fY`iz<0=SXi>d4!v|E5g0AFMPq zdC!ULyIEBfn=7}VX9dNTAPJz5^Fup_uaTxIql>)@$3vRwXLc>dfgh4L3u$PxJij(w zJq4n52NjW33tAGBCmw5M9Py{@M!;nv6e+F9Zis1*2V{OQJ@JbpT2ILP8Wn$gf!@I@~UM5%ZO&XkzNl* zuNfg_7}a{^T#gB)Koieip{89(3U9_t(&zIW^%KKWXF%sxZGIGDyy{UlcDf(9w#=pw ze$h|E)%-A*E^;c}8SD9AT0FcMv7>Gf^Lo1`33@c!{K+=tqmJ}mwF$KqnE?DxF*PR*UDIWvmnlT5n2lcV6V z(&zzRc{u=c~Bi{_D@j;Psi@@Cs zqZ{9sD~E}*y}J5Apz|R{o*_@2VE(0FAzf6swX1n{q|j^g#s^+U&{@3&jm*q8VZ1w# zS{wdaW!_ho-9FE4?=h#ZbC+#|RE*L7qjd$IIN zB;Ff*XJ7B5G|6Xh2pZYzZcP7*FZRpK`VtVdkhSqZ*-p#J2fs>jKiyOo-0uR?uB48M zN?BLLFhezSXPPW>*{r;uNRLmEZ6d}fug)pKGFTSAj- z^uX)^FkzM{Q~JG|{aIZIo`p&7g(cZBjmE)XMjWJ;V`5{zBxgF?AEcZ!Idt8wa;=L@ z8hhitt9w&i)A=H#-S9#*62xy;3!#onRuga^YdYGSm|;%ijn=J`Tm>~!zWXIJf3&vU zIx24(0I{poWy8tP2w*sVmnd7N)*I5~pd2S+K=hK|Pjg8BqGRmwF>9xuq4y`BpI!qC zcOK}w$ORT9xB#o0h5+uKOJNmWnv@|NI$enkU%=C1MH*cQ!@0*bdgU48J=t0MTNrqr zxcd^ppwh$DysprAJFT8*oy>c+MLhh0O`8`jK0yX5oV}i^hHV;y1L##I0prGAjXc(C zYb?0PV?HO4Hs=-|?7J@Pz^B%c8AgF-9JNhB7-kZ-cJ}jppZGgRueTl~>o$cd3n1PvwP>41Ple>RRIQpt}zy z3D++RLCOfH<5%ERFqnBy)se8MatRx}l3xhoeLdk}%De1}wjcpCj*djo^YeT4zpY5h z2s_9Jb+mv7@4V0FW8xA#dzyYM?#GSr0TzIE#JTVza%?}buoe^gB1AKiNXF8jVLxC1fo>EfBaLmi5FY{ zIG{X3C`PT*697o$NwK9Z9*4UWt$M??uEfEg;95k0Wo17$m6JIr)EYs)@(|pF@L9n! zk@vg5cv%8AdG@Z7L(ql`XBfG0DUIU5()>3TfX0iZX_ zcli1J?HRjYxzmC#uXjxNT=*H`8WVZ$^Ed7-oxWJi*xCw>N$G`>yD(6Je1YDNx$1LJ z4%q3Vv^~sv`(SnlK!>&0YPPC8KV5c5?K9*Of!J;}V@&#Ty!xW2UL6758P|yQ*2mQp zU|m)|Qip5#(yehHF@s4v&s#3`Ikv|k{zMB3KpNaMAN+er<|}9b+HG<9hb`G|;voP@ z>~{czSs1WC2Xm&#vs$#G){FwscnDTVldXCI%8Wi}0hb@hf|Es%u<9e=I8^thu}p|1 zapT=5!R~WSK-dJGN$L-(OqyjA|FpCUn`A-jUBZ> zp&JI_jZg0d-|XZ{X*^u#070HS35ei6%A*H6_a%x>Mjy{jK&91@a!1Gul;{I*c6g6O z0uRc;PQwA$4t}06_dST(@iejD`KfyZx{I`5>|#?1h;S34_D7Ci*c9BM7z{_EZiRul zsMiHM&jU{uXn@A`Qh1^P&q5Ajz~$V}c~>E72#gP=VATGIY913MEUCZ)*GnkUZ}7Z4 zz#g?08&RW`+N1hR#Cp*0sSn5;xBwx&_1CGJcmwi5=iOJ(Z}=%ZI^4WfJTiG)lL1!c z$k*ACGO(py@sE+ZzqCDb`DB+JO_Y5hbo(!sL_w+;ssjOc`rIJkf976Cs`+`U`6sGzN0TMdVx=Qj0V#%=QP@zlZAF z8_-gd6mI;GGvku|CHhfa#bs>{6EcD_s0&J4^ zAz8$s+o}KEuOscsr)GwcHLXYHt|z_C5Y-aaP>?w=3Re)}x+_Blq)|5!S5AJLI?0+6Cv00ulX z|8vy_`Aq$}Y&sL)!ylk_GHJg*R`LH+KHv4D-c}Oqg|oeN33e=M$psN zj^H&3-W77CBr;hw`Wx7eYMI!iH!F~}TWi%zAa{yl0MB65=<()U%iCkr}nRxy;fXUwy&wm9s{eu_$M~j8u(l?*d>u z_{{#N{q8G$71D*D$sJZ}D-_j2ww0$AW3he=KO3I|8iOV|ag4gR^k~OjF~^y{Phw#X zmnmG4F#phJh{|Oz<5$u9R`vncd0@c^*m|Mf^e>R@v1_|OI8!M3I>uS$#XNdH$4DXO zg$H?t%w3ZdFA?mfAA5!cMM7?d9bMWnL?_8&uf2F*N|9Fj8fPkiX;?qOi#x`1uMM*% z0b-= zVM`_UmRQzPTzlE@`wNbSWAiX~+I6+ULEoisUs`bVu_*onVu$slCmkGX4jXXg)Z`)M zERrrK+Av3=cV;g9nHtIpIHaV;=$?ch5H2ahP9B2ku1qJHMIa*c2VU0%dn9nD8y=(a zauX`_Az;uL^ew#4aZT9o2khbeGr(yWF*N9)qM^&Hh^osSnN)t)6E&*>*lp z7uv?oKZ#-2io<{OX)k}n`DVv}dUE(h;lPjq1=bu9)<9Qm%Ukicl~zz{6Q!wbld&EK z>hTUA^40H-BG#%rP9}Txw}_gQyOMk&J-W#!ChLdHiJx%5!v;i0sj~NnWeeLErlq%7 zI^YCw{!d8Sd2-jTV+YDK(;~m;-IX-m=g{S7E*RC3|1&0}R1b7!baM|A|7$N9$gx~# z|4$T65s<|41n5{3RNRo^JN9wb33vc8!MIPHXrSy;&HfV6lOej-gTl}DLiT6wPa9$w zM_TejbPl}p>Rbr> z6AS5HgPmAJhZzY{+L)#_tt^|u#dva-2*N15)nFLX)~`6K7f}?Xv?nk zhfA&z`@R&*Uty})g9F_y3YFoVPwQFcwq+cjGk6iD}RS$3l;`_m-H=gWi%6>`@m ziSlKcmmiW5zA(VSzeD4gRJta!d=k~UQzt+D^AyUlSC%`nH)<6t6N3{$dC~1R{u5>; zS`Wm(-I!dPl7C_EtGk<=fEgsvK>_poA|%*4wu;lT#OcMpt zj_m#Ti(EebAd@%b+EK^G33@!AU8@62p>!xYDzu7la0_d~At{E?qOYfNhK|Jn&=NaGu6BeA7H-S@ef!S7`&dpPZ$+H z5P-dKvXwxpjsixn!%k4Z+SB{oYE)XYN@I}I+z~v|3c^=2)E2gBO0NK`#-14=aAOYuRc`jwc+caW8#NuV-C=_CF-&d#A>lbR4~aoE^4=?( z$Si_5g93n$YA~YWxxKCH?>*DJK|!h#jHrk=dc6rGGz*ej0Fbt<#JVxti;=W&?k=e% z-XT&@E154tA%N}Jyd3T(184Pu0SQ1X3J7OBRmS{LFE?hxf3uUf@aqypSb0;O zTnZ?X`!?fyI$m7z-IHGpvhGhAI{p5lNu*I-Ej6pTG1v4J`2OEPHI)1Sua*O~C9Cn` zT7#2H0f(Zh<`i+I+9kyZ4U_0G&~jWwQ=4+!fvD_`z^tZ`kzi-r@XSQtAqqmnfIo!! zHy|c+mmuL8aiGC@qR|4KsMz^lm1F%&{s0EmTDm#-B|md5PMNa=oV%jFYSGYLJ& z0hb>`9cy_n60V>h_D+a<2P}Yi1#Plf8C=8#dTTzPdIz3e8#=AfAN%<=!YDzKyN*Pi zLIITEScGWl%^{-Dv^$_>{AOpmD}d%J3NqU98$b@r1OXDY#nE&(>2DFt=yjV{?!pS^ z17Q*v$}c5S*P;$lkL4Zf!%+7#bdV8sQyinu_Sco&*qA1%R(Zi zqA8FtOX4xDOo~>V&&P!y5+#Ss3LUQyT`U#7l$wp0;BKKqI#7$W z7~K5Ua*y)BPVDz5p@2-(^K{<_!EKJ{a2{gWhj#xIJ3;9?cdnr;tVh?zJU4X%4>PxR z?p;Is7M)LFh-?r*u%K#vOY9JJS1qzJ`9^XadUCL}gAar4qMmofwNAw*&&8$!kTPi? z!38KlA8=rJkq6FzA868fz+foG1Bci7;QPYB^u6sJ9N*yLt7P!tuaJuvVw83>0p;`y z6GMn9&oc%5pSnbO1VCy7=VU*LA$*QmZndlyU#gT$(=lj|)F||Tm1S-)lG2w1EQV+V zqjkk05h#sJW!)Djah(N%bQQ*&h6S`i;cqXvPhll#{u59|smm2O1`x=IQbrTuV5x=r zeLw*45B17@6zYyl=0&2uH3N9oAvXaqm=V&4_A!thkZ}M8(>^=_AOjGhO=qAD4=5b8 z-+5~ATQkZzbyr^$L>`)!LK z@Kytniaj_m0{{XNZ@||#Fg6_26w&2@s&ny|g`Xi&Q<|5FACcU)p@|T!k7PJAxm_MH zB+XRE04XJawWPo56h!=1VM($FOBDyuEL6E|CvIFOgPpdA{XT-hXGo<2Z|~bZ7d1q} z9e{qlg1rx_e8cm{kV(Q4P4GcOo(pu{Nl1hy!bjN6_Tt_OUSz?^mqWsJ*2}0H_lta# z^5h2q&~*zB0&s5)GU0z%4iZtj`fd3S<@k2;{w#O#`laTGntlCnxPN$U)${s1b-q{R zxH$5Qz*X5tRYuw}yp)dbfK1?>-7F?Ahtg8=G;-gP%8u#V69g#BG3j^C{h2PK zlBCLwhFWgmYJ#!K^!3`V^WLQ!{erv4aFs$yieZ(wG4Um~>s+$fCX4mM-QNn0 z5uJBm*)ZXrm;&X#+H*hCR2l(LrMWS$t{TP1!L> z{q|FF{utin+IO~k^?9;gy&4l|g>1Jj6Yk&sXNzjU^ zBb)ZyGD2lzTn6^ug}G^IN|VWo7pMaRfH8;Ivknhi3e_n#O) zn(xuiJF6naG;)NW)*=UO&8HhcQo?f_@U@{Bd7eQ_>J4_ohx~99-E_P-Q^eh$p%zza2{#I_J>y z#Pnl~;mV2lyNSXslKx~du|jAniIW$N3LgN@@YF;nR8qwwEpKwzNSa?nQ-Dy2f(ueY zXoAU~l72a1lh>}8^)CCamO`$RMaIE4pgk-6p0#`qfy!%%^Ys?$*0-8D*1_6$Sh9?Q zd(iR?m0hAH3W>d=?OODOQChLozTY0#lDPXGzdpUxPB8Xi>DoG3 zJYQipwv}fD>VQD7{k@aa63MYXiJbe#q5$WdXumv^836L)I!E?F&)1u(7c$g6@e)JD ziz`EB>R-NeMo=uLa@42#bO?4vaw*l2M0OHBRXXA*Qw;FfbYDId2A5$elEpe!l#L4U z2TMp4+-ye%Cg!j{Sua)o;O}a+-LVZx7}S%*kEAs0{H!NY^L1Iw_(Ig(SPlzpZK z09wO^k9?s&Qx2Lf9>!)_ZEG}?*`3;#FqvG1AS%8q(qY;KY>nJEELSGNGT!dD+IAKt zpBy!CPxv13!XbI~OQo?IN*8L44K>^wFcmOyYV@?Lq9FXGDGyc+Ua(7si(haArr#X~(rt^Wug~*6=kE7RVnJ|n?w6>GpB=@W zPstIx7%-cQcC=f=W)cw8a=12hxjY3n*mn&AXc{{DgI~n&8YC^|)=~FC>C%VDzc-m~#wAliQsC z)&2<*W%pk&YA5(G%zGU>u%^DDjCkBN;3g zCc-3u5_ce2rY~O`HlMiFq0FJyPP*OYlwp=z(iQ!7s%EgZfSmf2%<#6WRh@uV;Ng`upQ^np+Oq59A1rM9i-0 zP|${Z#EF^|nR`)KM1x0+97HoPyJjetnBNMy{KRw-(4~vKcF` zU)>qA0+Q;tjR*TV_%S7fsSRSA;B6EWq72j$@rB>^_X{6NJR?M%jkJK`ovlKhY4WFk zcfGnJY)0sWvk`xnABe02fnx3aOs)2KIFKR6U?mr1pdyBttedFFBTJbO(Oq9Jn)PcGU=>CS6m~-WqsAj-I26#{b zWz^qR4*eyi37i^%uG9z>4GSTE!FRS`OF3W@%2l!HjU(e56+q84m4%ahK7m?JdB6yy zoaWWXwCA~Z-Bqelt_ZJgeF5}z_2(kGDNtyrAH#|T7!^|a{TVSJlCDSp0YGb{P!e_2 za%s;=@B6TK!E+g<<;jAqz5P%KFq6mMcNofW?l#+a1}MNezQ5=T0_pd)TRYJ1jfe@Z z-`zx>pcD@Gj@&Ujl0nvf6Bk^RE`TV`leR*kE(esgAI2HriZVVIloIL#fqe_3X-LF0 ze12=EgyH+_@_0!16;$2R|11lnE@$dGBDgH$gLfs0 z5aH9jy@Tqdt)Gf%B=>|-?{8CXCMojHmIsE$Qo{~2%JTwEQBLhexy+mQ|Lhn}hPq2t zPDh$kQB9uvU$K}dAMvsTX{Qc)BDr&s4_$S9xqJCCZ>tK&Npi8WtX$#_1K)&ynx!y$ zyIdSesyrP;2|2eWN}Vh6oFF!R z%4b8@!beLi5?)Nmei~PzL#uUmC4718-10~jI`_0ytSKu!Y^*anJ?(k7^?0NbOzv(0 z+Q@x{UPb4Rj?#nJIkrv3PMi;Svbffc{P5mXxw>n(*(7~W-4VJwtT*9yf0&2tef8eM zmya}0-rn<@7gc9?Ke~nXT;*xR@z%%`S5JJ#d}lDRmb?i|YxUY*T7`-va78l}t21vq z?l+<_YfGVr2;2%n;ycQlmmpp&Bga~$>U{QQ;vjH>?6T7TVvhISiz z{8!RJW&d~F^uM?NS4}ju+sNs^QVc5lpPc@mIO>09b{jMNSL#D$|C8C@iZ`OaFz--{Z9Zna{uXh7$e%mCavq+kbHRGxYfHLCLosvVSFY6qkSP9jG|&KNsu=h z^Plzp?soU@1KdD8#(#GR{> {min(bits)}) & {hex(mask_value)};" " }" ) @@ -173,7 +173,7 @@ def render_mask(bit_def): 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"constexpr inline uint32_t {escape(bit_def['bit_name'])}(uint32_t num) {{ " f"return (num & {hex(mask_value)}) << {min(bits)};" " }" ) diff --git a/dreamcast2/regs/render_ta_parameter_struct.py b/dreamcast2/regs/render_ta_parameter_struct.py new file mode 100644 index 0000000..134ffc6 --- /dev/null +++ b/dreamcast2/regs/render_ta_parameter_struct.py @@ -0,0 +1,68 @@ +import sys + +from generate import renderer +from csv_input import read_input_headerless +from generic_sparse_struct import parse +from generic_sparse_struct import headers +from generic_sparse_struct import render_declarations + +_field_types = { + "parameter_control_word": "uint32_t", + "user_clip_": "uint32_t", + "object_pointer": "uint32_t", + "bounding_box_": "uint32_t", + "isp_tsp_instruction_word": "uint32_t", + "tsp_instruction_word": "uint32_t", + "texture_control_word": "uint32_t", + "data_size_for_sort_dma": "uint32_t", + "next_address_for_sort_dma": "uint32_t", + "face_color_": "float", + "face_offset_color_": "float", + "x": "float", + "y": "float", + "z": "float", + "base_color_": "float", + "base_color_0": "uint32_t", + "base_color_1": "uint32_t", + "offset_color_0": "uint32_t", + "offset_color_1": "uint32_t", + "base_intensity_": "uint32_t", + "u": "float", + "v": "float", + "u_v": "uint32_t", + "base_color": "uint32_t", + "offset_color": "uint32_t", + "offset_color_": "float", + "base_intensity": "float", + "offset_intensity": "float", + "a_": "float", + "b_": "float", + "c_": "float", + "d_": "float", + "a_u_a_v": "uint32_t", + "b_u_b_v": "uint32_t", + "c_u_c_v": "uint32_t", + "_res": "uint32_t" +} + +def get_type(field_name: str): + match = None + match_len = 0 + for name, type in _field_types.items(): + if field_name.startswith(name) and len(name) >= match_len: + match = type + assert match_len != len(name), (name, match) + match_len = len(name) + assert match != None, field_name + return match + +if __name__ == "__main__": + rows = read_input_headerless(sys.argv[1]) + namespace = sys.argv[2] + declarations = parse(rows, + expected_offset=4, + expected_sizes={32, 64}) + render, out = renderer() + render(headers()) + render(render_declarations(namespace, declarations, get_type)) + print(out.getvalue()) diff --git a/dreamcast2/regs/sh7091/sh7091_bits.ods b/dreamcast2/regs/sh7091/sh7091_bits.ods index 5956d1ea4f1364536bb1c782627711415f2bb663..77472eb1ab096d7aef3f96cbf455e8e589e27130 100644 GIT binary patch literal 28268 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 ARsaA1 delta 25087 zcmZs?1yoyG)HRA0EiGQ$2`(+#pe+;+?(PMOLns=G7AY1S0xj+qw75fYcXtR-q(IS^ zd++=H_rCGo7|F;vzy3cx6H!V2YgvXW^gjpmQ2kE? z|GNu4n&^L5jnOzDEnJ2g{>qc!23X$#D8W(kM2ea12PzH$iat2N-}RhTmc4$e98s;( zLUr1KE@iqVZZq#4n8=W@HXPI>>25{~#n@TOSQyKOxTL_Fm)4A+0jL|$f;tf3PfAEc}Y!%f` zKl4|iWym9e0B{7tU@$yYN!?_Xq|1S-3?gAxeFikk;H7sjay4F%xXLTZStdd#z_lUC zF$L><_8RNHM1=(kVkHXrE=I2_)uP0EaoHopzy1)&^zIa6>(-x)_$@Rg+hE<6Z>me5>9I5;Se#&F&^JL#TG^E0Z-@M{9qC~RU^TS|qnPYV!_$<@?VHHcZ6>%CK0dMt7He(V(Y|n%P2C%hUKpHFwPW zTXNmhcaL~r;k$`ortZXnIFa;s#*apoWUC}A1dy-Qwp!euK`X2y8NwuiHb!1zjo58gWqZNyeB8eg+uG{?^M~yEU7lyw!f&(hQcG6 zsuE;EigTc=?S!jGzBW)2vi~coj=H-a{H!i7S+CViX`i5uCFOfNM9t~+Y>x!M>73Je zS>^3?qkzG;mFO3LYsOe|nz6s>hRS0TV`M0+(9;-V6j~|(O420=N>ajYRT_xk%zlou z^d*Gah%f=)?OHud@g)~JA-DhU!na1H?7k4m>Y`=}1({bQ78NBTRCpQ`L1tq(oPp75 ziBdW0s65~fH{L7n;cE_}q*=!6xXj~8Nw)Bluy^#7ApSROWLZ;6+NNaD_Qo%;69H;G z7H-}7GVYzafAuBJzkXa%S7(ET|o?YHeDd3 z#M&G%wLZ2%DG7t#MQ^&Sxa(JL)ke*x^dmFFcD~Q-yFS`1`n(J%^ce?Sdml=-63ok* z{1|x_87!>)_lt{&%x+?}J}pC|iZ_$C+#ISlSSEomnn;uCwN$7VCUAzNJwK5e{E``w zGXBJ}-$|&RHE>)bd0m;TYaLxW3}bu{Ml?OxKsGLmQ=ayDlvp%8a(o(a4jz8!S>l9?j2x}O{x&-wFSI~Gx1 zs|l7=f0687d_1Qybf$9skYdJ6HGJ{bO-X!uNdI&GeTdLb2&H8$`x)qTjdM{NLZujO z&YAA0s$HoJn_LouFS+}c#7H_Yi0-n#Z(6K6}7|N4gEJ#W#G+?=J*lB7{5v8q

wvz=n`1t| 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 + constexpr inline uint32_t address(T a) { return (((uint32_t)a) >> 24) & 0b11100; } +} + +namespace sh7091::ccn::qacr1 { + template + constexpr inline uint32_t address(T a) { return (((uint32_t)a) >> 24) & 0b11100; } +} diff --git a/dreamcast2/sh7091/sh7091_bits.hpp b/dreamcast2/sh7091/sh7091_bits.hpp index f6ac2c4..6ad2844 100644 --- a/dreamcast2/sh7091/sh7091_bits.hpp +++ b/dreamcast2/sh7091/sh7091_bits.hpp @@ -5,12 +5,12 @@ 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; } + constexpr inline uint32_t VPN(uint32_t reg) { return (reg >> 10) & 0x3fffff; } + constexpr inline uint32_t ASID(uint32_t reg) { return (reg >> 0) & 0xff; } } namespace ptel { - constexpr uint32_t PPN(uint32_t reg) { return (reg >> 10) & 0x7ffff; } + constexpr inline uint32_t PPN(uint32_t reg) { return (reg >> 10) & 0x7ffff; } namespace v { constexpr uint32_t invalid = 0 << 8; @@ -67,9 +67,9 @@ namespace sh7091 { } 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; } + constexpr inline uint32_t LRUI(uint32_t reg) { return (reg >> 26) & 0x3f; } + constexpr inline uint32_t URB(uint32_t reg) { return (reg >> 18) & 0x3f; } + constexpr inline uint32_t URC(uint32_t reg) { return (reg >> 10) & 0x3f; } namespace sqmd { constexpr uint32_t user_privileged_access_possible = 0 << 9; @@ -100,11 +100,11 @@ namespace sh7091 { } namespace basra { - constexpr uint32_t basa(uint32_t num) { return (num & 0xff) << 0; } + constexpr inline uint32_t basa(uint32_t num) { return (num & 0xff) << 0; } } namespace basrb { - constexpr uint32_t basa(uint32_t num) { return (num & 0xff) << 0; } + constexpr inline uint32_t basa(uint32_t num) { return (num & 0xff) << 0; } } namespace ccr { @@ -171,15 +171,15 @@ namespace sh7091 { } namespace tra { - constexpr uint32_t imm(uint32_t reg) { return (reg >> 2) & 0xff; } + constexpr inline uint32_t imm(uint32_t reg) { return (reg >> 2) & 0xff; } } namespace expevt { - constexpr uint32_t exception_code(uint32_t reg) { return (reg >> 0) & 0xfff; } + constexpr inline 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; } + constexpr inline uint32_t exception_code(uint32_t reg) { return (reg >> 0) & 0xfff; } } namespace ptea { @@ -205,18 +205,18 @@ namespace sh7091 { } namespace qacr0 { - constexpr uint32_t area(uint32_t num) { return (num & 0x7) << 2; } + constexpr inline uint32_t area(uint32_t num) { return (num & 0x7) << 2; } } namespace qacr1 { - constexpr uint32_t area(uint32_t num) { return (num & 0x7) << 2; } + constexpr inline 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; } + constexpr inline uint32_t transfer_count(uint32_t num) { return (num & 0xffffff) << 0; } } namespace chcr { @@ -305,7 +305,7 @@ namespace sh7091 { } namespace rs { - constexpr uint32_t resource_select(uint32_t num) { return (num & 0xf) << 8; } + constexpr inline uint32_t resource_select(uint32_t num) { return (num & 0xf) << 8; } constexpr uint32_t bit_mask = 0xf << 8; } @@ -429,23 +429,23 @@ namespace sh7091 { } 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; } + constexpr inline uint32_t TMU0(uint32_t num) { return (num & 0xf) << 12; } + constexpr inline uint32_t TMU1(uint32_t num) { return (num & 0xf) << 8; } + constexpr inline uint32_t TMU2(uint32_t num) { return (num & 0xf) << 4; } + constexpr inline 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; } + constexpr inline uint32_t WDT(uint32_t num) { return (num & 0xf) << 12; } + constexpr inline uint32_t REF(uint32_t num) { return (num & 0xf) << 8; } + constexpr inline 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; } + constexpr inline uint32_t GPIO(uint32_t num) { return (num & 0xf) << 12; } + constexpr inline uint32_t DMAC(uint32_t num) { return (num & 0xf) << 8; } + constexpr inline uint32_t SCIF(uint32_t num) { return (num & 0xf) << 4; } + constexpr inline uint32_t UDI(uint32_t num) { return (num & 0xf) << 0; } } } @@ -653,13 +653,13 @@ namespace sh7091 { namespace scfsr2 { namespace per3_0 { - constexpr uint32_t number_of_parity_errors(uint32_t reg) { return (reg >> 12) & 0xf; } + constexpr inline 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 inline uint32_t number_of_framing_errors(uint32_t reg) { return (reg >> 8) & 0xf; } constexpr uint32_t bit_mask = 0xf << 8; } @@ -770,8 +770,8 @@ namespace sh7091 { } 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; } + constexpr inline uint32_t transmit_data_bytes(uint32_t reg) { return (reg >> 8) & 0x1f; } + constexpr inline uint32_t receive_data_bytes(uint32_t reg) { return (reg >> 0) & 0x1f; } } namespace scsptr2 { @@ -836,7 +836,7 @@ namespace sh7091 { 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 inline uint32_t imask(uint32_t num) { return (num & 0xf) << 4; } constexpr uint32_t s = 1 << 1; constexpr uint32_t t = 1 << 0; } diff --git a/dreamcast2/sh7091/store_queue_transfer.hpp b/dreamcast2/sh7091/store_queue_transfer.hpp index 6f8e205..bbc8bd3 100644 --- a/dreamcast2/sh7091/store_queue_transfer.hpp +++ b/dreamcast2/sh7091/store_queue_transfer.hpp @@ -1,6 +1,7 @@ #pragma once #include "sh7091/sh7091.hpp" +#include "sh7091/pref.hpp" #include "memorymap.hpp" namespace sh7091 { @@ -31,10 +32,7 @@ namespace sh7091 { base[5] = src32[5]; base[6] = src32[6]; base[7] = src32[7]; - asm volatile ("pref @%0" - : // output - : "r" (&base[0]) // input - : "memory"); + pref(&base[0]) length -= 32; base += 8; src32 += 8; @@ -66,10 +64,7 @@ namespace sh7091 { base[5] = value; base[6] = value; base[7] = value; - asm volatile ("pref @%0" - : // output - : "r" (&base[0]) // input - : "memory"); + pref(&base[0]); length -= 32; base += 8; } diff --git a/dreamcast2/systembus/systembus_bits.hpp b/dreamcast2/systembus/systembus_bits.hpp index 95ace0c..fc944c6 100644 --- a/dreamcast2/systembus/systembus_bits.hpp +++ b/dreamcast2/systembus/systembus_bits.hpp @@ -4,11 +4,11 @@ namespace systembus { namespace c2dstat { - constexpr uint32_t texture_memory_start_address(uint32_t num) { return (num & 0x13ffffe0) << 0; } + constexpr inline uint32_t texture_memory_start_address(uint32_t num) { return (num & 0x13ffffe0) << 0; } } namespace c2dlen { - constexpr uint32_t transfer_length(uint32_t num) { return (num & 0xffffe0) << 0; } + constexpr inline uint32_t transfer_length(uint32_t num) { return (num & 0xffffe0) << 0; } } namespace c2dst { @@ -74,9 +74,9 @@ namespace systembus { } namespace ffst { - constexpr uint32_t holly_cpu_if_block_internal_write_buffer(uint32_t reg) { return (reg >> 5) & 0x1; } - constexpr uint32_t holly_g2_if_block_internal_write_buffer(uint32_t reg) { return (reg >> 4) & 0x1; } - constexpr uint32_t aica_internal_write_buffer(uint32_t reg) { return (reg >> 0) & 0x1; } + constexpr inline uint32_t holly_cpu_if_block_internal_write_buffer(uint32_t reg) { return (reg >> 5) & 0x1; } + constexpr inline uint32_t holly_g2_if_block_internal_write_buffer(uint32_t reg) { return (reg >> 4) & 0x1; } + constexpr inline uint32_t aica_internal_write_buffer(uint32_t reg) { return (reg >> 0) & 0x1; } } namespace istext { diff --git a/tools/ftdi_transfer.cpp b/tools/ftdi_transfer.cpp index 98c4bb6..50da748 100644 --- a/tools/ftdi_transfer.cpp +++ b/tools/ftdi_transfer.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,48 @@ int init_ftdi_context(struct ftdi_context * ftdi, uint32_t scbrr) } ftdi_list_free(&devlist); + + if (0) { + for (int i = 0; i < 2; i++) { + timespec t = {.tv_sec = 0, .tv_nsec = 33000 * 2 }; + + // toggle ACBUS5 low (g reset asserted) + uint8_t bitmask1 = (0b0001 << 4) | (0b0001 << 0); + res = ftdi_set_bitmode(ftdi, bitmask1, BITMODE_CBUS); + if (res < 0) { + fprintf(stderr, "ftdi_set_bitmode: %s\n", ftdi_get_error_string(ftdi)); + return -1; + } + printf("cbus1\n"); + + nanosleep(&t, NULL); + + // toggle ACBUS5 low (g reset deasserted) + uint8_t bitmask2 = (0b0000 << 4) | (0b0001 << 0); + res = ftdi_set_bitmode(ftdi, bitmask2, BITMODE_CBUS); + if (res < 0) { + fprintf(stderr, "ftdi_set_bitmode: %s\n", ftdi_get_error_string(ftdi)); + return -1; + } + printf("cbus2\n"); + + nanosleep(&t, NULL); + } + + uint8_t bitmask2 = (0b0000 << 4) | (0b0000 << 0); + res = ftdi_set_bitmode(ftdi, bitmask2, BITMODE_CBUS); + if (res < 0) { + fprintf(stderr, "ftdi_set_bitmode: %s\n", ftdi_get_error_string(ftdi)); + return -1; + } + + sleep(2); + printf("cbus3\n"); + ftdi_disable_bitbang(ftdi); + //while (1); + //return 0; + } + res = ftdi_set_baudrate(ftdi, round(dreamcast_rate(current_cks, scbrr))); if (res < 0) { fprintf(stderr, "ftdi_set_baudrate: %s\n", ftdi_get_error_string(ftdi));