mirror of
https://github.com/alangarf/apple-one.git
synced 2024-06-11 04:29:33 +00:00
Ulx3s HDMI version
This commit is contained in:
parent
402be08794
commit
d2be2acb7f
|
@ -53,7 +53,11 @@ $(BUILDDIR)/apple1.json: $(SOURCEDIR)/apple1.v \
|
|||
$(SOURCEDIR)/vga/font_rom.v \
|
||||
$(SOURCEDIR)/ps2keyboard/debounce.v \
|
||||
$(SOURCEDIR)/ps2keyboard/ps2keyboard.v \
|
||||
$(SOURCEDIR)/boards/ulx3s/apple1_ecp5.v
|
||||
$(SOURCEDIR)/boards/ulx3s/apple1_dvi.v \
|
||||
$(SOURCEDIR)/boards/ulx3s/vga2dvid.v \
|
||||
$(SOURCEDIR)/boards/ulx3s/clk_25_250_125_25.v \
|
||||
$(SOURCEDIR)/boards/ulx3s/tmds_encoder.v \
|
||||
$(SOURCEDIR)/boards/ulx3s/fake_differential.v
|
||||
|
||||
prog: dir $(BUILDDIR)/apple1.bit
|
||||
ujprog $(filter-out $<,$^)
|
||||
|
|
|
@ -49,6 +49,7 @@ module apple1 #(
|
|||
output vga_grn, // green VGA signal
|
||||
output vga_blu, // blue VGA signal
|
||||
input vga_cls, // clear screen button
|
||||
output vga_blank, // set when vga not in active area
|
||||
|
||||
// Debugging ports
|
||||
output [15:0] pc_monitor // spy for program counter / debugging
|
||||
|
@ -223,6 +224,7 @@ module apple1 #(
|
|||
.mode(font_mode),
|
||||
.fg_colour(fg_colour),
|
||||
.bg_colour(bg_colour),
|
||||
.vga_blank(vga_blank),
|
||||
.clr_screen(vga_cls)
|
||||
);
|
||||
|
||||
|
|
181
rtl/boards/ulx3s/apple1_dvi.v
Normal file
181
rtl/boards/ulx3s/apple1_dvi.v
Normal file
|
@ -0,0 +1,181 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
//
|
||||
// Description: Apple 1 implementation for the Blackeice II ICE40HX8K +
|
||||
//
|
||||
// Author.....: Lawrie Griffiths and Alan Garfield
|
||||
// Date.......: 31-3-2018
|
||||
//
|
||||
|
||||
module apple1_top #(
|
||||
parameter BASIC_FILENAME = "../../../roms/basic.hex",
|
||||
parameter FONT_ROM_FILENAME = "../../../roms/vga_font_bitreversed.hex",
|
||||
parameter RAM_FILENAME = "../../../roms/ram.hex",
|
||||
parameter VRAM_FILENAME = "../../../roms/vga_vram.bin",
|
||||
parameter WOZMON_ROM_FILENAME = "../../../roms/wozmon.hex"
|
||||
) (
|
||||
input clk_25mhz, // 25 MHz board clock
|
||||
|
||||
// I/O interface to computer
|
||||
input uart_rx, // asynchronous serial data input from computer
|
||||
output uart_tx, // asynchronous serial data output to computer
|
||||
output uart_cts, // clear to send flag to computer - not used
|
||||
|
||||
// I/O interface to keyboard
|
||||
input ps2_clk, // PS/2 keyboard serial clock input
|
||||
input ps2_din, // PS/2 keyboard serial data input
|
||||
|
||||
output usb_fpga_pu_dp,
|
||||
output usb_fpga_pu_dn,
|
||||
|
||||
output [3:0] gpdi_dp, gpdi_dn,
|
||||
|
||||
// Debugging ports
|
||||
output [3:0] led,
|
||||
input [1:0] button // 2 buttons on board
|
||||
);
|
||||
|
||||
parameter C_ddr = 1'b1; // 0:SDR 1:DDR
|
||||
|
||||
// clock generator
|
||||
wire clk_250MHz, clk_125MHz, clk_25MHz, clk_locked;
|
||||
clk_25_250_125_25
|
||||
clock_instance
|
||||
(
|
||||
.clki(clk_25mhz),
|
||||
.clko(clk_250MHz),
|
||||
.clks1(clk_125MHz),
|
||||
.clks2(clk_25MHz),
|
||||
.locked(clk_locked)
|
||||
);
|
||||
|
||||
// shift clock choice SDR/DDR
|
||||
wire clk_pixel, clk_shift;
|
||||
assign clk_pixel = clk_25MHz;
|
||||
generate
|
||||
if(C_ddr == 1'b1)
|
||||
assign clk_shift = clk_125MHz;
|
||||
else
|
||||
assign clk_shift = clk_250MHz;
|
||||
endgenerate
|
||||
|
||||
assign usb_fpga_pu_dp = 1;
|
||||
assign usb_fpga_pu_dn = 1;
|
||||
|
||||
assign led[0] = 1;
|
||||
assign led[1] = reset_n;
|
||||
assign led[2] = clr_screen_n;
|
||||
assign led[3] = 0;
|
||||
|
||||
wire vga_bit;
|
||||
|
||||
// VGA signal generator
|
||||
wire [7:0] vga_r, vga_g, vga_b;
|
||||
wire vga_h_sync, vga_v_sync, vga_blank;
|
||||
|
||||
// set the monochrome base colour here..
|
||||
assign vga_r = vga_bit ? 8'b10000000 : 8'b00000000;
|
||||
assign vga_g = vga_bit ? 8'b11111111 : 8'b00000000;
|
||||
assign vga_b = vga_bit ? 8'b10000000 : 8'b00000000;
|
||||
|
||||
// debounce reset button
|
||||
wire reset_n;
|
||||
debounce reset_button (
|
||||
.clk25(clk_25mhz),
|
||||
.rst(1'b0),
|
||||
.sig_in(button[0]),
|
||||
.sig_out(reset_n)
|
||||
);
|
||||
|
||||
// debounce clear screen button
|
||||
wire clr_screen_n;
|
||||
debounce clr_button (
|
||||
.clk25(clk_25mhz),
|
||||
.rst(~reset_n),
|
||||
.sig_in(~button[1]),
|
||||
.sig_out(clr_screen_n)
|
||||
);
|
||||
|
||||
// apple one main system
|
||||
apple1 #(
|
||||
.BASIC_FILENAME (BASIC_FILENAME),
|
||||
.FONT_ROM_FILENAME (FONT_ROM_FILENAME),
|
||||
.RAM_FILENAME (RAM_FILENAME),
|
||||
.VRAM_FILENAME (VRAM_FILENAME),
|
||||
.WOZMON_ROM_FILENAME (WOZMON_ROM_FILENAME)
|
||||
) my_apple1(
|
||||
.clk25(clk_25mhz),
|
||||
.rst_n(reset_n),
|
||||
|
||||
.uart_rx(uart_rx),
|
||||
.uart_tx(uart_tx),
|
||||
.uart_cts(uart_cts),
|
||||
|
||||
.ps2_clk(ps2_clk),
|
||||
.ps2_din(ps2_din),
|
||||
.ps2_select(1'b1), // PS/2 enabled, UART TX disabled
|
||||
//.ps2_select(1'b0), // PS/2 disabled, UART TX enabled
|
||||
|
||||
.vga_h_sync(vga_h_sync),
|
||||
.vga_v_sync(vga_v_sync),
|
||||
.vga_red(vga_bit),
|
||||
//.vga_grn(vga_bit),
|
||||
//.vga_blu(vga_bit),
|
||||
.vga_blank(vga_blank),
|
||||
.vga_cls(~clr_screen_n),
|
||||
);
|
||||
|
||||
// VGA to digital video converter
|
||||
wire [1:0] tmds[3:0];
|
||||
vga2dvid
|
||||
#(
|
||||
.C_ddr(C_ddr),
|
||||
.C_shift_clock_synchronizer(1'b1)
|
||||
)
|
||||
vga2dvid_instance
|
||||
(
|
||||
.clk_pixel(clk_pixel),
|
||||
.clk_shift(clk_shift),
|
||||
.in_red(vga_r),
|
||||
.in_green(vga_g),
|
||||
.in_blue(vga_b),
|
||||
.in_hsync(vga_h_sync),
|
||||
.in_vsync(vga_v_sync),
|
||||
.in_blank(vga_blank),
|
||||
.out_clock(tmds[3]),
|
||||
.out_red(tmds[2]),
|
||||
.out_green(tmds[1]),
|
||||
.out_blue(tmds[0])
|
||||
);
|
||||
|
||||
// output TMDS SDR/DDR data to fake differential lanes
|
||||
fake_differential
|
||||
#(
|
||||
.C_ddr(C_ddr)
|
||||
)
|
||||
fake_differential_instance
|
||||
(
|
||||
.clk_shift(clk_shift),
|
||||
.in_clock(tmds[3]),
|
||||
.in_red(tmds[2]),
|
||||
.in_green(tmds[1]),
|
||||
.in_blue(tmds[0]),
|
||||
.out_p(gpdi_dp),
|
||||
.out_n(gpdi_dn)
|
||||
);
|
||||
|
||||
endmodule
|
60
rtl/boards/ulx3s/clk_25_250_125_25.v
Normal file
60
rtl/boards/ulx3s/clk_25_250_125_25.v
Normal file
|
@ -0,0 +1,60 @@
|
|||
// diamond 3.7 accepts this PLL
|
||||
// diamond 3.8-3.9 is untested
|
||||
// diamond 3.10 or higher is likely to abort with error about unable to use feedback signal
|
||||
// cause of this could be from wrong CPHASE/FPHASE parameters
|
||||
module clk_25_250_125_25
|
||||
(
|
||||
input clki, // 25 MHz, 0 deg
|
||||
output clko, // 250 MHz, 0 deg
|
||||
output clks1, // 125 MHz, 0 deg
|
||||
output clks2, // 25 MHz, 0 deg
|
||||
output locked
|
||||
);
|
||||
(* FREQUENCY_PIN_CLKI="25" *)
|
||||
(* FREQUENCY_PIN_CLKOP="250" *)
|
||||
(* FREQUENCY_PIN_CLKOS="125" *)
|
||||
(* FREQUENCY_PIN_CLKOS2="25" *)
|
||||
(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *)
|
||||
EHXPLLL #(
|
||||
.PLLRST_ENA("DISABLED"),
|
||||
.INTFB_WAKE("DISABLED"),
|
||||
.STDBY_ENABLE("DISABLED"),
|
||||
.DPHASE_SOURCE("DISABLED"),
|
||||
.OUTDIVIDER_MUXA("DIVA"),
|
||||
.OUTDIVIDER_MUXB("DIVB"),
|
||||
.OUTDIVIDER_MUXC("DIVC"),
|
||||
.OUTDIVIDER_MUXD("DIVD"),
|
||||
.CLKI_DIV(1),
|
||||
.CLKOP_ENABLE("ENABLED"),
|
||||
.CLKOP_DIV(2),
|
||||
.CLKOP_CPHASE(0),
|
||||
.CLKOP_FPHASE(0),
|
||||
.CLKOS_ENABLE("ENABLED"),
|
||||
.CLKOS_DIV(4),
|
||||
.CLKOS_CPHASE(0),
|
||||
.CLKOS_FPHASE(0),
|
||||
.CLKOS2_ENABLE("ENABLED"),
|
||||
.CLKOS2_DIV(20),
|
||||
.CLKOS2_CPHASE(0),
|
||||
.CLKOS2_FPHASE(0),
|
||||
.FEEDBK_PATH("CLKOP"),
|
||||
.CLKFB_DIV(10)
|
||||
) pll_i (
|
||||
.RST(1'b0),
|
||||
.STDBY(1'b0),
|
||||
.CLKI(clki),
|
||||
.CLKOP(clko),
|
||||
.CLKOS(clks1),
|
||||
.CLKOS2(clks2),
|
||||
.CLKFB(clko),
|
||||
.CLKINTFB(),
|
||||
.PHASESEL0(1'b0),
|
||||
.PHASESEL1(1'b0),
|
||||
.PHASEDIR(1'b1),
|
||||
.PHASESTEP(1'b1),
|
||||
.PHASELOADREG(1'b1),
|
||||
.PLLWAKESYNC(1'b0),
|
||||
.ENCLKOP(1'b0),
|
||||
.LOCK(locked)
|
||||
);
|
||||
endmodule
|
63
rtl/boards/ulx3s/fake_differential.v
Normal file
63
rtl/boards/ulx3s/fake_differential.v
Normal file
|
@ -0,0 +1,63 @@
|
|||
// DDR mode uses Lattice ECP5 vendor-specific module ODDRX1F
|
||||
|
||||
module fake_differential
|
||||
(
|
||||
input clk_shift, // used only in DDR mode
|
||||
// [1:0]:DDR [0]:SDR TMDS
|
||||
input [1:0] in_clock, in_red, in_green, in_blue,
|
||||
// [3]:clock [2]:red [1]:green [0]:blue
|
||||
output [3:0] out_p, out_n
|
||||
);
|
||||
parameter C_ddr = 1'b0; // 0:SDR 1:DDR
|
||||
|
||||
wire [1:0] tmds[3:0];
|
||||
assign tmds[3] = in_clock;
|
||||
assign tmds[2] = in_red;
|
||||
assign tmds[1] = in_green;
|
||||
assign tmds[0] = in_blue;
|
||||
|
||||
// register stage to improve timing of the fake differential
|
||||
reg [1:0] R_tmds_p[3:0], R_tmds_n[3:0];
|
||||
generate
|
||||
genvar i;
|
||||
for(i = 0; i < 4; i++)
|
||||
begin : TMDS_pn_registers
|
||||
always @(posedge clk_shift) R_tmds_p[i] <= tmds[i];
|
||||
always @(posedge clk_shift) R_tmds_n[i] <= ~tmds[i];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// output SDR/DDR to fake differential
|
||||
generate
|
||||
genvar i;
|
||||
if(C_ddr == 1'b1)
|
||||
for(i = 0; i < 4; i++)
|
||||
begin : DDR_output_mode
|
||||
ODDRX1F
|
||||
ddr_p_instance
|
||||
(
|
||||
.D0(R_tmds_p[i][0]),
|
||||
.D1(R_tmds_p[i][1]),
|
||||
.Q(out_p[i]),
|
||||
.SCLK(clk_shift),
|
||||
.RST(0)
|
||||
);
|
||||
ODDRX1F
|
||||
ddr_n_instance
|
||||
(
|
||||
.D0(R_tmds_n[i][0]),
|
||||
.D1(R_tmds_n[i][1]),
|
||||
.Q(out_n[i]),
|
||||
.SCLK(clk_shift),
|
||||
.RST(0)
|
||||
);
|
||||
end
|
||||
else
|
||||
for(i = 0; i < 4; i++)
|
||||
begin : SDR_output_mode
|
||||
assign out_p[i] = R_tmds_p[i][0];
|
||||
assign out_n[i] = R_tmds_n[i][0];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule
|
155
rtl/boards/ulx3s/tmds_encoder.v
Normal file
155
rtl/boards/ulx3s/tmds_encoder.v
Normal file
|
@ -0,0 +1,155 @@
|
|||
// File hdl/tmds_encoder.vhd translated with vhd2vl v3.0 VHDL to Verilog RTL translator
|
||||
// vhd2vl settings:
|
||||
// * Verilog Module Declaration Style: 2001
|
||||
|
||||
// vhd2vl is Free (libre) Software:
|
||||
// Copyright (C) 2001 Vincenzo Liguori - Ocean Logic Pty Ltd
|
||||
// http://www.ocean-logic.com
|
||||
// Modifications Copyright (C) 2006 Mark Gonzales - PMC Sierra Inc
|
||||
// Modifications (C) 2010 Shankar Giri
|
||||
// Modifications Copyright (C) 2002-2017 Larry Doolittle
|
||||
// http://doolittle.icarus.com/~larry/vhd2vl/
|
||||
// Modifications (C) 2017 Rodrigo A. Melo
|
||||
//
|
||||
// vhd2vl comes with ABSOLUTELY NO WARRANTY. Always check the resulting
|
||||
// Verilog for correctness, ideally with a formal verification tool.
|
||||
//
|
||||
// You are welcome to redistribute vhd2vl under certain conditions.
|
||||
// See the license (GPLv2) file included with the source for details.
|
||||
|
||||
// The result of translation follows. Its copyright status should be
|
||||
// considered unchanged from the original VHDL.
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Engineer: Mike Field <hamster@snap.net.nz>
|
||||
//
|
||||
// Description: TMDS Encoder
|
||||
// 8 bits colour, 2 control bits and one blanking bits in
|
||||
// 10 bits of TMDS encoded data out
|
||||
// Clocked at the pixel clock
|
||||
//
|
||||
//--------------------------------------------------------------------------------
|
||||
// See: http://hamsterworks.co.nz/mediawiki/index.php/Dvid_test
|
||||
// http://hamsterworks.co.nz/mediawiki/index.php/FPGA_Projects
|
||||
//
|
||||
// Copyright (c) 2012 Mike Field <hamster@snap.net.nz>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// no timescale needed
|
||||
|
||||
module tmds_encoder(
|
||||
input wire clk,
|
||||
input wire [7:0] data,
|
||||
input wire [1:0] c,
|
||||
input wire blank,
|
||||
output reg [9:0] encoded
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
wire [8:0] xored;
|
||||
wire [8:0] xnored;
|
||||
wire [3:0] ones;
|
||||
reg [8:0] data_word;
|
||||
reg [8:0] data_word_inv;
|
||||
wire [3:0] data_word_disparity;
|
||||
reg [3:0] dc_bias = 1'b0;
|
||||
|
||||
// Work our the two different encodings for the byte
|
||||
assign xored[0] = data[0];
|
||||
assign xored[1] = data[1] ^ xored[0];
|
||||
assign xored[2] = data[2] ^ xored[1];
|
||||
assign xored[3] = data[3] ^ xored[2];
|
||||
assign xored[4] = data[4] ^ xored[3];
|
||||
assign xored[5] = data[5] ^ xored[4];
|
||||
assign xored[6] = data[6] ^ xored[5];
|
||||
assign xored[7] = data[7] ^ xored[6];
|
||||
assign xored[8] = 1'b1;
|
||||
assign xnored[0] = data[0];
|
||||
assign xnored[1] = ~(data[1] ^ xnored[0]);
|
||||
assign xnored[2] = ~(data[2] ^ xnored[1]);
|
||||
assign xnored[3] = ~(data[3] ^ xnored[2]);
|
||||
assign xnored[4] = ~(data[4] ^ xnored[3]);
|
||||
assign xnored[5] = ~(data[5] ^ xnored[4]);
|
||||
assign xnored[6] = ~(data[6] ^ xnored[5]);
|
||||
assign xnored[7] = ~(data[7] ^ xnored[6]);
|
||||
assign xnored[8] = 1'b0;
|
||||
// Count how many ones are set in data
|
||||
assign ones = 4'b0000 + data[0] + data[1] + data[2] + data[3] + data[4] + data[5] + data[6] + data[7];
|
||||
// Decide which encoding to use
|
||||
always @(ones, data[0], xnored, xored) begin
|
||||
if(ones > 4 || (ones == 4 && data[0] == 1'b0)) begin
|
||||
data_word <= xnored;
|
||||
data_word_inv <= ~(xnored);
|
||||
end
|
||||
else begin
|
||||
data_word <= xored;
|
||||
data_word_inv <= ~(xored);
|
||||
end
|
||||
end
|
||||
|
||||
// Work out the DC bias of the dataword;
|
||||
assign data_word_disparity = 4'b1100 + data_word[0] + data_word[1] + data_word[2] + data_word[3] + data_word[4] + data_word[5] + data_word[6] + data_word[7];
|
||||
// Now work out what the output should be
|
||||
always @(posedge clk) begin
|
||||
if(blank == 1'b1) begin
|
||||
// In the control periods, all values have and have balanced bit count
|
||||
case(c)
|
||||
2'b00 : begin
|
||||
encoded <= 10'b1101010100;
|
||||
end
|
||||
2'b01 : begin
|
||||
encoded <= 10'b0010101011;
|
||||
end
|
||||
2'b10 : begin
|
||||
encoded <= 10'b0101010100;
|
||||
end
|
||||
default : begin
|
||||
encoded <= 10'b1010101011;
|
||||
end
|
||||
endcase
|
||||
dc_bias <= {4{1'b0}};
|
||||
end
|
||||
else begin
|
||||
if(dc_bias == 5'b00000 || data_word_disparity == 0) begin
|
||||
// dataword has no disparity
|
||||
if(data_word[8] == 1'b1) begin
|
||||
encoded <= {2'b01,data_word[7:0]};
|
||||
dc_bias <= dc_bias + data_word_disparity;
|
||||
end
|
||||
else begin
|
||||
encoded <= {2'b10,data_word_inv[7:0]};
|
||||
dc_bias <= dc_bias - data_word_disparity;
|
||||
end
|
||||
end
|
||||
else if((dc_bias[3] == 1'b0 && data_word_disparity[3] == 1'b0) || (dc_bias[3] == 1'b1 && data_word_disparity[3] == 1'b1)) begin
|
||||
encoded <= {1'b1,data_word[8],data_word_inv[7:0]};
|
||||
dc_bias <= dc_bias + data_word[8] - data_word_disparity;
|
||||
end
|
||||
else begin
|
||||
encoded <= {1'b0,data_word};
|
||||
dc_bias <= dc_bias - data_word_inv[8] + data_word_disparity;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
262
rtl/boards/ulx3s/vga2dvid.v
Normal file
262
rtl/boards/ulx3s/vga2dvid.v
Normal file
|
@ -0,0 +1,262 @@
|
|||
// File vga2dvid.vhd translated with vhd2vl v3.0 VHDL to Verilog RTL translator
|
||||
// vhd2vl settings:
|
||||
// * Verilog Module Declaration Style: 2001
|
||||
|
||||
// vhd2vl is Free (libre) Software:
|
||||
// Copyright (C) 2001 Vincenzo Liguori - Ocean Logic Pty Ltd
|
||||
// http://www.ocean-logic.com
|
||||
// Modifications Copyright (C) 2006 Mark Gonzales - PMC Sierra Inc
|
||||
// Modifications (C) 2010 Shankar Giri
|
||||
// Modifications Copyright (C) 2002-2017 Larry Doolittle
|
||||
// http://doolittle.icarus.com/~larry/vhd2vl/
|
||||
// Modifications (C) 2017 Rodrigo A. Melo
|
||||
//
|
||||
// vhd2vl comes with ABSOLUTELY NO WARRANTY. Always check the resulting
|
||||
// Verilog for correctness, ideally with a formal verification tool.
|
||||
//
|
||||
// You are welcome to redistribute vhd2vl under certain conditions.
|
||||
// See the license (GPLv2) file included with the source for details.
|
||||
|
||||
// The result of translation follows. Its copyright status should be
|
||||
// considered unchanged from the original VHDL.
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Engineer: Mike Field <hamster@snap.net.nz>
|
||||
// Description: Converts VGA signals into DVID bitstreams.
|
||||
//
|
||||
// 'clk_shift' 10x clk_pixel for SDR
|
||||
// 'clk_shift' 5x clk_pixel for DDR
|
||||
//
|
||||
// 'blank' should be asserted during the non-display
|
||||
// portions of the frame
|
||||
//------------------------------------------------------------------------------
|
||||
// See: http://hamsterworks.co.nz/mediawiki/index.php/Dvid_test
|
||||
// http://hamsterworks.co.nz/mediawiki/index.php/FPGA_Projects
|
||||
//
|
||||
// Copyright (c) 2012 Mike Field <hamster@snap.net.nz>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// takes VGA input and prepares output
|
||||
// for SDR buffer, which send 1 bit per 1 clock period output out_red(0), out_green(0), ... etc.
|
||||
// for DDR buffers, which send 2 bits per 1 clock period output out_red(1 downto 0), ...
|
||||
// EMARD unified SDR and DDR into one module
|
||||
// no timescale needed
|
||||
|
||||
module vga2dvid(
|
||||
input wire clk_pixel,
|
||||
input wire clk_shift,
|
||||
input wire [C_depth - 1:0] in_red,
|
||||
input wire [C_depth - 1:0] in_green,
|
||||
input wire [C_depth - 1:0] in_blue,
|
||||
input wire in_blank,
|
||||
input wire in_hsync,
|
||||
input wire in_vsync,
|
||||
output wire [9:0] outp_red,
|
||||
output wire [9:0] outp_green,
|
||||
output wire [9:0] outp_blue,
|
||||
output wire [1:0] out_red,
|
||||
output wire [1:0] out_green,
|
||||
output wire [1:0] out_blue,
|
||||
output wire [1:0] out_clock
|
||||
);
|
||||
|
||||
parameter C_shift_clock_synchronizer=1'b1;
|
||||
parameter C_parallel=1'b1;
|
||||
parameter C_serial=1'b1;
|
||||
parameter C_ddr=1'b0;
|
||||
parameter [31:0] C_depth=8;
|
||||
// VGA pixel clock, 25 MHz for 640x480
|
||||
// SDR: 10x clk_pixel, DDR: 5x clk_pixel, in phase with clk_pixel
|
||||
// parallel outputs
|
||||
// serial outputs
|
||||
|
||||
|
||||
|
||||
wire [9:0] encoded_red; wire [9:0] encoded_green; wire [9:0] encoded_blue;
|
||||
reg [9:0] latched_red = 1'b0; reg [9:0] latched_green = 1'b0; reg [9:0] latched_blue = 1'b0;
|
||||
reg [9:0] shift_red = 1'b0; reg [9:0] shift_green = 1'b0; reg [9:0] shift_blue = 1'b0;
|
||||
parameter C_shift_clock_initial = 10'b0000011111;
|
||||
reg [9:0] shift_clock = C_shift_clock_initial;
|
||||
reg R_shift_clock_off_sync = 1'b0;
|
||||
reg [7:0] R_shift_clock_synchronizer = 1'b0;
|
||||
reg [6:0] R_sync_fail; // counts sync fails, after too many, reinitialize shift_clock
|
||||
parameter c_red = 1'b0;
|
||||
parameter c_green = 1'b0;
|
||||
wire [1:0] c_blue;
|
||||
wire [7:0] red_d;
|
||||
wire [7:0] green_d;
|
||||
wire [7:0] blue_d;
|
||||
|
||||
assign c_blue = {in_vsync,in_hsync};
|
||||
assign red_d[7:8 - C_depth] = in_red[C_depth - 1:0];
|
||||
assign green_d[7:8 - C_depth] = in_green[C_depth - 1:0];
|
||||
assign blue_d[7:8 - C_depth] = in_blue[C_depth - 1:0];
|
||||
// fill vacant low bits with value repeated (so min/max value is always 0 or 255)
|
||||
generate if (C_depth < 8) begin: G_vacant_bits
|
||||
genvar i;
|
||||
generate for (i=0; i <= 8 - C_depth - 1; i = i + 1) begin: G_bits
|
||||
assign red_d[i] = in_red[0];
|
||||
assign green_d[i] = in_green[0];
|
||||
assign blue_d[i] = in_blue[0];
|
||||
end
|
||||
endgenerate
|
||||
end
|
||||
endgenerate
|
||||
generate if (C_shift_clock_synchronizer == 1'b1) begin: G_shift_clock_synchronizer
|
||||
// sampler verifies is shift_clock state synchronous with pixel_clock
|
||||
always @(posedge clk_pixel) begin
|
||||
// does 0 to 1 transition at bits 5 downto 4 happen at rising_edge of clk_pixel?
|
||||
// if shift_clock = C_shift_clock_initial then
|
||||
if(shift_clock[5:4] == C_shift_clock_initial[5:4]) begin
|
||||
// same as above line but simplified
|
||||
R_shift_clock_off_sync <= 1'b0;
|
||||
end
|
||||
else begin
|
||||
R_shift_clock_off_sync <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// every N cycles of clk_shift: signal to skip 1 cycle in order to get in sync
|
||||
always @(posedge clk_shift) begin
|
||||
if(R_shift_clock_off_sync == 1'b1) begin
|
||||
if(R_shift_clock_synchronizer[(7)] == 1'b1) begin
|
||||
R_shift_clock_synchronizer <= {8{1'b0}};
|
||||
end
|
||||
else begin
|
||||
R_shift_clock_synchronizer <= R_shift_clock_synchronizer + 1;
|
||||
end
|
||||
end
|
||||
else begin
|
||||
R_shift_clock_synchronizer <= {8{1'b0}};
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
endgenerate
|
||||
// shift_clock_synchronizer
|
||||
tmds_encoder u21(
|
||||
.clk(clk_pixel),
|
||||
.data(red_d),
|
||||
.c(c_red),
|
||||
.blank(in_blank),
|
||||
.encoded(encoded_red));
|
||||
|
||||
tmds_encoder u22(
|
||||
.clk(clk_pixel),
|
||||
.data(green_d),
|
||||
.c(c_green),
|
||||
.blank(in_blank),
|
||||
.encoded(encoded_green));
|
||||
|
||||
tmds_encoder u23(
|
||||
.clk(clk_pixel),
|
||||
.data(blue_d),
|
||||
.c(c_blue),
|
||||
.blank(in_blank),
|
||||
.encoded(encoded_blue));
|
||||
|
||||
always @(posedge clk_pixel) begin
|
||||
latched_red <= encoded_red;
|
||||
latched_green <= encoded_green;
|
||||
latched_blue <= encoded_blue;
|
||||
end
|
||||
|
||||
generate if (C_parallel == 1'b1) begin: G_parallel
|
||||
assign outp_red = latched_red;
|
||||
assign outp_green = latched_green;
|
||||
assign outp_blue = latched_blue;
|
||||
end
|
||||
endgenerate
|
||||
generate if ((C_serial & ~C_ddr) == 1'b1) begin: G_SDR
|
||||
always @(posedge clk_shift) begin
|
||||
//if shift_clock = "0000011111" then
|
||||
if(shift_clock[5:4] == C_shift_clock_initial[5:4]) begin
|
||||
// same as above line but simplified
|
||||
shift_red <= latched_red;
|
||||
shift_green <= latched_green;
|
||||
shift_blue <= latched_blue;
|
||||
end
|
||||
else begin
|
||||
shift_red <= {1'b0,shift_red[9:1]};
|
||||
shift_green <= {1'b0,shift_green[9:1]};
|
||||
shift_blue <= {1'b0,shift_blue[9:1]};
|
||||
end
|
||||
if(R_shift_clock_synchronizer[(7)] == 1'b0) begin
|
||||
shift_clock <= {shift_clock[0],shift_clock[9:1]};
|
||||
end
|
||||
else begin
|
||||
// synchronization failed.
|
||||
// after too many fails, reinitialize shift_clock
|
||||
if(R_sync_fail[(6)] == 1'b1) begin
|
||||
shift_clock <= C_shift_clock_initial;
|
||||
R_sync_fail <= {7{1'b0}};
|
||||
end
|
||||
else begin
|
||||
R_sync_fail <= R_sync_fail + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
endgenerate
|
||||
generate if ((C_serial & C_ddr) == 1'b1) begin: G_DDR
|
||||
always @(posedge clk_shift) begin
|
||||
//if shift_clock = "0000011111" then
|
||||
if(shift_clock[5:4] == C_shift_clock_initial[5:4]) begin
|
||||
// same as above line but simplified
|
||||
shift_red <= latched_red;
|
||||
shift_green <= latched_green;
|
||||
shift_blue <= latched_blue;
|
||||
end
|
||||
else begin
|
||||
shift_red <= {2'b00,shift_red[9:2]};
|
||||
shift_green <= {2'b00,shift_green[9:2]};
|
||||
shift_blue <= {2'b00,shift_blue[9:2]};
|
||||
end
|
||||
if(R_shift_clock_synchronizer[(7)] == 1'b0) begin
|
||||
shift_clock <= {shift_clock[1:0],shift_clock[9:2]};
|
||||
end
|
||||
else begin
|
||||
// synchronization failed.
|
||||
// after too many fails, reinitialize shift_clock
|
||||
if(R_sync_fail[(6)] == 1'b1) begin
|
||||
shift_clock <= C_shift_clock_initial;
|
||||
R_sync_fail <= {7{1'b0}};
|
||||
end
|
||||
else begin
|
||||
R_sync_fail <= R_sync_fail + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
endgenerate
|
||||
// SDR: use only bit 0 from each out_* channel
|
||||
// DDR: 2 bits per 1 clock period,
|
||||
// (one bit output on rising edge, other on falling edge of clk_shift)
|
||||
generate if (C_serial == 1'b1) begin: G_serial
|
||||
assign out_red = shift_red[1:0];
|
||||
assign out_green = shift_green[1:0];
|
||||
assign out_blue = shift_blue[1:0];
|
||||
assign out_clock = shift_clock[1:0];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule
|
|
@ -38,6 +38,7 @@ module vga #(
|
|||
input [1:0] mode, // 2-bit mode setting for pixel doubling
|
||||
input [2:0] bg_colour, // 3 bit background colour
|
||||
input [2:0] fg_colour, // 3 bit foreground colour
|
||||
output vga_blank, // set when out of active regions
|
||||
input clr_screen // clear screen button
|
||||
);
|
||||
|
||||
|
@ -94,6 +95,8 @@ module vga #(
|
|||
assign h_active = (h_cnt >= hbp && h_cnt < hfp);
|
||||
assign v_active = (v_cnt >= vbp && v_cnt < vfp);
|
||||
|
||||
assign vga_blank = !(h_active && v_active);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// VGA Sync Generation
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue
Block a user