systemVerilogサンプル・その3

structを使ってみる。

verilog-95を使っていて。。VHDL羨ましいな~~と指をくわえていたところが1点だけ有った。
VHDLはユーザー定義のデータ型を使用できて合成も出来る。→VHDLにしとけばと思っていたね。。
 →SPARC LEON-2のコードにユーザー定義のデータ型が使われていた。。当然合成も出来る。。

めでたくsystemVerilogで強力なデータ型の使用が可能となったので試してみた。

結果。。
union -> Quaruts2駄目。。
-> modelSim OK!!
 packedは使えるので。。とりあえず良し。。

例題はご存じtimer_core.sv下記に貼り付けた。

typedefにしてmoduleの外に置いているのはemacs-verilogモードの出来が悪くて
イデントが崩れる為。。汗)

/*
 union  packed{
 logic [1:0]  control_reg ;
 struct packed {
 logic count_en ;
 logic intr_clr ;
 } control ;
 } control_un ;
 */

typedef enum logic [2:0] {
                          IDLE,
                          LOAD,
                          RUN
                          } state_t ;
typedef struct packed{
                      logic count_en ;
                      logic intr_clr ;
                      } control_t ;

typedef struct {
                logic [31:0] count ;
                state_t      state ;
                logic [31:0] c_value ;
                logic        intr ;
                } timer_t ;

module timer_core(interface wb_bus) ;
   
   control_t control ;
   timer_t   timer ;
   logic [31:0] rdat ;
   
   wire         clk    = wb_bus.clk_i ;
   wire         nrst   = wb_bus.nrst_i ;
   wire [31:0]  dat_i  = wb_bus.dat_i ;
   wire         we_i   = wb_bus.we_i ;
   wire         stb_count   = wb_bus.stb_i == 1'b1 && wb_bus.sel_i == 4'b1111 && wb_bus.adr_i[2] == 1'b0 ;
   wire         stb_control = wb_bus.stb_i == 1'b1 && wb_bus.sel_i == 4'b1111 && wb_bus.adr_i[2] == 1'b1 ;
   
   assign wb_bus.intr_o = timer.intr == 1'b1 ;
   assign wb_bus.dat_o  = rdat ;
   assign wb_bus.ack_o  = 1'b0 ;
   
   always_comb begin
      case ({stb_count, stb_control})
        2'b10 : rdat = timer.count ;
        2'b01 : rdat = {30'h00, control} ;
        default : rdat = 32'h0 ;
      endcase // case ({stb_count, stb_control})
   end
   
   // -- count state -------------------
   // -  IDLE --> LOAD -> RUN
   // -   ^        ^       |
   // -   |        +-------+
   // -   +----------------+
   // - 
   // - IDLE -> LOAD :: control == RUN
   // - LOAD -> RUN  :: always
   // - RUN  -> LOAD :: count_end - 1
   // - RUN  -> IDLE :: control == STOP
   // ----------------------------------
   always_ff @(posedge clk, negedge nrst) begin
      if(nrst == 1'b0) begin
         timer.count <= #1 32'hffff_ffff ;
         // -- timer state --
         timer.state <= #1 IDLE ;
      end
      else
        case (timer.state)
          IDLE : begin
             timer.count <= #1 32'hffff_ffff ;
             // -- timer state --
             if(control.count_en == 1'b1)
               timer.state <= #1 LOAD ;
             else
               timer.state <= #1 IDLE ;
          end
          LOAD : begin
             timer.count <= #1 timer.c_value ;
             // -- timer state --
             timer.state <= #1 RUN ;
          end
          RUN : begin
             timer.count <= timer.count - 1 ;
             // -- timer state --
             if(control.count_en == 1'b0)
               timer.state <= #1 IDLE ;
             else if(timer.count == 32'h0000_0001) // -- end of count --
               timer.state <= #1 LOAD ;
             else
               timer.state <= #1 RUN ;
          end
          default : begin
             timer.count <= #1 32'hffff_ffff ;
             // -- timer state --
             timer.state <= #1 IDLE ;
          end
        endcase // case (state)
   end // always_ff @ (posedge clk, negedge nrst)
   
   // -- count value --
   always_ff @(posedge clk, negedge nrst) begin
      if(nrst == 1'b0)
        timer.c_value <= #1 32'hffff_ffff ;
      else if(stb_count == 1'b1 && we_i == 1'b1)
        timer.c_value <= #1 dat_i ;
      else
        timer.c_value <= #1 timer.c_value ;
   end
   
   // -- intrrput register --
   always_ff @(posedge clk, negedge nrst) begin
      if(nrst == 1'b0)
        timer.intr <= #1 1'b0 ;
      else if(control.intr_clr == 1'b0)
        timer.intr <= #1 1'b0 ;
      else if(timer.count == 32'h0000_0001)
        timer.intr <= #1 1'b1 ;
      else
        timer.intr <= #1 timer.intr ;
   end
   
   // -- control register --
   always_ff @(posedge clk, negedge nrst) begin
      if(nrst == 1'b0)
        control <= #1 0 ;
      else if(stb_control == 1'b1 && we_i == 1'b1)
        control <= #1 dat_i[1:0] ;
      else
        control <= #1 control ;
   end
   
endmodule