Virtual Machine 6502

This is the initial development of VM6502 project. Initially it is a VM
emulating MOS 6502 opcodes, but in the future my intention is to use the
free illegal opcodes to extend its functionality.
This commit is contained in:
makarcz 2016-02-20 18:14:25 -05:00
parent aebd9ed8ac
commit 0dd5a0299f
34 changed files with 8746 additions and 0 deletions

43
.gitignore vendored Normal file
View File

@ -0,0 +1,43 @@
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# =========================
# Operating System Files
# =========================
# OSX
# =========================
.DS_Store
.AppleDouble
.LSOverride
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

62
BCDCodes.dev Normal file
View File

@ -0,0 +1,62 @@
[Project]
FileName=BCDCodes.dev
Name=BCDCodes
Type=1
Ver=2
ObjFiles=
Includes=
Libs=
PrivateResource=
ResourceIncludes=
MakeIncludes=
Compiler=
CppCompiler=
Linker=
IsCpp=0
Icon=
ExeOutput=
ObjectOutput=
LogOutput=
LogOutputEnabled=0
OverrideOutput=0
OverrideOutputName=
HostApplication=
UseCustomMakefile=0
CustomMakefile=
CommandLine=
Folders=
IncludeVersionInfo=0
SupportXPThemes=0
CompilerSet=3
CompilerSettings=0000000100000000000000000
UnitCount=1
[VersionInfo]
Major=1
Minor=0
Release=0
Build=0
LanguageID=1033
CharsetID=1252
CompanyName=
FileVersion=
FileDescription=Developed using the Dev-C++ IDE
InternalName=
LegalCopyright=
LegalTrademarks=
OriginalFilename=
ProductName=
ProductVersion=
AutoIncBuildNr=0
SyncProduct=1
[Unit1]
FileName=bcd.c
CompileCpp=0
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=

245
Display.cpp Normal file
View File

@ -0,0 +1,245 @@
#include "Display.h"
#include <ctype.h>
#include <cstdlib>
#include <iostream>
#include <string.h>
using namespace std;
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
namespace MKBasic {
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
Display::Display()
{
InitScr();
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
Display::~Display()
{
}
/*
*--------------------------------------------------------------------
* Method: InitScr()
* Purpose: Initialize screen.
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
void Display::InitScr()
{
ClrScr();
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void Display::ScrollUp()
{
for (int row=0; row<SCREENDIM_ROW-1; row++) {
for (int col=0; col<SCREENDIM_COL; col++) {
mScreen[col][row] = mScreen[col][row+1];
}
}
for (int col=0; col<SCREENDIM_COL; col++) {
mScreen[col][SCREENDIM_ROW-1] = ' ';
}
}
/*
*--------------------------------------------------------------------
* Method: GotoXY()
* Purpose: Move cursor to new coordinates.
* Arguments: col, row - integer values, new cursor coordinates
* Returns: n/a
*--------------------------------------------------------------------
*/
void Display::GotoXY(unsigned int col, unsigned int row)
{
if (col < SCREENDIM_COL && row < SCREENDIM_ROW) {
mCursorCoord.col = col;
mCursorCoord.row = row;
}
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
bool Display::IsSpecChar(char c)
{
bool ret = false;
char sct[] = {SCREENSPECCHARS_NL,
SCREENSPECCHARS_CR,
SCREENSPECCHARS_TB,
SCREENSPECCHARS_BS,
SCREENSPECCHARS_BE,
0};
for (unsigned int i=0; i<strlen(sct); i++) {
if (c == sct[i]) {
ret = true;
break;
}
}
return ret;
}
/*
*--------------------------------------------------------------------
* Method: PutChar()
* Purpose: Output character to console. If going outside
* lower-right corner, scroll the contents up.
* Arguments: c - character to output.
* Returns: n/a
*--------------------------------------------------------------------
*/
void Display::PutChar(char c)
{
if (isalnum(c) || ispunct(c) || isspace(c) || IsSpecChar(c))
{
if (c == SCREENSPECCHARS_NL) {
//mCursorCoord.col = 0;
mCursorCoord.row++;
if (mCursorCoord.row >= SCREENDIM_ROW) {
ScrollUp();
mCursorCoord.row = SCREENDIM_ROW-1;
}
} else if (c == SCREENSPECCHARS_CR) {
mCursorCoord.col = 0;
} else if (c == SCREENSPECCHARS_TB) {
mCursorCoord.col += TABSIZE;
if (mCursorCoord.col >= SCREENDIM_COL) {
mCursorCoord.col = SCREENDIM_COL-1; // must work on it some more
}
} else if (c == SCREENSPECCHARS_BS) {
if (mCursorCoord.col > 0) mCursorCoord.col--;
} else if (c == SCREENSPECCHARS_BE) {
// no action
}
else {
mScreen[mCursorCoord.col][mCursorCoord.row] = c;
mCursorCoord.col++;
if (mCursorCoord.col >= SCREENDIM_COL) {
mCursorCoord.col = 0;
mCursorCoord.row++;
if (mCursorCoord.row >= SCREENDIM_ROW) {
ScrollUp();
mCursorCoord.row = SCREENDIM_ROW-1;
}
}
}
}
}
/*
*--------------------------------------------------------------------
* Method: ClrScr()
* Purpose: Fill the screen with spaces. Set cursor in left-upper
* corner.
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
void Display::ClrScr()
{
for (int col=0; col<SCREENDIM_COL; col++) {
for (int row=0; row<SCREENDIM_ROW; row++) {
mScreen[col][row] = ' ';
}
}
mCursorCoord.col = mCursorCoord.row = 0;
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
char Display::GetCharAt(unsigned int col, unsigned int row)
{
char c = -1;
if (col < SCREENDIM_COL && row < SCREENDIM_ROW)
c = mScreen[col][row];
return c;
}
/*
*--------------------------------------------------------------------
* Method: ShowScr()
* Purpose: Display contents of the emulated console on... well,
* real console.
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
void Display::ShowScr()
{
for (int row=0; row<SCREENDIM_ROW; row++) {
string line;
line.clear();
for (int col=0; col<SCREENDIM_COL; col++) {
char c = mScreen[col][row];
if (mCursorCoord.col == col && mCursorCoord.row == row) {
c = '_';
}
line = line + c;
//putchar(mScreen[col][row]);
}
cout << line;
}
}
/*
*--------------------------------------------------------------------
* Method: GetCursorCoord()
* Purpose: Get cursor coordinates.
* Arguments: n/a
* Returns: pointer to cursor coordinates
*--------------------------------------------------------------------
*/
CursorCoord *Display::GetCursorCoord()
{
return &mCursorCoord;
}
} // namespace MKBasic

54
Display.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef DISPLAY_H
#define DISPLAY_H
#define TABSIZE 4
namespace MKBasic {
enum eScreenDimensions {
SCREENDIM_COL = 80,
SCREENDIM_ROW = 24
};
enum eScreenSpecChars {
SCREENSPECCHARS_NL = (int)'\n', // new line
SCREENSPECCHARS_CR = (int)'\r', // caret
SCREENSPECCHARS_TB = (int)'\t', // tab
SCREENSPECCHARS_BS = (int)'\b', // backspace
SCREENSPECCHARS_BE = (int)'\a' // bell
};
struct CursorCoord {
int row;
int col;
};
class Display
{
public:
Display();
~Display();
void GotoXY(unsigned int col, unsigned int row);
void PutChar(char c);
void ClrScr();
char GetCharAt(unsigned int col, unsigned int row);
void ShowScr();
CursorCoord *GetCursorCoord();
protected:
private:
char mScreen[SCREENDIM_COL][SCREENDIM_ROW];
CursorCoord mCursorCoord;
void InitScr();
void ScrollUp();
bool IsSpecChar(char c);
};
} // namespace MKBasic
#endif

13
MKBasic.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "MKBasic.h"
namespace MKBasic {
MKBasic::MKBasic()
{
}
MKBasic::~MKBasic()
{
}
} // namespace MKBasic

182
MKBasic.dev Normal file
View File

@ -0,0 +1,182 @@
[Project]
FileName=MKBasic.dev
Name=MKBasic
Type=1
Ver=2
ObjFiles=
Includes=
Libs=
PrivateResource=
ResourceIncludes=
MakeIncludes=
Compiler=
CppCompiler=
Linker=
IsCpp=1
Icon=
ExeOutput=
ObjectOutput=
LogOutput=
LogOutputEnabled=0
OverrideOutput=0
OverrideOutputName=MKBasic.exe
HostApplication=
UseCustomMakefile=0
CustomMakefile=
CommandLine=
Folders=
IncludeVersionInfo=0
SupportXPThemes=0
CompilerSet=3
CompilerSettings=00000001c0111000001000000
UnitCount=13
[VersionInfo]
Major=1
Minor=0
Release=0
Build=0
LanguageID=1033
CharsetID=1252
CompanyName=
FileVersion=1.0.0.0
FileDescription=Developed using the Dev-C++ IDE
InternalName=
LegalCopyright=
LegalTrademarks=
OriginalFilename=
ProductName=
ProductVersion=1.0.0.0
AutoIncBuildNr=0
SyncProduct=1
[Unit1]
FileName=main.cpp
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit2]
FileName=VMachine.h
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit3]
FileName=VMachine.cpp
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit4]
FileName=MKBasic.h
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit5]
FileName=MKBasic.cpp
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit6]
FileName=MKCpu.h
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit7]
FileName=MKCpu.cpp
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit8]
FileName=Memory.h
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit9]
FileName=Memory.cpp
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit10]
FileName=Display.h
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit11]
FileName=Display.cpp
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit12]
FileName=MKGenException.h
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit13]
FileName=MKGenException.cpp
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=

18
MKBasic.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef MKBASIC_H
#define MKBASIC_H
#include "VMachine.h"
namespace MKBasic {
class MKBasic : public VMachine
{
public:
MKBasic();
~MKBasic();
protected:
};
} // namespace MKBasic
#endif

1471
MKCpu.cpp Normal file

File diff suppressed because it is too large Load Diff

424
MKCpu.h Normal file
View File

