rtl: perips: rewrite timer module

Signed-off-by: liangkangnan <liangkangnan@163.com>
pull/4/head
liangkangnan 2021-08-10 09:47:37 +08:00
parent f6c8a046c7
commit 64041b4d2b
10 changed files with 656 additions and 293 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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" }
]
}
]
}

View File

@ -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

View File

@ -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

View File

@ -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: <reg>_<field>_{wd|we|qs}
// or <reg>_{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

View File

@ -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

View File

@ -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