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,17 +166,70 @@ 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),
|
||||
.req_i(),
|
||||
.gnt_o(),
|
||||
.addr_i(slave_addr[SimCtrl]),
|
||||
.we_i(slave_we[SimCtrl]),
|
||||
.be_i(slave_be[SimCtrl]),
|
||||
.clk_i (clk),
|
||||
.rst_ni (ndmreset_n),
|
||||
.req_i (),
|
||||
.gnt_o (),
|
||||
.addr_i (slave_addr[SimCtrl]),
|
||||
.we_i (slave_we[SimCtrl]),
|
||||
.be_i (slave_be[SimCtrl]),
|
||||
.wdata_i(slave_wdata[SimCtrl]),
|
||||
.rdata_o(slave_rdata[SimCtrl])
|
||||
);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.bin
|
||||
*.dump
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.bin
|
||||
*.dump
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
**include**: 公共头文件目录。
|
||||
|
||||
**include**: 公共头文件目录。
|
||||
|
||||
**lib**: 公共函数目录。
|
|
@ -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
|
|
@ -1,19 +1,19 @@
|
|||
#ifndef _TRAP_CODE_H_
|
||||
#define _TRAP_CODE_H_
|
||||
|
||||
#define TRAP_USER_SW (0x80000000)
|
||||
#define TRAP_MACH_SW (0x80000003)
|
||||
#define TRAP_USER_TIMER (0x80000004)
|
||||
#define TRAP_MACH_TIMER (0x80000007)
|
||||
#define TRAP_USER_EXT (0x80000008)
|
||||
#define TRAP_MACH_EXT (0x8000000B)
|
||||
#define TRAP_INST_ADDR_MISA (0x00000000)
|
||||
#define TRAP_ILLEGAL_INST (0x00000002)
|
||||
#define TRAP_BREAKPOINT (0x00000003)
|
||||
#define TRAP_LOAD_ADDR_MISA (0x00000004)
|
||||
#define TRAP_STORE_ADDR_MISA (0x00000006)
|
||||
#define TRAP_ECALL_U (0x00000008)
|
||||
#define TRAP_ECALL_S (0x00000009)
|
||||
#define TRAP_ECALL_M (0x0000000B)
|
||||
|
||||
#endif
|
||||
#ifndef _TRAP_CODE_H_
|
||||
#define _TRAP_CODE_H_
|
||||
|
||||
#define TRAP_USER_SW (0x80000000)
|
||||
#define TRAP_MACH_SW (0x80000003)
|
||||
#define TRAP_USER_TIMER (0x80000004)
|
||||
#define TRAP_MACH_TIMER (0x80000007)
|
||||
#define TRAP_USER_EXT (0x80000008)
|
||||
#define TRAP_MACH_EXT (0x8000000B)
|
||||
#define TRAP_INST_ADDR_MISA (0x00000000)
|
||||
#define TRAP_ILLEGAL_INST (0x00000002)
|
||||
#define TRAP_BREAKPOINT (0x00000003)
|
||||
#define TRAP_LOAD_ADDR_MISA (0x00000004)
|
||||
#define TRAP_STORE_ADDR_MISA (0x00000006)
|
||||
#define TRAP_ECALL_U (0x00000008)
|
||||
#define TRAP_ECALL_S (0x00000009)
|
||||
#define TRAP_ECALL_M (0x0000000B)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,28 +1,33 @@
|
|||
#ifndef _UTILS_H_
|
||||
#define _UTILS_H_
|
||||
|
||||
#define CPU_FREQ_HZ (50000000) // 50MHz
|
||||
#define CPU_FREQ_MHZ (50) // 50MHz
|
||||
|
||||
|
||||
#define read_csr(reg) ({ unsigned long __tmp; \
|
||||
asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
|
||||
__tmp; })
|
||||
|
||||
#define write_csr(reg, val) ({ \
|
||||
if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
|
||||
asm volatile ("csrw " #reg ", %0" :: "i"(val)); \
|
||||
else \
|
||||
asm volatile ("csrw " #reg ", %0" :: "r"(val)); })
|
||||
|
||||
|
||||
#ifdef SIMULATION
|
||||
#define set_test_pass() asm("li x27, 0x01")
|
||||
#define set_test_fail() asm("li x27, 0x00")
|
||||
#endif
|
||||
|
||||
|
||||
uint64_t get_cycle_value();
|
||||
void busy_wait(uint32_t us);
|
||||
|
||||
#endif
|
||||
#ifndef _UTILS_H_
|
||||
#define _UTILS_H_
|
||||
|
||||
#define CPU_FREQ_HZ (50000000) // 50MHz
|
||||
#define CPU_FREQ_MHZ (50) // 50MHz
|
||||
|
||||
|
||||
#define read_csr(reg) ({ unsigned long __tmp; \
|
||||
asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
|
||||
__tmp; })
|
||||
|
||||
#define write_csr(reg, val) ({ \
|
||||
if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
|
||||
asm volatile ("csrw " #reg ", %0" :: "i"(val)); \
|
||||
else \
|
||||
asm volatile ("csrw " #reg ", %0" :: "r"(val)); })
|
||||
|
||||
|
||||
#ifdef SIMULATION
|
||||
#define set_test_pass() asm("li x27, 0x01")
|
||||
#define set_test_fail() asm("li x27, 0x00")
|
||||
#endif
|
||||
|
||||
|
||||
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
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
/*------------------------------------------------------------------------*/
|
||||
/* Universal string handler for user console interface (C)ChaN, 2011 */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _XPRINTF_H_
|
||||
#define _XPRINTF_H_
|
||||
|
||||
#define _CR_CRLF 0 /* 1: Convert \n ==> \r\n in the output char */
|
||||
|
||||
#define xdev_out(func) xfunc_out = (void(*)(unsigned char))(func)
|
||||
extern void (*xfunc_out)(unsigned char);
|
||||
void xputc (char c);
|
||||
void xputs (const char* str);
|
||||
void xprintf (const char* fmt, ...);
|
||||
#define DW_CHAR sizeof(char)
|
||||
#define DW_SHORT sizeof(short)
|
||||
#define DW_LONG sizeof(long)
|
||||
|
||||
#endif
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Universal string handler for user console interface (C)ChaN, 2011 */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _XPRINTF_H_
|
||||
#define _XPRINTF_H_
|
||||
|
||||
#define _CR_CRLF 0 /* 1: Convert \n ==> \r\n in the output char */
|
||||
|
||||
#define xdev_out(func) xfunc_out = (void(*)(unsigned char))(func)
|
||||
extern void (*xfunc_out)(unsigned char);
|
||||
void xputc (char c);
|
||||
void xputs (const char* str);
|
||||
void xprintf (const char* fmt, ...);
|
||||
#define DW_CHAR sizeof(char)
|
||||
#define DW_SHORT sizeof(short)
|
||||
#define DW_LONG sizeof(long)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.bin
|
||||
*.dump
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.bin
|
||||
*.dump
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -1,29 +1,29 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "../include/uart.h"
|
||||
#include "../include/xprintf.h"
|
||||
|
||||
|
||||
// send one char to uart
|
||||
void uart_putc(uint8_t c)
|
||||
{
|
||||
while (UART0_REG(UART0_STATUS) & 0x1);
|
||||
UART0_REG(UART0_TXDATA) = c;
|
||||
}
|
||||
|
||||
// Block, get one char from uart.
|
||||
uint8_t uart_getc()
|
||||
{
|
||||
UART0_REG(UART0_STATUS) &= ~0x2;
|
||||
while (!(UART0_REG(UART0_STATUS) & 0x2));
|
||||
return (UART0_REG(UART0_RXDATA) & 0xff);
|
||||
}
|
||||
|
||||
// 115200bps, 8 N 1
|
||||
void uart_init()
|
||||
{
|
||||
// enable tx and rx
|
||||
UART0_REG(UART0_CTRL) = 0x3;
|
||||
|
||||
xdev_out(uart_putc);
|
||||
}
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../include/uart.h"
|
||||
#include "../include/xprintf.h"
|
||||
|
||||
|
||||
// send one char to uart
|
||||
void uart_putc(uint8_t c)
|
||||
{
|
||||
while (UART0_REG(UART0_STATUS) & 0x1);
|
||||
UART0_REG(UART0_TXDATA) = c;
|
||||
}
|
||||
|
||||
// Block, get one char from uart.
|
||||
uint8_t uart_getc()
|
||||
{
|
||||
UART0_REG(UART0_STATUS) &= ~0x2;
|
||||
while (!(UART0_REG(UART0_STATUS) & 0x2));
|
||||
return (UART0_REG(UART0_RXDATA) & 0xff);
|
||||
}
|
||||
|
||||
// 115200bps, 8 N 1
|
||||
void uart_init()
|
||||
{
|
||||
// enable tx and rx
|
||||
UART0_REG(UART0_CTRL) = 0x3;
|
||||
|
||||
xdev_out(uart_putc);
|
||||
}
|
||||
|
|
|
@ -1,26 +1,46 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "../include/utils.h"
|
||||
|
||||
|
||||
|
||||
uint64_t get_cycle_value()
|
||||
{
|
||||
uint64_t cycle;
|
||||
|
||||
cycle = read_csr(cycle);
|
||||
cycle += (uint64_t)(read_csr(cycleh)) << 32;
|
||||
|
||||
return cycle;
|
||||
}
|
||||
|
||||
void busy_wait(uint32_t us)
|
||||
{
|
||||
uint64_t tmp;
|
||||
uint32_t count;
|
||||
|
||||
count = us * CPU_FREQ_MHZ;
|
||||
tmp = get_cycle_value();
|
||||
|
||||
while (get_cycle_value() < (tmp + count));
|
||||
}
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../include/utils.h"
|
||||
|
||||
|
||||
|
||||
uint64_t get_cycle_value()
|
||||
{
|
||||
uint64_t cycle;
|
||||
|
||||
cycle = read_csr(cycle);
|
||||
cycle += (uint64_t)(read_csr(cycleh)) << 32;
|
||||
|
||||
return cycle;
|
||||
}
|
||||
|
||||
void busy_wait(uint32_t us)
|
||||
{
|
||||
uint64_t tmp;
|
||||
uint32_t count;
|
||||
|
||||
count = us * CPU_FREQ_MHZ;
|
||||
tmp = get_cycle_value();
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -1,157 +1,157 @@
|
|||
/*------------------------------------------------------------------------/
|
||||
/ Universal string handler for user console interface
|
||||
/-------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2011, ChaN, all right reserved.
|
||||
/
|
||||
/ * This software is a free software and there is NO WARRANTY.
|
||||
/ * No restriction on use. You can use, modify and redistribute it for
|
||||
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
|
||||
/ * Redistributions of source code must retain the above copyright notice.
|
||||
/
|
||||
/-------------------------------------------------------------------------*/
|
||||
|
||||
#include "../include/xprintf.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
void (*xfunc_out)(unsigned char); /* Pointer to the output stream */
|
||||
static char *outptr;
|
||||
|
||||
/*----------------------------------------------*/
|
||||
/* Put a character */
|
||||
/*----------------------------------------------*/
|
||||
|
||||
void xputc (char c)
|
||||
{
|
||||
if (_CR_CRLF && c == '\n') xputc('\r'); /* CR -> CRLF */
|
||||
|
||||
if (outptr) {
|
||||
*outptr++ = (unsigned char)c;
|
||||
return;
|
||||
}
|
||||
|
||||
if (xfunc_out) xfunc_out((unsigned char)c);
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------*/
|
||||
/* Put a null-terminated string */
|
||||
/*----------------------------------------------*/
|
||||
|
||||
void xputs ( /* Put a string to the default device */
|
||||
const char* str /* Pointer to the string */
|
||||
)
|
||||
{
|
||||
while (*str)
|
||||
xputc(*str++);
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------*/
|
||||
/* Formatted string output */
|
||||
/*----------------------------------------------*/
|
||||
/* xprintf("%d", 1234); "1234"
|
||||
xprintf("%6d,%3d%%", -200, 5); " -200, 5%"
|
||||
xprintf("%-6u", 100); "100 "
|
||||
xprintf("%ld", 12345678L); "12345678"
|
||||
xprintf("%04x", 0xA3); "00a3"
|
||||
xprintf("%08LX", 0x123ABC); "00123ABC"
|
||||
xprintf("%016b", 0x550F); "0101010100001111"
|
||||
xprintf("%s", "String"); "String"
|
||||
xprintf("%-4s", "abc"); "abc "
|
||||
xprintf("%4s", "abc"); " abc"
|
||||
xprintf("%c", 'a'); "a"
|
||||
xprintf("%f", 10.0); <xprintf lacks floating point support>
|
||||
*/
|
||||
|
||||
static
|
||||
void xvprintf (
|
||||
const char* fmt, /* Pointer to the format string */
|
||||
va_list arp /* Pointer to arguments */
|
||||
)
|
||||
{
|
||||
unsigned int r, i, j, w, f;
|
||||
unsigned long v;
|
||||
char s[16], c, d, *p;
|
||||
|
||||
|
||||
for (;;) {
|
||||
c = *fmt++; /* Get a char */
|
||||
if (!c) break; /* End of format? */
|
||||
if (c != '%') { /* Pass through it if not a % sequense */
|
||||
xputc(c); continue;
|
||||
}
|
||||
f = 0;
|
||||
c = *fmt++; /* Get first char of the sequense */
|
||||
if (c == '0') { /* Flag: '0' padded */
|
||||
f = 1; c = *fmt++;
|
||||
} else {
|
||||
if (c == '-') { /* Flag: left justified */
|
||||
f = 2; c = *fmt++;
|
||||
}
|
||||
}
|
||||
for (w = 0; c >= '0' && c <= '9'; c = *fmt++) /* Minimum width */
|
||||
w = w * 10 + c - '0';
|
||||
if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
|
||||
f |= 4; c = *fmt++;
|
||||
}
|
||||
if (!c) break; /* End of format? */
|
||||
d = c;
|
||||
if (d >= 'a') d -= 0x20;
|
||||
switch (d) { /* Type is... */
|
||||
case 'S' : /* String */
|
||||
p = va_arg(arp, char*);
|
||||
for (j = 0; p[j]; j++) ;
|
||||
while (!(f & 2) && j++ < w) xputc(' ');
|
||||
xputs(p);
|
||||
while (j++ < w) xputc(' ');
|
||||
continue;
|
||||
case 'C' : /* Character */
|
||||
xputc((char)va_arg(arp, int)); continue;
|
||||
case 'B' : /* Binary */
|
||||
r = 2; break;
|
||||
case 'O' : /* Octal */
|
||||
r = 8; break;
|
||||
case 'D' : /* Signed decimal */
|
||||
case 'U' : /* Unsigned decimal */
|
||||
r = 10; break;
|
||||
case 'X' : /* Hexdecimal */
|
||||
r = 16; break;
|
||||
default: /* Unknown type (passthrough) */
|
||||
xputc(c); continue;
|
||||
}
|
||||
|
||||
/* Get an argument and put it in numeral */
|
||||
v = (f & 4) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : (long)va_arg(arp, unsigned int));
|
||||
if (d == 'D' && (v & 0x80000000)) {
|
||||
v = 0 - v;
|
||||
f |= 8;
|
||||
}
|
||||
i = 0;
|
||||
do {
|
||||
d = (char)(v % r); v /= r;
|
||||
if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
|
||||
s[i++] = d + '0';
|
||||
} while (v && i < sizeof(s));
|
||||
if (f & 8) s[i++] = '-';
|
||||
j = i; d = (f & 1) ? '0' : ' ';
|
||||
while (!(f & 2) && j++ < w) xputc(d);
|
||||
do xputc(s[--i]); while(i);
|
||||
while (j++ < w) xputc(' ');
|
||||
}
|
||||
}
|
||||
|
||||
void xprintf ( /* Put a formatted string to the default device */
|
||||
const char* fmt, /* Pointer to the format string */
|
||||
... /* Optional arguments */
|
||||
)
|
||||
{
|
||||
va_list arp;
|
||||
|
||||
|
||||
va_start(arp, fmt);
|
||||
xvprintf(fmt, arp);
|
||||
va_end(arp);
|
||||
}
|
||||
/*------------------------------------------------------------------------/
|
||||
/ Universal string handler for user console interface
|
||||
/-------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2011, ChaN, all right reserved.
|
||||
/
|
||||
/ * This software is a free software and there is NO WARRANTY.
|
||||
/ * No restriction on use. You can use, modify and redistribute it for
|
||||
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
|
||||
/ * Redistributions of source code must retain the above copyright notice.
|
||||
/
|
||||
/-------------------------------------------------------------------------*/
|
||||
|
||||
#include "../include/xprintf.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
void (*xfunc_out)(unsigned char); /* Pointer to the output stream */
|
||||
static char *outptr;
|
||||
|
||||
/*----------------------------------------------*/
|
||||
/* Put a character */
|
||||
/*----------------------------------------------*/
|
||||
|
||||
void xputc (char c)
|
||||
{
|
||||
if (_CR_CRLF && c == '\n') xputc('\r'); /* CR -> CRLF */
|
||||
|
||||
if (outptr) {
|
||||
*outptr++ = (unsigned char)c;
|
||||
return;
|
||||
}
|
||||
|
||||
if (xfunc_out) xfunc_out((unsigned char)c);
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------*/
|
||||
/* Put a null-terminated string */
|
||||
/*----------------------------------------------*/
|
||||
|
||||
void xputs ( /* Put a string to the default device */
|
||||
const char* str /* Pointer to the string */
|
||||
)
|
||||
{
|
||||
while (*str)
|
||||
xputc(*str++);
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------*/
|
||||
/* Formatted string output */
|
||||
/*----------------------------------------------*/
|
||||
/* xprintf("%d", 1234); "1234"
|
||||
xprintf("%6d,%3d%%", -200, 5); " -200, 5%"
|
||||
xprintf("%-6u", 100); "100 "
|
||||
xprintf("%ld", 12345678L); "12345678"
|
||||
xprintf("%04x", 0xA3); "00a3"
|
||||
xprintf("%08LX", 0x123ABC); "00123ABC"
|
||||
xprintf("%016b", 0x550F); "0101010100001111"
|
||||
xprintf("%s", "String"); "String"
|
||||
xprintf("%-4s", "abc"); "abc "
|
||||
xprintf("%4s", "abc"); " abc"
|
||||
xprintf("%c", 'a'); "a"
|
||||
xprintf("%f", 10.0); <xprintf lacks floating point support>
|
||||
*/
|
||||
|
||||
static
|
||||
void xvprintf (
|
||||
const char* fmt, /* Pointer to the format string */
|
||||
va_list arp /* Pointer to arguments */
|
||||
)
|
||||
{
|
||||
unsigned int r, i, j, w, f;
|
||||
unsigned long v;
|
||||
char s[16], c, d, *p;
|
||||
|
||||
|
||||
for (;;) {
|
||||
c = *fmt++; /* Get a char */
|
||||
if (!c) break; /* End of format? */
|
||||
if (c != '%') { /* Pass through it if not a % sequense */
|
||||
xputc(c); continue;
|
||||
}
|
||||
f = 0;
|
||||
c = *fmt++; /* Get first char of the sequense */
|
||||
if (c == '0') { /* Flag: '0' padded */
|
||||
f = 1; c = *fmt++;
|
||||
} else {
|
||||
if (c == '-') { /* Flag: left justified */
|
||||
f = 2; c = *fmt++;
|
||||
}
|
||||
}
|
||||
for (w = 0; c >= '0' && c <= '9'; c = *fmt++) /* Minimum width */
|
||||
w = w * 10 + c - '0';
|
||||
if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
|
||||
f |= 4; c = *fmt++;
|
||||
}
|
||||
if (!c) break; /* End of format? */
|
||||
d = c;
|
||||
if (d >= 'a') d -= 0x20;
|
||||
switch (d) { /* Type is... */
|
||||
case 'S' : /* String */
|
||||
p = va_arg(arp, char*);
|
||||
for (j = 0; p[j]; j++) ;
|
||||
while (!(f & 2) && j++ < w) xputc(' ');
|
||||
xputs(p);
|
||||
while (j++ < w) xputc(' ');
|
||||
continue;
|
||||
case 'C' : /* Character */
|
||||
xputc((char)va_arg(arp, int)); continue;
|
||||
case 'B' : /* Binary */
|
||||
r = 2; break;
|
||||
case 'O' : /* Octal */
|
||||
r = 8; break;
|
||||
case 'D' : /* Signed decimal */
|
||||
case 'U' : /* Unsigned decimal */
|
||||
r = 10; break;
|
||||
case 'X' : /* Hexdecimal */
|
||||
r = 16; break;
|
||||
default: /* Unknown type (passthrough) */
|
||||
xputc(c); continue;
|
||||
}
|
||||
|
||||
/* Get an argument and put it in numeral */
|
||||
v = (f & 4) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : (long)va_arg(arp, unsigned int));
|
||||
if (d == 'D' && (v & 0x80000000)) {
|
||||
v = 0 - v;
|
||||
f |= 8;
|
||||
}
|
||||
i = 0;
|
||||
do {
|
||||
d = (char)(v % r); v /= r;
|
||||
if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
|
||||
s[i++] = d + '0';
|
||||
} while (v && i < sizeof(s));
|
||||
if (f & 8) s[i++] = '-';
|
||||
j = i; d = (f & 1) ? '0' : ' ';
|
||||
while (!(f & 2) && j++ < w) xputc(d);
|
||||
do xputc(s[--i]); while(i);
|
||||
while (j++ < w) xputc(' ');
|
||||
}
|
||||
}
|
||||
|
||||
void xprintf ( /* Put a formatted string to the default device */
|
||||
const char* fmt, /* Pointer to the format string */
|
||||
... /* Optional arguments */
|
||||
)
|
||||
{
|
||||
va_list arp;
|
||||
|
||||
|
||||
va_start(arp, fmt);
|
||||
xvprintf(fmt, arp);
|
||||
va_end(arp);
|
||||
}
|
||||
|
|
|
@ -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