Skip to content

Commit

Permalink
Xilinx support on master branch (#20)
Browse files Browse the repository at this point in the history
xilinx oserdese2 + 4k30fps
  • Loading branch information
sameer authored Feb 28, 2021
1 parent 6502305 commit 1cbde77
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 83 deletions.
37 changes: 18 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ Most free and open source HDMI source (computer/gaming console) implementations
### Platform Support

- [x] Altera (tested on [MKR Vidor 4000](https://store.arduino.cc/usa/mkr-vidor-4000))
- [x] Xilinx
- Confirmed for [v1.1](https://github.com/hdl-util/hdmi/releases/tag/v1.1) by community
- Master will be tested soon using [Spartan Edge Accelerator Board](https://www.seeedstudio.com/Spartan-Edge-Accelerator-Board-p-4261.html)
- [x] Xilinx (tested on [Spartan Edge Accelerator Board](https://www.seeedstudio.com/Spartan-Edge-Accelerator-Board-p-4261.html))
- [ ] Lattice (unknown)

### To-do List (upon request)
Expand Down Expand Up @@ -61,23 +59,24 @@ Most free and open source HDMI source (computer/gaming console) implementations

You'll need to set up a PLL for producing the two HDMI clocks. The pixel clock for each supported format is shown below:

|Video Resolution|Video ID Code(s)|Refresh Rate|Pixel Clock Frequency|
|Video Resolution|Video ID Code(s)|Refresh Rate|Pixel Clock Frequency|[Progressive](https://en.wikipedia.org/wiki/Progressive_scan)/[Interlaced](https://en.wikipedia.org/wiki/Interlaced_video)|
|---|---|---|---|
|640x480|1|60Hz|25.2MHz|
|640x480|1|59.94Hz|25.175MHz|
|720x480|2, 3|60Hz|27.027MHz|
|720x480|2, 3|59.94Hz|27MHz|
|1280x720|4|60Hz|74.25MHz|
|1280x720|4|59.94Hz|74.176MHz|
|1920x1080|16|60Hz|148.5MHz|
|1920x1080|16|59.94Hz|148.352MHz|
|1920x1080|34|30Hz|74.25MHz|
|1920x1080|34|29.97Hz|74.176MHz|
|720x576|17, 18|50Hz|27MHz|
|1280x720|19|50Hz|74.25MHz|
|3840x2160|97, 107|60Hz|594MHz|

The second clock is a clock 5 times as fast as the pixel clock. Even if your FPGA only has a single PLL, the Altera MegaWizard (or the Xilinx equivalent) should still be able to produce both.
|640x480|1|60Hz|25.2MHz|P|
|640x480|1|59.94Hz|25.175MHz|P|
|720x480|2, 3|60Hz|27.027MHz|P|
|720x480|2, 3|59.94Hz|27MHz|P|
|720x576|17, 18|50Hz|27MHz|P|
|1280x720|4|60Hz|74.25MHz|P|
|1280x720|4|59.94Hz|74.176MHz|P|
|1280x720|19|50Hz|74.25MHz|P|
|1920x1080|16|60Hz|148.5MHz|P|
|1920x1080|16|59.94Hz|148.352MHz|P|
|1920x1080|34|30Hz|74.25MHz|P|
|1920x1080|34|29.97Hz|74.176MHz|P|
|3840x2160 (not ready)|97, 107|60Hz|594MHz|P|
|3840x2160|95, 105|30Hz|297MHz|P|

The second clock is a clock 5 times as fast as the pixel clock. Even if your FPGA only has a single PLL, the Altera MegaWizard (or the Xilinx equivalent) should still be able to produce both. See [hdl-util/hdmi-demo](https://github.com/hdl-util/hdmi-demo/) for example PLLs.

### L-PCM Audio Bitrate / Sampling Frequency

Expand Down
4 changes: 2 additions & 2 deletions src/hdmi.sv
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ generate
assign hsync = cx >= 440 && cx < 440 + 40;
assign vsync = cy >= 5 && cy < 5 + 5;
end
97, 107:
95, 105, 97, 107:
begin
assign frame_width = 4400;
assign frame_height = 2250;
Expand All @@ -147,7 +147,7 @@ localparam real VIDEO_RATE = (VIDEO_ID_CODE == 1 ? 25.2E6
: VIDEO_ID_CODE == 17 || VIDEO_ID_CODE == 18 ? 27E6
: VIDEO_ID_CODE == 19 ? 74.25E6
: VIDEO_ID_CODE == 34 ? 74.25E6
: VIDEO_ID_CODE == 97 || VIDEO_ID_CODE == 107 ? 594E6
: VIDEO_ID_CODE == 95 || VIDEO_ID_CODE == 105 || VIDEO_ID_CODE == 97 || VIDEO_ID_CODE == 107 ? 594E6
: 0) * (VIDEO_REFRESH_RATE == 59.94 || VIDEO_REFRESH_RATE == 29.97 ? 1000.0/1001.0 : 1); // https://groups.google.com/forum/#!topic/sci.engr.advanced-tv/DQcGk5R_zsM

// Wrap-around pixel position counters indicating the pixel to be generated by the user in THIS clock and sent out in the NEXT clock.
Expand Down
140 changes: 78 additions & 62 deletions src/serializer.sv
Original file line number Diff line number Diff line change
Expand Up @@ -14,74 +14,90 @@ module serializer
`ifndef VERILATOR
`ifdef SYNTHESIS
`ifndef ALTERA_RESERVED_QIS
// Based on VHDL implementation by Furkan Cayci, 2010
// https://www.xilinx.com/support/documentation/user_guides/ug471_7Series_SelectIO.pdf
logic tmds_plus_clock [NUM_CHANNELS:0];
assign tmds_plus_clock = '{tmds_clock, tmds[2], tmds[1], tmds[0]};
logic [9:0] tmds_internal_plus_clock [NUM_CHANNELS:0];
assign tmds_internal_plus_clock =tmds_internal_plus_clock '{10'b0000011111, tmds_internal[2], tmds_internal[1], tmds_internal[0]};
assign tmds_internal_plus_clock = '{10'b0000011111, tmds_internal[2], tmds_internal[1], tmds_internal[0]};
logic [1:0] cascade [NUM_CHANNELS:0];
genvar i;
generate
for (i = 0; i <= NUM_CHANNELS; i++)
begin: xilinx_serialize
OSERDES2 #(.DATA_RATE_OQ("DDR"), .DATA_RATE_TQ("SDR"), .DATA_WIDTH(10), .SERDES_MODE("MASTER"), .TRISTATE_WIDTH(1))
primary (
.OQ(i == NUM_CHANNELS ? tmds_clock : tmds[i]),
.OFB(),
.TQ(),
.TFB(),
.SHIFTOUT1(),
.SHIFTOUT2(),
.TBYTEOUT(),
.CLK(clk_pixel_x5),
.CLKDIV(clk_pixel),
.D1(tmds_internal_plus_clock[i][0]),
.D2(tmds_internal_plus_clock[i][1]),
.D3(tmds_internal_plus_clock[i][2]),
.D4(tmds_internal_plus_clock[i][3]),
.D5(tmds_internal_plus_clock[i][4]),
.D6(tmds_internal_plus_clock[i][5]),
.D7(tmds_internal_plus_clock[i][6]),
.D8(tmds_internal_plus_clock[i][7]),
.TCE(1'b0),
.OCE(1'b1),
.TBYTEIN(1'b0),
.RST(),
.SHIFTIN1(cascade[i][0]),
.SHIFTIN2(cascade[i][1]),
.T1(1'b0),
.T2(1'b0),
.T3(1'b0),
.T4(1'b0)
);
OSERDES2 #(.DATA_RATE_OQ("DDR"), .DATA_RATE_TQ("SDR"), .DATA_WIDTH(10), .SERDES_MODE("SLAVE"), .TRISTATE_WIDTH(1))
secondary (
.OQ(),
.OFB(),
.TQ(),
.TFB(),
.SHIFTOUT1(cascade[i][0]),
.SHIFTOUT2(cascade[i][1]),
.TBYTEOUT(),
.CLK(clk_pixel_x5),
.CLKDIV(clk_pixel),
.D1(1'b0),
.D2(1'b0),
.D3(tmds_internal_plus_clock[i][8]),
.D4(tmds_internal_plus_clock[i][9]),
.D5(1'b0),
.D6(1'b0),
.D7(1'b0),
.D8(1'b0),
.TCE(1'b0),
.OCE(1'b1),
.TBYTEIN(1'b0),
.RST(),
.SHIFTIN1(1'b0),
.SHIFTIN2(1'b0),
.T1(1'b0),
.T2(1'b0),
.T3(1'b0),
.T4(1'b0)
);
OSERDESE2 #(
.DATA_RATE_OQ("DDR"),
.DATA_RATE_TQ("SDR"),
.DATA_WIDTH(10),
.SERDES_MODE("MASTER"),
.TRISTATE_WIDTH(1),
.TBYTE_CTL("FALSE"),
.TBYTE_SRC("FALSE")
) primary (
.OQ(tmds_plus_clock[i]),
.OFB(),
.TQ(),
.TFB(),
.SHIFTOUT1(),
.SHIFTOUT2(),
.TBYTEOUT(),
.CLK(clk_pixel_x5),
.CLKDIV(clk_pixel),
.D1(tmds_internal_plus_clock[i][0]),
.D2(tmds_internal_plus_clock[i][1]),
.D3(tmds_internal_plus_clock[i][2]),
.D4(tmds_internal_plus_clock[i][3]),
.D5(tmds_internal_plus_clock[i][4]),
.D6(tmds_internal_plus_clock[i][5]),
.D7(tmds_internal_plus_clock[i][6]),
.D8(tmds_internal_plus_clock[i][7]),
.TCE(1'b0),
.OCE(1'b1),
.TBYTEIN(1'b0),
.RST(1'b0),
.SHIFTIN1(cascade[i][0]),
.SHIFTIN2(cascade[i][1]),
.T1(1'b0),
.T2(1'b0),
.T3(1'b0),
.T4(1'b0)
);
OSERDESE2 #(
.DATA_RATE_OQ("DDR"),
.DATA_RATE_TQ("SDR"),
.DATA_WIDTH(10),
.SERDES_MODE("SLAVE"),
.TRISTATE_WIDTH(1),
.TBYTE_CTL("FALSE"),
.TBYTE_SRC("FALSE")
) secondary (
.OQ(),
.OFB(),
.TQ(),
.TFB(),
.SHIFTOUT1(cascade[i][0]),
.SHIFTOUT2(cascade[i][1]),
.TBYTEOUT(),
.CLK(clk_pixel_x5),
.CLKDIV(clk_pixel),
.D1(1'b0),
.D2(1'b0),
.D3(tmds_internal_plus_clock[i][8]),
.D4(tmds_internal_plus_clock[i][9]),
.D5(1'b0),
.D6(1'b0),
.D7(1'b0),
.D8(1'b0),
.TCE(1'b0),
.OCE(1'b1),
.TBYTEIN(1'b0),
.RST(1'b0),
.SHIFTIN1(1'b0),
.SHIFTIN2(1'b0),
.T1(1'b0),
.T2(1'b0),
.T3(1'b0),
.T4(1'b0)
);
end
endgenerate
`endif
Expand Down

0 comments on commit 1cbde77

Please sign in to comment.