|
|||||||||
|
|||||||||
STEP 1 Next colour setup (scan lines 22 and 24 only) The first step presets the 60-byte portion of the line buffer with the color data. It picks the bytes from the odd locations of the video memory (high bytes of regular words), which are reserved for argument storage, and writes them to the special 60-byte line buffer. As there is not enough time to process all 60 bytes in a single scan line slice, which is reserved for that job (notified by green areas on the text row drawing), the task is divided in two parts. The first one, contained in the subroutine LINE4, presets the first 30 locations of the line buffer, and LINE5 presets the rest of the line buffer. In the addition, there are two 60-byte line buffers for temporary argument storage - one is at LINE_BUFFER+60 (we shall name it Line Buffer 2 here), and the another one is at LINE_BUFFER+120 (Line Buffer 3). The reason is that the whole line buffer has to be ready when the text row begins, and the program has to preset the next row while the first one is read; so, the two line buffers are written/read alternatively, and the bit FLAG,#14 decides which one shall be read, and which one written. The routine toggles that bit after each frame generation. This routine does not only move data from the attribute (odd) bytes of the video memory to the line buffer, but also processes blinking for both ink (foreground) and paper (background). RGB ink (foreground) bits (012) are copied to the line buffer, but they are reset to 0,0,0 IF the blink bit (3) is set AND IF blinking counter output (FLAG,#11) is set. That is why blink bits (3 and 7) from the video memory are represented as 0 in the line buffers - they are already "embedded" in RGB bits and they are not needed any more. In the same step, the equal operation is done with the upper nibble of the byte, with RGB paper (background) bits 456. The whole operation is significantly speeded up by using the lookup table BLINKTAB, which contains the outputs for all possible inputs in this logical operation. Note that Line Buffer 1 is built at the beginning of the each odd scan line (12 times during one text row generation, each time with the new scan line for character generator reading), but Line Buffers 2 and 3 only once for one text row, as they will remain the same for all scan lines. Actually, not both buffers but only one of them - the one which is not used for video signal generation at that moment. The first step is realized at the end of each text row generation, but its results will be used in the next text row. It is represented by the green areas on the next drawing.
|
|||||||||
STEP 2 Character setup (all odd scan lines) This step reads B&W character from video memory, translates it through the character generator (only for the required row, placed in WREG1H) and puts the output from the character generator in Line Buffer 1 (LINE_BUF...LINE_BUF+59). Only two instructions are needed for each byte:
w3 = video memory read pointer There is no time for looping, so the whole sequence of 60 bytes is realized in a string of 120 instructions. There is one more problem which could slow down the operation - RAW, Read After Write dependency. This problem is solved by using two sets of registers alternatively, to make some kind of pipeline. The final routine looks like:
...and so on, until the byte 60 is translated and written into the line buffer. All this is done at the beginning of subroutine LINE1 (yellow areas on the drawing), before the actual video signal output starts. It should be noted that this step has to be done only at the beginning of odd lines, as the same line buffer contents will be used in the next scan line (note that one pixel is represented by 2x2 screen pixels).
|
|||||||||
STEP 3 Cursor setup (even scan lines 6...20) This step writes the graphic line for two cursors in both line buffers, one for colour (Line Buffer 2 or Line Buffer 3, prepared in STEP 1) and the another one for data (Line Buffer 1, which was prepared in STEP 2). Subroutine LINE2 does this, but as the program calls it only at the beginning of even lines, when one character graphics (odd) scan line was already displayed without the cursor, it will be visible only in even lines. This makes the cursors pseudo-transparent, as the block does not cover all lines of the character. This is represented by pink areas on the previous drawing.
|
|||||||||
STEP 4 Video output generation (all scan lines) This is the most important and critical step, and it is represented by cyan areas on the previous drawing.. Each dot data (RGB ink or RGB paper) is created in two instruction cycles. Those "magic" instructions are:
where: w1 =
0b00100000 for the leftmost pixel in the
character Only the rightmost pixel (bit 0 in the character set) is represented as three screen pixels (1.5 character pixels), as it is displayed during the execution of three instructions. The 3rd "extra" instruction in the routine reads the colour byte from the "argument portion" of the line buffer (Line Buffer 2 or Line Buffer 3). That makes the rightmost 50% pixel wider than the other ones, but it does not affect the character shape, as this pixel is used only by the pseudographics frame characters, and all the ASCII characters use this pixel only for horizontal spacing. So, the character spacing is actually 150% of one character pixel. There is the same problem with the execution speed, like in the STEP 2. As the program has to be highly optimized for speed, there is no time for looping, so the whole routine must be located in one string, about 800 instructions long. Also, the same problem with RAW is present, so there are two sets of registers used alternatively here. Literals 0b0010000 to 0b00000001, which are represented in w1 in our example, are actually loaded at six registers, w9...w13. This seems like the very "bad economy" in microcontroller resources using, but it was the only way to maintain the required speed, as there was no time to load or shift their contents in the real time. Anyhow, there are no consequences "visible" from the user's program, as all those registers are saved on the stack at the beginning of the interrupt routine. In order to correct the uneven delays caused by interrupt latency, the routine aligns its flow with TMR2 contents at the beginning of each scan line (#hor_align is the literal which defines the horizontal position of text):
After this sequence, the program flow is synchronized with TMR2. As the OCx (which is driven by TMR2) generates the horizontal sync, the video signal is now synchronized with the program flow and the video signal is jitter-free.
|
|||||||||
|