Is there a "super simple" VGA template I can use?
cbmeeks
Posts: 634
I got the standard VGA Text demo to work. I want to learn how to write my own VGA driver. Even in spin if possible. I'm not looking for super high res at the moment. Just something I can build on.
But, all of the drivers I've seen have a lot of assembly in them. While I'm not stranger to asm (been coding 6502 for years), I would need a "hello world" in asm to get started.
I'm used to C++ with Arduino so spin/propeller asm is new to me.
Anyway, any suggestions would be great. Just something that could perhaps display a low-res VGA screen. Using the internal font would be great too.
Thanks for any help.
But, all of the drivers I've seen have a lot of assembly in them. While I'm not stranger to asm (been coding 6502 for years), I would need a "hello world" in asm to get started.
I'm used to C++ with Arduino so spin/propeller asm is new to me.
Anyway, any suggestions would be great. Just something that could perhaps display a low-res VGA screen. Using the internal font would be great too.
Thanks for any help.
Comments
http://forums.parallax.com/showthread.php/134552-Barebone-VGA-driver
Bit most other VGA drivers use waitvid to actually write a 'pixel' for sync
I think Spin will have hard time writing fonts as it can not keep updating waitvid in time.
The slowest common display VGA horizontal frequency is double what TV is. 640,400i
Any VGA driver worth building on will be all PASM. But PASM is just not that hard. Many here will likely say it is the easiest driver code they did. True for me.
Look around for Kye's work. He made some simple ones that do bitmaps. That is the easiest place to start. Well, color bars are one notch simpler and smaller, but it's not by much.
Thanks!
I'm sure there are C drivers, but they just call the same assembly that Spin does...
http://learn.parallax.com/propeller-c-simple-devices/vga-text-display should get you started.
Ken Gracey
It wouldn't be impossible to achieve that with CogC but you'll always be checking the resulting compiled code to make sure it happens the way you want it to. I suspect it's much easier to just code that part directly in PASM and run it in it's own Cog.
"WAITVID( lvar, LONG[lvar][2] ) takes 1232 cycles, which means there's only time for 3 WAITVIDs per line at 80MHz."
Standard VGA horizontal frequency is 31.4685kHz (double NTSC) so that's ~2,542 cycles (at 80MHz) per line, so there's just enough time for 2 WAITVIDs per line (but not enough time for anything else). So while VGA in SPIN is probably doable, it's going to be very low res. (~25 three color pixels per line)
The reason video drivers are written in PASM is timing. While WAITVID keeps the code in sync with the output, if the code between WAITVIDs takes too long you lose that sync.
I don't mind learning some ASM. So I will check that out too and see how these drivers are made.
OK, stupid question, everyone keeps talking about the WAITVID. What is that? lol
Thanks
WAITVID description can be found in the Propeller Manual, Ver 1.2, page 371. It can be opened from the Propeller Tool Help menu.
There is one Andy did. Kye has a similar one out there, but I bumped into this one first. It's small and pretty simple. Good start, IMHO. Get to know this one cold. Understanding your first one is hard. But if you do, future ones are a whole lot easier.
http://javiervalcarce.eu/wiki/VGA_Video_Signal_Format_and_Timing_Specifications
There are lots of references for signal info. I've linked one here. The 640x400(or maybe it's 480) interlaced timing is the slowest VGA frequency still displayable on most screens today. You should be following the driver activity, looking at the instructions, hardware output schematic and the signal reference to see how the Propeller builds the signal and sends it to the display. It's all in software. All waitvid does is take two longs, one for pixels, one for colors and sends it to the display a pixel at a time. The rest of the magic is in the loops and data, and for VGA, sync bits set and the timing of all that.
Slower frequencies = more time for a Propeller to do stuff while pixels are being drawn.
What you are going to want to do is take that assembly driver, the propeller manual and VGA timings and break it down line by line. Each instruction either sets up the necessary variables and data, or it's making the signal, or it's drawing pixels in the active part of the display.
Video drivers are essentially just a big loop. Everything gets initialized, then the loop starts sending frames out to the display. Many drivers take little bits of time to read variables and adjust the display or colors or both on the fly, but they don't have to do that. This one is passive. All the stuff gets set, and it runs. From there, it turns part of the HUB into a bitmap you can see. That's it. All the advanced stuff comes from this basis. And doing it involves reading more kinds of data from the HUB, setting flags, changing timings, etc... and it can come later on. For now, you just want to understand how a display happens.
Start by reading that one through from start to finish. Early on, focus on instructions. You want to know how compares, jumps, moves, waitvid, etc... work. The end product of this should be you understanding the flow of the driver program. There is some initialization, then the video loop, which just keeps running.
Then focus on what does what. In the initialization portion, there are variables that are required for the right timings. Use your signal reference and look at the code to see how it arrives at getting the right signal. Pulse lengths, sweep frequencies, etc...
Here you will also begin to understand the signal as opposed to the active part of the display and when blanking periods happen.
Finally, parse each instruction and you should be able to follow how pixels in the HUB end up on the screen. It will take a few passes, and just ask questions and keep asking them, until you get it.
When modifying video drivers, it's best to leave the signal parts alone to start. You can do all sorts of stuff with the active part of the display to get a feel for how it all works. Change one thing at a time and keep your old versions.
01_driver.spin, 02_driver.spin, etc... or use GitHub. Doesn't matter, just keep 'em.
When you get a blank screen, compare old to new. There is learning for you each time. Fix it.
You may end up writing your own. You may find you can modify one that is out there too. Either way is just fine.
Colors are another discussion. This driver is any pixel any color. Other drivers will be 2 colors or 4 colors per waitvid. Waitvids are the blocks of pixels and colors that get streamed from the HUB to the display. Waitvids can have a frame length (how many pixels and how fast) and a color set (4 colors tops) Any color any pixel drivers use a 4 pixel frame so that the 4 colors can be specified every waitvid which means any pixel on the display can be any color. This is nice, but memory hungry, but also pretty easy to work with.
The thing about waitvids is they come one after the other once started, unless you stop them. So a driver, once running, always, always feeds the waitvid with the NEXT pixel / color / sync info while the CURRENT pixels are being drawn. It's all about feeding that waitvid before it's needing more info. There are more complex cases out there, but this way of doing it is by far the most common and flexible way.
One recommended exercise here would be to modify this driver to use only two colors or 4 colors. Good opportunity to understand waitvid, timings, etc... needed to put the pixels onto the scan line properly.
Eric
Yes, "worth building on" is subjective.
As I recall, that got built the last time I mentioned PASM in this context. This time I really was writing about SPIN, as a driver can be made, but really won't do much.
Well done, BTW. I never did say that and meant to.
My bias toward PASM for video centers on both advanced technique, which C may well get in the way of due to space in the cog and directives needed, and or in line PASM needed to get it done, which some may find more laborious than just authoring PASM would be otherwise.
Where C is the target environment, this can make sense. It all works the same.
Where it's not, a PASM driver stands alone and can be incorporated into most anything.
Personally, I find it easier to do PASM than I do writing C cog code, and that is the basis for the value judgement, not that C has some basic problem.
IF I can get the time, I will comment one of the basic VGA drivers to help make it more approachable.
Thanks for taking a long time and really putting some effort into your answer. This was extremely helpful.
I'm starting to feel more comfortable with the propeller in general. Seeing smaller projects like this help me figure out what is going on vs. debugging tightly optimized and large projects.
I am excited that I can use C, C++, SPIN or PASM (amongst others, I would imagine).
I will take that river and start building on it. My goal is pretty simple. If I could create something with TMS9918 abilities (and yes, I'm aware of the FPGA version and the
Using the following code, I can only get the 128x96 resolution using a 1024x768 VGA resolution.
What I would like to do is have a native monitor resolution of 640x480. For now, I'm fine with the virtual 128x96 framebuffer. But for the life of me, I cannot get the native resolution to drop to 640x480 (@60Hz).
Any clues? I've tried changing the variables but cannot find the right values.
https://gist.github.com/cbmeeks/4abb596103d026ab00d1
On a tangent, knowing the recommended relationships between the video timing specs comes in handy. There is a fancy VESA built spreadsheet that helps here. The newest version, "CVT1.2 Generator.xlsx", doesn't play well with LibreOffice but the older one is fine. I've attached a copy of the older one.
Key bits of info are:
- Horizontal sync pulse width is calculated at 8% of the horizontal total. It looks like you can go smaller as Chip is using 6% in his drivers. Minimum horizontal retrace doesn't come up as an issue due to it being a busy period in the Propeller drivers so is usually over extended anyway. The nice part here is that upping the dotclock is an easy way to gain horizontal blanking time.
- Vertical retrace time, sync + backporch, is minimum of 550us.
The rest of it mostly just deciding on sensible scan and refresh rates.
vscl_pixel is a hard coded scale factor of 8. That will need tweaked to suit pixel size verses dot clock size.
Line 104 also has a hard coded scale factor of 8 for the vertical.
The fastest the inner loop can cycle is every 32 system clocks, meaning max pixel rate is 80MHz / 32 * 4 = 10MP/s. Anything faster and it'll require splitting across multiple Cogs.
hp must be a multiple of 4 for the inner loop to function correctly. Oh, and VESA recommends horizontal total to be a multiple of 8.
That VGA driver is 640x480i, or maybe 400i, and it's the slowest sweeps you can get. Timings in there might be helpful. That one actually displays non-interlaced on some LCD monitors that automagically handle it all. Spiffy!
Also, the VGA.spin is 640x480.
So, do you want to write your own, or do you want to make the TMS9918 type capabilities, or both?
And, is this about stuffing something into the Apple 2?
If so, I want in, and I've been chipping away at a card myself. Progress has been slow.
What we did in the past to do this kind of thing was take the VGA.spin and modify it to perform the tasks. The chip you want to do isn't too big of a deal. It's gonna take two COGS. Maybe three, but most likely two.
One way would be to cram tiles and a scan line buffer into the signal cog. That's the COG drawing the display. And it can be derived from VGA.spin, or anything really. Doesn't matter much.
You need the scan line buffer, and in fact will need at least a couple of them, because doing sprites requires a sprite COG or what I like to call the graphics COG to fill buffers BEFORE the display gets to 'em. That way there is time to mask, shift, combine, whatever.
So the two COG solution is tiles on the VGA.spin COG, and sprites on another COG, and they work together to make the display.
That chip has collisions and various modes. It might make a whole lot more sense to do just a signal COG that has scan line buffers. First iteration of it will be color bars. Setup the scan line buffer, populate it with some colors and get that to all work just fine. Then add graphics cog to do tiles / character mode graphics, and bitmap graphics, if the chip has them. I've not looked in a loooong time.
Then a sprite cog gets written, and depending on how long things take, maybe a couple more scan line buffers get created to produce enough time for it all to happen. Sprite COG reads the graphics cog data in the scan line buffer, combines the sprites with it, and sets collision flags, etc...
Tomorrow I'll track down some samples. Poke through my blog in the meantime.
I don't think you need to build up a complete driver as much as you need one that has signal timing you can modify, or that is just what you want. That exists.
What you do need to do is make the graphics code to build scanlines like the target chip does.
From there you will have all the functions, but they won't be mapped to registers and modes like the chip will be. That is probably a COG. And if the whole works is going into an Apple, that COG can probably read the bus and pass requests along, etc...
On TV, it's possible to do 320 pixels horizontal, any pixel, any color. You need this for the TMS chip, because it can pack lots of colors onto a scan line when it's sprites are combined with other graphics.
Maybe not... This needs to be broken down to understand. Life is much easier at 2 or 4 colors per waitvid.
On VGA, 256 pixels horizontal is possible.
Now that was before Kurenko (sp?) figured out something called the "waitvid hand off point" (WHOP), and doing that trick frees up a few cycles per waitvid loop, which would put 320 pixels horizontal, any color, within the reach of VGA, but only lower frequency VGA.
His work is excellent, but I've not stepped through a driver yet. Just so you know, wativids repeat. They repeat even when there is no waitvid instruction! And what he does is drop the data the waitvid needs right on the bus, right when a waitvid is looking for it and that allows for really tight pixel loops because there isn't a waitvid instruction in there, like you see in almost every driver now. But doing that requires the Prop run at a specific clock (80Mhz is what I saw) and that the driver adhers to specific timings. It's gonna be worth it to go pick through the ones he's done to see what might do the job.
You are right for seeking 640x480. The lower sweep frequencies free up time to get pixels onto the screen. If this project is possible, it's gonna be possible at 640x480 or 480i
The reason for this is to get "any pixel any color" waitvids are always 4 pixels, which means a lot of waitvids per line, which doesn't leave time for a lot of messing around, and the time it does take limits the horizontal sweep frequency possible at a given number of pixels.
TV is really slow That's part of why I like TV.
Your project seems possible in VGA though. But it's going to take making a fast driver. Good news is there are several to work from, and I'm betting at least one can be gutted to run on scan line buffers, which is all the signal cog needs to do. That and set a few flags for the other COGS to operate from.
Now that I think about it. 4 colors per waitvid won't work. Sprites get their color, chars another one, etc... Add up 4 sprites per line, plus the character colors, and that's gonna be more than 4. So "any color any pixel" is how it is.
Hmm, good point. My newness is apparent here:
So, we've got a special case here of a fixed 8 dot clocks per pixel to handle the limit of 4 colours per waitvid, ie: This line has to stay hardcoded as is for hi-colour modes. That fits the max 10MP/s parameter of course. 640x480@60Hz is nominally around 25MHz so a scale of 2 for 320x240 would require some fiddling ...
I've not yet delved into what it takes to synchronise the counters of two Cogs but I figure it's doable since there is plenty of existing drivers that share video output already. Don't know if any are hi-colour though, they generally burst the waitvids and do the handover at blanking time.
Of course, 32KB of Hub space quickly becomes a limiting factor for VRAM size so most of the high-res hi-colour talk is just academic.
Well, I've had a little bit of sleep and I am thinking more clearly now.
Let me back up and tell you what my goals are (there are several). I love old hardware. I have over 50+ "retro" computers like Atari's, Commodores and Apple II's (among many other kinds). So one of my goals is to build a Mockingboard clone for the Apple IIe (which is where Potatohead got that reference). I hadn't thought about putting a VGA/NTSC propeller board into an Apple IIe but I'm not opposed to it! Actually, I have a schematic that puts a real TMS9918 into an Apple IIe that was published YEARS ago but that's another story.
Anyway, my biggest goal is to design my own 8bit computer. I could use the Z80 or the 6502 (I've programmed the 6502 since I was 12). But I want this computer to have "retro" graphics with a little bit of enhancements. I bought several TMS9918's to use. I have all the data sheets. But the problem I keep running into is designing around the DRAM that chip expects. No one has those anymore and for good reason (-5v, +12v requirements!).
So, without going FPGA (I'm on a Mac so you can forget FPGA), all of my research for "graphics chips" leads me to Propeller. Arduino's have done excellent work in video but not like the prop. Hard to beat those 8 cogs.
Anyway, I figured once I had a "virtual graphics chip", I could put it into other designs as well. For example, my retro computer could easily be put into box and called a console. So in "console" mode, it would connect to a TV. In "computer" mode, it would connect to a VGA with a keyboard/mouse.
So, what abilities do I want it to have?
My goal for level one is:
256x192 resolution (fits TMS9918 and ZX Spectrum)
32 sprites of at least 16x16 resolution (fits TMS9918)
At least 8 sprites per scanline (double the TMS9918).
64+ colors
I wasn't really going for a cycle accurate version of the TMS9918 but if that could be achieved I certainly wouldn't mind it. The FPGA (F18 I think) clone of the TMS9918 does just that along with some enhancements like all 32 sprites on one scanline and choosing what your 16 colors look like. But it only works on VGA.
To be honest, I'm not so much concerned with writing the actual video drivers as I am using the chip in my designs. I'd like to treat the propeller/video chip as my "poor man's ASIC" to use in my console/computer.
So, Potatohead (and anyone else), I would welcome any help you would like to offer if you're interested.
Now, my goal for my first computer/console would be:
Z80 as the CPU
A propeller as the video and audio (with a SIDCog and AYCog thrown in if room permits)
An Arduino for the IO (could probably use another propeller here but I am much more familiar with Arduino and their IO libraries)
256K SRAM to share
To me, that's a 4 chip solution (minus glue logic) that should hopefully be within my reach. Plus, it has a similar architecture (graphics/sound/cpu) as the ColecoVision and MSX so perhaps games could be patched to run on it.
Wow. That was a lot. Might be better to move this to another thread if people prefer.
Thanks again everyone!
http://forums.parallax.com/showthread.php/127123-Full-Color-Tile-Driver-Thread?p=953824&viewfull=1#post953824
See the JB drivers for VGA and mine for TV. VGA is 256, TV is 320. It would take attempting this with the latest trick (WHOP) to get 320 on VGA.
It's not quite the TMS chip, in that things are full color, but it's fast, has tiles, lots of sprites, etc... You can tune the number of sprites / line by adjusting the number of sprite COGs able to work on the problem. One render COG will deliver many sprites per line. They are 4x8 sprites, and you just use two of them for an 8x8, etc... It can deliver several hundred sprites per screen, and 50 or so per line with just a couple render COGs.
Doing text on this one is expensive, due to it being full color, but there are a couple of paths. One is to get a text driver and just run it when you want a text mode, or make a text COG that takes bitmap fonts and converts them to true color on the fly. That's not very hard to do.
If you put this into your project, you would need a little program to send receive data somehow... Once you have that, it's simple to display on screen.
BTW: I wouldn't mind seeing that schematic. Does it put the TMS right on the bus, or through a PIA?
Edit: There are a variety of drivers written. One path on this is to store a few in an EEPROM, or SD card, and have them load and run based on events you trigger. Check out the loderunner type game for an example of one that fetches data from SD card while the game is running. Game level data is loaded into the HUB each time it's needed. Easy for Props to do stuff like that.
Your retro computer could deliver quite a number of video output scenarios that way.
http://forums.parallax.com/showthread.php/138254-TEXAS-INSTRUMENTS-TMS9918-9928-VDP-Emulation-on-Propeller?highlight=tms9918
The more I see NTSC, the more "retro" it feels. So I think I will stay in that camp for a while.
Oh, here's the schematic.
https://dl.dropboxusercontent.com/u/471665/Hi-Res%20Graphics%20TMS9918%20BYTE%200882.pdf
I totally forgot about the clone... Not sure I ran that one. Cool beans. Maybe it is a good fit.
That may be something to look at as well. If you do not mind lower resolutions (up to 460x480), you can also do a direct bitbanged VGA in PASM with out any of the video helper HW, and this will give you the ability to set any pixel to any of the 64 possible colors with the standard RDAC used on propeller based systems. Though memory could still be a problem, and it would take two cogs minimum to make it usable. There is also the possibility of using the Prop to generate addresses, and having a frame buffer in external Parallel SRAM, and bit bang out from the SRAM outputs, instead of using the Prop's outputs to bitbang (this can get rid of the RAM problem).
Though there are many other ways to do the same thing.