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:
Marek Karcz 2016-03-15 01:09:40 -04:00
parent d99ed03232
commit dce9babd36
8 changed files with 1161 additions and 1099 deletions

View File

@ -52,6 +52,7 @@ Display::~Display()
*/
void Display::InitScr()
{
mLastChar = 0;
mScrLines = SCREENDIM_ROW;
mScrColumns = SCREENDIM_COL;
mShellConsoleWidth = GetConsoleWidth();
@ -133,11 +134,11 @@ void Display::ScrollUp()
{
for (unsigned int row=0; row<mScrLines-1; row++) {
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++) {
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 (c == SCREENSPECCHARS_NL) {
mLastChar = SCREENSPECCHARS_NL;
//mCursorCoord.col = 0;
mCursorCoord.row++;
if (mCursorCoord.row >= mScrLines) {
@ -206,19 +208,24 @@ void Display::PutChar(char c)
mCursorCoord.row = mScrLines-1;
}
} else if (c == SCREENSPECCHARS_CR) {
mLastChar = SCREENSPECCHARS_CR;
mCursorCoord.col = 0;
} else if (c == SCREENSPECCHARS_TB) {
mLastChar = SCREENSPECCHARS_TB;
mCursorCoord.col += TABSIZE;
if (mCursorCoord.col >= mScrColumns) {
mCursorCoord.col = mScrColumns-1; // must work on it some more
}
} else if (c == SCREENSPECCHARS_BS) {
mLastChar = SCREENSPECCHARS_BS;
if (mCursorCoord.col > 0) mCursorCoord.col--;
} else if (c == SCREENSPECCHARS_BE) {
mLastChar = SCREENSPECCHARS_BE;
// no action
}
else {
mScreen[mCursorCoord.col][mCursorCoord.row] = c;
mScreen[mCursorCoord.row][mCursorCoord.col] = c;
mLastChar = c;
mCursorCoord.col++;
if (mCursorCoord.col >= mScrColumns) {
mCursorCoord.col = 0;
@ -245,7 +252,7 @@ void Display::ClrScr()
{
for (unsigned int col=0; col<mScrColumns; col++) {
for (unsigned int row=0; row<mScrLines; row++) {
mScreen[col][row] = ' ';
mScreen[row][col] = ' ';
}
}
mCursorCoord.col = mCursorCoord.row = 0;
@ -264,7 +271,7 @@ char Display::GetCharAt(unsigned int col, unsigned int row)
char c = -1;
if (col < mScrColumns && row < mScrLines)
c = mScreen[col][row];
c = mScreen[row][col];
return c;
}
@ -280,20 +287,23 @@ char Display::GetCharAt(unsigned int col, unsigned int row)
*/
void Display::ShowScr()
{
char buf[SCREENDIM_COL] = {0};
string scr;
scr.clear();
for (unsigned int row=0; row<mScrLines; row++) {
string line;
line.clear();
for (unsigned int col=0; col<mScrColumns; col++) {
char c = mScreen[col][row];
if (mCursorCoord.col == col && mCursorCoord.row == row) {
c = '_';
char *linebuf = &(mScreen[row][0]);
memset(buf, 0, mScrColumns);
strncpy(buf, linebuf, mScrColumns);
buf[mScrColumns] = 0;
if (mCursorCoord.row == row) {
buf[mCursorCoord.col] = '_';
}
line = line + c;
}
cout << line;
string line(buf);
// 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;
}
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
char Display::GetLastChar()
{
return mLastChar;
}
} // namespace MKBasic

View File

@ -37,12 +37,14 @@ class Display
char GetCharAt(unsigned int col, unsigned int row);
void ShowScr();
CursorCoord *GetCursorCoord();
char GetLastChar();
protected:
private:
char mScreen[SCREENDIM_COL][SCREENDIM_ROW];
char mScreen[SCREENDIM_ROW][SCREENDIM_COL];
char mLastChar;
CursorCoord mCursorCoord;
unsigned int mShellConsoleWidth;
unsigned int mScrLines;

View File

@ -225,10 +225,10 @@ unsigned char Memory::ReadCharKb(bool nonblock)
set_conio_terminal_mode();
#endif
static int c = ' ';
putchar('\n');
//putchar('\n');
if (mIOEcho && isprint(c)) putchar(c);
else putchar(' ');
fputs("<-Character Input (CTRL-Y to BREAK) ?\r",stdout);
//else putchar(' ');
//fputs("<-Character Input (CTRL-Y to BREAK) ?\r",stdout);
fflush(stdout);
if (!nonblock) while(!kbhit());
else c = 0;
@ -239,8 +239,8 @@ unsigned char Memory::ReadCharKb(bool nonblock)
kill(getpid(),SIGINT);
}
#endif
fputs(" \r",stdout);
fflush(stdout);
//fputs(" \r",stdout);
//fflush(stdout);
mCharIOBufIn[mInBufDataEnd] = c;
mInBufDataEnd++;
if (mInBufDataEnd >= CHARIO_BUF_SIZE) mInBufDataEnd = 0;

View File

@ -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 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
being put in the IOADDR memory location and also written to the character
output buffer of the emulated display device. That character is not
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
emulator is currently working (continuous or step-by-step code execution),
the emulated display device contents may or may not be updated on the user's
screen in real time fashion. Remember that this is a DOS/shell console
application. The user's console is shared among various functions of the
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
corresponding debug console command: 'T'.
output buffer of the emulated display device.
When VM is running in one of the debug modes, like step-by-step mode
(S - step, N - go number of steps) or one of the debug code execution modes
(C- continue or G - go/cont. from new address), that character is not
immediately transferred to the user's DOS/shell session.
It is only written to the emulated display's text memory.
When VM is running in non-debug code execution mode (X - execute from new
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.

View File

@ -280,7 +280,8 @@ Regs *VMachine::Exec()
while (true) {
cpureg = Step();
if (mCharIO) {
ShowDisp();
cout << mpDisp->GetLastChar();
cout << flush;
}
if (cpureg->LastRTS || mOpInterrupt) break;
}

View File

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

View File

@ -346,6 +346,8 @@ int main(int argc, char** argv) {
newaddr = 0x10000;
}
if (brk || opbrk || stop || lrts) {
pvm->ClearScreen();
pvm->ShowIO();
cout << endl;
if (opbrk) {
cout << "Interrupted at " << hex << preg->PtrAddr << endl;

View File

@ -13,3 +13,6 @@ $F0 $06 $8D $00 $E0 $E8 $D0 $F5
$00 $00 $EA $4C $00 $02 $45 $6E
$74 $65 $72 $20 $74 $65 $78 $74
$3A $00 $00 $00 $00 $00 $00 $00
ENIO
EXEC
$0200