diff --git a/Makefile b/Makefile index 46e6b6d..108c2ed 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,7 @@ build-fonts: include example/example.mk include text_editor/text_editor.mk +include snake/snake.mk include pokemon/pokemon.mk .PHONY: phony diff --git a/example/example.mk b/example/example.mk index 19d5ecc..c19eabc 100644 --- a/example/example.mk +++ b/example/example.mk @@ -329,6 +329,19 @@ MAPLE_ANALOG_OBJ = \ example/maple_analog.elf: LDSCRIPT = $(LIB)/main.lds example/maple_analog.elf: $(START_OBJ) $(MAPLE_ANALOG_OBJ) +MAPLE_MOUSE_OBJ = \ + example/maple_mouse.o \ + holly/video_output.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + sh7091/serial.o \ + maple/maple.o + +example/maple_mouse.elf: LDSCRIPT = $(LIB)/main.lds +example/maple_mouse.elf: $(START_OBJ) $(MAPLE_MOUSE_OBJ) + SERIAL_TRANSFER_OBJ = \ example/serial_transfer.o \ sh7091/serial.o \ diff --git a/example/macaw.cpp b/example/macaw.cpp index 803ff9a..bf122e2 100644 --- a/example/macaw.cpp +++ b/example/macaw.cpp @@ -30,10 +30,10 @@ struct vertex { const struct vertex strip_vertices[4] = { // [ position ] [ uv coordinates ] [color ] - { -0.5f, 0.5f, 0.f, 0.f , 127.f/128.f, 0x00000000}, // the first two base colors in a - { -0.5f, -0.5f, 0.f, 0.f , 0.f , 0x00000000}, // non-Gouraud triangle strip are ignored - { 0.5f, 0.5f, 0.f, 127.f/128.f, 127.f/128.f, 0x00000000}, - { 0.5f, -0.5f, 0.f, 127.f/128.f, 0.f , 0x00000000}, + { -0.5f, 0.5f, 0.f, 0.f, 1.f, 0x00000000}, // the first two base colors in a + { -0.5f, -0.5f, 0.f, 0.f, 0.f, 0x00000000}, // non-Gouraud triangle strip are ignored + { 0.5f, 0.5f, 0.f, 1.f, 1.f, 0x00000000}, + { 0.5f, -0.5f, 0.f, 1.f, 0.f, 0x00000000}, }; constexpr uint32_t strip_length = (sizeof (strip_vertices)) / (sizeof (struct vertex)); diff --git a/example/maple_analog.cpp b/example/maple_analog.cpp index ac8d926..4257af4 100644 --- a/example/maple_analog.cpp +++ b/example/maple_analog.cpp @@ -17,40 +17,36 @@ #include "holly/background.hpp" #include "holly/texture_memory_alloc.hpp" #include "memorymap.hpp" -#include "sh7091/serial.hpp" #include "geometry/border.hpp" #include "geometry/circle.hpp" #include "math/vec4.hpp" #include "maple/maple.hpp" -#include "maple/maple_impl.hpp" +#include "maple/maple_host_command_writer.hpp" #include "maple/maple_bus_bits.hpp" #include "maple/maple_bus_commands.hpp" #include "maple/maple_bus_ft0.hpp" -uint32_t _command_buf[(1024 + 32) / 4]; -uint32_t _receive_buf[(1024 + 32) / 4]; - static ft0::data_transfer::data_format data[4]; -void do_get_condition(uint32_t * command_buf, - uint32_t * receive_buf) +void do_get_condition() { - using command_type = get_condition; - using response_type = data_transfer; + uint32_t send_buf[1024] __attribute__((aligned(32))); + uint32_t recv_buf[1024] __attribute__((aligned(32))); - get_condition::data_fields data_fields = { - .function_type = std::byteswap(function_type::controller) - }; + using command_type = maple::get_condition; + using response_type = maple::data_transfer; - const uint32_t command_size = maple::init_host_command_all_ports(command_buf, receive_buf, - data_fields); - using host_response_type = struct maple::host_response; - auto host_response = reinterpret_cast(receive_buf); + auto writer = maple::host_command_writer(send_buf, recv_buf); - maple::dma_start(command_buf, command_size, - receive_buf, maple::sizeof_command(host_response)); + auto [host_command, host_response] + = writer.append_command_all_ports(); + + host_command->bus_data.data_fields.function_type = std::byteswap(function_type::controller); + + maple::dma_start(send_buf, writer.send_offset, + recv_buf, writer.recv_offset); for (uint8_t port = 0; port < 4; port++) { auto& bus_data = host_response[port].bus_data; @@ -156,9 +152,6 @@ uint32_t _ta_parameter_buf[((32 * 8192) + 32) / 4]; void main() { - uint32_t * command_buf = align_32byte(_command_buf); - uint32_t * receive_buf = align_32byte(_receive_buf); - video_output::set_mode_vga(); // The address of `ta_parameter_buf` must be a multiple of 32 bytes. @@ -188,7 +181,7 @@ void main() uint32_t frame_ix = 0; while (1) { - do_get_condition(command_buf, receive_buf); + do_get_condition(); ta_polygon_converter_init(opb_size.total(), ta_alloc, diff --git a/example/maple_mouse.cpp b/example/maple_mouse.cpp new file mode 100644 index 0000000..900a34c --- /dev/null +++ b/example/maple_mouse.cpp @@ -0,0 +1,247 @@ +#include +#include + +#include "align.hpp" + +#include "holly/video_output.hpp" +#include "holly/holly.hpp" +#include "holly/core.hpp" +#include "holly/core_bits.hpp" +#include "holly/ta_fifo_polygon_converter.hpp" +#include "holly/ta_parameter.hpp" +#include "holly/ta_vertex_parameter.hpp" +#include "holly/ta_global_parameter.hpp" +#include "holly/ta_bits.hpp" +#include "holly/isp_tsp.hpp" +#include "holly/region_array.hpp" +#include "holly/background.hpp" +#include "holly/texture_memory_alloc.hpp" +#include "memorymap.hpp" +#include "sh7091/serial.hpp" + +#include "geometry/border.hpp" +#include "geometry/circle.hpp" +#include "math/vec4.hpp" + +#include "maple/maple.hpp" +#include "maple/maple_host_command_writer.hpp" +#include "maple/maple_bus_bits.hpp" +#include "maple/maple_bus_commands.hpp" +#include "maple/maple_bus_ft0.hpp" +#include "maple/maple_bus_ft9.hpp" + +static ft9::data_transfer::data_format data; + +void do_get_condition() +{ + uint32_t send_buf[1024] __attribute__((aligned(32))); + uint32_t recv_buf[1024] __attribute__((aligned(32))); + + using command_type = maple::get_condition; + using response_type = maple::data_transfer; + + auto writer = maple::host_command_writer(send_buf, recv_buf); + + auto [host_command, host_response] + = writer.append_command_all_ports(); + + host_command->bus_data.data_fields.function_type = std::byteswap(function_type::pointing); + + maple::dma_start(send_buf, writer.send_offset, + recv_buf, writer.recv_offset); + + for (uint8_t port = 0; port < 4; port++) { + auto& bus_data = host_response[port].bus_data; + if (bus_data.command_code != response_type::command_code) { + continue; + } + + auto& data_fields = bus_data.data_fields; + if ((std::byteswap(data_fields.function_type) & function_type::pointing) == 0) { + continue; + } + + for (uint32_t i = 0; i < 8; i++) { + data.analog_coordinate_axis[i] = data_fields.data.analog_coordinate_axis[i]; + } + + break; + } +} + +void transform(ta_parameter_writer& parameter, + const vec3 * vertices, + const face_vtn& face, + const vec4& color, + const vec3& position, + const float scale + ) +{ + const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume + | para_control::list_type::opaque + | obj_control::col_type::floating_color + | obj_control::gouraud; + + const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater + | isp_tsp_instruction_word::culling_mode::cull_if_positive; + + 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; + + parameter.append() = + ta_global_parameter::polygon_type_0(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + 0, // texture_control_word + 0, // data_size_for_sort_dma + 0 // next_address_for_sort_dma + ); + + constexpr uint32_t strip_length = 3; + for (uint32_t i = 0; i < strip_length; i++) { + + // world transform + uint32_t vertex_ix = face[i].vertex; + auto& vertex = vertices[vertex_ix]; + auto point = vertex; + + // rotate 90° around the X axis + float x = point.x; + float y = point.z; + float z = point.y; + + // world transform + x *= scale; // world space + y *= scale; // world space + z *= 10; + + // object transform + x += position.x; // object space + y += position.y; // object space + z += position.z; // object space + + // camera transform + z += 1; + //y -= 10; + + // screen space transform + x *= 240.f; + y *= 240.f; + x += 320.f; + y += 240.f; + z = 1 / z; + + bool end_of_strip = i == strip_length - 1; + + parameter.append() = + ta_vertex_parameter::polygon_type_1(polygon_vertex_parameter_control_word(end_of_strip), + x, y, z, + color.w, // alpha + color.x, // r + color.y, // g + color.z // b + ); + } +} + +void init_texture_memory(const struct opb_size& opb_size) +{ + region_array2(640 / 32, // width + 480 / 32, // height + opb_size + ); + background_parameter(0xff220000); +} + +uint32_t _ta_parameter_buf[((32 * 8192) + 32) / 4]; + +void main() +{ + video_output::set_mode_vga(); + + // 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 + }; + + 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; + float x_pos = 0.0f; + float y_pos = 0.0f; + float z_pos = 0.0f; + + while (1) { + do_get_condition(); + + ta_polygon_converter_init(opb_size.total(), + ta_alloc, + 640 / 32, + 480 / 32); + + x_pos += static_cast(data.analog_coordinate_axis[0] - 0x200) * 0.0015; + y_pos += static_cast(data.analog_coordinate_axis[1] - 0x200) * 0.0015; + z_pos += static_cast(data.analog_coordinate_axis[2] - 0x200) * 0.015; + + auto parameter = ta_parameter_writer(ta_parameter_buf); + for (uint32_t i = 0; i < border::num_faces; i++) { + transform(parameter, + border::vertices, + border::faces[i], + {1.0, 0.0, 0.0, 1.0}, // color + {0.0, 0.0, 0.0}, // position + 0.5f * (1.f / 0.95f) // scale + ); + } + + for (uint32_t i = 0; i < circle::num_faces; i++) { + transform(parameter, + circle::vertices, + circle::faces[i], + {0.0, 1.0, 1.0, 1.0}, // color + {x_pos, y_pos, 0.0}, // position + 0.05f // scale + ); + } + + for (uint32_t i = 0; i < circle::num_faces; i++) { + transform(parameter, + circle::vertices, + circle::faces[i], + {0.0, 1.0, 1.0, 0.0}, // color + {1.0, z_pos, 0.0}, // position + 0.05f // scale + ); + } + + parameter.append() = ta_global_parameter::end_of_list(para_control::para_type::end_of_list); + ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset); + ta_wait_opaque_list(); + core_start_render(frame_ix); + core_wait_end_of_render_video(); + + while (!spg_status::vsync(holly.SPG_STATUS)); + core_flip(frame_ix); + while (spg_status::vsync(holly.SPG_STATUS)); + + frame_ix = (frame_ix + 1) & 1; + } +} diff --git a/headers.mk b/headers.mk index 4217714..4a8f766 100644 --- a/headers.mk +++ b/headers.mk @@ -62,6 +62,9 @@ maple/maple_bus_ft6_key_scan_codes.hpp: regs/maple_bus_ft6_key_scan_codes.csv re maple/maple_bus_ft8.hpp: regs/maple_bus_ft8.csv regs/gen/maple_data_format.py python regs/gen/maple_data_format.py $< > $@ +maple/maple_bus_ft9.hpp: regs/maple_bus_ft9.csv regs/gen/maple_data_format.py + python regs/gen/maple_data_format.py $< > $@ + # AICA aica/aica_channel.hpp: regs/aica_channel_data.csv regs/gen/aica.py diff --git a/maple/maple_bus_ft0.hpp b/maple/maple_bus_ft0.hpp index 999ab82..753a748 100644 --- a/maple/maple_bus_ft0.hpp +++ b/maple/maple_bus_ft0.hpp @@ -62,6 +62,7 @@ namespace ft0 { uint8_t analog_axis_5; uint8_t analog_axis_6; }; + static_assert((sizeof (struct data_format)) % 4 == 0); static_assert((sizeof (struct data_format)) == 8); } diff --git a/maple/maple_bus_ft6.hpp b/maple/maple_bus_ft6.hpp index 4026ff1..06ddb8b 100644 --- a/maple/maple_bus_ft6.hpp +++ b/maple/maple_bus_ft6.hpp @@ -1,4 +1,5 @@ #pragma once + namespace ft6 { namespace data_transfer { namespace modifier_key { @@ -60,6 +61,7 @@ namespace ft6 { uint8_t led_state; uint8_t scan_code_array[6]; }; + static_assert((sizeof (struct data_format)) % 4 == 0); static_assert((sizeof (struct data_format)) == 8); } @@ -70,6 +72,7 @@ namespace ft6 { uint8_t w2_reserved; uint8_t w3_reserved; }; + static_assert((sizeof (struct data_format)) % 4 == 0); static_assert((sizeof (struct data_format)) == 4); } diff --git a/maple/maple_bus_ft8.hpp b/maple/maple_bus_ft8.hpp index 8f9c35f..8b34165 100644 --- a/maple/maple_bus_ft8.hpp +++ b/maple/maple_bus_ft8.hpp @@ -1,4 +1,5 @@ #pragma once + namespace ft8 { namespace data_transfer { namespace vset { @@ -33,6 +34,7 @@ namespace ft8 { uint8_t fm0; uint8_t fm1; }; + static_assert((sizeof (struct data_format)) % 4 == 0); static_assert((sizeof (struct data_format)) == 4); } @@ -43,6 +45,7 @@ namespace ft8 { uint8_t freq; uint8_t inc; }; + static_assert((sizeof (struct data_format)) % 4 == 0); static_assert((sizeof (struct data_format)) == 4); } diff --git a/maple/maple_bus_ft9.hpp b/maple/maple_bus_ft9.hpp new file mode 100644 index 0000000..d2abd1f --- /dev/null +++ b/maple/maple_bus_ft9.hpp @@ -0,0 +1,53 @@ +#pragma once + +namespace ft9 { + namespace data_transfer { + namespace button { + constexpr uint32_t r() { return 0b1 << 7; } + constexpr uint32_t r(uint32_t reg) { return (reg >> 7) & 0b1; } + + constexpr uint32_t l() { return 0b1 << 6; } + constexpr uint32_t l(uint32_t reg) { return (reg >> 6) & 0b1; } + + constexpr uint32_t d() { return 0b1 << 5; } + constexpr uint32_t d(uint32_t reg) { return (reg >> 5) & 0b1; } + + constexpr uint32_t u() { return 0b1 << 4; } + constexpr uint32_t u(uint32_t reg) { return (reg >> 4) & 0b1; } + + constexpr uint32_t s() { return 0b1 << 3; } + constexpr uint32_t s(uint32_t reg) { return (reg >> 3) & 0b1; } + + constexpr uint32_t a() { return 0b1 << 2; } + constexpr uint32_t a(uint32_t reg) { return (reg >> 2) & 0b1; } + + constexpr uint32_t b() { return 0b1 << 1; } + constexpr uint32_t b(uint32_t reg) { return (reg >> 1) & 0b1; } + + constexpr uint32_t c() { return 0b1 << 0; } + constexpr uint32_t c(uint32_t reg) { return (reg >> 0) & 0b1; } + + } + + namespace option { + constexpr uint32_t batt() { return 0b1 << 1; } + constexpr uint32_t batt(uint32_t reg) { return (reg >> 1) & 0b1; } + + constexpr uint32_t wire() { return 0b1 << 0; } + constexpr uint32_t wire(uint32_t reg) { return (reg >> 0) & 0b1; } + + } + + struct data_format { + uint8_t button; + uint8_t option; + uint8_t analog_coordinate_overflow; + uint8_t reserved; + uint16_t analog_coordinate_axis[8]; + }; + static_assert((sizeof (struct data_format)) % 4 == 0); + static_assert((sizeof (struct data_format)) == 20); + } + +} + diff --git a/regs/gen/maple_data_format.py b/regs/gen/maple_data_format.py index 2716745..b084dd1 100644 --- a/regs/gen/maple_data_format.py +++ b/regs/gen/maple_data_format.py @@ -28,6 +28,8 @@ def parse_bits(bits: list[str]): bit_order = [7, 6, 5, 4, 3, 2, 1, 0] by_name = defaultdict(list) for bit_ix, bit in zip(bit_order, bits): + if bit == '': + continue by_name[bit].append(bit_ix) for name, indicies in by_name.items(): yield Bit(name=name, @@ -65,8 +67,8 @@ def parse_data_format(ix, rows): ix += 1 excess_bits = [b for b in _bits[8:] if b != ""] assert excess_bits == [] - bits = [b for b in _bits[:8] if b != ""] - assert len(bits) in {0, 8}, bits + bits = [b for b in _bits[:8]] + assert len(bits) == 8, bits fields[field_name].append(Field(field_name, list(parse_bits(bits)))) _, variable = parse_format_name(field_name) @@ -126,6 +128,9 @@ def render_format(format): yield f"uint16_t {field_name};" elif len(subfields) in {3, 6}: yield f"uint8_t {field_name}[{len(subfields)}];" + elif len(subfields) == 16: + # bleh: hacky + yield f"uint16_t {field_name}[8];" elif len(subfields) == 4: yield f"uint32_t {field_name};" else: diff --git a/regs/maple_bus_ft9.csv b/regs/maple_bus_ft9.csv new file mode 100644 index 0000000..a24c916 --- /dev/null +++ b/regs/maple_bus_ft9.csv @@ -0,0 +1,21 @@ +"data_transfer",7,6,5,4,3,2,1,0 +"button","r","l","d","u","s","a","b","c" +"option",,,,,,,"batt","wire" +"analog_coordinate_overflow",,,,,,,, +"reserved",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, +"analog_coordinate_axis",,,,,,,, diff --git a/regs/maple_bus_ft9.ods b/regs/maple_bus_ft9.ods new file mode 100644 index 0000000..1184608 Binary files /dev/null and b/regs/maple_bus_ft9.ods differ