Made class methods static for greater performance

This commit is contained in:
andrew-jacobs 2016-10-22 23:46:41 +01:00
parent c3d347d906
commit 6638462e10
16 changed files with 457 additions and 402 deletions

View File

@ -3,10 +3,15 @@
The repository contains the source code for a simple 65C816 emulator for Windows,
Linux and the embedded ChipKIT platform.
This is the first release of the code and it has only had a limited amount of
This is the second release of the code and it has only had a limited amount of
testing. Currently there is no support for decimal arithmetic but the full
instruction set is supported.
The major change since the last release has been the recoding of all the classes
to make them static. This was done to increase the execution performance of the
code. On my development laptop (AMD8 1.8GHz) it now runs at an emulated speed of
around 225 MHz with full optimization.
There is no I/O at the moment or source of interrupts. Executing a WDM #$FF will
cause the emulator to exit.

View File

@ -9,7 +9,7 @@
//
// A Portable C++ WDC 65C816 Emulator
//------------------------------------------------------------------------------
// Copyright (C)2016 Andrew John Jacobs
// Copyright (C),2016 Andrew John Jacobs
// All rights reserved.
//
// This work is made available under the terms of the Creative Commons
@ -32,14 +32,32 @@
using namespace std;
#endif
union emu816::FLAGS emu816::p;
emu816::Bit emu816::e;
union emu816::REGS emu816::a;
union emu816::REGS emu816::x;
union emu816::REGS emu816::y;
union emu816::REGS emu816::sp;
union emu816::REGS emu816::dp;
emu816::Word emu816::pc;
emu816::Byte emu816::pbr;
emu816::Byte emu816::dbr;
bool emu816::stopped;
bool emu816::interrupted;
unsigned long emu816::cycles;
bool emu816::trace;
//==============================================================================
// Construct a emu816 instance.
emu816::emu816(mem816 &mem)
: mem(mem)
// Not used.
emu816::emu816()
{ }
// Destroy a emu816 instance.
// Not used
emu816::~emu816()
{ }
@ -51,13 +69,13 @@ void emu816::reset(bool trace)
dbr = 0x00 << 16;
dp.w = 0x0000;
sp.w = 0x0100;
pc = mem.getWord(0xfffc);
pc = getWord(0xfffc);
p.b = 0x34;
stopped = false;
interrupted = false;
this -> trace = trace;
emu816::trace = trace;
}
// Execute a single instruction or invoke an interrupt
@ -67,7 +85,7 @@ void emu816::step()
SHOWPC();
switch (mem.getByte (join(pbr, pc++))) {
switch (getByte (join(pbr, pc++))) {
case 0x00: op_brk(am_immb()); break;
case 0x01: op_ora(am_dpix()); break;
case 0x02: op_cop(am_immb()); break;
@ -357,7 +375,7 @@ void emu816::show()
Serial.print (':');
Serial.print (toHex(pc, 4));
Serial.print (' ');
Serial.print (toHex(mem.getByte(join(pbr, pc)), 2));
Serial.print (toHex(getByte(join(pbr, pc)), 2));
}
// Display the operand bytes
@ -365,21 +383,21 @@ void emu816::bytes(unsigned int count)
{
if (count > 0) {
Serial.print(' ');
Serial.print(toHex(mem.getByte(bank(pbr) | (pc + 0)), 2));
Serial.print(toHex(getByte(bank(pbr) | (pc + 0)), 2));
}
else
Serial.print(" ");
if (count > 1) {
Serial.print(' ');
Serial.print(toHex(mem.getByte(bank(pbr) | (pc + 1)), 2));
Serial.print(toHex(getByte(bank(pbr) | (pc + 1)), 2));
}
else
Serial.print(" ");
if (count > 2) {
Serial.print(' ');
Serial.print(toHex(mem.getByte(bank(pbr) | (pc + 2)), 2));
Serial.print(toHex(getByte(bank(pbr) | (pc + 2)), 2));
}
else
Serial.print(" ");
@ -461,13 +479,13 @@ void emu816::dump(const char *mnem, Addr ea)
Serial.print(" {");
Serial.print(' ');
Serial.print(toHex(mem.getByte(sp.w + 1), 2));
Serial.print(toHex(getByte(sp.w + 1), 2));
Serial.print(' ');
Serial.print(toHex(mem.getByte(sp.w + 2), 2));
Serial.print(toHex(getByte(sp.w + 2), 2));
Serial.print(' ');
Serial.print(toHex(mem.getByte(sp.w + 3), 2));
Serial.print(toHex(getByte(sp.w + 3), 2));
Serial.print(' ');
Serial.print(toHex(mem.getByte(sp.w + 4), 2));
Serial.print(toHex(getByte(sp.w + 4), 2));
Serial.print(" }");
Serial.print(" DBR=");
@ -480,24 +498,24 @@ void emu816::show()
cout << '{' << toHex(cycles, 4) << "} ";
cout << toHex(pbr, 2);
cout << ':' << toHex(pc, 4);
cout << ' ' << toHex(mem.getByte(join(pbr, pc)), 2);
cout << ' ' << toHex(getByte(join(pbr, pc)), 2);
}
// Display the operand bytes
void emu816::bytes(unsigned int count)
{
if (count > 0)
cout << ' ' << toHex(mem.getByte(bank(pbr) | (pc + 0)), 2);
cout << ' ' << toHex(getByte(bank(pbr) | (pc + 0)), 2);
else
cout << " ";
if (count > 1)
cout << ' ' << toHex(mem.getByte(bank(pbr) | (pc + 1)), 2);
cout << ' ' << toHex(getByte(bank(pbr) | (pc + 1)), 2);
else
cout << " ";
if (count > 2)
cout << ' ' << toHex(mem.getByte(bank(pbr) | (pc + 2)), 2);
cout << ' ' << toHex(getByte(bank(pbr) | (pc + 2)), 2);
else
cout << " ";
@ -545,10 +563,10 @@ void emu816::dump(const char *mnem, Addr ea)
cout << '[' << toHex(hi(sp.w), 2);
cout << toHex(sp.b, 2) << ']';
cout << " {";
cout << ' ' << toHex(mem.getByte(sp.w + 1), 2);
cout << ' ' << toHex(mem.getByte(sp.w + 2), 2);
cout << ' ' << toHex(mem.getByte(sp.w + 3), 2);
cout << ' ' << toHex(mem.getByte(sp.w + 4), 2);
cout << ' ' << toHex(getByte(sp.w + 1), 2);
cout << ' ' << toHex(getByte(sp.w + 2), 2);
cout << ' ' << toHex(getByte(sp.w + 3), 2);
cout << ' ' << toHex(getByte(sp.w + 4), 2);
cout << " }";
cout << " DBR=" << toHex(dbr, 2) << endl;
}

561
emu816.h

File diff suppressed because it is too large Load Diff

View File

@ -86,7 +86,7 @@
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<Optimization>Custom</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
@ -116,6 +116,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<OmitFramePointers>true</OmitFramePointers>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommandArguments>-t examples/simple/simple.s28</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>examples/simple/simple.s28</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerCommandArguments>-t examples/simple/simple.s28</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>examples/simple/simple.s28</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

Binary file not shown.

View File

@ -26,7 +26,7 @@ OBJS = \
simple.obj
all: simple.s28
all: simple.s28 simple.hex
clean:
$(RM) *.obj
@ -39,6 +39,10 @@ clean:
simple.s28: $(OBJS)
$(LK65) -bss $$0000-$$7FFF -code $$F000-$$FFFF -s28 -output $@ $(OBJS)
simple.hex: $(OBJS)
$(LK65) -bss $$0000-$$7FFF -code $$F000-$$FFFF -hex -output $@ $(OBJS)
java -cp $(DEV65_JAR) uk.co.demon.obelisk.util.Hex2C < simple.hex > simple.txt
#===============================================================================
# Dependencies

View File

@ -47,15 +47,16 @@ RESET:
lda #STACK
tcs
ldy #2
ldy #100
repeat
ldx #123
ldx #0
repeat
dex
until eq
dey
until eq
wdm #$ff
wdm #$ff
bra RESET
;===============================================================================
; Dummy Interrupt Handlers

View File

@ -168,18 +168,19 @@ Portable 65xx Assembler [16.06]
00:F006 A9???? : lda #STACK
00:F009 1B : tcs
00:F00A A00200 : ldy #2
00:F00A A06400 : ldy #100
Portable 65xx Assembler [16.06]
repeat
00:F00D A27B00 : ldx #123
00:F00D A20000 : ldx #0
repeat
00:F010 CA : dex
00:F011 D0FD : until eq
00:F013 88 : dey
00:F014 D0F7 : until eq
00:F016 42FF : wdm #$ff
00:F016 42FF : wdm #$ff
00:F018 80E6 : bra RESET
;===============================================================================
; Dummy Interrupt Handlers
@ -190,13 +191,13 @@ Portable 65xx Assembler [16.06]
ABORTN:
NMIN:
BRKN
00:F018 80FE : bra $
00:F01A 80FE : bra $
COP:
ABORT:
NMI:
IRQBRK:
00:F01A 80FE : bra $
00:F01C 80FE : bra $
;===============================================================================
; Vectors
@ -205,20 +206,20 @@ Portable 65xx Assembler [16.06]
.org $ffe0
00:FFE0 00000000 : .space 4 ; Reserved
00:FFE4 18F0 : .word COPN ; $FFE4 - COP(816)
00:FFE6 18F0 : .word BRKN ; $FFE6 - BRK(816)
00:FFE8 18F0 : .word ABORTN ; $FFE8 - ABORT(816)
00:FFEA 18F0 : .word NMIN ; $FFEA - NMI(816)
00:FFE4 1AF0 : .word COPN ; $FFE4 - COP(816)
00:FFE6 1AF0 : .word BRKN ; $FFE6 - BRK(816)
00:FFE8 1AF0 : .word ABORTN ; $FFE8 - ABORT(816)
00:FFEA 1AF0 : .word NMIN ; $FFEA - NMI(816)
00:FFEC 0000 : .space 2 ; Reserved
00:FFEE 18F0 : .word IRQN ; $FFEE - IRQ(816)
00:FFEE 1AF0 : .word IRQN ; $FFEE - IRQ(816)
00:FFF0 00000000 : .space 4
00:FFF4 1AF0 : .word COP ; $FFF4 - COP(C02)
00:FFF4 1CF0 : .word COP ; $FFF4 - COP(C02)
00:FFF6 0000 : .space 2 ; $Reserved
00:FFF8 1AF0 : .word ABORT ; $FFF8 - ABORT(C02)
00:FFFA 1AF0 : .word NMI ; $FFFA - NMI(C02)
00:FFF8 1CF0 : .word ABORT ; $FFF8 - ABORT(C02)
00:FFFA 1CF0 : .word NMI ; $FFFA - NMI(C02)
00:FFFC 00F0 : .word RESET ; $FFFC - RESET(C02)
00:FFFE 1AF0 : .word IRQBRK ; $FFFE - IRQBRK(C02)
00:FFFE 1CF0 : .word IRQBRK ; $FFFE - IRQBRK(C02)
.end
@ -227,29 +228,29 @@ Portable 65xx Assembler [16.06]
Symbol Table
ABORT 0000F01A | __6501__ 00000000
ABORTN 0000F018 | __6502__ 00000000
BRKN 0000F018 | __65832__ 00000000
ABORT 0000F01C | __6501__ 00000000
ABORTN 0000F01A | __6502__ 00000000
BRKN 0000F01A | __65832__ 00000000
B_FLAG 00000010 | __65C02__ 00000000
COP 0000F01A | __65SC02__ 00000000
COPN 0000F018 | C_FLAG 00000001
COP 0000F01C | __65SC02__ 00000000
COPN 0000F01A | C_FLAG 00000001
C_FLAG 00000001 | __65816__ 00000001
D_FLAG 00000008 | Z_FLAG 00000002
IRQBRK 0000F01A | I_FLAG 00000004
IRQN 0000F018 | D_FLAG 00000008
IRQBRK 0000F01C | I_FLAG 00000004
IRQN 0000F01A | D_FLAG 00000008
I_FLAG 00000004 | B_FLAG 00000010
M_FLAG 00000020 | X_FLAG 00000010
NMI 0000F01A | M_FLAG 00000020
NMIN 0000F018 | V_FLAG 00000040
NMI 0000F01C | M_FLAG 00000020
NMIN 0000F01A | V_FLAG 00000040
N_FLAG 00000080 | N_FLAG 00000080
RESET 0000F000 | STACK 00000080'
STACK 00000080' | RESET 0000F000
V_FLAG 00000040 | ABORTN 0000F018
X_FLAG 00000010 | BRKN 0000F018
Z_FLAG 00000002 | COPN 0000F018
__6501__ 00000000 | IRQN 0000F018
__6502__ 00000000 | NMIN 0000F018
__65816__ 00000001 | ABORT 0000F01A
__65832__ 00000000 | COP 0000F01A
__65C02__ 00000000 | IRQBRK 0000F01A
__65SC02__ 00000000 | NMI 0000F01A
V_FLAG 00000040 | ABORTN 0000F01A
X_FLAG 00000010 | BRKN 0000F01A
Z_FLAG 00000002 | COPN 0000F01A
__6501__ 00000000 | IRQN 0000F01A
__6502__ 00000000 | NMIN 0000F01A
__65816__ 00000001 | ABORT 0000F01C
__65832__ 00000000 | COP 0000F01C
__65C02__ 00000000 | IRQBRK 0000F01C
__65SC02__ 00000000 | NMI 0000F01C

View File

@ -5,5 +5,5 @@ Global Symbol Map
Sections:
.page0 : 00000000 - 0000007F in simple.obj
.code : 0000F000 - 0000F01B in simple.obj
.code : 0000F000 - 0000F01D in simple.obj
0000FFE0 - 0000FFFF in simple.obj

View File

@ -1,4 +1,4 @@
S22400F00078D818FBC230A980001BA00200A27B00CAD0FD88D0F742FF80FE80FE0000000070
S22400F00078D818FBC230A980001BA06400A20000CAD0FD88D0F742FF80E680FE80FE000023
S22400F0200000000000000000000000000000000000000000000000000000000000000000CB
S22400F0400000000000000000000000000000000000000000000000000000000000000000AB
S22400F06000000000000000000000000000000000000000000000000000000000000000008B
@ -125,6 +125,6 @@ S22400FF6000000000000000000000000000000000000000000000000000000000000000007C
S22400FF8000000000000000000000000000000000000000000000000000000000000000005C
S22400FFA000000000000000000000000000000000000000000000000000000000000000003C
S22400FFC000000000000000000000000000000000000000000000000000000000000000001C
S22400FFE00000000018F018F018F018F0000018F0000000001AF000001AF01AF000F01AF0BC
S22400FFE0000000001AF01AF01AF01AF000001AF0000000001CF000001CF01CF000F01CF0AA
S505000000807A
S80400F0000B

View File

@ -9,7 +9,7 @@
//
// A Portable C++ WDC 65C816 Emulator
//------------------------------------------------------------------------------
// Copyright (C)2016 Andrew John Jacobs
// Copyright (C),2016 Andrew John Jacobs
// All rights reserved.
//
// This work is made available under the terms of the Creative Commons
@ -21,22 +21,33 @@
#include "mem816.h"
mem816::Addr mem816::memMask;
mem816::Addr mem816::ramSize;
mem816::Byte *mem816::pRAM;
const mem816::Byte *mem816::pROM;
//==============================================================================
// Construct a memory area using dynamic allocation
mem816::mem816(Addr memMask, Addr ramSize, const Byte *pROM)
: memMask(memMask), ramSize(ramSize), pROM(pROM), freeRAM(true)
{
pRAM = new Byte[ramSize];
}
// Construct a memory area using statically allocated arrays
mem816::mem816(Addr memMask, Addr ramSize, Byte *pRAM, const Byte *pROM)
: memMask(memMask), ramSize(ramSize), pRAM(pRAM), pROM(pROM), freeRAM(false)
// Never used.
mem816::mem816()
{ }
// Destory an instance releasing the RAM if allocated.
// Never used.
mem816::~mem816()
{ }
// Sets up the memory areas using a dynamically allocated array
void mem816::setMemory(Addr memMask, Addr ramSize, const Byte *pROM)
{
if (freeRAM) delete pRAM;
setMemory(memMask, ramSize, new Byte[ramSize], pROM);
}
// Sets up the memory area using pre-allocated array
void mem816::setMemory(Addr memMask, Addr ramSize, Byte *pRAM, const Byte *pROM)
{
mem816::memMask = memMask;
mem816::ramSize = ramSize;
mem816::pRAM = pRAM;
mem816::pROM = pROM;
}

View File

@ -9,7 +9,7 @@
//
// A Portable C++ WDC 65C816 Emulator
//------------------------------------------------------------------------------
// Copyright (C)2016 Andrew John Jacobs
// Copyright (C),2016 Andrew John Jacobs
// All rights reserved.
//
// This work is made available under the terms of the Creative Commons
@ -24,15 +24,19 @@
#include "wdc816.h"
// The mem816 class defines a set of standard methods for defining and accessing
// the emulated memory area.
class mem816 :
public wdc816
{
public:
mem816(Addr memMask, Addr ramSize, const Byte *pROM);
mem816(Addr memMask, Addr ramSize, Byte *pRAM, const Byte *pROM);
~mem816();
// Define the memory areas and sizes
static void setMemory (Addr memMask, Addr ramSize, const Byte *pROM);
static void setMemory (Addr memMask, Addr ramSize, Byte *pRAM, const Byte *pROM);
INLINE Byte getByte(Addr ea)
// Fetch a byte from memory
INLINE static Byte getByte(Addr ea)
{
if ((ea &= memMask) < ramSize)
return (pRAM[ea]);
@ -40,35 +44,41 @@ public:
return (pROM[ea - ramSize]);
}
INLINE Word getWord(Addr ea)
// Fetch a word from memory
INLINE static Word getWord(Addr ea)
{
return (join(getByte(ea + 0), getByte(ea + 1)));
return (join(getByte(ea + 0), getByte(ea + 1)));
}
INLINE Addr getAddr(Addr ea)
// Fetch a long address from memory
INLINE static Addr getAddr(Addr ea)
{
return (join(getByte(ea + 2), getWord(ea + 0)));
}
INLINE void setByte(Addr ea, Byte data)
// Write a byte to memory
INLINE static void setByte(Addr ea, Byte data)
{
if ((ea &= memMask) < ramSize)
pRAM[ea] = data;
}
INLINE void setWord(Addr ea, Word data)
// Write a word to memory
INLINE static void setWord(Addr ea, Word data)
{
setByte(ea + 0, lo(data));
setByte(ea + 1, hi(data));
setByte(ea + 0, lo(data));
setByte(ea + 1, hi(data));
}
protected:
mem816();
~mem816();
private:
const Addr memMask;
const Addr ramSize;
static Addr memMask; // The address mask pattern
static Addr ramSize; // The amount of RAM
Byte *pRAM;
const Byte *pROM;
const bool freeRAM;
static Byte *pRAM; // Base of RAM memory array
static const Byte *pROM; // Base of ROM memory array
};
#endif
#endif

View File

@ -40,23 +40,20 @@ using namespace std;
#define RAM_SIZE (512 * 1024)
#define MEM_MASK (512 * 1024L - 1)
mem816 mem(MEM_MASK, RAM_SIZE, NULL);
emu816 emu(mem);
bool trace = false;
//==============================================================================
// Initialise the emulator
void setup()
INLINE void setup()
{
emu.reset(trace);
emu816::setMemory(MEM_MASK, RAM_SIZE, NULL);
}
// Execute instructions
void loop()
INLINE void loop()
{
emu.step();
emu816::step();
}
//==============================================================================
@ -108,7 +105,7 @@ void load(char *filename)
unsigned long addr = toAddr(line, offset);
count -= 4;
while (count-- > 0) {
mem.setByte(addr++, toByte(line, offset));
emu816::setByte(addr++, toByte(line, offset));
}
}
}
@ -123,6 +120,8 @@ int main(int argc, char **argv)
{
int index = 1;
setup();
while (index < argc) {
if (argv[index][0] != '-') break;
@ -155,16 +154,17 @@ int main(int argc, char **argv)
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&start);
setup();
while (!emu.isStopped ())
emu816::reset(trace);
while (!emu816::isStopped ())
loop();
QueryPerformanceCounter(&end);
double secs = (end.QuadPart - start.QuadPart) / (double) freq.QuadPart;
double speed = emu.getCycles() / secs;
double speed = emu816::getCycles() / secs;
cout << endl << "Executed " << emu816::getCycles() << " in " << secs << " Secs";
cout << endl << "Overall CPU Frequency = ";
if (speed < 1000.0)
cout << speed << " Hz";
@ -176,5 +176,6 @@ int main(int argc, char **argv)
}
cout << endl;
system("pause");
return(0);
}

