Skip to content

Instantly share code, notes, and snippets.

@xopr
Last active August 1, 2019 17:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xopr/16377abde525e23e974b5ba7ef3991e5 to your computer and use it in GitHub Desktop.
Save xopr/16377abde525e23e974b5ba7ef3991e5 to your computer and use it in GitHub Desktop.
// Standard includes
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
// System include
#include <Gigatron.h>
const int tinyfont[96] = {
#include "../Utils/BabelFish/tinyfont.h"
};
#define romType (*(byte*)0x0021)
#define romTypeValue_ROMv4 0x38
#define SYS_Draw4_30 0x04d4
#define SYS_SetMemory_v2_54 0x0b03
#define SYS_ExpanderControl_v4_40 0x0b09
#define SYS_SpiExchangeBytes_v4_134 0x0b15
#define CHAR_LEADING 0
#define CHAR_WIDTH 4
#define CHAR_HEIGHT 6
byte oldchar;
byte keyrepeat = 0;
int cursor[ 12 ];
int character[ 12 ];
void Newline_ex(void)
{
// NOTE: we have 20 or ~17 lines, depending whether we want extra 'leading'
// between the font's ascend (like 'd' and descend (like 'j' which are shifted down)
int Y;
Y = (ScreenPos >> 8) - videoTable[0];
if ( Y < 0 )
Y += 120;
// carriage return
ScreenPos &= 0xff00;
// line feed
ScreenPos += ( ( CHAR_HEIGHT + CHAR_LEADING ) * 256 );
if ( ScreenPos > 0x7fff )
ScreenPos -= 0x7800;
// Wrap around screen memory
if ( (Y + ( CHAR_HEIGHT + CHAR_LEADING )) >= 120 )
{
int i;
// Clear this line
sysFn = SYS_SetMemory_v2_54;
sysArgs[1] = BgColor; // Set background color
i = ScreenPos + 1280;
while ( i >= ScreenPos )
{
*(int*)(sysArgs+2) = i; // Destination
sysArgs[0] = 160; // Count
__syscall(243); // 270-54/2
i -= 256;
}
// Scroll up by manipulating video indirection table
i = 240;
do
{
byte page;
i -= 2;
page = videoTable[i] + CHAR_HEIGHT + CHAR_LEADING;
videoTable[i] = page & 128 ? page - 120 : page;
} while (i);
}
}
void drawChar( int* _char )
{
*(int*)ScreenPos = _char[0];
*(int*)(ScreenPos + 2) = _char[1];
*(int*)(ScreenPos + 256) = _char[2];
*(int*)(ScreenPos + 258) = _char[3];
*(int*)(ScreenPos + 512) = _char[4];
*(int*)(ScreenPos + 514) = _char[5];
*(int*)(ScreenPos + 768) = _char[6];
*(int*)(ScreenPos + 770) = _char[7];
*(int*)(ScreenPos + 1024) = _char[8];
*(int*)(ScreenPos + 1026) = _char[9];
*(int*)(ScreenPos + 1280) = _char[10];
*(int*)(ScreenPos + 1282) = _char[11];
}
void PutChar_ex(int c)
{
// TODO: look if SYS_Draw4_30 performs better
// # sysArgs[0:3] Pixels
// # sysArgs[4:5] X Y: Position on screen
byte *bitmap;
int i;
int pixels;
byte p = 0;;
// Accept newlines
if (c == '\n')
{
Newline_ex();
return;
}
// Ignore non-printable characters
// XXX This still can print rubish?
i = c - 32;
if ((unsigned)i >= 128-32)
return;
// Get pixel data for character
//const double pixels = tinyfont[c-32];
pixels = tinyfont[ i ];
// Render character in bitmap
if (pixels >= 0)
{
((byte*)character)[ 20 ] = BgColor;
((byte*)character)[ 21 ] = BgColor;
((byte*)character)[ 22 ] = BgColor;
((byte*)character)[ 23 ] = BgColor;
}
else
{
((byte*)character)[ p++ ] = BgColor;
((byte*)character)[ p++ ] = BgColor;
((byte*)character)[ p++ ] = (c == 'j') ? Color: BgColor; // Special case to dot the j
((byte*)character)[ p++ ] = BgColor;
}
// Note that the characters are mirrored in both directions; bottom right pixel comes first
((byte*)character)[ p++ ] = (pixels >> 14) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = (pixels >> 9) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = (pixels >> 4) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = BgColor;
((byte*)character)[ p++ ] = (pixels >> 13) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = (pixels >> 8) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = (pixels >> 3) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = BgColor;
((byte*)character)[ p++ ] = (pixels >> 12) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = (pixels >> 7) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = (pixels >> 2) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = BgColor;
((byte*)character)[ p++ ] = (pixels >> 11) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = (pixels >> 6) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = (pixels >> 1) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = BgColor;
((byte*)character)[ p++ ] = (pixels >> 10) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = (pixels >> 5) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = (pixels >> 0) & 1 ? Color : BgColor;
((byte*)character)[ p++ ] = BgColor;
drawChar( character );
// Advance position
ScreenPos += CHAR_WIDTH;
// Automatic line wrapping
if (((byte*)&ScreenPos)[0] > 160-CHAR_WIDTH)
Newline_ex();
}
int puts_ex(const char *s)
{
for (; *s; s++)
{
PutChar_ex(*s);
}
return EOF;
}
byte SPIExchangeKey( byte _key )
{
return _key;
// Enable SPI0
sysFn = SYS_ExpanderControl_v4_40;
vAC = 0x78;
__syscall(250); // 270-40/2
*(int*)(sysArgs) = (int)&_key; // Start address
*(int*)(sysArgs+2) = (int)(&_key) + 1; // End address
sysFn = SYS_SpiExchangeBytes_v4_134;
__syscall(203); // 270-134/2
// Disable SPI0
sysFn = SYS_ExpanderControl_v4_40;
vAC = 0x7c;
__syscall(250); // 270-40/2
return _key;
}
void drawCursor( byte _copy )
{
byte i;
if ( _copy )
{
cursor[0] = *(int*)ScreenPos;
cursor[1] = *(int*)(ScreenPos + 2);
cursor[2] = *(int*)(ScreenPos + 256);
cursor[3] = *(int*)(ScreenPos + 258);
cursor[4] = *(int*)(ScreenPos + 512);
cursor[5] = *(int*)(ScreenPos + 514);
cursor[6] = *(int*)(ScreenPos + 768);
cursor[7] = *(int*)(ScreenPos + 770);
cursor[8] = *(int*)(ScreenPos + 1024);
cursor[9] = *(int*)(ScreenPos + 1026);
cursor[10] = *(int*)(ScreenPos + 1280);
cursor[11] = *(int*)(ScreenPos + 1282);
}
else
{
for ( i = 0; i < 12; i++ )
cursor[i] = BgColor << 8 | BgColor;
}
// Prepare SYS call
sysFn = SYS_Draw4_30;//SYS_VDrawBits_134;
sysArgs[0] = Color;
sysArgs[1] = Color;
sysArgs[2] = Color;
sysArgs[3] = BgColor;
*(int*)(sysArgs+4) = ScreenPos;
// Draw bitmap to screen as 'n' vertical slices
for (i=CHAR_HEIGHT; i>0; --i)
{
__syscall(255); // 270-30/2
sysArgs[5]++;
}
}
void setCursor( byte _r, byte _c )
{
// Restore character behind cursor
drawChar( cursor );
// Update position; Adjust for scrolling
_r = ( ( _r - 1 ) * CHAR_HEIGHT ) + videoTable[0];
_c = ( _c - 1 ) * CHAR_WIDTH;
ScreenPos = ( _r << 8 ) + _c;
// Draw cursor
drawCursor( 1 );
}
void ClearScreen_ex()
{
int i;
// Clear this line
sysFn = SYS_SetMemory_v2_54;
sysArgs[1] = BgColor; // Set background color
ScreenPos = (int)screenMemory + 0x7700;
while ( ScreenPos >= (int)screenMemory )
{
*(int*)(sysArgs+2) = ScreenPos; // Destination
sysArgs[0] = 160; // Count
__syscall(243); // 270-54/2
ScreenPos -= 256;
}
// Reset scroll offsets
i = 240;
do
{
i -= 2;
videoTable[i] = i / 2 + 0x08;
} while (i);
}
void cursorUp()
{
int Y;
Y = (ScreenPos >> 8);
Y -= videoTable[0];
if ( Y == 0 /*|| Y > ( 120 - CHAR_HEIGHT )*/ )
return;
drawChar( cursor );
if ( (ScreenPos >> 8) < ( 8 + CHAR_HEIGHT ) )
ScreenPos = ( (int)screenMemory + 0x7200 ) | ( ScreenPos & 0xff );
else
ScreenPos -= (CHAR_HEIGHT << 8);
drawCursor( 1 );
}
void cursorDown()
{
int Y;
Y = (ScreenPos >> 8) - videoTable[0];
if ( Y < 0 )
Y += 120;
// Wrap around screen memory
if ( (Y + ( CHAR_HEIGHT + CHAR_LEADING )) >= 120 )
return;
drawChar( cursor );
if ( (ScreenPos >> 8) > 120 )
ScreenPos = ( (int)screenMemory ) | ( ScreenPos & 0xff );
else
ScreenPos += (CHAR_HEIGHT << 8);
drawCursor( 1 );
}
void cursorLeft()
{
if ( (ScreenPos & 0xff) < CHAR_WIDTH )
return;
drawChar( cursor );
ScreenPos -= CHAR_WIDTH;
drawCursor( 1 );
}
void cursorRight()
{
if ( (ScreenPos & 0xff) > (160 - CHAR_WIDTH - CHAR_WIDTH) )
return;
drawChar( cursor );
ScreenPos += CHAR_WIDTH;
drawCursor( 1 );
}
int main(void)
{
int i;
byte keypress,spiData,row,column;
keypress = 0;
ScreenPos = (int)screenMemory;
if ( romType < romTypeValue_ROMv4 )
{
puts_ex( "Terminal is only supported\non ROMv4 or higher." );
while(1);
}
//ClearScreen_ex();
drawCursor( 1 );
setCursor( 1, 1 );
//drawCursor( 1 );
while ( 1 )
{
oldchar = keypress;
keypress = serialRaw;
spiData = keypress;
if ( oldchar == keypress )
spiData = 0;
if ( !keypress )
keyrepeat = 60;
else if ( oldchar == keypress && keyrepeat && keyrepeat-- )
spiData = 0;
// Send key to terminal server
spiData = SPIExchangeKey( spiData );
// https://en.wikipedia.org/wiki/VT52
// In escape mode?
switch ( oldchar )
{
case 27:
switch ( spiData )
{
case 'A': // cursor up (no scrolling)
cursorUp();
break;
case 'B': // cursor down
cursorDown();
break;
case 'C': // cursor right
cursorRight();
break;
case 'D': // cursor left
cursorLeft();
break;
case 'E': // clear screen
ClearScreen_ex();
break;
case 'F': // enter graphics mode
// TODO
break;
case 'G': // exit graphics mode
// TODO
break;
case 'H': // cursor home (1,1)
setCursor( 1, 1 );
break;
case 'I': // reverse line feed (insert above cursor, may scroll)
// TODO
break;
case 'J': // clear to end of screen
// TODO
break;
case 'K': // clear to end of line
// TODO
break;
case 'L': // insert line
// TODO
break;
case 'M': // delete line
// TODO
case 'Y': // set cursor position, add 31
keypress = 28;
break;
case 'Z': // ident
// reply: ESC/K (VT52)
spiData = 27;
spiData = SPIExchangeKey( spiData );
spiData = '/';
spiData = SPIExchangeKey( spiData );
spiData = 'K';
spiData = SPIExchangeKey( spiData );
break;
case '=': // enter alternate keypad
// TODO
break;
case '>': // exit alternate keypad
// TODO
break;
case '<': // enter/exit ANSI mode
// TODO
break;
case 0:
keypress = 27;
break;
default:
PutChar_ex( spiData );
break;
}
break;
case 28: // hack: row
//Color = Red;PutChar_ex( spiData );Color = White;
if ( !spiData )
{
keypress = 28;
}
else
{
row = spiData - 31;
keypress = 29;
}
break;
case 29: // hack: column
//Color = Green;PutChar_ex( spiData );Color = White;
if ( !spiData )
{
keypress = 28;
}
else
{
column = spiData - 31;
setCursor( row, column );
}
break;
default:
switch ( spiData )
{
// Handle arrow keys and/or buttons
case buttonLeft: cursorLeft(); break;
case buttonRight: cursorRight(); break;
case buttonUp: cursorUp(); break;
case buttonDown: cursorDown(); break;
case 127: // Delete key (also the [A] button...)
case 8: // Backspace
if ((ScreenPos & 255) >= CHAR_WIDTH)
{
// Remove cursor
drawChar( cursor );
// Backspace
ScreenPos -= CHAR_WIDTH;
// draw cursor
drawCursor( 0 );
}
break;
case 0: break; // Key up
case 255: break; // No data
case 27:
// Set escape code start sequence
oldchar = 27;
break;
//case 13:
case 13: // carriage return
break;
default:
drawChar( cursor );
PutChar_ex( spiData ); // Put character on screen
drawCursor( 1 );
break;
}
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment