Graphics device text/character mode. Linux port.

Graphics device text/character mode. Linux port. Documentation updates.
This commit is contained in:
Marek Karcz 2016-09-15 14:41:32 -04:00
parent 9d6706df96
commit f4526b73c0
17 changed files with 19484 additions and 8926 deletions

View File

@ -7,7 +7,8 @@
*
* Purpose: Implementation of ConsoleIO class.
* The ConsoleIO class has methods helpful when
* UI is utilizing STDIO (DOS) console.
* UI is utilizing STDIO (DOS) console OR curses on
* Linux.
*
* Date: 8/26/2016
*
@ -44,6 +45,15 @@
#include <conio.h>
#endif
#if defined(LINUX)
#include <termios.h>
#include <sys/ioctl.h>
#include <asm-generic/ioctls.h>
#include <ncurses.h>
static WINDOW *g_pWin = NULL;
#endif
using namespace std;
namespace MKBasic {
@ -141,7 +151,7 @@ void ConsoleIO::ScrHome()
SetConsoleCursorPosition( hStdOut, homeCoords );
}
#endif
#endif // WINDOWS
#if defined(LINUX)
@ -155,7 +165,12 @@ void ConsoleIO::ScrHome()
*/
void ConsoleIO::ClearScreen()
{
system("clear");
if (isendwin() || NULL == g_pWin) {
system("clear");
} else {
clear();
refresh();
}
}
/*
@ -168,9 +183,184 @@ void ConsoleIO::ClearScreen()
*/
void ConsoleIO::ScrHome()
{
cout << "\033[1;1H";
if (!isendwin() && NULL != g_pWin) {
move(0, 0);
refresh();
} else {
cout << "\033[1;1H";
}
}
#endif // #devine LINUX
#endif // #define LINUX
} // END namespace MKBasic
/*
*--------------------------------------------------------------------
* Method: GetChar()
* Purpose: Get character from console.
* Arguments: n/a
* Returns: int - character code.
*--------------------------------------------------------------------
*/
int ConsoleIO::GetChar()
{
#if defined(LINUX)
if (!isendwin() && NULL != g_pWin)
return getch();
else
return getchar();
#else
return getch();
#endif
}
/*
*--------------------------------------------------------------------
* Method: KbHit()
* Purpose: Check if key has been pressed.
* Arguments: n/a
* Returns: bool - true if key pressed
*--------------------------------------------------------------------
*/
bool ConsoleIO::KbHit()
{
#if defined(LINUX)
if (!isendwin() && NULL != g_pWin) {
int ch = getch();
if (ch != ERR) {
ungetch(ch);
return true;
} else {
return false;
}
} else {
static const int STDIN = 0;
static bool initialized = false;
if (! initialized) {
// Use termios to turn off line buffering
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return (bytesWaiting > 0);
}
#else
return (kbhit() != 0);
#endif
}
/*
*--------------------------------------------------------------------
* Method: InitCursesScr()
* Purpose: Initialize nsurses screen.
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
void ConsoleIO::InitCursesScr()
{
fflush(stdin);
#if defined(LINUX)
if (NULL == g_pWin) {
g_pWin = initscr();
cbreak();
keypad(stdscr, TRUE);
noecho();
nodelay(stdscr, TRUE);
scrollok(stdscr, TRUE);
} else if (isendwin()) {
refresh();
}
#endif
}
/*
*--------------------------------------------------------------------
* Method: closeCursesScr()
* Purpose: Close nsurses screen.
* Arguments: n/a
* Returns: n/a
*--------------------------------------------------------------------
*/
void ConsoleIO::CloseCursesScr()
{
#if defined(LINUX)
if (!isendwin() && NULL != g_pWin) {
endwin();
}
#endif
}
/*
*--------------------------------------------------------------------
* Method: PrintChar()
* Purpose: Print character on the screen.
* Arguments: char - character.
* Returns: n/a
*--------------------------------------------------------------------
*/
void ConsoleIO::PrintChar(char c)
{
#if defined(LINUX)
if (!isendwin() && NULL != g_pWin) {
echochar(c);
} else {
cout << c << flush;
}
#else
cout << c;
#endif
}
/*
*--------------------------------------------------------------------
* Method: PrintString()
* Purpose: Print string on the screen.
* Arguments: char * - pointer to char array.
* Returns: n/a
*--------------------------------------------------------------------
*/
void ConsoleIO::PrintString(string s)
{
#if defined(LINUX)
if (!isendwin() && NULL != g_pWin) {
addstr(s.c_str());
refresh();
} else {
cout << s;
}
#else
cout << s;
#endif
}
/*
*--------------------------------------------------------------------
* Method: Beep()
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void ConsoleIO::Beep()
{
#if defined(LINUX)
if (!isendwin() && NULL != g_pWin) {
beep();
} else {
cout << "\a";
}
#else
cout << "\a";
#endif
}
} // END namespace MKBasic

View File

@ -35,6 +35,7 @@
#include <string>
#include <queue>
#include <chrono>
#include <string.h>
#include "system.h"
//#define WINDOWS 1
@ -42,20 +43,29 @@
#include <windows.h>
#endif
using namespace std;
namespace MKBasic {
class ConsoleIO
{
public:
ConsoleIO();
~ConsoleIO();
ConsoleIO();
~ConsoleIO();
void ClearScreen();
void ScrHome();
void ClearScreen();
void ScrHome();
void InitCursesScr();
void CloseCursesScr();
void PrintChar(char c);
void PrintString(string s);
bool KbHit();
int GetChar();
void Beep();
};
} // namespace MKBasic
#endif // #ifndef CONSOLEIO_H
#endif // #ifndef CONSOLEIO_H

View File

@ -34,14 +34,23 @@
*--------------------------------------------------------------------
*/
#include "Display.h"
#include <ctype.h>
#include <cstdlib>
#include <iostream>
#include <string.h>
#include "Display.h"
#include "MKGenException.h"
using namespace std;
#if defined(LINUX)
#include <ncurses.h>
extern bool g_initialized;
#endif
/*
*--------------------------------------------------------------------
* Method:
@ -88,6 +97,9 @@ Display::~Display()
*/
void Display::InitScr()
{
mpConIO = new ConsoleIO();
if (NULL == mpConIO)
throw MKGenException("Display::InitScr() : Out of memory - ConsoleIO");
mLastChar = 0;
mScrLines = SCREENDIM_ROW;
mScrColumns = SCREENDIM_COL;
@ -248,7 +260,7 @@ void Display::PutChar(char c)
mCursorCoord.col = 0;
} else if (c == SCREENSPECCHARS_TB) {
mLastChar = SCREENSPECCHARS_TB;
mCursorCoord.col += TABSIZE;
mCursorCoord.col += DISP_TABSIZE;
if (mCursorCoord.col >= mScrColumns) {
mCursorCoord.col = mScrColumns-1; // must work on it some more
}
@ -339,7 +351,7 @@ void Display::ShowScr()
if (mShellConsoleWidth > mScrColumns) line = line + "\n";
scr = scr + line;
}
cout << scr;
mpConIO->PrintString(scr);
}
/*

View File

@ -34,8 +34,9 @@
#define DISPLAY_H
#include "system.h"
#include "ConsoleIO.h"
#define TABSIZE 4
#define DISP_TABSIZE 4
namespace MKBasic {
@ -81,6 +82,7 @@ class Display
unsigned int mShellConsoleWidth;
unsigned int mScrLines;
unsigned int mScrColumns;
ConsoleIO *mpConIO;
void InitScr();
void ScrollUp();

View File

@ -111,8 +111,28 @@ void GraphDisp::Initialize()
{
int desk_w, desk_h, winbd_top = 5, winbd_right = 5;
mContLoop = true;
mMainLoopActive = false;
mWidth = GRDISP_VR_X; // virtual display width
mHeight = GRDISP_VR_Y; // virtual display height
mPixelSizeX = GRAPHDISP_MAXW / mWidth;
mPixelSizeY = GRAPHDISP_MAXH / mHeight;
mWinPosX = 0; // SDL window position coordinate X
mWinPosY = 0; // SDL window position coordinate Y
mBgRgbR = 0; // bg color, RGB red intensity
mBgRgbG = 0; // bg color, RGB green intensity
mBgRgbB = 0; // bg color, RGB blue intensity
mFgRgbR = 0xFF; // fg color, RGB red intensity
mFgRgbG = 0xFF; // fg color, RGB green intensity
mFgRgbB = 0xFF; // fg color, RGB blue intensity
mpWindow = NULL;
mpSurface = NULL;
mpRenderer = NULL;
GetDesktopResolution(desk_w, desk_h);
// Available in version > 2.0.4
//SDL_GetWindowBordersSize(mpWindow, &winbd_top, NULL, NULL, &winbd_right);
@ -245,6 +265,82 @@ void GraphDisp::RenderPixel(int x, int y, bool set)
SDL_UpdateWindowSurface(mpWindow);
}
/*
*--------------------------------------------------------------------
* Method: RendedChar8x8()
* Purpose: Draw 8x8 character from its pixel definition.
* Arguments: chdef - character definition in 8x8 bit matrix
* x, y - coordinates
* reversed - reversed (true) or normal (false)
* Returns: n/a
*--------------------------------------------------------------------
*/
void GraphDisp::RenderChar8x8(unsigned char chdef[8], int x, int y, bool reversed)
{
SDL_Rect rtf;
int rgb_r = 0, rgb_g = 0, rgb_b = 0;
for (int yy = y, j=0; j < 8; j++, yy++) {
unsigned char chd = chdef[j];
for (int xx = x, i=0; i < 8; i++, xx++) {
bool pixset = (chd & 0x80) == 0x80;
if (reversed) pixset = !pixset;
rtf.x = xx * mPixelSizeX; rtf.y = yy * mPixelSizeY;
rtf.w = mPixelSizeX;
rtf.h = mPixelSizeY;
if (pixset) {
rgb_r = mFgRgbR;
rgb_g = mFgRgbG;
rgb_b = mFgRgbB;
} else {
rgb_r = mBgRgbR;
rgb_g = mBgRgbG;
rgb_b = mBgRgbB;
}
SDL_FillRect(mpSurface, &rtf, SDL_MapRGB(mpSurface->format, rgb_r, rgb_g, rgb_b));
chd = chd << 1; chd &= 0xFE;
}
}
SDL_UpdateWindowSurface(mpWindow);
}
/*
*--------------------------------------------------------------------
* Method: CopyCharRom8x8()
* Purpose: Copy provided 8x8 characters table to internal buffer.
* Arguments: pchrom - pointer to characters defintions table
* Returns:
*--------------------------------------------------------------------
*/
void GraphDisp::CopyCharRom8x8(unsigned char *pchrom)
{
for (int i=0; i<CHROM_8x8_SIZE; i++) {
mCharROM8x8[i] = pchrom[i];
}
}
/*
*--------------------------------------------------------------------
* Method: PrintChar8x8()
* Purpose: Print 8x8 character at specified row and column.
* Arguments: code - character code
* col, row - character coordinates in 8 pixel intervals
* reversed - color mode (reversed or nornal)
* Returns: n/a
*--------------------------------------------------------------------
*/
void GraphDisp::PrintChar8x8(int code, int col, int row, bool reversed)
{
int x = col * 8;
int y = row * 8;
int n = code * 8;
unsigned char chdef[8];
for (int i=0; i<8; i++) {
chdef[i] = mCharROM8x8[n+i];
}
RenderChar8x8(chdef, x, y, reversed);
}
/*
*--------------------------------------------------------------------
* Method: SetPixel()

View File

@ -40,6 +40,11 @@
#include <thread>
#include <SDL.h>
// defaults
#define GRDISP_VR_X 320
#define GRDISP_VR_Y 200
#define CHROM_8x8_SIZE 2048
using namespace std;
namespace MKBasic {
@ -51,8 +56,8 @@ class GraphDisp {
public:
bool mContLoop = true;
bool mMainLoopActive = false;
bool mContLoop; // = true;
bool mMainLoopActive; // = false;
GraphDisp();
GraphDisp(int width, int height);
@ -70,35 +75,39 @@ class GraphDisp {
void ClearScreen();
//void MainLoop();
bool IsMainLoopActive();
void PrintChar8x8(int code, int col, int row, bool reversed);
void CopyCharRom8x8(unsigned char *pchrom);
private:
int mWidth = 320; // virtual display width
int mHeight = 200; // virtual display 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
int mBgRgbG = 0; // bg color, RGB green intensity
int mBgRgbB = 0; // bg color, RGB blue intensity
int mFgRgbR = 0xFF; // fg color, RGB red intensity
int mFgRgbG = 0xFF; // fg color, RGB green intensity
int mFgRgbB = 0xFF; // fg color, RGB blue intensity
SDL_Window *mpWindow = NULL;
SDL_Surface *mpSurface = NULL;
SDL_Renderer *mpRenderer = NULL;
int mWidth; // virtual display width
int mHeight; // virtual display height
int mPixelSizeX; // virtual pixel width
int mPixelSizeY; // virtual pixel height
int mWinPosX; // SDL window position coordinate X
int mWinPosY; // SDL window position coordinate Y
int mBgRgbR; // bg color, RGB red intensity
int mBgRgbG; // bg color, RGB green intensity
int mBgRgbB; // bg color, RGB blue intensity
int mFgRgbR; // fg color, RGB red intensity
int mFgRgbG; // fg color, RGB green intensity
int mFgRgbB; // fg color, RGB blue intensity
SDL_Window *mpWindow;
SDL_Surface *mpSurface;
SDL_Renderer *mpRenderer;
thread mMainLoopThread;
unsigned char mCharROM8x8[CHROM_8x8_SIZE];
void Initialize();
void UpdateSurface();
void Clear();
void GetDesktopResolution(int& horizontal, int& vertical);
void DrawLine(int x1, int y1, int x2, int y2, bool draworerase);
void RenderPixel(int x, int y, bool set);
void RenderPixel(int x, int y, bool set);
void RenderChar8x8(unsigned char chdef[8], int x, int y, bool reversed);
}; // class GraphDisp
} // namespace MKBasic
#endif
#endif

View File

@ -47,6 +47,8 @@
#include "MKGenException.h"
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <ctype.h>
#if defined(WINDOWS)
#include <conio.h>
@ -120,6 +122,9 @@ MemMapDev::~MemMapDev()
*/
void MemMapDev::Initialize()
{
mpConsoleIO = new ConsoleIO();
if (NULL == mpConsoleIO)
throw MKGenException("MemMapDev::Initialize() : Out of memory - ConsoleIO");
mInBufDataBegin = mInBufDataEnd = 0;
mOutBufDataBegin = mOutBufDataEnd = 0;
mIOEcho = false;
@ -127,6 +132,11 @@ void MemMapDev::Initialize()
mGraphDispAddr = GRDISP_ADDR;
mpGraphDisp = NULL;
mpCharIODisp = NULL;
mGrDevRegs.mGraphDispChrTbl = CHARTBL_BANK;
mCharTblAddr = CHARTBL_BANK * ((MAX_8BIT_ADDR+1) / 0x10);
mGrDevRegs.mGraphDispTxtCurX = 0;
mGrDevRegs.mGraphDispTxtCurY = 0;
mGrDevRegs.mGraphDispCrsMode = GRAPHDEVCRSMODE_BLOCK;
AddrRange addr_range(CHARIO_ADDR, CHARIO_ADDR+1);
DevPar dev_par("echo", "false");
MemAddrRanges addr_ranges_chario;
@ -255,84 +265,28 @@ int MemMapDev::SetupDevice(int devnum,
}
#if defined(LINUX)
#include <stdlib.h>
#include <string.h>
#include <signal.h>
struct termios orig_termios;
#include <ncurses.h>
#endif // LINUX
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Method: SetCurses()
* Purpose: Initialize curses screen.
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void reset_terminal_mode()
/***
void MemMapDev::SetCurses()
{
tcsetattr(0, TCSANOW, &orig_termios);
mpConsoleIO->InitCursesScr();
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void MemMapDev::set_conio_terminal_mode()
{
struct termios new_termios;
/* take two copies - one for now, one for later */
tcgetattr(0, &orig_termios);
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
/* register cleanup handler, and set the new terminal mode */
atexit(reset_terminal_mode);
cfmakeraw(&new_termios);
tcsetattr(0, TCSANOW, &new_termios);
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
int MemMapDev::kbhit()
{
struct timeval tv = { 0L, 0L };
fd_set fds;
FD_ZERO(&fds);
FD_SET(0, &fds);
return select(1, &fds, NULL, NULL, &tv);
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
int MemMapDev::getch()
{
int r;
unsigned char c;
if ((r = read(0, &c, sizeof(c))) < 0) {
return r;
} else {
return c;
}
}
#endif // #define LINUX
***/
/*
*--------------------------------------------------------------------
@ -346,37 +300,36 @@ int MemMapDev::getch()
unsigned char MemMapDev::ReadCharKb(bool nonblock)
{
unsigned char ret = 0;
#if defined(LINUX)
set_conio_terminal_mode();
#endif
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 (mIOEcho && isprint(c)) mpConsoleIO->PrintChar(c);
if (nonblock) {
// get a keystroke only if character is already in buffer
if (kbhit()) c = getch();
if (mpConsoleIO->KbHit()) c = mpConsoleIO->GetChar();
else c = 0;
} else {
// wait for a keystroke, then get the character from buffer
while(!kbhit());
c = getch();
while(!mpConsoleIO->KbHit());
c = mpConsoleIO->GetChar();
}
#if defined(LINUX)
if (c == 3) { // capture CTRL-C in CONIO mode
reset_terminal_mode();
mpConsoleIO->CloseCursesScr();
kill(getpid(),SIGINT);
}
} else if (c == 0x0A) {
c = 0x0D; // without this conversion EhBasic won't work
} else if (c == KEY_BACKSPACE) {
c = 8; // raw/cbreak modes do not pass the backspace
}
#endif
mCharIOBufIn[mInBufDataEnd] = c;
mInBufDataEnd++;
if (mInBufDataEnd >= CHARIO_BUF_SIZE) mInBufDataEnd = 0;
ret = c;
#if defined(LINUX)
reset_terminal_mode();
#endif
return ret;
}
@ -456,7 +409,22 @@ void MemMapDev::PutCharIO(char c)
mOutBufDataEnd++;
if (mOutBufDataEnd >= CHARIO_BUF_SIZE) mOutBufDataEnd = 0;
if (mCharIOActive) {
putchar((int)c);
#if defined(LINUX)
// because ncurses will remove characters if sequence is
// CR,NL, I convert CR,NL to NL,CR (NL=0x0A, CR=0x0D)
static char prevc = 0;
if (c == 7) mpConsoleIO->Beep();
else
if (c == 0x0D && prevc != 0x0A) { prevc = c; c = 0x0A; }
else if (c == 0x0A && prevc == 0x0D) {
prevc = c; c = 0x0D;
mpConsoleIO->PrintChar(prevc);
mpConsoleIO->PrintChar(c);
}
else { prevc = c; mpConsoleIO->PrintChar(c); }
#else
mpConsoleIO->PrintChar(c);
#endif
CharIOFlush();
}
}
@ -471,7 +439,8 @@ void MemMapDev::PutCharIO(char c)
*/
void MemMapDev::CharIODevice_Write(int addr, int val)
{
if ((unsigned int)addr == mCharIOAddr) {
if ((unsigned int)addr == mCharIOAddr
|| (unsigned int)addr == mCharIOAddr+1) {
PutCharIO ((char) val);
}
}
@ -664,6 +633,44 @@ void MemMapDev::GraphDispDevice_Write(int addr, int val)
} else if ((unsigned int)addr == mGraphDispAddr + GRAPHDEVREG_Y2) {
// setup Y coordinate of the end of line
mGrDevRegs.mGraphDispY2 = (unsigned char)val;
} else if ((unsigned int)addr == mGraphDispAddr + GRAPHDEVREG_CHRTBL) {
// set new address of the character table, 2 kB bank #0-31
mGrDevRegs.mGraphDispChrTbl = (unsigned char)(val & 0x003F);
mCharTblAddr = mGrDevRegs.mGraphDispChrTbl * ((MAX_8BIT_ADDR+1) / 0x20);
unsigned char char_rom[CHROM_8x8_SIZE];
for (unsigned int i=0; i<CHROM_8x8_SIZE; i++) {
char_rom[i] = mpMem->Peek8bitImg((unsigned short)((mCharTblAddr + i) & 0xFFFF));
}
mpGraphDisp->CopyCharRom8x8(char_rom);
} else if ((unsigned int)addr == mGraphDispAddr + GRAPHDEVREG_TXTCURX) {
if (val <= TXTCRSR_MAXCOL)
mGrDevRegs.mGraphDispTxtCurX = (unsigned char) (val & 0x007F);
} else if ((unsigned int)addr == mGraphDispAddr + GRAPHDEVREG_TXTCURY) {
if (val <= TXTCRSR_MAXROW)
mGrDevRegs.mGraphDispTxtCurY = (unsigned char) (val & 0x001F);
} else if ((unsigned int)addr == mGraphDispAddr + GRAPHDEVREG_CRSMODE) {
if (val < GRAPHDEVCRSMODE_END)
mGrDevRegs.mGraphDispCrsMode = (unsigned char) (val & 0x000F);
} else if ((unsigned int)addr == mGraphDispAddr + GRAPHDEVREG_TXTMODE) {
if (val < GRAPHDEVTXTMODE_END)
mGrDevRegs.mGraphDispTxtMode = (unsigned char) (val & 0x000F);
} else if ((unsigned int)addr == mGraphDispAddr + GRAPHDEVREG_PUTC) {
if (val <= 0xFF) {
mpGraphDisp->PrintChar8x8(val,
mGrDevRegs.mGraphDispTxtCurX,
mGrDevRegs.mGraphDispTxtCurY,
(mGrDevRegs.mGraphDispTxtMode == GRAPHDEVTXTMODE_REVERSE));
/***
unsigned int n = val * 8;
int x = mGrDevRegs.mGraphDispTxtCurX * 8;
int y = mGrDevRegs.mGraphDispTxtCurY * 8;
unsigned char chdef[8];
for (int i=0; i<8; i++, n++) {
chdef[i] = mpMem->Peek8bitImg((unsigned short)((mCharTblAddr + n) & 0xFFFF));
}
mpGraphDisp->RenderChar8x8(chdef, x, y, (mGrDevRegs.mGraphDispTxtMode == GRAPHDEVTXTMODE_REVERSE));
***/
}
} else if ((unsigned int)addr == mGraphDispAddr + GRAPHDEVREG_CMD) {
// execute command
switch (val) {
@ -721,7 +728,6 @@ void MemMapDev::GraphDispDevice_Write(int addr, int val)
}
GraphDisp_ReadEvents();
GraphDisp_Update();
//mpGraphDisp->Update();
} // if (NULL != mpGraphDisp)
}
@ -752,7 +758,6 @@ void MemMapDev::ActivateGraphDisp()
mGrDevRegs.mGraphDispPixColG,
mGrDevRegs.mGraphDispPixColB);
GraphDisp_Update();
//mpGraphDisp->Start(mpGraphDisp);
}
}
@ -771,7 +776,6 @@ void MemMapDev::DeactivateGraphDisp()
cout << "DBG: ERROR: Main Loop is already inactive in Graphics Display." << endl;
}
#endif
//mpGraphDisp->Stop();
if (NULL != mpGraphDisp) delete mpGraphDisp;
mpGraphDisp = NULL;
}
@ -802,20 +806,4 @@ 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

