From dacdad61321459b58b0846ab8da20ea58c47457a Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Mon, 25 Aug 2025 16:40:15 -0500 Subject: [PATCH] dreamcast2: add triangle_core --- dreamcast2/Makefile | 6 + dreamcast2/addresses.lds | 2 +- dreamcast2/common.lds | 6 +- dreamcast2/example/example.mk | 7 + dreamcast2/example/framebuffer_shaded.cpp | 2 +- dreamcast2/example/triangle_core.cpp | 180 ++++++++++++++++ dreamcast2/holly/core/object_list_bits.hpp | 51 +++++ dreamcast2/holly/core/parameter.hpp | 144 +++++++++++++ dreamcast2/holly/core/parameter_bits.hpp | 195 ++++++++++++++++++ dreamcast2/holly/core/region_array.cpp | 77 +++++++ dreamcast2/holly/core/region_array.hpp | 39 ++++ dreamcast2/holly/core/region_array_bits.hpp | 20 ++ dreamcast2/holly/object_list_bits.hpp | 53 ----- dreamcast2/holly/region_array.cpp | 71 ------- dreamcast2/holly/region_array.hpp | 41 ---- dreamcast2/holly/region_array_bits.hpp | 22 -- dreamcast2/memorymap.hpp | 26 +-- dreamcast2/regs.mk | 11 +- .../holly/{ => core}/object_list_bits.ods | Bin dreamcast2/regs/holly/core/parameter_bits.ods | Bin 0 -> 28007 bytes .../holly/{ => core}/region_array_bits.ods | Bin dreamcast2/regs/render_bits.py | 7 +- dreamcast2/runtime.cpp | 6 - 23 files changed, 749 insertions(+), 217 deletions(-) create mode 100644 dreamcast2/example/triangle_core.cpp create mode 100644 dreamcast2/holly/core/object_list_bits.hpp create mode 100644 dreamcast2/holly/core/parameter.hpp create mode 100644 dreamcast2/holly/core/parameter_bits.hpp create mode 100644 dreamcast2/holly/core/region_array.cpp create mode 100644 dreamcast2/holly/core/region_array.hpp create mode 100644 dreamcast2/holly/core/region_array_bits.hpp delete mode 100644 dreamcast2/holly/object_list_bits.hpp delete mode 100644 dreamcast2/holly/region_array.cpp delete mode 100644 dreamcast2/holly/region_array.hpp delete mode 100644 dreamcast2/holly/region_array_bits.hpp rename dreamcast2/regs/holly/{ => core}/object_list_bits.ods (100%) create mode 100644 dreamcast2/regs/holly/core/parameter_bits.ods rename dreamcast2/regs/holly/{ => core}/region_array_bits.ods (100%) diff --git a/dreamcast2/Makefile b/dreamcast2/Makefile index 5f4be2d..d2c452f 100644 --- a/dreamcast2/Makefile +++ b/dreamcast2/Makefile @@ -7,3 +7,9 @@ CFLAGS += -I$(MAKEFILE_PATH) LIB ?= $(MAKEFILE_PATH) include example/example.mk + +clean: + find -P \ + -regextype posix-egrep \ + -regex '.*\.(iso|o|d|bin|elf|cue|gch)$$' \ + -exec rm {} \; diff --git a/dreamcast2/addresses.lds b/dreamcast2/addresses.lds index 1cd560c..7a5f752 100644 --- a/dreamcast2/addresses.lds +++ b/dreamcast2/addresses.lds @@ -1,6 +1,6 @@ system_boot_rom = 0xa0000000; -system = 0xa05f6800; +systembus = 0xa05f6800; maple_if = 0xa05f6c00; gdrom_if = 0xa05f7000; g1_if = 0xa05f7400; diff --git a/dreamcast2/common.lds b/dreamcast2/common.lds index ad18b42..19ea551 100644 --- a/dreamcast2/common.lds +++ b/dreamcast2/common.lds @@ -2,15 +2,15 @@ SECTIONS { . = ORIGIN(p2ram); - .text.start : + .text.start ALIGN(4) : { KEEP(*(.text.start)) - *(.text.startup.*) + *(.text.start.*) } > p2ram AT>p1ram . = ORIGIN(p1ram) + (. - ORIGIN(p2ram)); - .text : + .text ALIGN(4) : SUBALIGN(4) { *(.text.*) *(.text) diff --git a/dreamcast2/example/example.mk b/dreamcast2/example/example.mk index 1232778..0934c88 100644 --- a/dreamcast2/example/example.mk +++ b/dreamcast2/example/example.mk @@ -7,3 +7,10 @@ FRAMEBUFFER_SHADED_OBJ = \ 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) diff --git a/dreamcast2/example/framebuffer_shaded.cpp b/dreamcast2/example/framebuffer_shaded.cpp index 97364be..485bdc3 100644 --- a/dreamcast2/example/framebuffer_shaded.cpp +++ b/dreamcast2/example/framebuffer_shaded.cpp @@ -4,7 +4,7 @@ void main() { - volatile uint32_t * framebuffer = (volatile uint32_t * )texture_memory32; + volatile uint32_t * framebuffer = (volatile uint32_t * )&texture_memory32[0x200000]; for (int y = 0; y < 480; y++) { for (int x = 0; x < 640; x++) { diff --git a/dreamcast2/example/triangle_core.cpp b/dreamcast2/example/triangle_core.cpp new file mode 100644 index 0000000..b9cc291 --- /dev/null +++ b/dreamcast2/example/triangle_core.cpp @@ -0,0 +1,180 @@ +#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/holly.hpp" +#include "holly/holly_bits.hpp" + +void transfer_object_list(uint32_t object_list_start, uint32_t triangle_array_offset) +{ + using namespace holly::core; + + volatile uint32_t * object_list = (volatile uint32_t *)&texture_memory32[object_list_start]; + + object_list[0] = object_list::pointer_type::triangle_array + | object_list::triangle_array::number_of_triangles(0) + | object_list::triangle_array::skip(1) + | object_list::triangle_array::start(triangle_array_offset / 4); + + object_list[1] = object_list::pointer_type::object_pointer_block_link + | object_list::object_pointer_block_link::end_of_list; +} + +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_triangle_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 + | isp_tsp_instruction_word::gouraud_shading; + + 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 = 1.0f; + polygon->vertex[0].y = 29.0f; + polygon->vertex[0].z = 0.1f; + polygon->vertex[0].base_color = 0xff0000; + + polygon->vertex[1].x = 16.0f; + polygon->vertex[1].y = 3.0f; + polygon->vertex[1].z = 0.1f; + polygon->vertex[1].base_color = 0x00ff00; + + polygon->vertex[2].x = 31.0f; + polygon->vertex[2].y = 29.0f; + polygon->vertex[2].z = 0.1f; + polygon->vertex[2].base_color = 0x0000ff; +} + + +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() +{ + uint32_t framebuffer_start = 0x200000; + 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); + + using polygon = holly::core::parameter::isp_tsp_parameter<3>; + + uint32_t triangle_offset = (sizeof (polygon)) * 0; + uint32_t background_offset = (sizeof (polygon)) * 1; + + transfer_object_list(object_list_start, + triangle_offset); + + transfer_triangle_polygon(isp_tsp_parameter_start + triangle_offset); + + transfer_background_polygon(isp_tsp_parameter_start + background_offset); + + { + using namespace holly; + using holly::holly; + + // 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 + holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4) + | isp_backgnd_t::tag_offset(0) + | isp_backgnd_t::skip(1); + + holly.ISP_BACKGND_D = 0.000001f; + + // 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; + } +} diff --git a/dreamcast2/holly/core/object_list_bits.hpp b/dreamcast2/holly/core/object_list_bits.hpp new file mode 100644 index 0000000..78256a5 --- /dev/null +++ b/dreamcast2/holly/core/object_list_bits.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include + +namespace holly::core::object_list { + namespace pointer_type { + constexpr uint32_t triangle_strip = 0b000 << 29; + constexpr uint32_t triangle_array = 0b100 << 29; + constexpr uint32_t quad_array = 0b101 << 29; + constexpr uint32_t object_pointer_block_link = 0b111 << 29; + + constexpr uint32_t bit_mask = 0x7 << 29; + } + + namespace triangle_strip { + namespace mask { + constexpr uint32_t t0 = 0b100000 << 25; + constexpr uint32_t t1 = 0b010000 << 25; + constexpr uint32_t t2 = 0b001000 << 25; + constexpr uint32_t t3 = 0b000100 << 25; + constexpr uint32_t t4 = 0b000010 << 25; + constexpr uint32_t t5 = 0b000001 << 25; + + constexpr uint32_t bit_mask = 0x3f << 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; } + } + + namespace triangle_array { + constexpr 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; } + } + + namespace quad_array { + constexpr 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; } + } + + 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; } + } + +} diff --git a/dreamcast2/holly/core/parameter.hpp b/dreamcast2/holly/core/parameter.hpp new file mode 100644 index 0000000..0601125 --- /dev/null +++ b/dreamcast2/holly/core/parameter.hpp @@ -0,0 +1,144 @@ +#include + +namespace holly::core::parameter { + + enum struct volume_sel { + one_volume, + two_volumes + }; + + using volume_sel::one_volume; + using volume_sel::two_volumes; + + enum struct offset_sel { + offset, + non_offset + }; + + using offset_sel::offset; + using offset_sel::non_offset; + + enum struct texture_sel { + texture, + non_texture + }; + + using texture_sel::texture; + using texture_sel::non_texture; + + template + struct vertex; + + template <> + struct vertex { + float x; + float y; + float z; + uint32_t base_color; + }; + + template <> + struct vertex { + float x; + float y; + float z; + struct { + uint32_t base_color; + } volume[2]; + }; + + template <> + struct vertex { + float x; + float y; + float z; + uint32_t base_color; + uint32_t offset_color; + }; + + template <> + struct vertex { + float x; + float y; + float z; + struct { + uint32_t base_color; + uint32_t offset_color; + } volume[2]; + }; + + template <> + struct vertex { + float x; + float y; + float z; + float u; + float v; + uint32_t base_color; + }; + + template <> + struct vertex { + float x; + float y; + float z; + struct { + float u; + float v; + uint32_t base_color; + } volume[2]; + }; + + template <> + struct vertex { + float x; + float y; + float z; + float u; + float v; + uint32_t base_color; + uint32_t offset_color; + }; + + template <> + struct vertex { + float x; + float y; + float z; + struct { + float u; + float v; + uint32_t base_color; + uint32_t offset_color; + } volume[2]; + }; + + template + struct isp_tsp_parameter; + + template + struct isp_tsp_parameter { + uint32_t isp_tsp_instruction_word; + uint32_t tsp_instruction_word; + uint32_t texture_control_word; + struct vertex vertex[N]; + }; + + template + struct isp_tsp_parameter { + uint32_t isp_tsp_instruction_word; + struct { + uint32_t tsp_instruction_word; + uint32_t texture_control_word; + } volume[2]; + struct vertex vertex[N]; + }; + + static_assert((sizeof (isp_tsp_parameter<1>)) == 28); + static_assert((sizeof (isp_tsp_parameter<1, texture>)) == 36); + static_assert((sizeof (isp_tsp_parameter<1, texture, two_volumes>)) == 56); + static_assert((sizeof (isp_tsp_parameter<1, texture, two_volumes, offset>)) == 64); + + static_assert((sizeof (isp_tsp_parameter<1, non_texture, two_volumes>)) == 40); + static_assert((sizeof (isp_tsp_parameter<1, non_texture, two_volumes, offset>)) == 48); +} diff --git a/dreamcast2/holly/core/parameter_bits.hpp b/dreamcast2/holly/core/parameter_bits.hpp new file mode 100644 index 0000000..aa10f08 --- /dev/null +++ b/dreamcast2/holly/core/parameter_bits.hpp @@ -0,0 +1,195 @@ +#pragma once + +#include + +namespace holly::core::parameter { + namespace isp_tsp_instruction_word { + namespace depth_compare_mode { + constexpr uint32_t never = 0 << 29; + constexpr uint32_t less = 1 << 29; + constexpr uint32_t equal = 2 << 29; + constexpr uint32_t less_or_equal = 3 << 29; + constexpr uint32_t greater = 4 << 29; + constexpr uint32_t greater_or_equal = 5 << 29; + constexpr uint32_t not_equal = 6 << 29; + constexpr uint32_t always = 7 << 29; + + constexpr uint32_t bit_mask = 0x7 << 29; + } + + namespace volume_instruction { + constexpr uint32_t normal_polygon = 0 << 29; + constexpr uint32_t inside_last_polygon = 1 << 29; + constexpr uint32_t outside_last_polygon = 2 << 29; + + constexpr uint32_t bit_mask = 0x7 << 29; + } + + namespace culling_mode { + constexpr uint32_t no_culling = 0 << 27; + constexpr uint32_t cull_if_small = 1 << 27; + constexpr uint32_t cull_if_negative = 2 << 27; + constexpr uint32_t cull_if_positive = 3 << 27; + + constexpr uint32_t bit_mask = 0x3 << 27; + } + + constexpr uint32_t z_write_disable = 1 << 26; + constexpr uint32_t texture = 1 << 25; + constexpr uint32_t offset = 1 << 24; + constexpr uint32_t gouraud_shading = 1 << 23; + constexpr uint32_t _16bit_uv = 1 << 22; + constexpr uint32_t cache_bypass = 1 << 21; + constexpr uint32_t dcalc_ctrl = 1 << 20; + } + + namespace tsp_instruction_word { + namespace src_alpha_instr { + constexpr uint32_t zero = 0 << 29; + constexpr uint32_t one = 1 << 29; + constexpr uint32_t other_color = 2 << 29; + constexpr uint32_t inverse_other_color = 3 << 29; + constexpr uint32_t src_alpha = 4 << 29; + constexpr uint32_t inverse_src_alpha = 5 << 29; + constexpr uint32_t dst_alpha = 6 << 29; + constexpr uint32_t inverse_dst_alpha = 7 << 29; + + constexpr uint32_t bit_mask = 0x7 << 29; + } + + namespace dst_alpha_instr { + constexpr uint32_t zero = 0 << 26; + constexpr uint32_t one = 1 << 26; + constexpr uint32_t other_color = 2 << 26; + constexpr uint32_t inverse_other_color = 3 << 26; + constexpr uint32_t src_alpha = 4 << 26; + constexpr uint32_t inverse_src_alpha = 5 << 26; + constexpr uint32_t dst_alpha = 6 << 26; + constexpr uint32_t inverse_dst_alpha = 7 << 26; + + constexpr uint32_t bit_mask = 0x7 << 26; + } + + namespace src_select { + constexpr uint32_t primary_accumulation_buffer = 0 << 25; + constexpr uint32_t secondary_accumulation_buffer = 1 << 25; + + constexpr uint32_t bit_mask = 0x1 << 25; + } + + namespace dst_select { + constexpr uint32_t primary_accumulation_buffer = 0 << 24; + constexpr uint32_t secondary_accumulation_buffer = 1 << 24; + + constexpr uint32_t bit_mask = 0x1 << 24; + } + + namespace fog_control { + constexpr uint32_t look_up_table = 0b00 << 22; + constexpr uint32_t per_vertex = 0b01 << 22; + constexpr uint32_t no_fog = 0b10 << 22; + constexpr uint32_t look_up_table_mode_2 = 0b11 << 22; + + constexpr uint32_t bit_mask = 0x3 << 22; + } + + constexpr uint32_t color_clamp = 1 << 21; + constexpr uint32_t use_alpha = 1 << 20; + constexpr uint32_t ignore_texture_alpha = 1 << 19; + + namespace flip_uv { + constexpr uint32_t none = 0 << 17; + constexpr uint32_t v = 1 << 17; + constexpr uint32_t u = 2 << 17; + constexpr uint32_t uv = 3 << 17; + + constexpr uint32_t bit_mask = 0x3 << 17; + } + + namespace clamp_uv { + constexpr uint32_t none = 0 << 15; + constexpr uint32_t v = 1 << 15; + constexpr uint32_t u = 2 << 15; + constexpr uint32_t uv = 3 << 15; + + constexpr uint32_t bit_mask = 0x3 << 15; + } + + namespace filter_mode { + constexpr uint32_t point_sampled = 0b00 << 13; + constexpr uint32_t bilinear_filter = 0b01 << 13; + constexpr uint32_t trilinear_pass_a = 0b10 << 13; + constexpr uint32_t trilinear_pass_b = 0b11 << 13; + + constexpr uint32_t bit_mask = 0x3 << 13; + } + + constexpr uint32_t super_sample_texture = 1 << 12; + constexpr uint32_t mip_map_d_adjust(uint32_t num) { return (num & 0xf) << 8; } + + namespace texture_shading_instruction { + constexpr uint32_t decal = 0 << 6; + constexpr uint32_t modulate = 1 << 6; + constexpr uint32_t decal_alpha = 2 << 6; + constexpr uint32_t modulate_alpha = 3 << 6; + + constexpr uint32_t bit_mask = 0x3 << 6; + } + + namespace texture_u_size { + constexpr uint32_t _8 = 0 << 3; + constexpr uint32_t _16 = 1 << 3; + constexpr uint32_t _32 = 2 << 3; + constexpr uint32_t _64 = 3 << 3; + constexpr uint32_t _128 = 4 << 3; + constexpr uint32_t _256 = 5 << 3; + constexpr uint32_t _512 = 6 << 3; + constexpr uint32_t _1024 = 7 << 3; + + constexpr uint32_t bit_mask = 0x7 << 3; + } + + namespace texture_v_size { + constexpr uint32_t _8 = 0 << 0; + constexpr uint32_t _16 = 1 << 0; + constexpr uint32_t _32 = 2 << 0; + constexpr uint32_t _64 = 3 << 0; + constexpr uint32_t _128 = 4 << 0; + constexpr uint32_t _256 = 5 << 0; + constexpr uint32_t _512 = 6 << 0; + constexpr uint32_t _1024 = 7 << 0; + + constexpr uint32_t bit_mask = 0x7 << 0; + } + } + + namespace texture_control_word { + constexpr uint32_t mip_mapped = 1 << 31; + constexpr uint32_t vq_compressed = 1 << 30; + + namespace pixel_format { + constexpr uint32_t argb1555 = 0 << 27; + constexpr uint32_t rgb565 = 1 << 27; + constexpr uint32_t argb4444 = 2 << 27; + constexpr uint32_t yuv422 = 3 << 27; + constexpr uint32_t bump_map = 4 << 27; + constexpr uint32_t palette_4bpp = 5 << 27; + constexpr uint32_t palette_8bpp = 6 << 27; + + constexpr uint32_t bit_mask = 0x7 << 27; + } + + namespace scan_order { + constexpr uint32_t twiddled = 0 << 26; + constexpr uint32_t non_twiddled = 1 << 26; + + 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; } + } + +} diff --git a/dreamcast2/holly/core/region_array.cpp b/dreamcast2/holly/core/region_array.cpp new file mode 100644 index 0000000..8090d10 --- /dev/null +++ b/dreamcast2/holly/core/region_array.cpp @@ -0,0 +1,77 @@ +#include "holly/core/region_array.hpp" +#include "holly/core/region_array_bits.hpp" + +#include "sh7091/store_queue_transfer.hpp" + +#include "systembus/systembus.hpp" + +namespace holly::core::region_array { + void transfer(const int tile_width, + const int tile_height, + const list_block_size& list_block_size, + const uint32_t region_array_start, + const uint32_t object_list_start) + { + const uint32_t ol_base = object_list_start; + const uint32_t num_tiles = tile_width * tile_height; + //region_array_entry region_array[num_tiles]; + volatile region_array_entry * region_array = (volatile region_array_entry * )&texture_memory32[region_array_start]; + + int ix = 0; + + for (int y = 0; y < tile_height; y++) { + for (int x = 0; x < tile_width; x++) { + region_array[ix].tile = tile::y_position(y) + | tile::x_position(x); + + if (y == (tile_height - 1) && x == (tile_width - 1)) + region_array[ix].tile |= tile::last_region; + + region_array[ix].list_pointer.opaque = (list_block_size.opaque == 0) ? list_pointer::empty : + (ol_base + (list_block_size.opaque * ix) + ); + + region_array[ix].list_pointer.opaque_modifier_volume = (list_block_size.opaque_modifier_volume == 0) ? list_pointer::empty : + (ol_base + num_tiles * ( list_block_size.opaque + ) + + (list_block_size.opaque_modifier_volume * ix) + ); + + region_array[ix].list_pointer.translucent = (list_block_size.translucent == 0) ? list_pointer::empty : + (ol_base + num_tiles * ( list_block_size.opaque + + list_block_size.opaque_modifier_volume + ) + + (list_block_size.translucent * ix) + ); + region_array[ix].list_pointer.translucent_modifier_volume = (list_block_size.translucent_modifier_volume == 0) ? list_pointer::empty : + (ol_base + num_tiles * ( list_block_size.opaque + + list_block_size.opaque_modifier_volume + + list_block_size.translucent + ) + + (list_block_size.translucent_modifier_volume * ix) + ); + region_array[ix].list_pointer.punch_through = (list_block_size.punch_through == 0) ? list_pointer::empty : + (ol_base + num_tiles * ( list_block_size.opaque + + list_block_size.opaque_modifier_volume + + list_block_size.translucent + + list_block_size.translucent_modifier_volume + ) + + (list_block_size.punch_through * ix) + ); + + ix += 1; + } + } + + /* + using systembus::systembus; + + systembus.LMMODE0 = 1; // 32-bit address space + systembus.LMMODE1 = 1; // 32-bit address space + + void * dst = (void *)(&ta_fifo_texture_memory[region_array_start]); + void * src = (void *)(region_array); + sh7091::store_queue_transfer::copy(dst, src, (sizeof (region_array_entry)) * num_tiles); + */ + } +} diff --git a/dreamcast2/holly/core/region_array.hpp b/dreamcast2/holly/core/region_array.hpp new file mode 100644 index 0000000..ae28e62 --- /dev/null +++ b/dreamcast2/holly/core/region_array.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include + +namespace holly::core::region_array { + struct region_array_entry { + uint32_t tile; + struct { + uint32_t opaque; + uint32_t opaque_modifier_volume; + uint32_t translucent; + uint32_t translucent_modifier_volume; + uint32_t punch_through; + } list_pointer; + }; + + struct list_block_size { + uint32_t opaque; + uint32_t opaque_modifier_volume; + uint32_t translucent; + uint32_t translucent_modifier_volume; + uint32_t punch_through; + + uint32_t total() const + { + return opaque + + opaque_modifier_volume + + translucent + + translucent_modifier_volume + + punch_through; + } + }; + + void transfer(const int tile_width, + const int tile_height, + const list_block_size& list_block_size, + const uint32_t region_array_start, + const uint32_t object_list_start); +} diff --git a/dreamcast2/holly/core/region_array_bits.hpp b/dreamcast2/holly/core/region_array_bits.hpp new file mode 100644 index 0000000..0082289 --- /dev/null +++ b/dreamcast2/holly/core/region_array_bits.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace holly::core::region_array { + namespace tile { + constexpr uint32_t last_region = 1 << 31; + constexpr uint32_t z_clear = 1 << 30; + constexpr uint32_t pre_sort = 1 << 29; + constexpr uint32_t flush_accumulate = 1 << 28; + constexpr uint32_t y_position(uint32_t num) { return (num & 0x3f) << 8; } + constexpr uint32_t x_position(uint32_t num) { return (num & 0x3f) << 2; } + } + + namespace list_pointer { + constexpr uint32_t empty = 1 << 31; + constexpr uint32_t object_list(uint32_t num) { return (num & 0xfffffc) << 0; } + } + +} diff --git a/dreamcast2/holly/object_list_bits.hpp b/dreamcast2/holly/object_list_bits.hpp deleted file mode 100644 index 43d6474..0000000 --- a/dreamcast2/holly/object_list_bits.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include - -namespace holly { - namespace object_list { - namespace pointer_type { - constexpr uint32_t triangle_strip = 0b000 << 29; - constexpr uint32_t triangle_array = 0b100 << 29; - constexpr uint32_t quad_array = 0b101 << 29; - constexpr uint32_t object_pointer_block_link = 0b111 << 29; - - constexpr uint32_t bit_mask = 0x7 << 29; - } - - namespace triangle_strip { - namespace mask { - constexpr uint32_t t0 = 0b100000 << 25; - constexpr uint32_t t1 = 0b010000 << 25; - constexpr uint32_t t2 = 0b001000 << 25; - constexpr uint32_t t3 = 0b000100 << 25; - constexpr uint32_t t4 = 0b000010 << 25; - constexpr uint32_t t5 = 0b000001 << 25; - - constexpr uint32_t bit_mask = 0x3f << 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; } - } - - namespace triangle_array { - constexpr 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; } - } - - namespace quad_array { - constexpr 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; } - } - - 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; } - } - - } -} diff --git a/dreamcast2/holly/region_array.cpp b/dreamcast2/holly/region_array.cpp deleted file mode 100644 index e2e99f4..0000000 --- a/dreamcast2/holly/region_array.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "holly/region_array.hpp" -#include "holly/region_array_bits.hpp" - -#incllude "sh7091/store_queue_transfer.hpp" - -namespace holly::region_array { - - void transfer_region_array(const int tile_width, - const int tile_height, - const list_block_size& list_block_size, - const uint32_t region_array_start, - const uint32_t object_list_start); - { - const uint32_t ol_base = object_list_start; - const uint32_t num_tiles = width * height; - region_array_entry region_array[num_tiles]; - - int ix = 0; - - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - region_array[ix].tile = tile::y_position(y) - | tile::x_position(x); - - if (y == (height - 1) && x == (width - 1)) - region_array[ix].tile |= tile::last_region; - - region_array[ix].list_pointer.opaque = (opb_size.opaque == 0) ? REGION_ARRAY__LIST_POINTER__EMPTY : - (ol_base + (opb_size.opaque * ix) - ); - - region_array[ix].list_pointer.opaque_modifier_volume = (opb_size.opaque_modifier == 0) ? REGION_ARRAY__LIST_POINTER__EMPTY : - (ol_base + num_tiles * ( opb_size.opaque - ) - + (opb_size.opaque_modifier_volume * ix) - ); - - region_array[ix].list_pointer.translucent = (opb_size.translucent == 0) ? REGION_ARRAY__LIST_POINTER__EMPTY : - (ol_base + num_tiles * ( opb_size.opaque - + opb_size.opaque_modifier_volume - ) - + (opb_size.translucent * ix) - ); - region_array[ix].list_pointer.translucent_modifier_volume = (opb_size.translucent_modifier == 0) ? REGION_ARRAY__LIST_POINTER__EMPTY : - (ol_base + num_tiles * ( opb_size.opaque - + opb_size.opaque_modifier_volume - + opb_size.translucent - ) - + (opb_size.translucent_modifier_volume * ix) - ); - region_array[ix].list_pointer.punch_through = (opb_size.punch_through == 0) ? REGION_ARRAY__LIST_POINTER__EMPTY : - (ol_base + num_tiles * ( opb_size.opaque - + opb_size.opaque_modifier_volume - + opb_size.translucent - + opb_size.translucent_modifier_volume - ) - + (opb_size.punch_through * ix) - ); - - ix += 1; - } - } - - system.LMMODE0 = 1; // 32-bit address space - system.LMMODE1 = 1; // 32-bit address space - - void * dst = (void *)(&ta_fifo_texture_memory[region_array_start]); - void * src = (void *)(region_array); - sh7091::store_queue_transfer::copy(dst, src, (sizeof (region_array_entry)) * num_tiles); - } -} diff --git a/dreamcast2/holly/region_array.hpp b/dreamcast2/holly/region_array.hpp deleted file mode 100644 index c596b75..0000000 --- a/dreamcast2/holly/region_array.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -namespace holly { - namespace region_array { - struct region_array_entry { - uint32_t tile; - struct { - uint32_t opaque; - uint32_t opaque_modifier_volume; - uint32_t translucent; - uint32_t translucent_modifier_volume; - uint32_t punch_through; - } list_pointer; - }; - - struct list_block_size { - uint32_t opaque; - uint32_t opaque_modifier_volume; - uint32_t translucent; - uint32_t translucent_modifier_volume; - uint32_t punch_through; - - uint32_t total() const - { - return opaque - + opaque_modifier_volume - + translucent - + translucent_modifier_volume - + punch_through; - } - }; - - void transfer_region_array(const int tile_width, - const int tile_height, - const list_block_size& list_block_size, - const uint32_t region_array_start, - const uint32_t object_list_start); - } -} diff --git a/dreamcast2/holly/region_array_bits.hpp b/dreamcast2/holly/region_array_bits.hpp deleted file mode 100644 index 0769699..0000000 --- a/dreamcast2/holly/region_array_bits.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -namespace holly { - namespace region_array { - namespace tile { - constexpr uint32_t last_region = 1 << 31; - constexpr uint32_t z_clear = 1 << 30; - constexpr uint32_t pre_sort = 1 << 29; - constexpr uint32_t flush_accumulate = 1 << 28; - constexpr uint32_t y_position(uint32_t num) { return (num & 0x3f) << 8; } - constexpr uint32_t x_position(uint32_t num) { return (num & 0x3f) << 2; } - } - - namespace list_pointer { - constexpr uint32_t empty = 1 << 31; - constexpr uint32_t object_list(uint32_t num) { return (num & 0xfffffc) << 0; } - } - - } -} diff --git a/dreamcast2/memorymap.hpp b/dreamcast2/memorymap.hpp index ed0845f..a9d5f90 100644 --- a/dreamcast2/memorymap.hpp +++ b/dreamcast2/memorymap.hpp @@ -1,15 +1,15 @@ #include -extern volatile uint8_t system_boot_rom[0x200000] __asm("system_boot_rom"); -extern volatile uint8_t aica_wave_memory[0x200000] __asm("aica_wave_memory"); -extern volatile uint8_t texture_memory64[0x800000] __asm("texture_memory64"); -extern volatile uint8_t texture_memory32[0x800000] __asm("texture_memory32"); -extern volatile uint8_t system_memory[0x1000000] __asm("system_memory"); -extern volatile uint8_t ta_fifo_polygon_converter[0x800000] __asm("ta_fifo_polygon_converter"); -extern volatile uint8_t ta_fifo_yuv_converter[0x800000] __asm("ta_fifo_yuv_converter"); -extern volatile uint8_t ta_fifo_texture_memory[0x800000] __asm("ta_fifo_texture_memory"); -extern volatile uint8_t ta_fifo_polygon_converter_mirror[0x800000] __asm("ta_fifo_polygon_converter_mirror"); -extern volatile uint8_t ta_fifo_yuv_converter_mirror[0x800000] __asm("ta_fifo_yuv_converter_mirror"); -extern volatile uint8_t ta_fifo_texture_memory_mirror[0x800000] __asm("ta_fifo_texture_memory_mirror"); -extern volatile uint8_t store_queue[0x4000000] __asm("store_queue"); -extern volatile uint8_t sh7091_oc_d[0x1000] __asm("sh7091_oc_d"); +extern volatile uint8_t system_boot_rom[0x200000] __asm("system_boot_rom") __attribute__((aligned(32))); +extern volatile uint8_t aica_wave_memory[0x200000] __asm("aica_wave_memory") __attribute__((aligned(32))); +extern volatile uint8_t texture_memory64[0x800000] __asm("texture_memory64") __attribute__((aligned(32))); +extern volatile uint8_t texture_memory32[0x800000] __asm("texture_memory32") __attribute__((aligned(32))); +extern volatile uint8_t system_memory[0x1000000] __asm("system_memory") __attribute__((aligned(32))); +extern volatile uint8_t ta_fifo_polygon_converter[0x800000] __asm("ta_fifo_polygon_converter") __attribute__((aligned(32))); +extern volatile uint8_t ta_fifo_yuv_converter[0x800000] __asm("ta_fifo_yuv_converter") __attribute__((aligned(32))); +extern volatile uint8_t ta_fifo_texture_memory[0x800000] __asm("ta_fifo_texture_memory") __attribute__((aligned(32))); +extern volatile uint8_t ta_fifo_polygon_converter_mirror[0x800000] __asm("ta_fifo_polygon_converter_mirror") __attribute__((aligned(32))); +extern volatile uint8_t ta_fifo_yuv_converter_mirror[0x800000] __asm("ta_fifo_yuv_converter_mirror") __attribute__((aligned(32))); +extern volatile uint8_t ta_fifo_texture_memory_mirror[0x800000] __asm("ta_fifo_texture_memory_mirror") __attribute__((aligned(32))); +extern volatile uint8_t store_queue[0x4000000] __asm("store_queue") __attribute__((aligned(32))); +extern volatile uint8_t sh7091_oc_d[0x1000] __asm("sh7091_oc_d") __attribute__((aligned(32))); diff --git a/dreamcast2/regs.mk b/dreamcast2/regs.mk index ffa2a84..395539c 100644 --- a/dreamcast2/regs.mk +++ b/dreamcast2/regs.mk @@ -10,11 +10,14 @@ holly/holly.hpp: regs/holly/holly.csv regs/render_block_regs.py holly/holly_bits.hpp: regs/holly/holly_bits.csv regs/render_bits.py python regs/render_bits.py $< holly > $@ -holly/region_array_bits.hpp: regs/holly/region_array_bits.csv regs/render_bits.py - python regs/render_bits.py $< holly region_array > $@ +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/object_list_bits.hpp:regs/holly/object_list_bits.csv regs/render_bits.py - python regs/render_bits.py $< holly object_list > $@ +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 + python regs/render_bits.py $< holly::core::parameter > $@ # SH7091 diff --git a/dreamcast2/regs/holly/object_list_bits.ods b/dreamcast2/regs/holly/core/object_list_bits.ods similarity index 100% rename from dreamcast2/regs/holly/object_list_bits.ods rename to dreamcast2/regs/holly/core/object_list_bits.ods diff --git a/dreamcast2/regs/holly/core/parameter_bits.ods b/dreamcast2/regs/holly/core/parameter_bits.ods new file mode 100644 index 0000000000000000000000000000000000000000..657c73367e7881f321640a64fe23be98b5d1c962 GIT binary patch literal 28007 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 KS#&vg^?v}J|8=nd literal 0 HcmV?d00001 diff --git a/dreamcast2/regs/holly/region_array_bits.ods b/dreamcast2/regs/holly/core/region_array_bits.ods similarity index 100% rename from dreamcast2/regs/holly/region_array_bits.ods rename to dreamcast2/regs/holly/core/region_array_bits.ods diff --git a/dreamcast2/regs/render_bits.py b/dreamcast2/regs/render_bits.py index 883704b..1fe60c8 100644 --- a/dreamcast2/regs/render_bits.py +++ b/dreamcast2/regs/render_bits.py @@ -47,8 +47,11 @@ def aggregate_enums(aggregated_rows): def assert_unique_ordered(bits, row): nonlocal all_bits - assert all(bit not in all_bits for bit in bits), (bits, row) - assert max(all_bits, default=32) > max(bits), (all_bits, bits) + #assert all(bit not in all_bits for bit in bits), (bits, row) + if not all(bit not in all_bits for bit in bits): + print("bit overlap", row, file=sys.stderr) + else: + assert max(all_bits, default=32) > max(bits), (all_bits, bits) all_bits |= bits for row in aggregated_rows: diff --git a/dreamcast2/runtime.cpp b/dreamcast2/runtime.cpp index 327bf23..fcfbb83 100644 --- a/dreamcast2/runtime.cpp +++ b/dreamcast2/runtime.cpp @@ -51,9 +51,3 @@ void runtime_init() ((init_t *)(*ctors_start++))(); } } - -extern "C" -void foo() -{ - runtime_init(); -}