diff --git a/common.mk b/common.mk index 1380afc..3145c60 100644 --- a/common.mk +++ b/common.mk @@ -2,7 +2,7 @@ MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(dir $(MAKEFILE_PATH)) LIB ?= . -OPT ?= -Os +OPT ?= -O3 DEBUG ?= -g -gdwarf-4 GENERATED ?= diff --git a/example/example.mk b/example/example.mk index 62fc5b8..da693a3 100644 --- a/example/example.mk +++ b/example/example.mk @@ -33,6 +33,19 @@ MACAW_TWIDDLE_OBJ = \ example/macaw_twiddle.elf: LDSCRIPT = $(LIB)/alt.lds example/macaw_twiddle.elf: $(START_OBJ) $(MACAW_TWIDDLE_OBJ) +FONT_OBJ = \ + example/font.o \ + vga.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + serial.o \ + sperrypc.data.o + +example/font.elf: LDSCRIPT = $(LIB)/alt.lds +example/font.elf: $(START_OBJ) $(FONT_OBJ) + MACAW_MULTIPASS_OBJ = \ example/macaw_multipass.o \ vga.o \ diff --git a/example/font.cpp b/example/font.cpp new file mode 100644 index 0000000..316dc3a --- /dev/null +++ b/example/font.cpp @@ -0,0 +1,261 @@ +#include + +#include "align.hpp" + +#include "vga.hpp" +#include "holly.hpp" +#include "holly/core.hpp" +#include "holly/core_bits.hpp" +#include "holly/ta_parameter.hpp" +#include "holly/ta_fifo_polygon_converter.hpp" +#include "holly/texture_memory_alloc.hpp" +#include "memorymap.hpp" +#include "holly/background.hpp" +#include "holly/region_array.hpp" +#include "holly/ta_bits.hpp" +#include "twiddle.hpp" +#include "serial.hpp" + +#include "sperrypc.hpp" + +struct vertex { + float x; + float y; + float z; + float u; + float v; +}; + +/* +// screen space coordinates +const struct vertex quad_verticies[4] = { + { 0.f, 64.f, 0.01f, 0.f, 1.f }, + { 0.f, 0.f, 0.01f, 0.f, 0.f }, + { 64.f, 0.f, 0.01f, 1.f, 0.f }, + { 64.f, 64.f, 0.01f, 1.f, 1.f, }, +}; + +uint32_t transform(uint32_t * ta_parameter_buf) +{ + auto parameter = ta_parameter_writer(ta_parameter_buf); + uint32_t texture_address = (offsetof (struct texture_memory_alloc, texture)); + constexpr uint32_t base_color = 0xffffffff; + auto sprite = global_sprite(base_color); + sprite.parameter_control_word = para_control::para_type::sprite + | para_control::list_type::opaque + | obj_control::col_type::packed_color + | obj_control::texture + | obj_control::_16bit_uv; + sprite.tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one + | tsp_instruction_word::dst_alpha_instr::zero + | tsp_instruction_word::fog_control::no_fog + | tsp_instruction_word::texture_u_size::_8 // 8px + | tsp_instruction_word::texture_v_size::_8; // 8px + sprite.texture_control_word = texture_control_word::pixel_format::_565 + | texture_control_word::scan_order::twiddled + | texture_control_word::texture_address(texture_address / 8); + parameter.append() = sprite; + + parameter.append() = + vertex_sprite_type_1(quad_verticies[0].x, + quad_verticies[0].y, + quad_verticies[0].z, + quad_verticies[1].x, + quad_verticies[1].y, + quad_verticies[1].z, + quad_verticies[2].x, + quad_verticies[2].y, + quad_verticies[2].z, + quad_verticies[3].x, + quad_verticies[3].y, + uv_16bit(quad_verticies[0].u, quad_verticies[0].v), + uv_16bit(quad_verticies[1].u, quad_verticies[1].v), + uv_16bit(quad_verticies[2].u, quad_verticies[2].v)); + // curiously, there is no `dz` in vertex_sprite_type_1 + // curiously, there is no `du_dv` in vertex_sprite_type_1 + + parameter.append() = global_end_of_list(); + + return parameter.offset; +} +*/ + +const struct vertex strip_vertices[4] = { + // [ position ] [ uv coordinates ] + { -0.5f, 0.5f, 0.f, 0.f, 1.f, }, + { -0.5f, -0.5f, 0.f, 0.f, 0.f, }, + { 0.5f, 0.5f, 0.f, 1.f, 1.f, }, + { 0.5f, -0.5f, 0.f, 1.f, 0.f, }, +}; +constexpr uint32_t strip_length = (sizeof (strip_vertices)) / (sizeof (struct vertex)); + +uint32_t transform(uint32_t * ta_parameter_buf, const char * s, const uint32_t len) +{ + auto parameter = ta_parameter_writer(ta_parameter_buf); + uint32_t texture_address = (offsetof (struct texture_memory_alloc, texture)); + + for (uint32_t string_ix = 0; string_ix < len; string_ix++) { + auto polygon = global_polygon_type_0(texture_address); + polygon.parameter_control_word = para_control::para_type::polygon_or_modifier_volume + | para_control::list_type::opaque + | obj_control::col_type::packed_color + | obj_control::texture; + + 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 + | tsp_instruction_word::texture_u_size::_8 // 8px + | tsp_instruction_word::texture_v_size::_8; // 8px + + polygon.texture_control_word = texture_control_word::pixel_format::_8bpp_palette + | texture_control_word::scan_order::twiddled + | texture_control_word::texture_address((texture_address + 8 * 8 * (s[string_ix] - ' ')) / 8); + parameter.append() = polygon; + + for (uint32_t i = 0; i < strip_length; i++) { + bool end_of_strip = i == strip_length - 1; + + float x = strip_vertices[i].x; + float y = strip_vertices[i].y; + float z = strip_vertices[i].z; + + x *= 32.f; + y *= 32.f; + x += 64.f + 32 * string_ix; + y += 240.f; + z = 1.f / (z + 10.f); + + parameter.append() = + vertex_polygon_type_3(x, y, z, + strip_vertices[i].u, + strip_vertices[i].v, + 0x00000000, // base_color + end_of_strip); + } + } + + parameter.append() = global_end_of_list(); + + return parameter.offset; +} + + +void init_texture_memory(const struct opb_size& opb_size) +{ + volatile texture_memory_alloc * mem = reinterpret_cast(texture_memory); + + background_parameter(mem->background); + + region_array2(mem->region_array, + (offsetof (struct texture_memory_alloc, object_list)), + 640 / 32, // width + 480 / 32, // height + opb_size + ); +} + +inline void inflate_character(const uint8_t * src, const uint8_t c) +{ + uint8_t character_index = c - ' '; + + uint8_t temp[8 * 8]; + for (uint32_t y = 0; y < 8; y++) { + uint8_t row = src[y + 8 * character_index]; + for (uint32_t x = 0; x < 8; x++) { + uint8_t px = (row >> (7 - x)) & 1; + //serial::character((px == 1) ? 'X' : '_'); + //uint16_t rgb565 = px ? 0xffff : 0; + uint16_t palette_index = px ? 2 : 1; + + temp[y * 8 + x] = palette_index; + } + //serial::character('\n'); + } + + auto mem = reinterpret_cast(0xa400'0000); + auto texture = reinterpret_cast(mem->texture); + + uint32_t offset = 8 * 8 * character_index; + union { + uint8_t u8[8 * 8]; + uint32_t u32[8 * 8 / 4]; + } temp2; + + //twiddle::texture(&texture[offset], temp, 8, 8); + twiddle::texture(temp2.u8, temp, 8, 8); + for (uint32_t i = 0; i < 8 * 8 / 4; i++) { + texture[(offset / 4) + i] = temp2.u32[i]; + } +} + +void inflate_font(const uint8_t * src) +{ + for (uint8_t ix = 0x20; ix < 0x7f; ix++) { + inflate_character(src, ix); + } +} + +void palette_data() +{ + holly.PAL_RAM_CTRL = pal_ram_ctrl::pixel_format::rgb565; + + holly.PALETTE_RAM[1] = (15) << 11; + holly.PALETTE_RAM[2] = (15 << 11) | (30 << 5); +} + +uint32_t _ta_parameter_buf[((32 * 10 * 17) + 32) / 4]; + +void main() +{ + vga(); + + auto src = reinterpret_cast(&_binary_sperrypc_data_start); + inflate_font(src); + palette_data(); + + // The address of `ta_parameter_buf` must be a multiple of 32 bytes. + // This is mandatory for ch2-dma to the ta fifo polygon converter. + uint32_t * ta_parameter_buf = align_32byte(_ta_parameter_buf); + + constexpr uint32_t ta_alloc = 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; + + constexpr struct opb_size opb_size = { .opaque = 16 * 4 + , .opaque_modifier = 0 + , .translucent = 0 + , .translucent_modifier = 0 + , .punch_through = 0 + }; + + constexpr uint32_t tiles = (640 / 32) * (320 / 32); + + holly.SOFTRESET = softreset::pipeline_soft_reset + | softreset::ta_soft_reset; + holly.SOFTRESET = 0; + + core_init(); + init_texture_memory(opb_size); + + uint32_t frame_ix = 0; + constexpr uint32_t num_frames = 1; + + const char ana[18] = "A from ana i know"; + + while (true) { + ta_polygon_converter_init(opb_size.total() * tiles, ta_alloc); + uint32_t ta_parameter_size = transform(ta_parameter_buf, ana, 17); + ta_polygon_converter_transfer(ta_parameter_buf, ta_parameter_size); + ta_wait_opaque_list(); + + core_start_render(frame_ix, num_frames); + + v_sync_out(); + v_sync_in(); + core_wait_end_of_render_video(frame_ix, num_frames); + + frame_ix++; + } +} diff --git a/holly/core_bits.hpp b/holly/core_bits.hpp index 3b25c11..d288e96 100644 --- a/holly/core_bits.hpp +++ b/holly/core_bits.hpp @@ -51,6 +51,8 @@ namespace fb_r_ctrl { namespace vclk_div { constexpr uint32_t pclk_vclk_2 = 0 << 23; constexpr uint32_t pclk_vclk_1 = 1 << 23; + + constexpr uint32_t bit_mask = 0x1 << 23; } constexpr uint32_t fb_strip_buf_en = 1 << 22; @@ -63,6 +65,8 @@ namespace fb_r_ctrl { constexpr uint32_t _0565_rgb_16bit = 1 << 2; constexpr uint32_t _888_rgb_24bit_packed = 2 << 2; constexpr uint32_t _0888_rgb_32bit = 3 << 2; + + constexpr uint32_t bit_mask = 0x3 << 2; } constexpr uint32_t fb_line_double = 1 << 1; @@ -82,6 +86,8 @@ namespace fb_w_ctrl { constexpr uint32_t _888_rgb_24bit_packed = 4 << 0; constexpr uint32_t _0888_krgb_32bit = 5 << 0; constexpr uint32_t _8888_argb_32bit = 6 << 0; + + constexpr uint32_t bit_mask = 0x7 << 0; } } @@ -125,6 +131,8 @@ namespace fpu_shad_scale { namespace simple_shadow_enable { constexpr uint32_t parameter_selection_volume_mode = 0 << 8; constexpr uint32_t intensity_volume_mode = 1 << 8; + + constexpr uint32_t bit_mask = 0x1 << 8; } constexpr uint32_t scale_factor_for_shadows(uint32_t num) { return (num & 0xff) << 0; } @@ -138,6 +146,8 @@ namespace fpu_param_cfg { namespace region_header_type { constexpr uint32_t type_1 = 0 << 21; constexpr uint32_t type_2 = 1 << 21; + + constexpr uint32_t bit_mask = 0x1 << 21; } constexpr uint32_t tsp_parameter_burst_threshold(uint32_t num) { return (num & 0x3f) << 14; } @@ -150,16 +160,22 @@ namespace half_offset { namespace tsp_texel_sampling_position { constexpr uint32_t top_left = 1 << 2; constexpr uint32_t center = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; } namespace tsp_pixel_sampling_position { constexpr uint32_t top_left = 1 << 1; constexpr uint32_t center = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; } namespace fpu_pixel_sampling_position { constexpr uint32_t top_left = 1 << 0; constexpr uint32_t center = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; } } @@ -204,12 +220,16 @@ namespace sdram_arb_cfg { constexpr uint32_t isp_pointer_data = 0x9 << 18; constexpr uint32_t isp_parameters = 0xa << 18; constexpr uint32_t crt_controller = 0xb << 18; + + constexpr uint32_t bit_mask = 0xf << 18; } namespace arbiter_priority_control { constexpr uint32_t priority_arbitration_only = 0x0 << 16; constexpr uint32_t override_value_field = 0x1 << 16; constexpr uint32_t round_robin_counter = 0x2 << 16; + + constexpr uint32_t bit_mask = 0x3 << 16; } constexpr uint32_t arbiter_crt_page_break_latency_count_value(uint32_t num) { return (num & 0xff) << 8; } @@ -272,6 +292,8 @@ namespace spg_hblank_int { constexpr uint32_t output_equal_line_comp_val = 0x0 << 12; constexpr uint32_t output_every_line_comp_val = 0x1 << 12; constexpr uint32_t output_every_line = 0x2 << 12; + + constexpr uint32_t bit_mask = 0x3 << 12; } constexpr uint32_t line_comp_val(uint32_t num) { return (num & 0x3ff) << 0; } @@ -286,11 +308,15 @@ namespace spg_control { namespace csync_on_h { constexpr uint32_t hsync = 0 << 9; constexpr uint32_t csync = 1 << 9; + + constexpr uint32_t bit_mask = 0x1 << 9; } namespace sync_direction { constexpr uint32_t input = 0 << 8; constexpr uint32_t output = 1 << 8; + + constexpr uint32_t bit_mask = 0x1 << 8; } constexpr uint32_t pal = 1 << 7; @@ -302,16 +328,22 @@ namespace spg_control { namespace mcsync_pol { constexpr uint32_t active_low = 0 << 2; constexpr uint32_t active_high = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; } namespace mvsync_pol { constexpr uint32_t active_low = 0 << 1; constexpr uint32_t active_high = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; } namespace mhsync_pol { constexpr uint32_t active_low = 0 << 0; constexpr uint32_t active_high = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; } } @@ -341,11 +373,15 @@ namespace text_control { namespace code_book_endian { constexpr uint32_t little_endian = 0 << 17; constexpr uint32_t big_endian = 1 << 17; + + constexpr uint32_t bit_mask = 0x1 << 17; } namespace index_endian { constexpr uint32_t little_endian = 0 << 16; constexpr uint32_t big_endian = 1 << 16; + + constexpr uint32_t bit_mask = 0x1 << 16; } constexpr uint32_t bank_bit(uint32_t num) { return (num & 0x1f) << 8; } @@ -367,6 +403,8 @@ namespace vo_control { constexpr uint32_t field_1_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge = 0x6 << 4; constexpr uint32_t field_2_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge = 0x7 << 4; constexpr uint32_t inverted_at_the_active_edge_of_vsync = 0x8 << 4; + + constexpr uint32_t bit_mask = 0xf << 4; } constexpr uint32_t blank_video = 1 << 3; @@ -374,16 +412,22 @@ namespace vo_control { namespace blank_pol { constexpr uint32_t active_low = 0 << 2; constexpr uint32_t active_high = 1 << 2; + + constexpr uint32_t bit_mask = 0x1 << 2; } namespace vsync_pol { constexpr uint32_t active_low = 0 << 1; constexpr uint32_t active_high = 1 << 1; + + constexpr uint32_t bit_mask = 0x1 << 1; } namespace hsync_pol { constexpr uint32_t active_low = 0 << 0; constexpr uint32_t active_high = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; } } @@ -400,6 +444,8 @@ namespace scaler_ctl { namespace field_select { constexpr uint32_t field_1 = 0 << 18; constexpr uint32_t field_2 = 1 << 18; + + constexpr uint32_t bit_mask = 0x1 << 18; } constexpr uint32_t interlace = 1 << 17; @@ -407,12 +453,14 @@ namespace scaler_ctl { constexpr uint32_t vertical_scale_factor(uint32_t num) { return (num & 0xffff) << 0; } } -namespace pal_ram_ctl { +namespace pal_ram_ctrl { namespace pixel_format { constexpr uint32_t argb1555 = 0 << 0; constexpr uint32_t rgb565 = 1 << 0; constexpr uint32_t argb4444 = 2 << 0; constexpr uint32_t argb8888 = 3 << 0; + + constexpr uint32_t bit_mask = 0x3 << 0; } } diff --git a/holly/ta_parameter.hpp b/holly/ta_parameter.hpp index b0d2daf..a397542 100644 --- a/holly/ta_parameter.hpp +++ b/holly/ta_parameter.hpp @@ -131,6 +131,36 @@ static_assert((offsetof (struct vertex_polygon_type_0, _res1)) == 0x14); static_assert((offsetof (struct vertex_polygon_type_0, base_color)) == 0x18); static_assert((offsetof (struct vertex_polygon_type_0, _res2)) == 0x1c); +struct vertex_polygon_type_4 { + uint32_t parameter_control_word; + float x; + float y; + float z; + uint32_t uv; + uint32_t _res0; + uint32_t base_color; + uint32_t offset_color; + + vertex_polygon_type_4(const float x, + const float y, + const float z, + const uint32_t uv, + const uint32_t base_color, + const bool end_of_strip + ) + : parameter_control_word( para_control::para_type::vertex_parameter + | (end_of_strip ? para_control::end_of_strip : 0) + ) + , x(x) + , y(y) + , z(z) + , uv(uv) + , _res0(0) + , base_color(base_color) + , offset_color(0) + { } +}; + struct global_polygon_type_0 { uint32_t parameter_control_word; uint32_t isp_tsp_instruction_word; @@ -218,7 +248,8 @@ struct global_sprite { global_sprite(const uint32_t base_color) : parameter_control_word( para_control::para_type::sprite - | para_control::list_type::opaque ) + | para_control::list_type::opaque + | obj_control::col_type::packed_color ) , isp_tsp_instruction_word( isp_tsp_instruction_word::depth_compare_mode::always | isp_tsp_instruction_word::culling_mode::no_culling ) , tsp_instruction_word( tsp_instruction_word::src_alpha_instr::one @@ -284,6 +315,59 @@ struct vertex_sprite_type_0 { static_assert((sizeof (vertex_sprite_type_0)) == 64); +struct vertex_sprite_type_1 { + uint32_t parameter_control_word; + float ax; + float ay; + float az; + float bx; + float by; + float bz; + float cx; + + float cy; + float cz; + float dx; + float dy; + float _res0; + uint32_t au_av; + uint32_t bu_bv; + uint32_t cu_cv; + + vertex_sprite_type_1(const float ax, + const float ay, + const float az, + const float bx, + const float by, + const float bz, + const float cx, + const float cy, + const float cz, + const float dx, + const float dy, + const uint32_t au_av, + const uint32_t bu_bv, + const uint32_t cu_cv) + : parameter_control_word(para_control::para_type::vertex_parameter) + , ax(ax) + , ay(ay) + , az(az) + , bx(bx) + , by(by) + , bz(bz) + , cx(cx) + , cy(cy) + , dx(dx) + , dy(dy) + , _res0(0) + , au_av(au_av) + , bu_bv(bu_bv) + , cu_cv(cu_cv) + {} +}; + +static_assert((sizeof (vertex_sprite_type_1)) == 64); + struct global_end_of_list { uint32_t parameter_control_word; uint32_t _res0; @@ -347,3 +431,12 @@ union ta_parameter { }; static_assert((sizeof (ta_parameter)) == 32); */ + +uint32_t uv_16bit(float u, float v) +{ + uint32_t * ui = (reinterpret_cast(&u)); + uint32_t * vi = (reinterpret_cast(&v)); + uint32_t u_half = ((*ui) >> 16) & 0xffff; + uint32_t v_half = ((*vi) >> 16) & 0xffff; + return (u_half << 16) | (v_half << 0); +} diff --git a/regs/core_bits.csv b/regs/core_bits.csv index d2a82c0..dec7246 100644 --- a/regs/core_bits.csv +++ b/regs/core_bits.csv @@ -237,10 +237,10 @@ "SCALER_CTL",,16,"horizontal_scaling_enable",1,,,,,,, "SCALER_CTL",,"15-0","vertical_scale_factor",,"0xffff",,,,,, ,,,,,,,,,,, -"PAL_RAM_CTL","pixel_format","1-0","argb1555",0,,,,,,, -"PAL_RAM_CTL","pixel_format","1-0","rgb565",1,,,,,,, -"PAL_RAM_CTL","pixel_format","1-0","argb4444",2,,,,,,, -"PAL_RAM_CTL","pixel_format","1-0","argb8888",3,,,,,,, +"PAL_RAM_CTRL","pixel_format","1-0","argb1555",0,,,,,,, +"PAL_RAM_CTRL","pixel_format","1-0","rgb565",1,,,,,,, +"PAL_RAM_CTRL","pixel_format","1-0","argb4444",2,,,,,,, +"PAL_RAM_CTRL","pixel_format","1-0","argb8888",3,,,,,,, ,,,,,,,,,,, "SPG_STATUS",,13,"vsync",,,,,,,, "SPG_STATUS",,12,"hsync",,,,,,,, diff --git a/regs/core_bits.ods b/regs/core_bits.ods index f60fffd..986407c 100644 Binary files a/regs/core_bits.ods and b/regs/core_bits.ods differ diff --git a/sperrypc.data b/sperrypc.data new file mode 100644 index 0000000..e46ee5e Binary files /dev/null and b/sperrypc.data differ diff --git a/sperrypc.hpp b/sperrypc.hpp new file mode 100644 index 0000000..346857c --- /dev/null +++ b/sperrypc.hpp @@ -0,0 +1,5 @@ +#include + +extern uint32_t _binary_sperrypc_data_start __asm("_binary_sperrypc_data_start"); +extern uint32_t _binary_sperrypc_data_end __asm("_binary_sperrypc_data_end"); +extern uint32_t _binary_sperrypc_data_size __asm("_binary_sperrypc_data_size");