maple: add maple_bus_commands.h

This commit is contained in:
Zack Buhman 2023-12-09 16:14:21 +08:00
parent ec09e98757
commit c8ed8cdf9e
7 changed files with 441 additions and 0 deletions

210
maple_bus_commands.h Normal file
View File

@ -0,0 +1,210 @@
#include <stdint.h>
#include <stddef.h>
#include "type.h"
namespace device_request {
constexpr uint32_t command_code = 0x1;
}
namespace all_status_request {
constexpr uint32_t command_code = 0x2;
}
namespace device_reset {
constexpr uint32_t command_code = 0x3;
}
namespace device_kill {
constexpr uint32_t command_code = 0x4;
}
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;
template <int N>
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];
uint8_t free_device_status[N];
};
static_assert((sizeof (struct data_fields<0>)) == 112);
}
namespace device_reply {
constexpr uint32_t command_code = 0x7;
}
namespace data_transfer {
constexpr uint32_t command_code = 0x8;
template <int N>
struct data_fields {
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;
template <int N>
struct data_fields {
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;
template <int N>
struct data_fields {
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;
template <int N>
struct data_fields {
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;
template <int N>
struct data_fields {
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;
}
namespace command_unknown {
constexpr uint32_t command_code = 0xfd;
}
namespace transmit_again {
constexpr uint32_t command_code = 0xfc;
}
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);
}

160
regs/gen/maple_commands.py Normal file
View File

@ -0,0 +1,160 @@
from dataclasses import dataclass
from typing import Union
import sys
from sh7091 import read_input
from sh7091 import headers
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]]]):
yield f"namespace {namespace.name} {{"
yield f"constexpr uint32_t command_code = {hex(namespace.command_code)};"
if namespace.data_size == (0, None):
assert data_fields == []
# do nothing
else:
length, variable = namespace.data_size
yield ""
if variable is not None:
assert variable.lower() == "n"
yield "template <int N>"
yield "struct data_fields {"
for field_name, field_size in data_fields:
const, var = field_size
if var is None:
yield f"uint8_t {field_name}[{const}];"
elif const == 0:
assert var == "n"
yield f"uint8_t {field_name}[{var.upper()}];"
else:
yield f"uint8_t {field_name}[{const} + {var.upper()}];"
yield "};"
yield ""
if variable is not None:
assert variable == "n"
yield f"static_assert((sizeof (struct data_fields<0>)) == {length});"
else:
yield f"static_assert((sizeof (struct data_fields)) == {length});"
yield "}"
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
input_file = sys.argv[1]
rows = read_input(input_file)
process = new_aggregator()
render, out = renderer()
render(headers())
for namespace, data_fields in process(rows):
render(command_namespace(namespace, data_fields))
sys.stdout.write(out.getvalue())

View File

