unix line endings only

This commit is contained in:
Christopher A. Mosher 2022-12-11 02:12:11 -05:00
parent 340c8294f4
commit d0873ead1b
11 changed files with 10176 additions and 10176 deletions

View File

@ -1,163 +1,163 @@
/* /*
epple2 epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com> Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "diskcontroller.h" #include "diskcontroller.h"
DiskController::DiskController(ScreenImage& gui, int slot, bool lss13, double random_ones_rate): DiskController::DiskController(ScreenImage& gui, int slot, bool lss13, double random_ones_rate):
gui(gui), gui(gui),
slot(slot), slot(slot),
drive1(random_ones_rate), drive1(random_ones_rate),
drive2(random_ones_rate), drive2(random_ones_rate),
currentDrive(&this->drive1), currentDrive(&this->drive1),
load(false), load(false),
write(false), write(false),
ioStepped(false), ioStepped(false),
dataBusReadOnlyCopy(0), dataBusReadOnlyCopy(0),
lssp6rom(lss13), lssp6rom(lss13),
dataRegister(0), dataRegister(0),
seq(0x20), // gotta start somewhere seq(0x20), // gotta start somewhere
prev_seq(seq), prev_seq(seq),
t(0) { t(0) {
} }
DiskController::~DiskController() { DiskController::~DiskController() {
} }
unsigned char DiskController::io(const unsigned short addr, const unsigned char d, const bool writing) { unsigned char DiskController::io(const unsigned short addr, const unsigned char d, const bool writing) {
this->dataBusReadOnlyCopy = d; this->dataBusReadOnlyCopy = d;
const unsigned char q = (addr & 0x000E) >> 1; const unsigned char q = (addr & 0x000E) >> 1;
const bool on = (addr & 0x0001); const bool on = (addr & 0x0001);
// printf("Q%d<--%s\n", q, on?"ON":"OFF"); // printf("Q%d<--%s\n", q, on?"ON":"OFF");
switch (q) { switch (q) {
case 0: case 0:
case 1: // TODO if phase-1 is on, it also acts as write-protect (UA2, 9-8) case 1: // TODO if phase-1 is on, it also acts as write-protect (UA2, 9-8)
case 2: case 2:
case 3: case 3:
this->currentDrive->set_phase(q,on); this->currentDrive->set_phase(q,on);
this->gui.setTrack(this->slot, getCurrentDriveNumber(), getTrack()); this->gui.setTrack(this->slot, getCurrentDriveNumber(), getTrack());
break; break;
case 4: case 4:
this->motor.power(on); this->motor.power(on);
break; break;
case 5: case 5:
this->gui.clearCurrentDrive(this->slot, getCurrentDriveNumber()); this->gui.clearCurrentDrive(this->slot, getCurrentDriveNumber());
this->currentDrive = (on ? &this->drive2 : &this->drive1); this->currentDrive = (on ? &this->drive2 : &this->drive1);
this->gui.setCurrentDrive(this->slot, getCurrentDriveNumber(),getTrack(), this->motor.isOn()); this->gui.setCurrentDrive(this->slot, getCurrentDriveNumber(),getTrack(), this->motor.isOn());
break; break;
case 6: case 6:
this->load = on; this->load = on;
break; break;
case 7: case 7:
this->write = on; this->write = on;
break; break;
} }
if (this->write && !this->load) { if (this->write && !this->load) {
this->gui.setDirty(this->slot,getCurrentDriveNumber(),true); this->gui.setDirty(this->slot,getCurrentDriveNumber(),true);
} }
// UA2, 9-23, Figure 9.12 // UA2, 9-23, Figure 9.12
// 2 LSS cycles need to happen AFTER setting the Qx switch, and // 2 LSS cycles need to happen AFTER setting the Qx switch, and
// BEFORE reading LSS's update of the data register // BEFORE reading LSS's update of the data register
this->ioStepped = false; this->ioStepped = false;
tick(); tick();
this->ioStepped = true; // flag that we ran it already this->ioStepped = true; // flag that we ran it already
return on ? d : this->dataRegister; return on ? d : this->dataRegister;
} }
/* /*
* Get a timing cycle here, based on the MPU clock (1 MHz). * Get a timing cycle here, based on the MPU clock (1 MHz).
* In the real Apple we don't get really get this here. But... * In the real Apple we don't get really get this here. But...
* We need a 2MHz clock for the LSS; and * We need a 2MHz clock for the LSS; and
* we need to rotate the floppy @ 1 bit per 4 microseconds. * we need to rotate the floppy @ 1 bit per 4 microseconds.
* (When the motor is on, that is.) * (When the motor is on, that is.)
*/ */
void DiskController::tick() { void DiskController::tick() {
this->currentDrive->tick(); this->currentDrive->tick();
if (this->ioStepped) { // if we already ran it, above in io(), skip here if (this->ioStepped) { // if we already ran it, above in io(), skip here
this->ioStepped = false; this->ioStepped = false;
return; return;
} }
this->gui.setIO(this->slot, getCurrentDriveNumber(), this->motor.isOn()); this->gui.setIO(this->slot, getCurrentDriveNumber(), this->motor.isOn());
if (!this->motor.isOn()) { if (!this->motor.isOn()) {
this->ioStepped = false; this->ioStepped = false;
return; return;
} }
this->motor.tick(); // only need to send tick when motor is powered on this->motor.tick(); // only need to send tick when motor is powered on
// run two LSS cycles = 2MHz // run two LSS cycles = 2MHz
rotateCurrentDisk(); rotateCurrentDisk();
stepLss(); stepLss();
// pulse lasts only 500 nanoseconds (1 LSS clock cycle), so clear it now: // pulse lasts only 500 nanoseconds (1 LSS clock cycle), so clear it now:
this->currentDrive->clearPulse(); this->currentDrive->clearPulse();
rotateCurrentDisk(); rotateCurrentDisk();
stepLss(); stepLss();
} }
void DiskController::rotateCurrentDisk() { void DiskController::rotateCurrentDisk() {
this->t += 1.0; this->t += 1.0;
if (this->currentDrive->optimal_timing()/4.0 <= this->t) { // wait for optimal interval between bits if (this->currentDrive->optimal_timing()/4.0 <= this->t) { // wait for optimal interval between bits
this->currentDrive->rotateDiskOneBit(); // (will also generate a read-pulse when it reads a 1-bit) this->currentDrive->rotateDiskOneBit(); // (will also generate a read-pulse when it reads a 1-bit)
this->t -= this->currentDrive->optimal_timing()/4.0; this->t -= this->currentDrive->optimal_timing()/4.0;
} }
} }
enum lss_cmd { NOP, SL, SR, LD }; enum lss_cmd { NOP, SL, SR, LD };
void DiskController::stepLss() { void DiskController::stepLss() {
std::uint8_t adr = this->write<<3 | this->load<<2 | (this->dataRegister>>7)<<1 | this->currentDrive->readPulse(); std::uint8_t adr = this->write<<3 | this->load<<2 | (this->dataRegister>>7)<<1 | this->currentDrive->readPulse();
std::uint8_t cmd = this->lssp6rom.read(this->seq|adr); std::uint8_t cmd = this->lssp6rom.read(this->seq|adr);
this->seq = cmd & 0xF0u; this->seq = cmd & 0xF0u;
// LSS command functions (UA2, 9-15, Table 9.3) // LSS command functions (UA2, 9-15, Table 9.3)
if (cmd & 8u) { if (cmd & 8u) {
if (cmd & 3u) { if (cmd & 3u) {
if (this->write) { if (this->write) {
const bool one = (this->seq&0x80u) != (this->prev_seq&0x80u); const bool one = (this->seq&0x80u) != (this->prev_seq&0x80u);
this->prev_seq = this->seq; this->prev_seq = this->seq;
this->currentDrive->writeBit(one); this->currentDrive->writeBit(one);
} }
} }
switch (cmd & 3u) { switch (cmd & 3u) {
case LD: case LD:
this->dataRegister = this->dataBusReadOnlyCopy; this->dataRegister = this->dataBusReadOnlyCopy;
break; break;
case SR: case SR:
this->dataRegister >>= 1; this->dataRegister >>= 1;
this->dataRegister |= (isWriteProtected() << 7); this->dataRegister |= (isWriteProtected() << 7);
break; break;
case SL: case SL:
this->dataRegister <<= 1; this->dataRegister <<= 1;
this->dataRegister |= ((cmd & 4u) >> 2); this->dataRegister |= ((cmd & 4u) >> 2);
break; break;
} }
} else { } else {
this->dataRegister = 0; this->dataRegister = 0;
} }
} }

View File

