ネットを検索してもsystemVerilogの合成可能サンプルはほとんど無い。
ということで、簡単なtimerのRTLを載せよう。
ということで、簡単なtimerのRTLを載せよう。
mips-cpuに取り付けるtick-timerを探したが簡単なのが無くて作ってしまった。
→機能がいっぱいのtimer向けにドライバープログラムを作るより必要な機能だけのtimerの方が楽だと思う。
→機能がいっぱいのtimer向けにドライバープログラムを作るより必要な機能だけのtimerの方が楽だと思う。
注)wb_bus →WISHBONE bus net検索で調べてね。。フリーで使えるbus規格だ。
(このtimer-RTLはとりあえずつながるレベルだ。。)
(このtimer-RTLはとりあえずつながるレベルだ。。)
interface接続例は次の機会で。。
Quartus2でenumをステートマシンと認識させるためには
値の範囲を設定する必要がある。
→ logic [1:0] state ; //OK 例
→ integer state ; // 駄目例
あと算術で状態遷移を行うことも駄目。。
→ state <= state + 2 ; // 駄目例
Quartusのマニュアルに書いてあるよ。
値の範囲を設定する必要がある。
→ 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