2013-02-16 193 views
1

我有一个用Verilog编写的程序,我想自动将它转换成FSM。这是可能的(只是想象它)?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; 
    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 

如果没有自动的方式,你能解释这样做的呢?

这是手工制作的FSM,但无法测试等等......

fsm

它看起来好吗?

+1

我不明白你在问什么。你有什么是用Verilog编写的FSM。你是什​​么意思“将其转换为FSM”?你的意思是特定于某个特定的模拟器,或者你期望什么样的输出? – Tim 2013-02-16 19:00:26

+0

我的意思是我如何可视化它像我刚刚添加的图像自动。 – zaabalonso 2013-02-16 19:02:37

回答

2

有时写代码会更容易并从中产生文档。有时你会在没有文档的情况下继承遗留代码,在这种情况下尤其如果新增了语言工具来帮助可视化发生的事情会非常有用。

与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中,选择simple_fsm

$ irun simple_fsm.sv -coverage all -covdut simple_fsm 
$ imc & 

负载cov_work(由上述模拟创建的文件夹),然后选择FSM分析。

simple_fsm visualisation

IMC也有助于可视化你的测试覆盖率为好。未被击中的弧线和状态以红色显示。

我们已经看到有一些工具可以将FSM可视化,问题的另一部分是;是适用于这些工具的目的FSM的语法。

@vermaete报告说Modelsim SE无法看到FSM。从IMC我得到:

OPs FSM from Question

似乎没有哪个覆盖代码的复杂性,并显示为仅具有2个可到达的状态,IDLE和BUSY。我会建议如果OP正在使用工具进行可视化的路线,采用更简单的(语法)FSM结构,以便工具可以更好地解析它。

+0

你可以与问题的FSM分享图吗? Modelsim SE未检测到FSM。 – vermaete 2013-02-19 08:50:26

3

更好和更昂贵的模拟器可以检测代码中的FSM并对其进行可视化。例如。 Modelsim SE版本。这些可以很好地理解代码并检查相关的代码。但是让你自己绘制6态FSM并不困难。

+0

我添加了手工制作的fsm,但无法测试以检查是否可以。 – zaabalonso 2013-02-16 18:56:58

+0

你使用哪个模拟器?它有'代码覆盖率'吗?如果是这样,你可以建立一个应该触发所有状态的测试台,并在模拟之后检查它是否已经完成。如果没有相当ASIC级别的工具,那么你就无法做其他事情。 – vermaete 2013-02-16 19:10:17

+0

那么,你也可以写一些断言来检查你的模拟是否按照你所在的顺序通过了所有的状态。当编码和测试的重点从FSM偏离时,这可能有助于更大的设计。如果在FSM中出现问题,一条消息将使调试变得不那么痛苦。 – vermaete 2013-02-16 19:13:06

1

检查是否正常的方法是编写一个模拟并检查行为是否是您想要的。没有必要得到一个气泡图,看看它是否与你的手绘图匹配,因为你无法知道你的手绘图是否正确......

1
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

你可以更好地格式化一下吗? – slfan 2015-03-03 22:39:17