diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index d3e33cd6b..c62c606e8 100755 --- a/bsnes/base/base.hpp +++ b/bsnes/base/base.hpp @@ -1,7 +1,7 @@ #ifndef BASE_HPP #define BASE_HPP -const char Version[] = "086.03"; +const char Version[] = "086.04"; #include #include diff --git a/bsnes/snes/controller/controller.cpp b/bsnes/snes/controller/controller.cpp index 9091b21b3..e582f31e9 100755 --- a/bsnes/snes/controller/controller.cpp +++ b/bsnes/snes/controller/controller.cpp @@ -8,7 +8,8 @@ namespace SNES { #include "mouse/mouse.cpp" #include "superscope/superscope.cpp" #include "justifier/justifier.cpp" -#include "serial/serial.cpp" +#include "uart/uart.cpp" +#include "usart/usart.cpp" void Controller::Enter() { if(co_active() == input.port1->thread) input.port1->enter(); diff --git a/bsnes/snes/controller/controller.hpp b/bsnes/snes/controller/controller.hpp index 733271293..0883960a2 100755 --- a/bsnes/snes/controller/controller.hpp +++ b/bsnes/snes/controller/controller.hpp @@ -32,4 +32,5 @@ struct Controller : Processor { #include "mouse/mouse.hpp" #include "superscope/superscope.hpp" #include "justifier/justifier.hpp" -#include "serial/serial.hpp" +#include "uart/uart.hpp" +#include "usart/usart.hpp" diff --git a/bsnes/snes/controller/serial/serial.cpp b/bsnes/snes/controller/uart/uart.cpp similarity index 73% rename from bsnes/snes/controller/serial/serial.cpp rename to bsnes/snes/controller/uart/uart.cpp index 43b76bab4..13d987cf6 100755 --- a/bsnes/snes/controller/serial/serial.cpp +++ b/bsnes/snes/controller/uart/uart.cpp @@ -1,6 +1,6 @@ #ifdef CONTROLLER_CPP -//Serial communications cable emulation: +//Asynchronous serial communications cable emulation: //The SNES controller ports can be used for bi-directional serial communication //when wired to a specialized controller. This class implements said controller, //for the primary purpose of testing code outside of real hardware. @@ -30,15 +30,19 @@ static void snesserial_tick(unsigned clocks); static uint8 snesserial_read(); static void snesserial_write(uint8 data); -void Serial::enter() { - if(enable == false) while(true) step(1); //fallback, in case library was not found +void UART::enter() { + if(enable == false) { + //fallback, in case library was not found + interface->message("UART library not found"); + while(true) step(1); + } step(256 * 8); //simulate warm-up delay if(flowcontrol()) data2 = 1; main(snesserial_tick, snesserial_read, snesserial_write); //stubs for Serial::step, Serial::read, Serial::write while(true) step(1); //fallback, in case snesserial_main() returns (it should never do so) } -uint8 Serial::read() { +uint8 UART::read() { while(latched == 0) step(1); while(latched == 1) step(1); step(4); @@ -52,7 +56,7 @@ uint8 Serial::read() { return data; } -void Serial::write(uint8 data) { +void UART::write(uint8 data) { if(flowcontrol()) while(iobit()) step(1); step(8); @@ -69,20 +73,18 @@ void Serial::write(uint8 data) { step(8); } -uint2 Serial::data() { +uint2 UART::data() { return (data2 << 1) | (data1 << 0); } -void Serial::latch(bool data) { +void UART::latch(bool data) { latched = data; } -Serial::Serial(bool port) : Controller(port) { +UART::UART(bool port) : Controller(port) { enable = false; - string basename = interface->path(Cartridge::Slot::Base, "serial.so"); - string name = notdir(basename); - string path = dir(basename); - if(open(name, path)) { + string filename = interface->path(Cartridge::Slot::Base, "uart.so"); + if(open_absolute(filename)) { baudrate = sym("snesserial_baudrate"); flowcontrol = sym("snesserial_flowcontrol"); main = sym("snesserial_main"); @@ -95,7 +97,7 @@ Serial::Serial(bool port) : Controller(port) { data2 = 0; } -Serial::~Serial() { +UART::~UART() { if(opened()) close(); } @@ -103,42 +105,42 @@ Serial::~Serial() { static void snesserial_tick(unsigned clocks) { if(co_active() == input.port1->thread) { - if(dynamic_cast(input.port1)) { - return ((Serial*)input.port1)->step(clocks); + if(dynamic_cast(input.port1)) { + return ((UART*)input.port1)->step(clocks); } } if(co_active() == input.port2->thread) { - if(dynamic_cast(input.port2)) { - return ((Serial*)input.port2)->step(clocks); + if(dynamic_cast(input.port2)) { + return ((UART*)input.port2)->step(clocks); } } } static uint8 snesserial_read() { if(co_active() == input.port1->thread) { - if(dynamic_cast(input.port1)) { - return ((Serial*)input.port1)->read(); + if(dynamic_cast(input.port1)) { + return ((UART*)input.port1)->read(); } } if(co_active() == input.port2->thread) { - if(dynamic_cast(input.port2)) { - return ((Serial*)input.port2)->read(); + if(dynamic_cast(input.port2)) { + return ((UART*)input.port2)->read(); } } } static void snesserial_write(uint8 data) { if(co_active() == input.port1->thread) { - if(dynamic_cast(input.port1)) { - return ((Serial*)input.port1)->write(data); + if(dynamic_cast(input.port1)) { + return ((UART*)input.port1)->write(data); } } if(co_active() == input.port2->thread) { - if(dynamic_cast(input.port2)) { - return ((Serial*)input.port2)->write(data); + if(dynamic_cast(input.port2)) { + return ((UART*)input.port2)->write(data); } } } diff --git a/bsnes/snes/controller/serial/serial.hpp b/bsnes/snes/controller/uart/uart.hpp similarity index 80% rename from bsnes/snes/controller/serial/serial.hpp rename to bsnes/snes/controller/uart/uart.hpp index 2a68ba534..f1725cfc8 100755 --- a/bsnes/snes/controller/serial/serial.hpp +++ b/bsnes/snes/controller/uart/uart.hpp @@ -1,11 +1,11 @@ -struct Serial : Controller, public library { +struct UART : Controller, public library { void enter(); uint8 read(); void write(uint8 data); uint2 data(); void latch(bool data); - Serial(bool port); - ~Serial(); + UART(bool port); + ~UART(); private: bool enable; diff --git a/bsnes/snes/controller/usart/usart.cpp b/bsnes/snes/controller/usart/usart.cpp new file mode 100755 index 000000000..266376585 --- /dev/null +++ b/bsnes/snes/controller/usart/usart.cpp @@ -0,0 +1,75 @@ +#ifdef CONTROLLER_CPP + +//Synchronous serial communications cable emulation + +//Hardware: +//Teensy++ 2.0 USB +//AT90USB1286 + +//Connection Diagram: +//[SNES] [Teensy] +// +5v --- +// Clock D5 +// Latch D2 +// Data1 D3 +// Data2 --- +// IOBit --- +// GND GND + +static uint8 usart_read(); +static void usart_write(uint8 data); + +//USART -> SNES +uint2 USART::data() { + if(rxlength == 0) { + data1 = 0; + rxdata = usart_read(); + } else if(rxlength <= 8) { + data1 = rxdata & 1; + rxdata >>= 1; + } else { + data1 = 1; + rxlength = 0; + } + + return (data2 << 1) | (data1 << 0); +} + +//SNES -> USART +void USART::latch(bool data) { + if(txlength == 0 && latched == 1 && data == 0) { + txlength++; + } else if(txlength <= 8) { + txdata = (data << 7) | (txdata >> 1); + txlength++; + } else { + if(data == 1) usart_write(txdata); + txlength = 0; + } + + latched = data; +} + +USART::USART(bool port) : Controller(port) { + latched = 0; + data1 = 0; + data2 = 0; + + rxlength = 0; + rxdata = 0; + + txlength = 0; + txdata = 0; +} + +USART::~USART() { +} + +static uint8 usart_read() { + return 0xff; +} + +static void usart_write(uint8 data) { +} + +#endif diff --git a/bsnes/snes/controller/usart/usart.hpp b/bsnes/snes/controller/usart/usart.hpp new file mode 100755 index 000000000..385e6fd1a --- /dev/null +++ b/bsnes/snes/controller/usart/usart.hpp @@ -0,0 +1,17 @@ +struct USART : Controller, public library { + uint2 data(); + void latch(bool data); + USART(bool port); + ~USART(); + +private: + bool latched; + bool data1; + bool data2; + + uint8 rxlength; + uint8 rxdata; + + uint8 txlength; + uint8 txdata; +}; diff --git a/bsnes/snes/system/input.cpp b/bsnes/snes/system/input.cpp index 90503106a..558638ecf 100755 --- a/bsnes/snes/system/input.cpp +++ b/bsnes/snes/system/input.cpp @@ -17,7 +17,8 @@ void Input::connect(bool port, Input::Device id) { case Device::SuperScope: controller = new SuperScope(port); break; case Device::Justifier: controller = new Justifier(port, false); break; case Device::Justifiers: controller = new Justifier(port, true); break; - case Device::Serial: controller = new Serial(port); break; + case Device::UART: controller = new UART(port); break; + case Device::USART: controller = new USART(port); break; } switch(port) { diff --git a/bsnes/snes/system/input.hpp b/bsnes/snes/system/input.hpp index 13ef46e11..759b3e505 100755 --- a/bsnes/snes/system/input.hpp +++ b/bsnes/snes/system/input.hpp @@ -7,7 +7,8 @@ struct Input { SuperScope, Justifier, Justifiers, - Serial, + UART, + USART, }; enum class JoypadID : unsigned { diff --git a/bsnes/ui/general/main-window.cpp b/bsnes/ui/general/main-window.cpp index bc980209f..d9ed36c81 100755 --- a/bsnes/ui/general/main-window.cpp +++ b/bsnes/ui/general/main-window.cpp @@ -49,9 +49,10 @@ MainWindow::MainWindow() { snesPort2Device[4].setText("Super Scope"); snesPort2Device[5].setText("Justifier"); snesPort2Device[6].setText("Dual Justifiers"); - snesPort2Device[7].setText("Serial Cable"); + snesPort2Device[7].setText("Serial UART"); + snesPort2Device[8].setText("Serial USART"); RadioItem::group(snesPort2Device[0], snesPort2Device[1], snesPort2Device[2], snesPort2Device[3], - snesPort2Device[4], snesPort2Device[5], snesPort2Device[6], snesPort2Device[7]); + snesPort2Device[4], snesPort2Device[5], snesPort2Device[6], snesPort2Device[7], snesPort2Device[8]); snesPort2Device[config->snes.controllerPort2Device].setChecked(); snesCartridgeUnload.setText("&Unload Cartridge"); @@ -138,6 +139,7 @@ MainWindow::MainWindow() { snesPort2.append(snesPort2Device[5]); snesPort2.append(snesPort2Device[6]); snesPort2.append(snesPort2Device[7]); + snesPort2.append(snesPort2Device[8]); snesMenu.append(snesSeparator2); snesMenu.append(snesCartridgeUnload); @@ -255,6 +257,7 @@ MainWindow::MainWindow() { snesPort2Device[5].onActivate = [&] { interface->setController(1, 5); }; snesPort2Device[6].onActivate = [&] { interface->setController(1, 6); }; snesPort2Device[7].onActivate = [&] { interface->setController(1, 7); }; + snesPort2Device[8].onActivate = [&] { interface->setController(1, 8); }; snesCartridgeUnload.onActivate = { &Interface::unloadCartridge, interface }; diff --git a/bsnes/ui/general/main-window.hpp b/bsnes/ui/general/main-window.hpp index b595755a0..5edb2634e 100755 --- a/bsnes/ui/general/main-window.hpp +++ b/bsnes/ui/general/main-window.hpp @@ -31,7 +31,7 @@ struct MainWindow : Window { Menu snesPort1; RadioItem snesPort1Device[4]; Menu snesPort2; - RadioItem snesPort2Device[8]; + RadioItem snesPort2Device[9]; Separator snesSeparator2; Item snesCartridgeUnload; diff --git a/bsnes/ui/interface/snes/snes.cpp b/bsnes/ui/interface/snes/snes.cpp index 1c3420831..c9ef2cde5 100755 --- a/bsnes/ui/interface/snes/snes.cpp +++ b/bsnes/ui/interface/snes/snes.cpp @@ -22,7 +22,8 @@ void InterfaceSNES::setController(bool port, unsigned device) { case 4: return SNES::input.connect(1, SNES::Input::Device::SuperScope); case 5: return SNES::input.connect(1, SNES::Input::Device::Justifier); case 6: return SNES::input.connect(1, SNES::Input::Device::Justifiers); - case 7: return SNES::input.connect(1, SNES::Input::Device::Serial); + case 7: return SNES::input.connect(1, SNES::Input::Device::UART); + case 8: return SNES::input.connect(1, SNES::Input::Device::USART); } } @@ -412,7 +413,8 @@ string InterfaceSNES::path(SNES::Cartridge::Slot slot, const string &hint) { track.trim<1>("track-", ".pcm"); return interface->base.filename(hint, { "-", decimal(track), ".pcm" }); } - if(hint == "serial.so") return { dir(interface->base.name), "libserial.so" }; + if(hint == "uart.so") return { dir(interface->base.name), "uart.so" }; + if(hint == "usart.so") return { dir(interface->base.name), "usart.so" }; if(hint.endswith(".rom")) return { dir(interface->base.name), hint }; } return { dir(interface->base.name), hint };