Compare commits

...

2 Commits

20 changed files with 1982 additions and 1216 deletions

View File

@ -1,6 +1,8 @@
.global _illslot
_illslot:
trapa #12
rts
mova test,r0
nop
mova test,r0
test: .long 0x12345678

View File

@ -11,9 +11,11 @@ void vbr100()
{
serial::string("vbr100\n");
serial::string("expevt ");
serial::integer(sh7091.CCN.EXPEVT);
serial::integer<uint16_t>(sh7091.CCN.EXPEVT);
serial::string("intevt ");
serial::integer(sh7091.CCN.INTEVT);
serial::integer<uint16_t>(sh7091.CCN.INTEVT);
serial::string("tra ");
serial::integer<uint16_t>(sh7091.CCN.TRA);
uint32_t spc;
uint32_t ssr;
asm volatile ("stc spc,%0"
@ -42,9 +44,53 @@ void vbr600()
while (1);
}
__attribute__ ((interrupt_handler))
void dbr();
void dbr()
{
serial::string("dbr\n");
serial::string("expevt ");
serial::integer<uint16_t>(sh7091.CCN.EXPEVT);
serial::string("intevt ");
serial::integer<uint16_t>(sh7091.CCN.INTEVT);
serial::string("tra ");
serial::integer<uint16_t>(sh7091.CCN.TRA);
uint32_t spc;
uint32_t ssr;
asm volatile ("stc spc,%0" : "=r" (spc) );
asm volatile ("stc ssr,%0" : "=r" (ssr) );
serial::string("spc ");
serial::integer(spc);
serial::string("ssr ");
serial::integer(ssr);
uint32_t sr;
asm volatile ("stc sr,%0" : "=r" (sr) );
serial::string("sr ");
serial::integer(sr);
return;
}
int do_stuff(int a, int b)
{
serial::string("do_stuff\n");
asm volatile ("nop;");
return a + b;
}
extern "C" uint32_t * illslot(void);
void main()
{
serial::string("main\n");
for (int i = 0; i < 10000000; i++) {
asm volatile ("nop;");
}
//serial::init(0);
uint32_t vbr = reinterpret_cast<uint32_t>(&__vbr_link_start) - 0x100;
system.IML2NRM = 0;
@ -83,24 +129,64 @@ void main()
serial::string("sr ");
serial::integer<uint32_t>(sr);
sr = sr & (~(1 << 28)); // BL
sr &= ~sh::sr::bl; // BL
sr |= sh::sr::imask(15); // imask
asm volatile ("ldc %0, sr"
serial::string("sr ");
serial::integer<uint32_t>(sr);
asm volatile ("ldc %0,sr"
:
: "r" (sr));
/*
uint32_t vbr2;
asm volatile ("stc vbr,%0"
: "=r" (vbr2));
*/
serial::string("vbr ");
serial::integer<uint32_t>(vbr);
//serial::integer<uint32_t>(vbr2);
serial::string("vbr100 ");
serial::integer<uint32_t>(reinterpret_cast<uint32_t>(&vbr100));
uint32_t * test = illslot();
serial::integer<uint32_t>(*test);
(void)dbr;
uint32_t dbr_address = reinterpret_cast<uint32_t>(&dbr);
asm volatile ("ldc %0,dbr"
:
: "r" (dbr_address));
serial::string("dbr ");
serial::integer<uint32_t>(dbr_address);
while (1);
sh7091.UBC.BARA = reinterpret_cast<uint32_t>(&do_stuff);
sh7091.CCN.BASRA = 0;
sh7091.UBC.BAMRA
= ubc::bamra::bama::all_bara_bits_are_included_in_break_conditions
| ubc::bamra::basma::no_basra_bits_are_included_in_break_conditions
;
sh7091.UBC.BBRA
= ubc::bbra::sza::operand_size_is_not_included_in_break_conditions
| ubc::bbra::ida::instruction_access_cycle_is_used_as_break_condition
| ubc::bbra::rwa::read_cycle_or_write_cycle_is_used_as_break_condition
;
sh7091.UBC.BRCR
= ubc::brcr::pcba::channel_a_pc_break_is_effected_before_instruction_execution
| ubc::brcr::ubde::user_break_debug_function_is_used
;
serial::string("basra ");
serial::integer(sh7091.CCN.BASRA);
serial::string("bara ");
serial::integer(sh7091.UBC.BARA);
serial::string("bamra ");
serial::integer(sh7091.UBC.BAMRA);
serial::string("bbra ");
serial::integer(sh7091.UBC.BBRA);
serial::string("brcr ");
serial::integer(sh7091.UBC.BRCR);
int res = do_stuff(1, 2);
(void)res;
/*
uint32_t * test = illslot();
serial::string("illslot\n");
serial::integer<uint32_t>(*test);
*/
serial::string("return\n");
//while (1);
}

View File

@ -7,15 +7,15 @@
void main()
{
serial::init(0);
//serial::init(0);
uint32_t send_buf[1024] __attribute__((aligned(32)));
uint32_t recv_buf[1024] __attribute__((aligned(32)));
uint8_t send_buf[1024] __attribute__((aligned(32)));
uint8_t recv_buf[1024] __attribute__((aligned(32)));
using command_type = maple::device_request;
using response_type = maple::device_status;
auto writer = maple::host_command_writer(send_buf, recv_buf);
auto writer = maple::host_command_writer<>(send_buf, recv_buf);
auto [host_command, host_response]
= writer.append_command_all_ports<command_type, response_type>();
@ -47,5 +47,5 @@ void main()
}
}
while (1);
//while (1);
}

View File

