chiark / gitweb /
Something to do with the clock that wasn't checked in earlier
authorThomas Thurman <tthurman@gnome.org>
Sat, 6 Nov 2010 13:19:30 +0000 (09:19 -0400)
committerThomas Thurman <tthurman@gnome.org>
Sat, 6 Nov 2010 13:19:30 +0000 (09:19 -0400)
TODO.txt
albert.pro
src/Application.cpp
src/Application.h
src/Memory.cpp
src/Memory.h
src/Processor.cpp
src/Processor.h

index 4a2eb1d..6fdc7f9 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
@@ -1,2 +1,3 @@
- - More opcodes
- - Implement some of SHEILA
+ - Add the ability for separate classes to hook into particular addresses in F/J/S
+ - Document the behaviour of the system VIA when read and written to
+
index 0960df9..604d5b8 100644 (file)
@@ -1,11 +1,17 @@
 SOURCES += src/Processor.cpp
 SOURCES += src/Memory.cpp
 SOURCES += src/Application.cpp
+SOURCES += src/Clock.cpp
+SOURCES += src/MemoryMap.cpp
+SOURCES += src/SystemVIA.cpp
 SOURCES += src/albert.cpp
 
 HEADERS += src/Processor.h
 HEADERS += src/Memory.h
+HEADERS += src/Clock.h
 HEADERS += src/Application.h
+HEADERS += src/MemoryMap.h
+HEADERS += src/SystemVIA.h
 
 CONFIG += qt
 
index a7b83ad..8a94f46 100644 (file)
@@ -2,7 +2,9 @@
 
 Application::Application(int argc, char**argv):
   QApplication(argc, argv),
-  m_processor(&m_memory)
+  m_memory(),
+  mSystemVIA(&m_memory),
+  m_processor(&m_memory, &m_clock)
 {
   this->startTimer(250);
 }
index 6821dec..1cd6e5d 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "Memory.h"
 #include "Processor.h"
