sylefeb / Silice

Silice is an easy-to-learn, powerful hardware description language, that simplifies designing hardware algorithms with parallelism and pipelines.
Other
1.28k stars 77 forks source link

Changes made to hdmi.ice #116

Open rob-ng15 opened 3 years ago

rob-ng15 commented 3 years ago

Hi Sylvain,

I made a long time ago a change to the vga driver to give a "better" pixel number when not actually on screen. I made a similar to change to for hdmi, which gives a slightly better aligned picture for j1eforth and PAWS, not perfect, just better.

` // SL 2020-09-05 // Silice HDMI driver // // 640x480, 250MHz TMDS from 25MHz pixel clock // // Currently limited to the ULX3S, but should be relatively easy to port, // pending pll and differential serial output primitives // // See also // - https://www.digikey.com/eewiki/pages/viewpage.action?pageId=36569119 // - https://www.fpga4fun.com/HDMI.html // - https://github.com/lawrie/ulx3s_examples/blob/master/hdmi/tmds_encoder.v // // GNU AFFERO GENERAL PUBLIC LICENSE // Version 3, 19 November 2007 // // A copy of the license full text is included in // the distribution, please refer to it for details.

import('hdmi_clock.v') import('differential_pair.v') import('hdmi_differential_pairs.v')

// ----------------------------------------------------

algorithm tmds_encoder( input uint8 data, input uint2 ctrl, input uint1 data_or_ctrl, output uint10 tmds ) {

uint9 q_m = 0; int5 dc_bias = 0;

// tracks 'number on ones' in input uint4 num_ones := data[0,1] + data[1,1] + data[2,1] + data[3,1]

}

// ----------------------------------------------------

algorithm hdmi_ddr_shifter( input uint10 data_r, input uint10 data_g, input uint10 data_b, output uint8 p_outbits, output uint8 n_outbits, ) { uint3 mod5 = 0; uint10 shift_r = 0; uint10 shift_g = 0; uint10 shift_b = 0; uint2 clkbits = 0; always { shift_r = (mod5 == 0) ? data_r : shift_r[2,8]; shift_g = (mod5 == 0) ? data_g : shift_g[2,8]; shift_b = (mod5 == 0) ? data_b : shift_b[2,8]; clkbits = (mod5[0,2] < 2) ? 2b11 : ( (mod5 > 2) ? 2b00 : 2b01 ); p_outbits = { clkbits , shift_b[0,2] , shift_g[0,2] , shift_r[0,2] }; n_outbits = {~clkbits ,~shift_b[0,2] ,~shift_g[0,2] ,~shift_r[0,2] }; mod5 = (mod5 == 4) ? 0 : (mod5 + 1); } }

// ----------------------------------------------------

// Expects to run at 25 MHz (hdmi pixel clock) algorithm hdmi( output uint10 x, output uint10 y, output uint1 active, output uint1 vblank, output! uint4 gpdi_dp, output! uint4 gpdi_dn, input uint8 red, input uint8 green, input uint8 blue, ) {

uint10 cntx = 0; uint10 cnty = 0;

uint1 hsync = 0; uint1 vsync = 0;

// pll for tmds uint1 half_hdmi_clk = uninitialized; hdmi_clock pll( clk <: clock, // 25 MHz half_hdmi_clk :> half_hdmi_clk, // 125 MHz (half 250MHz HDMI, double data rate output) );

uint2 null_ctrl = 0; uint2 sync_ctrl = 0; uint10 tmds_red = 0; uint10 tmds_green = 0; uint10 tmds_blue = 0;

uint8 latch_red = 0; uint8 latch_green = 0; uint8 latch_blue = 0; uint2 prev_sync_ctrl = 0; uint1 prev_active = 0;

// encoders // => we use <:: to bind values from cycle start (ignoring changes during current cycle) tmds_encoder tmdsR( data <:: latch_red, ctrl <:: null_ctrl, data_or_ctrl<:: prev_active, tmds :> tmds_red ); tmds_encoder tmdsG( data <:: latch_green, ctrl <:: null_ctrl, data_or_ctrl<:: prev_active, tmds :> tmds_green ); tmds_encoder tmdsB( data <:: latch_blue, ctrl <:: prev_sync_ctrl, data_or_ctrl<:: prev_active, tmds :> tmds_blue );

// shifter uint8 crgb_pos = 0; uint8 crgb_neg = 0; hdmi_ddr_shifter shift<@half_hdmi_clk>( data_r <: tmds_red, data_g <: tmds_green, data_b <: tmds_blue, p_outbits :> crgb_pos, n_outbits :> crgb_neg, );

hdmi_differential_pairs hdmi_out( clock <: half_hdmi_clk, pos <: crgb_pos, neg <: crgb_neg, out_pos :> gpdi_dp, out_neg :> gpdi_dn );

always {

// record previous state of sync_ctrl and active,
// we receive the r,b,g value for the x,y set below with a one cycle latency
// these are then latched for the following cycle
// thus we have to delay corresponding sync and active two cycles
prev_sync_ctrl = sync_ctrl;
prev_active    = active;

// synchronization bits
hsync          = (cntx > 655) && (cntx < 752);
vsync          = (cnty > 489) && (cnty < 492);
sync_ctrl      = {vsync,hsync};
// output active area
active         = (cntx < 640) && (cnty < 480);
// output vblank
vblank         = (cnty >= 480);
// output x,y
x              = (cntx < 640) ? cntx : 0;
y              = (cnty >= 480) ? 0 : cnty;
// => we will get color result on next cycle

// update coordinates
cnty        = (cntx == 799) ? (cnty == 524 ? 0 : (cnty + 1)) : cnty;
cntx        = (cntx == 799) ? 0 : (cntx + 1);

// latch r,b,g received at this cycle, for previous coord
// will be fed into HDMI encoders next cycle
latch_red   = red;
latch_green = green;
latch_blue  = blue;

} }

// ----------------------------------------------------

`

These being the changed lines:

// output x,y x = (cntx < 640) ? cntx : 0; y = (cnty >= 480) ? 0 : cnty;

Rob.

sylefeb commented 3 years ago

Hi Rob - thanks - I have conflicted requirements on that (due to another use case), and was planning to make it an option. Maybe something like $$zero_coordinates_on_blank = true?

rob-ng15 commented 3 years ago

Hi there,

Yeah that could work. It isn't perfect, maybe your solution may be better? It stops a few glitches I was having, as I was with the VGA code.

Rob.

On Thu, 25 Feb 2021 at 08:59, sylefeb notifications@github.com wrote:

Hi Rob - thanks - I have conflicted requirements on that (due to another use case), and was planning to make it an option. Maybe something like $$zero_coordinates_on_blank = true?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/sylefeb/Silice/issues/116#issuecomment-785733556, or unsubscribe https://github.com/notifications/unsubscribe-auth/AN4SYT2RRXDC6OZDEPZV4ODTAYGOLANCNFSM4YF63Q3A .