@ -33,8 +33,8 @@ inline void copy(T * dst, const T * src, const int32_t n) noexcept
static uint8_t * framebuffer[2];
static char textbuffer[2][4 * 8];
static uint32_t send_buf[1024 / 4] __attribute__((aligned(32)));
static uint32_t recv_buf[1024 / 4] __attribute__((aligned(32)));
static uint8_t send_buf[1024] __attribute__((aligned(32)));
static uint8_t recv_buf[1024] __attribute__((aligned(32)));
struct serial_error_counter {
uint32_t brk;
@ -200,15 +200,8 @@ void send_device_request()
void send_raw(struct serial_load::maple_poll_state& state)
{
for (int i = 0; i < 1024; i++) {
((uint8_t*)&__recv_buf)[i] = 0xee;
}
maple::dma_start(&__send_buf, state.send_length,
&__recv_buf, state.recv_length);
/*
maple::dma_start((uint32_t*)0xac000020, state.send_length,
(uint32_t*)0xac002020, state.recv_length);
*/
maple::dma_start(reinterpret_cast<uint8_t *>(&__send_buf), state.send_length,
reinterpret_cast<uint8_t *>(&__recv_buf), state.recv_length);
}
void handle_maple(struct serial_load::maple_poll_state& state)

2
ip.lds
View File

@ -99,4 +99,4 @@ __vbr_load_end = 0;
INCLUDE "addresses.lds"
__send_buf = 0xac000020;
__recv_buf = 0xac002020;
__recv_buf = 0xac004020;

View File

@ -75,4 +75,4 @@ INCLUDE "addresses.lds"
__stack_end = 0x8c00f000;
__send_buf = 0xac000020;
__recv_buf = 0xac002020;
__recv_buf = 0xac004000;

View File

@ -107,12 +107,10 @@ uint32_t init_block_write(uint32_t * command_buf, uint32_t * receive_buf,
}
*/
static inline void _dma_start(const uint32_t * command_buf)
static inline void _dma_start(const uint8_t * command_buf)
{
using namespace dmac;
//command_buf = reinterpret_cast<uint32_t *>(reinterpret_cast<uint32_t>(command_buf) | 0xa000'0000);
sh7091.DMAC.DMAOR = dmaor::ddt::on_demand_data_transfer_mode /* on-demand data transfer mode */
| dmaor::pr::ch2_ch0_ch1_ch3 /* priority mode; CH2 > CH0 > CH1 > CH3 */
| dmaor::dme::operation_enabled_on_all_channels; /* DMAC master enable */
@ -161,9 +159,9 @@ bool dma_poll_complete()
return complete;
}
void dma_start(const uint32_t * send_buf,
void dma_start(uint8_t const * const send_buf,
const uint32_t send_size,
const uint32_t * recv_buf,
uint8_t * const recv_buf,
const uint32_t recv_size
)
{
@ -171,7 +169,7 @@ void dma_start(const uint32_t * send_buf,
for (uint32_t i = 0; i < align_32byte(send_size) / 32; i++) {
asm volatile ("ocbwb @%0"
: // output
: "r" (reinterpret_cast<uint32_t>(&send_buf[(32 * i) / 4])) // input
: "r" (reinterpret_cast<uint32_t>(&send_buf[32 * i])) // input
);
}
@ -182,7 +180,7 @@ void dma_start(const uint32_t * send_buf,
for (uint32_t i = 0; i < align_32byte(recv_size) / 32; i++) {
asm volatile ("ocbp @%0"
: // output
: "r" (reinterpret_cast<uint32_t>(&recv_buf[(32 * i) / 4])) // input
: "r" (reinterpret_cast<uint32_t>(&recv_buf[32 * i])) // input
);
}
}

View File

@ -38,9 +38,9 @@ void dma_wait_complete();
bool dma_poll_complete();
void dma_start(uint32_t const * const command_buf,
void dma_start(uint8_t const * const command_buf,
const uint32_t command_size,
uint32_t const * const receive_buf,
uint8_t * const receive_buf,
const uint32_t receive_size
);

View File

@ -12,14 +12,15 @@ namespace maple {
template <uint32_t base_address = 0>
struct host_command_writer {
uint32_t * const send_buf;
uint32_t * const recv_buf;
uint8_t * const send_buf;
uint8_t * const recv_buf;
uint32_t send_offset;
uint32_t recv_offset;
uint32_t last_send_offset;
constexpr host_command_writer(uint32_t * const send_buf,
uint32_t * const recv_buf)
: send_buf(send_buf), recv_buf(recv_buf), send_offset(0), recv_offset(0)
constexpr host_command_writer(uint8_t * const send_buf,
uint8_t * const recv_buf)
: send_buf(send_buf), recv_buf(recv_buf), send_offset(0), recv_offset(0), last_send_offset(0)
{ }
template <typename C, typename R>
@ -38,8 +39,8 @@ struct host_command_writer {
static_assert((sizeof (command_type)) % 4 == 0);
static_assert((sizeof (response_type)) % 4 == 0);
auto host_command = reinterpret_cast<command_type *>(&send_buf[send_offset / 4]);
auto host_response = reinterpret_cast<response_type *>(&recv_buf[recv_offset / 4]);
auto host_command = reinterpret_cast<command_type *>(&send_buf[send_offset]);
auto host_response = reinterpret_cast<response_type *>(&recv_buf[recv_offset]);
host_command->host_instruction = (end_flag ? host_instruction::end_flag : 0)
| (host_port_select & host_instruction::port_select::bit_mask)
@ -59,6 +60,7 @@ struct host_command_writer {
host_command->bus_data.source_ap = destination_ap & ap::port_select::bit_mask;
host_command->bus_data.data_size = data_size / 4;
last_send_offset = send_offset;
send_offset += (sizeof (command_type)) + send_trailing;
recv_offset += (sizeof (response_type)) + recv_trailing;
@ -76,6 +78,22 @@ struct host_command_writer {
append_command<C, R>(host_instruction::port_select::d, ap::de::device | ap::port_select::d, true);
return ret;
}
void set_end_flag()
{
using host_command_type = maple::host_command<uint8_t[0]>;
auto host_command = reinterpret_cast<host_command_type *>(&send_buf[last_send_offset]);
host_command->host_instruction |= host_instruction::end_flag;
}
uint32_t reset()
{
const uint32_t old_recv_offset = recv_offset;
// reset writer
send_offset = 0;
recv_offset = 0;
return old_recv_offset;
}
};
}

View File

@ -15,22 +15,26 @@ def aggregate_registers(d):
return dict(aggregated)
def parse_bit_number(s):
assert '-' not in s
assert '-' not in s, s
assert ',' not in s, s
return int(s, 10)
def parse_bit_set(s, split_char):
assert len(list(c for c in s if c == split_char)) == 1
left, right = map(parse_bit_number, s.split(split_char, maxsplit=1))
assert left > right, (left, right)
return left, right
def parse_bit_set(s, split_char, maxsplit):
#assert len(list(c for c in s if c == split_char)) == 1, s
split = list(map(parse_bit_number, s.split(split_char, maxsplit=maxsplit)))
for i in range(len(split) - 1):
left = split[i]
right = split[i+1]
assert left > right, (left, right)
return split
def parse_bit_range(s):
if '-' in s:
left, right = parse_bit_set(s, '-')
left, right = parse_bit_set(s, '-', 1)
return set(range(right, left+1))
elif ',' in s:
left, right = parse_bit_set(s, ',')
return set([right, left])
bits = parse_bit_set(s, ',', -1)
return set(bits)
else:
num = parse_bit_number(s)
return set([num])
@ -124,8 +128,10 @@ def aggregate_all_enums(aggregated):
'''
def mask_from_bits(bits):
h, l = max(bits), min(bits)
mask = 2 ** ((h - l) + 1) - 1
mask = 0
for b in bits:
mask |= 1 << b
mask >>= min(bits)
return mask
def parse_value(value):

View File

@ -293,3 +293,74 @@
"SCIF","SCSPTR2","SPB2DT","0","input_output_data_is_high_level","1",,
,,,,,,,
"SCIF","SCLSR2","ORER","0","overrun_error_occured","1",,
,,,,,,,
"SH","SR",,"30","md","1",,
"SH","SR",,"29","rb","1",,
"SH","SR",,"28","bl","1",,
"SH","SR",,"15","fd","1",,
"SH","SR",,"9","m","1",,
"SH","SR",,"8","q","1",,
"SH","SR",,"7-4","imask",,"0b1111",
"SH","SR",,"1","s","1",,
"SH","SR",,"0","t","1",,
,,,,,,,
"SH","FPSCR",,"21","fr","1",,
"SH","FPSCR",,"20","sz","1",,
"SH","FPSCR",,"19","pr","1",,
"SH","FPSCR",,"18","dn","1",,
"SH","FPSCR","CAUSE","17-12","fpu_error","0b100000",,
"SH","FPSCR","CAUSE","17-12","invalid_operation","0b010000",,
"SH","FPSCR","CAUSE","17-12","division_by_zero","0b001000",,
"SH","FPSCR","CAUSE","17-12","overflow","0b000100",,
"SH","FPSCR","CAUSE","17-12","underflow","0b000010",,
"SH","FPSCR","CAUSE","17-12","inexact","0b000001",,
"SH","FPSCR","ENABLED","11-7","invalid_operation","0b10000",,
"SH","FPSCR","ENABLED","11-7","division_by_zero","0b01000",,
"SH","FPSCR","ENABLED","11-7","overflow","0b00100",,
"SH","FPSCR","ENABLED","11-7","underflow","0b00010",,
"SH","FPSCR","ENABLED","11-7","inexact","0b00001",,
"SH","FPSCR","FLAG","6-2","invalid_operation","0b10000",,
"SH","FPSCR","FLAG","6-2","division_by_zero","0b01000",,
"SH","FPSCR","FLAG","6-2","overflow","0b00100",,
"SH","FPSCR","FLAG","6-2","underflow","0b00010",,
"SH","FPSCR","FLAG","6-2","inexact","0b00001",,
"SH","FPSCR","RM","1-0","round_to_nearest","0b00",,
"SH","FPSCR","RM","1-0","round_to_zero","0b01",,
,,,,,,,
"UBC","BAMRA","BAMA","3,1,0","all_bara_bits_are_included_in_break_conditions","0b0000",,
"UBC","BAMRA","BAMA","3,1,0","lower_10_bits_of_bara_are_not_included_in_break_conditions","0b0001",,
"UBC","BAMRA","BAMA","3,1,0","lower_12_bits_of_bara_are_not_included_in_break_conditions","0b0010",,
"UBC","BAMRA","BAMA","3,1,0","all_bara_bits_are_not_included_in_break_conditions","0b0011",,
"UBC","BAMRA","BAMA","3,1,0","lower_16_bits_of_bara_are_not_included_in_break_conditions","0b1000",,
"UBC","BAMRA","BAMA","3,1,0","lower_20_bits_of_bara_are_not_included_in_break_conditions","0b1001",,
"UBC","BAMRA","BASMA","2","all_basra_bits_are_included_in_break_conditions","0",,
"UBC","BAMRA","BASMA","2","no_basra_bits_are_included_in_break_conditions","1",,
,,,,,,,
"UBC","BBRA","SZA","6,1,0","operand_size_is_not_included_in_break_conditions","0b00",,
"UBC","BBRA","SZA","6,1,0","byte_access_is_used_as_break_condition","0b01",,
"UBC","BBRA","SZA","6,1,0","word_access_is_used_as_break_condition","0b10",,
"UBC","BBRA","SZA","6,1,0","longword_access_is_used_as_break_condition","0b11",,
"UBC","BBRA","SZA","6,1,0","quadword_access_is_used_as_break_condition","0b1000000",,
"UBC","BBRA","IDA","5-4","condition_comparison_is_not_performed","0b00",,
"UBC","BBRA","IDA","5-4","instruction_access_cycle_is_used_as_break_condition","0b01",,
"UBC","BBRA","IDA","5-4","operand_access_cycle_is_used_as_break_condition","0b10",,
"UBC","BBRA","IDA","5-4","instruction_access_cycle_or_operand_access_cycle_is_used_as_break_condition","0b11",,
"UBC","BBRA","RWA","3-2","condition_comparison_is_not_performed","0b00",,
"UBC","BBRA","RWA","3-2","read_cycle_is_used_as_break_condition","0b01",,
"UBC","BBRA","RWA","3-2","write_cycle_is_used_as_break_condition","0b10",,
"UBC","BBRA","RWA","3-2","read_cycle_or_write_cycle_is_used_as_break_condition","0b11",,
,,,,,,,
"UBC","BRCR","CMFA","15","channel_a_break_condition_is_not_matched","0",,
"UBC","BRCR","CMFA","15","channel_a_break_condition_match_has_occured","1",,
"UBC","BRCR","CMFB","14","channel_b_break_condition_is_not_matched","0",,
"UBC","BRCR","CMFB","14","channel_b_break_condition_match_has_occured","1",,
"UBC","BRCR","PCBA","10","channel_a_pc_break_is_effected_before_instruction_execution","0",,
"UBC","BRCR","PCBA","10","channel_a_pc_break_is_effected_after_instruction_execution","1",,
"UBC","BRCR","DBEB","7","data_bus_condition_is_not_included_in_channel_b_conditions","0",,
"UBC","BRCR","DBEB","7","data_bus_condition_is_included_in_channel_b_conditions","1",,
"UBC","BRCR","PCBB","6","channel_b_pc_break_is_effected_before_instruction_execution","0",,
"UBC","BRCR","PCBB","6","channel_b_pc_break_is_effected_after_instruction_execution","1",,
"UBC","BRCR","SEQ","3","channel_a_and_b_comparison_are_performed_as_independent_condition","0",,
"UBC","BRCR","SEQ","3","channel_a_and_b_comparison_are_performed_as_sequential_condition","1",,
"UBC","BRCR","UBDE","0","user_break_debug_function_is_not_used","0",,
"UBC","BRCR","UBDE","0","user_break_debug_function_is_used","1",,

1 block register_name enum_name bits bit_name value mask description
293 SCIF SCSPTR2 SPB2DT 0 input_output_data_is_high_level 1
294
295 SCIF SCLSR2 ORER 0 overrun_error_occured 1
296
297 SH SR 30 md 1
298 SH SR 29 rb 1
299 SH SR 28 bl 1
300 SH SR 15 fd 1
301 SH SR 9 m 1
302 SH SR 8 q 1
303 SH SR 7-4 imask 0b1111
304 SH SR 1 s 1
305 SH SR 0 t 1
306
307 SH FPSCR 21 fr 1
308 SH FPSCR 20 sz 1
309 SH FPSCR 19 pr 1
310 SH FPSCR 18 dn 1
311 SH FPSCR CAUSE 17-12 fpu_error 0b100000
312 SH FPSCR CAUSE 17-12 invalid_operation 0b010000
313 SH FPSCR CAUSE 17-12 division_by_zero 0b001000
314 SH FPSCR CAUSE 17-12 overflow 0b000100
315 SH FPSCR CAUSE 17-12 underflow 0b000010
316 SH FPSCR CAUSE 17-12 inexact 0b000001
317 SH FPSCR ENABLED 11-7 invalid_operation 0b10000
318 SH FPSCR ENABLED 11-7 division_by_zero 0b01000
319 SH FPSCR ENABLED 11-7 overflow 0b00100
320 SH FPSCR ENABLED 11-7 underflow 0b00010
321 SH FPSCR ENABLED 11-7 inexact 0b00001
322 SH FPSCR FLAG 6-2 invalid_operation 0b10000
323 SH FPSCR FLAG 6-2 division_by_zero 0b01000
324 SH FPSCR FLAG 6-2 overflow 0b00100
325 SH FPSCR FLAG 6-2 underflow 0b00010
326 SH FPSCR FLAG 6-2 inexact 0b00001
327 SH FPSCR RM 1-0 round_to_nearest 0b00
328 SH FPSCR RM 1-0 round_to_zero 0b01
329
330 UBC BAMRA BAMA 3,1,0 all_bara_bits_are_included_in_break_conditions 0b0000
331 UBC BAMRA BAMA 3,1,0 lower_10_bits_of_bara_are_not_included_in_break_conditions 0b0001
332 UBC BAMRA BAMA 3,1,0 lower_12_bits_of_bara_are_not_included_in_break_conditions 0b0010
333 UBC BAMRA BAMA 3,1,0 all_bara_bits_are_not_included_in_break_conditions 0b0011
334 UBC BAMRA BAMA 3,1,0 lower_16_bits_of_bara_are_not_included_in_break_conditions 0b1000
335 UBC BAMRA BAMA 3,1,0 lower_20_bits_of_bara_are_not_included_in_break_conditions 0b1001
336 UBC BAMRA BASMA 2 all_basra_bits_are_included_in_break_conditions 0
337 UBC BAMRA BASMA 2 no_basra_bits_are_included_in_break_conditions 1
338
339 UBC BBRA SZA 6,1,0 operand_size_is_not_included_in_break_conditions 0b00
340 UBC BBRA SZA 6,1,0 byte_access_is_used_as_break_condition 0b01
341 UBC BBRA SZA 6,1,0 word_access_is_used_as_break_condition 0b10
342 UBC BBRA SZA 6,1,0 longword_access_is_used_as_break_condition 0b11
343 UBC BBRA SZA 6,1,0 quadword_access_is_used_as_break_condition 0b1000000
344 UBC BBRA IDA 5-4 condition_comparison_is_not_performed 0b00
345 UBC BBRA IDA 5-4 instruction_access_cycle_is_used_as_break_condition 0b01
346 UBC BBRA IDA 5-4 operand_access_cycle_is_used_as_break_condition 0b10
347 UBC BBRA IDA 5-4 instruction_access_cycle_or_operand_access_cycle_is_used_as_break_condition 0b11
348 UBC BBRA RWA 3-2 condition_comparison_is_not_performed 0b00
349 UBC BBRA RWA 3-2 read_cycle_is_used_as_break_condition 0b01
350 UBC BBRA RWA 3-2 write_cycle_is_used_as_break_condition 0b10
351 UBC BBRA RWA 3-2 read_cycle_or_write_cycle_is_used_as_break_condition 0b11
352
353 UBC BRCR CMFA 15 channel_a_break_condition_is_not_matched 0
354 UBC BRCR CMFA 15 channel_a_break_condition_match_has_occured 1
355 UBC BRCR CMFB 14 channel_b_break_condition_is_not_matched 0
356 UBC BRCR CMFB 14 channel_b_break_condition_match_has_occured 1
357 UBC BRCR PCBA 10 channel_a_pc_break_is_effected_before_instruction_execution 0
358 UBC BRCR PCBA 10 channel_a_pc_break_is_effected_after_instruction_execution 1
359 UBC BRCR DBEB 7 data_bus_condition_is_not_included_in_channel_b_conditions 0
360 UBC BRCR DBEB 7 data_bus_condition_is_included_in_channel_b_conditions 1
361 UBC BRCR PCBB 6 channel_b_pc_break_is_effected_before_instruction_execution 0
362 UBC BRCR PCBB 6 channel_b_pc_break_is_effected_after_instruction_execution 1
363 UBC BRCR SEQ 3 channel_a_and_b_comparison_are_performed_as_independent_condition 0
364 UBC BRCR SEQ 3 channel_a_and_b_comparison_are_performed_as_sequential_condition 1
365 UBC BRCR UBDE 0 user_break_debug_function_is_not_used 0
366 UBC BRCR UBDE 0 user_break_debug_function_is_used 1

Binary file not shown.

View File

@ -72,7 +72,6 @@ static void poststart_read()
static void prestart_maple_raw__command()
{
uint32_t dest = reinterpret_cast<uint32_t>(&__send_buf);
//uint32_t dest = 0xac000020;
uint32_t size = state.buf.arg[0];
serial::recv_dma(dest - 1, size + 1);
state.reply_crc.value = 0xffffffff;
@ -82,7 +81,6 @@ static void prestart_maple_raw__command()
static void prestart_maple_raw__response()
{
uint32_t src = reinterpret_cast<uint32_t>(&__recv_buf);
//uint32_t src = 0xac002020;
uint32_t size = state.buf.arg[1];
serial::send_dma(src, size);
state.reply_crc.value = 0xffffffff;

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,12 @@ ttf_%: ttf_%.o
ftdi_%.o: ftdi_%.cpp
$(CXX) $(CFLAGS) $(CXXFLAGS) $(FTDI_CFLAGS) -c $< -o $@
ftdi_%: ftdi_%.o crc32.o
FTDI_OBJ = \
ftdi_transfer.o \
ftdi_maple.o \
crc32.o
ftdi_transfer: $(FTDI_OBJ)
$(CXX) $^ -o $@ $(FTDI_LDFLAGS)
ttf_outline: ttf_outline.o 2d_pack.o

480
tools/ftdi_maple.cpp Normal file
View File

@ -0,0 +1,480 @@
#include <stdint.h>
#include <stdio.h>
#include <bit>
#include "maple/maple_bus_bits.hpp"
#include "maple/maple.hpp"
#include "maple/maple_host_command_writer.hpp"
#include "maple/maple_bus_commands.hpp"
#include "maple/maple_port.hpp"
#include "maple/maple_bus_ft1.hpp"
#include "ftdi_transfer.hpp"
#include "ftdi_maple.hpp"
constexpr uint32_t base_address = 0x0c004020;
constexpr uint32_t maple_buffer_size = 16384;
struct storage_fd {
uint32_t fd;
uint32_t partitions() {
return ((fd >> 24) & 0xff) + 1;
}
uint32_t bytes_per_block() {
return (((fd >> 16) & 0xff) + 1) * 32;
}
uint32_t write_accesses() {
return (fd >> 12) & 0xf;
}
uint32_t read_accesses() {
return (fd >> 8) & 0xf;
}
uint32_t bytes_per_read_access()
{
// divide rounding up
return (bytes_per_block() + (read_accesses() - 1)) / read_accesses();
}
uint32_t bytes_per_write_access()
{
// divide rounding up
return (bytes_per_block() + (write_accesses() - 1)) / write_accesses();
}
};
constexpr int count_left_set_bits(uint32_t n, int stop_bit)
{
int bit_ix = 31;
int count = 0;
while (bit_ix != stop_bit) {
if (n & (1 << 31)) {
count += 1;
}
n <<= 1;
bit_ix -= 1;
}
return count;
}
static_assert(count_left_set_bits(0xe, 1) == 2);
static_assert(count_left_set_bits(0x2, 1) == 0);
consteval int count_trailing_zeros(uint32_t n)
{
int count = 0;
for (int i = 0; i < 32; i++) {
if ((n & 1) != 0)
break;
count += 1;
n >>= 1;
}
return count;
}
static_assert(count_trailing_zeros(0x80) == 7);
static_assert(count_trailing_zeros(0x2) == 1);
void print_storage_function_definition(const uint32_t fd)
{
int partitions = ((fd >> 24) & 0xff) + 1;
int bytes_per_block = (((fd >> 16) & 0xff) + 1) * 32;
int write_accesses = (fd >> 12) & 0xf;
int read_accesses = (fd >> 8) & 0xf;
fprintf(stderr, " storage function definition:\n");
fprintf(stderr, " partitions: %d\n", partitions);
fprintf(stderr, " bytes_per_block: %d\n", bytes_per_block);
fprintf(stderr, " write_accesses: %d\n", write_accesses);
fprintf(stderr, " read_accesses: %d\n", read_accesses);
}
template <typename T>
static inline T be_bswap(const T n)
{
if constexpr (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
return n;
else
return std::byteswap<T>(n);
}
void print_device_id(struct maple::device_id& device_id)
{
fprintf(stderr, " ft: %08x\n", be_bswap<uint32_t>(device_id.ft));
fprintf(stderr, " fd[0]: %08x\n", be_bswap<uint32_t>(device_id.fd[0]));
fprintf(stderr, " fd[1]: %08x\n", be_bswap<uint32_t>(device_id.fd[1]));
fprintf(stderr, " fd[2]: %08x\n", be_bswap<uint32_t>(device_id.fd[2]));
}
void print_media_info(struct ft1::get_media_info_data_transfer::data_format& data)
{
fprintf(stderr, " media_info:\n");
fprintf(stderr, " total_size: %04x\n", data.total_size);
fprintf(stderr, " partition_number: %04x\n", data.partition_number);
fprintf(stderr, " system_area_block_number: %04x\n", data.system_area_block_number);
fprintf(stderr, " fat_area_block_number: %04x\n", data.fat_area_block_number);
fprintf(stderr, " number_of_fat_area_blocks: %04x\n", data.number_of_fat_area_blocks);
fprintf(stderr, " file_information_block_number: %04x\n", data.file_information_block_number);
fprintf(stderr, " number_of_file_information_blocks: %04x\n", data.number_of_file_information_blocks);
fprintf(stderr, " volume_icon: %04x\n", data.volume_icon);
fprintf(stderr, " save_area_block_number: %04x\n", data.save_area_block_number);
fprintf(stderr, " number_of_save_area_blocks: %04x\n", data.number_of_save_area_blocks);
fprintf(stderr, " reserved_for_execution_file: %08x\n", data.reserved_for_execution_file);
}
void send_device_request_all_ports(maple::host_command_writer<base_address>& writer)
{
using command_type = maple::device_request;
using response_type = maple::device_status;
writer.template append_command_all_ports<command_type, response_type>();
}
void send_extension_device_request(maple::host_command_writer<base_address>& writer, uint8_t port, uint8_t lm)
{
uint32_t host_port_select = host_instruction_port_select(port);
uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm;
using command_type = maple::device_request;
using response_type = maple::device_status;
writer.template append_command<command_type, response_type>(host_port_select,
destination_ap,
false); // end_flag
}
void send_get_media_info(maple::host_command_writer<base_address>& writer, uint8_t port, uint8_t lm)
{
uint32_t host_port_select = host_instruction_port_select(port);
uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm;
using command_type = maple::get_media_info;
using response_type = maple::data_transfer<ft1::get_media_info_data_transfer::data_format>;
auto [host_command, host_response] =
writer.template append_command<command_type, response_type>(host_port_select,
destination_ap,
false); // end_flag
host_command->bus_data.data_fields.function_type = be_bswap<uint32_t>(function_type::storage);
host_command->bus_data.data_fields.pt = 0;
}
struct block_read_response {
union responses {
struct maple::file_error::data_fields file_error;
struct maple::data_transfer<ft1::block_read_data_transfer::data_format>::data_fields data_transfer;
};
using data_fields = union responses;
};
void send_block_read(maple::host_command_writer<base_address>& writer, uint8_t port, uint8_t lm, uint32_t recv_trailing, int partition, int phase, int block_number)
{
uint32_t host_port_select = host_instruction_port_select(port);
uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm;
using command_type = maple::block_read;
using response_type = block_read_response;
auto [host_command, host_response] =
writer.template append_command<command_type, response_type>(host_port_select,
destination_ap,
false, // end_flag
0, // send_trailing
recv_trailing // recv_trailing
);
auto& data_fields = host_command->bus_data.data_fields;
data_fields.function_type = be_bswap<uint32_t>(function_type::storage);
data_fields.pt = partition;
data_fields.phase = phase;
data_fields.block_number = be_bswap<uint16_t>(block_number);
}
void do_lm_requests(maple::host_command_writer<base_address>& writer, uint8_t port, uint8_t lm,
void (* func)(maple::host_command_writer<base_address>& writer, uint8_t port, uint8_t lm))
{
uint32_t bit = ap::lm_bus::_0;
for (int i = 0; i < 5; i++) {
if (lm & bit) {
func(writer, port, bit);
}
bit <<= 1;
}
}
int handle_block_read_dump(struct ftdi_context * ftdi,
maple::host_command_writer<base_address>& writer,
struct storage_fd& storage_fd,
FILE * dump)
{
writer.set_end_flag();
int res = do_maple_raw(ftdi,
writer.send_buf, writer.send_offset,
writer.recv_buf, writer.recv_offset);
if (res != 0) {
return -1;
}
using response_type = block_read_response;
using host_response_type = maple::host_response<response_type::data_fields>;
const uint32_t recv_trailing = storage_fd.bytes_per_read_access();
const uint32_t host_response_size = (sizeof (host_response_type)) + recv_trailing;
uint8_t * recv_buf = reinterpret_cast<uint8_t *>(writer.recv_buf);
for (uint32_t offset = 0; offset < writer.recv_offset; offset += host_response_size) {
auto host_response = reinterpret_cast<host_response_type *>(&recv_buf[offset]);
auto& bus_data = host_response->bus_data;
if (bus_data.command_code != maple::data_transfer<uint8_t[0]>::command_code) {
fprintf(stderr, "lm did not reply to block read: %d\n", bus_data.command_code);
auto& file_error = bus_data.data_fields.file_error;
if (bus_data.command_code == maple::file_error::command_code) {
fprintf(stderr, "function error code: %d\n", file_error.function_error_code);
}
return -1;
}
fwrite(bus_data.data_fields.data_transfer.data.block_data,
1,
storage_fd.bytes_per_read_access(),
dump);
}
writer.reset();
return 0;
}
int do_maple_block_read_dump(struct ftdi_context * ftdi,
int port,
int lm,
struct storage_fd& storage_fd,
struct ft1::get_media_info_data_transfer::data_format& media_info) // copy of media_info on the stack
{
uint8_t send_buf[maple_buffer_size];
uint8_t recv_buf[maple_buffer_size];
char filename[256];
snprintf(filename, (sizeof (filename)), "dump_p%dl%d.bin", port, ap_lm_bus_int(lm));
FILE * dump = fopen(filename, "wb");
auto writer = maple::host_command_writer<base_address>(send_buf,
recv_buf);
constexpr int partition = 0;
using response_type = maple::data_transfer<ft1::get_media_info_data_transfer::data_format>;
using host_response_type = maple::host_response<response_type>;
const uint32_t recv_trailing = storage_fd.bytes_per_read_access();
const uint32_t host_response_size = (sizeof (host_response_type)) + recv_trailing;
for (uint16_t block_number = 0; block_number < (media_info.total_size + 1); block_number++) {
for (uint32_t phase = 0; phase < storage_fd.read_accesses(); phase++) {
fprintf(stderr, "maple_block_read: block %d,%d\n", block_number, phase);
send_block_read(writer, port, lm, recv_trailing, partition, phase, block_number);
}
if (writer.recv_offset + host_response_size > maple_buffer_size) {
int res = handle_block_read_dump(ftdi,
writer,
storage_fd,
dump);
if (res != 0) {
return -1;
}
}
}
if (writer.send_offset != 0) {
int res = handle_block_read_dump(ftdi,
writer,
storage_fd,
dump);
if (res != 0) {
return -1;
}
}
fclose(dump);
return 0;
}
int handle_get_media_info_data_transfer_response(struct ftdi_context * ftdi,
maple::host_command_writer<base_address>& writer,
struct storage_fd storage_fd[4][5])
{
writer.set_end_flag();
int res = do_maple_raw(ftdi,
writer.send_buf, writer.send_offset,
writer.recv_buf, writer.recv_offset);
if (res != 0) {
return -1;
}
const uint32_t recv_offset = writer.reset();
using response_type = maple::data_transfer<ft1::get_media_info_data_transfer::data_format>;
using host_response_type = maple::host_response<response_type::data_fields>;
for (uint32_t offset = 0; offset < recv_offset; offset += (sizeof (host_response_type))) {
auto host_response = reinterpret_cast<host_response_type *>(&writer.recv_buf[offset]);
auto& bus_data = host_response->bus_data;
auto& data_fields = bus_data.data_fields;
auto& data = data_fields.data;
if (bus_data.command_code != response_type::command_code) {
fprintf(stderr, " disconnected %02x %02x %02x %02x\n",
bus_data.command_code,
bus_data.destination_ap,
bus_data.source_ap,
bus_data.data_size);
continue;
}
uint32_t port = (bus_data.source_ap & ap::port_select::bit_mask) >> 6;
uint32_t lm_bus = (bus_data.source_ap & ap::lm_bus::bit_mask) >> 0;
fprintf(stderr, "[extension] port: %d ; lm: %05b\n", port, lm_bus);
print_media_info(data);
do_maple_block_read_dump(ftdi,
port,
lm_bus,
storage_fd[port][ap_lm_bus_int(lm_bus)],
data);
}
return 0;
}
int handle_device_status_response_extension(struct ftdi_context * ftdi,
maple::host_command_writer<base_address>& writer,
struct storage_fd storage_fd[4][5])
{
writer.set_end_flag();
int res = do_maple_raw(ftdi,
writer.send_buf, writer.send_offset,
writer.recv_buf, writer.recv_offset);
if (res != 0) {
return -1;
}
const uint32_t recv_offset = writer.reset();
using response_type = maple::device_status;
using host_response_type = maple::host_response<response_type::data_fields>;
for (uint32_t offset = 0; offset < recv_offset; offset += (sizeof (host_response_type))) {
auto host_response = reinterpret_cast<host_response_type *>(&writer.recv_buf[offset]);
auto& bus_data = host_response->bus_data;
auto& data_fields = bus_data.data_fields;
if (bus_data.command_code != response_type::command_code) {
fprintf(stderr, " disconnected %02x %02x %02x %02x\n",
bus_data.command_code,
bus_data.destination_ap,
bus_data.source_ap,
bus_data.data_size);
continue;
}
uint32_t port = (bus_data.source_ap & ap::port_select::bit_mask) >> 6;
uint32_t lm_bus = (bus_data.source_ap & ap::lm_bus::bit_mask) >> 0;
fprintf(stderr, "[extension] port: %d ; lm: %05b\n", port, lm_bus);
print_device_id(data_fields.device_id);
uint32_t ft = be_bswap<uint32_t>(data_fields.device_id.ft);
if (ft & function_type::storage) {
int fd_ix = count_left_set_bits(ft, count_trailing_zeros(function_type::storage));
uint32_t fd = be_bswap<uint32_t>(data_fields.device_id.fd[fd_ix]);
print_storage_function_definition(fd);
storage_fd[port][ap_lm_bus_int(lm_bus)].fd = fd;
send_get_media_info(writer, port, lm_bus);
}
}
return 0;
}
int handle_device_status_response(struct ftdi_context * ftdi,
maple::host_command_writer<base_address>& writer)
{
int res = do_maple_raw(ftdi,
writer.send_buf, writer.send_offset,
writer.recv_buf, writer.recv_offset);
if (res != 0) {
return -1;
}
writer.reset();
using response_type = maple::device_status;
using host_response_type = maple::host_response<response_type::data_fields>;
for (uint8_t port = 0; port < 4; port++) {
auto host_response = reinterpret_cast<host_response_type *>(writer.recv_buf);
auto& bus_data = host_response[port].bus_data;
auto& data_fields = bus_data.data_fields;
fprintf(stderr, "[device] port: %d\n", port);
if (bus_data.command_code != response_type::command_code) {
fprintf(stderr, " disconnected %02x %02x %02x %02x\n",
bus_data.command_code,
bus_data.destination_ap,
bus_data.source_ap,
bus_data.data_size);
} else {
print_device_id(data_fields.device_id);
uint8_t source_ap__lm_bus = bus_data.source_ap & ap::lm_bus::bit_mask;
do_lm_requests(writer, port, source_ap__lm_bus, &send_extension_device_request);
}
}
return 0;
}
int do_maple_storage_dump(struct ftdi_context * ftdi)
{
uint8_t send_buf[maple_buffer_size];
uint8_t recv_buf[maple_buffer_size];
auto writer = maple::host_command_writer<base_address>(send_buf,
recv_buf);
int res;
send_device_request_all_ports(writer);
res = handle_device_status_response(ftdi, writer);
if (res != 0)
return -1;
if (writer.send_offset == 0)
return 0;
struct storage_fd storage_fd[4][5];
res = handle_device_status_response_extension(ftdi, writer, storage_fd);
if (res != 0)
return -1;
if (writer.send_offset == 0)
return 0;
res = handle_get_media_info_data_transfer_response(ftdi, writer, storage_fd);
if (res != 0)
return -1;
if (writer.send_offset == 0)
return 0;
return 0;
}

3
tools/ftdi_maple.hpp Normal file
View File

@ -0,0 +1,3 @@
#pragma once
int do_maple_storage_dump(struct ftdi_context * ftdi);

View File

@ -14,13 +14,8 @@
#include "crc32.h"
#include "serial_protocol.hpp"
#include "maple/maple_bus_bits.hpp"
#include "maple/maple.hpp"
#include "maple/maple_host_command_writer.hpp"
#include "maple/maple_bus_commands.hpp"
#include "maple/maple_port.hpp"
#include "maple/maple_bus_ft1.hpp"
#include "ftdi_transfer.hpp"
#include "ftdi_maple.hpp"
extern "C" int convert_baudrate_UT_export(int baudrate, struct ftdi_context *ftdi,
unsigned short *value, unsigned short *index);
@ -569,12 +564,14 @@ void do_console(struct ftdi_context * ftdi)
{
int res;
ftdi->usb_read_timeout = 1;
uint8_t read_buf[ftdi->readbuffer_chunksize];
while (1) {
res = ftdi_read_data(ftdi, read_buf, ftdi->readbuffer_chunksize);
if (res < 0) {
fprintf(stderr, "ftdi_read_data: %s\n", ftdi_get_error_string(ftdi));
}
assert(res >= 0);
if (res > 0) {
fwrite(read_buf, 1, res, stdout);
fflush(stdout);
@ -582,84 +579,6 @@ void do_console(struct ftdi_context * ftdi)
}
}
constexpr int count_left_set_bits(uint32_t n, int stop_bit)
{
int bit_ix = 31;
int count = 0;
while (bit_ix != stop_bit) {
if (n & (1 << 31)) {
count += 1;
}
n <<= 1;
bit_ix -= 1;
}
return count;
}
static_assert(count_left_set_bits(0xe, 1) == 2);
static_assert(count_left_set_bits(0x2, 1) == 0);
consteval int count_trailing_zeros(uint32_t n)
{
int count = 0;
for (int i = 0; i < 32; i++) {
if ((n & 1) != 0)
break;
count += 1;
n >>= 1;
}
return count;
}
static_assert(count_trailing_zeros(0x80) == 7);
static_assert(count_trailing_zeros(0x2) == 1);
void print_storage_function_definition(const uint32_t fd)
{
int partitions = ((fd >> 24) & 0xff) + 1;
int bytes_per_block = (((fd >> 16) & 0xff) + 1) * 32;
int write_accesses = (fd >> 12) & 0xf;
int read_accesses = (fd >> 8) & 0xf;
fprintf(stderr, " storage function definition:\n");
fprintf(stderr, " partitions: %d\n", partitions);
fprintf(stderr, " bytes_per_block: %d\n", bytes_per_block);
fprintf(stderr, " write_accesses: %d\n", write_accesses);
fprintf(stderr, " read_accesses: %d\n", read_accesses);
}
template <typename T>
static inline T be_bswap(const T n)
{
if constexpr (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
return n;
else
return std::byteswap<T>(n);
}
void print_device_id(struct maple::device_id& device_id)
{
fprintf(stderr, " ft: %08x\n", be_bswap<uint32_t>(device_id.ft));
fprintf(stderr, " fd[0]: %08x\n", be_bswap<uint32_t>(device_id.fd[0]));
fprintf(stderr, " fd[1]: %08x\n", be_bswap<uint32_t>(device_id.fd[1]));
fprintf(stderr, " fd[2]: %08x\n", be_bswap<uint32_t>(device_id.fd[2]));
}
void print_media_info(struct ft1::get_media_info_data_transfer::data_format& data)
{
fprintf(stderr, " media_info:\n");
fprintf(stderr, " total_size: %04x\n", data.total_size);
fprintf(stderr, " partition_number: %04x\n", data.partition_number);
fprintf(stderr, " system_area_block_number: %04x\n", data.system_area_block_number);
fprintf(stderr, " fat_area_block_number: %04x\n", data.fat_area_block_number);
fprintf(stderr, " number_of_fat_area_blocks: %04x\n", data.number_of_fat_area_blocks);
fprintf(stderr, " file_information_block_number: %04x\n", data.file_information_block_number);
fprintf(stderr, " number_of_file_information_blocks: %04x\n", data.number_of_file_information_blocks);
fprintf(stderr, " volume_icon: %04x\n", data.volume_icon);
fprintf(stderr, " save_area_block_number: %04x\n", data.save_area_block_number);
fprintf(stderr, " number_of_save_area_blocks: %04x\n", data.number_of_save_area_blocks);
fprintf(stderr, " reserved_for_execution_file: %08x\n", data.reserved_for_execution_file);
}
int do_maple_raw(struct ftdi_context * ftdi,
uint8_t * send_buf,
uint32_t send_size,
@ -738,399 +657,6 @@ int do_maple_raw(struct ftdi_context * ftdi,
return 0;
}
template <uint32_t base_address>
void send_extension_device_request(maple::host_command_writer<base_address>& writer, uint8_t port, uint8_t lm)
{
uint32_t host_port_select = host_instruction_port_select(port);
uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm;
using command_type = maple::device_request;
using response_type = maple::device_status;
writer.template append_command<command_type, response_type>(host_port_select,
destination_ap,
false); // end_flag
}
template <uint32_t base_address>
void send_get_media_info(maple::host_command_writer<base_address>& writer, uint8_t port, uint8_t lm)
{
uint32_t host_port_select = host_instruction_port_select(port);
uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm;
using command_type = maple::get_media_info;
using response_type = maple::data_transfer<ft1::get_media_info_data_transfer::data_format>;
auto [host_command, host_response] =
writer.template append_command<command_type, response_type>(host_port_select,
destination_ap,
false); // end_flag
host_command->bus_data.data_fields.function_type = be_bswap<uint32_t>(function_type::storage);
host_command->bus_data.data_fields.pt = 0;
}
struct block_read_response {
union responses {
struct maple::file_error::data_fields file_error;
struct maple::data_transfer<ft1::block_read_data_transfer::data_format>::data_fields data_transfer;
};
using data_fields = union responses;
};
template <uint32_t base_address>
void send_block_read(maple::host_command_writer<base_address>& writer, uint8_t port, uint8_t lm, uint32_t recv_trailing, int partition, int phase, int block_number)
{
uint32_t host_port_select = host_instruction_port_select(port);
uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm;
using command_type = maple::block_read;
using response_type = block_read_response;
auto [host_command, host_response] =
writer.template append_command<command_type, response_type>(host_port_select,
destination_ap,
false, // end_flag
0, // send_trailing
recv_trailing // recv_trailing
);
auto& data_fields = host_command->bus_data.data_fields;
data_fields.function_type = be_bswap<uint32_t>(function_type::storage);
data_fields.pt = partition;
data_fields.phase = phase;
data_fields.block_number = be_bswap<uint16_t>(block_number);
}
template <uint32_t base_address>
void do_lm_requests(maple::host_command_writer<base_address>& writer, uint8_t port, uint8_t lm, uint32_t& last_send_offset,
void (* func)(maple::host_command_writer<base_address>& writer, uint8_t port, uint8_t lm))
{
uint32_t bit = ap::lm_bus::_0;
for (int i = 0; i < 5; i++) {
if (lm & bit) {
last_send_offset = writer.send_offset;
func(writer, port, bit);
}
bit <<= 1;
}
}
struct storage_state {
uint32_t fd;
uint32_t partitions() {
return ((fd >> 24) & 0xff) + 1;
}
uint32_t bytes_per_block() {
return (((fd >> 16) & 0xff) + 1) * 32;
}
uint32_t write_accesses() {
return (fd >> 12) & 0xf;
}
uint32_t read_accesses() {
return (fd >> 8) & 0xf;
}
uint32_t bytes_per_read_access()
{
// divide rounding up
return (bytes_per_block() + (read_accesses() - 1)) / read_accesses();
}
uint32_t bytes_per_write_access()
{
// divide rounding up
return (bytes_per_block() + (write_accesses() - 1)) / write_accesses();
}
};
template <uint32_t base_address>
int handle_block_read_dump(struct ftdi_context * ftdi,
maple::host_command_writer<base_address>& writer,
struct storage_state& storage_state,
uint32_t last_send_offset,
FILE * dump)
{
using command_type = maple::block_read;
using host_command_type = maple::host_command<command_type::data_fields>;
uint8_t * send_buf = reinterpret_cast<uint8_t *>(writer.send_buf);
auto host_command = reinterpret_cast<host_command_type *>(&send_buf[last_send_offset]);
host_command->host_instruction |= host_instruction::end_flag;
int res = do_maple_raw(ftdi,
reinterpret_cast<uint8_t *>(writer.send_buf), writer.send_offset,
reinterpret_cast<uint8_t *>(writer.recv_buf), writer.recv_offset);
if (res != 0) {
return -1;
}
using response_type = block_read_response;
using host_response_type = maple::host_response<response_type::data_fields>;
const uint32_t recv_trailing = storage_state.bytes_per_read_access();
const uint32_t host_response_size = (sizeof (host_response_type)) + recv_trailing;
uint8_t * recv_buf = reinterpret_cast<uint8_t *>(writer.recv_buf);
for (uint32_t offset = 0; offset < writer.recv_offset; offset += host_response_size) {
auto host_response = reinterpret_cast<host_response_type *>(&recv_buf[offset]);
auto& bus_data = host_response->bus_data;
if (bus_data.command_code != maple::data_transfer<uint8_t[0]>::command_code) {
fprintf(stderr, "lm did not reply to block read: %d\n", bus_data.command_code);
auto& file_error = bus_data.data_fields.file_error;
if (bus_data.command_code == maple::file_error::command_code) {
fprintf(stderr, "function error code: %d\n", file_error.function_error_code);
}
return -1;
}
fwrite(bus_data.data_fields.data_transfer.data.block_data,
1,
storage_state.bytes_per_read_access(),
dump);
}
writer.send_offset = 0;
writer.recv_offset = 0;
return 0;
}
template <uint32_t base_address>
int do_maple_block_read_dump(struct ftdi_context * ftdi,
int port,
int lm,
struct storage_state& storage_state,
struct ft1::get_media_info_data_transfer::data_format& media_info) // copy of media_info on the stack
{
uint8_t send_buf[8192];
uint8_t recv_buf[8192];
char filename[256];
snprintf(filename, (sizeof (filename)), "dump_p%dl%d.bin", port, ap_lm_bus_int(lm));
FILE * dump = fopen(filename, "wb");
auto writer = maple::host_command_writer<base_address>(reinterpret_cast<uint32_t *>(send_buf),
reinterpret_cast<uint32_t *>(recv_buf));
uint32_t last_send_offset = 0;
constexpr int partition = 0;
using response_type = maple::data_transfer<ft1::get_media_info_data_transfer::data_format>;
using host_response_type = maple::host_response<response_type>;
const uint32_t recv_trailing = storage_state.bytes_per_read_access();
const uint32_t host_response_size = (sizeof (host_response_type)) + recv_trailing;
for (uint16_t block_number = 0; block_number < (media_info.total_size + 1); block_number++) {
for (uint32_t phase = 0; phase < storage_state.read_accesses(); phase++) {
fprintf(stderr, "maple_block_read: block %d,%d\n", block_number, phase);
last_send_offset = writer.send_offset;
send_block_read(writer, port, lm, recv_trailing, partition, phase, block_number);
}
constexpr uint32_t maple_buffer_size = 8192;
if (writer.recv_offset + host_response_size > maple_buffer_size) {
int res = handle_block_read_dump<base_address>(ftdi,
writer,
storage_state,
last_send_offset,
dump);
if (res != 0) {
return -1;
}
}
}
if (writer.send_offset != 0) {
int res = handle_block_read_dump<base_address>(ftdi,
writer,
storage_state,
last_send_offset,
dump);
if (res != 0) {
return -1;
}
}
fclose(dump);
return 0;
}
int do_maple_list(struct ftdi_context * ftdi)
{
constexpr uint32_t base_address = 0xac002020;
uint8_t send_buf[8192];
uint8_t recv_buf[8192];
using command_type = maple::device_request;
using response_type = maple::device_status;
auto writer = maple::host_command_writer<base_address>(reinterpret_cast<uint32_t *>(send_buf),
reinterpret_cast<uint32_t *>(recv_buf));
auto [host_command, host_response]
= writer.append_command_all_ports<command_type, response_type>();
int res = do_maple_raw(ftdi,
send_buf, writer.send_offset,
recv_buf, writer.recv_offset);
if (res != 0) {
return -1;
}
// reset writer
writer.send_offset = 0;
writer.recv_offset = 0;
uint32_t last_send_offset = 0;
for (uint8_t port = 0; port < 4; port++) {
auto& bus_data = host_response[port].bus_data;
auto& data_fields = bus_data.data_fields;
fprintf(stderr, "[device] port: %d\n", port);
if (bus_data.command_code != response_type::command_code) {
fprintf(stderr, " disconnected %02x %02x %02x %02x\n",
bus_data.command_code,
bus_data.destination_ap,
bus_data.source_ap,
bus_data.data_size);
} else {
print_device_id(data_fields.device_id);
uint8_t source_ap__lm_bus = bus_data.source_ap & ap::lm_bus::bit_mask;
do_lm_requests(writer, port, source_ap__lm_bus, last_send_offset, &send_extension_device_request);
}
}
if (writer.send_offset == 0) {
return 0;
}
struct storage_state storage_state[4][5];
{
// rewrite the end flag of the last request
using host_command_type = maple::host_command<uint8_t[0]>;
auto host_command = reinterpret_cast<host_command_type *>(&send_buf[last_send_offset]);
host_command->host_instruction |= host_instruction::end_flag;
int res = do_maple_raw(ftdi,
send_buf, writer.send_offset,
recv_buf, writer.recv_offset);
if (res != 0) {
return -1;
}
const uint32_t recv_offset = writer.recv_offset;
// reset writer
writer.send_offset = 0;
writer.recv_offset = 0;
last_send_offset = 0;
using response_type = maple::device_status;
using host_response_type = maple::host_response<response_type::data_fields>;
for (uint32_t offset = 0; offset < recv_offset; offset += (sizeof (host_response_type))) {
auto host_response = reinterpret_cast<host_response_type *>(&recv_buf[offset]);
auto& bus_data = host_response->bus_data;
auto& data_fields = bus_data.data_fields;
if (bus_data.command_code != response_type::command_code) {
fprintf(stderr, " disconnected %02x %02x %02x %02x\n",
bus_data.command_code,
bus_data.destination_ap,
bus_data.source_ap,
bus_data.data_size);
continue;
}
uint32_t port = (bus_data.source_ap & ap::port_select::bit_mask) >> 6;
uint32_t lm_bus = (bus_data.source_ap & ap::lm_bus::bit_mask) >> 0;
fprintf(stderr, "[extension] port: %d ; lm: %05b\n", port, lm_bus);
print_device_id(data_fields.device_id);
uint32_t ft = be_bswap<uint32_t>(data_fields.device_id.ft);
if (ft & function_type::storage) {
int fd_ix = count_left_set_bits(ft, count_trailing_zeros(function_type::storage));
uint32_t fd = be_bswap<uint32_t>(data_fields.device_id.fd[fd_ix]);
print_storage_function_definition(fd);
storage_state[port][ap_lm_bus_int(lm_bus)].fd = fd;
last_send_offset = writer.send_offset;
send_get_media_info(writer, port, lm_bus);
}
}
}
if (writer.send_offset == 0) {
return 0;
}
{
// rewrite the end flag of the last request
using host_command_type = maple::host_command<uint8_t[0]>;
auto host_command = reinterpret_cast<host_command_type *>(&send_buf[last_send_offset]);
host_command->host_instruction |= host_instruction::end_flag;
int res = do_maple_raw(ftdi,
send_buf, writer.send_offset,
recv_buf, writer.recv_offset);
if (res != 0) {
return -1;
}
const uint32_t recv_offset = writer.recv_offset;
// reset writer
writer.send_offset = 0;
writer.recv_offset = 0;
last_send_offset = 0;
using response_type = maple::data_transfer<ft1::get_media_info_data_transfer::data_format>;
using host_response_type = maple::host_response<response_type::data_fields>;
for (uint32_t offset = 0; offset < recv_offset; offset += (sizeof (host_response_type))) {
auto host_response = reinterpret_cast<host_response_type *>(&recv_buf[offset]);
auto& bus_data = host_response->bus_data;
auto& data_fields = bus_data.data_fields;
auto& data = data_fields.data;
if (bus_data.command_code != response_type::command_code) {
fprintf(stderr, " disconnected %02x %02x %02x %02x\n",
bus_data.command_code,
bus_data.destination_ap,
bus_data.source_ap,
bus_data.data_size);
continue;
}
uint32_t port = (bus_data.source_ap & ap::port_select::bit_mask) >> 6;
uint32_t lm_bus = (bus_data.source_ap & ap::lm_bus::bit_mask) >> 0;
fprintf(stderr, "[extension] port: %d ; lm: %05b\n", port, lm_bus);
print_media_info(data);
using command_type = maple::block_read;
using host_command_type = maple::host_command<command_type>;
using response_type = block_read_response;
using host_response_type = maple::host_response<response_type::data_fields>;
fprintf(stderr, "block read command size %ld\n", (sizeof (host_command_type)));
fprintf(stderr, "block read response size %ld\n", (sizeof (host_response_type)));
do_maple_block_read_dump<base_address>(ftdi,
port,
lm_bus,
storage_state[port][ap_lm_bus_int(lm_bus)],
data);
}
}
return 0;
}
enum struct argument_type {
string,
integer
@ -1150,7 +676,7 @@ struct cli_command commands[] = {
{ "list_baudrates" , 1, (void *)&do_list_baudrates },
{ "show_baudrate_error", 1, (void *)&do_show_baudrate_error },
{ "console" , 0, (void *)&do_console },
{ "maple_list" , 0, (void *)&do_maple_list },
{ "maple_storage_dump" , 0, (void *)&do_maple_storage_dump },
};
constexpr int commands_length = (sizeof (commands)) / (sizeof (commands[0]));
@ -1236,6 +762,8 @@ int handle_command(int argc, const char * argv[], struct ftdi_context * ftdi)
{
fprintf(stderr, "handle command: %s ()\n", commands[i].name);
func_0_arg func = (func_0_arg)commands[i].func;
fprintf(stderr, "%p\n", &do_console);
fprintf(stderr, "%p\n", func);
func_ret = func(ftdi);
}
break;

10
tools/ftdi_transfer.hpp Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include <stdint.h>
#include <ftdi.h>
int do_maple_raw(struct ftdi_context * ftdi,
uint8_t * send_buf,
uint32_t send_size,
uint8_t * recv_buf,
uint32_t recv_size);

View File

@ -13,5 +13,5 @@ set -ex
${SCRIPT_DIR}/ftdi_transfer \
write 0xac010000 "$filename" \
jump 0xac010000
# console
jump 0xac010000 \
console