Dual video generation (VGA / TIM)

A project log for TIM-011: FPGA-based VGA and PS/2 keyboard adapter

Trying to connect vintage TIM-011 home computer with PS/2 keyboard and VGA using a FPGA developer board

zpekiczpekic 05/03/2024 at 11:510 Comments

Problem statement

An international group of retro-computing enthusiasts came together to recreate the original TIM-011 hardware (details here), at which point the TIM-011 original video circuit became a focus of interest too. There are two main problems with TIM-011 video:

In original TIM-011, none of the above was a problem, because a special "paired" monitor was used. 

Looking at the details of TIM-011 video circuits, it dawned on me that with some extra logic on the PCB, standard 640*480 VGA signal could be generated - in addition to the TIM-011 video, but not at the same time. This project log is a description how it could be done - not only for TIM-011, but maybe for "home brew" computers, as the video circuitry is extremely "vanilla" and requires only basic 74xx ICs and few passive components.

Video signal summary

Regardless of the video format, a same set of signals is needed, but their frequency and timing must be different. Table below summarizes the signals and their values. Uxx refers to "virtual IC" in the FPGA implementation in VHDL

Signal name (or key value)     TIM-011    VGA  Notes
MODE01External signal (generated by software, or hardware switch or jumper) to select which video signals should be generated
PIXCLK (HCLK)12MHz24 or 25MHzIt is also the "horizontal" pixel dot frequency. 50% duty cycle 
HRESET768800Single pulse 1 PIXCLK long is generated at this count, determining the length of horizontal scan line.
Resets U13A (horizontal scan counter)
HS576 ... 639
active high
0 ... 95
active low
Horizontal sync signal timing is critical for CRTs to recognize and adjust to video signal. @msolajic provided updated TIM-011 values, while VGA ones are well known standard values
HBLANK512 ... 7680 ... 255 and 768 ... 800Horizontal blanking signal (active high) keeps the horizontal pixel counter (U13A) at 0, while at the same time "masking" the V1 and V2 digital video outputs.
f =  15.635kHz 
f = 31.25kHz
Because vertical scan and pixel counters are implemented using 74HC4040 which are clocked on falling edge, in case of active low HS for VGA, it has to be inverted. Scan frequency is PIXCLK / HRESET
VRESET320525Single pulse 1 VCLK long is generated at this count, determining the length of the (non-interlaced) frame.
Resets U3A (vertical scan counter)
VS280 ... 319
f = 49Hz
0 ... 3
f = 60Hz
Vertical sync signal - during this time CPU can read/write VRAM or update the scroll offset register.  Frame frequency is VCLK / VRESET
VBLANK256 ... 3200 ... 127 and 384 ... 525Vertical blanking signal (active high) keeps the vertical scan line counter (U3A) at 0, while at the same time "masking" the V1 and V2 digital video outputs.
Keeps U3 (vertical pixel counter) at 0.
Horizontal pixel range0 ... 5110 ... 511bits 1 and 0 select 1 out of 4 pixels in the byte, giving 128 bytes (7 bits) in the VRAM address schema:
1HHHHHHHvvvvvvvv (MSB is 1 because 32k VRAM I/O space is visible to CPU from 0x8000-0xFFFF
Vertical pixel range0 ... 2550 ... 255Vertical pixel counter is mapped to lowest 8-bits of the address. This allows easy hardware vertical scroll by adding to this value an 8-bit offset. 

Analyzing the signal comparison table above, one possible hardware solution becomes apparent:

Dual-mode video high-level schematic. Bold border ICs are additions to original TIM video (rest of circuit is unchanged)

TIM-011 mode

As I didn't have legacy CRT at hand (for example Sony CPD-1302) I used the Gonbes GBS-8200 to convert 4 signals to VGA (code from top-level VHDL component):

-- Connect to GBS8200 gray wire (composite sync!)
    gr_csync <= gr_hsync xor (not gr_vsync);
    GBS8200_GRAY <= gr_csync when (sw_mode = '0') else '0'; --gr_hsync xor (not gr_vsync);
-- connect to GBS8200 blue / green / red wires
-- colors: black, blue, green, white
    GBS8200_BLUE <= gr_vid1 when (sw_mode = '0') else '0';
    GBS8200_GREEN <= gr_vid2 when (sw_mode = '0') else '0';
    GBS8200_RED <= (gr_vid1 and gr_vid2) when (sw_mode = '0') else '0';

 Some notes:

TIM mode HS(ync) and HBLANK (HSync is positive, duration is 64 dot clocks @12MHz = 5.64us; HBLANK is simultaneously reset signal for horizontal counter U13A)

TIM mode VS(ync) and VBLANK (VSync is positive, VBLANK is simultaneously reset signal for vertical counter U3A )

VGA mode

VGA signal is generated directly from FPGA. Note the 2:1 aspect ratio (as TIM-011 resolution is 512*256 pixels) centered into 640*480 VGA pixel window (margins are "blanked" using the HBLANK and VBLANK signals explained in the table above).

From top-level VHDL component:

-- VGA connections
-- colors: black (000), dark gray (333), light gray (CCC), white (FFF)
    gr_color <= gr_vid2 & gr_vid2 & gr_vid1 & gr_vid1;
    HSYNC_O <= sw_mode and gr_hsync;
    VSYNC_O <= sw_mode and gr_vsync;
    RED_O <= gr_color when (sw_mode = '1') else X"0";
    GREEN_O <= gr_color when (sw_mode = '1') else X"0";
    BLUE_O <= gr_color when (sw_mode = '1') else X"0";


VGA mode HS(ysnc) and HBLANK (HSync is negative polarity, horizontal counter U13A can only count 0..511 when HBLANK is low)

VGA mode VS(ync) and VBLANK (VSync is negative polarity. Vertical counter U3A can count from 0 .. 255 only when VBLANK is low)