实验目标:
col(列) = 4 ;line(行) = 5。相邻三行,按列求和。输出新的数据流。
实现方法:
通过rs232通信协议,输入数据流。第一行存进fifo1,第二行存进fifo2.当输入第三行第一个数据的时候,从fifo1和ffo2中读数据,并于当前输入数据相加,并输出结果与标志信号。
设计中注意的事情:
1,这个fifo,读写信号同时拉高,我进行功能仿真时,它是写满后,同时拉高,写不进数据。我放一张仿真图:
所以我设计的时序图,fifo1和fifo2都是先读出数据,然后再写数据。
2,数据与标志信号在设计的时候,要注意时序上的对齐。这种小工程,仿真时,时序没问题没问题,上板子后出错,我觉得应该不是时序上的问题(亚稳态)。应该是代码的问题。
因为我在调用之前的uart_rs232模块,修改了参数,结果上板子出错了。就是这个uart模块的问题。苦恼了很久,一开始以为是fifo_sum的问题。我的写法和野火教程里是不完全一样的。
3,大于2的数字,尽量用参数parameter定义。在这方面,吃了大亏(uart模块又花了一个晚上重新写的)。
模块框图:
时序图:
代码:
module uart_rx(
input wire sys_clk ,
input wire sys_rst_n ,
input wire rx ,
output reg po_flag ,
output reg [7:0] po_data
);
// parameter
parameter CLK_UART = 50_000_000 ,
BPS = 9600 ;
localparam MAX_BPS = CLK_UART / BPS ;
// reg signal define
reg rx_reg1 ;
reg rx_reg2 ;
reg rx_reg3 ;
wire start ;
reg work_en ;
reg [12:0] cnt_bps ;
reg [ 3:0] cnt_bit ;
reg bit_flag;
reg [ 7:0] rx_data ; // 对rx_reg3采样,把串行数据转化为8bit并行数据。
reg rx_flag ; // 转化完拉高一个时钟周期。
/********************************************************/
// reg rx_reg1 ;
// reg rx_reg2 ;
// reg rx_reg3 ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
rx_reg1 <= 1'b1 ; // 由于空闲状态,rx是高电平。
rx_reg2 <= 1'b1 ;
rx_reg3 <= 1'b1 ;
end else begin
rx_reg1 <= rx ;
rx_reg2 <= rx_reg1 ;
rx_reg3 <= rx_reg2 ;
end
end
// reg start ; // 检测到下降沿,拉高一个sys_clk.
assign start = ~rx_reg2 && rx_reg3 ;
// reg work_en ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
work_en <= 1'b0 ;
else if((cnt_bit == 4'd0 && start) || (cnt_bit == 4'd8 && bit_flag)) // 正常来讲,这个两个条件应该是交替出现的。
work_en <= ~work_en ;
else
work_en <= work_en ;
end
// reg [12:0] cnt_bps ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_bps <= 13'd0 ;
else if(work_en && cnt_bps == (MAX_BPS - 1))
cnt_bps <= 13'd0 ;
else if(work_en)
cnt_bps <= cnt_bps + 1'b1 ;
else
cnt_bps <= 13'd0 ;
end
// reg bit_flag;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
bit_flag <= 1'b0 ;
else if(cnt_bps == MAX_BPS - 1) // 波特率计数器的最大值
bit_flag <= 1'b1 ;
else
bit_flag <= 1'b0 ;
end
// reg [ 3:0] cnt_bit ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_bit <= 4'd0 ;
else if(bit_flag && cnt_bit == 4'd8)
cnt_bit <= 4'd0 ;
else if(bit_flag)
cnt_bit <= cnt_bit + 1'b1 ;
else
cnt_bit <= cnt_bit ;
end
// reg [ 7:0] rx_data ; // 对rx_reg3采样,把串行数据转化为8bit并行数据。
// always @(posedge sys_clk or negedge sys_rst_n) begin
// if(~sys_rst_n)
// rx_data <= 8'd0 ;
// else if(work_en == 1'b1 && (cnt_bit >= 1) && (cnt_bps == MAX_BPS/2))
// rx_data <= {rx_reg3,rx_data[7:1]} ; // 由于rx是先发低位,所以rx_reg3放在前面.右移。
// else if(work_en == 1'b1 && (cnt_bit >= 1))
// rx_data <= rx_data ;
// else
// rx_data <= rx_data ;
// end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
rx_data <= 8'd0 ;
else if(work_en == 1'b1 && (cnt_bit >= 1)) begin
if(cnt_bps == MAX_BPS/2)
rx_data <= {rx_reg3,rx_data[7:1]} ;
else
rx_data <= rx_data ;
end else begin
rx_data <= rx_data ;
end
end
// reg rx_flag ; // 转化完拉高一个时钟周期。
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
rx_flag <= 1'b0 ;
else if(cnt_bit == 4'd8 && bit_flag)
rx_flag <= 1'b1 ;
else
rx_flag <= 1'b0 ;
end
/***********************************************************/
// output signal
// po_falg ,
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
po_flag <= 1'b0 ;
else if(rx_flag) // 可以理解为打一拍子或者使用时序逻辑采样
po_flag <= 1'b1 ;
else
po_flag <= 1'b0 ;
end
// po_data
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
po_data <= 8'd0 ;
else if(rx_flag) // 可以理解为打一拍子或者使用时序逻辑采样
po_data <= rx_data ;
else
po_data <= po_data ; // 可以归零,也可以保持。
end
endmodule
module uart_tx (
input wire sys_clk ,
input wire sys_rst_n ,
input wire pi_flag ,
input wire [7:0] pi_data ,
output reg tx
);
// parameter
parameter SUB_1K = 1000 , // 缩减第十位,空闲位的时间。
CLK_UART = 50_000_000 ,
BPS = 9600 ;
localparam MAX_BPS = CLK_UART / BPS ;
// reg signal define
reg pi_flag_reg1 ;
reg [ 7:0] pi_data_reg1 ;
reg work_en ;
reg [12:0] cnt_bps ;
reg [ 3:0] cnt_bit ;
reg bit_flag ;
/**********************************************/
// reg pi_flag_reg1 ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
pi_flag_reg1 <= 1'b0 ;
else
pi_flag_reg1 <= pi_flag ;
end
// reg pi_data_reg1 ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
pi_data_reg1 <= 8'd0 ;
else
pi_data_reg1 <= pi_data ;
end
// reg work_en ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
work_en <= 1'b0 ;
else if(((cnt_bit == 4'd0) && pi_flag_reg1) || (cnt_bit == 4'd9) && (bit_flag))
work_en <= ~work_en ;
else
work_en <= work_en ;
end
// reg [12:0] cnt_bps ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_bps <= 13'd0 ;
else if(work_en && cnt_bps == MAX_BPS - 1) // 波特率计数器计数到最大值。
cnt_bps <= 13'd0 ;
else if(work_en)
cnt_bps <= cnt_bps + 1'b1 ;
else
cnt_bps <= 13'd0 ;
end
// reg bit_flag ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
bit_flag <= 1'b0 ;
else if((work_en && cnt_bps == MAX_BPS - 1) || (work_en && cnt_bps == MAX_BPS - SUB_1K && cnt_bit == 9))
bit_flag <= 1'b1 ;
else
bit_flag <= 1'b0 ;
end
// reg [ 3:0] cnt_bit ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_bit <= 4'd0 ;
else if(work_en && bit_flag && cnt_bit == 4'd9) // 传递完第十位,位计数器要归零。
cnt_bit <= 4'd0 ;
else if(work_en && bit_flag)
cnt_bit <= cnt_bit + 1'b1 ;
else if(work_en)
cnt_bit <= cnt_bit ;
else
cnt_bit <= 4'd0 ;
end
/****************************************/
// output signal
// tx
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
tx <= 1'b1 ;
else if(work_en) begin
case (cnt_bit)
0 : tx <= 1'b0 ;
1 : tx <= pi_data_reg1[0] ; // 先发最低位。
2 : tx <= pi_data_reg1[1] ;
3 : tx <= pi_data_reg1[2] ;
4 : tx <= pi_data_reg1[3] ;
5 : tx <= pi_data_reg1[4] ;
6 : tx <= pi_data_reg1[5] ;
7 : tx <= pi_data_reg1[6] ;
8 : tx <= pi_data_reg1[7] ;
9 : tx <= 1'b1 ;
default: tx <= 1'b1 ;
endcase
end else begin
tx <= 1'b1 ;
end
end
endmodule
module fifo_sum(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [7:0] data_in ,
input wire data_flag ,
output reg [7:0] po_data ,
output reg po_data_falg
);
// parameter
parameter XLINE_SUM = 3 ,
MAX_LINE = 5 ,
MAX_COL = 4 ;
// reg signal define
reg [7:0] cnt_line ;
reg [7:0] cnt_col ;
reg rdreq_r ; // fifo1 fifo2 公用一个读使能。
reg wrreq1_r ;
reg [7:0] dataF1_in_r ;
reg wrreq2_r ;
reg [7:0] dataF2_in_r ;
reg [7:0] data_in_reg1;
reg [7:0] data_in_reg2;
reg flag_sum_r ;
// 例化连线
wire rdreq ;
wire [7:0] dataF1_in ;
wire wrreq1 ;
wire empty1 ;
wire full1 ;
wire [7:0] dataF1_out ;
wire [2:0] usedw1 ;
wire [7:0] dataF2_in ;
wire wrreq2 ;
wire empty2 ;
wire full2 ;
wire [7:0] dataF2_out ;
wire [2:0] usedw2 ;
/*************************************************************/
// reg [7:0] cnt_line
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_line <= 8'd0 ;
else if(data_flag && cnt_col == MAX_COL - 1 && cnt_line == MAX_LINE - 1)
cnt_line <= 8'd0 ;
else if(data_flag && cnt_col == MAX_COL - 1)
cnt_line <= cnt_line + 1'b1 ;
else
cnt_line <= cnt_line ;
end
// reg [7:0] cnt_col
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_col <= 8'd0 ;
else if(data_flag && cnt_col == MAX_COL - 1)
cnt_col <= 8'd0 ;
else if(data_flag)
cnt_col <= cnt_col + 1'b1 ;
else
cnt_col <= cnt_col ;
end
// reg rdreq_r ; // fifo1 fifo2 公用一个读使能。
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
rdreq_r <= 1'b0 ;
else if(cnt_line >= XLINE_SUM - 1)
rdreq_r <= data_flag ;
else
rdreq_r <= 1'b0 ;
end
// reg wrreq1_r ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
wrreq1_r <= 1'b0 ;
else if(cnt_line == 0)
wrreq1_r <= data_flag ;
else if((cnt_line == (XLINE_SUM - 1) && cnt_col != 0) || (cnt_line > (XLINE_SUM - 1) && cnt_line <= (MAX_LINE - 2)) || (cnt_line == (MAX_LINE - 1) && cnt_col == 0))
wrreq1_r <= wrreq2_r ;
else
wrreq1_r <= 1'b0 ;
end
// reg [7:0] dataF1_in_r ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
dataF1_in_r <= 8'd0 ;
else if(cnt_line == 0)
dataF1_in_r <= data_in ;
else if((cnt_line >= (XLINE_SUM - 1) && cnt_line <= (MAX_LINE - 2)) || (cnt_line == (MAX_LINE - 1) && cnt_col == 0))
dataF1_in_r <= dataF2_out ;
else
dataF1_in_r <= dataF1_in_r ;
end
// reg wrreq2_r ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
wrreq2_r <= 1'b0 ;
else if(cnt_line == 1)
wrreq2_r <= data_flag ;
else if((cnt_line >= (XLINE_SUM - 1) && cnt_line <= (MAX_LINE - 2)) || (cnt_line == (MAX_LINE - 1) && cnt_col == 0))
wrreq2_r <= rdreq_r ;
end
// reg [7:0] dataF2_in_r ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
dataF2_in_r <= 8'd0 ;
else if(cnt_line == 1)
dataF2_in_r <= data_in ;
else if((cnt_line >= (XLINE_SUM - 1) && cnt_line <= (MAX_LINE - 2)) || (cnt_line == (MAX_LINE - 1) && cnt_col == 0))
dataF2_in_r <= data_in_reg1 ;
else
dataF2_in_r <= dataF2_in_r ;
end
// reg flag_sum_r ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
flag_sum_r <= 1'b0 ;
else
flag_sum_r <= rdreq_r ;
end
/**********************************************************/
// reg [7:0] po_data ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
po_data <= 8'd0 ;
else if(flag_sum_r)
po_data <= dataF1_out + dataF2_out + data_in_reg2 ;
else
po_data <= po_data ;
end
// reg po_data_falg ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
po_data_falg <= 1'b0 ;
else if(flag_sum_r)
po_data_falg <=1'b1 ;
else
po_data_falg <= 1'b0 ;
end
// reg [7:0] data_in_reg1;
// reg [7:0] data_in_reg2;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
data_in_reg1 <= 8'd0 ;
data_in_reg2 <= 8'd0 ;
end else begin
data_in_reg1 <= data_in ;
data_in_reg2 <= data_in_reg1 ;
end
end
/*************************************************************/
assign dataF1_in = dataF1_in_r ;
assign wrreq1 = wrreq1_r ;
assign rdreq = rdreq_r ;
assign dataF2_in = dataF2_in_r ;
assign wrreq2 = wrreq2_r ;
fifo_8x8 fifo_8x8_inst1( // 我测试了一下这个fifo 写满了之后读写信号同时拉高,要写的数据不会被写进去。除非有余量才能同时拉高,并且写入数据。
.clock ( sys_clk ) ,
.data ( dataF1_in ) ,
.rdreq ( rdreq ) ,
.wrreq ( wrreq1 ) ,
.empty ( empty1 ) ,
.full ( full1 ) ,
.q ( dataF1_out ) ,
.usedw ( usedw1 )
);
fifo_8x8 fifo_8x8_inst2(
.clock ( sys_clk ) ,
.data ( dataF2_in ) ,
.rdreq ( rdreq ) ,
.wrreq ( wrreq2 ) ,
.empty ( empty2 ) ,
.full ( full2 ) ,
.q ( dataF2_out ) ,
.usedw ( usedw2 )
);
endmodule
module top(
input wire sys_clk ,
input wire sys_rst_n ,
input wire rx ,
output wire tx
);
// 例化间连线
wire po_flag ;
wire [7:0] po_data ;
wire sum_flag ;
wire [7:0] sum_data ;
uart_rx uart_rx_inst(
.sys_clk ( sys_clk ) ,
.sys_rst_n ( sys_rst_n ) ,
.rx ( rx ) ,
.po_flag ( po_flag ) ,
.po_data ( po_data )
);
fifo_sum fifo_sum_inst(
.sys_clk ( sys_clk ) ,
.sys_rst_n ( sys_rst_n ) ,
.data_in ( po_data ) ,
.data_flag ( po_flag ) ,
.po_data ( sum_data ) ,
.po_data_falg ( sum_flag )
);
uart_tx uart_tx_inst(
.sys_clk ( sys_clk ) ,
.sys_rst_n ( sys_rst_n ) ,
.pi_flag ( sum_flag ) ,
.pi_data ( sum_data ) ,
.tx ( tx )
);
endmodule
`timescale 1ns/1ns
module test_top();
reg sys_clk ;
reg sys_rst_n ;
reg rx ;
wire tx ;
// Instantiation
top top_inst(
.sys_clk ( sys_clk ) ,
.sys_rst_n ( sys_rst_n ) ,
.rx ( rx ) ,
.tx ( tx )
);
parameter CYCLE = 20 ;
defparam top_inst.uart_rx_inst.CLK_UART = 50_000_0 ;
defparam top_inst.uart_tx_inst.CLK_UART = 50_000_0 ;
defparam top_inst.uart_tx_inst.SUB_1K = 10 ;
task rx_bit ;
input [7:0] data ;
integer i ;
for (i = 0;i <= 9 ;i = i + 1 ) begin
case (i)
0: rx <= 1'b0 ;
1: rx <= data[i - 1];
2: rx <= data[i - 1];
3: rx <= data[i - 1];
4: rx <= data[i - 1];
5: rx <= data[i - 1];
6: rx <= data[i - 1];
7: rx <= data[i - 1];
8: rx <= data[i - 1];
9: rx <= 1'b1 ;
default: rx <= 1'b1 ;
endcase
#(CYCLE * 52) ;
end
endtask
initial begin
sys_clk = 1'b1 ;
sys_rst_n <= 1'b0 ;
rx <= 1'b1 ;
#( CYCLE * 10 ) ;
sys_rst_n <= 1'b1 ;
#( 210 ) ;
sys_rst_n <= 1'b0 ;
#( 10 ) ;
#( CYCLE * 10 ) ;
sys_rst_n <= 1'b1 ;
#( CYCLE * 100 ) ;
rx_bit(8'd1) ;
rx_bit(8'd1) ;
rx_bit(8'd2) ;
rx_bit(8'd2) ;
rx_bit(8'd3) ;
rx_bit(8'd3) ;
rx_bit(8'd4) ;
rx_bit(8'd4) ;
rx_bit(8'd5) ;
rx_bit(8'd5) ;
rx_bit(8'd6) ;
rx_bit(8'd6) ;
rx_bit(8'd7) ;
rx_bit(8'd7) ;
rx_bit(8'd8) ;
rx_bit(8'd8) ;
rx_bit(8'd9) ;
rx_bit(8'd9) ;
rx_bit(8'd1) ;
rx_bit(8'd1) ;
rx_bit(8'd1) ;
rx_bit(8'd1) ;
rx_bit(8'd1) ;
rx_bit(8'd1) ;
rx_bit(8'd2) ;
rx_bit(8'd2) ;
rx_bit(8'd2) ;
rx_bit(8'd2) ;
rx_bit(8'd1) ;
rx_bit(8'd1) ;
rx_bit(8'd1) ;
rx_bit(8'd1) ;
rx_bit(8'd3) ;
rx_bit(8'd3) ;
rx_bit(8'd3) ;
rx_bit(8'd3) ;
rx_bit(8'd3) ;
rx_bit(8'd3) ;
rx_bit(8'd3) ;
rx_bit(8'd3) ;
$stop ;
end
always #( CYCLE / 2 ) sys_clk = ~sys_clk ;
endmodule
仿真波形:
忘记截图了。