• Dual video generation (VGA / TIM)

    zpekic05/03/2024 at 11:51 0 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:

    • Non-standard timing of HSYNC and VSYNC signals, which confuse lots of digital input monitors even if they could take the 16kHz video signal otherwise
    • No physically compatible connection with any known connector - just 5 pins poking out from the PCB

    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.
    VCLKHS
    f =  15.635kHz 
    /HS
    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. 
    1hhhhhhhVVVVVVVV

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

    • Introduce a 8-bit wide 2 to 1 MUX to select the signals above, and the selection is the MODE signal
    • Keep the existing horizontal and vertical pixel counters (U13 and U3) as the VRAM addressing does not depend on the MODE, but use them only for that, not any other signal generation. So U13 and U3 always cover only 512*256
    • Introduce 2 additional 74HC4040 counters (U13A and U3A) which cover either...
    Read more »

  • TIM-011 video on Sony CPD-1302

    zpekic05/10/2021 at 01:40 0 comments

    I was hunting at the local PC-recycle for a monitor that could be connected directly to my vintage C-128  natively without the usual converter (Gonbess + other) and cable mess. I could not believe my luck when I found a Sony CPD-1302 with Trinitron tube (good old particle accelerator!) 

    This monitor appeared in the ideal moment when the classic home computers from the 80ies were still around, but the PC revolution started - VGA was expensive and tied first to PS/2, most PC users had MDA, CGA or EGA (all digital) - or maybe PGA which was always a rarity given how high-end expensive it was (analog to be able to produce 256 colors). This monitor supports all of them:

    • Analog mode (R, G, B, VSync, HVSync)
    • Digital mode (3 different variations, from 4 monochrome "intensities" to 16 colors I, R, G, B, plus VSync and HVSync)

    Looking at the CPD-1302 timing charts, it looked that the timing would match:

    • Horizontal: 63.78us for CGA vs. 64us for TIM-011 video signal
    • Vertical: 50Hz for CGA (16.65us) vs. 55Hz (18.424us) for TIM-011.

    Most importantly (where many vintage computer / monitor pairings fail), the CPD-1302 has a "smart" detection of VSync, extracting it from composite HVSync, or it can be fed directly.

    Connection was simple:

    TIM-011CPD-1302Color (on CPD side reference pics below)
    GNDGNDblack
    VSYNCHVSYNCorange
    HSYNCHSYNCyellow
    V0one out of R, G, B, Ired, green, blue, intensity is white
    V1one out of R, G, B, Ired, green, blue, intensity is white

    Here are some experiments:

    Analog mode

    Connecting "I" for a color as expected rendered only 2 color image as the "intensity" digital signal is ignored. But the other color signal (green in this case) is recognized as "analog".

    Digital

    With the same I + G switching to "digital" mode, suddenly 4 "colors" appear, as expected. However one would expect black, and 3 shades of green but monitor shows the darkest green as brownish/grayish?

    Now replacing the I+G with B+G:

    As expected, this allows black, blue, green and cyan:

    Summary

    In all probability, CPD-1302 would work well with a "real" TIM-011, as it works in all modes (even analog!) with the FPGA implementation of its video circuit. 

    There was a problem with vertical sync - as seen above the frequencies are somewhat different. This caused flicker, until the image was adjusted towards top of screen. This made the picture stationary but lost few top line of the screen. Not a too big problem in text modes (as the action happens near the bottom of screen) but annoying for graphics or games.

  • Notes about video quality and sampling approaches

    zpekic01/07/2021 at 22:00 0 comments

    While overall the sampling of TIM-011 video signal works, and is visibly displayed on the screen, it still has problems:

    • first column pixel is displayed (black instead) because there is no real pixel pipeline (and consequently, the last pixel column is not displayed
    • there are some random "ghost artifacts" (vertical bars)

    Perhaps not clearly visible, a picture from the VGA screen (generated by sampler + VGA controller):

    Now looking at screenshot from GONBES-8200, it has different problems:

    • top few lines dancing
    • distorted height / width ratio

    So in some ways, both are "worse" but the vertical bar artifacts are very annoying. I haven't tested if those would prevent reading of text on the TIM-011 display.

    First, I thought that the image would deteriorate going from left to right, due to the skew between video signal to be sampled and the sampling clock - after all they are synchronized only once per line using hsync signal, and by 512th video signal (or 2048th sampling clock) they could be slightly off. But that is not the case, the quality is evenly good (or bad).

    So the artifacts must come from the sampling approach itself. To "debug" it, I feed the sampler with 6 extra signals that control the sampling.

    From /sys_tim011_mercury.vhd

    tim: tim_sampler port map (
    		reset => RESET,
    		clk => freq48M, -- 48MHz (4 times oversample of 12MHz)
    		hsync => TIM_HSYNC,
    		vsync => TIM_VSYNC,
    		v2 =>	TIM_VIDEO2,
    		v1 => TIM_VIDEO1,
    		a => sampler_a,
    		d => vram_dina,
    		--limit => switch(7 downto 2),
    		-- best result with sampler "algorithm"
    		-- s2 from raising edge sample
    		-- s1 from raising edge sample
    		-- 4 out of 4 sample: on
    		-- 3 out of 4 sample: on
    		-- 2 out of 4 sample: off
    		-- 1 out of 4 sample: off
    		limit => "111100",
    		we_in => we_in,
    		we_out => sampler_wr_nrd
    	);

    The two MSB of the (not very well) named "limit" are consumed by the tim_sampler.vhd to select if for the  v1, v0 video signals should be captured at the rising or falling edge of the sampling clock (s2 and s1 are 16-bit shift registers, clocked at 4*12MHz  rate and ingesting the TIM-011 v1 and v0 video signals):

    generate_s: for i in 15 downto 1 generate
    begin
    	s2(i) <= s2r(i) when (limit(5) = '1') else s2f(i);
    	s1(i) <= s1r(i) when (limit(4) = '1') else s1f(1);
    end generate;
    s2(0) <= v2;
    s1(0) <= v1;

    Answer: raising is much better for picture quality.

    The 4 LSB are consumed in the "voter" circuit which gets 4 sample bits (per pixel) and has to decide if those 4 indicated "signal on" or off. It does that by looking at the sampled patterns:

    	with value select vote <=
    		limit(3) when "1111",	--4
    		limit(2) when "1110",	--3
    		limit(2) when "1101",	--3
    		limit(1) when "1100",	--2
    		limit(2) when "1011",	--3
    		limit(1) when "1010",	--2
    		limit(1) when "1001",	--2
    		limit(0) when "1000",	--1
    		limit(2) when "0111",	--3
    		limit(1) when "0110",	--2
    		limit(1) when "0101",	--2
    		limit(0) when "0100",	--1
    		limit(1) when "0011",	--2
    		limit(0) when "0010",	--1
    		limit(0) when "0001",	--1
    		'0' when others;	--0

    Obviously, if no bit was sampled "1" then the output must be "0" - this is the last, default line. But what if it was sampled one of more times "1"? In that case, the output is controlled by selecting on or off individually each combination with 1, 2, 3, or 4 bits sampled "1" (a simple 16->1 MUX).

    Through visual experimentation, turns out the best result is enable 4 and 3 bit "1" sample combinations, but not the 2 and 1 bit ones (1 results in unstable pic, 2 is effectively a no-op).

  • Converting TIM-011 video to VGA

    zpekic11/29/2020 at 06:14 0 comments

    Converting incompatible video standards especially in retrocomputing field is a well-known problem, for which a whole cottage industry has been created (e.g. GONBES and similar). 

    To recap:

    TIM-011VGA (basic mode)
    Color infoDigital, 4 level, 2 signalsAnalog, 3 signals, theoretically 2^24 colors with 3 8-bit DACs
    Pixel clock12MHz25.125MHz (25Mhz is used for design simplicity)
    Horizonal sync15.625kHz31.25kHz
    Vertical sync50Hz60Hz

    As can be seen from the above, any simple or "passive" connectivity between the two won't work. The apparent solution is to:

    1. Capture input signal (synchronized to TIM-011 timing)
    2. Store video data in memory (buffer)
    3. Generate output signal from memory (as VGA)


    Read more »

  • Initializing video memory for test purposes

    zpekic11/29/2020 at 04:01 0 comments

    In order to see if the generated video signal is good or not, one simple trick is to pre-populate video RAM with image as if CPU had generated it. 

    I used two images:

    TIM-011 signal generator on Anvyl - my lame MSPaint image:

    TIM-011 sampler on Mercury - model students busy learning Basic from original 1988 ad (I hope I am not breaking their copyright!)

    Of course, both of these converted to 512*256*4 colors look a bit less impressive...

    All FPGAs support initializing RAM/ROM which is part of the design. However, the file format varies. As I was using Xilinx ISE14.7, I needed .coe file to include into project.  

    Here are steps to generate the .coe:

    1. Convert image to .bin file using Img2Tim utility which will:

    • Ingest .png, .jpg, .bmp file and instantiate a memory image object from it
    • Resize (squish) to 512*256
    • Sample the colors using simple thresholds to get only 2 bits per pixel
    • Use the knowledge of TIM-011 video memory organization to generate 32kB .bin file

    (use Img2Tim.cmd)

    2. Once we have the .bin file, use file conversion mode of my microcode compiler to generate .coe from .bin

    (use mcc.cmd)

    3. Finally, use ISE native tooling to generate the RAM component and point it to .coe file

    There are other approaches too - for example, tooling could generate VHDL source code directly that initializes the memory and include that file into the project to be compiled, but such file would be very large and slow down compilation. mcc is able to generate VHDL from .bin file in case non-Xilinx approach is needed.

  • TIM-011 video signal generation ("grafika" component)

    zpekic11/29/2020 at 03:35 0 comments

    In order to convert video signal coming from TIM-011 to VGA, one has to first have it... As I don't have a TIM-011, I had to "simulate" one. Key component of this simulation is to re-create the custom graphics system of TIM-011 on FPGA.

    Luckily, I had the schematics from the magazine, so I could reverse-engineer it.

    First, a bit about TIM-011 graphics implementation:

    • Implemented using 74XX TTL and CDXXXX CMOS ICs - no VDP!
    • Resolution is 512 (H) * 256 (V)
    • Graphics mode only - text is "painted" by software similar to classic Macintosh computer approach of the same era
    • 4 "colors" - or shades of gray per pixel. This means 1 byte contains 4 pixels. Total memory needed for picture is then 512*256/4 = 32k
    • Video RAM is a single generic 32kB static RAM, it is mapped into I/O space of HD64180 CPU (which has 64k I/O space) from 0x8000 to 0xFFFF
    • In addition, simple scroll up/down is supported by varying the offset location of row 0 in video memory.

     As a result, following video signal is generated:

    • Dot clock is 12MHz
    • 1 scan line contains positive HSYC signal, 256 dot periods long (21us), after which 512 dot periods (43us) is the video signal (V2 and V1)
    • 1 scan line takes therefore 64us which gives the horizontal frequency of 15.625kHz
    • VSYC positive signal comes after every 256 scan lines, and is 2.04ms long (24480 dot clock periods)
    • VSYNC repeats at 50Hz, which is the vertical refresh rate (there is no interlacing)

    There are two interesting facts about TIM-011 video:

    • V2 and V1 are "anded" with dotclk - this means that their intensity is halved. Not sure why this was done, maybe it improves the image quality on old home computer monitors preventing the pixels to bleed to each other due to phosphorus luminance.
    • The pixels are "packed" in a byte in a strange way:
    Bit:76543210
    Pixel:1032
    Intensity:V2V1V2V1V2V1V2V1

    VDHL implemenation:

    To follow description below, refer to this source code file

    (to be updated)

  • Demo video

    zpekic11/29/2020 at 02:21 0 comments

    Really low-quality, terrible video, but hopefully illustrating what is working so far:

    Anvl-board generates video signal:

    • Converted to CSYNC (composite sync) + RGB digital, goes to GBS8200 board towards VGA
    • Raw (HSYNC+CSYNC+V2+V1) goes to Mercury board
    • Scroll up/down is supported like real TIM
    • Test signal mode has been added, it displays a 4 color box pattern

    Mercury board captures the video signal:

    • Incoming video signal is converted to memory bytes and stored in 32kB onboard RAM
    • VGA controller reads the same RAM, applies a 4-color palette and outputs as 640*480, 60Hz
    • Display outside TIM-011 512*256 window is filled with hard-coded ASCII characters (text display in the future)
    • TIM window can be moved on VGA screen (it is centered initially)

    Upcoming project logs will describe these in more details.