mirror of
https://github.com/makarcz/vm6502.git
synced 2024-05-31 14:41:28 +00:00
Char I/O
Improvements to character I/O emulation: * Performance. * Use native console STDIO in execute mode, text display emulation in debug mode. * Always shadow character I/O with text device emulation, even when native STDIO is used.
This commit is contained in:
parent
d99ed03232
commit
dce9babd36
647
Display.cpp
647
Display.cpp
|
@ -1,312 +1,335 @@
|
||||||
#include "Display.h"
|
#include "Display.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace MKBasic {
|
namespace MKBasic {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
Display::Display()
|
Display::Display()
|
||||||
{
|
{
|
||||||
InitScr();
|
InitScr();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
Display::~Display()
|
Display::~Display()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method: InitScr()
|
* Method: InitScr()
|
||||||
* Purpose: Initialize screen.
|
* Purpose: Initialize screen.
|
||||||
* Arguments: n/a
|
* Arguments: n/a
|
||||||
* Returns: n/a
|
* Returns: n/a
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void Display::InitScr()
|
void Display::InitScr()
|
||||||
{
|
{
|
||||||
mScrLines = SCREENDIM_ROW;
|
mLastChar = 0;
|
||||||
mScrColumns = SCREENDIM_COL;
|
mScrLines = SCREENDIM_ROW;
|
||||||
mShellConsoleWidth = GetConsoleWidth();
|
mScrColumns = SCREENDIM_COL;
|
||||||
if (mScrColumns > mShellConsoleWidth) {
|
mShellConsoleWidth = GetConsoleWidth();
|
||||||
mScrColumns = mShellConsoleWidth;
|
if (mScrColumns > mShellConsoleWidth) {
|
||||||
}
|
mScrColumns = mShellConsoleWidth;
|
||||||
ClrScr();
|
}
|
||||||
}
|
ClrScr();
|
||||||
|
}
|
||||||
#if defined(WINDOWS)
|
|
||||||
|
#if defined(WINDOWS)
|
||||||
#include <windows.h>
|
|
||||||
#include <conio.h>
|
#include <windows.h>
|
||||||
|
#include <conio.h>
|
||||||
/*
|
|
||||||
*--------------------------------------------------------------------
|
/*
|
||||||
* Method: GetConsoleWidth()
|
*--------------------------------------------------------------------
|
||||||
* Purpose: Obtain the width of shell console (the real one, not
|
* Method: GetConsoleWidth()
|
||||||
* the emulated one) on Windows.
|
* Purpose: Obtain the width of shell console (the real one, not
|
||||||
* Arguments: n/a
|
* the emulated one) on Windows.
|
||||||
* Returns: int - width of the shell console.
|
* Arguments: n/a
|
||||||
*--------------------------------------------------------------------
|
* Returns: int - width of the shell console.
|
||||||
*/
|
*--------------------------------------------------------------------
|
||||||
int Display::GetConsoleWidth()
|
*/
|
||||||
{
|
int Display::GetConsoleWidth()
|
||||||
HANDLE hStdOut;
|
{
|
||||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
HANDLE hStdOut;
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
|
|
||||||
if (hStdOut == INVALID_HANDLE_VALUE) return -1;
|
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
|
||||||
|
if (hStdOut == INVALID_HANDLE_VALUE) return -1;
|
||||||
if (!GetConsoleScreenBufferInfo( hStdOut, &csbi )) return -2;
|
|
||||||
|
if (!GetConsoleScreenBufferInfo( hStdOut, &csbi )) return -2;
|
||||||
return csbi.dwSize.X;
|
|
||||||
}
|
return csbi.dwSize.X;
|
||||||
|
}
|
||||||
#endif
|
|
||||||
|
#endif
|
||||||
#if defined(LINUX)
|
|
||||||
|
#if defined(LINUX)
|
||||||
#include <termcap.h>
|
|
||||||
|
#include <termcap.h>
|
||||||
/*
|
|
||||||
*--------------------------------------------------------------------
|
/*
|
||||||
* Method: GetConsoleWidth()
|
*--------------------------------------------------------------------
|
||||||
* Purpose: Obtain the width of shell console (the real one, not
|
* Method: GetConsoleWidth()
|
||||||
* the emulated one) on Linux.
|
* Purpose: Obtain the width of shell console (the real one, not
|
||||||
* Arguments: n/a
|
* the emulated one) on Linux.
|
||||||
* Returns: int - width of the shell console.
|
* Arguments: n/a
|
||||||
*--------------------------------------------------------------------
|
* Returns: int - width of the shell console.
|
||||||
*/
|
*--------------------------------------------------------------------
|
||||||
int Display::GetConsoleWidth()
|
*/
|
||||||
{
|
int Display::GetConsoleWidth()
|
||||||
unsigned int conwidth = SCREENDIM_COL;
|
{
|
||||||
char *termtype = getenv("TERM");
|
unsigned int conwidth = SCREENDIM_COL;
|
||||||
static char termbuf[2048];
|
char *termtype = getenv("TERM");
|
||||||
|
static char termbuf[2048];
|
||||||
if (tgetent(termbuf, termtype) < 0) {
|
|
||||||
cout << "WARNING: Could not access the termcap data base." << endl;
|
if (tgetent(termbuf, termtype) < 0) {
|
||||||
cout << " Unable to determine console width." << endl;
|
cout << "WARNING: Could not access the termcap data base." << endl;
|
||||||
} else {
|
cout << " Unable to determine console width." << endl;
|
||||||
conwidth = tgetnum("co");
|
} else {
|
||||||
}
|
conwidth = tgetnum("co");
|
||||||
|
}
|
||||||
return conwidth;
|
|
||||||
}
|
return conwidth;
|
||||||
|
}
|
||||||
#endif
|
|
||||||
|
#endif
|
||||||
/*
|
|
||||||
*--------------------------------------------------------------------
|
/*
|
||||||
* Method:
|
*--------------------------------------------------------------------
|
||||||
* Purpose:
|
* Method:
|
||||||
* Arguments:
|
* Purpose:
|
||||||
* Returns:
|
* Arguments:
|
||||||
*--------------------------------------------------------------------
|
* Returns:
|
||||||
*/
|
*--------------------------------------------------------------------
|
||||||
void Display::ScrollUp()
|
*/
|
||||||
{
|
void Display::ScrollUp()
|
||||||
for (unsigned int row=0; row<mScrLines-1; row++) {
|
{
|
||||||
for (unsigned int col=0; col<mScrColumns; col++) {
|
for (unsigned int row=0; row<mScrLines-1; row++) {
|
||||||
mScreen[col][row] = mScreen[col][row+1];
|
for (unsigned int col=0; col<mScrColumns; col++) {
|
||||||
}
|
mScreen[row][col] = mScreen[row+1][col];
|
||||||
}
|
}
|
||||||
for (unsigned int col=0; col<mScrColumns; col++) {
|
}
|
||||||
mScreen[col][mScrLines-1] = ' ';
|
for (unsigned int col=0; col<mScrColumns; col++) {
|
||||||
}
|
mScreen[mScrLines-1][col] = ' ';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/*
|
|
||||||
*--------------------------------------------------------------------
|
/*
|
||||||
* Method: GotoXY()
|
*--------------------------------------------------------------------
|
||||||
* Purpose: Move cursor to new coordinates.
|
* Method: GotoXY()
|
||||||
* Arguments: col, row - integer values, new cursor coordinates
|
* Purpose: Move cursor to new coordinates.
|
||||||
* Returns: n/a
|
* Arguments: col, row - integer values, new cursor coordinates
|
||||||
*--------------------------------------------------------------------
|
* Returns: n/a
|
||||||
*/
|
*--------------------------------------------------------------------
|
||||||
void Display::GotoXY(unsigned int col, unsigned int row)
|
*/
|
||||||
{
|
void Display::GotoXY(unsigned int col, unsigned int row)
|
||||||
if (col < mScrColumns && row < mScrLines) {
|
{
|
||||||
mCursorCoord.col = col;
|
if (col < mScrColumns && row < mScrLines) {
|
||||||
mCursorCoord.row = row;
|
mCursorCoord.col = col;
|
||||||
}
|
mCursorCoord.row = row;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/*
|
|
||||||
*--------------------------------------------------------------------
|
/*
|
||||||
* Method:
|
*--------------------------------------------------------------------
|
||||||
* Purpose:
|
* Method:
|
||||||
* Arguments:
|
* Purpose:
|
||||||
* Returns:
|
* Arguments:
|
||||||
*--------------------------------------------------------------------
|
* Returns:
|
||||||
*/
|
*--------------------------------------------------------------------
|
||||||
bool Display::IsSpecChar(char c)
|
*/
|
||||||
{
|
bool Display::IsSpecChar(char c)
|
||||||
bool ret = false;
|
{
|
||||||
char sct[] = {SCREENSPECCHARS_NL,
|
bool ret = false;
|
||||||
SCREENSPECCHARS_CR,
|
char sct[] = {SCREENSPECCHARS_NL,
|
||||||
SCREENSPECCHARS_TB,
|
SCREENSPECCHARS_CR,
|
||||||
SCREENSPECCHARS_BS,
|
SCREENSPECCHARS_TB,
|
||||||
SCREENSPECCHARS_BE,
|
SCREENSPECCHARS_BS,
|
||||||
0};
|
SCREENSPECCHARS_BE,
|
||||||
|
0};
|
||||||
for (unsigned int i=0; i<strlen(sct); i++) {
|
|
||||||
if (c == sct[i]) {
|
for (unsigned int i=0; i<strlen(sct); i++) {
|
||||||
ret = true;
|
if (c == sct[i]) {
|
||||||
break;
|
ret = true;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return ret;
|
|
||||||
}
|
return ret;
|
||||||
|
}
|
||||||
/*
|
|
||||||
*--------------------------------------------------------------------
|
/*
|
||||||
* Method: PutChar()
|
*--------------------------------------------------------------------
|
||||||
* Purpose: Output character to console. If going outside
|
* Method: PutChar()
|
||||||
* lower-right corner, scroll the contents up.
|
* Purpose: Output character to console. If going outside
|
||||||
* Arguments: c - character to output.
|
* lower-right corner, scroll the contents up.
|
||||||
* Returns: n/a
|
* Arguments: c - character to output.
|
||||||
*--------------------------------------------------------------------
|
* Returns: n/a
|
||||||
*/
|
*--------------------------------------------------------------------
|
||||||
void Display::PutChar(char c)
|
*/
|
||||||
{
|
void Display::PutChar(char c)
|
||||||
if (isalnum(c) || ispunct(c) || isspace(c) || IsSpecChar(c))
|
{
|
||||||
{
|
if (isalnum(c) || ispunct(c) || isspace(c) || IsSpecChar(c))
|
||||||
if (c == SCREENSPECCHARS_NL) {
|
{
|
||||||
//mCursorCoord.col = 0;
|
if (c == SCREENSPECCHARS_NL) {
|
||||||
mCursorCoord.row++;
|
mLastChar = SCREENSPECCHARS_NL;
|
||||||
if (mCursorCoord.row >= mScrLines) {
|
//mCursorCoord.col = 0;
|
||||||
ScrollUp();
|
mCursorCoord.row++;
|
||||||
mCursorCoord.row = mScrLines-1;
|
if (mCursorCoord.row >= mScrLines) {
|
||||||
}
|
ScrollUp();
|
||||||
} else if (c == SCREENSPECCHARS_CR) {
|
mCursorCoord.row = mScrLines-1;
|
||||||
mCursorCoord.col = 0;
|
}
|
||||||
} else if (c == SCREENSPECCHARS_TB) {
|
} else if (c == SCREENSPECCHARS_CR) {
|
||||||
mCursorCoord.col += TABSIZE;
|
mLastChar = SCREENSPECCHARS_CR;
|
||||||
if (mCursorCoord.col >= mScrColumns) {
|
mCursorCoord.col = 0;
|
||||||
mCursorCoord.col = mScrColumns-1; // must work on it some more
|
} else if (c == SCREENSPECCHARS_TB) {
|
||||||
}
|
mLastChar = SCREENSPECCHARS_TB;
|
||||||
} else if (c == SCREENSPECCHARS_BS) {
|
mCursorCoord.col += TABSIZE;
|
||||||
if (mCursorCoord.col > 0) mCursorCoord.col--;
|
if (mCursorCoord.col >= mScrColumns) {
|
||||||
} else if (c == SCREENSPECCHARS_BE) {
|
mCursorCoord.col = mScrColumns-1; // must work on it some more
|
||||||
// no action
|
}
|
||||||
}
|
} else if (c == SCREENSPECCHARS_BS) {
|
||||||
else {
|
mLastChar = SCREENSPECCHARS_BS;
|
||||||
mScreen[mCursorCoord.col][mCursorCoord.row] = c;
|
if (mCursorCoord.col > 0) mCursorCoord.col--;
|
||||||
mCursorCoord.col++;
|
} else if (c == SCREENSPECCHARS_BE) {
|
||||||
if (mCursorCoord.col >= mScrColumns) {
|
mLastChar = SCREENSPECCHARS_BE;
|
||||||
mCursorCoord.col = 0;
|
// no action
|
||||||
mCursorCoord.row++;
|
}
|
||||||
if (mCursorCoord.row >= mScrLines) {
|
else {
|
||||||
ScrollUp();
|
mScreen[mCursorCoord.row][mCursorCoord.col] = c;
|
||||||
mCursorCoord.row = mScrLines-1;
|
mLastChar = c;
|
||||||
}
|
mCursorCoord.col++;
|
||||||
}
|
if (mCursorCoord.col >= mScrColumns) {
|
||||||
}
|
mCursorCoord.col = 0;
|
||||||
}
|
mCursorCoord.row++;
|
||||||
}
|
if (mCursorCoord.row >= mScrLines) {
|
||||||
|
ScrollUp();
|
||||||
/*
|
mCursorCoord.row = mScrLines-1;
|
||||||
*--------------------------------------------------------------------
|
}
|
||||||
* Method: ClrScr()
|
}
|
||||||
* Purpose: Fill the screen with spaces. Set cursor in left-upper
|
}
|
||||||
* corner.
|
}
|
||||||
* Arguments: n/a
|
}
|
||||||
* Returns: n/a
|
|
||||||
*--------------------------------------------------------------------
|
/*
|
||||||
*/
|
*--------------------------------------------------------------------
|
||||||
void Display::ClrScr()
|
* Method: ClrScr()
|
||||||
{
|
* Purpose: Fill the screen with spaces. Set cursor in left-upper
|
||||||
for (unsigned int col=0; col<mScrColumns; col++) {
|
* corner.
|
||||||
for (unsigned int row=0; row<mScrLines; row++) {
|
* Arguments: n/a
|
||||||
mScreen[col][row] = ' ';
|
* Returns: n/a
|
||||||
}
|
*--------------------------------------------------------------------
|
||||||
}
|
*/
|
||||||
mCursorCoord.col = mCursorCoord.row = 0;
|
void Display::ClrScr()
|
||||||
}
|
{
|
||||||
|
for (unsigned int col=0; col<mScrColumns; col++) {
|
||||||
/*
|
for (unsigned int row=0; row<mScrLines; row++) {
|
||||||
*--------------------------------------------------------------------
|
mScreen[row][col] = ' ';
|
||||||
* Method:
|
}
|
||||||
* Purpose:
|
}
|
||||||
* Arguments:
|
mCursorCoord.col = mCursorCoord.row = 0;
|
||||||
* Returns:
|
}
|
||||||
*--------------------------------------------------------------------
|
|
||||||
*/
|
/*
|
||||||
char Display::GetCharAt(unsigned int col, unsigned int row)
|
*--------------------------------------------------------------------
|
||||||
{
|
* Method:
|
||||||
char c = -1;
|
* Purpose:
|
||||||
|
* Arguments:
|
||||||
if (col < mScrColumns && row < mScrLines)
|
* Returns:
|
||||||
c = mScreen[col][row];
|
*--------------------------------------------------------------------
|
||||||
|
*/
|
||||||
return c;
|
char Display::GetCharAt(unsigned int col, unsigned int row)
|
||||||
}
|
{
|
||||||
|
char c = -1;
|
||||||
/*
|
|
||||||
*--------------------------------------------------------------------
|
if (col < mScrColumns && row < mScrLines)
|
||||||
* Method: ShowScr()
|
c = mScreen[row][col];
|
||||||
* Purpose: Display contents of the emulated console on a... well,
|
|
||||||
* real console.
|
return c;
|
||||||
* Arguments: n/a
|
}
|
||||||
* Returns: n/a
|
|
||||||
*--------------------------------------------------------------------
|
/*
|
||||||
*/
|
*--------------------------------------------------------------------
|
||||||
void Display::ShowScr()
|
* Method: ShowScr()
|
||||||
{
|
* Purpose: Display contents of the emulated console on a... well,
|
||||||
for (unsigned int row=0; row<mScrLines; row++) {
|
* real console.
|
||||||
string line;
|
* Arguments: n/a
|
||||||
line.clear();
|
* Returns: n/a
|
||||||
for (unsigned int col=0; col<mScrColumns; col++) {
|
*--------------------------------------------------------------------
|
||||||
char c = mScreen[col][row];
|
*/
|
||||||
if (mCursorCoord.col == col && mCursorCoord.row == row) {
|
void Display::ShowScr()
|
||||||
c = '_';
|
{
|
||||||
}
|
char buf[SCREENDIM_COL] = {0};
|
||||||
line = line + c;
|
string scr;
|
||||||
}
|
scr.clear();
|
||||||
cout << line;
|
for (unsigned int row=0; row<mScrLines; row++) {
|
||||||
// add extra NL if the real console is wider than emulated one
|
char *linebuf = &(mScreen[row][0]);
|
||||||
if (mShellConsoleWidth > mScrColumns) cout << endl;
|
memset(buf, 0, mScrColumns);
|
||||||
}
|
strncpy(buf, linebuf, mScrColumns);
|
||||||
}
|
buf[mScrColumns] = 0;
|
||||||
|
if (mCursorCoord.row == row) {
|
||||||
/*
|
buf[mCursorCoord.col] = '_';
|
||||||
*--------------------------------------------------------------------
|
}
|
||||||
* Method: GetCursorCoord()
|
string line(buf);
|
||||||
* Purpose: Get cursor coordinates.
|
// add extra NL if the real console is wider than emulated one
|
||||||
* Arguments: n/a
|
if (mShellConsoleWidth > mScrColumns) line = line + "\n";
|
||||||
* Returns: pointer to cursor coordinates
|
scr = scr + line;
|
||||||
*--------------------------------------------------------------------
|
}
|
||||||
*/
|
cout << scr;
|
||||||
CursorCoord *Display::GetCursorCoord()
|
}
|
||||||
{
|
|
||||||
return &mCursorCoord;
|
/*
|
||||||
}
|
*--------------------------------------------------------------------
|
||||||
|
* Method: GetCursorCoord()
|
||||||
} // namespace MKBasic
|
* Purpose: Get cursor coordinates.
|
||||||
|
* Arguments: n/a
|
||||||
|
* Returns: pointer to cursor coordinates
|
||||||
|
*--------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
CursorCoord *Display::GetCursorCoord()
|
||||||
|
{
|
||||||
|
return &mCursorCoord;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*--------------------------------------------------------------------
|
||||||
|
* Method:
|
||||||
|
* Purpose:
|
||||||
|
* Arguments:
|
||||||
|
* Returns:
|
||||||
|
*--------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
char Display::GetLastChar()
|
||||||
|
{
|
||||||
|
return mLastChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace MKBasic
|
||||||
|
|
122
Display.h
122
Display.h
|
@ -1,60 +1,62 @@
|
||||||
#ifndef DISPLAY_H
|
#ifndef DISPLAY_H
|
||||||
#define DISPLAY_H
|
#define DISPLAY_H
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
#define TABSIZE 4
|
#define TABSIZE 4
|
||||||
|
|
||||||
namespace MKBasic {
|
namespace MKBasic {
|
||||||
|
|
||||||
enum eScreenDimensions {
|
enum eScreenDimensions {
|
||||||
SCREENDIM_COL = 80,
|
SCREENDIM_COL = 80,
|
||||||
SCREENDIM_ROW = 24
|
SCREENDIM_ROW = 24
|
||||||
};
|
};
|
||||||
|
|
||||||
enum eScreenSpecChars {
|
enum eScreenSpecChars {
|
||||||
SCREENSPECCHARS_NL = (int)'\n', // new line
|
SCREENSPECCHARS_NL = (int)'\n', // new line
|
||||||
SCREENSPECCHARS_CR = (int)'\r', // caret
|
SCREENSPECCHARS_CR = (int)'\r', // caret
|
||||||
SCREENSPECCHARS_TB = (int)'\t', // tab
|
SCREENSPECCHARS_TB = (int)'\t', // tab
|
||||||
SCREENSPECCHARS_BS = (int)'\b', // backspace
|
SCREENSPECCHARS_BS = (int)'\b', // backspace
|
||||||
SCREENSPECCHARS_BE = (int)'\a' // bell
|
SCREENSPECCHARS_BE = (int)'\a' // bell
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CursorCoord {
|
struct CursorCoord {
|
||||||
unsigned int row;
|
unsigned int row;
|
||||||
unsigned int col;
|
unsigned int col;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Display
|
class Display
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Display();
|
Display();
|
||||||
~Display();
|
~Display();
|
||||||
void GotoXY(unsigned int col, unsigned int row);
|
void GotoXY(unsigned int col, unsigned int row);
|
||||||
void PutChar(char c);
|
void PutChar(char c);
|
||||||
void ClrScr();
|
void ClrScr();
|
||||||
char GetCharAt(unsigned int col, unsigned int row);
|
char GetCharAt(unsigned int col, unsigned int row);
|
||||||
void ShowScr();
|
void ShowScr();
|
||||||
CursorCoord *GetCursorCoord();
|
CursorCoord *GetCursorCoord();
|
||||||
|
char GetLastChar();
|
||||||
protected:
|
|
||||||
|
protected:
|
||||||
private:
|
|
||||||
|
private:
|
||||||
char mScreen[SCREENDIM_COL][SCREENDIM_ROW];
|
|
||||||
CursorCoord mCursorCoord;
|
char mScreen[SCREENDIM_ROW][SCREENDIM_COL];
|
||||||
unsigned int mShellConsoleWidth;
|
char mLastChar;
|
||||||
unsigned int mScrLines;
|
CursorCoord mCursorCoord;
|
||||||
unsigned int mScrColumns;
|
unsigned int mShellConsoleWidth;
|
||||||
|
unsigned int mScrLines;
|
||||||
void InitScr();
|
unsigned int mScrColumns;
|
||||||
void ScrollUp();
|
|
||||||
bool IsSpecChar(char c);
|
void InitScr();
|
||||||
int GetConsoleWidth();
|
void ScrollUp();
|
||||||
|
bool IsSpecChar(char c);
|
||||||
};
|
int GetConsoleWidth();
|
||||||
|
|
||||||
} // namespace MKBasic
|
};
|
||||||
|
|
||||||
#endif
|
} // namespace MKBasic
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
926
Memory.cpp
926
Memory.cpp
|
@ -1,463 +1,463 @@
|
||||||
|
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#if defined(WINDOWS)
|
#if defined(WINDOWS)
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//#define DBG 1
|
//#define DBG 1
|
||||||
#if defined (DBG)
|
#if defined (DBG)
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace MKBasic {
|
namespace MKBasic {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
Memory::Memory()
|
Memory::Memory()
|
||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
Memory::~Memory()
|
Memory::~Memory()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void Memory::Initialize()
|
void Memory::Initialize()
|
||||||
{
|
{
|
||||||
unsigned short addr = 0;
|
unsigned short addr = 0;
|
||||||
for (int i=0; i < 0xFFFF; i++) {
|
for (int i=0; i < 0xFFFF; i++) {
|
||||||
m8bitMem[addr++] = 0;
|
m8bitMem[addr++] = 0;
|
||||||
}
|
}
|
||||||
mCharIOAddr = CHARIO_ADDR;
|
mCharIOAddr = CHARIO_ADDR;
|
||||||
mCharIOActive = false;
|
mCharIOActive = false;
|
||||||
mIOEcho = false;
|
mIOEcho = false;
|
||||||
mInBufDataBegin = mInBufDataEnd = 0;
|
mInBufDataBegin = mInBufDataEnd = 0;
|
||||||
mOutBufDataBegin = mOutBufDataEnd = 0;
|
mOutBufDataBegin = mOutBufDataEnd = 0;
|
||||||
mROMBegin = ROM_BEGIN;
|
mROMBegin = ROM_BEGIN;
|
||||||
mROMEnd = ROM_END;
|
mROMEnd = ROM_END;
|
||||||
mROMActive = false;
|
mROMActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(LINUX)
|
#if defined(LINUX)
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
struct termios orig_termios;
|
struct termios orig_termios;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void reset_terminal_mode()
|
void reset_terminal_mode()
|
||||||
{
|
{
|
||||||
tcsetattr(0, TCSANOW, &orig_termios);
|
tcsetattr(0, TCSANOW, &orig_termios);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void Memory::set_conio_terminal_mode()
|
void Memory::set_conio_terminal_mode()
|
||||||
{
|
{
|
||||||
struct termios new_termios;
|
struct termios new_termios;
|
||||||
|
|
||||||
/* take two copies - one for now, one for later */
|
/* take two copies - one for now, one for later */
|
||||||
tcgetattr(0, &orig_termios);
|
tcgetattr(0, &orig_termios);
|
||||||
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
|
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
|
||||||
|
|
||||||
/* register cleanup handler, and set the new terminal mode */
|
/* register cleanup handler, and set the new terminal mode */
|
||||||
atexit(reset_terminal_mode);
|
atexit(reset_terminal_mode);
|
||||||
cfmakeraw(&new_termios);
|
cfmakeraw(&new_termios);
|
||||||
tcsetattr(0, TCSANOW, &new_termios);
|
tcsetattr(0, TCSANOW, &new_termios);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
int Memory::kbhit()
|
int Memory::kbhit()
|
||||||
{
|
{
|
||||||
struct timeval tv = { 0L, 0L };
|
struct timeval tv = { 0L, 0L };
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(0, &fds);
|
FD_SET(0, &fds);
|
||||||
return select(1, &fds, NULL, NULL, &tv);
|
return select(1, &fds, NULL, NULL, &tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
int Memory::getch()
|
int Memory::getch()
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
if ((r = read(0, &c, sizeof(c))) < 0) {
|
if ((r = read(0, &c, sizeof(c))) < 0) {
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void Memory::EnableROM()
|
void Memory::EnableROM()
|
||||||
{
|
{
|
||||||
mROMActive = true;
|
mROMActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void Memory::DisableROM()
|
void Memory::DisableROM()
|
||||||
{
|
{
|
||||||
mROMActive = false;
|
mROMActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void Memory::SetROM(unsigned short start, unsigned short end)
|
void Memory::SetROM(unsigned short start, unsigned short end)
|
||||||
{
|
{
|
||||||
if (mROMEnd > mROMBegin) {
|
if (mROMEnd > mROMBegin) {
|
||||||
mROMBegin = start;
|
mROMBegin = start;
|
||||||
mROMEnd = end;
|
mROMEnd = end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void Memory::EnableROM(unsigned short start, unsigned short end)
|
void Memory::EnableROM(unsigned short start, unsigned short end)
|
||||||
{
|
{
|
||||||
SetROM(start,end);
|
SetROM(start,end);
|
||||||
EnableROM();
|
EnableROM();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method: ReadCharKb()
|
* Method: ReadCharKb()
|
||||||
* Purpose: If char I/O active, read character from console
|
* Purpose: If char I/O active, read character from console
|
||||||
* (non-blocking) and put in an input FIFO buffer.
|
* (non-blocking) and put in an input FIFO buffer.
|
||||||
* Arguments: nonblock - if true, works in non-blocking mode
|
* Arguments: nonblock - if true, works in non-blocking mode
|
||||||
* Returns: n/a
|
* Returns: n/a
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
unsigned char Memory::ReadCharKb(bool nonblock)
|
unsigned char Memory::ReadCharKb(bool nonblock)
|
||||||
{
|
{
|
||||||
unsigned char ret = 0;
|
unsigned char ret = 0;
|
||||||
if (mCharIOActive) {
|
if (mCharIOActive) {
|
||||||
#if defined(LINUX)
|
#if defined(LINUX)
|
||||||
set_conio_terminal_mode();
|
set_conio_terminal_mode();
|
||||||
#endif
|
#endif
|
||||||
static int c = ' ';
|
static int c = ' ';
|
||||||
putchar('\n');
|
//putchar('\n');
|
||||||
if (mIOEcho && isprint(c)) putchar(c);
|
if (mIOEcho && isprint(c)) putchar(c);
|
||||||
else putchar(' ');
|
//else putchar(' ');
|
||||||
fputs("<-Character Input (CTRL-Y to BREAK) ?\r",stdout);
|
//fputs("<-Character Input (CTRL-Y to BREAK) ?\r",stdout);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
if (!nonblock) while(!kbhit());
|
if (!nonblock) while(!kbhit());
|
||||||
else c = 0;
|
else c = 0;
|
||||||
c = getch();
|
c = getch();
|
||||||
#if defined(LINUX)
|
#if defined(LINUX)
|
||||||
if (c == 3) { // capture CTRL-C in CONIO mode
|
if (c == 3) { // capture CTRL-C in CONIO mode
|
||||||
reset_terminal_mode();
|
reset_terminal_mode();
|
||||||
kill(getpid(),SIGINT);
|
kill(getpid(),SIGINT);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
fputs(" \r",stdout);
|
//fputs(" \r",stdout);
|
||||||
fflush(stdout);
|
//fflush(stdout);
|
||||||
mCharIOBufIn[mInBufDataEnd] = c;
|
mCharIOBufIn[mInBufDataEnd] = c;
|
||||||
mInBufDataEnd++;
|
mInBufDataEnd++;
|
||||||
if (mInBufDataEnd >= CHARIO_BUF_SIZE) mInBufDataEnd = 0;
|
if (mInBufDataEnd >= CHARIO_BUF_SIZE) mInBufDataEnd = 0;
|
||||||
ret = c;
|
ret = c;
|
||||||
#if defined(LINUX)
|
#if defined(LINUX)
|
||||||
reset_terminal_mode();
|
reset_terminal_mode();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method: GetCharIn()
|
* Method: GetCharIn()
|
||||||
* Purpose: Return character from the emulated character I/O FIFO
|
* Purpose: Return character from the emulated character I/O FIFO
|
||||||
* input buffer or -1 if FIFO empty or char I/O not active.
|
* input buffer or -1 if FIFO empty or char I/O not active.
|
||||||
* Arguments: n/a
|
* Arguments: n/a
|
||||||
* Returns: character
|
* Returns: character
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
char Memory::GetCharIn()
|
char Memory::GetCharIn()
|
||||||
{
|
{
|
||||||
char ret = -1;
|
char ret = -1;
|
||||||
if (mCharIOActive) {
|
if (mCharIOActive) {
|
||||||
if (mInBufDataEnd != mInBufDataBegin) {
|
if (mInBufDataEnd != mInBufDataBegin) {
|
||||||
ret = mCharIOBufIn[mInBufDataBegin];
|
ret = mCharIOBufIn[mInBufDataBegin];
|
||||||
mInBufDataBegin++;
|
mInBufDataBegin++;
|
||||||
if (mInBufDataBegin >= CHARIO_BUF_SIZE) mInBufDataBegin = 0;
|
if (mInBufDataBegin >= CHARIO_BUF_SIZE) mInBufDataBegin = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method: GetCharOut()
|
* Method: GetCharOut()
|
||||||
* Purpose: Return character from the emulated character I/O FIFO
|
* Purpose: Return character from the emulated character I/O FIFO
|
||||||
* output buffer or -1 if FIFO empty or char I/O not
|
* output buffer or -1 if FIFO empty or char I/O not
|
||||||
* active.
|
* active.
|
||||||
* Arguments: n/a
|
* Arguments: n/a
|
||||||
* Returns: character
|
* Returns: character
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
char Memory::GetCharOut()
|
char Memory::GetCharOut()
|
||||||
{
|
{
|
||||||
char ret = -1;
|
char ret = -1;
|
||||||
if (mCharIOActive) {
|
if (mCharIOActive) {
|
||||||
if (mOutBufDataEnd != mOutBufDataBegin) {
|
if (mOutBufDataEnd != mOutBufDataBegin) {
|
||||||
ret = mCharIOBufOut[mOutBufDataBegin];
|
ret = mCharIOBufOut[mOutBufDataBegin];
|
||||||
mOutBufDataBegin++;
|
mOutBufDataBegin++;
|
||||||
if (mOutBufDataBegin >= CHARIO_BUF_SIZE) mOutBufDataBegin = 0;
|
if (mOutBufDataBegin >= CHARIO_BUF_SIZE) mOutBufDataBegin = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method: PutCharIO()
|
* Method: PutCharIO()
|
||||||
* Purpose: Put character in the output char I/O FIFO buffer.
|
* Purpose: Put character in the output char I/O FIFO buffer.
|
||||||
* Arguments: c - character
|
* Arguments: c - character
|
||||||
* Returns: n/a
|
* Returns: n/a
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void Memory::PutCharIO(char c)
|
void Memory::PutCharIO(char c)
|
||||||
{
|
{
|
||||||
if (mCharIOActive) {
|
if (mCharIOActive) {
|
||||||
mCharIOBufOut[mOutBufDataEnd] = c;
|
mCharIOBufOut[mOutBufDataEnd] = c;
|
||||||
mOutBufDataEnd++;
|
mOutBufDataEnd++;
|
||||||
if (mOutBufDataEnd >= CHARIO_BUF_SIZE) mOutBufDataEnd = 0;
|
if (mOutBufDataEnd >= CHARIO_BUF_SIZE) mOutBufDataEnd = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
unsigned char Memory::Peek8bit(unsigned short addr)
|
unsigned char Memory::Peek8bit(unsigned short addr)
|
||||||
{
|
{
|
||||||
if (mCharIOActive && addr == mCharIOAddr) {
|
if (mCharIOActive && addr == mCharIOAddr) {
|
||||||
m8bitMem[addr] = ReadCharKb(false); // blocking mode input
|
m8bitMem[addr] = ReadCharKb(false); // blocking mode input
|
||||||
} else if (mCharIOActive && addr == mCharIOAddr+1) {
|
} else if (mCharIOActive && addr == mCharIOAddr+1) {
|
||||||
m8bitMem[addr] = ReadCharKb(true); // non-blocking mode input
|
m8bitMem[addr] = ReadCharKb(true); // non-blocking mode input
|
||||||
}
|
}
|
||||||
|
|
||||||
return m8bitMem[addr];
|
return m8bitMem[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
unsigned short Memory::Peek16bit(unsigned short addr)
|
unsigned short Memory::Peek16bit(unsigned short addr)
|
||||||
{
|
{
|
||||||
unsigned short ret = 0;
|
unsigned short ret = 0;
|
||||||
|
|
||||||
if (mCharIOActive && addr == mCharIOAddr) {
|
if (mCharIOActive && addr == mCharIOAddr) {
|
||||||
m8bitMem[addr] = ReadCharKb(false); // blocking mode input
|
m8bitMem[addr] = ReadCharKb(false); // blocking mode input
|
||||||
} else if (mCharIOActive && addr == mCharIOAddr+1) {
|
} else if (mCharIOActive && addr == mCharIOAddr+1) {
|
||||||
m8bitMem[addr] = ReadCharKb(true); // non-blocking mode input
|
m8bitMem[addr] = ReadCharKb(true); // non-blocking mode input
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = m8bitMem[addr++];
|
ret = m8bitMem[addr++];
|
||||||
ret += m8bitMem[addr] * 256;
|
ret += m8bitMem[addr] * 256;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method: Poke8bit()
|
* Method: Poke8bit()
|
||||||
* Purpose: Write byte to specified memory location.
|
* Purpose: Write byte to specified memory location.
|
||||||
* If the memory location is mapped to character I/O,
|
* If the memory location is mapped to character I/O,
|
||||||
* write value to output buffer and memory location.
|
* write value to output buffer and memory location.
|
||||||
* If the memory location is protected (ROM), do not
|
* If the memory location is protected (ROM), do not
|
||||||
* write the value.
|
* write the value.
|
||||||
* Arguments: addr - (0x0000..0xffff) memory address,
|
* Arguments: addr - (0x0000..0xffff) memory address,
|
||||||
* val - value (0x00..0xff)
|
* val - value (0x00..0xff)
|
||||||
* Returns: n/a
|
* Returns: n/a
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void Memory::Poke8bit(unsigned short addr, unsigned char val)
|
void Memory::Poke8bit(unsigned short addr, unsigned char val)
|
||||||
{
|
{
|
||||||
if (mCharIOActive && addr == mCharIOAddr)
|
if (mCharIOActive && addr == mCharIOAddr)
|
||||||
PutCharIO(val);
|
PutCharIO(val);
|
||||||
if (!mROMActive || (addr < mROMBegin || addr > mROMEnd)) {
|
if (!mROMActive || (addr < mROMBegin || addr > mROMEnd)) {
|
||||||
m8bitMem[addr] = val;
|
m8bitMem[addr] = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method: SetCharIO()
|
* Method: SetCharIO()
|
||||||
* Purpose: Activates and sets an address of basic character I/O
|
* Purpose: Activates and sets an address of basic character I/O
|
||||||
* emulation (console).
|
* emulation (console).
|
||||||
* Arguments: addr - address of I/O area (0x0000..0xFFFF)
|
* Arguments: addr - address of I/O area (0x0000..0xFFFF)
|
||||||
* Returns: n/a
|
* Returns: n/a
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void Memory::SetCharIO(unsigned short addr, bool echo)
|
void Memory::SetCharIO(unsigned short addr, bool echo)
|
||||||
{
|
{
|
||||||
mCharIOAddr = addr;
|
mCharIOAddr = addr;
|
||||||
mCharIOActive = true;
|
mCharIOActive = true;
|
||||||
mIOEcho = echo;
|
mIOEcho = echo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method: DisableCharIO()
|
* Method: DisableCharIO()
|
||||||
* Purpose: Deactivates basic character I/O emulation (console).
|
* Purpose: Deactivates basic character I/O emulation (console).
|
||||||
* Arguments: n/a
|
* Arguments: n/a
|
||||||
* Returns: n/a
|
* Returns: n/a
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void Memory::DisableCharIO()
|
void Memory::DisableCharIO()
|
||||||
{
|
{
|
||||||
mCharIOActive = false;
|
mCharIOActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method: GetCharIOAddr()
|
* Method: GetCharIOAddr()
|
||||||
* Purpose: Returns current address of basic character I/O area.
|
* Purpose: Returns current address of basic character I/O area.
|
||||||
* Arguments: n/a
|
* Arguments: n/a
|
||||||
* Returns: address of I/O area
|
* Returns: address of I/O area
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
unsigned short Memory::GetCharIOAddr()
|
unsigned short Memory::GetCharIOAddr()
|
||||||
{
|
{
|
||||||
return mCharIOAddr;
|
return mCharIOAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
unsigned short Memory::GetROMBegin()
|
unsigned short Memory::GetROMBegin()
|
||||||
{
|
{
|
||||||
return mROMBegin;
|
return mROMBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
unsigned short Memory::GetROMEnd()
|
unsigned short Memory::GetROMEnd()
|
||||||
{
|
{
|
||||||
return mROMEnd;
|
return mROMEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
* Method:
|
* Method:
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Returns:
|
* Returns:
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool Memory::IsROMEnabled()
|
bool Memory::IsROMEnabled()
|
||||||
{
|
{
|
||||||
return mROMActive;
|
return mROMActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace MKBasic
|
} // namespace MKBasic
|
||||||
|
|
555
ReadMe.txt
555
ReadMe.txt
|
@ -1,262 +1,293 @@
|
||||||
|
|
||||||
Project: MKBasic (VM6502).
|
Project: MKBasic (VM6502).
|
||||||
|
|
||||||
Author: Copyright (C) Marek Karcz 2016. All rights reserved.
|
Author: Copyright (C) Marek Karcz 2016. All rights reserved.
|
||||||
Free for personal and non-commercial use.
|
Free for personal and non-commercial use.
|
||||||
Code can be distributed and included in derivative work under
|
Code can be distributed and included in derivative work under
|
||||||
condition that the original copyright notice is preserved.
|
condition that the original copyright notice is preserved.
|
||||||
For use in commercial product, please contact me to obtain
|
For use in commercial product, please contact me to obtain
|
||||||
permission and discuss possible fees, at: makarcz@yahoo.com
|
permission and discuss possible fees, at: makarcz@yahoo.com
|
||||||
This software is provided with no warranty.
|
This software is provided with no warranty.
|
||||||
|
|
||||||
Purpose:
|
Purpose:
|
||||||
|
|
||||||
MOS 6502 emulator, Virtual CPU/Machine and potentially retro-style 8-bit
|
MOS 6502 emulator, Virtual CPU/Machine and potentially retro-style 8-bit
|
||||||
computer emulator.
|
computer emulator.
|
||||||
MOS-6502-compatible virtual computer featuring BASIC interpreter, machine code
|
MOS-6502-compatible virtual computer featuring BASIC interpreter, machine code
|
||||||
monitor, input/output device emulation etc.
|
monitor, input/output device emulation etc.
|
||||||
Program works in DOS/shell console (text mode) only.
|
Program works in DOS/shell console (text mode) only.
|
||||||
Makefile are included to build under Windows 32/64 (mingw compiler required)
|
Makefile are included to build under Windows 32/64 (mingw compiler required)
|
||||||
and under Linux Ubuntu or Ubuntu based.
|
and under Linux Ubuntu or Ubuntu based.
|
||||||
|
|
||||||
To build under Windows 32/64:
|
To build under Windows 32/64:
|
||||||
|
|
||||||
* Install MINGW64 under C:\mingw-w64\x86_64-5.3.0 folder.
|
* Install MINGW64 under C:\mingw-w64\x86_64-5.3.0 folder.
|
||||||
* Run mingw terminal.
|
* Run mingw terminal.
|
||||||
* Change current directory to that of this project.
|
* Change current directory to that of this project.
|
||||||
* Run: makeming.bat
|
* Run: makeming.bat
|
||||||
|
|
||||||
To build under Linux:
|
To build under Linux:
|
||||||
|
|
||||||
* Make sure C++11 compliant version of GCC compiler is installed.
|
* Make sure C++11 compliant version of GCC compiler is installed.
|
||||||
* Change current directory to that of this project.
|
* Change current directory to that of this project.
|
||||||
* Run: make clean all
|
* Run: make clean all
|
||||||
|
|
||||||
Program passed following tests:
|
Program passed following tests:
|
||||||
|
|
||||||
* 6502 functional test by Klaus Dormann
|
* 6502 functional test by Klaus Dormann
|
||||||
* AllSuiteA.asm from project hmc-6502
|
* AllSuiteA.asm from project hmc-6502
|
||||||
|
|
||||||
1. Credits/attributions:
|
1. Credits/attributions:
|
||||||
|
|
||||||
Parts of this project is based on or contains 3-rd party work:
|
Parts of this project is based on or contains 3-rd party work:
|
||||||
|
|
||||||
- Tiny Basic.
|
- Tiny Basic.
|
||||||
- Enhanced Basic by Lee Davison.
|
- Enhanced Basic by Lee Davison.
|
||||||
- Microchess by Peter Jennings (http://www.benlo.com/microchess/index.html).
|
- Microchess by Peter Jennings (http://www.benlo.com/microchess/index.html).
|
||||||
- 6502 functional test by Klaus Dormann.
|
- 6502 functional test by Klaus Dormann.
|
||||||
- All Suite test from project hmc-6502.
|
- All Suite test from project hmc-6502.
|
||||||
|
|
||||||
2. Format of the memory image definition file.
|
2. Format of the memory image definition file.
|
||||||
|
|
||||||
Program can load raw binary image of MOS 6502 opcodes.
|
Program can load raw binary image of MOS 6502 opcodes.
|
||||||
Binary image is always loaded from address $0000 and can be up to 64 kB long,
|
Binary image is always loaded from address $0000 and can be up to 64 kB long,
|
||||||
so the code must be properly located inside that image.
|
so the code must be properly located inside that image.
|
||||||
Depending on your favorite 6502 assembler, you may need to use proper command
|
Depending on your favorite 6502 assembler, you may need to use proper command
|
||||||
line arguments or configuration to achieve properly formatted binary file.
|
line arguments or configuration to achieve properly formatted binary file.
|
||||||
E.g.: if using CL65 from CC65 package, create configuration file that defines
|
E.g.: if using CL65 from CC65 package, create configuration file that defines
|
||||||
memory segments that your 6502 code uses, then all of the segments (except the
|
memory segments that your 6502 code uses, then all of the segments (except the
|
||||||
last one) must have attribute 'fill' set to 'yes' so the unsused areas are
|
last one) must have attribute 'fill' set to 'yes' so the unsused areas are
|
||||||
filled with 0-s.
|
filled with 0-s.
|
||||||
Two CFG files, one for microchess and one for All Suite from hmc-6502 project
|
Two CFG files, one for microchess and one for All Suite from hmc-6502 project
|
||||||
are supplied with this project and assembler source code adapted to be
|
are supplied with this project and assembler source code adapted to be
|
||||||
compiled with CL65.
|
compiled with CL65.
|
||||||
Other assemblers may need a different approach or may not be able to generate
|
Other assemblers may need a different approach or may not be able to generate
|
||||||
binary images that are required for this emulator.
|
binary images that are required for this emulator.
|
||||||
|
|
||||||
Program can also load memory image definition file (plain text), which is
|
Program can also load memory image definition file (plain text), which is
|
||||||
a format developed especially for this project.
|
a format developed especially for this project.
|
||||||
|
|
||||||
The format of the plain text memory image definition file is described below:
|
The format of the plain text memory image definition file is described below:
|
||||||
|
|
||||||
; comments
|
; comments
|
||||||
ADDR
|
ADDR
|
||||||
address
|
address
|
||||||
data
|
data
|
||||||
ORG
|
ORG
|
||||||
address
|
address
|
||||||
data
|
data
|
||||||
IOADDR
|
IOADDR
|
||||||
address
|
address
|
||||||
ROMBEGIN
|
ROMBEGIN
|
||||||
address
|
address
|
||||||
ROMEND
|
ROMEND
|
||||||
address
|
address
|
||||||
ENROM
|
ENROM
|
||||||
ENIO
|
ENIO
|
||||||
EXEC
|
EXEC
|
||||||
address
|
address
|
||||||
|
|
||||||
Where:
|
Where:
|
||||||
ADDR - label indicating that starting and run address will follow in
|
ADDR - label indicating that starting and run address will follow in
|
||||||
the next line
|
the next line
|
||||||
ORG - label indicating that the address counter will change to the
|
ORG - label indicating that the address counter will change to the
|
||||||
value provided in next line
|
value provided in next line
|
||||||
IOADDR - label indicating that character I/O emulation trap address will
|
IOADDR - label indicating that character I/O emulation trap address will
|
||||||
follow in the next line
|
follow in the next line
|
||||||
ROMBEGIN - label indicating that the emulated read-only memory start address
|
ROMBEGIN - label indicating that the emulated read-only memory start address
|
||||||
will follow in the next line
|
will follow in the next line
|
||||||
ROMEND - label indicating that the emulated read-only memory end address
|
ROMEND - label indicating that the emulated read-only memory end address
|
||||||
will follow in the next line
|
will follow in the next line
|
||||||
ENROM - enable read-only memory emulation
|
ENROM - enable read-only memory emulation
|
||||||
ENIO - enable character I/O emulation
|
ENIO - enable character I/O emulation
|
||||||
EXEC - label indicating that the auto-execute address will follow
|
EXEC - label indicating that the auto-execute address will follow
|
||||||
in the next line
|
in the next line
|
||||||
|
|
||||||
|
|
||||||
address - decimal or hexadecimal (prefix $) address in memory
|
address - decimal or hexadecimal (prefix $) address in memory
|
||||||
|
|
||||||
E.g:
|
E.g:
|
||||||
ADDR
|
ADDR
|
||||||
$0200
|
$0200
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
ADDR
|
ADDR
|
||||||
512
|
512
|
||||||
|
|
||||||
changes the default start address (256) to 512.
|
changes the default start address (256) to 512.
|
||||||
|
|
||||||
ORG
|
ORG
|
||||||
49152
|
49152
|
||||||
|
|
||||||
moves address counter to address 49152, following data will be
|
moves address counter to address 49152, following data will be
|
||||||
loaded from that address forward
|
loaded from that address forward
|
||||||
|
|
||||||
data - the multi-line stream of decimal of hexadecimal ($xx) values
|
data - the multi-line stream of decimal of hexadecimal ($xx) values
|
||||||
of size unsigned char (byte: 0-255) separated with spaces
|
of size unsigned char (byte: 0-255) separated with spaces
|
||||||
or commas.
|
or commas.
|
||||||
|
|
||||||
E.g.:
|
E.g.:
|
||||||
$00 $00 $00 $00
|
$00 $00 $00 $00
|
||||||
$00 $00 $00 $00
|
$00 $00 $00 $00
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
$00,$00,$00,$00
|
$00,$00,$00,$00
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
0 0 0 0
|
0 0 0 0
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
0,0,0,0
|
0,0,0,0
|
||||||
0 0 0 0
|
0 0 0 0
|
||||||
|
|
||||||
Each described above element of the memory image definition file is optional.
|
Each described above element of the memory image definition file is optional.
|
||||||
|
|
||||||
3. Character I/O emulation.
|
3. Character I/O emulation.
|
||||||
|
|
||||||
Emulator has ability to simulate a 80x25 text output display device and
|
Emulator has ability to simulate a 80x25 text output display device and
|
||||||
rudimentary character I/O functions. The emulation is implemented by the means
|
rudimentary character I/O functions. The emulation is implemented by the means
|
||||||
of trapping memory locations defined to be designated I/O emulation addresses.
|
of trapping memory locations defined to be designated I/O emulation addresses.
|
||||||
The default memory location is $E000 and also by default, the character I/O
|
The default memory location is $E000 and also by default, the character I/O
|
||||||
is disabled. It can be enabled from the debug console with 'I' command:
|
is disabled. It can be enabled from the debug console with 'I' command:
|
||||||
|
|
||||||
I hexaddr
|
I hexaddr
|
||||||
|
|
||||||
E.g.:
|
E.g.:
|
||||||
|
|
||||||
I E000
|
I E000
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
I FE00
|
I FE00
|
||||||
|
|
||||||
or by putting optional statements in the memory image dedinition file:
|
or by putting optional statements in the memory image dedinition file:
|
||||||
|
|
||||||
ENIO
|
ENIO
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
IOADDR
|
IOADDR
|
||||||
address
|
address
|
||||||
ENIO
|
ENIO
|
||||||
|
|
||||||
Where:
|
Where:
|
||||||
|
|
||||||
address - decimal or hexadecimal (with prefix '$') address in memory
|
address - decimal or hexadecimal (with prefix '$') address in memory
|
||||||
$0000 - $FFFF.
|
$0000 - $FFFF.
|
||||||
|
|
||||||
The same address is used for both, input and output operations.
|
The same address is used for both, input and output operations.
|
||||||
|
|
||||||
Reading from IOADDR inside the 6502 code invokes a blocking character
|
Reading from IOADDR inside the 6502 code invokes a blocking character
|
||||||
input function from user's DOS/shell session.
|
input function from user's DOS/shell session.
|
||||||
After user enters the character, the memory location contains the character
|
After user enters the character, the memory location contains the character
|
||||||
code and also emulated CPU Acc register contains the same code.
|
code and also emulated CPU Acc register contains the same code.
|
||||||
|
|
||||||
Reading from IOADDR+1 inside 6502 code invokes a non-blocking character
|
Reading from IOADDR+1 inside 6502 code invokes a non-blocking character
|
||||||
input function from user's DOS/shell session.
|
input function from user's DOS/shell session.
|
||||||
This function is different than blocking one in one respect.
|
This function is different than blocking one in one respect.
|
||||||
This function will return value 0 in the memory location and Acc register
|
This function will return value 0 in the memory location and Acc register
|
||||||
if there was no key pressed by the user (no character waiting in buffer).
|
if there was no key pressed by the user (no character waiting in buffer).
|
||||||
If there was a key typed, the function will act as the blocking counterpart.
|
If there was a key typed, the function will act as the blocking counterpart.
|
||||||
|
|
||||||
Writing to IOADDR inside the 6502 code will result in character code
|
Note that there is no clearly distinguished prompt generated by emulator
|
||||||
being put in the IOADDR memory location and also written to the character
|
when there is character input operation performed. It is designed like that
|
||||||
output buffer of the emulated display device. That character is not
|
to avoid interfering with the character I/O performed by native 6502 code.
|
||||||
immediately transferred to the user's DOS/shell session. It is written to the
|
Therefore if user performs multi-step debugging in the debug console and
|
||||||
emulated display's text memory instead. Depending on the mode in which
|
program suddenly stops, it is likely waiting for character input.
|
||||||
emulator is currently working (continuous or step-by-step code execution),
|
This is more clear when running the native 6502 code in non-debug execute
|
||||||
the emulated display device contents may or may not be updated on the user's
|
mode. In this case the I/O operations are represented on the screen instantly
|
||||||
screen in real time fashion. Remember that this is a DOS/shell console
|
and 6502 code may also produce prompts so user is aware when to enter data
|
||||||
application. The user's console is shared among various functions of the
|
to the program.
|
||||||
program. In step-by-step mode, if the character I/O emulation is enabled, the
|
|
||||||
current contents of the emulated display device can be displayed with
|
Writing to IOADDR inside the 6502 code will result in character code
|
||||||
corresponding debug console command: 'T'.
|
being put in the IOADDR memory location and also written to the character
|
||||||
|
output buffer of the emulated display device.
|
||||||
4. ROM (read-only memory) emulation.
|
|
||||||
|
When VM is running in one of the debug modes, like step-by-step mode
|
||||||
This facility provides very basic means for memory mapping of the read-only
|
(S - step, N - go number of steps) or one of the debug code execution modes
|
||||||
area. This may be required by some 6502 programs that check for non-writable
|
(C- continue or G - go/cont. from new address), that character is not
|
||||||
memory to establish the bounds of memory that can be used for data and code.
|
immediately transferred to the user's DOS/shell session.
|
||||||
One good example is Tiny Basic.
|
It is only written to the emulated display's text memory.
|
||||||
By default the ROM emulation is disabled and the memory range of ROM is
|
|
||||||
defined as $D000 - $DFFF.
|
When VM is running in non-debug code execution mode (X - execute from new
|
||||||
ROM emulation can be enabled (and the memory range defined) using debug
|
address), the character is also output to the native DOS/shell console
|
||||||
console's command 'K':
|
(user's screen).
|
||||||
|
The character output history is therefore always kept in the memory of the
|
||||||
K [rombegin] [romend] - to enable
|
emulated text display device and can be recalled to the screen in debug
|
||||||
|
console with command 'T'.
|
||||||
or
|
|
||||||
|
There are 2 reasons for this:
|
||||||
K - to disable
|
|
||||||
|
* Performance.
|
||||||
The ROM emulation can also be defined and enabled in the memory image
|
In previous version only the emulated text display device approach was used.
|
||||||
definition file with following statements:
|
That meant that each time there was a new character in the emulated display
|
||||||
|
buffer, the entire emulated text output device screen had to be refreshed on
|
||||||
ROMBEGIN
|
the DOS/shell console. That was slow and caused screen flicker when characters
|
||||||
address
|
were output at high rate of speed.
|
||||||
ROMEND
|
|
||||||
address
|
* Record of character I/O operation.
|
||||||
ENROM
|
During step-by-step debugging or multiple-step animated registers mode, any
|
||||||
|
characters output is immediately replaced by the registers and stack status
|
||||||
5. Additional comments and remarks.
|
on the screen and is not visible on the screen. However user must be able to
|
||||||
|
debug applications that perform character I/O operations and recall the
|
||||||
IOADDR is permitted to be located in the emulated ROM memory range.
|
history of the characters output to the emulated text display device. This is
|
||||||
The writing to IOADDR is trapped first before checking ROM range and writing
|
when shadow copy of character I/O comes handy.
|
||||||
to it is permitted when character I/O emulation and ROM are enabled at the
|
|
||||||
same time. It is a good idea in fact to put the IOADDR inside ROM range,
|
4. ROM (read-only memory) emulation.
|
||||||
otherwise memory scanning routines like the one in Tiny Basic may trigger
|
|
||||||
unexpected character input because of the reading from IOADDR during the scan.
|
This facility provides very basic means for memory mapping of the read-only
|
||||||
If you experience unexpected character input prompt while emulating
|
area. This may be required by some 6502 programs that check for non-writable
|
||||||
6502 code, this may be the case. Reconfigure your IOADDR to be inside ROM in
|
memory to establish the bounds of memory that can be used for data and code.
|
||||||
such case and try again.
|
One good example is Tiny Basic.
|
||||||
|
By default the ROM emulation is disabled and the memory range of ROM is
|
||||||
6. Warranty and License Agreement.
|
defined as $D000 - $DFFF.
|
||||||
|
ROM emulation can be enabled (and the memory range defined) using debug
|
||||||
This software is provided with No Warranty.
|
console's command 'K':
|
||||||
I (The Author) will not be held responsible for any damage to computer
|
|
||||||
systems, data or user's health resulting from using this software.
|
K [rombegin] [romend] - to enable
|
||||||
Please use responsibly.
|
|
||||||
This software is provided in hope that it will be be useful and free of
|
or
|
||||||
charge for non-commercial and educational use.
|
|
||||||
Distribution of this software in non-commercial and educational derivative
|
K - to disable
|
||||||
work is permitted under condition that original copyright notices and
|
|
||||||
comments are preserved. Some 3-rd party work included with this project
|
The ROM emulation can also be defined and enabled in the memory image
|
||||||
may require separate application for permission from their respective
|
definition file with following statements:
|
||||||
authors/copyright owners.
|
|
||||||
|
ROMBEGIN
|
||||||
|
address
|
||||||
|
ROMEND
|
||||||
|
address
|
||||||
|
ENROM
|
||||||
|
|
||||||
|
5. Additional comments and remarks.
|
||||||
|
|
||||||
|
IOADDR is permitted to be located in the emulated ROM memory range.
|
||||||
|
The writing to IOADDR is trapped first before checking ROM range and writing
|
||||||
|
to it is permitted when character I/O emulation and ROM are enabled at the
|
||||||
|
same time. It is a good idea in fact to put the IOADDR inside ROM range,
|
||||||
|
otherwise memory scanning routines like the one in Tiny Basic may trigger
|
||||||
|
unexpected character input because of the reading from IOADDR during the scan.
|
||||||
|
If you experience unexpected character input prompt while emulating
|
||||||
|
6502 code, this may be the case. Reconfigure your IOADDR to be inside ROM in
|
||||||
|
such case and try again.
|
||||||
|
|
||||||
|
6. Warranty and License Agreement.
|
||||||
|
|
||||||
|
This software is provided with No Warranty.
|
||||||
|
I (The Author) will not be held responsible for any damage to computer
|
||||||
|
systems, data or user's health resulting from using this software.
|
||||||
|
Please use responsibly.
|
||||||
|
This software is provided in hope that it will be be useful and 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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -280,7 +280,8 @@ Regs *VMachine::Exec()
|
||||||
while (true) {
|
while (true) {
|
||||||
cpureg = Step();
|
cpureg = Step();
|
||||||
if (mCharIO) {
|
if (mCharIO) {
|
||||||
ShowDisp();
|
cout << mpDisp->GetLastChar();
|
||||||
|
cout << flush;
|
||||||
}
|
}
|
||||||
if (cpureg->LastRTS || mOpInterrupt) break;
|
if (cpureg->LastRTS || mOpInterrupt) break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
10 LET A=0
|
10 LET A=0
|
||||||
20 PR A;") HELLO WORLD FROM MKHBC!"
|
20 PRINT A;") HELLO WORLD FROM MKHBC!"
|
||||||
30 LET A=A+1
|
30 LET A=A+1
|
||||||
40 IF A>100 THEN END
|
40 IF A>100 THEN END
|
||||||
50 GOTO 20
|
50 GOTO 20
|
||||||
|
|
2
main.cpp
2
main.cpp
|
@ -346,6 +346,8 @@ int main(int argc, char** argv) {
|
||||||
newaddr = 0x10000;
|
newaddr = 0x10000;
|
||||||
}
|
}
|
||||||
if (brk || opbrk || stop || lrts) {
|
if (brk || opbrk || stop || lrts) {
|
||||||
|
pvm->ClearScreen();
|
||||||
|
pvm->ShowIO();
|
||||||
cout << endl;
|
cout << endl;
|
||||||
if (opbrk) {
|
if (opbrk) {
|
||||||
cout << "Interrupted at " << hex << preg->PtrAddr << endl;
|
cout << "Interrupted at " << hex << preg->PtrAddr << endl;
|
||||||
|
|
|
@ -13,3 +13,6 @@ $F0 $06 $8D $00 $E0 $E8 $D0 $F5
|
||||||
$00 $00 $EA $4C $00 $02 $45 $6E
|
$00 $00 $EA $4C $00 $02 $45 $6E
|
||||||
$74 $65 $72 $20 $74 $65 $78 $74
|
$74 $65 $72 $20 $74 $65 $78 $74
|
||||||
$3A $00 $00 $00 $00 $00 $00 $00
|
$3A $00 $00 $00 $00 $00 $00 $00
|
||||||
|
ENIO
|
||||||
|
EXEC
|
||||||
|
$0200
|
Loading…
Reference in New Issue
Block a user