systemVerilogサンプル。

ネットを検索してもsystemVerilogの合成可能サンプルはほとんど無い。
ということで、簡単なtimerのRTLを載せよう。

mips-cpuに取り付けるtick-timerを探したが簡単なのが無くて作ってしまった。
  →機能がいっぱいのtimer向けにドライバープログラムを作るより必要な機能だけのtimerの方が楽だと思う。

注)wb_bus →WISHBONE bus net検索で調べてね。。フリーで使えるbus規格だ。
        (このtimer-RTLはとりあえずつながるレベルだ。。)

verilog95との違いは、
enum, interface,alwaysl_ff, always_comb位か。。

interface接続例は次の機会で。。

Quartus2でenumをステートマシンと認識させるためには
値の範囲を設定する必要がある。
 → logic [1:0] state ; //OK 例
 → integer state ; // 駄目例
あと算術で状態遷移を行うことも駄目。。
 → state <= state + 2 ; // 駄目例
Quartusのマニュアルに書いてあるよ。

 注)バグ報告歓迎。。汗)

module timer_core(interface wb_bus) ;

//   enum  {
//   enum integer {
   enum logic [2:0] {
                     IDLE,
                     LOAD,
                     RUN
                     } state ;
   
   logic [31:0] count ;
   logic [1:0]  control ;
   logic [31:0] rdat ;
   logic [31:0] c_value ;
   logic        count_end ;
   logic        intr ;
   
   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 = 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 = 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)
        state <= #1 IDLE ;
      else
        case (state)
          IDLE : begin
             if(control[0] == 1'b1)
               state <= #1 LOAD ;
             else
               state <= #1 IDLE ;
          end
          LOAD : state <= #1 RUN ;
          RUN : begin
             if(control[0] == 1'b0)
               state <= #1 IDLE ;
             else if(count_end == 1'b1)
               state <= #1 LOAD ;
             else
               state <= #1 RUN ;
          end
          default : state <= #1 IDLE ;
        endcase // case (state)
   end // always_ff @ (posedge clk, negedge nrst)
   
   // -- count boby --
   always_ff @(posedge clk, negedge nrst) begin
      if(nrst == 1'b0)
        count <= #1 32'hffff_ffff ;
      else if(state == LOAD)
        count <= #1 c_value ;
      else if(state == RUN)
        count <= #1 count - 1 ;
      else
        count <= #1 count ;
   end
   assign count_end = count == 32'h0000_0001 ;
   
   // -- count value --
   always_ff @(posedge clk, negedge nrst) begin
      if(nrst == 1'b0)
        c_value <= #1 32'hffff_ffff ;
      else if(stb_count == 1'b1 && we_i == 1'b1)
        c_value <= #1 dat_i ;
      else
        c_value <= #1 c_value ;
   end

   // -- intrrput register --
   always_ff @(posedge clk, negedge nrst) begin
      if(nrst == 1'b0)
        intr <= #1 1'b0 ;
      else if(control[1] == 1'b0)
        intr <= #1 1'b0 ;
      else if(count_end == 1'b1)
        intr <= #1 1'b1 ;
      else
        intr <= #1 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