@ -0,0 +1,424 @@
#ifndef MKCPU_H
#define MKCPU_H
#include "Memory.h"
namespace MKBasic {
struct Regs {
unsigned char Acc; // 8-bit accumulator
unsigned short Acc16; // 16-bit accumulator
unsigned char IndX; // 8-bit index register X
unsigned char IndY; // 8-bit index register Y
unsigned short Ptr16; // general purpose 16-bit register
unsigned short PtrAddr; // cpu code counter - current read/write address
unsigned char PtrStack; // 8-bit stack pointer (0-255).
unsigned char Flags; // CPU flags
bool SoftIrq; // true when interrupted with BRK
bool LastRTS; // true if RTS encountered and stack empty.
};
/*
* Virtual CPU, 6502 addressing modes:
+---------------------+--------------------------+
| mode | assembler format |
+=====================+==========================+
| Immediate | #aa |
| Absolute | aaaa |
| Zero Page | aa | Note:
| Implied | |
| Indirect Absolute | (aaaa) | aa = 2 hex digits
| Absolute Indexed,X | aaaa,X | as $FF
| Absolute Indexed,Y | aaaa,Y |
| Zero Page Indexed,X | aa,X | aaaa = 4 hex
| Zero Page Indexed,Y | aa,Y | digits as
| Indexed Indirect | (aa,X) | $FFFF
| Indirect Indexed | (aa),Y |
| Relative | aaaa | Can also be
| Accumulator | A | assembler labels
+---------------------+--------------------------+
Short notation:
imm = #$00
zp = $00
zpx = $00,X
zpy = $00,Y
izx = ($00,X)
izy = ($00),Y
abs = $0000
abx = $0000,X
aby = $0000,Y
ind = ($0000)
rel = $0000 (PC-relative)
See: 6502AssemblyInOneStep.txt for details.
*/
enum eAddrModes {
ADDRMODE_IMM = 0,
ADDRMODE_ABS,
ADDRMODE_ZP,
ADDRMODE_IMP,
ADDRMODE_IND,
ADDRMODE_ABX,
ADDRMODE_ABY,
ADDRMODE_ZPX,
ADDRMODE_ZPY,
ADDRMODE_IZX,
ADDRMODE_IZY,
ADDRMODE_REL,
ADDRMODE_ACC
};
// assumed little-endian order of bytes (start with least significant)
// MEM - memory location from where the value is read/written,
// & - reference operator (e.g.: &addr means: value under addr memory location)
// PC - program counter (PC+1 means - next memory location after opcode)
enum eOpCodes {
OPCODE_BRK = 0x00, // software interrupt, no arguments ($00 : BRK)
/* full compatibility with 65C02 (illegal opcodes not supported, will be used for extended functions */
OPCODE_ORA_IZX = 0x01, // bitwise OR with Accumulator, Indexed Indirect ($01 arg : ORA (arg,X) ;arg=0..$FF), MEM=&(arg+X)
OPCODE_ILL_02 = 0x02, // illegal opcode
OPCODE_ILL_03 = 0x03, // illegal opcode
OPCODE_ILL_04 = 0x04, // illegal opcode
OPCODE_ORA_ZP = 0x05, // bitwise OR with Accumulator, Zero Page ($05 arg : ORA arg ;arg=0..$FF), MEM=arg
OPCODE_ASL_ZP = 0x06, // Arithmetic Shift Left, Zero Page ($06 arg : ASL arg ;arg=0..$FF), MEM=arg
OPCODE_ILL_07 = 0x07, // illegal opcode
OPCODE_PHP = 0x08, // PusH Processor status on Stack, Implied ($08 : PHP)
OPCODE_ORA_IMM = 0x09, // bitwise OR with Accumulator, Immediate ($09 arg : ORA #arg ;arg=0..$FF), MEM=PC+1
OPCODE_ASL = 0x0A, // Arithmetic Shift Left, Accumulator ($0A : ASL)
OPCODE_ILL_0B = 0x0B, // illegal opcode
OPCODE_ILL_0C = 0x0C, // illegal opcode
OPCODE_ORA_ABS = 0x0D, // bitwise OR with Accumulator, Absolute ($0D addrlo addrhi : ORA addr ;addr=0..$FFFF), MEM=addr
OPCODE_ASL_ABS = 0x0E, // Arithmetic Shift Left, Absolute ($0E addrlo addrhi : ASL addr ;addr=0..$FFFF), MEM=addr
OPCODE_ILL_0F = 0x0F, // illegal opcode
OPCODE_BPL_REL = 0x10, // Branch on PLus, Relative ($10 signoffs : BPL signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)])
OPCODE_ORA_IZY = 0x11, // bitwise OR with Accumulator, Indirect Indexed ($11 arg : ORA (arg),Y ;arg=0..$FF), MEM=&arg+Y
OPCODE_ILL_12 = 0x12, // illegal opcode
OPCODE_ILL_13 = 0x13, // illegal opcode
OPCODE_ILL_14 = 0x14, // illegal opcode
OPCODE_ORA_ZPX = 0x15, // bitwise OR with Accumulator, Zero Page Indexed, X ($15 arg : ORA arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_ASL_ZPX = 0x16, // Arithmetic Shift Left, Zero Page Indexed, X ($16 arg : ASL arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_ILL_17 = 0x17, // illegal opcode
OPCODE_CLC = 0x18, // CLear Carry, Implied ($18 : CLC)
OPCODE_ORA_ABY = 0x19, // bitwise OR with Accumulator, Absolute Indexed, Y ($19 addrlo addrhi : ORA addr,Y ;addr=0..$FFFF), MEM=addr+Y
OPCODE_ILL_1A = 0x1A, // illegal opcode
OPCODE_ILL_1B = 0x1B, // illegal opcode
OPCODE_ILL_1C = 0x1C, // illegal opcode
OPCODE_ORA_ABX = 0x1D, // bitwise OR with Accumulator, Absolute Indexed, X ($1D addrlo addrhi : ORA addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_ASL_ABX = 0x1E, // Arithmetic Shift Left, Absolute Indexed, X ($1E addrlo addrhi : ASL addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_ILL_1F = 0x1F, // illegal opcode
OPCODE_JSR_ABS = 0x20, // Jump to SubRoutine, Absolute ($20 addrlo addrhi : JSR addr ;addr=0..$FFFF), MEM=addr
OPCODE_AND_IZX = 0x21, // bitwise AND with accumulator, Indexed Indirect ($21 arg : AND (arg,X) ;arg=0..$FF), MEM=&(arg+X)
OPCODE_ILL_22 = 0x22, // illegal opcode
OPCODE_ILL_23 = 0x23, // illegal opcode
OPCODE_BIT_ZP = 0x24, // test BITs, Zero Page ($24 arg : BIT arg ;arg=0..$FF), MEM=arg
OPCODE_AND_ZP = 0x25, // bitwise AND with accumulator, Zero Page ($25 arg : AND arg ;arg=0..$FF), MEM=arg
OPCODE_ROL_ZP = 0x26, // ROtate Left, Zero Page ($26 arg : ROL arg ;arg=0..$FF), MEM=arg
OPCODE_ILL_27 = 0x27, // illegal opcode
OPCODE_PLP = 0x28, // PuLl Processor status, Implied ($28 : PLP)
OPCODE_AND_IMM = 0x29, // bitwise AND with accumulator, Immediate ($29 arg : AND #arg ;arg=0..$FF), MEM=PC+1
OPCODE_ROL = 0x2A, // ROtate Left, Accumulator ($2A : ROL)
OPCODE_ILL_2B = 0x2B, // illegal opcode
OPCODE_BIT_ABS = 0x2C, // test BITs, Absolute ($2C addrlo addrhi : BIT addr ;addr=0..$FFFF), MEM=addr
OPCODE_AND_ABS = 0x2D, // bitwise AND with accumulator, Absolute ($2D addrlo addrhi : AND addr ;addr=0..$FFFF), MEM=addr
OPCODE_ROL_ABS = 0x2E, // ROtate Left, Absolute ($2E addrlo addrhi : ROL addr ;addr=0..$FFFF), MEM=addr
OPCODE_ILL_2F = 0x2F, // illegal opcode
OPCODE_BMI_REL = 0x30, // Branch on MInus, Relative ($30 signoffs : BMI signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)])
OPCODE_AND_IZY = 0x31, // bitwise AND with accumulator, Indirect Indexed ($31 arg : AND (arg),Y ;arg=0..$FF), MEM=&arg+Y
OPCODE_ILL_32 = 0x32, // illegal opcode
OPCODE_ILL_33 = 0x33, // illegal opcode
OPCODE_ILL_34 = 0x34, // illegal opcode
OPCODE_AND_ZPX = 0x35, // bitwise AND with accumulator, Zero Page Indexed, X ($35 arg : AND arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_ROL_ZPX = 0x36, // ROtate Left, Zero Page Indexed, X ($36 arg : ROL arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_ILL_37 = 0x37, // illegal opcode
OPCODE_SEC = 0x38, // SEt Carry, Implied ($38 : SEC)
OPCODE_AND_ABY = 0x39, // bitwise AND with accumulator, Absolute Indexed, Y ($39 addrlo addrhi : AND addr,Y ;addr=0..$FFFF), MEM=addr+Y
OPCODE_ILL_3A = 0x3A, // illegal opcode
OPCODE_ILL_3B = 0x3B, // illegal opcode
OPCODE_ILL_3C = 0x3C, // illegal opcode
OPCODE_AND_ABX = 0x3D, // bitwise AND with accumulator, Absolute Indexed, X ($3D addrlo addrhi : AND addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_ROL_ABX = 0x3E, // ROtate Left, Absolute Indexed, X ($3E addrlo addrhi : ROL addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_ILL_3F = 0x3F, // illegal opcode
OPCODE_RTI = 0x40, // ReTurn from Interrupt, Implied ($40 : RTI)
OPCODE_EOR_IZX = 0x41, // bitwise Exclusive OR, Indexed Indirect ($41 arg : EOR (arg,X) ;arg=0..$FF), MEM=&(arg+X)
OPCODE_ILL_42 = 0x42, // illegal opcode
OPCODE_ILL_43 = 0x43, // illegal opcode
OPCODE_ILL_44 = 0x44, // illegal opcode
OPCODE_EOR_ZP = 0x45, // bitwise Exclusive OR, Zero Page ($45 arg : EOR arg ;arg=0..$FF), MEM=arg
OPCODE_LSR_ZP = 0x46, // Logical Shift Right, Zero Page ($46 arg : LSR arg ;arg=0..$FF), MEM=arg
OPCODE_ILL_47 = 0x47, // illegal opcode
OPCODE_PHA = 0x48, // PusH Accumulator, Implied ($48 : PHA)
OPCODE_EOR_IMM = 0x49, // bitwise Exclusive OR, Immediate ($49 arg : EOR #arg ;arg=0..$FF), MEM=PC+1
OPCODE_LSR = 0x4A, // Logical Shift Right, Accumulator ($4A : LSR)
OPCODE_ILL_4B = 0x4B, // illegal opcode
OPCODE_JMP_ABS = 0x4C, // JuMP, Absolute ($4C addrlo addrhi : JMP addr ;addr=0..$FFFF), MEM=addr
OPCODE_EOR_ABS = 0x4D, // bitwise Exclusive OR, Absolute ($4D addrlo addrhi : EOR addr ;addr=0..$FFFF), MEM=addr
OPCODE_LSR_ABS = 0x4E, // Logical Shift Right, Absolute ($4E addrlo addrhi : LSR addr ;addr=0..$FFFF), MEM=addr
OPCODE_ILL_4F = 0x4F, // illegal opcode
OPCODE_BVC_REL = 0x50, // Branch on oVerflow Clear, Relative ($50 signoffs : BVC signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)])
OPCODE_EOR_IZY = 0x51, // bitwise Exclusive OR, Indirect Indexed ($51 arg : EOR (arg),Y ;arg=0..$FF), MEM=&arg+Y
OPCODE_ILL_52 = 0x52, // illegal opcode
OPCODE_ILL_53 = 0x53, // illegal opcode
OPCODE_ILL_54 = 0x54, // illegal opcode
OPCODE_EOR_ZPX = 0x55, // bitwise Exclusive OR, Zero Page Indexed, X ($55 arg : EOR arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_LSR_ZPX = 0x56, // Logical Shift Right, Zero Page Indexed, X ($56 arg : LSR arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_ILL_57 = 0x57, // illegal opcode
OPCODE_CLI = 0x58, // CLear Interrupt, Implied ($58 : CLI)
OPCODE_EOR_ABY = 0x59, // bitwise Exclusive OR, Absolute Indexed, Y ($59 addrlo addrhi : EOR addr,Y ;addr=0..$FFFF), MEM=addr+Y
OPCODE_ILL_5A = 0x5A, // illegal opcode
OPCODE_ILL_5B = 0x5B, // illegal opcode
OPCODE_ILL_5C = 0x5C, // illegal opcode
OPCODE_EOR_ABX = 0x5D, // bitwise Exclusive OR, Absolute Indexed, X ($5D addrlo addrhi : EOR addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_LSR_ABX = 0x5E, // Logical Shift Right, Absolute Indexed, X ($5E addrlo addrhi : LSR addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_ILL_5F = 0x5F, // illegal opcode
OPCODE_RTS = 0x60, // ReTurn from Subroutine, Implied ($60 : RTS)
OPCODE_ADC_IZX = 0x61, // ADd with Carry, Indexed Indirect ($61 arg : ADC (arg,X) ;arg=0..$FF), MEM=&(arg+X)
OPCODE_ILL_62 = 0x62, // illegal opcode
OPCODE_ILL_63 = 0x63, // illegal opcode
OPCODE_ILL_64 = 0x64, // illegal opcode
OPCODE_ADC_ZP = 0x65, // ADd with Carry, Zero Page ($65 arg : ADC arg ;arg=0..$FF), MEM=arg
OPCODE_ROR_ZP = 0x66, // ROtate Right, Zero Page ($66 arg : ROR arg ;arg=0..$FF), MEM=arg
OPCODE_ILL_67 = 0x67, // illegal opcode
OPCODE_PLA = 0x68, // PuLl Accumulator, Implied ($68 : PLA)
OPCODE_ADC_IMM = 0x69, // ADd with Carry, Immediate ($69 arg : ADC #arg ;arg=0..$FF), MEM=PC+1
OPCODE_ROR = 0x6A, // ROtate Right, Accumulator ($6A : ROR)
OPCODE_ILL_6B = 0x6B, // illegal opcode
OPCODE_JMP_IND = 0x6C, // JuMP, Indirect Absolute ($6C addrlo addrhi : JMP (addr) ;addr=0..FFFF), MEM=&addr
OPCODE_ADC_ABS = 0x6D, // ADd with Carry, Absolute ($6D addrlo addrhi : ADC addr ;addr=0..$FFFF), MEM=addr
OPCODE_ROR_ABS = 0x6E, // ROtate Right, Absolute ($6E addrlo addrhi : ROR addr ;addr=0..$FFFF), MEM=addr
OPCODE_ILL_6F = 0x6F, // illegal opcode
OPCODE_BVS_REL = 0x70, // Branch on oVerflow Set, Relative ($70 signoffs : BVS signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)])
OPCODE_ADC_IZY = 0x71, // ADd with Carry, Indirect Indexed ($71 arg : ADC (arg),Y ;arg=0..$FF), MEM=&arg+Y
OPCODE_ILL_72 = 0x72, // illegal opcode
OPCODE_ILL_73 = 0x73, // illegal opcode
OPCODE_ILL_74 = 0x74, // illegal opcode
OPCODE_ADC_ZPX = 0x75, // ADd with Carry, Zero Page Indexed, X ($75 arg : ADC arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_ROR_ZPX = 0x76, // ROtate Right, Zero Page Indexed, X ($76 arg : ROR arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_ILL_77 = 0x77, // illegal opcode
OPCODE_SEI = 0x78, // SEt Interrupt, Implied ($78 : SEI)
OPCODE_ADC_ABY = 0x79, // ADd with Carry, Absolute Indexed, Y ($79 addrlo addrhi : ADC addr,Y ;addr=0..$FFFF), MEM=addr+Y
OPCODE_ILL_7A = 0x7A, // illegal opcode
OPCODE_ILL_7B = 0x7B, // illegal opcode
OPCODE_ILL_7C = 0x7C, // illegal opcode
OPCODE_ADC_ABX = 0x7D, // ADd with Carry, Absolute Indexed, X ($7D addrlo addrhi : ADC addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_ROR_ABX = 0x7E, // ROtate Right, Absolute Indexed, X ($7E addrlo addrhi : ROR addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_ILL_7F = 0x7F, // illegal opcode
OPCODE_ILL_80 = 0x80, // illegal opcode
OPCODE_STA_IZX = 0x81, // STore Accumulator, Indexed Indirect ($81 arg : STA (arg,X) ;arg=0..$FF), MEM=&(arg+X)
OPCODE_ILL_82 = 0x82, // illegal opcode
OPCODE_ILL_83 = 0x83, // illegal opcode
OPCODE_STY_ZP = 0x84, // STore Y register, Zero Page ($84 arg : STY arg ;arg=0..$FF), MEM=arg
OPCODE_STA_ZP = 0x85, // STore Accumulator, Zero Page ($85 arg : STA arg ;arg=0..$FF), MEM=arg
OPCODE_STX_ZP = 0x86, // STore X register, Zero Page ($86 arg : STX arg ;arg=0..$FF), MEM=arg
OPCODE_ILL_87 = 0x87, // illegal opcode
OPCODE_DEY = 0x88, // DEcrement Y, Implied ($88 : DEY)
OPCODE_ILL_89 = 0x89, // illegal opcode
OPCODE_TXA = 0x8A, // Transfer X to A, Implied ($8A : TXA)
OPCODE_ILL_8B = 0x8B, // illegal opcode
OPCODE_STY_ABS = 0x8C, // STore Y register, Absolute ($8C addrlo addrhi : STY addr ;addr=0..$FFFF), MEM=addr
OPCODE_STA_ABS = 0x8D, // STore Accumulator, Absolute ($8D addrlo addrhi : STA addr ;addr=0..$FFFF), MEM=addr
OPCODE_STX_ABS = 0x8E, // STore X register, Absolute ($8E addrlo addrhi : STX addr ;addr=0..$FFFF), MEM=addr
OPCODE_ILL_8F = 0x8F, // illegal opcode
OPCODE_BCC_REL = 0x90, // Branch on Carry Clear, Relative ($90 signoffs : BCC signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)])
OPCODE_STA_IZY = 0x91, // STore Accumulator, Indirect Indexed ($91 arg : STA (arg),Y ;arg=0..$FF), MEM=&arg+Y
OPCODE_ILL_92 = 0x92, // illegal opcode
OPCODE_ILL_93 = 0x93, // illegal opcode
OPCODE_STY_ZPX = 0x94, // STore Y register, Zero Page Indexed, X ($94 arg : STY arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_STA_ZPX = 0x95, // STore Accumulator, Zero Page Indexed, X ($95 arg : STA arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_STX_ZPY = 0x96, // STore X register, Zero Page Indexed, Y ($96 arg : STX arg,Y ;arg=0..$FF), MEM=arg+Y
OPCODE_ILL_97 = 0x97, // illegal opcode
OPCODE_TYA = 0x98, // Transfer Y to A, Implied ($98 : TYA)
OPCODE_STA_ABY = 0x99, // STore Accumulator, Absolute Indexed, Y ($99 addrlo addrhi : STA addr,Y ;addr=0..$FFFF), MEM=addr+Y
OPCODE_TXS = 0x9A, // Transfer X to Stack ptr, Implied ($9A : TXS)
OPCODE_ILL_9B = 0x9B, // illegal opcode
OPCODE_ILL_9C = 0x9C, // illegal opcode
OPCODE_STA_ABX = 0x9D, // STore Accumulator, Absolute Indexed, X ($9D addrlo addrhi : STA addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_ILL_9E = 0x9E, // illegal opcode
OPCODE_ILL_9F = 0x9F, // illegal opcode
OPCODE_LDY_IMM = 0xA0, // LoaD Y register, Immediate ($A0 arg : LDY #arg ;arg=0..$FF), MEM=PC+1
OPCODE_LDA_IZX = 0xA1, // LoaD Accumulator, Indexed Indirect ($A1 arg : LDA (arg,X) ;arg=0..$FF), MEM=&(arg+X)
OPCODE_LDX_IMM = 0xA2, // LoaD X register, Immediate ($A2 arg : LDX #arg ;arg=0..$FF), MEM=PC+1
OPCODE_ILL_A3 = 0xA3, // illegal opcode
OPCODE_LDY_ZP = 0xA4, // LoaD Y register, Zero Page ($A4 arg : LDY arg ;arg=0..$FF), MEM=arg
OPCODE_LDA_ZP = 0xA5, // LoaD Accumulator, Zero Page ($A5 arg : LDA arg ;arg=0..$FF), MEM=arg
OPCODE_LDX_ZP = 0xA6, // LoaD X register, Zero Page ($A6 arg : LDX arg ;arg=0..$FF), MEM=arg
OPCODE_ILL_A7 = 0xA7, // illegal opcode
OPCODE_TAY = 0xA8, // Transfer A to Y, Implied ($A8 : TAY)
OPCODE_LDA_IMM = 0xA9, // LoaD Accumulator, Immediate ($A9 arg : LDA #arg ;arg=0..$FF), MEM=PC+1
OPCODE_TAX = 0xAA, // Transfer A to X, Implied ($AA : TAX)
OPCODE_ILL_AB = 0xAB, // illegal opcode
OPCODE_LDY_ABS = 0xAC, // LoaD Y register, Absolute ($AC addrlo addrhi : LDY addr ;addr=0..$FFFF), MEM=addr
OPCODE_LDA_ABS = 0xAD, // LoaD Accumulator, Absolute ($AD addrlo addrhi : LDA addr ;addr=0..$FFFF), MEM=addr
OPCODE_LDX_ABS = 0xAE, // LoaD X register, Absolute ($AE addrlo addrhi : LDX addr ;addr=0..$FFFF), MEM=addr
OPCODE_ILL_AF = 0xAF, // illegal opcode
OPCODE_BCS_REL = 0xB0, // Branch on Carry Set, Relative ($B0 signoffs : BCS signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)])
OPCODE_LDA_IZY = 0xB1, // LoaD Accumulator, Indirect Indexed ($B1 arg : LDA (arg),Y ;arg=0..$FF), MEM=&arg+Y
OPCODE_ILL_B2 = 0xB2, // illegal opcode
OPCODE_ILL_B3 = 0xB3, // illegal opcode
OPCODE_LDY_ZPX = 0xB4, // LoaD Y register, Zero Page Indexed, X ($B4 arg : LDY arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_LDA_ZPX = 0xB5, // LoaD Accumulator, Zero Page Indexed, X ($B5 arg : LDA arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_LDX_ZPY = 0xB6, // LoaD X register, Zero Page Indexed, Y ($B6 arg : LDX arg,Y ;arg=0..$FF), MEM=arg+Y
OPCODE_ILL_B7 = 0xB7, // illegal opcode
OPCODE_CLV = 0xB8, // CLear oVerflow, Implied ($B8 : CLV)
OPCODE_LDA_ABY = 0xB9, // LoaD Accumulator, Absolute Indexed, Y ($B9 addrlo addrhi : LDA addr,Y ;addr=0..$FFFF), MEM=addr+Y
OPCODE_TSX = 0xBA, // Transfer Stack ptr to X, Implied ($BA : TSX)
OPCODE_ILL_BB = 0xBB, // illegal opcode
OPCODE_LDY_ABX = 0xBC, // LoaD Y register, Absolute Indexed, X ($BC addrlo addrhi : LDY addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_LDA_ABX = 0xBD, // LoaD Accumulator, Absolute Indexed, X ($BD addrlo addrhi : LDA addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_LDX_ABY = 0xBE, // LoaD X register, Absolute Indexed, Y ($BE addrlo addrhi : LDX addr,Y ;addr=0..$FFFF), MEM=addr+Y
OPCODE_ILL_BF = 0xBF, // illegal opcode
OPCODE_CPY_IMM = 0xC0, // ComPare Y register, Immediate ($C0 arg : CPY #arg ;arg=0..$FF), MEM=PC+1
OPCODE_CMP_IZX = 0xC1, // CoMPare accumulator, Indexed Indirect ($A1 arg : LDA (arg,X) ;arg=0..$FF), MEM=&(arg+X)
OPCODE_ILL_C2 = 0xC2, // illegal opcode
OPCODE_ILL_C3 = 0xC3, // illegal opcode
OPCODE_CPY_ZP = 0xC4, // ComPare Y register, Zero Page ($C4 arg : CPY arg ;arg=0..$FF), MEM=arg
OPCODE_CMP_ZP = 0xC5, // CoMPare accumulator, Zero Page ($C5 arg : CMP arg ;arg=0..$FF), MEM=arg
OPCODE_DEC_ZP = 0xC6, // DECrement memory, Zero Page ($C6 arg : DEC arg ;arg=0..$FF), MEM=arg
OPCODE_ILL_C7 = 0xC7, // illegal opcode
OPCODE_INY = 0xC8, // INcrement Y, Implied ($C8 : INY)OPCODE_INY = 0xC8, // INcrement Y, Implied ($C8 : INY)
OPCODE_CMP_IMM = 0xC9, // CoMPare accumulator, Immediate ($C9 arg : CMP #arg ;arg=0..$FF), MEM=PC+1
OPCODE_DEX = 0xCA, // DEcrement X, Implied ($CA : DEX)
OPCODE_ILL_CB = 0xCB, // illegal opcode
OPCODE_CPY_ABS = 0xCC, // ComPare Y register, Absolute ($CC addrlo addrhi : CPY addr ;addr=0..$FFFF), MEM=addr
OPCODE_CMP_ABS = 0xCD, // CoMPare accumulator, Absolute ($CD addrlo addrhi : CMP addr ;addr=0..$FFFF), MEM=addr
OPCODE_DEC_ABS = 0xCE, // DECrement memory, Absolute ($CE addrlo addrhi : CMP addr ;addr=0..$FFFF), MEM=addr
OPCODE_ILL_CF = 0xCF, // illegal opcode
OPCODE_BNE_REL = 0xD0, // Branch on Not Equal, Relative ($D0 signoffs : BNE signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)])
OPCODE_CMP_IZY = 0xD1, // CoMPare accumulator, Indirect Indexed ($D1 arg : CMP (arg),Y ;arg=0..$FF), MEM=&arg+Y
OPCODE_ILL_D2 = 0xD2, // illegal opcode
OPCODE_ILL_D3 = 0xD3, // illegal opcode
OPCODE_ILL_D4 = 0xD4, // illegal opcode
OPCODE_CMP_ZPX = 0xD5, // CoMPare accumulator, Zero Page Indexed, X ($D5 arg : CMP arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_DEC_ZPX = 0xD6, // DECrement memory, Zero Page Indexed, X ($D6 arg : DEC arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_ILL_D7 = 0xD7, // illegal opcode
OPCODE_CLD = 0xD8, // CLear Decimal, Implied ($D8 : CLD)
OPCODE_CMP_ABY = 0xD9, // CoMPare accumulator, Absolute Indexed, Y ($D9 addrlo addrhi : CMP addr,Y ;addr=0..$FFFF), MEM=addr+Y
OPCODE_ILL_DA = 0xDA, // illegal opcode
OPCODE_ILL_DB = 0xDB, // illegal opcode
OPCODE_ILL_DC = 0xDC, // illegal opcode
OPCODE_CMP_ABX = 0xDD, // CoMPare accumulator, Absolute Indexed, X ($DD addrlo addrhi : CMP addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_DEC_ABX = 0xDE, // DECrement memory, Absolute Indexed, X ($DE addrlo addrhi : DEC addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_ILL_DF = 0xDF, // illegal opcode
OPCODE_CPX_IMM = 0xE0, // ComPare X register, Immediate ($E0 arg : CPX #arg ;arg=0..$FF), MEM=PC+1
OPCODE_SBC_IZX = 0xE1, // SuBtract with Carry, Indexed Indirect ($E1 arg : SBC (arg,X) ;arg=0..$FF), MEM=&(arg+X)
OPCODE_ILL_E2 = 0xE2, // illegal opcode
OPCODE_ILL_E3 = 0xE3, // illegal opcode
OPCODE_CPX_ZP = 0xE4, // ComPare X register, Zero Page ($E4 arg : CPX arg ;arg=0..$FF), MEM=arg
OPCODE_SBC_ZP = 0xE5, // SuBtract with Carry, Zero Page ($E5 arg : SBC arg ;arg=0..$FF), MEM=arg
OPCODE_INC_ZP = 0xE6, // INCrement memory, Zero Page ($E6 arg : INC arg ;arg=0..$FF), MEM=arg
OPCODE_ILL_E7 = 0xE7, // illegal opcode
OPCODE_INX = 0xE8, // INcrement X, Implied ($E8 : INX)
OPCODE_SBC_IMM = 0xE9, // SuBtract with Carry, Immediate ($E9 arg : SBC #arg ;arg=0..$FF), MEM=PC+1
OPCODE_NOP = 0xEA, // NO oPeration, Implied ($EA : NOP)
OPCODE_ILL_EB = 0xEB, // illegal opcode
OPCODE_CPX_ABS = 0xEC, // ComPare X register, Absolute ($EC addrlo addrhi : CPX addr ;addr=0..$FFFF), MEM=addr
OPCODE_SBC_ABS = 0xED, // SuBtract with Carry, Absolute ($ED addrlo addrhi : SBC addr ;addr=0..$FFFF), MEM=addr
OPCODE_INC_ABS = 0xEE, // INCrement memory, Absolute ($EE addrlo addrhi : INC addr ;addr=0..$FFFF), MEM=addr
OPCODE_ILL_EF = 0xEF, // illegal opcode
OPCODE_BEQ_REL = 0xF0, // Branch on EQual, Relative ($F0 signoffs : BEQ signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)])
OPCODE_SBC_IZY = 0xF1, // SuBtract with Carry, Indirect Indexed ($F1 arg : SBC (arg),Y ;arg=0..$FF), MEM=&arg+Y
OPCODE_ILL_F2 = 0xF2, // illegal opcode
OPCODE_ILL_F3 = 0xF3, // illegal opcode
OPCODE_ILL_F4 = 0xF4, // illegal opcode
OPCODE_SBC_ZPX = 0xF5, // SuBtract with Carry, Zero Page Indexed, X ($F5 arg : SBC arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_INC_ZPX = 0xF6, // INCrement memory, Zero Page Indexed, X ($F6 arg : INC arg,X ;arg=0..$FF), MEM=arg+X
OPCODE_ILL_F7 = 0xF7, // illegal opcode
OPCODE_SED = 0xF8, // SEt Decimal, Implied ($F8 : SED)
OPCODE_SBC_ABY = 0xF9, // SuBtract with Carry, Absolute Indexed, Y ($F9 addrlo addrhi : SBC addr,Y ;addr=0..$FFFF), MEM=addr+Y
OPCODE_ILL_FA = 0xFA, // illegal opcode
OPCODE_ILL_FB = 0xFB, // illegal opcode
OPCODE_ILL_FC = 0xFC, // illegal opcode
OPCODE_SBC_ABX = 0xFD, // SuBtract with Carry, Absolute Indexed, X ($FD addrlo addrhi : SBC addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_INC_ABX = 0xFE, // INCrement memory, Absolute Indexed, X ($FE addrlo addrhi : INC addr,X ;addr=0..$FFFF), MEM=addr+X
OPCODE_ILL_FF = 0xFF, // illegal opcode
};
/*
*------------------------------------------------------------------------------
bit -> 7 0
+---+---+---+---+---+---+---+---+
| N | V | | B | D | I | Z | C | <-- flag, 0/1 = reset/set
+---+---+---+---+---+---+---+---+
N = NEGATIVE. Set if bit 7 of the accumulator is set.
V = OVERFLOW. Set if the addition of two like-signed numbers or the
subtraction of two unlike-signed numbers produces a result
greater than +127 or less than -128.
B = BRK COMMAND. Set if an interrupt caused by a BRK, reset if
caused by an external interrupt.
D = DECIMAL MODE. Set if decimal mode active.
I = IRQ DISABLE. Set if maskable interrupts are disabled.
Z = ZERO. Set if the result of the last operation (load/inc/dec/
add/sub) was zero.
C = CARRY. Set if the add produced a carry, or if the subtraction
produced a borrow. Also holds bits after a logical shift.
*------------------------------------------------------------------------------
*/
enum eCpuFlagMasks {
FLAGS_CARRY = 0x01, // 0: C
FLAGS_ZERO = 0x02, // 1: Z
FLAGS_IRQ = 0x04, // 2: I
FLAGS_DEC = 0x08, // 3: D
FLAGS_BRK = 0x10, // 4: B (Clear if interrupt vectoring, set if BRK or PHP)
FLAGS_UNUSED = 0x20, // 5: Unused flag (always set).
FLAGS_OVERFLOW = 0x40, // 6: V
FLAGS_SIGN = 0x80 // 7: N
};
enum eLogicOps {
LOGOP_OR,
LOGOP_AND,
LOGOP_EOR
};
class MKCpu
{
public:
MKCpu();
MKCpu(Memory *pmem);
~MKCpu();
Regs *ExecOpcode(unsigned short memaddr);
Regs *GetRegs();
protected:
private:
struct Regs mReg; // CPU registers
Memory *mpMem; // pointer to memory object
bool mLocalMem; // true - memory locally allocated
void InitCpu();
void SetFlags(unsigned char reg); // set CPU flags ZERO and SIGN based on Acc, X or Y
unsigned char ShiftLeft(unsigned char arg8); // Arithmetic Shift Left, set Carry flag
unsigned char ShiftRight(unsigned char arg8); // Logical Shift Right, update flags NZC.
unsigned char RotateLeft(unsigned char arg8); // Rotate left, Carry to bit 0, bit 7 to Carry, update flags N and Z.
unsigned char RotateRight(unsigned char arg8); // Rotate left, Carry to bit 7, bit 0 to Carry, update flags N and Z.
unsigned short GetArg16(unsigned char offs); // Get 2-byte argument, add offset, increase PC.
void LogicOpAcc(unsigned short addr, int logop); // Perform logical bitwise operation between memory location and Acc.
// Result in Acc. Set flags.
unsigned short ComputeRelJump(unsigned char offs); // Compute new PC based on relative offset.
unsigned char Conv2Bcd(unsigned short v); // Convert number to BCD representation.
unsigned short Bcd2Num(unsigned char v); // Convert BCD code to number.
bool CheckFlag(unsigned char flag); // Return true if given CPU status flag is set, false otherwise.
void SetFlag(bool set, unsigned char flag); // Set or unset processor status flag.
unsigned char AddWithCarry(unsigned char mem8); // Add With Carry, update flags and Acc.
unsigned char SubWithCarry(unsigned char mem8); // Subtract With Carry, update flags and Acc.
unsigned short GetAddrWithMode(int mode); // Get address of the byte argument with specified addr. mode
};
} // namespace MKBasic
#endif

