Shop OBEX P1 Docs P2 Docs Learn Events
VGA text driver questions/concepts - Q's probably for Chip - vga streamer interrupts wkg — Parallax Forums

VGA text driver questions/concepts - Q's probably for Chip - vga streamer interrupts wkg

Cluso99Cluso99 Posts: 18,069
edited 2021-02-16 04:10 in Propeller 2

I have the VGA demos that Chip released eg VGA_1280x1024

I will be attempting to put pasm text screen handling into this object but I am not sure how to insert it between the streamers operation of painting the VGA screen (within the same cog).

How do I ensure that I don't let the streamer under-run while maintaining the screen buffer ie writing characters to the screen, handling control codes, and clearing and scrolling?

I presume I am going to need to perform some timer style interrupts so I can keep the streamer fed. While not feeding the streamer I will then be able to perform the other screen functions? But I am unsure how to go about this. Any guidance would be appreciated.

Guess I should also ask, has anyone done this already?
@rogloh Is your driver capable of this (without external hyperram)?

«1

Comments

  • Cluso99Cluso99 Posts: 18,069

    As background info, here is the field display loop

    ' Field loop
    '
    .field  setq    #5-1                    'load settings
            rdlong  background0,ptra
    
            mov     ptrb,#$190              'point between $180/$1A0 color sets in LUT
    
            wrlut   background0,ptrb[-16]   'set colors for chr msb = 0
            wrlut   foreground0,ptrb[-15]
            wrlut   background1,ptrb[+16]   'set colors for chr msb = 1
            wrlut   foreground1,ptrb[+17]
    
    
    .line   xcont   m_bv,#0                 'do before-visible part of scan line
    
            rdfast  #0,screen_base          'set fifo to read from current screen row
    
            rep     @.chr,#cols             'ready to output 8 pixels for each chr
    
            rfbyte  pa      wc              '2  get chr
            bitc    m_px,#16                '2  select colors using msb of chr
            and     pa,#$7F                 '2  trim chr to 7 bits
            add     pa,font_base            '2  add offset for top/middle/bottom lines of chr
            rdlut   pa,pa                   '3  look up four lines of chr
            shr     pa,font_line            '2  get line of interest into lower 8 bits
            xcont   m_px,pa                 '2 =15  output 8 single-bit pixels to streamer
    .chr
            xcont   m_bs,#0                 'do before-sync part of scan line
            xzero   m_sn,#1                 'do sync part of scan line
    
            add     font_line,#$08          'increment chr line selector
            cmpsub  font_line,#$20  wz
        if_z    add font_base,#$080         'increment top/middle/bottom lines selector
        if_z    cmpsub  font_base,#$180 wz
        if_z    add screen_base,#cols       'increment screen pointer and row
        if_z    incmod  rowx,#rows-1    wz
        if_nz   jmp #.line                  'loop until all rows output
    
    
            callpa  #1+2,#blanks            'do bottom blanks
    
            drvnot  av_base_pin             'vertical sync on
            callpa  #3,#blanks              'do vertical sync blanks
            drvnot  av_base_pin             'vertical sync off
    
            callpa  #38+2,#blanks           'do top blanks
    
            jmp #.field                     'loop
    '
    '
    ' Output blank lines
    '
    blanks  xcont   m_bv,#0                 'do before-visible part of scan line
            xcont   m_vi,#0                 'do visible part of scan line (blank)
            xcont   m_bs,#0                 'do before-sync part of scan line
            xzero   m_sn,#1                 'do sync part of scan line
      _ret_ djnz    pa,#blanks              'loop if more blanks needed
    
  • cgraceycgracey Posts: 14,152
    edited 2021-02-13 10:25

    You need to get the video running on a streamer-empty interrupt (XMT event).

    Here is a program that generates NTSC on interrupts, along with one that does it in the main code. To make this work for VGA, you'll need to break the VGA program into pieces that can run on interrupts, instead. Looking at these two programs will show you what the difference is.

    To get that Space Invaders emulator running all in one cog, we did the video on interrupts, so that the 8080 emulator could take most of the time.

  • roglohrogloh Posts: 5,787
    edited 2021-02-13 12:23

    @Cluso99 said:
    I have the VGA demos that Chip released eg VGA_1280x1024

    Guess I should also ask, has anyone done this already?
    @rogloh Is your driver capable of this (without external hyperram)?

    Cluso my video driver COG in text mode is screen buffer based and requires the client to put character data into the screen buffer, so it isn't a terminal as such. I have included other SPIN2 APIs to select the active region, and FG+BG colours and basic tx(), out() APIs etc for printing which can conveniently be mapped to SEND from SPIN2 clients. Actually I will be releasing its update very soon with the external memory support, I have finally got it working again with PNut and PropTool a day or two ago instead of just in flexspin as the first release used to be. Just wondering if I'll release it before more demos and doc updates are in place...

    @"Ken Gracey" , if you need to use my VGA driver soon in Proptool let me know I can shoot you an updated build that works.

  • evanhevanh Posts: 15,915

    Here's Chip's code again but without the ASMCLK macro.

  • Ray, I also created a VGA text driver that supports ANSI escape codes and up to 1280x960 resolution (that one requires a 16 pixel wide font, with 8 pixel wide fonts it only goes up to 1024x768). Actually looking at the timings it should be able to do 1920 wide, I just haven't tried that. It's text only, but of course the font can contain graphics characters so you can do some old-style graphics that way.

    For my object I feed the streamer one character line (8 or 16 pixels) at a time. Timing can get tight at higher resolutions, but using wider characters (like the P1 ROM font at 16x32) really helps. The pixel depth also complicates things. Monochrome is the most efficient, but oddly enough using true color (24 bit color) is the second most efficient, since in that case we can just feed the raw color values to the streamer. The character data is slurped out of HUB ram during the horizontal blanking and then fed to the streamer from COG ram durinig the active video. No interrupts required.

  • I have used ER Smith's ANSI - VGA driver with great success. It is very solid and easily modifiable for your specific use.
    The screen sizes are especially useful for both low & high resolution. I use the original P1 font for all of my work.

    One thing I would like to add are either double height characters - And/OR - Custom designed bit-mapped characters using the P1 font 16x32 format

  • I’m another fan of ERSmith’s VGA driver. Its been bulletproof for me and it is really simple to hook up to FlexBASIC’s PRINT #n command. Once you initialize it, printing to the VGA becomes as simple as:

    print #3 “Hello world”

  • Cluso99Cluso99 Posts: 18,069

    @rogloh said:

    @Cluso99 said:
    I have the VGA demos that Chip released eg VGA_1280x1024

    Guess I should also ask, has anyone done this already?
    @rogloh Is your driver capable of this (without external hyperram)?

    Cluso my video driver COG in text mode is screen buffer based and requires the client to put character data into the screen buffer, so it isn't a terminal as such. I have included other SPIN2 APIs to select the active region, and FG+BG colours and basic tx(), out() APIs etc for printing which can conveniently be mapped to SEND from SPIN2 clients. Actually I will be releasing its update very soon with the external memory support, I have finally got it working again with PNut and PropTool a day or two ago instead of just in flexspin as the first release used to be. Just wondering if I'll release it before more demos and doc updates are in place...

    @"Ken Gracey" , if you need to use my VGA driver soon in Proptool let me know I can shoot you an updated build that works.

    Thanks Roger. Seems it's not what I'm after as I just want basic VGA that I can add the text code into.
    Looks like I have a selection of text code to choose from too :)

  • Cluso99Cluso99 Posts: 18,069

    Chip & Evan,
    Thanks. I'll take a good look.
    I think for what I'm doing, it will be a combo of this.

    Eric, PropGuy2 & JRoak,
    Thanks, and for the vote of confidence too.
    I'll take a look as this sounds very useful. Perhaps a combo of this with Chip's interrupt streamer will work nicely. I can always add in extra things if it's not there. I needed to do some basic pasm code for driving my LCD including scrolling in sw (even tho I removed it) so I have some of that to choose from too.

    While I never cared for ANSI codes way back, it is quite common and possibly makes more sense than VT52/100 ???

  • Cluso99Cluso99 Posts: 18,069

    Evan,
    Perhaps you might like to add the asmclk code to the P2 Tricks and Traps Reference thread?
    https://forums.parallax.com/discussion/169069/p2-tricks-traps-amp-differences-between-p1-reference-material-only/p1

  • evanhevanh Posts: 15,915

    Ah, what I did was hand crafted the clock mode constants. It's not as simple as generic code replacement.

  • Cluso99Cluso99 Posts: 18,069

    Thanks Evan :)
    I didn't look close enough to realise it was tailored to the requirements.

  • Cluso99Cluso99 Posts: 18,069

    So I've looked at the various pieces of code. Thanks guys :)

    I am trying to write a VGA Device Driver that will fit into my stable of code that uses my same format object (the one based on jonnymacs fullduplexserial) so that code can be independent of the attached devices.

    I know this will never be perfect. For instance, VGA might support ANSI sequences, but what about serial? This depends on what is on the other end of the serial.
    For instance, my LCD driver cannot do scrolling properly, so the cursor just flows from the bottom to the top and each time the cursor moves down a line, that line and the one following are cleared. Not ideal, and not ultra-fast either. But it serves the purpose.

    Now for Text VGA, I only want to allocate 1 cog do do this. So within the cog I need to...

    • Display the screen buffer using the streamer which requires specific timing - Chip has given me some NTSC code that will allow me to use the same concept for VGA.
    • Combine code to perform basic terminal functions such as
    • -- support CR, LF, HOME, CLS
    • -- support a cursor
    • -- support scrolling
    • -- support limited color text
    • -- support some ANSI - maybe ??? (the above does not need ansi)

    Most of the code posted above is unfortunately in spin and of course this needs to be in pasm. However, I've done all but ANSI already in pasm (I have a cursor in P1 1-pin TV code) but not in LCD yet.

  • @Cluso99: Why require that the ANSI processing happen in the VGA cog? If it happens in the original COG everything is much simpler -- the VGA cog can then stick to the one job it really needs to do (output the video) and the other COGs can handle any time consuming processing.

  • roglohrogloh Posts: 5,787
    edited 2021-02-14 02:07

    Cluso, so your intent is to have a COG that just takes an input stream of characters and puts them onto the screen without any API to call as such?

    If the client that wants to print text still runs SPIN2 it could call my video driver API to do exactly what you need for these things (apart from interpreting ANSI at this stage) and can be conveniently be hooked into printing text via SEND redirection. I'll send it out soon.

    @Cluso99 said:
    So I've looked at the various pieces of code. Thanks guys :)

    • Combine code to perform basic terminal functions such as
    • -- support CR, LF, HOME, CLS
    • -- support a cursor
    • -- support scrolling
    • -- support limited color text
    • -- support some ANSI - maybe ??? (the above does not need ansi)
  • Cluso99Cluso99 Posts: 18,069

    Eric,
    Because the user code is totally decoupled. The user doesn’t know what is connected. Ansi could be sent within the user section.

    However, I don’t want to burden the formatting object. I may execute ansi sequences in the vga pasm cog as its not difficult to implement a subset.

    Roger,
    I’m using a decoupled hub buffer(s) to communicate with device drivers. I can substitute the device drivers on the fly too with existing compiled code. So the driver must pick its characters from a hub buffer. I'm sure that could be done with your driver but then there wouldn’t be soace to implement the screen handling code.

    SEND doesn’t work in this regime.

  • @Cluso99: User code can be decoupled without having to force things into a cog. I think this is revealing a flaw in your framework: does every driver need to use a whole cog for its output routine? What if it's some kind of trivial thing that can easily be run with just a smartpin?

    Maybe it would be better to provide a jump table for the I/O routines, instead of a buffer. Then the driver would still be de-coupled, but the code could run in the same COG if it wants to.

  • @Cluso99 said:
    Roger,
    I’m using a decoupled hub buffer(s) to communicate with device drivers. I can substitute the device drivers on the fly too with existing compiled code. So the driver must pick its characters from a hub buffer. I'm sure that could be done with your driver but then there wouldn’t be soace to implement the screen handling code.

    SEND doesn’t work in this regime.

    Okay, sounds like you have a different display model where things are being done more automatically, under the hood. I can see some usefulness in some cases, like if you wanted to print from PASM cogs etc, but at least personally I'd still like to have control from SPIN2 to display whatever I want and get to use some richer APIs for various things. This SEND redirection is useful enough for me at the moment.

  • Cluso99Cluso99 Posts: 18,069
    edited 2021-02-14 06:33

    @rogloh said:

    @Cluso99 said:
    Roger,
    I’m using a decoupled hub buffer(s) to communicate with device drivers. I can substitute the device drivers on the fly too with existing compiled code. So the driver must pick its characters from a hub buffer. I'm sure that could be done with your driver but then there wouldn’t be soace to implement the screen handling code.

    SEND doesn’t work in this regime.

    Okay, sounds like you have a different display model where things are being done more automatically, under the hood. I can see some usefulness in some cases, like if you wanted to print from PASM cogs etc, but at least personally I'd still like to have control from SPIN2 to display whatever I want and get to use some richer APIs for various things. This SEND redirection is useful enough for me at the moment.

    Yes, it’s a different model, on the way to a P2 OS where different device drivers can be loaded and/or reloaded at run time.

    I’m really liking the simplicity of using interrupts to do the actual vga display. I think i can make the text font generation under interrupts optional which would permit graphics too, perhaps for part of the screen too.

  • Cluso99Cluso99 Posts: 18,069

    Chip,
    I’m not quite understanding the streamer / rdfast/ setq interaction.

    So presume I have the streamer running under interrupts. I’m using text only, so a font and a color lookup. I also want to do text screen processing, which is why I need the streamer under interrupts.

    Currently every character line generates (for an 8x8 font) 8 pixel lines. If we except that one line (usually the bottom line) is blank, then it’s a wasted line that just outputs blanks.

    So here’s the idea. The first line of pixels we make blank - this allows us to fetch the line of characters into the cog/LUT, and then on each of the next 7 pixel lines we process those characters into a line of pixels.
    Can we use SETQ/SETQ2 RDLONG pair to fetch the line of characters while we output a streamer pixel line of background color?
    For each of the 7 pixel font lines, we process (lookup) the pixel line within the cog/LUT and use SETQ/SETQ2 WRLONG pair to write back the pixel line to hub ready for output by the streamer on the next pixel line. (We will need a two pixel line in hub to ping/pong).

    Would this work? And do you think I might gain some additional time for the screen processing? Or can you think of a better way?

  • pik33pik33 Posts: 2,366

    It seems the cog can process text mode in the real time without any tricks with blank lines.

    This thing while not optimized, displays one line of 4 characters : about 60 cycles of 320 available between xconts used here. I am now trying to use 2 sets of LUT registers to change colors every 4 chars=one xcont so every 16 lines I read 50 longs to the cog using rdfast while displaying a border - HBlank period may be also used.

                   rdlong char,framebuf2
                    add    framebuf2,#4
    
                    getbyte test0001,char,#0
                    shl     test0001,#4
                    add     test0001,fontbuf
                    add     test0001,fontline
                    rdbyte  test0002,test0001
    
                    getbyte test0001,char,#1
                    shl     test0001,#4
                    add     test0001,fontbuf
                    add     test0001,fontline
                    rdbyte  test0003,test0001
    
                    shl test0003,#8
                    or  test0002,test0003
    
                    getbyte test0001,char,#2
                    shl     test0001,#4
                    add     test0001,fontbuf
                    add     test0001,fontline
                    rdbyte  test0003,test0001
    
                    shl test0003,#16
                    or  test0002,test0003
    
                    getbyte test0001,char,#3
                    shl     test0001,#4
                    add     test0001,fontbuf
                    add     test0001,fontline
                    rdbyte  test0003,test0001
    
                    shl test0003,#24
                    or  test0002,test0003
    
                    xcont   m_luttest3,test0002
    
  • cgraceycgracey Posts: 14,152
    edited 2021-02-14 22:14

    @Cluso99 said:
    Chip,
    I’m not quite understanding the streamer / rdfast/ setq interaction.

    So presume I have the streamer running under interrupts. I’m using text only, so a font and a color lookup. I also want to do text screen processing, which is why I need the streamer under interrupts.

    Currently every character line generates (for an 8x8 font) 8 pixel lines. If we except that one line (usually the bottom line) is blank, then it’s a wasted line that just outputs blanks.

    So here’s the idea. The first line of pixels we make blank - this allows us to fetch the line of characters into the cog/LUT, and then on each of the next 7 pixel lines we process those characters into a line of pixels.
    Can we use SETQ/SETQ2 RDLONG pair to fetch the line of characters while we output a streamer pixel line of background color?
    For each of the 7 pixel font lines, we process (lookup) the pixel line within the cog/LUT and use SETQ/SETQ2 WRLONG pair to write back the pixel line to hub ready for output by the streamer on the next pixel line. (We will need a two pixel line in hub to ping/pong).

    Would this work? And do you think I might gain some additional time for the screen processing? Or can you think of a better way?

    Because the streamer has immediate->LUT->pins modes, you could do such video on interrupts using SETQ+RDLONG with subsequent XCONTs, without even interrupting RDFAST/FIFO being used by XBYTE.

    I am going to move 16 longs of the Spin2 interpreter from LUT to register space, so that we'll have 16 longs free, usable as 1/2/4-bit LUT colors for streamer use on interrupts.

  • Cluso99Cluso99 Posts: 18,069
    edited 2021-02-15 00:39

    @cgracey said:

    @Cluso99 said:
    Chip,
    I’m not quite understanding the streamer / rdfast/ setq interaction.

    So presume I have the streamer running under interrupts. I’m using text only, so a font and a color lookup. I also want to do text screen processing, which is why I need the streamer under interrupts.

    Currently every character line generates (for an 8x8 font) 8 pixel lines. If we except that one line (usually the bottom line) is blank, then it’s a wasted line that just outputs blanks.

    So here’s the idea. The first line of pixels we make blank - this allows us to fetch the line of characters into the cog/LUT, and then on each of the next 7 pixel lines we process those characters into a line of pixels.
    Can we use SETQ/SETQ2 RDLONG pair to fetch the line of characters while we output a streamer pixel line of background color?
    For each of the 7 pixel font lines, we process (lookup) the pixel line within the cog/LUT and use SETQ/SETQ2 WRLONG pair to write back the pixel line to hub ready for output by the streamer on the next pixel line. (We will need a two pixel line in hub to ping/pong).

    Would this work? And do you think I might gain some additional time for the screen processing? Or can you think of a better way?

    Because the streamer has immediate->LUT->pins modes, you could do such video on interrupts using SETQ+RDLONG with subsequent XCONTs, without even interrupting RDFAST/FIFO being used by XBYTE.

    I am going to move 16 longs of the Spin2 interpreter from LUT to register space, so that we'll have 16 longs free, usable as 1/2/4-bit LUT colors for streamer use on interrupts.

    Thanks Chip.
    Sounds great. This cog is all pasm so no need for spin in this cog.

    I can read a line of characters into cog/lut with SETQ RDLONG and then convert each line to pixel data per line displayed.

    Scrolling is best done by shifting from hub via cog/lut and back to hub using setq as it would be fastest.
    BTW I have already done the pasm code for screen handling (some control characters and scrolling) in my LCD driver in a previous (not released) version before I ditched the screen buffer altogether and just used the LCD's RAM. So in reality, I've just to combine a few pieces of code with the interrupt VGA code.

    Being able to use the streamer from LUT concurrently with SETQ/SETQ2 is a real bonus! Forgot that's what the second LUT memory port was for.
    These P2 bonuses just keep popping up :wink:

  • Cluso99Cluso99 Posts: 18,069

    @pik33 said:
    It seems the cog can process text mode in the real time without any tricks with blank lines.

    This thing while not optimized, displays one line of 4 characters : about 60 cycles of 320 available between xconts used here. I am now trying to use 2 sets of LUT registers to change colors every 4 chars=one xcont so every 16 lines I read 50 longs to the cog using rdfast while displaying a border - HBlank period may be also used.

                   rdlong char,framebuf2
                    add    framebuf2,#4
    
                    getbyte test0001,char,#0
                    shl     test0001,#4
                    add     test0001,fontbuf
                    add     test0001,fontline
                    rdbyte  test0002,test0001
    
                    getbyte test0001,char,#1
                    shl     test0001,#4
                    add     test0001,fontbuf
                    add     test0001,fontline
                    rdbyte  test0003,test0001
    
                    shl test0003,#8
                    or  test0002,test0003
    
                    getbyte test0001,char,#2
                    shl     test0001,#4
                    add     test0001,fontbuf
                    add     test0001,fontline
                    rdbyte  test0003,test0001
    
                    shl test0003,#16
                    or  test0002,test0003
    
                    getbyte test0001,char,#3
                    shl     test0001,#4
                    add     test0001,fontbuf
                    add     test0001,fontline
                    rdbyte  test0003,test0001
    
                    shl test0003,#24
                    or  test0002,test0003
    
                    xcont   m_luttest3,test0002
    

    On the P1 and monochrome (ie one forecolor and one backcolor) and 80x25 I've done the whole job in a single cog. IIRC scrolling was included but it was shared over multiple scan lines. Of course color adds a lot to the mix!!!

  • @Cluso99 said:

    @pik33 said:
    It seems the cog can process text mode in the real time without any tricks with blank lines.

    This thing while not optimized, displays one line of 4 characters : about 60 cycles of 320 available between xconts used here. I am now trying to use 2 sets of LUT registers to change colors every 4 chars=one xcont so every 16 lines I read 50 longs to the cog using rdfast while displaying a border - HBlank period may be also used.

    ```
    rdlong char,framebuf2
    add framebuf2,#4

                getbyte test0001,char,#0
                shl     test0001,#4
                add     test0001,fontbuf
                add     test0001,fontline
                rdbyte  test0002,test0001
    
                getbyte test0001,char,#1
                shl     test0001,#4
                add     test0001,fontbuf
                add     test0001,fontline
                rdbyte  test0003,test0001
    
                shl test0003,#8
                or  test0002,test0003
    
                getbyte test0001,char,#2
                shl     test0001,#4
    

    On the P1 and monochrome (ie one forecolor and one backcolor) and 80x25 I've done the whole job in a single cog. IIRC scrolling was included but it was shared over multiple scan lines. Of course color adds a lot to the mix!!!

    I did a color one on P1 ;) Only 40x25, but I think I made the terminal code really efficient and it supports all the PST commands. It even has a "bell" (basically adding some constant to the DAC on every line until a timer runs out -> slightly distorred sawtooth wave. Just takes a few instructions.)

  • evanhevanh Posts: 15,915
    edited 2021-02-15 10:01

    Chip didn't really answer your original question of can the SETQ+RDLONG be used while the streamer is also using the FIFO to read hubRAM. The answer is yes, SETQ+RDLONG doesn't use the FIFO at all. And I think you'll be needing this mode.

  • @evanh said:
    Chip didn't really answer your original question of can the SETQ+RDLONG be used while the streamer is also using the FIFO to read hubRAM. The answer is yes, SETQ+RDLONG doesn't use the FIFO at all. And I think you'll be needing this mode.

    Yes that the key to making things run smoothly while doing video with the P2. I've exploited that capability significantly myself and is one of the more powerful capabilities of the P2 to allow multiple things to happen at once in a COG.

  • Cluso99Cluso99 Posts: 18,069

    Evan,
    Hub is only single port, so streamer and setq couldn’t both have access on the same clock from what I understand the circuit to be - there’s only one 32 bit buss going to the cog/LUT gated to one of 8 x 16KBx32 hub blocks. Guess I didn’t think that part thru.

    But the streamer does have concurrent access to the LUT as its dual port and the cog accesses it from the other port. IIRC this is why there’s a 3 clock rdlut and not a 2 clock rdlut. I’d forgotten all this.

    I can see some testing on the horizon ;)

  • evanhevanh Posts: 15,915

    That's the neat part about the FIFO. It bursts for the streamer, so the streamer can pace itself without worrying about hub access timings. There is plenty of time for the SETQ+RDLONG to also burst between the FIFO bursts.

  • Cluso99Cluso99 Posts: 18,069

    VGA using Interrupts
    Attached is VGA_640x480_text_80x40_interrupt which runs the streamer under interrupts

    I found a couple of traps

    • waitx does not work in the non-interrupt code - I presume we cannot interrupt a waitx instruction ?
    • don't use calls in the interrupt code - I expect/presume we only have one internal stack space

    ' setint1 #INT_XMT
    The INT_xxx definitions (as defined in the spin document 34r/s) appear not to work

Sign In or Register to comment.