Let's make a start with describing the design. Before I forget how everything is supposed to work. It's rather complicated.
The schematic (at it's current state) can be found in the file section of this project. Note that most IC's are HC in the diagram but many will be AC speed types in the end.
When the Kobold K2 computer project started, it was intended that the cpu and video would share RAM, and that the CPU would only run during blanking time (to avoid nasty visual effects when the processor accesses RAM).
On second thought, and also following advice in the comments, the design is now such that the processor can (almost) always run at full speed, at the cost of some extra RAM and extra buffers.
[ place block diagrams and comments TODO ]
CONNECTOR
Connection to the Kobold K2 host computer is found at the top left side in the diagram. It's a 96 pin DIN 41612 connector. It's main signals are:
- 16 bit address bus
- 16 bit data bus
- 5 Volt power and ground
- RAM2_CE/ selects this card
- MEM_WE/ writes a word to this card, if selected
- RGB signals and two sync signals output to connector on main board
- Several clock signals: 25, 12.5 and 6.25 MHz provided by main board
- Indication of processor Exec/ cycle
FRAME MEMORY
To the processor, the card looks like a 32K-word block of RAM, that can only be written. It will of course only write to this video frame memory when the processor does an EXEC cycle. It writes the data through the Data buffer (U6, U7) and the address is provided through the Address buffer (U8, U9). The frame memory is written when both MEM_WE/ and RAM2_CE/ are active. When EXEC is not active, it is a FETCH cycle where the processor fetches its next instruction. During this FETCH cycle, the address buffer and data buffer will be disabled, and the address will be provided by the frame counter (U10, U11). Output of the frame memory will be enabled and a "frame word" will become available every time when the processor fetches an instruction.
In the frame memory, only 1/4 of the available space (the upper part) is used for the frame buffer. The other 3/4 is available as general CPU RAM area. But is is not possible to execute code from this area.
The frame counter counts at a 6.25 MHz rate, that is a new frame word every 320 nS. The counter has 16 bits, so the maximum length of a frame is 65536 x 0.32 uS = 20.9 mS.
B/W TEXT MODE
The black&white text output has pixels of 40nS duration. The lower 8 bits of the frame are the 8 horizontal pixels of a character. The upper 8 bits tell this is a B&W frame word.
There are special frame words for:
- 8 pixels data. Data will be put in shift register U15 and shifted out at 25 MHz rate.
- horizontal sync on/off
- vertical sync on/off
- frame counter reset on
- NOP
Note that the very first instruction at address 0 in the frame memory must be an instruction to switch the frame reset signal OFF again.
Also note that the line and frame frequency, and the polarity of the sync signals are defined by software, that has to place the special frame words at the correct position in the frame memory.
There are several control flags (in U14) that can be switched ON or OFF by special frame words. The sync signals and the reset signal are some of them.
SOUND SYSTEM
A special value in the upper byte of the frame word sends the lower 8 bits to the sound register, U32. That register has a D-A converter (built from resistors) at its output. By placing such a frame word at the end of every VGA-line, or every other VGA-line, it should be possible to generate sound.
MAIN GRAPHIC SYSTEM
The main graphic system is also called BG (Background), because on the FG (Foreground) there can be sprites.
Background and foreground have their own memory (both are 256K x 16). The 16 bits in BG main memory are coded as:
URRR RRGG GGGB BBBB
- U is unused
- RRRRR is a 5-bit Red value
- GGGGG is a 5-bit Green value
- BBBBB is a 5-bit Blue value
Let's first assume that FG and BG memories already have valid contents, and afterwards describe how these memories are written.
To display the contents, the control flag VDU_WE/ must be inactive (high), and the flags VDU_BG_CE/ and VDU_FG_CE/ must be active (low).
A special frame word (at the beginning of each line or group of lines) generates the VDU_BG_POS/ signal. The lower 12 bits of this frame word define, together with 6 upper bits (that must be preset in advance into U16, by means of the VDU_SETPAGE/ frame word), the 18 bit position in the main memory from where pixels shall be fetched. The 12 bits are placed in a counter (U17, U18, U19), that are counting at 25MHz to address the consecutive pixels. The 6 upper bits (U20) are not a part of this counter.
The counter gets its clock signal from VDU_CLK1/ , that is generated by NAND gate U4B and AND-gate U5, so that provides 25MHz because VDU_WE/ is high.
The main memory will provide its RGB values to the final registers U28 and U29, clocked with the same signal, and the RGB values are then D-A converted by resistors, and will continue their way to the VGA monitor as analogue signals.
Note that because of the indirection, scrolling can be very fast.
SPRITE SYSTEM
The 16 bits in FG (sprite) memory are coded as:
TRRR RRGG GGGB BBBB
- T defines if a pixel is transparent
- RRRRR is a 5-bit Red value
- GGGGG is a 5-bit Green value
- BBBBB is a 5-bit Blue value
To display a special frame word generates the VDU_FG_POS/ signal. This can be at any position in a line, where the sprite should start. The system is a lot like that for the main memory. Here, the 12 bit counter is U21, U22 and U23, and the 6 bit upper part is U24.
But now there is the question: Display the sprite (foreground pixel) or the main image (background) ?
To enable main image, we must activate OE/ of its memory, with the BG_OE/ signal.
To enable the sprite, we can not simply use the OE/ control of the memory, because the upper bit must stay available when the sprite output is disabled (to access the transparency bit T). Therefore, the upper byte, that contains the transparency bit T, gets an extra buffer U27 with its own OE/ (called G/), the lower byte stays connected but we use the LB/ control instead of OE/. So for a sprite, we must activate the lower byte to be an output (FG_LB/ signal) and we must enable U27.
Both signals FG_LB/ and BG_OE/ are generated by the multiplexer U31 at the lower right of the schematic. We are still in read mode (VDU_RE/ is active, it's the opposite of VDU_WE/ ) so the outputs of U31 are enabled. We see that the inputs of U31 are switched between alternatives by the A/B input, that is connected to the mentioned T (Transparency) bit.
We now can have several situations:
- The transparency bit is HIGH. In this case the main image (background) must be selected. The multiplexer connects to the A inputs, so FG_LB/ will be VCC, inactive (high) and BG_OE/ will be GND, active (low). This shows main image.
- The transparency bit is LOW and a sprite is displayed. (Output of U30B is low, and output of U30C is high when a sprite is displayed, explained later). The multiplexer connects FG_LB/ to U30C (low), so that is active, and connects BG_OE/ to U30B (high), so that is inactive. This shows the sprite.
- The transparency bit is LOW and there is no sprite. (Output of U30B is high, and output of U30C is low when there is no sprite, explained later). The multiplexer connects FG_LB/ to U30C (high), so that is inactive, and connects BG_OE/ to U30B (low), so that is active. This shows main image. Is there a problem because we use the transparency bit of an undefined sprite ? No, because if the T bit were HIGH, we would get exactly the same logic values for FG_LB/ and BG_OE/.
Now one thing remains for the display action, and that is to determine if there is a valid sprite.
The mentioned gate U30B is part of a simple set/reset flipflop. As soon as the VDU_FG_POS/ is active to start a sprite, that sets the flipflop to the "valid sprite" state. Now when does the sprite end ? That is determined by the sprite data itself. At the end of the sprite, there should be a transparent pixel with bit 14 set high. This will get a logic low at the output of gate U30D (signal U_END/). It then travels through flipflop U29 to remove any spikes, and this is the END/ signal that, at a logic low, signals to the flipflop that the end of the sprite has been reached. So the display will continue with displaying background. Multiple sprites can be put on the same line.
It will be clear that to display a multi-line sprite, the frame memory must contain starting code for every line of the sprite.
WRITING TO FOREGROUND OR BACKGROUND MEMORY
Now here we come to one of the most complex parts of the design.
The BG memory must be available continuously during visible content, and the FG must be available whenever there are valid sprites. So to safely write one of these memories, all writing must be done during blanking time. But we can not do this very fast, because the processor has to get the data from somewhere, increment source and destination counters, and perhaps check for an end condition. It would be nice if there was a FIFO buffer, that is continuously, but slowly, filled by the processor, and that outputs its contents fast during blanking time.
And yes that is exactly what we are going to do here. But you will not find a FIFO in the design. The FIFO is part of the frame memory. All blanking time in the frame memory is available (except the hsync and sound signals that must be kept going).
So, the CPU writes a sequence of frame words in this available space. When the frame blanking has come, these frame words will be interpreted as "commands". Each command has 320 nS to execute.
1. Make the control flag VDU_WE/ active (low) since we are going to write. This will make VDU_RE/ active (inverter U4D). It disables the outputs of multiplexer U31. The pullup- and pulldown on its outputs will disable the data outputs of the FG and BG memory. VDU_WE/ will also activate the pixel-write-buffer (U25 and U26).
2. Make only one of the control flags VDU_FG_CE/ or VDU_BG_CE/ active (low) to enable either the FG or BG memory for writing and disable the other one.
3. In the same way as you do when reading, use the frame word that generates the VDU_BG_POS/ or VDU_FG_POS/ signal to set a starting address for the BG or FG memory. Nothing will happen yet, because the 25MHz clock signal has been blocked by gate U4B. So the selected counter will not run.
4. The next frame word is coded as 0RRRRRGGGGGBBBBB and activates the VDU_PIX_WR/ signal. It is the only command with bit15=0, all other commands have bit15=1. The RGB value goes through the pixel write buffer and through the U27 buffer, and is written into the selected FG or BG memory. Since the bit15 is always the same, it would always give the same value for the T (transparency) bit. Therefore, bit15 from the frame word is not used. Instead, the value of the VCOL_15 bit is written to T. So that must already be set to the correct value before this step 4 takes place.
The counter clock that has its 25 MHz signal blocked is now connected to the VDU_PIX_WR/ signal by gate U4C. So, after the pixel was written, the pointer into the memory is automatically advanced by one step. So next pixel values can immediately follow.
TODO
2. The main CPU needs a way to see where the frame is in its cycle.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.