@ -1,159 +1,159 @@
/* /*
epple2 epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com> Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "card.h" #include "card.h"
#include "drive.h" #include "drive.h"
#include "drivemotor.h" #include "drivemotor.h"
#include "wozfile.h" #include "wozfile.h"
#include "lss.h" #include "lss.h"
#include "screenimage.h" #include "screenimage.h"
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <cstdint> #include <cstdint>
class DiskController : public Card class DiskController : public Card
{ {
private: private:
ScreenImage& gui; ScreenImage& gui;
int slot; int slot;
Disk2Drive drive1; Disk2Drive drive1;
Disk2Drive drive2; Disk2Drive drive2;
Disk2Drive* currentDrive; Disk2Drive* currentDrive;
bool load; // Q6 bool load; // Q6
bool write; // Q7 bool write; // Q7
bool ioStepped; bool ioStepped;
/* /*
* Only one drive's motor can be on at a time, * Only one drive's motor can be on at a time,
* so we only need one instance. * so we only need one instance.
*/ */
DriveMotor motor; DriveMotor motor;
// Maintain a copy of the last thing on the data bus, so it can // Maintain a copy of the last thing on the data bus, so it can
// be read by the LSS algorithm when needed. // be read by the LSS algorithm when needed.
std::uint8_t dataBusReadOnlyCopy; std::uint8_t dataBusReadOnlyCopy;
LSS lssp6rom; // the LSS PROM P6 chip (one command per sequence/state combination) LSS lssp6rom; // the LSS PROM P6 chip (one command per sequence/state combination)
std::uint8_t dataRegister; // C3 the controller's LS323 data register std::uint8_t dataRegister; // C3 the controller's LS323 data register
std::uint8_t seq; // A3 sequence control LS174 (current sequence number, 0-F) std::uint8_t seq; // A3 sequence control LS174 (current sequence number, 0-F)
// For ease of use, we store the 4-bit seq number in the _high order_ nibble here. // For ease of use, we store the 4-bit seq number in the _high order_ nibble here.
// On the real Apple the read pulse goes thru this LS174 too, but we don't emulate that here. // On the real Apple the read pulse goes thru this LS174 too, but we don't emulate that here.
std::uint8_t prev_seq; // remember previous seq, to determine if A7 changes (indicating write a 1 bit) std::uint8_t prev_seq; // remember previous seq, to determine if A7 changes (indicating write a 1 bit)
double t; // used to keep track of optimal bit timing interval double t; // used to keep track of optimal bit timing interval
// TODO for a rev. 0 motherboard, the disk controller will auto reset the CPU (see UA2, 9-13) // TODO for a rev. 0 motherboard, the disk controller will auto reset the CPU (see UA2, 9-13)
void writeBit(bool on) { void writeBit(bool on) {
if (!this->motor.isOn()) { if (!this->motor.isOn()) {
return; return;
} }
this->currentDrive->writeBit(on); this->currentDrive->writeBit(on);
} }
Disk2Drive& getDrive(const unsigned char drive) { Disk2Drive& getDrive(const unsigned char drive) {
return (drive == 0) ? this->drive1 : this->drive2; return (drive == 0) ? this->drive1 : this->drive2;
} }
Disk2Drive& getOtherDrive() { Disk2Drive& getOtherDrive() {
return (this->currentDrive == &this->drive1) ? this->drive2 : this->drive1; return (this->currentDrive == &this->drive1) ? this->drive2 : this->drive1;
} }
void rotateCurrentDisk(); void rotateCurrentDisk();
void stepLss(); void stepLss();
public: public:
DiskController(ScreenImage& gui, int slot, bool lss13, double random_ones_rate); DiskController(ScreenImage& gui, int slot, bool lss13, double random_ones_rate);
~DiskController(); ~DiskController();
void tick(); void tick();
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing); virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
void reset() { void reset() {
this->gui.setIO(this->slot,getCurrentDriveNumber(),false); this->gui.setIO(this->slot,getCurrentDriveNumber(),false);
this->gui.clearCurrentDrive(this->slot,getCurrentDriveNumber()); this->gui.clearCurrentDrive(this->slot,getCurrentDriveNumber());
this->currentDrive = &this->drive1; this->currentDrive = &this->drive1;
this->motor.reset(); this->motor.reset();
this->gui.setCurrentDrive(this->slot,getCurrentDriveNumber(),getTrack(),false); this->gui.setCurrentDrive(this->slot,getCurrentDriveNumber(),getTrack(),false);
} }
void loadDisk(unsigned char drive, const std::string& fnib) { void loadDisk(unsigned char drive, const std::string& fnib) {
if (!this->getDrive(drive).loadDisk(fnib)) { if (!this->getDrive(drive).loadDisk(fnib)) {
return; return;
} }
this->gui.setDiskFile(this->slot,drive,fnib); this->gui.setDiskFile(this->slot,drive,fnib);
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false); this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
} }
void unloadDisk(unsigned char drive) { void unloadDisk(unsigned char drive) {
this->getDrive(drive).unloadDisk(); this->getDrive(drive).unloadDisk();
this->gui.setDiskFile(this->slot,drive,""); this->gui.setDiskFile(this->slot,drive,"");
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false); this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
} }
void save(int drive) { void save(int drive) {
this->getDrive(drive).saveDisk(); this->getDrive(drive).saveDisk();
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false); this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
} }
bool isMotorOn() { bool isMotorOn() {
return this->motor.isOn(); return this->motor.isOn();
} }
unsigned char getTrack() { unsigned char getTrack() {
return this->currentDrive->getTrack(); return this->currentDrive->getTrack();
} }
bool isWriting() { bool isWriting() {
return this->write; return this->write;
} }
bool isModified() { bool isModified() {
return this->currentDrive->isModified(); return this->currentDrive->isModified();
} }
bool isModifiedOther() { bool isModifiedOther() {
return getOtherDrive().isModified(); return getOtherDrive().isModified();
} }
bool isWriteProtected() { bool isWriteProtected() {
return this->currentDrive->isWriteProtected(); return this->currentDrive->isWriteProtected();
} }
bool isDirty() { bool isDirty() {
return isModified() || isModifiedOther(); return isModified() || isModifiedOther();
} }
unsigned char getCurrentDriveNumber() { unsigned char getCurrentDriveNumber() {
return this->currentDrive == &this->drive1 ? 0 : 1; return this->currentDrive == &this->drive1 ? 0 : 1;
} }
unsigned char getOtherDriveNumber() { unsigned char getOtherDriveNumber() {
return 1-getCurrentDriveNumber(); return 1-getCurrentDriveNumber();
} }
virtual std::string getName() { virtual std::string getName() {
return "disk][ drive 1 drive 2 "; return "disk][ drive 1 drive 2 ";
} }
void dumpLss() { void dumpLss() {
this->lssp6rom.dump(); this->lssp6rom.dump();
} }
}; };

View File

