From 8ef2d20749974b8dd5e24379210a134847349863 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Wed, 3 Sep 2025 14:12:06 -0500 Subject: [PATCH] dreamcast2: add maple headers --- dreamcast2/maple/maple.hpp | 38 +++ dreamcast2/maple/maple_bits.hpp | 90 ++++++ dreamcast2/maple/maple_bus_bits.hpp | 79 ++++++ dreamcast2/maple/maple_bus_commands.hpp | 260 ++++++++++++++++++ dreamcast2/maple/maple_bus_ft0.hpp | 67 +++++ dreamcast2/maple/maple_bus_ft6.hpp | 82 ++++++ dreamcast2/maple/maple_bus_ft6_scan_code.hpp | 151 ++++++++++ dreamcast2/regs.mk | 20 ++ dreamcast2/regs/maple/bus_bits.ods | Bin 0 -> 15789 bytes dreamcast2/regs/maple/maple_bits.ods | Bin 0 -> 23918 bytes dreamcast2/regs/maple/maple_bus_commands.ods | Bin 0 -> 17310 bytes dreamcast2/regs/maple/maple_bus_ft0.ods | Bin 0 -> 12046 bytes dreamcast2/regs/maple/maple_bus_ft6.ods | Bin 0 -> 13914 bytes .../regs/maple/maple_bus_ft6_scan_code.ods | Bin 0 -> 18669 bytes dreamcast2/regs/render_maple_bus_commands.py | 184 +++++++++++++ dreamcast2/regs/render_maple_data_format.py | 163 +++++++++++ dreamcast2/regs/render_maple_scan_code.py | 65 +++++ 17 files changed, 1199 insertions(+) create mode 100644 dreamcast2/maple/maple.hpp create mode 100644 dreamcast2/maple/maple_bits.hpp create mode 100644 dreamcast2/maple/maple_bus_bits.hpp create mode 100644 dreamcast2/maple/maple_bus_commands.hpp create mode 100644 dreamcast2/maple/maple_bus_ft0.hpp create mode 100644 dreamcast2/maple/maple_bus_ft6.hpp create mode 100644 dreamcast2/maple/maple_bus_ft6_scan_code.hpp create mode 100644 dreamcast2/regs/maple/bus_bits.ods create mode 100644 dreamcast2/regs/maple/maple_bits.ods create mode 100644 dreamcast2/regs/maple/maple_bus_commands.ods create mode 100644 dreamcast2/regs/maple/maple_bus_ft0.ods create mode 100644 dreamcast2/regs/maple/maple_bus_ft6.ods create mode 100644 dreamcast2/regs/maple/maple_bus_ft6_scan_code.ods create mode 100644 dreamcast2/regs/render_maple_bus_commands.py create mode 100644 dreamcast2/regs/render_maple_data_format.py create mode 100644 dreamcast2/regs/render_maple_scan_code.py diff --git a/dreamcast2/maple/maple.hpp b/dreamcast2/maple/maple.hpp new file mode 100644 index 0000000..fe5291e --- /dev/null +++ b/dreamcast2/maple/maple.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include + +namespace maple { + + struct protocol_header { + uint8_t command_code; + uint8_t destination_ap; + uint8_t source_ap; + uint8_t data_size; + }; + + template + struct host_command { + uint32_t host_instruction; // interpreted by the Maple DMA controller + uint32_t receive_data_address; // interpreted by the Maple DMA controller + protocol_header header; + T data; + }; + + static_assert((sizeof (host_command)) == 12); + static_assert((sizeof (host_command[4])) == 48); + + constexpr inline uint32_t align(uint32_t mem) + { + return (mem + 31) & ~31; + } + + template + struct host_response { + protocol_header header; + T data; + uint8_t _pad[align((sizeof (protocol_header)) + (sizeof (T))) - ((sizeof (protocol_header)) + (sizeof (T)))]; + }; + + static_assert((sizeof (host_response)) == 32); +} diff --git a/dreamcast2/maple/maple_bits.hpp b/dreamcast2/maple/maple_bits.hpp new file mode 100644 index 0000000..115a7bd --- /dev/null +++ b/dreamcast2/maple/maple_bits.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include + +namespace maple { + namespace mdstar { + constexpr inline uint32_t table_address(uint32_t num) { return (num & 0xfffffe0) << 0; } + } + + namespace mdtsel { + namespace trigger_select { + constexpr uint32_t software_initiation = 0 << 0; + constexpr uint32_t v_blank_initiation = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace mden { + namespace dma_enable { + constexpr uint32_t abort = 0 << 0; + constexpr uint32_t enable = 1 << 0; + constexpr inline uint32_t status(uint32_t reg) { return (reg >> 0) & 0x1; } + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace mdst { + namespace start_status { + constexpr inline uint32_t status(uint32_t reg) { return (reg >> 0) & 0x1; } + constexpr uint32_t start = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace msys { + constexpr inline uint32_t time_out_counter(uint32_t num) { return (num & 0xffff) << 16; } + constexpr uint32_t single_hard_trigger = 1 << 12; + + namespace sending_rate { + constexpr uint32_t _2M = 0 << 8; + constexpr uint32_t _1M = 1 << 8; + + constexpr uint32_t bit_mask = 0x3 << 8; + } + + constexpr inline uint32_t delay_time(uint32_t num) { return (num & 0xf) << 0; } + } + + namespace mst { + constexpr inline uint32_t move_status(uint32_t reg) { return (reg >> 31) & 0x1; } + constexpr inline uint32_t internal_frame_monitor(uint32_t reg) { return (reg >> 24) & 0x7; } + constexpr inline uint32_t internal_state_monitor(uint32_t reg) { return (reg >> 16) & 0x3f; } + constexpr inline uint32_t line_monitor(uint32_t reg) { return (reg >> 0) & 0xff; } + } + + namespace mshtcl { + constexpr uint32_t hard_dma_clear = 1 << 0; + } + + namespace mdapro { + constexpr uint32_t security_code = 0x6155 << 16; + constexpr inline uint32_t top_address(uint32_t num) { return (num & 0x7f) << 8; } + constexpr inline uint32_t bottom_address(uint32_t num) { return (num & 0x7f) << 0; } + } + + namespace mmsel { + namespace msb_selection { + constexpr uint32_t bit7 = 0 << 0; + constexpr uint32_t bit31 = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + + namespace mtxdad { + constexpr inline uint32_t txd_address_counter(uint32_t reg) { return (reg >> 0) & 0x1fffffff; } + } + + namespace mrxdad { + constexpr inline uint32_t rxd_address_counter(uint32_t reg) { return (reg >> 0) & 0x1fffffff; } + } + + namespace mrxdbd { + constexpr inline uint32_t rxd_base_address(uint32_t reg) { return (reg >> 0) & 0x1fffffff; } + } + +} diff --git a/dreamcast2/maple/maple_bus_bits.hpp b/dreamcast2/maple/maple_bus_bits.hpp new file mode 100644 index 0000000..ae0b5a0 --- /dev/null +++ b/dreamcast2/maple/maple_bus_bits.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include + +namespace maple { + namespace host_instruction { + constexpr uint32_t end_flag = 1 << 31; + + namespace port_select { + constexpr uint32_t a = 0 << 16; + constexpr uint32_t b = 1 << 16; + constexpr uint32_t c = 2 << 16; + constexpr uint32_t d = 3 << 16; + + constexpr uint32_t bit_mask = 0x3 << 16; + } + + namespace pattern { + constexpr uint32_t normal = 0b000 << 8; + constexpr uint32_t light_gun_mode = 0b010 << 8; + constexpr uint32_t reset = 0b011 << 8; + constexpr uint32_t return_from_light_gun_mode = 0b100 << 8; + constexpr uint32_t nop = 0b111 << 8; + + constexpr uint32_t bit_mask = 0x7 << 8; + } + + constexpr inline uint32_t transfer_length(uint32_t num) { return (num & 0xff) << 0; } + } + + namespace receive_data_storage_address { + constexpr inline uint32_t address(uint32_t num) { return (num & 0x1fffffff) << 0; } + } + + namespace ap { + namespace port_select { + constexpr uint32_t a = 0b00 << 6; + constexpr uint32_t b = 0b01 << 6; + constexpr uint32_t c = 0b10 << 6; + constexpr uint32_t d = 0b11 << 6; + + constexpr uint32_t bit_mask = 0x3 << 6; + } + + namespace de { + constexpr uint32_t device = 1 << 5; + constexpr uint32_t expansion_device = 0 << 5; + constexpr uint32_t port = 0 << 5; + + constexpr uint32_t bit_mask = 0x1 << 5; + } + + namespace lm_bus { + constexpr uint32_t _4 = 0b10000 << 0; + constexpr uint32_t _3 = 0b01000 << 0; + constexpr uint32_t _2 = 0b00100 << 0; + constexpr uint32_t _1 = 0b00010 << 0; + constexpr uint32_t _0 = 0b00001 << 0; + + constexpr uint32_t bit_mask = 0x1f << 0; + } + } + + namespace function_type { + constexpr uint32_t camera = 1 << 11; + constexpr uint32_t exchange_media = 1 << 10; + constexpr uint32_t pointing = 1 << 9; + constexpr uint32_t vibration = 1 << 8; + constexpr uint32_t light_gun = 1 << 7; + constexpr uint32_t keyboard = 1 << 6; + constexpr uint32_t ar_gun = 1 << 5; + constexpr uint32_t audio_input = 1 << 4; + constexpr uint32_t timer = 1 << 3; + constexpr uint32_t bw_lcd = 1 << 2; + constexpr uint32_t storage = 1 << 1; + constexpr uint32_t controller = 1 << 0; + } + +} diff --git a/dreamcast2/maple/maple_bus_commands.hpp b/dreamcast2/maple/maple_bus_commands.hpp new file mode 100644 index 0000000..408ea02 --- /dev/null +++ b/dreamcast2/maple/maple_bus_commands.hpp @@ -0,0 +1,260 @@ +#pragma once + +#include + +namespace maple { + + struct device_id { + uint32_t ft; + uint32_t fd[3]; + }; + static_assert((sizeof (struct device_id)) == 16); + + struct device_request { + static constexpr uint32_t command_code = 0x1; + + struct data_fields { + uint8_t _empty[0]; + }; + }; + static_assert((sizeof (struct device_request::data_fields)) == 0); + + struct all_status_request { + static constexpr uint32_t command_code = 0x2; + + struct data_fields { + uint8_t _empty[0]; + }; + }; + static_assert((sizeof (struct all_status_request::data_fields)) == 0); + + struct device_reset { + static constexpr uint32_t command_code = 0x3; + + struct data_fields { + uint8_t _empty[0]; + }; + }; + static_assert((sizeof (struct device_reset::data_fields)) == 0); + + struct device_kill { + static constexpr uint32_t command_code = 0x4; + + struct data_fields { + uint8_t _empty[0]; + }; + }; + static_assert((sizeof (struct device_kill::data_fields)) == 0); + + struct device_status { + static constexpr uint32_t command_code = 0x5; + + struct data_fields { + struct device_id device_id; + uint8_t destination_code; + uint8_t connection_direction; + uint8_t product_name[30]; + uint8_t license[60]; + uint16_t low_consumption_standby_current; + uint16_t maximum_current_consumption; + }; + + }; + static_assert((sizeof (struct device_status::data_fields)) == 112); + + template + struct device_all_status { + static constexpr uint32_t command_code = 0x6; + + struct data_fields { + struct device_id device_id; + uint8_t destination_code; + uint8_t connection_direction; + uint8_t product_name[30]; + uint8_t license[60]; + uint16_t low_consumption_standby_current; + uint16_t maximum_current_consumption; + T free_device_status; + }; + + }; + static_assert((sizeof (struct device_all_status::data_fields)) == 112); + + struct device_reply { + static constexpr uint32_t command_code = 0x7; + + struct data_fields { + uint8_t _empty[0]; + }; + }; + static_assert((sizeof (struct device_reply::data_fields)) == 0); + + template + struct data_transfer { + static constexpr uint32_t command_code = 0x8; + + struct data_fields { + uint32_t function_type; + T data; + }; + + }; + static_assert((sizeof (struct data_transfer::data_fields)) == 4); + + struct get_condition { + static constexpr uint32_t command_code = 0x9; + + struct data_fields { + uint32_t function_type; + }; + + }; + static_assert((sizeof (struct get_condition::data_fields)) == 4); + + struct get_media_info { + static constexpr uint32_t command_code = 0xa; + + struct data_fields { + uint32_t function_type; + uint32_t pt; + }; + + }; + static_assert((sizeof (struct get_media_info::data_fields)) == 8); + + struct block_read { + static constexpr uint32_t command_code = 0xb; + + struct data_fields { + uint32_t function_type; + uint8_t pt; + uint8_t phase; + uint16_t block_number; + }; + + }; + static_assert((sizeof (struct block_read::data_fields)) == 8); + + template + struct block_write { + static constexpr uint32_t command_code = 0xc; + + struct data_fields { + uint32_t function_type; + uint8_t pt; + uint8_t phase; + uint16_t block_number; + T written_data; + }; + + }; + static_assert((sizeof (struct block_write::data_fields)) == 8); + + struct get_last_error { + static constexpr uint32_t command_code = 0xd; + + struct data_fields { + uint32_t function_type; + uint8_t pt; + uint8_t phase; + uint16_t block_number; + }; + + }; + static_assert((sizeof (struct get_last_error::data_fields)) == 8); + + template + struct set_condition { + static constexpr uint32_t command_code = 0xe; + + struct data_fields { + uint32_t function_type; + T write_in_data; + }; + + }; + static_assert((sizeof (struct set_condition::data_fields)) == 4); + + template + struct ft4_control { + static constexpr uint32_t command_code = 0xf; + + struct data_fields { + uint32_t function_type; + T ft4_data; + }; + + }; + static_assert((sizeof (struct ft4_control::data_fields)) == 4); + + template + struct ar_control { + static constexpr uint32_t command_code = 0x10; + + struct data_fields { + uint32_t function_type; + T data; + }; + + }; + static_assert((sizeof (struct ar_control::data_fields)) == 4); + + struct function_type_unknown { + static constexpr uint32_t command_code = 0xfe; + + struct data_fields { + uint8_t _empty[0]; + }; + }; + static_assert((sizeof (struct function_type_unknown::data_fields)) == 0); + + struct command_unknown { + static constexpr uint32_t command_code = 0xfd; + + struct data_fields { + uint8_t _empty[0]; + }; + }; + static_assert((sizeof (struct command_unknown::data_fields)) == 0); + + struct transmit_again { + static constexpr uint32_t command_code = 0xfc; + + struct data_fields { + uint8_t _empty[0]; + }; + }; + static_assert((sizeof (struct transmit_again::data_fields)) == 0); + + struct file_error { + static constexpr uint32_t command_code = 0xfb; + + struct data_fields { + uint32_t function_error_code; + }; + + }; + static_assert((sizeof (struct file_error::data_fields)) == 4); + + struct lcd_error { + static constexpr uint32_t command_code = 0xfa; + + struct data_fields { + uint32_t function_error_code; + }; + + }; + static_assert((sizeof (struct lcd_error::data_fields)) == 4); + + struct ar_error { + static constexpr uint32_t command_code = 0xf9; + + struct data_fields { + uint32_t function_error_code; + }; + + }; + static_assert((sizeof (struct ar_error::data_fields)) == 4); + + +} diff --git a/dreamcast2/maple/maple_bus_ft0.hpp b/dreamcast2/maple/maple_bus_ft0.hpp new file mode 100644 index 0000000..2be5ffe --- /dev/null +++ b/dreamcast2/maple/maple_bus_ft0.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include + +namespace maple::ft0 { + namespace data_transfer { + namespace digital_button { + constexpr uint32_t ra() { return 0b1 << 7; } + constexpr uint32_t ra(uint32_t reg) { return (reg >> 7) & 0b1; } + + constexpr uint32_t la() { return 0b1 << 6; } + constexpr uint32_t la(uint32_t reg) { return (reg >> 6) & 0b1; } + + constexpr uint32_t da() { return 0b1 << 5; } + constexpr uint32_t da(uint32_t reg) { return (reg >> 5) & 0b1; } + + constexpr uint32_t ua() { return 0b1 << 4; } + constexpr uint32_t ua(uint32_t reg) { return (reg >> 4) & 0b1; } + + constexpr uint32_t start() { return 0b1 << 3; } + constexpr uint32_t start(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; } + + constexpr uint32_t rb() { return 0b1 << 15; } + constexpr uint32_t rb(uint32_t reg) { return (reg >> 15) & 0b1; } + + constexpr uint32_t lb() { return 0b1 << 14; } + constexpr uint32_t lb(uint32_t reg) { return (reg >> 14) & 0b1; } + + constexpr uint32_t db() { return 0b1 << 13; } + constexpr uint32_t db(uint32_t reg) { return (reg >> 13) & 0b1; } + + constexpr uint32_t ub() { return 0b1 << 12; } + constexpr uint32_t ub(uint32_t reg) { return (reg >> 12) & 0b1; } + + constexpr uint32_t d() { return 0b1 << 11; } + constexpr uint32_t d(uint32_t reg) { return (reg >> 11) & 0b1; } + + constexpr uint32_t x() { return 0b1 << 10; } + constexpr uint32_t x(uint32_t reg) { return (reg >> 10) & 0b1; } + + constexpr uint32_t y() { return 0b1 << 9; } + constexpr uint32_t y(uint32_t reg) { return (reg >> 9) & 0b1; } + + constexpr uint32_t z() { return 0b1 << 8; } + constexpr uint32_t z(uint32_t reg) { return (reg >> 8) & 0b1; } + + } + + struct data_format { + uint16_t digital_button; + uint8_t analog_coordinate_axis[6]; + }; + static_assert((sizeof (struct data_format)) % 4 == 0); + static_assert((sizeof (struct data_format)) == 8); + } + +} + diff --git a/dreamcast2/maple/maple_bus_ft6.hpp b/dreamcast2/maple/maple_bus_ft6.hpp new file mode 100644 index 0000000..4f27a03 --- /dev/null +++ b/dreamcast2/maple/maple_bus_ft6.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include + +namespace maple::ft6 { + namespace data_transfer { + namespace modifier_key { + constexpr uint32_t s2() { return 0b1 << 7; } + constexpr uint32_t s2(uint32_t reg) { return (reg >> 7) & 0b1; } + + constexpr uint32_t right_alt() { return 0b1 << 6; } + constexpr uint32_t right_alt(uint32_t reg) { return (reg >> 6) & 0b1; } + + constexpr uint32_t right_shift() { return 0b1 << 5; } + constexpr uint32_t right_shift(uint32_t reg) { return (reg >> 5) & 0b1; } + + constexpr uint32_t right_control() { return 0b1 << 4; } + constexpr uint32_t right_control(uint32_t reg) { return (reg >> 4) & 0b1; } + + constexpr uint32_t left_gui() { return 0b1 << 3; } + constexpr uint32_t left_gui(uint32_t reg) { return (reg >> 3) & 0b1; } + + constexpr uint32_t left_alt() { return 0b1 << 2; } + constexpr uint32_t left_alt(uint32_t reg) { return (reg >> 2) & 0b1; } + + constexpr uint32_t left_shift() { return 0b1 << 1; } + constexpr uint32_t left_shift(uint32_t reg) { return (reg >> 1) & 0b1; } + + constexpr uint32_t left_control() { return 0b1 << 0; } + constexpr uint32_t left_control(uint32_t reg) { return (reg >> 0) & 0b1; } + + } + + namespace led_state { + constexpr uint32_t shift() { return 0b1 << 7; } + constexpr uint32_t shift(uint32_t reg) { return (reg >> 7) & 0b1; } + + constexpr uint32_t power() { return 0b1 << 6; } + constexpr uint32_t power(uint32_t reg) { return (reg >> 6) & 0b1; } + + constexpr uint32_t kana() { return 0b1 << 5; } + constexpr uint32_t kana(uint32_t reg) { return (reg >> 5) & 0b1; } + + constexpr uint32_t reserved0() { return 0b1 << 4; } + constexpr uint32_t reserved0(uint32_t reg) { return (reg >> 4) & 0b1; } + + constexpr uint32_t reserved1() { return 0b1 << 3; } + constexpr uint32_t reserved1(uint32_t reg) { return (reg >> 3) & 0b1; } + + constexpr uint32_t scroll_lock() { return 0b1 << 2; } + constexpr uint32_t scroll_lock(uint32_t reg) { return (reg >> 2) & 0b1; } + + constexpr uint32_t caps_lock() { return 0b1 << 1; } + constexpr uint32_t caps_lock(uint32_t reg) { return (reg >> 1) & 0b1; } + + constexpr uint32_t num_lock() { return 0b1 << 0; } + constexpr uint32_t num_lock(uint32_t reg) { return (reg >> 0) & 0b1; } + + } + + struct data_format { + uint8_t modifier_key; + 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); + } + + namespace set_condition { + struct data_format { + uint8_t led_setting; + uint8_t w1_reserved; + 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/dreamcast2/maple/maple_bus_ft6_scan_code.hpp b/dreamcast2/maple/maple_bus_ft6_scan_code.hpp new file mode 100644 index 0000000..2105976 --- /dev/null +++ b/dreamcast2/maple/maple_bus_ft6_scan_code.hpp @@ -0,0 +1,151 @@ +#pragma once + +#include + +namespace maple::ft6::scan_code { + constexpr uint32_t no_operation = 0x0; + constexpr uint32_t rollover_error = 0x1; + constexpr uint32_t post_fail = 0x2; + constexpr uint32_t undefined_error = 0x3; + constexpr uint32_t a_A = 0x4; + constexpr uint32_t b_B = 0x5; + constexpr uint32_t c_C = 0x6; + constexpr uint32_t d_D = 0x7; + constexpr uint32_t e_E = 0x8; + constexpr uint32_t f_F = 0x9; + constexpr uint32_t g_G = 0xa; + constexpr uint32_t h_H = 0xb; + constexpr uint32_t i_I = 0xc; + constexpr uint32_t j_J = 0xd; + constexpr uint32_t k_K = 0xe; + constexpr uint32_t l_L = 0xf; + constexpr uint32_t m_M = 0x10; + constexpr uint32_t n_N = 0x11; + constexpr uint32_t o_O = 0x12; + constexpr uint32_t p_P = 0x13; + constexpr uint32_t q_Q = 0x14; + constexpr uint32_t r_R = 0x15; + constexpr uint32_t s_S = 0x16; + constexpr uint32_t t_T = 0x17; + constexpr uint32_t u_U = 0x18; + constexpr uint32_t v_V = 0x19; + constexpr uint32_t w_W = 0x1a; + constexpr uint32_t x_X = 0x1b; + constexpr uint32_t y_Y = 0x1c; + constexpr uint32_t z_Z = 0x1d; + constexpr uint32_t _1_exclam = 0x1e; + constexpr uint32_t _2_at = 0x1f; + constexpr uint32_t _3_numbersign = 0x20; + constexpr uint32_t _4_dollar = 0x21; + constexpr uint32_t _5_percent = 0x22; + constexpr uint32_t _6_asciicircum = 0x23; + constexpr uint32_t _7_ampersand = 0x24; + constexpr uint32_t _8_asterisk = 0x25; + constexpr uint32_t _9_parenleft = 0x26; + constexpr uint32_t _0_parenright = 0x27; + constexpr uint32_t _return = 0x28; + constexpr uint32_t esc = 0x29; + constexpr uint32_t backspace = 0x2a; + constexpr uint32_t tab = 0x2b; + constexpr uint32_t spacebar = 0x2c; + constexpr uint32_t minus_underscore = 0x2d; + constexpr uint32_t equal_plus = 0x2e; + constexpr uint32_t bracketleft_braceleft = 0x2f; + constexpr uint32_t bracketright_braceright = 0x30; + constexpr uint32_t backslash_bar = 0x31; + constexpr uint32_t iso_numbersign_tilde = 0x32; + constexpr uint32_t semicolon_colon = 0x33; + constexpr uint32_t apostrophe_quotedbl = 0x34; + constexpr uint32_t grave_asciitilde = 0x35; + constexpr uint32_t comma_less = 0x36; + constexpr uint32_t period_greater = 0x37; + constexpr uint32_t slash_question = 0x38; + constexpr uint32_t caps_lock = 0x39; + constexpr uint32_t F1 = 0x3a; + constexpr uint32_t F2 = 0x3b; + constexpr uint32_t F3 = 0x3c; + constexpr uint32_t F4 = 0x3d; + constexpr uint32_t F5 = 0x3e; + constexpr uint32_t F6 = 0x3f; + constexpr uint32_t F7 = 0x40; + constexpr uint32_t F8 = 0x41; + constexpr uint32_t F9 = 0x42; + constexpr uint32_t F10 = 0x43; + constexpr uint32_t F11 = 0x44; + constexpr uint32_t F12 = 0x45; + constexpr uint32_t print_screen = 0x46; + constexpr uint32_t scroll_lock = 0x47; + constexpr uint32_t pause = 0x48; + constexpr uint32_t insert = 0x49; + constexpr uint32_t home = 0x4a; + constexpr uint32_t page_up = 0x4b; + constexpr uint32_t _delete = 0x4c; + constexpr uint32_t end = 0x4d; + constexpr uint32_t page_down = 0x4e; + constexpr uint32_t right_arrow = 0x4f; + constexpr uint32_t left_arrow = 0x50; + constexpr uint32_t down_arrow = 0x51; + constexpr uint32_t up_arrow = 0x52; + constexpr uint32_t last_printable = 0x38; + + static const uint8_t code_point[last_printable + 1][2] = { + [scan_code::no_operation] = { 0, 0 }, + [scan_code::rollover_error] = { 0, 0 }, + [scan_code::post_fail] = { 0, 0 }, + [scan_code::undefined_error] = { 0, 0 }, + [scan_code::a_A] = { 'a', 'A' }, + [scan_code::b_B] = { 'b', 'B' }, + [scan_code::c_C] = { 'c', 'C' }, + [scan_code::d_D] = { 'd', 'D' }, + [scan_code::e_E] = { 'e', 'E' }, + [scan_code::f_F] = { 'f', 'F' }, + [scan_code::g_G] = { 'g', 'G' }, + [scan_code::h_H] = { 'h', 'H' }, + [scan_code::i_I] = { 'i', 'I' }, + [scan_code::j_J] = { 'j', 'J' }, + [scan_code::k_K] = { 'k', 'K' }, + [scan_code::l_L] = { 'l', 'L' }, + [scan_code::m_M] = { 'm', 'M' }, + [scan_code::n_N] = { 'n', 'N' }, + [scan_code::o_O] = { 'o', 'O' }, + [scan_code::p_P] = { 'p', 'P' }, + [scan_code::q_Q] = { 'q', 'Q' }, + [scan_code::r_R] = { 'r', 'R' }, + [scan_code::s_S] = { 's', 'S' }, + [scan_code::t_T] = { 't', 'T' }, + [scan_code::u_U] = { 'u', 'U' }, + [scan_code::v_V] = { 'v', 'V' }, + [scan_code::w_W] = { 'w', 'W' }, + [scan_code::x_X] = { 'x', 'X' }, + [scan_code::y_Y] = { 'y', 'Y' }, + [scan_code::z_Z] = { 'z', 'Z' }, + [scan_code::_1_exclam] = { '1', '!' }, + [scan_code::_2_at] = { '2', '@' }, + [scan_code::_3_numbersign] = { '3', '#' }, + [scan_code::_4_dollar] = { '4', '$' }, + [scan_code::_5_percent] = { '5', '%' }, + [scan_code::_6_asciicircum] = { '6', '^' }, + [scan_code::_7_ampersand] = { '7', '&' }, + [scan_code::_8_asterisk] = { '8', '*' }, + [scan_code::_9_parenleft] = { '9', '(' }, + [scan_code::_0_parenright] = { '0', ')' }, + [scan_code::_return] = { 0, 0 }, + [scan_code::esc] = { 0, 0 }, + [scan_code::backspace] = { 0, 0 }, + [scan_code::tab] = { 0, 0 }, + [scan_code::spacebar] = { 0, 0 }, + [scan_code::minus_underscore] = { '-', '_' }, + [scan_code::equal_plus] = { '=', '+' }, + [scan_code::bracketleft_braceleft] = { '[', '{' }, + [scan_code::bracketright_braceright] = { ']', '}' }, + [scan_code::backslash_bar] = { '\\', '|' }, + [scan_code::iso_numbersign_tilde] = { '#', '~' }, + [scan_code::semicolon_colon] = { ';', ':' }, + [scan_code::apostrophe_quotedbl] = { '\'', '"' }, + [scan_code::grave_asciitilde] = { '\'', '~' }, + [scan_code::comma_less] = { ',', '<' }, + [scan_code::period_greater] = { '.', '>' }, + [scan_code::slash_question] = { '/', '?' }, + }; +} + diff --git a/dreamcast2/regs.mk b/dreamcast2/regs.mk index ac70528..f9163db 100644 --- a/dreamcast2/regs.mk +++ b/dreamcast2/regs.mk @@ -43,3 +43,23 @@ systembus/systembus.hpp: regs/systembus/systembus.csv regs/render_block_regs.py systembus/systembus_bits.hpp: regs/systembus/systembus_bits.csv regs/render_bits.py python regs/render_bits.py $< systembus > $@ + +# MAPLE + +maple/maple_bits.hpp: regs/maple/maple_bits.csv regs/render_bits.py + python regs/render_bits.py $< maple > $@ + +maple/maple_bus_bits.hpp: regs/maple/maple_bus_bits.csv regs/render_bits.py + python regs/render_bits.py $< maple > $@ + +maple/maple_bus_commands.hpp: regs/maple/maple_bus_commands.csv regs/render_maple_bus_commands.py + python regs/render_maple_bus_commands.py $< > $@ + +maple/maple_bus_ft0.hpp: regs/maple/maple_bus_ft0.csv regs/render_maple_data_format.py + python regs/render_maple_data_format.py $< > $@ + +maple/maple_bus_ft6.hpp: regs/maple/maple_bus_ft6.csv regs/render_maple_data_format.py + python regs/render_maple_data_format.py $< > $@ + +maple/maple_bus_ft6_scan_code.hpp: regs/maple/maple_bus_ft6_scan_code.csv regs/render_maple_scan_code.py + python regs/render_maple_scan_code.py $< > $@ diff --git a/dreamcast2/regs/maple/bus_bits.ods b/dreamcast2/regs/maple/bus_bits.ods new file mode 100644 index 0000000000000000000000000000000000000000..c856a5e9d2be95b3312f4ce9fcd396051120c9db GIT binary patch literal 15789 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 R!`)cPKO}k5S+h9&_dnvk-=Y8j literal 0 HcmV?d00001 diff --git a/dreamcast2/regs/maple/maple_bus_commands.ods b/dreamcast2/regs/maple/maple_bus_commands.ods new file mode 100644 index 0000000000000000000000000000000000000000..ed58d40f7fa0577ebc720a474594dfb99f6ee134 GIT binary patch literal 17310 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 A-2eap literal 0 HcmV?d00001 diff --git a/dreamcast2/regs/maple/maple_bus_ft0.ods b/dreamcast2/regs/maple/maple_bus_ft0.ods new file mode 100644 index 0000000000000000000000000000000000000000..36a8ebf67964c3e60cd00cf1c0b0ebc845fb6d9b GIT binary patch literal 12046 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 C2_f$Q literal 0 HcmV?d00001 diff --git a/dreamcast2/regs/maple/maple_bus_ft6.ods b/dreamcast2/regs/maple/maple_bus_ft6.ods new file mode 100644 index 0000000000000000000000000000000000000000..a84742363fff53cdef36829cd49c9b53b629b4eb GIT binary patch literal 13914 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 literal 0 HcmV?d00001 diff --git a/dreamcast2/regs/maple/maple_bus_ft6_scan_code.ods b/dreamcast2/regs/maple/maple_bus_ft6_scan_code.ods new file mode 100644 index 0000000000000000000000000000000000000000..f5f6d3e25472c2cbf0175812daece1684e7be419 GIT binary patch literal 18669 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 literal 0 HcmV?d00001 diff --git a/dreamcast2/regs/render_maple_bus_commands.py b/dreamcast2/regs/render_maple_bus_commands.py new file mode 100644 index 0000000..f88b909 --- /dev/null +++ b/dreamcast2/regs/render_maple_bus_commands.py @@ -0,0 +1,184 @@ +from dataclasses import dataclass +from typing import Union +import sys + +from csv_input import read_input +from generate import renderer + +@dataclass +class CommandNamespace: + name: str + issuing_right: set[str] + command_code: int + data_size: int + +def command_namespace(namespace: CommandNamespace, + data_fields: list[tuple[str, tuple[int, str]]]): + length, variable = namespace.data_size + if variable is not None: + assert variable.lower() == "n" + yield "template " + + yield f"struct {namespace.name} {{" + yield f"static constexpr uint32_t command_code = {hex(namespace.command_code)};" + yield "" + + if namespace.data_size == (0, None): + assert data_fields == [] + yield "struct data_fields {" + yield "uint8_t _empty[0];" + yield "};" + else: + yield "struct data_fields {" + + for field_name, field_size in data_fields: + const, var = field_size + if var is None: + if const in {1, 2, 4}: + bits = const * 8 + yield f"uint{bits}_t {field_name};" + elif field_name == "device_id": + yield f"struct device_id {field_name};" + else: + yield f"uint8_t {field_name}[{const}];" + elif const == 0: + assert var == "n" + yield f"T {field_name};" + else: + yield f"uint8_t {field_name}[{const} + {var.upper()}];" + + yield "};" + + yield "" + + yield "};" + if variable is not None: + assert variable == "n" + yield f"static_assert((sizeof (struct {namespace.name}::data_fields)) == {length});" + else: + yield f"static_assert((sizeof (struct {namespace.name}::data_fields)) == {length});" + + yield "" + +def parse_data_size(data_size, base, multiple) -> tuple[int, str]: + def parse_term(s): + try: + return int(s, base) * multiple + except ValueError: + div = s.split("/") + if len(div) == 1: + # this must be a variable + assert multiple == 1, s + a, = div + return a + elif len(div) == 2: + # this must be a variable divided by a number + a, b = div + b = int(b, 10) + assert b == multiple + return a + else: + assert False, div + + _terms = data_size.split("+") + terms = tuple(parse_term(term) for term in _terms) + if len(terms) == 1: + term, = terms + if type(term) == str: + return (0, term) + elif type(term) == int: + return (term, None) + else: + assert False, (_terms, terms) + elif len(terms) == 2: + assert type(terms[0]) == int + assert type(terms[1]) == str + return terms + else: + assert False, (_terms, terms) + +def new_aggregator(): + last_name = None + namespace = None + data_fields = [] + all_names = set() + + def process_row(row): + nonlocal last_name + nonlocal namespace + nonlocal data_fields + + if row["name"] == "": + assert all(v == "" for v in row.values()), row + return + + if row["name"] != last_name: + if namespace is not None: + yield namespace, data_fields + else: + assert data_fields == [] + assert row["name"] != "" + last_name = row["name"] + issuing_right = set(row["issuing_right"].split(", ")) + assert all(s in {"host", "peripheral"} for s in issuing_right), row + assert issuing_right != set(), issuing_right + data_size = parse_data_size(row["data_size"], 16, 4) + + namespace = CommandNamespace( + name = row["name"], + issuing_right = issuing_right, + command_code = int(row["command_code"], 16), + data_size = data_size, + ) + data_fields = [] + # fall through + + assert last_name is None or row["name"] == last_name, (row["name"], last_name) + if row["data_field"] != "": + assert row["data_field_size"] != "" + data_fields.append(( + row["data_field"], + parse_data_size(row["data_field_size"], 10, 1) + )) + + def terminate(): + nonlocal namespace + nonlocal data_fields + if namespace is not None: + yield namespace, data_fields + + def process(rows): + for row in rows: + yield from process_row(row) + yield from terminate() + + return process + +def headers(): + yield "#pragma once" + yield "" + yield "#include " + yield "" + +def namespace(): + yield "namespace maple {" + yield "" + yield "struct device_id {" + yield "uint32_t ft;" + yield "uint32_t fd[3];" + yield "};" + yield "static_assert((sizeof (struct device_id)) == 16);" + yield "" + for namespace, data_fields in process(rows): + yield from command_namespace(namespace, data_fields) + yield "" + yield "}" + +input_file = sys.argv[1] +rows = read_input(input_file) +process = new_aggregator() + +render, out = renderer() +render(headers()) +render(namespace()) +sys.stdout.write(out.getvalue()) diff --git a/dreamcast2/regs/render_maple_data_format.py b/dreamcast2/regs/render_maple_data_format.py new file mode 100644 index 0000000..796c067 --- /dev/null +++ b/dreamcast2/regs/render_maple_data_format.py @@ -0,0 +1,163 @@ +import sys +import re +from dataclasses import dataclass +from collections import defaultdict + +from csv_input import read_input_headerless +from generate import renderer + +@dataclass +class Bit: + name: str + length: int + position: int + +@dataclass +class Field: + name: str + bits: list[str] + +@dataclass +class Format: + name: str + fields: list[Field] + field_order: list[str] + size: int + +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, + length=len(indicies), + position=min(indicies), + ) + +def parse_format_name(name): + if '<' in name: + head, middle, tail = re.split('[<>]', name) + assert tail == "", name + return head, middle + else: + return name, None + +def parse_data_format(ix, rows): + if ix >= len(rows): + return None + + while rows[ix][0] == "": + ix += 1 + if ix >= len(rows): + return None + + format_name, *header = rows[ix] + ix += 1 + assert format_name != "" + assert header == ["7", "6", "5", "4", "3", "2", "1", "0"] + + fields = defaultdict(list) + field_order = list() + size = 0 + while ix < len(rows) and rows[ix][0] != "": + field_name, *_bits = rows[ix] + ix += 1 + excess_bits = [b for b in _bits[8:] if b != ""] + assert excess_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) + if not variable: + size += 1 + if field_name not in field_order: + field_order.append(field_name) + + return ix, Format(format_name, dict(fields), field_order, size) + +def parse(rows): + ix = 0 + formats = [] + + while True: + ix_format = parse_data_format(ix, rows) + if ix_format is None: + break + ix, format = ix_format + formats.append(format) + + assert len(formats) > 0 + return formats + +def render_format(format): + yield f"namespace {format.name} {{" + for field_name in format.field_order: + subfields = format.fields[field_name] + if not any(field.bits != [] for field in subfields): + continue + + yield f"namespace {field_name} {{" + for ix, field in enumerate(subfields): + bit_offset = 8 * ix + for bit in field.bits: + name = bit.name.lower() + pos = bit_offset + bit.position + mask = bin(2 ** bit.length - 1) + yield f"constexpr uint32_t {name}() {{ return {mask} << {pos}; }}" + yield f"constexpr uint32_t {name}(uint32_t reg) {{ return (reg >> {pos}) & {mask}; }}" + yield "" + yield "}" + yield "" + + yield f"struct data_format {{" + + for _field_name in format.field_order: + field_name, variable = parse_format_name(_field_name) + subfields = format.fields[_field_name] + if variable is not None: + assert len(subfields) == 1 + yield f"uint8_t {field_name}[{variable}];" + elif len(subfields) == 1: + field, = subfields + yield f"uint8_t {field_name};" + elif len(subfields) == 2: + 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: + assert False, (len(subfields), field_name) + + yield "};" + yield f"static_assert((sizeof (struct data_format)) % 4 == 0);" + yield f"static_assert((sizeof (struct data_format)) == {format.size});" + yield "}" + +def render_formats(name, formats): + yield "#pragma once" + yield "" + yield "#include " + yield "" + yield f"namespace maple::{name} {{" + for format in formats: + yield from render_format(format) + yield "" + + yield "}" + +if __name__ == "__main__": + rows = read_input_headerless(sys.argv[1]) + name = sys.argv[1].split('.')[0].split('_')[-1] + assert len(name) == 3 or len(name) == 4 + formats = parse(rows) + render, out = renderer() + render(render_formats(name, formats)) + print(out.getvalue()) diff --git a/dreamcast2/regs/render_maple_scan_code.py b/dreamcast2/regs/render_maple_scan_code.py new file mode 100644 index 0000000..2e4cda9 --- /dev/null +++ b/dreamcast2/regs/render_maple_scan_code.py @@ -0,0 +1,65 @@ +import sys +import string + +from csv_input import read_input +from generate import renderer + +def render_row(row): + usage = row['usage'] + code = int(row['code'], 16) + yield f"constexpr uint32_t {usage} = {hex(code)};" + +def render_rows(rows): + for row in rows: + yield from render_row(row) + +def code_point(s): + if not s.strip(): + return '0' + elif len(s) == 1: + assert s in string.printable + if s == '\\': + return "'\\\\'" + elif s.strip() == "'": + return "'\\''" + else: + return f"'{s}'" + else: + assert False, s + +last_printable = 0x38 + +def render_normal_shift(row): + usage = row['usage'] + normal = code_point(row['normal']) + shift = code_point(row['shift']) + yield f"[scan_code::{usage}] = {{ {normal}, {shift} }}," + +def render_scancode_code_point(rows): + yield f"constexpr uint32_t last_printable = {hex(last_printable)};" + yield "" + yield f"static const uint8_t code_point[last_printable + 1][2] = {{" + for i, row in enumerate(rows): + yield from render_normal_shift(row) + if i == last_printable: + break + yield "};" + +def render_all(rows): + yield "namespace maple::ft6::scan_code {" + yield from render_rows(rows) + yield from render_scancode_code_point(rows) + yield "}" + +def header(): + yield "#pragma once" + yield "" + yield "#include " + yield "" + +if __name__ == "__main__": + rows = read_input(sys.argv[1]) + render, out = renderer() + render(header()) + render(render_all(rows)) + print(out.getvalue())