fpga项目:初始化序列的verilog实现方法 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
目的
- 逐条解析并执行指令,通过spi/i2c等接口执行指令。
- 其中包括delay指令,通过cnt实现。由cnt_start/cnt_end来交互
- spi/i2c通过xfer_start/xfer_end来交互
时序顺序构想为:
第1次(普通指令):cnt_start->cnt_end->state=1, rom_inex++->data->xfer_start->xfer_end
第2次(普通指令):xfer_end->rom_inex++->data->xfer_start->xfer_end
第n次(执行延时指令):xfer_end->rom_index++->data->cnt_start->state=2->cnt_end
第n+1次(延时指令结束):cnt_end->rom_inex++->data->xfer_start->xfer_end
第n+2次(普通指令):xfer_end->rom_inex++->data->xfer_start->xfer_end
最后一次(普通指令):xfer_end->rom_index++->state=0, data->xfer_start->xfer_end
线性序列机时序图
每一轮传输的发起,可能是xfer_end,也可能是cnt_end
实现时序波形图
代码
module tb3;
reg clk, rst_n;
initial clk=0;
always #10 clk=~clk;
initial begin
rst_n=0;
#1000;
rst_n=1;
end
//1)
parameter DLY_CNT_MAX=100;
parameter ARG_NMAX=12;
reg [15:0] dly_cnt;
//2)
reg [2:0] state;
always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
state<=0;
dly_cnt<=0;
end
else case(state)
0: if(dly_cnt==DLY_CNT_MAX-1) begin
dly_cnt<=0;
state<=1;
end
else if(rom_index<ARG_NMAX-1)
dly_cnt<=dly_cnt+1;
1: if(rom_index==ARG_NMAX-1)
state<=0;
else if(cnt_start)
state<=2;
else
state<=1;
2: if(rom_index==ARG_NMAX-1)
state<=0;
else if(dly_cnt==length-1) begin
dly_cnt<=0;
state<=1;
end
else
dly_cnt<=dly_cnt+1;
default: state<=0;
endcase
//3)
reg [7:0] rom_index;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
rom_index<=8'h00;
else if((dly_cnt==DLY_CNT_MAX-1 && state==0)
|| (dly_cnt==length-1 && state==2)
|| xfer_end && state==1)
rom_index<=rom_index+1;
//else if(rom_index==ARG_NMAX-1)
// rom_index<=8'h00;
reg [31:0] rom_data;
reg [7:0] cmd;
reg [7:0] length;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
rom_data<=32'h00;
else
case(rom_index)
1: rom_data <=32'h12345678;
2: rom_data <=32'h23456789;
3: rom_data <=32'h3456789a;
4: rom_data <=32'h456789ab;
5: rom_data <=32'hffabcdef;
6: rom_data <=32'h56789abc;
7: rom_data <=32'h6789abcd;
8: rom_data <=32'h789abcde;
9: rom_data <=32'h89abcdef;
10: rom_data <=32'hffabcdef;
11: rom_data <=32'h89abcdef;
default: rom_data<=32'h00;
endcase
assign cmd=rom_data[31:24];
assign length=rom_data[23:16];
//4)
reg [7:0] cmd_s;
wire xfer_start;
reg xfer_end;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
cmd_s<=8'h00;
else
cmd_s<=cmd;
assign xfer_start= (cmd!=cmd_s) && (cmd!=8'hff);
assign cnt_start= (cmd!=cmd_s) && (cmd==8'hff);
initial begin
xfer_end=0;
repeat(ARG_NMAX) begin
// while(rom_index<=ARG_NMAX-1) begin
wait(xfer_start==1);
#200;
@(posedge clk) #1 xfer_end=1;
@(posedge clk) #1 xfer_end=0;
end
end
endmodule
波形分析
整体
第一次传输
第一次执行dly
第一次dly结束
最后一次命令执行
代码修改(将计数器独立出来)
虽然将计数器独立出来,代码会更长一点。但实际上,更容易维护,在思路上更清晰。因为我们在设计的时候,往往是先设计状态机。通过先假设几个交互信号(cnt_start/cnt_end, xfer_start/xfer_end),先状态机代码确定下来。然后再去实现计数器,和这些交互信号。这种思路是,先整体,再局部。
module tb4;
reg clk, rst_n;
initial clk=0;
always #10 clk=~clk;
initial begin
rst_n=0;
#1000;
rst_n=1;
end
//1)
parameter DLY_CNT_MAX=100;
parameter ARG_NMAX=13;
reg [15:0] dly_cnt;
always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
dly_cnt<=0;
end
else case(state)
0: if(cnt_end)
dly_cnt<=0;
else if(rom_index<ARG_NMAX-1)
dly_cnt<=dly_cnt+1;
2: if(cnt_end)
dly_cnt<=0;
else
dly_cnt<=dly_cnt+1;
default: dly_cnt<=0;
endcase
assign cnt_end=(state==0 && dly_cnt==DLY_CNT_MAX-1) || (state==2 && dly_cnt==length-1);
//2)
reg [2:0] state;
always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
state<=0;
end
else case(state)
0: if(cnt_end)
state<=1;
1: if(rom_index==ARG_NMAX-1)
state<=0;
else if(cnt_start)
state<=2;
2: if(rom_index==ARG_NMAX-1)
state<=0;
else if(cnt_end)
state<=1;
default: state<=0;
endcase
//3)
reg [7:0] rom_index;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
rom_index<=8'h00;
else if(cnt_end|| xfer_end)
rom_index<=rom_index+1;
//4)
reg [31:0] rom_data;
reg [7:0] cmd;
reg [7:0] length;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
rom_data<=32'h00;
else
case(rom_index)
1: rom_data <=32'h12345678;
2: rom_data <=32'h23456789;
3: rom_data <=32'h3456789a;
4: rom_data <=32'h456789ab;
5: rom_data <=32'hffabcdef;
6: rom_data <=32'h56789abc;
7: rom_data <=32'h6789abcd;
8: rom_data <=32'h789abcde;
9: rom_data <=32'h89abcdef;
10: rom_data <=32'hffabcdef;
11: rom_data <=32'h89abcdef;
12: rom_data <=32'hffabcdef;
default: rom_data<=32'h00;
endcase
assign cmd=rom_data[31:24];
assign length=rom_data[23:16];
//5)
reg [7:0] cmd_s;
wire xfer_start;
reg xfer_end;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
cmd_s<=8'h00;
else
cmd_s<=cmd;
assign xfer_start= (cmd!=cmd_s) && (cmd!=8'hff);
assign cnt_start= (cmd!=cmd_s) && (cmd==8'hff);
//6)
initial begin
xfer_end=0;
repeat(ARG_NMAX) begin
// while(rom_index<=ARG_NMAX-1) begin
wait(xfer_start==1);
#200;
@(posedge clk) #1 xfer_end=1;
@(posedge clk) #1 xfer_end=0;
end
end
endmodule
代码修改(将rom单独拎出来)
module tb4;
reg clk, rst_n;
initial clk=0;
always #10 clk=~clk;
initial begin
rst_n=0;
#1000;
rst_n=1;
end
//1)
parameter DLY_CNT_MAX=100;
parameter ARG_NMAX=13;
reg [15:0] dly_cnt;
always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
dly_cnt<=0;
end
else case(state)
0: if(cnt_end)
dly_cnt<=0;
else if(rom_index<ARG_NMAX-1)
dly_cnt<=dly_cnt+1;
2: if(cnt_end)
dly_cnt<=0;
else
dly_cnt<=dly_cnt+1;
default: dly_cnt<=0;
endcase
assign cnt_end=(state==0 && dly_cnt==DLY_CNT_MAX-1) || (state==2 && dly_cnt==length-1);
//2)
reg [2:0] state;
always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
state<=0;
end
else case(state)
0: if(cnt_end)
state<=1;
1: if(rom_index==ARG_NMAX-1)
state<=0;
else if(cnt_start)
state<=2;
2: if(rom_index==ARG_NMAX-1)
state<=0;
else if(cnt_end)
state<=1;
default: state<=0;
endcase
//3)
reg [7:0] rom_index;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
rom_index<=8'h00;
else if(cnt_end|| xfer_end)
rom_index<=rom_index+1;
//4)
reg [0: 32*(ARG_NMAX-1)-1] rom={
32'h12345678,
32'h23456789,
32'h3456789a,
32'h456789ab,
32'hffabcdef,
32'h56789abc,
32'h6789abcd,
32'h789abcde,
32'h89abcdef,
32'hffabcdef,
32'h89abcdef,
32'hffabcdef
};
reg [31:0] rom_data;
reg [7:0] cmd;
reg [7:0] length;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
rom_data<=32'h00;
else if(rom_index>=1 && rom_index<ARG_NMAX)
rom_data<=rom[32*(rom_index-1) +:32];
assign cmd=rom_data[31:24];
assign length=rom_data[23:16];
//5)
reg [7:0] cmd_s;
wire xfer_start;
reg xfer_end;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
cmd_s<=8'h00;
else
cmd_s<=cmd;
assign xfer_start= (cmd!=cmd_s) && (cmd!=8'hff);
assign cnt_start= (cmd!=cmd_s) && (cmd==8'hff);
//6)
initial begin
xfer_end=0;
repeat(ARG_NMAX) begin
// while(rom_index<=ARG_NMAX-1) begin
wait(xfer_start==1);
#200;
@(posedge clk) #1 xfer_end=1;
@(posedge clk) #1 xfer_end=0;
end
end
endmodule