diff --git a/common.mk b/common.mk index 9bf6328..1380afc 100644 --- a/common.mk +++ b/common.mk @@ -2,7 +2,7 @@ MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(dir $(MAKEFILE_PATH)) LIB ?= . -OPT ?= -O0 +OPT ?= -Os DEBUG ?= -g -gdwarf-4 GENERATED ?= diff --git a/example/example.mk b/example/example.mk index d5eaa91..e7f774b 100644 --- a/example/example.mk +++ b/example/example.mk @@ -54,6 +54,15 @@ CUBE_OBJ = \ example/cube.elf: LDSCRIPT = $(LIB)/alt.lds example/cube.elf: $(START_OBJ) $(CUBE_OBJ) +MAPLE_CONTROLLER_OBJ = \ + example/maple_controller.o \ + vga.o \ + serial.o \ + maple/maple.o + +example/maple_controller.elf: LDSCRIPT = $(LIB)/alt.lds +example/maple_controller.elf: $(START_OBJ) $(MAPLE_CONTROLLER_OBJ) + MAPLE_WINK_OBJ = \ example/maple_wink.o \ vga.o \ diff --git a/example/maple_controller.cpp b/example/maple_controller.cpp new file mode 100644 index 0000000..356f2f6 --- /dev/null +++ b/example/maple_controller.cpp @@ -0,0 +1,37 @@ +#include "align.hpp" + +#include "maple/maple.hpp" +#include "maple/maple_bus_commands.hpp" +#include "serial.hpp" + +constexpr uint32_t command_data_size = (sizeof (device_request::data_fields)); +constexpr uint32_t response_data_size = (sizeof (device_status::data_fields)); + +constexpr uint32_t host_command_size = ((sizeof (struct maple::host_command))); +constexpr uint32_t command_response_size = ((sizeof (struct maple::command_response)) + 31) & ~31; + +uint32_t _command_buf[host_command_size * 4 + 32] = {0}; +uint32_t _receive_buf[command_response_size * 4 + 32] = {0}; + +void main() +{ + uint32_t * command_buf = align_32byte(_command_buf); + uint32_t * receive_buf = align_32byte(_receive_buf); + + maple::init_host_command_all_ports(command_buf, receive_buf, + device_request::command_code, command_data_size, response_data_size); + + maple::dma_start(command_buf); + + uint8_t * buf = reinterpret_cast(receive_buf); + for (uint8_t port = 0; port < 4; port++) { + serial::string("port "); + serial::integer(port); + for (uint32_t i = 0; i < command_response_size; i++) { + serial::integer(buf[port * command_response_size + i]); + } + serial::character('\n'); + } + + while (1); +} diff --git a/example/maple_wink.cpp b/example/maple_wink.cpp index 6e105e0..5d552d2 100644 --- a/example/maple_wink.cpp +++ b/example/maple_wink.cpp @@ -1,6 +1,7 @@ #include #include "maple/maple.hpp" +#include "maple/maple_bus_bits.hpp" #include "vga.hpp" #include "align.hpp" #include "serial.hpp" @@ -30,18 +31,25 @@ void main() constexpr int height = 32; constexpr int pixels_per_byte = 8; - uint32_t wink_buf[width * height / pixels_per_byte]; + uint32_t __attribute__((aligned(4))) wink_buf[(width * height / pixels_per_byte + 32) / 4]; make_wink(wink_buf); + if ((((uint32_t)wink_buf) & 3) != 0) serial::string("misaligned\n"); - uint32_t _command_buf[128 / 4]; - uint32_t _receive_buf[128 / 4]; + uint32_t _command_buf[(1024 + 32) / 4]; + uint32_t _receive_buf[(1024 + 32) / 4]; uint32_t * command_buf = align_32byte(_command_buf); uint32_t * receive_buf = align_32byte(_receive_buf); + if ((((uint32_t)command_buf) & 31) != 0) serial::string("misaligned\n"); + if ((((uint32_t)receive_buf) & 31) != 0) serial::string("misaligned\n"); - maple::init_block_write(command_buf, receive_buf, wink_buf); + maple::init_block_write(command_buf, receive_buf, + host_instruction::port_select::a, + ap::de::expansion_device | ap::port_select::a | ap::lm_bus::_0, + wink_buf, + 192); maple::dma_start(command_buf); - for (int i = 0; i < 32; i++) { + for (int i = 0; i < 1; i++) { serial::integer(receive_buf[i]); } diff --git a/maple/maple.cpp b/maple/maple.cpp index 9a7e5c3..e0aee50 100644 --- a/maple/maple.cpp +++ b/maple/maple.cpp @@ -13,32 +13,73 @@ namespace maple { -void init_host_command(uint32_t * buf, uint32_t * receive_buf, uint8_t command_code, uint8_t data_size) +void init_host_command(uint32_t * command_buf, uint32_t * receive_buf, + uint32_t destination_port, + uint8_t destination_ap, uint8_t command_code, uint8_t data_size, + bool end_flag) { // this function does not care about the template instantiation of // host_command--data_fields is not manipulated here. - auto host_command = reinterpret_cast *>(buf); + auto host_command = reinterpret_cast *>(command_buf); - host_command->host_instruction = host_instruction::end_flag - | host_instruction::port_select::a + host_command->host_instruction = (end_flag ? host_instruction::end_flag : 0) + | (destination_port & host_instruction::port_select::bit_mask) // host_instruction::port_select::a | host_instruction::transfer_length((data_size / 4)); - host_command->receive_data_storage_address = reinterpret_cast(receive_buf) & 0x1fff'ffff; + host_command->receive_data_storage_address = receive_data_storage_address::address(reinterpret_cast(receive_buf)); host_command->bus_data.command_code = command_code; - host_command->bus_data.destination_ap = ap::de::expansion_device | ap::port_select::a | ap::lm_bus::_0; - host_command->bus_data.source_ap = ap::port_select::a; + host_command->bus_data.destination_ap = destination_ap; //ap::de::expansion_device | ap::port_select::a | ap::lm_bus::_0 + + host_command->bus_data.source_ap = destination_ap & ap::port_select::bit_mask; host_command->bus_data.data_size = data_size / 4; } -void init_device_request(uint32_t * buf, uint32_t * receive_buf) +void init_host_command_all_ports(uint32_t * buf, uint32_t * receive_buf, + uint8_t command_code, uint32_t command_data_size, uint32_t response_data_size) { - init_host_command(buf, receive_buf, device_request::command_code, (sizeof (struct device_request::data_fields))); + const uint32_t command_size = (((sizeof (struct host_command)) + command_data_size)); + const uint32_t response_size = (((sizeof (struct command_response)) + response_data_size) + 31) & ~31; + + init_host_command(&buf[(command_size / 4) * 0], &receive_buf[(response_size / 4) * 0], + host_instruction::port_select::a, // destination_port + ap::de::device | ap::port_select::a, command_code, command_data_size, + false); // end_flag + + init_host_command(&buf[(command_size / 4) * 1], &receive_buf[(response_size / 4) * 1], + host_instruction::port_select::b, // destination_port + ap::de::device | ap::port_select::b, command_code, command_data_size, + false); // end_flag + + init_host_command(&buf[(command_size / 4) * 2], &receive_buf[(response_size / 4) * 2], + host_instruction::port_select::c, // destination_port + ap::de::device | ap::port_select::c, command_code, command_data_size, + false); // end_flag + + init_host_command(&buf[(command_size / 4) * 3], &receive_buf[(response_size / 4) * 3], + host_instruction::port_select::d, // destination_port + ap::de::device | ap::port_select::d, command_code, command_data_size, + true); // end_flag } -void init_get_condition(uint32_t * buf, uint32_t * receive_buf) +void init_device_request(uint32_t * buf, uint32_t * receive_buf, + uint32_t destination_port, + uint8_t destination_ap) { - init_host_command(buf, receive_buf, get_condition::command_code, (sizeof (struct get_condition::data_fields))); + init_host_command(buf, receive_buf, + destination_port, + destination_ap, device_request::command_code, (sizeof (struct device_request::data_fields)), + true); +} + +void init_get_condition(uint32_t * buf, uint32_t * receive_buf, + uint32_t destination_port, + uint8_t destination_ap) +{ + init_host_command(buf, receive_buf, + destination_port, + destination_ap, get_condition::command_code, (sizeof (struct get_condition::data_fields)), + true); auto host_command = reinterpret_cast *>(buf); @@ -47,11 +88,18 @@ void init_get_condition(uint32_t * buf, uint32_t * receive_buf) fields.function_type = std::byteswap(function_type::controller); } -void init_block_write(uint32_t * buf, uint32_t * receive_buf, uint32_t * data) +void init_block_write(uint32_t * command_buf, uint32_t * receive_buf, + uint32_t destination_port, + uint8_t destination_ap, + uint32_t * data, + uint32_t data_size) { - init_host_command(buf, receive_buf, block_write::command_code, (sizeof (struct block_write::data_fields))); + init_host_command(command_buf, receive_buf, + destination_port, + destination_ap, block_write::command_code, (sizeof (struct block_write::data_fields)) + data_size, + true); - auto host_command = reinterpret_cast> *>(buf); + auto host_command = reinterpret_cast> *>(command_buf); auto& fields = host_command->bus_data.data_fields; // BW LCD function type @@ -66,16 +114,16 @@ void init_block_write(uint32_t * buf, uint32_t * receive_buf, uint32_t * data) // plane 0 (2 total levels of gradation) fields.block_no = std::byteswap(0x0000); - for (uint32_t i = 0; i < (192 / 4); i++) { + for (uint32_t i = 0; i < (data_size / 4); i++) { fields.written_data[i] = data[i]; } } void dma_start(uint32_t * command_buf) { - sh7091.DMAC.DMAOR = DMAOR__DDT /* on-demand data transfer mode */ - | DMAOR__PR__CH2_CH0_CH1_CH3 /* priority mode; CH2 > CH0 > CH1 > CH3 */ - | DMAOR__DME; /* DMAC master enable */ + sh7091.DMAC.DMAOR = DMAOR__DDT // on-demand data transfer mode + | DMAOR__PR__CH2_CH0_CH1_CH3 // priority mode; CH2 > CH0 > CH1 > CH3 + | DMAOR__DME; // DMAC master enable // clear maple-DMA end status system.ISTNRM = ISTNRM__END_OF_DMA_MAPLE_DMA; @@ -90,8 +138,8 @@ void dma_start(uint32_t * command_buf) maple_if.MSYS = msys::time_out_counter(one_msec) | msys::sending_rate::_2M; - /* top address: the first/lowest address - bottom address: the last/highest address */ + // top address: the first/lowest address + // bottom address: the last/highest address maple_if.MDAPRO = mdapro::security_code | mdapro::top_address(0x00) | mdapro::bottom_address(0x7f); diff --git a/maple/maple.hpp b/maple/maple.hpp index 9450fd3..6900633 100644 --- a/maple/maple.hpp +++ b/maple/maple.hpp @@ -17,11 +17,39 @@ struct host_command { } bus_data; }; -void init_host_command(uint32_t * command_buf, uint32_t * receive_buf); -void init_device_request(uint32_t * command_buf, uint32_t * receive_buf); -void init_get_condition(uint32_t * command_buf, uint32_t * receive_buf); -void init_block_write(uint32_t * command_buf, uint32_t * receive_buf, uint32_t * data); +template +struct command_response { + struct bus_data { + uint8_t command_code; + uint8_t destination_ap; + uint8_t source_ap; + uint8_t data_size; + T data_fields; + } bus_data; +}; + +void init_host_command(uint32_t * buf, uint32_t * receive_buf, + uint32_t destination_port, + uint8_t destination_ap, uint8_t command_code, uint8_t data_size, + bool end_flag); + +void init_host_command_all_ports(uint32_t * buf, uint32_t * receive_buf, + uint8_t command_code, uint32_t command_data_size, uint32_t response_data_size); + +void init_device_request(uint32_t * buf, uint32_t * receive_buf, + uint32_t destination_port, + uint8_t destination_ap); + +void init_get_condition(uint32_t * buf, uint32_t * receive_buf, + uint32_t destination_port, + uint8_t destination_ap); + +void init_block_write(uint32_t * buf, uint32_t * receive_buf, + uint32_t destination_port, + uint8_t destination_ap, + uint32_t * data, + uint32_t data_size); + void dma_start(uint32_t * command_buf); } - diff --git a/maple/maple_bus_bits.hpp b/maple/maple_bus_bits.hpp index 85c2980..ce4e37d 100644 --- a/maple/maple_bus_bits.hpp +++ b/maple/maple_bus_bits.hpp @@ -10,6 +10,8 @@ namespace host_instruction { 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 { @@ -18,23 +20,33 @@ namespace host_instruction { 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 uint32_t transfer_length(uint32_t num) { return (num & 0xff) << 0; } } +namespace receive_data_storage_address { + constexpr 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 { @@ -43,6 +55,8 @@ namespace ap { 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; } } diff --git a/maple/maple_bus_commands.hpp b/maple/maple_bus_commands.hpp index 560291e..377646b 100644 --- a/maple/maple_bus_commands.hpp +++ b/maple/maple_bus_commands.hpp @@ -2,35 +2,35 @@ namespace device_request { constexpr uint32_t command_code = 0x1; - + struct data_fields { }; } namespace all_status_request { constexpr uint32_t command_code = 0x2; - + struct data_fields { }; } namespace device_reset { constexpr uint32_t command_code = 0x3; - + struct data_fields { }; } namespace device_kill { constexpr uint32_t command_code = 0x4; - + struct data_fields { }; } namespace device_status { constexpr uint32_t command_code = 0x5; - + struct data_fields { uint8_t device_id[16]; uint8_t destination_code; @@ -40,13 +40,13 @@ namespace device_status { uint16_t low_consumption_standby_current; uint16_t maximum_current_consumption; }; - + static_assert((sizeof (struct data_fields)) == 112); } namespace device_all_status { constexpr uint32_t command_code = 0x6; - + template struct data_fields { uint8_t device_id[16]; @@ -58,66 +58,66 @@ namespace device_all_status { uint16_t maximum_current_consumption; T free_device_status; }; - + static_assert((sizeof (struct data_fields)) == 112); } namespace device_reply { constexpr uint32_t command_code = 0x7; - + struct data_fields { }; } namespace data_transfer { constexpr uint32_t command_code = 0x8; - + template struct data_fields { uint32_t function_type; T data; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace get_condition { constexpr uint32_t command_code = 0x9; - + struct data_fields { uint32_t function_type; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace get_media_info { constexpr uint32_t command_code = 0xa; - + struct data_fields { uint32_t function_type; uint32_t pt; }; - + static_assert((sizeof (struct data_fields)) == 8); } namespace block_read { constexpr uint32_t command_code = 0xb; - + struct data_fields { uint32_t function_type; uint8_t pt; uint8_t phase; uint16_t block_no; }; - + static_assert((sizeof (struct data_fields)) == 8); } namespace block_write { constexpr uint32_t command_code = 0xc; - + template struct data_fields { uint32_t function_type; @@ -126,107 +126,108 @@ namespace block_write { uint16_t block_no; T written_data; }; - + static_assert((sizeof (struct data_fields)) == 8); + static_assert((offsetof (struct data_fields, written_data)) == 8); + static_assert((offsetof (struct data_fields, written_data)) == 8); } namespace get_last_error { constexpr uint32_t command_code = 0xd; - + struct data_fields { uint32_t function_type; uint8_t pt; uint8_t phase; uint16_t block_no; }; - + static_assert((sizeof (struct data_fields)) == 8); } namespace set_condition { constexpr uint32_t command_code = 0xe; - + template struct data_fields { uint32_t function_type; T write_in_data; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace ft4_control { constexpr uint32_t command_code = 0xf; - + template struct data_fields { uint32_t function_type; T ft4_data; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace ar_control { constexpr uint32_t command_code = 0x10; - + template struct data_fields { uint32_t function_type; T data; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace function_type_unknown { constexpr uint32_t command_code = 0xfe; - + struct data_fields { }; } namespace command_unknown { constexpr uint32_t command_code = 0xfd; - + struct data_fields { }; } namespace transmit_again { constexpr uint32_t command_code = 0xfc; - + struct data_fields { }; } namespace file_error { constexpr uint32_t command_code = 0xfb; - + struct data_fields { uint32_t function_error_code; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace lcd_error { constexpr uint32_t command_code = 0xfa; - + struct data_fields { uint32_t function_error_code; }; - + static_assert((sizeof (struct data_fields)) == 4); } namespace ar_error { constexpr uint32_t command_code = 0xf9; - + struct data_fields { uint32_t function_error_code; }; - + static_assert((sizeof (struct data_fields)) == 4); } - diff --git a/regs/gen/core_bits.py b/regs/gen/core_bits.py index aca89c1..5c2949b 100644 --- a/regs/gen/core_bits.py +++ b/regs/gen/core_bits.py @@ -175,10 +175,22 @@ def render_defs(bit_def): else: yield from render_read_only(bit_def) +def render_enum_mask(enum_def): + all_bits = set(bit_def["bits"] for bit_def in enum_def.defs) + assert len(all_bits) == 1 + assert all(bit_def["bit_name"] != "bit_mask" for bit_def in enum_def.defs), bit_def + _bits = next(iter(all_bits)) + bits = parse_bit_range(_bits) + mask_value = mask_from_bits(bits) + bit_ix = min(bits) + yield "" + yield f"constexpr uint32_t bit_mask = {hex(mask_value)} << {bit_ix};" + def render_enum(enum_def): yield f"namespace {enum_def.name.lower()} {{" for bit_def in enum_def.defs: yield from render_defs(bit_def) + yield from render_enum_mask(enum_def) yield "}" def render_register(register): diff --git a/regs/maple_bus_bits.csv b/regs/maple_bus_bits.csv index 029a65e..2644cc4 100644 --- a/regs/maple_bus_bits.csv +++ b/regs/maple_bus_bits.csv @@ -14,6 +14,8 @@ ,,,,,, "host_instruction",,"7-0","transfer_length",,"0xff", ,,,,,, +"receive_data_storage_address",,"31-0","address",,"0x1fff_ffff", +,,,,,, "ap","port_select","7-6","a","0b00",, "ap","port_select","7-6","b","0b01",, "ap","port_select","7-6","c","0b10",, diff --git a/regs/maple_bus_bits.ods b/regs/maple_bus_bits.ods index 16322fc..3c5318c 100644 Binary files a/regs/maple_bus_bits.ods and b/regs/maple_bus_bits.ods differ