add LSS ROMs and WOZ file reading

This commit is contained in:
Christopher A. Mosher 2018-12-15 23:39:08 -05:00
parent b4f9563a1c
commit 19d698dbb4
5 changed files with 543 additions and 23 deletions

View File

@ -4,34 +4,34 @@ METASOURCES=AUTO
bin_PROGRAMS=epple2
AM_CXXFLAGS=-std=c++11 -Wall -O3
AM_CXXFLAGS=-std=c++14 -Wall -O3
AM_CPPFLAGS=$(all_includes)
epple2_LDFLAGS=$(all_libraries)
epple2_CPPFLAGS = $(AM_CPPFLAGS) -DETCDIR=\"$(sysconfdir)\"
epple2_SOURCES = a2colorsobserved.cpp addressbus.cpp analogtv.cpp apple2.cpp \
applentsc.cpp card.cpp cassette.cpp clipboardhandler.cpp clockcard.cpp \
configep2.cpp cpu.cpp diskbytes.cpp diskcontroller.cpp drive.cpp \
emptyslot.cpp emulator.cpp firmwarecard.cpp gui.cpp hypermode.cpp \
keyboard.cpp keyboardbuffermode.cpp languagecard.cpp lowpass_1_5_mhz.cpp \
lowpass_3_58_mhz.cpp main.cpp memory.cpp paddlebuttonstates.cpp \
paddles.cpp picturegenerator.cpp powerupreset.cpp raminitializer.cpp \
screenimage.cpp slots.cpp speakerclicker.cpp standardin.cpp \
standardinproducer.cpp standardout.cpp steppermotor.cpp textcharacters.cpp \
timable.cpp video.cpp videoaddressing.cpp videomode.cpp \
videostaticgenerator.cpp \
Circuit.cpp Common.cpp Cpu6502.cpp Cpu6502Helper.cpp Emu6502.cpp SegmentCache.cpp \
StateCalculator.cpp Trace.cpp TransCache.cpp TransNetwork.cpp
applentsc.cpp card.cpp cassette.cpp clipboardhandler.cpp clockcard.cpp \
configep2.cpp cpu.cpp diskbytes.cpp diskcontroller.cpp drive.cpp \
emptyslot.cpp emulator.cpp firmwarecard.cpp gui.cpp hypermode.cpp \
keyboard.cpp keyboardbuffermode.cpp languagecard.cpp lowpass_1_5_mhz.cpp \
lowpass_3_58_mhz.cpp lss.cpp main.cpp memory.cpp paddlebuttonstates.cpp \
paddles.cpp picturegenerator.cpp powerupreset.cpp raminitializer.cpp \
screenimage.cpp slots.cpp speakerclicker.cpp standardin.cpp \
standardinproducer.cpp standardout.cpp steppermotor.cpp textcharacters.cpp \
timable.cpp video.cpp videoaddressing.cpp videomode.cpp \
videostaticgenerator.cpp wozfile.cpp \
Circuit.cpp Common.cpp Cpu6502.cpp Cpu6502Helper.cpp Emu6502.cpp SegmentCache.cpp \
StateCalculator.cpp Trace.cpp TransCache.cpp TransNetwork.cpp
noinst_HEADERS = a2colorsobserved.h addressbus.h analogtv.h apple2.h applentsc.h \
card.h cassette.h clipboardhandler.h clockcard.h configep2.h cpu.h diskbytes.h \
diskcontroller.h drive.h e2const.h emptyslot.h emulator.h firmwarecard.h font3x5.h gui.h \
hypermode.h keyboardbuffermode.h keyboard.h languagecard.h lowpass_1_5_mhz.h \
lowpass_3_58_mhz.h memory.h paddlebuttonstates.h paddles.h picturegenerator.h \
powerupreset.h raminitializer.h screenimage.h slots.h speakerclicker.h \
standardin.h standardinproducer.h standardout.h steppermotor.h \
textcharacterimages.h textcharacters.h timable.h util.h \
videoaddressing.h video.h videomode.h videostaticgenerator.h \
Circuit.h Common.h Cpu6502.h Cpu6502Helper.h Emu6502.h SegmentCache.h SegmentTypes.h \
StateCalculator.h Trace.h TransCache.h TransNetwork.h addressbus.h ptr_less.h trans.h
card.h cassette.h clipboardhandler.h clockcard.h configep2.h cpu.h diskbytes.h \
diskcontroller.h drive.h e2const.h emptyslot.h emulator.h firmwarecard.h font3x5.h gui.h \
hypermode.h keyboardbuffermode.h keyboard.h languagecard.h lowpass_1_5_mhz.h \
lowpass_3_58_mhz.h lss.h memory.h paddlebuttonstates.h paddles.h picturegenerator.h \
powerupreset.h raminitializer.h screenimage.h slots.h speakerclicker.h \
standardin.h standardinproducer.h standardout.h steppermotor.h \
textcharacterimages.h textcharacters.h timable.h util.h \
videoaddressing.h video.h videomode.h videostaticgenerator.h wozfile.h \
Circuit.h Common.h Cpu6502.h Cpu6502Helper.h Emu6502.h SegmentCache.h SegmentTypes.h \
StateCalculator.h Trace.h TransCache.h TransNetwork.h addressbus.h ptr_less.h trans.h

