mirror of
https://github.com/JorjBauer/aiie.git
synced 2024-12-26 23:29:21 +00:00
threading fixes
This commit is contained in:
parent
e1288db403
commit
0024764fc4
@ -130,11 +130,11 @@ void AppleUI::blit()
|
||||
uint8_t yoff = 213;
|
||||
|
||||
for (int x=0; x<6; x++) {
|
||||
g_display->drawUIPixel(x + xoff, yoff, driveActivity[0] ? 0xF800 : 0x8AA9);
|
||||
g_display->drawUIPixel(x + xoff, yoff + 1, driveActivity[0] ? 0xF800 : 0x8AA9);
|
||||
g_display->drawUIPixel(x + xoff, yoff, driveActivity[0] ? 0xFA00 : 0x0000);
|
||||
g_display->drawUIPixel(x + xoff, yoff + 1, driveActivity[0] ? 0xFA00 : 0x0000);
|
||||
|
||||
g_display->drawUIPixel(x + xoff + 135, yoff, driveActivity[1] ? 0xF800 : 0x8AA9);
|
||||
g_display->drawUIPixel(x + xoff + 135, yoff + 1, driveActivity[1] ? 0xF800 : 0x8AA9);
|
||||
g_display->drawUIPixel(x + xoff + 135, yoff, driveActivity[1] ? 0xFA00 : 0x0000);
|
||||
g_display->drawUIPixel(x + xoff + 135, yoff + 1, driveActivity[1] ? 0xFA00 : 0x0000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,9 +27,9 @@ class AppleUI : public VMui {
|
||||
virtual void blit();
|
||||
|
||||
private:
|
||||
bool redrawFrame;
|
||||
bool redrawDriveLatches;
|
||||
bool redrawDriveActivity;
|
||||
volatile bool redrawFrame;
|
||||
volatile bool redrawDriveLatches;
|
||||
volatile bool redrawDriveActivity;
|
||||
bool driveInserted[2];
|
||||
bool driveActivity[2];
|
||||
};
|
||||
|
@ -257,8 +257,7 @@ void DiskII::driveOn()
|
||||
}
|
||||
// FIXME: does the sequencer get reset? Maybe if it's the selected disk? Or no?
|
||||
// sequencer = 0;
|
||||
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, true); // FIXME: do we really want to update the UI from inside this thread?
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, true);
|
||||
}
|
||||
|
||||
uint8_t DiskII::readSwitches(uint8_t s)
|
||||
@ -595,11 +594,11 @@ void DiskII::select(int8_t which)
|
||||
diskIsSpinningUntil[selectedDisk] = 0;
|
||||
// FIXME: consume any disk bits that need to be consumed, and
|
||||
// spin it down
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: queue for later drawing?
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false);
|
||||
|
||||
// Spin up the other one though
|
||||
diskIsSpinningUntil[which] = -1;
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + which, false); // FIXME: queue for later drawing?
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + which, true);
|
||||
}
|
||||
|
||||
// Queue flushing the cache of the disk that's no longer selected
|
||||
@ -751,7 +750,7 @@ void DiskII::maintenance(uint32_t cycle)
|
||||
// Stop the given disk drive spinning
|
||||
diskIsSpinningUntil[i] = 0;
|
||||
// FIXME: consume any disk bits that need to be consumed, and spin it down
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + i, false); // FIXME: queue for later drawing?
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + i, false);
|
||||
}
|
||||
|
||||
if (flushAt[i] &&
|
||||
|
12
bios.cpp
12
bios.cpp
@ -8,7 +8,9 @@
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
#include <TeensyThreads.h>
|
||||
#include <Bounce2.h>
|
||||
#include "teensy-paddles.h"
|
||||
extern Bounce resetButtonDebouncer;
|
||||
#endif
|
||||
|
||||
enum {
|
||||
@ -53,9 +55,6 @@ const uint8_t diskActions[] = { ACT_DISK1, ACT_DISK2,
|
||||
#define CPUSPEED_DOUBLE 2
|
||||
#define CPUSPEED_QUAD 3
|
||||
|
||||
// FIXME: abstract the pin # rather than repeating it here
|
||||
#define RESETPIN 39
|
||||
|
||||
const char *staticPathConcat(const char *rootPath, const char *filePath)
|
||||
{
|
||||
static char buf[MAXPATH];
|
||||
@ -284,7 +283,7 @@ uint8_t BIOS::GetAction(int8_t selection)
|
||||
while (!g_keyboard->kbhit()
|
||||
#ifdef TEENSYDUINO
|
||||
&&
|
||||
(digitalRead(RESETPIN) == HIGH)
|
||||
(resetButtonDebouncer.read() == HIGH)
|
||||
#endif
|
||||
) {
|
||||
#ifndef TEENSYDUINO
|
||||
@ -296,10 +295,9 @@ uint8_t BIOS::GetAction(int8_t selection)
|
||||
}
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
// FIXME: debounce!
|
||||
if (digitalRead(RESETPIN) == LOW) {
|
||||
if (resetButtonDebouncer.read() == LOW) {
|
||||
// wait until it's no longer pressed
|
||||
while (digitalRead(RESETPIN) == HIGH)
|
||||
while (resetButtonDebouncer.read() == HIGH)
|
||||
;
|
||||
threads.delay(100); // wait long enough for it to debounce
|
||||
// then return an exit code
|
||||
|
@ -29,9 +29,9 @@
|
||||
#include "globals.h"
|
||||
#include "applevm.h"
|
||||
|
||||
DMAMEM uint16_t dmaBuffer[240][320]; // 240 rows, 320 columns
|
||||
volatile DMAMEM uint16_t dmaBuffer[240][320]; // 240 rows, 320 columns
|
||||
|
||||
#define RGBto565(r,g,b) (((r & 0x3E00) << 2) | ((g & 0x3F00) >>3) | ((b & 0x3E00) >> 9))
|
||||
#define RGBto565(r,g,b) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | ((b) >> 3))
|
||||
|
||||
ILI9341_t3 tft = ILI9341_t3(PIN_CS, PIN_DC, PIN_RST, PIN_MOSI, PIN_SCK, PIN_MISO);
|
||||
|
||||
@ -155,7 +155,8 @@ void TeensyDisplay::clrScr()
|
||||
|
||||
void TeensyDisplay::drawUIPixel(uint16_t x, uint16_t y, uint16_t color)
|
||||
{
|
||||
tft.drawPixel(x,y,color);
|
||||
// These pixels are just cached in the buffer; they're not drawn directly.
|
||||
dmaBuffer[y][x] = color;
|
||||
}
|
||||
|
||||
void TeensyDisplay::drawPixel(uint16_t x, uint16_t y, uint16_t color)
|
||||
|
@ -80,7 +80,7 @@ void onKeyrelease(int unicode)
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(230400);
|
||||
#if 0
|
||||
#if 1
|
||||
// Wait for USB serial connection before booting while debugging
|
||||
while (!Serial) {
|
||||
yield();
|
||||
@ -110,37 +110,22 @@ void setup()
|
||||
pinMode(SPEAKERPIN, OUTPUT); // analog speaker output, used as digital volume control
|
||||
pinMode(BATTERYPIN, INPUT);
|
||||
|
||||
Serial.print("Free RAM: ");
|
||||
println(FreeRamEstimate());
|
||||
|
||||
println("creating virtual hardware");
|
||||
g_speaker = new TeensySpeaker(SPEAKERPIN);
|
||||
|
||||
Serial.print("Free RAM: ");
|
||||
println(FreeRamEstimate());
|
||||
|
||||
println(" fm");
|
||||
// First create the filemanager - the interface to the host file system.
|
||||
g_filemanager = new TeensyFileManager();
|
||||
|
||||
Serial.print("Free RAM: ");
|
||||
println(FreeRamEstimate());
|
||||
|
||||
// Construct the interface to the host display. This will need the
|
||||
// VM's video buffer in order to draw the VM, but we don't have that
|
||||
// yet.
|
||||
println(" display");
|
||||
g_display = new TeensyDisplay();
|
||||
|
||||
Serial.print("Free RAM: ");
|
||||
println(FreeRamEstimate());
|
||||
|
||||
println(" UI");
|
||||
g_ui = new AppleUI();
|
||||
|
||||
Serial.print("Free RAM: ");
|
||||
println(FreeRamEstimate());
|
||||
|
||||
// Next create the virtual CPU. This needs the VM's MMU in order to
|
||||
// run, but we don't have that yet.
|
||||
println(" cpu");
|
||||
@ -151,47 +136,30 @@ void setup()
|
||||
usb.attachKeypress(onKeypress);
|
||||
usb.attachKeyrelease(onKeyrelease);
|
||||
|
||||
Serial.print("Free RAM: ");
|
||||
println(FreeRamEstimate());
|
||||
|
||||
// Create the virtual machine. This may read from g_filemanager to
|
||||
// get ROMs if necessary. (The actual Apple VM we've built has them
|
||||
// compiled in, though.) It will create its virutal hardware (MMU,
|
||||
// video driver, floppy, paddles, whatever).
|
||||
println(" vm");
|
||||
Serial.flush();
|
||||
g_vm = new AppleVM();
|
||||
|
||||
Serial.print("Free RAM: ");
|
||||
println(FreeRamEstimate());
|
||||
|
||||
// Now that the VM exists and it has created an MMU, we tell the CPU
|
||||
// how to access memory through the MMU.
|
||||
println(" [setMMU]");
|
||||
println(" [setMMU]");
|
||||
g_cpu->SetMMU(g_vm->getMMU());
|
||||
|
||||
Serial.print("Free RAM: ");
|
||||
println(FreeRamEstimate());
|
||||
|
||||
|
||||
// And the physical keyboard needs hooks in to the virtual keyboard...
|
||||
println(" keyboard");
|
||||
g_keyboard = new TeensyKeyboard(g_vm->getKeyboard());
|
||||
|
||||
Serial.print("Free RAM: ");
|
||||
println(FreeRamEstimate());
|
||||
|
||||
println(" paddles");
|
||||
g_paddles = new TeensyPaddles(A3, A4, g_invertPaddleX, g_invertPaddleY);
|
||||
|
||||
Serial.print("Free RAM: ");
|
||||
println(FreeRamEstimate());
|
||||
|
||||
// Now that all the virtual hardware is glued together, reset the VM
|
||||
println("Resetting VM");
|
||||
g_vm->Reset();
|
||||
|
||||
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
|
||||
|
||||
@ -200,13 +168,11 @@ void setup()
|
||||
//((AppleVM *)g_vm)->insertDisk(0, "/A2DISKS/JORJ/disk_s6d1.dsk", false);
|
||||
// ((AppleVM *)g_vm)->insertDisk(0, "/A2DISKS/GAMES/ALIBABA.DSK", false);
|
||||
|
||||
Serial.print("Free RAM: ");
|
||||
println(FreeRamEstimate());
|
||||
|
||||
resetButtonDebouncer.attach(RESETPIN);
|
||||
resetButtonDebouncer.interval(5); // ms
|
||||
|
||||
println("free-running");
|
||||
Serial.flush();
|
||||
|
||||
threads.setMicroTimer(); // use a 100uS timer instead of a 1mS timer
|
||||
cpuThreadId = threads.addThread(runCPU);
|
||||
@ -252,30 +218,24 @@ void biosInterrupt()
|
||||
Threads::Scope lock1(cpulock);
|
||||
Threads::Scope lock2(displaylock);
|
||||
|
||||
Serial.println("Waiting for button to be released");
|
||||
// wait for the interrupt button to be released
|
||||
while (!resetButtonDebouncer.read())
|
||||
;
|
||||
|
||||
Serial.println("Invoking BIOS");
|
||||
// invoke the BIOS
|
||||
if (bios.runUntilDone()) {
|
||||
// if it returned true, we have something to store persistently in EEPROM.
|
||||
// The EEPROM doesn't like to be written to from a thread?
|
||||
Serial.println("Writing prefs");
|
||||
g_writePrefsFromMainLoop = true;
|
||||
while (g_writePrefsFromMainLoop) {
|
||||
Serial.println("Waiting for prefs to be written");
|
||||
delay(100);
|
||||
// wait for write to complete
|
||||
}
|
||||
// Also might have changed the paddles state
|
||||
Serial.println("Updating paddle state");
|
||||
TeensyPaddles *tmp = (TeensyPaddles *)g_paddles;
|
||||
tmp->setRev(g_invertPaddleX, g_invertPaddleY);
|
||||
}
|
||||
|
||||
Serial.println("Cleaning up");
|
||||
// if we turned off debugMode, make sure to clear the debugMsg
|
||||
if (g_debugMode == D_NONE) {
|
||||
g_display->debugMsg("");
|
||||
@ -291,12 +251,10 @@ void biosInterrupt()
|
||||
// Drain the speaker queue (FIXME: a little hacky)
|
||||
g_speaker->maintainSpeaker(-1, -1);
|
||||
|
||||
Serial.println("Forcing display redraw");
|
||||
// Force the display to redraw
|
||||
g_display->redraw(); // Redraw the UI
|
||||
((AppleDisplay*)(g_vm->vmdisplay))->modeChange(); // force a full re-draw and blit
|
||||
|
||||
Serial.println("re-priming keyboard");
|
||||
// Poll the keyboard before we start, so we can do selftest on startup
|
||||
g_keyboard->maintainKeyboard();
|
||||
}
|
||||
@ -322,9 +280,7 @@ void runMaintenance()
|
||||
}
|
||||
} else if (threads.getState(biosThreadId) != Threads::RUNNING) {
|
||||
// When the BIOS thread exits, we clean up
|
||||
Serial.println("Cleaing up bios thread");
|
||||
threads.wait(biosThreadId);
|
||||
Serial.println("BIOS thread is cleaned");
|
||||
biosThreadId = -1;
|
||||
}
|
||||
|
||||
@ -382,12 +338,13 @@ void runMaintenance()
|
||||
// appropriately use threads.yield()
|
||||
void runDisplay()
|
||||
{
|
||||
g_display->redraw(); // Redraw the UI; don't blit to the physical device
|
||||
|
||||
while (1) {
|
||||
{
|
||||
Threads::Scope lock(displaylock);
|
||||
doDebugging();
|
||||
|
||||
// FIXME: this is sometimes *VERY* slow.
|
||||
|
||||
uint32_t startDisp = millis();
|
||||
uint32_t cpuBefore = g_cpu->cycles;
|
||||
g_ui->blit();
|
||||
@ -404,10 +361,10 @@ void runDisplay()
|
||||
uint32_t dispTime = millis() - startDisp;
|
||||
uint32_t cpuAfter = g_cpu->cycles;
|
||||
if (dispTime > 75) {
|
||||
Serial.print("Slow blit: ");
|
||||
Serial.print(dispTime);
|
||||
Serial.print(" cpu ran: ");
|
||||
Serial.println(cpuAfter - cpuBefore);
|
||||
print("Slow blit: ");
|
||||
print(dispTime);
|
||||
print(" cpu ran: ");
|
||||
println(cpuAfter - cpuBefore);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -421,7 +378,6 @@ void runCPU()
|
||||
|
||||
uint32_t startMillis = millis();
|
||||
|
||||
Serial.println("CPU thread is started");
|
||||
while (1) {
|
||||
// Relatively critical timing: CPU needs to run ahead at least 4
|
||||
// cycles, b/c we're calling this interrupt (runCPU, that is) just
|
||||
@ -440,14 +396,14 @@ void runCPU()
|
||||
// was ((1000/1023) * numberOfCycles) - which is about 97.8%.
|
||||
if (expectedCycles > g_cpu->cycles) {
|
||||
nextInstructionMicros = micros();
|
||||
#if 0
|
||||
#if 1
|
||||
// show a warning on serial about our current performance
|
||||
double percentage = ((double)g_cpu->cycles / (double)expectedCycles) * 100.0;
|
||||
static uint32_t nextWarningTime = 0;
|
||||
if (millis() > nextWarningTime) {
|
||||
static char buf[100];
|
||||
sprintf(buf, "CPU running at %f%% of %d", percentage, g_speed);
|
||||
Serial.println(buf);
|
||||
println(buf);
|
||||
nextWarningTime = millis() + 1000;
|
||||
}
|
||||
#endif
|
||||
@ -468,7 +424,6 @@ void loop()
|
||||
resetButtonDebouncer.update();
|
||||
|
||||
if (g_writePrefsFromMainLoop) {
|
||||
Serial.println("Writing prefs");
|
||||
writePrefs();
|
||||
g_writePrefsFromMainLoop = false;
|
||||
}
|
||||
@ -568,7 +523,6 @@ void writePrefs()
|
||||
TeensyPrefs np;
|
||||
prefs_t p;
|
||||
|
||||
Serial.println("writePrefs()");
|
||||
p.magic = PREFSMAGIC;
|
||||
p.prefsSize = sizeof(prefs_t);
|
||||
p.version = PREFSVERSION;
|
||||
|
Loading…
Reference in New Issue
Block a user