mirror of
https://github.com/cmosher01/Epple-II.git
synced 2024-12-28 08:30:51 +00:00
RAM config; remove obsolete nib paths from config files
This commit is contained in:
parent
0183c5304f
commit
e8cdb8975e
@ -9,3 +9,9 @@
|
||||
import motherboard rom 1000 $(PREFIX)lib/apple2/system/a2/intbasic.a65
|
||||
import motherboard rom 2425 $(PREFIX)lib/apple2/system/a2/other.a65
|
||||
import motherboard rom 2800 $(PREFIX)lib/apple2/system/a2/monitor.a65
|
||||
|
||||
|
||||
|
||||
# 4K RAM
|
||||
motherboard ram C 4K 4K 4K 4K 4K 4K 4K 4K
|
||||
motherboard strap C 4K 0000
|
||||
|
@ -9,6 +9,16 @@
|
||||
|
||||
|
||||
|
||||
# 48K RAM
|
||||
motherboard ram E 16K
|
||||
motherboard ram D 16K
|
||||
motherboard ram C 16K
|
||||
motherboard strap E 16K 8000
|
||||
motherboard strap D 16K 4000
|
||||
motherboard strap C 16K 0000
|
||||
|
||||
|
||||
|
||||
# Integer BASIC and old Monitor ROMs
|
||||
import motherboard rom 1000 $(PREFIX)lib/apple2/system/a2/intbasic.a65
|
||||
import motherboard rom 2425 $(PREFIX)lib/apple2/system/a2/other.a65
|
||||
@ -21,4 +31,4 @@ slot 6 disk13
|
||||
import slot 6 rom 0 $(PREFIX)lib/apple2/dos/13sector/disk2.a65
|
||||
|
||||
# Insert DOS 3.1 System Master disk into drive 1
|
||||
load slot 6 drive 1 $(PREFIX)lib/apple2/dos/13sector/dos310/clean31sysmas_stock_rawdos.nib
|
||||
#load slot 6 drive 1 $(PREFIX)lib/apple2/dos/13sector/dos310/clean31sysmas_stock_rawdos.dsk.woz
|
||||
|
@ -9,6 +9,17 @@
|
||||
# indicator on the language card line turning on or off.
|
||||
|
||||
|
||||
|
||||
# 48K RAM
|
||||
motherboard ram E 16K
|
||||
motherboard ram D 16K
|
||||
motherboard ram C 16K
|
||||
motherboard strap E 16K 8000
|
||||
motherboard strap D 16K 4000
|
||||
motherboard strap C 16K 0000
|
||||
|
||||
|
||||
|
||||
# Integer BASIC and old Monitor ROMs
|
||||
import motherboard rom 1000 $(PREFIX)lib/apple2/system/a2/intbasic.a65
|
||||
import motherboard rom 2425 $(PREFIX)lib/apple2/system/a2/other.a65
|
||||
@ -26,4 +37,4 @@ slot 6 disk
|
||||
import slot 6 rom 0 $(PREFIX)lib/apple2/dos/16sector/disk2.a65
|
||||
|
||||
# Insert DOS 3.3 System Master disk (original version) in drive 1
|
||||
load slot 6 drive 1 $(PREFIX)lib/apple2/dos/16sector/dos330/clean330sysmas.nib
|
||||
#load slot 6 drive 1 $(PREFIX)lib/apple2/dos/16sector/dos330/clean330sysmas.dsk.woz
|
||||
|
@ -9,6 +9,16 @@
|
||||
|
||||
|
||||
|
||||
# 48K RAM
|
||||
motherboard ram E 16K
|
||||
motherboard ram D 16K
|
||||
motherboard ram C 16K
|
||||
motherboard strap E 16K 8000
|
||||
motherboard strap D 16K 4000
|
||||
motherboard strap C 16K 0000
|
||||
|
||||
|
||||
|
||||
# Integer BASIC and old Monitor ROMs
|
||||
import motherboard rom 1000 $(PREFIX)lib/apple2/system/a2/intbasic.a65
|
||||
import motherboard rom 2425 $(PREFIX)lib/apple2/system/a2/other.a65
|
||||
@ -48,7 +58,7 @@ import slot 4 rom 0 $(PREFIX)lib/epple2/cards/clock.a65
|
||||
slot 5 disk13
|
||||
import slot 5 rom 0 $(PREFIX)lib/apple2/dos/13sector/disk2.a65
|
||||
# Insert the DOS 3.1 System Master disk into drive 1 of slot 5
|
||||
load slot 5 drive 1 $(PREFIX)lib/apple2/dos/13sector/dos310/clean31sysmas_stock_rawdos.nib
|
||||
#load slot 5 drive 1 $(PREFIX)lib/apple2/dos/13sector/dos310/clean31sysmas_stock_rawdos.dsk.woz
|
||||
|
||||
|
||||
|
||||
@ -57,7 +67,7 @@ load slot 5 drive 1 $(PREFIX)lib/apple2/dos/13sector/dos310/clean31sysmas_stock_
|
||||
slot 6 disk
|
||||
import slot 6 rom 0 $(PREFIX)lib/apple2/dos/16sector/disk2.a65
|
||||
# Insert the DOS 3.3 System Master disk (original version) into slot 6
|
||||
load slot 6 drive 1 $(PREFIX)lib/apple2/dos/16sector/dos330/clean330sysmas.nib
|
||||
#load slot 6 drive 1 $(PREFIX)lib/apple2/dos/16sector/dos330/clean330sysmas.dsk.woz
|
||||
|
||||
|
||||
|
||||
|
@ -8,3 +8,9 @@
|
||||
|
||||
import motherboard rom 0000 $(PREFIX)lib/apple2/system/a2p/applesoft.a65
|
||||
import motherboard rom 2800 $(PREFIX)lib/apple2/system/a2p/monitor.a65
|
||||
|
||||
|
||||
|
||||
# 4K RAM
|
||||
motherboard ram C 4K 4K 4K 4K 4K 4K 4K 4K
|
||||
motherboard strap C 4K 0000
|
||||
|
@ -9,6 +9,16 @@
|
||||
# indicator on the language card line turning on or off.
|
||||
|
||||
|
||||
# 48K RAM
|
||||
motherboard ram E 16K
|
||||
motherboard ram D 16K
|
||||
motherboard ram C 16K
|
||||
motherboard strap E 16K 8000
|
||||
motherboard strap D 16K 4000
|
||||
motherboard strap C 16K 0000
|
||||
|
||||
|
||||
|
||||
# Applesoft BASIC and Autostart Monitor ROMs
|
||||
import motherboard rom 0000 $(PREFIX)lib/apple2/system/a2p/applesoft.a65
|
||||
import motherboard rom 2800 $(PREFIX)lib/apple2/system/a2p/monitor.a65
|
||||
@ -25,4 +35,4 @@ slot 6 disk
|
||||
import slot 6 rom 0 $(PREFIX)lib/apple2/dos/16sector/disk2.a65
|
||||
|
||||
# Insert DOS 3.3 System Master disk (original version) in drive 1
|
||||
load slot 6 drive 1 $(PREFIX)lib/apple2/dos/16sector/disks/dos330/clean330sysmas.nib
|
||||
#load slot 6 drive 1 $(PREFIX)lib/apple2/dos/16sector/disks/dos330/clean330sysmas.dsk.woz
|
||||
|
@ -9,6 +9,16 @@
|
||||
|
||||
|
||||
|
||||
# 48K RAM
|
||||
motherboard ram E 16K
|
||||
motherboard ram D 16K
|
||||
motherboard ram C 16K
|
||||
motherboard strap E 16K 8000
|
||||
motherboard strap D 16K 4000
|
||||
motherboard strap C 16K 0000
|
||||
|
||||
|
||||
|
||||
# Applesoft BASIC and Autostart Monitor ROMs
|
||||
import motherboard rom 0000 $(PREFIX)lib/apple2/system/a2p/applesoft.a65
|
||||
import motherboard rom 2800 $(PREFIX)lib/apple2/system/a2p/monitor.a65
|
||||
@ -47,7 +57,7 @@ import slot 4 rom 0 $(PREFIX)lib/epple2/cards/clock.a65
|
||||
slot 5 disk13
|
||||
import slot 5 rom 0 $(PREFIX)lib/apple2/dos/13sector/disk2.a65
|
||||
# Insert the DOS 3.1 System Master disk into drive 1 of slot 5
|
||||
load slot 5 drive 1 $(PREFIX)lib/apple2/dos/13sector/dos310/clean31sysmas_stock_rawdos.nib
|
||||
#load slot 5 drive 1 $(PREFIX)lib/apple2/dos/13sector/dos310/clean31sysmas_stock_rawdos.dsk.woz
|
||||
|
||||
|
||||
|
||||
@ -56,7 +66,7 @@ load slot 5 drive 1 $(PREFIX)lib/apple2/dos/13sector/dos310/clean31sysmas_stock_
|
||||
slot 6 disk
|
||||
import slot 6 rom 0 $(PREFIX)lib/apple2/dos/16sector/disk2.a65
|
||||
# Insert the DOS 3.3 System Master disk (original version) into slot 6
|
||||
load slot 6 drive 1 $(PREFIX)lib/apple2/dos/16sector/dos330/clean330sysmas.nib
|
||||
#load slot 6 drive 1 $(PREFIX)lib/apple2/dos/16sector/dos330/clean330sysmas.dsk.woz
|
||||
|
||||
|
||||
|
||||
|
@ -11,6 +11,14 @@
|
||||
|
||||
|
||||
|
||||
# standard 48K RAM
|
||||
motherboard ram E 16K
|
||||
motherboard ram D 16K
|
||||
motherboard ram C 16K
|
||||
motherboard strap E 16K 8000
|
||||
motherboard strap D 16K 4000
|
||||
motherboard strap C 16K 0000
|
||||
|
||||
# Demo system ROM for the emulator. This is only to allow the
|
||||
# emulator to do something useful when there are no real Apple ROM
|
||||
# images provided.
|
||||
@ -40,11 +48,11 @@ import slot 4 rom 0 $(PREFIX)lib/epple2/cards/clock.a65
|
||||
|
||||
#slot 5 disk13
|
||||
#import slot 5 rom 0 $(PREFIX)lib/apple2/dos/13sector/disk2.a65
|
||||
#load slot 5 drive 1 $(PREFIX)lib/apple2/dos/13sector/dos310/clean31sysmas_stock_rawdos.nib
|
||||
#load slot 5 drive 1 $(PREFIX)lib/apple2/dos/13sector/dos310/clean31sysmas_stock_rawdos.dsk.woz
|
||||
|
||||
#slot 6 disk
|
||||
#import slot 6 rom 0 $(PREFIX)lib/apple2/dos/16sector/disk2.a65
|
||||
#load slot 6 drive 1 $(PREFIX)lib/apple2/dos/16sector/dos330/clean330sysmas.nib
|
||||
#load slot 6 drive 1 $(PREFIX)lib/apple2/dos/16sector/dos330/clean330sysmas.dsk.woz
|
||||
|
||||
#slot 7 firmware
|
||||
#import slot 7 rombank 1000 $(PREFIX)lib/apple2/system/a2/intbasic.a65
|
||||
|
@ -10,6 +10,11 @@
|
||||
|
||||
|
||||
|
||||
# Use an original, revision zero, motherboard
|
||||
revision 0
|
||||
|
||||
|
||||
|
||||
# Load Integer BASIC and old Monitor ROMs
|
||||
import motherboard rom 1000 $(PREFIX)lib/apple2/system/a2/intbasic.a65
|
||||
import motherboard rom 2425 $(PREFIX)lib/apple2/system/a2/other.a65
|
||||
@ -17,5 +22,6 @@ import motherboard rom 2800 $(PREFIX)lib/apple2/system/a2/monitor.a65
|
||||
|
||||
|
||||
|
||||
# Use an original, revision zero, motherboard
|
||||
revision 0
|
||||
# 4K RAM
|
||||
motherboard ram C 4K 4K 4K 4K 4K 4K 4K 4K
|
||||
motherboard strap C 4K 0000
|
||||
|
@ -2,7 +2,7 @@ anchor:commands[]
|
||||
|
||||
=== Commands
|
||||
|
||||
+<<slot>> <<import>> <<load>> <<unload>> <<save>> <<cassette>> <<revision>>+
|
||||
+<<slot>> <<motherboard>> <<import>> <<load>> <<unload>> <<save>> <<cassette>> <<revision>>+
|
||||
|
||||
|
||||
|
||||
@ -45,6 +45,58 @@ The emulated Apple should be _powered off_ before inserting or removing cards.
|
||||
|
||||
|
||||
|
||||
anchor:motherboard[]
|
||||
|
||||
==== motherboard
|
||||
|
||||
The +motherboard+ command configures the emulated Apple's motherboard RAM chips and strapping block.
|
||||
|
||||
--------
|
||||
motherboard ram {C|D|E} { 4K | 4096 | 16K | 4116 | - } [...up to 8]
|
||||
motherboard strap {C|D|E} { 4K | 16K } <base>
|
||||
--------
|
||||
|
||||
The RAM configuration lines represent the rows of chips on the motherboard. The motherboard labels the
|
||||
rows as C, D, and E. Each row has 8 chips, one per bit in a byte. The Apple ][ accepts 4K or 16K chips.
|
||||
You use the +ram+ command to insert (or remove) chips from the sockets.
|
||||
You configure each row's address range by using a "strapping block" on the original Apple. In the
|
||||
emulator, use the +strap+ command to perform this function. You should strap 4K rows to a 4K range
|
||||
of RAM. You should always assign some RAM to the zero address.
|
||||
|
||||
For more information about RAM configuration, see
|
||||
https://archive.org/details/Apple_II_Reference_Manual_1979_Apple/page/n79[Christopher Espinosa, Apple II Reference Manual
|
||||
(Cupertino, Calif.: Apple Computer, 1978), pp. 70-72].
|
||||
|
||||
Example of normal 48K RAM configuration:
|
||||
--------
|
||||
ram e 16K
|
||||
strap e 16K 8000
|
||||
ram d 16K
|
||||
strap d 16K 4000
|
||||
ram c 16K
|
||||
strap c 16K 0000
|
||||
--------
|
||||
|
||||
Example of 4K, showing how you could specify each chip:
|
||||
--------
|
||||
ram e - - - - - - - -
|
||||
ram d - - - - - - - -
|
||||
ram c 4K 4K 4K 4K 4K 4K 4K 4K
|
||||
strap c 4K 0000
|
||||
--------
|
||||
|
||||
Example of 4K at zero address, and 8K at HI-RES page one:
|
||||
--------
|
||||
ram e 4K
|
||||
strap e 4K 3000
|
||||
ram d 4K
|
||||
strap d 4K 2000
|
||||
ram c 4K
|
||||
strap c 4K 0000
|
||||
--------
|
||||
|
||||
|
||||
|
||||
anchor:import[]
|
||||
|
||||
==== import
|
||||
@ -53,7 +105,7 @@ The +import+ command imports a binary image file into the emulated Apple's memor
|
||||
|
||||
--------
|
||||
import slot <slot> { rom | rom7 | rombank } <base> <file-path>
|
||||
import motherboard { rom | ram } <base> <file-path>
|
||||
import motherboard rom <base> <file-path>
|
||||
--------
|
||||
|
||||
+<slot>+ Slot number, 0 through 7, of peripheral card to import the binary image into.
|
||||
@ -63,17 +115,16 @@ import motherboard { rom | ram } <base> <file-path>
|
||||
+<file-path>+ Path of the binary image to import.
|
||||
|
||||
The +import+ command reads the binary image byte-for-byte from the given file-path
|
||||
into an area of memory in the emulated Apple. You can load into either the motherboard or
|
||||
a card in one of the slots. For the motherboard, you choose the RAM or ROM area. For a card
|
||||
in a slot, you can choose either the normal ROM, the bank-switched ROM, or the so-called
|
||||
``seventh ROM'' area.
|
||||
into an area of ROM in the emulated Apple. You can load into either the motherboard or
|
||||
a card in one of the slots. For a card in a slot, you can choose either the normal ROM,
|
||||
the bank-switched ROM, or the so-called ``seventh ROM'' area.
|
||||
|
||||
You also have to specify the base address within the specific memory
|
||||
area at which the image file will be loaded. Note that the base address is specified as the offset
|
||||
within the specific memory area, and not necessarily as the actual memory address as seen
|
||||
by the Apple. So for motherboard ROM, for example, specifying a base as 2DED will cause the
|
||||
image to be loaded at offset 2DED in the ROM, which will be addressed by the Apple at
|
||||
memory address $FDED (because motherboard ROM ``starts'' at address $D000).
|
||||
image to be loaded at offset $2DED in the ROM, which will be addressed by the Apple at
|
||||
memory address $FDED, because motherboard ROM ``starts'' at address $D000, and $D000 + $2DED = $FDED.
|
||||
|
||||
For peripheral cards, the ROM will be seen at locations $Cs00-$CsFF, where s is the slot
|
||||
number (1 through 7). The ``seventh ROM'' can be seen as locations $C800-$CFFF; Jim Sather
|
||||
|
@ -16,7 +16,9 @@ clipboardhandler.cpp clockcard.cpp \
|
||||
configep2.cpp cpu.cpp diskcontroller.cpp drive.cpp drivemotor.cpp \
|
||||
emptyslot.cpp emulator.cpp firmwarecard.cpp gui.cpp hypermode.cpp \
|
||||
keyboard.cpp keyboardbuffermode.cpp languagecard.cpp filterchroma.cpp \
|
||||
filterluma.cpp lss.cpp main.cpp memory.cpp paddlebuttonstates.cpp \
|
||||
filterluma.cpp lss.cpp main.cpp memory.cpp \
|
||||
memorychip.cpp memoryrow.cpp memorystrapping.cpp memoryrandomaccess.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 \
|
||||
@ -31,7 +33,9 @@ card.h cassette.h cassettein.h cassetteout.h \
|
||||
clipboardhandler.h clockcard.h configep2.h cpu.h \
|
||||
diskcontroller.h drive.h drivemotor.h e2const.h emptyslot.h emulator.h firmwarecard.h font3x5.h gui.h \
|
||||
hypermode.h keyboardbuffermode.h keyboard.h languagecard.h filterchroma.h \
|
||||
filterluma.h lss.h memory.h paddlebuttonstates.h paddles.h picturegenerator.h \
|
||||
filterluma.h lss.h memory.h \
|
||||
memorychip.h memoryrow.h memorystrapping.h memoryrandomaccess.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 \
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
#include "addressbus.h"
|
||||
#include "memory.h"
|
||||
#include "memoryrandomaccess.h"
|
||||
#include "keyboard.h"
|
||||
#include "videomode.h"
|
||||
#include "paddles.h"
|
||||
@ -26,7 +27,7 @@
|
||||
#include "cassetteout.h"
|
||||
#include "slots.h"
|
||||
|
||||
AddressBus::AddressBus(ScreenImage& gui, int& revision, Memory& ram, Memory& rom, Keyboard& kbd, VideoMode& vid, Paddles& paddles, PaddleButtonStates& paddleButtonStates, SpeakerClicker& speaker, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Slots& slts):
|
||||
AddressBus::AddressBus(ScreenImage& gui, int& revision, MemoryRandomAccess& ram, Memory& rom, Keyboard& kbd, VideoMode& vid, Paddles& paddles, PaddleButtonStates& paddleButtonStates, SpeakerClicker& speaker, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Slots& slts):
|
||||
gui(gui), revision(revision), ram(ram), rom(rom), kbd(kbd), vid(vid), paddles(paddles), paddleButtonStates(paddleButtonStates), speaker(speaker), cassetteIn(cassetteIn), cassetteOut(cassetteOut), slts(slts)
|
||||
{
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
class ScreenImage;
|
||||
class Memory;
|
||||
class MemoryRandomAccess;
|
||||
class Keyboard;
|
||||
class VideoMode;
|
||||
class Paddles;
|
||||
@ -33,7 +34,7 @@ class AddressBus {
|
||||
private:
|
||||
ScreenImage& gui;
|
||||
int& revision;
|
||||
Memory& ram;
|
||||
MemoryRandomAccess& ram;
|
||||
Memory& rom;
|
||||
Keyboard& kbd;
|
||||
VideoMode& vid;
|
||||
@ -47,7 +48,7 @@ class AddressBus {
|
||||
unsigned char data; // this emulates the (floating) data bus
|
||||
|
||||
public:
|
||||
AddressBus(ScreenImage& gui, int& revision, Memory& ram, Memory& rom, Keyboard& kbd, VideoMode& vid, Paddles& paddles, PaddleButtonStates& paddleButtonStates, SpeakerClicker& speaker, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Slots& slts);
|
||||
AddressBus(ScreenImage& gui, int& revision, MemoryRandomAccess& ram, Memory& rom, Keyboard& kbd, VideoMode& vid, Paddles& paddles, PaddleButtonStates& paddleButtonStates, SpeakerClicker& speaker, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Slots& slts);
|
||||
~AddressBus();
|
||||
|
||||
unsigned char read(const unsigned short address);
|
||||
|
@ -42,7 +42,7 @@ Apple2::Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates
|
||||
slts(gui),
|
||||
kbd(keypresses,fhyper,buffered),
|
||||
rom(AddressBus::MOTHERBOARD_ROM_SIZ),
|
||||
ram(AddressBus::MOTHERBOARD_RAM_SIZ),
|
||||
ram(revision),
|
||||
cassetteIn(gui),
|
||||
cassetteOut(gui),
|
||||
addressBus(gui,revision,ram,rom,kbd,videoMode,paddles,paddleButtonStates,speaker,cassetteIn,cassetteOut,slts),
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "keyboard.h"
|
||||
#include "addressbus.h"
|
||||
#include "memory.h"
|
||||
#include "memoryrandomaccess.h"
|
||||
#include "picturegenerator.h"
|
||||
#include "textcharacters.h"
|
||||
#include "video.h"
|
||||
@ -51,7 +52,7 @@ class Apple2 : public Timable
|
||||
Paddles paddles;
|
||||
SpeakerClicker speaker;
|
||||
Memory rom;
|
||||
Memory ram;
|
||||
MemoryRandomAccess ram;
|
||||
CassetteIn cassetteIn;
|
||||
CassetteOut cassetteOut;
|
||||
AddressBus addressBus;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "configep2.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "memoryrandomaccess.h"
|
||||
#include "slots.h"
|
||||
#include "diskcontroller.h"
|
||||
#include "languagecard.h"
|
||||
@ -36,6 +37,34 @@
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
#define K 1024u
|
||||
|
||||
static std::uint16_t chip_size(const std::string &chip_model) {
|
||||
if (chip_model == "4K") {
|
||||
return 4u*K;
|
||||
}
|
||||
if (chip_model == "16K") {
|
||||
return 16u*K;
|
||||
}
|
||||
if (chip_model == "-") {
|
||||
return 0u;
|
||||
}
|
||||
throw ConfigException("unrecognized RAM chip model");
|
||||
}
|
||||
|
||||
static std::uint16_t memory_block_size(const std::string &block_size) {
|
||||
if (block_size == "4K") {
|
||||
return 4u*K;
|
||||
}
|
||||
if (block_size == "16K") {
|
||||
return 16u*K;
|
||||
}
|
||||
throw ConfigException("invalid RAM strapping block size (must be 4K or 16K)");
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned char Config::disk_mask(0);
|
||||
|
||||
Config::Config(const std::string& file_path):
|
||||
@ -75,7 +104,7 @@ static void trim(std::string& str)
|
||||
}
|
||||
}
|
||||
|
||||
void Config::parse(Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut)
|
||||
void Config::parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut)
|
||||
{
|
||||
std::ifstream* pConfig;
|
||||
|
||||
@ -154,7 +183,7 @@ void Config::parse(Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenI
|
||||
|
||||
// TODO: make sure there is no more than ONE stdin and/or ONE stdout card
|
||||
}
|
||||
void Config::parseLine(const std::string& line, Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut)
|
||||
void Config::parseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -166,7 +195,7 @@ void Config::parseLine(const std::string& line, Memory& ram, Memory& rom, Slots&
|
||||
}
|
||||
}
|
||||
|
||||
void Config::tryParseLine(const std::string& line, Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut)
|
||||
void Config::tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut)
|
||||
{
|
||||
std::istringstream tok(line);
|
||||
|
||||
@ -180,7 +209,62 @@ void Config::tryParseLine(const std::string& line, Memory& ram, Memory& rom, Slo
|
||||
|
||||
insertCard(sCardType,slot,slts,gui);
|
||||
}
|
||||
else if (cmd == "import")
|
||||
else if (cmd == "motherboard") {
|
||||
std::string op;
|
||||
tok >> op;
|
||||
if (op == "ram") {
|
||||
/* ram ROW BIT0 [BIT1 [... [BIT7]]]
|
||||
* ram e -
|
||||
* ram d 4096 MK4096 4K
|
||||
* ram c 16K 4116 MK4116 MM5290 16K 16K 16K 16K
|
||||
*/
|
||||
std::string row;
|
||||
tok >> row;
|
||||
std::transform(row.begin(), row.end(), row.begin(), ::toupper);
|
||||
if (row != "C" && row != "D" && row != "E") {
|
||||
throw ConfigException("expected row to be C, D, or E");
|
||||
}
|
||||
std::string chip_model;
|
||||
tok >> chip_model;
|
||||
std::uint16_t siz = chip_size(chip_model);
|
||||
for (std::uint_fast8_t bit = 0u; bit < 8u; ++bit) {
|
||||
if (siz) {
|
||||
ram.insert_chip(row, MemoryChip(siz,chip_model), bit);
|
||||
} else {
|
||||
ram.remove_chip(row, bit);
|
||||
}
|
||||
std::string chip_model_optional;
|
||||
tok >> chip_model_optional;
|
||||
if (chip_model_optional.length()) {
|
||||
chip_model = chip_model_optional;
|
||||
}
|
||||
siz = chip_size(chip_model);
|
||||
}
|
||||
} else if (op == "strap") {
|
||||
/* strap ROM K start-addr
|
||||
* strap c 4K 0000
|
||||
* strap d 4K 1000
|
||||
* strap e 4K 2000
|
||||
*/
|
||||
std::string row;
|
||||
tok >> row;
|
||||
std::transform(row.begin(), row.end(), row.begin(), ::toupper);
|
||||
if (row != "C" && row != "D" && row != "E") {
|
||||
throw ConfigException("expected row to be C, D, or E");
|
||||
}
|
||||
|
||||
std::string block_size;
|
||||
tok >> block_size;
|
||||
std::uint16_t siz = memory_block_size(block_size);
|
||||
unsigned short base(0);
|
||||
tok >> std::hex >> base;
|
||||
// TODO validate siz/base combination
|
||||
ram.strap_to(row, base, siz);
|
||||
} else {
|
||||
throw ConfigException("error at \"motherboard\"; expected \"ram\" or \"strap\"");
|
||||
}
|
||||
}
|
||||
else if (cmd == "import")
|
||||
{
|
||||
std::string sm;
|
||||
tok >> sm;
|
||||
@ -216,10 +300,6 @@ void Config::tryParseLine(const std::string& line, Memory& ram, Memory& rom, Slo
|
||||
{
|
||||
rom.load(base,memfile);
|
||||
}
|
||||
else if (romtype == "ram")
|
||||
{
|
||||
ram.load(base,memfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ConfigException("error at \""+romtype+"\"; expected rom or ram");
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include <string>
|
||||
class Memory;
|
||||
class MemoryRandomAccess;
|
||||
class Slots;
|
||||
class ScreenImage;
|
||||
class CassetteIn;
|
||||
@ -42,14 +43,14 @@ private:
|
||||
static void unloadDisk(Slots& slts, int slot, int drive);
|
||||
static void saveDisk(Slots& slts, int slot, int drive);
|
||||
static void insertCard(const std::string& cardType, int slot, Slots& slts, ScreenImage& gui);
|
||||
static void tryParseLine(const std::string& line, Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut);
|
||||
static void tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut);
|
||||
|
||||
public:
|
||||
Config(const std::string& file_path);
|
||||
~Config();
|
||||
|
||||
void parse(Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut);
|
||||
static void parseLine(const std::string& line, Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut);
|
||||
void parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut);
|
||||
static void parseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
|
||||
|
||||
Copyright © 2008, 2019, 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
|
||||
@ -19,32 +20,76 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <istream>
|
||||
#include <cstdlib>
|
||||
#include "raminitializer.h"
|
||||
|
||||
const int Memory::CLEAR_VALUE(0);
|
||||
|
||||
|
||||
/*
|
||||
* If any RAM IC sockets are empty, set the corresponding bits to 1 most of the time.
|
||||
* But set to 0 instead, with probability 1 in 137 (a rough estimate obtained empirically)
|
||||
*/
|
||||
static std::uint8_t randomize_missing_bits(std::uint8_t v, const std::uint8_t bits) {
|
||||
std::uint8_t bit = 1u;
|
||||
for (std::uint_fast8_t i = 0; i < 8; ++i) {
|
||||
if (bits & bit) {
|
||||
double r = static_cast<double>(std::rand())/RAND_MAX;
|
||||
if (r < 1.0/137.0) {
|
||||
v &= ~bit;
|
||||
} else {
|
||||
v |= bit;
|
||||
}
|
||||
}
|
||||
bit <<= 1;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Memory::Memory(const size_t n):
|
||||
bytes(n)
|
||||
{
|
||||
bytes(n),
|
||||
clear_value(0u),
|
||||
missing_bits(0u) {
|
||||
}
|
||||
|
||||
void Memory::clear()
|
||||
{
|
||||
std::fill(this->bytes.begin(),this->bytes.end(),CLEAR_VALUE);
|
||||
|
||||
|
||||
void Memory::clear() {
|
||||
std::fill(this->bytes.begin(), this->bytes.end(), this->clear_value);
|
||||
}
|
||||
|
||||
void Memory::powerOn()
|
||||
{
|
||||
RAMInitializer initRam(*this);
|
||||
initRam.init();
|
||||
void Memory::init() {
|
||||
RAMInitializer initRam(*this);
|
||||
initRam.init();
|
||||
}
|
||||
|
||||
void Memory::powerOff()
|
||||
{
|
||||
clear();
|
||||
void Memory::load(const std::uint16_t base, std::istream& in) {
|
||||
in.read(reinterpret_cast<char*>(&this->bytes[base]), static_cast<ptrdiff_t>(this->bytes.size()-base));
|
||||
}
|
||||
|
||||
void Memory::load(const unsigned short base, std::istream& in)
|
||||
{
|
||||
in.read((char*)&this->bytes[base],this->bytes.size()-base);
|
||||
|
||||
|
||||
void Memory::powerOn() {
|
||||
init();
|
||||
}
|
||||
|
||||
void Memory::powerOff() {
|
||||
clear();
|
||||
}
|
||||
|
||||
size_t Memory::size() const {
|
||||
return this->bytes.size();
|
||||
}
|
||||
|
||||
std::uint8_t Memory::read(const std::uint16_t address) const {
|
||||
std::uint8_t v = this->bytes[address];
|
||||
if (this->missing_bits) {
|
||||
v = randomize_missing_bits(v, this->missing_bits);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void Memory::write(const std::uint16_t address, const std::uint8_t data) {
|
||||
this->bytes[address] = data;
|
||||
}
|
||||
|
45
src/memory.h
45
src/memory.h
@ -20,34 +20,27 @@
|
||||
|
||||
#include <vector>
|
||||
#include <istream>
|
||||
#include <cstdint>
|
||||
|
||||
class Memory
|
||||
{
|
||||
private:
|
||||
std::vector<unsigned char> bytes;
|
||||
static const int CLEAR_VALUE;
|
||||
class Memory {
|
||||
private:
|
||||
std::vector<std::uint8_t> bytes;
|
||||
const std::uint8_t clear_value;
|
||||
const std::uint8_t missing_bits;
|
||||
|
||||
public:
|
||||
Memory(const size_t n);
|
||||
size_t size() const
|
||||
{
|
||||
return this->bytes.size();
|
||||
}
|
||||
|
||||
unsigned char read(const unsigned short address) const
|
||||
{
|
||||
return this->bytes[address];
|
||||
}
|
||||
|
||||
void write(const unsigned short address, const unsigned char data)
|
||||
{
|
||||
this->bytes[address] = data;
|
||||
}
|
||||
|
||||
void clear();
|
||||
void powerOn();
|
||||
void powerOff();
|
||||
void load(const unsigned short base, std::istream& in);
|
||||
public:
|
||||
Memory(const size_t n);
|
||||
virtual ~Memory() { }
|
||||
|
||||
size_t size() const;
|
||||
std::uint8_t read(const std::uint16_t address) const;
|
||||
void write(const std::uint16_t address, const std::uint8_t data);
|
||||
void powerOn();
|
||||
void powerOff();
|
||||
|
||||
void clear();
|
||||
void init();
|
||||
void load(const std::uint16_t base, std::istream& in);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
74
src/memorychip.cpp
Normal file
74
src/memorychip.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "memorychip.h"
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#define K 1024
|
||||
|
||||
MemoryChip::MemoryChip(const std::uint16_t size, const std::string &id_model):
|
||||
size_bits(size),
|
||||
id_model(id_model) {
|
||||
if (size_bits != 4*K && size_bits != 16*K) {
|
||||
throw std::out_of_range("MemoryChip must be 4K or 16K");
|
||||
}
|
||||
}
|
||||
|
||||
MemoryChip::MemoryChip(const MemoryChip &that):
|
||||
size_bits(that.size_bits),
|
||||
id_model(that.id_model) {
|
||||
}
|
||||
|
||||
MemoryChip &MemoryChip::operator=(const MemoryChip &that) {
|
||||
this->size_bits = that.size_bits;
|
||||
this->id_model = that.id_model;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MemoryChip::~MemoryChip() {
|
||||
}
|
||||
|
||||
std::uint16_t MemoryChip::size() const {
|
||||
return this->size_bits;
|
||||
}
|
||||
|
||||
std::string MemoryChip::id() const {
|
||||
return this->id_model;
|
||||
}
|
||||
|
||||
bool MemoryChip::exists() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bitflag(const bool on, const std::uint8_t mask, std::uint8_t &byte) {
|
||||
if (on) {
|
||||
byte |= mask;
|
||||
} else {
|
||||
byte &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
//#define CYCLE 128u
|
||||
#define CYCLE 2u
|
||||
|
||||
void MemoryChip::init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size) const {
|
||||
bool on = false;
|
||||
std::uint8_t c = 0u;
|
||||
for (std::uint16_t i = 0u; i < std::min(size, this->size_bits); ++i) {
|
||||
bitflag(on, mask, bytes[i]);
|
||||
if (CYCLE <= ++c) {
|
||||
c = 0u;
|
||||
on = !on;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemoryChipEmptySocket::MemoryChipEmptySocket():
|
||||
MemoryChip(4*K,"[empty]") {
|
||||
}
|
||||
|
||||
MemoryChipEmptySocket::~MemoryChipEmptySocket() {
|
||||
}
|
||||
|
||||
bool MemoryChipEmptySocket::exists() const {
|
||||
return false;
|
||||
}
|
29
src/memorychip.h
Normal file
29
src/memorychip.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef MEMORYCHIP_H
|
||||
#define MEMORYCHIP_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class MemoryChip {
|
||||
private:
|
||||
std::uint16_t size_bits;
|
||||
std::string id_model;
|
||||
public:
|
||||
MemoryChip(const std::uint16_t size, const std::string &id_model);
|
||||
MemoryChip(const MemoryChip &that);
|
||||
MemoryChip &operator=(const MemoryChip &that);
|
||||
virtual ~MemoryChip();
|
||||
std::uint16_t size() const;
|
||||
std::string id() const;
|
||||
virtual void init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size) const;
|
||||
virtual bool exists() const;
|
||||
};
|
||||
|
||||
class MemoryChipEmptySocket : public MemoryChip {
|
||||
public:
|
||||
MemoryChipEmptySocket();
|
||||
virtual ~MemoryChipEmptySocket();
|
||||
virtual bool exists() const;
|
||||
};
|
||||
|
||||
#endif // MEMORYCHIP_H
|
149
src/memoryrandomaccess.cpp
Normal file
149
src/memoryrandomaccess.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
#include "memoryrandomaccess.h"
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
|
||||
#define K 1024u
|
||||
|
||||
MemoryRandomAccess::MemoryRandomAccess(int &revision):
|
||||
revision(revision),
|
||||
rowE('E'),
|
||||
strapE(rowE),
|
||||
rowD('D'),
|
||||
strapD(rowD),
|
||||
rowC('C'),
|
||||
strapC(rowC) {
|
||||
}
|
||||
|
||||
MemoryRow &MemoryRandomAccess::row_of(const std::string &row) {
|
||||
if (row == "E") {
|
||||
return this->rowE;
|
||||
}
|
||||
if (row == "D") {
|
||||
return this->rowD;
|
||||
}
|
||||
if (row == "C") {
|
||||
return this->rowC;
|
||||
}
|
||||
throw std::logic_error("expected C/D/E");
|
||||
}
|
||||
|
||||
MemoryStrapping &MemoryRandomAccess::strapping_of(const std::string &row) {
|
||||
if (row == "E") {
|
||||
return this->strapE;
|
||||
}
|
||||
if (row == "D") {
|
||||
return this->strapD;
|
||||
}
|
||||
if (row == "C") {
|
||||
return this->strapC;
|
||||
}
|
||||
throw std::logic_error("expected C/D/E");
|
||||
}
|
||||
|
||||
void MemoryRandomAccess::insert_chip(const std::string &row, MemoryChip chip, const std::uint_fast8_t socket) {
|
||||
row_of(row).insert_chip(chip, socket);
|
||||
}
|
||||
|
||||
void MemoryRandomAccess::remove_chip(const std::string &row, const std::uint_fast8_t socket) {
|
||||
row_of(row).remove_chip(socket);
|
||||
}
|
||||
|
||||
void MemoryRandomAccess::strap_to(const std::string &row, std::uint16_t addr_base, std::uint16_t addr_size) {
|
||||
strapping_of(row).strap_to(addr_base, addr_size);
|
||||
}
|
||||
|
||||
bool MemoryRandomAccess::k20or24() const {
|
||||
const std::uint32_t k = this->rowC.size() + this->rowD.size() + this->rowD.size();
|
||||
return (k==20*K) || (k==24*K);
|
||||
}
|
||||
|
||||
/* for 20K or 24K on rev. 0: pages 40-5F are dup w/ 60-7F */
|
||||
std::uint8_t MemoryRandomAccess::buggyRamRead(const std::uint16_t address) const {
|
||||
std::uint16_t ax = address & ~0x2000u;
|
||||
if (this->strapE.contains(ax)) {
|
||||
return this->strapE.read(ax);
|
||||
}
|
||||
if (this->strapD.contains(ax)) {
|
||||
return this->strapD.read(ax);
|
||||
}
|
||||
if (this->strapC.contains(ax)) {
|
||||
return this->strapC.read(ax);
|
||||
}
|
||||
ax = address | 0x2000u;
|
||||
if (this->strapE.contains(ax)) {
|
||||
return this->strapE.read(ax);
|
||||
}
|
||||
if (this->strapD.contains(ax)) {
|
||||
return this->strapD.read(ax);
|
||||
}
|
||||
if (this->strapC.contains(ax)) {
|
||||
return this->strapC.read(ax);
|
||||
}
|
||||
return MemoryRow::missing_memory_byte_value();
|
||||
}
|
||||
|
||||
std::uint8_t MemoryRandomAccess::read(const std::uint16_t address) const {
|
||||
if (this->revision == 0 && k20or24() && ((address & 0xC000u) == 0x4000u)) {
|
||||
return buggyRamRead(address);
|
||||
}
|
||||
if (this->strapE.contains(address)) {
|
||||
return this->strapE.read(address);
|
||||
}
|
||||
if (this->strapD.contains(address)) {
|
||||
return this->strapD.read(address);
|
||||
}
|
||||
if (this->strapC.contains(address)) {
|
||||
return this->strapC.read(address);
|
||||
}
|
||||
return MemoryRow::missing_memory_byte_value();
|
||||
}
|
||||
|
||||
void MemoryRandomAccess::buggyRamWrite(std::uint16_t address, const std::uint8_t data) {
|
||||
std::uint16_t ax = address & ~0x2000u;
|
||||
if (this->strapE.contains(ax)) {
|
||||
this->strapE.write(ax, data);
|
||||
}
|
||||
if (this->strapD.contains(ax)) {
|
||||
this->strapD.write(ax, data);
|
||||
}
|
||||
if (this->strapC.contains(ax)) {
|
||||
this->strapC.write(ax, data);
|
||||
}
|
||||
ax = address | 0x2000u;
|
||||
if (this->strapE.contains(ax)) {
|
||||
this->strapE.write(ax, data);
|
||||
}
|
||||
if (this->strapD.contains(ax)) {
|
||||
this->strapD.write(ax, data);
|
||||
}
|
||||
if (this->strapC.contains(ax)) {
|
||||
this->strapC.write(ax, data);
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryRandomAccess::write(const std::uint16_t address, const std::uint8_t data) {
|
||||
if (this->revision == 0 && k20or24() && ((address & 0xC000u) == 0x4000u)) {
|
||||
buggyRamWrite(address, data);
|
||||
}
|
||||
if (this->strapE.contains(address)) {
|
||||
this->strapE.write(address, data);
|
||||
}
|
||||
if (this->strapD.contains(address)) {
|
||||
this->strapD.write(address, data);
|
||||
}
|
||||
if (this->strapC.contains(address)) {
|
||||
this->strapC.write(address, data);
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryRandomAccess::powerOn() {
|
||||
this->rowE.powerOn();
|
||||
this->rowD.powerOn();
|
||||
this->rowC.powerOn();
|
||||
}
|
||||
|
||||
void MemoryRandomAccess::powerOff() {
|
||||
this->rowE.powerOff();
|
||||
this->rowD.powerOff();
|
||||
this->rowC.powerOff();
|
||||
}
|
38
src/memoryrandomaccess.h
Normal file
38
src/memoryrandomaccess.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef MEMORYRANDOMACCESS_H
|
||||
#define MEMORYRANDOMACCESS_H
|
||||
|
||||
#include "memorystrapping.h"
|
||||
#include "memoryrow.h"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class MemoryRandomAccess {
|
||||
private:
|
||||
int &revision;
|
||||
MemoryRow rowE;
|
||||
MemoryStrapping strapE;
|
||||
MemoryRow rowD;
|
||||
MemoryStrapping strapD;
|
||||
MemoryRow rowC;
|
||||
MemoryStrapping strapC;
|
||||
|
||||
MemoryRow &row_of(const std::string &row);
|
||||
MemoryStrapping &strapping_of(const std::string &row);
|
||||
std::uint8_t buggyRamRead(std::uint16_t address) const;
|
||||
void buggyRamWrite(std::uint16_t address, const std::uint8_t data);
|
||||
bool k20or24() const;
|
||||
|
||||
public:
|
||||
MemoryRandomAccess(int &revision);
|
||||
|
||||
void insert_chip(const std::string &row, MemoryChip chip, const std::uint_fast8_t socket);
|
||||
void remove_chip(const std::string &row, const std::uint_fast8_t socket);
|
||||
void strap_to(const std::string &row, std::uint16_t addr_base, std::uint16_t addr_size);
|
||||
|
||||
std::uint8_t read(std::uint16_t address) const;
|
||||
void write(std::uint16_t address, const std::uint8_t data);
|
||||
void powerOn();
|
||||
void powerOff();
|
||||
};
|
||||
|
||||
#endif
|
131
src/memoryrow.cpp
Normal file
131
src/memoryrow.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
#include "memoryrow.h"
|
||||
#include <exception>
|
||||
#include <cstdlib>
|
||||
|
||||
/*
|
||||
* If any RAM IC sockets are empty, set the corresponding bits to 1 most of the time.
|
||||
* For some addresses it seems they are always 1, but for other addresses they can return
|
||||
* 0 sometimes, empirically I've seen anywhere from 8% to 15% of the time.
|
||||
*/
|
||||
static std::uint8_t randomize_missing_bits(std::uint8_t v, const std::uint8_t bits) {
|
||||
std::uint8_t bit = 1u;
|
||||
for (std::uint_fast8_t i = 0; i < 8; ++i) {
|
||||
if (bits & bit) {
|
||||
double r = static_cast<double>(std::rand())/RAND_MAX;
|
||||
if (r < 0.11) {
|
||||
v &= ~bit;
|
||||
} else {
|
||||
v |= bit;
|
||||
}
|
||||
}
|
||||
bit <<= 1;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
MemoryRow::MemoryRow(const char label):
|
||||
label(label) {
|
||||
}
|
||||
|
||||
MemoryRow::~MemoryRow() {
|
||||
}
|
||||
|
||||
void MemoryRow::insert_chip(MemoryChip chip, const std::uint_fast8_t socket) {
|
||||
if (socket < 8u) {
|
||||
remove_chip(socket);
|
||||
if (chip.exists()) {
|
||||
this->chips[socket] = chip;
|
||||
this->missing_bits &= ~(1u << socket);
|
||||
this->values_stored.resize(calculate_size());
|
||||
}
|
||||
} else {
|
||||
throw std::out_of_range("socket must be < 8");
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryRow::remove_chip(const std::uint_fast8_t socket) {
|
||||
if (socket < 8u) {
|
||||
this->chips[socket] = MemoryChipEmptySocket();
|
||||
this->missing_bits |= (1u << socket);
|
||||
this->values_stored.resize(calculate_size());
|
||||
} else {
|
||||
throw std::out_of_range("socket must be < 8");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If no chips, return 0.
|
||||
* Otherwise, return minimum of existing chips (4K or 16K)
|
||||
*/
|
||||
std::uint16_t MemoryRow::calculate_size() const {
|
||||
std::uint16_t size_new = 0u;
|
||||
|
||||
for (std::uint_fast8_t i_chip = 0; i_chip < 8; ++i_chip) {
|
||||
const MemoryChip &chip = this->chips[i_chip];
|
||||
if (chip.exists()) {
|
||||
const std::uint16_t s = chip.size();
|
||||
if (size_new == 0u || s < size_new) {
|
||||
size_new = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return size_new;
|
||||
}
|
||||
|
||||
void MemoryRow::powerOff() {
|
||||
this->power = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calls init of each chip, and uses a bit mask to assemble into bytes.
|
||||
*/
|
||||
void MemoryRow::powerOn() {
|
||||
if (!this->power) {
|
||||
this->power = true;
|
||||
|
||||
std::uint8_t mask_bit = 1u;
|
||||
for (std::uint_fast8_t i_bit = 0; i_bit < 8; ++i_bit) {
|
||||
const MemoryChip &chip = this->chips[i_bit];
|
||||
if (chip.exists()) {
|
||||
chip.init(mask_bit, this->values_stored, size());
|
||||
}
|
||||
mask_bit <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::uint16_t MemoryRow::size() const {
|
||||
return static_cast<std::uint16_t>(this->values_stored.size());
|
||||
}
|
||||
|
||||
std::uint8_t MemoryRow::missing_memory_byte_value() {
|
||||
return randomize_missing_bits(0xFFu, 0xFFu);
|
||||
}
|
||||
|
||||
std::uint8_t MemoryRow::read(const std::uint16_t address_offset) const {
|
||||
if (this->power) {
|
||||
std::uint8_t v;
|
||||
if (address_offset < this->values_stored.size()) {
|
||||
v = this->values_stored[address_offset];
|
||||
if (this->missing_bits) {
|
||||
v = randomize_missing_bits(v, this->missing_bits);
|
||||
}
|
||||
} else {
|
||||
v = missing_memory_byte_value();
|
||||
}
|
||||
return v;
|
||||
} else {
|
||||
throw std::logic_error("cannot read memory when power is off");
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryRow::write(const std::uint16_t address, const std::uint8_t data) {
|
||||
if (this->power) {
|
||||
this->values_stored[address] = data;
|
||||
} else {
|
||||
throw std::logic_error("cannot write memory when power is off");
|
||||
}
|
||||
}
|
49
src/memoryrow.h
Normal file
49
src/memoryrow.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef MEMORYROW_H
|
||||
#define MEMORYROW_H
|
||||
|
||||
#include "memorychip.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
class MemoryRow {
|
||||
private:
|
||||
/* C, D, E */
|
||||
const char label;
|
||||
|
||||
bool power = false;
|
||||
|
||||
/* 8 sockets for memory chips (empty socket represented by MemoryChipEmptySocket) */
|
||||
std::array<MemoryChip,8> chips = {MemoryChipEmptySocket(),MemoryChipEmptySocket(),MemoryChipEmptySocket(),MemoryChipEmptySocket(),MemoryChipEmptySocket(),MemoryChipEmptySocket(),MemoryChipEmptySocket(),MemoryChipEmptySocket()};
|
||||
|
||||
/* bit mask of empty chip sockets */
|
||||
std::uint8_t missing_bits = 0xFFu;
|
||||
|
||||
/*
|
||||
* Instead of storing each bit in a MemoryChip (too slow), we store the data here as bytes,
|
||||
* representing one bit for each chip.
|
||||
*/
|
||||
std::vector<std::uint8_t> values_stored;
|
||||
|
||||
std::uint16_t calculate_size() const;
|
||||
|
||||
public:
|
||||
MemoryRow(const char label);
|
||||
virtual ~MemoryRow();
|
||||
|
||||
void insert_chip(MemoryChip chip, const std::uint_fast8_t socket);
|
||||
void remove_chip(const std::uint_fast8_t socket);
|
||||
void powerOff();
|
||||
void powerOn();
|
||||
|
||||
/* 4K or 16K, size of each chip (or minimum in corner case of mixed sizes) */
|
||||
std::uint16_t size() const;
|
||||
|
||||
std::uint8_t read(const std::uint16_t address) const;
|
||||
void write(const std::uint16_t address, const std::uint8_t data);
|
||||
|
||||
static std::uint8_t missing_memory_byte_value();
|
||||
};
|
||||
|
||||
#endif // MEMORYROW_H
|
23
src/memorystrapping.cpp
Normal file
23
src/memorystrapping.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "memorystrapping.h"
|
||||
#include <algorithm>
|
||||
|
||||
MemoryStrapping::MemoryStrapping(MemoryRow &row):
|
||||
row(row) {
|
||||
}
|
||||
|
||||
void MemoryStrapping::strap_to(std::uint16_t addr_base, std::uint16_t addr_size) {
|
||||
this->addr_base = addr_base;
|
||||
this->addr_size = addr_size;
|
||||
}
|
||||
|
||||
bool MemoryStrapping::contains(std::uint16_t address) const {
|
||||
return this->addr_base <= address && address < this->addr_base + std::min(this->row.size(), this->addr_size);
|
||||
}
|
||||
|
||||
std::uint8_t MemoryStrapping::read(const std::uint16_t address) const {
|
||||
return this->row.read(address - this->addr_base);
|
||||
}
|
||||
|
||||
void MemoryStrapping::write(const std::uint16_t address, const std::uint8_t data) {
|
||||
this->row.write(address - this->addr_base, data);
|
||||
}
|
20
src/memorystrapping.h
Normal file
20
src/memorystrapping.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef MEMORYSTRAPPING_H
|
||||
#define MEMORYSTRAPPING_H
|
||||
|
||||
#include "memoryrow.h"
|
||||
#include <cstdint>
|
||||
|
||||
class MemoryStrapping {
|
||||
private:
|
||||
MemoryRow &row;
|
||||
std::uint16_t addr_base;
|
||||
std::uint16_t addr_size;
|
||||
public:
|
||||
MemoryStrapping(MemoryRow &row);
|
||||
void strap_to(std::uint16_t addr_base, std::uint16_t addr_size);
|
||||
bool contains(std::uint16_t address) const;
|
||||
std::uint8_t read(const std::uint16_t address) const;
|
||||
void write(const std::uint16_t address, const std::uint8_t data);
|
||||
};
|
||||
|
||||
#endif
|
@ -40,7 +40,7 @@ void RAMInitializer::init()
|
||||
putBytesUntilFull(b++,2);
|
||||
putBytesUntilFull(b++,2);
|
||||
putBytesUntilFull(b++,1);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void RAMInitializer::putBytesUntilFull(int bit, int pat)
|
||||
|
Loading…
Reference in New Issue
Block a user