187
src/lss.cpp Normal file
View File

@ -0,0 +1,187 @@
/*
epple2
Copyright © 2018, Christopher Alan Mosher, Shelton, CT, USA. <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 "lss.h"
#include <algorithm>
#include <iterator>
static void setcmd(std::uint8_t lssrom[], std::uint8_t x, std::uint8_t cmd) {
lssrom[x] = (lssrom[x] & 0xF0u) | cmd;
}
static void setseq(std::uint8_t lssrom[], std::uint8_t x, std::uint8_t seq) {
lssrom[x] = (lssrom[x] & 0x0Fu) | seq;
}
static void setbth(std::uint8_t lssrom[], std::uint8_t x, std::uint8_t both) {
lssrom[x] = both;
}
static void showua2seq(std::uint8_t lssrom[], std::uint8_t seq) {
printf("| %02x %02x %02x %02x | %02x %02x %02x %02x",
lssrom[seq|0x9],
lssrom[seq|0xB],
lssrom[seq|0xD],
lssrom[seq|0xF],
lssrom[seq|0x8],
lssrom[seq|0xA],
lssrom[seq|0xC],
lssrom[seq|0xE]
);
printf("| %02x %02x %02x %02x | %02x %02x %02x %02x |\n",
lssrom[seq|0x1],
lssrom[seq|0x0],
lssrom[seq|0x3],
lssrom[seq|0x2],
lssrom[seq|0x5],
lssrom[seq|0x4],
lssrom[seq|0x7],
lssrom[seq|0x6]
);
}
LSS::LSS(bool use13SectorDos32LSS):
use13SectorDos32LSS(use13SectorDos32LSS) {
/*
* LSS P6 ROM is stored here with different addressing bits
* than in the original hardware, just for ease of understanding.
*
* Addressing bits:
* S3 S2 S1 S0: 4-bit sequence number, 0x00-0x0F
* P: read pulse (from disk) indicator (1=pulse, 0=no pulse)
* QA: MSB of controller card data register
* Q7: READ/WRITE ($C08E/F) soft switch
* Q6: SHIFT/LOAD ($C08C/D) soft switch
*
* Original hardware addressing: S3 S2 S0 P Q7 Q6 QA S1
*
* Addressing used here: S3 S2 S1 S0 Q7 Q6 QA P
*/
// First fill in some reasonably global default values
for (std::uint8_t s(0u); s < 0x10u; ++s) {
std::uint8_t seq(s << 4u);
for (std::uint8_t adr(0u); adr < 0x10u; ++adr) {
lssrom[seq|adr] = seq+0x18u;
if ((adr & 0xCu) == 4u) {
lssrom[seq|adr] = 0x0Au;
}
if (adr == 1u || adr == 3u) {
lssrom[seq|adr] = 0xD8u;
}
}
}
setcmd(lssrom,0x10u,0x0Du);
setbth(lssrom,0x90u,0x29u);
setcmd(lssrom,0xA0u,0x0Du);
setbth(lssrom,0xB0u,0x59u);
setcmd(lssrom,0xC0u,0x09u);
setseq(lssrom,0xD0u,0x00u);
setcmd(lssrom,0xE0u,0x0Du);
setbth(lssrom,0xF0u,0x4Du);
setseq(lssrom,0x01u,0x10u);
setbth(lssrom,0x11u,0x2Du);
setbth(lssrom,0xA1u,0xCDu);
setcmd(lssrom,0xB1u,0x09u);
setcmd(lssrom,0xC1u,0x09u);
setbth(lssrom,0xE1u,0xFDu);
setcmd(lssrom,0xF1u,0x0Du);
setseq(lssrom,0x12u,0x30u);
setseq(lssrom,0x22u,0x20u);
setbth(lssrom,0xC2u,0xA0u);
setbth(lssrom,0xF2u,0xE0u);
setseq(lssrom,0x03u,0x10u);
setseq(lssrom,0x13u,0x30u);
setseq(lssrom,0x23u,0x00u);
setseq(lssrom,0x33u,0x40u);
setseq(lssrom,0xD3u,0xE0u);
setseq(lssrom,0xE3u,0xF0u);
setbth(lssrom,0xF3u,0xE0u);
setcmd(lssrom,0x28u,0x09u);
setseq(lssrom,0x78u,0x00u);
setcmd(lssrom,0xA8u,0x09u);
setseq(lssrom,0xF8u,0x80u);
setcmd(lssrom,0x29u,0x09u);
setseq(lssrom,0x79u,0x00u);
setcmd(lssrom,0xA9u,0x09u);
setseq(lssrom,0xF9u,0x80u);
setcmd(lssrom,0x2Au,0x09u);
setcmd(lssrom,0xAAu,0x09u);
setcmd(lssrom,0x2Bu,0x09u);
setcmd(lssrom,0xABu,0x09u);
setcmd(lssrom,0x2Cu,0x0Bu);
setseq(lssrom,0x7Cu,0x00u);
setcmd(lssrom,0xACu,0x0Bu);
setseq(lssrom,0xFCu,0x80u);
setcmd(lssrom,0x2Du,0x0Bu);
setseq(lssrom,0x7Du,0x00u);
setcmd(lssrom,0xADu,0x0Bu);
setseq(lssrom,0xFDu,0x80u);
setcmd(lssrom,0x2Eu,0x0Bu);
setcmd(lssrom,0xAEu,0x0Bu);
setcmd(lssrom,0x2Fu,0x0Bu);
setcmd(lssrom,0xAFu,0x0Bu);
// build 13-sector LSS based on 16-sector LSS
std::copy(std::begin(lssrom), std::end(lssrom), std::begin(lss13rom));
setcmd(lss13rom,0x10u,0x08u);
setseq(lss13rom,0x90u,0x00u);
setseq(lss13rom,0xB0u,0x30u);
setcmd(lss13rom,0xD0u,0x0Du);
setseq(lss13rom,0x01u,0xD0u);
setbth(lss13rom,0x11u,0xD8u);
setbth(lss13rom,0xD1u,0x1Du);
setseq(lss13rom,0x02u,0x00u);
setseq(lss13rom,0x12u,0x20u);
setseq(lss13rom,0x22u,0x30u);
setseq(lss13rom,0x13u,0x20u);
setseq(lss13rom,0x23u,0x30u);
setseq(lss13rom,0x33u,0xD0u);
for (unsigned int seq = 0; seq < 0x100u; seq += 0x10u) {
showua2seq(lssrom,seq);
}
for (unsigned int seq = 0; seq < 0x100u; seq += 0x10u) {
showua2seq(lss13rom,seq);
}
}
LSS::~LSS() {
}

