bsnes/sfc/controller/usart/usart.cpp

138 lines
2.4 KiB
C++

#ifdef CONTROLLER_CPP
//Synchronous serial communications cable emulation
//Hardware:
//Teensy++ 2.0 USB
//AT90USB1286
//Connection Diagram:
//SNES GND <> Teensy GND
//SNES IOBit <> Teensy B0
//SNES Latch <> Teensy D2
//SNES Data1 <> Teensy D3
//SNES Clock <> 1Kohm Resistor <> Teensy D5
//Teensy D5 <> Teensy D7
void USART::enter() {
if(init && main) {
init(
{&USART::quit, this},
{&USART::usleep, this},
{&USART::readable, this},
{&USART::read, this},
{&USART::writable, this},
{&USART::write, this}
);
main();
}
while(true) step(10000000);
}
bool USART::quit() {
step(1);
return false;
}
void USART::usleep(unsigned milliseconds) {
step(10 * milliseconds);
}
bool USART::readable() {
step(1);
return txbuffer.size();
}
//SNES -> USART
uint8 USART::read() {
step(1);
while(txbuffer.size() == 0) step(1);
uint8 data = txbuffer[0];
txbuffer.remove(0);
return data;
}
bool USART::writable() {
step(1);
return true;
}
//USART -> SNES
void USART::write(uint8 data) {
step(1);
rxbuffer.append(data ^ 0xff);
}
//clock
uint2 USART::data() {
//Joypad
if(iobit()) {
if(counter >= 16) return 1;
uint2 result = 0;
if(counter < 12) result = interface->inputPoll(port, (unsigned)Input::Device::Joypad, counter);
if(latched == 0) counter++;
return result;
}
//SNES -> USART
if(txlength == 0) {
if(latched == 0) txlength++;
} else if(txlength <= 8) {
txdata = (latched << 7) | (txdata >> 1);
txlength++;
} else {
if(latched == 1) txbuffer.append(txdata);
txlength = 0;
}
//USART -> SNES
if(rxlength == 0 && rxbuffer.size()) {
data1 = 1;
rxdata = rxbuffer[0];
rxbuffer.remove(0);
rxlength++;
} else if(rxlength <= 8) {
data1 = rxdata & 1;
rxdata >>= 1;
rxlength++;
} else {
data1 = 0;
rxlength = 0;
}
return (data2 << 1) | (data1 << 0);
}
//latch
void USART::latch(bool data) {
if(latched == data) return;
latched = data;
counter = 0;
}
USART::USART(bool port) : Controller(port) {
latched = 0;
data1 = 0;
data2 = 0;
counter = 0;
rxlength = 0;
rxdata = 0;
txlength = 0;
txdata = 0;
string filename = {interface->path(ID::SuperFamicom), "usart.so"};
if(open_absolute(filename)) {
init = sym("usart_init");
main = sym("usart_main");
if(init && main) create(Controller::Enter, 10000000);
}
}
USART::~USART() {
if(open()) close();
}
#endif