Cuda improvements

* Implements missing Cuda commands
* Proper One Second Mode handling
* Add Stat Response ADB bit
* Typo fixes

Co-Authored-By: Tim Jarzombek <tim@jarz.net>
This commit is contained in:
dingusdev
2026-03-08 16:26:47 -07:00
parent 16117e6c60
commit 3decd4b9fc
3 changed files with 78 additions and 32 deletions
+1
View File
@@ -38,6 +38,7 @@ enum {
ADB_STAT_SRQ_ACTIVE = 1 << 0,
ADB_STAT_TIMEOUT = 1 << 1,
ADB_STAT_AUTOPOLL = 1 << 6,
ADB_STAT_RESPONSE = 1 << 7,
};
class AdbDevice; // forward declaration to prevent compiler errors
+65 -24
View File
@@ -64,7 +64,7 @@ ViaCuda::ViaCuda() : I2CBus() {
this->_via_ifr = 0; // all flags cleared
this->_via_ier = 0; // all interrupts disabled
// intialize counters/timers
// initialize counters/timers
this->t1_counter = 0xFFFF;
this->t2_counter = 0xFFFF;
@@ -573,11 +573,11 @@ template void ViaCuda::append_data(uint16_t data);
template void ViaCuda::append_data(uint32_t data);
void ViaCuda::process_adb_command() {
uint8_t adb_stat, output_size;
uint8_t adb_stat;
adb_stat = this->adb_bus_obj->process_command(&this->in_buf[1],
this->in_count - 1);
response_header(CUDA_PKT_ADB, adb_stat);
response_header(CUDA_PKT_ADB, adb_stat | ADB_STAT_RESPONSE);
this->append_data(this->adb_bus_obj->get_output_buf(), this->adb_bus_obj->get_output_count());
}
@@ -587,6 +587,14 @@ void ViaCuda::autopoll_handler() {
this->do_post_keyboard_state_events = false;
}
// Don't send async packets while the host has TIP asserted - that
// means an active byte transfer is in progress in either direction.
// The real Cuda is single-threaded and would never enter its idle
// loop during a transaction.
if (!this->old_tip) {
return;
}
uint8_t poll_command = this->autopoll_enabled ? this->adb_bus_obj->poll() : 0;
if (poll_command) {
@@ -595,7 +603,7 @@ void ViaCuda::autopoll_handler() {
}
// prepare autopoll packet
response_header(CUDA_PKT_ADB, ADB_STAT_OK | ADB_STAT_AUTOPOLL);
response_header(CUDA_PKT_ADB, ADB_STAT_OK | ADB_STAT_AUTOPOLL | ADB_STAT_RESPONSE);
this->out_buf[2] = poll_command; // put the proper ADB command
this->append_data(this->adb_bus_obj->get_output_buf(), this->adb_bus_obj->get_output_count());
@@ -607,24 +615,40 @@ void ViaCuda::autopoll_handler() {
schedule_sr_int(USECS_TO_NSECS(30));
} else if (this->one_sec_mode != 0) {
uint32_t this_time = calc_real_time();
// Don't send one-second packets if a command response is pending.
// Unlike autopoll, time packets are not urgent enough to preempt.
if (!this->treq || this->treq_timer_id) {
// ERS: track missed ticks for mode $02/$03 fallback
if (this_time != this->last_time)
this->one_sec_missed = true;
return;
}
if (this_time != this->last_time) {
/*
We'll send a time packet every 4
seconds just in case we get out of
sync.
*/
// ERS: first one-sec packet after mode change is always mode $01;
// missed packets also fall back to mode $01.
bool force_full = this->one_sec_first_pkt || this->one_sec_missed;
bool send_time = !(this->last_time & 3);
if (send_time || this->one_sec_mode < 3) {
if (force_full || send_time || this->one_sec_mode == 1) {
// Mode $01 (or fallback): full header + 4-byte RTC
response_header(CUDA_PKT_PSEUDO, 0);
this->out_buf[2] = CUDA_GET_REAL_TIME;
uint32_t real_time = this_time + this->time_offset;
this->append_data(real_time);
} else if (this->one_sec_mode == 2) {
// Mode $02: header only (no time data)
response_header(CUDA_PKT_PSEUDO, 0);
this->out_buf[2] = CUDA_GET_REAL_TIME;
if (send_time || this->one_sec_mode == 1) {
uint32_t real_time = this_time + this->time_offset;
this->append_data(real_time);
}
} else if (this->one_sec_mode == 3) {
// Mode $03: truncated - attention + type only
one_byte_header(CUDA_PKT_TICK);
}
this->last_time = this_time;
this->one_sec_first_pkt = false;
this->one_sec_missed = false;
this->last_time = this_time;
// assert TREQ
this->via_portb &= ~CUDA_TREQ;
@@ -638,11 +662,13 @@ void ViaCuda::autopoll_handler() {
void ViaCuda::disable_async_packets() {
// disable autopolling of ADB devices
this->autopoll_enabled = false;
this->autopoll_enabled = false;
this->do_post_keyboard_state_events = false;
// disable one second packets
this->one_sec_mode = 0;
this->one_sec_mode = 0;
this->one_sec_first_pkt = true;
this->one_sec_missed = false;
}
void ViaCuda::pseudo_command() {
@@ -672,7 +698,7 @@ void ViaCuda::pseudo_command() {
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
// HACK: Cuda ROM dump requested so let's partially fake it
this->append_data(uint8_t(0)); // empty copyright string
this->append_data(uint16_t(0x0019U));
this->append_data(uint16_t(CUDA_FW_VERSION_MAJOR));
@@ -688,7 +714,7 @@ void ViaCuda::pseudo_command() {
break;
}
case CUDA_WRITE_MCU_MEM:
addr = READ_WORD_BE_A(&this->in_buf[2]);
addr = READ_WORD_BE_U(&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) {
@@ -700,7 +726,7 @@ void ViaCuda::pseudo_command() {
response_header(CUDA_PKT_PSEUDO, 0);
break;
case CUDA_READ_PRAM:
addr = READ_WORD_BE_A(&this->in_buf[2]);
addr = READ_WORD_BE_U(&this->in_buf[2]);
if (addr <= 0xFF) {
response_header(CUDA_PKT_PSEUDO, 0);
// this command is open-ended so set up the corresponding context
@@ -719,7 +745,7 @@ void ViaCuda::pseudo_command() {
break;
}
case CUDA_WRITE_PRAM:
addr = READ_WORD_BE_A(&this->in_buf[2]);
addr = READ_WORD_BE_U(&this->in_buf[2]);
if (addr <= 0xFF) {
// transfer data from in_buf to PRAM
for (i = 0; i < this->in_count - 4; i++) {
@@ -760,6 +786,7 @@ void ViaCuda::pseudo_command() {
case CUDA_ONE_SECOND_MODE:
LOG_F(INFO, "Cuda: One Second Interrupt Mode: %d", this->in_buf[2]);
this->one_sec_mode = this->in_buf[2];
this->one_sec_first_pkt = true;
response_header(CUDA_PKT_PSEUDO, 0);
break;
case CUDA_SET_POWER_MESSAGES:
@@ -795,11 +822,25 @@ void ViaCuda::pseudo_command() {
power_on = false;
power_off_reason = po_shut_down;
break;
case CUDA_SET_POWER_UPTIME: {
uint32_t alarm_time = READ_DWORD_BE_U(&this->in_buf[2]);
LOG_F(INFO, "Cuda: Set Power-Up Alarm to 0x%08X", alarm_time);
response_header(CUDA_PKT_PSEUDO, 0);
break;
}
case CUDA_WARM_START:
LOG_F(INFO, "Cuda: Warm Start - disabling async packets");
this->disable_async_packets();
response_header(CUDA_PKT_PSEUDO, 0);
break;
case CUDA_MONO_STABLE_RESET:
/* really kludge temp code */
LOG_F(INFO, "Cuda: Restart/Shutdown signal sent with command 0x%x!", cmd);
//exit(0);
this->mono_stable = !!this->in_buf[2];
LOG_F(INFO, "Cuda: Monostable Reset %s", this->mono_stable ? "set" : "cleared");
response_header(CUDA_PKT_PSEUDO, 0);
break;
case CUDA_TOGGLE_WAKEUP:
LOG_F(INFO, "Cuda: Toggle Wakeup");
response_header(CUDA_PKT_PSEUDO, 0);
break;
default:
LOG_F(ERROR, "Cuda: unsupported pseudo command 0x%X", cmd);
+12 -8
View File
@@ -67,7 +67,7 @@ enum {
VIA_T2CH = 0x09, // high-order timer 2 counter
VIA_SR = 0x0A, // shift register
VIA_ACR = 0x0B, // auxiliary control register
VIA_PCR = 0x0C, // periheral control register
VIA_PCR = 0x0C, // peripheral control register
VIA_IFR = 0x0D, // interrupt flag register
VIA_IER = 0x0E, // interrupt enable register
VIA_ANH = 0x0F, // input/output register A, no handshake
@@ -135,7 +135,7 @@ enum {
CUDA_ONE_SECOND_MODE = 0x1B, // one second interrupt mode
CUDA_SET_POWER_MESSAGES = 0x21, // set power message flag
CUDA_READ_WRITE_I2C = 0x22, // read/write I2C
CUDE_TOGGLE_WAKEUP = 0x23, // toggle wake-up
CUDA_TOGGLE_WAKEUP = 0x23, // toggle wake-up
CUDA_TIMER_TICKLE = 0x24, // set timer tickle
CUDA_COMB_FMT_I2C = 0x25, // combined format I2C transaction
CUDA_OUT_PB0 = 0x26, // output one bit to Cuda's PB0 line
@@ -190,7 +190,7 @@ private:
uint8_t via_porta = 0;
uint8_t via_ddrb = 0;
uint8_t via_ddra = 0;
uint8_t via_sr;
uint8_t via_sr = 0;
uint8_t via_acr = 0;
uint8_t via_pcr = 0;
@@ -231,18 +231,22 @@ private:
int max_in_count = 0;
uint8_t out_buf[16];
int32_t out_count;
int32_t out_pos;
int32_t out_pos = 0;
uint8_t poll_rate;
uint32_t last_time = 0;
uint32_t time_offset = 0;
std::chrono::time_point<std::chrono::system_clock> mac_epoch;
uint8_t one_sec_mode = 0;
bool file_server;
bool one_sec_first_pkt = true; // ERS: first one-sec pkt always mode $01
bool one_sec_missed = false; // ERS: missed pkt -> fallback to mode $01
bool file_server = false;
bool mono_stable = false;
uint8_t ipl_level = 0;
uint16_t device_mask = 0;
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
bool is_open_ended = false; // true if current transaction is open-ended
uint8_t curr_i2c_addr = 0; // current I2C address
uint8_t cur_pram_addr = 0; // current PRAM address, range 0...FF
void (ViaCuda::*out_handler)(void);
void (ViaCuda::*next_out_handler)(void);