From 235012a411c0495aef9f130c8111881eef5d5a6d Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Mon, 6 Jul 2020 21:31:37 -0400 Subject: [PATCH] Teensy 4.1 work; bios option to invert paddles --- bios.cpp | 79 +++++++++++++++++++++++++++++++++++++-- bios.h | 2 + globals.cpp | 2 + globals.h | 3 +- physicaldisplay.h | 3 +- prefsstore.h | 5 ++- sdl/sdl-display.cpp | 5 +++ sdl/sdl-display.h | 1 + teensy/teensy-display.cpp | 17 ++++++++- teensy/teensy-display.h | 1 + teensy/teensy-paddles.cpp | 6 +++ teensy/teensy-paddles.h | 2 + teensy/teensy-speaker.cpp | 4 +- teensy/teensy.ino | 57 ++++++++++++---------------- vmram.cpp | 7 +++- 15 files changed, 148 insertions(+), 46 deletions(-) diff --git a/bios.cpp b/bios.cpp index 85c79c0..664c6ed 100644 --- a/bios.cpp +++ b/bios.cpp @@ -6,6 +6,9 @@ #include "physicaldisplay.h" #include "cpu.h" +#ifdef TEENSYDUINO +#include "teensy-paddles.h" +#endif enum { ACT_EXIT = 1, @@ -23,8 +26,11 @@ enum { ACT_SUSPEND = 13, ACT_RESTORE = 14, ACT_PRIMODE = 15, - ACT_SPEED = 16, - ACT_ABOUT = 17, + ACT_PADX_INV = 16, + ACT_PADY_INV = 17, + ACT_PADDLES = 18, + ACT_SPEED = 19, + ACT_ABOUT = 20, }; #define NUM_TITLES 4 @@ -36,7 +42,8 @@ const uint8_t aiieActions[] = { ACT_ABOUT }; const uint8_t vmActions[] = { ACT_EXIT, ACT_RESET, ACT_COLDBOOT, ACT_MONITOR, ACT_DEBUG, ACT_SUSPEND, ACT_RESTORE }; const uint8_t hardwareActions[] = { ACT_DISPLAYTYPE, ACT_SPEED, - ACT_PRIMODE, ACT_VOLPLUS, ACT_VOLMINUS }; + ACT_PRIMODE, ACT_PADX_INV, ACT_PADY_INV, + ACT_PADDLES, ACT_VOLPLUS, ACT_VOLMINUS }; const uint8_t diskActions[] = { ACT_DISK1, ACT_DISK2, ACT_HD1, ACT_HD2 }; @@ -210,6 +217,21 @@ bool BIOS::runUntilDone() } } break; + case ACT_PADX_INV: + g_invertPaddleX = !g_invertPaddleX; +#ifdef TEENSYDUINO + ((TeensyPaddles *)g_paddles)->setRev(g_invertPaddleX, g_invertPaddleY); +#endif + break; + case ACT_PADY_INV: + g_invertPaddleY = !g_invertPaddleY; +#ifdef TEENSYDUINO + ((TeensyPaddles *)g_paddles)->setRev(g_invertPaddleX, g_invertPaddleY); +#endif + break; + case ACT_PADDLES: + ConfigurePaddles(); + break; case ACT_VOLPLUS: g_volume ++; if (g_volume > 15) { @@ -363,6 +385,9 @@ bool BIOS::isActionActive(int8_t action) case ACT_HD2: case ACT_SUSPEND: case ACT_RESTORE: + case ACT_PADX_INV: + case ACT_PADY_INV: + case ACT_PADDLES: return true; case ACT_VOLPLUS: @@ -524,6 +549,21 @@ void BIOS::DrawHardwareMenu() else strcpy(buf, "Prioritize audio over display"); break; + case ACT_PADX_INV: + if (g_invertPaddleX) + strcpy(buf, "Paddle X inverted"); + else + strcpy(buf, "Paddle X normal"); + break; + case ACT_PADY_INV: + if (g_invertPaddleY) + strcpy(buf, "Paddle Y inverted"); + else + strcpy(buf, "Paddle Y normal"); + break; + case ACT_PADDLES: + strcpy(buf, "Configure paddles"); + break; case ACT_VOLPLUS: strcpy(buf, "Volume +"); break; @@ -641,6 +681,39 @@ void BIOS::DrawMainMenu() g_display->flush(); } +void BIOS::ConfigurePaddles() +{ + while (1) { + bool needsUpdate = true; + uint8_t lastPaddleX = g_paddles->paddle0(); + uint8_t lastPaddleY = g_paddles->paddle1(); + + if (g_paddles->paddle0() != lastPaddleX) { + lastPaddleX = g_paddles->paddle0(); + needsUpdate = true; + } + if (g_paddles->paddle1() != lastPaddleY) { + lastPaddleY = g_paddles->paddle1(); + needsUpdate = true; + } + + if (needsUpdate) { + char buf[50]; + g_display->clrScr(); + sprintf(buf, "Paddle X: %d ", lastPaddleX); + g_display->drawString(M_NORMAL, 0, 12, buf); + sprintf(buf, "Paddle Y: %d ", lastPaddleY); + g_display->drawString(M_NORMAL, 0, 42, buf); + g_display->drawString(M_NORMAL, 0, 92, "Exit with any key"); + g_display->flush(); + } + + if (g_keyboard->kbhit()) { + g_keyboard->read(); // throw out keypress + return; + } + } +} // return true if the user selects an image // sets selectedFile (index; -1 = "nope") and fileDirectory[][] (names of up to BIOS_MAXFILES files) diff --git a/bios.h b/bios.h index a1d752a..2d55759 100644 --- a/bios.h +++ b/bios.h @@ -39,6 +39,8 @@ class BIOS { void DrawDiskNames(uint8_t page, int8_t selection, const char *filter); uint8_t GatherFilenames(uint8_t pageOffset, const char *filter); + void ConfigurePaddles(); + void stripDirectory(); void showAbout(); diff --git a/globals.cpp b/globals.cpp index a64de20..0222e48 100644 --- a/globals.cpp +++ b/globals.cpp @@ -17,3 +17,5 @@ volatile uint8_t g_debugMode = D_NONE; bool g_prioritizeDisplay = false; volatile bool g_biosInterrupt = false; uint32_t g_speed = 1023000; // Hz +bool g_invertPaddleX = false; +bool g_invertPaddleY = false; diff --git a/globals.h b/globals.h index f6898c1..7be57bb 100644 --- a/globals.h +++ b/globals.h @@ -52,5 +52,6 @@ extern volatile uint8_t g_debugMode; extern bool g_prioritizeDisplay; extern volatile bool g_biosInterrupt; extern uint32_t g_speed; - +extern bool g_invertPaddleX; +extern bool g_invertPaddleY; #endif diff --git a/physicaldisplay.h b/physicaldisplay.h index 90adc41..b8644e2 100644 --- a/physicaldisplay.h +++ b/physicaldisplay.h @@ -12,7 +12,8 @@ class PhysicalDisplay { virtual void flush() = 0; // flush any pending drawings virtual void redraw() = 0; // total redraw, assuming nothing - virtual void blit(AiieRect r) = 0; // redraw just the VM display area + virtual void blit() = 0; // blit everything to the display (including UI area) + virtual void blit(AiieRect r) = 0; // blit a piece of the VM area to the display virtual void drawImageOfSizeAt(const uint8_t *img, uint16_t sizex, uint8_t sizey, uint16_t wherex, uint8_t wherey) = 0; diff --git a/prefsstore.h b/prefsstore.h index 45f0817..8a1af57 100644 --- a/prefsstore.h +++ b/prefsstore.h @@ -6,7 +6,7 @@ // Fun trivia: the Apple //e was in production from January 1983 to // November 1993. And the 65C02 in them supported weird BCD math modes. #define PREFSMAGIC 0x01831093 -#define PREFSVERSION 1 +#define PREFSVERSION 2 #ifndef MAXPATH #define MAXPATH 255 @@ -25,6 +25,9 @@ typedef struct _prefs { uint8_t priorityMode; uint8_t speed; + uint8_t invertPaddleX; + uint8_t invertPaddleY; + char reserved[MAXPATH]; // 255 is the Teensy MAXPATH size char disk1[MAXPATH]; diff --git a/sdl/sdl-display.cpp b/sdl/sdl-display.cpp index 12637f2..58c341f 100644 --- a/sdl/sdl-display.cpp +++ b/sdl/sdl-display.cpp @@ -91,6 +91,11 @@ void SDLDisplay::drawImageOfSizeAt(const uint8_t *img, } } +void SDLDisplay::blit() +{ + // Whole-screen blit - unimplemented here +} + // Blit the videoBuffer to the display device, in the rect given void SDLDisplay::blit(AiieRect r) { diff --git a/sdl/sdl-display.h b/sdl/sdl-display.h index ec6ac1f..78640c7 100644 --- a/sdl/sdl-display.h +++ b/sdl/sdl-display.h @@ -17,6 +17,7 @@ class SDLDisplay : public PhysicalDisplay { SDLDisplay(); virtual ~SDLDisplay(); + virtual void blit(); virtual void blit(AiieRect r); virtual void redraw(); diff --git a/teensy/teensy-display.cpp b/teensy/teensy-display.cpp index 410d37a..5d73408 100644 --- a/teensy/teensy-display.cpp +++ b/teensy/teensy-display.cpp @@ -7,7 +7,7 @@ #include "appleui.h" #include -#define _clock 65000000 +#define _clock 50000000 #define PIN_RST 8 #define PIN_DC 9 @@ -175,7 +175,7 @@ void TeensyDisplay::flush() blit({0,0,191,279}); } -void TeensyDisplay::blit(AiieRect r) +void TeensyDisplay::blit() { // The goal here is for blitting to happen automatically in DMA transfers. @@ -196,6 +196,19 @@ void TeensyDisplay::blit(AiieRect r) } } +void TeensyDisplay::blit(AiieRect r) +{ + // It's probably faster to just blit the whole thing, rather than a piece, + // because of how it streams data easily when the buffer aligns properly. + tft.writeRect(0,0,320,240,(const uint16_t *)dmaBuffer); + + // ... but if we wanted to blit just part, we'd have to create a new + // subset of teh dmaBuffer that has the right row length to match + // the rect width we're blitting, and then do something like this: + // + // tft.writeRect(r.left+HOFFSET,,r.top+VOFFSET,r.right-r.left+HOFFSET,r.bottom-r.top+VOFFSET,(const uint16_t *)some_subset_of_dmaBuffer); +} + void TeensyDisplay::drawCharacter(uint8_t mode, uint16_t x, uint8_t y, char c) { int8_t xsize = 8, diff --git a/teensy/teensy-display.h b/teensy/teensy-display.h index 0b12fad..b36f7c5 100644 --- a/teensy/teensy-display.h +++ b/teensy/teensy-display.h @@ -16,6 +16,7 @@ class TeensyDisplay : public PhysicalDisplay { TeensyDisplay(); virtual ~TeensyDisplay(); + virtual void blit(); virtual void blit(AiieRect r); virtual void redraw(); diff --git a/teensy/teensy-paddles.cpp b/teensy/teensy-paddles.cpp index ae1306c..15e1209 100644 --- a/teensy/teensy-paddles.cpp +++ b/teensy/teensy-paddles.cpp @@ -47,3 +47,9 @@ void TeensyPaddles::startReading() g_vm->triggerPaddleInCycles(0, 12 * paddle0()); g_vm->triggerPaddleInCycles(1, 12 * paddle1()); } + +void TeensyPaddles::setRev(bool p0rev, bool p1rev) +{ + this->p0rev = p0rev; + this->p1rev = p1rev; +} diff --git a/teensy/teensy-paddles.h b/teensy/teensy-paddles.h index 3f50994..4e3293d 100644 --- a/teensy/teensy-paddles.h +++ b/teensy/teensy-paddles.h @@ -7,6 +7,8 @@ class TeensyPaddles : public PhysicalPaddles { TeensyPaddles(uint8_t p0pin, uint8_t p1pin, bool p0rev, bool p1rev); virtual ~TeensyPaddles(); + void setRev(bool p0rev, bool p1rev); + virtual uint8_t paddle0(); virtual uint8_t paddle1(); virtual void startReading(); diff --git a/teensy/teensy-speaker.cpp b/teensy/teensy-speaker.cpp index 6bc1d02..b224b5e 100644 --- a/teensy/teensy-speaker.cpp +++ b/teensy/teensy-speaker.cpp @@ -22,9 +22,7 @@ void TeensySpeaker::toggle(uint32_t c) mixerValue = (toggleState ? 0x1FF : 0x00); mixerValue >>= (16-g_volume); - // FIXME: glad it's DAC0 and all, but... how does that relate to the pin passed in the constructor? - // FIXME: really doesn't work for the Teensy 4 at all - // analogWriteDAC0(mixerValue); + analogWrite(speakerPin, mixerValue); } void TeensySpeaker::maintainSpeaker(uint32_t c, uint64_t runtimeInMicros) diff --git a/teensy/teensy.ino b/teensy/teensy.ino index e25e5c6..00b3447 100644 --- a/teensy/teensy.ino +++ b/teensy/teensy.ino @@ -20,7 +20,7 @@ #define RESETPIN 39 #define BATTERYPIN 32 -#define SPEAKERPIN 19 // FIXME this isn't right +#define SPEAKERPIN A17 // aka digital 41 #include "globals.h" #include "teensy-crash.h" @@ -62,16 +62,11 @@ void setup() pinMode(RESETPIN, INPUT); digitalWrite(RESETPIN, HIGH); - println("FIXME: skipping analogReference, speaker, battery for Teensy 4"); - /* - analogReference(EXTERNAL); // 3.3v external, or 1.7v internal. We need 1.7 internal for the battery level, which means we're gonna have to do something about the paddles :/ analogReadRes(8); // We only need 8 bits of resolution (0-255) for battery & paddles analogReadAveraging(4); // ?? dunno if we need this or not. - analogWriteResolution(12); pinMode(SPEAKERPIN, OUTPUT); // analog speaker output, used as digital volume control pinMode(BATTERYPIN, INPUT); - */ Serial.print("Free RAM: "); println(FreeRamEstimate()); @@ -139,7 +134,7 @@ void setup() println(FreeRamEstimate()); println(" paddles"); - g_paddles = new TeensyPaddles(A3, A4, 1, 1); + g_paddles = new TeensyPaddles(A3, A4, g_invertPaddleX, g_invertPaddleY); Serial.print("Free RAM: "); println(FreeRamEstimate()); @@ -148,8 +143,7 @@ void setup() println("Resetting VM"); g_vm->Reset(); - g_display->redraw(); -// g_display->blit(); + g_display->redraw(); // Redraw the UI; don't blit to the physical device println("Reading prefs"); readPrefs(); // read from eeprom and set anything we need setting @@ -212,6 +206,10 @@ void biosInterrupt() if (bios.runUntilDone()) { // if it returned true, we have something to store persistently in EEPROM. writePrefs(); + // Also might have changed the paddles state + TeensyPaddles *tmp = (TeensyPaddles *)g_paddles; + tmp->setRev(g_invertPaddleX, g_invertPaddleY); + } // if we turned off debugMode, make sure to clear the debugMsg @@ -227,8 +225,8 @@ void biosInterrupt() g_speaker->maintainSpeaker(-1, -1); // Force the display to redraw - g_display->redraw(); - ((AppleDisplay*)(g_vm->vmdisplay))->modeChange(); + g_display->redraw(); // Redraw the UI + ((AppleDisplay*)(g_vm->vmdisplay))->modeChange(); // force a full re-draw and blit // Poll the keyboard before we start, so we can do selftest on startup g_keyboard->maintainKeyboard(); @@ -285,35 +283,17 @@ void loop() doDebugging(); - // Only redraw if the CPU is caught up; and then we'll suspend the - // CPU to draw a full frame. - - // Note that this breaks audio, b/c it's real-time and requires the - // CPU running to change the audio line's value. So we need to EITHER - // - // - delay the audio line by at least the time it takes for one - // display update, OR - // - lock display updates so the CPU can update the memory, but we - // keep drawing what was going to be displayed - // - // The Timer1.stop()/start() is bad. Using it, the display doesn't - // tear; but the audio is also broken. Taking it out, audio is good - // but the display tears. So there's a global - g_prioritizeDisplay - - // which lets the user pick which they want. - - if (g_prioritizeDisplay) - Timer1.stop(); g_ui->blit(); g_vm->vmdisplay->lockDisplay(); - if (g_vm->vmdisplay->needsRedraw()) { + if (g_vm->vmdisplay->needsRedraw()) { // necessary for the VM to redraw + // Used to get the dirty rect and blit just that rect. Could still do, + // but instead, I'm just wildly wasting resources. MWAHAHAHA // AiieRect what = g_vm->vmdisplay->getDirtyRect(); - // g_vm->vmdisplay->didRedraw(); + g_vm->vmdisplay->didRedraw(); // g_display->blit(what); } - g_display->blit({0,0,191,279}); + g_display->blit(); // Blit the whole thing, including UI area g_vm->vmdisplay->unlockDisplay(); - if (g_prioritizeDisplay) - Timer1.start(); static unsigned long nextBattCheck = millis() + 30;// debugging static int batteryLevel = 0; // static for debugging code! When done @@ -442,6 +422,12 @@ void readPrefs() ((AppleVM *)g_vm)->insertHD(1, p.hd2); } } + + g_invertPaddleX = p.invertPaddleX; + g_invertPaddleY = p.invertPaddleY; + + // Update the paddles with the new inversion state + ((TeensyPaddles *)g_paddles)->setRev(g_invertPaddleX, g_invertPaddleY); } void writePrefs() @@ -457,6 +443,9 @@ void writePrefs() p.prefsSize = sizeof(prefs_t); p.version = PREFSVERSION; + p.invertPaddleX = g_invertPaddleX; + p.invertPaddleY = g_invertPaddleY; + p.volume = g_volume; p.displayType = g_displayType; p.debug = g_debugMode; diff --git a/vmram.cpp b/vmram.cpp index 9cadf56..a4f99d8 100644 --- a/vmram.cpp +++ b/vmram.cpp @@ -1,13 +1,18 @@ #ifdef TEENSYDUINO #include #include "teensy-println.h" -EXTMEM uint8_t preallocatedRam[591*256]; #endif #include "vmram.h" #include #include "globals.h" +#ifdef TEENSYDUINO +EXTMEM uint8_t preallocatedRam[591*256]; +#else +uint8_t preallocatedRam[591*256]; +#endif + #ifndef TEENSYDUINO #include #else