在之前彩条显示工程中增添一个rom模块,在中心显示100 X 100 的一个图像。
主要考察rom的使用。读数据拉高,并输入地址。下个周期输出该地址对应的数据。
如果输出口不加reg寄存一下,数据只会滞后一个时钟周期输出(相对于读使能)。
加了 滞后两个。相当于打了一拍嘛。比较好理解。
在设计这个实验中,还重点考察了,坐标与数据,在时序上要对齐。
尤其输出信号用reg,对某个“数据输出信号”采样。虽然“数据输出信号”和坐标对齐了。
但是真正要输出的信号,还是滞后了一个时钟周期(相对于坐标)。
所以还要把“数据输出信号”提前一个时钟周期的同时,把输出信号的采样点也提前一个时钟周期,这样输出信号才能完全和坐标对齐。
仿真图上有直观的文字说明。
// #define BLACK 0x0000 // 黑色
// #define NAVY 0x000F // 深蓝色
// #define DGREEN 0x03E0 // 深绿色
// #define DCYAN 0x03EF // 深青色
// #define MAROON 0x7800 // 深红色
// #define PURPLE 0x780F // 紫色
// #define OLIVE 0x7BE0 // 橄榄绿
// #define LGRAY 0xC618 // 灰白色
// #define DGRAY 0x7BEF // 深灰色
// #define BLUE 0x001F // 蓝色
// #define GREEN 0x07E0 // 绿色
// #define CYAN 0x07FF // 青色
// #define RED 0xF800 // 红色
// #define MAGENTA 0xF81F // 品红
// #define YELLOW 0xFFE0 // 黄色
// #define WHITE 0xFFFF // 白色
// rgb 565
module vga_pix (
input wire vga_clk ,
input wire vga_rst_n ,
input wire [9:0] pix_x ,
input wire [9:0] pix_y ,
output reg [15:0] pix_data
);
reg [13:0] address ; // 在读使能信号拉高,每个时钟周期自加一,0 ~ 9999
reg rden ; // 读使能信号超前图像数据一个时钟周期。
wire [15:0] q ; // 从rom里读出的数据。
wire [13:0] address_w ;
wire rden_w ;
// parameter
parameter H_VALID = 10'd640 ,
V_VALID = 10'd480 ;
parameter RED = 16'hF800 ,
ORANGE = 16'hFC00 ,
YELLOW = 16'hFFe0 ,
GREEN = 16'h07e0 ,
QING = 16'h07FF ,
BLUE = 16'h001F ,
PURPLE = 16'hF81F ,
BLACK = 16'h0000 ,
WHITE = 16'hFFFF ,
GRAY = 16'hD69A ;
// output signal
always @(posedge vga_clk or negedge vga_rst_n) begin
if(~vga_rst_n) begin
pix_data <= 10'h3ff ;
end else begin // 有简便写法 ( H_VALID / 10 ) * n
if((pix_y >= 190) && (pix_y <= 289) && (pix_x >= 269) && (pix_x <= 368))
pix_data <= q ;
else
if((pix_y >= 10'd0) && (pix_y <= V_VALID / 10 - 1'b1))
pix_data <= RED ;
else
if((pix_y >= V_VALID / 10) && (pix_y <= (V_VALID / 10) * 2 - 1'b1))
pix_data <= ORANGE ;
else
if((pix_y >= (V_VALID / 10) * 2) && (pix_y <= (V_VALID / 10) * 3 - 1'b1))
pix_data <= YELLOW ;
else
if((pix_y >= (V_VALID / 10) * 3) && (pix_y <= (V_VALID / 10) * 4 - 1'b1))
pix_data <= GREEN ;
else
if((pix_y >= (V_VALID / 10) * 4) && (pix_y <= (V_VALID / 10) * 5 - 1'b1))
pix_data <= QING ;
else
if((pix_y >= (V_VALID / 10) * 5) && (pix_y <= (V_VALID / 10) * 6 - 1'b1))
pix_data <= BLUE ;
else
if((pix_y >= (V_VALID / 10) * 6) && (pix_y <= (V_VALID / 10) * 7 - 1'b1))
pix_data <= PURPLE ;
else
if((pix_y >= (V_VALID / 10) * 7) && (pix_y <= (V_VALID / 10) * 8 - 1'b1))
pix_data <= BLACK ;
else
if((pix_y >= (V_VALID / 10) * 8) && (pix_y <= (V_VALID / 10) * 9 - 1'b1))
pix_data <= WHITE ;
else
if((pix_y >= (V_VALID / 10) * 9) && (pix_y <= V_VALID - 1'b1) )
pix_data <= GRAY ;
else
pix_data <= BLACK ;
end
end
/****************新增代码*******************/
rom_pic rom_pic_insert(
.address ( address_w ),
.clock ( vga_clk ),
.rden ( rden_w ),
.q ( q )
);
// reg [13:0] address; // 在读使能信号拉高,每个时钟周期自加一,0 ~ 9999
always @(posedge vga_clk or negedge vga_rst_n) begin
if(~vga_rst_n) begin
address <= 0 ;
end else begin
if(rden == 1'b1) begin
if(address == 9999) begin
address <= 0 ;
end else begin
address <= address + 1'b1 ;
end
end else begin
address <= address ;
end
end
end
assign address_w = address ;
// reg rden; // 读使能信号超前图像数据一个时钟周期。..或者说rom读出的数据,滞后读使能信号一个时钟周期。这是输出端口没有加reg的情况。加了要滞后两个时钟周期。
always @(posedge vga_clk or negedge vga_rst_n) begin // 这其实也说明了,时序逻辑会滞后条件一个时钟周期。说明输出是reg型。
if(~vga_rst_n) begin
rden <= 1'b0 ;
end else begin
if((pix_y >= 190) && (pix_y <= 289) && (pix_x >= 267) && (pix_x <= 366)) begin
rden <= 1'b1 ;
end else begin
rden <= 1'b0 ;
end
end
end
assign rden_w = rden ;
endmodule