20
MKGenException.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "MKGenException.h"
namespace MKBasic {
MKGenException::MKGenException()
{
msCause = "Ouch!";
}
MKGenException::MKGenException(string cause)
{
msCause = cause;
}
string MKGenException::GetCause()
{
return msCause;
}
} // namespace MKBasic

23
MKGenException.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef MKGENEXCEPTION_H
#define MKGENEXCEPTION_H
#include <string>
#include <exception>
using namespace std;
namespace MKBasic {
class MKGenException : public exception {
public:
MKGenException();
MKGenException(string cause);
string GetCause();
private:
string msCause;
};
} // namespace MKBasic
#endif

310
Memory.cpp Normal file
View File

@ -0,0 +1,310 @@
#include "Memory.h"
#include <stdio.h>
#include <conio.h>
//#define DBG 1
#if defined (DBG)
#include <iostream>
using namespace std;
#endif
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
namespace MKBasic {
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
Memory::Memory()
{
Initialize();
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
Memory::~Memory()
{
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void Memory::Initialize()
{
unsigned short addr = 0;
for (int i=0; i < 0xFFFF; i++) {
m8bitMem[addr++] = 0;
}
mCharIOAddr = CHARIO_ADDR;
mCharIOActive = false;
mIOEcho = false;
mInBufDataBegin = mInBufDataEnd = 0;
mOutBufDataBegin = mOutBufDataEnd = 0;
mROMBegin = ROM_BEGIN;
mROMEnd = ROM_END;
mROMActive = false;
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void Memory::EnableROM()
{
mROMActive = true;
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void Memory::EnableROM(unsigned short start, unsigned short end)
{
if (mROMEnd > mROMBegin) {
mROMBegin = start;
mROMEnd = end;
}
EnableROM();
}
/*
*--------------------------------------------------------------------
* Method: ReadCharKb()
* Purpose: If char I/O active, read character from console
* (non-blocking) and put in an input FIFO buffer.
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
unsigned char Memory::ReadCharKb()
{
unsigned char ret = 0;
if (mCharIOActive) {
int c;
putchar('?');
while(!kbhit());
c = getch();
if (mIOEcho) putchar(c);
mCharIOBufIn[mInBufDataEnd] = c;
mInBufDataEnd++;
if (mInBufDataEnd >= CHARIO_BUF_SIZE) mInBufDataEnd = 0;
ret = c;
}
return ret;
}
/*
*--------------------------------------------------------------------
* Method: GetCharIn()
* Purpose: Return character from the emulated character I/O FIFO
* input buffer or -1 if FIFO empty or char I/O not active.
* Arguments: n/a
* Returns: character
*--------------------------------------------------------------------
*/
char Memory::GetCharIn()
{
char ret = -1;
if (mCharIOActive) {
if (mInBufDataEnd != mInBufDataBegin) {
ret = mCharIOBufIn[mInBufDataBegin];
mInBufDataBegin++;
if (mInBufDataBegin >= CHARIO_BUF_SIZE) mInBufDataBegin = 0;
}
}
return ret;
}
/*
*--------------------------------------------------------------------
* Method: GetCharOut()
* Purpose: Return character from the emulated character I/O FIFO
* output buffer or -1 if FIFO empty or char I/O not
* active.
* Arguments: n/a
* Returns: character
*--------------------------------------------------------------------
*/
char Memory::GetCharOut()
{
char ret = -1;
if (mCharIOActive) {
if (mOutBufDataEnd != mOutBufDataBegin) {
ret = mCharIOBufOut[mOutBufDataBegin];
mOutBufDataBegin++;
if (mOutBufDataBegin >= CHARIO_BUF_SIZE) mOutBufDataBegin = 0;
}
}
return ret;
}
/*
*--------------------------------------------------------------------
* Method: PutCharIO()
* Purpose: Put character in the output char I/O FIFO buffer.
* Arguments: c - character
* Returns: n/a
*--------------------------------------------------------------------
*/
void Memory::PutCharIO(char c)
{
if (mCharIOActive) {
mCharIOBufOut[mOutBufDataEnd] = c;
mOutBufDataEnd++;
if (mOutBufDataEnd >= CHARIO_BUF_SIZE) mOutBufDataEnd = 0;
}
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
unsigned char Memory::Peek8bit(unsigned short addr)
{
if (mCharIOActive && addr == mCharIOAddr) {
#if defined (DBG)
cout << "DBG: Peek8bit($" << hex << addr << ") BEFORE ReadCharKb()" << endl;
cout << "DBG: m8bitMem[$" << hex << addr << "] = $" << hex << (unsigned short)m8bitMem[addr] << endl;
for (unsigned int a = 0xFFF0; a < 0x10000; a++) {
cout << "DBG: m8bitMem[$" << hex << a << "] = $" << hex << (unsigned short)m8bitMem[a] << endl;
}
#endif
m8bitMem[addr] = ReadCharKb();
#if defined (DBG)
cout << "************************" << endl;
cout << "DBG: Peek8bit($" << hex << addr << ") AFTER ReadCharKb()" << endl;
cout << "DBG: m8bitMem[$" << hex << addr << "] = $" << hex << (unsigned short)m8bitMem[addr] << endl;
for (unsigned int a = 0xFFF0; a < 0x10000; a++) {
cout << "DBG: m8bitMem[$" << hex << a << "] = $" << hex << (unsigned short)m8bitMem[a] << endl;
}
#endif
}
return m8bitMem[addr];
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
unsigned short Memory::Peek16bit(unsigned short addr)
{
unsigned short ret = 0;
if (mCharIOActive && addr == mCharIOAddr) {
#if defined (DBG)
cout << "DBG: Peek16bit(" << addr << ")" << endl;
#endif
m8bitMem[addr] = ReadCharKb();
}
ret = m8bitMem[addr++];
ret += m8bitMem[addr] * 256;
return ret;
}
/*
*--------------------------------------------------------------------
* Method: Poke8bit()
* Purpose: Write byte to specified memory location.
* If the memory location is mapped to character I/O,
* write value to output buffer and memory location.
* If the memory location is protected (ROM), do not
* write the value.
* Arguments: addr - (0x0000..0xffff) memory address,
* val - value (0x00..0xff)
* Returns: n/a
*--------------------------------------------------------------------
*/
void Memory::Poke8bit(unsigned short addr, unsigned char val)
{
if (mCharIOActive && addr == mCharIOAddr)
PutCharIO(val);
if (!mROMActive || (addr < ROM_BEGIN || addr > ROM_END)) {
m8bitMem[addr] = val;
}
}
/*
*--------------------------------------------------------------------
* Method: SetCharIO()
* Purpose: Activates and sets an address of basic character I/O
* emulation (console).
* Arguments: addr - address of I/O area (0x0000..0xFFFF)
* Returns: n/a
*--------------------------------------------------------------------
*/
void Memory::SetCharIO(unsigned short addr, bool echo)
{
mCharIOAddr = addr;
mCharIOActive = true;
mIOEcho = echo;
}
/*
*--------------------------------------------------------------------
* Method: DisableCharIO()
* Purpose: Deactivates basic character I/O emulation (console).
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
void Memory::DisableCharIO()
{
mCharIOActive = false;
}
/*
*--------------------------------------------------------------------
* Method: GetCharIOAddr()
* Purpose: Returns current address of basic character I/O area.
* Arguments: n/a
* Returns: address of I/O area
*--------------------------------------------------------------------
*/
unsigned short Memory::GetCharIOAddr()
{
return mCharIOAddr;
}
} // namespace MKBasic

55
Memory.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef MEMORY_H
#define MEMORY_H
#define MAX_8BIT_ADDR 0xFFFF
#define CHARIO_ADDR 0xE000
#define CHARIO_BUF_SIZE 256
#define ROM_BEGIN 0xD000
#define ROM_END 0xDFFF
namespace MKBasic {
class Memory
{
public:
Memory();
~Memory();
void Initialize();
unsigned char Peek8bit(unsigned short addr);
unsigned short Peek16bit(unsigned short addr);
void Poke8bit(unsigned short addr, unsigned char val);
void SetCharIO(unsigned short addr, bool echo);
void DisableCharIO();
unsigned short GetCharIOAddr();
char GetCharIn();
char GetCharOut();
void EnableROM();
void EnableROM(unsigned short start, unsigned short end);
protected:
private:
unsigned char m8bitMem[MAX_8BIT_ADDR+1];
char mCharIOBufIn[CHARIO_BUF_SIZE];
char mCharIOBufOut[CHARIO_BUF_SIZE];
unsigned int mInBufDataBegin;
unsigned int mInBufDataEnd;
unsigned int mOutBufDataBegin;
unsigned int mOutBufDataEnd;
unsigned short mCharIOAddr;
bool mCharIOActive;
bool mIOEcho;
unsigned short mROMBegin;
unsigned short mROMEnd;
bool mROMActive;
unsigned char ReadCharKb();
void PutCharIO(char c);
};
} // namespace MKBasic
#endif

25
Notes.txt Normal file
View File

@ -0,0 +1,25 @@
http://visual6502.org/wiki/index.php?title=6502DecimalMode
NV-BDIZC
Tests for ADC
00 + 00 and C=0 gives 00 and N=0 V=0 Z=1 C=0 (simulate)
79 + 00 and C=1 gives 80 and N=1 V=1 Z=0 C=0 (simulate)
24 + 56 and C=0 gives 80 and N=1 V=1 Z=0 C=0 (simulate)
93 + 82 and C=0 gives 75 and N=0 V=1 Z=0 C=1 (simulate)
89 + 76 and C=0 gives 65 and N=0 V=0 Z=0 C=1 (simulate)
89 + 76 and C=1 gives 66 and N=0 V=0 Z=1 C=1 (simulate)
80 + f0 and C=0 gives d0 and N=0 V=1 Z=0 C=1 (simulate)
80 + fa and C=0 gives e0 and N=1 V=0 Z=0 C=1 (simulate)
2f + 4f and C=0 gives 74 and N=0 V=0 Z=0 C=0 (simulate)
6f + 00 and C=1 gives 76 and N=0 V=0 Z=0 C=0 (simulate)
Tests for SBC
00 - 00 and C=0 gives 99 and N=1 V=0 Z=0 C=0 (simulate)
00 - 00 and C=1 gives 00 and N=0 V=0 Z=1 C=1 (simulate)
00 - 01 and C=1 gives 99 and N=1 V=0 Z=0 C=0 (simulate)
0a - 00 and C=1 gives 0a and N=0 V=0 Z=0 C=1 (simulate)
0b - 00 and C=0 gives 0a and N=0 V=0 Z=0 C=1 (simulate)
9a - 00 and C=1 gives 9a and N=1 V=0 Z=0 C=1 (simulate)
9b - 00 and C=0 gives 9a and N=1 V=0 Z=0 C=1 (simulate)

62
ReadMe.txt Normal file
View File

@ -0,0 +1,62 @@
Project: MKBasic
Author: Copyright (C) Marek Karcz 2016. All rights reserved.
Purpose:
MOS 6502 emulator, Virtual CPU/Machine and potentially retro-style 8-bit computer emulator,
MOS-6502-compatible virtual computer featuring BASIC interpreter, machine code monitor etc.
Memory images extensions: .RAM, .ROM
Format of the memory definition file:
; comment
ADDR
address
data
ORG
address
Where:
ADDR - label indicating that starting address will follow in next
line
ORG - label indicating that the address counter will change to the
value provided in next line
address - decimal or hexadecimal (prefix $) address in memory
E.g:
ADDR
$200
or
ADDR
512
changes the default start address (256) to 512.
ORG
49152
moves address counter to address 49152, following data will be
loaded from that address forward
data - the multi-line stream of decimal of hexadecimal ($xx) values
of size unsigned char (byte: 0-255) separated with spaces
or commas.
E.g.:
$00 $00 $00 $00
$00 $00 $00 $00
or
$00,$00,$00,$00
or
0 0 0 0
or
0,0,0,0
0 0 0 0

291
TestBCD.65s Normal file
View File

@ -0,0 +1,291 @@
; Verify decimal mode behavior
; Written by Bruce Clark. This code is public domain.
;
; Returns:
; ERROR = 0 if the test passed
; ERROR = 1 if the test failed
;
; This routine requires 17 bytes of RAM -- 1 byte each for:
; AR, CF, DA, DNVZC, ERROR, HA, HNVZC, N1, N1H, N1L, N2, N2L, NF, VF, and ZF
; and 2 bytes for N2H
;
; Variables:
; N1 and N2 are the two numbers to be added or subtracted
; N1H, N1L, N2H, and N2L are the upper 4 bits and lower 4 bits of N1 and N2
; DA and DNVZC are the actual accumulator and flag results in decimal mode
; HA and HNVZC are the accumulator and flag results when N1 and N2 are
; added or subtracted using binary arithmetic
; AR, NF, VF, ZF, and CF are the predicted decimal mode accumulator and
; flag results, calculated using binary arithmetic
;
; This program takes approximately 1 minute at 1 MHz (a few seconds more on
; a 65C02 than a 6502 or 65816)
;
*=$0300
AR: .DB 0
CF: .DB 0
DA: .DB 0
DNVZC: .DB 0
ERROR: .DB 0
HA: .DB 0
HNVZC: .DB 0
N1: .DB 0
N1H: .DB 0
N1L: .DB 0
N2: .DB 0
N2L: .DB 0
NF: .DB 0
VF: .DB 0
ZF: .DB 0
N2H: .DB 0,0
*=$0400
TEST: LDY #1 ; initialize Y (used to loop through carry flag values)
STY ERROR ; store 1 in ERROR until the test passes
LDA #0 ; initialize N1 and N2
STA N1
STA N2
LOOP1: LDA N2 ; N2L = N2 & $0F
AND #$0F ; [1] see text
STA N2L
LDA N2 ; N2H = N2 & $F0
AND #$F0 ; [2] see text
STA N2H
ORA #$0F ; N2H+1 = (N2 & $F0) + $0F
STA N2H+1
LOOP2: LDA N1 ; N1L = N1 & $0F
AND #$0F ; [3] see text
STA N1L
LDA N1 ; N1H = N1 & $F0
AND #$F0 ; [4] see text
STA N1H
JSR ADD
JSR A6502
JSR COMPARE
BNE DONE
JSR SUB
JSR S6502
JSR COMPARE
BNE DONE
INC N1 ; [5] see text
BNE LOOP2 ; loop through all 256 values of N1
INC N2 ; [6] see text
BNE LOOP1 ; loop through all 256 values of N2
DEY
BPL LOOP1 ; loop through both values of the carry flag
LDA #0 ; test passed, so store 0 in ERROR
STA ERROR
DONE: RTS
BRK
; Calculate the actual decimal mode accumulator and flags, the accumulator
; and flag results when N1 is added to N2 using binary arithmetic, the
; predicted accumulator result, the predicted carry flag, and the predicted
; V flag
;
ADD: SED ; decimal mode
CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1
ADC N2
STA DA ; actual accumulator result in decimal mode
PHP
PLA
STA DNVZC ; actual flags result in decimal mode
CLD ; binary mode
CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1
ADC N2
STA HA ; accumulator result of N1+N2 using binary arithmetic
PHP
PLA
STA HNVZC ; flags result of N1+N2 using binary arithmetic
CPY #1
LDA N1L
ADC N2L
CMP #$0A
LDX #0
BCC A1
INX
ADC #5 ; add 6 (carry is set)
AND #$0F
SEC
A1: ORA N1H
;
; if N1L + N2L < $0A, then add N2 & $F0
; if N1L + N2L >= $0A, then add (N2 & $F0) + $0F + 1 (carry is set)
;
ADC N2H,X
PHP
BCS A2
CMP #$A0
BCC A3
A2: ADC #$5F ; add $60 (carry is set)
SEC
A3: STA AR ; predicted accumulator result
PHP
PLA
STA CF ; predicted carry result
PLA
;
; note that all 8 bits of the P register are stored in VF
;
STA VF ; predicted V flags
RTS
; Calculate the actual decimal mode accumulator and flags, and the
; accumulator and flag results when N2 is subtracted from N1 using binary
; arithmetic
;
SUB: SED ; decimal mode
CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1
SBC N2
STA DA ; actual accumulator result in decimal mode
PHP
PLA
STA DNVZC ; actual flags result in decimal mode
CLD ; binary mode
CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1
SBC N2
STA HA ; accumulator result of N1-N2 using binary arithmetic
PHP
PLA
STA HNVZC ; flags result of N1-N2 using binary arithmetic
RTS
; Calculate the predicted SBC accumulator result for the 6502 and 65816
;
SUB1: CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1L
SBC N2L
LDX #0
BCS S11
INX
SBC #5 ; subtract 6 (carry is clear)
AND #$0F
CLC
S11: ORA N1H
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
SBC N2H,X
BCS S12
SBC #$5F ; subtract $60 (carry is clear)
S12: STA AR
RTS
; Calculate the predicted SBC accumulator result for the 6502 and 65C02
;
SUB2: CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1L
SBC N2L
LDX #0
BCS S21
INX
AND #$0F
CLC
S21: ORA N1H
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
SBC N2H,X
BCS S22
SBC #$5F ; subtract $60 (carry is clear)
S22: CPX #0
BEQ S23
SBC #6
S23: STA AR ; predicted accumulator result
RTS
; Compare accumulator actual results to predicted results
;
; Return:
; Z flag = 1 (BEQ branch) if same
; Z flag = 0 (BNE branch) if different
;
COMPARE:
LDA DA
CMP AR
BNE C1
LDA DNVZC ; [7] see text
EOR NF
AND #$80 ; mask off N flag
BNE C1
LDA DNVZC ; [8] see text
EOR VF
AND #$40 ; mask off V flag
BNE C1 ; [9] see text
LDA DNVZC
EOR ZF ; mask off Z flag
AND #2
BNE C1 ; [10] see text
LDA DNVZC
EOR CF
AND #1 ; mask off C flag
C1: RTS
; These routines store the predicted values for ADC and SBC for the 6502,
; 65C02, and 65816 in AR, CF, NF, VF, and ZF
A6502: LDA VF
;
; since all 8 bits of the P register were stored in VF, bit 7 of VF contains
; the N flag for NF
;
STA NF
LDA HNVZC
STA ZF
RTS
S6502: JSR SUB1
LDA HNVZC
STA NF
STA VF
STA ZF
STA CF
RTS
A65C02: LDA AR
PHP
PLA
STA NF
STA ZF
RTS
S65C02: JSR SUB2
LDA AR
PHP
PLA
STA NF
STA ZF
LDA HNVZC
STA VF
STA CF
RTS
A65816: LDA AR
PHP
PLA
STA NF
STA ZF
RTS
S65816: JSR SUB1
LDA AR
PHP
PLA
STA NF
STA ZF
LDA HNVZC
STA VF
STA CF
RTS

579
VMachine.cpp Normal file
View File

@ -0,0 +1,579 @@
#include <stdio.h>
#include <iostream>
#include <conio.h>
#include <string.h>
#include "VMachine.h"
#include "MKGenException.h"
using namespace std;
namespace MKBasic {
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
/*
*--------------------------------------------------------------------
* Method: VMachine()
* Purpose: Default class constructor.
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
VMachine::VMachine()
{
InitVM();
}
/*
*--------------------------------------------------------------------
* Method: VMachine()
* Purpose: Custom class constructor.
* Arguments: romfname - name of the ROM definition file
* ramfname - name of the RAM definition file
* Returns: n/a
*--------------------------------------------------------------------
*/
VMachine::VMachine(string romfname, string ramfname)
{
InitVM();
LoadROM(romfname);
LoadRAM(ramfname);
}
/*
*--------------------------------------------------------------------
* Method: ~VMachine()
* Purpose: Class destructor.
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
VMachine::~VMachine()
{
delete mpDisp;
delete mpCPU;
delete mpROM;
delete mpRAM;
}
/*
*--------------------------------------------------------------------
* Method: InitVM()
* Purpose: Initialize class.
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
void VMachine::InitVM()
{
mpRAM = new Memory();
mRunAddr = 0x200;
mCharIOAddr = CHARIO_ADDR;
mCharIOActive = mCharIO = false;
if (NULL == mpRAM) {
throw MKGenException("Unable to initialize VM (RAM).");
}
mpROM = new Memory();
if (NULL == mpROM) {
throw MKGenException("Unable to initialize VM (ROM).");
}
mpCPU = new MKCpu(mpRAM);
if (NULL == mpCPU) {
throw MKGenException("Unable to initialize VM (CPU).");
}
mpDisp = new Display();
if (NULL == mpDisp) {
throw MKGenException("Unable to initialize VM (Display).");
}
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void VMachine::ClearScreen()
{
HANDLE hStdOut;
CONSOLE_SCREEN_BUFFER_INFO csbi;
DWORD count;
DWORD cellCount;
COORD homeCoords = { 0, 0 };
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
if (hStdOut == INVALID_HANDLE_VALUE) return;
/* Get the number of cells in the current buffer */
if (!GetConsoleScreenBufferInfo( hStdOut, &csbi )) return;
cellCount = csbi.dwSize.X *csbi.dwSize.Y;
/* Fill the entire buffer with spaces */
if (!FillConsoleOutputCharacter(
hStdOut,
(TCHAR) ' ',
cellCount,
homeCoords,
&count
)) return;
/* Fill the entire buffer with the current colors and attributes */
if (!FillConsoleOutputAttribute(
hStdOut,
csbi.wAttributes,
cellCount,
homeCoords,
&count
)) return;
/* Move the cursor home */
SetConsoleCursorPosition( hStdOut, homeCoords );
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void VMachine::ScrHome()
{
HANDLE hStdOut;
COORD homeCoords = { 0, 0 };
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
if (hStdOut == INVALID_HANDLE_VALUE) return;
/* Move the cursor home */
SetConsoleCursorPosition( hStdOut, homeCoords );
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void VMachine::ShowDisp()
{
if (mCharIOActive) {
#if defined (WINDOWS)
//ClearScreen();
ScrHome();
#elif defined (LINUX)
system("clear");
#endif
mpDisp->ShowScr();
}
}
/*
*--------------------------------------------------------------------
* Method: Run()
* Purpose: Run VM until software break instruction.
* Arguments: n/a
* Returns: Pointer to CPU registers and flags.
*--------------------------------------------------------------------
*/
Regs *VMachine::Run()
{
Regs *cpureg = NULL;
#if defined (WINDOWS)
ClearScreen();
#elif defined (LINUX)
system("clear");
#endif
ShowDisp();
while (true) {
cpureg = Step();
if (mCharIO) {
ShowDisp();
}
if (cpureg->SoftIrq)
break;
}
ShowDisp();
return cpureg;
}
/*
*--------------------------------------------------------------------
* Method: Run()
* Purpose: Run VM from specified address until software break
* instruction.
* Arguments: addr - start execution address
* Returns: Pointer to CPU registers and flags.
*--------------------------------------------------------------------
*/
Regs *VMachine::Run(unsigned short addr)
{
mRunAddr = addr;
return Run();
}
/*
*--------------------------------------------------------------------
* Method: Exec()
* Purpose: Run VM from current address until last RTS.
* NOTE: Stack must be empty!
* Arguments: n/a
* Returns: Pointer to CPU registers and flags.
*--------------------------------------------------------------------
*/
Regs *VMachine::Exec()
{
Regs *cpureg = NULL;
#if defined (WINDOWS)
ClearScreen();
#elif defined (LINUX)
system("clear");
#endif
ShowDisp();
while (true) {
cpureg = Step();
if (mCharIO) {
ShowDisp();
}
if (cpureg->LastRTS) break;
}
ShowDisp();
return cpureg;
}
/*
*--------------------------------------------------------------------
* Method: Exec()
* Purpose: Run VM from specified address until RTS.
* Arguments: addr - start execution address
* Returns: Pointer to CPU registers and flags.
*--------------------------------------------------------------------
*/
Regs *VMachine::Exec(unsigned short addr)
{
mRunAddr = addr;
return Exec();
}
/*
*--------------------------------------------------------------------
* Method: Step()
* Purpose: Execute single opcode.
* Arguments: n/a
* Returns: Pointer to CPU registers and flags.
*--------------------------------------------------------------------
*/
Regs *VMachine::Step()
{
unsigned short addr = mRunAddr;
Regs *cpureg = NULL;
cpureg = mpCPU->ExecOpcode(addr);
addr = cpureg->PtrAddr;
mRunAddr = addr;
if (mCharIOActive) {
char c = -1;
mCharIO = false;
while ((c = mpRAM->GetCharOut()) != -1) {
mpDisp->PutChar(c);
mCharIO = true;
}
}
return cpureg;
}
/*
*--------------------------------------------------------------------
* Method: Step()
* Purpose: Execute single opcode.
* Arguments: addr (unsigned short) - opcode address
* Returns: Pointer to CPU registers and flags.
*--------------------------------------------------------------------
*/
Regs *VMachine::Step(unsigned short addr)
{
mRunAddr = addr;
return Step();
}
/*
*--------------------------------------------------------------------
* Method: LoadROM()
* Purpose: Load data from memory definition file to the memory.
* Arguments: romfname - name of the ROM file definition
* Returns: n/a
*--------------------------------------------------------------------
*/
void VMachine::LoadROM(string romfname)
{
LoadMEM(romfname, mpROM);
}
/*
*--------------------------------------------------------------------
* Method: LoadRAM()
* Purpose: Load data from memory definition file to the memory.
* Arguments: ramfname - name of the RAM file definition
* Returns: n/a
*--------------------------------------------------------------------
*/
void VMachine::LoadRAM(string ramfname)
{
LoadMEM(ramfname, mpRAM);
mpRAM->EnableROM();
}
/*
*--------------------------------------------------------------------
* Method: LoadMEM()
* Purpose: Load data from memory definition file to the memory.
* Arguments: memfname - name of memory definition file
* pmem - pointer to memory object
* Returns: n/a
* Details:
* Format of the memory definition file:
* ; comment
* ADDR
* address
* data
* ORG
* address
*
* Where:
* ADDR - label indicating that starting address will follow in next
* line
* ORG - label indicating that the address counter will change to the
* value provided in next line
* address - decimal or hexadecimal (prefix $) address in memory
* E.g:
* ADDR
* $200
*
* or
*
* ADDR
* 512
*
* changes the default start address (256) to 512.
*
* ORG
* 49152
*
* moves address counter to address 49152, following data will be
* loaded from that address forward
*
* data - the multi-line stream of decimal of hexadecimal ($xx) values
* of size unsigned char (byte: 0-255) separated with spaces
* or commas.
* E.g.:
* $00 $00 $00 $00
* $00 $00 $00 $00
*
* or
*
* $00,$00,$00,$00
*
* or
*
* 0 0 0 0
*
* or
*
* 0,0,0,0
* 0 0 0 0
*--------------------------------------------------------------------
*/
void VMachine::LoadMEM(string memfname, Memory *pmem)
{
FILE *fp = NULL;
char line[256] = "\0";
unsigned short addr = 0x200;
unsigned int nAddr;
Memory *pm = pmem;
if ((fp = fopen(memfname.c_str(), "r")) != NULL) {
fgets(line, 256, fp);
if (0 == strcmp(line, "ADDR")) {
line[0] = '\0';
fgets(line, 256, fp);
if (*line == '$') {
sscanf(line+1, "%04x", &nAddr);
addr = nAddr;
} else {
addr = (unsigned short) atoi(line);
}
mRunAddr = addr;
}
while (0 == feof(fp) && 0 == ferror(fp))
{
line[0] = '\0';
fgets(line, 256, fp);
if (0 == strncmp(line, "ORG", 3)) {
line[0] = '\0';
fgets(line, 256, fp);
if (*line == '$') {
sscanf(line+1, "%04x", &nAddr);
addr = nAddr;
} else {
addr = (unsigned short) atoi(line);
}
continue;
}
if (';' == *line) continue; // skip comment lines
char *s = strtok (line, " ,");
while (NULL != s) {
unsigned int nVal;
if (*s == '$') {
sscanf(s+1, "%02x", &nVal);
pm->Poke8bit(addr++, (unsigned short)nVal);
} else {
pm->Poke8bit(addr++, (unsigned short)atoi(s));
}
s = strtok(NULL, " ,");
}
}
}
else {
cout << "WARNING: Unable to open memory definition file: " << memfname << endl;
cout << "Press [ENTER]...";
getchar();
//throw MKGenException("Unable to open memory definition file: " + memfname);
}
}
/*
*--------------------------------------------------------------------
* Method: MemPeek8bit()
* Purpose: Read value from specified RAM address.
* Arguments: addr - RAM address (0..0xFFFF)
* Returns: unsigned short - value read from specified RAM address
*--------------------------------------------------------------------
*/
unsigned short VMachine::MemPeek8bit(unsigned short addr)
{
unsigned short ret = 0;
ret = (unsigned short)mpRAM->Peek8bit(addr);
return ret;
}
/*
*--------------------------------------------------------------------
* Method: MemPoke8bit()
* Purpose: Write value to specified RAM address.
* Arguments: addr - RAM address (0..0xFFFF)
* v - 8-bit byte value
* Returns: n/a
*--------------------------------------------------------------------
*/
void VMachine::MemPoke8bit(unsigned short addr, unsigned char v)
{
mpRAM->Poke8bit(addr, v);
}
/*
*--------------------------------------------------------------------
* Method: GetRegs()
* Purpose: Return pointer to CPU status register.
* Arguments: n/a
* Returns: pointer to status register
*--------------------------------------------------------------------
*/
Regs *VMachine::GetRegs()
{
return mpCPU->GetRegs();
}
/*
*--------------------------------------------------------------------
* Method: SetCharIO()
* Purpose: Activates and sets an address of basic character I/O
* emulation (console).
* Arguments: addr - address of I/O area (0x0000..0xFFFF)
* Returns: n/a
*--------------------------------------------------------------------
*/
void VMachine::SetCharIO(unsigned short addr, bool echo)
{
mCharIOAddr = addr;
mCharIOActive = true;
mpRAM->SetCharIO(addr, echo);
mpDisp->ClrScr();
}
/*
*--------------------------------------------------------------------
* Method: DisableCharIO()
* Purpose: Deactivates basic character I/O emulation (console).
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
void VMachine::DisableCharIO()
{
mCharIOActive = false;
mpRAM->DisableCharIO();
}
/*
*--------------------------------------------------------------------
* Method: GetCharIOAddr()
* Purpose: Returns current address of basic character I/O area.
* Arguments: n/a
* Returns: address of I/O area
*--------------------------------------------------------------------
*/
unsigned short VMachine::GetCharIOAddr()
{
return mCharIOAddr;
}
/*
*--------------------------------------------------------------------
* Method: GetCharIOActive()
* Purpose: Returns status of character I/O emulation.
* Arguments: n/a
* Returns: true if I/O emulation active
*--------------------------------------------------------------------
*/
bool VMachine::GetCharIOActive()
{
return mCharIOActive;
}
/*
*--------------------------------------------------------------------
* Method: ShowIO()
* Purpose: Show contents of emulated char I/O.
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
void VMachine::ShowIO()
{
if (mCharIOActive)
mpDisp->ShowScr();
}
} // namespace MKBasic

65
VMachine.h Normal file
View File

@ -0,0 +1,65 @@
#ifndef VMACHINE_H
#define VMACHINE_H
#include <string>
#include "MKCpu.h"
#include "Memory.h"
#include "Display.h"
#define WINDOWS 1
#if defined (WINDOWS)
#include <windows.h>
#endif
#define IOREFRESH 32
using namespace std;
namespace MKBasic {
class VMachine
{
public:
VMachine();
VMachine(string romfname, string ramfname);
~VMachine();
void InitVM();
Regs *Run();
Regs *Run(unsigned short addr);
Regs *Exec();
Regs *Exec(unsigned short addr);
Regs *Step();
Regs *Step(unsigned short addr);
void LoadROM(string romfname);
void LoadRAM(string ramfname);
unsigned short MemPeek8bit(unsigned short addr);
void MemPoke8bit(unsigned short addr, unsigned char v);
Regs *GetRegs();
void SetCharIO(unsigned short addr, bool echo);
void DisableCharIO();
unsigned short GetCharIOAddr();
bool GetCharIOActive();
void ShowIO();
void ClearScreen();
void ScrHome();
protected:
private:
MKCpu *mpCPU;
Memory *mpROM;
Memory *mpRAM;
Display *mpDisp;
unsigned short mRunAddr;
unsigned short mCharIOAddr;
bool mCharIOActive;
bool mCharIO;
void LoadMEM(string memfname, Memory *pmem);
void ShowDisp();
};
} // namespace MKBasic
#endif

56
bcd.c Normal file
View File

@ -0,0 +1,56 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
unsigned char conv2bcd(unsigned short v)
{
unsigned char arg8 = 0;
arg8 = (unsigned char)((v/10) << 4);
arg8 |= ((unsigned char)(v - (v/10)*10)) & 0x0F;
return arg8;
}
char *conv24bitbin(unsigned char v)
{
static char retbuf[5];
int i=3;
memset(retbuf, '0', 4);
retbuf[4]=0;
if (v == 0) return retbuf;
while (v > 0 && i >= 0) {
int r = v % 2;
retbuf[i] = ((r==0) ? '0' : '1');
v = v/2;
i--;
}
return retbuf;
}
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int main(int argc, char *argv[])
{
unsigned short v = 0;
for (v = 0; v < 100; v++) {
unsigned char cv = conv2bcd(v), hinyb, lonyb;
hinyb = (cv & 0xF0) >> 4;
lonyb = cv & 0x0F;
char buf_hinyb[5], buf_lonyb[5];
strcpy(buf_hinyb, conv24bitbin(hinyb));
strcpy(buf_lonyb, conv24bitbin(lonyb));
printf("%d (dec) \t= %4s(%d) %4s(%d) (BCD, dec:%d)\n", v,
buf_hinyb,
hinyb,
buf_lonyb,
lonyb,
cv);
}
return 0;
}

315
dummy.ram Normal file
View File

@ -0,0 +1,315 @@
;
; test program #1
; address: $0200
; load Acc with value 12
; write Acc to address $c000 (49152)
;
; nop
; nop
; lda #$0c
; sta $c000
; brk
;
$EA $EA $A9 $0c $8D $00 $c0 $00 $00
;
; test program #2
; address: $0400
; copy 0-terminated string from
; address $d000 to $0200
; "Hello World!"
;
; ORG=$0400
; hello:
; ldx #0
; loop:
; lda $d000,x
; beq $06 ;branch to end (+6) if A=0
; sta $0200,x
; inx
; bne $f5 ; branch to loop (-11) if X<>0
; end:
; brk
ORG
$0400
$A2 $00
$BD $00 $d0
$F0 $06
$9D $00 $02
$E8
$D0 $F5
$00 $00
; data
; address: $d000
ORG
$D000
;DEC: 53248
; "Hello World!"
72 101 108 108 111 32 87 111 114 108 100 33 0
;
; test program #3 - copy Hello World! string to $0300
; using different assembly instructions
; address: $0500
;
; ORG=$0500 ;dec: 1280
; hello:
; lda #0
; sta $05
; ldx $05
; loop:
; lda $d000,x
; sta $0300,x
; beq end ;(+6)
; inx
; beq end ;(+3)
; jmp loop
; end:
; brk
ORG
$0500
;DEC: 1280
$A9 $00
$85 $05
$A6 $05
$BD $00 $d0
$9D $00 $03
$F0 $06
$E8
$F0 $03
$4C $06 $05
$00 $00
;
; test program #4
; left-shift memory location $05 at zero page,
; then location $06 using zero page indexed addressing,
; then memory location $c001 (outside zero page) using absolute addressing
; then location $c002 using indexed absolute addressing
; and finally left-shift Acc.
; stop after each step for debugging
; exit loop when Acc=0
;
; start:
; lda #$ff
; ldx #$01
; sta $05
; sta $05,x
; sta $c000,x
; inx
; sta $c000,x
; ldx #$01
; loop2:
; brk
; asl $05
; asl $05,x
; asl $c001
; asl $c001,x
; asl
; bne loop2 ;(-15 or $f1)
; brk
ORG
$0600
$A9 $FF
$A2 $01
$85 $05
$95 $05
$9D $00 $C0
$E8
$9D $00 $C0
$A2 $01
$00 $00
$06 $05
$16 $05
$0E $01 $C0
$1E $01 $C0
$0A
$D0 $F1
$00 $00
;
; test program #5
; Test ORA opcode with various arguments and addressing modes.
; At each break, the contents of Acc should equal $AA.
;
; start:
; lda #$aa ;%10101010
; sta $05
; sta $aa
; lda #$00
; tax
; ora ($05,x)
; brk
; lda #$00
; ora $05
; brk
; lda #$00
; ora #$aa
; brk
; lda #$00
; ora $0005
; brk
; lda #$05
; sta $06
; lda #$00
; sta $07
; tay
; ora ($06),y
; brk
; lda #$00
; tax
; ora $05,x
; brk
; lda #$00
; tay
; ora $0005,y
; brk
; lda #$00
; tax
; ora $0005,x
; brk
ORG
$0700
$A9 $AA
$85 $05
$85 $AA
$A9 $00
$AA
$01 $05
$00 $00
$A9 $00
$05 $05
$00 $00
$A9 $00
$09 $AA
$00 $00
$A9 $00
$0D $05 $00
$00 $00
$A9 $05
$85 $06
$A9 $00
$85 $07
$A8
$11 $06
$00 $00
$A9 $00
$AA
$15 $05
$00 $00
$A9 $00
$A8
$19 $05 $00
$00 $00
$A9 $00
$AA
$1D $05 $00
$00 $00
;
; test program #6
; Test JSR opcode.
; After each break examine memory at $c000 and $c001.
; After 1-st break, $c000 should equal $dd.
; Return address-1 ($0802) should be on stack.
; After 2-nd break, PC counter should be at $0805.
; After 3-rd break, $c000 should equal $ee.
; Return address-1 ($0807) should be on stack.
; After 4-th break, PC counter should be at $080a.
;
; start:
; jsr sub1
; brk
; jsr sub2
; brk
; brk
; brk
; sub1:
; lda #$dd
; sta $c000
; brk
; rts
; sub2:
; lda #$ee
; sta $c000
; brk
; rts
;
ORG
$0800
$20 $0B $08
$00 $00
$20 $13 $08
$00
$00
$00
$A9 $DD
$8D $00 $C0
$00 $00
$60
$A9 $EE
$8D $00 $C0
$00 $00
$60
;
; test program #7
; Test ADC opcode.
; Expected results:
; First break: Acc=$01, Carry=1
; 2-nd break: Acc=$02, Carry=1
; 3-rd break: Acc=$22, Carry=0
; 4-th break: Acc=$23, Carry=0
;
; start:
; clc
; lda #$ff
; adc #$02
; brk
; sec
; lda #$ff
; adc #$02
; brk
; clc
; lda #$20
; adc #$02
; brk
; sec
; lda #$20
; adc #$02
; brk
;
ORG
$0900
$18
$A9 $FF
$69 $02
$00 $00
$38
$A9 $FF
$69 $02
$00 $00
$18
$A9 $20
$69 $02
$00 $00
$38
$A9 $20
$69 $02
$00 $00
;
; test program #8
; Test ROR opcode.
;
; start:
; sec
; lda #$00
; loop:
; ror
; brk
; bcc loop ;(-5 -> $FB)
; brk
;
ORG
$0920
$38
$A9 $00
$6A
$00 $00
$90 $FB
$00 $00
;

315
dummy.rom Normal file
View File

@ -0,0 +1,315 @@
;
; test program #1
; address: $0200
; load Acc with value 12
; write Acc to address $c000 (49152)
;
; nop
; nop
; lda #$0c
; sta $c000
; brk
;
$EA $EA $A9 $0c $8D $00 $c0 $00 $00
;
; test program #2
; address: $0400
; copy 0-terminated string from
; address $d000 to $0200
; "Hello World!"
;
; ORG=$0400
; hello:
; ldx #0
; loop:
; lda $d000,x
; beq $06 ;branch to end (+6) if A=0
; sta $0200,x
; inx
; bne $f5 ; branch to loop (-11) if X<>0
; end:
; brk
ORG
$0400
$A2 $00
$BD $00 $d0
$F0 $06
$9D $00 $02
$E8
$D0 $F5
$00 $00
; data
; address: $d000
ORG
$D000
;DEC: 53248
; "Hello World!"
72 101 108 108 111 32 87 111 114 108 100 33 0
;
; test program #3 - copy Hello World! string to $0300
; using different assembly instructions
; address: $0500
;
; ORG=$0500 ;dec: 1280
; hello:
; lda #0
; sta $05
; ldx $05
; loop:
; lda $d000,x
; sta $0300,x
; beq end ;(+6)
; inx
; beq end ;(+3)
; jmp loop
; end:
; brk
ORG
$0500
;DEC: 1280
$A9 $00
$85 $05
$A6 $05
$BD $00 $d0
$9D $00 $03
$F0 $06
$E8
$F0 $03
$4C $06 $05
$00 $00
;
; test program #4
; left-shift memory location $05 at zero page,
; then location $06 using zero page indexed addressing,
; then memory location $c001 (outside zero page) using absolute addressing
; then location $c002 using indexed absolute addressing
; and finally left-shift Acc.
; stop after each step for debugging
; exit loop when Acc=0
;
; start:
; lda #$ff
; ldx #$01
; sta $05
; sta $05,x
; sta $c000,x
; inx
; sta $c000,x
; ldx #$01
; loop2:
; brk
; asl $05
; asl $05,x
; asl $c001
; asl $c001,x
; asl
; bne loop2 ;(-15 or $f1)
; brk
ORG
$0600
$A9 $FF
$A2 $01
$85 $05
$95 $05
$9D $00 $C0
$E8
$9D $00 $C0
$A2 $01
$00 $00
$06 $05
$16 $05
$0E $01 $C0
$1E $01 $C0
$0A
$D0 $F1
$00 $00
;
; test program #5
; Test ORA opcode with various arguments and addressing modes.
; At each break, the contents of Acc should equal $AA.
;
; start:
; lda #$aa ;%10101010
; sta $05
; sta $aa
; lda #$00
; tax
; ora ($05,x)
; brk
; lda #$00
; ora $05
; brk
; lda #$00
; ora #$aa
; brk
; lda #$00
; ora $0005
; brk
; lda #$05
; sta $06
; lda #$00
; sta $07
; tay
; ora ($06),y
; brk
; lda #$00
; tax
; ora $05,x
; brk
; lda #$00
; tay
; ora $0005,y
; brk
; lda #$00
; tax
; ora $0005,x
; brk
ORG
$0700
$A9 $AA
$85 $05
$85 $AA
$A9 $00
$AA
$01 $05
$00 $00
$A9 $00
$05 $05
$00 $00
$A9 $00
$09 $AA
$00 $00
$A9 $00
$0D $05 $00
$00 $00
$A9 $05
$85 $06
$A9 $00
$85 $07
$A8
$11 $06
$00 $00
$A9 $00
$AA
$15 $05
$00 $00
$A9 $00
$A8
$19 $05 $00
$00 $00
$A9 $00
$AA
$1D $05 $00
$00 $00
;
; test program #6
; Test JSR opcode.
; After each break examine memory at $c000 and $c001.
; After 1-st break, $c000 should equal $dd.
; Return address-1 ($0802) should be on stack.
; After 2-nd break, PC counter should be at $0805.
; After 3-rd break, $c000 should equal $ee.
; Return address-1 ($0807) should be on stack.
; After 4-th break, PC counter should be at $080a.
;
; start:
; jsr sub1
; brk
; jsr sub2
; brk
; brk
; brk
; sub1:
; lda #$dd
; sta $c000
; brk
; rts
; sub2:
; lda #$ee
; sta $c000
; brk
; rts
;
ORG
$0800
$20 $0B $08
$00 $00
$20 $13 $08
$00
$00
$00
$A9 $DD
$8D $00 $C0
$00 $00
$60
$A9 $EE
$8D $00 $C0
$00 $00
$60
;
; test program #7
; Test ADC opcode.
; Expected results:
; First break: Acc=$01, Carry=1
; 2-nd break: Acc=$02, Carry=1
; 3-rd break: Acc=$22, Carry=0
; 4-th break: Acc=$23, Carry=0
;
; start:
; clc
; lda #$ff
; adc #$02
; brk
; sec
; lda #$ff
; adc #$02
; brk
; clc
; lda #$20
; adc #$02
; brk
; sec
; lda #$20
; adc #$02
; brk
;
ORG
$0900
$18
$A9 $FF
$69 $02
$00 $00
$38
$A9 $FF
$69 $02
$00 $00
$18
$A9 $20
$69 $02
$00 $00
$38
$A9 $20
$69 $02
$00 $00
;
; test program #8
; Test ROR opcode.
;
; start:
; sec
; lda #$00
; loop:
; ror
; brk
; bcc loop ;(-5 -> $FB)
; brk
;
ORG
$0920
$38
$A9 $00
$6A
$00 $00
$90 $FB
$00 $00
;

5
hello_world.bas Normal file
View File

@ -0,0 +1,5 @@
10 LET A=1
20 PR A;") HELLO WORLD FROM MKHBC!"
30 LET A=A+1
40 IF A=0 THEN END
50 GOTO 20

333
main.cpp Normal file
View File

@ -0,0 +1,333 @@
#include <cstdlib>
#include <iostream>
#include <bitset>
#include "MKCpu.h"
#include "Memory.h"
#include "Display.h"
#include "VMachine.h"
#include "MKGenException.h"
using namespace std;
using namespace MKBasic;
/*
*--------------------------------------------------------------------
* Method: ShowHelp()
* Purpose: Display commands help.
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
void ShowHelp()
{
cout << "Virtual Machine/CPU emulator/Debugger Command Reference." << endl << endl;
cout << "S - step" << endl;
cout << " Executes single opcode at current address." << endl;
cout << "C - continue" << endl;
cout << " Continues code execution from current address until BRK." << endl;
cout << "D - dump memory" << endl;
cout << " Usage: D [startaddr] [endaddr]" << endl;
cout << " Where: startaddr,endaddr - memory addr. in hexadecimal format [0000..FFFF]." << endl;
cout << " Dumps contents of memory, hexadecimal and ASCII formats." << endl;
cout << "G - go/continue from new address until BRK" << endl;
cout << " Usage: G [address]" << endl;
cout << " Where: address - memory addr. in hexadecimal format [0000.FFFF]." << endl;
cout << " Executes code at provided address, interrupted by BRK opcode." << endl;
cout << "X - execute code from new address until RTS" << endl;
cout << " Usage: X [address]" << endl;
cout << " Where: address - memory addr. in hexadecimal format [0000.FFFF]." << endl;
cout << " Executes code at provided address, until RTS (last one)." << endl;
cout << "Q - quit" << endl;
cout << " Exits from the emulator/debugger." << endl;
cout << "A - set address for next step" << endl;
cout << " Usage: A [address]" << endl;
cout << " Where: address - memory addr. in hexadecimal format [0000.FFFF]." << endl;
cout << " Sets current address to a new value." << endl;
cout << "N - go number of steps" << endl;
cout << " Usage: N [steps]" << endl;
cout << " Where: steps - number of steps in decimal format" << endl;
cout << " Execute number of opcodes provided in steps argument starting" << endl;
cout << " from current address." << endl;
cout << "W - write to memory" << endl;
cout << " Usage: W [address] [hexval] [hexval] ... 100" << endl;
cout << " Where: address - memory addr. in hexadecimal format [0000.FFFF]," << endl;
cout << " hexval - byte value in hexadecimal format [00.FF]." << endl;
cout << " Writes provided values to memory starting at specified address." << endl;
cout << "I - toggle char I/O emulation" << endl;
cout << " Usage: I [address]" << endl;
cout << " Where: address - memory addr. in hexadecimal format [0000.FFFF]," << endl;
cout << " Toggles basic character I/O emulation. When enabled, all writes" << endl;
cout << " to the specified memory address also writes a character code to" << endl;
cout << " to a virtual console. All reads from specified memory address" << endl;
cout << " are interpreted as console character input." << endl;
cout << "R - regs" << endl;
cout << " Displays CPU registers and flags." << endl;
cout << "T - show I/O console" << endl;
cout << " Displays/prints the contents of the virtual console screen." << endl;
cout << " Note that in run mode (commands X, G or C), virtual screen is" << endl;
cout << " displayed automatically in real-time if I/O emulation is enabled." << endl;
cout << "E - toggle I/O local echo" << endl;
cout << " Toggles local echo on/off when I/O emulation is enabled." << endl;
cout << "B - blank (clear) screen" << endl;
cout << " Clears the screen, useful when after exiting I/O emulation" << endl;
cout << " your screen is messed up." << endl;
cout << "NOTE:" << endl;
cout << " If no arguments provided, each command will prompt user to enter" << endl;
cout << " missing data." << endl;
cout << endl;
}
/*
*--------------------------------------------------------------------
* Method: PromptNewAddress()
* Purpose: Prompt user to enter 16-bit address (hex) in console.
* Arguments: prompt - prompt text
* Returns: unsigned int - address entered by user
*--------------------------------------------------------------------
*/
unsigned int PromptNewAddress(string prompt)
{
unsigned int newaddr = 0x10000;
while (newaddr > 0xFFFF) {
cout << prompt;
cin >> hex >> newaddr;
}
return newaddr;
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void ShowRegs(Regs *preg, VMachine *pvm, unsigned short ioaddr, bool ioecho)
{
cout << "Registers:" << endl;
cout << " Acc: $" << hex << (unsigned short)preg->Acc << "\t(%" << bitset<8>((int)preg->Acc) << ")" << endl;
cout << " X: $" << hex << (unsigned short)preg->IndX << endl;
cout << " Y: $" << hex << (unsigned short)preg->IndY << endl;
cout << " Addr: $" << hex << preg->PtrAddr << endl;
cout << " Acc16: $" << hex << preg->Acc16 << endl;
cout << " Ptr16: $" << hex << preg->Ptr16 << endl;
cout << " Stack: $" << hex << (unsigned short)preg->PtrStack << endl;
cout << " Flags: NV-BDIZC" << endl;
cout << " " << bitset<8>((int)preg->Flags) << endl;
cout << endl << "I/O status: " << (pvm->GetCharIOActive() ? "enabled" : "disabled") << ", ";
cout << " at: $" << hex << ioaddr << ", ";
cout << " local echo: " << (ioecho ? "ON" : "OFF") << "." << endl;
// cout << "-------------------------------------------------------------------------------" << endl;
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void ShowMenu()
{
cout << "---------------------------------------------------------------------------" << endl;
cout << "S - step | C - continue, D - dump memory | G - go/continue from new address" << endl;
cout << "Q - quit | A - set address for next step | N - go number of steps" << endl;
cout << "H - help | I - toggle char I/O emulation | W - write to memory" << endl;
cout << "R - regs | T - show I/O console | E - toggle I/O local echo" << endl;
cout << " | X - execute from new address | B - blank (clear) screen" << endl;
cout << "---------------------------------------------------------------------------" << endl;
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
#define RUNSTEPS(step,nsteps,brk,preg,stct,pvm,lrts) \
brk = preg->SoftIrq; \
lrts = preg->LastRTS; \
while(step && nsteps > 1 && !brk && !lrts) { \
cout << "addr: $" << hex << preg->PtrAddr << ", step: " << dec << stct << "\r"; \
preg = pvm->Step(); \
brk = preg->SoftIrq; \
nsteps--; \
stct++; \
}
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int main(int argc, char** argv) {
string romfile("dummy.rom"), ramfile("dummy.ram");
if (argc > 1) {
ramfile = argv[1];
}
try {
cout << endl;
VMachine *pvm = new VMachine(romfile, ramfile);
pvm->ClearScreen();
cout << "Welcome to Virtual Machine/CPU Emulator (6502)/Debugger." << endl;
cout << "Copyright (C) by Marek Karcz 2016. All rights reserved." << endl;
string cmd;
bool runvm = false, step = false, brk = false, execaddr = false, stop = true;
bool ioecho = false, lrts = false, execvm = false;
unsigned int newaddr = 0x10000, ioaddr = 0xE000, tmpaddr = 0x0000;
int nsteps = 0;
while (true) {
Regs *preg = pvm->GetRegs();
if (runvm) {
int stct = 1;
if (execaddr) {
preg = ((step) ? pvm->Step(newaddr) : pvm->Run(newaddr));
RUNSTEPS(step,nsteps,brk,preg,stct,pvm,lrts);
execaddr = false;
newaddr = 0x10000;
} else {
preg = ((step) ? pvm->Step() : pvm->Run());
RUNSTEPS(step,nsteps,brk,preg,stct,pvm,lrts);
}
if (step)
cout << "\rExecuted " << dec << stct << ((stct == 1) ? " step." : " steps.") << " " << endl;
nsteps = 0;
runvm = step = false;
} else if (execvm) {
preg = (execaddr ? pvm->Exec(newaddr) : pvm->Exec());
execvm = false;
brk = preg->SoftIrq;
lrts = preg->LastRTS;
}
if (brk || stop || lrts) {
cout << endl;
if (brk) {
cout << "BRK at " << hex << preg->PtrAddr << endl;
brk = stop = lrts = false;
} else if (lrts) {
cout << "FINISHED at " << hex << ((newaddr > 0xFFFF) ? preg->PtrAddr : newaddr) << endl;
brk = stop = lrts = false;
} else if (stop) {
cout << "STOPPED at " << hex << ((newaddr > 0xFFFF) ? preg->PtrAddr : newaddr) << endl;
brk = stop = lrts = false;
}
ShowRegs(preg,pvm,ioaddr,ioecho);
}
ShowMenu();
cout << "> ";
cin >> cmd;
char c = tolower(cmd.c_str()[0]);
if (c == 'h') {
ShowHelp();
} else if (c == 'b') {
pvm->ClearScreen();
} else if (c == 'r') {
stop = true;
} else if (c == 'e') {
if (pvm->GetCharIOActive()) {
ioecho = !ioecho;
cout << "I/O echo is " << (ioecho ? "activated." : "deactivated.") << endl;
pvm->SetCharIO(ioaddr, ioecho);
} else {
cout << "ERROR: I/O is deactivated." << endl;
}
} else if (c == 't') {
if (pvm->GetCharIOActive()) {
pvm->ShowIO();
} else {
cout << "ERROR: I/O is deactivated." << endl;
}
} else if (c == 'i') {
if (pvm->GetCharIOActive()) {
pvm->DisableCharIO();
cout << "I/O deactivated." << endl;
} else {
ioaddr = PromptNewAddress("Address (0..FFFF): ");
cout << " [" << hex << ioaddr << "]" << endl;
pvm->SetCharIO(ioaddr, ioecho);
cout << "I/O activated." << endl;
}
} else if (c == 'w') {
tmpaddr = PromptNewAddress("Address (0..FFFF): ");
cout << " [" << hex << tmpaddr << "]" << endl;
cout << "Enter hex bytes [00..FF] values separated with NL or spaces, end with [100]:" << endl;
unsigned short v = 0;
while (true) {
cin >> hex >> v;
cout << " " << hex << v;
if (v > 0xFF) break;
pvm->MemPoke8bit(tmpaddr++, v & 0xFF);
};
cout << endl;
} else if (c == 'a') {
execaddr = stop = true;
newaddr = PromptNewAddress("Address (0..FFFF): ");
cout << " [" << hex << newaddr << "]" << endl;
} else if (c == 's') {
runvm = step = stop = true;
} else if (c == 'n') {
nsteps = 0;
while (nsteps < 1) {
cout << "# of steps [n>1]: ";
cin >> dec >> nsteps;
}
cout << " [" << dec << nsteps << "]" << endl;
runvm = step = stop = true;
} else if (c == 'c') {
runvm = true;
} else if (c == 'g') {
runvm = true;
execaddr = true;
newaddr = PromptNewAddress("Address (0..FFFF): ");
cout << " [" << hex << newaddr << "]" << endl;
} else if (c == 'x') {
execvm = true;
execaddr = true;
newaddr = PromptNewAddress("Address (0..FFFF): ");
cout << " [" << hex << newaddr << "]" << endl;
} else if (c == 'q') {
break;
} else if (c == 'd') {
unsigned int addrbeg = 0x10000, addrend = 0x10000;
cout << "Enter address range (0..0xFFFF)..." << endl;
addrbeg = PromptNewAddress("Start address (0..FFFF): ");
cout << " [" << hex << addrbeg << "]" << endl;
addrend = PromptNewAddress("End address (0..FFFF): ");
cout << " [" << hex << addrend << "]" << endl;
cout << endl;
for (unsigned int addr = addrbeg; addr <= addrend; addr+=16) {
cout << "\t|";
for (unsigned int j=0; j < 16; j++) {
unsigned int hv = (unsigned int)pvm->MemPeek8bit(addr+j);
if (hv < 16) {
cout << 0;
}
cout << hex << hv << " ";
}
cout << "|";
for (int j=0; j < 16; j++) {
char cc = (char)pvm->MemPeek8bit(addr+j);
if (isprint(cc))
cout << cc;
else
cout << "?";
}
cout << '\r';
cout << hex << addr;
cout << endl;
}
}
}
}
catch (MKGenException& ex) {
cout << "ERROR: " << ex.GetCause() << endl;
}
catch (...) {
cout << "ERROR: Fatal." << endl;
}
return 0;
}

99
t_adc_bcd_01.65s Normal file
View File

@ -0,0 +1,99 @@
; ADC, test decimal mode.
;
; NV-BDIZC
; ??1110??
;
; The results I got on Rockwell 6502 AP
;
; 00 + 00 and C=0 gives 00 and N=0 V=0 Z=1 C=0 (3A)
; 79 + 00 and C=1 gives 80 and N=1 V=1 Z=0 C=0 (F8)
; 24 + 56 and C=0 gives 80 and N=1 V=1 Z=0 C=0 (F8)
; 93 + 82 and C=0 gives 75 and N=0 V=1 Z=0 C=1 (79)
; 89 + 76 and C=0 gives 65 and N=0 V=0 Z=0 C=1 (39)
; 89 + 76 and C=1 gives 66 and N=0 V=0 Z=0 C=1 (39)
; 80 + f0 and C=0 gives d0 and N=1 V=1 Z=0 C=1 (F9)
; 80 + fa and C=0 gives e0 and N=1 V=0 Z=0 C=1 (B9)
; 2f + 4f and C=0 gives 74 and N=0 V=0 Z=0 C=0 (38)
; 6f + 00 and C=1 gives 76 and N=0 V=0 Z=0 C=0 (38)
RES=$0300
*=$0200
SED
CLC
LDA #$00
ADC #$00
STA RES
PHP
PLA
STA RES+1
SEC
LDA #$79
ADC #$00
STA RES+2
PHP
PLA
STA RES+3
CLC
LDA #$24
ADC #$56
STA RES+4
PHP
PLA
STA RES+5
CLC
LDA #$93
ADC #$82
STA RES+6
PHP
PLA
STA RES+7
CLC
LDA #$89
ADC #$76
STA RES+8
PHP
PLA
STA RES+9
SEC
LDA #$89
ADC #$76
STA RES+10
PHP
PLA
STA RES+11
CLC
LDA #$80
ADC #$F0
STA RES+12
PHP
PLA
STA RES+13
CLC
LDA #$80
ADC #$FA
STA RES+14
PHP
PLA
STA RES+15
CLC
LDA #$2F
ADC #$4F
STA RES+16
PHP
PLA
STA RES+17
SEC
LDA #$6F
ADC #$00
STA RES+18
PHP
PLA
STA RES+19
BRK
*=$0300
.DS 20

36
t_adc_bcd_01.dat Normal file
View File

@ -0,0 +1,36 @@
; Test ADC BCD mode.
ORG
$0200
$F8 $18 $A9 $00 $69 $00 $8D $00
$03 $08 $68 $8D $01 $03 $38 $A9
$79 $69 $00 $8D $02 $03 $08 $68
$8D $03 $03 $18 $A9 $24 $69 $56
$8D $04 $03 $08 $68 $8D $05 $03
$18 $A9 $93 $69 $82 $8D $06 $03
$08 $68 $8D $07 $03 $18 $A9 $89
$69 $76 $8D $08 $03 $08 $68 $8D
$09 $03 $38 $A9 $89 $69 $76 $8D
$0A $03 $08 $68 $8D $0B $03 $18
$A9 $80 $69 $F0 $8D $0C $03 $08
$68 $8D $0D $03 $18 $A9 $80 $69
$FA $8D $0E $03 $08 $68 $8D $0F
$03 $18 $A9 $2F $69 $4F $8D $10
$03 $08 $68 $8D $11 $03 $38 $A9
$6F $69 $00 $8D $12 $03 $08 $68
$8D $13 $03 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00

85
t_sbc_bcd_01.65s Normal file
View File

@ -0,0 +1,85 @@
; SBC, test decimal mode.
;
; NV-BDIZC
; ??1110??
;
; Expected results (I got on Rockwell 6502 AP):
; 00 - 00 and C=0 gives 99 and N=1 V=0 Z=0 C=0 (B8)
; 00 - 00 and C=1 gives 00 and N=0 V=0 Z=1 C=1 (3B)
; 00 - 01 and C=1 gives 99 and N=1 V=0 Z=0 C=0 (B8)
; 0a - 00 and C=1 gives 0a and N=0 V=0 Z=0 C=1 (39)
; 0b - 00 and C=0 gives 0a and N=0 V=0 Z=0 C=1 (39)
; 9a - 00 and C=1 gives 9a and N=1 V=0 Z=0 C=1 (B9)
; 9b - 00 and C=0 gives 9a and N=1 V=0 Z=0 C=1 (B9)
;
*=$0200
SED
CLC
LDA #$00
SBC #$00
STA SBT1A
PHP
PLA
STA SBT1F
SEC
LDA #$00
SBC #$00
STA SBT2A
PHP
PLA
STA SBT2F
SEC
LDA #$00
SBC #$01
STA SBT3A
PHP
PLA
STA SBT3F
SEC
LDA #$0A
SBC #$00
STA SBT4A
PHP
PLA
STA SBT4F
CLC
LDA #$0B
SBC #$00
STA SBT5A
PHP
PLA
STA SBT5F
SEC
LDA #$9A
SBC #$00
STA SBT6A
PHP
PLA
STA SBT6F
CLC
LDA #$9B
SBC #$00
STA SBT7A
PHP
PLA
STA SBT7F
BRK
*=$0300
SBT1A: .DB 0
SBT1F: .DB 0
SBT2A: .DB 0
SBT2F: .DB 0
SBT3A: .DB 0
SBT3F: .DB 0
SBT4A: .DB 0
SBT4F: .DB 0
SBT5A: .DB 0
SBT5F: .DB 0
SBT6A: .DB 0
SBT6F: .DB 0
SBT7A: .DB 0
SBT7F: .DB 0

36
t_sbc_bcd_01.dat Normal file
View File

@ -0,0 +1,36 @@
; Test BCD mode.
ORG
$0200
$F8 $18 $A9 $00 $E9 $00 $8D $00
$03 $08 $68 $8D $01 $03 $38 $A9
$00 $E9 $00 $8D $02 $03 $08 $68
$8D $03 $03 $38 $A9 $00 $E9 $01
$8D $04 $03 $08 $68 $8D $05 $03
$38 $A9 $0A $E9 $00 $8D $06 $03
$08 $68 $8D $07 $03 $18 $A9 $0B
$E9 $00 $8D $08 $03 $08 $68 $8D
$09 $03 $38 $A9 $9A $E9 $00 $8D
$0A $03 $08 $68 $8D $0B $03 $18
$A9 $9B $E9 $00 $8D $0C $03 $08
$68 $8D $0D $03 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00

50
test_char_io_01.65s Normal file
View File

@ -0,0 +1,50 @@
; Basic test of char I/O emulation
.ORG $0200
CHRGET = $E000
PUTCH = $E000
TXTBUF = $0400
CR = $0D
NL = $0A
START: LDX #$00
PR1: LDA PROMPT,X ;print prompt
BEQ L0
STA PUTCH
INX
BNE PR1
L0: LDX #$00
GETTXT: LDA CHRGET ;get text from input
BEQ GETTXT
CMP #CR
BEQ L1
CMP #NL
BEQ L1
STA PUTCH ;echo char
STA TXTBUF,X ;store char
INX
BNE GETTXT
L1: LDA #NL ; add line break
STA TXTBUF,X
STA PUTCH
INX
LDA #CR
STA TXTBUF,X
STA PUTCH
INX
LDA #$00 ; add null
STA TXTBUF,X
TAX
PRINT: LDA TXTBUF,X ; print to output
BEQ L2
STA PUTCH
INX
BNE PRINT
L2: BRK
NOP
JMP START
PROMPT: .DB "Enter text:",0

15
test_char_io_01.dat Normal file
View File

@ -0,0 +1,15 @@
; I/O test for MKBASIC VM.
ORG
$0200
$A2 $00 $BD $4E $02 $F0 $06 $8D
$00 $E0 $E8 $D0 $F5 $A2 $00 $AD
$00 $E0 $F0 $FB $C9 $0D $F0 $0D
$C9 $0A $F0 $09 $8D $00 $E0 $9D
$00 $04 $E8 $D0 $EA $A9 $0A $9D
$00 $04 $8D $00 $E0 $E8 $A9 $0D
$9D $00 $04 $8D $00 $E0 $E8 $A9
$00 $9D $00 $04 $AA $BD $00 $04
$F0 $06 $8D $00 $E0 $E8 $D0 $F5
$00 $00 $EA $4C $00 $02 $45 $6E
$74 $65 $72 $20 $74 $65 $78 $74
$3A $00 $00 $00 $00 $00 $00 $00

925
testall.asm Normal file
View File

@ -0,0 +1,925 @@
.ORG $4000
start:
; EXPECTED FINAL RESULTS: $0210 = FF
; (any other number will be the
; test that failed)
; initialize:
LDA #$00
STA $0210
; store each test's expected
LDA #$55
STA $0200
LDA #$AA
STA $0201
LDA #$FF
STA $0202
LDA #$6E
STA $0203
LDA #$42
STA $0204
LDA #$33
STA $0205
LDA #$9D
STA $0206
LDA #$7F
STA $0207
LDA #$A5
STA $0208
LDA #$1F
STA $0209
LDA #$CE
STA $020A
LDA #$29
STA $020B
LDA #$42
STA $020C
LDA #$6C
STA $020D
LDA #$42
STA $020E
; expected result: $022A = 0x55
test00:
LDA #85
LDX #42
LDY #115
STA $81
LDA #$01
STA $61
LDA #$7E
LDA $81
STA $0910
LDA #$7E
LDA $0910
STA $56,X
LDA #$7E
LDA $56,X
STY $60
STA ($60),Y
LDA #$7E
LDA ($60),Y
STA $07ff,X
LDA #$7E
LDA $07ff,X
STA $07ff,Y
LDA #$7E
LDA $07ff,Y
STA ($36,X)
LDA #$7E
LDA ($36,X)
STX $50
LDX $60
LDY $50
STX $0913
LDX #$22
LDX $0913
STY $0914
LDY #$99
LDY $0914
STY $2D,X
STX $77,Y
LDY #$99
LDY $2D,X
LDX #$22
LDX $77,Y
LDY #$99
LDY $08A0,X
LDX #$22
LDX $08A1,Y
STA $0200,X
; CHECK test00:
LDA $022A
CMP $0200
BEQ test00pass
JMP theend
test00pass:
LDA #$FE
STA $0210
; expected result: $A9 = 0xAA
test01:
; imm
LDA #85
AND #83
ORA #56
EOR #17
; zpg
STA $99
LDA #185
STA $10
LDA #231
STA $11
LDA #57
STA $12
LDA $99
AND $10
ORA $11
EOR $12
; zpx
LDX #16
STA $99
LDA #188
STA $20
LDA #49
STA $21
LDA #23
STA $22
LDA $99
AND $10,X
ORA $11,X
EOR $12,X
; abs
STA $99
LDA #111
STA $0110
LDA #60
STA $0111
LDA #39
STA $0112
LDA $99
AND $0110
ORA $0111
EOR $0112
; abx
STA $99
LDA #138
STA $0120
LDA #71
STA $0121
LDA #143
STA $0122
LDA $99
AND $0110,X
ORA $0111,X
EOR $0112,X
; aby
LDY #32
STA $99
LDA #115
STA $0130
LDA #42
STA $0131
LDA #241
STA $0132
LDA $99
AND $0110,Y
ORA $0111,Y
EOR $0112,Y
; idx
STA $99
LDA #112
STA $30
LDA #$01
STA $31
LDA #113
STA $32
LDA #$01
STA $33
LDA #114
STA $34
LDA #$01
STA $35
LDA #197
STA $0170
LDA #124
STA $0171
LDA #161
STA $0172
LDA $99
AND ($20,X)
ORA ($22,X)
EOR ($24,X)
; idy
STA $99
LDA #96
STA $40
LDA #$01
STA $41
LDA #97
STA $42
LDA #$01
STA $43
LDA #98
STA $44
LDA #$01
STA $45
LDA #55
STA $0250
LDA #35
STA $0251
LDA #157
STA $0252
LDA $99
LDY #$F0
AND ($40),Y
ORA ($42),Y
EOR ($44),Y
STA $A9
; CHECK test01
LDA $A9
CMP $0201
BEQ test02
LDA #$01
STA $0210
JMP theend
; expected result: $71 = 0xFF
test02:
LDA #$FF
LDX #$00
STA $90
INC $90
INC $90
LDA $90
LDX $90
STA $90,X
INC $90,X
LDA $90,X
LDX $91
STA $0190,X
INC $0192
LDA $0190,X
LDX $0192
STA $0190,X
INC $0190,X
LDA $0190,X
LDX $0193
STA $0170,X
DEC $0170,X
LDA $0170,X
LDX $0174
STA $0170,X
DEC $0173
LDA $0170,X
LDX $0173
STA $70,X
DEC $70,X
LDA $70,X
LDX $72
STA $70,X
DEC $71
DEC $71
; CHECK test02
LDA $71
CMP $0202
BEQ test03
LDA #$02
STA $0210
JMP theend
; expected result: $01DD = 0x6E
test03:
LDA #$4B
LSR
ASL
STA $50
ASL $50
ASL $50
LSR $50
LDA $50
LDX $50
ORA #$C9
STA $60
ASL $4C,X
LSR $4C,X
LSR $4C,X
LDA $4C,X
LDX $60
ORA #$41
STA $012E
LSR $0100,X
LSR $0100,X
ASL $0100,X
LDA $0100,X
LDX $012E
ORA #$81
STA $0100,X
LSR $0136
LSR $0136
ASL $0136
LDA $0100,X
; rol & ror
ROL
ROL
ROR
STA $70
LDX $70
ORA #$03
STA $0C,X
ROL $C0
ROR $C0
ROR $C0
LDA $0C,X
LDX $C0
STA $D0
ROL $75,X
ROL $75,X
ROR $75,X
LDA $D0
LDX $D0
STA $0100,X
ROL $01B7
ROL $01B7
ROL $01B7
ROR $01B7
LDA $0100,X
LDX $01B7
STA $01DD
ROL $0100,X
ROR $0100,X
ROR $0100,X
; CHECK test03
LDA $01DD
CMP $0203
BEQ test04
LDA #$03
STA $0210
JMP theend
; expected result: $40 = 0x42
test04:
LDA #$E8 ;originally:#$7C
STA $20
LDA #$42 ;originally:#$02
STA $21
LDA #$00
ORA #$03
JMP jump1
ORA #$FF ; not done
jump1:
ORA #$30
JSR subr
ORA #$42
JMP ($0020)
ORA #$FF ; not done
subr:
STA $30
LDX $30
LDA #$00
RTS
final:
STA $0D,X
; CHECK test04
LDA $40
CMP $0204
BEQ test05
LDA #$04
STA $0210
JMP theend
; expected result: $40 = 0x33
test05:
LDA #$35
TAX
DEX
DEX
INX
TXA
TAY
DEY
DEY
INY
TYA
TAX
LDA #$20
TXS
LDX #$10
TSX
TXA
STA $40
; CHECK test05
LDA $40
CMP $0205
BEQ test06
LDA #$05
STA $0210
JMP theend
; expected result: $30 = 9D
test06:
; RESET TO CARRY FLAG = 0
ROL
LDA #$6A
STA $50
LDA #$6B
STA $51
LDA #$A1
STA $60
LDA #$A2
STA $61
LDA #$FF
ADC #$FF
ADC #$FF
SBC #$AE
STA $40
LDX $40
ADC $00,X
SBC $01,X
ADC $60
SBC $61
STA $0120
LDA #$4D
STA $0121
LDA #$23
ADC $0120
SBC $0121
STA $F0
LDX $F0
LDA #$64
STA $0124
LDA #$62
STA $0125
LDA #$26
ADC $0100,X
SBC $0101,X
STA $F1
LDY $F1
LDA #$E5
STA $0128
LDA #$E9
STA $0129
LDA #$34
ADC $0100,Y
SBC $0101,Y
STA $F2
LDX $F2
LDA #$20
STA $70
LDA #$01
STA $71
LDA #$24
STA $72
LDA #$01
STA $73
ADC ($41,X)
SBC ($3F,X)
STA $F3
LDY $F3
LDA #$DA
STA $80
LDA #$00
STA $81
LDA #$DC
STA $82
LDA #$00
STA $83
LDA #$AA
ADC ($80),Y
SBC ($82),Y
STA $30
; CHECK test06
LDA $30
CMP $0206
BEQ test07
LDA #$06
STA $0210
JMP theend
; expected result: $15 = 0x7F
test07:
; prepare memory
LDA #$00
STA $34
LDA #$FF
STA $0130
LDA #$99
STA $019D
LDA #$DB
STA $0199
LDA #$2F
STA $32
LDA #$32
STA $4F
LDA #$30
STA $33
LDA #$70
STA $AF
LDA #$18
STA $30
; imm
CMP #$18
BEQ beq1 ; taken
AND #$00 ; not done
beq1:
; zpg
ORA #$01
CMP $30
BNE bne1 ; taken
AND #$00 ; not done
bne1:
; abs
LDX #$00
CMP $0130
BEQ beq2 ; not taken
STA $40
LDX $40
beq2:
; zpx
CMP $27,X
BNE bne2 ; not taken
ORA #$84
STA $41
LDX $41
bne2:
; abx
AND #$DB
CMP $0100,X
BEQ beq3 ; taken
AND #$00 ; not done
beq3:
; aby
STA $42
LDY $42
AND #$00
CMP $0100,Y
BNE bne3 ; taken
ORA #$0F ; not done
bne3:
; idx
STA $43
LDX $43
ORA #$24
CMP ($40,X)
BEQ beq4 ; not taken
ORA #$7F
beq4:
; idy
STA $44
LDY $44
EOR #$0F
CMP ($33),Y
BNE bne4 ; not taken
LDA $44
STA $15
bne4:
; CHECK test07
LDA $15
CMP $0207
BEQ test08
LDA #$07
STA $0210
JMP theend
; expected result: $42 = 0xA5
test08:
; prepare memory
LDA #$A5
STA $20
STA $0120
LDA #$5A
STA $21
; cpx imm...
LDX #$A5
CPX #$A5
BEQ b1 ; taken
LDX #$01 ; not done
b1:
; cpx zpg...
CPX $20
BEQ b2 ; taken
LDX #$02 ; not done
b2:
; cpx abs...
CPX $0120
BEQ b3 ; taken
LDX #$03 ; not done
b3:
; cpy imm...
STX $30
LDY $30
CPY #$A5
BEQ b4 ; taken
LDY #$04 ; not done
b4:
; cpy zpg...
CPY $20
BEQ b5 ; taken
LDY #$05 ; not done
b5:
; cpy abs...
CPY $0120
BEQ b6 ; taken
LDY #$06 ; not done
b6:
; bit zpg...
STY $31
LDA $31
BIT $20
BNE b7 ; taken
LDA #$07 ; not done
b7:
; bit abs...
BIT $0120
BNE b8 ; taken
LDA #$08 ; not done
b8:
BIT $21
BNE b9 ; not taken
STA $42
b9:
; CHECK test08
LDA $42
CMP $0208
BEQ test09
LDA #$08
STA $0210
JMP theend
; expected result: $80 = 0x1F
test09:
; prepare memory
LDA #$54
STA $32
LDA #$B3
STA $A1
LDA #$87
STA $43
; BPL
LDX #$A1
BPL bpl1 ; not taken
LDX #$32
bpl1:
LDY $00,X
BPL bpl2 ; taken
LDA #$05 ; not done
LDX $A1 ; not done
bpl2:
; BMI
BMI bmi1 ; not taken
SBC #$03
bmi1:
BMI bmi2 ; taken
LDA #$41 ; not done
bmi2:
; BVC
EOR #$30
STA $32
ADC $00,X
BVC bvc1 ; not taken
LDA #$03
bvc1:
STA $54
LDX $00,Y
ADC $51,X
BVC bvc2 ; taken
LDA #$E5 ; not done
bvc2:
; BVS
ADC $40,X
BVS bvs1 ; not taken
STA $0001,Y
ADC $55
bvs1:
BVS bvs2 ; taken
LDA #$00
bvs2:
; BCC
ADC #$F0
BCC bcc1 ; not taken
STA $60
ADC $43
bcc1:
BCC bcc2 ; taken
LDA #$FF
bcc2:
; BCS
ADC $54
BCS bcs1 ; not taken
ADC #$87
LDX $60
bcs1:
BCS bcs2 ; taken
LDA #$00 ; not done
bcs2:
STA $73,X
; CHECK test09
LDA $80
CMP $0209
BEQ test10
LDA #$09
STA $0210
JMP theend
; expected result: $30 = 0xCE
test10:
; RESET TO CARRY = 0 & OVERFLOW = 0
ADC #$00
LDA #$99
ADC #$87
CLC
NOP
BCC t10bcc1 ; taken
ADC #$60 ; not done
ADC #$93 ; not done
t10bcc1:
SEC
NOP
BCC t10bcc2 ; not taken
CLV
t10bcc2:
BVC t10bvc1 ; taken
LDA #$00 ; not done
t10bvc1:
ADC #$AD
NOP
STA $30
; CHECK test10
LDA $30
CMP $020A
BEQ test11
LDA #$0A
STA $0210
JMP theend
; expected result: $30 = 0x29
test11:
; RESET TO CARRY = 0 & ZERO = 0
ADC #$01
LDA #$27
ADC #$01
SEC
PHP
CLC
PLP
ADC #$00
PHA
LDA #$00
PLA
STA $30
; CHECK test11
LDA $30
CMP $020B
BEQ test12
LDA #$0B
STA $0210
JMP theend
; expected result: $33 = 0x42
test12:
CLC
LDA #$42
BCC runstuff
STA $33
BCS t12end
runstuff:
LDA #$45
PHA
LDA #$61
PHA
SEC
PHP
CLC
RTI
t12end:
; CHECK test12
LDA $33
CMP $020C
BEQ test13
LDA #$0C
STA $0210
JMP theend
; expected result: $21 = 0x6C (simulator)
; $21 = 0x0C (ours)
test13:
; RESET TO CARRY = 0 & ZERO = 0
ADC #$01
SEI
SED
PHP
PLA
STA $20
CLI
CLD
PHP
PLA
ADC $20
STA $21
; CHECK test13
LDA $21
CMP $020D
BEQ test14
LDA #$0D
STA $0210
JMP theend
; expect result: $60 = 0x42
test14:
; !!! NOTICE: BRK doesn't work in this
; simulator, so commented instructions
; are what should be executed...
;JMP pass_intrp
LDA #$41
STA $60
;RTI
;pass_intrp:
;LDA #$FF
;STA $60
;BRK (two bytes)
INC $60
; CHECK test14
LDA $60
CMP $020E
BEQ suiteafinal
LDA #$0E
STA $0210
JMP theend
suiteafinal:
; IF $0210 == 0xFE, INCREMENT
; (checking that it didn't
; happen to wander off and
; not run our instructions
; to say which tests failed...)
LDA #$FE
CMP $0210
BNE theend
INC $0210
theend:
BRK
;JMP theend

195
testall.dat Normal file
View File

@ -0,0 +1,195 @@
; Test 6502 emulation.
ORG
$4000
$A9 $00 $8D $10 $02 $A9 $55 $8D
$00 $02 $A9 $AA $8D $01 $02 $A9
$FF $8D $02 $02 $A9 $6E $8D $03
$02 $A9 $42 $8D $04 $02 $A9 $33
$8D $05 $02 $A9 $9D $8D $06 $02
$A9 $7F $8D $07 $02 $A9 $A5 $8D
$08 $02 $A9 $1F $8D $09 $02 $A9
$CE $8D $0A $02 $A9 $29 $8D $0B
$02 $A9 $42 $8D $0C $02 $A9 $6C
$8D $0D $02 $A9 $42 $8D $0E $02
$A9 $55 $A2 $2A $A0 $73 $85 $81
$A9 $01 $85 $61 $A9 $7E $A5 $81
$8D $10 $09 $A9 $7E $AD $10 $09
$95 $56 $A9 $7E $B5 $56 $84 $60
$91 $60 $A9 $7E $B1 $60 $9D $FF
$07 $A9 $7E $BD $FF $07 $99 $FF
$07 $A9 $7E $B9 $FF $07 $81 $36
$A9 $7E $A1 $36 $86 $50 $A6 $60
$A4 $50 $8E $13 $09 $A2 $22 $AE
$13 $09 $8C $14 $09 $A0 $99 $AC
$14 $09 $94 $2D $96 $77 $A0 $99
$B4 $2D $A2 $22 $B6 $77 $A0 $99
$BC $A0 $08 $A2 $22 $BE $A1 $08
$9D $00 $02 $AD $2A $02 $CD $00
$02 $F0 $03 $4C $C0 $45 $A9 $FE
$8D $10 $02 $A9 $55 $29 $53 $09
$38 $49 $11 $85 $99 $A9 $B9 $85
$10 $A9 $E7 $85 $11 $A9 $39 $85
$12 $A5 $99 $25 $10 $05 $11 $45
$12 $A2 $10 $85 $99 $A9 $BC $85
$20 $A9 $31 $85 $21 $A9 $17 $85
$22 $A5 $99 $35 $10 $15 $11 $55
$12 $85 $99 $A9 $6F $8D $10 $01
$A9 $3C $8D $11 $01 $A9 $27 $8D
$12 $01 $A5 $99 $2D $10 $01 $0D
$11 $01 $4D $12 $01 $85 $99 $A9
$8A $8D $20 $01 $A9 $47 $8D $21
$01 $A9 $8F $8D $22 $01 $A5 $99
$3D $10 $01 $1D $11 $01 $5D $12
$01 $A0 $20 $85 $99 $A9 $73 $8D
$30 $01 $A9 $2A $8D $31 $01 $A9
$F1 $8D $32 $01 $A5 $99 $39 $10
$01 $19 $11 $01 $59 $12 $01 $85
$99 $A9 $70 $85 $30 $A9 $01 $85
$31 $A9 $71 $85 $32 $A9 $01 $85
$33 $A9 $72 $85 $34 $A9 $01 $85
$35 $A9 $C5 $8D $70 $01 $A9 $7C
$8D $71 $01 $A9 $A1 $8D $72 $01
$A5 $99 $21 $20 $01 $22 $41 $24
$85 $99 $A9 $60 $85 $40 $A9 $01
$85 $41 $A9 $61 $85 $42 $A9 $01
$85 $43 $A9 $62 $85 $44 $A9 $01
$85 $45 $A9 $37 $8D $50 $02 $A9
$23 $8D $51 $02 $A9 $9D $8D $52
$02 $A5 $99 $A0 $F0 $31 $40 $11
$42 $51 $44 $85 $A9 $A5 $A9 $CD
$01 $02 $F0 $08 $A9 $01 $8D $10
$02 $4C $C0 $45 $A9 $FF $A2 $00
$85 $90 $E6 $90 $E6 $90 $A5 $90
$A6 $90 $95 $90 $F6 $90 $B5 $90
$A6 $91 $9D $90 $01 $EE $92 $01
$BD $90 $01 $AE $92 $01 $9D $90
$01 $FE $90 $01 $BD $90 $01 $AE
$93 $01 $9D $70 $01 $DE $70 $01
$BD $70 $01 $AE $74 $01 $9D $70
$01 $CE $73 $01 $BD $70 $01 $AE
$73 $01 $95 $70 $D6 $70 $B5 $70
$A6 $72 $95 $70 $C6 $71 $C6 $71
$A5 $71 $CD $02 $02 $F0 $08 $A9
$02 $8D $10 $02 $4C $C0 $45 $A9
$4B $4A $0A $85 $50 $06 $50 $06
$50 $46 $50 $A5 $50 $A6 $50 $09
$C9 $85 $60 $16 $4C $56 $4C $56
$4C $B5 $4C $A6 $60 $09 $41 $8D
$2E $01 $5E $00 $01 $5E $00 $01
$1E $00 $01 $BD $00 $01 $AE $2E
$01 $09 $81 $9D $00 $01 $4E $36
$01 $4E $36 $01 $0E $36 $01 $BD
$00 $01 $2A $2A $6A $85 $70 $A6
$70 $09 $03 $95 $0C $26 $C0 $66
$C0 $66 $C0 $B5 $0C $A6 $C0 $85
$D0 $36 $75 $36 $75 $76 $75 $A5
$D0 $A6 $D0 $9D $00 $01 $2E $B7
$01 $2E $B7 $01 $2E $B7 $01 $6E
$B7 $01 $BD $00 $01 $AE $B7 $01
$8D $DD $01 $3E $00 $01 $7E $00
$01 $7E $00 $01 $AD $DD $01 $CD
$03 $02 $F0 $08 $A9 $03 $8D $10
$02 $4C $C0 $45 $A9 $E8 $85 $20
$A9 $42 $85 $21 $A9 $00 $09 $03
$4C $D5 $42 $09 $FF $09 $30 $20
$E1 $42 $09 $42 $6C $20 $00 $09
$FF $85 $30 $A6 $30 $A9 $00 $60
$95 $0D $A5 $40 $CD $04 $02 $F0
$08 $A9 $04 $8D $10 $02 $4C $C0
$45 $A9 $35 $AA $CA $CA $E8 $8A
$A8 $88 $88 $C8 $98 $AA $A9 $20
$9A $A2 $10 $BA $8A $85 $40 $A5
$40 $CD $05 $02 $F0 $08 $A9 $05
$8D $10 $02 $4C $C0 $45 $2A $A9
$6A $85 $50 $A9 $6B $85 $51 $A9
$A1 $85 $60 $A9 $A2 $85 $61 $A9
$FF $69 $FF $69 $FF $E9 $AE $85
$40 $A6 $40 $75 $00 $F5 $01 $65
$60 $E5 $61 $8D $20 $01 $A9 $4D
$8D $21 $01 $A9 $23 $6D $20 $01
$ED $21 $01 $85 $F0 $A6 $F0 $A9
$64 $8D $24 $01 $A9 $62 $8D $25
$01 $A9 $26 $7D $00 $01 $FD $01
$01 $85 $F1 $A4 $F1 $A9 $E5 $8D
$28 $01 $A9 $E9 $8D $29 $01 $A9
$34 $79 $00 $01 $F9 $01 $01 $85
$F2 $A6 $F2 $A9 $20 $85 $70 $A9
$01 $85 $71 $A9 $24 $85 $72 $A9
$01 $85 $73 $61 $41 $E1 $3F $85
$F3 $A4 $F3 $A9 $DA $85 $80 $A9
$00 $85 $81 $A9 $DC $85 $82 $A9
$00 $85 $83 $A9 $AA $71 $80 $F1
$82 $85 $30 $A5 $30 $CD $06 $02
$F0 $08 $A9 $06 $8D $10 $02 $4C
$C0 $45 $A9 $00 $85 $34 $A9 $FF
$8D $30 $01 $A9 $99 $8D $9D $01
$A9 $DB $8D $99 $01 $A9 $2F $85
$32 $A9 $32 $85 $4F $A9 $30 $85
$33 $A9 $70 $85 $AF $A9 $18 $85
$30 $C9 $18 $F0 $02 $29 $00 $09
$01 $C5 $30 $D0 $02 $29 $00 $A2
$00 $CD $30 $01 $F0 $04 $85 $40
$A6 $40 $D5 $27 $D0 $06 $09 $84
$85 $41 $A6 $41 $29 $DB $DD $00
$01 $F0 $02 $29 $00 $85 $42 $A4
$42 $29 $00 $D9 $00 $01 $D0 $02
$09 $0F $85 $43 $A6 $43 $09 $24
$C1 $40 $F0 $02 $09 $7F $85 $44
$A4 $44 $49 $0F $D1 $33 $D0 $04
$A5 $44 $85 $15 $A5 $15 $CD $07
$02 $F0 $08 $A9 $07 $8D $10 $02
$4C $C0 $45 $A9 $A5 $85 $20 $8D
$20 $01 $A9 $5A $85 $21 $A2 $A5
$E0 $A5 $F0 $02 $A2 $01 $E4 $20
$F0 $02 $A2 $02 $EC $20 $01 $F0
$02 $A2 $03 $86 $30 $A4 $30 $C0
$A5 $F0 $02 $A0 $04 $C4 $20 $F0
$02 $A0 $05 $CC $20 $01 $F0 $02
$A0 $06 $84 $31 $A5 $31 $24 $20
$D0 $02 $A9 $07 $2C $20 $01 $D0
$02 $A9 $08 $24 $21 $D0 $02 $85
$42 $A5 $42 $CD $08 $02 $F0 $08
$A9 $08 $8D $10 $02 $4C $C0 $45
$A9 $54 $85 $32 $A9 $B3 $85 $A1
$A9 $87 $85 $43 $A2 $A1 $10 $02
$A2 $32 $B4 $00 $10 $04 $A9 $05
$A6 $A1 $30 $02 $E9 $03 $30 $02
$A9 $41 $49 $30 $85 $32 $75 $00
$50 $02 $A9 $03 $85 $54 $B6 $00
$75 $51 $50 $02 $A9 $E5 $75 $40
$70 $05 $99 $01 $00 $65 $55 $70
$02 $A9 $00 $69 $F0 $90 $04 $85
$60 $65 $43 $90 $02 $A9 $FF $65
$54 $B0 $04 $69 $87 $A6 $60 $B0
$02 $A9 $00 $95 $73 $A5 $80 $CD
$09 $02 $F0 $08 $A9 $09 $8D $10
$02 $4C $C0 $45 $69 $00 $A9 $99
$69 $87 $18 $EA $90 $04 $69 $60
$69 $93 $38 $EA $90 $01 $B8 $50
$02 $A9 $00 $69 $AD $EA $85 $30
$A5 $30 $CD $0A $02 $F0 $08 $A9
$0A $8D $10 $02 $4C $C0 $45 $69
$01 $A9 $27 $69 $01 $38 $08 $18
$28 $69 $00 $48 $A9 $00 $68 $85
$30 $A5 $30 $CD $0B $02 $F0 $08
$A9 $0B $8D $10 $02 $4C $C0 $45
$18 $A9 $42 $90 $04 $85 $33 $B0
$0A $A9 $45 $48 $A9 $61 $48 $38
$08 $18 $40 $A5 $33 $CD $0C $02
$F0 $08 $A9 $0C $8D $10 $02 $4C
$C0 $45 $69 $01 $78 $F8 $08 $68
$85 $20 $58 $D8 $08 $68 $65 $20
$85 $21 $A5 $21 $CD $0D $02 $F0
$08 $A9 $0D $8D $10 $02 $4C $C0
$45 $A9 $41 $85 $60 $E6 $60 $A5
$60 $CD $0E $02 $F0 $08 $A9 $0E
$8D $10 $02 $4C $C0 $45 $A9 $FE
$CD $10 $02 $D0 $03 $EE $10 $02
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00

69
testbcd.dat Normal file
View File

@ -0,0 +1,69 @@
; Program disassembly from $0400 to $0600 2/9/2016
; Test BCD mode.
ORG
$0400
$A0 $01 $8C $04 $03 $A9 $00 $8D
$07 $03 $8D $0A $03 $AD $0A $03
$29 $0F $8D $0B $03 $AD $0A $03
$29 $F0 $8D $0F $03 $09 $0F $8D
$10 $03 $AD $07 $03 $29 $0F $8D
$09 $03 $AD $07 $03 $29 $F0 $8D
$08 $03 $20 $5E $04 $20 $47 $05
$20 $18 $05 $D0 $1D $20 $B1 $04
$20 $54 $05 $20 $18 $05 $D0 $12
$EE $07 $03 $D0 $D5 $EE $0A $03
$D0 $BB $88 $10 $B8 $A9 $00 $8D
$04 $03 $00 $00 $00 $00 $F8 $C0
$01 $AD $07 $03 $6D $0A $03 $8D
$02 $03 $08 $68 $8D $03 $03 $D8
$C0 $01 $AD $07 $03 $6D $0A $03
$8D $05 $03 $08 $68 $8D $06 $03
$C0 $01 $AD $09 $03 $6D $0B $03
$C9 $0A $A2 $00 $90 $06 $E8 $69
$05 $29 $0F $38 $0D $08 $03 $7D
$0F $03 $08 $B0 $04 $C9 $A0 $90
$03 $69 $5F $38 $8D $00 $03 $08
$68 $8D $01 $03 $68 $8D $0D $03
$60 $F8 $C0 $01 $AD $07 $03 $ED
$0A $03 $8D $02 $03 $08 $68 $8D
$03 $03 $D8 $C0 $01 $AD $07 $03
$ED $0A $03 $8D $05 $03 $08 $68
$8D $06 $03 $60 $C0 $01 $AD $09
$03 $ED $0B $03 $A2 $00 $B0 $06
$E8 $E9 $05 $29 $0F $18 $0D $08
$03 $FD $0F $03 $B0 $02 $E9 $5F
$8D $00 $03 $60 $C0 $01 $AD $09
$03 $ED $0B $03 $A2 $00 $B0 $04
$E8 $29 $0F $18 $0D $08 $03 $FD
$0F $03 $B0 $02 $E9 $5F $E0 $00
$F0 $02 $E9 $06 $8D $00 $03 $60
$AD $02 $03 $CD $00 $03 $D0 $26
$AD $03 $03 $4D $0C $03 $29 $80
$D0 $1C $AD $03 $03 $4D $0D $03
$29 $40 $D0 $12 $AD $03 $03 $4D
$0E $03 $29 $02 $D0 $08 $AD $03
$03 $4D $01 $03 $29 $01 $60 $AD
$0D $03 $8D $0C $03 $AD $06 $03
$8D $0E $03 $60 $20 $D4 $04 $AD
$06 $03 $8D $0C $03 $8D $0D $03
$8D $0E $03 $8D $01 $03 $60 $AD
$00 $03 $08 $68 $8D $0C $03 $8D
$0E $03 $60 $20 $F4 $04 $AD $00
$03 $08 $68 $8D $0C $03 $8D $0E
$03 $AD $06 $03 $8D $0D $03 $8D
$01 $03 $60 $AD $00 $03 $08 $68
$8D $0C $03 $8D $0E $03 $60 $20
$D4 $04 $AD $00 $03 $08 $68 $8D
$0C $03 $8D $0E $03 $AD $06 $03
$8D $0D $03 $8D $01 $03 $60 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00

1496
tinybasic.asm Normal file

File diff suppressed because it is too large Load Diff

774
tinybasic.dat Normal file
View File

@ -0,0 +1,774 @@
; Tiny Basic for MKBASIC 6502 emulator.
; Run address: $0CF0
; I/O emulation: $E000
ORG
$0400
$4C $85 $04 $4C $BD $04 $4C $2C
$0F $4C $31 $0F $EA $18 $60 $5F
$18 $80 $00 $20 $86 $C3 $90 $05
$86 $C3 $91 $C2 $60 $B1 $C2 $A0
$00 $60 $62 $05 $64 $05 $D8 $05
$05 $06 $33 $06 $FD $05 $9F $07
$42 $0B $3F $0B $7A $07 $FC $08
$95 $07 $9F $07 $9F $07 $BD $0A
$C1 $0A $8A $0A $9B $0A $E9 $0A
$61 $07 $51 $07 $41 $0A $52 $0A
$4F $0A $62 $0A $E7 $09 $CD $06
$06 $07 $9F $07 $15 $08 $A7 $07
$B7 $06 $BF $06 $83 $08 $A1 $06
$9F $07 $9F $07 $A8 $08 $4F $0B
$4D $0B $07 $09 $AA $04 $37 $07
$BD $04 $1B $0B $B1 $0A $20 $41
$54 $20 $80 $70 $0B $A9 $00 $85
$20 $85 $22 $A9 $1C $85 $21 $85
$23 $A0 $01 $B1 $22 $AA $49 $FF
$91 $22 $D1 $22 $08 $8A $91 $22
$E6 $22 $D0 $02 $E6 $23 $28 $F0
$EA $88 $D8 $A5 $20 $6D $13 $04
$85 $24 $98 $65 $21 $85 $25 $98
$91 $20 $C8 $91 $20 $A5 $22 $85
$C6 $85 $26 $A5 $23 $85 $C7 $85
$27 $20 $87 $08 $AD $83 $04 $85
$2A $AD $84 $04 $85 $2B $A9 $80
$85 $C1 $A9 $30 $85 $C0 $A2 $00
$86 $BE $86 $C2 $CA $9A $D8 $20
$F9 $06 $20 $F2 $04 $4C $E6 $04
$83 $65 $C9 $30 $B0 $7B $C9 $08
$90 $0C $0A $AA $BD $1F $04 $48
$BD $1E $04 $48 $08 $40 $65 $C1
$AA $B1 $C1 $48 $B5 $00 $91 $C1
$68 $95 $00 $60 $20 $87 $08 $A9
$21 $20 $09 $04 $A5 $2A $38 $ED
$83 $04 $AA $A5 $2B $ED $84 $04
$20 $A0 $07 $A5 $BE $F0 $12 $A9
$7E $85 $2A $A9 $20 $85 $2B $20
$A1 $06 $A6 $28 $A5 $29 $20 $A0
$07 $A9 $07 $20 $09 $04 $20 $87
$08 $A5 $26 $85 $C6 $A5 $27 $85
$C7 $4C $CC $04 $A2 $7C $E4 $C1
$90 $BA $A6 $C1 $E6 $C1 $E6 $C1
$18 $60 $C6 $BD $A5 $BD $F0 $AC
$A5 $BC $85 $2A $A5 $BD $85 $2B
$60 $C9 $40 $B0 $43 $48 $20 $F9
$06 $6D $83 $04 $85 $BC $68 $48
$29 $07 $6D $84 $04 $85 $BD $68
$29 $08 $D0 $DC $A5 $BC $A6 $2A
$85 $2A $86 $BC $A5 $BD $A6 $2B
$85 $2B $86 $BD $A5 $C6 $E9 $01
$85 $C6 $B0 $02 $C6 $C7 $C5 $24
$A5 $C7 $E5 $25 $90 $AA $A5 $BC
$91 $C6 $C8 $A5 $BD $91 $C6 $60
$48 $4A $4A $4A $4A $29 $0E $AA
$68 $C9 $60 $29 $1F $B0 $02 $09
$E0 $18 $F0 $07 $65 $2A $85 $BC
$98 $65 $2B $85 $BD $4C $FC $04
$A5 $2C $85 $B8 $A5 $2D $85 $B9
$20 $25 $06 $20 $14 $06 $51 $2A
$AA $20 $F9 $06 $8A $F0 $F1 $0A
$F0 $12 $A5 $B8 $85 $2C $A5 $B9
$85 $2D $4C $64 $05 $20 $25 $06
$C9 $0D $D0 $F6 $60 $20 $25 $06
$C9 $5B $B0 $EE $C9 $41 $90 $EA
$0A $20 $87 $07 $A0 $00 $B1 $2C
$E6 $2C $D0 $02 $E6 $2D $C9 $0D
$18 $60 $20 $14 $06 $B1 $2C $C9
$20 $F0 $F7 $C9 $3A $18 $10 $02
$C9 $30 $60 $20 $25 $06 $90 $C2
$84 $BC $84 $BD $A5 $BC $A6 $BD
$06 $BC $26 $BD $06 $BC $26 $BD
$18 $65 $BC $85 $BC $8A $65 $BD
$06 $BC $2A $85 $BD $20 $14 $06
$29 $0F $65 $BC $85 $BC $98 $65
$BD $85 $BD $20 $25 $06 $B0 $D4
$4C $80 $07 $20 $FC $08 $A5 $BC
$05 $BD $F0 $48 $A5 $20 $85 $2C
$A5 $21 $85 $2D $20 $6D $07 $F0
$12 $A5 $28 $C5 $BC $A5 $29 $E5
$BD $B0 $08 $20 $14 $06 $D0 $FB
$4C $7C $06 $A5 $28 $45 $BC $D0
$04 $A5 $29 $45 $BD $60 $20 $A6
$06 $20 $F9 $06 $10 $F8 $E6 $BF
$30 $03 $4C $09 $04 $C6 $BF $60
$C9 $22 $F0 $FB $20 $A6 $06 $20
$14 $06 $D0 $F4 $4C $14 $05 $A9
$20 $20 $A6 $06 $A5 $BF $29 $87
$30 $E5 $D0 $F3 $60 $A2 $7B $20
$56 $05 $E6 $C1 $E6 $C1 $E6 $C1
$38 $B5 $03 $F5 $00 $95 $00 $B5
$04 $F5 $01 $50 $04 $49 $80 $09
$01 $30 $0A $D0 $04 $15 $00 $F0
$02 $56 $02 $56 $02 $56 $02 $90
$0C $A0 $00 $B1 $2A $E6 $2A $D0
$02 $E6 $2B $09 $00 $60 $A5 $BE
$F0 $28 $20 $14 $06 $D0 $FB $20
$6D $07 $F0 $1B $20 $4C $07 $20
$0C $04 $B0 $09 $A5 $C4 $85 $2A
$A5 $C5 $85 $2B $60 $AD $83 $04
$85 $2A $AD $84 $04 $85 $2B $4C
$14 $05 $85 $BF $4C $49 $05 $A5
$20 $85 $2C $A5 $21 $85 $2D $20
$6D $07 $F0 $EB $A5 $2A $85 $C4
$A5 $2B $85 $C5 $A9 $01 $85 $BE
$60 $20 $6B $06 $F0 $BE $A5 $BC
$85 $28 $A5 $BD $85 $29 $4C $14
$05 $20 $FD $0A $20 $FA $0A $20
$74 $06 $D0 $EA $60 $20 $14 $06
$85 $28 $20 $14 $06 $85 $29 $05
$28 $60 $20 $FC $08 $20 $80 $07
$A5 $BD $20 $87 $07 $A5 $BC $A6
$C1 $CA $95 $00 $86 $C1 $E4 $C0
$D0 $0D $4C $14 $05 $A6 $C1 $E0
$80 $10 $F7 $B5 $00 $E6 $C1 $60
$85 $BD $86 $BC $4C $B8 $07 $A6
$C1 $B5 $01 $10 $08 $20 $41 $0A
$A9 $2D $20 $A6 $06 $20 $FC $08
$A9 $1F $85 $B8 $85 $BA $A9 $2A
$85 $B9 $85 $BB $A6 $BC $A4 $BD
$38 $E6 $B8 $8A $E9 $10 $AA $98
$E9 $27 $A8 $B0 $F4 $C6 $B9 $8A
$69 $E8 $AA $98 $69 $03 $A8 $90
$F4 $8A $38 $E6 $BA $E9 $64 $B0
$F9 $88 $10 $F6 $C6 $BB $69 $0A
$90 $FA $09 $30 $85 $BC $A9 $20
$85 $BD $A2 $FB $86 $C3 $B5 $BD
$05 $BD $C9 $20 $F0 $09 $A0 $30
$84 $BD $05 $BD $20 $A6 $06 $A6
$C3 $E8 $D0 $E8 $60 $A5 $2D $48
$A5 $2C $48 $A5 $20 $85 $2C $A5
$21 $85 $2D $A5 $24 $A6 $25 $20
$5B $08 $F0 $03 $20 $5B $08 $A5
$2C $38 $E5 $B6 $A5 $2D $E5 $B7
$B0 $42 $20 $6D $07 $F0 $3D $A6
$28 $A5 $29 $20 $A0 $07 $A9 $20
$20 $A6 $06 $20 $0C $04 $B0 $2C
$20 $14 $06 $D0 $F3 $20 $83 $08
$4C $2F $08 $85 $B6 $E6 $B6 $D0
$01 $E8 $86 $B7 $A4 $C1 $C0 $80
$F0 $18 $20 $6B $06 $A5 $2C $A6
$2D $38 $E9 $02 $B0 $01 $CA $85
$2C $4C $48 $0B $68 $85 $2C $68
$85 $2D $60 $A5 $BF $30 $FB $A9
$0D $20 $09 $04 $AD $11 $04 $29
$7F $85 $BF $F0 $07 $20 $64 $0B
$C6 $BF $D0 $F9 $A9 $0A $4C $61
$0B $AC $12 $04 $84 $BF $B0 $0B
$A9 $30 $85 $2C $85 $C0 $84 $2D
$20 $80 $07 $45 $80 $85 $80 $20
$06 $04 $A0 $00 $A6 $C0 $29 $7F
$F0 $F1 $C9 $7F $F0 $ED $C9 $13
$F0 $DA $C9 $0A $F0 $D3 $CD $10
$04 $F0 $09 $CD $0F $04 $D0 $0A
$E0 $30 $D0 $16 $A6 $2C $84 $BF
$A9 $0D $E4 $C1 $30 $08 $A9 $07
$20 $A6 $06 $4C $B3 $08 $95 $00
$E8 $E8 $CA $86 $C0 $C9 $0D $D0
$BA $20 $83 $08 $20 $95 $07 $85
$BC $20 $95 $07 $85 $BD $60 $20
$D6 $0A $20 $6B $06 $08 $20 $6D
$08 $85 $B8 $86 $B9 $A5 $BC $85
$B6 $A5 $BD $85 $B7 $A2 $00 $28
$D0 $0B $20 $6D $07 $CA $CA $CA
$20 $14 $06 $D0 $FA $84 $28 $84
$29 $20 $D6 $0A $A9 $0D $D1 $2C
$F0 $11 $E8 $E8 $E8 $E8 $C8 $D1
$2C $D0 $FA $A5 $B6 $85 $28 $A5
$B7 $85 $29 $A5 $B8 $85 $BC $A5
$B9 $85 $BD $18 $A0 $00 $8A $F0
$6E $10 $29 $65 $2E $85 $B8 $A5
$2F $E9 $00 $85 $B9 $B1 $2E $91
$B8 $A6 $2E $E4 $24 $D0 $06 $A5
$2F $C5 $25 $F0 $4A $E8 $86 $2E
$D0 $02 $E6 $2F $E6 $B8 $D0 $E5
$E6 $B9 $D0 $E1 $65 $24 $85 $B8
$85 $2E $98 $65 $25 $85 $B9 $85
$2F $A5 $2E $E5 $C6 $A5 $2F $E5
$C7 $90 $05 $C6 $2A $4C $14 $05
$B1 $24 $91 $2E $A6 $24 $D0 $02
$C6 $25 $C6 $24 $A6 $2E $D0 $02
$C6 $2F $CA $86 $2E $E4 $BC $D0
$E7 $A6 $2F $E4 $BD $D0 $E1 $A5
$B8 $85 $24 $A5 $B9 $85 $25 $A5
$28 $05 $29 $F0 $17 $A5 $28 $91
$BC $C8 $A5 $29 $91 $BC $C8 $84
$B6 $20 $14 $06 $08 $A4 $B6 $91
$BC $28 $D0 $F2 $4C $CC $04 $20
$54 $05 $B5 $03 $29 $80 $F0 $02
$A9 $FF $85 $BC $85 $BD $48 $75
$02 $95 $02 $68 $48 $75 $03 $95
$03 $68 $55 $01 $85 $BB $10 $03
$20 $43 $0A $A0 $11 $B5 $00 $15
$01 $D0 $03 $4C $14 $05 $38 $A5
$BC $F5 $00 $48 $A5 $BD $F5 $01
$48 $45 $BD $30 $0A $68 $85 $BD
$68 $85 $BC $38 $4C $32 $0A $68
$68 $18 $36 $02 $36 $03 $26 $BC
$26 $BD $88 $D0 $D9 $A5 $BB $10
$0D $A6 $C1 $38 $98 $F5 $00 $95
$00 $98 $F5 $01 $95 $01 $60 $20
$41 $0A $20 $54 $05 $B5 $00 $75
$02 $95 $02 $B5 $01 $75 $03 $95
$03 $60 $20 $54 $05 $A0 $10 $B5
$02 $85 $BC $B5 $03 $85 $BD $16
$02 $36 $03 $26 $BC $26 $BD $90
$0D $18 $B5 $02 $75 $00 $95 $02
$B5 $03 $75 $01 $95 $03 $88 $D0
$E6 $60 $20 $95 $07 $AA $B5 $00
$B4 $01 $C6 $C1 $A6 $C1 $94 $00
$4C $87 $07 $A2 $7D $20 $56 $05
$B5 $01 $48 $B5 $00 $48 $20 $95
$07 $AA $68 $95 $00 $68 $95 $01
$60 $20 $FD $0A $A5 $BC $85 $2A
$A5 $BD $85 $2B $60 $A2 $2C $D0
$02 $A2 $2E $B5 $00 $C9 $80 $B0
$0D $B5 $01 $D0 $09 $A5 $2C $85
$2E $A5 $2D $85 $2F $60 $A5 $2C
$A4 $2E $84 $2C $85 $2E $A5 $2D
$A4 $2F $84 $2D $85 $2F $A0 $00
$60 $A5 $28 $85 $BC $A5 $29 $85
$BD $20 $9C $05 $A5 $C6 $85 $26
$A5 $C7 $85 $27 $60 $B1 $C6 $85
$BC $20 $08 $0B $B1 $C6 $85 $BD
$E6 $C6 $D0 $02 $E6 $C7 $A5 $22
$C5 $C6 $A5 $23 $E5 $C7 $B0 $E4
$4C $14 $05 $20 $24 $0B $85 $BC
$98 $4C $82 $07 $20 $FC $08 $A5
$BC $85 $B6 $20 $FC $08 $A5 $BD
$85 $B7 $A4 $BC $20 $FC $08 $A6
$B7 $A5 $B6 $18 $6C $BC $00 $20
$42 $0B $20 $F9 $06 $4C $87 $07
$86 $2D $E0 $00 $60 $A0 $02 $84
$BC $A0 $29 $84 $BD $A0 $00 $B1
$BC $C9 $08 $D0 $03 $4C $0B $0A
$60 $20 $09 $04 $A9 $FF $2C $11
$04 $30 $02 $A9 $00 $4C $09 $04
$24 $3A $91 $27 $10 $E1 $59 $C5
$2A $56 $10 $11 $2C $8B $4C $45
$D4 $A0 $80 $BD $30 $BC $E0 $13
$1D $94 $47 $CF $88 $54 $CF $30
$BC $E0 $10 $11 $16 $80 $53 $55
$C2 $30 $BC $E0 $14 $16 $90 $50
$D2 $83 $49 $4E $D4 $E5 $71 $88
$BB $E1 $1D $8F $A2 $21 $58 $6F
$83 $AC $22 $55 $83 $BA $24 $93
$E0 $23 $1D $30 $BC $20 $48 $91
$49 $C6 $30 $BC $31 $34 $30 $BC
$84 $54 $48 $45 $CE $1C $1D $38
$0D $9A $49 $4E $50 $55 $D4 $A0
$10 $E7 $24 $3F $20 $91 $27 $E1
$59 $81 $AC $30 $BC $13 $11 $82
$AC $4D $E0 $1D $89 $52 $45 $54
$55 $52 $CE $E0 $15 $1D $85 $45
$4E $C4 $E0 $2D $98 $4C $49 $53
$D4 $EC $24 $00 $00 $00 $00 $0A
$80 $1F $24 $93 $23 $1D $30 $BC
$E1 $50 $80 $AC $59 $85 $52 $55
$CE $38 $0A $86 $43 $4C $45 $41
$D2 $2B $84 $52 $45 $CD $1D $A0
$80 $BD $38 $14 $85 $AD $30 $D3
$17 $64 $81 $AB $30 $D3 $85 $AB
$30 $D3 $18 $5A $85 $AD $30 $D3
$19 $54 $2F $30 $E2 $85 $AA $30
$E2 $1A $5A $85 $AF $30 $E2 $1B
$54 $2F $98 $52 $4E $C4 $0A $80
$80 $12 $0A $09 $29 $1A $0A $1A
$85 $18 $13 $09 $80 $12 $01 $0B
$31 $30 $61 $72 $0B $04 $02 $03
$05 $03 $1B $1A $19 $0B $09 $06
$0A $00 $00 $1C $17 $2F $8F $55
$53 $D2 $80 $A8 $30 $BC $31 $2A
$31 $2A $80 $A9 $2E $2F $A2 $12
$2F $C1 $2F $80 $A8 $30 $BC $80
$A9 $2F $83 $AC $38 $BC $0B $2F
$80 $A8 $52 $2F $84 $BD $09 $02
$2F $8E $BC $84 $BD $09 $93 $2F
$84 $BE $09 $05 $2F $09 $91 $2F
$80 $BE $84 $BD $09 $06 $2F $84
$BC $09 $95 $2F $09 $04 $2F $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$EA $EA $EA $EA $EA $EA $EA $EA
$EA $EA $EA $EA $EA $20 $0D $0F
$A0 $00 $20 $1D $0F $20 $2C $0F
$C9 $43 $D0 $03 $4C $85 $04 $C9
$57 $D0 $03 $4C $BD $04 $A2 $2F
$20 $1D $0F $4C $05 $0D $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$4F $4D $45 $47 $41 $20 $4D $49
$43 $52 $4F $20 $53 $59 $53 $54
$45 $4D $53 $0D $0A $4D $4B $48
$42 $43 $2D $38 $2D $52 $31 $20
$54 $49 $4E $59 $20 $42 $41 $53
$49 $43 $20 $36 $35 $30 $32 $20
$50 $4F $52 $54 $0D $0A $56 $65
$72 $73 $69 $6F $6E $3A $20 $31
$2E $30 $2E $32 $2C $20 $31 $2F
$31 $31 $2F $32 $30 $31 $32 $0D
$0A $28 $4E $4F $54 $45 $3A $20
$55 $73 $65 $20 $63 $61 $70 $73
$20 $66 $6F $72 $20 $42 $61 $73
$69 $63 $29 $0D $0A $42 $6F $6F
$74 $20 $28 $5B $43 $5D $6F $6C
$64 $2F $5B $57 $5D $61 $72 $6D
$29 $3F $20 $07 $FF $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$86 $C3 $B1 $C2 $48 $C8 $B1 $C2
$AA $68 $A8 $8A $60 $A2 $19 $A9
$0D $20 $31 $0F $A9 $0A $20 $31
$0F $CA $D0 $FA $60 $B9 $00 $0E
$C9 $FF $F0 $07 $20 $31 $0F $C8
$4C $1D $0F $60 $AD $00 $E0 $F0
$FB $85 $FE $C9 $FF $F0 $1E $C9
$00 $F0 $1A $C9 $91 $F0 $16 $C9
$93 $F0 $12 $C9 $80 $F0 $0E $4C
$50 $0F $20 $F0 $FF $A5 $FE $60
$A5 $FE $8D $00 $E0 $60 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $00