example: new maple "get_condition" demo

This is very barebones, and uses the serial interface to communicate
the status of the "a" controller button being pressed.

I'd like to make this a more interactive/graphical demo.
This commit is contained in:
Zack Buhman 2023-12-15 22:08:23 +08:00
parent 9bd79c6664
commit 39aa6b75a6
7 changed files with 206 additions and 65 deletions

View File

@ -54,6 +54,15 @@ CUBE_OBJ = \
example/cube.elf: LDSCRIPT = $(LIB)/alt.lds
example/cube.elf: $(START_OBJ) $(CUBE_OBJ)
MAPLE_DEVICE_REQUEST_OBJ = \
example/maple_device_request.o \
vga.o \
serial.o \
maple/maple.o
example/maple_device_request.elf: LDSCRIPT = $(LIB)/alt.lds
example/maple_device_request.elf: $(START_OBJ) $(MAPLE_DEVICE_REQUEST_OBJ)
MAPLE_CONTROLLER_OBJ = \
example/maple_controller.o \
vga.o \

View File

@ -1,37 +1,116 @@
#include <bit>
#include "vga.hpp"
#include "align.hpp"
#include "maple/maple.hpp"
#include "maple/maple_bus_bits.hpp"
#include "maple/maple_bus_commands.hpp"
#include "maple/maple_bus_ft0.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));
uint32_t _command_buf[1024 / 4 + 32] = {0};
uint32_t _receive_buf[1024 / 4 + 32] = {0};
constexpr uint32_t host_command_size = (sizeof (struct maple::host_command<device_request::data_fields>));
constexpr uint32_t command_response_size = align_32byte((sizeof (struct maple::command_response<device_status::data_fields>)));
static uint32_t * command_buf;
static uint32_t * receive_buf;
uint32_t _command_buf[host_command_size * 4 + 32] = {0};
uint32_t _receive_buf[command_response_size * 4 + 32] = {0};
struct port_state {
bool controller_connected;
};
static port_state state[4] = {0};
void do_get_condition(uint32_t port)
{
uint32_t destination_port;
uint32_t destination_ap;
switch (port) {
case 0:
destination_port = host_instruction::port_select::a;
destination_ap = ap::de::device | ap::port_select::a;
break;
case 1:
destination_port = host_instruction::port_select::b;
destination_ap = ap::de::device | ap::port_select::b;
break;
case 2:
destination_port = host_instruction::port_select::c;
destination_ap = ap::de::device | ap::port_select::c;
break;
case 3:
destination_port = host_instruction::port_select::d;
destination_ap = ap::de::device | ap::port_select::d;
break;
default:
return;
}
maple::init_get_condition(command_buf, receive_buf,
destination_port,
destination_ap,
std::byteswap(function_type::controller));
maple::dma_start(command_buf);
using response_type = struct maple::command_response<data_transfer::data_fields<struct ft0::data_transfer::data_format>>;
auto response = reinterpret_cast<response_type *>(receive_buf);
auto& bus_data = response->bus_data;
auto& data_fields = response->bus_data.data_fields;
if (bus_data.command_code != data_transfer::command_code) {
return;
}
if ((data_fields.function_type & std::byteswap(function_type::controller)) == 0) {
return;
}
state[port].controller_connected = 1;
bool a = data_fields.data.digital_button & ft0::data_transfer::digital_button::a;
if (a == 0) {
serial::string("port ");
serial::integer<uint8_t>(port);
serial::string(" `a` press ");
serial::integer<uint8_t>(a);
}
}
void do_device_request()
{
using response_type = struct maple::command_response<device_status::data_fields>;
constexpr uint32_t response_size = align_32byte(sizeof (response_type));
maple::init_host_command_all_ports(command_buf, receive_buf,
device_request::command_code,
(sizeof (device_request::data_fields)), // command_data_size
(sizeof (device_status::data_fields))); // response_data_size
maple::dma_start(command_buf);
for (uint8_t port = 0; port < 4; port++) {
auto response = reinterpret_cast<response_type *>(&receive_buf[response_size * port / 4]);
auto& bus_data = response->bus_data;
auto& data_fields = response->bus_data.data_fields;
if (bus_data.command_code != device_status::command_code) {
// the controller is disconnected
state[port].controller_connected = 0;
} else {
if ((data_fields.device_id.ft & std::byteswap(function_type::controller)) != 0) {
//serial::string("is controller: ");
//serial::integer<uint8_t>(port);
do_get_condition(port);
}
}
}
}
void main()
{
uint32_t * command_buf = align_32byte(_command_buf);
uint32_t * receive_buf = align_32byte(_receive_buf);
command_buf = align_32byte(_command_buf);
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<uint8_t *>(receive_buf);
for (uint8_t port = 0; port < 4; port++) {
serial::string("port ");
serial::integer<uint8_t>(port);
for (uint32_t i = 0; i < command_response_size; i++) {
serial::integer<uint8_t>(buf[port * command_response_size + i]);
}
serial::character('\n');
}
while (1);
while (1) {
v_sync_out();
v_sync_in();
do_device_request();
};
}

