mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-11 05:29:43 +00:00
VIA-CUDA: support for I2C related pseudo commands.
This commit is contained in:
parent
12eada5bb1
commit
cf3f8b6db1
@ -16,12 +16,25 @@ using namespace std;
|
|||||||
|
|
||||||
ViaCuda::ViaCuda()
|
ViaCuda::ViaCuda()
|
||||||
{
|
{
|
||||||
|
/* FIXME: is this the correct
|
||||||
|
VIA initialization? */
|
||||||
this->via_regs[VIA_A] = 0x80;
|
this->via_regs[VIA_A] = 0x80;
|
||||||
this->via_regs[VIA_DIRB] = 0xFF;
|
this->via_regs[VIA_DIRB] = 0xFF;
|
||||||
this->via_regs[VIA_DIRA] = 0xFF;
|
this->via_regs[VIA_DIRA] = 0xFF;
|
||||||
this->via_regs[VIA_T1LL] = 0xFF;
|
this->via_regs[VIA_T1LL] = 0xFF;
|
||||||
this->via_regs[VIA_T1LH] = 0xFF;
|
this->via_regs[VIA_T1LH] = 0xFF;
|
||||||
this->via_regs[VIA_IER] = 0x7F;
|
this->via_regs[VIA_IER] = 0x7F;
|
||||||
|
|
||||||
|
this->cuda_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViaCuda::cuda_init()
|
||||||
|
{
|
||||||
|
this->old_tip = 0;
|
||||||
|
this->old_byteack = 0;
|
||||||
|
this->treq = 1;
|
||||||
|
this->in_count = 0;
|
||||||
|
this->out_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ViaCuda::read(int reg)
|
uint8_t ViaCuda::read(int reg)
|
||||||
@ -34,6 +47,13 @@ uint8_t ViaCuda::read(int reg)
|
|||||||
|
|
||||||
/* reading from some VIA registers triggers special actions */
|
/* reading from some VIA registers triggers special actions */
|
||||||
switch(reg & 0xF) {
|
switch(reg & 0xF) {
|
||||||
|
case VIA_B:
|
||||||
|
res = this->via_regs[VIA_B];
|
||||||
|
break;
|
||||||
|
case VIA_A:
|
||||||
|
case VIA_ANH:
|
||||||
|
cout << "WARNING: read attempt from VIA Port A!" << endl;
|
||||||
|
break;
|
||||||
case VIA_IER:
|
case VIA_IER:
|
||||||
res |= 0x80; /* bit 7 always reads as "1" */
|
res |= 0x80; /* bit 7 always reads as "1" */
|
||||||
}
|
}
|
||||||
@ -45,22 +65,28 @@ void ViaCuda::write(int reg, uint8_t value)
|
|||||||
{
|
{
|
||||||
switch(reg & 0xF) {
|
switch(reg & 0xF) {
|
||||||
case VIA_B:
|
case VIA_B:
|
||||||
cout << "VIA_B = " << hex << (uint32_t)value << endl;
|
this->via_regs[VIA_B] = value;
|
||||||
|
cuda_write(value);
|
||||||
break;
|
break;
|
||||||
case VIA_A:
|
case VIA_A:
|
||||||
cout << "VIA_A = " << hex << (uint32_t)value << endl;
|
case VIA_ANH:
|
||||||
|
cout << "WARNING: write attempt to VIA Port A!" << endl;
|
||||||
break;
|
break;
|
||||||
case VIA_DIRB:
|
case VIA_DIRB:
|
||||||
cout << "VIA_DIRB = " << hex << (uint32_t)value << endl;
|
cout << "VIA_DIRB = " << hex << (uint32_t)value << endl;
|
||||||
|
this->via_regs[VIA_DIRB] = value;
|
||||||
break;
|
break;
|
||||||
case VIA_DIRA:
|
case VIA_DIRA:
|
||||||
cout << "VIA_DIRA = " << hex << (uint32_t)value << endl;
|
cout << "VIA_DIRA = " << hex << (uint32_t)value << endl;
|
||||||
|
this->via_regs[VIA_DIRA] = value;
|
||||||
break;
|
break;
|
||||||
case VIA_PCR:
|
case VIA_PCR:
|
||||||
cout << "VIA_PCR = " << hex << (uint32_t)value << endl;
|
cout << "VIA_PCR = " << hex << (uint32_t)value << endl;
|
||||||
|
this->via_regs[VIA_PCR] = value;
|
||||||
break;
|
break;
|
||||||
case VIA_ACR:
|
case VIA_ACR:
|
||||||
cout << "VIA_ACR = " << hex << (uint32_t)value << endl;
|
cout << "VIA_ACR = " << hex << (uint32_t)value << endl;
|
||||||
|
this->via_regs[VIA_ACR] = value;
|
||||||
break;
|
break;
|
||||||
case VIA_IER:
|
case VIA_IER:
|
||||||
this->via_regs[VIA_IER] = (value & 0x80) ? value & 0x7F
|
this->via_regs[VIA_IER] = (value & 0x80) ? value & 0x7F
|
||||||
@ -69,9 +95,6 @@ void ViaCuda::write(int reg, uint8_t value)
|
|||||||
<< endl;
|
<< endl;
|
||||||
print_enabled_ints();
|
print_enabled_ints();
|
||||||
break;
|
break;
|
||||||
case VIA_ANH:
|
|
||||||
cout << "VIA_ANH = " << hex << (uint32_t)value << endl;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
this->via_regs[reg & 0xF] = value;
|
this->via_regs[reg & 0xF] = value;
|
||||||
}
|
}
|
||||||
@ -86,3 +109,138 @@ void ViaCuda::print_enabled_ints()
|
|||||||
cout << "VIA " << via_int_src[i] << " interrupt enabled." << endl;
|
cout << "VIA " << via_int_src[i] << " interrupt enabled." << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool ViaCuda::cuda_ready()
|
||||||
|
{
|
||||||
|
return ((this->via_regs[VIA_DIRB] & 0x38) == 0x30);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ViaCuda::assert_sr_int()
|
||||||
|
{
|
||||||
|
this->via_regs[VIA_IFR] |= 0x84;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViaCuda::cuda_write(uint8_t new_state)
|
||||||
|
{
|
||||||
|
if (!cuda_ready()) {
|
||||||
|
cout << "Cuda not ready!" << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int new_tip = !!(new_state & CUDA_TIP);
|
||||||
|
int new_byteack = !!(new_state & CUDA_BYTEACK);
|
||||||
|
|
||||||
|
/* return if there is no state change */
|
||||||
|
if (new_tip == this->old_tip && new_byteack == this->old_byteack)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cout << "Cuda state changed!" << endl;
|
||||||
|
|
||||||
|
this->old_tip = new_tip;
|
||||||
|
this->old_byteack = new_byteack;
|
||||||
|
|
||||||
|
if (new_tip) {
|
||||||
|
if (new_byteack) {
|
||||||
|
this->via_regs[VIA_B] |= CUDA_TREQ; /* negate TREQ */
|
||||||
|
this->treq = 1;
|
||||||
|
|
||||||
|
if (this->in_count) {
|
||||||
|
cuda_process_packet();
|
||||||
|
|
||||||
|
/* start response transaction */
|
||||||
|
this->via_regs[VIA_B] &= ~CUDA_TREQ; /* assert TREQ */
|
||||||
|
this->treq = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->in_count = 0;
|
||||||
|
} else {
|
||||||
|
cout << "Cuda: enter sync state" << endl;
|
||||||
|
this->via_regs[VIA_B] &= ~CUDA_TREQ; /* assert TREQ */
|
||||||
|
this->treq = 0;
|
||||||
|
this->in_count = 0;
|
||||||
|
this->out_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_sr_int(); /* send dummy byte as idle acknowledge or attention */
|
||||||
|
} else {
|
||||||
|
if (this->via_regs[VIA_ACR] & 0x10) { /* data transfer: Host --> Cuda */
|
||||||
|
if (this->in_count < 16) {
|
||||||
|
this->in_buf[this->in_count++] = this->via_regs[VIA_SR];
|
||||||
|
assert_sr_int(); /* tell the system we've read the data */
|
||||||
|
} else {
|
||||||
|
cout << "Cuda input buffer exhausted!" << endl;
|
||||||
|
}
|
||||||
|
} else { /* data transfer: Cuda --> Host */
|
||||||
|
if (this->out_count) {
|
||||||
|
this->via_regs[VIA_SR] = this->out_buf[this->out_pos++];
|
||||||
|
|
||||||
|
if (this->out_pos >= this->out_count) {
|
||||||
|
cout << "Cuda: sending last byte" << endl;
|
||||||
|
this->out_count = 0;
|
||||||
|
this->via_regs[VIA_B] |= CUDA_TREQ; /* negate TREQ */
|
||||||
|
this->treq = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_sr_int(); /* tell the system we've written the data */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViaCuda::cuda_null_response(uint32_t pkt_type, uint32_t pkt_flag, uint32_t cmd)
|
||||||
|
{
|
||||||
|
this->out_buf[0] = pkt_type;
|
||||||
|
this->out_buf[1] = pkt_flag;
|
||||||
|
this->out_buf[2] = cmd;
|
||||||
|
this->out_count = 3;
|
||||||
|
this->out_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViaCuda::cuda_process_packet()
|
||||||
|
{
|
||||||
|
if (this->in_count < 2) {
|
||||||
|
cout << "Cuda: invalid packet (too few data)!" << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(this->in_buf[0]) {
|
||||||
|
case 0:
|
||||||
|
cout << "Cuda: ADB packet received" << endl;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
cout << "Cuda: pseudo command packet received" << endl;
|
||||||
|
cout << "Command: " << hex << (uint32_t)(this->in_buf[1]) << endl;
|
||||||
|
cout << "Data count: " << dec << this->in_count << endl;
|
||||||
|
for (int i = 0; i < this->in_count; i++) {
|
||||||
|
cout << hex << (uint32_t)(this->in_buf[i]) << ", ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
cuda_pseudo_command(this->in_buf[1], this->in_count - 2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cout << "Cuda: unsupported packet type = " << dec << (uint32_t)(this->in_buf[0]) << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViaCuda::cuda_pseudo_command(int cmd, int data_count)
|
||||||
|
{
|
||||||
|
switch(cmd) {
|
||||||
|
case CUDA_READ_WRITE_I2C:
|
||||||
|
cuda_null_response(1, 0, cmd);
|
||||||
|
/* bit 0 of the I2C address byte indicates operation kind:
|
||||||
|
0 - write to device, 1 - read from device
|
||||||
|
In the case of reading, Cuda will append one-byte result
|
||||||
|
to the response packet header */
|
||||||
|
if (this->in_buf[2] & 1) {
|
||||||
|
this->out_buf[3] = 0xDD; /* send dummy byte for now */
|
||||||
|
this->out_count++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CUDA_OUT_PB0: /* undocumented call! */
|
||||||
|
cout << "Cuda: send " << dec << (int)(this->in_buf[2]) << " to PB0" << endl;
|
||||||
|
cuda_null_response(1, 0, cmd);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cout << "Cuda: unsupported pseudo command 0x" << hex << cmd << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
- Apple Desktop Bus (ADB) master
|
- Apple Desktop Bus (ADB) master
|
||||||
- I2C bus master
|
- I2C bus master
|
||||||
- Realtime clock (RTC)
|
- Realtime clock (RTC)
|
||||||
- parameter RAM
|
- parameter RAM (first generation of the Power Macintosh)
|
||||||
- power management
|
- power management
|
||||||
|
|
||||||
MC68HC05 doesn't provide any dedicated hardware for serial communication
|
MC68HC05 doesn't provide any dedicated hardware for serial communication
|
||||||
@ -51,6 +51,21 @@ enum {
|
|||||||
VIA_ANH = 0x0F, /* input/output register A, no handshake */
|
VIA_ANH = 0x0F, /* input/output register A, no handshake */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Cuda communication signals. */
|
||||||
|
enum {
|
||||||
|
CUDA_TIP = 0x20, /* transaction in progress: 0 - true, 1 - false */
|
||||||
|
CUDA_BYTEACK = 0x10, /* byte acknowledge: 0 - true, 1 - false */
|
||||||
|
CUDA_TREQ = 0x08 /* Cuda requests transaction from host */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Cuda pseudo commands. */
|
||||||
|
enum {
|
||||||
|
CUDA_READ_WRITE_I2C = 0x22, /* read/write I2C device */
|
||||||
|
CUDA_COMB_FMT_I2C = 0x25, /* combined format I2C transaction */
|
||||||
|
CUDA_OUT_PB0 = 0x26, /* output one bit to Cuda's PB0 line */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class ViaCuda
|
class ViaCuda
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -63,7 +78,25 @@ public:
|
|||||||
private:
|
private:
|
||||||
uint8_t via_regs[16]; /* VIA virtual registers */
|
uint8_t via_regs[16]; /* VIA virtual registers */
|
||||||
|
|
||||||
|
/* Cuda state. */
|
||||||
|
uint8_t old_tip;
|
||||||
|
uint8_t old_byteack;
|
||||||
|
uint8_t treq;
|
||||||
|
uint8_t in_buf[16];
|
||||||
|
int32_t in_count;
|
||||||
|
uint8_t out_buf[16];
|
||||||
|
int32_t out_count;
|
||||||
|
int32_t out_pos;
|
||||||
|
|
||||||
void print_enabled_ints(); /* print enabled VIA interrupts and their sources */
|
void print_enabled_ints(); /* print enabled VIA interrupts and their sources */
|
||||||
|
|
||||||
|
void cuda_init();
|
||||||
|
bool cuda_ready();
|
||||||
|
void assert_sr_int();
|
||||||
|
void cuda_write(uint8_t new_state);
|
||||||
|
void cuda_null_response(uint32_t pkt_type, uint32_t pkt_flag, uint32_t cmd);
|
||||||
|
void cuda_process_packet();
|
||||||
|
void cuda_pseudo_command(int cmd, int data_count);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* VIACUDA_H */
|
#endif /* VIACUDA_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user