41
src/lss.h Normal file
View File

@ -0,0 +1,41 @@
/*
epple2
Copyright © 2018, Christopher Alan Mosher, Shelton, CT, USA. <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 LSS_H
#define LSS_H
#include <cstdint>
class LSS
{
private:
bool use13SectorDos32LSS;
std::uint8_t lssrom[0x100];
std::uint8_t lss13rom[0x100];
public:
LSS(bool use13SectorDos32LSS);
~LSS();
std::uint8_t read(const std::uint8_t addr) {
return use13SectorDos32LSS ? lss13rom[addr] : lssrom[addr];
}
};
#endif

225
src/wozfile.cpp Normal file
View File

@ -0,0 +1,225 @@
/*
epple2
Copyright © 2018, Christopher Alan Mosher, Shelton, CT, USA. <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 "wozfile.h"
#include <istream>
#include <ostream>
#include <fstream>
WozFile::WozFile() {
unload();
}
WozFile::~WozFile() {
}
bool WozFile::load(const std::string& filePath) {
std::ifstream in(filePath.c_str(),std::ios::binary|std::ios::in);
if (!in.is_open()) {
printf("Error opening file: %d\n", errno);
return false;
}
if (isLoaded()) {
unload();
}
std::uint32_t woz1;
in.read((char*)&woz1, sizeof(woz1));
if (woz1 != 0x315A4F57u) {
printf("WOZ1 magic bytes missing.");
throw "WOZ1 magic bytes missing";
}
printf("WOZ1 magic bytes present\n");
std::uint32_t sanity;
in.read((char*)&sanity, sizeof(sanity));
if (sanity != 0x0A0D0AFFu) {
printf("FF 0A 0D 0A bytes corrupt.\n");
throw "FF 0A 0D 0A bytes corrupt";
}
std::uint32_t crc_given;
in.read((char*)&crc_given, sizeof(crc_given));
printf("Read given CRC: %08x\n", crc_given);
// TODO verify CRC
std::uint32_t chunk_id;
std::uint32_t chunk_size;
bool five_25(false);
while (in.read((char*)&chunk_id, sizeof(chunk_id))) {
in.read((char*)&chunk_size, sizeof(chunk_size));
printf("Chunk %.4s of size 0x%08x\n", (char*)&chunk_id, chunk_size);
switch (chunk_id) {
case 0x4F464E49: { // INFO
std::uint8_t* buf = new std::uint8_t[chunk_size];
in.read((char*)buf, chunk_size);
printf("INFO version %d\n", *buf);
five_25 = (buf[1]==1);
printf("Disk type: %s\n", five_25 ? "5.25" : buf[1]==2 ? "3.5" : "?");
writable = !(buf[2]==1);
printf("Write protected?: %s\n", writable ? "No" : "Yes");
printf("Imaged with cross-track sync?: %s\n", buf[3]==1 ? "Yes" : "No");
printf("MC3470 fake bits removed?: %s\n", buf[4]==1 ? "Yes" : "No");
printf("Creator: \"%.32s\"\n", buf+5);
delete[] buf;
}
break;
case 0x50414D54: { // TMAP
std::uint8_t* buf = new std::uint8_t[chunk_size];
in.read((char*)buf, chunk_size);
if (!five_25) {
printf("Can only handle 5.25 floppy disk images.\n");
throw "Can only handle 5.25 floppy disk images.";
} else {
printf("\x1b[31;47m-------------------------------------------\x1b[0m\n");
std::uint8_t i(0);
for (std::uint16_t t(0); t <= 3500; t += 25) {
if (buf[i] == 0xFFu) {
printf("\x1b[31;47m");
}
if (t % 100) {
printf("TMAP track 0x%02X +.%02d: TRKS track index 0x%02X", t/100, t%100, buf[i++]);
} else {
printf("TMAP track 0x%02X : TRKS track index 0x%02X", t/100, buf[i++]);
}
printf("\x1b[0m\n");
}
printf("\x1b[31;47m-------------------------------------------\x1b[0m\n");
for (std::uint8_t qt(0); qt <= 140; ++qt) {
tmap[qt] = buf[qt];
}
}
delete[] buf;
}
break;
case 0x534B5254: { // TRKS
std::uint8_t* buf = new std::uint8_t[chunk_size];
in.read((char*)buf, chunk_size);
if (chunk_size % 6656) {
printf("chunk size is not an even multiple of 6656.");
}
c_trks = chunk_size / 6656;
printf("Count of tracks: 0x%02X\n", c_trks);
if (c_trks > 141) {
printf("Error: cannot handle more than 141 tracks.");
throw "Error: cannot handle more than 141 tracks";
}
for (std::uint8_t t(0); t < c_trks; ++t) {
printf("track 0x%02X:\n", t);
std::uint16_t usedBytes = *(std::uint16_t*)&buf[t*6656+6646+0];
printf(" used bytes: 0x%0X\n", usedBytes);
trk_bits[t] = *(std::uint16_t*)&buf[t*6656+6646+2];
printf(" count of bits: 0x%0X\n", trk_bits[t]);
std::uint16_t spliceBit = *(std::uint16_t*)&buf[t*6656+6646+4];
if (spliceBit == 0xFFFFu) {
printf(" no splice information exists\n");
} else {
printf(" bit after splice point: 0x%0X\n", spliceBit);
}
std::uint8_t spliceNib = *(std::uint8_t*)&buf[t*6656+6646+6];
printf(" Nibble value to use for splice: 0x%0X\n", spliceNib);
std::uint8_t cSpliceBit = *(std::uint8_t*)&buf[t*6656+6646+7];
printf(" Bit count of splice nibble: 0x%0X\n", cSpliceBit);
std::uint8_t *base = (std::uint8_t*)&buf[t*6656+0];
std::uint8_t *pd = base;
printf(" beginning of data: 0x: ");
for (int cd(0); cd < 32; ++cd) {
printf("%02X", *pd++);
}
printf("\n");
for (int i(0); i < 6646; ++i) {
trks[t][i] = *base++;
}
}
delete[] buf;
}
break;
case 0x4154454D: { // META
std::uint8_t* buf = new std::uint8_t[chunk_size];
in.read((char*)buf, chunk_size);
std::uint32_t i(0);
char* pc((char*)buf);
while (i++ < chunk_size) {
if (*pc == '\t') {
printf(": ");
} else {
printf("%c", *pc);
}
pc++;
}
delete[] buf;
}
break;
default: { // unknown type of chunk; safely skip past it and ignore it
in.seekg(chunk_size, in.cur);
}
break;
}
}
in.close();
this->filePath = filePath;
checkForWriteProtection();
this->loaded = true;
this->modified = false;
return true;
}
void WozFile::checkForWriteProtection() {
if (!this->writable) {
return;
}
std::ofstream outf(filePath.c_str(),std::ios::binary|std::ios::app);
this->writable = outf.is_open();
outf.close();
}
void WozFile::save()
{
if (isWriteProtected() || !isLoaded())
{
return;
}
// std::ofstream out(filePath.c_str(),std::ios::binary);
// TODO SAVE FILE!
// out.flush();
// out.close();
// this->modified = false;
}
void WozFile::unload()
{
this->byt = 0;
this->writable = true;
this->loaded = false;
this->filePath = "";
this->modified = false;
}

67
src/wozfile.h Normal file
View File

@ -0,0 +1,67 @@
/*
epple2
Copyright © 2018, Christopher Alan Mosher, Shelton, CT, USA. <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 WOZFILE_H
#define WOZFILE_H
#include <string>
class WozFile {
std::string fileName;
std::string filePath;
bool writable;
bool loaded;
// TODO add bit position:
unsigned int byt; // represents rotational position of disk
bool modified;
std::uint8_t tmap[141]; // quarter-tracks from 0 through 35, values are indexes into trks
std::uint8_t c_trks; // count of actual tracks:
std::uint8_t trks[141][6646]; // 141 is theoretical max; will always be less
std::uint16_t trk_bits[141]; // count of bits in each track
void nextByte();
void checkForWriteProtection();
public:
WozFile();
~WozFile();
bool load(const std::string& filePath);
std::string getFileName() {
return this->fileName;
}
bool isLoaded() {
return this->loaded;
}
void save();
void unload();
bool isWriteProtected() {
return !this->writable;
}
bool isModified() {
return this->modified;
}
};
#endif // WOZFILE_H