Skip to content

Instantly share code, notes, and snippets.

@tangentstorm
Created December 16, 2012 22:34
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 tangentstorm/4313762 to your computer and use it in GitHub Desktop.
Save tangentstorm/4313762 to your computer and use it in GitHub Desktop.
just experimenting... migrated to an OO style, stripped out a bunch of error handling and just let pascal handle range checking ( by crashing with a stack trace )
{$i xpc.inc}
unit romVDP;
interface uses romFont, SDL, SysUtils, xpc;
{This is a simple soft-core of a text-display processor. It features a
resolution of 99 columns x 40 rows and 256 colours. There exist three
memory areas, the character, attribute and font-data map:
character map (4000 byte)
attribute map (8000 byte)
font data (3584 byte)
A character is composed of 14 scan-lines of 8 pixel (8x14) whereby the
colour information for each character is stored in two bytes of the
attribute map start from offset zero:
character map 0000: 65 'A'
attribute map 0000: 128 foreground
0001: 32 background colour
Colour 0 is specially handled. This colour value is replaced with two
internal colour registers for global fore and background colours so
clearing the attribute map to zero enabled a mode where the fore and
background colour is selected by these two internal registers for the
whole screen!
All three areas can either be mapped into an unified address space or
handled seperatly. If the first option is choosen, the character map
should begin at address 0, followed by the attribute map at FA0 and
the font data at 2EE0. Beware the address mapping in combination with
handling values though the abstract tVDPData type cost performance.
The aternative way is to handle all maps as seperate memory areas.
The choice is by you !}
const
cScnXRes = 800;
cScnYRes = 600;
cScnCRes = 8;
cChrXRes = 8;
cChrYRes = 14;
cScnCol = 100 - 1;
cScnRow = 40;
cScnHLine = $2BC0;
cScnAtrMap = $FA0;
cScnFntDta = $2EE0;
cScnChrSize = $FA0 - $28;
cScnAtrSize = $1F40;
cScnFntSize = $E00;
type
tKeymap = array [0..9] of array [0..1] of char;
tVDPData = record
fontData: taChar;
chrMapData: byte;
atrMapData: array [0..1] of byte;
end;
tVDPAttrData = record
fg, bg : byte
end;
vdp = class
rFG: int32;
rBG: int32;
rBR: int32;
rHStart: int32;
rVStart: int32;
aCharMap: array [0..cScnChrSize] of byte;
aAttrMap: array [0..cScnAtrSize] of byte;
pBitmap: pSDL_SURFACE;
constructor Init;
function Open: boolean;
procedure Close;
function ReadAttrMap(adr: int32): tVDPAttrData;
procedure WriteAttrMap(adr: int32; Value: tVDPAttrData);
function ReadCharMap(adr: int32): byte;
procedure WriteCharMap(adr: int32; Value: byte);
procedure PlotPixel(adr: int32; Value: byte);
procedure RenderChar(adr: int32; Value: byte);
procedure RenderDisplay;
procedure Display;
function PollKeyboard: char;
end;
implementation
var
cScnColPal: array [0..255] of array [0..2] of byte;
cScnOfsTab: array [0..cScnChrSize] of int32;
procedure vdp.plotPixel( adr: int32; Value: byte);
var rBitmap: ^int32;
begin
rBitmap := self.rVStart * cScnXRes + self.rHStart + pBitmap^.pixels + adr;
rBitmap^ := Value;
end;
constructor vdp.Init;
var
i, j, n, m: int32;
begin
SDL_INIT(SDL_INIT_VIDEO);
SDL_EnableUnicode(1);
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
{transformation table bitmap address -> character offset}
m := 0;
n := 0;
for i := 1 to cScnRow do
begin
for j := 1 to cScnCol do
begin
cScnOfsTab[m] := n;
n := n + 8;
m := m + 1;
end;
n := i * cScnHLine;
end;
{init linear grayscale palette}
for i := 0 to 255 do
begin
cScnColPal[i][0] := i;
cScnColPal[i][1] := i;
cScnColPal[i][2] := i;
end;
end;
function vdp.Open: boolean;
var
i: int32;
begin
self.pBitmap := SDL_SETVIDEOMODE(cScnXRes, cScnYRes, cScnCRes, SDL_HWSURFACE);
result := self.pBitmap <> nil;
self.rFG := 7;
self.rBG := 0;
self.rBR := 128;
for i := 0 to cScnChrSize do self.aCharMap[i] := 0;
for i := 0 to cScnAtrSize do self.aAttrMap[i] := 0;
self.rHStart := 4;
self.rVStart := 18;
end;
procedure vdp.Close;
begin
SDL_FREESURFACE(self.pBitmap);
SDL_QUIT;
end;
function vdp.ReadAttrMap(adr: int32): tVDPAttrData;
begin
adr := adr * 2;
Result.bg := self.aAttrMap[adr];
Result.fg := self.aAttrMap[adr + 1];
end;
procedure vdp.WriteAttrMap(adr: int32; Value: tVDPAttrData);
begin
adr := adr * 2;
self.aAttrMap[adr] := value.fg;
self.aAttrMap[adr + 1] := value.fg;
end;
function vdp.ReadCharMap(adr: int32): byte;
begin
result := self.aCharMap[adr]
end;
procedure vdp.WriteCharMap(adr: int32; Value: byte);
begin
self.aCharMap[adr] := Value;
end;
procedure vdp.RenderChar(adr: int32; Value: byte);
var
attr: tVDPAttrData;
chr: taChar;
ofs: int32;
i, j: int32;
fg, bg: int32;
begin
attr := self.ReadAttrMap(adr);
chr := romFontReadChar(self.aCharMap[adr]);
if Value > 32 then
writeln('( ', system.chr(Value), ': ', attr.fg, '/', attr.bg);
if attr.fg = 0 then fg := self.rFG else fg := attr.fg;
if attr.fg = 0 then bg := self.rBG else bg := attr.bg;
ofs := cScnOfsTab[adr];
for i := 0 to cChrYRes - 1 do begin
for j := 0 to cChrXRes - 1 do begin
if ((chr[i] shr 7) and 1) = 1
then self.plotPixel(ofs, fg)
else self.plotPixel(ofs, bg);
inc(ofs);
chr[i] := chr[i] shl 1;
end;
ofs += cScnXRes - cChrXRes;
end;
end;
procedure vdp.RenderDisplay;
var
i: int32;
begin
for i := 0 to cScnChrSize do self.RenderChar(i, self.aCharMap[i]);
SDL_FLIP(self.pBitmap);
end;
procedure vdp.Display; inline;
begin
SDL_FLIP(self.pBitmap);
end;
function vdp.PollKeyboard: char;
var
done: boolean;
evt: pSDL_Event;
key: TSDLKey;
ch: char;
begin
done := False;
new(evt);
repeat
if SDL_PollEvent(evt) = 1 then
case evt^.type_ of
SDL_KEYDOWN:
begin
key := evt^.key.keysym.unicode;
if key in [1 .. 255] then
begin
ch := chr(key);
done := True;
result := ch;
end;
end;
SDL_QUITEV: halt;
end;
until done;
end;
begin
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment