From 64041b4d2b207734cadec3d09618d241bb985289 Mon Sep 17 00:00:00 2001 From: liangkangnan Date: Tue, 10 Aug 2021 09:47:37 +0800 Subject: [PATCH] rtl: perips: rewrite timer module Signed-off-by: liangkangnan --- rtl.flist | 6 +- rtl/core/defines.sv | 9 +- rtl/perips/machine_timer.sv | 119 ------------ rtl/perips/timer.sv | 151 --------------- rtl/perips/timer/timer.hjson | 58 ++++++ rtl/perips/timer/timer_core.sv | 102 ++++++++++ rtl/perips/timer/timer_reg_pkg.sv | 110 +++++++++++ rtl/perips/timer/timer_reg_top.sv | 303 ++++++++++++++++++++++++++++++ rtl/perips/timer/timer_top.sv | 60 ++++++ rtl/top/tinyriscv_soc_top.sv | 31 +-- 10 files changed, 656 insertions(+), 293 deletions(-) delete mode 100644 rtl/perips/machine_timer.sv delete mode 100644 rtl/perips/timer.sv create mode 100644 rtl/perips/timer/timer.hjson create mode 100644 rtl/perips/timer/timer_core.sv create mode 100644 rtl/perips/timer/timer_reg_pkg.sv create mode 100644 rtl/perips/timer/timer_reg_top.sv create mode 100644 rtl/perips/timer/timer_top.sv diff --git a/rtl.flist b/rtl.flist index d02465d..834d9c1 100644 --- a/rtl.flist +++ b/rtl.flist @@ -36,8 +36,6 @@ ../rtl/perips/gpio.sv ../rtl/perips/ram.sv ../rtl/perips/rom.sv -../rtl/perips/timer.sv -../rtl/perips/machine_timer.sv ../rtl/perips/rvic.sv ../rtl/perips/uart/uart_reg_pkg.sv ../rtl/perips/uart/uart_reg_top.sv @@ -45,6 +43,10 @@ ../rtl/perips/uart/uart_rx.sv ../rtl/perips/uart/uart_top.sv ../rtl/perips/uart/uart_tx.sv +../rtl/perips/timer/timer_reg_pkg.sv +../rtl/perips/timer/timer_reg_top.sv +../rtl/perips/timer/timer_core.sv +../rtl/perips/timer/timer_top.sv ../rtl/sys_bus/obi_interconnect.sv ../rtl/sys_bus/obi_interconnect_master_sel.sv diff --git a/rtl/core/defines.sv b/rtl/core/defines.sv index 412d3d6..65e35f2 100644 --- a/rtl/core/defines.sv +++ b/rtl/core/defines.sv @@ -34,15 +34,12 @@ // GPIO `define GPIO_ADDR_MASK ~32'hffff `define GPIO_ADDR_BASE 32'h30000000 -// Timer -`define TIMER_ADDR_MASK ~32'hffff -`define TIMER_ADDR_BASE 32'h40000000 +// Timer0 +`define TIMER0_ADDR_MASK ~32'hffff +`define TIMER0_ADDR_BASE 32'h40000000 // UART0 `define UART0_ADDR_MASK ~32'hffff `define UART0_ADDR_BASE 32'h50000000 -// Machine Timer -`define MTIMER_ADDR_MASK ~32'hffff -`define MTIMER_ADDR_BASE 32'hA0000000 // Interrupt controller `define RVIC_ADDR_MASK ~32'hffff `define RVIC_ADDR_BASE 32'hD0000000 diff --git a/rtl/perips/machine_timer.sv b/rtl/perips/machine_timer.sv deleted file mode 100644 index 66f9a6e..0000000 --- a/rtl/perips/machine_timer.sv +++ /dev/null @@ -1,119 +0,0 @@ - /* - Copyright 2021 Blue Liang, liangkangnan@163.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -module machine_timer( - - input wire clk, - input wire rst_n, - input wire[31:0] addr_i, - input wire[31:0] data_i, - input wire[3:0] sel_i, - input wire we_i, - output wire[31:0] data_o, - output wire irq_o - - ); - - localparam mtime_ctrl_reg = 4'h0; - localparam mtime_cmp_reg = 4'h4; - localparam mtime_count_reg = 4'h8; - - localparam start = 0; - localparam irq_pending = 1; - - reg[31:0] mtime_ctrl_d, mtime_ctrl_q; - reg[31:0] mtime_cmp_d, mtime_cmp_q; - reg[31:0] mtime_count_q; - reg[31:0] data_d, data_q; - - wire[3:0] rw_addr = addr_i[3:0]; - wire w0 = we_i & sel_i[0]; - wire w1 = we_i & sel_i[1]; - wire w2 = we_i & sel_i[2]; - wire w3 = we_i & sel_i[3]; - - // write - always @ (*) begin - mtime_cmp_d = mtime_cmp_q; - mtime_ctrl_d = mtime_ctrl_q; - - case (rw_addr) - mtime_ctrl_reg: begin - if (w0) begin - mtime_ctrl_d[0] = data_i[0]; - mtime_ctrl_d[irq_pending] = mtime_ctrl_q & (~data_i[irq_pending]); - end - end - - mtime_cmp_reg: begin - if (w0) mtime_cmp_d[7:0] = data_i[7:0]; - if (w1) mtime_cmp_d[15:8] = data_i[15:8]; - if (w2) mtime_cmp_d[23:16] = data_i[23:16]; - if (w3) mtime_cmp_d[31:24] = data_i[31:24]; - end - - default:; - endcase - - if (mtime_count_q == mtime_cmp_q) begin - mtime_ctrl_d[irq_pending] = 1'b1; - end - end - - assign irq_o = mtime_ctrl_q[irq_pending] & mtime_ctrl_q[start]; - - // read - always @ (*) begin - data_d = data_q; - - case (rw_addr) - mtime_ctrl_reg: data_d = mtime_ctrl_q; - mtime_cmp_reg: data_d = mtime_cmp_q; - mtime_count_reg: data_d = mtime_count_q; - default:; - endcase - end - - assign data_o = data_q; - - always @ (posedge clk or negedge rst_n) begin - if (!rst_n) begin - mtime_ctrl_q <= 32'h0; - mtime_cmp_q <= 32'h0; - data_q <= 32'h0; - end else begin - mtime_ctrl_q <= mtime_ctrl_d; - mtime_cmp_q <= mtime_cmp_d; - data_q <= data_d; - end - end - - always @ (posedge clk or negedge rst_n) begin - if (!rst_n) begin - mtime_count_q <= 32'h0; - end else begin - if (mtime_ctrl_q[start]) begin - mtime_count_q <= mtime_count_q + 1'b1; - if (mtime_count_q == mtime_cmp_q) begin - mtime_count_q <= 32'h0; - end - end else begin - mtime_count_q <= 32'h0; - end - end - end - -endmodule diff --git a/rtl/perips/timer.sv b/rtl/perips/timer.sv deleted file mode 100644 index b5c71b3..0000000 --- a/rtl/perips/timer.sv +++ /dev/null @@ -1,151 +0,0 @@ - /* - Copyright 2020 Blue Liang, liangkangnan@163.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -`include "../core/defines.sv" - -// 32位向上计数定时器模块 -module timer( - - input wire clk, - input wire rst_n, - input wire[31:0] addr_i, - input wire[31:0] data_i, - input wire[3:0] sel_i, - input wire we_i, - output wire[31:0] data_o, - output wire int_sig_o - - ); - - // 寄存器(偏移)地址 - localparam REG_CTRL = 4'h0; - localparam REG_COUNT = 4'h4; - localparam REG_VALUE = 4'h8; - - // 定时器控制寄存器,可读可写 - // bit[0]: 定时器使能 - // bit[1]: 定时器中断使能 - // bit[2]: 定时器中断pending标志,写1清零 - reg[31:0] timer_ctrl; - - // 定时器当前计数值寄存器, 只读 - reg[31:0] timer_count; - - // 定时器溢出值寄存器,当定时器计数值达到该值时产生pending,可读可写 - reg[31:0] timer_value; - - wire wen = we_i & req_valid_i; - wire ren = (~we_i) & req_valid_i; - wire timer_en = (timer_ctrl[0] == 1'b1); - wire timer_int_en = (timer_ctrl[1] == 1'b1); - wire timer_expired = (timer_count >= timer_value); - wire write_reg_ctrl_en = wen & (addr_i[3:0] == REG_CTRL); - wire write_reg_value_en = wen & (addr_i[3:0] == REG_VALUE); - - // 计数 - always @ (posedge clk or negedge rst_n) begin - if (!rst_n) begin - timer_count <= 32'h0; - end else begin - if (timer_en) begin - if (timer_expired) begin - timer_count <= 32'h0; - end else begin - timer_count <= timer_count + 1'b1; - end - end else begin - timer_count <= 32'h0; - end - end - end - - reg int_sig_r; - // 产生中断信号 - always @ (posedge clk or negedge rst_n) begin - if (!rst_n) begin - int_sig_r <= 1'b0; - end else begin - if (write_reg_ctrl_en & (data_i[2] == 1'b1)) begin - int_sig_r <= 1'b0; - end else if (timer_int_en & timer_en & timer_expired) begin - int_sig_r <= 1'b1; - end - end - end - - assign int_sig_o = int_sig_r; - - // 写timer_ctrl - always @ (posedge clk or negedge rst_n) begin - if (!rst_n) begin - timer_ctrl <= 32'h0; - end else begin - if (write_reg_ctrl_en) begin - if (sel_i[0]) begin - timer_ctrl[7:0] <= {data_i[7:3], timer_ctrl[2] & (~data_i[2]), data_i[1:0]}; - end - end else begin - if (timer_expired) begin - timer_ctrl[0] <= 1'b0; - end - end - end - end - - // 写timer_value - always @ (posedge clk or negedge rst_n) begin - if (!rst_n) begin - timer_value <= 32'h0; - end else begin - if (write_reg_value_en) begin - if (sel_i[0]) begin - timer_value[7:0] <= data_i[7:0]; - end - if (sel_i[1]) begin - timer_value[15:8] <= data_i[15:8]; - end - if (sel_i[2]) begin - timer_value[23:16] <= data_i[23:16]; - end - if (sel_i[3]) begin - timer_value[31:24] <= data_i[31:24]; - end - end - end - end - - reg[31:0] data_r; - // 读寄存器 - always @ (posedge clk or negedge rst_n) begin - if (!rst_n) begin - data_r <= 32'h0; - end else begin - if (ren) begin - case (addr_i[3:0]) - REG_VALUE: data_r <= timer_value; - REG_CTRL: data_r <= timer_ctrl; - REG_COUNT: data_r <= timer_count; - default: data_r <= 32'h0; - endcase - end else begin - data_r <= 32'h0; - end - end - end - - assign data_o = data_r; - -endmodule diff --git a/rtl/perips/timer/timer.hjson b/rtl/perips/timer/timer.hjson new file mode 100644 index 0000000..de8bf1f --- /dev/null +++ b/rtl/perips/timer/timer.hjson @@ -0,0 +1,58 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ name: "timer", + clocking: [{clock: "clk_i", reset: "rst_ni"}], + bus_interfaces: [ + { protocol: "tlul", direction: "device" } + ], + regwidth: "32", + registers: [ + { name: "CTRL", + desc: "Timer control register", + swaccess: "rw", + hwaccess: "hrw", + hwqe: "true", + fields: [ + { bits: "0", + name: "EN", + desc: "Timer enable(start)", + } + { bits: "1", + name: "INT_EN", + desc: "Timer interrupt enable", + } + { bits: "2", + name: "INT_PENDING", + swaccess: "rw1c", + desc: "Timer interrupt pending", + } + { bits: "3", + name: "MODE", + desc: "Timer mode", + } + { bits: "31:8", + name: "CLK_DIV", + desc: "Timer clock divider count", + } + ] + } + { name: "VALUE", + desc: "Timer expired value register", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:0" } + ] + } + { name: "COUNT", + desc: "Timer current count register", + swaccess: "ro", + hwaccess: "hrw", + hwext: "true", + fields: [ + { bits: "31:0" } + ] + } + ] +} diff --git a/rtl/perips/timer/timer_core.sv b/rtl/perips/timer/timer_core.sv new file mode 100644 index 0000000..f74058b --- /dev/null +++ b/rtl/perips/timer/timer_core.sv @@ -0,0 +1,102 @@ + /* + Copyright 2021 Blue Liang, liangkangnan@163.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +module timer_core ( + input logic clk_i, + input logic rst_ni, + + output logic irq_o, + + input logic reg_we_i, + input logic reg_re_i, + input logic [31:0] reg_wdata_i, + input logic [ 3:0] reg_be_i, + input logic [31:0] reg_addr_i, + output logic [31:0] reg_rdata_o + ); + + import timer_reg_pkg::*; + + timer_reg_pkg::timer_reg2hw_t reg2hw; + timer_reg_pkg::timer_hw2reg_t hw2reg; + + logic start; + logic int_en; + logic int_pending; + logic mode; + logic [23:0] div_cont; + logic [31:0] count_q; + logic [31:0] value; + logic tick; + + assign start = reg2hw.ctrl.en.q; + assign int_en = reg2hw.ctrl.int_en.q; + assign int_pending = reg2hw.ctrl.int_pending.q; + assign mode = reg2hw.ctrl.mode.q; + assign div_cont = reg2hw.ctrl.clk_div.q; + assign value = reg2hw.value.q; + + // 当前计数值 + assign hw2reg.count.d = count_q; + assign hw2reg.ctrl.int_pending.d = 1'b1; + assign hw2reg.ctrl.int_pending.de = (count_q == value) && int_en && start; + + assign hw2reg.ctrl.en.d = 1'b0; + assign hw2reg.ctrl.en.de = (count_q == value) && (mode == 1'b0) && start; + + assign irq_o = int_pending; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + count_q <= 32'h0; + end else begin + if (start) begin + if (tick) begin + count_q <= count_q + 1'b1; + if (count_q == value) begin + count_q <= 32'h0; + end + end + end else begin + count_q <= 32'h0; + end + end + end + + clk_div #( + .RATIO_WIDTH(24) + ) u_clk_div ( + .clk_i(clk_i), + .rst_ni(rst_ni || (~(count_q == value))), + .en_i(start), + .ratio_i(div_cont), + .clk_o(tick) + ); + + timer_reg_top u_timer_reg_top ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .reg2hw (reg2hw), + .hw2reg (hw2reg), + .reg_we (reg_we_i), + .reg_re (reg_re_i), + .reg_wdata (reg_wdata_i), + .reg_be (reg_be_i), + .reg_addr (reg_addr_i), + .reg_rdata (reg_rdata_o) + ); + +endmodule diff --git a/rtl/perips/timer/timer_reg_pkg.sv b/rtl/perips/timer/timer_reg_pkg.sv new file mode 100644 index 0000000..39923fd --- /dev/null +++ b/rtl/perips/timer/timer_reg_pkg.sv @@ -0,0 +1,110 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Package auto-generated by `reggen` containing data structure + +package timer_reg_pkg; + + // Address widths within the block + parameter int BlockAw = 4; + + //////////////////////////// + // Typedefs for registers // + //////////////////////////// + + typedef struct packed { + struct packed { + logic q; + logic qe; + } en; + struct packed { + logic q; + logic qe; + } int_en; + struct packed { + logic q; + logic qe; + } int_pending; + struct packed { + logic q; + logic qe; + } mode; + struct packed { + logic [23:0] q; + logic qe; + } clk_div; + } timer_reg2hw_ctrl_reg_t; + + typedef struct packed { + logic [31:0] q; + } timer_reg2hw_value_reg_t; + + typedef struct packed { + logic [31:0] q; + } timer_reg2hw_count_reg_t; + + typedef struct packed { + struct packed { + logic d; + logic de; + } en; + struct packed { + logic d; + logic de; + } int_en; + struct packed { + logic d; + logic de; + } int_pending; + struct packed { + logic d; + logic de; + } mode; + struct packed { + logic [23:0] d; + logic de; + } clk_div; + } timer_hw2reg_ctrl_reg_t; + + typedef struct packed { + logic [31:0] d; + } timer_hw2reg_count_reg_t; + + // Register -> HW type + typedef struct packed { + timer_reg2hw_ctrl_reg_t ctrl; // [96:64] + timer_reg2hw_value_reg_t value; // [63:32] + timer_reg2hw_count_reg_t count; // [31:0] + } timer_reg2hw_t; + + // HW -> register type + typedef struct packed { + timer_hw2reg_ctrl_reg_t ctrl; // [64:32] + timer_hw2reg_count_reg_t count; // [31:0] + } timer_hw2reg_t; + + // Register offsets + parameter logic [BlockAw-1:0] TIMER_CTRL_OFFSET = 4'h0; + parameter logic [BlockAw-1:0] TIMER_VALUE_OFFSET = 4'h4; + parameter logic [BlockAw-1:0] TIMER_COUNT_OFFSET = 4'h8; + + // Reset values for hwext registers and their fields + parameter logic [31:0] TIMER_COUNT_RESVAL = 32'h0; + + // Register index + typedef enum int { + TIMER_CTRL, + TIMER_VALUE, + TIMER_COUNT + } timer_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] TIMER_PERMIT [3] = '{ + 4'b1111, // index[0] TIMER_CTRL + 4'b1111, // index[1] TIMER_VALUE + 4'b1111 // index[2] TIMER_COUNT + }; + +endpackage + diff --git a/rtl/perips/timer/timer_reg_top.sv b/rtl/perips/timer/timer_reg_top.sv new file mode 100644 index 0000000..9df8b8a --- /dev/null +++ b/rtl/perips/timer/timer_reg_top.sv @@ -0,0 +1,303 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Top module auto-generated by `reggen` + + +module timer_reg_top ( + input logic clk_i, + input logic rst_ni, + + // To HW + output timer_reg_pkg::timer_reg2hw_t reg2hw, // Write + input timer_reg_pkg::timer_hw2reg_t hw2reg, // Read + + input logic reg_we, + input logic reg_re, + input logic [31:0] reg_wdata, + input logic [ 3:0] reg_be, + input logic [31:0] reg_addr, + output logic [31:0] reg_rdata +); + + import timer_reg_pkg::* ; + + localparam int AW = 4; + localparam int DW = 32; + localparam int DBW = DW/8; // Byte Width + + logic reg_error; + logic addrmiss, wr_err; + + logic [DW-1:0] reg_rdata_next; + + assign reg_rdata = reg_rdata_next; + assign reg_error = wr_err; + + // Define SW related signals + // Format: __{wd|we|qs} + // or _{wd|we|qs} if field == 1 or 0 + logic ctrl_we; + logic ctrl_en_qs; + logic ctrl_en_wd; + logic ctrl_int_en_qs; + logic ctrl_int_en_wd; + logic ctrl_int_pending_qs; + logic ctrl_int_pending_wd; + logic ctrl_mode_qs; + logic ctrl_mode_wd; + logic [23:0] ctrl_clk_div_qs; + logic [23:0] ctrl_clk_div_wd; + logic value_we; + logic [31:0] value_qs; + logic [31:0] value_wd; + logic count_re; + logic [31:0] count_qs; + + // Register instances + // R[ctrl]: V(False) + + // F[en]: 0:0 + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_ctrl_en ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_en_wd), + + // from internal hardware + .de (hw2reg.ctrl.en.de), + .d (hw2reg.ctrl.en.d), + + // to internal hardware + .qe (reg2hw.ctrl.en.qe), + .q (reg2hw.ctrl.en.q), + + // to register interface (read) + .qs (ctrl_en_qs) + ); + + + // F[int_en]: 1:1 + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_ctrl_int_en ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_int_en_wd), + + // from internal hardware + .de (hw2reg.ctrl.int_en.de), + .d (hw2reg.ctrl.int_en.d), + + // to internal hardware + .qe (reg2hw.ctrl.int_en.qe), + .q (reg2hw.ctrl.int_en.q), + + // to register interface (read) + .qs (ctrl_int_en_qs) + ); + + + // F[int_pending]: 2:2 + prim_subreg #( + .DW (1), + .SWACCESS("W1C"), + .RESVAL (1'h0) + ) u_ctrl_int_pending ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_int_pending_wd), + + // from internal hardware + .de (hw2reg.ctrl.int_pending.de), + .d (hw2reg.ctrl.int_pending.d), + + // to internal hardware + .qe (reg2hw.ctrl.int_pending.qe), + .q (reg2hw.ctrl.int_pending.q), + + // to register interface (read) + .qs (ctrl_int_pending_qs) + ); + + + // F[mode]: 3:3 + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_ctrl_mode ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_mode_wd), + + // from internal hardware + .de (hw2reg.ctrl.mode.de), + .d (hw2reg.ctrl.mode.d), + + // to internal hardware + .qe (reg2hw.ctrl.mode.qe), + .q (reg2hw.ctrl.mode.q), + + // to register interface (read) + .qs (ctrl_mode_qs) + ); + + + // F[clk_div]: 31:8 + prim_subreg #( + .DW (24), + .SWACCESS("RW"), + .RESVAL (24'h0) + ) u_ctrl_clk_div ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ctrl_we), + .wd (ctrl_clk_div_wd), + + // from internal hardware + .de (hw2reg.ctrl.clk_div.de), + .d (hw2reg.ctrl.clk_div.d), + + // to internal hardware + .qe (reg2hw.ctrl.clk_div.qe), + .q (reg2hw.ctrl.clk_div.q), + + // to register interface (read) + .qs (ctrl_clk_div_qs) + ); + + + // R[value]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("RW"), + .RESVAL (32'h0) + ) u_value ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (value_we), + .wd (value_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.value.q), + + // to register interface (read) + .qs (value_qs) + ); + + + // R[count]: V(True) + + prim_subreg_ext #( + .DW (32) + ) u_count ( + .re (count_re), + .we (1'b0), + .wd ('0), + .d (hw2reg.count.d), + .qre (), + .qe (), + .q (reg2hw.count.q), + .qs (count_qs) + ); + + + logic [2:0] addr_hit; + always_comb begin + addr_hit = '0; + addr_hit[0] = (reg_addr == TIMER_CTRL_OFFSET); + addr_hit[1] = (reg_addr == TIMER_VALUE_OFFSET); + addr_hit[2] = (reg_addr == TIMER_COUNT_OFFSET); + end + + assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; + + // Check sub-word write is permitted + always_comb begin + wr_err = (reg_we & + ((addr_hit[0] & (|(TIMER_PERMIT[0] & ~reg_be))) | + (addr_hit[1] & (|(TIMER_PERMIT[1] & ~reg_be))) | + (addr_hit[2] & (|(TIMER_PERMIT[2] & ~reg_be))))); + end + + assign ctrl_we = addr_hit[0] & reg_we & !reg_error; + + assign ctrl_en_wd = reg_wdata[0]; + + assign ctrl_int_en_wd = reg_wdata[1]; + + assign ctrl_int_pending_wd = reg_wdata[2]; + + assign ctrl_mode_wd = reg_wdata[3]; + + assign ctrl_clk_div_wd = reg_wdata[31:8]; + assign value_we = addr_hit[1] & reg_we & !reg_error; + + assign value_wd = reg_wdata[31:0]; + assign count_re = addr_hit[2] & reg_re & !reg_error; + + // Read data return + always_comb begin + reg_rdata_next = '0; + unique case (1'b1) + addr_hit[0]: begin + reg_rdata_next[0] = ctrl_en_qs; + reg_rdata_next[1] = ctrl_int_en_qs; + reg_rdata_next[2] = ctrl_int_pending_qs; + reg_rdata_next[3] = ctrl_mode_qs; + reg_rdata_next[31:8] = ctrl_clk_div_qs; + end + + addr_hit[1]: begin + reg_rdata_next[31:0] = value_qs; + end + + addr_hit[2]: begin + reg_rdata_next[31:0] = count_qs; + end + + default: begin + reg_rdata_next = '1; + end + endcase + end + + // Unused signal tieoff + + // wdata / byte enable are not always fully used + // add a blanket unused statement to handle lint waivers + logic unused_wdata; + logic unused_be; + assign unused_wdata = ^reg_wdata; + assign unused_be = ^reg_be; + +endmodule diff --git a/rtl/perips/timer/timer_top.sv b/rtl/perips/timer/timer_top.sv new file mode 100644 index 0000000..8d233c3 --- /dev/null +++ b/rtl/perips/timer/timer_top.sv @@ -0,0 +1,60 @@ + /* + Copyright 2021 Blue Liang, liangkangnan@163.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +module timer_top ( + input logic clk_i, + input logic rst_ni, + + output logic irq_o, + + // OBI总线接口信号 + input logic req_i, + input logic we_i, + input logic [ 3:0] be_i, + input logic [31:0] addr_i, + input logic [31:0] data_i, + output logic [31:0] data_o + ); + + logic re; + logic we; + logic [31:0] addr; + logic [31:0] reg_rdata; + + // 读信号 + assign re = req_i & (!we_i); + // 写信号 + assign we = req_i & we_i; + // 去掉基地址 + assign addr = {16'h0, addr_i[15:0]}; + + timer_core u_timer_core ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .irq_o (irq_o), + .reg_we_i (we), + .reg_re_i (re), + .reg_wdata_i(data_i), + .reg_be_i (be_i), + .reg_addr_i (addr), + .reg_rdata_o(reg_rdata) + ); + + always_ff @(posedge clk_i) begin + data_o <= reg_rdata; + end + +endmodule diff --git a/rtl/top/tinyriscv_soc_top.sv b/rtl/top/tinyriscv_soc_top.sv index 30ec84a..38adffd 100644 --- a/rtl/top/tinyriscv_soc_top.sv +++ b/rtl/top/tinyriscv_soc_top.sv @@ -55,7 +55,7 @@ module tinyriscv_soc_top #( localparam int Rom = 0; localparam int Ram = 1; localparam int JtagDevice = 2; - localparam int Mtimer = 3; + localparam int Timer0 = 3; localparam int Gpio = 4; localparam int Uart0 = 5; localparam int Rvic = 6; @@ -105,7 +105,7 @@ module tinyriscv_soc_top #( wire int_req; wire[7:0] int_id; - wire mtimer_irq; + wire timer0_irq; wire uart0_irq; wire[1:0] io_in; @@ -114,7 +114,7 @@ module tinyriscv_soc_top #( always @ (*) begin irq_src = 32'h0; - irq_src[0] = mtimer_irq; + irq_src[0] = timer0_irq; irq_src[1] = uart0_irq; end @@ -187,18 +187,19 @@ module tinyriscv_soc_top #( .data_o (slave_rdata[Ram]) ); - assign slave_addr_mask[Mtimer] = `MTIMER_ADDR_MASK; - assign slave_addr_base[Mtimer] = `MTIMER_ADDR_BASE; - // 3.机器定时器模块 - machine_timer u_machine_timer( - .clk (clk), - .rst_n (ndmreset_n), - .addr_i (slave_addr[Mtimer]), - .data_i (slave_wdata[Mtimer]), - .sel_i (slave_be[Mtimer]), - .we_i (slave_we[Mtimer]), - .data_o (slave_rdata[Mtimer]), - .irq_o (mtimer_irq) + assign slave_addr_mask[Timer0] = `TIMER0_ADDR_MASK; + assign slave_addr_base[Timer0] = `TIMER0_ADDR_BASE; + // 3.定时器0模块 + timer_top timer0( + .clk_i (clk), + .rst_ni (ndmreset_n), + .irq_o (timer0_irq), + .req_i (slave_req[Timer0]), + .we_i (slave_we[Timer0]), + .be_i (slave_be[Timer0]), + .addr_i (slave_addr[Timer0]), + .data_i (slave_wdata[Timer0]), + .data_o (slave_rdata[Timer0]) ); // IO0