How Video Modes Work

From Uzebox Wiki
Jump to navigation Jump to search

Foundational Knowledge

To understand how the Uzebox generates a video signal, you must first comprehend what the television display expects before it will output. The standard Uzebox is designed to interface with televisions using the NTSC signal. This standard displays 30 frames(each frame being 2 fields) a second drawn one horizontal line at a time, from top to bottom. For each horizontal line, there is a period before and after actual rendering begins known as a horizontal blanking period. During this time sound must be processed and updated, and preparations to draw the next line from the Uzebox memory must take place. This time period is very small, and like all video mode details, must have exact timing. If the time is off, the picture will shear, lose vertical lock, or other anomalous things because it does not meet the NTSC standard that the television is expecting. After each frame is drawn, there is a short time in between which is known as the vertical blank period where no pixels are drawn. While outputting to the television there is no time to do anything else without generating a bad signal, so this vertical blank is the only place we can do any other kind of processing to update a game world. Vertical blank must last an exact length to avoid display problems, so an interrupt system will override any other processing taking place in order to maintain. This is a complicated subject, I recommend further reading here: Video Generation


The Uzebox has several video modes that are designed to capitalize on the systems capabilities and limitations. You might notice that Uzebox video modes can be quite different from other machines with similar capabilities. This is to be expected, because the Uzebox has radically different hardware! Most modes are tile based, as bitmap displays consume large amounts of memory. The advantage of tile based is that 1 byte can act as a pointer to ~64 bytes of flash memory, that is we can display ~64 bytes of visual data(in flash format that we have 64k of) using only ~1 byte(2 in certain modes) of actual ram(which we only have 4k of!). This allows full 8 bits per pixel display of 256 different colors at resolutions of 240x224 or greater, where a bitmap display cannot possibly achieve such a high combination of resolution and color depth due to limited ram(do the math, 1 byte per PIXEL!!). Tile based modes also save a lot of processing time, as we don't have to actually draw game worlds that consist mainly of repeating patterns individually to a buffer, but merely point VRAM at the right pre-calculated drawings. In general, the types of games we will do on Uzebox are retro style. Retro style games used tile based methods because that's what the hardware was based on. It is for these exact same reasons, even though their hardware was different. It is a very efficient blend to achieve good visual output with modest hardware resources. There are also some bitmap display modes that perform a compromise of color depth and resolution to provide the most useful possible bitmap display within ram limits. For the above reasons, they are not commonly used for games, though they are also quite interesting and can be useful for certain things.

Software Acting As Hardware

There seems to be some confusion amongst aspiring Uzebox programmers, as to what the hardware supports for video output. Quite simply, the Uzebox supports anything that can be calculated and output correctly in time to meet the NTSC standard. The Uzebox has no video chip, accelerator, or anything of that nature, so it is not limited to a small amount of possible configurations. The Uzebox literally outputs a byte that represents a color, for every pixel on the television display you see, straight out to the DAC pins. This happens at an extremely fast pace, as the NTSC signal speed is 3.58mhz. In the old days of 80's era 6502/z80/etc. computers, which are the most comparable to Uzebox, the machines also had to feed data at this speed. The processors were often not capable of completing even 1 instruction during the time the NTSC signal expects another pixel. So the processors could not directly deal with individual pixel elements, and instead needed to be able to deal with chunks of pixel elements(hence, tiles and sprites). This was accomplished by dedicated hardware that was specifically created for this purpose and nothing else, adding cost and complication. The Uzebox is exactly the opposite of this. To replace these chips that were required back then, Uzebox does it with sheer processing speed! The ATmega644 operates at over 28mhz, which is drastically faster than the older processors clock speed(plus other technically superior things). This allows enough instructions to happen per pixel to directly instruct the television, instead of instructing custom hardware how to interface with the TV and figure out what to display next. It should be noted, this is not an over sight, nor is it lack of understanding that dedicated hardware could be made to do more. The whole novelty/particularity of the system is that it is just a small micro-controller doing things that used to require a whole complex circuit board! This way it is cheap, fun, and easy to build for hobbyists as well as creating an interesting development environment for games. And it's just cool to do it that way!

To begin to understand how the video is calculated by software is to look in the source code. You should acquire a copy of the kernel and look inside. You will see different video modes, and in each one there is a videomodeXcore.s file(where X is mode number)which is the actual assembly language instructions that do the work. Let's quickly look at a snippet of video mode 3(in kernel\videoMode3\videoMode3core.s) assembly source code:

 lpm r16,Z+
 out _SFR_IO_ADDR(DATA_PORT),r16        ;pixel 1
 ld r18,Y+                              ;load next tile # from VRAM

 lpm r16,Z+
 out _SFR_IO_ADDR(DATA_PORT),r16        ;pixel 2
 mul r18,r19                            ;tile*width*height

 lpm r16,Z+
 out _SFR_IO_ADDR(DATA_PORT),r16        ;pixel 3
 cpi r18,RAM_TILES_COUNT		;is tile in RAM or ROM? (RAM tiles have indexes<RAM_TILES_COUNT)
 in r6,_SFR_IO_ADDR(SREG)	        ;save the carry flag

 lpm r16,Z+
 out _SFR_IO_ADDR(DATA_PORT),r16        ;pixel 4
 brsh .+2		                ;skip if next tile is in ROM	
 movw r20,r4 	                        ;load RAM title table address +row offset	
 lpm r16,Z+
 out _SFR_IO_ADDR(DATA_PORT),r16        ;pixel 5
 bst r6,SREG_C	                        ;store carry state in T flag for later branch
 add r0,r20		                ;add tile table address +row offset lsb
 lpm r16,Z+
 out _SFR_IO_ADDR(DATA_PORT),r16        ;pixel 6
 adc r1,r21		                ;add title table address +row offset msb
 dec r17			        ;decrement tiles to draw on line

 lpm r16,Z+
 out _SFR_IO_ADDR(DATA_PORT),r16        ;pixel 7   
 lpm r16,Z+

 breq end	
 movw ZL,r0   	                        ;copy next tile adress

 out _SFR_IO_ADDR(DATA_PORT),r16        ;pixel 8   
 brtc romloop
 rjmp .

There is even more code to handle frame timing, sound updating, etc, but this gives you and idea of what is being done to draw the right picture to the television. There is a lot of work done only by software, to negate the need for hardware, and bit bang out some visuals! You'll note here that while perfect timing of pixel output is maintained, the time between is used to figure out what we will be drawing next. That way when we get there we are ready to continue. Different video modes will handle the specifics differently, but the general idea is the same. The processor reads, writes, and preforms calculations using ram and flash data within the correct time restraints to achieve the desired result.

For more details on the inner working of the kernel see: Uzebox: How it works (pdf)

Tweaking video modes: A how-to tutorial

How to create or tweak a video mode