mirror of
https://github.com/makarcz/vm6502.git
synced 2025-05-18 08:38:34 +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
53
Display.cpp
53
Display.cpp
@ -52,6 +52,7 @@ Display::~Display()
|
|||||||
*/
|
*/
|
||||||
void Display::InitScr()
|
void Display::InitScr()
|
||||||
{
|
{
|
||||||
|
mLastChar = 0;
|
||||||
mScrLines = SCREENDIM_ROW;
|
mScrLines = SCREENDIM_ROW;
|
||||||
mScrColumns = SCREENDIM_COL;
|
mScrColumns = SCREENDIM_COL;
|
||||||
mShellConsoleWidth = GetConsoleWidth();
|
mShellConsoleWidth = GetConsoleWidth();
|
||||||
@ -133,11 +134,11 @@ void Display::ScrollUp()
|
|||||||
{
|
{
|
||||||
for (unsigned int row=0; row<mScrLines-1; row++) {
|
for (unsigned int row=0; row<mScrLines-1; row++) {
|
||||||
for (unsigned int col=0; col<mScrColumns; col++) {
|
for (unsigned int col=0; col<mScrColumns; col++) {
|
||||||
mScreen[col][row] = mScreen[col][row+1];
|
mScreen[row][col] = mScreen[row+1][col];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (unsigned int col=0; col<mScrColumns; col++) {
|
for (unsigned int col=0; col<mScrColumns; col++) {
|
||||||
mScreen[col][mScrLines-1] = ' ';
|
mScreen[mScrLines-1][col] = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,6 +200,7 @@ 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) {
|
if (c == SCREENSPECCHARS_NL) {
|
||||||
|
mLastChar = SCREENSPECCHARS_NL;
|
||||||
//mCursorCoord.col = 0;
|
//mCursorCoord.col = 0;
|
||||||
mCursorCoord.row++;
|
mCursorCoord.row++;
|
||||||
if (mCursorCoord.row >= mScrLines) {
|
if (mCursorCoord.row >= mScrLines) {
|
||||||
@ -206,19 +208,24 @@ void Display::PutChar(char c)
|
|||||||
mCursorCoord.row = mScrLines-1;
|
mCursorCoord.row = mScrLines-1;
|
||||||
}
|
}
|
||||||
} else if (c == SCREENSPECCHARS_CR) {
|
} else if (c == SCREENSPECCHARS_CR) {
|
||||||
|
mLastChar = SCREENSPECCHARS_CR;
|
||||||
mCursorCoord.col = 0;
|
mCursorCoord.col = 0;
|
||||||
} else if (c == SCREENSPECCHARS_TB) {
|
} else if (c == SCREENSPECCHARS_TB) {
|
||||||
|
mLastChar = SCREENSPECCHARS_TB;
|
||||||
mCursorCoord.col += TABSIZE;
|
mCursorCoord.col += TABSIZE;
|
||||||
if (mCursorCoord.col >= mScrColumns) {
|
if (mCursorCoord.col >= mScrColumns) {
|
||||||
mCursorCoord.col = mScrColumns-1; // must work on it some more
|
mCursorCoord.col = mScrColumns-1; // must work on it some more
|
||||||
}
|
}
|
||||||
} else if (c == SCREENSPECCHARS_BS) {
|
} else if (c == SCREENSPECCHARS_BS) {
|
||||||
|
mLastChar = SCREENSPECCHARS_BS;
|
||||||
if (mCursorCoord.col > 0) mCursorCoord.col--;
|
if (mCursorCoord.col > 0) mCursorCoord.col--;
|
||||||
} else if (c == SCREENSPECCHARS_BE) {
|
} else if (c == SCREENSPECCHARS_BE) {
|
||||||
|
mLastChar = SCREENSPECCHARS_BE;
|
||||||
// no action
|
// no action
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mScreen[mCursorCoord.col][mCursorCoord.row] = c;
|
mScreen[mCursorCoord.row][mCursorCoord.col] = c;
|
||||||
|
mLastChar = c;
|
||||||
mCursorCoord.col++;
|
mCursorCoord.col++;
|
||||||
if (mCursorCoord.col >= mScrColumns) {
|
if (mCursorCoord.col >= mScrColumns) {
|
||||||
mCursorCoord.col = 0;
|
mCursorCoord.col = 0;
|
||||||
@ -245,7 +252,7 @@ void Display::ClrScr()
|
|||||||
{
|
{
|
||||||
for (unsigned int col=0; col<mScrColumns; col++) {
|
for (unsigned int col=0; col<mScrColumns; col++) {
|
||||||
for (unsigned int row=0; row<mScrLines; row++) {
|
for (unsigned int row=0; row<mScrLines; row++) {
|
||||||
mScreen[col][row] = ' ';
|
mScreen[row][col] = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mCursorCoord.col = mCursorCoord.row = 0;
|
mCursorCoord.col = mCursorCoord.row = 0;
|
||||||
@ -264,7 +271,7 @@ char Display::GetCharAt(unsigned int col, unsigned int row)
|
|||||||
char c = -1;
|
char c = -1;
|
||||||
|
|
||||||
if (col < mScrColumns && row < mScrLines)
|
if (col < mScrColumns && row < mScrLines)
|
||||||
c = mScreen[col][row];
|
c = mScreen[row][col];
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -280,20 +287,23 @@ char Display::GetCharAt(unsigned int col, unsigned int row)
|
|||||||
*/
|
*/
|
||||||
void Display::ShowScr()
|
void Display::ShowScr()
|
||||||
{
|
{
|
||||||
|
char buf[SCREENDIM_COL] = {0};
|
||||||
|
string scr;
|
||||||
|
scr.clear();
|
||||||
for (unsigned int row=0; row<mScrLines; row++) {
|
for (unsigned int row=0; row<mScrLines; row++) {
|
||||||
string line;
|
char *linebuf = &(mScreen[row][0]);
|
||||||
line.clear();
|
memset(buf, 0, mScrColumns);
|
||||||
for (unsigned int col=0; col<mScrColumns; col++) {
|
strncpy(buf, linebuf, mScrColumns);
|
||||||
char c = mScreen[col][row];
|
buf[mScrColumns] = 0;
|
||||||
if (mCursorCoord.col == col && mCursorCoord.row == row) {
|
if (mCursorCoord.row == row) {
|
||||||
c = '_';
|
buf[mCursorCoord.col] = '_';
|
||||||
}
|
|
||||||
line = line + c;
|
|
||||||
}
|
}
|
||||||
cout << line;
|
string line(buf);
|
||||||
// add extra NL if the real console is wider than emulated one
|
// add extra NL if the real console is wider than emulated one
|
||||||
if (mShellConsoleWidth > mScrColumns) cout << endl;
|
if (mShellConsoleWidth > mScrColumns) line = line + "\n";
|
||||||
|
scr = scr + line;
|
||||||
}
|
}
|
||||||
|
cout << scr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -309,4 +319,17 @@ CursorCoord *Display::GetCursorCoord()
|
|||||||
return &mCursorCoord;
|
return &mCursorCoord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*--------------------------------------------------------------------
|
||||||
|
* Method:
|
||||||
|
* Purpose:
|
||||||
|
* Arguments:
|
||||||
|
* Returns:
|
||||||
|
*--------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
char Display::GetLastChar()
|
||||||
|
{
|
||||||
|
return mLastChar;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace MKBasic
|
} // namespace MKBasic
|
||||||
|
@ -37,12 +37,14 @@ class Display
|
|||||||
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];
|
char mScreen[SCREENDIM_ROW][SCREENDIM_COL];
|
||||||
|
char mLastChar;
|
||||||
CursorCoord mCursorCoord;
|
CursorCoord mCursorCoord;
|
||||||
unsigned int mShellConsoleWidth;
|
unsigned int mShellConsoleWidth;
|
||||||
unsigned int mScrLines;
|
unsigned int mScrLines;
|
||||||
|
10
Memory.cpp
10
Memory.cpp
@ -225,10 +225,10 @@ unsigned char Memory::ReadCharKb(bool nonblock)
|
|||||||
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;
|
||||||
@ -239,8 +239,8 @@ unsigned char Memory::ReadCharKb(bool nonblock)
|
|||||||
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;
|
||||||
|
51
ReadMe.txt
51
ReadMe.txt
@ -193,18 +193,49 @@ 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.
|
||||||
|
|
||||||
|
Note that there is no clearly distinguished prompt generated by emulator
|
||||||
|
when there is character input operation performed. It is designed like that
|
||||||
|
to avoid interfering with the character I/O performed by native 6502 code.
|
||||||
|
Therefore if user performs multi-step debugging in the debug console and
|
||||||
|
program suddenly stops, it is likely waiting for character input.
|
||||||
|
This is more clear when running the native 6502 code in non-debug execute
|
||||||
|
mode. In this case the I/O operations are represented on the screen instantly
|
||||||
|
and 6502 code may also produce prompts so user is aware when to enter data
|
||||||
|
to the program.
|
||||||
|
|
||||||
Writing to IOADDR inside the 6502 code will result in character code
|
Writing to IOADDR inside the 6502 code will result in character code
|
||||||
being put in the IOADDR memory location and also written to the character
|
being put in the IOADDR memory location and also written to the character
|
||||||
output buffer of the emulated display device. That character is not
|
output buffer of the emulated display device.
|
||||||
immediately transferred to the user's DOS/shell session. It is written to the
|
|
||||||
emulated display's text memory instead. Depending on the mode in which
|
When VM is running in one of the debug modes, like step-by-step mode
|
||||||
emulator is currently working (continuous or step-by-step code execution),
|
(S - step, N - go number of steps) or one of the debug code execution modes
|
||||||
the emulated display device contents may or may not be updated on the user's
|
(C- continue or G - go/cont. from new address), that character is not
|
||||||
screen in real time fashion. Remember that this is a DOS/shell console
|
immediately transferred to the user's DOS/shell session.
|
||||||
application. The user's console is shared among various functions of the
|
It is only written to the emulated display's text memory.
|
||||||
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
|
When VM is running in non-debug code execution mode (X - execute from new
|
||||||
corresponding debug console command: 'T'.
|
address), the character is also output to the native DOS/shell console
|
||||||
|
(user's screen).
|
||||||
|
The character output history is therefore always kept in the memory of the
|
||||||
|
emulated text display device and can be recalled to the screen in debug
|
||||||
|
console with command 'T'.
|
||||||
|
|
||||||
|
There are 2 reasons for this:
|
||||||
|
|
||||||
|
* Performance.
|
||||||
|
In previous version only the emulated text display device approach was used.
|
||||||
|
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
|
||||||
|
the DOS/shell console. That was slow and caused screen flicker when characters
|
||||||
|
were output at high rate of speed.
|
||||||
|
|
||||||
|
* Record of character I/O operation.
|
||||||
|
During step-by-step debugging or multiple-step animated registers mode, any
|
||||||
|
characters output is immediately replaced by the registers and stack status
|
||||||
|
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
|
||||||
|
history of the characters output to the emulated text display device. This is
|
||||||
|
when shadow copy of character I/O comes handy.
|
||||||
|
|
||||||
4. ROM (read-only memory) emulation.
|
4. ROM (read-only memory) emulation.
|
||||||
|
|
||||||
|
@ -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…
x
Reference in New Issue
Block a user