View File

@ -9,7 +9,7 @@
//
// A Portable C++ WDC 65C816 Emulator
//------------------------------------------------------------------------------
// Copyright (C)2016 Andrew John Jacobs
// Copyright (C),2016 Andrew John Jacobs
// All rights reserved.
//
// This work is made available under the terms of the Creative Commons
@ -21,9 +21,11 @@
#include "wdc816.h"
// Never used.
wdc816::wdc816()
{ }
// Never used.
wdc816::~wdc816()
{ }

View File

@ -9,7 +9,7 @@
//
// A Portable C++ WDC 65C816 Emulator
//------------------------------------------------------------------------------
// Copyright (C)2016 Andrew John Jacobs
// Copyright (C),2016 Andrew John Jacobs
// All rights reserved.
//
// This work is made available under the terms of the Creative Commons
@ -22,25 +22,23 @@
#ifndef WDC816_H
#define WDC816_H
//#define CHIPKIT
#ifdef CHIPKIT
# define INLINE inline
#else
# define INLINE inline
#endif
// The wdc816 class defines common types for 8-, 16- and 24-bit data values and
// a set of common functions for manipulating them.
class wdc816
{
public:
// Common types for memory and register sizes
typedef unsigned char Bit;
typedef unsigned char Byte;
typedef unsigned short Word;
typedef unsigned long Addr;
wdc816 ();
~wdc816();
typedef unsigned char Bit;
typedef unsigned char Byte;
typedef unsigned short Word;
typedef unsigned long Addr;
// Convert a value to a hex string.
static char *toHex(unsigned long value, unsigned int digits);
@ -80,5 +78,9 @@ public:
{
return ((value >> 8) | (value << 8));
}
protected:
wdc816();
~wdc816();
};
#endif