diff --git a/devices/viacuda.cpp b/devices/viacuda.cpp index 5cb9f5b..6bc313b 100644 --- a/devices/viacuda.cpp +++ b/devices/viacuda.cpp @@ -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); } diff --git a/devices/viacuda.h b/devices/viacuda.h index 00a0aea..ef20f5a 100644 --- a/devices/viacuda.h +++ b/devices/viacuda.h @@ -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);