View File

@ -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<device_request::data_fields>));
constexpr uint32_t command_response_size = align_32byte((sizeof (struct maple::command_response<device_status::data_fields>)));
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<uint8_t *>(receive_buf);
for (uint8_t port = 0; port < 4; port++) {
serial::string("port ");
serial::integer<uint8_t>(port);
for (uint32_t i = 0; i < command_response_size; i++) {
serial::integer<uint8_t>(buf[port * command_response_size + i]);
}
serial::character('\n');
}
while (1);
}

View File

@ -76,7 +76,8 @@ void init_device_request(uint32_t * buf, uint32_t * receive_buf,
void init_get_condition(uint32_t * buf, uint32_t * receive_buf,
uint32_t destination_port,
uint8_t destination_ap)
uint8_t destination_ap,
uint32_t function_type)
{
init_host_command(buf, receive_buf,
destination_port,
@ -87,7 +88,7 @@ void init_get_condition(uint32_t * buf, uint32_t * receive_buf,
auto& fields = host_command->bus_data.data_fields;
// controller function type
fields.function_type = std::byteswap(function_type::controller);
fields.function_type = function_type;
}
void init_block_write(uint32_t * command_buf, uint32_t * receive_buf,

View File

@ -42,7 +42,8 @@ void init_device_request(uint32_t * buf, uint32_t * receive_buf,
void init_get_condition(uint32_t * buf, uint32_t * receive_buf,
uint32_t destination_port,
uint8_t destination_ap);
uint8_t destination_ap,
uint32_t function_type);
void init_block_write(uint32_t * buf, uint32_t * receive_buf,
uint32_t destination_port,

View File

@ -1,5 +1,11 @@
#include <cstdint>
struct device_id {
uint32_t ft;
uint32_t fd[3];
};
static_assert((sizeof (struct device_id)) == 16);
namespace device_request {
constexpr uint32_t command_code = 0x1;
@ -32,7 +38,7 @@ namespace device_status {
constexpr uint32_t command_code = 0x5;
struct data_fields {
uint8_t device_id[16];
struct device_id device_id;
uint8_t destination_code;
uint8_t connection_direction;
uint8_t product_name[30];
@ -49,7 +55,7 @@ namespace device_all_status {
template <typename T>
struct data_fields {
uint8_t device_id[16];
struct device_id device_id;
uint8_t destination_code;
uint8_t connection_direction;
uint8_t product_name[30];
@ -229,3 +235,4 @@ namespace ar_error {
static_assert((sizeof (struct data_fields)) == 4);
}

View File

@ -37,6 +37,8 @@ def command_namespace(namespace: CommandNamespace,
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:
@ -155,6 +157,11 @@ def new_aggregator():
def headers():
yield "#include <cstdint>"
yield ""
yield "struct device_id {"
yield "uint32_t ft;"
yield "uint32_t fd[3];"
yield "};"
yield "static_assert((sizeof (struct device_id)) == 16);"
input_file = sys.argv[1]
rows = read_input(input_file)