From 6cbc312f11cbaac1f5168c3b11ff0031bc0e0fb9 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sat, 25 Feb 2012 19:49:27 +1100 Subject: [PATCH] Update to v086r04 release. byuu says: There will probably be a series of small WIPs as I experiment here. snes/controller/serial is now snes/controller/uart. Asynchronous serial communications, typically capped at 57,600 baud. snes/controller/usart is new. It aims to emulate the SNES connected to a Teensy++ board, and can easily handle 524,288 baud. And much more importantly, it's synchronous, so there are no timing issues anymore. Just bit-bang as fast as you can. Right now, the USART code is just enough for SNES->PC to transfer data to ... well, nothing yet. Unless anyone is actually using the UART stuff, I'll be removing it once the USART is totally up and running. No sense maintaining code that is 10x slower, more error prone, and used by nobody. Note: this is all thanks to blargg being absolutely amazing. --- bsnes/base/base.hpp | 2 +- bsnes/snes/controller/controller.cpp | 3 +- bsnes/snes/controller/controller.hpp | 3 +- .../{serial/serial.cpp => uart/uart.cpp} | 52 ++++++------- .../{serial/serial.hpp => uart/uart.hpp} | 6 +- bsnes/snes/controller/usart/usart.cpp | 75 +++++++++++++++++++ bsnes/snes/controller/usart/usart.hpp | 17 +++++ bsnes/snes/system/input.cpp | 3 +- bsnes/snes/system/input.hpp | 3 +- bsnes/ui/general/main-window.cpp | 7 +- bsnes/ui/general/main-window.hpp | 2 +- bsnes/ui/interface/snes/snes.cpp | 6 +- 12 files changed, 141 insertions(+), 38 deletions(-) rename bsnes/snes/controller/{serial/serial.cpp => uart/uart.cpp} (73%) rename bsnes/snes/controller/{serial/serial.hpp => uart/uart.hpp} (80%) create mode 100755 bsnes/snes/controller/usart/usart.cpp create mode 100755 bsnes/snes/controller/usart/usart.hpp diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index d3e33cd6..c62c606e 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 9091b21b..e582f31e 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 73327129..0883960a 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 43b76bab..13d987cf 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 2a68ba53..f1725cfc 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 00000000..26637658 --- /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 00000000..385e6fd1 --- /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 90503106..558638ec 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 13ef46e1..759b3e50 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 bc980209..d9ed36c8 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 b595755a..5edb2634 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 1c342083..c9ef2cde 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 };