parent
5811bdde13
commit
6e466fbbf7
|
@ -37,6 +37,7 @@
|
|||
../rtl/perips/rom.sv
|
||||
../rtl/perips/timer.sv
|
||||
../rtl/perips/uart.sv
|
||||
../rtl/perips/machine_timer.sv
|
||||
|
||||
../rtl/sys_bus/obi_interconnect.sv
|
||||
../rtl/sys_bus/obi_interconnect_master_sel.sv
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
// UART
|
||||
`define UART_ADDR_MASK ~32'hffff
|
||||
`define UART_ADDR_BASE 32'h50000000
|
||||
// Machine Timer
|
||||
`define MTIMER_ADDR_MASK ~32'hffff
|
||||
`define MTIMER_ADDR_BASE 32'hA0000000
|
||||
// SIM CTRL
|
||||
`define SIM_CTRL_ADDR_MASK ~32'hffff
|
||||
`define SIM_CTRL_ADDR_BASE 32'hE0000000
|
||||
|
|
|
@ -89,14 +89,14 @@ module exception (
|
|||
localparam FAST_INT_OFFSET = 44;
|
||||
|
||||
|
||||
localparam S_IDLE = 4'b0001;
|
||||
localparam S_W_MEPC = 4'b0010;
|
||||
localparam S_W_DCSR = 4'b0100;
|
||||
localparam S_ASSERT = 4'b1000;
|
||||
|
||||
localparam S_IDLE = 5'b00001;
|
||||
localparam S_W_MEPC = 5'b00010;
|
||||
localparam S_W_DCSR = 5'b00100;
|
||||
localparam S_ASSERT = 5'b01000;
|
||||
localparam S_W_MSTATUS = 5'b10000;
|
||||
|
||||
reg debug_mode_d, debug_mode_q;
|
||||
reg[3:0] state_d, state_q;
|
||||
reg[4:0] state_d, state_q;
|
||||
reg[31:0] assert_addr_d, assert_addr_q;
|
||||
reg[31:0] return_addr_d, return_addr_q;
|
||||
reg csr_we;
|
||||
|
@ -239,13 +239,13 @@ module exception (
|
|||
|
||||
case (state_q)
|
||||
S_IDLE: begin
|
||||
if (int_or_exception_req) begin
|
||||
if (int_or_exception_req & (!debug_mode_q)) begin
|
||||
csr_we = 1'b1;
|
||||
csr_waddr = {20'h0, `CSR_MCAUSE};
|
||||
csr_wdata = int_or_exception_cause;
|
||||
assert_addr_d = mtvec_i + int_or_exception_offset;
|
||||
return_addr_d = inst_addr_i;
|
||||
state_d = S_W_MEPC;
|
||||
state_d = S_W_MSTATUS;
|
||||
end else if (debug_mode_req) begin
|
||||
debug_mode_d = 1'b1;
|
||||
if (enter_debug_cause_debugger_req |
|
||||
|
@ -269,6 +269,9 @@ module exception (
|
|||
end
|
||||
end else if (inst_mret_i) begin
|
||||
assert_addr_d = mepc_i;
|
||||
csr_we = 1'b1;
|
||||
csr_waddr = {20'h0, `CSR_MSTATUS};
|
||||
csr_wdata = {mstatus_i[31:4], 1'b1, mstatus_i[2:0]};
|
||||
state_d = S_ASSERT;
|
||||
end else if (inst_dret_i) begin
|
||||
assert_addr_d = dpc_i;
|
||||
|
@ -277,6 +280,13 @@ module exception (
|
|||
end
|
||||
end
|
||||
|
||||
S_W_MSTATUS: begin
|
||||
csr_we = 1'b1;
|
||||
csr_waddr = {20'h0, `CSR_MSTATUS};
|
||||
csr_wdata = {mstatus_i[31:4], 1'b0, mstatus_i[2:0]};
|
||||
state_d = S_W_MEPC;
|
||||
end
|
||||
|
||||
S_W_MEPC: begin
|
||||
csr_we = 1'b1;
|
||||
csr_waddr = {20'h0, `CSR_MEPC};
|
||||
|
|
|
@ -46,8 +46,8 @@ module gpio(
|
|||
assign reg_ctrl = gpio_ctrl;
|
||||
assign reg_data = gpio_data;
|
||||
|
||||
wire wen = we_i & req_valid_i;
|
||||
wire ren = (~we_i) & req_valid_i;
|
||||
wire wen = we_i;
|
||||
wire ren = (~we_i);
|
||||
wire write_reg_ctrl_en = wen & (addr_i[3:0] == GPIO_CTRL);
|
||||
wire write_reg_data_en = wen & (addr_i[3:0] == GPIO_DATA);
|
||||
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
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 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_q = 32'h0;
|
||||
|
||||
case (rw_addr)
|
||||
mtime_ctrl_reg: data_q = mtime_ctrl_q;
|
||||
mtime_cmp_reg: data_q = mtime_cmp_q;
|
||||
mtime_count_reg: data_q = 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;
|
||||
end else begin
|
||||
mtime_ctrl_q <= mtime_ctrl_d;
|
||||
mtime_cmp_q <= mtime_cmp_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
|
|
@ -85,8 +85,8 @@ module uart(
|
|||
// UART接收数据寄存器,只读
|
||||
reg[31:0] uart_rx;
|
||||
|
||||
wire wen = we_i & req_valid_i;
|
||||
wire ren = (~we_i) & req_valid_i;
|
||||
wire wen = we_i;
|
||||
wire ren = (~we_i);
|
||||
wire write_reg_ctrl_en = wen & (addr_i[7:0] == UART_CTRL);
|
||||
wire write_reg_status_en = wen & (addr_i[7:0] == UART_STATUS);
|
||||
wire write_reg_baud_en = wen & (addr_i[7:0] == UART_BAUD);
|
||||
|
|
|
@ -39,9 +39,9 @@ module tinyriscv_soc_top(
|
|||
|
||||
localparam int MASTERS = 3; // Number of master ports
|
||||
`ifdef VERILATOR
|
||||
localparam int SLAVES = 4; // Number of slave ports
|
||||
localparam int SLAVES = 7; // Number of slave ports
|
||||
`else
|
||||
localparam int SLAVES = 3; // Number of slave ports
|
||||
localparam int SLAVES = 6; // Number of slave ports
|
||||
`endif
|
||||
|
||||
// masters
|
||||
|
@ -53,8 +53,11 @@ module tinyriscv_soc_top(
|
|||
localparam int Rom = 0;
|
||||
localparam int Ram = 1;
|
||||
localparam int JtagDevice = 2;
|
||||
localparam int Mtimer = 3;
|
||||
localparam int Gpio = 4;
|
||||
localparam int Uart = 5;
|
||||
`ifdef VERILATOR
|
||||
localparam int SimCtrl = 3;
|
||||
localparam int SimCtrl = 6;
|
||||
`endif
|
||||
|
||||
|
||||
|
@ -93,6 +96,12 @@ module tinyriscv_soc_top(
|
|||
wire debug_req;
|
||||
wire core_halted;
|
||||
|
||||
wire mtimer_irq;
|
||||
|
||||
wire[1:0] io_in;
|
||||
wire[31:0] gpio_ctrl;
|
||||
wire[31:0] gpio_data;
|
||||
|
||||
assign halted_ind_pin = core_halted;
|
||||
|
||||
tinyriscv_core #(
|
||||
|
@ -120,7 +129,7 @@ module tinyriscv_soc_top(
|
|||
.data_err_i (1'b0),
|
||||
|
||||
.irq_software_i (1'b0),
|
||||
.irq_timer_i (1'b0),
|
||||
.irq_timer_i (mtimer_irq),
|
||||
.irq_external_i (1'b0),
|
||||
.irq_fast_i (15'b0),
|
||||
|
||||
|
@ -129,7 +138,7 @@ module tinyriscv_soc_top(
|
|||
|
||||
assign slave_addr_mask[Rom] = `ROM_ADDR_MASK;
|
||||
assign slave_addr_base[Rom] = `ROM_ADDR_BASE;
|
||||
// 指令存储器
|
||||
// 1.指令存储器
|
||||
rom #(
|
||||
.DP(`ROM_DEPTH)
|
||||
) u_rom (
|
||||
|
@ -144,7 +153,7 @@ module tinyriscv_soc_top(
|
|||
|
||||
assign slave_addr_mask[Ram] = `RAM_ADDR_MASK;
|
||||
assign slave_addr_base[Ram] = `RAM_ADDR_BASE;
|
||||
// 数据存储器
|
||||
// 2.数据存储器
|
||||
ram #(
|
||||
.DP(`RAM_DEPTH)
|
||||
) u_ram (
|
||||
|
@ -157,9 +166,62 @@ 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)
|
||||
);
|
||||
|
||||
// IO0
|
||||
assign gpio_pins[0] = (gpio_ctrl[1:0] == 2'b01)? gpio_data[0]: 1'bz;
|
||||
assign io_in[0] = gpio_pins[0];
|
||||
// IO1
|
||||
assign gpio_pins[1] = (gpio_ctrl[3:2] == 2'b01)? gpio_data[1]: 1'bz;
|
||||
assign io_in[1] = gpio_pins[1];
|
||||
|
||||
assign slave_addr_mask[Gpio] = `GPIO_ADDR_MASK;
|
||||
assign slave_addr_base[Gpio] = `GPIO_ADDR_BASE;
|
||||
// 4.GPIO模块
|
||||
gpio u_gpio(
|
||||
.clk (clk),
|
||||
.rst_n (ndmreset_n),
|
||||
.addr_i (slave_addr[Gpio]),
|
||||
.data_i (slave_wdata[Gpio]),
|
||||
.sel_i (slave_be[Gpio]),
|
||||
.we_i (slave_we[Gpio]),
|
||||
.data_o (slave_rdata[Gpio]),
|
||||
.io_pin_i(io_in),
|
||||
.reg_ctrl(gpio_ctrl),
|
||||
.reg_data(gpio_data)
|
||||
);
|
||||
|
||||
assign slave_addr_mask[Uart] = `UART_ADDR_MASK;
|
||||
assign slave_addr_base[Uart] = `UART_ADDR_BASE;
|
||||
// 5.串口模块
|
||||
uart u_uart(
|
||||
.clk (clk),
|
||||
.rst_n (ndmreset_n),
|
||||
.addr_i (slave_addr[Uart]),
|
||||
.data_i (slave_wdata[Uart]),
|
||||
.sel_i (slave_be[Uart]),
|
||||
.we_i (slave_we[Uart]),
|
||||
.data_o (slave_rdata[Uart]),
|
||||
.tx_pin (uart_tx_pin),
|
||||
.rx_pin (uart_rx_pin)
|
||||
);
|
||||
|
||||
`ifdef VERILATOR
|
||||
assign slave_addr_mask[SimCtrl] = `SIM_CTRL_ADDR_MASK;
|
||||
assign slave_addr_base[SimCtrl] = `SIM_CTRL_ADDR_BASE;
|
||||
// 6.仿真控制模块
|
||||
sim_ctrl u_sim_ctrl(
|
||||
.clk_i (clk),
|
||||
.rst_ni (ndmreset_n),
|
||||
|
|
|
@ -22,6 +22,7 @@ C_SRCS += $(BSP_DIR)/lib/utils.c
|
|||
C_SRCS += $(BSP_DIR)/lib/xprintf.c
|
||||
C_SRCS += $(BSP_DIR)/lib/uart.c
|
||||
C_SRCS += $(BSP_DIR)/lib/sim_ctrl.c
|
||||
C_SRCS += $(BSP_DIR)/lib/machine_timer.c
|
||||
|
||||
LINKER_SCRIPT := $(BSP_DIR)/link.lds
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef _MACHINE_TIMER_H_
|
||||
#define _MACHINE_TIMER_H_
|
||||
|
||||
#define MTIMER_BASE (0xA0000000)
|
||||
#define MTIMER_CTRL (MTIMER_BASE + (0x00))
|
||||
#define MTIMER_CMP (MTIMER_BASE + (0x04))
|
||||
#define MTIMER_COUNT (MTIMER_BASE + (0x08))
|
||||
|
||||
#define MTIMER_REG(addr) (*((volatile uint32_t *)addr))
|
||||
|
||||
void machine_timer_set_cmp_val(uint32_t val);
|
||||
void machine_timer_enable(uint8_t en);
|
||||
void machine_timer_irq_enable(uint8_t en);
|
||||
void machine_timer_clear_irq_pending();
|
||||
|
||||
#endif
|
|
@ -25,4 +25,9 @@
|
|||
uint64_t get_cycle_value();
|
||||
void busy_wait(uint32_t us);
|
||||
|
||||
void global_irq_enable();
|
||||
void global_irq_disable();
|
||||
void mtime_irq_enable();
|
||||
void mtime_irq_disable();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "../../bsp/include/machine_timer.h"
|
||||
#include "../../bsp/include/utils.h"
|
||||
|
||||
void machine_timer_set_cmp_val(uint32_t val)
|
||||
{
|
||||
MTIMER_REG(MTIMER_CMP) = val;
|
||||
}
|
||||
|
||||
void machine_timer_enable(uint8_t en)
|
||||
{
|
||||
if (en)
|
||||
MTIMER_REG(MTIMER_CTRL) |= 1;
|
||||
else
|
||||
MTIMER_REG(MTIMER_CTRL) &= ~1;
|
||||
}
|
||||
|
||||
void machine_timer_irq_enable(uint8_t en)
|
||||
{
|
||||
if (en)
|
||||
mtime_irq_enable();
|
||||
else
|
||||
mtime_irq_disable();
|
||||
}
|
||||
|
||||
void machine_timer_clear_irq_pending()
|
||||
{
|
||||
MTIMER_REG(MTIMER_CTRL) |= 1 << 1;
|
||||
}
|
|
@ -24,3 +24,23 @@ void busy_wait(uint32_t us)
|
|||
|
||||
while (get_cycle_value() < (tmp + count));
|
||||
}
|
||||
|
||||
void global_irq_enable()
|
||||
{
|
||||
asm volatile("csrs mstatus, %0\n" : : "r"(0x8));
|
||||
}
|
||||
|
||||
void global_irq_disable()
|
||||
{
|
||||
asm volatile("csrc mstatus, %0\n" : : "r"(0x8));
|
||||
}
|
||||
|
||||
void mtime_irq_enable()
|
||||
{
|
||||
asm volatile("csrs mie, %0\n" : : "r"(0x80));
|
||||
}
|
||||
|
||||
void mtime_irq_disable()
|
||||
{
|
||||
asm volatile("csrc mie, %0\n" : : "r"(0x80));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.bin
|
||||
*.dump
|
||||
*.mem
|
||||
machine_timer
|
|
@ -0,0 +1,20 @@
|
|||
RISCV_ARCH := rv32im
|
||||
RISCV_ABI := ilp32
|
||||
RISCV_MCMODEL := medlow
|
||||
|
||||
|
||||
TARGET = machine_timer
|
||||
|
||||
|
||||
CFLAGS += -DSIMULATION
|
||||
#CFLAGS += -Os
|
||||
#ASM_SRCS +=
|
||||
#LDFLAGS +=
|
||||
#INCLUDES += -I.
|
||||
|
||||
C_SRCS := \
|
||||
main.c \
|
||||
|
||||
|
||||
BSP_DIR = ../../bsp
|
||||
include ../../bsp/bsp.mk
|
|
@ -0,0 +1 @@
|
|||
机器定时器(中断)例程。
|
|
@ -0,0 +1,55 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "../../bsp/include/machine_timer.h"
|
||||
#include "../../bsp/include/utils.h"
|
||||
#include "../../bsp/include/gpio.h"
|
||||
|
||||
static volatile uint32_t count;
|
||||
|
||||
int main()
|
||||
{
|
||||
count = 0;
|
||||
|
||||
#ifdef SIMULATION
|
||||
machine_timer_set_cmp_val(5000); // 100us period
|
||||
machine_timer_clear_irq_pending();
|
||||
global_irq_enable();
|
||||
machine_timer_irq_enable(1);
|
||||
machine_timer_enable(1);
|
||||
|
||||
while (1) {
|
||||
if (count == 3) {
|
||||
machine_timer_enable(0);
|
||||
// TODO: do something
|
||||
set_test_pass();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
machine_timer_set_cmp_val(500000); // 10ms period
|
||||
machine_timer_clear_irq_pending();
|
||||
global_irq_enable();
|
||||
machine_timer_irq_enable(1);
|
||||
machine_timer_enable(1);
|
||||
|
||||
GPIO_REG(GPIO_CTRL) |= 0x1; // set gpio0 output mode
|
||||
|
||||
while (1) {
|
||||
// 500ms
|
||||
if (count == 50) {
|
||||
count = 0;
|
||||
GPIO_REG(GPIO_DATA) ^= 0x1; // toggle led
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void timer_irq_handler() __attribute__((interrupt));
|
||||
void timer_irq_handler()
|
||||
{
|
||||
count++;
|
||||
|
||||
machine_timer_clear_irq_pending();
|
||||
}
|
Loading…
Reference in New Issue