verilog到FSM转换
我有一个用Verilog写的程序,我想把它自动转换成FSM。这是可能的(只是为了形象化) 代码如下:verilog到FSM转换,verilog,fsm,system-verilog,Verilog,Fsm,System Verilog,我有一个用Verilog写的程序,我想把它自动转换成FSM。这是可能的(只是为了形象化) 代码如下: module pci(reset,clk,frame,irdy,trdy,devsel,idsel,ad,cbe,par,stop,inta,led_out); input reset; input clk; input frame; input irdy; output trdy; output devsel; input idsel;
module pci(reset,clk,frame,irdy,trdy,devsel,idsel,ad,cbe,par,stop,inta,led_out);
input reset;
input clk;
input frame;
input irdy;
output trdy;
output devsel;
input idsel;
inout [31:0] ad;
input [3:0] cbe;
inout par;
output stop;
output inta;
output [3:0] led_out;
parameter DEVICE_ID = 16'h9500;
parameter VENDOR_ID = 16'h106d; // Sequent!
parameter DEVICE_CLASS = 24'hFF0000; // Misc
parameter DEVICE_REV = 8'h01;
parameter SUBSYSTEM_ID = 16'h0001; // Card identifier
parameter SUBSYSTEM_VENDOR_ID = 16'hBEBE; // Card identifier
parameter DEVSEL_TIMING = 2'b00; // Fast!
reg [2:0] state;
reg [31:0] data;
reg [1:0] enable;
parameter EN_NONE = 0;
parameter EN_RD = 1;
parameter EN_WR = 2;
parameter EN_TR = 3;
reg memen; // respond to baseaddr?
reg [7:0] baseaddr;
reg [5:0] address;
parameter ST_IDLE = 3'b000;
parameter ST_BUSY = 3'b010;
parameter ST_MEMREAD = 3'b100;
parameter ST_MEMWRITE = 3'b101;
parameter ST_CFGREAD = 3'b110;
parameter ST_CFGWRITE = 3'b111;
parameter MEMREAD = 4'b0110;
parameter MEMWRITE = 4'b0111;
parameter CFGREAD = 4'b1010;
parameter CFGWRITE = 4'b1011;
`define LED
`ifdef LED
reg [3:0] led;
`endif
`undef STATE_DEBUG_LED
`ifdef STATE_DEBUG_LED
assign led_out = ~state;
`else
`ifdef LED
assign led_out = ~led; // board is wired for active low LEDs
`endif
`endif
assign ad = (enable == EN_RD) ? data : 32'bZ;
assign trdy = (enable == EN_NONE) ? 'bZ : (enable == EN_TR ? 1 : 0);
assign par = (enable == EN_RD) ? 0 : 'bZ;
reg devsel;
assign stop = 1'bZ;
assign inta = 1'bZ;
wire cfg_hit = ((cbe == CFGREAD || cbe == CFGWRITE) && idsel && ad[1:0] == 2'b00);
wire addr_hit = ((cbe == MEMREAD || cbe == MEMWRITE) && memen && ad[31:12] == {12'b0, baseaddr});
wire hit = cfg_hit | addr_hit;
always @(posedge clk)
begin
if (~reset) begin
state <= ST_IDLE;
enable <= EN_NONE;
baseaddr <= 0;
devsel <= 'bZ;
memen <= 0;
`ifdef LED
led <= 0;
`endif
end
else begin
case (state)
ST_IDLE: begin
enable <= EN_NONE;
devsel <= 'bZ;
if (~frame) begin
address <= ad[7:2];
if (hit) begin
state <= {1'b1, cbe[3], cbe[0]};
devsel <= 0;
// pipeline the write enable
if (cbe[0])
enable <= EN_WR;
end
else begin
state <= ST_BUSY;
enable <= EN_NONE;
end
end
end
ST_BUSY: begin
devsel <= 'bZ;
enable <= EN_NONE;
if (frame)
state <= ST_IDLE;
end
ST_CFGREAD: begin
enable <= EN_RD;
if (~irdy || trdy) begin
case (address)
0: data <= { DEVICE_ID, VENDOR_ID };
1: data <= { 5'b0, DEVSEL_TIMING, 9'b0, 14'b0, memen, 1'b0};
2: data <= { DEVICE_CLASS, DEVICE_REV };
4: data <= { 12'b0, baseaddr, 8'b0, 4'b0010 }; // baseaddr + request mem < 1Mbyte
11: data <= {SUBSYSTEM_ID, SUBSYSTEM_VENDOR_ID };
16: data <= { 24'b0, baseaddr };
default: data <= 'h00000000;
endcase
address <= address + 1;
end
if (frame && ~irdy && ~trdy) begin
devsel <= 1;
state <= ST_IDLE;
enable <= EN_TR;
end
end
ST_CFGWRITE: begin
enable <= EN_WR;
if (~irdy) begin
case (address)
4: baseaddr <= ad[19:12]; // XXX examine cbe
1: memen <= ad[1];
default: ;
endcase
address <= address + 1;
if (frame) begin
devsel <= 1;
state <= ST_IDLE;
enable <= EN_TR;
end
end
end
ST_MEMREAD: begin
enable <= EN_RD;
if (~irdy || trdy) begin
case (address)
`ifdef LED
0: data <= { 28'b0, led };
`endif
default: data <= 'h00000000;
endcase
address <= address + 1;
end
if (frame && ~irdy && ~trdy) begin
devsel <= 1;
state <= ST_IDLE;
enable <= EN_TR;
end
end
ST_MEMWRITE: begin
enable <= EN_WR;
if (~irdy) begin
case (address)
`ifdef LED
0: led <= ad[3:0];
`endif
default: ;
endcase
address <= address + 1;
if (frame) begin
devsel <= 1;
state <= ST_IDLE;
enable <= EN_TR;
end
end
end
endcase
end
end
endmodule
<代码>模块PCI(复位、CLK、帧、IrDy、TrDy、DEVEL、IDSEL、AD、CBE、PAR、STEP、ITA、LeDIOUT);
输入复位;
输入时钟;
输入帧;
输入irdy;
输出trdy;
输出devsel;
输入idsel;
伊努特[31:0]公元;
输入[3:0]cbe;
不合格;
输出停止;
输出inta;
输出[3:0]发光二极管输出;
参数装置ID=16'h9500;
参数VENDOR_ID=16'h106d;//接着!
参数设备_类=24'hFF0000;//杂项
参数装置_REV=8'h01;
参数子系统_ID=16'h0001;//卡片标识符
参数子系统供应商ID=16'hBEBE;//卡片标识符
参数DEVSEL_计时=2'b00;//快速的
reg[2:0]状态;
reg[31:0]数据;
reg[1:0]启用;
参数EN_NONE=0;
参数EN_RD=1;
参数EN_WR=2;
参数EN_TR=3;
注册会员;//回应baseaddr?
reg[7:0]baseaddr;
注册[5:0]地址;
参数ST_IDLE=3'b000;
参数ST_BUSY=3'b010;
参数ST_MEMREAD=3'b100;
参数ST_MEMWRITE=3'b101;
参数ST_CFGREAD=3'b110;
参数ST_CFGWRITE=3'b111;
参数MEMREAD=4'b0110;
参数MEMWRITE=4'b0111;
参数CFGREAD=4'b1010;
参数CFGWRITE=4'b1011;
`定义LED
`ifdef发光二极管
reg[3:0]发光二极管;
`恩迪夫
`未定义状态\u调试\u指示灯
`ifdef状态调试指示灯
分配led_out=~状态;
`否则
`ifdef发光二极管
分配led_out=~led;//电路板接线用于有源低电平LED
`恩迪夫
`恩迪夫
分配ad=(启用==EN\u RD)?数据:32'bZ;
分配trdy=(启用==无)?'bZ:(使能==EN_TR?1:0);
分配PAR =(启用= = EnRyd)?0:bZ;
reg devsel;
指定停止=1'bZ;
分配inta=1'bZ;
导线cfg|u hit=((cbe==CFGREAD | | cbe==CFGWRITE)和&idsel&ad[1:0]==2'b00);
wire addr|u hit=((cbe==MEMREAD | | cbe==MEMWRITE)&&memen&&ad[31:12]==12'b0,baseaddr});
线击=cfg|u hit | addr|u hit;
始终@(posedge clk)
开始
如果(~reset)开始
状态更好、更昂贵的模拟器可以检测代码中的FSM并使其可视化。例如,Modelsim SE版本。这些可以很好地理解代码并检查Covage。
但是,制作自己的6态FSM并不难。更好、更昂贵的模拟器可以检测代码中的FSM,并将其可视化。例如,Modelsim SE版本。这些可以很好地理解代码并检查Covage。
但是,自己绘制一个6态FSM并不难。检查是否可以的方法是编写一个模拟,并检查行为是否符合您的要求。拿出一张气泡图,看看它是否与手绘图相符是没有意义的,因为你无法知道手绘图是否正确……检查是否正确的方法是编写一个模拟,并检查行为是否符合你的要求。拿出一个气泡图并查看它是否与手绘图匹配是没有意义的,因为您无法知道手绘图是否正确……有时编写代码并由此生成文档更容易。有时您在没有文档的情况下继承遗留代码,在这些情况下,尤其是对于语言新手来说,帮助可视化正在发生的事情的工具可能非常有用 使用cadence工具,您可以使用“代码覆盖率”运行代码,然后imc可以加载覆盖率数据并运行FSM分析 我在下面包含了一个简单的FSM,并显示了生成的状态图
module simple_fsm();
//Inputs to FSM
logic clk;
logic rst_n;
logic [1:0] state ;
logic [1:0] nextstate;
logic turn_on ;
logic turn_off ;
localparam S_OFF = 2'b00;
localparam S_GO_ON = 2'b01;
localparam S_ON = 2'b10;
localparam S_GO_OFF = 2'b11;
// State FlipFlop
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
state <= 2'b0;
end
else begin
state <= nextstate;
end
end
//Nextstate Logic
always @* begin
case (state)
2'd0 : if (turn_on) begin
nextstate = S_GO_ON;
end
2'd1 : nextstate = S_ON;
2'd2 : if (turn_off) begin
nextstate = S_GO_OFF ;
end
2'd3 : nextstate = S_OFF;
endcase
end
//TB clk
initial begin
#1ns;
clk = 0;
forever begin
#20ns;
clk = ~clk;
end
end
//The Test
initial begin
rst_n = 1'b0;
turn_on = 1'b0;
turn_off = 1'b0;
@(posedge clk);
@(posedge clk);
rst_n = 1'b1 ;
@(posedge clk);
turn_on = 1'b1;
@(posedge clk);
turn_on = 1'b0;
@(posedge clk);
@(posedge clk);
#100ms;
$finish();
end
endmodule
在imc中加载cov_工作(通过上述模拟创建的文件夹),选择simple_fsm并选择fsm Analysis
imc也有助于可视化您的测试覆盖率。未命中的弧和状态显示为红色
我们已经看到,有一些工具可以可视化FSM,问题的另一部分是;专用FSM的语法是否适用于这些工具
@vermaete报告说Modelsim SE无法看到FSM。从imc我得到:
它似乎没有覆盖代码的复杂性,并且显示为只有两个可到达的状态,空闲和忙碌。如果OP正在使用工具进行可视化,我建议您采用更简单的(语法)FSM结构,以便工具能够更好地解析它。有时编写代码和生成文档会更容易。有时您在没有文档的情况下继承遗留代码,在这些情况下,尤其是对于语言新手来说,帮助可视化正在发生的事情的工具可能非常有用
case(segmentRead)
//-------------------
SEGMENT0: begin
READ_Ready_EEPROM <= 1'b0;
READ_RDSR_Enable <= 1'b0;
Read_Enable <= 1'b0;
READ_RDSR_DATA_REG <= 8'b0;
// READ_DATA_REG <= 8'b0;
end
//-------------------
SEGMENT2: begin
READ_RDSR_Enable <= 1'b1;
READ_RDSR_DATA_REG <= 8'b0;
end
// //-------------------
SEGMENT3: begin
READ_RDSR_Enable <= 1'b0;
READ_RDSR_DATA_REG <= RDSR_Data;
end
//-------------------
SEGMENT4: begin
Read_Enable <= 1'b1;
end
//-------------------
SEGMENT5: begin
Read_Enable <= 1'b0;
READ_DATA_REG <= Read_Data;
end
//-------------------
SEGMENT6: begin
READ_Ready_EEPROM <= 1'b1;
end
//-------------------
endcase
使用cadence工具,您可以使用“代码覆盖率”运行代码,然后imc可以加载覆盖率数据并运行FSM分析
我在下面包含了一个简单的FSM,并显示了生成的状态图
module simple_fsm();
//Inputs to FSM
logic clk;
logic rst_n;
logic [1:0] state ;
logic [1:0] nextstate;
logic turn_on ;
logic turn_off ;
localparam S_OFF = 2'b00;
localparam S_GO_ON = 2'b01;
localparam S_ON = 2'b10;
localparam S_GO_OFF = 2'b11;
// State FlipFlop
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
state <= 2'b0;
end
else begin
state <= nextstate;
end
end
//Nextstate Logic
always @* begin
case (state)
2'd0 : if (turn_on) begin
nextstate = S_GO_ON;
end
2'd1 : nextstate = S_ON;
2'd2 : if (turn_off) begin
nextstate = S_GO_OFF ;
end
2'd3 : nextstate = S_OFF;
endcase
end
//TB clk
initial begin
#1ns;
clk = 0;
forever begin
#20ns;
clk = ~clk;
end
end
//The Test
initial begin
rst_n = 1'b0;
turn_on = 1'b0;
turn_off = 1'b0;
@(posedge clk);
@(posedge clk);
rst_n = 1'b1 ;
@(posedge clk);
turn_on = 1'b1;
@(posedge clk);
turn_on = 1'b0;
@(posedge clk);
@(posedge clk);
#100ms;
$finish();
end
endmodule
在imc中加载cov_工作(通过上述模拟创建的文件夹),选择simple_fsm并选择fsm Analysis
imc也有助于可视化您的测试覆盖率。未命中的弧和状态显示为红色
我们已经看到,有一些工具可以可视化FSM,问题的另一部分是;专用FSM的语法是否适用于这些工具
@vermaete报告说Modelsim SE无法看到FSM。从imc我得到:
它似乎没有覆盖代码的复杂性,并且显示为只有两个可到达的状态,空闲和忙碌。如果OP正在使用工具进行可视化,我建议采用更简单的(语法)FSM结构,以便工具能够更好地解析它。case(segmentRead)
case(segmentRead)
//-------------------
SEGMENT0: begin
READ_Ready_EEPROM <= 1'b0;
READ_RDSR_Enable <= 1'b0;
Read_Enable <= 1'b0;
READ_RDSR_DATA_REG <= 8'b0;
// READ_DATA_REG <= 8'b0;
end
//-------------------
SEGMENT2: begin
READ_RDSR_Enable <= 1'b1;
READ_RDSR_DATA_REG <= 8'b0;
end
// //-------------------
SEGMENT3: begin
READ_RDSR_Enable <= 1'b0;
READ_RDSR_DATA_REG <= RDSR_Data;
end
//-------------------
SEGMENT4: begin
Read_Enable <= 1'b1;
end
//-------------------
SEGMENT5: begin
Read_Enable <= 1'b0;
READ_DATA_REG <= Read_Data;
end
//-------------------
SEGMENT6: begin
READ_Ready_EEPROM <= 1'b1;
end
//-------------------
endcase
//-------------------
第0部分:开始
READ_Ready_EEPROMcase(分段读取)
//-------------------
第0部分:开始
READ_Ready_EEPROM我添加了一个手工制作的fsm,但无法测试是否正常。您使用哪个模拟器?做