Alt8800 — Esp32 Devkit C V4 simulation

An interactive Esp32 Devkit C V4 circuit simulation you can run free in your browser on Velxio, by alireza-cs94.

Components

Sketch code

#include "Altair680BMachine.h"

Altair680BMachine::Altair680BMachine()
  : machineConfig(defaultConfig()), ready(false), running(false),
    addressSwitch(0), dataSwitch(0), addressReg(0), dataReg(0),
    processor(), memoryBus(), ioDevice() {}

Altair680BMachine::Config Altair680BMachine::defaultConfig() {
  const auto& p = AltairModelProfile::get(AltairModelProfile::ALTAIR_680B);
  Config c;
  c.model = AltairModelProfile::ALTAIR_680B;
  c.ramSize = M6800Bus::RAM_64K;
  c.inputPort = p.inputPort;
  c.outputPort = p.outputPort;
  return c;
}

bool Altair680BMachine::beginModel(AltairModelProfile::Model model) {
  if (model != AltairModelProfile::ALTAIR_680B) return false;
  return begin(defaultConfig());
}

bool Altair680BMachine::begin(const Config& config) {
  ready = false;
  running = false;
  machineConfig = config;

  if (machineConfig.model != AltairModelProfile::ALTAIR_680B) return false;
  const auto& p = AltairModelProfile::get(machineConfig.model);
  if (p.cpuFamily != AltairModelProfile::CPU_MOTOROLA_6800) return false;

  if (!memoryBus.begin(machineConfig.ramSize)) return false;
  ioDevice.begin(machineConfig.inputPort, machineConfig.outputPort);
  processor.attachBus(&memoryBus);

  // A real 680B reset fetches its reset vector. Preserve RAM contents while
  // initializing the machine state, so a loaded monitor/program survives RESET.
  processor.reset();
  addressSwitch = processor.PC;
  dataSwitch = 0;
  addressReg = processor.PC;
  dataReg = memoryBus.readMemory(addressReg);
  ready = true;
  return true;
}

void Altair680BMachine::reset() {
  if (!ready) return;
  running = false;
  processor.reset();
  ioDevice.clearBuffers();
  // The physical 680B address switches are independent of RESET. Keep the
  // selected address and refresh the displayed byte after reset.
  addressReg = addressSwitch;
  dataReg = memoryBus.readMemory(addressReg);
}

void Altair680BMachine::stop() {
  if (!ready) return;
  running = false;
  processor.halted = true;
}

void Altair680BMachine::run() {
  if (!ready) return;
  running = true;
  processor.halted = false;
}

bool Altair680BMachine::step() {
  if (!ready || !running) return false;
  if (processor.halted && !processor.waiting) return false;
  processor.step();
  if (processor.halted && !processor.waiting) running = false;
  return true;
}

size_t Altair680BMachine::runSteps(size_t maxSteps) {
  size_t executed = 0;
  while (running && executed < maxSteps) {
    if (!step()) break;
    ++executed;
  }
  return executed;
}

bool Altair680BMachine::load(const uint8_t* data, uint16_t address, size_t length) {
  if (!ready || !data || length == 0) return false;
  memoryBus.load(data, address, length);
  // Program loading establishes the entry point at the requested address,
  // matching the 8080 loader contract. A subsequent RUN begins there.
  processor.PC = address;
  running = false;
  processor.halted = true;
  processor.waiting = false;
  addressSwitch = address;
  addressReg = address;

More projects by alireza-cs94