@ -1,97 +1,97 @@
/* /*
epple2 epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com> Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "drive.h" #include "drive.h"
Disk2Drive::Disk2Drive(double p_random_ones_rate): Disk2Drive::Disk2Drive(double p_random_ones_rate):
stepper(head), stepper(head),
pulse(false), pulse(false),
bitBufferRead(0), bitBufferRead(0),
random_ones_rate(p_random_ones_rate), random_ones_rate(p_random_ones_rate),
generator(std::chrono::system_clock::now().time_since_epoch().count()), generator(std::chrono::system_clock::now().time_since_epoch().count()),
distribution(0.0,1.0) { distribution(0.0,1.0) {
} }
bool Disk2Drive::loadDisk(const std::string& fnib) { bool Disk2Drive::loadDisk(const std::string& fnib) {
return this->disk.load(fnib); return this->disk.load(fnib);
} }
void Disk2Drive::unloadDisk() { void Disk2Drive::unloadDisk() {
this->disk.unload(); this->disk.unload();
} }
bool Disk2Drive::isLoaded() const { bool Disk2Drive::isLoaded() const {
return this->disk.isLoaded(); return this->disk.isLoaded();
} }
void Disk2Drive::saveDisk() { void Disk2Drive::saveDisk() {
this->disk.save(); this->disk.save();
} }
bool Disk2Drive::isWriteProtected() const { bool Disk2Drive::isWriteProtected() const {
return this->disk.isWriteProtected(); return this->disk.isWriteProtected();
} }
bool Disk2Drive::isModified() const { bool Disk2Drive::isModified() const {
return this->disk.isModified(); return this->disk.isModified();
} }
int Disk2Drive::optimal_timing() const { int Disk2Drive::optimal_timing() const {
return this->disk.optimal_timing(); return this->disk.optimal_timing();
} }
int Disk2Drive::position() const { int Disk2Drive::position() const {
return this->head.position(); return this->head.position();
} }
void Disk2Drive::tick() { void Disk2Drive::tick() {
this->stepper.tick(); this->stepper.tick();
} }
void Disk2Drive::set_phase(int i_phase_0_to_3, bool on) { void Disk2Drive::set_phase(int i_phase_0_to_3, bool on) {
this->stepper.set_phase(i_phase_0_to_3, on); this->stepper.set_phase(i_phase_0_to_3, on);
} }
int Disk2Drive::getTrack() const { int Disk2Drive::getTrack() const {
return this->head.position() >> 2; return this->head.position() >> 2;
} }
void Disk2Drive::rotateDiskOneBit() { void Disk2Drive::rotateDiskOneBit() {
this->disk.rotateOneBit(this->head.position()); this->disk.rotateOneBit(this->head.position());
bitBufferRead <<= 1; bitBufferRead <<= 1;
const bool exists(this->disk.exists(this->head.position())); const bool exists(this->disk.exists(this->head.position()));
if (exists) { if (exists) {
bitBufferRead |= this->disk.getBit(this->head.position()); bitBufferRead |= this->disk.getBit(this->head.position());
} }
if ((bitBufferRead & 0x0Fu) && exists) { if ((bitBufferRead & 0x0Fu) && exists) {
this->pulse = (bitBufferRead & 0x02u) >> 1; this->pulse = (bitBufferRead & 0x02u) >> 1;
} else { } else {
this->pulse = randomBit(); this->pulse = randomBit();
} }
} }
bool Disk2Drive::readPulse() const { bool Disk2Drive::readPulse() const {
return this->pulse; return this->pulse;
} }
void Disk2Drive::clearPulse() { void Disk2Drive::clearPulse() {
this->pulse = false; this->pulse = false;
} }
void Disk2Drive::writeBit(bool on) { void Disk2Drive::writeBit(bool on) {
this->disk.setBit(this->head.position(), on); this->disk.setBit(this->head.position(), on);
} }

View File

@ -1,68 +1,68 @@
/* /*
epple2 epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com> Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef DRIVE_H #ifndef DRIVE_H
#define DRIVE_H #define DRIVE_H
#include <random> #include <random>
#include <chrono> #include <chrono>
#include <string> #include <string>
#include <cstdint> #include <cstdint>
#include <iostream> #include <iostream>
#include "disk2steppermotor.h" #include "disk2steppermotor.h"
#include "disk2readwritehead.h" #include "disk2readwritehead.h"
#include "wozfile.h" #include "wozfile.h"
class Disk2Drive { class Disk2Drive {
private: private:
Disk2StepperMotor stepper; Disk2StepperMotor stepper;
Disk2ReadWriteHead head; Disk2ReadWriteHead head;
WozFile disk; WozFile disk;
bool pulse; bool pulse;
std::uint8_t bitBufferRead; std::uint8_t bitBufferRead;
const double random_ones_rate; const double random_ones_rate;
std::default_random_engine generator; std::default_random_engine generator;
std::uniform_real_distribution<double> distribution; std::uniform_real_distribution<double> distribution;
bool randomBit() { bool randomBit() {
return distribution(generator) < random_ones_rate; return distribution(generator) < random_ones_rate;
} }
public: public:
Disk2Drive(double p_random_ones_rate); Disk2Drive(double p_random_ones_rate);
bool loadDisk(const std::string& fnib); bool loadDisk(const std::string& fnib);
void unloadDisk(); void unloadDisk();
bool isLoaded() const; bool isLoaded() const;
void saveDisk(); void saveDisk();
bool isWriteProtected() const; bool isWriteProtected() const;
bool isModified() const; bool isModified() const;
int optimal_timing() const; int optimal_timing() const;
int position() const; int position() const;
void tick(); void tick();
void set_phase(int i_phase_0_to_3, bool on); void set_phase(int i_phase_0_to_3, bool on);
int getTrack() const; int getTrack() const;
void rotateDiskOneBit(); void rotateDiskOneBit();
bool readPulse() const; bool readPulse() const;
void clearPulse(); void clearPulse();
void writeBit(bool on); void writeBit(bool on);
}; };
#endif #endif

View File

@ -1,169 +1,169 @@
/* /*
epple2 epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com> Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef E2CONST_H #ifndef E2CONST_H
#define E2CONST_H #define E2CONST_H
class E2Const class E2Const
{ {
public: public:
/* /*
The NTSC standard defines the field rate as 60 fields per second. The number 60 The NTSC standard defines the field rate as 60 fields per second. The number 60
is based on the USA AC current frequency of 60 Hz. This, in turn, was based on the is based on the USA AC current frequency of 60 Hz. This, in turn, was based on the
clock standard (60 seconds per minute and 60 minutes per hour). clock standard (60 seconds per minute and 60 minutes per hour).
*/ */
static const int NTSC_FIELD_HZ = 60; static const int NTSC_FIELD_HZ = 60;
/* /*
The NTSC standard defines 525 lines per frame, which was chosen to be a multiple The NTSC standard defines 525 lines per frame, which was chosen to be a multiple
of a small number of standard tubes at the time, to produce a rate between RCA's of a small number of standard tubes at the time, to produce a rate between RCA's
recommended 441 (used by NBC) and Philco's suggested 600-800 lines. recommended 441 (used by NBC) and Philco's suggested 600-800 lines.
*/ */
static const int NTSC_LINES_PER_FRAME = 3*5*5*7; static const int NTSC_LINES_PER_FRAME = 3*5*5*7;
/* /*
When color was added to the NTSC signal, studies by General Electric showed that When color was added to the NTSC signal, studies by General Electric showed that
minimum interference was achieved using a subcarrier frequency 455 times the field minimum interference was achieved using a subcarrier frequency 455 times the field
rate, which can also be obtained using standard tubes. rate, which can also be obtained using standard tubes.
*/ */
static const int NTSC_COLOR_MULTIPLE = 5*7*13; static const int NTSC_COLOR_MULTIPLE = 5*7*13;
/* /*
Adding color to NTSC also required slowing down the frame rate, by dropping one Adding color to NTSC also required slowing down the frame rate, by dropping one
field after every 1000. field after every 1000.
*/ */
static const int NTSC_COLOR_DROP_FIELD = 1000; static const int NTSC_COLOR_DROP_FIELD = 1000;
/* /*
Calculate the color sub-channel rate, times 4. Calculate the color sub-channel rate, times 4.
This will be the (approximate) Hz of the "14M" This will be the (approximate) Hz of the "14M"
crystal oscillator in the Apple ][. crystal oscillator in the Apple ][.
14318181.818181818... Hz rounds to 14318182 Hz 14318181.818181818... Hz rounds to 14318182 Hz
U.A.II, p.3-2 U.A.II, p.3-2
*/ */
static const int CRYSTAL_HZ = (int)(1.0F*NTSC_FIELD_HZ * NTSC_LINES_PER_FRAME * NTSC_COLOR_MULTIPLE * NTSC_COLOR_DROP_FIELD / (NTSC_COLOR_DROP_FIELD+1)); static const int CRYSTAL_HZ = (int)(1.0F*NTSC_FIELD_HZ * NTSC_LINES_PER_FRAME * NTSC_COLOR_MULTIPLE * NTSC_COLOR_DROP_FIELD / (NTSC_COLOR_DROP_FIELD+1));
/* /*
U.A.II, p. 3-3 U.A.II, p. 3-3
Normal 6502 cycle == 14 crystal periods Normal 6502 cycle == 14 crystal periods
Long 6502 cycle == 16 crystal periods Long 6502 cycle == 16 crystal periods
*/ */
static const int CRYSTAL_CYCLES_PER_CPU_CYCLE = 14; static const int CRYSTAL_CYCLES_PER_CPU_CYCLE = 14;
static const int EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE = 2; static const int EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE = 2;
/* /*
65 bytes per row (64 normal CPU cycles plus one long CPU cycle) 65 bytes per row (64 normal CPU cycles plus one long CPU cycle)
*/ */
static const int BYTES_PER_ROW = (int)((NTSC_COLOR_DROP_FIELD+1)*1.0F*CRYSTAL_HZ/(NTSC_FIELD_HZ/2*NTSC_COLOR_DROP_FIELD*NTSC_LINES_PER_FRAME*CRYSTAL_CYCLES_PER_CPU_CYCLE)); static const int BYTES_PER_ROW = (int)((NTSC_COLOR_DROP_FIELD+1)*1.0F*CRYSTAL_HZ/(NTSC_FIELD_HZ/2*NTSC_COLOR_DROP_FIELD*NTSC_LINES_PER_FRAME*CRYSTAL_CYCLES_PER_CPU_CYCLE));
static const int HORIZ_CYCLES = BYTES_PER_ROW; static const int HORIZ_CYCLES = BYTES_PER_ROW;
/* /*
U.A.II, p. 3-2, "composite frequency... 1.0205 MHz" U.A.II, p. 3-2, "composite frequency... 1.0205 MHz"
Actually 1020484 Hz. Actually 1020484 Hz.
*/ */
static const int AVG_CPU_HZ = (int)((1.0F*CRYSTAL_HZ*HORIZ_CYCLES)/(CRYSTAL_CYCLES_PER_CPU_CYCLE*HORIZ_CYCLES+EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE)); static const int AVG_CPU_HZ = (int)((1.0F*CRYSTAL_HZ*HORIZ_CYCLES)/(CRYSTAL_CYCLES_PER_CPU_CYCLE*HORIZ_CYCLES+EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE));
/* /*
A normal NTSC field is 262.5 lines (half of a full frame's 525 lines). A normal NTSC field is 262.5 lines (half of a full frame's 525 lines).
The Apple rounds this down to 262 lines. The Apple rounds this down to 262 lines.
*/ */
static const int NTSC_WHOLE_LINES_PER_FIELD = NTSC_LINES_PER_FRAME/2; static const int NTSC_WHOLE_LINES_PER_FIELD = NTSC_LINES_PER_FRAME/2;
static const int BYTES_PER_FIELD = BYTES_PER_ROW*NTSC_WHOLE_LINES_PER_FIELD; static const int BYTES_PER_FIELD = BYTES_PER_ROW*NTSC_WHOLE_LINES_PER_FIELD;
// exactly 1 million // exactly 1 million
static const int MEGA = 1000000; static const int MEGA = 1000000;
static const int VISIBLE_BITS_PER_BYTE = 7; static const int VISIBLE_BITS_PER_BYTE = 7;
static const int VISIBLE_LINES_PER_CHARACTER = 8; static const int VISIBLE_LINES_PER_CHARACTER = 8;
/* /*
* 1000+1 seconds 2 fields 1 frame 1000000 microseconds 63 50 * 1000+1 seconds 2 fields 1 frame 1000000 microseconds 63 50
* total horizontal line period = -------------- * -------- * ------------- * -------------------- = ( -- + -- ) microseconds per line * total horizontal line period = -------------- * -------- * ------------- * -------------------- = ( -- + -- ) microseconds per line
* 60*1000 fields 1 frame 3*5*5*7 lines 1 second 90 * 60*1000 fields 1 frame 3*5*5*7 lines 1 second 90
* *
* 10 81 * 10 81
* horizontal blanking period = (1.5+4.7+.6+2.5+1.6) = 10.9 microseconds per line = ( -- + -- ) microseconds per line * horizontal blanking period = (1.5+4.7+.6+2.5+1.6) = 10.9 microseconds per line = ( -- + -- ) microseconds per line
* 90 * 90
* *
* visible line period = total horizontal line period minus horizontal blanking period = * visible line period = total horizontal line period minus horizontal blanking period =
* *
* 52 59 * 52 59
* -- + -- microseconds per line * -- + -- microseconds per line
* 90 * 90
* *
* *
* To avoid the over-scan area, the Apple ][ uses only the middle 75% of the visible line, or 4739/120 microseconds * To avoid the over-scan area, the Apple ][ uses only the middle 75% of the visible line, or 4739/120 microseconds
* *
* Apple ][ uses half the clock rate, or 315/44 MHz, to oscillate the video signal. * Apple ][ uses half the clock rate, or 315/44 MHz, to oscillate the video signal.
* *
* The result is 315/44 MHz * 4739/120 microseconds/line, rounded down, = 282 full pixel spots across the screen. * The result is 315/44 MHz * 4739/120 microseconds/line, rounded down, = 282 full pixel spots across the screen.
* The Apple ][ displays 7 bits per byte hi-res or lo-res, (or 7 pixel-wide characters for text mode), so that * The Apple ][ displays 7 bits per byte hi-res or lo-res, (or 7 pixel-wide characters for text mode), so that
* gives 282/7, which rounds down to 40 bytes per line. * gives 282/7, which rounds down to 40 bytes per line.
*/ */
static const int VISIBLE_BYTES_PER_ROW = (int)((((1.0F*(NTSC_COLOR_DROP_FIELD+1)/(NTSC_FIELD_HZ*NTSC_COLOR_DROP_FIELD)*2/NTSC_LINES_PER_FRAME*MEGA)-(1.5+4.7+.6+2.5+1.6)) * 3/4) * (CRYSTAL_HZ/2)) / MEGA / VISIBLE_BITS_PER_BYTE; static const int VISIBLE_BYTES_PER_ROW = (int)((((1.0F*(NTSC_COLOR_DROP_FIELD+1)/(NTSC_FIELD_HZ*NTSC_COLOR_DROP_FIELD)*2/NTSC_LINES_PER_FRAME*MEGA)-(1.5+4.7+.6+2.5+1.6)) * 3/4) * (CRYSTAL_HZ/2)) / MEGA / VISIBLE_BITS_PER_BYTE;
/* /*
* NTSC total lines per frame (525) minus unusable lines (19 plus 20) = 486 usable lines * NTSC total lines per frame (525) minus unusable lines (19 plus 20) = 486 usable lines
* To avoid the over-scan area, use the middle 80% of the vertical lines, giving 388 (rounded down) clearly visible lines * To avoid the over-scan area, use the middle 80% of the vertical lines, giving 388 (rounded down) clearly visible lines
* Apple ][ uses only half the vertical resolution because it doesn't interlace, giving 194. * Apple ][ uses only half the vertical resolution because it doesn't interlace, giving 194.
* Text characters are 8 pixels tall, so 194/8 rounded down gives 24 text lines. * Text characters are 8 pixels tall, so 194/8 rounded down gives 24 text lines.
* Multiply by 8 to give 192 lines total. * Multiply by 8 to give 192 lines total.
*/ */
static const int VISIBLE_ROWS_PER_FIELD = (NTSC_LINES_PER_FRAME-(20+19)) * 8/10 / 2 /VISIBLE_LINES_PER_CHARACTER*VISIBLE_LINES_PER_CHARACTER; static const int VISIBLE_ROWS_PER_FIELD = (NTSC_LINES_PER_FRAME-(20+19)) * 8/10 / 2 /VISIBLE_LINES_PER_CHARACTER*VISIBLE_LINES_PER_CHARACTER;
static const int BLANKED_BYTES_PER_ROW = BYTES_PER_ROW-VISIBLE_BYTES_PER_ROW; static const int BLANKED_BYTES_PER_ROW = BYTES_PER_ROW-VISIBLE_BYTES_PER_ROW;
static const int VISIBLE_BYTES_PER_FIELD = BYTES_PER_ROW*VISIBLE_ROWS_PER_FIELD; static const int VISIBLE_BYTES_PER_FIELD = BYTES_PER_ROW*VISIBLE_ROWS_PER_FIELD;
static const int SCANNABLE_ROWS = 0x100; static const int SCANNABLE_ROWS = 0x100;
static const int SCANNABLE_BYTES = SCANNABLE_ROWS*BYTES_PER_ROW; static const int SCANNABLE_BYTES = SCANNABLE_ROWS*BYTES_PER_ROW;
static const int RESET_ROWS = NTSC_WHOLE_LINES_PER_FIELD-SCANNABLE_ROWS; static const int RESET_ROWS = NTSC_WHOLE_LINES_PER_FIELD-SCANNABLE_ROWS;
static const int RESET_BYTES = RESET_ROWS*BYTES_PER_ROW; static const int RESET_BYTES = RESET_ROWS*BYTES_PER_ROW;
static const int MIXED_TEXT_LINES = 4; static const int MIXED_TEXT_LINES = 4;
static const int ROWS_PER_TEXT_LINE = 8; static const int ROWS_PER_TEXT_LINE = 8;
static const int MIXED_TEXT_CYCLE = (VISIBLE_ROWS_PER_FIELD-MIXED_TEXT_LINES*ROWS_PER_TEXT_LINE)*BYTES_PER_ROW; static const int MIXED_TEXT_CYCLE = (VISIBLE_ROWS_PER_FIELD-MIXED_TEXT_LINES*ROWS_PER_TEXT_LINE)*BYTES_PER_ROW;
static int test() static int test()
{ {
if (NTSC_FIELD_HZ!=60) return NTSC_FIELD_HZ; if (NTSC_FIELD_HZ!=60) return NTSC_FIELD_HZ;
if (NTSC_LINES_PER_FRAME!=525) return NTSC_LINES_PER_FRAME; if (NTSC_LINES_PER_FRAME!=525) return NTSC_LINES_PER_FRAME;
if (NTSC_COLOR_MULTIPLE!=455) return NTSC_COLOR_MULTIPLE; if (NTSC_COLOR_MULTIPLE!=455) return NTSC_COLOR_MULTIPLE;
if (NTSC_COLOR_DROP_FIELD!=1000) return NTSC_COLOR_DROP_FIELD; if (NTSC_COLOR_DROP_FIELD!=1000) return NTSC_COLOR_DROP_FIELD;
if (CRYSTAL_HZ!=14318182) return CRYSTAL_HZ; if (CRYSTAL_HZ!=14318182) return CRYSTAL_HZ;
if (BYTES_PER_ROW!=65) return BYTES_PER_ROW; if (BYTES_PER_ROW!=65) return BYTES_PER_ROW;
if (AVG_CPU_HZ!=1020484) return AVG_CPU_HZ; if (AVG_CPU_HZ!=1020484) return AVG_CPU_HZ;
if (BYTES_PER_FIELD!=17030) return BYTES_PER_FIELD; if (BYTES_PER_FIELD!=17030) return BYTES_PER_FIELD;
if (VISIBLE_BYTES_PER_ROW!=40) return VISIBLE_BYTES_PER_ROW; if (VISIBLE_BYTES_PER_ROW!=40) return VISIBLE_BYTES_PER_ROW;
if (VISIBLE_ROWS_PER_FIELD!=192) return VISIBLE_ROWS_PER_FIELD; if (VISIBLE_ROWS_PER_FIELD!=192) return VISIBLE_ROWS_PER_FIELD;
if (RESET_BYTES!=390) return RESET_BYTES; if (RESET_BYTES!=390) return RESET_BYTES;
if (BLANKED_BYTES_PER_ROW!=25) return BLANKED_BYTES_PER_ROW; if (BLANKED_BYTES_PER_ROW!=25) return BLANKED_BYTES_PER_ROW;
if (VISIBLE_BYTES_PER_FIELD!=12480) return VISIBLE_BYTES_PER_FIELD; if (VISIBLE_BYTES_PER_FIELD!=12480) return VISIBLE_BYTES_PER_FIELD;
if (SCANNABLE_BYTES!=16640) return SCANNABLE_BYTES; if (SCANNABLE_BYTES!=16640) return SCANNABLE_BYTES;
return -1; return -1;
} }
}; };
#endif #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,303 +1,303 @@
/* If you are using a C++ compiler to compile tinyfiledialogs.c (maybe renamed with an extension ".cpp") /* If you are using a C++ compiler to compile tinyfiledialogs.c (maybe renamed with an extension ".cpp")
then comment out << extern "C" >> bellow in this header file) */ then comment out << extern "C" >> bellow in this header file) */
/*_________ /*_________
/ \ tinyfiledialogs.h v3.8.9 [Oct 27, 2022] zlib licence / \ tinyfiledialogs.h v3.8.9 [Oct 27, 2022] zlib licence
|tiny file| Unique header file created [November 9, 2014] |tiny file| Unique header file created [November 9, 2014]
| dialogs | Copyright (c) 2014 - 2021 Guillaume Vareille http://ysengrin.com | dialogs | Copyright (c) 2014 - 2021 Guillaume Vareille http://ysengrin.com
\____ ___/ http://tinyfiledialogs.sourceforge.net \____ ___/ http://tinyfiledialogs.sourceforge.net
\| git clone http://git.code.sf.net/p/tinyfiledialogs/code tinyfd \| git clone http://git.code.sf.net/p/tinyfiledialogs/code tinyfd
____________________________________________ ____________________________________________
| | | |
| email: tinyfiledialogs at ysengrin.com | | email: tinyfiledialogs at ysengrin.com |
|____________________________________________| |____________________________________________|
________________________________________________________________________________ ________________________________________________________________________________
| ____________________________________________________________________________ | | ____________________________________________________________________________ |
| | | | | | | |
| | on windows: | | | | on windows: | |
| | - for UTF-16, use the wchar_t functions at the bottom of the header file | | | | - for UTF-16, use the wchar_t functions at the bottom of the header file | |
| | - _wfopen() requires wchar_t | | | | - _wfopen() requires wchar_t | |
| | | | | | | |
| | - in tinyfiledialogs, char is UTF-8 by default (since v3.6) | | | | - in tinyfiledialogs, char is UTF-8 by default (since v3.6) | |
| | - but fopen() expects MBCS (not UTF-8) | | | | - but fopen() expects MBCS (not UTF-8) | |
| | - if you want char to be MBCS: set tinyfd_winUtf8 to 0 | | | | - if you want char to be MBCS: set tinyfd_winUtf8 to 0 | |
| | | | | | | |
| | - alternatively, tinyfiledialogs provides | | | | - alternatively, tinyfiledialogs provides | |
| | functions to convert between UTF-8, UTF-16 and MBCS | | | | functions to convert between UTF-8, UTF-16 and MBCS | |
| |____________________________________________________________________________| | | |____________________________________________________________________________| |
|________________________________________________________________________________| |________________________________________________________________________________|
If you like tinyfiledialogs, please upvote my stackoverflow answer If you like tinyfiledialogs, please upvote my stackoverflow answer
https://stackoverflow.com/a/47651444 https://stackoverflow.com/a/47651444
- License - - License -
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
arising from the use of this software. arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions: freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not 1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be in a product, an acknowledgment in the product documentation would be
appreciated but is not required. appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#ifndef TINYFILEDIALOGS_H #ifndef TINYFILEDIALOGS_H
#define TINYFILEDIALOGS_H #define TINYFILEDIALOGS_H
#ifdef __cplusplus #ifdef __cplusplus
/* if tinydialogs.c is compiled as C++ code rather than C code, you may need to comment this out /* if tinydialogs.c is compiled as C++ code rather than C code, you may need to comment this out
and the corresponding closing bracket near the end of this file. */ and the corresponding closing bracket near the end of this file. */
extern "C" { extern "C" {
#endif #endif
/******************************************************************************************************/ /******************************************************************************************************/
/**************************************** UTF-8 on Windows ********************************************/ /**************************************** UTF-8 on Windows ********************************************/
/******************************************************************************************************/ /******************************************************************************************************/
#ifdef _WIN32 #ifdef _WIN32
/* On windows, if you want to use UTF-8 ( instead of the UTF-16/wchar_t functions at the end of this file ) /* On windows, if you want to use UTF-8 ( instead of the UTF-16/wchar_t functions at the end of this file )
Make sure your code is really prepared for UTF-8 (on windows, functions like fopen() expect MBCS and not UTF-8) */ Make sure your code is really prepared for UTF-8 (on windows, functions like fopen() expect MBCS and not UTF-8) */
extern int tinyfd_winUtf8; /* on windows char strings can be 1:UTF-8(default) or 0:MBCS */ extern int tinyfd_winUtf8; /* on windows char strings can be 1:UTF-8(default) or 0:MBCS */
/* for MBCS change this to 0, in tinyfiledialogs.c or in your code */ /* for MBCS change this to 0, in tinyfiledialogs.c or in your code */
/* Here are some functions to help you convert between UTF-16 UTF-8 MBSC */ /* Here are some functions to help you convert between UTF-16 UTF-8 MBSC */
char * tinyfd_utf8toMbcs(char const * aUtf8string); char * tinyfd_utf8toMbcs(char const * aUtf8string);
char * tinyfd_utf16toMbcs(wchar_t const * aUtf16string); char * tinyfd_utf16toMbcs(wchar_t const * aUtf16string);
wchar_t * tinyfd_mbcsTo16(char const * aMbcsString); wchar_t * tinyfd_mbcsTo16(char const * aMbcsString);
char * tinyfd_mbcsTo8(char const * aMbcsString); char * tinyfd_mbcsTo8(char const * aMbcsString);
wchar_t * tinyfd_utf8to16(char const * aUtf8string); wchar_t * tinyfd_utf8to16(char const * aUtf8string);
char * tinyfd_utf16to8(wchar_t const * aUtf16string); char * tinyfd_utf16to8(wchar_t const * aUtf16string);
#endif #endif
/******************************************************************************************************/ /******************************************************************************************************/
/******************************************************************************************************/ /******************************************************************************************************/
/******************************************************************************************************/ /******************************************************************************************************/
/************* 3 funtions for C# (you don't need this in C or C++) : */ /************* 3 funtions for C# (you don't need this in C or C++) : */
char const * tinyfd_getGlobalChar(char const * aCharVariableName); /* returns NULL on error */ char const * tinyfd_getGlobalChar(char const * aCharVariableName); /* returns NULL on error */
int tinyfd_getGlobalInt(char const * aIntVariableName); /* returns -1 on error */ int tinyfd_getGlobalInt(char const * aIntVariableName); /* returns -1 on error */
int tinyfd_setGlobalInt(char const * aIntVariableName, int aValue); /* returns -1 on error */ int tinyfd_setGlobalInt(char const * aIntVariableName, int aValue); /* returns -1 on error */
/* aCharVariableName: "tinyfd_version" "tinyfd_needs" "tinyfd_response" /* aCharVariableName: "tinyfd_version" "tinyfd_needs" "tinyfd_response"
aIntVariableName : "tinyfd_verbose" "tinyfd_silent" "tinyfd_allowCursesDialogs" aIntVariableName : "tinyfd_verbose" "tinyfd_silent" "tinyfd_allowCursesDialogs"
"tinyfd_forceConsole" "tinyfd_assumeGraphicDisplay" "tinyfd_winUtf8" "tinyfd_forceConsole" "tinyfd_assumeGraphicDisplay" "tinyfd_winUtf8"
**************/ **************/
extern char tinyfd_version[8]; /* contains tinyfd current version number */ extern char tinyfd_version[8]; /* contains tinyfd current version number */
extern char tinyfd_needs[]; /* info about requirements */ extern char tinyfd_needs[]; /* info about requirements */
extern int tinyfd_verbose; /* 0 (default) or 1 : on unix, prints the command line calls */ extern int tinyfd_verbose; /* 0 (default) or 1 : on unix, prints the command line calls */
extern int tinyfd_silent; /* 1 (default) or 0 : on unix, hide errors and warnings from called dialogs */ extern int tinyfd_silent; /* 1 (default) or 0 : on unix, hide errors and warnings from called dialogs */
/* Curses dialogs are difficult to use, on windows they are only ascii and uses the unix backslah */ /* Curses dialogs are difficult to use, on windows they are only ascii and uses the unix backslah */
extern int tinyfd_allowCursesDialogs; /* 0 (default) or 1 */ extern int tinyfd_allowCursesDialogs; /* 0 (default) or 1 */
extern int tinyfd_forceConsole; /* 0 (default) or 1 */ extern int tinyfd_forceConsole; /* 0 (default) or 1 */
/* for unix & windows: 0 (graphic mode) or 1 (console mode). /* for unix & windows: 0 (graphic mode) or 1 (console mode).
0: try to use a graphic solution, if it fails then it uses console mode. 0: try to use a graphic solution, if it fails then it uses console mode.
1: forces all dialogs into console mode even when an X server is present, 1: forces all dialogs into console mode even when an X server is present,
it can use the package dialog or dialog.exe. it can use the package dialog or dialog.exe.
on windows it only make sense for console applications */ on windows it only make sense for console applications */
extern int tinyfd_assumeGraphicDisplay; /* 0 (default) or 1 */ extern int tinyfd_assumeGraphicDisplay; /* 0 (default) or 1 */
/* some systems don't set the environment variable DISPLAY even when a graphic display is present. /* some systems don't set the environment variable DISPLAY even when a graphic display is present.
set this to 1 to tell tinyfiledialogs to assume the existence of a graphic display */ set this to 1 to tell tinyfiledialogs to assume the existence of a graphic display */
extern char tinyfd_response[1024]; extern char tinyfd_response[1024];
/* if you pass "tinyfd_query" as aTitle, /* if you pass "tinyfd_query" as aTitle,
the functions will not display the dialogs the functions will not display the dialogs
but will return 0 for console mode, 1 for graphic mode. but will return 0 for console mode, 1 for graphic mode.
tinyfd_response is then filled with the retain solution. tinyfd_response is then filled with the retain solution.
possible values for tinyfd_response are (all lowercase) possible values for tinyfd_response are (all lowercase)
for graphic mode: for graphic mode:
windows_wchar windows applescript kdialog zenity zenity3 matedialog windows_wchar windows applescript kdialog zenity zenity3 matedialog
shellementary qarma yad python2-tkinter python3-tkinter python-dbus shellementary qarma yad python2-tkinter python3-tkinter python-dbus
perl-dbus gxmessage gmessage xmessage xdialog gdialog perl-dbus gxmessage gmessage xmessage xdialog gdialog
for console mode: for console mode:
dialog whiptail basicinput no_solution */ dialog whiptail basicinput no_solution */
void tinyfd_beep(void); void tinyfd_beep(void);
int tinyfd_notifyPopup( int tinyfd_notifyPopup(
char const * aTitle, /* NULL or "" */ char const * aTitle, /* NULL or "" */
char const * aMessage, /* NULL or "" may contain \n \t */ char const * aMessage, /* NULL or "" may contain \n \t */
char const * aIconType); /* "info" "warning" "error" */ char const * aIconType); /* "info" "warning" "error" */
/* return has only meaning for tinyfd_query */ /* return has only meaning for tinyfd_query */
int tinyfd_messageBox( int tinyfd_messageBox(
char const * aTitle , /* NULL or "" */ char const * aTitle , /* NULL or "" */
char const * aMessage , /* NULL or "" may contain \n \t */ char const * aMessage , /* NULL or "" may contain \n \t */
char const * aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */ char const * aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */
char const * aIconType , /* "info" "warning" "error" "question" */ char const * aIconType , /* "info" "warning" "error" "question" */
int aDefaultButton ) ; int aDefaultButton ) ;
/* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */
char * tinyfd_inputBox( char * tinyfd_inputBox(
char const * aTitle , /* NULL or "" */ char const * aTitle , /* NULL or "" */
char const * aMessage , /* NULL or "" (\n and \t have no effect) */ char const * aMessage , /* NULL or "" (\n and \t have no effect) */
char const * aDefaultInput ) ; /* NULL passwordBox, "" inputbox */ char const * aDefaultInput ) ; /* NULL passwordBox, "" inputbox */
/* returns NULL on cancel */ /* returns NULL on cancel */
char * tinyfd_saveFileDialog( char * tinyfd_saveFileDialog(
char const * aTitle , /* NULL or "" */ char const * aTitle , /* NULL or "" */
char const * aDefaultPathAndFile , /* NULL or "" */ char const * aDefaultPathAndFile , /* NULL or "" */
int aNumOfFilterPatterns , /* 0 (1 in the following example) */ int aNumOfFilterPatterns , /* 0 (1 in the following example) */
char const * const * aFilterPatterns , /* NULL or char const * lFilterPatterns[1]={"*.txt"} */ char const * const * aFilterPatterns , /* NULL or char const * lFilterPatterns[1]={"*.txt"} */
char const * aSingleFilterDescription ) ; /* NULL or "text files" */ char const * aSingleFilterDescription ) ; /* NULL or "text files" */
/* returns NULL on cancel */ /* returns NULL on cancel */
char * tinyfd_openFileDialog( char * tinyfd_openFileDialog(
char const * aTitle, /* NULL or "" */ char const * aTitle, /* NULL or "" */
char const * aDefaultPathAndFile, /* NULL or "" */ char const * aDefaultPathAndFile, /* NULL or "" */
int aNumOfFilterPatterns , /* 0 (2 in the following example) */ int aNumOfFilterPatterns , /* 0 (2 in the following example) */
char const * const * aFilterPatterns, /* NULL or char const * lFilterPatterns[2]={"*.png","*.jpg"}; */ char const * const * aFilterPatterns, /* NULL or char const * lFilterPatterns[2]={"*.png","*.jpg"}; */
char const * aSingleFilterDescription, /* NULL or "image files" */ char const * aSingleFilterDescription, /* NULL or "image files" */
int aAllowMultipleSelects ) ; /* 0 or 1 */ int aAllowMultipleSelects ) ; /* 0 or 1 */
/* in case of multiple files, the separator is | */ /* in case of multiple files, the separator is | */
/* returns NULL on cancel */ /* returns NULL on cancel */
char * tinyfd_selectFolderDialog( char * tinyfd_selectFolderDialog(
char const * aTitle, /* NULL or "" */ char const * aTitle, /* NULL or "" */
char const * aDefaultPath); /* NULL or "" */ char const * aDefaultPath); /* NULL or "" */
/* returns NULL on cancel */ /* returns NULL on cancel */
char * tinyfd_colorChooser( char * tinyfd_colorChooser(
char const * aTitle, /* NULL or "" */ char const * aTitle, /* NULL or "" */
char const * aDefaultHexRGB, /* NULL or "#FF0000" */ char const * aDefaultHexRGB, /* NULL or "#FF0000" */
unsigned char const aDefaultRGB[3] , /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */ unsigned char const aDefaultRGB[3] , /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */
unsigned char aoResultRGB[3] ) ; /* unsigned char lResultRGB[3]; */ unsigned char aoResultRGB[3] ) ; /* unsigned char lResultRGB[3]; */
/* returns the hexcolor as a string "#FF0000" */ /* returns the hexcolor as a string "#FF0000" */
/* aoResultRGB also contains the result */ /* aoResultRGB also contains the result */
/* aDefaultRGB is used only if aDefaultHexRGB is NULL */ /* aDefaultRGB is used only if aDefaultHexRGB is NULL */
/* aDefaultRGB and aoResultRGB can be the same array */ /* aDefaultRGB and aoResultRGB can be the same array */
/* returns NULL on cancel */ /* returns NULL on cancel */
/************ WINDOWS ONLY SECTION ************************/ /************ WINDOWS ONLY SECTION ************************/
#ifdef _WIN32 #ifdef _WIN32
/* windows only - utf-16 version */ /* windows only - utf-16 version */
int tinyfd_notifyPopupW( int tinyfd_notifyPopupW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aMessage, /* NULL or L"" may contain \n \t */ wchar_t const * aMessage, /* NULL or L"" may contain \n \t */
wchar_t const * aIconType); /* L"info" L"warning" L"error" */ wchar_t const * aIconType); /* L"info" L"warning" L"error" */
/* windows only - utf-16 version */ /* windows only - utf-16 version */
int tinyfd_messageBoxW( int tinyfd_messageBoxW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aMessage, /* NULL or L"" may contain \n \t */ wchar_t const * aMessage, /* NULL or L"" may contain \n \t */
wchar_t const * aDialogType, /* L"ok" L"okcancel" L"yesno" */ wchar_t const * aDialogType, /* L"ok" L"okcancel" L"yesno" */
wchar_t const * aIconType, /* L"info" L"warning" L"error" L"question" */ wchar_t const * aIconType, /* L"info" L"warning" L"error" L"question" */
int aDefaultButton ); /* 0 for cancel/no , 1 for ok/yes */ int aDefaultButton ); /* 0 for cancel/no , 1 for ok/yes */
/* returns 0 for cancel/no , 1 for ok/yes */ /* returns 0 for cancel/no , 1 for ok/yes */
/* windows only - utf-16 version */ /* windows only - utf-16 version */
wchar_t * tinyfd_inputBoxW( wchar_t * tinyfd_inputBoxW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aMessage, /* NULL or L"" (\n nor \t not respected) */ wchar_t const * aMessage, /* NULL or L"" (\n nor \t not respected) */
wchar_t const * aDefaultInput); /* NULL passwordBox, L"" inputbox */ wchar_t const * aDefaultInput); /* NULL passwordBox, L"" inputbox */
/* windows only - utf-16 version */ /* windows only - utf-16 version */
wchar_t * tinyfd_saveFileDialogW( wchar_t * tinyfd_saveFileDialogW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultPathAndFile, /* NULL or L"" */ wchar_t const * aDefaultPathAndFile, /* NULL or L"" */
int aNumOfFilterPatterns, /* 0 (1 in the following example) */ int aNumOfFilterPatterns, /* 0 (1 in the following example) */
wchar_t const * const * aFilterPatterns, /* NULL or wchar_t const * lFilterPatterns[1]={L"*.txt"} */ wchar_t const * const * aFilterPatterns, /* NULL or wchar_t const * lFilterPatterns[1]={L"*.txt"} */
wchar_t const * aSingleFilterDescription); /* NULL or L"text files" */ wchar_t const * aSingleFilterDescription); /* NULL or L"text files" */
/* returns NULL on cancel */ /* returns NULL on cancel */
/* windows only - utf-16 version */ /* windows only - utf-16 version */
wchar_t * tinyfd_openFileDialogW( wchar_t * tinyfd_openFileDialogW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultPathAndFile, /* NULL or L"" */ wchar_t const * aDefaultPathAndFile, /* NULL or L"" */
int aNumOfFilterPatterns , /* 0 (2 in the following example) */ int aNumOfFilterPatterns , /* 0 (2 in the following example) */
wchar_t const * const * aFilterPatterns, /* NULL or wchar_t const * lFilterPatterns[2]={L"*.png","*.jpg"} */ wchar_t const * const * aFilterPatterns, /* NULL or wchar_t const * lFilterPatterns[2]={L"*.png","*.jpg"} */
wchar_t const * aSingleFilterDescription, /* NULL or L"image files" */ wchar_t const * aSingleFilterDescription, /* NULL or L"image files" */
int aAllowMultipleSelects ) ; /* 0 or 1 */ int aAllowMultipleSelects ) ; /* 0 or 1 */
/* in case of multiple files, the separator is | */ /* in case of multiple files, the separator is | */
/* returns NULL on cancel */ /* returns NULL on cancel */
/* windows only - utf-16 version */ /* windows only - utf-16 version */
wchar_t * tinyfd_selectFolderDialogW( wchar_t * tinyfd_selectFolderDialogW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultPath); /* NULL or L"" */ wchar_t const * aDefaultPath); /* NULL or L"" */
/* returns NULL on cancel */ /* returns NULL on cancel */
/* windows only - utf-16 version */ /* windows only - utf-16 version */
wchar_t * tinyfd_colorChooserW( wchar_t * tinyfd_colorChooserW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultHexRGB, /* NULL or L"#FF0000" */ wchar_t const * aDefaultHexRGB, /* NULL or L"#FF0000" */
unsigned char const aDefaultRGB[3], /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */ unsigned char const aDefaultRGB[3], /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */
unsigned char aoResultRGB[3]); /* unsigned char lResultRGB[3]; */ unsigned char aoResultRGB[3]); /* unsigned char lResultRGB[3]; */
/* returns the hexcolor as a string L"#FF0000" */ /* returns the hexcolor as a string L"#FF0000" */
/* aoResultRGB also contains the result */ /* aoResultRGB also contains the result */
/* aDefaultRGB is used only if aDefaultHexRGB is NULL */ /* aDefaultRGB is used only if aDefaultHexRGB is NULL */
/* aDefaultRGB and aoResultRGB can be the same array */ /* aDefaultRGB and aoResultRGB can be the same array */
/* returns NULL on cancel */ /* returns NULL on cancel */
#endif /*_WIN32 */ #endif /*_WIN32 */
#ifdef __cplusplus #ifdef __cplusplus
} /*extern "C"*/ } /*extern "C"*/
#endif #endif
#endif /* TINYFILEDIALOGS_H */ #endif /* TINYFILEDIALOGS_H */
/* /*
________________________________________________________________________________ ________________________________________________________________________________
| ____________________________________________________________________________ | | ____________________________________________________________________________ |
| | | | | | | |
| | on windows: | | | | on windows: | |
| | - for UTF-16, use the wchar_t functions at the bottom of the header file | | | | - for UTF-16, use the wchar_t functions at the bottom of the header file | |
| | - _wfopen() requires wchar_t | | | | - _wfopen() requires wchar_t | |
| | | | | | | |
| | - in tinyfiledialogs, char is UTF-8 by default (since v3.6) | | | | - in tinyfiledialogs, char is UTF-8 by default (since v3.6) | |
| | - but fopen() expects MBCS (not UTF-8) | | | | - but fopen() expects MBCS (not UTF-8) | |
| | - if you want char to be MBCS: set tinyfd_winUtf8 to 0 | | | | - if you want char to be MBCS: set tinyfd_winUtf8 to 0 | |
| | | | | | | |
| | - alternatively, tinyfiledialogs provides | | | | - alternatively, tinyfiledialogs provides | |
| | functions to convert between UTF-8, UTF-16 and MBCS | | | | functions to convert between UTF-8, UTF-16 and MBCS | |
| |____________________________________________________________________________| | | |____________________________________________________________________________| |
|________________________________________________________________________________| |________________________________________________________________________________|
- This is not for ios nor android (it works in termux though). - This is not for ios nor android (it works in termux though).
- The files can be renamed with extension ".cpp" as the code is 100% compatible C C++ - The files can be renamed with extension ".cpp" as the code is 100% compatible C C++
(just comment out << extern "C" >> in the header file) (just comment out << extern "C" >> in the header file)
- Windows is fully supported from XP to 10 (maybe even older versions) - Windows is fully supported from XP to 10 (maybe even older versions)
- C# & LUA via dll, see files in the folder EXTRAS - C# & LUA via dll, see files in the folder EXTRAS
- OSX supported from 10.4 to latest (maybe even older versions) - OSX supported from 10.4 to latest (maybe even older versions)
- Do not use " and ' as the dialogs will be displayed with a warning - Do not use " and ' as the dialogs will be displayed with a warning
instead of the title, message, etc... instead of the title, message, etc...
- There's one file filter only, it may contain several patterns. - There's one file filter only, it may contain several patterns.
- If no filter description is provided, - If no filter description is provided,
the list of patterns will become the description. the list of patterns will become the description.
- On windows link against Comdlg32.lib and Ole32.lib - On windows link against Comdlg32.lib and Ole32.lib
(on windows the no linking claim is a lie) (on windows the no linking claim is a lie)
- On unix: it tries command line calls, so no such need (NO LINKING). - On unix: it tries command line calls, so no such need (NO LINKING).
- On unix you need one of the following: - On unix you need one of the following:
applescript, kdialog, zenity, matedialog, shellementary, qarma, yad, applescript, kdialog, zenity, matedialog, shellementary, qarma, yad,
python (2 or 3)/tkinter/python-dbus (optional), Xdialog python (2 or 3)/tkinter/python-dbus (optional), Xdialog
or curses dialogs (opens terminal if running without console). or curses dialogs (opens terminal if running without console).
- One of those is already included on most (if not all) desktops. - One of those is already included on most (if not all) desktops.
- In the absence of those it will use gdialog, gxmessage or whiptail - In the absence of those it will use gdialog, gxmessage or whiptail
with a textinputbox. If nothing is found, it switches to basic console input, with a textinputbox. If nothing is found, it switches to basic console input,
it opens a console if needed (requires xterm + bash). it opens a console if needed (requires xterm + bash).
- for curses dialogs you must set tinyfd_allowCursesDialogs=1 - for curses dialogs you must set tinyfd_allowCursesDialogs=1
- You can query the type of dialog that will be used (pass "tinyfd_query" as aTitle) - You can query the type of dialog that will be used (pass "tinyfd_query" as aTitle)
- String memory is preallocated statically for all the returned values. - String memory is preallocated statically for all the returned values.
- File and path names are tested before return, they should be valid. - File and path names are tested before return, they should be valid.
- tinyfd_forceConsole=1; at run time, forces dialogs into console mode. - tinyfd_forceConsole=1; at run time, forces dialogs into console mode.
- On windows, console mode only make sense for console applications. - On windows, console mode only make sense for console applications.
- On windows, console mode is not implemented for wchar_T UTF-16. - On windows, console mode is not implemented for wchar_T UTF-16.
- Mutiple selects are not possible in console mode. - Mutiple selects are not possible in console mode.
- The package dialog must be installed to run in curses dialogs in console mode. - The package dialog must be installed to run in curses dialogs in console mode.
It is already installed on most unix systems. It is already installed on most unix systems.
- On osx, the package dialog can be installed via - On osx, the package dialog can be installed via
http://macappstore.org/dialog or http://macports.org http://macappstore.org/dialog or http://macports.org
- On windows, for curses dialogs console mode, - On windows, for curses dialogs console mode,
dialog.exe should be copied somewhere on your executable path. dialog.exe should be copied somewhere on your executable path.
It can be found at the bottom of the following page: It can be found at the bottom of the following page:
http://andrear.altervista.org/home/cdialog.php http://andrear.altervista.org/home/cdialog.php
*/ */

View File

@ -1,125 +1,125 @@
/* /*
epple2 epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com> Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "video.h" #include "video.h"
#include "e2const.h" #include "e2const.h"
#include "videoaddressing.h" #include "videoaddressing.h"
#include "videomode.h" #include "videomode.h"
#include "addressbus.h" #include "addressbus.h"
#include "picturegenerator.h" #include "picturegenerator.h"
#include "textcharacters.h" #include "textcharacters.h"
static const int FLASH_HALF_PERIOD = E2Const::AVG_CPU_HZ/4; // 2 Hz period = 4 Hz half-period static const int FLASH_HALF_PERIOD = E2Const::AVG_CPU_HZ/4; // 2 Hz period = 4 Hz half-period
Video::Video(VideoMode& mode, AddressBus& addressBus, PictureGenerator& picgen, TextCharacters& textRows): Video::Video(VideoMode& mode, AddressBus& addressBus, PictureGenerator& picgen, TextCharacters& textRows):
mode(mode), addressBus(addressBus), picgen(picgen), textRows(textRows) mode(mode), addressBus(addressBus), picgen(picgen), textRows(textRows)
{ {
VideoAddressing::buildLUT(TEXT_BASE_1,TEXT_LEN,lutTEXT[0]); VideoAddressing::buildLUT(TEXT_BASE_1,TEXT_LEN,lutTEXT[0]);
VideoAddressing::buildLUT(TEXT_BASE_2,TEXT_LEN,lutTEXT[1]); VideoAddressing::buildLUT(TEXT_BASE_2,TEXT_LEN,lutTEXT[1]);
VideoAddressing::buildLUT(HRES_BASE_1,HRES_LEN,lutHRES[0]); VideoAddressing::buildLUT(HRES_BASE_1,HRES_LEN,lutHRES[0]);
VideoAddressing::buildLUT(HRES_BASE_2,HRES_LEN,lutHRES[1]); VideoAddressing::buildLUT(HRES_BASE_2,HRES_LEN,lutHRES[1]);
} }
Video::~Video() Video::~Video()
{ {
} }
void Video::powerOn() void Video::powerOn()
{ {
this->t = 0; this->t = 0;
this->flash = false; this->flash = false;
this->cflash = 0; this->cflash = 0;
} }
void Video::tick() void Video::tick()
{ {
const unsigned char data = getDataByte(); const unsigned char data = getDataByte();
const unsigned char rowToPlot = getRowToPlot(data); const unsigned char rowToPlot = getRowToPlot(data);
this->picgen.tick(this->t,rowToPlot); this->picgen.tick(this->t,rowToPlot);
updateFlash(); updateFlash();
++this->t; ++this->t;
if (this->t >= E2Const::BYTES_PER_FIELD) if (this->t >= E2Const::BYTES_PER_FIELD)
{ {
this->t = 0; this->t = 0;
} }
} }
void Video::updateFlash() void Video::updateFlash()
{ {
++this->cflash; ++this->cflash;
if (this->cflash >= FLASH_HALF_PERIOD) if (this->cflash >= FLASH_HALF_PERIOD)
{ {
this->flash = !this->flash; this->flash = !this->flash;
this->cflash = 0; this->cflash = 0;
} }
} }
unsigned char Video::getDataByte() unsigned char Video::getDataByte()
{ {
// TODO should fix the mixed-mode scanning during VBL (see U.A.][, p. 5-13) // TODO should fix the mixed-mode scanning during VBL (see U.A.][, p. 5-13)
std::vector<unsigned short>& lut = std::vector<unsigned short>& lut =
(this->mode.isDisplayingText(this->t) || !this->mode.isHiRes()) (this->mode.isDisplayingText(this->t) || !this->mode.isHiRes())
? ?
this->lutTEXT[this->mode.getPage()] this->lutTEXT[this->mode.getPage()]
: :
this->lutHRES[this->mode.getPage()]; this->lutHRES[this->mode.getPage()];
return this->addressBus.read(lut[this->t]); return this->addressBus.read(lut[this->t]);
} }
unsigned char Video::getRowToPlot(unsigned char d) unsigned char Video::getRowToPlot(unsigned char d)
{ {
if (this->mode.isDisplayingText(this->t)) if (this->mode.isDisplayingText(this->t))
{ {
const bool inverse = inverseChar(d); const bool inverse = inverseChar(d);
const int y = this->t / E2Const::BYTES_PER_ROW; const int y = this->t / E2Const::BYTES_PER_ROW;
d = this->textRows.get(((d & 0x3F) << 3) | (y & 0x07)); d = this->textRows.get(((d & 0x3F) << 3) | (y & 0x07));
if (inverse) if (inverse)
{ {
d = ~d & 0x7F; d = ~d & 0x7F;
} }
} }
return d; return d;
} }
bool Video::inverseChar(const unsigned char d) bool Video::inverseChar(const unsigned char d)
{ {
bool inverse; bool inverse;
const unsigned char cs = (d >> 6) & 3; const unsigned char cs = (d >> 6) & 3;
if (cs == 0) if (cs == 0)
{ {
inverse = true; inverse = true;
} }
else if (cs == 1) else if (cs == 1)
{ {
inverse = this->flash; inverse = this->flash;
} }
else else
{ {
inverse = false; inverse = false;
} }
return inverse; return inverse;
} }

View File

@ -1,65 +1,65 @@
/* /*
epple2 epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com> Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef VIDEO_H_ #ifndef VIDEO_H_
#define VIDEO_H_ #define VIDEO_H_
#include <vector> #include <vector>
class VideoMode; class VideoMode;
class AddressBus; class AddressBus;
class PictureGenerator; class PictureGenerator;
class TextCharacters; class TextCharacters;
class Video class Video
{ {
private: private:
enum { TEXT_BASE_1 = 0x0400 }; enum { TEXT_BASE_1 = 0x0400 };
enum { TEXT_BASE_2 = 0x0800 }; enum { TEXT_BASE_2 = 0x0800 };
enum { TEXT_LEN = 0x0400 }; enum { TEXT_LEN = 0x0400 };
enum { HRES_BASE_1 = 0x2000 }; enum { HRES_BASE_1 = 0x2000 };
enum { HRES_BASE_2 = 0x4000 }; enum { HRES_BASE_2 = 0x4000 };
enum { HRES_LEN = 0x2000 }; enum { HRES_LEN = 0x2000 };
std::vector<unsigned short> lutTEXT[2]; // [0] is page 1, [1] is page 2 std::vector<unsigned short> lutTEXT[2]; // [0] is page 1, [1] is page 2
std::vector<unsigned short> lutHRES[2]; // [0] is page 1, [1] is page 2 std::vector<unsigned short> lutHRES[2]; // [0] is page 1, [1] is page 2
VideoMode& mode; VideoMode& mode;
AddressBus& addressBus; AddressBus& addressBus;
PictureGenerator& picgen; PictureGenerator& picgen;
TextCharacters& textRows; TextCharacters& textRows;
unsigned int t; unsigned int t;
bool flash; bool flash;
int cflash; int cflash;
void updateFlash(); void updateFlash();
unsigned char getDataByte(); unsigned char getDataByte();
unsigned char getRowToPlot(unsigned char d); unsigned char getRowToPlot(unsigned char d);
bool inverseChar(const unsigned char d); bool inverseChar(const unsigned char d);
public: public:
Video(VideoMode& mode, AddressBus& addressBus, PictureGenerator& picgen, TextCharacters& textRows); Video(VideoMode& mode, AddressBus& addressBus, PictureGenerator& picgen, TextCharacters& textRows);
~Video(); ~Video();
void powerOn(); void powerOn();
void tick(); void tick();
}; };
#endif /*VIDEO_H_*/ #endif /*VIDEO_H_*/