viacuda: improve READ_MCU_MEM & WRITE_MCU_MEM emulation.

68k boot code in ROM uses those commands for applying patches
to Cuda and getting Cuda firmware version. This commit
implements as much as needed for boot code to work.
This commit is contained in:
Maxim Poliakovski 2021-10-17 22:31:54 +02:00
parent f194887d34
commit 7daf4aa317
2 changed files with 50 additions and 7 deletions

View File

@ -195,7 +195,7 @@ void ViaCuda::write(uint8_t new_state) {
this->in_buf[this->in_count++] = this->via_regs[VIA_SR];
assert_sr_int(); /* tell the system we've read the data */
} else {
LOG_F(WARNING, "Cuda input buffer exhausted!");
LOG_F(WARNING, "Cuda input buffer too small. Truncating data!");
}
} else { /* data transfer: Cuda --> Host */
(this->*out_handler)();
@ -320,7 +320,8 @@ void ViaCuda::process_adb_command(uint8_t cmd_byte, int data_count) {
}
void ViaCuda::pseudo_command(int cmd, int data_count) {
uint16_t addr;
uint16_t addr;
int i;
switch (cmd) {
case CUDA_START_STOP_AUTOPOLL:
@ -331,6 +332,36 @@ void ViaCuda::pseudo_command(int cmd, int data_count) {
}
response_header(CUDA_PKT_PSEUDO, 0);
break;
case CUDA_READ_MCU_MEM:
addr = READ_WORD_BE_A(&this->in_buf[2]);
response_header(CUDA_PKT_PSEUDO, 0);
// if starting address is within PRAM region
// prepare to transfer PRAM content, othwesise we will send zeroes
if (addr >= CUDA_PRAM_START && addr <= CUDA_PRAM_END) {
this->cur_pram_addr = addr - CUDA_PRAM_START;
this->next_out_handler = &ViaCuda::pram_out_handler;
} else if (addr >= CUDA_ROM_START) {
// HACK: Cuda ROM dump requsted so let's partially fake it
this->out_buf[3] = 0; // empty copyright string
WRITE_WORD_BE_A(&this->out_buf[4], 0x0019U);
WRITE_WORD_BE_A(&this->out_buf[6], CUDA_FW_VERSION_MAJOR);
WRITE_WORD_BE_A(&this->out_buf[8], CUDA_FW_VERSION_MINOR);
this->out_count += 7;
}
this->is_open_ended = true;
break;
case CUDA_WRITE_MCU_MEM:
addr = READ_WORD_BE_A(&this->in_buf[2]);
// if addr is inside PRAM, update PRAM with data from in_buf
// otherwise, ignore data in in_buf
if (addr >= CUDA_PRAM_START && addr <= CUDA_PRAM_END) {
for (i = 0; i < this->in_count - 4; i++) {
this->pram_obj->write_byte((addr - CUDA_PRAM_START + i) & 0xFF,
this->in_buf[4+i]);
}
}
response_header(CUDA_PKT_PSEUDO, 0);
break;
case CUDA_READ_PRAM:
addr = READ_WORD_BE_A(&this->in_buf[2]);
if (addr <= 0xFF) {
@ -346,9 +377,11 @@ void ViaCuda::pseudo_command(int cmd, int data_count) {
case CUDA_WRITE_PRAM:
addr = READ_WORD_BE_A(&this->in_buf[2]);
if (addr <= 0xFF) {
// TODO: implement open-ended write transaction properly
// transfer data from in_buf to PRAM
for (i = 0; i < this->in_count - 4; i++) {
this->pram_obj->write_byte((addr + i) & 0xFF, this->in_buf[4+i]);
}
response_header(CUDA_PKT_PSEUDO, 0);
this->pram_obj->write_byte(addr, this->in_buf[4]);
} else {
error_response(CUDA_ERR_BAD_PAR);
}

View File

@ -90,7 +90,9 @@ enum {
/** Cuda pseudo commands. */
enum {
CUDA_START_STOP_AUTOPOLL = 0x01, /* start/stop device auto-polling */
CUDA_READ_MCU_MEM = 0x02, /* read internal Cuda memory */
CUDA_READ_PRAM = 0x07, /* read parameter RAM */
CUDA_WRITE_MCU_MEM = 0x08, /* write internal Cuda memory */
CUDA_WRITE_PRAM = 0x0C, /* write parameter RAM */
CUDA_SET_AUTOPOLL_RATE = 0x14, /* set auto-polling rate */
CUDA_GET_AUTOPOLL_RATE = 0x16, /* get auto-polling rate */
@ -108,6 +110,14 @@ enum {
CUDA_ERR_I2C = 5 /* invalid I2C data or no acknowledge */
};
/** PRAM addresses within Cuda's internal memory */
#define CUDA_PRAM_START 0x100 // starting address of PRAM
#define CUDA_PRAM_END 0x1FF // last byte of PRAM
#define CUDA_ROM_START 0xF00 // starting address of ROM containing Cuda FW
/** Latest Cuda Firmware version. */
#define CUDA_FW_VERSION_MAJOR 0x0002
#define CUDA_FW_VERSION_MINOR 0x0029
class ViaCuda : public HWComponent, public I2CBus {
public:
@ -135,9 +145,9 @@ private:
int32_t out_pos;
uint8_t poll_rate;
bool is_open_ended;
uint8_t curr_i2c_addr;
uint8_t cur_pram_addr;
bool is_open_ended; // true if current transaction is open-ended
uint8_t curr_i2c_addr; // current I2C address
uint8_t cur_pram_addr; // current PRAM address, range 0...FF
void (ViaCuda::*out_handler)(void);
void (ViaCuda::*next_out_handler)(void);