mirror of https://github.com/makarcz/vm6502.git
Performance, bug fixes, debug options, documentation updates.
Performance stats., refactoring, bug fixes, documentation updates, cosmetic changes, debug options.
This commit is contained in:
parent
3cd0bc3f20
commit
9d6706df96
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: ConsoleIO.cpp
|
||||
*
|
||||
* Purpose: Implementation of ConsoleIO class.
|
||||
* The ConsoleIO class has methods helpful when
|
||||
* UI is utilizing STDIO (DOS) console.
|
||||
*
|
||||
* Date: 8/26/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
#include "system.h"
|
||||
#include "ConsoleIO.h"
|
||||
|
||||
#include "MKGenException.h"
|
||||
|
||||
#if defined(WINDOWS)
|
||||
#include <conio.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace MKBasic {
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
ConsoleIO::ConsoleIO()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
ConsoleIO::~ConsoleIO()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#if defined(WINDOWS)
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: ClearScreen()
|
||||
* Purpose: Clear the console screen.
|
||||
* Arguments: n/a
|
||||
* Returns: n/a
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void ConsoleIO::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: ScrHome()
|
||||
* Purpose: Bring the console cursor to home position.
|
||||
* Arguments: n/a
|
||||
* Returns: n/a
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void ConsoleIO::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 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(LINUX)
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: ClearScreen()
|
||||
* Purpose: Clear the console screen.
|
||||
* Arguments: n/a
|
||||
* Returns: n/a
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void ConsoleIO::ClearScreen()
|
||||
{
|
||||
system("clear");
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: ScrHome()
|
||||
* Purpose: Bring the console cursor to home position.
|
||||
* Arguments: n/a
|
||||
* Returns: n/a
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void ConsoleIO::ScrHome()
|
||||
{
|
||||
cout << "\033[1;1H";
|
||||
}
|
||||
|
||||
#endif // #devine LINUX
|
||||
|
||||
} // END namespace MKBasic
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: ConsoleIO.h
|
||||
*
|
||||
* Purpose: Prototype of ConsoleIO class.
|
||||
*
|
||||
* Date: 8/26/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef CONSOLEIO_H
|
||||
#define CONSOLEIO_H
|
||||
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include <chrono>
|
||||
#include "system.h"
|
||||
|
||||
//#define WINDOWS 1
|
||||
#if defined (WINDOWS)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace MKBasic {
|
||||
|
||||
class ConsoleIO
|
||||
{
|
||||
public:
|
||||
|
||||
ConsoleIO();
|
||||
~ConsoleIO();
|
||||
|
||||
void ClearScreen();
|
||||
void ScrHome();
|
||||
|
||||
};
|
||||
|
||||
} // namespace MKBasic
|
||||
|
||||
#endif // #ifndef CONSOLEIO_H
|
36
Display.cpp
36
Display.cpp
|
@ -1,3 +1,39 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: Display.cpp
|
||||
*
|
||||
* Purpose: Implementation of Display class.
|
||||
* The Display class emulates the character I/O device.
|
||||
* It defines the abstract device. The actual
|
||||
* input/output to the screen of the platform on which
|
||||
* the emulator runs is defined in MemMapDev class
|
||||
* or on higher level of abstraction.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#include "Display.h"
|
||||
#include <ctype.h>
|
||||
#include <cstdlib>
|
||||
|
|
32
Display.h
32
Display.h
|
@ -1,3 +1,35 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: Display.h
|
||||
*
|
||||
* Purpose: Prototype of Display class and all supportig data
|
||||
* structures, enumerations, constants and macros.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef DISPLAY_H
|
||||
#define DISPLAY_H
|
||||
|
||||
|
|
|
@ -1,4 +1,40 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: GraphDisp.cpp
|
||||
*
|
||||
* Purpose: Implementation of GraphDisp class.
|
||||
* The GraphDisp class emulates the graphics raster
|
||||
* device. It handles displaying of the graphics, the
|
||||
* events loop and the 'hardware' API to the device.
|
||||
* The higher level abstraction layer - MemMapDev
|
||||
* defines the actual behavior/response of the emulated
|
||||
* device in the emulated system.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#include "GraphDisp.h"
|
||||
#include "MKGenException.h"
|
||||
#include "system.h"
|
||||
|
@ -75,6 +111,8 @@ void GraphDisp::Initialize()
|
|||
{
|
||||
int desk_w, desk_h, winbd_top = 5, winbd_right = 5;
|
||||
|
||||
mPixelSizeX = GRAPHDISP_MAXW / mWidth;
|
||||
mPixelSizeY = GRAPHDISP_MAXH / mHeight;
|
||||
GetDesktopResolution(desk_w, desk_h);
|
||||
// Available in version > 2.0.4
|
||||
//SDL_GetWindowBordersSize(mpWindow, &winbd_top, NULL, NULL, &winbd_right);
|
||||
|
|
40
GraphDisp.h
40
GraphDisp.h
|
@ -1,3 +1,35 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: GraphDisp.h
|
||||
*
|
||||
* Purpose: Prototype of GraphDisp class and supporting data
|
||||
* structures, enumerations, constants and macros.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef GRAPHDISP_H
|
||||
#define GRAPHDISP_H
|
||||
|
||||
|
@ -12,8 +44,8 @@ using namespace std;
|
|||
|
||||
namespace MKBasic {
|
||||
|
||||
const int GRAPHDISP_MAXW = 640; // "real" display width or maximum virtual width
|
||||
const int GRAPHDISP_MAXH = 400; // "real" display width or maximum virtual height
|
||||
const int GRAPHDISP_MAXW = 960; // "real" display width or maximum virtual width
|
||||
const int GRAPHDISP_MAXH = 600; // "real" display width or maximum virtual height
|
||||
|
||||
class GraphDisp {
|
||||
|
||||
|
@ -43,8 +75,8 @@ class GraphDisp {
|
|||
|
||||
int mWidth = 320; // virtual display width
|
||||
int mHeight = 200; // virtual display height
|
||||
int mPixelSizeX = 2; // virtual pixel width
|
||||
int mPixelSizeY = 2; // virtual pixel height
|
||||
int mPixelSizeX = 3; // virtual pixel width
|
||||
int mPixelSizeY = 3; // virtual pixel height
|
||||
int mWinPosX = 0; // SDL window position coordinate X
|
||||
int mWinPosY = 0; // SDL window position coordinate Y
|
||||
int mBgRgbR = 0; // bg color, RGB red intensity
|
||||
|
|
59
MKBasic.cpp
59
MKBasic.cpp
|
@ -1,13 +1,46 @@
|
|||
#include "MKBasic.h"
|
||||
|
||||
namespace MKBasic {
|
||||
|
||||
MKBasic::MKBasic()
|
||||
{
|
||||
}
|
||||
|
||||
MKBasic::~MKBasic()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace MKBasic
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File:
|
||||
*
|
||||
* Purpose: Implementation of MKBasic class.
|
||||
* NOTE: This is obsolete concept and will likely be
|
||||
* removed from project.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#include "MKBasic.h"
|
||||
|
||||
namespace MKBasic {
|
||||
|
||||
MKBasic::MKBasic()
|
||||
{
|
||||
}
|
||||
|
||||
MKBasic::~MKBasic()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace MKBasic
|
||||
|
|
70
MKBasic.h
70
MKBasic.h
|
@ -1,18 +1,52 @@
|
|||
#ifndef MKBASIC_H
|
||||
#define MKBASIC_H
|
||||
|
||||
#include "VMachine.h"
|
||||
|
||||
namespace MKBasic {
|
||||
|
||||
class MKBasic : public VMachine
|
||||
{
|
||||
public:
|
||||
MKBasic();
|
||||
~MKBasic();
|
||||
protected:
|
||||
};
|
||||
|
||||
} // namespace MKBasic
|
||||
|
||||
#endif
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File:
|
||||
*
|
||||
* Purpose: Prototype of MKBasic class and all supporting data
|
||||
* structures, enumerations, constants and macros.
|
||||
* NOTE: This is obsolete concept and will likely be
|
||||
* removed from project.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef MKBASIC_H
|
||||
#define MKBASIC_H
|
||||
|
||||
#include "VMachine.h"
|
||||
|
||||
namespace MKBasic {
|
||||
|
||||
class MKBasic : public VMachine
|
||||
{
|
||||
public:
|
||||
MKBasic();
|
||||
~MKBasic();
|
||||
protected:
|
||||
};
|
||||
|
||||
} // namespace MKBasic
|
||||
|
||||
#endif
|
||||
|
|
36
MKCpu.cpp
36
MKCpu.cpp
|
@ -1,4 +1,38 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: MKCpu.cpp
|
||||
*
|
||||
* Purpose: Implementation of MKCpu class.
|
||||
* MKCpu class implements the op-codes and other
|
||||
* supporting functions of a virtual CPU. This one in
|
||||
* particular emulates a real world microprocessor from
|
||||
* 1970-s, the venerable MOS-6502.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and exercise common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "MKCpu.h"
|
||||
#include "MKGenException.h"
|
||||
|
@ -347,7 +381,7 @@ void MKCpu::InitCpu()
|
|||
mReg.PtrStack = 0xFF; // top of stack
|
||||
mReg.SoftIrq = false;
|
||||
mReg.IrqPending = false;
|
||||
mReg.CyclesLeft = 0;
|
||||
mReg.CyclesLeft = 1;
|
||||
mReg.PageBoundary = false;
|
||||
mLocalMem = false;
|
||||
mExitAtLastRTS = true;
|
||||
|
|
34
MKCpu.h
34
MKCpu.h
|
@ -1,3 +1,35 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: MKCpu.h
|
||||
*
|
||||
* Purpose: Prototype of MKCpu class. Data structures, enumerations
|
||||
* and constants definitions supporting MKCpu class.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and exercise common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef MKCPU_H
|
||||
#define MKCPU_H
|
||||
|
||||
|
@ -26,7 +58,7 @@ struct Regs {
|
|||
bool SoftIrq; // true when interrupted with BRK or trapped opcode
|
||||
bool LastRTS; // true if RTS encountered and stack empty.
|
||||
unsigned short LastAddr; // PC at the time of previous op-code
|
||||
string LastInstr; // instruction and argument executed in previous step
|
||||
//string LastInstr; // instruction and argument executed in previous step
|
||||
int LastOpCode; // op-code of last instruction
|
||||
unsigned short LastArg; // argument to the last instruction
|
||||
int LastAddrMode; // addressing mode of last instruction
|
||||
|
|
160
MemMapDev.cpp
160
MemMapDev.cpp
|
@ -1,4 +1,47 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: MemMapDev.cpp
|
||||
*
|
||||
* Purpose: Implementation of MemMapDev class.
|
||||
* The MemMapDev class implements the highest abstraction
|
||||
* layer for interfacing with emulated devices via memory
|
||||
* addressing space, which is a typical way of
|
||||
* interfacing the CPU with peripherals in the real world
|
||||
* microprocessor systems.
|
||||
* It also implements/emulates the behavior of the
|
||||
* devices. The core implementation of the devices may
|
||||
* be contained in separate classes or inside MemMapDev
|
||||
* class. Note that MemMapDev class always contains
|
||||
* at least partial (highest abstraction layer)
|
||||
* implementation of the emulated device as it defines
|
||||
* the methods triggered by corresponding memory address
|
||||
* accesses.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#include "MemMapDev.h"
|
||||
#include "Memory.h"
|
||||
#include "MKGenException.h"
|
||||
|
@ -83,6 +126,7 @@ void MemMapDev::Initialize()
|
|||
mCharIOAddr = CHARIO_ADDR;
|
||||
mGraphDispAddr = GRDISP_ADDR;
|
||||
mpGraphDisp = NULL;
|
||||
mpCharIODisp = NULL;
|
||||
AddrRange addr_range(CHARIO_ADDR, CHARIO_ADDR+1);
|
||||
DevPar dev_par("echo", "false");
|
||||
MemAddrRanges addr_ranges_chario;
|
||||
|
@ -112,6 +156,7 @@ void MemMapDev::Initialize()
|
|||
&MemMapDev::GraphDispDevice_Write,
|
||||
dev_params_grdisp);
|
||||
mDevices.push_back(dev_grdisp);
|
||||
mCharIOActive = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -287,7 +332,7 @@ int MemMapDev::getch()
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #define LINUX
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
|
@ -304,10 +349,11 @@ unsigned char MemMapDev::ReadCharKb(bool nonblock)
|
|||
#if defined(LINUX)
|
||||
set_conio_terminal_mode();
|
||||
#endif
|
||||
static int c = ' ';
|
||||
if (mIOEcho && isprint(c)) putchar(c);
|
||||
fflush(stdout);
|
||||
|
||||
static int c = ' '; // static, initializes once, remembers prev.
|
||||
// value
|
||||
// checking mCharIOActive may be too much of a precaution since
|
||||
// this method will not be called unless char I/O is enabled
|
||||
if (mCharIOActive && mIOEcho && isprint(c)) putchar(c);
|
||||
if (nonblock) {
|
||||
// get a keystroke only if character is already in buffer
|
||||
if (kbhit()) c = getch();
|
||||
|
@ -375,10 +421,31 @@ char MemMapDev::GetCharOut()
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: CharIOFlush()
|
||||
* Purpose: Flush the character I/O FIFO output buffer contents
|
||||
* to the character I/O device's screen buffer.
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void MemMapDev::CharIOFlush()
|
||||
{
|
||||
char cr = -1;
|
||||
while ((cr = GetCharOut()) != -1) {
|
||||
mpCharIODisp->PutChar(cr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: PutCharIO()
|
||||
* Purpose: Put character in the output char I/O FIFO buffer.
|
||||
* If character I/O device emulation is enabled, print the
|
||||
* character to the standard output, then flush the I/O
|
||||
* FIFO output buffer to the character device screen
|
||||
* buffer.
|
||||
* Arguments: c - character
|
||||
* Returns: n/a
|
||||
*--------------------------------------------------------------------
|
||||
|
@ -388,6 +455,10 @@ void MemMapDev::PutCharIO(char c)
|
|||
mCharIOBufOut[mOutBufDataEnd] = c;
|
||||
mOutBufDataEnd++;
|
||||
if (mOutBufDataEnd >= CHARIO_BUF_SIZE) mOutBufDataEnd = 0;
|
||||
if (mCharIOActive) {
|
||||
putchar((int)c);
|
||||
CharIOFlush();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -451,6 +522,69 @@ bool MemMapDev::GetCharIOEchoOn()
|
|||
return mIOEcho;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: IsCharIOActive()
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
bool MemMapDev::IsCharIOActive()
|
||||
{
|
||||
return mCharIOActive;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: ActivateCharIO()
|
||||
* Purpose: Activate character I/O device, create Display object.
|
||||
* Arguments: n/a
|
||||
* Returns: Pointer to Display object.
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
Display *MemMapDev::ActivateCharIO()
|
||||
{
|
||||
if (NULL == mpCharIODisp) {
|
||||
mpCharIODisp = new Display();
|
||||
if (NULL == mpCharIODisp)
|
||||
throw MKGenException(
|
||||
"Out of memory while initializing Character I/O Display Device");
|
||||
}
|
||||
mCharIOActive = true;
|
||||
mpCharIODisp->ClrScr();
|
||||
|
||||
return mpCharIODisp;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: GetDispPtr()
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns: Pointer to Display object.
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
Display *MemMapDev::GetDispPtr()
|
||||
{
|
||||
return mpCharIODisp;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: DeactivateCharIO()
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void MemMapDev::DeactivateCharIO()
|
||||
{
|
||||
if (NULL != mpCharIODisp) delete mpCharIODisp;
|
||||
mpCharIODisp = NULL;
|
||||
mCharIOActive = false;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: GetGraphDispAddrBase()
|
||||
|
@ -668,4 +802,20 @@ void MemMapDev::GraphDisp_Update()
|
|||
if (NULL != mpGraphDisp) mpGraphDisp->Update();
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: SetCharIODispPtr()
|
||||
* Purpose: Set internal pointer to character I/O device object.
|
||||
* Arguments: p - pointer to Display object.
|
||||
* active - bool, true if character I/O is active
|
||||
* Returns: n/a
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
void MemMapDev::SetCharIODispPtr(Display *p, bool active)
|
||||
{
|
||||
mpCharIODisp = p;
|
||||
mCharIOActive = active;
|
||||
}*/
|
||||
|
||||
} // namespace MKBasic
|
||||
|
|
45
MemMapDev.h
45
MemMapDev.h
|
@ -1,3 +1,35 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: MemMapDev.h
|
||||
*
|
||||
* Purpose: Prototype of MemMapDev class and all supporting
|
||||
* data structures, enumarators, constants and macros.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef MEMMAPDEV_H
|
||||
#define MEMMAPDEV_H
|
||||
|
||||
|
@ -6,6 +38,7 @@
|
|||
#include "system.h"
|
||||
//#include "Memory.h"
|
||||
#include "GraphDisp.h"
|
||||
#include "Display.h"
|
||||
|
||||
#if defined(LINUX)
|
||||
#include <unistd.h>
|
||||
|
@ -102,6 +135,7 @@ struct Device {
|
|||
|
||||
typedef vector<Device> MemMappedDevices;
|
||||
|
||||
// currently supported devices
|
||||
enum DevNums {
|
||||
DEVNUM_CHARIO = 0, // character I/O device
|
||||
DEVNUM_GRDISP = 1, // raster graphics display device
|
||||
|
@ -112,7 +146,7 @@ enum DevNums {
|
|||
*
|
||||
* The emulated device is a model of a electronic device that is connected
|
||||
* to the CPU-s bus (address, memory, control signals).
|
||||
* Depending on the device, the memory address range maybe as simple as
|
||||
* Depending on the device, the memory address range may be as simple as
|
||||
* a single memory address or it may contain multiple memory addresses
|
||||
* or ranges of addresses positioned at various non-contiguous places.
|
||||
* The functions of these addresses are handled internally by the MemMapDev
|
||||
|
@ -184,8 +218,13 @@ class MemMapDev {
|
|||
|
||||
char GetCharIn();
|
||||
char GetCharOut();
|
||||
void CharIOFlush();
|
||||
unsigned short GetCharIOAddr();
|
||||
bool GetCharIOEchoOn();
|
||||
bool IsCharIOActive();
|
||||
Display* ActivateCharIO();
|
||||
Display* GetDispPtr();
|
||||
void DeactivateCharIO();
|
||||
|
||||
int CharIODevice_Read(int addr);
|
||||
void CharIODevice_Write(int addr, int val);
|
||||
|
@ -200,6 +239,8 @@ class MemMapDev {
|
|||
void GraphDisp_ReadEvents();
|
||||
void GraphDisp_Update();
|
||||
|
||||
//void SetCharIODispPtr(Display *p, bool active);
|
||||
|
||||
private:
|
||||
|
||||
Memory *mpMem; // pointer to memory object
|
||||
|
@ -214,6 +255,8 @@ class MemMapDev {
|
|||
bool mIOEcho;
|
||||
unsigned int mGraphDispAddr;
|
||||
GraphDisp *mpGraphDisp; // pointer to Graphics Device object
|
||||
Display *mpCharIODisp; // pointer to character I/O device object
|
||||
bool mCharIOActive; // indicate if character I/O is active
|
||||
GraphDeviceRegs mGrDevRegs; // graphics display device registers
|
||||
|
||||
void Initialize();
|
||||
|
|
97
Memory.cpp
97
Memory.cpp
|
@ -1,4 +1,42 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: Memory.cpp.
|
||||
*
|
||||
* Purpose: Implementation of class Memory.
|
||||
* The Memory class implements the highest abstraction
|
||||
* layer of Visrtual Machine's memory. in this particular
|
||||
* case the Virtual Machine emulates a computer system
|
||||
* based on a 8-bit microprocessor. Therefore it
|
||||
* implements image size and addressing space adequate
|
||||
* for the specific architecture of such microprocessor.
|
||||
* The Memory class also interfaces with the MemMapDev
|
||||
* API (Memory Mapped Devices).
|
||||
*
|
||||
* Date:
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#include "Memory.h"
|
||||
#include "MKGenException.h"
|
||||
|
||||
|
@ -322,6 +360,7 @@ void Memory::SetCharIO(unsigned short addr, bool echo)
|
|||
SetupDevice(DEVNUM_CHARIO, memaddr_ranges, dev_params);
|
||||
if (false == mCharIOActive) AddDevice(DEVNUM_CHARIO);
|
||||
mCharIOActive = true;
|
||||
mpMemMapDev->ActivateCharIO();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -336,6 +375,7 @@ void Memory::DisableCharIO()
|
|||
{
|
||||
mCharIOActive = false;
|
||||
DeleteDevice(DEVNUM_CHARIO);
|
||||
mpMemMapDev->DeactivateCharIO();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -405,10 +445,10 @@ unsigned short Memory::GetGraphDispAddr()
|
|||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
* Method: GetROMBegin()
|
||||
* Purpose: Get starting address of read-only memory.
|
||||
* Arguments:
|
||||
* Returns: unsigned short - address ($0000-$FFFF)
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
unsigned short Memory::GetROMBegin()
|
||||
|
@ -418,10 +458,10 @@ unsigned short Memory::GetROMBegin()
|
|||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Method: GetROMEnd()
|
||||
* Purpose: Get end address of read-only memory.
|
||||
* Arguments:
|
||||
* Returns:
|
||||
* Returns: unsigned short - address ($0000-$FFFF)
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
unsigned short Memory::GetROMEnd()
|
||||
|
@ -431,10 +471,10 @@ unsigned short Memory::GetROMEnd()
|
|||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
* Method: IsROMEnabled()
|
||||
* Purpose: Get status of ROM.
|
||||
* Arguments:
|
||||
* Returns: bool - true if enabled.
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
bool Memory::IsROMEnabled()
|
||||
|
@ -445,7 +485,7 @@ bool Memory::IsROMEnabled()
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: AddDevice()
|
||||
* Purpose: Add device number to active devices list.
|
||||
* Purpose: Add device to active devices cache.
|
||||
* Arguments: devnum - device number
|
||||
* Returns: -1 if device is not supported OR already cached
|
||||
* devnum - device number if it was found
|
||||
|
@ -487,7 +527,7 @@ int Memory::AddDevice(int devnum)
|
|||
}
|
||||
}
|
||||
} // END if (dev.num >= 0)
|
||||
// else device with wuch number is not supported
|
||||
// else device with such number is not supported
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -495,7 +535,7 @@ int Memory::AddDevice(int devnum)
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: DeleteDevice()
|
||||
* Purpose: Delete device number from active devices list.
|
||||
* Purpose: Delete device from active devices cache.
|
||||
* Arguments: devnum - device number
|
||||
* Returns: >=0 if device was found in local cache and deleted
|
||||
* -1 if device was not found
|
||||
|
@ -607,10 +647,10 @@ char Memory::GetCharOut()
|
|||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
* Method: GraphDisp_ReadEvents()
|
||||
* Purpose: Read events from the graphics display window.
|
||||
* Arguments: n/a
|
||||
* Returns: n/a
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void Memory::GraphDisp_ReadEvents()
|
||||
|
@ -620,10 +660,10 @@ void Memory::GraphDisp_ReadEvents()
|
|||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
* Method: GraphDisp_Update()
|
||||
* Purpose: Trigger update handler of the graphics display window.
|
||||
* Arguments: n/a
|
||||
* Returns: n/a
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void Memory::GraphDisp_Update()
|
||||
|
@ -646,4 +686,17 @@ bool Memory::GraphDispOp()
|
|||
return mDispOp;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: GetMemMapDevPtr()
|
||||
* Purpose: Get the pointer to MemMapDev object.
|
||||
* Arguments: n/a
|
||||
* Returns: Pointer to MemMapDev object.
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
MemMapDev *Memory::GetMemMapDevPtr()
|
||||
{
|
||||
return mpMemMapDev;
|
||||
}
|
||||
|
||||
} // namespace MKBasic
|
||||
|
|
33
Memory.h
33
Memory.h
|
@ -1,3 +1,35 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: Memory.h
|
||||
*
|
||||
* Purpose: Prototype of Memory class and supporting data
|
||||
* structures, constants, enumerations and macros.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and exercise common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
|
@ -49,6 +81,7 @@ class Memory
|
|||
void GraphDisp_ReadEvents();
|
||||
void GraphDisp_Update();
|
||||
bool GraphDispOp();
|
||||
MemMapDev *GetMemMapDevPtr();
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -82,11 +82,14 @@ provided image file and enter the debug console menu.
|
|||
which will be referred to as Debug Console:
|
||||
|
||||
STOPPED at 0
|
||||
|
||||
Emulation performance stats is OFF.
|
||||
|
||||
*-------------*-----------------------*----------*----------*
|
||||
| PC: $0000 | Acc: $00 (00000000) | X: $00 | Y: $00 |
|
||||
*-------------*-----------------------*----------*----------*
|
||||
| NV-BDIZC |
|
||||
| 00100000 | Last instr.:
|
||||
| NV-BDIZC | :
|
||||
| 00100000 | :
|
||||
*-------------*
|
||||
|
||||
Stack: $ff
|
||||
|
@ -95,6 +98,7 @@ Stack: $ff
|
|||
I/O status: disabled, at: $e000, local echo: OFF.
|
||||
Graphics status: disabled, at: $e002
|
||||
ROM: disabled. Range: $d000 - $dfff.
|
||||
Op-code execute history: disabled.
|
||||
------------------------------------+----------------------------------------
|
||||
C - continue, S - step | A - set address for next step
|
||||
G - go/cont. from new address | N - go number of steps, P - IRQ
|
||||
|
@ -103,11 +107,38 @@ ROM: disabled. Range: $d000 - $dfff.
|
|||
E - toggle I/O local echo | F - toggle registers animation
|
||||
J - set animation delay | M - dump memory, W - write memory
|
||||
K - toggle ROM emulation | R - show registers, Y - snapshot
|
||||
L - load memory image | O - display op-codes history
|
||||
L - load memory image | O - display op-code exec. history
|
||||
D - disassemble code in memory | Q - quit, 0 - reset, H - help
|
||||
V - toggle graphics emulation |
|
||||
V - toggle graphics emulation | U - enable/disable exec. history
|
||||
Z - enable/disable debug traces | 1 - enable/disable perf. stats
|
||||
2 - display debug traces | ? - show this menu
|
||||
------------------------------------+----------------------------------------
|
||||
> _
|
||||
>
|
||||
|
||||
Upper part of the screen consists of current CPU registers status.
|
||||
If performance statistics are enabled, they are right above the CPU
|
||||
registers.
|
||||
PC shows address of currently executed op-code, while to the right of status
|
||||
flags below PC is a disassembled (now empty, showing just the ':' signs)
|
||||
instructions section. It shows 2 lines, 1-st line is the previously executed
|
||||
instruction while the 2-nd line shows current instruction. Instructions are
|
||||
shown in binary (hex) and symbolic (disassembled mnemonics, hex arguments)
|
||||
format.
|
||||
Accumulator and index registers X and Y values are also shown in the CPU
|
||||
registers section.
|
||||
Stack pointer and its contents are displayed below the CPU registers.
|
||||
The contents of the Processor registers, disassembled executed instructions
|
||||
and stack pointer and contents are updated dymanically during the multi-step
|
||||
program debugging.
|
||||
|
||||
Below the stack data we have current status of various flags and parameters
|
||||
that don't belong to emulated CPU.
|
||||
|
||||
Next goes the full list of available commands with short descriptions.
|
||||
The menu of commands is not always displayed. It is usually skipped when
|
||||
there were no screen actions that could potentially obstruct that menu.
|
||||
The menu of commands can be always recalled to the screen by issuing
|
||||
command '?' after the command prompt '>' and pressing ENTER.
|
||||
|
||||
Each of the commands in Debug Console is interactive and can be used in two
|
||||
ways - user can issue command in the prompt, press enter and follow the
|
||||
|
@ -116,9 +147,9 @@ ROM: disabled. Range: $d000 - $dfff.
|
|||
To see full help for above commands, issue command H in the prompt and press
|
||||
ENTER.
|
||||
|
||||
A quick overview of the some commands available in Debug Console:
|
||||
A quick overview of some of the commands available in Debug Console:
|
||||
|
||||
* Code execution and debugging commands.
|
||||
2.1. Code execution and debugging aid commands.
|
||||
|
||||
C - Continue
|
||||
|
||||
|
@ -126,11 +157,12 @@ ROM: disabled. Range: $d000 - $dfff.
|
|||
|
||||
S - Step
|
||||
|
||||
Executes single opcode at current address.
|
||||
Executes single op-code at current address. The address for the next
|
||||
step can be changed with command 'A'.
|
||||
|
||||
A - Set address for next step
|
||||
|
||||
Sets current address to one provided is argument (or prompts for one).
|
||||
Sets current address to one provided as argument (or prompts for one).
|
||||
|
||||
G - Execute (continue) from address.
|
||||
|
||||
|
@ -138,6 +170,10 @@ ROM: disabled. Range: $d000 - $dfff.
|
|||
|
||||
N - Execute # of steps.
|
||||
|
||||
Useful when we want to skip ahead (e.g.: in a loop) and execute multiple
|
||||
op-codes before next stop. Look also at commands 'F' and 'J' for
|
||||
features and parameters associated with it.
|
||||
|
||||
X - Execute from address.
|
||||
|
||||
F - Toggle registers animation.
|
||||
|
@ -159,7 +195,7 @@ ROM: disabled. Range: $d000 - $dfff.
|
|||
|
||||
Displays current status of CPU registers, flags and stack.
|
||||
|
||||
O - Display op-codes history.
|
||||
O - Display op-codes execute history.
|
||||
|
||||
Show the history of last executed op-codes/instructions, full with
|
||||
disassembled mnemonic and argument.
|
||||
|
@ -181,7 +217,47 @@ ROM: disabled. Range: $d000 - $dfff.
|
|||
opcode if stack is empty, so the VM will never return from opcodes
|
||||
execution loop unless user interrupts with CTRL-C or CTRL-Break.
|
||||
|
||||
* Memory access commands.
|
||||
Z - Toggle enable/disable debug traces.
|
||||
|
||||
Emulator may produce debug messages that can be helpful when
|
||||
troubleshooting issues with 6502 code. Since the immediate output
|
||||
to the same console where emulated program is connected is in many
|
||||
cases undesired, the debug messages are remembered in an internal
|
||||
log. The log holds last 200 messages. If enabled, this log can be
|
||||
recalled with command '2'. When the log is disabled and then enabled
|
||||
again, the old log messages will be deleted.
|
||||
|
||||
2 - Display debug traces.
|
||||
|
||||
Displays debug traces log (200 maximum) in 20 messages long pages.
|
||||
|
||||
U - Toggle enable/disable op-codes execute history.
|
||||
|
||||
See also option 'O'.
|
||||
This debuggin aid is not needed during normal emulator run, therefore
|
||||
option to disable this feature was added, mainly because it affects
|
||||
performance. But in debugging mode, when we often trace code step by
|
||||
step, the performance compromise may be justified as a trade off for
|
||||
getting more internal data from the system.
|
||||
|
||||
1 - Toggle enable/disable emulation performance statistics.
|
||||
|
||||
MKCpu class includes code to measure the emulation speed.
|
||||
The speed is measured as a % of model 1 MHz MOS-6502. Number of executed
|
||||
cycles is divided by number of microseconds that passed and multiplied
|
||||
by 100 to get this figure.
|
||||
Performance is only measured in the execute/run modes.
|
||||
It doesn't make much sense in debug/step by step modes, therefore even
|
||||
when the feature is enabled, the stats are not calculated in these modes
|
||||
of operation.
|
||||
Emulation performance feature is useful mainly during the development
|
||||
cycle of the emulator and since this is a programming framework for
|
||||
buiding your own virtual machines/CPU emulators, then it is included.
|
||||
However as with any debugging aid, it affects performance, therefore
|
||||
option was added to disable it when we just want to run the 6502 code
|
||||
and enjoy it at maximum possible speed.
|
||||
|
||||
2.2. Memory access commands.
|
||||
|
||||
M - Dump memory.
|
||||
|
||||
|
@ -191,7 +267,7 @@ ROM: disabled. Range: $d000 - $dfff.
|
|||
|
||||
Writes provided values to memory starting at specified address.
|
||||
|
||||
* I/O devices commands.
|
||||
2.3. I/O devices commands.
|
||||
|
||||
I - Toggle char I/O emulation.
|
||||
|
||||
|
@ -251,6 +327,76 @@ ROM: disabled. Range: $d000 - $dfff.
|
|||
NOTE: All addresses and memory values are to be entered in hexadecimal
|
||||
format.
|
||||
|
||||
2.4. Typical debug session.
|
||||
|
||||
Your typical debug session, after starting VM65 is:
|
||||
|
||||
* Load the memory image with command 'L' (if not already loaded from
|
||||
command line). E.g.:
|
||||
|
||||
L A 6502_func_test.bin
|
||||
|
||||
* Set the program start address with command 'A' (if not already set
|
||||
in the memory image definition file). E.g.:
|
||||
|
||||
A 0400
|
||||
|
||||
* Enable/disable various debug and I/O facilities as required by the
|
||||
loaded 6502 code. E.g.: to enable dymanic processor registers updates
|
||||
and show the executed code dynamically while executing multiple steps
|
||||
with command 'N', you need to issue command 'F' to enable registers
|
||||
animation and optionally 'J' to change the speed (delay) of the
|
||||
step-by-step animation:
|
||||
|
||||
F
|
||||
J 100
|
||||
N 1000
|
||||
|
||||
OR if command 'S' is used to manually step through 6502 instructions,
|
||||
the animation of the CPU registers doesn't have top be enabled.
|
||||
The registers values and disassembled instructions will be refreshed
|
||||
after each step on the screen.
|
||||
Each step is considered a single instructions (not a clock cycle).
|
||||
If user wants to skip several (thousands perhaps) instructions, then
|
||||
registers animation (command 'F') should be disabled, which will
|
||||
make the steps to proceed much quicker. E.g.: assuming that currently
|
||||
the animation is enabled, and user wants to skip 5000 instructions
|
||||
quickly without looking at the changing registers and disassembled
|
||||
instructions, user would issue commands:
|
||||
|
||||
F
|
||||
N 5000
|
||||
|
||||
At any moment during multi-step execution (command 'N'), user can
|
||||
interrupt before all the steps are concluded with CTRL-C and then
|
||||
lool-up/alter memory content (commands 'M', 'W'), change the address
|
||||
of the next executed instruction (command 'A') etc. and then continue
|
||||
debugging with 'S', 'N', 'X', 'C', '0' or 'P' commands.
|
||||
|
||||
User can enable the history of executed op-codes with command 'U' and
|
||||
display the history of the last 20 op-codes and CPU registers values
|
||||
in the last 20 steps. E.g.:
|
||||
|
||||
L A 6502_func_test.bin
|
||||
A 0400
|
||||
U
|
||||
N 5
|
||||
O
|
||||
|
||||
Output from 'O':
|
||||
|
||||
> o
|
||||
PC : INSTR ACC | X | Y | PS | SP
|
||||
------------------------------------+-----+-----+-----+-----
|
||||
$0400: CLD $00 | $00 | $00 | $20 | $ff
|
||||
$0401: LDX #$FF $00 | $ff | $00 | $a0 | $ff
|
||||
$0403: TXS $00 | $ff | $00 | $a0 | $ff
|
||||
$0404: LDA #$00 $00 | $ff | $00 | $22 | $ff
|
||||
$0406: STA $0200 $00 | $ff | $00 | $22 | $ff
|
||||
|
||||
Type '?' and press [ENTER] for Menu ...
|
||||
|
||||
|
||||
3. Implementing the Virtual Machine.
|
||||
|
||||
The Virtual Machine (or Emulator) is implemented by the means of multiple
|
||||
|
@ -565,3 +711,58 @@ ROM: disabled. Range: $d000 - $dfff.
|
|||
See Memory::SetGraphDisp() and VMachine::SetGraphDisp() methods for
|
||||
an example. The SetGraphDisp() method in Memory class defines the memory
|
||||
mapped device on a lower level and calls SetupDevice().
|
||||
|
||||
5. Debug traces.
|
||||
|
||||
VMachine class implements debug messages queue which can be used during
|
||||
development cycle.
|
||||
|
||||
void EnableDebugTrace();
|
||||
void DisableDebugTrace();
|
||||
bool IsDebugTraceActive();
|
||||
queue<string> GetDebugTraces();
|
||||
void AddDebugTrace(string msg);
|
||||
|
||||
This is a FIFO queue and it is maintained to not exceed the length as
|
||||
defined:
|
||||
|
||||
#define DBG_TRACE_SIZE 200 // maximum size of debug messages queue
|
||||
|
||||
Therefore the next message added to queue that overfills the queue causes
|
||||
the earliest added message to be removed.
|
||||
Shortly put - the last 200 added messages only are remembered internally
|
||||
in VMachine object and can be recalled with GetDebugTraces() method like
|
||||
shown in this example:
|
||||
|
||||
VMachine *pvm;
|
||||
[...]
|
||||
queue<string> dbgtrc(pvm->GetDebugTraces());
|
||||
while (dbgtrc.size()) {
|
||||
cout << dbgtrc.front() << endl;
|
||||
dbgtrc.pop();
|
||||
}
|
||||
|
||||
Good example of AddDebugTrace() use is EnableROM() method:
|
||||
|
||||
void VMachine::EnableROM(unsigned short start, unsigned short end)
|
||||
{
|
||||
mpRAM->EnableROM(start, end);
|
||||
if (mDebugTraceActive) {
|
||||
stringstream sssa, ssea;
|
||||
string msg, startaddr, endaddr;
|
||||
sssa << start;
|
||||
sssa >> startaddr;
|
||||
ssea << end;
|
||||
ssea >> endaddr;
|
||||
msg = "ROM ENABLED, Start: " + startaddr + ", End: " + endaddr + ".";
|
||||
AddDebugTrace(msg);
|
||||
}
|
||||
}
|
||||
|
||||
NOTE: The AddDebugTrace method checks mDebugTraceActive flag internally,
|
||||
however for performance's sake we also check it in the higher level
|
||||
code especially if there are intermediate objects to be created
|
||||
to produce the debug string. This way we don't execute code related
|
||||
to creation of debug message unnecessarily if the debugging messages
|
||||
are disabled.
|
||||
|
||||
|
|
14
ReadMe.txt
14
ReadMe.txt
|
@ -21,13 +21,15 @@ Graphics display emulation requires SDL2.
|
|||
Makefile are included to build under Windows 32/64 (mingw compiler required)
|
||||
and under Linux Ubuntu or Ubuntu based distro.
|
||||
SDL2 library must be on your execution path in order to run program.
|
||||
E.g.:
|
||||
set PATH=C:\src\SDL\lib\x64;%PATH%
|
||||
|
||||
To build under Windows 32/64:
|
||||
|
||||
* Install MINGW64 under C:\mingw-w64\x86_64-5.3.0 folder.
|
||||
* Run mingw terminal.
|
||||
* Change current directory to that of this project.
|
||||
* Set environment variable SDLDIR.
|
||||
* Set environment variable SDLDIR. (E.g.: set SDLDIR=C:\src\SDL)
|
||||
* Run: makeming.bat
|
||||
|
||||
To build under Linux:
|
||||
|
@ -595,6 +597,12 @@ D - diassemble code in memory
|
|||
U - enable/disable exec. history
|
||||
Toggle enable/disable of op-codes execute history.
|
||||
Disabling this feature improves performance.
|
||||
Z - enable/disable debug traces
|
||||
Toggle enable/disable of debug traces.
|
||||
2 - display debug traces
|
||||
Display recent debug traces.
|
||||
1 - enable/disable performance stats
|
||||
Toggle enable/disable emulation speed measurement.
|
||||
|
||||
NOTE:
|
||||
1. If no arguments provided, each command will prompt user to enter
|
||||
|
@ -603,7 +611,7 @@ NOTE:
|
|||
by pressing CTRL-C or CTRL-Pause/Break, which will generate
|
||||
a "Operator Interrupt". However in the character input mode
|
||||
use CTRL-Y combination or CTRL-Break (DOS), CTRL-C (Linux).
|
||||
You may need to press ENTER after that in input mode (DOS).
|
||||
You may need to press ENTER after that in input mode (DOS).
|
||||
|
||||
7. Command line usage.
|
||||
|
||||
|
@ -770,7 +778,7 @@ With all peripherals disabled and op-code history enabled we are down to
|
|||
411 % on PC1 and 312 % on PC2.
|
||||
|
||||
Enabling and adding the emulated memory mapped devices to the pool may cause
|
||||
the emulation speed to drop as well. Hovever even with currently implemented
|
||||
the emulation speed to drop as well. However even with currently implemented
|
||||
peripherals (char I/O, graphics raster device) enabled and actively used and
|
||||
op-codes execute history enabled the performance is still well above 300 %
|
||||
on both PC1 and on PC2 (* see annotations for PC configurations/specs).
|
||||
|
|
518
VMachine.cpp
518
VMachine.cpp
|
@ -1,14 +1,52 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: VMachine.cpp
|
||||
*
|
||||
* Purpose: Implementation of VMachine class.
|
||||
* The VMachine class implements the Virtual Machine
|
||||
* in its entirety. It creates all the objects that
|
||||
* emulate the component's of the whole system and
|
||||
* implements the methods to execute the code on the
|
||||
* emulated platform.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
#include "system.h"
|
||||
#include "VMachine.h"
|
||||
#include "MKGenException.h"
|
||||
|
||||
/*
|
||||
#if defined(WINDOWS)
|
||||
#include <conio.h>
|
||||
#endif
|
||||
*/
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -62,10 +100,11 @@ VMachine::VMachine(string romfname, string ramfname)
|
|||
*/
|
||||
VMachine::~VMachine()
|
||||
{
|
||||
delete mpDisp;
|
||||
//delete mpDisp;
|
||||
delete mpCPU;
|
||||
delete mpROM;
|
||||
delete mpRAM;
|
||||
delete mpConIO;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -82,7 +121,6 @@ void VMachine::InitVM()
|
|||
mpRAM = new Memory();
|
||||
|
||||
mPerfStats.cycles = 0;
|
||||
mPerfStats.micro_secs = 0;
|
||||
mPerfStats.perf_onemhz = 0;
|
||||
mPerfStats.prev_cycles = 0;
|
||||
mPerfStats.prev_usec = 0;
|
||||
|
@ -93,6 +131,8 @@ void VMachine::InitVM()
|
|||
mCharIOAddr = CHARIO_ADDR;
|
||||
mCharIOActive = mCharIO = false;
|
||||
mGraphDispActive = false;
|
||||
mPerfStatsActive = false;
|
||||
mDebugTraceActive = false;
|
||||
if (NULL == mpRAM) {
|
||||
throw MKGenException("Unable to initialize VM (RAM).");
|
||||
}
|
||||
|
@ -105,14 +145,18 @@ void VMachine::InitVM()
|
|||
if (NULL == mpCPU) {
|
||||
throw MKGenException("Unable to initialize VM (CPU).");
|
||||
}
|
||||
/*
|
||||
mpDisp = new Display();
|
||||
if (NULL == mpDisp) {
|
||||
throw MKGenException("Unable to initialize VM (Display).");
|
||||
}
|
||||
} */
|
||||
mpConIO = new ConsoleIO();
|
||||
if (NULL == mpConIO) {
|
||||
throw MKGenException("Unable to initialize VM (ConsoleIO)");
|
||||
}
|
||||
mBeginTime = high_resolution_clock::now();
|
||||
}
|
||||
|
||||
#if defined(WINDOWS)
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: ClearScreen()
|
||||
|
@ -124,39 +168,7 @@ void VMachine::InitVM()
|
|||
*/
|
||||
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 );
|
||||
mpConIO->ClearScreen();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -170,50 +182,9 @@ void VMachine::ClearScreen()
|
|||
*/
|
||||
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 );
|
||||
mpConIO->ScrHome();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(LINUX)
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: ClearScreen()
|
||||
* Purpose: Clear the working are of the VM - Linux.
|
||||
* This is not a part of virtual display emulation.
|
||||
* Arguments: n/a
|
||||
* Returns: n/a
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void VMachine::ClearScreen()
|
||||
{
|
||||
system("clear");
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: ScrHome()
|
||||
* Purpose: Bring the console cursor to home position - Linux.
|
||||
* This is not a part of virtual display emulation.
|
||||
* Arguments: n/a
|
||||
* Returns: n/a
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void VMachine::ScrHome()
|
||||
{
|
||||
cout << "\033[1;1H";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: ShowDisp()
|
||||
|
@ -224,7 +195,7 @@ void VMachine::ScrHome()
|
|||
*/
|
||||
void VMachine::ShowDisp()
|
||||
{
|
||||
if (mCharIOActive) {
|
||||
if (mCharIOActive && NULL != mpDisp) {
|
||||
ScrHome();
|
||||
mpDisp->ShowScr();
|
||||
}
|
||||
|
@ -233,36 +204,67 @@ void VMachine::ShowDisp()
|
|||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
* Method: CalcCurrPerf()
|
||||
* Purpose: Calculate CPU emulation performance based on 1 MHz model
|
||||
* CPU.
|
||||
* Arguments: n/a
|
||||
* Returns: Integer, the % of speed as compared to 1 MHz CPU.
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
int VMachine::CalcCurrPerf()
|
||||
{
|
||||
auto lap = high_resolution_clock::now();
|
||||
auto beg = mPerfStats.begin_time;
|
||||
mPerfStats.micro_secs = duration_cast<microseconds>(lap-beg).count();
|
||||
if (!mPerfStatsActive) return 0;
|
||||
|
||||
if (mPerfStats.micro_secs > 0) {
|
||||
int currperf = (int)
|
||||
(((double)mPerfStats.cycles / (double)mPerfStats.micro_secs) * 100.0);
|
||||
auto lap = high_resolution_clock::now();
|
||||
long usec = duration_cast<microseconds>(lap-mPerfStats.begin_time).count();
|
||||
|
||||
if (usec > 0) {
|
||||
int currperf = (int)(((double)mPerfStats.cycles / (double)usec) * 100.0);
|
||||
if (mPerfStats.perf_onemhz == 0)
|
||||
mPerfStats.perf_onemhz = currperf;
|
||||
else
|
||||
mPerfStats.perf_onemhz = (mPerfStats.perf_onemhz + currperf) / 2;
|
||||
|
||||
mPerfStats.prev_cycles = mPerfStats.cycles;
|
||||
mPerfStats.prev_usec = mPerfStats.micro_secs;
|
||||
mPerfStats.prev_usec = usec;
|
||||
mPerfStats.cycles = 0;
|
||||
mPerfStats.micro_secs = 0;
|
||||
mPerfStats.begin_time = high_resolution_clock::now();
|
||||
mPerfStats.begin_time = lap;
|
||||
if (mDebugTraceActive) { // prepare and log some debug traces
|
||||
stringstream sscp, ssap;
|
||||
string msg, avgprf, curprf;
|
||||
ssap << mPerfStats.perf_onemhz;
|
||||
ssap >> avgprf;
|
||||
sscp << currperf;
|
||||
sscp >> curprf;
|
||||
msg = "Perf. measured. Curr.: " + curprf + " %, Avg.: " + avgprf + " %";
|
||||
AddDebugTrace(msg);
|
||||
}
|
||||
}
|
||||
|
||||
return mPerfStats.perf_onemhz;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: PERFSTAT_LAP (macro)
|
||||
* Purpose: Calculate emulation performace at pre-defined interval
|
||||
* of real time and clock ticks.
|
||||
* Arguments: cycles - long : number of clock ticks executed so far
|
||||
* begin - time_point<high_resolution_clock> : the moment
|
||||
* when time measurement started
|
||||
* Returns: n/a
|
||||
* Remarks: Call inside emulation execute loop.
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#define PERFSTAT_LAP(cycles,begin) \
|
||||
{ \
|
||||
if (mPerfStatsActive && cycles%PERFSTAT_CYCLES == 0) { \
|
||||
long usec = duration_cast<microseconds> \
|
||||
(high_resolution_clock::now()-begin).count(); \
|
||||
if (usec >= PERFSTAT_INTERVAL) CalcCurrPerf(); \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: Run()
|
||||
|
@ -275,18 +277,18 @@ Regs *VMachine::Run()
|
|||
{
|
||||
Regs *cpureg = NULL;
|
||||
|
||||
AddDebugTrace("Running code at: $" + Addr2HexStr(mRunAddr));
|
||||
mOpInterrupt = false;
|
||||
ClearScreen();
|
||||
ShowDisp();
|
||||
mPerfStats.cycles = 0;
|
||||
mPerfStats.micro_secs = 0;
|
||||
mPerfStats.begin_time = high_resolution_clock::now();
|
||||
while (true) {
|
||||
mPerfStats.cycles++;
|
||||
cpureg = Step();
|
||||
if (cpureg->CyclesLeft == 0 && mCharIO) ShowDisp();
|
||||
if (cpureg->SoftIrq || mOpInterrupt) break;
|
||||
//if (mPerfStats.cycles == PERFSTAT_INTERVAL) CalcCurrPerf();
|
||||
PERFSTAT_LAP(mPerfStats.cycles,mPerfStats.begin_time);
|
||||
}
|
||||
CalcCurrPerf();
|
||||
|
||||
|
@ -323,21 +325,17 @@ Regs *VMachine::Exec()
|
|||
{
|
||||
Regs *cpureg = NULL;
|
||||
|
||||
AddDebugTrace("Executing code at: $" + Addr2HexStr(mRunAddr));
|
||||
mOpInterrupt = false;
|
||||
ClearScreen();
|
||||
ShowDisp();
|
||||
mPerfStats.cycles = 0;
|
||||
mPerfStats.micro_secs = 0;
|
||||
mPerfStats.begin_time = high_resolution_clock::now();
|
||||
while (true) {
|
||||
mPerfStats.cycles++;
|
||||
cpureg = Step();
|
||||
if (cpureg->CyclesLeft == 0 && mCharIO) {
|
||||
cout << mpDisp->GetLastChar();
|
||||
cout << flush;
|
||||
}
|
||||
if (cpureg->LastRTS || mOpInterrupt) break;
|
||||
//if (mPerfStats.cycles == PERFSTAT_INTERVAL) CalcCurrPerf();
|
||||
PERFSTAT_LAP(mPerfStats.cycles,mPerfStats.begin_time);
|
||||
}
|
||||
CalcCurrPerf();
|
||||
|
||||
|
@ -383,28 +381,13 @@ Regs *VMachine::Exec(unsigned short addr)
|
|||
*/
|
||||
Regs *VMachine::Step()
|
||||
{
|
||||
unsigned short addr = mRunAddr;
|
||||
Regs *cpureg = NULL;
|
||||
|
||||
cpureg = mpCPU->ExecOpcode(addr);
|
||||
cpureg = mpCPU->ExecOpcode(mRunAddr);
|
||||
if (mGraphDispActive && cpureg->CyclesLeft == 0) {
|
||||
mpRAM->GraphDisp_ReadEvents();
|
||||
}
|
||||
addr = cpureg->PtrAddr;
|
||||
mRunAddr = addr;
|
||||
|
||||
if (cpureg->CyclesLeft == 0 && mCharIOActive && !mOpInterrupt) {
|
||||
char c = -1;
|
||||
mCharIO = false;
|
||||
|
||||
while ((c = mpRAM->GetCharOut()) != -1) {
|
||||
mOpInterrupt = mOpInterrupt || (c == OPINTERRUPT);
|
||||
if (!mOpInterrupt) {
|
||||
mpDisp->PutChar(c);
|
||||
mCharIO = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
mRunAddr = cpureg->PtrAddr;
|
||||
|
||||
return cpureg;
|
||||
}
|
||||
|
@ -458,6 +441,15 @@ int VMachine::LoadRAM(string ramfname)
|
|||
break;
|
||||
}
|
||||
mError = err;
|
||||
if (mDebugTraceActive && err) {
|
||||
stringstream sserr;
|
||||
string msg, strerr;
|
||||
sserr << err;
|
||||
sserr >> strerr;
|
||||
msg = "ERROR: LoadRAM, error code: " + strerr;
|
||||
AddDebugTrace(msg);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -560,6 +552,8 @@ bool VMachine::HasHdrData(FILE *fp)
|
|||
}
|
||||
ret = (0 == strncmp(buf, HDRMAGICKEY, l));
|
||||
|
||||
AddDebugTrace(((ret) ? "HasHdrData: YES" : "HasHdrData: NO"));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -590,6 +584,8 @@ bool VMachine::HasOldHdrData(FILE *fp)
|
|||
}
|
||||
ret = (0 == strncmp(buf, HDRMAGICKEY_OLD, l));
|
||||
|
||||
AddDebugTrace(((ret) ? "HasOldHdrData: YES" : "HasOldHdrData: NO"));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -655,20 +651,26 @@ bool VMachine::LoadHdrData(FILE *fp)
|
|||
switch (n)
|
||||
{
|
||||
case 1: mRunAddr = l + 256 * val;
|
||||
ADD_DBG_LDMEMPARHEX("LoadHdrData : mRunAddr",mRunAddr);
|
||||
break;
|
||||
case 3: mCharIOAddr = l + 256 * val;
|
||||
ADD_DBG_LDMEMPARHEX("LoadHdrData : mCharIOAddr",mCharIOAddr);
|
||||
break;
|
||||
case 5: rb = l + 256 * val;
|
||||
break;
|
||||
case 7: re = l + 256 * val;
|
||||
break;
|
||||
case 8: mCharIOActive = (val != 0);
|
||||
ADD_DBG_LDMEMPARVAL("LoadHdrData : mCharIOActive",mCharIOActive);
|
||||
break;
|
||||
case 9: if (val != 0) {
|
||||
mpRAM->EnableROM(rb, re);
|
||||
} else {
|
||||
mpRAM->SetROM(rb, re);
|
||||
}
|
||||
ADD_DBG_LDMEMPARHEX("LoadHdrData : ROM begin",rb);
|
||||
ADD_DBG_LDMEMPARHEX("LoadHdrData : ROM end",re);
|
||||
ADD_DBG_LDMEMPARVAL("LoadHdrData : ROM enable",((val!=0)?1:0));
|
||||
break;
|
||||
case 10: r.Acc = val;
|
||||
break;
|
||||
|
@ -682,9 +684,11 @@ bool VMachine::LoadHdrData(FILE *fp)
|
|||
ret = true;
|
||||
break;
|
||||
case 15: mGraphDispActive = (val != 0);
|
||||
ADD_DBG_LDMEMPARVAL("LoadHdrData : mGraphDispActive",mGraphDispActive);
|
||||
break;
|
||||
case 17: if (mGraphDispActive) SetGraphDisp(l + 256 * val);
|
||||
else DisableGraphDisp();
|
||||
ADD_DBG_LDMEMPARHEX("LoadHdrData : Graph. Disp. addr",(l + 256 * val));
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
@ -699,9 +703,6 @@ bool VMachine::LoadHdrData(FILE *fp)
|
|||
return ret;
|
||||
}
|
||||
|
||||
// Macro to save header data: v - value, fp - file pointer, n - data counter (dec)
|
||||
#define SAVE_HDR_DATA(v,fp,n) {fputc(v, fp); n--;}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: SaveHdrData()
|
||||
|
@ -788,6 +789,14 @@ int VMachine::SaveSnapshot(string fname)
|
|||
fclose(fp);
|
||||
}
|
||||
if (0 != ret) mError = VMERR_SAVE_SNAPSHOT;
|
||||
if (mDebugTraceActive && ret) {
|
||||
stringstream sserr;
|
||||
string msg, strerr;
|
||||
sserr << ret;
|
||||
sserr >> strerr;
|
||||
msg = "ERROR: SaveSnapshot, error code: " + strerr;
|
||||
AddDebugTrace(msg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -829,6 +838,7 @@ int VMachine::LoadRAMBin(string ramfname)
|
|||
Memory *pm = mpRAM;
|
||||
int ret = MEMIMGERR_RAMBIN_OPEN;
|
||||
|
||||
AddDebugTrace("LoadRAMBin : " + ramfname);
|
||||
mOldStyleHeader = false;
|
||||
if ((fp = fopen(ramfname.c_str(), "rb")) != NULL) {
|
||||
if (HasHdrData(fp) || (mOldStyleHeader = HasOldHdrData(fp))) {
|
||||
|
@ -1074,7 +1084,11 @@ int VMachine::LoadMEM(string memfname, Memory *pmem)
|
|||
bool romendset = false, engraph = false, graphset = false;
|
||||
Memory *pm = pmem;
|
||||
int err = MEMIMGERR_OK;
|
||||
|
||||
|
||||
if (mDebugTraceActive) {
|
||||
string msg = "LoadMEM: " + memfname;
|
||||
AddDebugTrace(msg);
|
||||
}
|
||||
if ((fp = fopen(memfname.c_str(), "r")) != NULL) {
|
||||
DisableROM();
|
||||
DisableCharIO();
|
||||
|
@ -1100,8 +1114,10 @@ int VMachine::LoadMEM(string memfname, Memory *pmem)
|
|||
} else {
|
||||
err = MEMIMGERR_VM65_IGNPROCWRN;
|
||||
errc++;
|
||||
cout << "LINE #" << dec << lc << " WARNING: Run address was already set. Ignoring..." << endl;
|
||||
ADD_DBG_LOADMEM(lc," WARNING: Run address was already set. Ignoring...");
|
||||
//cout << "LINE #" << dec << lc << " WARNING: Run address was already set. Ignoring..." << endl;
|
||||
}
|
||||
ADD_DBG_LDMEMPARHEX("ADDR",addr);
|
||||
continue;
|
||||
}
|
||||
// change address counter
|
||||
|
@ -1115,6 +1131,7 @@ int VMachine::LoadMEM(string memfname, Memory *pmem)
|
|||
} else {
|
||||
addr = (unsigned short) atoi(line);
|
||||
}
|
||||
ADD_DBG_LDMEMPARHEX("ORG",addr);
|
||||
continue;
|
||||
}
|
||||
// define I/O emulation address (once)
|
||||
|
@ -1133,8 +1150,10 @@ int VMachine::LoadMEM(string memfname, Memory *pmem)
|
|||
} else {
|
||||
err = MEMIMGERR_VM65_IGNPROCWRN;
|
||||
errc++;
|
||||
cout << "LINE #" << dec << lc << " WARNING: I/O address was already set. Ignoring..." << endl;
|
||||
ADD_DBG_LOADMEM(lc," WARNING: I/O address was already set. Ignoring...");
|
||||
//cout << "LINE #" << dec << lc << " WARNING: I/O address was already set. Ignoring..." << endl;
|
||||
}
|
||||
ADD_DBG_LDMEMPARHEX("IOADDR",mCharIOAddr);
|
||||
continue;
|
||||
}
|
||||
// define generic graphics display device base address (once)
|
||||
|
@ -1153,23 +1172,28 @@ int VMachine::LoadMEM(string memfname, Memory *pmem)
|
|||
} else {
|
||||
err = MEMIMGERR_VM65_IGNPROCWRN;
|
||||
errc++;
|
||||
cout << "LINE #" << dec << lc << " WARNING: graphics device base address was already set. Ignoring..." << endl;
|
||||
ADD_DBG_LOADMEM(lc," WARNING: graphics device base address was already set. Ignoring...");
|
||||
//cout << "LINE #" << dec << lc << " WARNING: graphics device base address was already set. Ignoring..." << endl;
|
||||
}
|
||||
ADD_DBG_LDMEMPARHEX("GRAPHADDR",graphaddr);
|
||||
continue;
|
||||
}
|
||||
// enable character I/O emulation
|
||||
if (0 == strncmp(line, "ENIO", 4)) {
|
||||
enio = true;
|
||||
ADD_DBG_LDMEMPARVAL("ENIO",enio);
|
||||
continue;
|
||||
}
|
||||
// enable generic graphics display emulation
|
||||
if (0 == strncmp(line, "ENGRAPH", 7)) {
|
||||
engraph = true;
|
||||
ADD_DBG_LDMEMPARVAL("ENIO",engraph);
|
||||
continue;
|
||||
}
|
||||
// enable ROM emulation
|
||||
if (0 == strncmp(line, "ENROM", 5)) {
|
||||
enrom = true;
|
||||
ADD_DBG_LDMEMPARVAL("ENROM",enrom);
|
||||
continue;
|
||||
}
|
||||
// auto execute from address
|
||||
|
@ -1189,13 +1213,16 @@ int VMachine::LoadMEM(string memfname, Memory *pmem)
|
|||
} else {
|
||||
err = MEMIMGERR_VM65_IGNPROCWRN;
|
||||
errc++;
|
||||
cout << "LINE #" << dec << lc << " WARNING: auto-exec address was already set. Ignoring..." << endl;
|
||||
ADD_DBG_LOADMEM(lc," WARNING: auto-exec address was already set. Ignoring...");
|
||||
//cout << "LINE #" << dec << lc << " WARNING: auto-exec address was already set. Ignoring..." << endl;
|
||||
}
|
||||
ADD_DBG_LDMEMPARHEX("EXEC",mRunAddr);
|
||||
continue;
|
||||
}
|
||||
// auto reset
|
||||
if (0 == strncmp(line, "RESET", 5)) {
|
||||
mAutoReset = true;
|
||||
ADD_DBG_LDMEMPARVAL("RESET",mAutoReset);
|
||||
continue;
|
||||
}
|
||||
// define ROM begin address
|
||||
|
@ -1214,8 +1241,10 @@ int VMachine::LoadMEM(string memfname, Memory *pmem)
|
|||
} else {
|
||||
err = MEMIMGERR_VM65_IGNPROCWRN;
|
||||
errc++;
|
||||
cout << "LINE #" << dec << lc << " WARNING: ROM-begin address was already set. Ignoring..." << endl;
|
||||
ADD_DBG_LOADMEM(lc," WARNING: ROM-begin address was already set. Ignoring...");
|
||||
//cout << "LINE #" << dec << lc << " WARNING: ROM-begin address was already set. Ignoring..." << endl;
|
||||
}
|
||||
ADD_DBG_LDMEMPARHEX("ROMBEGIN",rombegin);
|
||||
continue;
|
||||
}
|
||||
// define ROM end address
|
||||
|
@ -1234,8 +1263,10 @@ int VMachine::LoadMEM(string memfname, Memory *pmem)
|
|||
} else {
|
||||
err = MEMIMGERR_VM65_IGNPROCWRN;
|
||||
errc++;
|
||||
cout << "LINE #" << dec << lc << " WARNING: ROM-end address was already set. Ignoring..." << endl;
|
||||
ADD_DBG_LOADMEM(lc," WARNING: ROM-end address was already set. Ignoring...");
|
||||
//cout << "LINE #" << dec << lc << " WARNING: ROM-end address was already set. Ignoring..." << endl;
|
||||
}
|
||||
ADD_DBG_LDMEMPARHEX("ROMEND",romend);
|
||||
continue;
|
||||
}
|
||||
if (';' == *line) continue; // skip comment lines
|
||||
|
@ -1269,7 +1300,8 @@ int VMachine::LoadMEM(string memfname, Memory *pmem)
|
|||
}
|
||||
else {
|
||||
err = MEMIMGERR_VM65_OPEN;
|
||||
cout << "WARNING: Unable to open memory definition file: " << memfname << endl;
|
||||
cout << "WARNING: Unable to open memory definition file: ";
|
||||
cout << memfname << endl;
|
||||
errc++;
|
||||
}
|
||||
if (errc) {
|
||||
|
@ -1341,7 +1373,13 @@ void VMachine::SetCharIO(unsigned short addr, bool echo)
|
|||
mCharIOAddr = addr;
|
||||
mCharIOActive = true;
|
||||
mpRAM->SetCharIO(addr, echo);
|
||||
mpDisp->ClrScr();
|
||||
mpDisp = mpRAM->GetMemMapDevPtr()->GetDispPtr();
|
||||
if (mDebugTraceActive) {
|
||||
string msg;
|
||||
msg = "Char I/O activated at: $" + Addr2HexStr(addr) + ", echo: "
|
||||
+ ((echo) ? "ON" : "OFF");
|
||||
AddDebugTrace(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1356,6 +1394,8 @@ void VMachine::DisableCharIO()
|
|||
{
|
||||
mCharIOActive = false;
|
||||
mpRAM->DisableCharIO();
|
||||
AddDebugTrace("Char I/O DISABLED");
|
||||
//mpRAM->GetMemMapDevPtr()->DeactivateCharIO();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1386,16 +1426,21 @@ bool VMachine::GetCharIOActive()
|
|||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
* Method: SetGraphDisp()
|
||||
* Purpose: Set graphics device address and enable.
|
||||
* Arguments: addr - unsigned short : device base address.
|
||||
* Returns: n/a
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void VMachine::SetGraphDisp(unsigned short addr)
|
||||
{
|
||||
mGraphDispActive = true;
|
||||
mpRAM->SetGraphDisp(addr);
|
||||
if (mDebugTraceActive) {
|
||||
string msg;
|
||||
msg = "Graphics Device set at: $" + Addr2HexStr(addr) + ".";
|
||||
AddDebugTrace(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1410,6 +1455,7 @@ void VMachine::DisableGraphDisp()
|
|||
{
|
||||
mGraphDispActive = false;
|
||||
mpRAM->DisableGraphDisp();
|
||||
AddDebugTrace("Graphics Device DISABLED.");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1448,7 +1494,7 @@ bool VMachine::GetGraphDispActive()
|
|||
*/
|
||||
void VMachine::ShowIO()
|
||||
{
|
||||
if (mCharIOActive)
|
||||
if (mCharIOActive && NULL != mpDisp)
|
||||
mpDisp->ShowScr();
|
||||
}
|
||||
|
||||
|
@ -1489,6 +1535,7 @@ bool VMachine::IsAutoReset()
|
|||
void VMachine::EnableROM()
|
||||
{
|
||||
mpRAM->EnableROM();
|
||||
AddDebugTrace("ROM ENABLED.");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1502,6 +1549,7 @@ void VMachine::EnableROM()
|
|||
void VMachine::DisableROM()
|
||||
{
|
||||
mpRAM->DisableROM();
|
||||
AddDebugTrace("ROM DISABLED.");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1515,19 +1563,32 @@ void VMachine::DisableROM()
|
|||
void VMachine::SetROM(unsigned short start, unsigned short end)
|
||||
{
|
||||
mpRAM->SetROM(start, end);
|
||||
if (mDebugTraceActive) {
|
||||
string msg;
|
||||
msg = "ROM SET, Start: $" + Addr2HexStr(start) + ", End: $";
|
||||
msg += Addr2HexStr(end) + ".";
|
||||
AddDebugTrace(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
* Method: EnableROM()
|
||||
* Purpose: Sets and enables Read Only Memory range.
|
||||
* Arguments: start, end - unsigned short : start and end addresses
|
||||
* of the ROM.
|
||||
* Returns: n/a
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void VMachine::EnableROM(unsigned short start, unsigned short end)
|
||||
{
|
||||
mpRAM->EnableROM(start, end);
|
||||
if (mDebugTraceActive) {
|
||||
string msg;
|
||||
msg = "ROM ENABLED, Start: $" + Addr2HexStr(start) + ", End: $";
|
||||
msg += Addr2HexStr(end) + ".";
|
||||
AddDebugTrace(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1650,6 +1711,7 @@ void VMachine::Reset()
|
|||
mpCPU->Reset();
|
||||
Exec(mpCPU->GetRegs()->PtrAddr);
|
||||
mpCPU->mExitAtLastRTS = true;
|
||||
AddDebugTrace("*** CPU RESET ***");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1692,6 +1754,13 @@ int VMachine::GetLastError()
|
|||
void VMachine::EnableExecHistory(bool enexehist)
|
||||
{
|
||||
mpCPU->EnableExecHistory(enexehist);
|
||||
if (mDebugTraceActive) {
|
||||
string msg;
|
||||
msg = "The op-code execute history "
|
||||
+ (string)((enexehist) ? "ENABLED" : "DISABLED");
|
||||
msg += ".";
|
||||
AddDebugTrace(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1707,4 +1776,173 @@ bool VMachine::IsExecHistoryActive()
|
|||
return mpCPU->IsExecHistoryEnabled();
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void VMachine::EnableDebugTrace()
|
||||
{
|
||||
if (!mDebugTraceActive) {
|
||||
mDebugTraceActive = true;
|
||||
while (!mDebugTraces.empty()) mDebugTraces.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void VMachine::DisableDebugTrace()
|
||||
{
|
||||
mDebugTraceActive = false;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
bool VMachine::IsDebugTraceActive()
|
||||
{
|
||||
return mDebugTraceActive;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
queue<string> VMachine::GetDebugTraces()
|
||||
{
|
||||
return mDebugTraces;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void VMachine::EnablePerfStats()
|
||||
{
|
||||
if (!mPerfStatsActive) {
|
||||
mPerfStatsActive = true;
|
||||
mPerfStats.cycles = 0;
|
||||
mPerfStats.prev_cycles = 0;
|
||||
mPerfStats.prev_usec = 0;
|
||||
mPerfStats.perf_onemhz = 0;
|
||||
AddDebugTrace("Performance stats ENABLED.");
|
||||
}
|
||||
}
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void VMachine::DisablePerfStats()
|
||||
{
|
||||
mPerfStatsActive = false;
|
||||
AddDebugTrace("Performance stats DISABLED.");
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
bool VMachine::IsPerfStatsActive()
|
||||
{
|
||||
return mPerfStatsActive;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: AddDebugTrace()
|
||||
* Purpose: Add string to the debug messages queue. String is
|
||||
* prefixed with time stamp (number of microseconds since
|
||||
* start of program. Queue is maintained to not exceed
|
||||
* DBG_TRACE_SIZE. If the size is exceeded with the next
|
||||
* added debug message, the first one in the queue is
|
||||
* deleted (FIFO).
|
||||
* Arguments: msg - string : debug message.
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void VMachine::AddDebugTrace(string msg)
|
||||
{
|
||||
if (mDebugTraceActive) {
|
||||
stringstream ss;
|
||||
string mmsg;
|
||||
|
||||
// add timestamp in front (micro seconds)
|
||||
auto lap = high_resolution_clock::now();
|
||||
unsigned long usec = duration_cast<microseconds>(lap-mBeginTime).count();
|
||||
ss << usec;
|
||||
ss >> mmsg;
|
||||
mmsg += " : " + msg;
|
||||
mDebugTraces.push(mmsg);
|
||||
while (mDebugTraces.size() > DBG_TRACE_SIZE) mDebugTraces.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: Addr2HexStr()
|
||||
* Purpose: Convert 16-bit address to a hex notation string.
|
||||
* Arguments: addr - 16-bit unsigned
|
||||
* Returns: string
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
string VMachine::Addr2HexStr(unsigned short addr)
|
||||
{
|
||||
stringstream ss;
|
||||
string ret;
|
||||
|
||||
ss << hex << addr;
|
||||
ss >> ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: Addr2DecStr()
|
||||
* Purpose: Convert 16-bit address to a decimal notation string.
|
||||
* Arguments: addr - 16-bit unsigned
|
||||
* Returns: string
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
string VMachine::Addr2DecStr(unsigned short addr)
|
||||
{
|
||||
stringstream ss;
|
||||
string ret;
|
||||
|
||||
ss << addr;
|
||||
ss >> ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace MKBasic
|
||||
|
|
94
VMachine.h
94
VMachine.h
|
@ -1,3 +1,35 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: VMachine.h
|
||||
*
|
||||
* Purpose: Prototype of VMachine class and all supporting data
|
||||
* structures, enumerations, constants and macros.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef VMACHINE_H
|
||||
#define VMACHINE_H
|
||||
|
||||
|
@ -8,6 +40,7 @@
|
|||
#include "MKCpu.h"
|
||||
#include "Memory.h"
|
||||
#include "Display.h"
|
||||
#include "ConsoleIO.h"
|
||||
|
||||
//#define WINDOWS 1
|
||||
#if defined (WINDOWS)
|
||||
|
@ -21,11 +54,46 @@
|
|||
#define HDRDATALEN 128
|
||||
#define HDRDATALEN_OLD 15
|
||||
#define HEXEOF ":00000001FF"
|
||||
//#define PERFSTAT_INTERVAL 30000000
|
||||
// take emulation speed measurement every 2 minutes (120,000,000 usec)
|
||||
#define PERFSTAT_INTERVAL 120000000
|
||||
// but not more often than 30,000,000 clock ticks
|
||||
#define PERFSTAT_CYCLES 30000000
|
||||
#define DBG_TRACE_SIZE 200 // maximum size of debug messages queue
|
||||
|
||||
using namespace std;
|
||||
using namespace chrono;
|
||||
|
||||
// Macros for debug log.
|
||||
#define ADD_DBG_LOADMEM(lc,txt) \
|
||||
if (mDebugTraceActive) \
|
||||
{ \
|
||||
stringstream ss; \
|
||||
string msg, s; \
|
||||
ss << lc; \
|
||||
ss >> s; \
|
||||
msg = "LINE #" + s + txt; \
|
||||
AddDebugTrace(msg); \
|
||||
}
|
||||
|
||||
#define ADD_DBG_LDMEMPARHEX(name,value) \
|
||||
if (mDebugTraceActive) \
|
||||
{ \
|
||||
string msg; \
|
||||
msg = (string)name + " = $" + Addr2HexStr(value); \
|
||||
AddDebugTrace(msg); \
|
||||
}
|
||||
|
||||
#define ADD_DBG_LDMEMPARVAL(name,value) \
|
||||
if (mDebugTraceActive) \
|
||||
{ \
|
||||
string msg; \
|
||||
msg = (string)name + " = " + Addr2DecStr(value); \
|
||||
AddDebugTrace(msg); \
|
||||
}
|
||||
|
||||
// Macro to save header data: v - value, fp - file pointer, n - data counter (dec)
|
||||
#define SAVE_HDR_DATA(v,fp,n) {fputc(v, fp); n--;}
|
||||
|
||||
namespace MKBasic {
|
||||
|
||||
// Types of memory image definition file.
|
||||
|
@ -70,7 +138,6 @@ struct PerfStats {
|
|||
time_point<high_resolution_clock>
|
||||
begin_time; // the moment of time count start
|
||||
long cycles; // performance stats
|
||||
long micro_secs; // performance stats
|
||||
long prev_cycles; // previously measured stats
|
||||
long prev_usec; // previously measured stats
|
||||
int perf_onemhz; // avg. % perf. based on 1MHz CPU.
|
||||
|
@ -131,16 +198,24 @@ class VMachine
|
|||
// cycles per second (1 MHz CPU).
|
||||
void EnableExecHistory(bool enexehist);
|
||||
bool IsExecHistoryActive();
|
||||
void EnableDebugTrace();
|
||||
void DisableDebugTrace();
|
||||
bool IsDebugTraceActive();
|
||||
void EnablePerfStats();
|
||||
void DisablePerfStats();
|
||||
bool IsPerfStatsActive();
|
||||
queue<string> GetDebugTraces();
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
MKCpu *mpCPU;
|
||||
Memory *mpROM;
|
||||
Memory *mpRAM;
|
||||
Display *mpDisp;
|
||||
MKCpu *mpCPU; // object maintained locally
|
||||
Memory *mpROM; // object maintained locally
|
||||
Memory *mpRAM; // object maintained locally
|
||||
Display *mpDisp; // just a pointer
|
||||
ConsoleIO *mpConIO; // object maintained locally
|
||||
unsigned short mRunAddr;
|
||||
unsigned short mCharIOAddr;
|
||||
bool mCharIOActive;
|
||||
|
@ -152,6 +227,10 @@ class VMachine
|
|||
bool mGraphDispActive;
|
||||
bool mOldStyleHeader;
|
||||
PerfStats mPerfStats;
|
||||
queue<string> mDebugTraces;
|
||||
bool mPerfStatsActive;
|
||||
bool mDebugTraceActive;
|
||||
time_point<high_resolution_clock> mBeginTime;
|
||||
|
||||
int LoadMEM(string memfname, Memory *pmem);
|
||||
void ShowDisp();
|
||||
|
@ -161,6 +240,9 @@ class VMachine
|
|||
void SaveHdrData(FILE *fp);
|
||||
eMemoryImageTypes GetMemoryImageType(string ramfname);
|
||||
int CalcCurrPerf();
|
||||
void AddDebugTrace(string msg);
|
||||
string Addr2HexStr(unsigned short addr);
|
||||
string Addr2DecStr(unsigned short addr);
|
||||
};
|
||||
|
||||
} // namespace MKBasic
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
1 REM GRAPHICS DISPLAY DEVICE DEMO
|
||||
2 REM BASE ADDRESS $FFE2
|
||||
3 REM DRAW HORIZONTAL AND VERTICAL LINES
|
||||
4 REM DRAW SINUSOID
|
||||
10 GB=65506:REM SET BASE ADDRESS
|
||||
12 REM INITIALIZE, SET COLORS
|
||||
15 POKE GB+1,0:POKE GB+11,0
|
||||
16 POKE GB+3,0:POKE GB+4,255:POKE GB+5,0
|
||||
17 POKE GB+6,0:POKE GB+7,0:POKE GB+8,0
|
||||
18 POKE GB+9,3:POKE GB+9,4:POKE GB+9,0
|
||||
19 GOSUB 1120:REM DRAW SINUSOID
|
||||
20 Y=100:REM X-AXIS
|
||||
30 GOSUB 1000
|
||||
50 X=100:REM Y-AXIS
|
||||
60 GOSUB 1060
|
||||
70 REM SOME EXTRA DOTTED LINES
|
||||
80 Y=50:GOSUB 1200
|
||||
90 Y=150:GOSUB 1200
|
||||
100 X=50:GOSUB 1260
|
||||
110 X=150:GOSUB 1260
|
||||
120 PRINT "... HIT [SPACE] TO END ..."
|
||||
125 GET K$:IF K$=" " THEN END
|
||||
130 FOR I=1 TO 2000:NEXT I:REM SHORT PAUSE
|
||||
140 GOTO 15
|
||||
998 END
|
||||
999 REM ------- SUBROUTINES SECTION -------
|
||||
1000 REM DRAW HORIZONTAL LINE AT Y
|
||||
1005 POKE GB+2,Y
|
||||
1006 POKE GB+12,Y
|
||||
1020 POKE GB,0
|
||||
1025 POKE GB+10,199:POKE GB+9,5
|
||||
1050 RETURN
|
||||
1060 REM DRAW VERTICAL LINE AT X
|
||||
1070 POKE GB,X
|
||||
1075 POKE GB+10,X
|
||||
1090 POKE GB+2,0
|
||||
1095 POKE GB+12,199:POKE GB+9,5
|
||||
1110 RETURN
|
||||
1120 REM SINUSOID
|
||||
1130 FOR X=0 TO 199-4 STEP 5
|
||||
1140 XX=X*(6.28/200)
|
||||
1145 XE=(X+5)*(6.28/200)
|
||||
1150 YY=SIN(XX):YE=SIN(XE)
|
||||
1160 Y=199-INT((YY+1)*100)
|
||||
1165 Y2=199-INT((YE+1)*100)
|
||||
1170 POKE GB,X:POKE GB+2,Y
|
||||
1175 POKE GB+10,X+5:POKE GB+12,Y2:POKE GB+9,5
|
||||
1180 NEXT X
|
||||
1190 RETURN
|
||||
1200 REM DRAW DOTTED HORIZONTAL LINE AT Y
|
||||
1205 POKE GB+2,Y
|
||||
1210 FOR X=0 TO 199 STEP 4
|
||||
1220 POKE GB,X
|
||||
1230 POKE GB+9,1
|
||||
1240 NEXT X
|
||||
1250 RETURN
|
||||
1260 REM DRAW DOTTED VERTICAL LINE AT X
|
||||
1270 POKE GB,X
|
||||
1280 FOR Y=0 TO 199 STEP 4
|
||||
1290 POKE GB+2,Y
|
||||
1300 POKE GB+9,1
|
||||
1310 NEXT Y
|
||||
1320 RETURN
|
377
main.cpp
377
main.cpp
|
@ -1,3 +1,35 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: main.cpp
|
||||
*
|
||||
* Purpose: Define User Interface, Debug Console and main loop
|
||||
* of the app.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and exercise common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
|
@ -17,9 +49,16 @@ using namespace std;
|
|||
using namespace MKBasic;
|
||||
|
||||
#define ANIM_DELAY 250
|
||||
#define PROMPT_ADDR "Address (0..FFFF): "
|
||||
#define PROMPT_START_ADDR "Start address (0..FFFF): "
|
||||
#define PROMPT_RANGE_ADDR "Enter address range (0..0xFFFF).."
|
||||
#define PROMPT_END_ADDR "End address (0..FFFF): "
|
||||
|
||||
const bool ClsIfDirty = true;
|
||||
|
||||
char diss_buf[DISS_BUF_SIZE]; // last disassembled instruction buffer
|
||||
char curr_buf[DISS_BUF_SIZE]; // current disassembled instruction buffer
|
||||
|
||||
VMachine *pvm = NULL;
|
||||
Regs *preg = NULL;
|
||||
bool ioecho = false, opbrk = false, needhelp = false;
|
||||
|
@ -32,6 +71,26 @@ void ShowHelp();
|
|||
void CmdArgHelp(string prgname);
|
||||
void CopyrightBanner();
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: PressEnter2Cont()
|
||||
* Purpose: Print a message and wait for ENTER to be pressed.
|
||||
* Arguments: msg - string : message
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void PressEnter2Cont(string msg)
|
||||
{
|
||||
string mesg = msg;
|
||||
if (0 == msg.length()) mesg = "Press [ENTER]...";
|
||||
cout << mesg;
|
||||
fflush(stdin);
|
||||
while (true) {
|
||||
int c = getchar();
|
||||
if ('\n' == c || EOF == c) break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: RunSingleInstr()
|
||||
|
@ -44,9 +103,14 @@ void CopyrightBanner();
|
|||
{
|
||||
Regs *ret = NULL;
|
||||
|
||||
pvm->Disassemble(addr, diss_buf);
|
||||
// skip # cycles per op-code specs
|
||||
do {
|
||||
ret = pvm->Step(addr);
|
||||
} while (ret->CyclesLeft > 0);
|
||||
// and now execute the actual op-code
|
||||
ret = pvm->Step(addr);
|
||||
pvm->Disassemble(ret->PtrAddr, curr_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -64,13 +128,56 @@ void CopyrightBanner();
|
|||
{
|
||||
Regs *ret = NULL;
|
||||
|
||||
pvm->Disassemble(preg->PtrAddr, diss_buf);
|
||||
// skip # cycles per op-code specs
|
||||
do {
|
||||
ret = pvm->Step();
|
||||
} while (ret->CyclesLeft > 0);
|
||||
// and now execute the actual op-code
|
||||
ret = pvm->Step();
|
||||
pvm->Disassemble(ret->PtrAddr, curr_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: VMErr
|
||||
* Purpose: Data structure and macros supporting VM errors
|
||||
* messages
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define WARN_UNEXPECTED_EOF "WARNING: Unexpected EOF (image shorter than 64kB)."
|
||||
#define WARN_NOHDR_BINIMG "WARNING: No header found in binary image."
|
||||
#define WARN_HDRPRBLM_BINIMG "WARNING: Problem with binary image header."
|
||||
|
||||
struct VMErr {
|
||||
|
||||
int id;
|
||||
char text1[80];
|
||||
char text2[80];
|
||||
|
||||
} g_vmerrtbl[] = {
|
||||
|
||||
{MEMIMGERR_RAMBIN_EOF, WARN_UNEXPECTED_EOF, ""},
|
||||
{MEMIMGERR_RAMBIN_OPEN, "WARNING: Unable to open memory image file.", ""},
|
||||
{MEMIMGERR_RAMBIN_HDR, WARN_HDRPRBLM_BINIMG, ""},
|
||||
{MEMIMGERR_RAMBIN_NOHDR, WARN_NOHDR_BINIMG, ""},
|
||||
{MEMIMGERR_RAMBIN_HDRANDEOF, WARN_HDRPRBLM_BINIMG, WARN_UNEXPECTED_EOF},
|
||||
{MEMIMGERR_RAMBIN_NOHDRANDEOF,WARN_NOHDR_BINIMG, WARN_UNEXPECTED_EOF},
|
||||
{MEMIMGERR_INTELH_OPEN, "WARNING: Unable to open Intel HEX file.", ""},
|
||||
{MEMIMGERR_INTELH_SYNTAX, "ERROR: Syntax error.", ""},
|
||||
{MEMIMGERR_INTELH_FMT, "ERROR: Intel HEX format error.", ""},
|
||||
{MEMIMGERR_VM65_OPEN, "ERROR: Unable to open memory definition file.", ""},
|
||||
{MEMIMGERR_VM65_IGNPROCWRN, "WARNING: There were problems while processing memory definition file.", ""},
|
||||
{VMERR_SAVE_SNAPSHOT, "WARNING: There was a problem saving memory snapshot.", ""},
|
||||
{-1, "", ""}
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: PrintVMErr()
|
||||
|
@ -81,57 +188,23 @@ void CopyrightBanner();
|
|||
*/
|
||||
void PrintVMErr(int err)
|
||||
{
|
||||
bool pressenter = true;
|
||||
switch (err) {
|
||||
case MEMIMGERR_RAMBIN_EOF:
|
||||
cout << "WARNING: Unexpected EOF (image shorter than 64kB).";
|
||||
cout << endl;
|
||||
break;
|
||||
case MEMIMGERR_RAMBIN_OPEN:
|
||||
cout << "WARNING: Unable to open memory image file." << endl;
|
||||
break;
|
||||
case MEMIMGERR_RAMBIN_HDR:
|
||||
cout << "WARNING: Problem with binary image header." << endl;
|
||||
break;
|
||||
case MEMIMGERR_RAMBIN_NOHDR:
|
||||
cout << "WARNING: No header found in binary image." << endl;
|
||||
break;
|
||||
case MEMIMGERR_RAMBIN_HDRANDEOF:
|
||||
cout << "WARNING: Problem with binary image header." << endl;
|
||||
cout << "WARNING: Unexpected EOF (image shorter than 64kB).";
|
||||
cout << endl;
|
||||
break;
|
||||
case MEMIMGERR_RAMBIN_NOHDRANDEOF:
|
||||
cout << "WARNING: No header found in binary image." << endl;
|
||||
cout << "WARNING: Unexpected EOF (image shorter than 64kB).";
|
||||
cout << endl;
|
||||
break;
|
||||
case MEMIMGERR_INTELH_OPEN:
|
||||
cout << "WARNING: Unable to open Intel HEX file." << endl;
|
||||
break;
|
||||
case MEMIMGERR_INTELH_SYNTAX:
|
||||
cout << "ERROR: Syntax error." << endl;
|
||||
break;
|
||||
case MEMIMGERR_INTELH_FMT:
|
||||
cout << "ERROR: Intel HEX format error." << endl;
|
||||
bool pressenter = false;
|
||||
|
||||
for (int i=0; g_vmerrtbl[i].id >= 0; i++) {
|
||||
if (g_vmerrtbl[i].id == err) {
|
||||
pressenter = true;
|
||||
if (strlen(g_vmerrtbl[i].text1)) {
|
||||
cout << g_vmerrtbl[i].text1 << endl;
|
||||
}
|
||||
if (strlen(g_vmerrtbl[i].text2)) {
|
||||
cout << g_vmerrtbl[i].text2 << endl;
|
||||
}
|
||||
break;
|
||||
case MEMIMGERR_VM65_OPEN:
|
||||
cout << "ERROR: Unable to open memory definition file.";
|
||||
cout << endl;
|
||||
break;
|
||||
case MEMIMGERR_VM65_IGNPROCWRN:
|
||||
cout << "WARNING: There were problems while processing";
|
||||
cout << " memory definition file." << endl;
|
||||
break;
|
||||
case VMERR_SAVE_SNAPSHOT:
|
||||
cout << "WARNING: There was a problem saving memory snapshot.";
|
||||
cout << endl;
|
||||
break;
|
||||
default: pressenter = false; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pressenter) {
|
||||
cout << "Press [ENTER]...";
|
||||
getchar();
|
||||
PressEnter2Cont("");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,7 +229,7 @@ void trap_signal(int signum)
|
|||
pvm->SetOpInterrupt(true);
|
||||
opbrk = true;
|
||||
}
|
||||
//exit(signum);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -181,7 +254,7 @@ BOOL CtrlHandler(DWORD fdwCtrlType)
|
|||
switch( fdwCtrlType )
|
||||
{
|
||||
case CTRL_C_EVENT:
|
||||
//Beep( 750, 300 );
|
||||
|
||||
if (NULL != pvm && NULL != preg) {
|
||||
pvm->SetOpInterrupt(true);
|
||||
opbrk = true;
|
||||
|
@ -190,12 +263,12 @@ BOOL CtrlHandler(DWORD fdwCtrlType)
|
|||
|
||||
|
||||
case CTRL_CLOSE_EVENT:
|
||||
//Beep( 600, 200 );
|
||||
|
||||
cout << "Ctrl-Close event" << endl;
|
||||
return TRUE ;
|
||||
|
||||
case CTRL_BREAK_EVENT:
|
||||
//Beep( 900, 200 );
|
||||
|
||||
if (NULL != pvm && NULL != preg) {
|
||||
pvm->SetOpInterrupt(true);
|
||||
opbrk = true;
|
||||
|
@ -203,7 +276,7 @@ BOOL CtrlHandler(DWORD fdwCtrlType)
|
|||
return TRUE;
|
||||
|
||||
case CTRL_LOGOFF_EVENT:
|
||||
//Beep( 1000, 200 );
|
||||
|
||||
cout << "Ctrl-Logoff event" << endl;
|
||||
return FALSE;
|
||||
|
||||
|
@ -275,18 +348,24 @@ bool ShowRegs(Regs *preg, VMachine *pvm, bool ioecho, bool showiostat)
|
|||
bool ret = false;
|
||||
char sBuf[80] = {0};
|
||||
|
||||
sprintf(sBuf, "| PC: $%04x | Acc: $%02x (" BYTETOBINARYPATTERN ") | X: $%02x | Y: $%02x |",
|
||||
preg->PtrAddr, preg->Acc, BYTETOBINARY(preg->Acc), preg->IndX, preg->IndY);
|
||||
cout << "*-------------*-----------------------*----------*----------*" << endl;
|
||||
sprintf(sBuf, "| PC: $%04x | Acc: $%02x (" BYTETOBINARYPATTERN
|
||||
") | X: $%02x | Y: $%02x |",
|
||||
preg->PtrAddr, preg->Acc, BYTETOBINARY(preg->Acc),
|
||||
preg->IndX, preg->IndY);
|
||||
cout << "*-------------*-----------------------*----------*----------*";
|
||||
cout << endl;
|
||||
cout << sBuf << endl;
|
||||
cout << "*-------------*-----------------------*----------*----------*" << endl;
|
||||
cout << "| NV-BDIZC |" << endl;
|
||||
cout << "*-------------*-----------------------*----------*----------*";
|
||||
cout << endl;
|
||||
cout << "| NV-BDIZC |";
|
||||
cout << " : " << diss_buf << " " << endl;
|
||||
cout << "| " << bitset<8>((int)preg->Flags) << " |";
|
||||
cout << " Last instr.: " << preg->LastInstr << " " << endl;
|
||||
cout << " : " << curr_buf << " " << endl;
|
||||
cout << "*-------------*" << endl;
|
||||
cout << endl;
|
||||
cout << "Stack: $" << hex << (unsigned short)preg->PtrStack << " " << endl;
|
||||
cout << " \r";
|
||||
cout << " ";
|
||||
cout << " \r";
|
||||
// display stack contents
|
||||
cout << " [";
|
||||
int j = 0, stacklines = 1;
|
||||
|
@ -310,14 +389,19 @@ bool ShowRegs(Regs *preg, VMachine *pvm, bool ioecho, bool showiostat)
|
|||
// end display stack contents
|
||||
|
||||
if (showiostat) {
|
||||
cout << endl << "I/O status: " << (pvm->GetCharIOActive() ? "enabled" : "disabled") << ", ";
|
||||
cout << endl << "I/O status: ";
|
||||
cout << (pvm->GetCharIOActive() ? "enabled" : "disabled") << ", ";
|
||||
cout << " at: $" << hex << pvm->GetCharIOAddr() << ", ";
|
||||
cout << " local echo: " << (ioecho ? "ON" : "OFF") << "." << endl;
|
||||
cout << "Graphics status: " << (pvm->GetGraphDispActive() ? "enabled" : "disabled") << ", ";
|
||||
cout << "Graphics status: ";
|
||||
cout << (pvm->GetGraphDispActive() ? "enabled" : "disabled") << ", ";
|
||||
cout << " at: $" << hex << pvm->GetGraphDispAddr() << endl;
|
||||
cout << "ROM: " << ((pvm->IsROMEnabled()) ? "enabled." : "disabled.") << " ";
|
||||
cout << "Range: $" << hex << pvm->GetROMBegin() << " - $" << hex << pvm->GetROMEnd() << "." << endl;
|
||||
cout << "Op-code execute history: " << (pvm->IsExecHistoryActive() ? "enabled" : "disabled");
|
||||
cout << "ROM: ";
|
||||
cout << ((pvm->IsROMEnabled()) ? "enabled." : "disabled.") << " ";
|
||||
cout << "Range: $" << hex << pvm->GetROMBegin() << " - $";
|
||||
cout << hex << pvm->GetROMEnd() << "." << endl;
|
||||
cout << "Op-code execute history: ";
|
||||
cout << (pvm->IsExecHistoryActive() ? "enabled" : "disabled");
|
||||
cout << "." << endl;
|
||||
}
|
||||
cout << " \r";
|
||||
|
@ -327,8 +411,8 @@ bool ShowRegs(Regs *preg, VMachine *pvm, bool ioecho, bool showiostat)
|
|||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method:
|
||||
* Purpose:
|
||||
* Method: ShowMenu()
|
||||
* Purpose: Print available commands on the console.
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
|
@ -346,6 +430,8 @@ void ShowMenu()
|
|||
cout << " L - load memory image | O - display op-code exec. history" << endl;
|
||||
cout << " D - disassemble code in memory | Q - quit, 0 - reset, H - help" << endl;
|
||||
cout << " V - toggle graphics emulation | U - enable/disable exec. history" << endl;
|
||||
cout << " Z - enable/disable debug traces | 1 - enable/disable perf. stats" << endl;
|
||||
cout << " 2 - display debug traces | ? - show this menu" << endl;
|
||||
cout << "------------------------------------+----------------------------------------" << endl;
|
||||
}
|
||||
|
||||
|
@ -377,9 +463,9 @@ void ShowMenu()
|
|||
brk = preg->SoftIrq; \
|
||||
lrts = preg->LastRTS; \
|
||||
while(step && nsteps > 1 && !brk && !lrts && !opbrk) { \
|
||||
preg = RunSingleCurrInstr(); \
|
||||
cout << "addr: $" << hex << preg->PtrAddr << ", step: " << dec << stct; \
|
||||
cout << " \r"; \
|
||||
preg = RunSingleCurrInstr(); \
|
||||
if (anim) { \
|
||||
if (cls & ClsIfDirty) { pvm->ClearScreen(); cls = false; } \
|
||||
pvm->ScrHome(); \
|
||||
|
@ -404,13 +490,19 @@ void ShowMenu()
|
|||
*/
|
||||
void ShowSpeedStats()
|
||||
{
|
||||
if (pvm->IsPerfStatsActive()) {
|
||||
cout << endl;
|
||||
cout << dec;
|
||||
cout << "CPU emulation speed stats: " << endl;
|
||||
cout << "|-> Average speed based on 1MHz CPU: " << pvm->GetPerfStats().perf_onemhz << " %" << endl;
|
||||
cout << "|-> Last measured # of cycles exec.: " << pvm->GetPerfStats().prev_cycles << endl;
|
||||
cout << "|-> Last measured time of execution: " << pvm->GetPerfStats().prev_usec << " usec" << endl;
|
||||
cout << endl;
|
||||
cout << dec;
|
||||
cout << "CPU emulation speed stats: " << endl;
|
||||
cout << "|-> Average speed based on 1MHz CPU: " << pvm->GetPerfStats().perf_onemhz << " %" << endl;
|
||||
cout << "|-> Last measured # of cycles exec.: " << pvm->GetPerfStats().prev_cycles << endl;
|
||||
cout << "|-> Last measured time of execution: " << pvm->GetPerfStats().prev_usec << " usec" << endl;
|
||||
cout << endl;
|
||||
} else {
|
||||
cout << endl;
|
||||
cout << "Emulation performance stats is OFF." << endl;
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -425,8 +517,10 @@ void ExecHistory()
|
|||
{
|
||||
if (pvm->IsExecHistoryActive()) {
|
||||
queue<string> exechist(pvm->GetExecHistory());
|
||||
cout << "PC : INSTR ACC | X | Y | PS | SP" << endl;
|
||||
cout << "------------------------------------+-----+-----+-----+-----" << endl;
|
||||
cout << "PC : INSTR ACC | X | Y | PS | SP";
|
||||
cout << endl;
|
||||
cout << "------------------------------------+-----+-----+-----+-----";
|
||||
cout << endl;
|
||||
while (exechist.size()) {
|
||||
cout << exechist.front() << endl;
|
||||
exechist.pop();
|
||||
|
@ -478,6 +572,7 @@ unsigned int LoadImage(unsigned int newaddr)
|
|||
if (pvm->IsAutoExec()) execvm = true;
|
||||
if (newaddr == 0) newaddr = 0x10000;
|
||||
}
|
||||
PrintVMErr(pvm->GetLastError());
|
||||
|
||||
return newaddr;
|
||||
}
|
||||
|
@ -496,7 +591,7 @@ unsigned int ToggleIO(unsigned int ioaddr)
|
|||
pvm->DisableCharIO();
|
||||
cout << "I/O deactivated." << endl;
|
||||
} else {
|
||||
ioaddr = PromptNewAddress("Address (0..FFFF): ");
|
||||
ioaddr = PromptNewAddress(PROMPT_ADDR);
|
||||
cout << " [" << hex << ioaddr << "]" << endl;
|
||||
pvm->SetCharIO(ioaddr, ioecho);
|
||||
cout << "I/O activated." << endl;
|
||||
|
@ -519,7 +614,7 @@ unsigned int ToggleGrDisp(unsigned int graddr)
|
|||
pvm->DisableGraphDisp();
|
||||
cout << "Graphics display deactivated." << endl;
|
||||
} else {
|
||||
graddr = PromptNewAddress("Address (0..FFFF): ");
|
||||
graddr = PromptNewAddress(PROMPT_ADDR);
|
||||
cout << " [" << hex << graddr << "]" << endl;
|
||||
pvm->SetGraphDisp(graddr);
|
||||
cout << "Graphics display activated." << endl;
|
||||
|
@ -531,14 +626,14 @@ unsigned int ToggleGrDisp(unsigned int graddr)
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: WriteToMemory()
|
||||
* Purpose:
|
||||
* Purpose: Take user input and write to memory.
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void WriteToMemory()
|
||||
{
|
||||
unsigned int tmpaddr = PromptNewAddress("Address (0..FFFF): ");
|
||||
unsigned int tmpaddr = PromptNewAddress(PROMPT_ADDR);
|
||||
cout << " [" << hex << tmpaddr << "]" << endl;
|
||||
cout << "Enter hex bytes [00..FF] values separated with NL or spaces, end with [100]:" << endl;
|
||||
unsigned short v = 0;
|
||||
|
@ -554,7 +649,7 @@ void WriteToMemory()
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: DisassembleMemory()
|
||||
* Purpose:
|
||||
* Purpose: Disassemble machine code in memory to symbolic format.
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
|
@ -562,10 +657,10 @@ void WriteToMemory()
|
|||
void DisassembleMemory()
|
||||
{
|
||||
unsigned int addrbeg = 0x10000, addrend = 0x10000;
|
||||
cout << "Enter address range (0..0xFFFF)..." << endl;
|
||||
addrbeg = PromptNewAddress("Start address (0..FFFF): ");
|
||||
cout << PROMPT_RANGE_ADDR << endl;
|
||||
addrbeg = PromptNewAddress(PROMPT_START_ADDR);
|
||||
cout << " [" << hex << addrbeg << "]" << endl;
|
||||
addrend = PromptNewAddress("End address (0..FFFF): ");
|
||||
addrend = PromptNewAddress(PROMPT_END_ADDR);
|
||||
cout << " [" << hex << addrend << "]" << endl;
|
||||
cout << endl;
|
||||
for (unsigned int addr = addrbeg; addr <= addrend;) {
|
||||
|
@ -578,7 +673,7 @@ void DisassembleMemory()
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: DumpMemory()
|
||||
* Purpose:
|
||||
* Purpose: Display contents of memory, range entered by user.
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
|
@ -586,10 +681,10 @@ void DisassembleMemory()
|
|||
void DumpMemory()
|
||||
{
|
||||
unsigned int addrbeg = 0x10000, addrend = 0x10000;
|
||||
cout << "Enter address range (0..0xFFFF)..." << endl;
|
||||
addrbeg = PromptNewAddress("Start address (0..FFFF): ");
|
||||
cout << PROMPT_RANGE_ADDR << endl;
|
||||
addrbeg = PromptNewAddress(PROMPT_START_ADDR);
|
||||
cout << " [" << hex << addrbeg << "]" << endl;
|
||||
addrend = PromptNewAddress("End address (0..FFFF): ");
|
||||
addrend = PromptNewAddress(PROMPT_END_ADDR);
|
||||
cout << " [" << hex << addrend << "]" << endl;
|
||||
cout << endl;
|
||||
for (unsigned int addr = addrbeg; addr <= addrend; addr+=16) {
|
||||
|
@ -615,6 +710,87 @@ void DumpMemory()
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: ToggleDebugTraces()
|
||||
* Purpose: Enable/disable debug traces.
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void ToggleDebugTraces()
|
||||
{
|
||||
if (pvm->IsDebugTraceActive()) {
|
||||
pvm->DisableDebugTrace();
|
||||
cout << "Debug traces disabled." << endl;
|
||||
} else {
|
||||
pvm->EnableDebugTrace();
|
||||
cout << "Debug traces enabled." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Macro: SCRDIV_xxCOL
|
||||
* Purpose: Print line out of xx '-' signs, no NL.
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#define SCRDIV_20COL cout << "--------------------";
|
||||
#define SCRDIV_19COL cout << "-------------------";
|
||||
#define SCRDIV_79COL SCRDIV_20COL; SCRDIV_20COL; SCRDIV_20COL; SCRDIV_19COL;
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: DebugTraces()
|
||||
* Purpose: Show debug traces.
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void DebugTraces()
|
||||
{
|
||||
if (pvm->IsDebugTraceActive()) {
|
||||
queue<string> dbgtrc(pvm->GetDebugTraces());
|
||||
cout << "Time [usec] : Message" << endl;
|
||||
SCRDIV_79COL; cout << endl;
|
||||
int n=0;
|
||||
while (dbgtrc.size()) {
|
||||
cout << dbgtrc.front() << endl;
|
||||
dbgtrc.pop();
|
||||
if (n++ == 20) {
|
||||
n = 0;
|
||||
cout << endl;
|
||||
PressEnter2Cont("Press [ENTER] for more...");
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
SCRDIV_79COL; cout << endl;
|
||||
} else {
|
||||
cout << "Sorry. Debug traces are currently disabled." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: TogglePerfStats()
|
||||
* Purpose: Enable/disable performance stats.
|
||||
* Arguments:
|
||||
* Returns:
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
void TogglePerfStats()
|
||||
{
|
||||
if (pvm->IsPerfStatsActive()) {
|
||||
pvm->DisablePerfStats();
|
||||
cout << "Performance stats were disabled." << endl;
|
||||
} else {
|
||||
pvm->EnablePerfStats();
|
||||
cout << "Performance stats were enabled." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Method: LoadArgs()
|
||||
|
@ -769,7 +945,7 @@ int main(int argc, char *argv[]) {
|
|||
} else {
|
||||
|
||||
cout << endl;
|
||||
cout << "Type '?' and press ENTER for Menu ..." << endl;
|
||||
cout << "Type '?' and press [ENTER] for Menu ..." << endl;
|
||||
cout << endl;
|
||||
|
||||
}
|
||||
|
@ -805,6 +981,7 @@ int main(int argc, char *argv[]) {
|
|||
ExecHistory();
|
||||
} else if (c == 'l') { // load memory image
|
||||
newaddr = LoadImage(newaddr);
|
||||
ioaddr = pvm->GetCharIOAddr();
|
||||
} else if (c == 'k') { // toggle ROM emulation
|
||||
if (!enrom) {
|
||||
enrom = true;
|
||||
|
@ -856,7 +1033,7 @@ int main(int argc, char *argv[]) {
|
|||
WriteToMemory();
|
||||
} else if (c == 'a') { // change run address
|
||||
execaddr = stop = true;
|
||||
newaddr = PromptNewAddress("Address (0..FFFF): ");
|
||||
newaddr = PromptNewAddress(PROMPT_ADDR);
|
||||
cout << " [" << hex << newaddr << "]" << endl;
|
||||
} else if (c == 's') {
|
||||
runvm = step = stop = true;
|
||||
|
@ -875,13 +1052,13 @@ int main(int argc, char *argv[]) {
|
|||
} else if (c == 'g') { // run from new address until BRK
|
||||
runvm = true;
|
||||
execaddr = true;
|
||||
newaddr = PromptNewAddress("Address (0..FFFF): ");
|
||||
newaddr = PromptNewAddress(PROMPT_ADDR);
|
||||
cout << " [" << hex << newaddr << "]" << endl;
|
||||
show_menu = true;
|
||||
} else if (c == 'x') { // execute code at address
|
||||
execvm = true;
|
||||
execaddr = true;
|
||||
newaddr = PromptNewAddress("Address (0..FFFF): ");
|
||||
newaddr = PromptNewAddress(PROMPT_ADDR);
|
||||
cout << " [" << hex << newaddr << "]" << endl;
|
||||
show_menu = true;
|
||||
} else if (c == 'q') { // quit
|
||||
|
@ -895,6 +1072,14 @@ int main(int argc, char *argv[]) {
|
|||
cout << "Op-code execute history has been ";
|
||||
cout << (pvm->IsExecHistoryActive() ? "enabled" : "disabled") << ".";
|
||||
cout << endl;
|
||||
} else if (c == 'z') { // toggle enable/disable debug traces in VM
|
||||
ToggleDebugTraces();
|
||||
} else if (c == '2') { // show debug traces
|
||||
DebugTraces();
|
||||
} else if (c == '1') { // toggle enable/disable perf. stats
|
||||
TogglePerfStats();
|
||||
} else {
|
||||
cout << "ERROR: Unknown command." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1158,6 +1343,12 @@ D - diassemble code in memory
|
|||
U - enable/disable exec. history
|
||||
Toggle enable/disable of op-codes execute history.
|
||||
Disabling this feature improves performance.
|
||||
Z - enable/disable debug traces
|
||||
Toggle enable/disable of debug traces.
|
||||
2 - display debug traces
|
||||
Display recent debug traces.
|
||||
1 - enable/disable performance stats
|
||||
Toggle enable/disable emulation speed measurement.
|
||||
|
||||
NOTE:
|
||||
1. If no arguments provided, each command will prompt user to enter
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Project: MKBasic
|
||||
# Project: VM65
|
||||
# Makefile created by Dev-C++ 5.11
|
||||
# and modified for standalone MINGW compiler installation.
|
||||
|
||||
|
@ -7,9 +7,9 @@ SDLBASE = $(SDLDIR)
|
|||
CPP = g++.exe -D__DEBUG__
|
||||
CC = gcc.exe -D__DEBUG__
|
||||
WINDRES = windres.exe
|
||||
OBJ = main.o VMachine.o MKBasic.o MKCpu.o Memory.o Display.o GraphDisp.o MemMapDev.o MKGenException.o
|
||||
OBJ = main.o VMachine.o MKCpu.o Memory.o Display.o GraphDisp.o MemMapDev.o MKGenException.o ConsoleIO.o
|
||||
OBJ2 = bin2hex.o
|
||||
LINKOBJ = main.o VMachine.o MKBasic.o MKCpu.o Memory.o Display.o GraphDisp.o MemMapDev.o MKGenException.o
|
||||
LINKOBJ = main.o VMachine.o MKCpu.o Memory.o Display.o GraphDisp.o MemMapDev.o MKGenException.o ConsoleIO.o
|
||||
LINKOBJ2 = bin2hex.o
|
||||
LIBS = -L"C:\mingw-w64\x86_64-5.3.0\mingw64\x86_64-w64-mingw32/lib" -L"C:\mingw-w64\x86_64-5.3.0\mingw64\x86_64-w64-mingw32/lib" -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic -lmingw32
|
||||
SDLLIBS = -L"$(SDLBASE)\x86_64-w64-mingw32/lib" -lSDL2main -lSDL2
|
||||
|
@ -40,9 +40,6 @@ main.o: main.cpp
|
|||
VMachine.o: VMachine.cpp VMachine.h
|
||||
$(CPP) -c VMachine.cpp -o VMachine.o $(CXXFLAGS) $(SDLINCS)
|
||||
|
||||
MKBasic.o: MKBasic.cpp MKBasic.h
|
||||
$(CPP) -c MKBasic.cpp -o MKBasic.o $(CXXFLAGS) $(SDLINCS)
|
||||
|
||||
MKCpu.o: MKCpu.cpp MKCpu.h
|
||||
$(CPP) -c MKCpu.cpp -o MKCpu.o $(CXXFLAGS) $(SDLINCS)
|
||||
|
||||
|
@ -61,6 +58,9 @@ MemMapDev.o: MemMapDev.cpp MemMapDev.h
|
|||
MKGenException.o: MKGenException.cpp MKGenException.h
|
||||
$(CPP) -c MKGenException.cpp -o MKGenException.o $(CXXFLAGS)
|
||||
|
||||
ConsoleIO.o: ConsoleIO.cpp ConsoleIO.h
|
||||
$(CPP) -c ConsoleIO.cpp -o ConsoleIO.o $(CXXFLAGS)
|
||||
|
||||
$(BIN2): $(OBJ2)
|
||||
$(CC) $(LINKOBJ2) -o $(BIN2) $(LIBS)
|
||||
|
||||
|
|
31
system.h
31
system.h
|
@ -1,3 +1,34 @@
|
|||
/*
|
||||
*--------------------------------------------------------------------
|
||||
* Project: VM65 - Virtual Machine/CPU emulator programming
|
||||
* framework.
|
||||
*
|
||||
* File: system.h
|
||||
*
|
||||
* Purpose: Definitions related to platform portability.
|
||||
*
|
||||
* Date: 8/25/2016
|
||||
*
|
||||
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
|
||||
*
|
||||
* Contact: makarcz@yahoo.com
|
||||
*
|
||||
* License Agreement and Warranty:
|
||||
|
||||
This software is provided with No Warranty.
|
||||
I (Marek Karcz) will not be held responsible for any damage to
|
||||
computer systems, data or user's health resulting from use.
|
||||
Please proceed responsibly and apply common sense.
|
||||
This software is provided in hope that it will be useful.
|
||||
It is free of charge for non-commercial and educational use.
|
||||
Distribution of this software in non-commercial and educational
|
||||
derivative work is permitted under condition that original
|
||||
copyright notices and comments are preserved. Some 3-rd party work
|
||||
included with this project may require separate application for
|
||||
permission from their respective authors/copyright owners.
|
||||
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
#if !defined(LINUX)
|
||||
#define WINDOWS
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue