maple: read controller input on real hardware
There were two notable bugs: - the maple transfer/data sizes were not being set correctly - align_32byte always realigned the address of `_scene`, and not the `mem` parameter as expected. This had the effect of the maple-DMA send and receive buffers being the same buffer. On real hardware, this causes unpredicable behavior.
This commit is contained in:
parent
ca77db1734
commit
25fef821b0
20
imask.h
Normal file
20
imask.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
inline void set_imask(uint32_t imask)
|
||||||
|
{
|
||||||
|
uint32_t sr;
|
||||||
|
|
||||||
|
asm volatile ("stc sr,%0"
|
||||||
|
: "=r" (sr)
|
||||||
|
:
|
||||||
|
);
|
||||||
|
|
||||||
|
sr = (sr & ~0xf0) | (imask << 4);
|
||||||
|
|
||||||
|
asm volatile ("ldc %0,sr"
|
||||||
|
:
|
||||||
|
: "r" (sr)
|
||||||
|
);
|
||||||
|
}
|
74
main.cpp
74
main.cpp
@ -11,6 +11,8 @@
|
|||||||
#include "systembus.h"
|
#include "systembus.h"
|
||||||
#include "maple/maple.h"
|
#include "maple/maple.h"
|
||||||
#include "maple/maple_bits.h"
|
#include "maple/maple_bits.h"
|
||||||
|
#include "maple/maple_bus_commands.h"
|
||||||
|
#include "maple/maple_bus_ft0.h"
|
||||||
|
|
||||||
#include "holly/texture_memory_alloc.h"
|
#include "holly/texture_memory_alloc.h"
|
||||||
|
|
||||||
@ -47,6 +49,10 @@ inline void serial_char(const char c)
|
|||||||
// wait for transmit fifo to become empty
|
// wait for transmit fifo to become empty
|
||||||
while ((sh7091.SCIF.SCFSR2 & SCFSR2__TDFE) == 0);
|
while ((sh7091.SCIF.SCFSR2 & SCFSR2__TDFE) == 0);
|
||||||
|
|
||||||
|
for (int i = 0; i < 100000; i++) {
|
||||||
|
asm volatile ("nop;");
|
||||||
|
}
|
||||||
|
|
||||||
sh7091.SCIF.SCFTDR2 = static_cast<uint8_t>(c);
|
sh7091.SCIF.SCFTDR2 = static_cast<uint8_t>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,14 +66,16 @@ void serial_string(const char * s)
|
|||||||
/* must be aligned to 32-bytes for DMA transfer */
|
/* must be aligned to 32-bytes for DMA transfer */
|
||||||
// the aligned(32) attribute does not actually align to 32 bytes; gcc is the best compiler.
|
// the aligned(32) attribute does not actually align to 32 bytes; gcc is the best compiler.
|
||||||
// `+ 32` to allow for repositioning _scene to an actual 32-byte alignment.
|
// `+ 32` to allow for repositioning _scene to an actual 32-byte alignment.
|
||||||
uint32_t __attribute__((aligned(32))) _scene[((32 * 6) + 32) / 4];
|
// __attribute__((aligned(32)))
|
||||||
|
uint32_t _scene[((32 * 6) + 32) / 4];
|
||||||
|
|
||||||
uint32_t * align_32byte(uint32_t * mem)
|
template <typename T>
|
||||||
|
T * align_32byte(T * mem)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<uint32_t *>(((reinterpret_cast<uint32_t>(_scene) + 31) & ~31));
|
return reinterpret_cast<T *>((((reinterpret_cast<uint32_t>(mem) + 31) & ~31)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_int(const uint32_t n)
|
void serial_int32(const uint32_t n)
|
||||||
{
|
{
|
||||||
char num_buf[9];
|
char num_buf[9];
|
||||||
string::hex<char>(num_buf, 8, n);
|
string::hex<char>(num_buf, 8, n);
|
||||||
@ -77,19 +85,52 @@ void serial_int(const uint32_t n)
|
|||||||
serial_string("\n");
|
serial_string("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void maple_test()
|
void serial_int8(const uint8_t n)
|
||||||
|
{
|
||||||
|
char num_buf[3];
|
||||||
|
string::hex<char>(num_buf, 2, n);
|
||||||
|
num_buf[2] = 0;
|
||||||
|
serial_string("0x");
|
||||||
|
serial_string(num_buf);
|
||||||
|
serial_string("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t _receive_address[(32 + 32) / 4] = {0};
|
||||||
|
uint32_t _command_buf[(32 + 32) / 4] = {0};
|
||||||
|
|
||||||
|
bool maple_test()
|
||||||
{
|
{
|
||||||
uint32_t _command_buf[(32 + 32) / 4];
|
|
||||||
uint32_t _receive_address[(32 + 32) / 4];
|
|
||||||
uint32_t * command_buf = align_32byte(_command_buf);
|
uint32_t * command_buf = align_32byte(_command_buf);
|
||||||
uint32_t * receive_address = align_32byte(_receive_address);
|
uint32_t * receive_address = align_32byte(_receive_address);
|
||||||
|
if ((((uint32_t)command_buf) & 31) != 0) serial_string("misaligned\n");
|
||||||
|
if ((((uint32_t)receive_address) & 31) != 0) serial_string("misaligned\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < (32 / 4); i++) {
|
||||||
|
command_buf[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < (32 / 4); i++) {
|
||||||
|
receive_address[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
v_sync_out();
|
||||||
|
|
||||||
|
//maple_init_device_request(command_buf, receive_address);
|
||||||
|
maple_init_get_condition(command_buf, receive_address);
|
||||||
|
|
||||||
maple_init_host_command(command_buf, receive_address);
|
|
||||||
maple_dma_start(command_buf);
|
maple_dma_start(command_buf);
|
||||||
|
|
||||||
for (int i = 0; i < 32; i++) {
|
v_sync_in();
|
||||||
serial_int(receive_address[i]);
|
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < (4 + 4 + 8); i++) {
|
||||||
|
serial_int8(reinterpret_cast<volatile uint8_t *>(receive_address)[i]);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// the data format for a FT0 (controller) data read
|
||||||
|
auto data_format = reinterpret_cast<volatile data_transfer::data_fields<ft0::data_transfer::data_format> *>(&receive_address[1]);
|
||||||
|
return !(data_format->data.digital_button & ft0::data_transfer::digital_button::a);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
@ -110,8 +151,7 @@ void main()
|
|||||||
|
|
||||||
v_sync_in();
|
v_sync_in();
|
||||||
|
|
||||||
maple_test();
|
/*
|
||||||
|
|
||||||
volatile uint16_t * framebuffer = reinterpret_cast<volatile uint16_t *>(&texture_memory[0]);
|
volatile uint16_t * framebuffer = reinterpret_cast<volatile uint16_t *>(&texture_memory[0]);
|
||||||
for (int y = 0; y < 480; y++) {
|
for (int y = 0; y < 480; y++) {
|
||||||
for (int x = 0; x < 640; x++) {
|
for (int x = 0; x < 640; x++) {
|
||||||
@ -120,7 +160,9 @@ void main()
|
|||||||
framebuffer[y * 640 + x] = ((rgb.r >> 3) << 11) | ((rgb.g >> 2) << 5) | ((rgb.b >> 3) << 0);
|
framebuffer[y * 640 + x] = ((rgb.r >> 3) << 11) | ((rgb.g >> 2) << 5) | ((rgb.b >> 3) << 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
volatile texture_memory_alloc * mem = reinterpret_cast<volatile texture_memory_alloc *>(0xa400'0000);
|
volatile texture_memory_alloc * mem = reinterpret_cast<volatile texture_memory_alloc *>(0xa400'0000);
|
||||||
|
|
||||||
volatile uint8_t * macaw = reinterpret_cast<volatile uint8_t *>(&_binary_macaw_data_start);
|
volatile uint8_t * macaw = reinterpret_cast<volatile uint8_t *>(&_binary_macaw_data_start);
|
||||||
@ -133,6 +175,7 @@ void main()
|
|||||||
uint16_t rgb565 = ((r / 8) << 11) | ((g / 4) << 5) | ((b / 8) << 0);
|
uint16_t rgb565 = ((r / 8) << 11) | ((g / 4) << 5) | ((b / 8) << 0);
|
||||||
mem->texture[px] = rgb565;
|
mem->texture[px] = rgb565;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
holly.SOFTRESET = softreset::pipeline_soft_reset
|
holly.SOFTRESET = softreset::pipeline_soft_reset
|
||||||
| softreset::ta_soft_reset;
|
| softreset::ta_soft_reset;
|
||||||
@ -156,17 +199,22 @@ void main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
int frame = 0;
|
int frame = 0;
|
||||||
|
bool a_pressed = 0;
|
||||||
|
uint32_t color;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
v_sync_out();
|
v_sync_out();
|
||||||
v_sync_in();
|
v_sync_in();
|
||||||
|
|
||||||
ta_polygon_converter_init();
|
ta_polygon_converter_init();
|
||||||
uint32_t ta_parameter_size = scene_transform(scene);
|
if (a_pressed) { color = 0xffffffff; } else { color = 0xffff7f00; }
|
||||||
|
uint32_t ta_parameter_size = scene_transform_quad(scene, color);
|
||||||
ta_polygon_converter_transfer(scene, ta_parameter_size);
|
ta_polygon_converter_transfer(scene, ta_parameter_size);
|
||||||
ta_wait_opaque_list();
|
ta_wait_opaque_list();
|
||||||
core_start_render(frame);
|
core_start_render(frame);
|
||||||
|
|
||||||
|
a_pressed = maple_test();
|
||||||
|
|
||||||
frame = !frame;
|
frame = !frame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,20 +24,41 @@ struct maple_host_command {
|
|||||||
} bus_data;
|
} bus_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
void maple_init_host_command(uint32_t * buf, uint32_t * receive_address)
|
void maple_init_host_command(uint32_t * buf, uint32_t * receive_address, uint8_t command_code, uint8_t data_size)
|
||||||
{
|
{
|
||||||
auto host_command = reinterpret_cast<maple_host_command<device_request::data_fields> *>(buf);
|
// this function does not care about the template instantiation of
|
||||||
|
// maple_host_command--data_fields is not manipulated here.
|
||||||
|
auto host_command = reinterpret_cast<maple_host_command<uint32_t> *>(buf);
|
||||||
|
|
||||||
host_command->host_instruction = host_instruction::end_flag
|
host_command->host_instruction = host_instruction::end_flag
|
||||||
| host_instruction::port_select::a
|
| host_instruction::port_select::a
|
||||||
| host_instruction::transfer_length(0); // 4 bytes
|
| host_instruction::transfer_length((data_size / 4));
|
||||||
|
|
||||||
host_command->receive_data_storage_address = reinterpret_cast<uint32_t>(receive_address);
|
host_command->receive_data_storage_address = reinterpret_cast<uint32_t>(receive_address) & 0x1fff'ffff;
|
||||||
|
|
||||||
host_command->bus_data.command_code = device_request::command_code;
|
host_command->bus_data.command_code = command_code;
|
||||||
host_command->bus_data.destination_ap = ap::de::device | ap::port_select::a;
|
host_command->bus_data.destination_ap = ap::de::device | ap::port_select::a;
|
||||||
host_command->bus_data.source_ap = ap::port_select::a;
|
host_command->bus_data.source_ap = ap::port_select::a;
|
||||||
host_command->bus_data.data_size = 0;
|
host_command->bus_data.data_size = data_size / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void maple_init_device_request(uint32_t * buf, uint32_t * receive_address)
|
||||||
|
{
|
||||||
|
maple_init_host_command(buf, receive_address, device_request::command_code, (sizeof (struct device_request::data_fields)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void maple_init_get_condition(uint32_t * buf, uint32_t * receive_address)
|
||||||
|
{
|
||||||
|
maple_init_host_command(buf, receive_address, get_condition::command_code, (sizeof (struct get_condition::data_fields)));
|
||||||
|
|
||||||
|
auto host_command = reinterpret_cast<maple_host_command<get_condition::data_fields> *>(buf);
|
||||||
|
|
||||||
|
auto& function_type = host_command->bus_data.data_fields.function_type;
|
||||||
|
// controller function type
|
||||||
|
function_type[0] = 0x00;
|
||||||
|
function_type[1] = 0x00;
|
||||||
|
function_type[2] = 0x00;
|
||||||
|
function_type[3] = 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
void maple_dma_start(uint32_t * command_buf)
|
void maple_dma_start(uint32_t * command_buf)
|
||||||
@ -52,29 +73,28 @@ void maple_dma_start(uint32_t * command_buf)
|
|||||||
// disable maple-DMA
|
// disable maple-DMA
|
||||||
maple_if.MDEN = mden::dma_enable::abort;
|
maple_if.MDEN = mden::dma_enable::abort;
|
||||||
|
|
||||||
volatile uint32_t _dummy = maple_if.MDST;
|
while (mdst::start_status::status(maple_if.MDST) != 0);
|
||||||
(void)_dummy;
|
|
||||||
|
|
||||||
// 20nsec * 0xc350 = 1ms
|
// 20nsec * 0xc350 = 1ms
|
||||||
constexpr uint32_t one_msec = 0xc350;
|
constexpr uint32_t one_msec = 0xc350;
|
||||||
maple_if.MSYS = msys::time_out_counter(one_msec)
|
maple_if.MSYS = msys::time_out_counter(one_msec)
|
||||||
| msys::sending_rate::_2M;
|
| msys::sending_rate::_2M;
|
||||||
|
|
||||||
maple_if.MDTSEL = mdtsel::trigger_select::software_initiation;
|
|
||||||
|
|
||||||
/* top address: the first/lowest address
|
/* top address: the first/lowest address
|
||||||
bottom address: the last/highest address */
|
bottom address: the last/highest address */
|
||||||
maple_if.MDAPRO = mdapro::security_code
|
maple_if.MDAPRO = mdapro::security_code
|
||||||
| mdapro::top_address(0x00)
|
| mdapro::top_address(0x00)
|
||||||
| mdapro::bottom_address(0x7f);
|
| mdapro::bottom_address(0x7f);
|
||||||
|
|
||||||
|
maple_if.MDTSEL = mdtsel::trigger_select::software_initiation;
|
||||||
|
|
||||||
maple_if.MDSTAR = mdstar::table_address(reinterpret_cast<uint32_t>(command_buf));
|
maple_if.MDSTAR = mdstar::table_address(reinterpret_cast<uint32_t>(command_buf));
|
||||||
|
|
||||||
maple_if.MDEN = mden::dma_enable::enable;
|
maple_if.MDEN = mden::dma_enable::enable;
|
||||||
maple_if.MDST = mdst::start_status::start;
|
maple_if.MDST = mdst::start_status::start;
|
||||||
|
|
||||||
// wait for completion
|
// wait for completion
|
||||||
|
//while (mdst::start_status::status(maple_if.MDST) != 0);
|
||||||
while ((system.ISTNRM & ISTNRM__END_OF_DMA_MAPLE_DMA) == 0);
|
while ((system.ISTNRM & ISTNRM__END_OF_DMA_MAPLE_DMA) == 0);
|
||||||
|
|
||||||
system.ISTNRM = ISTNRM__END_OF_DMA_MAPLE_DMA;
|
system.ISTNRM = ISTNRM__END_OF_DMA_MAPLE_DMA;
|
||||||
}
|
}
|
||||||
|
@ -3,4 +3,6 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
void maple_init_host_command(uint32_t * buf, uint32_t * receive_address);
|
void maple_init_host_command(uint32_t * buf, uint32_t * receive_address);
|
||||||
|
void maple_init_device_request(uint32_t * buf, uint32_t * receive_address);
|
||||||
|
void maple_init_get_condition(uint32_t * buf, uint32_t * receive_address);
|
||||||
void maple_dma_start(uint32_t * command_buf);
|
void maple_dma_start(uint32_t * command_buf);
|
||||||
|
@ -47,7 +47,7 @@ namespace device_status {
|
|||||||
namespace device_all_status {
|
namespace device_all_status {
|
||||||
constexpr uint32_t command_code = 0x6;
|
constexpr uint32_t command_code = 0x6;
|
||||||
|
|
||||||
template <int N>
|
template <typename T>
|
||||||
struct data_fields {
|
struct data_fields {
|
||||||
uint8_t device_id[16];
|
uint8_t device_id[16];
|
||||||
uint8_t destination_code[1];
|
uint8_t destination_code[1];
|
||||||
@ -56,10 +56,10 @@ namespace device_all_status {
|
|||||||
uint8_t license[60];
|
uint8_t license[60];
|
||||||
uint8_t low_consumption_standby_current[2];
|
uint8_t low_consumption_standby_current[2];
|
||||||
uint8_t maximum_current_consumption[2];
|
uint8_t maximum_current_consumption[2];
|
||||||
uint8_t free_device_status[N];
|
T free_device_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields<0>)) == 112);
|
static_assert((sizeof (struct data_fields<char[0]>)) == 112);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace device_reply {
|
namespace device_reply {
|
||||||
@ -72,12 +72,13 @@ namespace device_reply {
|
|||||||
namespace data_transfer {
|
namespace data_transfer {
|
||||||
constexpr uint32_t command_code = 0x8;
|
constexpr uint32_t command_code = 0x8;
|
||||||
|
|
||||||
template <int N>
|
template <typename T>
|
||||||
struct data_fields {
|
struct data_fields {
|
||||||
uint8_t data[N];
|
uint8_t function_type[4];
|
||||||
|
T data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields<0>)) == 0);
|
static_assert((sizeof (struct data_fields<char[0]>)) == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace get_condition {
|
namespace get_condition {
|
||||||
@ -117,16 +118,16 @@ namespace block_read {
|
|||||||
namespace block_write {
|
namespace block_write {
|
||||||
constexpr uint32_t command_code = 0xc;
|
constexpr uint32_t command_code = 0xc;
|
||||||
|
|
||||||
template <int N>
|
template <typename T>
|
||||||
struct data_fields {
|
struct data_fields {
|
||||||
uint8_t function_type[4];
|
uint8_t function_type[4];
|
||||||
uint8_t pt[1];
|
uint8_t pt[1];
|
||||||
uint8_t phase[1];
|
uint8_t phase[1];
|
||||||
uint8_t block_no[2];
|
uint8_t block_no[2];
|
||||||
uint8_t written_data[N];
|
T written_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields<0>)) == 8);
|
static_assert((sizeof (struct data_fields<char[0]>)) == 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace get_last_error {
|
namespace get_last_error {
|
||||||
@ -145,37 +146,37 @@ namespace get_last_error {
|
|||||||
namespace set_condition {
|
namespace set_condition {
|
||||||
constexpr uint32_t command_code = 0xe;
|
constexpr uint32_t command_code = 0xe;
|
||||||
|
|
||||||
template <int N>
|
template <typename T>
|
||||||
struct data_fields {
|
struct data_fields {
|
||||||
uint8_t function_type[4];
|
uint8_t function_type[4];
|
||||||
uint8_t write_in_data[N];
|
T write_in_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields<0>)) == 4);
|
static_assert((sizeof (struct data_fields<char[0]>)) == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ft4_control {
|
namespace ft4_control {
|
||||||
constexpr uint32_t command_code = 0xf;
|
constexpr uint32_t command_code = 0xf;
|
||||||
|
|
||||||
template <int N>
|
template <typename T>
|
||||||
struct data_fields {
|
struct data_fields {
|
||||||
uint8_t function_type[4];
|
uint8_t function_type[4];
|
||||||
uint8_t ft4_data[N];
|
T ft4_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields<0>)) == 4);
|
static_assert((sizeof (struct data_fields<char[0]>)) == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ar_control {
|
namespace ar_control {
|
||||||
constexpr uint32_t command_code = 0x10;
|
constexpr uint32_t command_code = 0x10;
|
||||||
|
|
||||||
template <int N>
|
template <typename T>
|
||||||
struct data_fields {
|
struct data_fields {
|
||||||
uint8_t function_type[4];
|
uint8_t function_type[4];
|
||||||
uint8_t data[N];
|
T data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields<0>)) == 4);
|
static_assert((sizeof (struct data_fields<char[0]>)) == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace function_type_unknown {
|
namespace function_type_unknown {
|
||||||
|
34
maple/maple_bus_ft0.h
Normal file
34
maple/maple_bus_ft0.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
namespace ft0 {
|
||||||
|
namespace data_transfer {
|
||||||
|
namespace digital_button {
|
||||||
|
constexpr uint32_t ra = 1 << 7;
|
||||||
|
constexpr uint32_t la = 1 << 6;
|
||||||
|
constexpr uint32_t da = 1 << 5;
|
||||||
|
constexpr uint32_t ua = 1 << 4;
|
||||||
|
constexpr uint32_t start = 1 << 3;
|
||||||
|
constexpr uint32_t a = 1 << 2;
|
||||||
|
constexpr uint32_t b = 1 << 1;
|
||||||
|
constexpr uint32_t c = 1 << 0;
|
||||||
|
constexpr uint32_t rb = 1 << 15;
|
||||||
|
constexpr uint32_t lb = 1 << 14;
|
||||||
|
constexpr uint32_t db = 1 << 13;
|
||||||
|
constexpr uint32_t ub = 1 << 12;
|
||||||
|
constexpr uint32_t d = 1 << 11;
|
||||||
|
constexpr uint32_t x = 1 << 10;
|
||||||
|
constexpr uint32_t y = 1 << 9;
|
||||||
|
constexpr uint32_t z = 1 << 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data_format {
|
||||||
|
uint16_t digital_button;
|
||||||
|
uint8_t analog_axis_1;
|
||||||
|
uint8_t analog_axis_2;
|
||||||
|
uint8_t analog_axis_3;
|
||||||
|
uint8_t analog_axis_4;
|
||||||
|
uint8_t analog_axis_5;
|
||||||
|
uint8_t analog_axis_6;
|
||||||
|
};
|
||||||
|
static_assert((sizeof (struct data_format)) == 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,225 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "type.h"
|
|
||||||
|
|
||||||
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[1];
|
|
||||||
uint8_t connection_direction[1];
|
|
||||||
uint8_t product_name[30];
|
|
||||||
uint8_t license[60];
|
|
||||||
uint8_t low_consumption_standby_current[2];
|
|
||||||
uint8_t maximum_current_consumption[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields)) == 112);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace device_all_status {
|
|
||||||
constexpr uint32_t command_code = 0x6;
|
|
||||||
struct data_fields {
|
|
||||||
|
|
||||||
template <int N>
|
|
||||||
uint8_t device_id[16];
|
|
||||||
uint8_t destination_code[1];
|
|
||||||
uint8_t connection_direction[1];
|
|
||||||
uint8_t product_name[30];
|
|
||||||
uint8_t license[60];
|
|
||||||
uint8_t low_consumption_standby_current[2];
|
|
||||||
uint8_t maximum_current_consumption[2];
|
|
||||||
uint8_t free_device_status[N];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields<0>)) == 112);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace device_reply {
|
|
||||||
constexpr uint32_t command_code = 0x7;
|
|
||||||
struct data_fields {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace data_transfer {
|
|
||||||
constexpr uint32_t command_code = 0x8;
|
|
||||||
struct data_fields {
|
|
||||||
|
|
||||||
template <int N>
|
|
||||||
uint8_t data[N];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields<0>)) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace get_condition {
|
|
||||||
constexpr uint32_t command_code = 0x9;
|
|
||||||
struct data_fields {
|
|
||||||
|
|
||||||
uint8_t function_type[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields)) == 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace get_media_info {
|
|
||||||
constexpr uint32_t command_code = 0xa;
|
|
||||||
struct data_fields {
|
|
||||||
|
|
||||||
uint8_t function_type[4];
|
|
||||||
uint8_t pt[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields)) == 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace block_read {
|
|
||||||
constexpr uint32_t command_code = 0xb;
|
|
||||||
struct data_fields {
|
|
||||||
|
|
||||||
uint8_t function_type[4];
|
|
||||||
uint8_t pt[1];
|
|
||||||
uint8_t phase[1];
|
|
||||||
uint8_t block_no[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields)) == 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace block_write {
|
|
||||||
constexpr uint32_t command_code = 0xc;
|
|
||||||
struct data_fields {
|
|
||||||
|
|
||||||
template <int N>
|
|
||||||
uint8_t function_type[4];
|
|
||||||
uint8_t pt[1];
|
|
||||||
uint8_t phase[1];
|
|
||||||
uint8_t block_no[2];
|
|
||||||
uint8_t written_data[N];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields<0>)) == 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace get_last_error {
|
|
||||||
constexpr uint32_t command_code = 0xd;
|
|
||||||
struct data_fields {
|
|
||||||
|
|
||||||
uint8_t function_type[4];
|
|
||||||
uint8_t pt[1];
|
|
||||||
uint8_t phase[1];
|
|
||||||
uint8_t block_no[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields)) == 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace set_condition {
|
|
||||||
constexpr uint32_t command_code = 0xe;
|
|
||||||
struct data_fields {
|
|
||||||
|
|
||||||
template <int N>
|
|
||||||
uint8_t function_type[4];
|
|
||||||
uint8_t write_in_data[N];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields<0>)) == 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ft4_control {
|
|
||||||
constexpr uint32_t command_code = 0xf;
|
|
||||||
struct data_fields {
|
|
||||||
|
|
||||||
template <int N>
|
|
||||||
uint8_t function_type[4];
|
|
||||||
uint8_t ft4_data[N];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields<0>)) == 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ar_control {
|
|
||||||
constexpr uint32_t command_code = 0x10;
|
|
||||||
struct data_fields {
|
|
||||||
|
|
||||||
template <int N>
|
|
||||||
uint8_t function_type[4];
|
|
||||||
uint8_t data[N];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields<0>)) == 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 {
|
|
||||||
|
|
||||||
uint8_t function_error_code[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields)) == 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace lcd_error {
|
|
||||||
constexpr uint32_t command_code = 0xfa;
|
|
||||||
struct data_fields {
|
|
||||||
|
|
||||||
uint8_t function_error_code[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields)) == 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ar_error {
|
|
||||||
constexpr uint32_t command_code = 0xf9;
|
|
||||||
struct data_fields {
|
|
||||||
|
|
||||||
uint8_t function_error_code[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert((sizeof (struct data_fields)) == 4);
|
|
||||||
}
|
|
@ -27,7 +27,7 @@ def command_namespace(namespace: CommandNamespace,
|
|||||||
|
|
||||||
if variable is not None:
|
if variable is not None:
|
||||||
assert variable.lower() == "n"
|
assert variable.lower() == "n"
|
||||||
yield "template <int N>"
|
yield "template <typename T>"
|
||||||
|
|
||||||
yield "struct data_fields {"
|
yield "struct data_fields {"
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ def command_namespace(namespace: CommandNamespace,
|
|||||||
yield f"uint8_t {field_name}[{const}];"
|
yield f"uint8_t {field_name}[{const}];"
|
||||||
elif const == 0:
|
elif const == 0:
|
||||||
assert var == "n"
|
assert var == "n"
|
||||||
yield f"uint8_t {field_name}[{var.upper()}];"
|
yield f"T {field_name};"
|
||||||
else:
|
else:
|
||||||
yield f"uint8_t {field_name}[{const} + {var.upper()}];"
|
yield f"uint8_t {field_name}[{const} + {var.upper()}];"
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ def command_namespace(namespace: CommandNamespace,
|
|||||||
|
|
||||||
if variable is not None:
|
if variable is not None:
|
||||||
assert variable == "n"
|
assert variable == "n"
|
||||||
yield f"static_assert((sizeof (struct data_fields<0>)) == {length});"
|
yield f"static_assert((sizeof (struct data_fields<char[0]>)) == {length});"
|
||||||
else:
|
else:
|
||||||
yield f"static_assert((sizeof (struct data_fields)) == {length});"
|
yield f"static_assert((sizeof (struct data_fields)) == {length});"
|
||||||
|
|
||||||
|
124
regs/gen/maple_data_format.py
Normal file
124
regs/gen/maple_data_format.py
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
import csv
|
||||||
|
import sys
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from generate import renderer
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Field:
|
||||||
|
name: str
|
||||||
|
bits: list[str]
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Format:
|
||||||
|
name: str
|
||||||
|
fields: list[Field]
|
||||||
|
field_order: list[str]
|
||||||
|
size: int
|
||||||
|
|
||||||
|
def read_input(filename):
|
||||||
|
with open(filename) as f:
|
||||||
|
reader = csv.reader(f, delimiter=",", quotechar='"')
|
||||||
|
rows = [
|
||||||
|
[s.strip() for s in row]
|
||||||
|
for row in reader
|
||||||
|
]
|
||||||
|
return rows
|
||||||
|
|
||||||
|
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] if b != ""]
|
||||||
|
assert len(bits) in {0, 8}, bits
|
||||||
|
fields[field_name].append(Field(field_name, list(bits)))
|
||||||
|
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
|
||||||
|
|
||||||
|
bit_order = [7, 6, 5, 4, 3, 2, 1, 0]
|
||||||
|
|
||||||
|
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
|
||||||
|
if field.bits != []:
|
||||||
|
assert len(field.bits) == 8
|
||||||
|
for byte_ix, bit in zip(bit_order, field.bits):
|
||||||
|
bit_ix = byte_ix + bit_offset
|
||||||
|
yield f"constexpr uint32_t {bit.lower()} = 1 << {bit_ix};"
|
||||||
|
yield "}"
|
||||||
|
yield ""
|
||||||
|
|
||||||
|
yield f"struct data_format {{"
|
||||||
|
|
||||||
|
for field_name in format.field_order:
|
||||||
|
subfields = format.fields[field_name]
|
||||||
|
if len(subfields) == 1:
|
||||||
|
field, = subfields
|
||||||
|
yield f"uint8_t {field_name};"
|
||||||
|
elif len(subfields) == 2:
|
||||||
|
yield f"uint16_t {field_name};"
|
||||||
|
else:
|
||||||
|
assert False, len(subfields)
|
||||||
|
|
||||||
|
yield "};"
|
||||||
|
assert format.size % 4 == 0, format.size
|
||||||
|
yield f"static_assert((sizeof (struct data_format)) == {format.size});"
|
||||||
|
yield "}"
|
||||||
|
|
||||||
|
def render_formats(name, formats):
|
||||||
|
yield f"namespace {name} {{"
|
||||||
|
for format in formats:
|
||||||
|
yield from render_format(format)
|
||||||
|
yield "}"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
rows = read_input(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())
|
@ -26,7 +26,8 @@
|
|||||||
,,,,,
|
,,,,,
|
||||||
"device_reply","peripheral","0x07","0x00",,
|
"device_reply","peripheral","0x07","0x00",,
|
||||||
,,,,,
|
,,,,,
|
||||||
"data_transfer","peripheral","0x08","n/4","data","n"
|
"data_transfer","peripheral","0x08","0x01+n/4","function_type",4
|
||||||
|
"data_transfer",,,,"data","n"
|
||||||
,,,,,
|
,,,,,
|
||||||
"get_condition","host","0x09","0x01","function_type",4
|
"get_condition","host","0x09","0x01","function_type",4
|
||||||
,,,,,
|
,,,,,
|
||||||
|
|
Binary file not shown.
9
regs/maple_bus_ft0.csv
Normal file
9
regs/maple_bus_ft0.csv
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
"data_transfer",7,6,5,4,3,2,1,0
|
||||||
|
"digital_button","Ra","La","Da","Ua","Start","A","B","C"
|
||||||
|
"digital_button","Rb","Lb","Db","Ub","D","X","Y","Z"
|
||||||
|
"analog_axis_1",,,,,,,,
|
||||||
|
"analog_axis_2",,,,,,,,
|
||||||
|
"analog_axis_3",,,,,,,,
|
||||||
|
"analog_axis_4",,,,,,,,
|
||||||
|
"analog_axis_5",,,,,,,,
|
||||||
|
"analog_axis_6",,,,,,,,
|
|
Binary file not shown.
@ -49,11 +49,11 @@ struct scene_quad_ta_parameters {
|
|||||||
|
|
||||||
static_assert((sizeof (scene_quad_ta_parameters)) == 32 * 4);
|
static_assert((sizeof (scene_quad_ta_parameters)) == 32 * 4);
|
||||||
|
|
||||||
uint32_t scene_transform_quad(uint32_t * _scene)
|
uint32_t scene_transform_quad(uint32_t * _scene, uint32_t base_color)
|
||||||
{
|
{
|
||||||
auto scene = reinterpret_cast<scene_quad_ta_parameters *>(&_scene[0]);
|
auto scene = reinterpret_cast<scene_quad_ta_parameters *>(&_scene[0]);
|
||||||
|
|
||||||
uint32_t base_color = 0xffffff00;
|
//uint32_t base_color = 0xffffff00;
|
||||||
scene->sprite = global_sprite(base_color);
|
scene->sprite = global_sprite(base_color);
|
||||||
scene->vertex = vertex_sprite_type_0(scene_quad[0].x * 240 + 320,
|
scene->vertex = vertex_sprite_type_0(scene_quad[0].x * 240 + 320,
|
||||||
scene_quad[0].y * 240 + 240,
|
scene_quad[0].y * 240 + 240,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user