+#include "SystemVIA.h"
 #include <QApplication>
 
 class Application: public QApplication {
@@ -17,6 +18,8 @@ class Application: public QApplication {
 
  private:
   Memory m_memory;
+  Clock m_clock;
+  SystemVIA mSystemVIA;
   Processor m_processor;
 };
 
index 54c2d6d..47fb6ab 100644 (file)
@@ -1,8 +1,10 @@
-#include "Memory.h"
 #include <QFile>
 #include <QDebug>
 #include <stdio.h>
 
+#include "Memory.h"
+#include "MemoryMap.h"
+
 // 0000 to 7FFF - RAM
 // 8000 to BFFF - one or more language ROMs
 // C000 to FFFF - MOS ROM
@@ -43,23 +45,16 @@ int Memory::readByteFrom(int position) {
     // Language ROM read.
     return m_languageRom[position-0x8000] & 0xFF;
 
-  } else if (position>=0xFC00 && position<=0xFCFF) {
-
-    // FRED read.
-    qDebug() << "FRED read";
-    return 0;
-
-  } else if (position>=0xFD00 && position<=0xFDFF) {
-
-    // JIM read.
-    qDebug() << "JIM read";
-    return 0;
+  } else if (position>=0xFC00 && position<=0xFEFF) {
 
-  } else if (position>=0xFE00 && position<=0xFEFF) {
+    // FRED/JIM/SHEILA read.
 
-    // SHEILA read.
-    qDebug() << QString("SHEILA read %1").arg(position, 0, 16);
-    return 0;
+    if (mMemoryMap.contains(position)) {
+      return mMemoryMap[position]->read(position);
+    } else {
+      qDebug() << QString("Unknown FRED/JIM/SHEILA read %1").arg(position, 0, 16);
+      return 0;
+    }
 
   } else if (position>=0xC000 && position<=0xFFFF) {
 
@@ -93,24 +88,21 @@ void Memory::writeByteTo(int position, int byte) {
       printf("%c", byte);
     }
 
-  } else if (position>=0xFC00 && position<=0xFCFF) {
+  } else if (position>=0xFC00 && position<=0xFEFF) {
 
-    // FRED write.
-    qDebug() << "FRED write";
+    // FRED/JIM/SHEILA write.
 
+    // === FRED ===
+    //
     // FC10 to FC13 - Teletext
     // FC40 to FC43 - SCSI
 
-  } else if (position>=0xFD00 && position<=0xFDFF) {
-
-    // JIM write.
-    qDebug() << "JIM write";
-
+    // === JIM ===
+    //
     // FDF0 to FDF3 - SASI
 
-  } else if (position>=0xFE00 && position<=0xFEFF) {
-
-    // SHEILA write.
+    // === SHEILA ===
+    //
     // FE00 to FE07 - CRTC
     // FE08 - ACIA Status
     // FE09 - ACIA Data
@@ -130,7 +122,12 @@ void Memory::writeByteTo(int position, int byte) {
     // FEEx - Tube
     // FEFx - Tube
     
-    qDebug() << QString("SHEILA write %1 %2").arg(position, 0, 16).arg(byte, 0, 16);
+
+    if (mMemoryMap.contains(position)) {
+      mMemoryMap[position]->write(position, byte);
+    } else {
+      qDebug() << QString("Unknown FRED/JIM/SHEILA write %1 %2").arg(position, 0, 16).arg(byte, 0, 16);
+    }
 
   } else {
 
@@ -139,3 +136,12 @@ void Memory::writeByteTo(int position, int byte) {
   }
 
 }
+
+void Memory::hookMemoryMap(int startAddress,
+                          int endAddress,
+                          MemoryMap *map)
+{
+  for (int i=startAddress; i<=endAddress; i++) {
+    mMemoryMap[i] = map;
+  }
+}
index abef615..c5d7af7 100644 (file)
@@ -2,6 +2,9 @@
 #define MEMORY_H 1
 
 #include <QObject>
+#include <QHash>
+
+class MemoryMap;
 
 class Memory : public QObject {
 
@@ -15,10 +18,22 @@ class Memory : public QObject {
 
   void writeByteTo(int position, int byte);
 
+  /**
+   * Hooks a given series of addresses.
+   * When these addresses are
+   * read to or written from, the given MemoryMap
+   * will be notified.  This only works for addresses
+   * within FRED, JIM, and SHEILA (FC00 to FEFF).
+   */
+  void hookMemoryMap(int startAddress,
+                    int endAddress,
+                    MemoryMap *map);
+
  private:
   QByteArray m_ram;
   QByteArray m_languageRom;
   QByteArray m_mos;
+  QHash<int, MemoryMap*> mMemoryMap;
 };
 
 #endif
index 304f3fd..d40113a 100644 (file)
@@ -31,10 +31,11 @@ struct Opcode {
 
 #include "opcodes.cpp"
 
-Processor::Processor(Memory *memory):
+Processor::Processor(Memory *memory, Clock *clock):
   QObject()
 {
   m_memory = memory;
+  m_clock = clock;
 
   m_programCounter = memory->readWordFrom(0xFFFC);
 
@@ -51,8 +52,6 @@ Processor::Processor(Memory *memory):
   m_interrupt = false;
   m_break = false;
 
-  m_waiting = 0;
-
   m_goldenTrailPosition = 0;
 }
 
@@ -114,7 +113,8 @@ void Processor::oneShot() {
 #endif
 
   opcode = m_memory->readByteFrom(m_programCounter++);
-  m_waiting = opcodes[opcode].cycles;
+  // A machine cycle is two clock cycles.
+  m_clock->advance(opcodes[opcode].cycles * 2);
 
   switch (opcodes[opcode].mode) {
 
@@ -210,7 +210,7 @@ void Processor::oneShot() {
     OpcodeDetails(0x10, MODE_BRANCH,         2);
     if (!m_sign) {
       m_programCounter += branchDisplacement;
-      m_waiting++;
+      m_clock->advance(1);
     }
     break;
 
@@ -218,7 +218,7 @@ void Processor::oneShot() {
     OpcodeDetails(0x30, MODE_BRANCH,         2);
     if (m_sign) {
       m_programCounter += branchDisplacement;
-      m_waiting++;
+      m_clock->advance(1);
     }
     break;
 
@@ -226,7 +226,7 @@ void Processor::oneShot() {
     OpcodeDetails(0x50, MODE_BRANCH,         2);
     if (!m_overflow) {
       m_programCounter += branchDisplacement;
-      m_waiting++;
+      m_clock->advance(1);
     }
     break;
 
@@ -234,7 +234,7 @@ void Processor::oneShot() {
     OpcodeDetails(0x70, MODE_BRANCH,         2);
     if (m_overflow) {
       m_programCounter += branchDisplacement;
-      m_waiting++;
+      m_clock->advance(1);
     }
     break;
 
@@ -242,7 +242,7 @@ void Processor::oneShot() {
     OpcodeDetails(0x90, MODE_BRANCH,         2);
     if (!m_carry) {
       m_programCounter += branchDisplacement;
-      m_waiting++;
+      m_clock->advance(1);
     }
     break;
 
@@ -250,7 +250,7 @@ void Processor::oneShot() {
     OpcodeDetails(0xb0, MODE_BRANCH,         2);
     if (m_carry) {
       m_programCounter += branchDisplacement;
-      m_waiting++;
+      m_clock->advance(1);
     }
     break;
 
@@ -258,7 +258,7 @@ void Processor::oneShot() {
     OpcodeDetails(0xd0, MODE_BRANCH,         2);
     if (!m_zero) {
       m_programCounter += branchDisplacement;
-      m_waiting++;
+      m_clock->advance(1);
     }
     break;
 
@@ -266,7 +266,7 @@ void Processor::oneShot() {
     OpcodeDetails(0xf0, MODE_BRANCH,         2);
     if (m_zero) {
       m_programCounter += branchDisplacement;
-      m_waiting++;
+      m_clock->advance(1);
     }
     break;
 
@@ -637,32 +637,31 @@ void Processor::oneShot() {
 
     break;
 
-  case OP_JMP:
+  case OP_JMP:  // Jump
     OpcodeDetails(0x4c, MODE_ABSOLUTE,       3);
     OpcodeDetails(0x6c, MODE_INDIRECT,       5);
     m_programCounter = address;
     break;
 
-    ////////////////////////////////////////////////////////////////
+  case OP_LSR:  // Logical shift right
+    OpcodeDetails(0x46, MODE_ZERO_PAGE,      5);
+    OpcodeDetails(0x4a, MODE_ACCUMULATOR,    2);
+    OpcodeDetails(0x4e, MODE_ABSOLUTE,       6);
+    OpcodeDetails(0x56, MODE_ZERO_PAGE_X,    6);
+    OpcodeDetails(0x5e, MODE_ABSOLUTE_X,     7);
 
-  case OP_XXX:
-    qDebug() << "Alert!  Unknown opcode: " << QString("%1").arg(opcode, 2, 16);
-    throw "Unknown opcode.";
+    param = this->readParam(address);
+    m_carry = (param & 0x01) != 0;
+    if (param & 0x01) {
+      param |= 0x100;
+    }
+    param >>= 1;
+    m_zero = param == 0;
+    m_sign = (param & 0x80) != 0;
+    this->writeParam(address, param);
     break;
 
-    // Not implemented:
-
-  case OP_SBC:
-    OpcodeDetails(0xe1, MODE_INDIRECT_X,     6);
-    OpcodeDetails(0xe5, MODE_ZERO_PAGE,      3);
-    OpcodeDetails(0xe9, MODE_IMMEDIATE,      2);
-    OpcodeDetails(0xed, MODE_ABSOLUTE,       4);
-    OpcodeDetails(0xf1, MODE_INDIRECT_Y,     5);
-    OpcodeDetails(0xf5, MODE_ZERO_PAGE_X,    4);
-    OpcodeDetails(0xf9, MODE_ABSOLUTE_Y,     4);
-    OpcodeDetails(0xfd, MODE_ABSOLUTE_X,     4);
-
-  case OP_AND:
+  case OP_AND: // Bitwise AND with accumulator
     OpcodeDetails(0x21, MODE_INDIRECT_X,     6);
     OpcodeDetails(0x25, MODE_ZERO_PAGE,      2);
     OpcodeDetails(0x29, MODE_IMMEDIATE,      2);
@@ -672,7 +671,14 @@ void Processor::oneShot() {
     OpcodeDetails(0x39, MODE_ABSOLUTE_Y,     4);
     OpcodeDetails(0x3d, MODE_ABSOLUTE_X,     4);
 
-  case OP_EOR:
+    param = this->readParam(address);
+    param &= m_accumulator;
+    m_zero = param == 0;
+    m_sign = (param & 0x80) != 0;
+    this->writeParam(address, param);
+    break;
+
+  case OP_EOR: // Bitwise exclusive OR with accumulator
     OpcodeDetails(0x41, MODE_INDIRECT_X,     6);
     OpcodeDetails(0x45, MODE_ZERO_PAGE,      3);
     OpcodeDetails(0x49, MODE_IMMEDIATE,      2);
@@ -682,10 +688,14 @@ void Processor::oneShot() {
     OpcodeDetails(0x59, MODE_ABSOLUTE_Y,     4);
     OpcodeDetails(0x5d, MODE_ABSOLUTE_X,     4);
 
-  case OP_RTI:
-    OpcodeDetails(0x40, MODE_IMPLIED,        6);
+    param = this->readParam(address);
+    param ^= m_accumulator;
+    m_zero = param == 0;
+    m_sign = (param & 0x80) != 0;
+    this->writeParam(address, param);
+    break;
 
-  case OP_ORA:
+  case OP_ORA: // Bitwise OR with accumulator
     OpcodeDetails(0x01, MODE_INDIRECT_X,     6);
     OpcodeDetails(0x05, MODE_ZERO_PAGE,      2);
     OpcodeDetails(0x09, MODE_IMMEDIATE,      2);
@@ -695,16 +705,44 @@ void Processor::oneShot() {
     OpcodeDetails(0x19, MODE_ABSOLUTE_Y,     4);
     OpcodeDetails(0x1d, MODE_ABSOLUTE_X,     4);
 
-  case OP_BIT:
+    param = this->readParam(address);
+    param |= m_accumulator;
+    m_zero = param == 0;
+    m_sign = (param & 0x80) != 0;
+    this->writeParam(address, param);
+    break;
+
+  case OP_BIT: // Test bits
     OpcodeDetails(0x24, MODE_ZERO_PAGE,      3);
     OpcodeDetails(0x2c, MODE_ABSOLUTE,       4);
 
-  case OP_LSR:
-    OpcodeDetails(0x46, MODE_ZERO_PAGE,      5);
-    OpcodeDetails(0x4a, MODE_ACCUMULATOR,    2);
-    OpcodeDetails(0x4e, MODE_ABSOLUTE,       6);
-    OpcodeDetails(0x56, MODE_ZERO_PAGE_X,    6);
-    OpcodeDetails(0x5e, MODE_ABSOLUTE_X,     7);
+    param = this->readParam(address);
+    m_sign = (param & 0x80) != 0;
+    m_overflow = (param & 0x40) != 0;
+    m_zero = (param & m_accumulator) == 0;
+    break;
+
+    ////////////////////////////////////////////////////////////////
+
+  case OP_XXX:
+    qDebug() << "Alert!  Unknown opcode: " << QString("%1").arg(opcode, 2, 16);
+    throw "Unknown opcode.";
+    break;
+
+    // Not implemented:
+
+  case OP_SBC:
+    OpcodeDetails(0xe1, MODE_INDIRECT_X,     6);
+    OpcodeDetails(0xe5, MODE_ZERO_PAGE,      3);
+    OpcodeDetails(0xe9, MODE_IMMEDIATE,      2);
+    OpcodeDetails(0xed, MODE_ABSOLUTE,       4);
+    OpcodeDetails(0xf1, MODE_INDIRECT_Y,     5);
+    OpcodeDetails(0xf5, MODE_ZERO_PAGE_X,    4);
+    OpcodeDetails(0xf9, MODE_ABSOLUTE_Y,     4);
+    OpcodeDetails(0xfd, MODE_ABSOLUTE_X,     4);
+
+  case OP_RTI:
+    OpcodeDetails(0x40, MODE_IMPLIED,        6);
 
   case OP_ADC:
     OpcodeDetails(0x61, MODE_INDIRECT_X,     6);
@@ -725,20 +763,11 @@ void Processor::oneShot() {
 
 void Processor::runCycles(int count) {
 
-  if (m_waiting >= count) {
-    m_waiting -= count;
-    return;
-  }
-
-  int cyclesTaken = m_waiting;
-
-  while (cyclesTaken < count) {
-    m_waiting = 0;
+  unsigned long endTime = m_clock->getTime() + count;
 
+  do {
     this->oneShot();
-
-    cyclesTaken += m_waiting;
-  }
+  } while (m_clock->getTime() < endTime);
 
 }
 
index 900e2a2..5972914 100644 (file)
@@ -2,13 +2,15 @@
 #define PROCESSOR_H 1
 
 #include "Memory.h"
+#include "Clock.h"
 
 class Processor: public QObject {
 
   Q_OBJECT
 
  public:
-  Processor(Memory *memory);
+  Processor(Memory *memory,
+           Clock *clock);
 
   void oneShot();
 
@@ -29,6 +31,7 @@ class Processor: public QObject {
   void writeParam(int address, int param);
 
   Memory *m_memory;
+  Clock *m_clock;
 
   int m_programCounter;
 
@@ -45,8 +48,6 @@ class Processor: public QObject {
   bool m_interrupt;
   bool m_break;
 
-  int m_waiting;
-
   int m_goldenTrailPosition;
 };