我试图做的是从 Verilog 中的 Lattice MachXO CPLD 创建一个 VGA 控制器。
问题
我正在尝试使用 CPLD 内部的 25.175 MHz 时钟以 640x480 @ 60Hz 的分辨率显示红色;但是,当我将 CPLD 插入显示器时,我会收到“超出范围”消息;我尝试的任何显示器都无法理解我想要的分辨率。
我试过的
我已经在 ModelSim 中模拟了代码(包括图片),除了一个问题,一切看起来都不错。当我计算从 V-Sync 显示区域(绘制 H-Sync 时)发生的时间步长并将其除以 H-Sync 的频率时,我得到 479 个脉冲 - 比 480 个少一个我应该画的线条。我不明白这可能来自哪里,因为我已经多次检查了我的时间,我怀疑这可能是问题的征兆,但我不确定。
我用来生成计时数字的数字来自 Tiny VGA: tinyvga.com/vga-timing/640x480@60Hz
下面是我的代码,以及来自 ModelSim 的时序图片,谢谢。
module Top(RESET, H_SYNC, V_SYNC, RED);
input wire RESET;
output wire H_SYNC;
output wire V_SYNC;
output wire RED;
wire rgb_en;
/*** Test Bench Code ***/
//reg osc_clk, reset;
//initial begin
//#0 reset = 0;
//#0 osc_clk = 0;
//#2 reset = 1;
//end
//always #1 osc_clk = ~osc_clk;
OSCC OSCC_1 (.OSC(osc_clk)); /*< IP clock module for Lattice CPLD >*/
Controller CNTRL(.NRST(RESET), .CLK(osc_clk), .H_SYNC(H_SYNC), .V_SYNC(V_SYNC), .RGB_EN(rgb_en));
assign RED = (rgb_en ? 1:1'bz);
endmodule
module Controller(CLK, NRST, H_SYNC, V_SYNC, RGB_EN);
input wire CLK; /*< CLK input from Top module >*/
input wire NRST; /*< Reset input from Top module >*/
output reg H_SYNC; /*< Goes to VGA Horizontal Sync >*/
output reg V_SYNC; /*< Goes to VGA Verical Sync >*/
output reg RGB_EN ; /*< Enables RGB values durning display time on H_SYNC >*/
reg [10:0] h_counter; /*< Tracks amount of pulses from CLK >*/
reg [19:0] v_counter; /*< Tracks amount of pulses from H_SYNC >*/
`define H_SYNC_PULSE 11'd96 /*< Length of Sync Pulse >*/
`define H_BACK_PORCH_END 11'd144 /*< Pulse len + Porch Len >*/
`define H_FRONT_PORCH_STRT 11'd784 /*< Front Porch Len - Max >*/
`define H_COUNT_MAX 11'd799 /*< Max line pulses for resolution >*/
`define V_SYNC_PULSE 19'd1600
`define V_BACK_PORCH_END 19'd28000
`define V_FRONT_PORCH_STRT 19'd412000
`define V_COUNT_MAX 19'd419999
/*** State Machine for H_SYNC ***/
always @(*) begin
/* If the vertical sync line is not in the display zone, keep H_Sync low */
if(!(v_counter > `V_BACK_PORCH_END && v_counter < `V_FRONT_PORCH_STRT)) begin
H_SYNC = 0;
RGB_EN = 0;
end
/* If the vertical sync line is in display zone, allow H_Sync to go through its procedure */
else begin
if (h_counter < `H_SYNC_PULSE) begin
H_SYNC = 0;
RGB_EN = 0;
end
/* If H_Sync is in the display zone, enable RGB */
else if (h_counter > `H_BACK_PORCH_END && h_counter < `H_FRONT_PORCH_STRT) begin
H_SYNC = 1;
RGB_EN = 1;
end
/* During the Front Porch period, disable RGB */
else begin
H_SYNC = 1;
RGB_EN = 0;
end
end
end
/*** State Machine for V_SYNC ***/
always @(*) begin
if (v_counter < `V_SYNC_PULSE) begin
V_SYNC = 0;
end
else begin
V_SYNC = 1;
end
end
/*** Counter logic ***/
always @(posedge CLK) begin
if (h_counter >= `H_COUNT_MAX || !NRST) begin
h_counter <= 11'b00;
end
else begin
h_counter <= h_counter + 1;
end
end
always @(posedge CLK) begin
if (v_counter >= `V_COUNT_MAX || !NRST) begin
v_counter <= 11'b00;
end
else begin
v_counter <= v_counter + 1;
end
end
endmodule