Reference: Video Configuration

We are going to write a function for setting up the Video Interface for every valid possible combination. This will include "parsing" a constant value and conditionally branching to set the right configuration register values. Please see other references to understand the basics of each instruction, this tutorial is going to be about "abusing' these instruction.

Function Specification

  • Name: VI_INIT
  • Parameter:
    • a0: Single constant
    • a1: Screen Buffer
    • a2: Output Buffer Size
  • Return:
    • v0: Success = 0, Errors -#
  • Actions:
    • Disable Interrupts
    • Wait for VBLANK
    • Setup Video
    • Enable Interrupts

In the Lessons (5+) we used a Macro to setup the Video and it took 4 parameters (width,height, status, origin) why do we want to replace this? While the code works and is easy to understand as a beginner, it's a little too flexible and doesn't validate it's parameters.

Most TV's are good at saying "I don't understand the signal so I'm going to go 'black' ". Unfortunately there is going to be one TV that is damaged by sending the wrong settings, so we really should be very careful. One of the easiest ways to validate parameters is to use the right variable type. For example there are only 2 resolutions for each TV format if we accept a height and width it's easy for the developer to choose a bad resolution. Instead we can have the resolution as a bit flag in the parameter and the risk of a bad resolution is gone. As soon as we start talking about bit flags, it's easy to see we don't need many actual bits to setup the video interface.

The bits we need are:

  • TV Format (NTSC, PAL, MPAL, FPAL) 2 bits
  • Interlaced 1 bit
  • Resolution 1 bit
  • Color Depth 1 bit

We will setup our parameter as follows [31..0] [msb .. lsb]

  • [31..25] Reserved
  • [24] Color Depth
  • [17..23] Reserved
  • [16] Resolution
  • [15..9] Reserved
  • [8] Interlacing
  • [7..2] Reserved
  • [1..0] TV Format

Planning the structure of this parameter constant will save us some parsing effort later so this is all worth it. Reserved bits will help in the readability of these constants.

The next thing to consider is how are we going to call it. If we write out the code to do this it becomes clearer what the code inside has to do.

li a0, ntsc_32bit_Inter_High 
jal video_init 
nop

Using a well named constant can make things clearer, compared to commented code. Also note it's easy to think that the 'li' instruction could be inserted into the delay slot, unfortunately the 'li' instruction is actually a psuedo instruction which becomes 2 instructions after assembly. An 'optimized' version could be created to split the parameter into an upper and lower 16 bits, and split the instructions for example:

lui a0, r0, ntsc_32bit
jal video_init
andi a0, a0, Inter_High

While it's easy to say this is one instruction faster, I would argue against it for the following reasons:

  • Loss of readability
  • Risk of a programmer not including both assignment values
  • A programmer could easily use the available delay slot for unrelated things.
  • This is one time initialization code, 1 instruction doesn't save much