diff --git a/example/example.mk b/example/example.mk index b5b8795..e90640a 100644 --- a/example/example.mk +++ b/example/example.mk @@ -1,3 +1,15 @@ +VIDEO_OUTPUT_OBJ = \ + example/video_output.o \ + holly/video_output.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + sh7091/serial.o + +example/video_output.elf: LDSCRIPT = $(LIB)/alt.lds +example/video_output.elf: $(START_OBJ) $(VIDEO_OUTPUT_OBJ) + SPRITE_OBJ = \ example/sprite.o \ holly/video_output.o \ diff --git a/example/macaw_multipass.cpp b/example/macaw_multipass.cpp index 5383899..dc112ca 100644 --- a/example/macaw_multipass.cpp +++ b/example/macaw_multipass.cpp @@ -155,7 +155,7 @@ void main() } }; - constexpr uint32_t tiles = (640 / 32) * (320 / 32); + constexpr uint32_t tiles = (640 / 32) * (480 / 32); uint32_t frame_ix = 0; constexpr uint32_t num_frames = 1; diff --git a/example/sprite.cpp b/example/sprite.cpp index 7526e62..bd0a55c 100644 --- a/example/sprite.cpp +++ b/example/sprite.cpp @@ -21,7 +21,7 @@ struct vertex { }; // screen space coordinates -const struct vertex quad_verticies[4] = { +const struct vertex quad_vertices[4] = { { 200.f, 360.f, 0.1f }, { 200.f, 120.f, 0.1f }, { 440.f, 120.f, 0.1f }, @@ -35,17 +35,17 @@ uint32_t transform(uint32_t * ta_parameter_buf) constexpr uint32_t base_color = 0xffff0000; parameter.append() = global_sprite(base_color); parameter.append() = - vertex_sprite_type_0(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); + vertex_sprite_type_0(quad_vertices[0].x, + quad_vertices[0].y, + quad_vertices[0].z, + quad_vertices[1].x, + quad_vertices[1].y, + quad_vertices[1].z, + quad_vertices[2].x, + quad_vertices[2].y, + quad_vertices[2].z, + quad_vertices[3].x, + quad_vertices[3].y); // curiously, there is no quad_veritices[3].z in vertex_sprite_type_0 parameter.append() = global_end_of_list(); @@ -90,7 +90,7 @@ void main() , .punch_through = 0 }; - constexpr uint32_t tiles = (640 / 32) * (320 / 32); + constexpr uint32_t tiles = (640 / 32) * (480 / 32); holly.SOFTRESET = softreset::pipeline_soft_reset | softreset::ta_soft_reset; diff --git a/example/video_output.cpp b/example/video_output.cpp new file mode 100644 index 0000000..568913c --- /dev/null +++ b/example/video_output.cpp @@ -0,0 +1,187 @@ +#include "align.hpp" +#include "dve.hpp" +#include "memorymap.hpp" +#include "holly/holly.hpp" +#include "holly/core.hpp" +#include "holly/core_bits.hpp" +#include "holly/video_output.hpp" +#include "holly/ta_bits.hpp" +#include "holly/ta_parameter.hpp" +#include "holly/ta_global_parameter.hpp" +#include "holly/ta_vertex_parameter.hpp" +#include "holly/ta_fifo_polygon_converter.hpp" +#include "holly/isp_tsp.hpp" +#include "holly/texture_memory_alloc.hpp" +#include "holly/background.hpp" +#include "holly/region_array.hpp" + +#include "sh7091/serial.hpp" + +void print_cable_type_resolution(const uint32_t cable_type, const struct video_output::framebuffer_resolution& framebuffer_resolution) +{ + serial::string("cable type: "); + switch (cable_type) { + case pdtra::cable_type::vga: serial::string("vga\n"); break; + case pdtra::cable_type::rgb: serial::string("rgb\n"); break; + case pdtra::cable_type::cvbs_yc: serial::string("cvbs_yc\n"); break; + default: serial::string("undefined/reserved\n"); break; + } + serial::string("framebuffer resolution: "); + serial::integer(framebuffer_resolution.width, ' ', 3); + serial::integer(framebuffer_resolution.height, '\n', 3); +} + +struct vertex { + float x; + float y; + float z; +}; + +// screen space coordinates +const struct vertex quad_vertices[4] = { + { -0.5f, 0.5f, 0.1f }, + { -0.5f, -0.5f, 0.1f }, + { 0.5f, -0.5f, 0.1f }, + { 0.5f, 0.5f, 0.1f }, +}; + +struct vertex transform_vertex(const struct vertex& v, + const struct video_output::framebuffer_resolution& framebuffer_resolution, + const float theta) +{ + float x = v.x * __builtin_cosf(theta) - v.y * __builtin_sinf(theta); + float y = v.x * __builtin_sinf(theta) + v.y * __builtin_cosf(theta); + + return { + x * (framebuffer_resolution.height / 2) + (framebuffer_resolution.width / 2), + y * (framebuffer_resolution.height / 2) + (framebuffer_resolution.height / 2), + v.z, + }; +} + +uint32_t transform(uint32_t * ta_parameter_buf, + const struct video_output::framebuffer_resolution& framebuffer_resolution, + const float theta) +{ + auto parameter = ta_parameter_writer(ta_parameter_buf); + + auto a = transform_vertex(quad_vertices[0], framebuffer_resolution, theta); + auto b = transform_vertex(quad_vertices[1], framebuffer_resolution, theta); + auto c = transform_vertex(quad_vertices[2], framebuffer_resolution, theta); + auto d = transform_vertex(quad_vertices[3], framebuffer_resolution, theta); + + const uint32_t parameter_control_word = para_control::para_type::sprite + | para_control::list_type::opaque + | obj_control::col_type::packed_color; + + const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater + | isp_tsp_instruction_word::culling_mode::no_culling; + + const uint32_t tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one + | tsp_instruction_word::dst_alpha_instr::zero + | tsp_instruction_word::fog_control::no_fog; + + const uint32_t texture_control_word = 0; + + + constexpr uint32_t base_color = 0xffff0000; + parameter.append() = + ta_global_parameter::sprite(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + texture_control_word, + base_color, + 0, // offset_color + 0, // data_size_for_sort_dma + 0); // next_address_for_sort_dma + + parameter.append() = + ta_vertex_parameter::sprite_type_0(para_control::para_type::vertex_parameter, + a.x, a.y, a.z, + b.x, b.y, b.z, + c.x, c.y, c.z, + d.x, d.y); + // curiously, there is no quad_veritices[3].z in vertex_sprite_type_0 + + parameter.append() = ta_global_parameter::end_of_list(para_control::para_type::end_of_list); + + return parameter.offset; +} + +void init_texture_memory(const struct opb_size& opb_size, const struct video_output::framebuffer_resolution& framebuffer_resolution) +{ + auto mem = reinterpret_cast(texture_memory32); + + background_parameter(mem->background, 0xff220000); + + region_array2(mem->region_array, + (offsetof (struct texture_memory_alloc, object_list)), + framebuffer_resolution.width / 32, // width + framebuffer_resolution.height / 32, // height + opb_size + ); +} + +uint32_t _ta_parameter_buf[((32 + 64 + 32) + 32) / 4]; + +void main() +{ + 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 + }; + + holly.SOFTRESET = softreset::pipeline_soft_reset + | softreset::ta_soft_reset; + holly.SOFTRESET = 0; + + uint32_t cable_type = video_output::get_cable_type(); + auto framebuffer_resolution = video_output::set_mode_by_cable_type(cable_type); + print_cable_type_resolution(cable_type, framebuffer_resolution); + init_texture_memory(opb_size, framebuffer_resolution); + core_init(); + + float theta = 0; + uint32_t frame_ix = 0; + constexpr uint32_t num_frames = 1; + + while (true) { + ta_polygon_converter_init(opb_size.total(), + ta_alloc, + framebuffer_resolution.width / 32, + framebuffer_resolution.height / 32); + uint32_t ta_parameter_size = transform(ta_parameter_buf, framebuffer_resolution, theta); + ta_polygon_converter_transfer(ta_parameter_buf, ta_parameter_size); + ta_wait_opaque_list(); + + core_start_render((offsetof (struct texture_memory_alloc, framebuffer)), + framebuffer_resolution.width, // frame_width + 0x00096000, // frame_size + frame_ix, num_frames);; + core_wait_end_of_render_video(); + + while (!spg_status::vsync(holly.SPG_STATUS)); + core_flip(frame_ix, num_frames); + if (cable_type != video_output::get_cable_type()) { + cable_type = video_output::get_cable_type(); + framebuffer_resolution = video_output::set_mode_by_cable_type(cable_type); + print_cable_type_resolution(cable_type, framebuffer_resolution); + init_texture_memory(opb_size, framebuffer_resolution); + } + while (spg_status::vsync(holly.SPG_STATUS)); + + constexpr float half_degree = 0.01745329f / 2.f; + theta += half_degree; + frame_ix += 1; + } +} diff --git a/holly/holly.hpp b/holly/holly.hpp index 24952c6..96b064b 100644 --- a/holly/holly.hpp +++ b/holly/holly.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include diff --git a/holly/ta_global_parameter.hpp b/holly/ta_global_parameter.hpp index 5ef88e1..ee9162f 100644 --- a/holly/ta_global_parameter.hpp +++ b/holly/ta_global_parameter.hpp @@ -25,6 +25,11 @@ namespace ta_global_parameter { , _res5(0) , _res6(0) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (end_of_list)) == 32); static_assert((offsetof (struct end_of_list, parameter_control_word)) == 0x00); @@ -61,6 +66,11 @@ namespace ta_global_parameter { , user_clip_x_max(user_clip_x_max) , user_clip_y_max(user_clip_y_max) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (user_tile_clip)) == 32); static_assert((offsetof (struct user_tile_clip, parameter_control_word)) == 0x00); @@ -98,6 +108,11 @@ namespace ta_global_parameter { , bounding_box_x_max(bounding_box_x_max) , bounding_box_y_max(bounding_box_y_max) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (object_list_set)) == 32); static_assert((offsetof (struct object_list_set, parameter_control_word)) == 0x00); @@ -135,6 +150,11 @@ namespace ta_global_parameter { , data_size_for_sort_dma(data_size_for_sort_dma) , next_address_for_sort_dma(next_address_for_sort_dma) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_0)) == 32); static_assert((offsetof (struct polygon_type_0, parameter_control_word)) == 0x00); @@ -174,6 +194,11 @@ namespace ta_global_parameter { , face_color_g(face_color_g) , face_color_b(face_color_b) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_1)) == 32); static_assert((offsetof (struct polygon_type_1, parameter_control_word)) == 0x00); @@ -235,6 +260,11 @@ namespace ta_global_parameter { , face_offset_color_g(face_offset_color_g) , face_offset_color_b(face_offset_color_b) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_2)) == 64); static_assert((offsetof (struct polygon_type_2, parameter_control_word)) == 0x00); @@ -282,6 +312,11 @@ namespace ta_global_parameter { , data_size_for_sort_dma(data_size_for_sort_dma) , next_address_for_sort_dma(next_address_for_sort_dma) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_3)) == 32); static_assert((offsetof (struct polygon_type_3, parameter_control_word)) == 0x00); @@ -345,6 +380,11 @@ namespace ta_global_parameter { , face_color_g_1(face_color_g_1) , face_color_b_1(face_color_b_1) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_4)) == 64); static_assert((offsetof (struct polygon_type_4, parameter_control_word)) == 0x00); @@ -392,6 +432,11 @@ namespace ta_global_parameter { , data_size_for_sort_dma(data_size_for_sort_dma) , next_address_for_sort_dma(next_address_for_sort_dma) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (sprite)) == 32); static_assert((offsetof (struct sprite, parameter_control_word)) == 0x00); @@ -425,6 +470,11 @@ namespace ta_global_parameter { , _res4(0) , _res5(0) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (modifier_volume)) == 32); static_assert((offsetof (struct modifier_volume, parameter_control_word)) == 0x00); diff --git a/holly/ta_vertex_parameter.hpp b/holly/ta_vertex_parameter.hpp index c253d08..19609b4 100644 --- a/holly/ta_vertex_parameter.hpp +++ b/holly/ta_vertex_parameter.hpp @@ -29,6 +29,11 @@ namespace ta_vertex_parameter { , base_color(base_color) , _res2(0) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_0)) == 32); static_assert((offsetof (struct polygon_type_0, parameter_control_word)) == 0x00); @@ -68,6 +73,11 @@ namespace ta_vertex_parameter { , base_color_g(base_color_g) , base_color_b(base_color_b) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_1)) == 32); static_assert((offsetof (struct polygon_type_1, parameter_control_word)) == 0x00); @@ -104,6 +114,11 @@ namespace ta_vertex_parameter { , base_intensity(base_intensity) , _res2(0) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_2)) == 32); static_assert((offsetof (struct polygon_type_2, parameter_control_word)) == 0x00); @@ -143,6 +158,11 @@ namespace ta_vertex_parameter { , base_color(base_color) , offset_color(offset_color) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_3)) == 32); static_assert((offsetof (struct polygon_type_3, parameter_control_word)) == 0x00); @@ -181,6 +201,11 @@ namespace ta_vertex_parameter { , base_color(base_color) , offset_color(offset_color) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_4)) == 32); static_assert((offsetof (struct polygon_type_4, parameter_control_word)) == 0x00); @@ -242,6 +267,11 @@ namespace ta_vertex_parameter { , offset_color_g(offset_color_g) , offset_color_b(offset_color_b) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_5)) == 64); static_assert((offsetof (struct polygon_type_5, parameter_control_word)) == 0x00); @@ -310,6 +340,11 @@ namespace ta_vertex_parameter { , offset_color_g(offset_color_g) , offset_color_b(offset_color_b) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_6)) == 64); static_assert((offsetof (struct polygon_type_6, parameter_control_word)) == 0x00); @@ -357,6 +392,11 @@ namespace ta_vertex_parameter { , base_intensity(base_intensity) , offset_intensity(offset_intensity) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_7)) == 32); static_assert((offsetof (struct polygon_type_7, parameter_control_word)) == 0x00); @@ -395,6 +435,11 @@ namespace ta_vertex_parameter { , base_intensity(base_intensity) , offset_intensity(offset_intensity) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_8)) == 32); static_assert((offsetof (struct polygon_type_8, parameter_control_word)) == 0x00); @@ -432,6 +477,11 @@ namespace ta_vertex_parameter { , _res0(0) , _res1(0) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_9)) == 32); static_assert((offsetof (struct polygon_type_9, parameter_control_word)) == 0x00); @@ -469,6 +519,11 @@ namespace ta_vertex_parameter { , _res0(0) , _res1(0) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_10)) == 32); static_assert((offsetof (struct polygon_type_10, parameter_control_word)) == 0x00); @@ -528,6 +583,11 @@ namespace ta_vertex_parameter { , _res2(0) , _res3(0) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_11)) == 64); static_assert((offsetof (struct polygon_type_11, parameter_control_word)) == 0x00); @@ -593,6 +653,11 @@ namespace ta_vertex_parameter { , _res4(0) , _res5(0) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_12)) == 64); static_assert((offsetof (struct polygon_type_12, parameter_control_word)) == 0x00); @@ -660,6 +725,11 @@ namespace ta_vertex_parameter { , _res2(0) , _res3(0) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_13)) == 64); static_assert((offsetof (struct polygon_type_13, parameter_control_word)) == 0x00); @@ -725,6 +795,11 @@ namespace ta_vertex_parameter { , _res4(0) , _res5(0) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (polygon_type_14)) == 64); static_assert((offsetof (struct polygon_type_14, parameter_control_word)) == 0x00); @@ -792,6 +867,11 @@ namespace ta_vertex_parameter { , _res2(0) , _res3(0) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (sprite_type_0)) == 64); static_assert((offsetof (struct sprite_type_0, parameter_control_word)) == 0x00); @@ -862,6 +942,11 @@ namespace ta_vertex_parameter { , b_u_b_v(b_u_b_v) , c_u_c_v(c_u_c_v) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (sprite_type_1)) == 64); static_assert((offsetof (struct sprite_type_1, parameter_control_word)) == 0x00); @@ -927,6 +1012,11 @@ namespace ta_vertex_parameter { , _res4(0) , _res5(0) { } + + const uint8_t * _data() + { + return reinterpret_cast(this); + } }; static_assert((sizeof (modifier_volume)) == 64); static_assert((offsetof (struct modifier_volume, parameter_control_word)) == 0x00); diff --git a/holly/video_output.cpp b/holly/video_output.cpp index b42ac6b..4483d70 100644 --- a/holly/video_output.cpp +++ b/holly/video_output.cpp @@ -9,6 +9,7 @@ #include "video_output.hpp" #include "video_output_mode.inc" +#include "video_output.hpp" namespace video_output { @@ -64,24 +65,27 @@ uint32_t get_cable_type() return sh7091.BSC.PDTRA & pdtra::cable_type::bit_mask; } -void set_mode_automatic() +framebuffer_resolution set_mode_by_cable_type(uint32_t cable_type) { - switch (get_cable_type()) { + switch (cable_type) { default: [[fallthrough]]; case pdtra::cable_type::vga: set_mode(vga); set_framebuffer_resolution(640, 480); aica_sound.common.VREG(vreg::output_mode::vga); + return {640, 480}; break; case pdtra::cable_type::rgb: set_mode(ntsc_ni); set_framebuffer_resolution(320, 240); aica_sound.common.VREG(vreg::output_mode::rgb); + return {320, 240}; break; case pdtra::cable_type::cvbs_yc: set_mode(ntsc_ni); set_framebuffer_resolution(320, 240); aica_sound.common.VREG(vreg::output_mode::cvbs_yc); + return {320, 240}; break; } } diff --git a/holly/video_output.hpp b/holly/video_output.hpp index cc34016..f8f8c21 100644 --- a/holly/video_output.hpp +++ b/holly/video_output.hpp @@ -24,10 +24,15 @@ extern const struct mode ntsc_i; extern const struct mode pal_ni; extern const struct mode pal_i; +struct framebuffer_resolution { + uint32_t width; + uint32_t height; +}; + void set_framebuffer_resolution(const uint32_t x_size, const uint32_t y_size); void set_mode(const struct mode& mode); uint32_t get_cable_type(); -void set_mode_automatic(); +framebuffer_resolution set_mode_by_cable_type(uint32_t cable_type); void set_mode_vga(); void reset_sdram(); diff --git a/regs/gen/sh7091.py b/regs/gen/sh7091.py index ec64379..b93e545 100644 --- a/regs/gen/sh7091.py +++ b/regs/gen/sh7091.py @@ -126,6 +126,8 @@ def blocks(rows): yield 'extern struct sh7091_reg sh7091 __asm("sh7091");' def headers(): + yield "#pragma once" + yield "" yield "#include " yield "#include " yield "" diff --git a/sh7091/serial.cpp b/sh7091/serial.cpp index b2d8032..ca8361e 100644 --- a/sh7091/serial.cpp +++ b/sh7091/serial.cpp @@ -1,9 +1,11 @@ #include +#include #include "sh7091.hpp" #include "sh7091_bits.hpp" #include "string.hpp" +#include "serial.hpp" namespace serial { @@ -64,30 +66,23 @@ void hexlify(const uint8_t n) character(num_buf[1]); } -template -void integer(const T n, const char end) +template +void integer(const T n, const char end, const uint32_t length) { - constexpr uint32_t length = (sizeof (T)) * 2; - char num_buf[length + 1]; - string::hex(num_buf, length, n); - num_buf[length] = 0; - string("0x"); - string(num_buf); + uint8_t num_buf[length]; + conv_type::template render(num_buf, length, n); + if constexpr (std::is_same::value) + string("0x"); + string(num_buf, length); character(end); } -template -void integer(const T n) -{ - return integer(n, '\n'); -} +template void integer(uint32_t param, char end, uint32_t length); +template void integer(uint16_t param, char end, uint32_t length); +template void integer(uint8_t param, char end, uint32_t length); -template void integer(uint32_t param); -template void integer(uint16_t param); -template void integer(uint8_t param); - -template void integer(uint32_t param, char end); -template void integer(uint16_t param, char end); -template void integer(uint8_t param, char end); +template void integer(uint32_t param, char end, uint32_t length); +template void integer(uint16_t param, char end, uint32_t length); +template void integer(uint8_t param, char end, uint32_t length); } diff --git a/sh7091/serial.hpp b/sh7091/serial.hpp index 9450830..070621c 100644 --- a/sh7091/serial.hpp +++ b/sh7091/serial.hpp @@ -1,3 +1,5 @@ +#include "string.hpp" + namespace serial { void init(uint8_t bit_rate); @@ -10,10 +12,23 @@ void string(const uint8_t * s, uint32_t len); void hexlify(const uint8_t n); -template -void integer(const T n, const char end); +using hex = string::hex_type; +using dec = string::dec_type; -template -void integer(const T n); +template +void integer(const T n, const char end, const uint32_t length); + +template +inline void integer(const T n, const char end) +{ + constexpr uint32_t length = (sizeof (T)) * 2; + return integer(n, end, length); +} + +template +inline void integer(const T n) +{ + return integer(n, '\n'); +} } diff --git a/sh7091/sh7091.hpp b/sh7091/sh7091.hpp index 4807594..1e640e2 100644 --- a/sh7091/sh7091.hpp +++ b/sh7091/sh7091.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include diff --git a/string.hpp b/string.hpp index 8365d74..f0ab6d8 100644 --- a/string.hpp +++ b/string.hpp @@ -3,6 +3,7 @@ #include namespace string { + template inline void hex(T * c, uint32_t len, uint32_t n) { @@ -18,4 +19,30 @@ namespace string { c[--len] = nib; } } + + template + inline void dec(T * c, uint32_t len, uint32_t n) + { + while (len > 0) { + const uint32_t digit = n % 10; + n = n / 10; + c[--len] = digit + 48; + } + } + + struct hex_type { + template + static void render(T * c, uint32_t len, uint32_t n) + { + hex(c, len, n); + } + }; + + struct dec_type { + template + static void render(T * c, uint32_t len, uint32_t n) + { + dec(c, len, n); + } + }; }