mirror of
https://github.com/JorjBauer/aiie.git
synced 2024-11-25 19:31:36 +00:00
initial commit
This commit is contained in:
commit
85a97abe13
16
Makefile
Executable file
16
Makefile
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
LDFLAGS=-L/usr/local/lib
|
||||||
|
CXXFLAGS=-Wall -I .. -I . -O3
|
||||||
|
|
||||||
|
TSRC=cpu.cpp util/testharness.cpp
|
||||||
|
|
||||||
|
all:
|
||||||
|
@echo There is no 'all' target. Yet.
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *~ */*.o */*~ testharness.basic testharness.verbose testharness.extended
|
||||||
|
|
||||||
|
test: $(TSRC)
|
||||||
|
g++ $(CXXFLAGS) -DBASICTEST $(TSRC) -o testharness.basic
|
||||||
|
g++ $(CXXFLAGS) -DVERBOSETEST $(TSRC) -o testharness.verbose
|
||||||
|
g++ $(CXXFLAGS) -DEXTENDEDTEST $(TSRC) -o testharness.extended
|
||||||
|
|
52
README.txt
Normal file
52
README.txt
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
Aiie!
|
||||||
|
=====
|
||||||
|
|
||||||
|
Aiie! is an Apple //e emulator, written ground-up for the Teensy
|
||||||
|
3.6.
|
||||||
|
|
||||||
|
The name comes from a game I used to play on the Apple //e back
|
||||||
|
around 1986 - Ali Baba and the Forty Thieves, published by Quality
|
||||||
|
Software in 1981.
|
||||||
|
|
||||||
|
http://crpgaddict.blogspot.com/2013/07/game-103-ali-baba-and-forty-thieves-1981.html
|
||||||
|
|
||||||
|
When characters in the game did damage to each other, they exclaimed
|
||||||
|
something like "HAH! JUST A SCRATCH!" or "AAARGH!" or "OH MA, I THINK
|
||||||
|
ITS MY TIME" [sic]. One of these exclamations was "AIIYEEEEE!!"
|
||||||
|
|
||||||
|
Build log:
|
||||||
|
----------
|
||||||
|
|
||||||
|
https://hackaday.io/project/19925-aiie-an-embedded-apple-e-emulator
|
||||||
|
|
||||||
|
CPU
|
||||||
|
===
|
||||||
|
|
||||||
|
The CPU is a 65C02, not quite complete; it supports all of the 65C02
|
||||||
|
documented opcodes but not the undocumented ones here:
|
||||||
|
|
||||||
|
http://www.oxyron.de/html/opcodes02.html
|
||||||
|
|
||||||
|
The timing of the CPU is also not quite correct. It's close, but
|
||||||
|
doesn't count cycles due to page boundary crossings during branch
|
||||||
|
instructions. (See the "cycle count footnotes" in cpu.cpp.)
|
||||||
|
|
||||||
|
The CPU passes the 6502 functional test from here:
|
||||||
|
|
||||||
|
https://github.com/Klaus2m5/6502_65C02_functional_tests
|
||||||
|
|
||||||
|
... which is included in binary form in the test harness (see the .h
|
||||||
|
files in util/ for notes).
|
||||||
|
|
||||||
|
testharness.basic should reach "test number 240", hang for a while,
|
||||||
|
and then exit.
|
||||||
|
|
||||||
|
testharness.verbose should show that it gets through 43 tests, test
|
||||||
|
240, and then loops repeatedly for a while (exiting at a somewhat
|
||||||
|
arbitrary point).
|
||||||
|
|
||||||
|
testharness.extended currently fails (hanging at 0x733) because I
|
||||||
|
haven't implemented the undocumented opcodes. It should get to address
|
||||||
|
0x24a8 and hang. Some day I'll finish implementing all of the
|
||||||
|
undocumented opcodes :)
|
||||||
|
|
73
cpu.h
Normal file
73
cpu.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#ifndef __CPU_H
|
||||||
|
#define __CPU_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class MMU;
|
||||||
|
|
||||||
|
// Flags (P) register bit definitions.
|
||||||
|
// Negative
|
||||||
|
#define F_N (1<<7)
|
||||||
|
// Overflow
|
||||||
|
#define F_V (1<<6)
|
||||||
|
#define F_UNK (1<<5) // What the heck is this?
|
||||||
|
// Break
|
||||||
|
#define F_B (1<<4)
|
||||||
|
// Decimal
|
||||||
|
#define F_D (1<<3)
|
||||||
|
// Interrupt Disable
|
||||||
|
#define F_I (1<<2)
|
||||||
|
// Zero
|
||||||
|
#define F_Z (1<<1)
|
||||||
|
// Carry
|
||||||
|
#define F_C (1<<0)
|
||||||
|
|
||||||
|
class Cpu {
|
||||||
|
public:
|
||||||
|
Cpu();
|
||||||
|
~Cpu();
|
||||||
|
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
void nmi();
|
||||||
|
void rst();
|
||||||
|
void brk();
|
||||||
|
void irq();
|
||||||
|
|
||||||
|
uint8_t Run(uint8_t numSteps);
|
||||||
|
uint8_t step();
|
||||||
|
|
||||||
|
uint8_t X();
|
||||||
|
uint8_t Y();
|
||||||
|
uint8_t A();
|
||||||
|
uint16_t PC();
|
||||||
|
uint8_t SP();
|
||||||
|
uint8_t P();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Stack manipulation
|
||||||
|
void pushS8(uint8_t b);
|
||||||
|
void pushS16(uint16_t w);
|
||||||
|
uint8_t popS8();
|
||||||
|
uint16_t popS16();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void SetMMU(MMU *mmu) { this->mmu = mmu; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint16_t pc;
|
||||||
|
uint8_t sp;
|
||||||
|
uint8_t a;
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
uint8_t flags;
|
||||||
|
|
||||||
|
uint32_t cycles;
|
||||||
|
|
||||||
|
MMU *mmu;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
17
mmu.h
Normal file
17
mmu.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef __MMU_H
|
||||||
|
#define __MMU_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class MMU {
|
||||||
|
public:
|
||||||
|
virtual ~MMU() {}
|
||||||
|
|
||||||
|
virtual void Reset() = 0;
|
||||||
|
|
||||||
|
virtual uint8_t read(uint16_t mem) = 0;
|
||||||
|
virtual void write(uint16_t mem, uint8_t val) = 0;
|
||||||
|
virtual uint8_t readDirect(uint16_t address, uint8_t fromPage) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
8202
util/6502_functional_test.h
Normal file
8202
util/6502_functional_test.h
Normal file
File diff suppressed because it is too large
Load Diff
8206
util/6502_functional_test_2.h
Normal file
8206
util/6502_functional_test_2.h
Normal file
File diff suppressed because it is too large
Load Diff
8202
util/65C02_extended_opcodes_test.h
Normal file
8202
util/65C02_extended_opcodes_test.h
Normal file
File diff suppressed because it is too large
Load Diff
64
util/testharness.cpp
Normal file
64
util/testharness.cpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cpu.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
|
||||||
|
#ifdef BASICTEST
|
||||||
|
#include "6502_functional_test.h"
|
||||||
|
#elif defined(VERBOSETEST)
|
||||||
|
#include "6502_functional_test_2.h"
|
||||||
|
#elif defined(EXTENDEDTEST)
|
||||||
|
#include "65C02_extended_opcodes_test.h"
|
||||||
|
#else
|
||||||
|
#error undefined test - specify one of BASICTEST, VERBOSETEST, or EXTENDEDTEST
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class TestMMU : public MMU {
|
||||||
|
public:
|
||||||
|
TestMMU() {}
|
||||||
|
virtual ~TestMMU() {}
|
||||||
|
|
||||||
|
virtual void Reset() {}
|
||||||
|
|
||||||
|
virtual uint8_t read(uint16_t mem) { if (mem == 0xBFF0) { return 'R'; } return ram[mem];}
|
||||||
|
virtual void write(uint16_t mem, uint8_t val) {
|
||||||
|
if (mem == 0xBFF0) {printf("%c", val); return;}
|
||||||
|
if (mem == 0x200) {printf("Start test %d\n", val);}
|
||||||
|
ram[mem] = val;}
|
||||||
|
virtual uint8_t readDirect(uint16_t address, uint8_t fromPage) { return read(address);}
|
||||||
|
|
||||||
|
uint8_t ram[65536];
|
||||||
|
};
|
||||||
|
|
||||||
|
Cpu cpu;
|
||||||
|
TestMMU mmu;
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
cpu.SetMMU(&mmu);
|
||||||
|
cpu.rst();
|
||||||
|
|
||||||
|
// Load the 6502 functional test
|
||||||
|
memcpy(mmu.ram, functest, 0x10000);
|
||||||
|
cpu.pc = 0x400;
|
||||||
|
// cpu.Reset();
|
||||||
|
|
||||||
|
time_t startTime = time(NULL);
|
||||||
|
// call cpu.Run() in the worst possible way (most overhead)
|
||||||
|
for (uint32_t i=0; i<1000000000; i++) {
|
||||||
|
cpu.Run(1);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (cpu.pc < 0x477F) {
|
||||||
|
printf("%llu OP $%.2X #%d 0x%.2X X 0x%.2X Y 0x%.2X A 0x%.2X SP 0x%.2X S 0x%.2X\n", cpu.cycles, mmu.read(cpu.pc), mmu.read(0x200), cpu.pc, cpu.x, cpu.y, cpu.a, cpu.sp, cpu.flags);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
time_t endTime = time(NULL);
|
||||||
|
|
||||||
|
printf("%ld seconds\n", endTime - startTime);
|
||||||
|
printf("Ending PC: 0x%X\n", cpu.pc);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user