mirror of
https://github.com/JorjBauer/aiie.git
synced 2025-03-25 13:33:30 +00:00
Teensy 4.1 work; bios option to invert paddles
This commit is contained in:
parent
677bf3a9b4
commit
235012a411
79
bios.cpp
79
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)
|
||||
|
2
bios.h
2
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();
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -17,6 +17,7 @@ class SDLDisplay : public PhysicalDisplay {
|
||||
SDLDisplay();
|
||||
virtual ~SDLDisplay();
|
||||
|
||||
virtual void blit();
|
||||
virtual void blit(AiieRect r);
|
||||
virtual void redraw();
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "appleui.h"
|
||||
#include <SPI.h>
|
||||
|
||||
#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,
|
||||
|
@ -16,6 +16,7 @@ class TeensyDisplay : public PhysicalDisplay {
|
||||
TeensyDisplay();
|
||||
virtual ~TeensyDisplay();
|
||||
|
||||
virtual void blit();
|
||||
virtual void blit(AiieRect r);
|
||||
virtual void redraw();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -1,13 +1,18 @@
|
||||
#ifdef TEENSYDUINO
|
||||
#include <Arduino.h>
|
||||
#include "teensy-println.h"
|
||||
EXTMEM uint8_t preallocatedRam[591*256];
|
||||
#endif
|
||||
|
||||
#include "vmram.h"
|
||||
#include <string.h>
|
||||
#include "globals.h"
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
EXTMEM uint8_t preallocatedRam[591*256];
|
||||
#else
|
||||
uint8_t preallocatedRam[591*256];
|
||||
#endif
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
#include <assert.h>
|
||||
#else
|
||||
|
Loading…
x
Reference in New Issue
Block a user