"Nostalgic" 80x30 vga text driver with border - now beta
pik33
Posts: 2,383
Edited 08.06.2012
Beta stage reached.
This can be usable object now. Please download and test it.
I leaved a high _clkfreq defined in spin file. Please, comment this out, and uncomment or add line with your clk frequency.
I have tested this at all these frequencies - 80, 100, 118 MHz
(I didn't test it @ 64 MHz but I think it will not work.)
Features:
2 cogs used
80x30 text, 8x16 font with semigraphic and redefinable character definitions
Individual color set for every 4 character group (20x30 color tiles)
Individual border color for every line
Color buffer in cog ram
Standard timed 800x600 @ 60Hz resolution at every clock speed (80..118 MHz tested)
640x480 text window with border
Text cursor with definable shape and blink rate. Cursor and blinking can be disabled
High level function set:
cursor functions:
pub cursoron - switch cursor on
pub cursoroff - switch cursor off
pub setcursor(x,y,on) - set x,y position of cursor and switch it off/on
pub setcursorx(x) - set x position of cursor
pub setcursory(y) - set y position of cursor
pub setcursorxy(x,y) - set x and y position of cursor
pub setcursorshape(l1,l2,l3,l4) - define a cursor shape (16 bytes = 4 longs)
pub setblinkrate(rate) - Define a cursor blink rate (in 1/30th of second)
Color functions
pub setscreencolors(fr,fg,fb,br,bg,bb) - Set font and back colors for all screen
pub setbordcolors(r,g,b) - Set border color for all screen
pub setfontcolor(line,pos,r,g,b) - set color for text at line (0..29) and position (0..19)
pub setbackcolor(line,pos,r,g,b) - set color for background at line (0..29) and position (0..19)
pub setbordcolor(line,r,g,b) - set border color for line (0..29, 30 and 31 - upper and lower border)r
Text functions
pub outtextxy(x,y,text) - Output string at position x,y
pub putchar(x,y,charcode) - Output a character at position x,y
pub box(x1,y1,x2,y2) - Draw a semigraphic box at position x1,y1,x2,y2
pub write(text) - Output string at cursor position, set new cursor position at the end of string
pub writeln(text) - Output string at cursor position, set new cursor position at the beginning of new line
pub inttostr(j) - Convert integer to dec string, return a pointer to string
pub hextostr(j) - Convert integer to hex string, return a pointer to string
pub cls - Clear screen, filling it with spaces and not touching any colors, set cursor at 0,0
pub scrollup - Scrolls screen one line up
pub scrolldown - Scrolls screen one line down
pub defchr(code,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf) - redefine a character
Edited 25.05.2012:
First alpha to test with some high level functions available to download. See end of this topic
Attached zip contains two versions of it:
- 2 cogs, for 80..100 MHz Propeller (you can use it over 100 MHz if your monitor can sync over 75 Hz)
- 1 cog for 100 or more MHz (you can use it @ 80 MHz if your monitor can sync @43 Hz)
2 cogs version displays 800x600 @60 Hz (80 MHz Prop) or 75 Hz (100 MHz Prop) at standard 800x600@60 Hz timings
1 cog version works @ 53 Hz (100 MHz Prop) or 63 Hz (118 MHz Prop); timings are out of standards, but it was tested on 4 different monitors, 3 LCD and 1 CRT, all of them can display proper picture.
Please download and test
To do: cursor, and more high level functions (write, writeln, setcursor)
Planned in future: one color set for 8 characters, color buffer in cog instead of hub.
Edit: added 2 cogs version with proper header.
Original post
It is my first working attempt to write a vga driver. This is stil beginner's unoptimized code. Version 0.01 Alpha
I called it nostalgic, because it uses Atari ST mono font and it has a border.
You can change bacgkround color, font color and border color in realtime
You can attach any 128-chars 8x16 font definition. Simply replace a font definition file name in spin code. 8th bit is "reverse color" bit
It uses 800x600 resolution @ 50 Hz. Inside it, there is active display area, 672x480 pixels, 84x30 chars
This driver uses 2 cogs. First cog displays scanlines from 8-line long buffer. Second cog gets a charcodes from main buffer, gets bytes from font definition, then feeds the line buffer in real time.
Newest version here: All history below
Beta stage reached.
This can be usable object now. Please download and test it.
I leaved a high _clkfreq defined in spin file. Please, comment this out, and uncomment or add line with your clk frequency.
I have tested this at all these frequencies - 80, 100, 118 MHz
(I didn't test it @ 64 MHz but I think it will not work.)
Features:
2 cogs used
80x30 text, 8x16 font with semigraphic and redefinable character definitions
Individual color set for every 4 character group (20x30 color tiles)
Individual border color for every line
Color buffer in cog ram
Standard timed 800x600 @ 60Hz resolution at every clock speed (80..118 MHz tested)
640x480 text window with border
Text cursor with definable shape and blink rate. Cursor and blinking can be disabled
High level function set:
cursor functions:
pub cursoron - switch cursor on
pub cursoroff - switch cursor off
pub setcursor(x,y,on) - set x,y position of cursor and switch it off/on
pub setcursorx(x) - set x position of cursor
pub setcursory(y) - set y position of cursor
pub setcursorxy(x,y) - set x and y position of cursor
pub setcursorshape(l1,l2,l3,l4) - define a cursor shape (16 bytes = 4 longs)
pub setblinkrate(rate) - Define a cursor blink rate (in 1/30th of second)
Color functions
pub setscreencolors(fr,fg,fb,br,bg,bb) - Set font and back colors for all screen
pub setbordcolors(r,g,b) - Set border color for all screen
pub setfontcolor(line,pos,r,g,b) - set color for text at line (0..29) and position (0..19)
pub setbackcolor(line,pos,r,g,b) - set color for background at line (0..29) and position (0..19)
pub setbordcolor(line,r,g,b) - set border color for line (0..29, 30 and 31 - upper and lower border)r
Text functions
pub outtextxy(x,y,text) - Output string at position x,y
pub putchar(x,y,charcode) - Output a character at position x,y
pub box(x1,y1,x2,y2) - Draw a semigraphic box at position x1,y1,x2,y2
pub write(text) - Output string at cursor position, set new cursor position at the end of string
pub writeln(text) - Output string at cursor position, set new cursor position at the beginning of new line
pub inttostr(j) - Convert integer to dec string, return a pointer to string
pub hextostr(j) - Convert integer to hex string, return a pointer to string
pub cls - Clear screen, filling it with spaces and not touching any colors, set cursor at 0,0
pub scrollup - Scrolls screen one line up
pub scrolldown - Scrolls screen one line down
pub defchr(code,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf) - redefine a character
Edited 25.05.2012:
First alpha to test with some high level functions available to download. See end of this topic
Attached zip contains two versions of it:
- 2 cogs, for 80..100 MHz Propeller (you can use it over 100 MHz if your monitor can sync over 75 Hz)
- 1 cog for 100 or more MHz (you can use it @ 80 MHz if your monitor can sync @43 Hz)
2 cogs version displays 800x600 @60 Hz (80 MHz Prop) or 75 Hz (100 MHz Prop) at standard 800x600@60 Hz timings
1 cog version works @ 53 Hz (100 MHz Prop) or 63 Hz (118 MHz Prop); timings are out of standards, but it was tested on 4 different monitors, 3 LCD and 1 CRT, all of them can display proper picture.
Please download and test
To do: cursor, and more high level functions (write, writeln, setcursor)
Planned in future: one color set for 8 characters, color buffer in cog instead of hub.
Edit: added 2 cogs version with proper header.
Original post
It is my first working attempt to write a vga driver. This is stil beginner's unoptimized code. Version 0.01 Alpha
I called it nostalgic, because it uses Atari ST mono font and it has a border.
You can change bacgkround color, font color and border color in realtime
You can attach any 128-chars 8x16 font definition. Simply replace a font definition file name in spin code. 8th bit is "reverse color" bit
It uses 800x600 resolution @ 50 Hz. Inside it, there is active display area, 672x480 pixels, 84x30 chars
This driver uses 2 cogs. First cog displays scanlines from 8-line long buffer. Second cog gets a charcodes from main buffer, gets bytes from font definition, then feeds the line buffer in real time.
Newest version here: All history below
Comments
Now, it is enough coding for me today this code needs cleaning and adding Spin functions like putchar, outtextxy, etc.
vn002.zip
Edit: tried it on another monitor. It detected 720x576 instead of 800x600 and gave an awful picture quality. I had to change frqa_val to $1b000000 and shorten porches and vsync pulse; then 800x600 resolution was correctly detected. It still needs a lot of experiments.
The driver is alpha and it is subject of rapid changes. Directions of these changes: color per character; 1024x768 resolution enable; add semigraphic to font definition; add a cursor; add a high level print functions. For 1024x768 I need to optimize code of "cache" cog; now it uses about 117 µs per 4 display lines and this is about 100% available time for this work. No place to get higher resolution until I change these rdbyte/wrbyte with rdlong/wrlong
In my blog, I've got a TV driver that operates in a similar way. Potatotext 2 final. There is a pretty great loop for color / character and pixels using rd/rwlong. I don't know whether or not you've worked through HUB operation optimization, but...
Generally, once a loop is running, the following is true:
Fastest case: One hub instruction, two ordinary instructions, one hub instruction...
Next fastest case: One hub instruction, six ordinary instructions, one hub instruction...
General case: One hub instruction, 10 ordinary instructions, one hub instruction...
It really pays to sort operations, do them out of order if needed to hit those 6 and 2 instruction windows. Generally, the savings of using longs to build the display can be captured with a nicely unrolled loop for max speed, or if a single 4 character loop is desired, careful out of order execution to hit the optimal hub windows.
I found IBM style color attributes quicker than having a separate color map.
Looking great!
Edit: it seems to be harder than I thought.... less hubops, but A LOT of additional ops which takes more time than these saved hub ops...
This is main character decode loop. It fills a 4 scanlines from 84 chars:
This is ripped from Atari ST - 16 bit machine. Mono font - 8x16.
Cheers, looking great!
800x600 with 672x480 active area, 84x30 chars, 8th bit as inverse bit, color selection per char line.
Ant then start to experiment with 1024x768 from scratch
When overclocking @ 100 MHz I have place left for about 600 instructions in one display line and it may be sufficient to do all decoding... will try to do it... maybe written once, it can be optimized to run @ 80 MHz...
Linus stumbled into this on his first 800x600 driver attempt. It went unexplored for a while.
http://forums.parallax.com/showthread.php?139112-FYI-VGA-128xH-P-quad-cog-per-cell-colour-%28-quot-Rainy-Day-quot-release%29
Some early explanation can be found here:
http://forums.parallax.com/showthread.php?135844-POC-most-useless-piece-of-code-ever-The
I have a propeller for about 3 weeks so I still need a lot of experiments to "feel" this chip. So I will try these WHOPs too simply to learn
I had to remove reverse color bit. No place left for it. Still every line of characters has its 3 colors: font, background and border
@ 80 MHz... not at my current PASM skill level. I use a hub ram for temporary buffer, so there are additional, maybe not necessary, hub operations. Maybe when using avaliable cog ram it can be faster, but I have to learn what I can do without indexed adressing mode and byte operations. To do what I need, I have to change byte order from ABCD-EFGH-IJKL-MNOP to AEIM-BFJN-CGKO-DHLP. I still don't know how to do it fast. The fastest way I know at this time is wrbyte 16 bytes to hub ram, then read 4 longs from there.
There should be wrbyte_to_cog_ram instruction in PASM
I had to remove reverse color bit. No place for it left. Still every line of characters has its 3 colors: font, background and border.
One is the addition to get the font pointer offset for each scan line.
fontaddress + scan_line_offset = fontaddressbase
In the video loop then, only the multiply and one add are needed to fetch the pixels.
Something like
Before loop
mov fontaddress, fontaddressbase
mov scanline, scancount
and scanline, #%111
add fontaddress, scanline
That offsets the font pointer to work on the right character row
In loop:
rdbyte character, screen
shl character, #3
add fontaddressbase, character
rdbyte pixels, fontaddressbase
waitvid colors, pixels
etc....
It looks like this:
every scan line, 4 scanlines of 20 characters are decoded and put in temporary hub ram buffer.
this decoding is interleaved with displaying longs from temporary buffer
The buffer can contain 8 scanlines, when 4 scanlines displaying, next 4 decoding
You can see 2 cogs version of this (download it from second post of this topic) - cog #1 displays data, cog 2 decodes characters. This code is unoptimized at all, but it works.
Details was changed , but idea is the same: decode 4 scanlines to temporary buffer, then display them.
So - 4 characters are decoded in back porch and left border, 10 when displaying (1 char per 2 waitvids) then 6 in right border, front porch and sync
First display line is still messy because of uninitialized temporary buffer. I have to write code to initialize first 4 scanlines before they will be displayed and then do something to clean awfull mess in all this code and comment it.
Edit: first line fixed, colors added.
Todo: clean the mess, remove unnecessary variables, add high level spin functions.
This is 80x30 text; 2 kB font definitions (127 chars, 16 bytes/char), hub memory used: 2400 bytes text buffer, 640 bytes scanline buffer, 62 longs color table (this will be subject of optimization, because I need only 91 bytes for this).
Edit2: Maybe it is possible to do this
:
- independent colors per every 8 chars - still in one cog. This screen was done by dynamically modifying colors in display loop (add $04040404), but I still have some place in cog ram for color buffer. These colors can be read from hub ram when displaying borders, porches and vsync.
This structure with temporary scanline buffers can make possible drawing lines, cursors, sprites etc, using second cog.
Photographed screen was generated by this piece of mostly uncomented and messy code:
Marc71
One cog version needs 100 MHz Propeller. At 80MHz you can get only about 42 Hz vblanks, this is out of range for most VGA momitors.
Also, timings in this 1 cog version are weird, far,far out of standard, only to get this code fit in one cog, but these LG monitors still can display it.
Now I plan to do both version, this experimental 1 cog/100 MHz, and standard 2 cogs version, which can work with 80 MHz, closer to standard timings and higher vblank frequency. Both will be compatible at Spin level, the same buffers, colors, etc.
And as you can see, this is still alpha quality experimental code
Edit: tested vn0014.spin with 2 more monitors I have in laboratory. 19" Samsung HDReady and old 17" CRT CTX. Both of these can display this weird timed output from it.
Samsung monitor says: 33.6 kHz, 53 Hz.
Edit: this is how it can look in real application. This is simulated (by putting some strings) DOS screen on 19" Samsung LCD with 4:3 mode on:
Border and background set as rgb 0-1-2, textcolor is 2-3-3. Strange combination of Atari ST mono font and Atari 8 bit colors.
It seems to be easy to change font definition to 8x8 and get 80x60 chars screen. To do this I have to rip Atari 8-bit font
Now it displays 640x480 window in 800x600 standard timed at 60 Hz.
Still lacks high level functions, but it now should be able to work on all standard monitors. VGA is supposed to be on 16..23; if not, change "pinmask" and "Vcfg_val" in DAT.
-vn2010 - 2 cogs version for 80..100 MHz. It displays 800x600@60 Hz with 80 MHz, and 800x600@75 MHz with 100 MHz.
-vn1009 - 1 cog version for 100..118 MHz. 800x600@53 Hz with 100 MHz, 62 Hz with 118 MHz
Both versions have the same high level structure and displays 80x30 text using 8x16 font.
2 cogs version is cleaned and commented, 1 cog version is stil messy.
Changes from previous versions:
- high level functions added: cls (clean screen), clcolors (set default colors), outtextxy (outputs a string at position x,y), scrollup (scrolls all screen 1 line up)
- removed bug with timings (2 cog version didn't work @ 100 MHz because of this
- MIT license added
Edit: 2 cog version had improper header copied from 1 cog version. Corrected.
I leaved a high _clkfreq defined in spin file. Please, comment this out, and uncomment or add line with your clk frequency.
I have tested this at all these frequencies - 80, 100, 118 MHz
(I didn't test it @ 64 MHz but I think it will not work.)
This can be usable object now.
Features:
2 cogs used
80x30 text, 8x16 font with semigraphic and redefinable character definitions
Individual color set for every 4 character group (20x30 color tiles)
Individual border color for every line
Color buffer in cog ram
Standard timed 800x600 @ 60Hz resolution at every clock speed (80..118 MHz tested)
640x480 text window with border
Text cursor with definable shape and blink rate. Cursor and blinking can be disabled
High level function set:
cursor functions:
pub cursoron - switch cursor on
pub cursoroff - switch cursor off
pub setcursor(x,y,on) - set x,y position of cursor and switch it off/on
pub setcursorx(x) - set x position of cursor
pub setcursory(y) - set y position of cursor
pub setcursorxy(x,y) - set x and y position of cursor
pub setcursorshape(l1,l2,l3,l4) - define a cursor shape (16 bytes = 4 longs)
pub setblinkrate(rate) - Define a cursor blink rate (in 1/30th of second)
Color functions
pub setscreencolors(fr,fg,fb,br,bg,bb) - Set font and back colors for all screen
pub setbordcolors(r,g,b) - Set border color for all screen
pub setfontcolor(line,pos,r,g,b) - set color for text at line (0..29) and position (0..19)
pub setbackcolor(line,pos,r,g,b) - set color for background at line (0..29) and position (0..19)
pub setbordcolor(line,r,g,b) - set border color for line (0..29, 30 and 31 - upper and lower border)r
Text functions
pub outtextxy(x,y,text) - Output string at position x,y
pub putchar(x,y,charcode) - Output a character at position x,y
pub box(x1,y1,x2,y2) - Draw a semigraphic box at position x1,y1,x2,y2
pub write(text) - Output string at cursor position, set new cursor position at the end of string
pub writeln(text) - Output string at cursor position, set new cursor position at the beginning of new line
pub inttostr(j) - Convert integer to dec string, return a pointer to string
pub hextostr(j) - Convert integer to hex string, return a pointer to string
pub cls - Clear screen, filling it with spaces and not touching any colors, set cursor at 0,0
pub scrollup - Scrolls screen one line up
pub scrolldown - Scrolls screen one line down
pub defchr(code,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf) - redefine a character
- The frqx calculation could be better, at 80MHz it comes out as $10025000 (should be $10000000). This introduces horizontal jitter.
- You're using the wrong sync polarity for 800x600 @40MHz (it's positive). Some old'ish monitors don't work with that (mine does though).
The attached driver is based on Version 0.31 beta - 10.06.2012 (from sidplay002.zip) and only addresses the sync issue. More accurate frqx calculation still needs to be done.Nice work! That fixed the display issues here. No more flashing monitor.
@Pik33
The driver positively looks awesome! Excellent!
OBC
Changes from 0.30:
- positive sync by kuroneko
- patch for frq (if _clkfreq==80_000_000 set it manually to $10000000 (and now I know why there was this jitter at 80 MHz - 100 and 118 MHz gives a stable picture)
- new char redefine function using table instead of 16 parameters
- bugs removed from inttostr functions.
Changes from 0.32:
- pll settings changed from pll/2 to pll/4; it looks the picture is better (crisper and more stable) with this setting
- faster, much faster (look at the demo and compare...) color changing, now poke procedure works in every line of picture, not only vertical back porch.
The bug described in previous post seems to be patched. Needs testing.
I inserted this bug commenting waitcnt instruction in outtextxy function, to speed up file selector of vga sid player.
Now outtextxy waits for vbl only if cursor is on
Vblank signalling added.