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

View File

@ -1,159 +1,159 @@
/*
epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "card.h"
#include "drive.h"
#include "drivemotor.h"
#include "wozfile.h"
#include "lss.h"
#include "screenimage.h"
#include <string>
#include <iostream>
#include <cstdint>
class DiskController : public Card
{
private:
ScreenImage& gui;
int slot;
Disk2Drive drive1;
Disk2Drive drive2;
Disk2Drive* currentDrive;
bool load; // Q6
bool write; // Q7
bool ioStepped;
/*
* Only one drive's motor can be on at a time,
* so we only need one instance.
*/
DriveMotor motor;
// Maintain a copy of the last thing on the data bus, so it can
// be read by the LSS algorithm when needed.
std::uint8_t dataBusReadOnlyCopy;
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 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.
// 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)
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)
void writeBit(bool on) {
if (!this->motor.isOn()) {
return;
}
this->currentDrive->writeBit(on);
}
Disk2Drive& getDrive(const unsigned char drive) {
return (drive == 0) ? this->drive1 : this->drive2;
}
Disk2Drive& getOtherDrive() {
return (this->currentDrive == &this->drive1) ? this->drive2 : this->drive1;
}
void rotateCurrentDisk();
void stepLss();
public:
DiskController(ScreenImage& gui, int slot, bool lss13, double random_ones_rate);
~DiskController();
void tick();
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
void reset() {
this->gui.setIO(this->slot,getCurrentDriveNumber(),false);
this->gui.clearCurrentDrive(this->slot,getCurrentDriveNumber());
this->currentDrive = &this->drive1;
this->motor.reset();
this->gui.setCurrentDrive(this->slot,getCurrentDriveNumber(),getTrack(),false);
}
void loadDisk(unsigned char drive, const std::string& fnib) {
if (!this->getDrive(drive).loadDisk(fnib)) {
return;
}
this->gui.setDiskFile(this->slot,drive,fnib);
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
}
void unloadDisk(unsigned char drive) {
this->getDrive(drive).unloadDisk();
this->gui.setDiskFile(this->slot,drive,"");
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
}
void save(int drive) {
this->getDrive(drive).saveDisk();
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
}
bool isMotorOn() {
return this->motor.isOn();
}
unsigned char getTrack() {
return this->currentDrive->getTrack();
}
bool isWriting() {
return this->write;
}
bool isModified() {
return this->currentDrive->isModified();
}
bool isModifiedOther() {
return getOtherDrive().isModified();
}
bool isWriteProtected() {
return this->currentDrive->isWriteProtected();
}
bool isDirty() {
return isModified() || isModifiedOther();
}
unsigned char getCurrentDriveNumber() {
return this->currentDrive == &this->drive1 ? 0 : 1;
}
unsigned char getOtherDriveNumber() {
return 1-getCurrentDriveNumber();
}
virtual std::string getName() {
return "disk][ drive 1 drive 2 ";
}
void dumpLss() {
this->lssp6rom.dump();
}
};
/*
epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "card.h"
#include "drive.h"
#include "drivemotor.h"
#include "wozfile.h"
#include "lss.h"
#include "screenimage.h"
#include <string>
#include <iostream>
#include <cstdint>
class DiskController : public Card
{
private:
ScreenImage& gui;
int slot;
Disk2Drive drive1;
Disk2Drive drive2;
Disk2Drive* currentDrive;
bool load; // Q6
bool write; // Q7
bool ioStepped;
/*
* Only one drive's motor can be on at a time,
* so we only need one instance.
*/
DriveMotor motor;
// Maintain a copy of the last thing on the data bus, so it can
// be read by the LSS algorithm when needed.
std::uint8_t dataBusReadOnlyCopy;
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 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.
// 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)
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)
void writeBit(bool on) {
if (!this->motor.isOn()) {
return;
}
this->currentDrive->writeBit(on);
}
Disk2Drive& getDrive(const unsigned char drive) {
return (drive == 0) ? this->drive1 : this->drive2;
}
Disk2Drive& getOtherDrive() {
return (this->currentDrive == &this->drive1) ? this->drive2 : this->drive1;
}
void rotateCurrentDisk();
void stepLss();
public:
DiskController(ScreenImage& gui, int slot, bool lss13, double random_ones_rate);
~DiskController();
void tick();
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
void reset() {
this->gui.setIO(this->slot,getCurrentDriveNumber(),false);
this->gui.clearCurrentDrive(this->slot,getCurrentDriveNumber());
this->currentDrive = &this->drive1;
this->motor.reset();
this->gui.setCurrentDrive(this->slot,getCurrentDriveNumber(),getTrack(),false);
}
void loadDisk(unsigned char drive, const std::string& fnib) {
if (!this->getDrive(drive).loadDisk(fnib)) {
return;
}
this->gui.setDiskFile(this->slot,drive,fnib);
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
}
void unloadDisk(unsigned char drive) {
this->getDrive(drive).unloadDisk();
this->gui.setDiskFile(this->slot,drive,"");
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
}
void save(int drive) {
this->getDrive(drive).saveDisk();
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
}
bool isMotorOn() {
return this->motor.isOn();
}
unsigned char getTrack() {
return this->currentDrive->getTrack();
}
bool isWriting() {
return this->write;
}
bool isModified() {
return this->currentDrive->isModified();
}
bool isModifiedOther() {
return getOtherDrive().isModified();
}
bool isWriteProtected() {
return this->currentDrive->isWriteProtected();
}
bool isDirty() {
return isModified() || isModifiedOther();
}
unsigned char getCurrentDriveNumber() {
return this->currentDrive == &this->drive1 ? 0 : 1;
}
unsigned char getOtherDriveNumber() {
return 1-getCurrentDriveNumber();
}
virtual std::string getName() {
return "disk][ drive 1 drive 2 ";
}
void dumpLss() {
this->lssp6rom.dump();
}
};

View File

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

View File

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

View File

@ -1,169 +1,169 @@
/*
epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef E2CONST_H
#define E2CONST_H
class E2Const
{
public:
/*
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
clock standard (60 seconds per minute and 60 minutes per hour).
*/
static const int NTSC_FIELD_HZ = 60;
/*
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
recommended 441 (used by NBC) and Philco's suggested 600-800 lines.
*/
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
minimum interference was achieved using a subcarrier frequency 455 times the field
rate, which can also be obtained using standard tubes.
*/
static const int NTSC_COLOR_MULTIPLE = 5*7*13;
/*
Adding color to NTSC also required slowing down the frame rate, by dropping one
field after every 1000.
*/
static const int NTSC_COLOR_DROP_FIELD = 1000;
/*
Calculate the color sub-channel rate, times 4.
This will be the (approximate) Hz of the "14M"
crystal oscillator in the Apple ][.
14318181.818181818... Hz rounds to 14318182 Hz
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));
/*
U.A.II, p. 3-3
Normal 6502 cycle == 14 crystal periods
Long 6502 cycle == 16 crystal periods
*/
static const int CRYSTAL_CYCLES_PER_CPU_CYCLE = 14;
static const int EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE = 2;
/*
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 HORIZ_CYCLES = BYTES_PER_ROW;
/*
U.A.II, p. 3-2, "composite frequency... 1.0205 MHz"
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));
/*
A normal NTSC field is 262.5 lines (half of a full frame's 525 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 BYTES_PER_FIELD = BYTES_PER_ROW*NTSC_WHOLE_LINES_PER_FIELD;
// exactly 1 million
static const int MEGA = 1000000;
static const int VISIBLE_BITS_PER_BYTE = 7;
static const int VISIBLE_LINES_PER_CHARACTER = 8;
/*
* 1000+1 seconds 2 fields 1 frame 1000000 microseconds 63 50
* total horizontal line period = -------------- * -------- * ------------- * -------------------- = ( -- + -- ) microseconds per line
* 60*1000 fields 1 frame 3*5*5*7 lines 1 second 90
*
* 10 81
* horizontal blanking period = (1.5+4.7+.6+2.5+1.6) = 10.9 microseconds per line = ( -- + -- ) microseconds per line
* 90
*
* visible line period = total horizontal line period minus horizontal blanking period =
*
* 52 59
* -- + -- microseconds per line
* 90
*
*
* 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.
*
* 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
* 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;
/*
* 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
* 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.
* 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 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 SCANNABLE_ROWS = 0x100;
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_BYTES = RESET_ROWS*BYTES_PER_ROW;
static const int MIXED_TEXT_LINES = 4;
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 int test()
{
if (NTSC_FIELD_HZ!=60) return NTSC_FIELD_HZ;
if (NTSC_LINES_PER_FRAME!=525) return NTSC_LINES_PER_FRAME;
if (NTSC_COLOR_MULTIPLE!=455) return NTSC_COLOR_MULTIPLE;
if (NTSC_COLOR_DROP_FIELD!=1000) return NTSC_COLOR_DROP_FIELD;
if (CRYSTAL_HZ!=14318182) return CRYSTAL_HZ;
if (BYTES_PER_ROW!=65) return BYTES_PER_ROW;
if (AVG_CPU_HZ!=1020484) return AVG_CPU_HZ;
if (BYTES_PER_FIELD!=17030) return BYTES_PER_FIELD;
if (VISIBLE_BYTES_PER_ROW!=40) return VISIBLE_BYTES_PER_ROW;
if (VISIBLE_ROWS_PER_FIELD!=192) return VISIBLE_ROWS_PER_FIELD;
if (RESET_BYTES!=390) return RESET_BYTES;
if (BLANKED_BYTES_PER_ROW!=25) return BLANKED_BYTES_PER_ROW;
if (VISIBLE_BYTES_PER_FIELD!=12480) return VISIBLE_BYTES_PER_FIELD;
if (SCANNABLE_BYTES!=16640) return SCANNABLE_BYTES;
return -1;
}
};
#endif
/*
epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef E2CONST_H
#define E2CONST_H
class E2Const
{
public:
/*
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
clock standard (60 seconds per minute and 60 minutes per hour).
*/
static const int NTSC_FIELD_HZ = 60;
/*
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
recommended 441 (used by NBC) and Philco's suggested 600-800 lines.
*/
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
minimum interference was achieved using a subcarrier frequency 455 times the field
rate, which can also be obtained using standard tubes.
*/
static const int NTSC_COLOR_MULTIPLE = 5*7*13;
/*
Adding color to NTSC also required slowing down the frame rate, by dropping one
field after every 1000.
*/
static const int NTSC_COLOR_DROP_FIELD = 1000;
/*
Calculate the color sub-channel rate, times 4.
This will be the (approximate) Hz of the "14M"
crystal oscillator in the Apple ][.
14318181.818181818... Hz rounds to 14318182 Hz
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));
/*
U.A.II, p. 3-3
Normal 6502 cycle == 14 crystal periods
Long 6502 cycle == 16 crystal periods
*/
static const int CRYSTAL_CYCLES_PER_CPU_CYCLE = 14;
static const int EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE = 2;
/*
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 HORIZ_CYCLES = BYTES_PER_ROW;
/*
U.A.II, p. 3-2, "composite frequency... 1.0205 MHz"
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));
/*
A normal NTSC field is 262.5 lines (half of a full frame's 525 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 BYTES_PER_FIELD = BYTES_PER_ROW*NTSC_WHOLE_LINES_PER_FIELD;
// exactly 1 million
static const int MEGA = 1000000;
static const int VISIBLE_BITS_PER_BYTE = 7;
static const int VISIBLE_LINES_PER_CHARACTER = 8;
/*
* 1000+1 seconds 2 fields 1 frame 1000000 microseconds 63 50
* total horizontal line period = -------------- * -------- * ------------- * -------------------- = ( -- + -- ) microseconds per line
* 60*1000 fields 1 frame 3*5*5*7 lines 1 second 90
*
* 10 81
* horizontal blanking period = (1.5+4.7+.6+2.5+1.6) = 10.9 microseconds per line = ( -- + -- ) microseconds per line
* 90
*
* visible line period = total horizontal line period minus horizontal blanking period =
*
* 52 59
* -- + -- microseconds per line
* 90
*
*
* 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.
*
* 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
* 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;
/*
* 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
* 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.
* 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 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 SCANNABLE_ROWS = 0x100;
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_BYTES = RESET_ROWS*BYTES_PER_ROW;
static const int MIXED_TEXT_LINES = 4;
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 int test()
{
if (NTSC_FIELD_HZ!=60) return NTSC_FIELD_HZ;
if (NTSC_LINES_PER_FRAME!=525) return NTSC_LINES_PER_FRAME;
if (NTSC_COLOR_MULTIPLE!=455) return NTSC_COLOR_MULTIPLE;
if (NTSC_COLOR_DROP_FIELD!=1000) return NTSC_COLOR_DROP_FIELD;
if (CRYSTAL_HZ!=14318182) return CRYSTAL_HZ;
if (BYTES_PER_ROW!=65) return BYTES_PER_ROW;
if (AVG_CPU_HZ!=1020484) return AVG_CPU_HZ;
if (BYTES_PER_FIELD!=17030) return BYTES_PER_FIELD;
if (VISIBLE_BYTES_PER_ROW!=40) return VISIBLE_BYTES_PER_ROW;
if (VISIBLE_ROWS_PER_FIELD!=192) return VISIBLE_ROWS_PER_FIELD;
if (RESET_BYTES!=390) return RESET_BYTES;
if (BLANKED_BYTES_PER_ROW!=25) return BLANKED_BYTES_PER_ROW;
if (VISIBLE_BYTES_PER_FIELD!=12480) return VISIBLE_BYTES_PER_FIELD;
if (SCANNABLE_BYTES!=16640) return SCANNABLE_BYTES;
return -1;
}
};
#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")
then comment out << extern "C" >> bellow in this header file) */
/*_________
/ \ tinyfiledialogs.h v3.8.9 [Oct 27, 2022] zlib licence
|tiny file| Unique header file created [November 9, 2014]
| dialogs | Copyright (c) 2014 - 2021 Guillaume Vareille http://ysengrin.com
\____ ___/ http://tinyfiledialogs.sourceforge.net
\| git clone http://git.code.sf.net/p/tinyfiledialogs/code tinyfd
____________________________________________
| |
| email: tinyfiledialogs at ysengrin.com |
|____________________________________________|
________________________________________________________________________________
| ____________________________________________________________________________ |
| | | |
| | on windows: | |
| | - for UTF-16, use the wchar_t functions at the bottom of the header file | |
| | - _wfopen() requires wchar_t | |
| | | |
| | - in tinyfiledialogs, char is UTF-8 by default (since v3.6) | |
| | - but fopen() expects MBCS (not UTF-8) | |
| | - if you want char to be MBCS: set tinyfd_winUtf8 to 0 | |
| | | |
| | - alternatively, tinyfiledialogs provides | |
| | functions to convert between UTF-8, UTF-16 and MBCS | |
| |____________________________________________________________________________| |
|________________________________________________________________________________|
If you like tinyfiledialogs, please upvote my stackoverflow answer
https://stackoverflow.com/a/47651444
- License -
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
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
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef TINYFILEDIALOGS_H
#define TINYFILEDIALOGS_H
#ifdef __cplusplus
/* 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. */
extern "C" {
#endif
/******************************************************************************************************/
/**************************************** UTF-8 on Windows ********************************************/
/******************************************************************************************************/
#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 )
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 */
/* 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 */
char * tinyfd_utf8toMbcs(char const * aUtf8string);
char * tinyfd_utf16toMbcs(wchar_t const * aUtf16string);
wchar_t * tinyfd_mbcsTo16(char const * aMbcsString);
char * tinyfd_mbcsTo8(char const * aMbcsString);
wchar_t * tinyfd_utf8to16(char const * aUtf8string);
char * tinyfd_utf16to8(wchar_t const * aUtf16string);
#endif
/******************************************************************************************************/
/******************************************************************************************************/
/******************************************************************************************************/
/************* 3 funtions for C# (you don't need this in C or C++) : */
char const * tinyfd_getGlobalChar(char const * aCharVariableName); /* returns NULL on error */
int tinyfd_getGlobalInt(char const * aIntVariableName); /* returns -1 on error */
int tinyfd_setGlobalInt(char const * aIntVariableName, int aValue); /* returns -1 on error */
/* aCharVariableName: "tinyfd_version" "tinyfd_needs" "tinyfd_response"
aIntVariableName : "tinyfd_verbose" "tinyfd_silent" "tinyfd_allowCursesDialogs"
"tinyfd_forceConsole" "tinyfd_assumeGraphicDisplay" "tinyfd_winUtf8"
**************/
extern char tinyfd_version[8]; /* contains tinyfd current version number */
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_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 */
extern int tinyfd_allowCursesDialogs; /* 0 (default) or 1 */
extern int tinyfd_forceConsole; /* 0 (default) or 1 */
/* 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.
1: forces all dialogs into console mode even when an X server is present,
it can use the package dialog or dialog.exe.
on windows it only make sense for console applications */
extern int tinyfd_assumeGraphicDisplay; /* 0 (default) or 1 */
/* 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 */
extern char tinyfd_response[1024];
/* if you pass "tinyfd_query" as aTitle,
the functions will not display the dialogs
but will return 0 for console mode, 1 for graphic mode.
tinyfd_response is then filled with the retain solution.
possible values for tinyfd_response are (all lowercase)
for graphic mode:
windows_wchar windows applescript kdialog zenity zenity3 matedialog
shellementary qarma yad python2-tkinter python3-tkinter python-dbus
perl-dbus gxmessage gmessage xmessage xdialog gdialog
for console mode:
dialog whiptail basicinput no_solution */
void tinyfd_beep(void);
int tinyfd_notifyPopup(
char const * aTitle, /* NULL or "" */
char const * aMessage, /* NULL or "" may contain \n \t */
char const * aIconType); /* "info" "warning" "error" */
/* return has only meaning for tinyfd_query */
int tinyfd_messageBox(
char const * aTitle , /* NULL or "" */
char const * aMessage , /* NULL or "" may contain \n \t */
char const * aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */
char const * aIconType , /* "info" "warning" "error" "question" */
int aDefaultButton ) ;
/* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */
char * tinyfd_inputBox(
char const * aTitle , /* NULL or "" */
char const * aMessage , /* NULL or "" (\n and \t have no effect) */
char const * aDefaultInput ) ; /* NULL passwordBox, "" inputbox */
/* returns NULL on cancel */
char * tinyfd_saveFileDialog(
char const * aTitle , /* NULL or "" */
char const * aDefaultPathAndFile , /* NULL or "" */
int aNumOfFilterPatterns , /* 0 (1 in the following example) */
char const * const * aFilterPatterns , /* NULL or char const * lFilterPatterns[1]={"*.txt"} */
char const * aSingleFilterDescription ) ; /* NULL or "text files" */
/* returns NULL on cancel */
char * tinyfd_openFileDialog(
char const * aTitle, /* NULL or "" */
char const * aDefaultPathAndFile, /* NULL or "" */
int aNumOfFilterPatterns , /* 0 (2 in the following example) */
char const * const * aFilterPatterns, /* NULL or char const * lFilterPatterns[2]={"*.png","*.jpg"}; */
char const * aSingleFilterDescription, /* NULL or "image files" */
int aAllowMultipleSelects ) ; /* 0 or 1 */
/* in case of multiple files, the separator is | */
/* returns NULL on cancel */
char * tinyfd_selectFolderDialog(
char const * aTitle, /* NULL or "" */
char const * aDefaultPath); /* NULL or "" */
/* returns NULL on cancel */
char * tinyfd_colorChooser(
char const * aTitle, /* NULL or "" */
char const * aDefaultHexRGB, /* NULL or "#FF0000" */
unsigned char const aDefaultRGB[3] , /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */
unsigned char aoResultRGB[3] ) ; /* unsigned char lResultRGB[3]; */
/* returns the hexcolor as a string "#FF0000" */
/* aoResultRGB also contains the result */
/* aDefaultRGB is used only if aDefaultHexRGB is NULL */
/* aDefaultRGB and aoResultRGB can be the same array */
/* returns NULL on cancel */
/************ WINDOWS ONLY SECTION ************************/
#ifdef _WIN32
/* windows only - utf-16 version */
int tinyfd_notifyPopupW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aMessage, /* NULL or L"" may contain \n \t */
wchar_t const * aIconType); /* L"info" L"warning" L"error" */
/* windows only - utf-16 version */
int tinyfd_messageBoxW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aMessage, /* NULL or L"" may contain \n \t */
wchar_t const * aDialogType, /* L"ok" L"okcancel" L"yesno" */
wchar_t const * aIconType, /* L"info" L"warning" L"error" L"question" */
int aDefaultButton ); /* 0 for cancel/no , 1 for ok/yes */
/* returns 0 for cancel/no , 1 for ok/yes */
/* windows only - utf-16 version */
wchar_t * tinyfd_inputBoxW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aMessage, /* NULL or L"" (\n nor \t not respected) */
wchar_t const * aDefaultInput); /* NULL passwordBox, L"" inputbox */
/* windows only - utf-16 version */
wchar_t * tinyfd_saveFileDialogW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultPathAndFile, /* NULL or L"" */
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 * aSingleFilterDescription); /* NULL or L"text files" */
/* returns NULL on cancel */
/* windows only - utf-16 version */
wchar_t * tinyfd_openFileDialogW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultPathAndFile, /* NULL or L"" */
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 * aSingleFilterDescription, /* NULL or L"image files" */
int aAllowMultipleSelects ) ; /* 0 or 1 */
/* in case of multiple files, the separator is | */
/* returns NULL on cancel */
/* windows only - utf-16 version */
wchar_t * tinyfd_selectFolderDialogW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultPath); /* NULL or L"" */
/* returns NULL on cancel */
/* windows only - utf-16 version */
wchar_t * tinyfd_colorChooserW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultHexRGB, /* NULL or L"#FF0000" */
unsigned char const aDefaultRGB[3], /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */
unsigned char aoResultRGB[3]); /* unsigned char lResultRGB[3]; */
/* returns the hexcolor as a string L"#FF0000" */
/* aoResultRGB also contains the result */
/* aDefaultRGB is used only if aDefaultHexRGB is NULL */
/* aDefaultRGB and aoResultRGB can be the same array */
/* returns NULL on cancel */
#endif /*_WIN32 */
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /* TINYFILEDIALOGS_H */
/*
________________________________________________________________________________
| ____________________________________________________________________________ |
| | | |
| | on windows: | |
| | - for UTF-16, use the wchar_t functions at the bottom of the header file | |
| | - _wfopen() requires wchar_t | |
| | | |
| | - in tinyfiledialogs, char is UTF-8 by default (since v3.6) | |
| | - but fopen() expects MBCS (not UTF-8) | |
| | - if you want char to be MBCS: set tinyfd_winUtf8 to 0 | |
| | | |
| | - alternatively, tinyfiledialogs provides | |
| | functions to convert between UTF-8, UTF-16 and MBCS | |
| |____________________________________________________________________________| |
|________________________________________________________________________________|
- 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++
(just comment out << extern "C" >> in the header file)
- Windows is fully supported from XP to 10 (maybe even older versions)
- C# & LUA via dll, see files in the folder EXTRAS
- OSX supported from 10.4 to latest (maybe even older versions)
- Do not use " and ' as the dialogs will be displayed with a warning
instead of the title, message, etc...
- There's one file filter only, it may contain several patterns.
- If no filter description is provided,
the list of patterns will become the description.
- On windows link against Comdlg32.lib and Ole32.lib
(on windows the no linking claim is a lie)
- On unix: it tries command line calls, so no such need (NO LINKING).
- On unix you need one of the following:
applescript, kdialog, zenity, matedialog, shellementary, qarma, yad,
python (2 or 3)/tkinter/python-dbus (optional), Xdialog
or curses dialogs (opens terminal if running without console).
- One of those is already included on most (if not all) desktops.
- 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,
it opens a console if needed (requires xterm + bash).
- 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)
- String memory is preallocated statically for all the returned values.
- File and path names are tested before return, they should be valid.
- 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 is not implemented for wchar_T UTF-16.
- Mutiple selects are not possible 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.
- On osx, the package dialog can be installed via
http://macappstore.org/dialog or http://macports.org
- On windows, for curses dialogs console mode,
dialog.exe should be copied somewhere on your executable path.
It can be found at the bottom of the following page:
http://andrear.altervista.org/home/cdialog.php
*/
/* 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) */
/*_________
/ \ tinyfiledialogs.h v3.8.9 [Oct 27, 2022] zlib licence
|tiny file| Unique header file created [November 9, 2014]
| dialogs | Copyright (c) 2014 - 2021 Guillaume Vareille http://ysengrin.com
\____ ___/ http://tinyfiledialogs.sourceforge.net
\| git clone http://git.code.sf.net/p/tinyfiledialogs/code tinyfd
____________________________________________
| |
| email: tinyfiledialogs at ysengrin.com |
|____________________________________________|
________________________________________________________________________________
| ____________________________________________________________________________ |
| | | |
| | on windows: | |
| | - for UTF-16, use the wchar_t functions at the bottom of the header file | |
| | - _wfopen() requires wchar_t | |
| | | |
| | - in tinyfiledialogs, char is UTF-8 by default (since v3.6) | |
| | - but fopen() expects MBCS (not UTF-8) | |
| | - if you want char to be MBCS: set tinyfd_winUtf8 to 0 | |
| | | |
| | - alternatively, tinyfiledialogs provides | |
| | functions to convert between UTF-8, UTF-16 and MBCS | |
| |____________________________________________________________________________| |
|________________________________________________________________________________|
If you like tinyfiledialogs, please upvote my stackoverflow answer
https://stackoverflow.com/a/47651444
- License -
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
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
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef TINYFILEDIALOGS_H
#define TINYFILEDIALOGS_H
#ifdef __cplusplus
/* 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. */
extern "C" {
#endif
/******************************************************************************************************/
/**************************************** UTF-8 on Windows ********************************************/
/******************************************************************************************************/
#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 )
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 */
/* 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 */
char * tinyfd_utf8toMbcs(char const * aUtf8string);
char * tinyfd_utf16toMbcs(wchar_t const * aUtf16string);
wchar_t * tinyfd_mbcsTo16(char const * aMbcsString);
char * tinyfd_mbcsTo8(char const * aMbcsString);
wchar_t * tinyfd_utf8to16(char const * aUtf8string);
char * tinyfd_utf16to8(wchar_t const * aUtf16string);
#endif
/******************************************************************************************************/
/******************************************************************************************************/
/******************************************************************************************************/
/************* 3 funtions for C# (you don't need this in C or C++) : */
char const * tinyfd_getGlobalChar(char const * aCharVariableName); /* returns NULL on error */
int tinyfd_getGlobalInt(char const * aIntVariableName); /* returns -1 on error */
int tinyfd_setGlobalInt(char const * aIntVariableName, int aValue); /* returns -1 on error */
/* aCharVariableName: "tinyfd_version" "tinyfd_needs" "tinyfd_response"
aIntVariableName : "tinyfd_verbose" "tinyfd_silent" "tinyfd_allowCursesDialogs"
"tinyfd_forceConsole" "tinyfd_assumeGraphicDisplay" "tinyfd_winUtf8"
**************/
extern char tinyfd_version[8]; /* contains tinyfd current version number */
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_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 */
extern int tinyfd_allowCursesDialogs; /* 0 (default) or 1 */
extern int tinyfd_forceConsole; /* 0 (default) or 1 */
/* 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.
1: forces all dialogs into console mode even when an X server is present,
it can use the package dialog or dialog.exe.
on windows it only make sense for console applications */
extern int tinyfd_assumeGraphicDisplay; /* 0 (default) or 1 */
/* 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 */
extern char tinyfd_response[1024];
/* if you pass "tinyfd_query" as aTitle,
the functions will not display the dialogs
but will return 0 for console mode, 1 for graphic mode.
tinyfd_response is then filled with the retain solution.
possible values for tinyfd_response are (all lowercase)
for graphic mode:
windows_wchar windows applescript kdialog zenity zenity3 matedialog
shellementary qarma yad python2-tkinter python3-tkinter python-dbus
perl-dbus gxmessage gmessage xmessage xdialog gdialog
for console mode:
dialog whiptail basicinput no_solution */
void tinyfd_beep(void);
int tinyfd_notifyPopup(
char const * aTitle, /* NULL or "" */
char const * aMessage, /* NULL or "" may contain \n \t */
char const * aIconType); /* "info" "warning" "error" */
/* return has only meaning for tinyfd_query */
int tinyfd_messageBox(
char const * aTitle , /* NULL or "" */
char const * aMessage , /* NULL or "" may contain \n \t */
char const * aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */
char const * aIconType , /* "info" "warning" "error" "question" */
int aDefaultButton ) ;
/* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */
char * tinyfd_inputBox(
char const * aTitle , /* NULL or "" */
char const * aMessage , /* NULL or "" (\n and \t have no effect) */
char const * aDefaultInput ) ; /* NULL passwordBox, "" inputbox */
/* returns NULL on cancel */
char * tinyfd_saveFileDialog(
char const * aTitle , /* NULL or "" */
char const * aDefaultPathAndFile , /* NULL or "" */
int aNumOfFilterPatterns , /* 0 (1 in the following example) */
char const * const * aFilterPatterns , /* NULL or char const * lFilterPatterns[1]={"*.txt"} */
char const * aSingleFilterDescription ) ; /* NULL or "text files" */
/* returns NULL on cancel */
char * tinyfd_openFileDialog(
char const * aTitle, /* NULL or "" */
char const * aDefaultPathAndFile, /* NULL or "" */
int aNumOfFilterPatterns , /* 0 (2 in the following example) */
char const * const * aFilterPatterns, /* NULL or char const * lFilterPatterns[2]={"*.png","*.jpg"}; */
char const * aSingleFilterDescription, /* NULL or "image files" */
int aAllowMultipleSelects ) ; /* 0 or 1 */
/* in case of multiple files, the separator is | */
/* returns NULL on cancel */
char * tinyfd_selectFolderDialog(
char const * aTitle, /* NULL or "" */
char const * aDefaultPath); /* NULL or "" */
/* returns NULL on cancel */
char * tinyfd_colorChooser(
char const * aTitle, /* NULL or "" */
char const * aDefaultHexRGB, /* NULL or "#FF0000" */
unsigned char const aDefaultRGB[3] , /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */
unsigned char aoResultRGB[3] ) ; /* unsigned char lResultRGB[3]; */
/* returns the hexcolor as a string "#FF0000" */
/* aoResultRGB also contains the result */
/* aDefaultRGB is used only if aDefaultHexRGB is NULL */
/* aDefaultRGB and aoResultRGB can be the same array */
/* returns NULL on cancel */
/************ WINDOWS ONLY SECTION ************************/
#ifdef _WIN32
/* windows only - utf-16 version */
int tinyfd_notifyPopupW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aMessage, /* NULL or L"" may contain \n \t */
wchar_t const * aIconType); /* L"info" L"warning" L"error" */
/* windows only - utf-16 version */
int tinyfd_messageBoxW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aMessage, /* NULL or L"" may contain \n \t */
wchar_t const * aDialogType, /* L"ok" L"okcancel" L"yesno" */
wchar_t const * aIconType, /* L"info" L"warning" L"error" L"question" */
int aDefaultButton ); /* 0 for cancel/no , 1 for ok/yes */
/* returns 0 for cancel/no , 1 for ok/yes */
/* windows only - utf-16 version */
wchar_t * tinyfd_inputBoxW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aMessage, /* NULL or L"" (\n nor \t not respected) */
wchar_t const * aDefaultInput); /* NULL passwordBox, L"" inputbox */
/* windows only - utf-16 version */
wchar_t * tinyfd_saveFileDialogW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultPathAndFile, /* NULL or L"" */
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 * aSingleFilterDescription); /* NULL or L"text files" */
/* returns NULL on cancel */
/* windows only - utf-16 version */
wchar_t * tinyfd_openFileDialogW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultPathAndFile, /* NULL or L"" */
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 * aSingleFilterDescription, /* NULL or L"image files" */
int aAllowMultipleSelects ) ; /* 0 or 1 */
/* in case of multiple files, the separator is | */
/* returns NULL on cancel */
/* windows only - utf-16 version */
wchar_t * tinyfd_selectFolderDialogW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultPath); /* NULL or L"" */
/* returns NULL on cancel */
/* windows only - utf-16 version */
wchar_t * tinyfd_colorChooserW(
wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultHexRGB, /* NULL or L"#FF0000" */
unsigned char const aDefaultRGB[3], /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */
unsigned char aoResultRGB[3]); /* unsigned char lResultRGB[3]; */
/* returns the hexcolor as a string L"#FF0000" */
/* aoResultRGB also contains the result */
/* aDefaultRGB is used only if aDefaultHexRGB is NULL */
/* aDefaultRGB and aoResultRGB can be the same array */
/* returns NULL on cancel */
#endif /*_WIN32 */
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /* TINYFILEDIALOGS_H */
/*
________________________________________________________________________________
| ____________________________________________________________________________ |
| | | |
| | on windows: | |
| | - for UTF-16, use the wchar_t functions at the bottom of the header file | |
| | - _wfopen() requires wchar_t | |
| | | |
| | - in tinyfiledialogs, char is UTF-8 by default (since v3.6) | |
| | - but fopen() expects MBCS (not UTF-8) | |
| | - if you want char to be MBCS: set tinyfd_winUtf8 to 0 | |
| | | |
| | - alternatively, tinyfiledialogs provides | |
| | functions to convert between UTF-8, UTF-16 and MBCS | |
| |____________________________________________________________________________| |
|________________________________________________________________________________|
- 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++
(just comment out << extern "C" >> in the header file)
- Windows is fully supported from XP to 10 (maybe even older versions)
- C# & LUA via dll, see files in the folder EXTRAS
- OSX supported from 10.4 to latest (maybe even older versions)
- Do not use " and ' as the dialogs will be displayed with a warning
instead of the title, message, etc...
- There's one file filter only, it may contain several patterns.
- If no filter description is provided,
the list of patterns will become the description.
- On windows link against Comdlg32.lib and Ole32.lib
(on windows the no linking claim is a lie)
- On unix: it tries command line calls, so no such need (NO LINKING).
- On unix you need one of the following:
applescript, kdialog, zenity, matedialog, shellementary, qarma, yad,
python (2 or 3)/tkinter/python-dbus (optional), Xdialog
or curses dialogs (opens terminal if running without console).
- One of those is already included on most (if not all) desktops.
- 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,
it opens a console if needed (requires xterm + bash).
- 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)
- String memory is preallocated statically for all the returned values.
- File and path names are tested before return, they should be valid.
- 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 is not implemented for wchar_T UTF-16.
- Mutiple selects are not possible 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.
- On osx, the package dialog can be installed via
http://macappstore.org/dialog or http://macports.org
- On windows, for curses dialogs console mode,
dialog.exe should be copied somewhere on your executable path.
It can be found at the bottom of the following page:
http://andrear.altervista.org/home/cdialog.php
*/

View File

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

View File

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