example: add video_output example

The intent of this example is to change video output modes in response
to swapping the cable type.
This commit is contained in:
Zack Buhman 2024-03-09 17:15:36 +08:00
parent 2a121625c8
commit f8dc9f1250
14 changed files with 432 additions and 41 deletions

View File

@ -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 \

View File

@ -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;

View File

@ -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>() = global_sprite(base_color);
parameter.append<vertex_sprite_type_0>() =
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>() = 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;

187
example/video_output.cpp Normal file
View File

@ -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<uint16_t, serial::dec>(framebuffer_resolution.width, ' ', 3);
serial::integer<uint16_t, serial::dec>(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>() =
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>() =
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>() = 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<volatile texture_memory_alloc *>(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;
}
}

View File

@ -1,3 +1,5 @@
#pragma once
#include <cstdint>
#include <cstddef>

View File

@ -25,6 +25,11 @@ namespace ta_global_parameter {
, _res5(0)
, _res6(0)
{ }
const uint8_t * _data()
{
return reinterpret_cast<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(this);
}
};
static_assert((sizeof (modifier_volume)) == 32);
static_assert((offsetof (struct modifier_volume, parameter_control_word)) == 0x00);

View File

@ -29,6 +29,11 @@ namespace ta_vertex_parameter {
, base_color(base_color)
, _res2(0)
{ }
const uint8_t * _data()
{
return reinterpret_cast<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(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<const uint8_t *>(this);
}
};
static_assert((sizeof (modifier_volume)) == 64);
static_assert((offsetof (struct modifier_volume, parameter_control_word)) == 0x00);

View File

@ -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;
}
}

View File

@ -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();

View File

@ -126,6 +126,8 @@ def blocks(rows):
yield 'extern struct sh7091_reg sh7091 __asm("sh7091");'
def headers():
yield "#pragma once"
yield ""
yield "#include <cstdint>"
yield "#include <cstddef>"
yield ""

View File

@ -1,9 +1,11 @@
#include <cstdint>
#include <type_traits>
#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 <typename T>
void integer(const T n, const char end)
template <typename T, typename conv_type>
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<char>(num_buf, length, n);
num_buf[length] = 0;
string("0x");
string(num_buf);
uint8_t num_buf[length];
conv_type::template render<uint8_t>(num_buf, length, n);
if constexpr (std::is_same<conv_type, string::hex_type>::value)
string("0x");
string(num_buf, length);
character(end);
}
template <typename T>
void integer(const T n)
{
return integer(n, '\n');
}
template void integer<uint32_t, hex>(uint32_t param, char end, uint32_t length);
template void integer<uint16_t, hex>(uint16_t param, char end, uint32_t length);
template void integer<uint8_t, hex>(uint8_t param, char end, uint32_t length);
template void integer<uint32_t>(uint32_t param);
template void integer<uint16_t>(uint16_t param);
template void integer<uint8_t>(uint8_t param);
template void integer<uint32_t>(uint32_t param, char end);
template void integer<uint16_t>(uint16_t param, char end);
template void integer<uint8_t>(uint8_t param, char end);
template void integer<uint32_t, dec>(uint32_t param, char end, uint32_t length);
template void integer<uint16_t, dec>(uint16_t param, char end, uint32_t length);
template void integer<uint8_t, dec>(uint8_t param, char end, uint32_t length);
}

View File

@ -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 <typename T>
void integer(const T n, const char end);
using hex = string::hex_type;
using dec = string::dec_type;
template <typename T>
void integer(const T n);
template <typename T, typename conv_type>
void integer(const T n, const char end, const uint32_t length);
template <typename T, typename conv_type = hex>
inline void integer(const T n, const char end)
{
constexpr uint32_t length = (sizeof (T)) * 2;
return integer<T, conv_type>(n, end, length);
}
template <typename T, typename conv_type = hex>
inline void integer(const T n)
{
return integer<T, conv_type>(n, '\n');
}
}

View File

@ -1,3 +1,5 @@
#pragma once
#include <cstdint>
#include <cstddef>

View File

@ -3,6 +3,7 @@
#include <cstdint>
namespace string {
template <typename T>
inline void hex(T * c, uint32_t len, uint32_t n)
{
@ -18,4 +19,30 @@ namespace string {
c[--len] = nib;
}
}
template <typename T>
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 <typename T>
static void render(T * c, uint32_t len, uint32_t n)
{
hex<T>(c, len, n);
}
};
struct dec_type {
template <typename T>
static void render(T * c, uint32_t len, uint32_t n)
{
dec<T>(c, len, n);
}
};
}