diff --git a/src/Makefile.am b/src/Makefile.am index d2891fa..28f1495 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/lss.cpp b/src/lss.cpp new file mode 100644 index 0000000..ff422b1 --- /dev/null +++ b/src/lss.cpp @@ -0,0 +1,187 @@ +/* + epple2 + + Copyright © 2018, Christopher Alan Mosher, Shelton, CT, USA. + + 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 . +*/ + +#include "lss.h" + +#include +#include + +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() { +} diff --git a/src/lss.h b/src/lss.h new file mode 100644 index 0000000..d64ec8e --- /dev/null +++ b/src/lss.h @@ -0,0 +1,41 @@ +/* + epple2 + + Copyright © 2018, Christopher Alan Mosher, Shelton, CT, USA. + + 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 . +*/ + +#ifndef LSS_H +#define LSS_H + +#include + +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 diff --git a/src/wozfile.cpp b/src/wozfile.cpp new file mode 100644 index 0000000..0c2e237 --- /dev/null +++ b/src/wozfile.cpp @@ -0,0 +1,225 @@ +/* + epple2 + + Copyright © 2018, Christopher Alan Mosher, Shelton, CT, USA. + + 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 . +*/ + +#include "wozfile.h" + +#include +#include +#include + +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; +} diff --git a/src/wozfile.h b/src/wozfile.h new file mode 100644 index 0000000..402de2c --- /dev/null +++ b/src/wozfile.h @@ -0,0 +1,67 @@ +/* + epple2 + + Copyright © 2018, Christopher Alan Mosher, Shelton, CT, USA. + + 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 . +*/ + +#ifndef WOZFILE_H +#define WOZFILE_H + +#include + +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