abstractaccelerator/uriscv/demo/top.v

3813 lines
84 KiB
Verilog

//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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 riscv_core
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
parameter SUPPORT_MUL = 1
,parameter SUPPORT_DIV = 1
,parameter SUPPORT_CSR = 1
,parameter SUPPORT_TRAP_LSU_ALIGN = 1
,parameter SUPPORT_MTVEC = 0
,parameter SUPPORT_MTVAL = 0
,parameter SUPPORT_MIP_MIE = 0
,parameter SUPPORT_MSCRATCH = 0
,parameter SUPPORT_MCYCLE = 1
,parameter SUPPORT_MTIMECMP = 0
,parameter SUPPORT_TRAP_INVALID_OPC = 1
,parameter SUPPORT_BRAM_REGFILE = 0
,parameter ISR_VECTOR = 32'h00000010
)
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
// Clock
input clk_i
// Reset (active high)
,input rst_i
// External interrupt (M_EXT)
,input intr_i
// Initial boot address
,input [ 31:0] reset_vector_i
// MHARTID value
,input [ 31:0] cpu_id_i
// Instruction Fetch
,output mem_i_rd_o
,output [ 31:0] mem_i_pc_o
,input mem_i_accept_i
,input mem_i_valid_i
,input [ 31:0] mem_i_inst_i
// Instruction fetch: Unused on this core
,output mem_i_flush_o
,output mem_i_invalidate_o
// Instruction fetch: Unused (tie low)
,input mem_i_error_i
// Data Access
,output [ 31:0] mem_d_addr_o
,output [ 31:0] mem_d_data_wr_o
,output mem_d_rd_o
,output [ 3:0] mem_d_wr_o
,input [ 31:0] mem_d_data_rd_i
,input mem_d_accept_i
,input mem_d_ack_i
// Instruction fetch: Unused on this core
,output mem_d_cacheable_o
,output [ 10:0] mem_d_req_tag_o
,output mem_d_invalidate_o
,output mem_d_writeback_o
,output mem_d_flush_o
// Data Access: Unused (tie low)
,input mem_d_error_i
,input [ 10:0] mem_d_resp_tag_i
);
//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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.
//-----------------------------------------------------------------
//--------------------------------------------------------------------
// ALU Operations
//--------------------------------------------------------------------
//-----------------------------------------------------------------
// Privilege levels
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Status Register
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// IRQ Numbers
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// CSR Registers - Machine
//-----------------------------------------------------------------
// Non-std
//-----------------------------------------------------------------
// CSR Registers - Simulation control
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Exception Causes
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Debug defines for exception types
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
localparam PC_W = 32;
localparam PC_PAD_W = 0;
localparam PC_EXT_W = 0;
localparam ADDR_W = 32;
localparam ADDR_PAD_W = 0;
// Current state
localparam STATE_W = 3;
localparam STATE_RESET = 0;
localparam STATE_FETCH_WB = 1;
localparam STATE_EXEC = 2;
localparam STATE_MEM = 3;
localparam STATE_DECODE = 4; // Only if SUPPORT_BRAM_REGFILE = 1
//-----------------------------------------------------------------
// Registers
//-----------------------------------------------------------------
// Current state
reg [STATE_W-1:0] state_q;
// Executing PC
reg [PC_W-1:0] pc_q;
// Destination register
reg [4:0] rd_q;
// Destination writeback enable
reg rd_wr_en_q;
// ALU inputs
reg [31:0] alu_a_q;
reg [31:0] alu_b_q;
// ALU operation selection
reg [3:0] alu_func_q;
// CSR read data
wire [31:0] csr_data_w;
// Instruction decode fault
reg invalid_inst_r;
// Register indexes
wire [4:0] rd_w;
wire [4:0] rs1_w;
wire [4:0] rs2_w;
// Operand values
wire [31:0] rs1_val_w;
wire [31:0] rs2_val_w;
// Opcode (memory bus)
wire [31:0] opcode_w;
wire opcode_valid_w;
wire opcode_fetch_w = mem_i_rd_o & mem_i_accept_i;
// Execute exception (or interrupt)
wire exception_w;
wire [5:0] exception_type_w;
wire [31:0] exception_target_w;
wire [31:0] csr_mepc_w;
// Load result (formatted based on load type)
reg [31:0] load_result_r;
// Writeback enable / value
wire rd_writeen_w;
wire [31:0] rd_val_w;
// Memory interface
wire mem_misaligned_w;
reg [ADDR_W-1:0] mem_addr_q;
reg [31:0] mem_data_q;
reg [3:0] mem_wr_q;
reg mem_rd_q;
// Load type / byte / half index
reg [1:0] load_offset_q;
reg load_signed_q;
reg load_byte_q;
reg load_half_q;
wire enable_w = 1'b1;
wire [31:0] muldiv_result_w;
wire muldiv_ready_w;
wire muldiv_inst_w;
//-----------------------------------------------------------------
// ALU
//-----------------------------------------------------------------
uriscv_alu alu
(
// ALU operation select
.op_i(alu_func_q),
// Operands
.a_i(alu_a_q),
.b_i(alu_b_q),
// Result
.p_o(rd_val_w)
);
//-----------------------------------------------------------------
// Register file
//-----------------------------------------------------------------
reg [31:0] reg_file[0:31];
always @ (posedge clk_i)
if (rd_writeen_w)
reg_file[rd_q] <= rd_val_w;
wire [31:0] rs1_val_gpr_w = reg_file[mem_i_inst_i[19:15]];
wire [31:0] rs2_val_gpr_w = reg_file[mem_i_inst_i[24:20]];
reg [31:0] rs1_val_gpr_q;
reg [31:0] rs2_val_gpr_q;
always @ (posedge clk_i)
begin
rs1_val_gpr_q <= rs1_val_gpr_w;
rs2_val_gpr_q <= rs2_val_gpr_w;
end
assign rs1_val_w = SUPPORT_BRAM_REGFILE ? rs1_val_gpr_q : rs1_val_gpr_w;
assign rs2_val_w = SUPPORT_BRAM_REGFILE ? rs2_val_gpr_q : rs2_val_gpr_w;
// Writeback enable
assign rd_writeen_w = rd_wr_en_q & (state_q == STATE_FETCH_WB);
// Simulation friendly names
//-----------------------------------------------------------------
// Next State Logic
//-----------------------------------------------------------------
reg [STATE_W-1:0] next_state_r;
always @ *
begin
next_state_r = state_q;
case (state_q)
// RESET - First cycle after reset
STATE_RESET:
begin
next_state_r = STATE_FETCH_WB;
end
// FETCH_WB - Writeback / Fetch next isn
STATE_FETCH_WB :
begin
if (opcode_fetch_w)
next_state_r = SUPPORT_BRAM_REGFILE ? STATE_DECODE : STATE_EXEC;
end
// DECODE - Used to access register file if SUPPORT_BRAM_REGFILE=1
STATE_DECODE:
begin
if (mem_i_valid_i)
next_state_r = STATE_EXEC;
end
// EXEC - Execute instruction (when ready)
STATE_EXEC :
begin
// Instruction ready
if (opcode_valid_w)
begin
if (exception_w)
next_state_r = STATE_FETCH_WB;
else if (type_load_w || type_store_w)
next_state_r = STATE_MEM;
// Multiplication / division - stay in exec state until result ready
else if (muldiv_inst_w)
;
else
next_state_r = STATE_FETCH_WB;
end
else if (muldiv_ready_w)
next_state_r = STATE_FETCH_WB;
end
// MEM - Perform load or store
STATE_MEM :
begin
// Memory access complete
if (mem_d_ack_i)
next_state_r = STATE_FETCH_WB;
end
default:
;
endcase
if (!enable_w)
next_state_r = STATE_RESET;
end
// Update state
always @ (posedge clk_i )
if (rst_i)
state_q <= STATE_RESET;
else
state_q <= next_state_r;
//-----------------------------------------------------------------
// Instruction Decode
//-----------------------------------------------------------------
reg [31:0] opcode_q;
always @ (posedge clk_i )
if (rst_i)
opcode_q <= 32'b0;
else if (state_q == STATE_DECODE)
opcode_q <= mem_i_inst_i;
reg opcode_valid_q;
always @ (posedge clk_i )
if (rst_i)
opcode_valid_q <= 1'b0;
else if (state_q == STATE_DECODE)
opcode_valid_q <= mem_i_valid_i;
else
opcode_valid_q <= 1'b0;
assign opcode_w = SUPPORT_BRAM_REGFILE ? opcode_q : mem_i_inst_i;
assign opcode_valid_w = SUPPORT_BRAM_REGFILE ? opcode_valid_q : mem_i_valid_i;
assign rs1_w = opcode_w[19:15];
assign rs2_w = opcode_w[24:20];
assign rd_w = opcode_w[11:7];
wire type_rvc_w = (opcode_w[1:0] != 2'b11);
wire type_load_w = (opcode_w[6:2] == 5'b00000);
wire type_opimm_w = (opcode_w[6:2] == 5'b00100);
wire type_auipc_w = (opcode_w[6:2] == 5'b00101);
wire type_store_w = (opcode_w[6:2] == 5'b01000);
wire type_op_w = (opcode_w[6:2] == 5'b01100);
wire type_lui_w = (opcode_w[6:2] == 5'b01101);
wire type_branch_w = (opcode_w[6:2] == 5'b11000);
wire type_jalr_w = (opcode_w[6:2] == 5'b11001);
wire type_jal_w = (opcode_w[6:2] == 5'b11011);
wire type_system_w = (opcode_w[6:2] == 5'b11100);
wire type_miscm_w = (opcode_w[6:2] == 5'b00011);
wire [2:0] func3_w = opcode_w[14:12]; // R, I, S
wire [6:0] func7_w = opcode_w[31:25]; // R
// ALU operations excluding mul/div
wire type_alu_op_w = (type_op_w && (func7_w == 7'b0000000)) ||
(type_op_w && (func7_w == 7'b0100000));
// Loose decoding - gate with type_load_w on use
wire inst_lb_w = (func3_w == 3'b000);
wire inst_lh_w = (func3_w == 3'b001);
wire inst_lbu_w = (func3_w == 3'b100);
wire inst_lhu_w = (func3_w == 3'b101);
wire inst_ecall_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h000000);
wire inst_ebreak_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h002000);
wire inst_mret_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h604000);
wire inst_csr_w = SUPPORT_CSR && type_system_w && (func3_w != 3'b000 && func3_w != 3'b100);
wire mul_inst_w = SUPPORT_MUL && type_op_w && (func7_w == 7'b0000001) && ~func3_w[2];
wire div_inst_w = SUPPORT_DIV && type_op_w && (func7_w == 7'b0000001) && func3_w[2];
wire inst_mul_w = mul_inst_w && (func3_w == 3'b000);
wire inst_mulh_w = mul_inst_w && (func3_w == 3'b001);
wire inst_mulhsu_w = mul_inst_w && (func3_w == 3'b010);
wire inst_mulhu_w = mul_inst_w && (func3_w == 3'b011);
wire inst_div_w = div_inst_w && (func3_w == 3'b100);
wire inst_divu_w = div_inst_w && (func3_w == 3'b101);
wire inst_rem_w = div_inst_w && (func3_w == 3'b110);
wire inst_remu_w = div_inst_w && (func3_w == 3'b111);
wire inst_nop_w = (type_miscm_w && (func3_w == 3'b000)) | // fence
(type_miscm_w && (func3_w == 3'b001)); // fence.i
assign muldiv_inst_w = mul_inst_w | div_inst_w;
reg [31:0] imm20_r;
reg [31:0] imm12_r;
always @ *
begin
imm20_r = {opcode_w[31:12], 12'b0};
imm12_r = {{20{opcode_w[31]}}, opcode_w[31:20]};
end
//-----------------------------------------------------------------
// ALU inputs
//-----------------------------------------------------------------
// ALU operation selection
reg [3:0] alu_func_r;
// ALU operands
reg [31:0] alu_input_a_r;
reg [31:0] alu_input_b_r;
reg write_rd_r;
always @ *
begin
alu_func_r = 4'b0000;
alu_input_a_r = rs1_val_w;
alu_input_b_r = rs2_val_w;
write_rd_r = 1'b0;
case (1'b1)
type_alu_op_w:
begin
alu_input_a_r = rs1_val_w;
alu_input_b_r = rs2_val_w;
end
type_opimm_w:
begin
alu_input_a_r = rs1_val_w;
alu_input_b_r = imm12_r;
end
type_lui_w:
begin
alu_input_a_r = 32'b0;
alu_input_b_r = imm20_r;
end
type_auipc_w:
begin
alu_input_a_r[PC_W-1:0] = pc_q;
alu_input_b_r = imm20_r;
end
type_jal_w,
type_jalr_w:
begin
alu_input_a_r[PC_W-1:0] = pc_q;
alu_input_b_r = 32'd4;
end
default : ;
endcase
if (muldiv_inst_w)
write_rd_r = 1'b1;
else if (type_opimm_w || type_alu_op_w)
begin
case (func3_w)
3'b000: alu_func_r = (type_op_w & opcode_w[30]) ?
4'b0110: // SUB
4'b0100; // ADD / ADDI
3'b001: alu_func_r = 4'b0001; // SLL / SLLI
3'b010: alu_func_r = 4'b1011; // SLT / SLTI
3'b011: alu_func_r = 4'b1010; // SLTU / SLTIU
3'b100: alu_func_r = 4'b1001; // XOR / XORI
3'b101: alu_func_r = opcode_w[30] ?
4'b0011: // SRA / SRAI
4'b0010; // SRL / SRLI
3'b110: alu_func_r = 4'b1000; // OR / ORI
3'b111: alu_func_r = 4'b0111; // AND / ANDI
endcase
write_rd_r = 1'b1;
end
else if (inst_csr_w)
begin
alu_func_r = 4'b0100;
alu_input_a_r = 32'b0;
alu_input_b_r = csr_data_w;
write_rd_r = 1'b1;
end
else if (type_auipc_w || type_lui_w || type_jalr_w || type_jal_w)
begin
write_rd_r = 1'b1;
alu_func_r = 4'b0100;
end
else if (type_load_w)
write_rd_r = 1'b1;
end
//-------------------------------------------------------------------
// Load result resolve
//-------------------------------------------------------------------
always @ *
begin
load_result_r = 32'b0;
if (load_byte_q)
begin
case (load_offset_q[1:0])
2'h3:
load_result_r = {24'b0, mem_d_data_rd_i[31:24]};
2'h2:
load_result_r = {24'b0, mem_d_data_rd_i[23:16]};
2'h1:
load_result_r = {24'b0, mem_d_data_rd_i[15:8]};
2'h0:
load_result_r = {24'b0, mem_d_data_rd_i[7:0]};
endcase
if (load_signed_q && load_result_r[7])
load_result_r = {24'hFFFFFF, load_result_r[7:0]};
end
else if (load_half_q)
begin
if (load_offset_q[1])
load_result_r = {16'b0, mem_d_data_rd_i[31:16]};
else
load_result_r = {16'b0, mem_d_data_rd_i[15:0]};
if (load_signed_q && load_result_r[15])
load_result_r = {16'hFFFF, load_result_r[15:0]};
end
else
load_result_r = mem_d_data_rd_i;
end
//-----------------------------------------------------------------
// Branches
//-----------------------------------------------------------------
wire branch_w;
wire [31:0] branch_target_w;
wire [31:0] pc_ext_w = {{PC_EXT_W{1'b0}}, pc_q};
uriscv_branch
u_branch
(
.pc_i(pc_ext_w)
,.opcode_i(opcode_w)
,.rs1_val_i(rs1_val_w)
,.rs2_val_i(rs2_val_w)
,.branch_o(branch_w)
,.branch_target_o(branch_target_w)
);
//-----------------------------------------------------------------
// Invalid instruction
//-----------------------------------------------------------------
always @ *
begin
invalid_inst_r = SUPPORT_TRAP_INVALID_OPC;
if ( type_load_w
| type_opimm_w
| type_auipc_w
| type_store_w
| type_alu_op_w
| type_lui_w
| type_branch_w
| type_jalr_w
| type_jal_w
| inst_ecall_w
| inst_ebreak_w
| inst_mret_w
| inst_csr_w
| inst_nop_w
| muldiv_inst_w)
invalid_inst_r = SUPPORT_TRAP_INVALID_OPC && type_rvc_w;
end
//-----------------------------------------------------------------
// Execute: ALU control
//-----------------------------------------------------------------
always @ (posedge clk_i )
if (rst_i)
begin
alu_func_q <= 4'b0000;
alu_a_q <= 32'h00000000;
alu_b_q <= 32'h00000000;
rd_q <= 5'b00000;
// Reset x0 in-case of RAM
rd_wr_en_q <= 1'b1;
end
// Load result ready
else if ((state_q == STATE_MEM) && mem_d_ack_i)
begin
// Update ALU input with load result
alu_func_q <= 4'b0000;
alu_a_q <= load_result_r;
alu_b_q <= 32'b0;
end
// Multiplier / Divider result
else if (muldiv_ready_w)
begin
// Update ALU input with load result
alu_func_q <= 4'b0000;
alu_a_q <= muldiv_result_w;
alu_b_q <= 32'b0;
end
// Execute instruction
else if (opcode_valid_w)
begin
// Update ALU input flops
alu_func_q <= alu_func_r;
alu_a_q <= alu_input_a_r;
alu_b_q <= alu_input_b_r;
// Take exception
if (exception_w)
begin
// No register writeback
rd_q <= 5'b0;
rd_wr_en_q <= 1'b0;
end
// Valid instruction
else
begin
// Instruction with register writeback
rd_q <= rd_w;
rd_wr_en_q <= write_rd_r & (rd_w != 5'b0);
end
end
else if (state_q == STATE_FETCH_WB)
rd_wr_en_q <= 1'b0;
//-----------------------------------------------------------------
// Execute: Branch / exceptions
//-----------------------------------------------------------------
wire [31:0] boot_vector_w = reset_vector_i;
always @ (posedge clk_i )
if (rst_i)
pc_q <= boot_vector_w[PC_W-1:0];
else if (state_q == STATE_RESET)
pc_q <= boot_vector_w[PC_W-1:0];
else if (opcode_valid_w)
begin
// Exception / Break / ecall (branch to ISR)
if (exception_w || inst_ebreak_w || inst_ecall_w)
pc_q <= exception_target_w[PC_W-1:0];
// MRET (branch to EPC)
else if (inst_mret_w)
pc_q <= csr_mepc_w;
// Branch
else if (branch_w)
pc_q <= branch_target_w[PC_W-1:0];
else
pc_q <= pc_q + 32'd4;
end
//-----------------------------------------------------------------
// Writeback/Fetch: Instruction Fetch
//-----------------------------------------------------------------
assign mem_i_rd_o = (state_q == STATE_FETCH_WB);
assign mem_i_pc_o = pc_ext_w;
//-----------------------------------------------------------------
// Execute: Memory operations
//-----------------------------------------------------------------
wire mem_rd_w;
wire [3:0] mem_wr_w;
wire [31:0] mem_addr_w;
wire [31:0] mem_data_w;
uriscv_lsu
#( .SUPPORT_TRAP_LSU_ALIGN(SUPPORT_TRAP_LSU_ALIGN) )
u_lsu
(
.opcode_i(opcode_w)
,.rs1_val_i(rs1_val_w)
,.rs2_val_i(rs2_val_w)
,.mem_rd_o(mem_rd_w)
,.mem_wr_o(mem_wr_w)
,.mem_addr_o(mem_addr_w)
,.mem_data_o(mem_data_w)
,.mem_misaligned_o(mem_misaligned_w)
);
always @ (posedge clk_i )
if (rst_i)
begin
mem_addr_q <= {ADDR_W{1'b0}};
mem_data_q <= 32'h00000000;
mem_wr_q <= 4'b0000;
mem_rd_q <= 1'b0;
end
// Valid instruction to execute
else if (opcode_valid_w && !exception_w)
begin
mem_addr_q <= {mem_addr_w[ADDR_W-1:2], 2'b0};
mem_data_q <= mem_data_w;
mem_wr_q <= mem_wr_w;
mem_rd_q <= mem_rd_w;
end
// No instruction, clear memory request
else if (mem_d_accept_i)
begin
mem_wr_q <= 4'b0000;
mem_rd_q <= 1'b0;
end
always @ (posedge clk_i )
if (rst_i)
begin
load_signed_q <= 1'b0;
load_byte_q <= 1'b0;
load_half_q <= 1'b0;
load_offset_q <= 2'b0;
end
// Valid instruction to execute
else if (opcode_valid_w)
begin
load_signed_q <= inst_lh_w | inst_lb_w;
load_byte_q <= inst_lb_w | inst_lbu_w;
load_half_q <= inst_lh_w | inst_lhu_w;
load_offset_q <= mem_addr_w[1:0];
end
assign mem_d_addr_o = {{ADDR_PAD_W{1'b0}}, mem_addr_q};
assign mem_d_data_wr_o = mem_data_q;
assign mem_d_wr_o = mem_wr_q;
assign mem_d_rd_o = mem_rd_q;
//-----------------------------------------------------------------
// Execute: CSR Access
//-----------------------------------------------------------------
uriscv_csr
#(
.SUPPORT_CSR(SUPPORT_CSR)
,.SUPPORT_MCYCLE(SUPPORT_MCYCLE)
,.SUPPORT_MTIMECMP(SUPPORT_MTIMECMP)
,.SUPPORT_MSCRATCH(SUPPORT_MSCRATCH)
,.SUPPORT_MIP_MIE(SUPPORT_MIP_MIE)
,.SUPPORT_MTVEC(SUPPORT_MTVEC)
,.SUPPORT_MTVAL(SUPPORT_MTVAL)
,.SUPPORT_MULDIV(SUPPORT_MUL || SUPPORT_DIV)
)
u_csr
(
.clk_i(clk_i)
,.rst_i(rst_i)
// Reset vector (only used if SUPPORT_MTVEC=0)
,.isr_vector_i(reset_vector_i + ISR_VECTOR)
// HartID
,.cpu_id_i(cpu_id_i)
// External interrupt
,.intr_i(intr_i)
// Executing instruction
,.valid_i(opcode_valid_w)
,.opcode_i(opcode_w)
,.pc_i(pc_q)
,.rs1_val_i(rs1_val_w)
,.rs2_val_i(rs2_val_w)
// CSR read result
,.csr_rdata_o(csr_data_w)
// Exception sources
,.excpn_invalid_inst_i(invalid_inst_r)
,.excpn_lsu_align_i(mem_misaligned_w)
// Used on memory alignment errors
,.mem_addr_i(mem_addr_w)
// CSR registers
,.csr_mepc_o(csr_mepc_w)
// Exception entry
,.exception_o(exception_w)
,.exception_type_o(exception_type_w)
,.exception_pc_o(exception_target_w)
);
//-----------------------------------------------------------------
// Multiplier / Divider
//-----------------------------------------------------------------
generate
if (SUPPORT_MUL != 0 || SUPPORT_DIV != 0)
begin
uriscv_muldiv
u_muldiv
(
.clk_i(clk_i),
.rst_i(rst_i),
// Operation select
.valid_i(opcode_valid_w & ~exception_w),
.inst_mul_i(inst_mul_w),
.inst_mulh_i(inst_mulh_w),
.inst_mulhsu_i(inst_mulhsu_w),
.inst_mulhu_i(inst_mulhu_w),
.inst_div_i(inst_div_w),
.inst_divu_i(inst_divu_w),
.inst_rem_i(inst_rem_w),
.inst_remu_i(inst_remu_w),
// Operands
.operand_ra_i(rs1_val_w),
.operand_rb_i(rs2_val_w),
// Result
.stall_o(),
.ready_o(muldiv_ready_w),
.result_o(muldiv_result_w)
);
end
else
begin
assign muldiv_ready_w = 1'b0;
assign muldiv_result_w = 32'b0;
end
endgenerate
//-----------------------------------------------------------------
// Unused
//-----------------------------------------------------------------
assign mem_i_flush_o = 1'b0;
assign mem_i_invalidate_o = 1'b0;
assign mem_d_flush_o = 1'b0;
assign mem_d_cacheable_o = 1'b0;
assign mem_d_req_tag_o = 11'b0;
assign mem_d_invalidate_o = 1'b0;
assign mem_d_writeback_o = 1'b0;
//-------------------------------------------------------------------
// Hooks for debug
//-------------------------------------------------------------------
endmodule
//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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 uriscv_alu
(
// ALU operation select
input [3:0] op_i,
// Operands
input [31:0] a_i,
input [31:0] b_i,
// Result
output [31:0] p_o
);
//-----------------------------------------------------------------
// Includes
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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.
//-----------------------------------------------------------------
//--------------------------------------------------------------------
// ALU Operations
//--------------------------------------------------------------------
//-----------------------------------------------------------------
// Privilege levels
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Status Register
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// IRQ Numbers
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// CSR Registers - Machine
//-----------------------------------------------------------------
// Non-std
//-----------------------------------------------------------------
// CSR Registers - Simulation control
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Exception Causes
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Debug defines for exception types
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Registers
//-----------------------------------------------------------------
reg [31:0] result_r;
reg [31:16] shift_right_fill_r;
reg [31:0] shift_right_1_r;
reg [31:0] shift_right_2_r;
reg [31:0] shift_right_4_r;
reg [31:0] shift_right_8_r;
reg [31:0] shift_left_1_r;
reg [31:0] shift_left_2_r;
reg [31:0] shift_left_4_r;
reg [31:0] shift_left_8_r;
wire [31:0] sub_res_w = a_i - b_i;
//-----------------------------------------------------------------
// ALU
//-----------------------------------------------------------------
always @ *
begin
case (op_i)
//----------------------------------------------
// Shift Left
//----------------------------------------------
4'b0001 :
begin
if (b_i[0] == 1'b1)
shift_left_1_r = {a_i[30:0],1'b0};
else
shift_left_1_r = a_i;
if (b_i[1] == 1'b1)
shift_left_2_r = {shift_left_1_r[29:0],2'b00};
else
shift_left_2_r = shift_left_1_r;
if (b_i[2] == 1'b1)
shift_left_4_r = {shift_left_2_r[27:0],4'b0000};
else
shift_left_4_r = shift_left_2_r;
if (b_i[3] == 1'b1)
shift_left_8_r = {shift_left_4_r[23:0],8'b00000000};
else
shift_left_8_r = shift_left_4_r;
if (b_i[4] == 1'b1)
result_r = {shift_left_8_r[15:0],16'b0000000000000000};
else
result_r = shift_left_8_r;
end
//----------------------------------------------
// Shift Right
//----------------------------------------------
4'b0010, 4'b0011:
begin
// Arithmetic shift? Fill with 1's if MSB set
if (a_i[31] == 1'b1 && op_i == 4'b0011)
shift_right_fill_r = 16'b1111111111111111;
else
shift_right_fill_r = 16'b0000000000000000;
if (b_i[0] == 1'b1)
shift_right_1_r = {shift_right_fill_r[31], a_i[31:1]};
else
shift_right_1_r = a_i;
if (b_i[1] == 1'b1)
shift_right_2_r = {shift_right_fill_r[31:30], shift_right_1_r[31:2]};
else
shift_right_2_r = shift_right_1_r;
if (b_i[2] == 1'b1)
shift_right_4_r = {shift_right_fill_r[31:28], shift_right_2_r[31:4]};
else
shift_right_4_r = shift_right_2_r;
if (b_i[3] == 1'b1)
shift_right_8_r = {shift_right_fill_r[31:24], shift_right_4_r[31:8]};
else
shift_right_8_r = shift_right_4_r;
if (b_i[4] == 1'b1)
result_r = {shift_right_fill_r[31:16], shift_right_8_r[31:16]};
else
result_r = shift_right_8_r;
end
//----------------------------------------------
// Arithmetic
//----------------------------------------------
4'b0100 :
begin
result_r = (a_i + b_i);
end
4'b0110 :
begin
result_r = sub_res_w;
end
//----------------------------------------------
// Logical
//----------------------------------------------
4'b0111 :
begin
result_r = (a_i & b_i);
end
4'b1000 :
begin
result_r = (a_i | b_i);
end
4'b1001 :
begin
result_r = (a_i ^ b_i);
end
//----------------------------------------------
// Comparision
//----------------------------------------------
4'b1010 :
begin
result_r = (a_i < b_i) ? 32'h1 : 32'h0;
end
4'b1011 :
begin
if (a_i[31] != b_i[31])
result_r = a_i[31] ? 32'h1 : 32'h0;
else
result_r = sub_res_w[31] ? 32'h1 : 32'h0;
end
default :
begin
result_r = a_i;
end
endcase
end
assign p_o = result_r;
endmodule
//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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 uriscv_branch
(
input [31:0] pc_i
,input [31:0] opcode_i
,input [31:0] rs1_val_i
,input [31:0] rs2_val_i
,output branch_o
,output [31:0] branch_target_o
);
//-----------------------------------------------------------------
// Includes
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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.
//-----------------------------------------------------------------
//--------------------------------------------------------------------
// ALU Operations
//--------------------------------------------------------------------
//-----------------------------------------------------------------
// Privilege levels
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Status Register
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// IRQ Numbers
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// CSR Registers - Machine
//-----------------------------------------------------------------
// Non-std
//-----------------------------------------------------------------
// CSR Registers - Simulation control
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Exception Causes
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Debug defines for exception types
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// less_than_signed: Less than operator (signed)
// Inputs: x = left operand, y = right operand
// Return: (int)x < (int)y
//-----------------------------------------------------------------
function [0:0] less_than_signed;
input [31:0] x;
input [31:0] y;
reg [31:0] v;
begin
v = (x - y);
if (x[31] != y[31])
less_than_signed = x[31];
else
less_than_signed = v[31];
end
endfunction
//-----------------------------------------------------------------
// greater_than_signed: Greater than operator (signed)
// Inputs: x = left operand, y = right operand
// Return: (int)x > (int)y
//-----------------------------------------------------------------
function [0:0] greater_than_signed;
input [31:0] x;
input [31:0] y;
reg [31:0] v;
begin
v = (y - x);
if (x[31] != y[31])
greater_than_signed = y[31];
else
greater_than_signed = v[31];
end
endfunction
//-----------------------------------------------------------------
// Branch Decode
//-----------------------------------------------------------------
wire type_branch_w = (opcode_i[6:2] == 5'b11000);
wire type_jalr_w = (opcode_i[6:2] == 5'b11001);
wire type_jal_w = (opcode_i[6:2] == 5'b11011);
wire [2:0] func3_w = opcode_i[14:12]; // R, I, S
wire [6:0] func7_w = opcode_i[31:25]; // R
wire branch_beq_w = (func3_w == 3'b000);
wire branch_bne_w = (func3_w == 3'b001);
wire branch_blt_w = (func3_w == 3'b100);
wire branch_bge_w = (func3_w == 3'b101);
wire branch_bltu_w = (func3_w == 3'b110);
wire branch_bgeu_w = (func3_w == 3'b111);
reg branch_r;
reg [31:0] branch_target_r;
reg [31:0] imm12_r;
reg [31:0] bimm_r;
reg [31:0] jimm20_r;
always @ *
begin
branch_r = 1'b0;
branch_target_r = 32'b0;
// Opcode decode
imm12_r = {{20{opcode_i[31]}}, opcode_i[31:20]};
bimm_r = {{19{opcode_i[31]}}, opcode_i[31], opcode_i[7], opcode_i[30:25], opcode_i[11:8], 1'b0};
jimm20_r = {{12{opcode_i[31]}}, opcode_i[19:12], opcode_i[20], opcode_i[30:25], opcode_i[24:21], 1'b0};
// Default branch target is relative to current PC
branch_target_r = (pc_i + bimm_r);
if (type_jal_w)
begin
branch_r = 1'b1;
branch_target_r = pc_i + jimm20_r;
end
else if (type_jalr_w)
begin
branch_r = 1'b1;
branch_target_r = rs1_val_i + imm12_r;
branch_target_r[0] = 1'b0;
end
else if (type_branch_w)
begin
case (1'b1)
branch_beq_w: // beq
branch_r = (rs1_val_i == rs2_val_i);
branch_bne_w: // bne
branch_r = (rs1_val_i != rs2_val_i);
branch_blt_w: // blt
branch_r = less_than_signed(rs1_val_i, rs2_val_i);
branch_bge_w: // bge
branch_r = greater_than_signed(rs1_val_i, rs2_val_i) | (rs1_val_i == rs2_val_i);
branch_bltu_w: // bltu
branch_r = (rs1_val_i < rs2_val_i);
branch_bgeu_w: // bgeu
branch_r = (rs1_val_i >= rs2_val_i);
default:
;
endcase
end
end
assign branch_o = branch_r;
assign branch_target_o = branch_target_r;
endmodule
//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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 uriscv_csr
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
parameter SUPPORT_CSR = 1
,parameter SUPPORT_MCYCLE = 1
,parameter SUPPORT_MTIMECMP = 1
,parameter SUPPORT_MSCRATCH = 1
,parameter SUPPORT_MIP_MIE = 1
,parameter SUPPORT_MTVEC = 1
,parameter SUPPORT_MTVAL = 1
,parameter SUPPORT_MULDIV = 1
)
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
input clk_i
,input rst_i
,input intr_i
,input [31:0] isr_vector_i
,input [31:0] cpu_id_i
,input valid_i
,input [31:0] pc_i
,input [31:0] opcode_i
,input [31:0] rs1_val_i
,input [31:0] rs2_val_i
,output [31:0] csr_rdata_o
,input excpn_invalid_inst_i
,input excpn_lsu_align_i
,input [31:0] mem_addr_i
,output [31:0] csr_mepc_o
,output exception_o
,output [5:0] exception_type_o
,output [31:0] exception_pc_o
);
//-----------------------------------------------------------------
// Includes
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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.
//-----------------------------------------------------------------
//--------------------------------------------------------------------
// ALU Operations
//--------------------------------------------------------------------
//-----------------------------------------------------------------
// Privilege levels
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Status Register
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// IRQ Numbers
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// CSR Registers - Machine
//-----------------------------------------------------------------
// Non-std
//-----------------------------------------------------------------
// CSR Registers - Simulation control
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Exception Causes
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Debug defines for exception types
//-----------------------------------------------------------------
wire take_interrupt_w;
wire exception_w;
//-----------------------------------------------------------------
// Instruction Decode
//-----------------------------------------------------------------
wire [2:0] func3_w = opcode_i[14:12]; // R, I, S
wire [4:0] rs1_w = opcode_i[19:15];
wire [4:0] rs2_w = opcode_i[24:20];
wire [4:0] rd_w = opcode_i[11:7];
wire type_system_w = (opcode_i[6:2] == 5'b11100);
wire type_store_w = (opcode_i[6:2] == 5'b01000);
wire inst_csr_w = SUPPORT_CSR && type_system_w && (func3_w != 3'b000 && func3_w != 3'b100);
wire inst_csrrw_w = inst_csr_w && (func3_w == 3'b001);
wire inst_csrrs_w = inst_csr_w && (func3_w == 3'b010);
wire inst_csrrc_w = inst_csr_w && (func3_w == 3'b011);
wire inst_csrrwi_w = inst_csr_w && (func3_w == 3'b101);
wire inst_csrrsi_w = inst_csr_w && (func3_w == 3'b110);
wire inst_csrrci_w = inst_csr_w && (func3_w == 3'b111);
wire inst_ecall_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h000000);
wire inst_ebreak_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h002000);
wire inst_mret_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h604000);
wire [11:0] csr_addr_w = valid_i ? opcode_i[31:20] : 12'b0;
wire [31:0] csr_data_w = (inst_csrrwi_w || inst_csrrsi_w || inst_csrrci_w) ? {27'b0, rs1_w} : rs1_val_i;
wire csr_set_w = (valid_i && !exception_w) ? (inst_csrrw_w || inst_csrrs_w || inst_csrrwi_w || inst_csrrsi_w): 1'b0;
wire csr_clr_w = (valid_i && !exception_w) ? (inst_csrrw_w || inst_csrrc_w || inst_csrrwi_w || inst_csrrci_w): 1'b0;
//-----------------------------------------------------------------
// Execute: CSR Access
//-----------------------------------------------------------------
reg [31:0] csr_mepc_q;
reg [31:0] csr_mepc_r;
reg [31:0] csr_mcause_q;
reg [31:0] csr_mcause_r;
reg [31:0] csr_sr_q;
reg [31:0] csr_sr_r;
reg [31:0] csr_mcycle_q;
reg [31:0] csr_mcycle_r;
reg [31:0] csr_mtimecmp_q;
reg [31:0] csr_mtimecmp_r;
reg [31:0] csr_mscratch_q;
reg [31:0] csr_mscratch_r;
reg [31:0] csr_mip_q;
reg [31:0] csr_mip_r;
reg [31:0] csr_mie_q;
reg [31:0] csr_mie_r;
reg [31:0] csr_mtvec_q;
reg [31:0] csr_mtvec_r;
reg [31:0] csr_mtval_q;
reg [31:0] csr_mtval_r;
always @ *
begin
csr_mepc_r = csr_mepc_q;
csr_mcause_r = csr_mcause_q;
csr_sr_r = csr_sr_q;
csr_mcycle_r = csr_mcycle_q + 32'd1;
csr_mtimecmp_r = csr_mtimecmp_q;
csr_mscratch_r = csr_mscratch_q;
csr_mip_r = csr_mip_q;
csr_mie_r = csr_mie_q;
csr_mtvec_r = csr_mtvec_q;
csr_mtval_r = csr_mtval_q;
// External interrupt
if (intr_i)
csr_mip_r[11] = 1'b1;
// Timer match - generate IRQ
if (SUPPORT_MTIMECMP && csr_mcycle_r == csr_mtimecmp_r)
csr_mip_r[7] = 1'b1;
// Execute instruction / exception
if (valid_i)
begin
// Exception / break / ecall
if (exception_w || inst_ebreak_w || inst_ecall_w)
begin
// Save interrupt / supervisor state
csr_sr_r[7] = csr_sr_q[3];
csr_sr_r[12:11] = 3;
// Disable interrupts and enter supervisor mode
csr_sr_r[3] = 1'b0;
// Save PC of next instruction (not yet executed)
csr_mepc_r = pc_i;
// Extra info (badaddr / fault opcode)
csr_mtval_r = 32'b0;
// Exception source
if (excpn_invalid_inst_i)
begin
csr_mcause_r = ((0 << 31) | 2);
csr_mtval_r = opcode_i;
end
else if (inst_ebreak_w)
csr_mcause_r = ((0 << 31) | 3);
else if (inst_ecall_w)
csr_mcause_r = ((0 << 31) | 11);
else if (excpn_lsu_align_i)
begin
csr_mcause_r = type_store_w ? ((0 << 31) | 6) : ((0 << 31) | 4);
csr_mtval_r = mem_addr_i;
end
else if (take_interrupt_w)
csr_mcause_r = (1 << 31);
end
// MRET
else if (inst_mret_w)
begin
// Interrupt enable pop
csr_sr_r[3] = csr_sr_r[7];
csr_sr_r[7] = 1'b1;
// This CPU only supports machine mode
csr_sr_r[12:11] = 3;
end
else
begin
case (csr_addr_w)
12'h341:
begin
if (csr_set_w && csr_clr_w)
csr_mepc_r = csr_data_w;
else if (csr_set_w)
csr_mepc_r = csr_mepc_r | csr_data_w;
else if (csr_clr_w)
csr_mepc_r = csr_mepc_r & ~csr_data_w;
end
12'h342:
begin
if (csr_set_w && csr_clr_w)
csr_mcause_r = csr_data_w;
else if (csr_set_w)
csr_mcause_r = csr_mcause_r | csr_data_w;
else if (csr_clr_w)
csr_mcause_r = csr_mcause_r & ~csr_data_w;
end
12'h300:
begin
if (csr_set_w && csr_clr_w)
csr_sr_r = csr_data_w;
else if (csr_set_w)
csr_sr_r = csr_sr_r | csr_data_w;
else if (csr_clr_w)
csr_sr_r = csr_sr_r & ~csr_data_w;
end
12'h7c0:
begin
if (SUPPORT_MTIMECMP && csr_set_w && csr_data_w != 32'b0)
begin
csr_mtimecmp_r = csr_data_w;
// Clear interrupt pending
csr_mip_r[7] = 1'b0;
end
end
12'h340:
begin
if (csr_set_w && csr_clr_w)
csr_mscratch_r = csr_data_w;
else if (csr_set_w)
csr_mscratch_r = csr_mscratch_r | csr_data_w;
else if (csr_clr_w)
csr_mscratch_r = csr_mscratch_r & ~csr_data_w;
end
12'h344:
begin
if (csr_set_w && csr_clr_w)
csr_mip_r = csr_data_w;
else if (csr_set_w)
csr_mip_r = csr_mip_r | csr_data_w;
else if (csr_clr_w)
csr_mip_r = csr_mip_r & ~csr_data_w;
end
12'h304:
begin
if (csr_set_w && csr_clr_w)
csr_mie_r = csr_data_w;
else if (csr_set_w)
csr_mie_r = csr_mie_r | csr_data_w;
else if (csr_clr_w)
csr_mie_r = csr_mie_r & ~csr_data_w;
end
12'h305:
begin
if (csr_set_w && csr_clr_w)
csr_mtvec_r = csr_data_w;
else if (csr_set_w)
csr_mtvec_r = csr_mtvec_r | csr_data_w;
else if (csr_clr_w)
csr_mtvec_r = csr_mtvec_r & ~csr_data_w;
end
12'h343:
begin
if (csr_set_w && csr_clr_w)
csr_mtval_r = csr_data_w;
else if (csr_set_w)
csr_mtval_r = csr_mtval_r | csr_data_w;
else if (csr_clr_w)
csr_mtval_r = csr_mtval_r & ~csr_data_w;
end
default:
;
endcase
end
end
end
always @ (posedge clk_i )
if (rst_i)
begin
csr_mepc_q <= 32'b0;
csr_mcause_q <= 32'b0;
csr_sr_q <= 32'b0;
csr_mcycle_q <= 32'b0;
csr_mtimecmp_q <= 32'b0;
csr_mscratch_q <= 32'b0;
csr_mie_q <= 32'b0;
csr_mip_q <= 32'b0;
csr_mtvec_q <= 32'b0;
csr_mtval_q <= 32'b0;
end
else
begin
csr_mepc_q <= csr_mepc_r;
csr_mcause_q <= csr_mcause_r;
csr_sr_q <= csr_sr_r;
csr_mcycle_q <= SUPPORT_MCYCLE ? csr_mcycle_r : 32'b0;
csr_mtimecmp_q <= SUPPORT_MTIMECMP ? csr_mtimecmp_r : 32'b0;
csr_mscratch_q <= SUPPORT_MSCRATCH ? csr_mscratch_r : 32'b0;
csr_mie_q <= SUPPORT_MIP_MIE ? csr_mie_r : 32'b0;
csr_mip_q <= SUPPORT_MIP_MIE ? csr_mip_r : 32'b0;
csr_mtvec_q <= SUPPORT_MTVEC ? csr_mtvec_r : 32'b0;
csr_mtval_q <= SUPPORT_MTVAL ? csr_mtval_r : 32'b0;
end
//-----------------------------------------------------------------
// CSR Read Data MUX
//-----------------------------------------------------------------
reg [31:0] csr_data_r;
always @ *
begin
csr_data_r = 32'b0;
case (csr_addr_w)
12'h341: csr_data_r = csr_mepc_q & 32'hFFFFFFFF;
12'h342: csr_data_r = csr_mcause_q & 32'h8000000F;
12'h300: csr_data_r = csr_sr_q & 32'hFFFFFFFF;
12'h305: csr_data_r = csr_mtvec_q & 32'hFFFFFFFF;
12'h343: csr_data_r = csr_mtval_q & 32'hFFFFFFFF;
12'hc01,
12'hc00: csr_data_r = csr_mcycle_q & 32'hFFFFFFFF;
12'h7c0: csr_data_r = csr_mtimecmp_q & 32'hFFFFFFFF;
12'h340: csr_data_r = csr_mscratch_q & 32'hFFFFFFFF;
12'h344: csr_data_r = csr_mip_q & ((1 << 11) | (1 << 7) | (1 << 3));
12'h304: csr_data_r = csr_mie_q & ((1 << 11) | (1 << 7) | (1 << 3));
12'h301: csr_data_r = (SUPPORT_MULDIV ? 32'h00001000 : 32'b0) |
32'h40000000 | 32'h00000100;
12'hF14: csr_data_r = cpu_id_i;
default: csr_data_r = 32'b0;
endcase
end
assign csr_rdata_o = csr_data_r;
// Interrupt request and interrupt enabled
assign take_interrupt_w = SUPPORT_MIP_MIE ? ((|(csr_mip_q & csr_mie_q)) & csr_sr_q[3]) : (intr_i & csr_sr_q[3]);
assign exception_w = valid_i && (take_interrupt_w || excpn_invalid_inst_i || (SUPPORT_CSR && excpn_lsu_align_i));
assign exception_o = exception_w;
assign exception_pc_o = SUPPORT_MTVEC ? csr_mtvec_q :
SUPPORT_CSR ? isr_vector_i :
pc_i + 32'd4;
assign csr_mepc_o = csr_mepc_q;
//-----------------------------------------------------------------
// Debug - exception type (checker use only)
//-----------------------------------------------------------------
reg [5:0] v_etype_r;
always @ *
begin
v_etype_r = 6'b0;
if (csr_mcause_r[31])
v_etype_r = 6'h20;
else case (csr_mcause_r)
((0 << 31) | 0) : v_etype_r = 6'h10;
((0 << 31) | 1) : v_etype_r = 6'h11;
((0 << 31) | 2): v_etype_r = 6'h12;
((0 << 31) | 3) : v_etype_r = 6'h13;
((0 << 31) | 4) : v_etype_r = 6'h14;
((0 << 31) | 5) : v_etype_r = 6'h15;
((0 << 31) | 6) : v_etype_r = 6'h16;
((0 << 31) | 7) : v_etype_r = 6'h17;
((0 << 31) | 8) : v_etype_r = 6'h18;
((0 << 31) | 9) : v_etype_r = 6'h19;
((0 << 31) | 10) : v_etype_r = 6'h1a;
((0 << 31) | 11) : v_etype_r = 6'h1b;
((0 << 31) | 12) : v_etype_r = 6'h1c;
((0 << 31) | 13) : v_etype_r = 6'h1d;
((0 << 31) | 15) : v_etype_r = 6'h1f;
endcase
end
assign exception_type_o = v_etype_r;
endmodule
//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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.
//-----------------------------------------------------------------
//--------------------------------------------------------------------
// ALU Operations
//--------------------------------------------------------------------
//-----------------------------------------------------------------
// Privilege levels
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Status Register
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// IRQ Numbers
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// CSR Registers - Machine
//-----------------------------------------------------------------
// Non-std
//-----------------------------------------------------------------
// CSR Registers - Simulation control
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Exception Causes
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Debug defines for exception types
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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 uriscv_lsu
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
parameter SUPPORT_TRAP_LSU_ALIGN = 1
)
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
input [31:0] opcode_i
,input [31:0] rs1_val_i
,input [31:0] rs2_val_i
,output mem_rd_o
,output [3:0] mem_wr_o
,output [31:0] mem_addr_o
,output [31:0] mem_data_o
,output mem_misaligned_o
);
//-----------------------------------------------------------------
// Includes
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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.
//-----------------------------------------------------------------
//--------------------------------------------------------------------
// ALU Operations
//--------------------------------------------------------------------
//-----------------------------------------------------------------
// Privilege levels
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Status Register
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// IRQ Numbers
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// CSR Registers - Machine
//-----------------------------------------------------------------
// Non-std
//-----------------------------------------------------------------
// CSR Registers - Simulation control
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Exception Causes
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Debug defines for exception types
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Instruction Decode
//-----------------------------------------------------------------
wire type_load_w = (opcode_i[6:2] == 5'b00000);
wire type_store_w = (opcode_i[6:2] == 5'b01000);
wire [2:0] func3_w = opcode_i[14:12]; // R, I, S
wire inst_lb_w = type_load_w && (func3_w == 3'b000);
wire inst_lh_w = type_load_w && (func3_w == 3'b001);
wire inst_lw_w = type_load_w && (func3_w == 3'b010);
wire inst_lbu_w = type_load_w && (func3_w == 3'b100);
wire inst_lhu_w = type_load_w && (func3_w == 3'b101);
wire inst_sb_w = type_store_w && (func3_w == 3'b000);
wire inst_sh_w = type_store_w && (func3_w == 3'b001);
wire inst_sw_w = type_store_w && (func3_w == 3'b010);
//-----------------------------------------------------------------
// Decode LSU operation
//-----------------------------------------------------------------
reg [31:0] imm12_r;
reg [31:0] storeimm_r;
reg [31:0] mem_addr_r;
reg [31:0] mem_data_r;
reg [3:0] mem_wr_r;
reg mem_rd_r;
reg mem_misaligned_r;
always @ *
begin
imm12_r = {{20{opcode_i[31]}}, opcode_i[31:20]};
storeimm_r = {{20{opcode_i[31]}}, opcode_i[31:25], opcode_i[11:7]};
// Memory address
mem_addr_r = rs1_val_i + (type_store_w ? storeimm_r : imm12_r);
if (SUPPORT_TRAP_LSU_ALIGN)
mem_misaligned_r = (inst_lh_w | inst_lhu_w | inst_sh_w) ? mem_addr_r[0]:
(inst_lw_w | inst_sw_w) ? (|mem_addr_r[1:0]):
1'b0;
else
mem_misaligned_r = 1'b0;
mem_data_r = 32'h00000000;
mem_wr_r = 4'b0000;
mem_rd_r = 1'b0;
case (1'b1)
type_load_w:
mem_rd_r = 1'b1;
inst_sb_w:
begin
case (mem_addr_r[1:0])
2'h3 :
begin
mem_data_r = {rs2_val_i[7:0], 24'h000000};
mem_wr_r = 4'b1000;
mem_rd_r = 1'b0;
end
2'h2 :
begin
mem_data_r = {8'h00,rs2_val_i[7:0],16'h0000};
mem_wr_r = 4'b0100;
mem_rd_r = 1'b0;
end
2'h1 :
begin
mem_data_r = {16'h0000,rs2_val_i[7:0],8'h00};
mem_wr_r = 4'b0010;
mem_rd_r = 1'b0;
end
2'h0 :
begin
mem_data_r = {24'h000000,rs2_val_i[7:0]};
mem_wr_r = 4'b0001;
mem_rd_r = 1'b0;
end
default : ;
endcase
end
inst_sh_w:
begin
case (mem_addr_r[1:0])
2'h2 :
begin
mem_data_r = {rs2_val_i[15:0],16'h0000};
mem_wr_r = 4'b1100;
mem_rd_r = 1'b0;
end
default :
begin
mem_data_r = {16'h0000,rs2_val_i[15:0]};
mem_wr_r = 4'b0011;
mem_rd_r = 1'b0;
end
endcase
end
inst_sw_w:
begin
mem_data_r = rs2_val_i;
mem_wr_r = 4'b1111;
mem_rd_r = 1'b0;
end
// Non load / store
default:
;
endcase
end
assign mem_rd_o = mem_rd_r;
assign mem_wr_o = mem_wr_r;
assign mem_addr_o = mem_addr_r;
assign mem_data_o = mem_data_r;
assign mem_misaligned_o = mem_misaligned_r;
endmodule
//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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 uriscv_muldiv
(
input clk_i,
input rst_i,
// Operation select
input valid_i,
input inst_mul_i,
input inst_mulh_i,
input inst_mulhsu_i,
input inst_mulhu_i,
input inst_div_i,
input inst_divu_i,
input inst_rem_i,
input inst_remu_i,
// Operands
input [31:0] operand_ra_i,
input [31:0] operand_rb_i,
// Result
output stall_o,
output ready_o,
output [31:0] result_o
);
//-----------------------------------------------------------------
// Includes
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// 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.
//-----------------------------------------------------------------
//--------------------------------------------------------------------
// ALU Operations
//--------------------------------------------------------------------
//-----------------------------------------------------------------
// Privilege levels
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Status Register
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// IRQ Numbers
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// CSR Registers - Machine
//-----------------------------------------------------------------
// Non-std
//-----------------------------------------------------------------
// CSR Registers - Simulation control
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Exception Causes
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Debug defines for exception types
//-----------------------------------------------------------------
//-------------------------------------------------------------
// Multiplier
//-------------------------------------------------------------
reg [32:0] mul_operand_a_q;
reg [32:0] mul_operand_b_q;
reg mulhi_sel_q;
//-------------------------------------------------------------
// Multiplier
//-------------------------------------------------------------
wire [64:0] mult_result_w;
reg [32:0] operand_b_r;
reg [32:0] operand_a_r;
reg [31:0] mul_result_r;
wire mult_inst_w = inst_mul_i |
inst_mulh_i |
inst_mulhsu_i |
inst_mulhu_i;
always @ *
begin
if (inst_mulhsu_i)
operand_a_r = {operand_ra_i[31], operand_ra_i[31:0]};
else if (inst_mulh_i)
operand_a_r = {operand_ra_i[31], operand_ra_i[31:0]};
else // MULHU || MUL
operand_a_r = {1'b0, operand_ra_i[31:0]};
end
always @ *
begin
if (inst_mulhsu_i)
operand_b_r = {1'b0, operand_rb_i[31:0]};
else if (inst_mulh_i)
operand_b_r = {operand_rb_i[31], operand_rb_i[31:0]};
else // MULHU || MUL
operand_b_r = {1'b0, operand_rb_i[31:0]};
end
// Pipeline flops for multiplier
always @(posedge clk_i )
if (rst_i)
begin
mul_operand_a_q <= 33'b0;
mul_operand_b_q <= 33'b0;
mulhi_sel_q <= 1'b0;
end
else if (valid_i && mult_inst_w)
begin
mul_operand_a_q <= operand_a_r;
mul_operand_b_q <= operand_b_r;
mulhi_sel_q <= ~inst_mul_i;
end
else
begin
mul_operand_a_q <= 33'b0;
mul_operand_b_q <= 33'b0;
mulhi_sel_q <= 1'b0;
end
assign mult_result_w = {{ 32 {mul_operand_a_q[32]}}, mul_operand_a_q}*{{ 32 {mul_operand_b_q[32]}}, mul_operand_b_q};
always @ *
begin
mul_result_r = mulhi_sel_q ? mult_result_w[63:32] : mult_result_w[31:0];
end
reg mul_busy_q;
always @(posedge clk_i )
if (rst_i)
mul_busy_q <= 1'b0;
else
mul_busy_q <= valid_i & mult_inst_w;
//-------------------------------------------------------------
// Divider
//-------------------------------------------------------------
wire div_rem_inst_w = inst_div_i ||
inst_divu_i ||
inst_rem_i ||
inst_remu_i;
wire signed_operation_w = inst_div_i || inst_rem_i;
wire div_operation_w = inst_div_i || inst_divu_i;
reg [31:0] dividend_q;
reg [62:0] divisor_q;
reg [31:0] quotient_q;
reg [31:0] q_mask_q;
reg div_inst_q;
reg div_busy_q;
reg invert_res_q;
wire div_start_w = valid_i & div_rem_inst_w & !stall_o;
wire div_complete_w = !(|q_mask_q) & div_busy_q;
always @ (posedge clk_i )
if (rst_i)
begin
div_busy_q <= 1'b0;
dividend_q <= 32'b0;
divisor_q <= 63'b0;
invert_res_q <= 1'b0;
quotient_q <= 32'b0;
q_mask_q <= 32'b0;
div_inst_q <= 1'b0;
end
else if (div_start_w)
begin
div_busy_q <= 1'b1;
div_inst_q <= div_operation_w;
if (signed_operation_w && operand_ra_i[31])
dividend_q <= -operand_ra_i;
else
dividend_q <= operand_ra_i;
if (signed_operation_w && operand_rb_i[31])
divisor_q <= {-operand_rb_i, 31'b0};
else
divisor_q <= {operand_rb_i, 31'b0};
invert_res_q <= (inst_div_i && (operand_ra_i[31] != operand_rb_i[31]) && |operand_rb_i) ||
(inst_rem_i && operand_ra_i[31]);
quotient_q <= 32'b0;
q_mask_q <= 32'h80000000;
end
else if (div_complete_w)
begin
div_busy_q <= 1'b0;
end
else if (div_busy_q)
begin
if (divisor_q <= {31'b0, dividend_q})
begin
dividend_q <= dividend_q - divisor_q[31:0];
quotient_q <= quotient_q | q_mask_q;
end
divisor_q <= {1'b0, divisor_q[62:1]};
q_mask_q <= {1'b0, q_mask_q[31:1]};
end
reg [31:0] div_result_r;
always @ *
begin
div_result_r = 32'b0;
if (div_inst_q)
div_result_r = invert_res_q ? -quotient_q : quotient_q;
else
div_result_r = invert_res_q ? -dividend_q : dividend_q;
end
//-------------------------------------------------------------
// Shared logic
//-------------------------------------------------------------
// Stall if divider logic is busy and new multiplier or divider op
assign stall_o = (div_busy_q & (mult_inst_w | div_rem_inst_w)) ||
(mul_busy_q & div_rem_inst_w);
reg [31:0] result_q;
reg ready_q;
always @ (posedge clk_i )
if (rst_i)
ready_q <= 1'b0;
else if (mul_busy_q)
ready_q <= 1'b1;
else if (div_complete_w)
ready_q <= 1'b1;
else
ready_q <= 1'b0;
always @ (posedge clk_i )
if (rst_i)
result_q <= 32'b0;
else if (div_complete_w)
result_q <= div_result_r;
else if (mul_busy_q)
result_q <= mul_result_r;
assign result_o = result_q;
assign ready_o = ready_q;
endmodule
module soc_top (
input bit clk,
input bit rst
);
reg [7:0] mem[65535:0];
integer i;
integer f;
initial begin
$display("Starting bench");
// Load TCM memory
for (i = 0; i < 65535; i = i + 1) mem[i] = 0;
// $readmemh("test.hex", mem);
$readmemh("program.hex", mem);
for (i = 0; i < 65535; i = i + 1) u_mem.write(i, mem[i]);
end
wire mem_i_rd_w;
wire mem_i_flush_w;
wire mem_i_invalidate_w;
wire [31:0] mem_i_pc_w;
wire [31:0] mem_d_addr_w;
wire [31:0] mem_d_data_wr_w;
wire mem_d_rd_w;
wire [ 3:0] mem_d_wr_w;
wire mem_d_cacheable_w;
wire [10:0] mem_d_req_tag_w;
wire mem_d_invalidate_w;
wire mem_d_writeback_w;
wire mem_d_flush_w;
wire mem_i_accept_w;
wire mem_i_valid_w;
wire mem_i_error_w;
wire [31:0] mem_i_inst_w;
wire [31:0] mem_d_data_rd_w;
wire mem_d_accept_w;
wire mem_d_ack_w;
wire mem_d_error_w;
wire [10:0] mem_d_resp_tag_w;
riscv_core u_dut
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
// Inputs
.clk_i(clk),
.rst_i(rst),
.mem_d_data_rd_i(mem_d_data_rd_w),
.mem_d_accept_i(mem_d_accept_w),
.mem_d_ack_i(mem_d_ack_w),
.mem_d_error_i(mem_d_error_w),
.mem_d_resp_tag_i(mem_d_resp_tag_w),
.mem_i_accept_i(mem_i_accept_w),
.mem_i_valid_i(mem_i_valid_w),
.mem_i_error_i(mem_i_error_w),
.mem_i_inst_i(mem_i_inst_w),
.intr_i(1'b0),
.reset_vector_i(32'h80000000),
.cpu_id_i('b0)
// Outputs
, .mem_d_addr_o(mem_d_addr_w),
.mem_d_data_wr_o(mem_d_data_wr_w),
.mem_d_rd_o(mem_d_rd_w),
.mem_d_wr_o(mem_d_wr_w),
.mem_d_cacheable_o(mem_d_cacheable_w),
.mem_d_req_tag_o(mem_d_req_tag_w),
.mem_d_invalidate_o(mem_d_invalidate_w),
.mem_d_writeback_o(mem_d_writeback_w),
.mem_d_flush_o(mem_d_flush_w),
.mem_i_rd_o(mem_i_rd_w),
.mem_i_flush_o(mem_i_flush_w),
.mem_i_invalidate_o(mem_i_invalidate_w),
.mem_i_pc_o(mem_i_pc_w)
);
tcm_mem u_mem (
// Inputs
.clk_i(clk),
.rst_i(rst),
.mem_i_rd_i(mem_i_rd_w),
.mem_i_flush_i(mem_i_flush_w),
.mem_i_invalidate_i(mem_i_invalidate_w),
.mem_i_pc_i(mem_i_pc_w),
.mem_d_addr_i(mem_d_addr_w),
.mem_d_data_wr_i(mem_d_data_wr_w),
.mem_d_rd_i(mem_d_rd_w),
.mem_d_wr_i(mem_d_wr_w),
.mem_d_cacheable_i(mem_d_cacheable_w),
.mem_d_req_tag_i(mem_d_req_tag_w),
.mem_d_invalidate_i(mem_d_invalidate_w),
.mem_d_writeback_i(mem_d_writeback_w),
.mem_d_flush_i(mem_d_flush_w)
// Outputs
, .mem_i_accept_o(mem_i_accept_w),
.mem_i_valid_o(mem_i_valid_w),
.mem_i_error_o(mem_i_error_w),
.mem_i_inst_o(mem_i_inst_w),
.mem_d_data_rd_o(mem_d_data_rd_w),
.mem_d_accept_o(mem_d_accept_w),
.mem_d_ack_o(mem_d_ack_w),
.mem_d_error_o(mem_d_error_w),
.mem_d_resp_tag_o(mem_d_resp_tag_w)
);
endmodule
module tcm_mem_ram (
// Inputs
input clk0_i,
input rst0_i,
input [13:0] addr0_i,
input [31:0] data0_i,
input [ 3:0] wr0_i,
input clk1_i,
input rst1_i,
input [13:0] addr1_i,
input [31:0] data1_i,
input [ 3:0] wr1_i
// Outputs
, output [31:0] data0_o,
output [31:0] data1_o
);
integer memlog;
initial begin
memlog = $fopen("mem.log", "w");
end
//-----------------------------------------------------------------
// Dual Port RAM 64KB
// Mode: Read First
//-----------------------------------------------------------------
/* verilator lint_off MULTIDRIVEN */
reg [31:0] ram[16383:0] /*verilator public*/;
/* verilator lint_on MULTIDRIVEN */
reg [31:0] ram_read0_q;
reg [31:0] ram_read1_q;
// Synchronous write
always @(posedge clk0_i) begin
if (wr0_i[0]) ram[addr0_i][7:0] <= data0_i[7:0];
if (wr0_i[1]) ram[addr0_i][15:8] <= data0_i[15:8];
if (wr0_i[2]) ram[addr0_i][23:16] <= data0_i[23:16];
if (wr0_i[3]) ram[addr0_i][31:24] <= data0_i[31:24];
ram_read0_q <= ram[addr0_i];
$fwrite(memlog, "addr0: 0x%0h data: 0x%0h \n", addr0_i, ram[addr0_i]);
end
always @(posedge clk1_i) begin
if (wr1_i[0]) ram[addr1_i][7:0] <= data1_i[7:0];
if (wr1_i[1]) ram[addr1_i][15:8] <= data1_i[15:8];
if (wr1_i[2]) ram[addr1_i][23:16] <= data1_i[23:16];
if (wr1_i[3]) ram[addr1_i][31:24] <= data1_i[31:24];
ram_read1_q <= ram[addr1_i];
$fwrite(memlog, "addr1: 0x%0h data: 0x%0h \n", addr1_i, ram[addr1_i]);
end
assign data0_o = ram_read0_q;
assign data1_o = ram_read1_q;
endmodule
module tcm_mem
(
// Inputs
input clk_i
,input rst_i
,input mem_i_rd_i
,input mem_i_flush_i
,input mem_i_invalidate_i
,input [ 31:0] mem_i_pc_i
,input [ 31:0] mem_d_addr_i
,input [ 31:0] mem_d_data_wr_i
,input mem_d_rd_i
,input [ 3:0] mem_d_wr_i
,input mem_d_cacheable_i
,input [ 10:0] mem_d_req_tag_i
,input mem_d_invalidate_i
,input mem_d_writeback_i
,input mem_d_flush_i
// Outputs
,output mem_i_accept_o
,output mem_i_valid_o
,output mem_i_error_o
,output [ 31:0] mem_i_inst_o
,output [ 31:0] mem_d_data_rd_o
,output mem_d_accept_o
,output mem_d_ack_o
,output mem_d_error_o
,output [ 10:0] mem_d_resp_tag_o
);
//-------------------------------------------------------------
// Dual Port RAM
//-------------------------------------------------------------
wire [31:0] data_r_w;
tcm_mem_ram
u_ram
(
// Instruction fetch
.clk0_i(clk_i)
,.rst0_i(rst_i)
,.addr0_i(mem_i_pc_i[15:2])
,.data0_i(32'b0)
,.wr0_i(4'b0)
// External access / Data access
,.clk1_i(clk_i)
,.rst1_i(rst_i)
,.addr1_i(mem_d_addr_i[15:2])
,.data1_i(mem_d_data_wr_i)
,.wr1_i(mem_d_wr_i)
// Outputs
,.data0_o(mem_i_inst_o)
,.data1_o(data_r_w)
);
//-------------------------------------------------------------
// Instruction Fetch
//-------------------------------------------------------------
reg mem_i_valid_q;
always @ (posedge clk_i )
if (rst_i)
mem_i_valid_q <= 1'b0;
else
mem_i_valid_q <= mem_i_rd_i;
assign mem_i_accept_o = 1'b1;
assign mem_i_valid_o = mem_i_valid_q;
assign mem_i_error_o = 1'b0;
//-------------------------------------------------------------
// Data Access / Incoming external access
//-------------------------------------------------------------
reg mem_d_accept_q;
reg mem_d_ack_q;
reg [10:0] mem_d_tag_q;
always @ (posedge clk_i )
if (rst_i)
begin
mem_d_ack_q <= 1'b0;
mem_d_tag_q <= 11'b0;
end
else if ((mem_d_rd_i || mem_d_wr_i != 4'b0 || mem_d_flush_i || mem_d_invalidate_i || mem_d_writeback_i) && mem_d_accept_o)
begin
mem_d_ack_q <= 1'b1;
mem_d_tag_q <= mem_d_req_tag_i;
end
else
mem_d_ack_q <= 1'b0;
assign mem_d_ack_o = mem_d_ack_q;
assign mem_d_resp_tag_o = mem_d_tag_q;
assign mem_d_data_rd_o = data_r_w;
assign mem_d_error_o = 1'b0;
assign mem_d_accept_o = 1'b1;
//-------------------------------------------------------------
// write: Write byte into memory
//-------------------------------------------------------------
task write; /*verilator public*/
input [31:0] addr;
input [7:0] data;
begin
case (addr[1:0])
2'd0: u_ram.ram[addr/4][7:0] = data;
2'd1: u_ram.ram[addr/4][15:8] = data;
2'd2: u_ram.ram[addr/4][23:16] = data;
2'd3: u_ram.ram[addr/4][31:24] = data;
endcase
end
endtask
endmodule
module soc_sim (
input bit core_clk
);
logic rst_l;
parameter MAX_CYCLES = 1000;
// parameter MAX_CYCLES = 10_000_000_0;
int cycleCnt;
always @(posedge core_clk) begin
cycleCnt <= cycleCnt + 1;
if (cycleCnt == MAX_CYCLES) begin
$display("Hit max cycle count (%0d) .. stopping", cycleCnt);
$finish;
end
end
assign rst_l = cycleCnt > 5;
soc_top rvsoc (
.clk(core_clk),
.rst(rst_l)
);
endmodule