Shop OBEX P1 Docs P2 Docs Learn Events
"Nostalgic" 80x30 vga text driver with border - now beta — Parallax Forums

"Nostalgic" 80x30 vga text driver with border - now beta

pik33pik33 Posts: 2,347
edited 2012-06-16 12:05 in Propeller 1
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 :)
«1

Comments

  • pik33pik33 Posts: 2,347
    edited 2012-05-09 04:38
    Adding version 0.02. This has a separate font color, background color and border color for every text line. These colors can be changed for each scanline, it only needs to declare a bigger color buffer and remove this shr linenum, #4 from code.

    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.
  • pedwardpedward Posts: 1,642
    edited 2012-05-09 14:10
    Can you post some pictures? Those are always useful.
  • pik33pik33 Posts: 2,347
    edited 2012-05-09 21:15
    This is a quick photo of screen from 0.02 version + $1b00000000 frqa made with a mobile phone.

    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


    Img0377.jpg
    1024 x 768 - 141K
  • potatoheadpotatohead Posts: 10,253
    edited 2012-05-09 22:03
    There it is, that Atari font! I ripped it from my 8 bit computer when first doing some text on Prop. :)

    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!
  • pik33pik33 Posts: 2,347
    edited 2012-05-09 22:45
    They are now sorted. 1 hub - 2 standard. This cannot be done faster until I do rdlong/wrlong instead of rdbyte/wrbyte Now I have 6 hub operations for one char. When doing it long I will have 9 hub operation for 4 chars. This should be fast enough to switch on 1024x768.

    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:
                            mov counter3,#84        '4
    loop2                   rdbyte char,m_b_ptr2    '8
    
                            cmp char,#128            wc '4
                  if_nc     mov xormask,ffffffff        '4
                  if_c      mov xormask,zero            '4
                            and char,#127           '4
                            shl char,#4             '4
                            add char,f_b_ptr2       '4
                            rdlong bytes, char      '8
                            xor bytes,xormask       '4
                            add m_b_ptr2,#1         '4
                            wrbyte bytes,l_b_ptr2   '8
                            add l_b_ptr2,#84        '4
                            shr bytes,#8            '4
                            wrbyte bytes,l_b_ptr2   '8
                            add l_b_ptr2,#84        '4
                            shr bytes,#8            '4
                            wrbyte bytes,l_b_ptr2   '8
                            add l_b_ptr2,#84        '4
                            shr bytes,#8            '4
                            wrbyte bytes,l_b_ptr2   '8
                            sub l_b_ptr2,#251       '4
                            djnz counter3,#loop2    '4             '112 cycles, 1.4 us/loop, 117.6 us/all
    
                            waitpeq zero,hsyncmask2
                            waitpeq hsyncmask2,hsyncmask2
    
    There it is, that Atari font! I ripped it from my 8 bit computer when first doing some text on Prop

    This is ripped from Atari ST - 16 bit machine. Mono font - 8x16.
  • potatoheadpotatohead Posts: 10,253
    edited 2012-05-09 23:34
    Nice!! I don't have that machine handy. From the picture, it looked like a damn fine 8x8. No wonder! It's 8x16. Never was an ST user. Now we've got both in the Propeller land.

    Cheers, looking great!
  • pik33pik33 Posts: 2,347
    edited 2012-05-10 01:31
    It seems this driver cannot do any more without rewriting its code from scratch. So I will only clean this code as is, add a semigraphic chars to font definition and high level spin functions.

    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 :)
  • pedwardpedward Posts: 1,642
    edited 2012-05-10 12:32
    Nice looking text driver! How many COGs and how much memory does it use?
  • pik33pik33 Posts: 2,347
    edited 2012-05-10 20:48
    At now: 2 cogs, 2520 bytes char buffer (84x30chars), 60 longs color buffer (3 colors per line, can be optimized to 90 bytes), 672 bytes temporary buffer for 8 scanlines; it is attached to post #2, you can download and look at it :)
  • pik33pik33 Posts: 2,347
    edited 2012-05-14 08:39
    I am trying to optimize this and fit in one cog. Seems to be very hard (over my current PASM programming skills)... I have space for about 480 instructions in one display line to decode 4 scanlines of 20 characters.

    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...
  • potatoheadpotatohead Posts: 10,253
    edited 2012-05-14 08:55
    For the absolute best waitvid timing case, take a look at Kurenko's fine application of what we now know as the WHOP. "Waitvid Hand Off Point"

    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
  • pik33pik33 Posts: 2,347
    edited 2012-05-14 09:10
    Yes, I saw this. It may save some cycles, but as I understand this, it needs strict pixel clock. 20/40/80 MHz @80 MHz - or 25/50/100 MHz @100 MHz. Now I use 33..35 MHz pixel clock (33.25 is minimum for my monitor to display 800x600). 40 MHz instead of 35 MHz can eat all time gained with using WHOPs

    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 :)
  • kuronekokuroneko Posts: 3,623
    edited 2012-05-14 18:04
    potatohead wrote: »
    For the record, the last WHOP based driver was the [thread=138654]100xH/P[/thread] one. The 128 column driver runs at 65MHz which makes it unsuitable for this technique.
  • potatoheadpotatohead Posts: 10,253
    edited 2012-05-15 08:09
    Thanks for that correction.
  • pik33pik33 Posts: 2,347
    edited 2012-05-15 10:11
    Tried to fit this in one cog. Even at 100 MHz it is hard. I fit decoding characters and displaying them - 11 instruction left for additional computation, such as computing pointers for new line. It is too few. There is still some place for optimizing and some nops here and there between hub operation so it is still some chance I will get it working in one cog @ 100 MHz

    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.
  • potatoheadpotatohead Posts: 10,253
    edited 2012-05-15 11:25
    Some of the character decode can be placed outside of the video loop;.

    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....
  • potatoheadpotatohead Posts: 10,253
    edited 2012-05-15 11:33
    For some reason I could not edit my post. What does your current loop look like?
  • pik33pik33 Posts: 2,347
    edited 2012-05-15 11:43
    Tomorrow I'll put some code here.

    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
  • pik33pik33 Posts: 2,347
    edited 2012-05-16 02:43
    First success in 1 overclocked cog (100 MHz) :)

    Img0391.jpg


    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.

    Img0392.jpg


    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

    Img0393.jpg
    :


    - 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:
    1024 x 768 - 159K
    1024 x 768 - 131K
    1024 x 768 - 156K
  • Marc71Marc71 Posts: 14
    edited 2012-05-16 12:14
    Hello, sorry for the stupid question, but why do not I see anything on the monitor, and goes out of range, this driver is designed to connect RGB scart? only 50 hertz? and not compatible with the PC monitor? Thank you.

    Marc71
  • pik33pik33 Posts: 2,347
    edited 2012-05-16 21:43
    This driver was tested on 2 LG LCD monitors, one 24" and one 19" and it can display 800x600 @ 53 Hz. You can try changing frqa value from $17700000 to something other, but in this version $17800000 is maximum value to get this code working and it gives 53 Hz @800x600. Maybe at about $16e000000 or something like it, when vblank will be exactly 50 Hz, your monitor can sync. It is for VGA connected to 16..23 pins.

    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:

    Img0394.jpg


    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 :)
    1024 x 768 - 73K
  • pik33pik33 Posts: 2,347
    edited 2012-05-23 05:47
    Here is cleaned and somewhere commented 2 cog version of Nostalgic VGA for 80 MHz Propeller.

    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.
  • pik33pik33 Posts: 2,347
    edited 2012-05-25 03:25
    First usable alpha versions of these drivers:

    -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.
  • pik33pik33 Posts: 2,347
    edited 2012-06-08 03:58
    Beta stage reached. Please test...


    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
  • kuronekokuroneko Posts: 3,623
    edited 2012-06-12 21:10
    While trouble shooting this driver with Oldbitcollector (Jeff) we stumbled over two issues:
    • 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.
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2012-06-12 21:39
    @Kuroneko,

    Nice work! That fixed the display issues here. No more flashing monitor.

    @Pik33

    The driver positively looks awesome! Excellent!


    OBC
  • pik33pik33 Posts: 2,347
    edited 2012-06-12 23:27
    Version 0.32:

    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.
  • pik33pik33 Posts: 2,347
    edited 2012-06-15 23:02
    0.33

    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.
  • kuronekokuroneko Posts: 3,623
    edited 2012-06-16 06:20
    @pik33: When the cursor is enabled (flashing) and you scroll text (e.g. due to repeated string writing) sometimes characters are lost. A minimal demo showing this effect:
    cursoron
    
    repeat
      repeat i from 0 to 10
        writeln(s1)
        writeln(s2)
        writeln(s3)
        writeln(s4)
        writeln(s5)
        writeln(s6)
        writeln(s7)
        writeln(inttostr(12345678))
        writeln(hextostr(12345678))
    
      waitcnt(cnt+clkfreq<<2)
    
  • pik33pik33 Posts: 2,347
    edited 2012-06-16 12:05
    0.34

    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.
Sign In or Register to comment.