在之前彩条显示工程中增添一个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