@ -0,0 +1,71 @@
"name","issuing_right","command_code","data_size","data_field","data_field_size"
"device_request","host","0x01","0x00",,
,,,,,
"all_status_request","host","0x02","0x00",,
,,,,,
"device_reset","host","0x03","0x00",,
,,,,,
"device_kill","host","0x04","0x00",,
,,,,,
"device_status","peripheral","0x05","0x1c","device_id",16
"device_status",,,,"destination_code",1
"device_status",,,,"connection_direction",1
"device_status",,,,"product_name",30
"device_status",,,,"license",60
"device_status",,,,"low_consumption_standby_current",2
"device_status",,,,"maximum_current_consumption",2
,,,,,
"device_all_status","peripheral","0x06","0x1c+n/4","device_id",16
"device_all_status",,,,"destination_code",1
"device_all_status",,,,"connection_direction",1
"device_all_status",,,,"product_name",30
"device_all_status",,,,"license",60
"device_all_status",,,,"low_consumption_standby_current",2
"device_all_status",,,,"maximum_current_consumption",2
"device_all_status",,,,"free_device_status","n"
,,,,,
"device_reply","peripheral","0x07","0x00",,
,,,,,
"data_transfer","peripheral","0x08","n/4","data","n"
,,,,,
"get_condition","host","0x09","0x01","function_type",4
,,,,,
"get_media_info","host","0x0a","0x02","function_type",4
"get_media_info",,,,"pt",4
,,,,,
"block_read","host","0x0b","0x02","function_type",4
"block_read",,,,"pt",1
"block_read",,,,"phase",1
"block_read",,,,"block_no",2
,,,,,
"block_write","host","0x0c","0x02+n/4","function_type",4
"block_write",,,,"pt",1
"block_write",,,,"phase",1
"block_write",,,,"block_no",2
"block_write",,,,"written_data","n"
,,,,,
"get_last_error","host","0x0d","0x02","function_type",4
"get_last_error",,,,"pt",1
"get_last_error",,,,"phase",1
"get_last_error",,,,"block_no",2
,,,,,
"set_condition","host","0x0e","0x01+n/4","function_type",4
"set_condition",,,,"write_in_data","n"
,,,,,
"ft4_control","host","0x0f","0x01+n/4","function_type",4
"ft4_control",,,,"ft4_data","n"
,,,,,
"ar_control","host","0x10","0x01+n/4","function_type",4
"ar_control",,,,"data","n"
,,,,,
"function_type_unknown","peripheral","0xfe","0x00",,
,,,,,
"command_unknown","peripheral","0xfd","0x00",,
,,,,,
"transmit_again","host, peripheral","0xfc","0x00",,
,,,,,
"file_error","peripheral","0xfb","0x01","function_error_code",4
,,,,,
"lcd_error","peripheral","0xfa","0x01","function_error_code",4
,,,,,
"ar_error","peripheral","0xf9","0x01","function_error_code",4
1 name issuing_right command_code data_size data_field data_field_size
2 device_request host 0x01 0x00
3
4 all_status_request host 0x02 0x00
5
6 device_reset host 0x03 0x00
7
8 device_kill host 0x04 0x00
9
10 device_status peripheral 0x05 0x1c device_id 16
11 device_status destination_code 1
12 device_status connection_direction 1
13 device_status product_name 30
14 device_status license 60
15 device_status low_consumption_standby_current 2
16 device_status maximum_current_consumption 2
17
18 device_all_status peripheral 0x06 0x1c+n/4 device_id 16
19 device_all_status destination_code 1
20 device_all_status connection_direction 1
21 device_all_status product_name 30
22 device_all_status license 60
23 device_all_status low_consumption_standby_current 2
24 device_all_status maximum_current_consumption 2
25 device_all_status free_device_status n
26
27 device_reply peripheral 0x07 0x00
28
29 data_transfer peripheral 0x08 n/4 data n
30
31 get_condition host 0x09 0x01 function_type 4
32
33 get_media_info host 0x0a 0x02 function_type 4
34 get_media_info pt 4
35
36 block_read host 0x0b 0x02 function_type 4
37 block_read pt 1
38 block_read phase 1
39 block_read block_no 2
40
41 block_write host 0x0c 0x02+n/4 function_type 4
42 block_write pt 1
43 block_write phase 1
44 block_write block_no 2
45 block_write written_data n
46
47 get_last_error host 0x0d 0x02 function_type 4
48 get_last_error pt 1
49 get_last_error phase 1
50 get_last_error block_no 2
51
52 set_condition host 0x0e 0x01+n/4 function_type 4
53 set_condition write_in_data n
54
55 ft4_control host 0x0f 0x01+n/4 function_type 4
56 ft4_control ft4_data n
57
58 ar_control host 0x10 0x01+n/4 function_type 4
59 ar_control data n
60
61 function_type_unknown peripheral 0xfe 0x00
62
63 command_unknown peripheral 0xfd 0x00
64
65 transmit_again host, peripheral 0xfc 0x00
66
67 file_error peripheral 0xfb 0x01 function_error_code 4
68
69 lcd_error peripheral 0xfa 0x01 function_error_code 4
70
71 ar_error peripheral 0xf9 0x01 function_error_code 4

BIN
regs/maple_bus_commands.ods Normal file

Binary file not shown.

BIN
regs/maple_bus_ft0.ods Normal file

Binary file not shown.

BIN
regs/maple_bus_ft6.ods Normal file

Binary file not shown.

Binary file not shown.