From b99722a6df00db771c6d21027723d04f15bcb0b7 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Tue, 5 Dec 2023 00:16:38 +0800 Subject: [PATCH] _bits: use more bits generated from spreadsheets This rearranges scene.cpp to a file organization that more closely follows which code is responsible for what area of (hardware) initialization. All TA and CORE register accesses now use the new ta_bits.h and core_bits.h, respectively. --- common.mk | 9 +- holly/core.cpp | 84 ++++++++++++ holly/core.h | 5 + holly/core_bits.h | 12 +- holly/ta_bits.h | 4 +- holly/ta_fifo_polygon_converter.cpp | 87 +++++++++++++ holly/ta_fifo_polygon_converter.h | 7 + holly/texture_memory_alloc.h | 12 ++ main.cpp | 55 ++++---- regs/core_bits.csv | 12 +- regs/core_bits.ods | Bin 22187 -> 22199 bytes regs/ta_bits.csv | 4 +- regs/ta_bits.ods | Bin 18336 -> 18337 bytes scene.cpp | 192 +++------------------------- scene.h | 9 +- sh7091_bits.h | 71 ++++++++++ storequeue.cpp | 3 +- systembus_bits.h | 28 ++++ ta.h | 84 ------------ texture_memory_alloc.h | 12 ++ 20 files changed, 382 insertions(+), 308 deletions(-) create mode 100644 holly/core.cpp create mode 100644 holly/core.h create mode 100644 holly/ta_fifo_polygon_converter.cpp create mode 100644 holly/ta_fifo_polygon_converter.h create mode 100644 holly/texture_memory_alloc.h create mode 100644 systembus_bits.h delete mode 100644 ta.h create mode 100644 texture_memory_alloc.h diff --git a/common.mk b/common.mk index 2ca3900..4f2de30 100644 --- a/common.mk +++ b/common.mk @@ -55,7 +55,8 @@ MAIN_OBJ = \ holly/background.o \ holly/region_array.o \ holly/ta_parameter.o \ - storequeue.o \ + holly/ta_fifo_polygon_converter.o \ + holly/core.o \ scene.o all: main.cdi @@ -139,6 +140,12 @@ audio.pcm: %.data.o: %.data $(BUILD_BINARY_O) +clean: + find -P \ + -regextype posix-egrep \ + -regex '.*\.(iso|o|bin|elf|cue|gch)$$' \ + -exec rm {} \; + .SUFFIXES: .INTERMEDIATE: .SECONDARY: diff --git a/holly/core.cpp b/holly/core.cpp new file mode 100644 index 0000000..7715260 --- /dev/null +++ b/holly/core.cpp @@ -0,0 +1,84 @@ +#include "float_uint32.h" +#include "core_bits.h" +#include "../holly.h" +#include "../memorymap.h" + +#include "texture_memory_alloc.h" + +#include "core.h" +#include "background.h" +#include "region_array.h" + +void core_init() +{ + holly.ISP_FEED_CFG = isp_feed_cfg::cache_size_for_translucency(0x200); + + holly.FPU_SHAD_SCALE = fpu_shad_scale::scale_factor_for_shadows(1); + holly.FPU_CULL_VAL = _i(1.f); + holly.FPU_PERP_VAL = _i(0.f); + holly.SPAN_SORT_CFG = span_sort_cfg::span_sort_enable + | span_sort_cfg::offset_sort_enable; + + holly.FOG_COL_RAM = fog_col_ram::red(127) + | fog_col_ram::green(127) + | fog_col_ram::blue(127); + + holly.FOG_COL_VERT = fog_col_vert::red(127) + | fog_col_vert::green(127) + | fog_col_vert::blue(127); + + holly.FOG_CLAMP_MIN = fog_clamp_min::alpha(0) + | fog_clamp_min::red(0) + | fog_clamp_min::green(0) + | fog_clamp_min::blue(0); + + holly.FOG_CLAMP_MAX = fog_clamp_max::alpha(255) + | fog_clamp_max::red(255) + | fog_clamp_max::green(255) + | fog_clamp_max::blue(255); + + holly.HALF_OFFSET = half_offset::tsp_texel_sampling_position::center + | half_offset::tsp_pixel_sampling_position::center + | half_offset::fpu_pixel_sampling_position::center; + + holly.FPU_PARAM_CFG = fpu_param_cfg::region_header_type::type_2 + | fpu_param_cfg::tsp_parameter_burst_threshold(31) + | fpu_param_cfg::isp_parameter_burst_threshold(31) + | fpu_param_cfg::pointer_burst_size(7) // must be less than opb size + | fpu_param_cfg::pointer_first_burst_size(7); // half of pointer burst size(?) +} + +void core_init_texture_memory() +{ + volatile texture_memory_alloc * mem = reinterpret_cast(texture_memory); + + background_parameter(mem->background); + region_array(mem->region_array, + (offsetof (struct texture_memory_alloc, object_list)), + 640 / 32, // width + 480 / 32 // height + ); +} + +void core_start_render(int fb) +{ + holly.REGION_BASE = (offsetof (struct texture_memory_alloc, region_array)); + holly.PARAM_BASE = (offsetof (struct texture_memory_alloc, isp_tsp_parameters)); + + holly.ISP_BACKGND_T = isp_backgnd_t::tag_address((offsetof (struct texture_memory_alloc, background)) / 4) + | isp_backgnd_t::tag_offset(0) + | isp_backgnd_t::skip(1); + holly.ISP_BACKGND_D = _i(1.f/100000); + + holly.FB_W_CTRL = 1 << 3 | fb_w_ctrl::fb_packmode::_565_rgb_16bit; + holly.FB_W_LINESTRIDE = (640 * 2) / 8; + + int w_fb = (!(!fb)) * 0x00096000; + int r_fb = (!fb) * 0x00096000; + holly.FB_W_SOF1 = (offsetof (struct texture_memory_alloc, framebuffer)) + w_fb; + holly.FB_W_SOF2 = (offsetof (struct texture_memory_alloc, framebuffer)) + w_fb; + holly.FB_R_SOF1 = (offsetof (struct texture_memory_alloc, framebuffer)) + r_fb; + holly.FB_R_SOF2 = (offsetof (struct texture_memory_alloc, framebuffer)) + r_fb; + + holly.STARTRENDER = 1; +} diff --git a/holly/core.h b/holly/core.h new file mode 100644 index 0000000..540c78d --- /dev/null +++ b/holly/core.h @@ -0,0 +1,5 @@ +#pragma once + +void core_init(); +void core_init_texture_memory(); +void core_start_render(int fb); diff --git a/holly/core_bits.h b/holly/core_bits.h index f114bd5..5761bde 100644 --- a/holly/core_bits.h +++ b/holly/core_bits.h @@ -148,18 +148,18 @@ namespace fpu_param_cfg { namespace half_offset { namespace tsp_texel_sampling_position { - constexpr uint32_t top_left(uint32_t reg) { return (reg >> 2) & 0x1; } - constexpr uint32_t center(uint32_t reg) { return (reg >> 2) & 0x1; } + constexpr uint32_t top_left = 1 << 2; + constexpr uint32_t center = 1 << 2; } namespace tsp_pixel_sampling_position { - constexpr uint32_t top_left(uint32_t reg) { return (reg >> 1) & 0x1; } - constexpr uint32_t center(uint32_t reg) { return (reg >> 1) & 0x1; } + constexpr uint32_t top_left = 1 << 1; + constexpr uint32_t center = 1 << 1; } namespace fpu_pixel_sampling_position { - constexpr uint32_t top_left(uint32_t reg) { return (reg >> 0) & 0x1; } - constexpr uint32_t center(uint32_t reg) { return (reg >> 0) & 0x1; } + constexpr uint32_t top_left = 1 << 0; + constexpr uint32_t center = 1 << 0; } } diff --git a/holly/ta_bits.h b/holly/ta_bits.h index 04b2917..40d84d0 100644 --- a/holly/ta_bits.h +++ b/holly/ta_bits.h @@ -33,8 +33,8 @@ namespace ta_glob_tile_clip { namespace ta_alloc_ctrl { namespace opb_mode { - constexpr uint32_t decreasing_addresses = 0 << 20; - constexpr uint32_t increasing_addresses = 1 << 20; + constexpr uint32_t increasing_addresses = 0 << 20; + constexpr uint32_t decreasing_addresses = 1 << 20; } namespace pt_opb { diff --git a/holly/ta_fifo_polygon_converter.cpp b/holly/ta_fifo_polygon_converter.cpp new file mode 100644 index 0000000..68f0d41 --- /dev/null +++ b/holly/ta_fifo_polygon_converter.cpp @@ -0,0 +1,87 @@ +#include + +#include "core_bits.h" +#include "ta_bits.h" +#include "../holly.h" +#include "../systembus.h" +#include "../systembus_bits.h" +#include "../sh7091.h" +#include "../sh7091_bits.h" + +#include "texture_memory_alloc.h" + +#include "ta_fifo_polygon_converter.h" + +void ta_polygon_converter_init() +{ + holly.SOFTRESET = softreset::ta_soft_reset; + holly.SOFTRESET = 0; + + holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num((480 / 32) - 1) + | ta_glob_tile_clip::tile_x_num((640 / 32) - 1); + + holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses + | ta_alloc_ctrl::pt_opb::no_list + | ta_alloc_ctrl::tm_opb::no_list + | ta_alloc_ctrl::t_opb::no_list + | ta_alloc_ctrl::om_opb::no_list + | ta_alloc_ctrl::o_opb::_16x4byte; + + holly.TA_ISP_BASE = (offsetof (struct texture_memory_alloc, isp_tsp_parameters)); + holly.TA_ISP_LIMIT = (offsetof (struct texture_memory_alloc, object_list)); // the end of isp_tsp_parameters + holly.TA_OL_BASE = (offsetof (struct texture_memory_alloc, object_list)); + holly.TA_OL_LIMIT = (offsetof (struct texture_memory_alloc, _res0)); // the end of the object_list + holly.TA_NEXT_OPB_INIT = (offsetof (struct texture_memory_alloc, object_list)); + //holly.TA_NEXT_OPB_INIT = (offsetof (struct texture_memory_alloc, object_list)) + // + (640 / 32) * (320 / 32) * 16 * 4; + + holly.TA_LIST_INIT = ta_list_init::list_init; + + volatile uint32_t _dummy_read = holly.TA_LIST_INIT; + (void)_dummy_read; +} + +extern void serial_string(const char * s); + +void ta_polygon_converter_transfer(volatile uint32_t * buf, uint32_t size) +{ + /* wait for previous transfer to complete (if any) */ + //while ((system.C2DST & C2DST__STATUS) != 0); /* 1 == transfer is in progress */ + /* CHCR2__TE can be reset even if there is no in-progress transfer. Despite + DCDBSysArc990907E's claim, it does not appear to be useful to check TE. */ + //while ((sh7091.DMAC.CHCR2 & CHCR2__TE) == 0); /* 1 == all transfers are completed */ + + /* start a new CH2-DMA transfer from "system memory" to "TA FIFO polygon converter" */ + // this dummy read is required on real hardware. + volatile uint32_t _dummy = sh7091.DMAC.CHCR2; + (void)_dummy; + sh7091.DMAC.CHCR2 = 0; /* disable DMA channel */ + sh7091.DMAC.SAR2 = reinterpret_cast(&buf[0]); /* start address, must be aligned to a CHCHR__TS-sized (32-byte) boundary */ + sh7091.DMAC.DMATCR2 = DMATCR2__TRANSFER_COUNT(size / 32); /* transfer count, in CHCHR__TS-sized (32-byte) units */ + sh7091.DMAC.CHCR2 = CHCR2__DM__DESTINATION_ADDRESS_FIXED + | CHCR2__SM__SOURCE_ADDRESS_INCREMENTED + | CHCR2__RS(0b0010) /* external request, single address mode; + external address space → external device */ + | CHCR2__TM__BURST_MODE /* transmit mode */ + | CHCR2__TS__32_BYTE /* transfer size */ + | CHCR2__DE; /* DMAC (channel) enable */ + + sh7091.DMAC.DMAOR = DMAOR__DDT /* on-demand data transfer mode */ + | DMAOR__PR__CH2_CH0_CH1_CH3 /* priority mode; CH2 > CH0 > CH1 > CH3 */ + | DMAOR__DME; /* DMAC master enable */ + system.C2DSTAT = C2DSTAT__ADDRESS(0x10000000); /* CH2-DMA destination address */ + system.C2DLEN = CD2LEN__LENGTH(size) ; /* CH2-DMA length (must be a multiple of 32) */ + system.C2DST = 1; /* CH2-DMA start (an 'external' request from SH7091's perspective) */ + + // wait for CH2-DMA completion + while ((system.ISTNRM & ISTNRM__END_OF_DMA_CH2_DMA) == 0); + // reset CH2-DMA interrupt status + system.ISTNRM = ISTNRM__END_OF_DMA_CH2_DMA; +} + +void ta_wait_opaque_list() +{ + while ((system.ISTNRM & ISTNRM__END_OF_TRANSFERRING_OPAQUE_LIST) == 0); + + system.ISTNRM = ISTNRM__END_OF_TRANSFERRING_OPAQUE_LIST; +} diff --git a/holly/ta_fifo_polygon_converter.h b/holly/ta_fifo_polygon_converter.h new file mode 100644 index 0000000..f3e9f02 --- /dev/null +++ b/holly/ta_fifo_polygon_converter.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +void ta_polygon_converter_init(); +void ta_polygon_converter_transfer(volatile uint32_t * buf, uint32_t size); +void ta_wait_opaque_list(); diff --git a/holly/texture_memory_alloc.h b/holly/texture_memory_alloc.h new file mode 100644 index 0000000..c831b9b --- /dev/null +++ b/holly/texture_memory_alloc.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +struct texture_memory_alloc { + uint32_t isp_tsp_parameters[0x00100000 / 4]; // TA_ISP_BASE / PARAM_BASE (the actual objects) + uint32_t object_list[0x00100000 / 4]; // TA_OL_BASE (contains object pointer blocks) + uint32_t _res0[ 0x20 / 4]; // (the TA may clobber 4 bytes starting at TA_OL_LIMIT) + uint32_t region_array[0x00002000 / 4]; // REGION_BASE + uint32_t background[0x00000020 / 4]; // ISP_BACKGND_T + uint32_t framebuffer[2][0x00096000 / 4]; // FB_R_SOF1 / FB_W_SOF1 +}; diff --git a/main.cpp b/main.cpp index 2924ea5..e257e38 100644 --- a/main.cpp +++ b/main.cpp @@ -1,16 +1,18 @@ #include +#include "memorymap.h" + +#include "sh7091.h" +#include "sh7091_bits.h" +#include "holly.h" +#include "holly/core.h" +#include "holly/core_bits.h" +#include "holly/ta_fifo_polygon_converter.h" +#include "systembus.h" + #include "cache.h" #include "load.h" #include "vga.h" - -#include "sh7091.h" -#include "sh7091_bits.h" -#include "memorymap.h" -#include "systembus.h" -#include "holly.h" -#include "holly/core_bits.h" - #include "rgb.h" #include "scene.h" @@ -43,12 +45,15 @@ inline void serial_char(const char c) void serial_string(const char * s) { - return; while (*s != '\0') { serial_char(*s++); } } +/* must be aligned to 32-bytes for DMA transfer */ +// the aligned(32) attribute does not actually align to 32 bytes. +volatile uint32_t __attribute__((aligned(32))) scene[(32 * 5) / 4]; + extern "C" void main() { @@ -76,7 +81,6 @@ void main() } } - holly.SOFTRESET = softreset::pipeline_soft_reset | softreset::ta_soft_reset; holly.SOFTRESET = 0; @@ -86,22 +90,29 @@ void main() v_sync_out(); v_sync_in(); - scene_holly_init(); - scene_init_texture_memory(); + + core_init(); + core_init_texture_memory(); int frame = 0; + // the address of `scene` must be a multiple of 32 bytes + // this is mandatory for ch2-dma to the ta fifo polygon converter + if ((reinterpret_cast(scene) & 31) != 0) { + serial_string("unaligned\n"); + while(1); + } - while (1) { - scene_ta_init(); - scene_geometry_transfer(); - scene_wait_opaque_list(); - scene_start_render(frame); - frame = !frame; - - // I do not understand why, but flycast does not show the first-rendered - // framebuffer. - + while (true) { v_sync_out(); v_sync_in(); + + ta_polygon_converter_init(); + uint32_t ta_parameter_count = scene_transform(&scene[0]); + uint32_t ta_parameter_size = ta_parameter_count * 32; /* 32 bytes per parameter */ + ta_polygon_converter_transfer(&scene[0], ta_parameter_size); + ta_wait_opaque_list(); + core_start_render(frame); + + frame = !frame; } } diff --git a/regs/core_bits.csv b/regs/core_bits.csv index d70f83b..d2a82c0 100644 --- a/regs/core_bits.csv +++ b/regs/core_bits.csv @@ -83,12 +83,12 @@ "FPU_PARAM_CFG",,"7-4","pointer_burst_size",,"0xf",,,,,, "FPU_PARAM_CFG",,"3-0","pointer_first_burst_size",,"0xf",,,,,, ,,,,,,,,,,, -"HALF_OFFSET","tsp_texel_sampling_position",2,"top_left",,,,,,,, -"HALF_OFFSET","tsp_texel_sampling_position",2,"center",,,,,,,, -"HALF_OFFSET","tsp_pixel_sampling_position",1,"top_left",,,,,,,, -"HALF_OFFSET","tsp_pixel_sampling_position",1,"center",,,,,,,, -"HALF_OFFSET","fpu_pixel_sampling_position",0,"top_left",,,,,,,, -"HALF_OFFSET","fpu_pixel_sampling_position",0,"center",,,,,,,, +"HALF_OFFSET","tsp_texel_sampling_position",2,"top_left",1,,,,,,, +"HALF_OFFSET","tsp_texel_sampling_position",2,"center",1,,,,,,, +"HALF_OFFSET","tsp_pixel_sampling_position",1,"top_left",1,,,,,,, +"HALF_OFFSET","tsp_pixel_sampling_position",1,"center",1,,,,,,, +"HALF_OFFSET","fpu_pixel_sampling_position",0,"top_left",1,,,,,,, +"HALF_OFFSET","fpu_pixel_sampling_position",0,"center",1,,,,,,, ,,,,,,,,,,, "FPU_PERP_VAL",,"30-0","perpendicular_triangle_compare",,"float_0_8_23",,,,,, ,,,,,,,,,,, diff --git a/regs/core_bits.ods b/regs/core_bits.ods index 21a62de688110b4f3becbc4760398259375a6d95..f60fffd632e485f94178dab38b2a7ba79291605e 100644 GIT binary patch delta 10247 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 delta 4368 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 -#include "holly/region_array.h" -#include "holly/background.h" #include "holly/ta_parameter.h" -#include "holly/core_bits.h" -#include "holly.h" -#include "ta.h" -#include "sh7091.h" - -#include "memorymap.h" -#include "storequeue.h" -#include "systembus.h" -#include "holly/float_uint32.h" - -struct texture_memory_alloc { - uint32_t isp_tsp_parameters[0x00100000 / 4]; // TA_ISP_BASE / PARAM_BASE (the actual objects) - uint32_t object_list[0x00100000 / 4]; // TA_OL_BASE (contains object pointer blocks) - uint32_t _res0[ 0x20 / 4]; // (the TA may clobber 4 bytes starting at TA_OL_LIMIT) - uint32_t region_array[0x00002000 / 4]; // REGION_BASE - uint32_t background[0x00000020 / 4]; // ISP_BACKGND_T - uint32_t framebuffer[2][0x00096000 / 4]; // FB_R_SOF1 / FB_W_SOF1 -}; /* - 0,-.5 - | - --- + 0,-.5 + | + --- -0.5,0.5 | 0.5,0.5 */ @@ -35,108 +15,16 @@ float scene_triangle[3][3] = { { -0.5f, 0.5f, 1/10.f}, }; -void scene_holly_init() -{ - holly.ISP_FEED_CFG = ISP_FEED_CFG__TRANSLUCENCY_CACHE_SIZE(0x200); - - holly.FPU_SHAD_SCALE = FPU_SHAD_SCALE__SCALE_FACTOR(1); - holly.FPU_CULL_VAL = _i(1.f); - holly.FPU_PERP_VAL = _i(0.f); - holly.SPAN_SORT_CFG = SPAN_SORT_CFG__SPAN_SORT_ENABLE - | SPAN_SORT_CFG__OFFSET_SORT_ENABLE; - - holly.FOG_COL_RAM = FOG_COL_RAM__RED(127) - | FOG_COL_RAM__GREEN(127) - | FOG_COL_RAM__BLUE(127); - - holly.FOG_COL_VERT = FOG_COL_VERT__RED(127) - | FOG_COL_VERT__GREEN(127) - | FOG_COL_VERT__BLUE(127); - - holly.FOG_CLAMP_MIN = FOG_CLAMP_MIN__ALPHA(0) - | FOG_CLAMP_MIN__RED(0) - | FOG_CLAMP_MIN__GREEN(0) - | FOG_CLAMP_MIN__BLUE(0); - - holly.FOG_CLAMP_MAX = FOG_CLAMP_MAX__ALPHA(255) - | FOG_CLAMP_MAX__RED(255) - | FOG_CLAMP_MAX__GREEN(255) - | FOG_CLAMP_MAX__BLUE(255); - - holly.HALF_OFFSET = HALF_OFFSET__TSP_TEXEL_SAMPLE_POSITION_CENTER - | HALF_OFFSET__TSP_PIXEL_SAMPLE_POSITION_CENTER - | HALF_OFFSET__FPU_PIXEL_SAMPLE_POSITION_CENTER; - - holly.FPU_PARAM_CFG = FPU_PARAM_CFG__REGION_HEADER_TYPE__2 - | FPU_PARAM_CFG__TSP_PARAMETER_BURST_TRIGGER(31) - | FPU_PARAM_CFG__ISP_PARAMETER_BURST_TRIGGER(31) - | FPU_PARAM_CFG__POINTER_BURST_SIZE(7) // must be less than OPB size - | FPU_PARAM_CFG__POINTER_FIRST_BURST_SIZE(7); // half of pointer burst size(?) -} - -void scene_ta_init() -{ - holly.SOFTRESET = SOFTRESET__TA_SOFT_RESET; - holly.SOFTRESET = 0; - - holly.TA_GLOB_TILE_CLIP = TA_GLOB_TILE_CLIP__TILE_Y_NUM((480 / 32) - 1) - | TA_GLOB_TILE_CLIP__TILE_X_NUM((640 / 32) - 1); - - holly.TA_ALLOC_CTRL = TA_ALLOC_CTRL__OPB_MODE_INCREASING - | TA_ALLOC_CTRL__PT_OPB__NONE - | TA_ALLOC_CTRL__TM_OPB__NONE - | TA_ALLOC_CTRL__T_OPB__NONE - | TA_ALLOC_CTRL__OM_OPB__NONE - | TA_ALLOC_CTRL__O_OPB__16; - - holly.TA_ISP_BASE = (offsetof (struct texture_memory_alloc, isp_tsp_parameters)); - holly.TA_ISP_LIMIT = (offsetof (struct texture_memory_alloc, object_list)); // the end of isp_tsp_parameters - holly.TA_OL_BASE = (offsetof (struct texture_memory_alloc, object_list)); - holly.TA_OL_LIMIT = (offsetof (struct texture_memory_alloc, _res0)); // the end of the object_list - holly.TA_NEXT_OPB_INIT = (offsetof (struct texture_memory_alloc, object_list)); - //holly.TA_NEXT_OPB_INIT = (offsetof (struct texture_memory_alloc, object_list)) - // + (640 / 32) * (320 / 32) * 16 * 4; - - holly.TA_LIST_INIT = TA_LIST_INIT__LIST_INIT; - - volatile uint32_t _dummy_read = holly.TA_LIST_INIT; - (void)_dummy_read; -} - -void scene_wait_opaque_list() -{ - while ((system.ISTNRM & SB_ISTNRM__TAEOINT) == 0); - - system.ISTNRM = SB_ISTNRM__TAEOINT; -} - static float theta = 0; -constexpr float degree = 0.01745329f; +constexpr float one_degree = 0.01745329f; -void scene_geometry_transfer() +uint32_t scene_transform(volatile uint32_t * scene) { - /* - triangle(store_queue); - sq_transfer_32byte(ta_fifo_polygon_converter); + uint32_t ix = 0; - for (int i = 0; i < 3; i++) { - bool end_of_strip = i == 2; + triangle(&scene[(32 * ix) / 4]); + ix++; - vertex(store_queue, - scene_triangle[i][0], // x - scene_triangle[i][1], // y - scene_triangle[i][2], // z - 0xffff00ff, // base_color - end_of_strip); - - sq_transfer_32byte(ta_fifo_polygon_converter); - } - - end_of_list(store_queue); - sq_transfer_32byte(ta_fifo_polygon_converter); - */ - uint32_t __attribute__((aligned(32))) scene[(32 * 5) / 4]; - triangle(&scene[(32 * 0) / 4]); for (int i = 0; i < 3; i++) { bool end_of_strip = i == 2; @@ -150,69 +38,19 @@ void scene_geometry_transfer() x += 320.f; y += 240.f; - vertex(&scene[(32 * (i + 1)) / 4], + vertex(&scene[(32 * ix) / 4], x, // x y, // y scene_triangle[i][2], // z 0xffff00ff, // base_color end_of_strip); + ix++; } - end_of_list(&scene[(32 * 4) / 4]); - theta += degree; - volatile uint32_t _dummy = sh7091.DMAC.CHCR2; - (void)_dummy; - sh7091.DMAC.CHCR2 = 0; - sh7091.DMAC.SAR2 = reinterpret_cast(&scene[0]); - sh7091.DMAC.DMATCR2 = (32 * 5) / 32; - // SM(1) {source address increment} - // | RS(2) {external request, single address mode} - // | TM {burst mode} - // | TS(2) {32-byte block} - // | DE {enable channel} - sh7091.DMAC.CHCR2 = 0x12c1; - sh7091.DMAC.DMAOR = 0x8201; - system.C2DSTAT = 0x10000000; - system.C2DLEN = 32 * 5; - system.C2DST = 1; + end_of_list(&scene[(32 * ix) / 4]); + ix++; - while ((system.ISTNRM & (1 << 19)) == 0); - system.ISTNRM = (1 << 19); -} - -void scene_init_texture_memory() -{ - volatile texture_memory_alloc * mem = reinterpret_cast(texture_memory); - - background_parameter(mem->background); - region_array(mem->region_array, - (offsetof (struct texture_memory_alloc, object_list)), - 640 / 32, // width - 480 / 32 // height - ); -} - -void scene_start_render(int fb) -{ - holly.REGION_BASE = (offsetof (struct texture_memory_alloc, region_array)); - holly.PARAM_BASE = (offsetof (struct texture_memory_alloc, isp_tsp_parameters)); - - holly.ISP_BACKGND_T = ISP_BACKGND_T__TAG_ADDRESS((offsetof (struct texture_memory_alloc, background)) / 4) - | ISP_BACKGND_T__TAG_OFFSET(0) - | ISP_BACKGND_T__SKIP(1); - holly.ISP_BACKGND_D = _i(1.f/100000); - - //holly.SOFTRESET = softreset::pipeline_soft_reset; - - holly.FB_W_CTRL = 1 << 3 | FB_W_CTRL__FB_PACKMODE__565_RGB; - holly.FB_W_LINESTRIDE = (640 * 2) / 8; - - int w_fb = (!(!fb)) * 0x00096000; - int r_fb = (!fb) * 0x00096000; - holly.FB_W_SOF1 = (offsetof (struct texture_memory_alloc, framebuffer)) + w_fb; - holly.FB_R_SOF1 = (offsetof (struct texture_memory_alloc, framebuffer)) + r_fb; - - //holly.SOFTRESET = 0; - - holly.STARTRENDER = 1; + theta += one_degree; + + return ix; } diff --git a/scene.h b/scene.h index 0326f6b..1817f99 100644 --- a/scene.h +++ b/scene.h @@ -1,8 +1,5 @@ #pragma once -void scene_holly_init(); -void scene_ta_init(); -void scene_init_texture_memory(); -void scene_geometry_transfer(); -void scene_wait_opaque_list(); -void scene_start_render(int fb); +#include + +uint32_t scene_transform(volatile uint32_t * scene); diff --git a/sh7091_bits.h b/sh7091_bits.h index 794b464..e5996c1 100644 --- a/sh7091_bits.h +++ b/sh7091_bits.h @@ -28,3 +28,74 @@ #define SCFSR2__PER (1 << 2) /* parity error */ #define SCFSR2__RDF (1 << 1) /* receive FIFO data full */ #define SCFSR2__DR (1 << 0) /* receive data ready */ + +#define DMAOR__DDT (1 << 15) /* on-demand data transfer mode */ +/* priority mode */ +#define DMAOR__PR__CH0_CH1_CH2_CH3 (0b11 << 8) +#define DMAOR__PR__CH0_CH2_CH3_CH1 (0b01 << 8) +#define DMAOR__PR__CH2_CH0_CH1_CH3 (0b10 << 8) +#define DMAOR__PR__ROUND_ROBIN (0b11 << 8) +#define DMAOR__AE (1 << 2) /* address error flag; clear-only */ +#define DMAOR__NMIF (1 << 1) /* non-maskable interrupt flag; clear-only */ +#define DMAOR__DME (1 << 0) /* DMAC master enable */ + +/* source address space attribute specification */ +#define CHCR2__SSA__RESERVED_IN_PCMCIA_ACCESS (0b000 << 29) +#define CHCR2__SSA__DYNAMIC_BUS_SIZING_IO_SPACE (0b001 << 29) +#define CHCR2__SSA__8BIT_IO_SPACE (0b010 << 29) +#define CHCR2__SSA__16BIT_IO_SPACE (0b011 << 29) +#define CHCR2__SSA__8BIT_COMMON_MEMORY_SPACE (0b100 << 29) +#define CHCR2__SSA__16BIT_COMMON_MEMORY_SPACE (0b101 << 29) +#define CHCR2__SSA__8BIT_ATTRIBUTE_MEMORY_SPACE (0b110 << 29) +#define CHCR2__SSA__16BIT_ATTRIBUTE_MEMORY_SPACE (0b111 << 29) +/* source address wait control select */ +#define CHCR2__STC__C5_SPACE_WAIT_CYCLE_SELECTION (0 << 28) +#define CHCR2__STC__C6_SPACE_WAIT_CYCLE_SELECTION (1 << 28) +/* destination address space attribute specification */ +#define CHCR2__DSA__RESERVED_IN_PCMCIA_ACCESS (0b000 << 25) +#define CHCR2__DSA__DYNAMIC_BUS_SIZING_IO_SPACE (0b001 << 25) +#define CHCR2__DSA__8BIT_IO_SPACE (0b010 << 25) +#define CHCR2__DSA__16BIT_IO_SPACE (0b011 << 25) +#define CHCR2__DSA__8BIT_COMMON_MEMORY_SPACE (0b100 << 25) +#define CHCR2__DSA__16BIT_COMMON_MEMORY_SPACE (0b101 << 25) +#define CHCR2__DSA__8BIT_ATTRIBUTE_MEMORY_SPACE (0b110 << 25) +#define CHCR2__DSA__16BIT_ATTRIBUTE_MEMORY_SPACE (0b111 << 25) +/* destination address wait control select */ +#define CHCR2__DTC__C5_SPACE_WAIT_CYCLE_SELECTION (0 << 24) +#define CHCR2__DTC__C6_SPACE_WAIT_CYCLE_SELECTION (1 << 24) +/* DREQ select */ +#define CHCR2__DS__LOW_LEVEL_DETECTION (0 << 19) +#define CHCR2__DS__FALLING_EDGE_DETECTION (1 << 19) +/* request check level */ +#define CHCR2__RL__DRAK_IS_AN_ACTIVE_HIGH_OUTPUT (0 << 18) +#define CHCR2__RL__DRAK_IS_AN_ACTIVE_LOW_OUTPUT (1 << 18) +/* acknowledge mode */ +#define CHCR2__AM__DACK_IS_OUTPUT_IN_READ_CYCLE (0 << 17) +#define CHCR2__AM__DACK_IS_OUTPUT_IN_WRITE_CYCLE (1 << 17) +/* acknowledge level */ +#define CHCR2__AL__ACTIVE_HIGH_OUTPUT (0 << 16) +#define CHCR2__AL__ACTIVE_LOW_OUTPUT (1 << 16) +/* destination address mode */ +#define CHCR2__DM__DESTINATION_ADDRESS_FIXED (0b00 << 14) +#define CHCR2__DM__DESTINATION_ADDRESS_INCREMENTED (0b01 << 14) +#define CHCR2__DM__DESTINATION_ADDRESS_DECREMENTED (0b10 << 14) +/* source address mode */ +#define CHCR2__SM__SOURCE_ADDRESS_FIXED (0b00 << 12) +#define CHCR2__SM__SOURCE_ADDRESS_INCREMENTED (0b01 << 12) +#define CHCR2__SM__SOURCE_ADDRESS_DECREMENTED (0b10 << 12) +/* resource select */ +#define CHCR2__RS(n) (((n) & 0b1111) << 8) +/* transmit mode */ +#define CHCR2__TM__CYCLE_STEAL_MODE (0 << 7) +#define CHCR2__TM__BURST_MODE (1 << 7) +/* transmit size */ +#define CHCR2__TS__64_BIT (0b000 << 4) +#define CHCR2__TS__8_BIT (0b001 << 4) +#define CHCR2__TS__16_BIT (0b010 << 4) +#define CHCR2__TS__32_BIT (0b011 << 4) +#define CHCR2__TS__32_BYTE (0b100 << 4) +#define CHCR2__IE (1 << 2) /* interrupt enable */ +#define CHCR2__TE (1 << 1) /* transfer end; clear only */ +#define CHCR2__DE (1 << 0) /* DMAC (channel) enable */ + +#define DMATCR2__TRANSFER_COUNT(n) (((n) & 0xffffff) << 0) diff --git a/storequeue.cpp b/storequeue.cpp index be5f210..e3d05ed 100644 --- a/storequeue.cpp +++ b/storequeue.cpp @@ -4,8 +4,7 @@ void sq_transfer_32byte(volatile void * dst) { // dst typically 0x10000000 (ta polygon converter) - //sh7091.CCN.QACR0 = ((reinterpret_cast(dst) >> 26) & 0b111) << 2; - sh7091.CCN.QACR0 = 0xac; + sh7091.CCN.QACR0 = ((reinterpret_cast(dst) >> 26) & 0b111) << 2; // start 32-byte transfer from store queue 0 (SQ0) to QACR0 asm volatile ("pref @%0" diff --git a/systembus_bits.h b/systembus_bits.h new file mode 100644 index 0000000..f93ebcb --- /dev/null +++ b/systembus_bits.h @@ -0,0 +1,28 @@ +#define C2DST__STATUS (1 << 0) + +#define CD2LEN__LENGTH(n) (((n) & 0xffffe0) << 0) + +#define C2DSTAT__ADDRESS(n) ((((n) & 0x13ffffe0) | 0x10000000) << 0) + +#define ISTNRM__END_OF_TRANSFERRING_PUNCH_THROUGH_LIST (1 << 21) +#define ISTNRM__END_OF_DMA_SORT_DMA (1 << 20) +#define ISTNRM__END_OF_DMA_CH2_DMA (1 << 19) +#define ISTNRM__END_OF_DMA_DEV_DMA (1 << 18) +#define ISTNRM__END_OF_DMA_EXT_DMA2 (1 << 17) +#define ISTNRM__END_OF_DMA_EXT_DMA1 (1 << 16) +#define ISTNRM__END_OF_DMA_AICA_DMA (1 << 15) +#define ISTNRM__END_OF_DMA_GD_DMA (1 << 14) +#define ISTNRM__MAPLE_V_BLANK_OVER_INTERRUPT (1 << 13) +#define ISTNRM__END_OF_DMA_MAPLE_DMA (1 << 12) +#define ISTNRM__END_OF_DMA_PVR_DMA (1 << 11) +#define ISTNRM__END_OF_TRANSFERRING_TRANSLUCENT_MODIFIER_VOLUME_LIST (1 << 10) +#define ISTNRM__END_OF_TRANSFERRING_TRANSLUCENT_LIST (1 << 9) +#define ISTNRM__END_OF_TRANSFERRING_OPAQUE_MODIFIER_VOLUME_LIST (1 << 8) +#define ISTNRM__END_OF_TRANSFERRING_OPAQUE_LIST (1 << 7) +#define ISTNRM__END_OF_TRANSFERRING_YUV (1 << 6) +#define ISTNRM__H_BLANK_IN_INTERRUPT (1 << 5) +#define ISTNRM__V_BLANK_OUT_INTERRUPT (1 << 4) +#define ISTNRM__V_BLANK_IN_INTERRUPT (1 << 3) +#define ISTNRM__END_OF_RENDER_TSP (1 << 2) +#define ISTNRM__END_OF_RENDER_ISP (1 << 1) +#define ISTNRM__END_OF_RENDER_VIDEO (1 << 0) diff --git a/ta.h b/ta.h deleted file mode 100644 index 6dd6715..0000000 --- a/ta.h +++ /dev/null @@ -1,84 +0,0 @@ -#define ISP_FEED_CFG__TRANSLUCENCY_CACHE_SIZE(n) (((n) & 0x3ff) << 14) - -#define FPU_SHAD_SCALE__INTENSITY_SHADOW_ENABLE (1 << 8) -#define FPU_SHAD_SCALE__SCALE_FACTOR(n) (((n) & 0xff) << 0) - -#define SPAN_SORT_CFG__CACHE_BYPASS (1 << 16) -#define SPAN_SORT_CFG__OFFSET_SORT_ENABLE (1 << 8) -#define SPAN_SORT_CFG__SPAN_SORT_ENABLE (1 << 0) - -#define FOG_COL_RAM__RED(n) (((n) & 0xff) << 16) -#define FOG_COL_RAM__GREEN(n) (((n) & 0xff) << 8) -#define FOG_COL_RAM__BLUE(n) (((n) & 0xff) << 0) - -#define FOG_COL_VERT__RED(n) (((n) & 0xff) << 16) -#define FOG_COL_VERT__GREEN(n) (((n) & 0xff) << 8) -#define FOG_COL_VERT__BLUE(n) (((n) & 0xff) << 0) - -#define FOG_CLAMP_MIN__ALPHA(n) (((n) & 0xff) << 24) -#define FOG_CLAMP_MIN__RED(n) (((n) & 0xff) << 16) -#define FOG_CLAMP_MIN__GREEN(n) (((n) & 0xff) << 8) -#define FOG_CLAMP_MIN__BLUE(n) (((n) & 0xff) << 0) - -#define FOG_CLAMP_MAX__ALPHA(n) (((n) & 0xff) << 24) -#define FOG_CLAMP_MAX__RED(n) (((n) & 0xff) << 16) -#define FOG_CLAMP_MAX__GREEN(n) (((n) & 0xff) << 8) -#define FOG_CLAMP_MAX__BLUE(n) (((n) & 0xff) << 0) - -#define HALF_OFFSET__TSP_TEXEL_SAMPLE_POSITION_CENTER (1 << 2) -#define HALF_OFFSET__TSP_PIXEL_SAMPLE_POSITION_CENTER (1 << 1) -#define HALF_OFFSET__FPU_PIXEL_SAMPLE_POSITION_CENTER (1 << 0) - -#define FPU_PARAM_CFG__REGION_HEADER_TYPE__1 (0 << 21) -#define FPU_PARAM_CFG__REGION_HEADER_TYPE__2 (1 << 21) -#define FPU_PARAM_CFG__TSP_PARAMETER_BURST_TRIGGER(n) (((n) & 0x3f) << 14) -#define FPU_PARAM_CFG__ISP_PARAMETER_BURST_TRIGGER(n) (((n) & 0x3f) << 8) -#define FPU_PARAM_CFG__POINTER_BURST_SIZE(n) (((n) & 0xf) << 4) -#define FPU_PARAM_CFG__POINTER_FIRST_BURST_SIZE(n) (((n) & 0xf) << 0) - -// -------------------- - -#define TA_GLOB_TILE_CLIP__TILE_Y_NUM(n) (((n) & 0b1111) << 16) -#define TA_GLOB_TILE_CLIP__TILE_X_NUM(n) (((n) & 0b11111) << 0) - -#define TA_ALLOC_CTRL__OPB_MODE_INCREASING (0 << 20) -#define TA_ALLOC_CTRL__OPB_MODE_DECREASING (1 << 20) -#define TA_ALLOC_CTRL__PT_OPB__NONE (0b00 << 16) -#define TA_ALLOC_CTRL__PT_OPB__8 (0b01 << 16) -#define TA_ALLOC_CTRL__PT_OPB__16 (0b10 << 16) -#define TA_ALLOC_CTRL__PT_OPB__32 (0b11 << 16) -#define TA_ALLOC_CTRL__TM_OPB__NONE (0b00 << 12) -#define TA_ALLOC_CTRL__TM_OPB__8 (0b01 << 12) -#define TA_ALLOC_CTRL__TM_OPB__16 (0b10 << 12) -#define TA_ALLOC_CTRL__TM_OPB__32 (0b11 << 12) -#define TA_ALLOC_CTRL__T_OPB__NONE (0b00 << 8) -#define TA_ALLOC_CTRL__T_OPB__8 (0b01 << 8) -#define TA_ALLOC_CTRL__T_OPB__16 (0b10 << 8) -#define TA_ALLOC_CTRL__T_OPB__32 (0b11 << 8) -#define TA_ALLOC_CTRL__OM_OPB__NONE (0b00 << 4) -#define TA_ALLOC_CTRL__OM_OPB__8 (0b01 << 4) -#define TA_ALLOC_CTRL__OM_OPB__16 (0b10 << 4) -#define TA_ALLOC_CTRL__OM_OPB__32 (0b11 << 4) -#define TA_ALLOC_CTRL__O_OPB__NONE (0b00 << 0) -#define TA_ALLOC_CTRL__O_OPB__8 (0b01 << 0) -#define TA_ALLOC_CTRL__O_OPB__16 (0b10 << 0) -#define TA_ALLOC_CTRL__O_OPB__32 (0b11 << 0) - -#define SOFTRESET__SDRAM_IF_SOFT_RESET (1 << 2) -#define SOFTRESET__CORE_SOFT_RESET (1 << 1) -#define SOFTRESET__TA_SOFT_RESET (1 << 0) - -#define TA_LIST_INIT__LIST_INIT (1 << 31) - -#define SB_ISTNRM__TAEOINT (1 << 7) // End of Transferring interrupt : Opaque List - -#define FB_W_CTRL__FB_PACKMODE__565_RGB (1 << 0); - -#define ISP_BACKGND_T__CACHE_BYPASS (1 << 28) -#define ISP_BACKGND_T__SHADOW (1 << 27) -#define ISP_BACKGND_T__SKIP(n) (((n) & 0b111) << 24) -//#define ISP_BACKGND_T__TAG_ADDRESS(n) ((n) & 0xfffff8) -#define ISP_BACKGND_T__TAG_ADDRESS(n) (((n) & 0x3fffff) << 3) -#define ISP_BACKGND_T__TAG_OFFSET(n) (((n) & 0b111) << 0) - -// ---------- diff --git a/texture_memory_alloc.h b/texture_memory_alloc.h new file mode 100644 index 0000000..5118577 --- /dev/null +++ b/texture_memory_alloc.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +struct __attribute__((__packed__)) texture_memory_alloc { + uint32_t isp_tsp_parameters[0x00100000 / 4]; // TA_ISP_BASE / PARAM_BASE (the actual objects) + uint32_t object_list[0x00100000 / 4]; // TA_OL_BASE (contains object pointer blocks) + uint32_t _res0[ 0x20 / 4]; // (the TA may clobber 4 bytes starting at TA_OL_LIMIT) + uint32_t region_array[0x00002000 / 4]; // REGION_BASE + uint32_t background[0x00000020 / 4]; // ISP_BACKGND_T + uint32_t framebuffer[2][0x00096000 / 4]; // FB_R_SOF1 / FB_W_SOF1 +};