View File

@ -39,6 +39,7 @@
//#include "Memory.h"
#include "GraphDisp.h"
#include "Display.h"
#include "ConsoleIO.h"
#if defined(LINUX)
#include <unistd.h>
@ -50,6 +51,10 @@
#define CHARIO_ADDR 0xE000
#define GRDISP_ADDR 0xE002
#define CHARIO_BUF_SIZE 256
#define CHARTBL_BANK 0x0B // $B000
#define CHARTBL_LEN 0x1000 // 4 kB
#define TXTCRSR_MAXCOL 79
#define TXTCRSR_MAXROW 24
using namespace std;
@ -138,7 +143,7 @@ typedef vector<Device> MemMappedDevices;
// currently supported devices
enum DevNums {
DEVNUM_CHARIO = 0, // character I/O device
DEVNUM_GRDISP = 1, // raster graphics display device
DEVNUM_GRDISP = 1 // raster graphics display device
};
/*
@ -174,9 +179,24 @@ enum GraphDevRegs {
GRAPHDEVREG_CMD = 9,
GRAPHDEVREG_X2 = 10,
GRAPHDEVREG_Y2 = 12,
GRAPHDEVREG_CHRTBL = 13, // set the 2 kB bank where char. table resides
GRAPHDEVREG_TXTCURX = 14, // set text cursor position (column)
GRAPHDEVREG_TXTCURY = 15, // set text cursor position (row)
GRAPHDEVREG_PUTC = 16, // output char. to current pos. and move cursor
GRAPHDEVREG_CRSMODE = 17, // set cursor mode (0 - not visible, 1 - block...)
GRAPHDEVREG_TXTMODE = 18, // set text mode (0 - normal, 1 - reverse)
//---------------------------
GRAPHDEVREG_END
};
/*
* Note to GRAPHDEVREG_PUTC:
* value put to register is not an ASCII code of the character, but rather
* a screen code in order how character is positioned in character table.
* Each character definition takes 8 bytes. There is 4096 bytes which defines
* 512 characters. First 256 are normal color and next 256 are reverse color
* definitions.
*/
// graphics display commands
enum GraphDevCmds {
@ -189,6 +209,25 @@ enum GraphDevCmds {
GRAPHDEVCMD_ERASLN = 6
};
// Cursor modes.
// note: bit 7 will decide if cursor will blink (1)
#define CRS_BLINK 0x80
enum TextCursorModes {
GRAPHDEVCRSMODE_BLANK = 0, // not visible
GRAPHDEVCRSMODE_BLOCK = 1, // block
GRAPHDEVCRSMODE_UND = 2, // underscore
//------------------------------------------
GRAPHDEVCRSMODE_END
};
// Text modes.
enum TextModes {
GRAPHDEVTXTMODE_NORMAL = 0, // normal mode
GRAPHDEVTXTMODE_REVERSE = 1, // reverse colors mode
//------------------------------------------
GRAPHDEVTXTMODE_END
};
struct GraphDeviceRegs {
unsigned char mGraphDispLoX;
unsigned char mGraphDispHiX;
@ -202,6 +241,11 @@ struct GraphDeviceRegs {
unsigned char mGraphDispBgColR;
unsigned char mGraphDispBgColG;
unsigned char mGraphDispBgColB;
unsigned char mGraphDispChrTbl; // 2 kB char. table bank (0-31)
unsigned char mGraphDispTxtCurX; // text cursor column
unsigned char mGraphDispTxtCurY; // text cursor row
unsigned char mGraphDispCrsMode; // cursor mode
unsigned char mGraphDispTxtMode; // text mode
};
// Functionality of memory mapped devices
@ -258,22 +302,17 @@ class MemMapDev {
Display *mpCharIODisp; // pointer to character I/O device object
bool mCharIOActive; // indicate if character I/O is active
GraphDeviceRegs mGrDevRegs; // graphics display device registers
unsigned int mCharTblAddr; // start address of characters table
ConsoleIO *mpConsoleIO;
void Initialize();
unsigned char ReadCharKb(bool nonblock);
void PutCharIO(char c);
#if defined(LINUX)
void set_conio_terminal_mode();
int kbhit();
int getch();
#endif
//void SetCurses();
};
} // namespace MKBasic
#endif // MEMMAPDEV_H
#endif // MEMMAPDEV_H

View File

@ -500,7 +500,7 @@ Op-code execute history: disabled.
0 GRAPHDEVREG_X_LO Least significant part of pixel's X (column)
coordinate or begin of line coord. (0-255)
1 GRAPHDEVREG_X_HI Most significant part of pixel's X (column)
coordinate or begin of line coord. (0-1)
coordinate or begin of line coord. (0-1)
2 GRAPHDEVREG_Y Pixel's Y (row) coordinate (0-199)
3 GRAPHDEVREG_PXCOL_R Pixel's RGB color component - Red (0-255)
4 GRAPHDEVREG_PXCOL_G Pixel's RGB color component - Green (0-255)
@ -514,6 +514,14 @@ Op-code execute history: disabled.
11 GRAPHDEVREG_X2_HI Most significant part of end of line's X
coordinate
12 GRAPHDEVREG_Y2 End of line's Y (row) coordinate (0-199)
13 GRAPHDEVREG_CHRTBL Set the 2 kB bank where char. table resides
14 GRAPHDEVREG_TXTCURX Set text cursor position (column)
15 GRAPHDEVREG_TXTCURY Set text cursor position (row)
16 GRAPHDEVREG_PUTC Output char. to current pos. and move cursor
17 GRAPHDEVREG_CRSMODE Set cursor mode : 0 - not visible, 1 - block
18 GRAPHDEVREG_TXTMODE Set text mode : 0 - normal, 1 - reverse
NOTE: Functionality maintaining text cursor is not yet implemented.
Writing values to above memory locations when Graphics Device is enabled
allows to set the corresponding parameters of the device, while writing to
@ -603,6 +611,33 @@ Op-code execute history: disabled.
1310 NEXT Y
1320 RETURN
And another one to show how to render characters.
Before entering program below, load files c64_char.dat and ehbas_xx.dat to the
emulator. The two 2 kB C64 character banks reside at $B000.
The EhBasic version in file ehbas_xx.dat has top of RAM capped at $AFFF.
5 PRINT:PRINT "BITMAP TEXT DEMO. PRESS [SPACE] TO QUIT...":PRINT
10 C=0:M=0:N=22:B=65506:POKE B+9,0
12 PRINT "NORMAL MODE, CHAR BANK ";N*2048
15 POKE B+13,N:POKE B+17,0:POKE B+18,0
20 FOR Y=0 TO 24
30 FOR X=0 TO 39
40 POKE B+14,X:POKE B+15,Y
50 POKE B+16,C
60 C=C+1:IF C<256 THEN 120
70 IF N=22 THEN N=23:GOTO 100
80 N=22:IF M=0 THEN M=1:GOTO 100
90 M=0
100 POKE B+13,N:POKE B+18,M
110 Y=Y+1:X=-1:C=0
115 IF M=0 THEN PRINT "NORMAL"; ELSE PRINT "REVERSE";
116 PRINT " MODE, CHAR BANK ";N*2048
120 GET K$:IF K$=" " THEN END
130 NEXT X
140 NEXT Y
150 GOTO 5
4.1. Adding new device implementation.
MemMapDev.h and MemMapDev.cpp define the higher abstraction layer for memory
@ -700,7 +735,7 @@ Op-code execute history: disabled.
in all read/write memory methods. Some local methods and flags specific
to the devices may be needed for implementation convenience.
Important relevant methods in Memory class:
Important relevant methods in Memory class:
int AddDevice(int devnum);
int DeleteDevice(int devnum);
@ -766,3 +801,79 @@ Op-code execute history: disabled.
to creation of debug message unnecessarily if the debugging messages
are disabled.
5. Linux port.
I don't pay as much attention to Linux version of this software, however
I try my best to make the program work correctly on Linux and behave in the
same manner on both Windows and Linux platforms.
The most challenging part surprisingly was implementation of the character
I/O emulation on Linux. Easy on Windows with its conio.h header and kbhit()
and getch() functions that provide non-blocking keyboard input, Linux part
required some research and implementing some known programming tricks to get
this to work. I got it working but then lost touch with Linux version for
a while. After I added graphics device and SDL2 library, I worked on Linux
port to have these features working on Linux platform as well. To my surprise
I discovered then that my implementation of character I/O (the non-blocking
character input) stopped working. After many failed attempts and research
I decided to rewrite the Linux character I/O part using ncurses library.
This works although has its own problems. E.g.: ncurses getch() returns NL
character (0x0A) when ENTER is pressed, while Windows conio equivalent returns
CR (0x0D) and this is the code that 6502 programs, like Tiny Basic or EhBasic
expect. Backspace also wasn't working. I enabled function keys during ncurses
initialization and intercept backspace code for later conversion. This
solved it, but there may be more issues discovered later which I didn't fully
test.
unsigned char MemMapDev::ReadCharKb(bool nonblock)
{
[...]
#if defined(LINUX)
if (c == 3) { // capture CTRL-C in CONIO mode
mpConsoleIO->CloseCursesScr();
kill(getpid(),SIGINT);
} else if (c == 0x0A) {
c = 0x0D; // without this conversion EhBasic won't work
} else if (c == KEY_BACKSPACE) {
c = 8; // raw/cbreak modes do not pass the backspace
}
#endif
[...]
Another issue was that when 6502 code sends CR/LF sequence, the CR code
moves the cursor to the beginning of the line before applying NL (new line)
and clears the characters on its path! Therefore I'd have the text removed
from the screen (although my internal display device emulation in Display
class has its own buffer and all characters were there, it was only a visual
side effect). Therefore I have to convert CR/LF sequences to LF/CR.
Also because of the way I output characters to nsurses screen, control
characters don't work and must be intercepted and properly converted to
appropriate action. Example - the bell (audible) code 7:
void MemMapDev::PutCharIO(char c)
{
mCharIOBufOut[mOutBufDataEnd] = c;
mOutBufDataEnd++;
if (mOutBufDataEnd >= CHARIO_BUF_SIZE) mOutBufDataEnd = 0;
if (mCharIOActive) {
#if defined(LINUX)
// because ncurses will remove characters if sequence is
// CR,NL, I convert CR,NL to NL,CR (NL=0x0A, CR=0x0D)
static char prevc = 0;
if (c == 7) mpConsoleIO->Beep();
else
if (c == 0x0D && prevc != 0x0A) { prevc = c; c = 0x0A; }
else if (c == 0x0A && prevc == 0x0D) {
prevc = c; c = 0x0D;
mpConsoleIO->PrintChar(prevc);
mpConsoleIO->PrintChar(c);
}
else { prevc = c; mpConsoleIO->PrintChar(c); }
#else
mpConsoleIO->PrintChar(c);
#endif
CharIOFlush();
}
}

View File

@ -42,25 +42,10 @@
#include "VMachine.h"
#include "MKGenException.h"
/*
#if defined(WINDOWS)
#include <conio.h>
#endif
*/
using namespace std;
namespace MKBasic {
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
/*
*--------------------------------------------------------------------
* Method: VMachine()
@ -100,7 +85,6 @@ VMachine::VMachine(string romfname, string ramfname)
*/
VMachine::~VMachine()
{
//delete mpDisp;
delete mpCPU;
delete mpROM;
delete mpRAM;
@ -145,11 +129,6 @@ 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)");
@ -279,6 +258,7 @@ Regs *VMachine::Run()
AddDebugTrace("Running code at: $" + Addr2HexStr(mRunAddr));
mOpInterrupt = false;
mpConIO->InitCursesScr();
ClearScreen();
ShowDisp();
mPerfStats.cycles = 0;
@ -293,6 +273,7 @@ Regs *VMachine::Run()
CalcCurrPerf();
ShowDisp();
mpConIO->CloseCursesScr();
return cpureg;
}
@ -327,6 +308,7 @@ Regs *VMachine::Exec()
AddDebugTrace("Executing code at: $" + Addr2HexStr(mRunAddr));
mOpInterrupt = false;
mpConIO->InitCursesScr();
ClearScreen();
ShowDisp();
mPerfStats.cycles = 0;
@ -340,16 +322,17 @@ Regs *VMachine::Exec()
CalcCurrPerf();
ShowDisp();
mpConIO->CloseCursesScr();
return cpureg;
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Method: GetPerfStats()
* Purpose: Get performance stats data.
* Arguments:
* Returns:
* Returns: struct PerfStats
*--------------------------------------------------------------------
*/
PerfStats VMachine::GetPerfStats()
@ -1526,7 +1509,7 @@ bool VMachine::IsAutoReset()
/*
*--------------------------------------------------------------------
* Method:
* Method: EnableROM()
* Purpose:
* Arguments:
* Returns:
@ -1540,7 +1523,7 @@ void VMachine::EnableROM()
/*
*--------------------------------------------------------------------
* Method:
* Method: DisableROM()
* Purpose:
* Arguments:
* Returns:
@ -1554,7 +1537,7 @@ void VMachine::DisableROM()
/*
*--------------------------------------------------------------------
* Method:
* Method: SetROM()
* Purpose:
* Arguments:
* Returns:
@ -1593,7 +1576,7 @@ void VMachine::EnableROM(unsigned short start, unsigned short end)
/*
*--------------------------------------------------------------------
* Method:
* Method: GetROMBegin()
* Purpose:
* Arguments:
* Returns:
@ -1606,7 +1589,7 @@ unsigned short VMachine::GetROMBegin()
/*
*--------------------------------------------------------------------
* Method:
* Method: GetROMEnd()
* Purpose:
* Arguments:
* Returns:
@ -1619,7 +1602,7 @@ unsigned short VMachine::GetROMEnd()
/*
*--------------------------------------------------------------------
* Method:
* Method: IsROMEnabled()
* Purpose:
* Arguments:
* Returns:
@ -1632,7 +1615,7 @@ bool VMachine::IsROMEnabled()
/*
*--------------------------------------------------------------------
* Method:
* Method: GetRunAddr()
* Purpose:
* Arguments:
* Returns:
@ -1745,7 +1728,7 @@ int VMachine::GetLastError()
/*
*--------------------------------------------------------------------
* Method:
* Method: EnableExecHistory()
* Purpose:
* Arguments:
* Returns:
@ -1765,7 +1748,7 @@ void VMachine::EnableExecHistory(bool enexehist)
/*
*--------------------------------------------------------------------
* Method:
* Method: IsExecHistoryActive()
* Purpose:
* Arguments:
* Returns:
@ -1778,7 +1761,7 @@ bool VMachine::IsExecHistoryActive()
/*
*--------------------------------------------------------------------
* Method:
* Method: EnableDebugTrace()
* Purpose:
* Arguments:
* Returns:
@ -1794,7 +1777,7 @@ void VMachine::EnableDebugTrace()
/*
*--------------------------------------------------------------------
* Method:
* Method: DisableDebugTrace()
* Purpose:
* Arguments:
* Returns:
@ -1807,7 +1790,7 @@ void VMachine::DisableDebugTrace()
/*
*--------------------------------------------------------------------
* Method:
* Method: IsDebugTraceActive()
* Purpose:
* Arguments:
* Returns:
@ -1820,7 +1803,7 @@ bool VMachine::IsDebugTraceActive()
/*
*--------------------------------------------------------------------
* Method:
* Method: GetDebugTraces()
* Purpose:
* Arguments:
* Returns:
@ -1833,7 +1816,7 @@ queue<string> VMachine::GetDebugTraces()
/*
*--------------------------------------------------------------------
* Method:
* Method: EnablePerfStats()
* Purpose:
* Arguments:
* Returns:
@ -1852,7 +1835,7 @@ void VMachine::EnablePerfStats()
}
/*
*--------------------------------------------------------------------
* Method:
* Method: DisablePerfStats()
* Purpose:
* Arguments:
* Returns:
@ -1866,7 +1849,7 @@ void VMachine::DisablePerfStats()
/*
*--------------------------------------------------------------------
* Method:
* Method: IsPerfStatsActive()
* Purpose:
* Arguments:
* Returns:

268
c64_char.dat Normal file
View File

@ -0,0 +1,268 @@
ADDR
$b000
; Created with BIN2HEX (C) Marek Karcz 2016. All rights reserved.
; 09/08/16 13:19:24
; This is the character ROM dump of C64.
; C64 char ROM begins @$D000 and takes 4 kB ($1000): $D000..$DFFF.
; This image loads to address $B000 so I can use it with EhBASIC.
; Use EhBASIC with modified RAM Top @$B000.
;
ORG
$b000
$3c $66 $6e $6e $60 $62 $3c $00 $18 $3c $66 $7e $66 $66 $66 $00
$7c $66 $66 $7c $66 $66 $7c $00 $3c $66 $60 $60 $60 $66 $3c $00
$78 $6c $66 $66 $66 $6c $78 $00 $7e $60 $60 $78 $60 $60 $7e $00
$7e $60 $60 $78 $60 $60 $60 $00 $3c $66 $60 $6e $66 $66 $3c $00
$66 $66 $66 $7e $66 $66 $66 $00 $3c $18 $18 $18 $18 $18 $3c $00
$1e $0c $0c $0c $0c $6c $38 $00 $66 $6c $78 $70 $78 $6c $66 $00
$60 $60 $60 $60 $60 $60 $7e $00 $63 $77 $7f $6b $63 $63 $63 $00
$66 $76 $7e $7e $6e $66 $66 $00 $3c $66 $66 $66 $66 $66 $3c $00
$7c $66 $66 $7c $60 $60 $60 $00 $3c $66 $66 $66 $66 $3c $0e $00
$7c $66 $66 $7c $78 $6c $66 $00 $3c $66 $60 $3c $06 $66 $3c $00
$7e $18 $18 $18 $18 $18 $18 $00 $66 $66 $66 $66 $66 $66 $3c $00
$66 $66 $66 $66 $66 $3c $18 $00 $63 $63 $63 $6b $7f $77 $63 $00
$66 $66 $3c $18 $3c $66 $66 $00 $66 $66 $66 $3c $18 $18 $18 $00
$7e $06 $0c $18 $30 $60 $7e $00 $3c $30 $30 $30 $30 $30 $3c $00
$0c $12 $30 $7c $30 $62 $fc $00 $3c $0c $0c $0c $0c $0c $3c $00
$00 $18 $3c $7e $18 $18 $18 $18 $00 $10 $30 $7f $7f $30 $10 $00
$00 $00 $00 $00 $00 $00 $00 $00 $18 $18 $18 $18 $00 $00 $18 $00
$66 $66 $66 $00 $00 $00 $00 $00 $66 $66 $ff $66 $ff $66 $66 $00
$18 $3e $60 $3c $06 $7c $18 $00 $62 $66 $0c $18 $30 $66 $46 $00
$3c $66 $3c $38 $67 $66 $3f $00 $06 $0c $18 $00 $00 $00 $00 $00
$0c $18 $30 $30 $30 $18 $0c $00 $30 $18 $0c $0c $0c $18 $30 $00
$00 $66 $3c $ff $3c $66 $00 $00 $00 $18 $18 $7e $18 $18 $00 $00
$00 $00 $00 $00 $00 $18 $18 $30 $00 $00 $00 $7e $00 $00 $00 $00
$00 $00 $00 $00 $00 $18 $18 $00 $00 $03 $06 $0c $18 $30 $60 $00
$3c $66 $6e $76 $66 $66 $3c $00 $18 $18 $38 $18 $18 $18 $7e $00
$3c $66 $06 $0c $30 $60 $7e $00 $3c $66 $06 $1c $06 $66 $3c $00
$06 $0e $1e $66 $7f $06 $06 $00 $7e $60 $7c $06 $06 $66 $3c $00
$3c $66 $60 $7c $66 $66 $3c $00 $7e $66 $0c $18 $18 $18 $18 $00
$3c $66 $66 $3c $66 $66 $3c $00 $3c $66 $66 $3e $06 $66 $3c $00
$00 $00 $18 $00 $00 $18 $00 $00 $00 $00 $18 $00 $00 $18 $18 $30
$0e $18 $30 $60 $30 $18 $0e $00 $00 $00 $7e $00 $7e $00 $00 $00
$70 $18 $0c $06 $0c $18 $70 $00 $3c $66 $06 $0c $18 $00 $18 $00
$00 $00 $00 $ff $ff $00 $00 $00 $08 $1c $3e $7f $7f $1c $3e $00
$18 $18 $18 $18 $18 $18 $18 $18 $00 $00 $00 $ff $ff $00 $00 $00
$00 $00 $ff $ff $00 $00 $00 $00 $00 $ff $ff $00 $00 $00 $00 $00
$00 $00 $00 $00 $ff $ff $00 $00 $30 $30 $30 $30 $30 $30 $30 $30
$0c $0c $0c $0c $0c $0c $0c $0c $00 $00 $00 $e0 $f0 $38 $18 $18
$18 $18 $1c $0f $07 $00 $00 $00 $18 $18 $38 $f0 $e0 $00 $00 $00
$c0 $c0 $c0 $c0 $c0 $c0 $ff $ff $c0 $e0 $70 $38 $1c $0e $07 $03
$03 $07 $0e $1c $38 $70 $e0 $c0 $ff $ff $c0 $c0 $c0 $c0 $c0 $c0
$ff $ff $03 $03 $03 $03 $03 $03 $00 $3c $7e $7e $7e $7e $3c $00
$00 $00 $00 $00 $00 $ff $ff $00 $36 $7f $7f $7f $3e $1c $08 $00
$60 $60 $60 $60 $60 $60 $60 $60 $00 $00 $00 $07 $0f $1c $18 $18
$c3 $e7 $7e $3c $3c $7e $e7 $c3 $00 $3c $7e $66 $66 $7e $3c $00
$18 $18 $66 $66 $18 $18 $3c $00 $06 $06 $06 $06 $06 $06 $06 $06
$08 $1c $3e $7f $3e $1c $08 $00 $18 $18 $18 $ff $ff $18 $18 $18
$c0 $c0 $30 $30 $c0 $c0 $30 $30 $18 $18 $18 $18 $18 $18 $18 $18
$00 $00 $03 $3e $76 $36 $36 $00 $ff $7f $3f $1f $0f $07 $03 $01
$00 $00 $00 $00 $00 $00 $00 $00 $f0 $f0 $f0 $f0 $f0 $f0 $f0 $f0
$00 $00 $00 $00 $ff $ff $ff $ff $ff $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $ff $c0 $c0 $c0 $c0 $c0 $c0 $c0 $c0
$cc $cc $33 $33 $cc $cc $33 $33 $03 $03 $03 $03 $03 $03 $03 $03
$00 $00 $00 $00 $cc $cc $33 $33 $ff $fe $fc $f8 $f0 $e0 $c0 $80
$03 $03 $03 $03 $03 $03 $03 $03 $18 $18 $18 $1f $1f $18 $18 $18
$00 $00 $00 $00 $0f $0f $0f $0f $18 $18 $18 $1f $1f $00 $00 $00
$00 $00 $00 $f8 $f8 $18 $18 $18 $00 $00 $00 $00 $00 $00 $ff $ff
$00 $00 $00 $1f $1f $18 $18 $18 $18 $18 $18 $ff $ff $00 $00 $00
$00 $00 $00 $ff $ff $18 $18 $18 $18 $18 $18 $f8 $f8 $18 $18 $18
$c0 $c0 $c0 $c0 $c0 $c0 $c0 $c0 $e0 $e0 $e0 $e0 $e0 $e0 $e0 $e0
$07 $07 $07 $07 $07 $07 $07 $07 $ff $ff $00 $00 $00 $00 $00 $00
$ff $ff $ff $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $ff $ff $ff
$03 $03 $03 $03 $03 $03 $ff $ff $00 $00 $00 $00 $f0 $f0 $f0 $f0
$0f $0f $0f $0f $00 $00 $00 $00 $18 $18 $18 $f8 $f8 $00 $00 $00
$f0 $f0 $f0 $f0 $00 $00 $00 $00 $f0 $f0 $f0 $f0 $0f $0f $0f $0f
$c3 $99 $91 $91 $9f $99 $c3 $ff $e7 $c3 $99 $81 $99 $99 $99 $ff
$83 $99 $99 $83 $99 $99 $83 $ff $c3 $99 $9f $9f $9f $99 $c3 $ff
$87 $93 $99 $99 $99 $93 $87 $ff $81 $9f $9f $87 $9f $9f $81 $ff
$81 $9f $9f $87 $9f $9f $9f $ff $c3 $99 $9f $91 $99 $99 $c3 $ff
$99 $99 $99 $81 $99 $99 $99 $ff $c3 $e7 $e7 $e7 $e7 $e7 $c3 $ff
$e1 $f3 $f3 $f3 $f3 $93 $c7 $ff $99 $93 $87 $8f $87 $93 $99 $ff
$9f $9f $9f $9f $9f $9f $81 $ff $9c $88 $80 $94 $9c $9c $9c $ff
$99 $89 $81 $81 $91 $99 $99 $ff $c3 $99 $99 $99 $99 $99 $c3 $ff
$83 $99 $99 $83 $9f $9f $9f $ff $c3 $99 $99 $99 $99 $c3 $f1 $ff
$83 $99 $99 $83 $87 $93 $99 $ff $c3 $99 $9f $c3 $f9 $99 $c3 $ff
$81 $e7 $e7 $e7 $e7 $e7 $e7 $ff $99 $99 $99 $99 $99 $99 $c3 $ff
$99 $99 $99 $99 $99 $c3 $e7 $ff $9c $9c $9c $94 $80 $88 $9c $ff
$99 $99 $c3 $e7 $c3 $99 $99 $ff $99 $99 $99 $c3 $e7 $e7 $e7 $ff
$81 $f9 $f3 $e7 $cf $9f $81 $ff $c3 $cf $cf $cf $cf $cf $c3 $ff
$f3 $ed $cf $83 $cf $9d $03 $ff $c3 $f3 $f3 $f3 $f3 $f3 $c3 $ff
$ff $e7 $c3 $81 $e7 $e7 $e7 $e7 $ff $ef $cf $80 $80 $cf $ef $ff
$ff $ff $ff $ff $ff $ff $ff $ff $e7 $e7 $e7 $e7 $ff $ff $e7 $ff
$99 $99 $99 $ff $ff $ff $ff $ff $99 $99 $00 $99 $00 $99 $99 $ff
$e7 $c1 $9f $c3 $f9 $83 $e7 $ff $9d $99 $f3 $e7 $cf $99 $b9 $ff
$c3 $99 $c3 $c7 $98 $99 $c0 $ff $f9 $f3 $e7 $ff $ff $ff $ff $ff
$f3 $e7 $cf $cf $cf $e7 $f3 $ff $cf $e7 $f3 $f3 $f3 $e7 $cf $ff
$ff $99 $c3 $00 $c3 $99 $ff $ff $ff $e7 $e7 $81 $e7 $e7 $ff $ff
$ff $ff $ff $ff $ff $e7 $e7 $cf $ff $ff $ff $81 $ff $ff $ff $ff
$ff $ff $ff $ff $ff $e7 $e7 $ff $ff $fc $f9 $f3 $e7 $cf $9f $ff
$c3 $99 $91 $89 $99 $99 $c3 $ff $e7 $e7 $c7 $e7 $e7 $e7 $81 $ff
$c3 $99 $f9 $f3 $cf $9f $81 $ff $c3 $99 $f9 $e3 $f9 $99 $c3 $ff
$f9 $f1 $e1 $99 $80 $f9 $f9 $ff $81 $9f $83 $f9 $f9 $99 $c3 $ff
$c3 $99 $9f $83 $99 $99 $c3 $ff $81 $99 $f3 $e7 $e7 $e7 $e7 $ff
$c3 $99 $99 $c3 $99 $99 $c3 $ff $c3 $99 $99 $c1 $f9 $99 $c3 $ff
$ff $ff $e7 $ff $ff $e7 $ff $ff $ff $ff $e7 $ff $ff $e7 $e7 $cf
$f1 $e7 $cf $9f $cf $e7 $f1 $ff $ff $ff $81 $ff $81 $ff $ff $ff
$8f $e7 $f3 $f9 $f3 $e7 $8f $ff $c3 $99 $f9 $f3 $e7 $ff $e7 $ff
$ff $ff $ff $00 $00 $ff $ff $ff $f7 $e3 $c1 $80 $80 $e3 $c1 $ff
$e7 $e7 $e7 $e7 $e7 $e7 $e7 $e7 $ff $ff $ff $00 $00 $ff $ff $ff
$ff $ff $00 $00 $ff $ff $ff $ff $ff $00 $00 $ff $ff $ff $ff $ff
$ff $ff $ff $ff $00 $00 $ff $ff $cf $cf $cf $cf $cf $cf $cf $cf
$f3 $f3 $f3 $f3 $f3 $f3 $f3 $f3 $ff $ff $ff $1f $0f $c7 $e7 $e7
$e7 $e7 $e3 $f0 $f8 $ff $ff $ff $e7 $e7 $c7 $0f $1f $ff $ff $ff
$3f $3f $3f $3f $3f $3f $00 $00 $3f $1f $8f $c7 $e3 $f1 $f8 $fc
$fc $f8 $f1 $e3 $c7 $8f $1f $3f $00 $00 $3f $3f $3f $3f $3f $3f
$00 $00 $fc $fc $fc $fc $fc $fc $ff $c3 $81 $81 $81 $81 $c3 $ff
$ff $ff $ff $ff $ff $00 $00 $ff $c9 $80 $80 $80 $c1 $e3 $f7 $ff
$9f $9f $9f $9f $9f $9f $9f $9f $ff $ff $ff $f8 $f0 $e3 $e7 $e7
$3c $18 $81 $c3 $c3 $81 $18 $3c $ff $c3 $81 $99 $99 $81 $c3 $ff
$e7 $e7 $99 $99 $e7 $e7 $c3 $ff $f9 $f9 $f9 $f9 $f9 $f9 $f9 $f9
$f7 $e3 $c1 $80 $c1 $e3 $f7 $ff $e7 $e7 $e7 $00 $00 $e7 $e7 $e7
$3f $3f $cf $cf $3f $3f $cf $cf $e7 $e7 $e7 $e7 $e7 $e7 $e7 $e7
$ff $ff $fc $c1 $89 $c9 $c9 $ff $00 $80 $c0 $e0 $f0 $f8 $fc $fe
$ff $ff $ff $ff $ff $ff $ff $ff $0f $0f $0f $0f $0f $0f $0f $0f
$ff $ff $ff $ff $00 $00 $00 $00 $00 $ff $ff $ff $ff $ff $ff $ff
$ff $ff $ff $ff $ff $ff $ff $00 $3f $3f $3f $3f $3f $3f $3f $3f
$33 $33 $cc $cc $33 $33 $cc $cc $fc $fc $fc $fc $fc $fc $fc $fc
$ff $ff $ff $ff $33 $33 $cc $cc $00 $01 $03 $07 $0f $1f $3f $7f
$fc $fc $fc $fc $fc $fc $fc $fc $e7 $e7 $e7 $e0 $e0 $e7 $e7 $e7
$ff $ff $ff $ff $f0 $f0 $f0 $f0 $e7 $e7 $e7 $e0 $e0 $ff $ff $ff
$ff $ff $ff $07 $07 $e7 $e7 $e7 $ff $ff $ff $ff $ff $ff $00 $00
$ff $ff $ff $e0 $e0 $e7 $e7 $e7 $e7 $e7 $e7 $00 $00 $ff $ff $ff
$ff $ff $ff $00 $00 $e7 $e7 $e7 $e7 $e7 $e7 $07 $07 $e7 $e7 $e7
$3f $3f $3f $3f $3f $3f $3f $3f $1f $1f $1f $1f $1f $1f $1f $1f
$f8 $f8 $f8 $f8 $f8 $f8 $f8 $f8 $00 $00 $ff $ff $ff $ff $ff $ff
$00 $00 $00 $ff $ff $ff $ff $ff $ff $ff $ff $ff $ff $00 $00 $00
$fc $fc $fc $fc $fc $fc $00 $00 $ff $ff $ff $ff $0f $0f $0f $0f
$f0 $f0 $f0 $f0 $ff $ff $ff $ff $e7 $e7 $e7 $07 $07 $ff $ff $ff
$0f $0f $0f $0f $ff $ff $ff $ff $0f $0f $0f $0f $f0 $f0 $f0 $f0
$3c $66 $6e $6e $60 $62 $3c $00 $00 $00 $3c $06 $3e $66 $3e $00
$00 $60 $60 $7c $66 $66 $7c $00 $00 $00 $3c $60 $60 $60 $3c $00
$00 $06 $06 $3e $66 $66 $3e $00 $00 $00 $3c $66 $7e $60 $3c $00
$00 $0e $18 $3e $18 $18 $18 $00 $00 $00 $3e $66 $66 $3e $06 $7c
$00 $60 $60 $7c $66 $66 $66 $00 $00 $18 $00 $38 $18 $18 $3c $00
$00 $06 $00 $06 $06 $06 $06 $3c $00 $60 $60 $6c $78 $6c $66 $00
$00 $38 $18 $18 $18 $18 $3c $00 $00 $00 $66 $7f $7f $6b $63 $00
$00 $00 $7c $66 $66 $66 $66 $00 $00 $00 $3c $66 $66 $66 $3c $00
$00 $00 $7c $66 $66 $7c $60 $60 $00 $00 $3e $66 $66 $3e $06 $06
$00 $00 $7c $66 $60 $60 $60 $00 $00 $00 $3e $60 $3c $06 $7c $00
$00 $18 $7e $18 $18 $18 $0e $00 $00 $00 $66 $66 $66 $66 $3e $00
$00 $00 $66 $66 $66 $3c $18 $00 $00 $00 $63 $6b $7f $3e $36 $00
$00 $00 $66 $3c $18 $3c $66 $00 $00 $00 $66 $66 $66 $3e $0c $78
$00 $00 $7e $0c $18 $30 $7e $00 $3c $30 $30 $30 $30 $30 $3c $00
$0c $12 $30 $7c $30 $62 $fc $00 $3c $0c $0c $0c $0c $0c $3c $00
$00 $18 $3c $7e $18 $18 $18 $18 $00 $10 $30 $7f $7f $30 $10 $00
$00 $00 $00 $00 $00 $00 $00 $00 $18 $18 $18 $18 $00 $00 $18 $00
$66 $66 $66 $00 $00 $00 $00 $00 $66 $66 $ff $66 $ff $66 $66 $00
$18 $3e $60 $3c $06 $7c $18 $00 $62 $66 $0c $18 $30 $66 $46 $00
$3c $66 $3c $38 $67 $66 $3f $00 $06 $0c $18 $00 $00 $00 $00 $00
$0c $18 $30 $30 $30 $18 $0c $00 $30 $18 $0c $0c $0c $18 $30 $00
$00 $66 $3c $ff $3c $66 $00 $00 $00 $18 $18 $7e $18 $18 $00 $00
$00 $00 $00 $00 $00 $18 $18 $30 $00 $00 $00 $7e $00 $00 $00 $00
$00 $00 $00 $00 $00 $18 $18 $00 $00 $03 $06 $0c $18 $30 $60 $00
$3c $66 $6e $76 $66 $66 $3c $00 $18 $18 $38 $18 $18 $18 $7e $00
$3c $66 $06 $0c $30 $60 $7e $00 $3c $66 $06 $1c $06 $66 $3c $00
$06 $0e $1e $66 $7f $06 $06 $00 $7e $60 $7c $06 $06 $66 $3c $00
$3c $66 $60 $7c $66 $66 $3c $00 $7e $66 $0c $18 $18 $18 $18 $00
$3c $66 $66 $3c $66 $66 $3c $00 $3c $66 $66 $3e $06 $66 $3c $00
$00 $00 $18 $00 $00 $18 $00 $00 $00 $00 $18 $00 $00 $18 $18 $30
$0e $18 $30 $60 $30 $18 $0e $00 $00 $00 $7e $00 $7e $00 $00 $00
$70 $18 $0c $06 $0c $18 $70 $00 $3c $66 $06 $0c $18 $00 $18 $00
$00 $00 $00 $ff $ff $00 $00 $00 $18 $3c $66 $7e $66 $66 $66 $00
$7c $66 $66 $7c $66 $66 $7c $00 $3c $66 $60 $60 $60 $66 $3c $00
$78 $6c $66 $66 $66 $6c $78 $00 $7e $60 $60 $78 $60 $60 $7e $00
$7e $60 $60 $78 $60 $60 $60 $00 $3c $66 $60 $6e $66 $66 $3c $00
$66 $66 $66 $7e $66 $66 $66 $00 $3c $18 $18 $18 $18 $18 $3c $00
$1e $0c $0c $0c $0c $6c $38 $00 $66 $6c $78 $70 $78 $6c $66 $00
$60 $60 $60 $60 $60 $60 $7e $00 $63 $77 $7f $6b $63 $63 $63 $00
$66 $76 $7e $7e $6e $66 $66 $00 $3c $66 $66 $66 $66 $66 $3c $00
$7c $66 $66 $7c $60 $60 $60 $00 $3c $66 $66 $66 $66 $3c $0e $00
$7c $66 $66 $7c $78 $6c $66 $00 $3c $66 $60 $3c $06 $66 $3c $00
$7e $18 $18 $18 $18 $18 $18 $00 $66 $66 $66 $66 $66 $66 $3c $00
$66 $66 $66 $66 $66 $3c $18 $00 $63 $63 $63 $6b $7f $77 $63 $00
$66 $66 $3c $18 $3c $66 $66 $00 $66 $66 $66 $3c $18 $18 $18 $00
$7e $06 $0c $18 $30 $60 $7e $00 $18 $18 $18 $ff $ff $18 $18 $18
$c0 $c0 $30 $30 $c0 $c0 $30 $30 $18 $18 $18 $18 $18 $18 $18 $18
$33 $33 $cc $cc $33 $33 $cc $cc $33 $99 $cc $66 $33 $99 $cc $66
$00 $00 $00 $00 $00 $00 $00 $00 $f0 $f0 $f0 $f0 $f0 $f0 $f0 $f0
$00 $00 $00 $00 $ff $ff $ff $ff $ff $00 $00 $00 $00 $00 $00 $00
$00 $00 $00 $00 $00 $00 $00 $ff $c0 $c0 $c0 $c0 $c0 $c0 $c0 $c0
$cc $cc $33 $33 $cc $cc $33 $33 $03 $03 $03 $03 $03 $03 $03 $03
$00 $00 $00 $00 $cc $cc $33 $33 $cc $99 $33 $66 $cc $99 $33 $66
$03 $03 $03 $03 $03 $03 $03 $03 $18 $18 $18 $1f $1f $18 $18 $18
$00 $00 $00 $00 $0f $0f $0f $0f $18 $18 $18 $1f $1f $00 $00 $00
$00 $00 $00 $f8 $f8 $18 $18 $18 $00 $00 $00 $00 $00 $00 $ff $ff
$00 $00 $00 $1f $1f $18 $18 $18 $18 $18 $18 $ff $ff $00 $00 $00
$00 $00 $00 $ff $ff $18 $18 $18 $18 $18 $18 $f8 $f8 $18 $18 $18
$c0 $c0 $c0 $c0 $c0 $c0 $c0 $c0 $e0 $e0 $e0 $e0 $e0 $e0 $e0 $e0
$07 $07 $07 $07 $07 $07 $07 $07 $ff $ff $00 $00 $00 $00 $00 $00
$ff $ff $ff $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $ff $ff $ff
$01 $03 $06 $6c $78 $70 $60 $00 $00 $00 $00 $00 $f0 $f0 $f0 $f0
$0f $0f $0f $0f $00 $00 $00 $00 $18 $18 $18 $f8 $f8 $00 $00 $00
$f0 $f0 $f0 $f0 $00 $00 $00 $00 $f0 $f0 $f0 $f0 $0f $0f $0f $0f
$c3 $99 $91 $91 $9f $99 $c3 $ff $ff $ff $c3 $f9 $c1 $99 $c1 $ff
$ff $9f $9f $83 $99 $99 $83 $ff $ff $ff $c3 $9f $9f $9f $c3 $ff
$ff $f9 $f9 $c1 $99 $99 $c1 $ff $ff $ff $c3 $99 $81 $9f $c3 $ff
$ff $f1 $e7 $c1 $e7 $e7 $e7 $ff $ff $ff $c1 $99 $99 $c1 $f9 $83
$ff $9f $9f $83 $99 $99 $99 $ff $ff $e7 $ff $c7 $e7 $e7 $c3 $ff
$ff $f9 $ff $f9 $f9 $f9 $f9 $c3 $ff $9f $9f $93 $87 $93 $99 $ff
$ff $c7 $e7 $e7 $e7 $e7 $c3 $ff $ff $ff $99 $80 $80 $94 $9c $ff
$ff $ff $83 $99 $99 $99 $99 $ff $ff $ff $c3 $99 $99 $99 $c3 $ff
$ff $ff $83 $99 $99 $83 $9f $9f $ff $ff $c1 $99 $99 $c1 $f9 $f9
$ff $ff $83 $99 $9f $9f $9f $ff $ff $ff $c1 $9f $c3 $f9 $83 $ff
$ff $e7 $81 $e7 $e7 $e7 $f1 $ff $ff $ff $99 $99 $99 $99 $c1 $ff
$ff $ff $99 $99 $99 $c3 $e7 $ff $ff $ff $9c $94 $80 $c1 $c9 $ff
$ff $ff $99 $c3 $e7 $c3 $99 $ff $ff $ff $99 $99 $99 $c1 $f3 $87
$ff $ff $81 $f3 $e7 $cf $81 $ff $c3 $cf $cf $cf $cf $cf $c3 $ff
$f3 $ed $cf $83 $cf $9d $03 $ff $c3 $f3 $f3 $f3 $f3 $f3 $c3 $ff
$ff $e7 $c3 $81 $e7 $e7 $e7 $e7 $ff $ef $cf $80 $80 $cf $ef $ff
$ff $ff $ff $ff $ff $ff $ff $ff $e7 $e7 $e7 $e7 $ff $ff $e7 $ff
$99 $99 $99 $ff $ff $ff $ff $ff $99 $99 $00 $99 $00 $99 $99 $ff
$e7 $c1 $9f $c3 $f9 $83 $e7 $ff $9d $99 $f3 $e7 $cf $99 $b9 $ff
$c3 $99 $c3 $c7 $98 $99 $c0 $ff $f9 $f3 $e7 $ff $ff $ff $ff $ff
$f3 $e7 $cf $cf $cf $e7 $f3 $ff $cf $e7 $f3 $f3 $f3 $e7 $cf $ff
$ff $99 $c3 $00 $c3 $99 $ff $ff $ff $e7 $e7 $81 $e7 $e7 $ff $ff
$ff $ff $ff $ff $ff $e7 $e7 $cf $ff $ff $ff $81 $ff $ff $ff $ff
$ff $ff $ff $ff $ff $e7 $e7 $ff $ff $fc $f9 $f3 $e7 $cf $9f $ff
$c3 $99 $91 $89 $99 $99 $c3 $ff $e7 $e7 $c7 $e7 $e7 $e7 $81 $ff
$c3 $99 $f9 $f3 $cf $9f $81 $ff $c3 $99 $f9 $e3 $f9 $99 $c3 $ff
$f9 $f1 $e1 $99 $80 $f9 $f9 $ff $81 $9f $83 $f9 $f9 $99 $c3 $ff
$c3 $99 $9f $83 $99 $99 $c3 $ff $81 $99 $f3 $e7 $e7 $e7 $e7 $ff
$c3 $99 $99 $c3 $99 $99 $c3 $ff $c3 $99 $99 $c1 $f9 $99 $c3 $ff
$ff $ff $e7 $ff $ff $e7 $ff $ff $ff $ff $e7 $ff $ff $e7 $e7 $cf
$f1 $e7 $cf $9f $cf $e7 $f1 $ff $ff $ff $81 $ff $81 $ff $ff $ff
$8f $e7 $f3 $f9 $f3 $e7 $8f $ff $c3 $99 $f9 $f3 $e7 $ff $e7 $ff
$ff $ff $ff $00 $00 $ff $ff $ff $e7 $c3 $99 $81 $99 $99 $99 $ff
$83 $99 $99 $83 $99 $99 $83 $ff $c3 $99 $9f $9f $9f $99 $c3 $ff
$87 $93 $99 $99 $99 $93 $87 $ff $81 $9f $9f $87 $9f $9f $81 $ff
$81 $9f $9f $87 $9f $9f $9f $ff $c3 $99 $9f $91 $99 $99 $c3 $ff
$99 $99 $99 $81 $99 $99 $99 $ff $c3 $e7 $e7 $e7 $e7 $e7 $c3 $ff
$e1 $f3 $f3 $f3 $f3 $93 $c7 $ff $99 $93 $87 $8f $87 $93 $99 $ff
$9f $9f $9f $9f $9f $9f $81 $ff $9c $88 $80 $94 $9c $9c $9c $ff
$99 $89 $81 $81 $91 $99 $99 $ff $c3 $99 $99 $99 $99 $99 $c3 $ff
$83 $99 $99 $83 $9f $9f $9f $ff $c3 $99 $99 $99 $99 $c3 $f1 $ff
$83 $99 $99 $83 $87 $93 $99 $ff $c3 $99 $9f $c3 $f9 $99 $c3 $ff
$81 $e7 $e7 $e7 $e7 $e7 $e7 $ff $99 $99 $99 $99 $99 $99 $c3 $ff
$99 $99 $99 $99 $99 $c3 $e7 $ff $9c $9c $9c $94 $80 $88 $9c $ff
$99 $99 $c3 $e7 $c3 $99 $99 $ff $99 $99 $99 $c3 $e7 $e7 $e7 $ff
$81 $f9 $f3 $e7 $cf $9f $81 $ff $e7 $e7 $e7 $00 $00 $e7 $e7 $e7
$3f $3f $cf $cf $3f $3f $cf $cf $e7 $e7 $e7 $e7 $e7 $e7 $e7 $e7
$cc $cc $33 $33 $cc $cc $33 $33 $cc $66 $33 $99 $cc $66 $33 $99
$ff $ff $ff $ff $ff $ff $ff $ff $0f $0f $0f $0f $0f $0f $0f $0f
$ff $ff $ff $ff $00 $00 $00 $00 $00 $ff $ff $ff $ff $ff $ff $ff
$ff $ff $ff $ff $ff $ff $ff $00 $3f $3f $3f $3f $3f $3f $3f $3f
$33 $33 $cc $cc $33 $33 $cc $cc $fc $fc $fc $fc $fc $fc $fc $fc
$ff $ff $ff $ff $33 $33 $cc $cc $33 $66 $cc $99 $33 $66 $cc $99
$fc $fc $fc $fc $fc $fc $fc $fc $e7 $e7 $e7 $e0 $e0 $e7 $e7 $e7
$ff $ff $ff $ff $f0 $f0 $f0 $f0 $e7 $e7 $e7 $e0 $e0 $ff $ff $ff
$ff $ff $ff $07 $07 $e7 $e7 $e7 $ff $ff $ff $ff $ff $ff $00 $00
$ff $ff $ff $e0 $e0 $e7 $e7 $e7 $e7 $e7 $e7 $00 $00 $ff $ff $ff
$ff $ff $ff $00 $00 $e7 $e7 $e7 $e7 $e7 $e7 $07 $07 $e7 $e7 $e7
$3f $3f $3f $3f $3f $3f $3f $3f $1f $1f $1f $1f $1f $1f $1f $1f
$f8 $f8 $f8 $f8 $f8 $f8 $f8 $f8 $00 $00 $ff $ff $ff $ff $ff $ff
$00 $00 $00 $ff $ff $ff $ff $ff $ff $ff $ff $ff $ff $00 $00 $00
$fe $fc $f9 $93 $87 $8f $9f $ff $ff $ff $ff $ff $0f $0f $0f $0f
$f0 $f0 $f0 $f0 $ff $ff $ff $ff $e7 $e7 $e7 $07 $07 $ff $ff $ff
$0f $0f $0f $0f $ff $ff $ff $ff $0f $0f $0f $0f $f0 $f0 $f0 $f0
;$00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00

17446
eh_basic.asm

File diff suppressed because it is too large Load Diff

8733
eh_basic_mk.asm Normal file

File diff suppressed because it is too large Load Diff

1049
ehbas_xx.dat Normal file

File diff suppressed because it is too large Load Diff

View File

@ -43,6 +43,7 @@
#include "VMachine.h"
#include "GraphDisp.h"
#include "MemMapDev.h"
#include "ConsoleIO.h"
#include "MKGenException.h"
using namespace std;
@ -60,6 +61,7 @@ char diss_buf[DISS_BUF_SIZE]; // last disassembled instruction buffer
char curr_buf[DISS_BUF_SIZE]; // current disassembled instruction buffer
VMachine *pvm = NULL;
ConsoleIO *pconio = NULL;
Regs *preg = NULL;
bool ioecho = false, opbrk = false, needhelp = false;
bool loadbin = false, loadhex = false, reset = false, execvm = false;
@ -224,16 +226,34 @@ void trap_signal(int signum);
*/
void trap_signal(int signum)
{
cout << "Signal caught: " << dec << signum << endl;
if (NULL != pvm && NULL != preg) {
pvm->SetOpInterrupt(true);
opbrk = true;
}
if (NULL != pconio) {
pconio->CloseCursesScr();
}
if (NULL != pvm && NULL != preg) {
pvm->SetOpInterrupt(true);
opbrk = true;
}
cout << "Signal caught: " << dec << signum << endl;
return;
return;
}
#endif
/*
*--------------------------------------------------------------------
* Method: reset_terminal_mode()
* Purpose: Close curses window.
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
void reset_terminal_mode()
{
if (NULL != pconio) pconio->CloseCursesScr();
cout << "Thank you for using VM65." << endl;
}
#endif // #if defined(LINUX)
#if defined(WINDOWS)
#include <windows.h>
@ -842,10 +862,18 @@ int main(int argc, char *argv[]) {
#if defined(LINUX)
signal(SIGINT, trap_signal);
signal(SIGTERM, trap_signal);
if (atexit(reset_terminal_mode)) {
cout << "WARNING: Can't set exit function." << endl;
PressEnter2Cont("");
}
#endif
#if defined(WINDOWS)
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE );
#endif
pconio = new ConsoleIO();
if (NULL == pconio) throw MKGenException("Out of memory - ConsoleIO");
pconio->InitCursesScr();
pconio->CloseCursesScr();
string romfile("dummy.rom");
LoadArgs(argc, argv);
if (needhelp) { CmdArgHelp(argv[0]); exit(0); }
@ -871,7 +899,7 @@ int main(int argc, char *argv[]) {
if (NULL != pvm && !reset) { reset = execvm = pvm->IsAutoReset(); }
}
if (NULL == pvm) {
throw MKGenException("Out of memory");
throw MKGenException("Out of memory - VMachine");
}
pvm->ClearScreen();
CopyrightBanner();
@ -899,6 +927,8 @@ int main(int argc, char *argv[]) {
preg = ((step) ? RunSingleCurrInstr() : pvm->Run());
RUNSTEPS(step,nsteps,brk,preg,stct,pvm,lrts,anim,delay);
}
pconio->InitCursesScr();
pconio->CloseCursesScr();
if (step)
cout << "\rExecuted " << dec << stct << ((stct == 1) ? " step." : " steps.") << " " << endl;
nsteps = 0;
@ -918,6 +948,8 @@ int main(int argc, char *argv[]) {
lrts = preg->LastRTS;
newaddr = 0x10000;
}
pconio->InitCursesScr();
pconio->CloseCursesScr();
if (brk || opbrk || stop || lrts) {
pvm->ClearScreen();
pvm->ShowIO();
@ -1008,6 +1040,7 @@ int main(int argc, char *argv[]) {
anim = !anim;
cout << "Registers status animation " << ((anim) ? "enabled." : "disabled.") << endl;
} else if (c == 'b') { // clear screen
pconio->CloseCursesScr();
pvm->ClearScreen();
} else if (c == 'r') { // show registers
stop = true;
@ -1082,11 +1115,14 @@ int main(int argc, char *argv[]) {
cout << "ERROR: Unknown command." << endl;
}
}
if (NULL != pconio) pconio->CloseCursesScr();
}
catch (MKGenException& ex) {
if (NULL != pconio) pconio->CloseCursesScr();
cout << ex.GetCause() << endl;
}
catch (...) {
if (NULL != pconio) pconio->CloseCursesScr();
cout << "ERROR: Fatal." << endl;
}
return 0;

View File

@ -1,11 +1,14 @@
# Project: MKBasic
SDLBASE = $(SDLDIR)
SDLINCS = -I"$(SDLBASE)/include"
CPP = g++ -D__DEBUG__ -DLINUX
CC = gcc -D__DEBUG__
OBJ = main.o VMachine.o MKBasic.o MKCpu.o Memory.o Display.o MKGenException.o
LINKOBJ = main.o VMachine.o MKBasic.o MKCpu.o Memory.o Display.o MKGenException.o
BIN = mkbasic
LIBS = -static-libgcc -m32 -g3 -ltermcap
OBJ = main.o VMachine.o MKCpu.o Memory.o Display.o GraphDisp.o MemMapDev.o MKGenException.o ConsoleIO.o
LINKOBJ = main.o VMachine.o MKCpu.o Memory.o Display.o GraphDisp.o MemMapDev.o MKGenException.o ConsoleIO.o
BIN = vm65
SDLLIBS = -L/usr/local/lib -lSDL2main -lSDL2
LIBS = -static-libgcc -m32 -g3 -ltermcap -lncurses
CLIBS = -static-libgcc -m32 -g3
INCS =
CXXINCS =
@ -22,22 +25,22 @@ clean: clean-custom
${RM} $(OBJ) $(BIN) bin2hex
$(BIN): $(OBJ)
$(CPP) $(LINKOBJ) -o $(BIN) $(LIBS)
$(CPP) $(LINKOBJ) -o $(BIN) $(LIBS) $(SDLLIBS)
main.o: main.cpp
$(CPP) -c main.cpp -o main.o $(CXXFLAGS)
$(CPP) -c main.cpp -o main.o $(CXXFLAGS) $(SDLINCS)
VMachine.o: VMachine.cpp
$(CPP) -c VMachine.cpp -o VMachine.o $(CXXFLAGS)
$(CPP) -c VMachine.cpp -o VMachine.o $(CXXFLAGS) $(SDLINCS)
MKBasic.o: MKBasic.cpp
$(CPP) -c MKBasic.cpp -o MKBasic.o $(CXXFLAGS)
MKCpu.o: MKCpu.cpp
$(CPP) -c MKCpu.cpp -o MKCpu.o $(CXXFLAGS)
$(CPP) -c MKCpu.cpp -o MKCpu.o $(CXXFLAGS) $(SDLINCS)
Memory.o: Memory.cpp
$(CPP) -c Memory.cpp -o Memory.o $(CXXFLAGS)
$(CPP) -c Memory.cpp -o Memory.o $(CXXFLAGS) $(SDLINCS)
Display.o: Display.cpp
$(CPP) -c Display.cpp -o Display.o $(CXXFLAGS)
@ -47,3 +50,12 @@ bin2hex: bin2hex.c
MKGenException.o: MKGenException.cpp
$(CPP) -c MKGenException.cpp -o MKGenException.o $(CXXFLAGS)
GraphDisp.o: GraphDisp.cpp GraphDisp.h
$(CPP) -c GraphDisp.cpp -o GraphDisp.o $(CXXFLAGS) $(SDLINCS)
MemMapDev.o: MemMapDev.cpp MemMapDev.h
$(CPP) -c MemMapDev.cpp -o MemMapDev.o $(CXXFLAGS) $(SDLINCS)
ConsoleIO.o: ConsoleIO.cpp ConsoleIO.h
$(CPP) -c ConsoleIO.cpp -o ConsoleIO.o $(CXXFLAGS)

20
test_grtxt.bas Normal file
View File

@ -0,0 +1,20 @@
5 PRINT:PRINT "BITMAP TEXT DEMO. PRESS [SPACE] TO QUIT...":PRINT
10 C=0:M=0:N=22:B=65506:POKE B+9,0
12 PRINT "NORMAL MODE, CHAR BANK ";N*2048
15 POKE B+13,N:POKE B+17,0:POKE B+18,0
20 FOR Y=0 TO 24
30 FOR X=0 TO 39
40 POKE B+14,X:POKE B+15,Y
50 POKE B+16,C
60 C=C+1:IF C<256 THEN 120
70 IF N=22 THEN N=23:GOTO 100
80 N=22:IF M=0 THEN M=1:GOTO 100
90 M=0
100 POKE B+13,N:POKE B+18,M
110 Y=Y+1:X=-1:C=0
115 IF M=0 THEN PRINT "NORMAL"; ELSE PRINT "REVERSE";
116 PRINT " MODE, CHAR BANK ";N*2048
120 GET K$:IF K$=" " THEN END
130 NEXT X
140 NEXT Y
150 GOTO 5