//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// AltOR32
|
// AltOR32
|
// Alternative Lightweight OpenRisc
|
// Alternative Lightweight OpenRisc
|
// V2.0
|
// V2.0
|
// Ultra-Embedded.com
|
// Ultra-Embedded.com
|
// Copyright 2011 - 2013
|
// Copyright 2011 - 2013
|
//
|
//
|
// Email: admin@ultra-embedded.com
|
// Email: admin@ultra-embedded.com
|
//
|
//
|
// License: LGPL
|
// License: LGPL
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
//
|
//
|
// Copyright (C) 2011 - 2013 Ultra-Embedded.com
|
// Copyright (C) 2011 - 2013 Ultra-Embedded.com
|
//
|
//
|
// This source file may be used and distributed without
|
// This source file may be used and distributed without
|
// restriction provided that this copyright statement is not
|
// restriction provided that this copyright statement is not
|
// removed from the file and that any derivative work contains
|
// removed from the file and that any derivative work contains
|
// the original copyright notice and the associated disclaimer.
|
// the original copyright notice and the associated disclaimer.
|
//
|
//
|
// This source file is free software; you can redistribute it
|
// This source file is free software; you can redistribute it
|
// and/or modify it under the terms of the GNU Lesser General
|
// and/or modify it under the terms of the GNU Lesser General
|
// Public License as published by the Free Software Foundation;
|
// Public License as published by the Free Software Foundation;
|
// either version 2.1 of the License, or (at your option) any
|
// either version 2.1 of the License, or (at your option) any
|
// later version.
|
// later version.
|
//
|
//
|
// This source is distributed in the hope that it will be
|
// This source is distributed in the hope that it will be
|
// useful, but WITHOUT ANY WARRANTY; without even the implied
|
// useful, but WITHOUT ANY WARRANTY; without even the implied
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
// PURPOSE. See the GNU Lesser General Public License for more
|
// PURPOSE. See the GNU Lesser General Public License for more
|
// details.
|
// details.
|
//
|
//
|
// You should have received a copy of the GNU Lesser General
|
// You should have received a copy of the GNU Lesser General
|
// Public License along with this source; if not, write to the
|
// Public License along with this source; if not, write to the
|
// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
// Boston, MA 02111-1307 USA
|
// Boston, MA 02111-1307 USA
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
|
|
//`define CONF_CORE_DEBUG
|
//`define CONF_CORE_DEBUG
|
//`define CONF_CORE_DEBUG_BUBBLE
|
//`define CONF_CORE_DEBUG_BUBBLE
|
//`define CONF_CORE_TRACE
|
//`define CONF_CORE_TRACE
|
//`define CONF_CORE_FAULT_ON_OPCODE0
|
//`define CONF_CORE_FAULT_ON_OPCODE0
|
|
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Includes
|
// Includes
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
`include "altor32_defs.v"
|
`include "altor32_defs.v"
|
|
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Module - Instruction Execute
|
// Module - Instruction Execute
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
module altor32_exec
|
module altor32_exec
|
(
|
(
|
// General
|
// General
|
input clk_i /*verilator public*/,
|
input clk_i /*verilator public*/,
|
input rst_i /*verilator public*/,
|
input rst_i /*verilator public*/,
|
|
|
// Maskable interrupt
|
// Maskable interrupt
|
input intr_i /*verilator public*/,
|
input intr_i /*verilator public*/,
|
|
|
// Unmaskable interrupt
|
// Unmaskable interrupt
|
input nmi_i /*verilator public*/,
|
input nmi_i /*verilator public*/,
|
|
|
// Fault
|
// Fault
|
output reg fault_o /*verilator public*/,
|
output reg fault_o /*verilator public*/,
|
|
|
// Breakpoint / Trap
|
// Breakpoint / Trap
|
output reg break_o /*verilator public*/,
|
output reg break_o /*verilator public*/,
|
|
|
// Cache control
|
// Cache control
|
output reg icache_flush_o /*verilator public*/,
|
output reg icache_flush_o /*verilator public*/,
|
output reg dcache_flush_o /*verilator public*/,
|
output reg dcache_flush_o /*verilator public*/,
|
|
|
// Branch
|
// Branch
|
output branch_o /*verilator public*/,
|
output branch_o /*verilator public*/,
|
output [31:0] branch_pc_o /*verilator public*/,
|
output [31:0] branch_pc_o /*verilator public*/,
|
output stall_o /*verilator public*/,
|
output stall_o /*verilator public*/,
|
|
|
// Opcode & arguments
|
// Opcode & arguments
|
input [31:0] opcode_i /*verilator public*/,
|
input [31:0] opcode_i /*verilator public*/,
|
input [31:0] opcode_pc_i /*verilator public*/,
|
input [31:0] opcode_pc_i /*verilator public*/,
|
input opcode_valid_i /*verilator public*/,
|
input opcode_valid_i /*verilator public*/,
|
|
|
// Reg A
|
// Reg A
|
input [4:0] reg_ra_i /*verilator public*/,
|
input [4:0] reg_ra_i /*verilator public*/,
|
input [31:0] reg_ra_value_i /*verilator public*/,
|
input [31:0] reg_ra_value_i /*verilator public*/,
|
|
|
// Reg B
|
// Reg B
|
input [4:0] reg_rb_i /*verilator public*/,
|
input [4:0] reg_rb_i /*verilator public*/,
|
input [31:0] reg_rb_value_i /*verilator public*/,
|
input [31:0] reg_rb_value_i /*verilator public*/,
|
|
|
// Reg D
|
// Reg D
|
input [4:0] reg_rd_i /*verilator public*/,
|
input [4:0] reg_rd_i /*verilator public*/,
|
|
|
// Output
|
// Output
|
output [31:0] opcode_o /*verilator public*/,
|
output [31:0] opcode_o /*verilator public*/,
|
output [4:0] reg_rd_o /*verilator public*/,
|
output [4:0] reg_rd_o /*verilator public*/,
|
output [31:0] reg_rd_value_o /*verilator public*/,
|
output [31:0] reg_rd_value_o /*verilator public*/,
|
output mult_o /*verilator public*/,
|
output mult_o /*verilator public*/,
|
output [31:0] mult_res_o /*verilator public*/,
|
output [31:0] mult_res_o /*verilator public*/,
|
|
|
// Register write back bypass
|
// Register write back bypass
|
input [4:0] wb_rd_i /*verilator public*/,
|
input [4:0] wb_rd_i /*verilator public*/,
|
input [31:0] wb_rd_value_i /*verilator public*/,
|
input [31:0] wb_rd_value_i /*verilator public*/,
|
|
|
// Memory Interface
|
// Memory Interface
|
output reg [31:0] dmem_addr_o /*verilator public*/,
|
output reg [31:0] dmem_addr_o /*verilator public*/,
|
output reg [31:0] dmem_data_out_o /*verilator public*/,
|
output reg [31:0] dmem_data_out_o /*verilator public*/,
|
input [31:0] dmem_data_in_i /*verilator public*/,
|
input [31:0] dmem_data_in_i /*verilator public*/,
|
output reg [3:0] dmem_wr_o /*verilator public*/,
|
output reg [3:0] dmem_wr_o /*verilator public*/,
|
output reg dmem_rd_o /*verilator public*/,
|
output reg dmem_rd_o /*verilator public*/,
|
input dmem_accept_i /*verilator public*/,
|
input dmem_accept_i /*verilator public*/,
|
input dmem_ack_i /*verilator public*/
|
input dmem_ack_i /*verilator public*/
|
);
|
);
|
|
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Params
|
// Params
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
parameter BOOT_VECTOR = 32'h00000000;
|
parameter BOOT_VECTOR = 32'h00000000;
|
parameter ISR_VECTOR = 32'h00000000;
|
parameter ISR_VECTOR = 32'h00000000;
|
|
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Registers
|
// Registers
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
|
|
// Branch PC
|
// Branch PC
|
reg [31:0] r_pc_branch;
|
reg [31:0] r_pc_branch;
|
reg r_pc_fetch;
|
reg r_pc_fetch;
|
reg r_stall;
|
reg r_stall;
|
|
|
// Exception saved program counter
|
// Exception saved program counter
|
reg [31:0] r_epc;
|
reg [31:0] r_epc;
|
|
|
// Supervisor register
|
// Supervisor register
|
reg [31:0] r_sr;
|
reg [31:0] r_sr;
|
|
|
// Exception saved supervisor register
|
// Exception saved supervisor register
|
reg [31:0] r_esr;
|
reg [31:0] r_esr;
|
|
|
// Destination register number (post execute stage)
|
// Destination register number (post execute stage)
|
reg [4:0] r_e_rd;
|
reg [4:0] r_e_rd;
|
|
|
// Current opcode (PC for debug)
|
// Current opcode (PC for debug)
|
reg [31:0] r_e_opcode;
|
reg [31:0] r_e_opcode;
|
reg [31:0] r_e_opcode_pc;
|
reg [31:0] r_e_opcode_pc;
|
|
|
// ALU input A
|
// ALU input A
|
reg [31:0] r_e_alu_a;
|
reg [31:0] r_e_alu_a;
|
|
|
// ALU input B
|
// ALU input B
|
reg [31:0] r_e_alu_b;
|
reg [31:0] r_e_alu_b;
|
|
|
// ALU output
|
// ALU output
|
wire [31:0] r_e_result;
|
wire [31:0] r_e_result;
|
|
|
// Resolved RA/RB register contents
|
// Resolved RA/RB register contents
|
wire [31:0] ra_value_resolved;
|
wire [31:0] ra_value_resolved;
|
wire [31:0] rb_value_resolved;
|
wire [31:0] rb_value_resolved;
|
wire resolve_failed;
|
wire resolve_failed;
|
|
|
// ALU Carry
|
// ALU Carry
|
wire alu_carry_out;
|
wire alu_carry_out;
|
wire alu_carry_update;
|
wire alu_carry_update;
|
|
|
// ALU operation selection
|
// ALU operation selection
|
reg [3:0] r_e_alu_func;
|
reg [3:0] r_e_alu_func;
|
|
|
// Load instruction details
|
// Load instruction details
|
reg [4:0] r_load_rd;
|
reg [4:0] r_load_rd;
|
reg [7:0] r_load_inst;
|
reg [7:0] r_load_inst;
|
reg [1:0] r_load_offset;
|
reg [1:0] r_load_offset;
|
|
|
// Load forwarding
|
// Load forwarding
|
wire load_insn;
|
wire load_insn;
|
wire [31:0] load_result;
|
wire [31:0] load_result;
|
|
|
// Memory access?
|
// Memory access?
|
reg r_mem_load;
|
reg r_mem_load;
|
reg r_mem_store;
|
reg r_mem_store;
|
reg r_mem_access;
|
reg r_mem_access;
|
|
|
wire load_pending;
|
wire load_pending;
|
wire store_pending;
|
wire store_pending;
|
wire load_insert;
|
wire load_insert;
|
wire load_stall;
|
wire load_stall;
|
|
|
reg d_mem_load;
|
reg d_mem_load;
|
|
|
// Delayed NMI
|
// Delayed NMI
|
reg r_nmi;
|
reg r_nmi;
|
|
|
|
// SIM PUTC
|
|
`ifdef SIM_EXT_PUTC
|
|
reg [7:0] r_putc;
|
|
`endif
|
|
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Instantiation
|
// Instantiation
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
|
|
// ALU
|
// ALU
|
altor32_alu alu
|
altor32_alu alu
|
(
|
(
|
// ALU operation select
|
// ALU operation select
|
.op_i(r_e_alu_func),
|
.op_i(r_e_alu_func),
|
|
|
// Operands
|
// Operands
|
.a_i(r_e_alu_a),
|
.a_i(r_e_alu_a),
|
.b_i(r_e_alu_b),
|
.b_i(r_e_alu_b),
|
.c_i(r_sr[`OR32_SR_CY]),
|
.c_i(r_sr[`OR32_SR_CY]),
|
|
|
// Result
|
// Result
|
.p_o(r_e_result),
|
.p_o(r_e_result),
|
|
|
// Carry
|
// Carry
|
.c_o(alu_carry_out),
|
.c_o(alu_carry_out),
|
.c_update_o(alu_carry_update)
|
.c_update_o(alu_carry_update)
|
);
|
);
|
|
|
// Load result forwarding
|
// Load result forwarding
|
altor32_lfu
|
altor32_lfu
|
u_lfu
|
u_lfu
|
(
|
(
|
// Opcode
|
// Opcode
|
.opcode_i(r_load_inst),
|
.opcode_i(r_load_inst),
|
|
|
// Memory load result
|
// Memory load result
|
.mem_result_i(dmem_data_in_i),
|
.mem_result_i(dmem_data_in_i),
|
.mem_offset_i(r_load_offset),
|
.mem_offset_i(r_load_offset),
|
|
|
// Result
|
// Result
|
.load_result_o(load_result),
|
.load_result_o(load_result),
|
.load_insn_o(load_insn)
|
.load_insn_o(load_insn)
|
);
|
);
|
|
|
// Load / store pending logic
|
// Load / store pending logic
|
altor32_lsu
|
altor32_lsu
|
u_lsu
|
u_lsu
|
(
|
(
|
// Current instruction
|
// Current instruction
|
.opcode_valid_i(opcode_valid_i & ~r_pc_fetch),
|
.opcode_valid_i(opcode_valid_i & ~r_pc_fetch),
|
.opcode_i({2'b00,opcode_i[31:26]}),
|
.opcode_i({2'b00,opcode_i[31:26]}),
|
|
|
// Load / Store pending
|
// Load / Store pending
|
.load_pending_i(r_mem_load),
|
.load_pending_i(r_mem_load),
|
.store_pending_i(r_mem_store),
|
.store_pending_i(r_mem_store),
|
|
|
// Load dest register
|
// Load dest register
|
.rd_load_i(r_load_rd),
|
.rd_load_i(r_load_rd),
|
|
|
// Load insn in WB stage
|
// Load insn in WB stage
|
.load_wb_i(d_mem_load),
|
.load_wb_i(d_mem_load),
|
|
|
// Memory status
|
// Memory status
|
.mem_access_i(r_mem_access),
|
.mem_access_i(r_mem_access),
|
.mem_ack_i(dmem_ack_i),
|
.mem_ack_i(dmem_ack_i),
|
|
|
// Load / store still pending
|
// Load / store still pending
|
.load_pending_o(load_pending),
|
.load_pending_o(load_pending),
|
.store_pending_o(store_pending),
|
.store_pending_o(store_pending),
|
|
|
// Insert load result into pipeline
|
// Insert load result into pipeline
|
.write_result_o(load_insert),
|
.write_result_o(load_insert),
|
|
|
// Stall pipeline due
|
// Stall pipeline due
|
.stall_o(load_stall)
|
.stall_o(load_stall)
|
);
|
);
|
|
|
// Operand forwarding
|
// Operand forwarding
|
altor32_dfu
|
altor32_dfu
|
u_dfu
|
u_dfu
|
(
|
(
|
// Input registers
|
// Input registers
|
.ra_i(reg_ra_i),
|
.ra_i(reg_ra_i),
|
.rb_i(reg_rb_i),
|
.rb_i(reg_rb_i),
|
|
|
// Input register contents
|
// Input register contents
|
.ra_regval_i(reg_ra_value_i),
|
.ra_regval_i(reg_ra_value_i),
|
.rb_regval_i(reg_rb_value_i),
|
.rb_regval_i(reg_rb_value_i),
|
|
|
// Dest register (EXEC stage)
|
// Dest register (EXEC stage)
|
.rd_ex_i(r_e_rd),
|
.rd_ex_i(r_e_rd),
|
|
|
// Dest register (WB stage)
|
// Dest register (WB stage)
|
.rd_wb_i(wb_rd_i),
|
.rd_wb_i(wb_rd_i),
|
|
|
// Load pending / target
|
// Load pending / target
|
.load_pending_i(load_pending),
|
.load_pending_i(load_pending),
|
.rd_load_i(r_load_rd),
|
.rd_load_i(r_load_rd),
|
|
|
// Multiplier status
|
// Multiplier status
|
.mult_lo_ex_i(1'b0),
|
.mult_lo_ex_i(1'b0),
|
.mult_hi_ex_i(1'b0),
|
.mult_hi_ex_i(1'b0),
|
.mult_lo_wb_i(1'b0),
|
.mult_lo_wb_i(1'b0),
|
.mult_hi_wb_i(1'b0),
|
.mult_hi_wb_i(1'b0),
|
|
|
// Multiplier result
|
// Multiplier result
|
.result_mult_i(64'b0),
|
.result_mult_i(64'b0),
|
|
|
// Result (EXEC)
|
// Result (EXEC)
|
.result_ex_i(r_e_result),
|
.result_ex_i(r_e_result),
|
|
|
// Result (WB)
|
// Result (WB)
|
.result_wb_i(wb_rd_value_i),
|
.result_wb_i(wb_rd_value_i),
|
|
|
// Resolved register values
|
// Resolved register values
|
.result_ra_o(ra_value_resolved),
|
.result_ra_o(ra_value_resolved),
|
.result_rb_o(rb_value_resolved),
|
.result_rb_o(rb_value_resolved),
|
|
|
// Stall due to failed resolve
|
// Stall due to failed resolve
|
.stall_o(resolve_failed)
|
.stall_o(resolve_failed)
|
);
|
);
|
|
|
//-------------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Execute: Execute opcode
|
// Opcode decode
|
//-------------------------------------------------------------------
|
//-----------------------------------------------------------------
|
|
reg [7:0] inst_r;
|
// Execute stage blocking assignment vars
|
reg [7:0] alu_op_r;
|
reg [7:0] v_inst;
|
reg [1:0] shift_op_r;
|
reg [4:0] v_rd;
|
reg [15:0] sfxx_op_r;
|
reg [7:0] v_alu_op;
|
reg [15:0] uint16_r;
|
reg [1:0] v_shift_op;
|
reg [31:0] uint32_r;
|
reg [15:0] v_sfxx_op;
|
reg [31:0] int32_r;
|
reg [15:0] v_imm;
|
reg [31:0] store_int32_r;
|
reg [31:0] v_imm_uint32;
|
reg [15:0] mxspr_uint16_r;
|
reg [31:0] v_imm_int32;
|
reg [31:0] target_int26_r;
|
reg [31:0] v_store_imm;
|
reg [31:0] reg_ra_r;
|
reg [15:0] v_mxspr_imm;
|
reg [31:0] reg_rb_r;
|
reg [31:0] v_target;
|
reg [31:0] shift_rb_r;
|
reg [31:0] v_reg_ra;
|
reg [31:0] shift_imm_r;
|
reg [31:0] v_reg_rb;
|
|
reg [31:0] v_pc;
|
always @ *
|
reg [31:0] v_offset;
|
begin
|
reg [31:0] v_shift_val;
|
// Instruction
|
reg [31:0] v_shift_imm;
|
inst_r = {2'b00,opcode_i[31:26]};
|
reg [31:0] v_vector;
|
|
reg [31:0] v_sr;
|
// Sub instructions
|
reg [31:0] v_mem_addr;
|
alu_op_r = {opcode_i[9:6],opcode_i[3:0]};
|
reg [31:0] v_mem_data_in;
|
sfxx_op_r = {5'b00,opcode_i[31:21]};
|
reg v_exception;
|
shift_op_r = opcode_i[7:6];
|
reg v_branch;
|
|
reg v_jmp;
|
|
reg v_write_rd;
|
|
reg v_store_pending;
|
|
reg v_load_pending;
|
|
reg v_inst_load;
|
|
reg v_inst_store;
|
|
reg v_stall;
|
|
reg v_no_intr;
|
|
reg v_opcode_valid;
|
|
reg v_check_load_rd;
|
|
|
|
always @ (posedge clk_i or posedge rst_i)
|
|
begin
|
|
if (rst_i == 1'b1)
|
|
begin
|
|
r_pc_branch <= 32'h00000000;
|
|
r_pc_fetch <= 1'b0;
|
|
r_stall <= 1'b0;
|
|
|
|
// Status registers
|
// Branch target
|
r_epc <= 32'h00000000;
|
target_int26_r = sign_extend_imm26(opcode_i[25:0]);
|
r_sr <= 32'h00000000;
|
|
r_esr <= 32'h00000000;
|
|
|
|
r_e_rd <= 5'b00000;
|
// Store immediate
|
|
store_int32_r = sign_extend_imm16({opcode_i[25:21],opcode_i[10:0]});
|
|
|
// Default to no ALU operation
|
// Signed & unsigned imm -> 32-bits
|
r_e_alu_func <= `ALU_NONE;
|
uint16_r = opcode_i[15:0];
|
r_e_alu_a <= 32'h00000000;
|
int32_r = sign_extend_imm16(opcode_i[15:0]);
|
r_e_alu_b <= 32'h00000000;
|
uint32_r = extend_imm16(opcode_i[15:0]);
|
|
|
|
// Register values [ra/rb]
|
|
reg_ra_r = ra_value_resolved;
|
|
reg_rb_r = rb_value_resolved;
|
|
|
r_e_opcode <= 32'h00000000;
|
// Shift ammount (from register[rb])
|
r_e_opcode_pc <= 32'h00000000;
|
shift_rb_r = {26'b00,rb_value_resolved[5:0]};
|
|
|
// Data memory
|
// Shift ammount (from immediate)
|
dmem_addr_o <= 32'h00000000;
|
shift_imm_r = {26'b00,opcode_i[5:0]};
|
dmem_data_out_o <= 32'h00000000;
|
|
dmem_rd_o <= 1'b0;
|
|
dmem_wr_o <= 4'b0000;
|
|
|
|
fault_o <= 1'b0;
|
// MTSPR/MFSPR operand
|
break_o <= 1'b0;
|
mxspr_uint16_r = (ra_value_resolved[15:0] | {5'b00000,opcode_i[10:0]});
|
|
end
|
|
|
r_nmi <= 1'b0;
|
//-----------------------------------------------------------------
|
|
// Instruction Decode
|
|
//-----------------------------------------------------------------
|
|
wire inst_add_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_ADD); // l.add
|
|
wire inst_addc_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_ADDC); // l.addc
|
|
wire inst_and_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_AND); // l.and
|
|
wire inst_or_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_OR); // l.or
|
|
wire inst_sll_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_SLL); // l.sll
|
|
wire inst_sra_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_SRA); // l.sra
|
|
wire inst_srl_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_SRL); // l.srl
|
|
wire inst_sub_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_SUB); // l.sub
|
|
wire inst_xor_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_XOR); // l.xor
|
|
|
|
wire inst_addi_w = (inst_r == `INST_OR32_ADDI); // l.addi
|
|
wire inst_andi_w = (inst_r == `INST_OR32_ANDI); // l.andi
|
|
wire inst_bf_w = (inst_r == `INST_OR32_BF); // l.bf
|
|
wire inst_bnf_w = (inst_r == `INST_OR32_BNF); // l.bnf
|
|
wire inst_j_w = (inst_r == `INST_OR32_J); // l.j
|
|
wire inst_jal_w = (inst_r == `INST_OR32_JAL); // l.jal
|
|
wire inst_jalr_w = (inst_r == `INST_OR32_JALR); // l.jalr
|
|
wire inst_jr_w = (inst_r == `INST_OR32_JR); // l.jr
|
|
wire inst_lbs_w = (inst_r == `INST_OR32_LBS); // l.lbs
|
|
wire inst_lhs_w = (inst_r == `INST_OR32_LHS); // l.lhs
|
|
wire inst_lws_w = (inst_r == `INST_OR32_LWS); // l.lws
|
|
wire inst_lbz_w = (inst_r == `INST_OR32_LBZ); // l.lbz
|
|
wire inst_lhz_w = (inst_r == `INST_OR32_LHZ); // l.lhz
|
|
wire inst_lwz_w = (inst_r == `INST_OR32_LWZ); // l.lwz
|
|
wire inst_mfspr_w = (inst_r == `INST_OR32_MFSPR); // l.mfspr
|
|
wire inst_mtspr_w = (inst_r == `INST_OR32_MTSPR); // l.mtspr
|
|
wire inst_movhi_w = (inst_r == `INST_OR32_MOVHI); // l.movhi
|
|
wire inst_nop_w = (inst_r == `INST_OR32_NOP); // l.nop
|
|
wire inst_ori_w = (inst_r == `INST_OR32_ORI); // l.ori
|
|
wire inst_rfe_w = (inst_r == `INST_OR32_RFE); // l.rfe
|
|
|
|
wire inst_sb_w = (inst_r == `INST_OR32_SB); // l.sb
|
|
wire inst_sh_w = (inst_r == `INST_OR32_SH); // l.sh
|
|
wire inst_sw_w = (inst_r == `INST_OR32_SW); // l.sw
|
|
|
|
wire inst_slli_w = (inst_r == `INST_OR32_SHIFTI) & (shift_op_r == `INST_OR32_SLLI); // l.slli
|
|
wire inst_srai_w = (inst_r == `INST_OR32_SHIFTI) & (shift_op_r == `INST_OR32_SRAI); // l.srai
|
|
wire inst_srli_w = (inst_r == `INST_OR32_SHIFTI) & (shift_op_r == `INST_OR32_SRLI); // l.srli
|
|
|
|
wire inst_xori_w = (inst_r == `INST_OR32_XORI); // l.xori
|
|
|
|
wire inst_sfxx_w = (inst_r == `INST_OR32_SFXX);
|
|
wire inst_sfxxi_w = (inst_r == `INST_OR32_SFXXI);
|
|
|
|
wire inst_sfeq_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFEQ); // l.sfeq
|
|
wire inst_sfges_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFGES); // l.sfges
|
|
|
|
wire inst_sfgeu_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFGEU); // l.sfgeu
|
|
wire inst_sfgts_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFGTS); // l.sfgts
|
|
wire inst_sfgtu_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFGTU); // l.sfgtu
|
|
wire inst_sfles_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFLES); // l.sfles
|
|
wire inst_sfleu_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFLEU); // l.sfleu
|
|
wire inst_sflts_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFLTS); // l.sflts
|
|
wire inst_sfltu_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFLTU); // l.sfltu
|
|
wire inst_sfne_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFNE); // l.sfne
|
|
|
|
wire inst_sfeqi_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFEQI); // l.sfeqi
|
|
wire inst_sfgesi_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFGESI); // l.sfgesi
|
|
wire inst_sfgeui_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFGEUI); // l.sfgeui
|
|
wire inst_sfgtsi_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFGTSI); // l.sfgtsi
|
|
wire inst_sfgtui_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFGTUI); // l.sfgtui
|
|
wire inst_sflesi_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFLESI); // l.sflesi
|
|
|
|
wire inst_sfleui_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFLEUI); // l.sfleui
|
|
wire inst_sfltsi_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFLTSI); // l.sfltsi
|
|
wire inst_sfltui_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFLTUI); // l.sfltui
|
|
wire inst_sfnei_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFNEI); // l.sfnei
|
|
|
icache_flush_o <= 1'b0;
|
wire inst_sys_w = (inst_r == `INST_OR32_MISC) & (opcode_i[31:24] == `INST_OR32_SYS); // l.sys
|
dcache_flush_o <= 1'b0;
|
wire inst_trap_w = (inst_r == `INST_OR32_MISC) & (opcode_i[31:24] == `INST_OR32_TRAP); // l.trap
|
|
|
r_mem_load <= 1'b0;
|
//-----------------------------------------------------------------
|
r_mem_store <= 1'b0;
|
// Stall / Execute
|
r_mem_access <= 1'b0;
|
//-----------------------------------------------------------------
|
|
reg execute_inst_r;
|
|
reg stall_inst_r;
|
|
|
r_load_rd <= 5'b00000;
|
always @ *
|
r_load_inst <= 8'h00;
|
begin
|
r_load_offset <= 2'b00;
|
execute_inst_r = 1'b1;
|
|
stall_inst_r = 1'b0;
|
|
|
d_mem_load <= 1'b0;
|
// No opcode ready or branch delay slot
|
|
if (~opcode_valid_i | r_pc_fetch)
|
|
execute_inst_r = 1'b0;
|
|
// Valid instruction, but load result / operand not ready
|
|
else if (resolve_failed | load_stall)
|
|
stall_inst_r = 1'b1;
|
end
|
end
|
else
|
|
begin
|
|
|
|
// If memory access accepted by slave
|
//-----------------------------------------------------------------
|
if (dmem_accept_i)
|
// Next PC
|
|
//-----------------------------------------------------------------
|
|
reg [31:0] next_pc_r;
|
|
|
|
always @ *
|
begin
|
begin
|
dmem_rd_o <= 1'b0;
|
// Next expected PC (current PC + 4)
|
dmem_wr_o <= 4'b0000;
|
next_pc_r = (opcode_pc_i + 4);
|
end
|
end
|
|
|
r_mem_access <= 1'b0;
|
//-----------------------------------------------------------------
|
break_o <= 1'b0;
|
// Next SR
|
icache_flush_o <= 1'b0;
|
//-----------------------------------------------------------------
|
dcache_flush_o <= 1'b0;
|
reg [31:0] next_sr_r;
|
|
reg compare_result_r;
|
// Record NMI in-case it can't be processed this cycle
|
always @ *
|
if (nmi_i)
|
begin
|
r_nmi <= 1'b1;
|
next_sr_r = r_sr;
|
|
|
// Reset branch request
|
// Latch carry if updated
|
r_pc_fetch <= 1'b0;
|
if (alu_carry_update)
|
|
next_sr_r[`OR32_SR_CY] = alu_carry_out;
|
|
|
v_exception = 1'b0;
|
// If valid instruction, check if SR needs updating
|
v_vector = 32'h00000000;
|
if (execute_inst_r & ~stall_inst_r)
|
v_branch = 1'b0;
|
begin
|
v_jmp = 1'b0;
|
case (1'b1)
|
v_write_rd = 1'b0;
|
inst_mtspr_w:
|
v_sr = r_sr;
|
begin
|
v_stall = 1'b0;
|
case (mxspr_uint16_r)
|
v_no_intr = 1'b0;
|
// SR - Supervision register
|
|
`SPR_REG_SR:
|
|
begin
|
|
next_sr_r = reg_rb_r;
|
|
|
d_mem_load <= r_mem_access & r_mem_load;
|
// Don't store cache flush requests
|
|
next_sr_r[`OR32_SR_ICACHE_FLUSH] = 1'b0;
|
|
next_sr_r[`OR32_SR_DCACHE_FLUSH] = 1'b0;
|
|
end
|
|
default:
|
|
;
|
|
endcase
|
|
end
|
|
inst_rfe_w:
|
|
next_sr_r = r_esr;
|
|
inst_sfxx_w,
|
|
inst_sfxxi_w:
|
|
next_sr_r[`OR32_SR_F] = compare_result_r;
|
|
default:
|
|
;
|
|
endcase
|
|
end
|
|
end
|
|
|
//---------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Opcode
|
// Next EPC/ESR
|
//---------------------------------------------------------------
|
//-----------------------------------------------------------------
|
|
reg [31:0] next_epc_r;
|
|
reg [31:0] next_esr_r;
|
|
|
// Instruction not ready
|
always @ *
|
if (!opcode_valid_i)
|
|
begin
|
begin
|
v_opcode_valid = 1'b0;
|
next_epc_r = r_epc;
|
|
next_esr_r = r_esr;
|
|
|
`ifdef CONF_CORE_DEBUG_BUBBLE
|
case (1'b1)
|
$display("%08x: Execute - Instruction not ready", opcode_pc_i);
|
inst_mtspr_w: // l.mtspr
|
`endif
|
|
end
|
|
// Branch request, always drop the next instruction
|
|
else if (r_pc_fetch)
|
|
begin
|
begin
|
v_opcode_valid = 1'b0;
|
case (mxspr_uint16_r)
|
|
// EPCR - EPC Exception saved PC
|
|
`SPR_REG_EPCR: next_epc_r = reg_rb_r;
|
|
|
`ifdef CONF_CORE_DEBUG
|
// ESR - Exception saved SR
|
$display("%08x: Exec - Branch pending, skip instruction (%x)", opcode_pc_i, opcode_i);
|
`SPR_REG_ESR: next_esr_r = reg_rb_r;
|
`endif
|
endcase
|
end
|
end
|
// Valid instruction ready
|
default:
|
else
|
;
|
begin
|
endcase
|
v_mem_data_in = opcode_i;
|
|
v_opcode_valid = 1'b1;
|
|
|
|
`ifdef CONF_CORE_FAULT_ON_OPCODE0
|
|
// This is a valid opcode (branch to same instruction),
|
|
// but rare and useful for catching pipeline errors
|
|
if (v_mem_data_in == 32'h00000000)
|
|
fault_o <= 1'b1;
|
|
`endif
|
|
end
|
end
|
|
|
//---------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Decode opcode
|
// ALU inputs
|
//---------------------------------------------------------------
|
//-----------------------------------------------------------------
|
v_alu_op = {v_mem_data_in[9:6],v_mem_data_in[3:0]};
|
|
v_sfxx_op = {5'b00,v_mem_data_in[31:21]};
|
|
v_shift_op = v_mem_data_in[7:6];
|
|
v_target = sign_extend_imm26(v_mem_data_in[25:0]);
|
|
v_store_imm = sign_extend_imm16({v_mem_data_in[25:21],v_mem_data_in[10:0]});
|
|
|
|
// Signed & unsigned imm -> 32-bits
|
|
v_imm = v_mem_data_in[15:0];
|
|
v_imm_int32 = sign_extend_imm16(v_imm);
|
|
v_imm_uint32 = extend_imm16(v_imm);
|
|
|
|
// Load register[ra]
|
|
v_reg_ra = ra_value_resolved;
|
|
|
|
// Load register[rb]
|
|
v_reg_rb = rb_value_resolved;
|
|
|
|
// Default to no ALU operation (output == input_a)
|
// ALU operation selection
|
r_e_alu_func <= `ALU_NONE;
|
reg [3:0] alu_func_r;
|
r_e_alu_a <= 32'h00000000;
|
|
|
|
// Default target is R[d]
|
// ALU operands
|
v_rd = reg_rd_i;
|
reg [31:0] alu_input_a_r;
|
|
reg [31:0] alu_input_b_r;
|
|
reg write_rd_r;
|
|
|
//---------------------------------------------------------------
|
always @ *
|
// Outstanding memory access
|
begin
|
//---------------------------------------------------------------
|
alu_func_r = `ALU_NONE;
|
|
alu_input_a_r = 32'b0;
|
|
alu_input_b_r = 32'b0;
|
|
write_rd_r = 1'b0;
|
|
|
// Pending accesses
|
case (1'b1)
|
v_load_pending = load_pending;
|
|
v_store_pending = store_pending;
|
|
v_check_load_rd = 1'b1;
|
|
|
|
// Stall pipeline due to load / store
|
inst_add_w: // l.add
|
if (v_opcode_valid & load_stall)
|
|
begin
|
begin
|
v_stall = 1'b1;
|
alu_func_r = `ALU_ADD;
|
v_opcode_valid = 1'b0;
|
alu_input_a_r = reg_ra_r;
|
|
alu_input_b_r = reg_rb_r;
|
|
write_rd_r = 1'b1;
|
end
|
end
|
|
|
// Insert load result into pipeline?
|
inst_addc_w: // l.addc
|
if (load_insert)
|
|
begin
|
begin
|
// Feed load result into pipeline
|
alu_func_r = `ALU_ADDC;
|
r_e_alu_func <= `ALU_NONE;
|
alu_input_a_r = reg_ra_r;
|
r_e_alu_a <= load_result;
|
alu_input_b_r = reg_rb_r;
|
v_rd = r_load_rd;
|
write_rd_r = 1'b1;
|
v_write_rd = 1'b1;
|
|
end
|
end
|
|
|
//---------------------------------------------------------------
|
inst_and_w: // l.and
|
// Invalid PC detection
|
|
//---------------------------------------------------------------
|
|
|
|
// Detect incorrect program counter and cause FAULT
|
|
if (opcode_valid_i && (opcode_pc_i[1:0] != 2'b00))
|
|
begin
|
begin
|
fault_o <= 1'b1;
|
alu_func_r = `ALU_AND;
|
v_opcode_valid = 1'b0;
|
alu_input_a_r = reg_ra_r;
|
v_exception = 1'b1;
|
alu_input_b_r = reg_rb_r;
|
v_vector = ISR_VECTOR + `VECTOR_BUS_ERROR;
|
write_rd_r = 1'b1;
|
end
|
end
|
|
|
//---------------------------------------------------------------
|
inst_or_w: // l.or
|
// Failed operand resolve?
|
|
//---------------------------------------------------------------
|
|
if (opcode_valid_i & resolve_failed)
|
|
begin
|
begin
|
`ifdef CONF_CORE_DEBUG
|
alu_func_r = `ALU_OR;
|
$display("%08x: Operand resolve failed RA=%d, RB=%d", opcode_pc_i, reg_ra_i, reg_rb_i);
|
alu_input_a_r = reg_ra_r;
|
`endif
|
alu_input_b_r = reg_rb_r;
|
// Stall!
|
write_rd_r = 1'b1;
|
v_opcode_valid = 1'b0;
|
|
v_stall = 1'b1;
|
|
end
|
end
|
|
|
//---------------------------------------------------------------
|
inst_sll_w: // l.sll
|
// Final instruction decoding
|
|
//---------------------------------------------------------------
|
|
|
|
// Insert bubble into the pipeline?
|
|
if (!v_opcode_valid)
|
|
begin
|
begin
|
v_mem_data_in = `OPCODE_INST_BUBBLE;
|
alu_func_r = `ALU_SHIFTL;
|
v_check_load_rd = 1'b0;
|
alu_input_a_r = reg_ra_r;
|
|
alu_input_b_r = shift_rb_r;
|
|
write_rd_r = 1'b1;
|
end
|
end
|
|
|
// Store opcode (after possible bubble generation)
|
inst_sra_w: // l.sra
|
r_e_opcode <= v_mem_data_in;
|
|
r_e_opcode_pc <= opcode_pc_i;
|
|
|
|
// Decode instruction
|
|
v_inst = {2'b00,v_mem_data_in[31:26]};
|
|
|
|
// Shift ammount (from register[rb])
|
|
v_shift_val = {26'b00,v_reg_rb[5:0]};
|
|
|
|
// Shift ammount (from immediate)
|
|
v_shift_imm = {26'b00,v_imm[5:0]};
|
|
|
|
// MTSPR/MFSPR operand
|
|
v_mxspr_imm = (v_reg_ra[15:0] | {5'b00000,v_mem_data_in[10:0]});
|
|
|
|
// Next expected PC (current PC + 4)
|
|
v_pc = (opcode_pc_i + 4);
|
|
|
|
// Latch carry if updated
|
|
if (alu_carry_update)
|
|
v_sr[`OR32_SR_CY] = alu_carry_out;
|
|
|
|
`ifdef CONF_CORE_TRACE
|
|
if (v_opcode_valid)
|
|
begin
|
begin
|
$display("%08x: Execute 0x%08x", opcode_pc_i, v_mem_data_in);
|
alu_func_r = `ALU_SHIRTR_ARITH;
|
$display(" rA[%d] = 0x%08x", reg_ra_i, v_reg_ra);
|
alu_input_a_r = reg_ra_r;
|
$display(" rB[%d] = 0x%08x", reg_rb_i, v_reg_rb);
|
alu_input_b_r = shift_rb_r;
|
|
write_rd_r = 1'b1;
|
end
|
end
|
`endif
|
|
|
|
//---------------------------------------------------------------
|
inst_srl_w: // l.srl
|
// Execute instruction
|
|
//---------------------------------------------------------------
|
|
case (v_inst)
|
|
`INST_OR32_BUBBLE :
|
|
begin
|
|
// Do not allow external interrupts whilst executing a bubble
|
|
// as this will result in pipeline issues.
|
|
v_no_intr = 1'b1;
|
|
end
|
|
`INST_OR32_ALU :
|
|
begin
|
|
case (v_alu_op)
|
|
`INST_OR32_ADD: // l.add
|
|
begin
|
begin
|
r_e_alu_func <= `ALU_ADD;
|
alu_func_r = `ALU_SHIFTR;
|
r_e_alu_a <= v_reg_ra;
|
alu_input_a_r = reg_ra_r;
|
r_e_alu_b <= v_reg_rb;
|
alu_input_b_r = shift_rb_r;
|
v_write_rd = 1'b1;
|
write_rd_r = 1'b1;
|
end
|
end
|
|
|
`INST_OR32_ADDC: // l.addc
|
inst_sub_w: // l.sub
|
begin
|
begin
|
r_e_alu_func <= `ALU_ADDC;
|
alu_func_r = `ALU_SUB;
|
r_e_alu_a <= v_reg_ra;
|
alu_input_a_r = reg_ra_r;
|
r_e_alu_b <= v_reg_rb;
|
alu_input_b_r = reg_rb_r;
|
v_write_rd = 1'b1;
|
write_rd_r = 1'b1;
|
end
|
end
|
|
|
`INST_OR32_AND: // l.and
|
inst_xor_w: // l.xor
|
begin
|
begin
|
r_e_alu_func <= `ALU_AND;
|
alu_func_r = `ALU_XOR;
|
r_e_alu_a <= v_reg_ra;
|
alu_input_a_r = reg_ra_r;
|
r_e_alu_b <= v_reg_rb;
|
alu_input_b_r = reg_rb_r;
|
v_write_rd = 1'b1;
|
write_rd_r = 1'b1;
|
end
|
end
|
|
|
`INST_OR32_OR: // l.or
|
inst_addi_w: // l.addi
|
begin
|
begin
|
r_e_alu_func <= `ALU_OR;
|
alu_func_r = `ALU_ADD;
|
r_e_alu_a <= v_reg_ra;
|
alu_input_a_r = reg_ra_r;
|
r_e_alu_b <= v_reg_rb;
|
alu_input_b_r = int32_r;
|
v_write_rd = 1'b1;
|
write_rd_r = 1'b1;
|
end
|
end
|
|
|
`INST_OR32_SLL: // l.sll
|
inst_andi_w: // l.andi
|
begin
|
begin
|
r_e_alu_func <= `ALU_SHIFTL;
|
alu_func_r = `ALU_AND;
|
r_e_alu_a <= v_reg_ra;
|
alu_input_a_r = reg_ra_r;
|
r_e_alu_b <= v_shift_val;
|
alu_input_b_r = uint32_r;
|
v_write_rd = 1'b1;
|
write_rd_r = 1'b1;
|
end
|
end
|
|
|
`INST_OR32_SRA: // l.sra
|
inst_jal_w: // l.jal
|
begin
|
begin
|
r_e_alu_func <= `ALU_SHIRTR_ARITH;
|
alu_input_a_r = next_pc_r;
|
r_e_alu_a <= v_reg_ra;
|
write_rd_r = 1'b1;
|
r_e_alu_b <= v_shift_val;
|
|
v_write_rd = 1'b1;
|
|
end
|
end
|
|
|
`INST_OR32_SRL: // l.srl
|
inst_jalr_w: // l.jalr
|
begin
|
begin
|
r_e_alu_func <= `ALU_SHIFTR;
|
alu_input_a_r = next_pc_r;
|
r_e_alu_a <= v_reg_ra;
|
write_rd_r = 1'b1;
|
r_e_alu_b <= v_shift_val;
|
|
v_write_rd = 1'b1;
|
|
end
|
end
|
|
|
`INST_OR32_SUB: // l.sub
|
inst_mfspr_w: // l.mfspr
|
|
begin
|
|
case (mxspr_uint16_r)
|
|
// SR - Supervision register
|
|
`SPR_REG_SR:
|
begin
|
begin
|
r_e_alu_func <= `ALU_SUB;
|
alu_input_a_r = next_sr_r;
|
r_e_alu_a <= v_reg_ra;
|
write_rd_r = 1'b1;
|
r_e_alu_b <= v_reg_rb;
|
|
v_write_rd = 1'b1;
|
|
end
|
end
|
|
|
`INST_OR32_XOR: // l.xor
|
// EPCR - EPC Exception saved PC
|
|
`SPR_REG_EPCR:
|
begin
|
begin
|
r_e_alu_func <= `ALU_XOR;
|
alu_input_a_r = r_epc;
|
r_e_alu_a <= v_reg_ra;
|
write_rd_r = 1'b1;
|
r_e_alu_b <= v_reg_rb;
|
|
v_write_rd = 1'b1;
|
|
end
|
end
|
|
|
default:
|
// ESR - Exception saved SR
|
|
`SPR_REG_ESR:
|
begin
|
begin
|
fault_o <= 1'b1;
|
alu_input_a_r = r_esr;
|
v_exception = 1'b1;
|
write_rd_r = 1'b1;
|
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
|
|
end
|
end
|
|
default:
|
|
;
|
endcase
|
endcase
|
end
|
end
|
|
|
`INST_OR32_ADDI: // l.addi
|
inst_movhi_w: // l.movhi
|
begin
|
begin
|
r_e_alu_func <= `ALU_ADD;
|
alu_input_a_r = {uint16_r,16'h0000};
|
r_e_alu_a <= v_reg_ra;
|
write_rd_r = 1'b1;
|
r_e_alu_b <= v_imm_int32;
|
|
v_write_rd = 1'b1;
|
|
end
|
end
|
|
|
`INST_OR32_ANDI: // l.andi
|
inst_ori_w: // l.ori
|
begin
|
begin
|
r_e_alu_func <= `ALU_AND;
|
alu_func_r = `ALU_OR;
|
r_e_alu_a <= v_reg_ra;
|
alu_input_a_r = reg_ra_r;
|
r_e_alu_b <= v_imm_uint32;
|
alu_input_b_r = uint32_r;
|
v_write_rd = 1'b1;
|
write_rd_r = 1'b1;
|
end
|
end
|
|
|
`INST_OR32_BF: // l.bf
|
inst_slli_w: // l.slli
|
begin
|
begin
|
if (v_sr[`OR32_SR_F] == 1'b1)
|
alu_func_r = `ALU_SHIFTL;
|
v_branch = 1'b1;
|
alu_input_a_r = reg_ra_r;
|
|
alu_input_b_r = shift_imm_r;
|
|
write_rd_r = 1'b1;
|
end
|
end
|
|
|
`INST_OR32_BNF: // l.bnf
|
inst_srai_w: // l.srai
|
begin
|
begin
|
if (v_sr[`OR32_SR_F] == 1'b0)
|
alu_func_r = `ALU_SHIRTR_ARITH;
|
v_branch = 1'b1;
|
alu_input_a_r = reg_ra_r;
|
|
alu_input_b_r = shift_imm_r;
|
|
write_rd_r = 1'b1;
|
end
|
end
|
|
|
`INST_OR32_J: // l.j
|
inst_srli_w: // l.srli
|
begin
|
begin
|
v_branch = 1'b1;
|
alu_func_r = `ALU_SHIFTR;
|
|
alu_input_a_r = reg_ra_r;
|
|
alu_input_b_r = shift_imm_r;
|
|
write_rd_r = 1'b1;
|
end
|
end
|
|
|
`INST_OR32_JAL: // l.jal
|
// l.lbs l.lhs l.lws l.lbz l.lhz l.lwz
|
begin
|
inst_lbs_w,
|
r_e_alu_a <= v_pc;
|
inst_lhs_w,
|
v_write_rd = 1'b1;
|
inst_lws_w,
|
v_rd = 5'b01001; // Write to REG_9_LR
|
inst_lbz_w,
|
`ifdef CONF_CORE_DEBUG
|
inst_lhz_w,
|
$display(" Save 0x%x to LR", v_pc);
|
inst_lwz_w:
|
`endif
|
write_rd_r = 1'b1;
|
v_branch = 1'b1;
|
|
|
inst_xori_w: // l.xori
|
|
begin
|
|
alu_func_r = `ALU_XOR;
|
|
alu_input_a_r = reg_ra_r;
|
|
alu_input_b_r = int32_r;
|
|
write_rd_r = 1'b1;
|
|
end
|
|
default:
|
|
;
|
|
endcase
|
end
|
end
|
|
|
`INST_OR32_JALR: // l.jalr
|
//-----------------------------------------------------------------
|
|
// Comparisons
|
|
//-----------------------------------------------------------------
|
|
always @ *
|
begin
|
begin
|
r_e_alu_a <= v_pc;
|
compare_result_r = 1'b0;
|
v_write_rd = 1'b1;
|
|
v_rd = 5'b01001; // Write to REG_9_LR
|
|
`ifdef CONF_CORE_DEBUG
|
|
$display(" Save 0x%x to LR", v_pc);
|
|
`endif
|
|
v_pc = v_reg_rb;
|
|
v_jmp = 1;
|
|
end
|
|
|
|
`INST_OR32_JR: // l.jr
|
case (1'b1)
|
|
inst_sfeq_w: // l.sfeq
|
begin
|
begin
|
v_pc = v_reg_rb;
|
if (reg_ra_r == reg_rb_r)
|
v_jmp = 1;
|
compare_result_r = 1'b1;
|
|
else
|
|
compare_result_r = 1'b0;
|
end
|
end
|
|
|
// l.lbs l.lhs l.lws l.lbz l.lhz l.lwz
|
inst_sfeqi_w: // l.sfeqi
|
`INST_OR32_LBS, `INST_OR32_LHS, `INST_OR32_LWS, `INST_OR32_LBZ, `INST_OR32_LHZ, `INST_OR32_LWZ :
|
|
begin
|
begin
|
v_mem_addr = (v_reg_ra + v_imm_int32);
|
if (reg_ra_r == int32_r)
|
dmem_addr_o <= v_mem_addr;
|
compare_result_r = 1'b1;
|
dmem_data_out_o <= 32'h00000000;
|
else
|
dmem_rd_o <= 1'b1;
|
compare_result_r = 1'b0;
|
|
end
|
// Writeback if load result ready
|
|
v_write_rd = 1'b1;
|
|
v_check_load_rd = 1'b0;
|
|
|
|
// Mark load as pending
|
|
v_load_pending = 1'b1;
|
|
r_mem_access <= 1'b1;
|
|
|
|
// Record target register
|
|
r_load_rd <= reg_rd_i;
|
|
r_load_inst <= v_inst;
|
|
r_load_offset<= v_mem_addr[1:0];
|
|
|
|
`ifdef CONF_CORE_DEBUG
|
inst_sfges_w: // l.sfges
|
$display(" Load from 0x%08x to R%d", v_mem_addr, reg_rd_i);
|
|
`endif
|
|
// Detect bad load address & fault (ignore bit 31)
|
|
if (v_mem_addr[30:28] != 3'h1)
|
|
begin
|
begin
|
v_load_pending = 1'b0;
|
if (greater_than_equal_signed(reg_ra_r, reg_rb_r) == 1'b1)
|
dmem_rd_o <= 1'b0;
|
compare_result_r = 1'b1;
|
r_mem_access <= 1'b0;
|
else
|
fault_o <= 1'b1;
|
compare_result_r = 1'b0;
|
v_exception = 1'b1;
|
|
v_vector = ISR_VECTOR + `VECTOR_BUS_ERROR;
|
|
end
|
|
end
|
end
|
|
|
`INST_OR32_MFSPR: // l.mfspr
|
inst_sfgesi_w: // l.sfgesi
|
begin
|
begin
|
case (v_mxspr_imm)
|
if (greater_than_equal_signed(reg_ra_r, int32_r) == 1'b1)
|
// SR - Supervision register
|
compare_result_r = 1'b1;
|
`SPR_REG_SR:
|
else
|
begin
|
compare_result_r = 1'b0;
|
r_e_alu_a <= v_sr;
|
|
v_write_rd = 1'b1;
|
|
end
|
end
|
|
|
// EPCR - EPC Exception saved PC
|
inst_sfgeu_w: // l.sfgeu
|
`SPR_REG_EPCR:
|
|
begin
|
begin
|
r_e_alu_a <= r_epc;
|
if (reg_ra_r >= reg_rb_r)
|
v_write_rd = 1'b1;
|
compare_result_r = 1'b1;
|
|
else
|
|
compare_result_r = 1'b0;
|
end
|
end
|
|
|
// ESR - Exception saved SR
|
inst_sfgeui_w: // l.sfgeui
|
`SPR_REG_ESR:
|
|
begin
|
begin
|
r_e_alu_a <= r_esr;
|
if (reg_ra_r >= int32_r)
|
v_write_rd = 1'b1;
|
compare_result_r = 1'b1;
|
|
else
|
|
compare_result_r = 1'b0;
|
end
|
end
|
|
|
default:
|
inst_sfgts_w: // l.sfgts
|
begin
|
begin
|
fault_o <= 1'b1;
|
if (greater_than_signed(reg_ra_r, reg_rb_r) == 1'b1)
|
v_exception = 1'b1;
|
compare_result_r = 1'b1;
|
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
|
else
|
end
|
compare_result_r = 1'b0;
|
endcase
|
|
end
|
end
|
|
|
`INST_OR32_MTSPR: // l.mtspr
|
inst_sfgtsi_w: // l.sfgtsi
|
begin
|
|
case (v_mxspr_imm)
|
|
// SR - Supervision register
|
|
`SPR_REG_SR:
|
|
begin
|
begin
|
v_sr = v_reg_rb;
|
if (greater_than_signed(reg_ra_r, int32_r) == 1'b1)
|
|
compare_result_r = 1'b1;
|
// Cache flush request?
|
else
|
icache_flush_o <= v_reg_rb[`OR32_SR_ICACHE_FLUSH];
|
compare_result_r = 1'b0;
|
dcache_flush_o <= v_reg_rb[`OR32_SR_DCACHE_FLUSH];
|
|
|
|
// Don't store cache flush requests
|
|
v_sr[`OR32_SR_ICACHE_FLUSH] = 1'b0;
|
|
v_sr[`OR32_SR_DCACHE_FLUSH] = 1'b0;
|
|
end
|
end
|
|
|
// EPCR - EPC Exception saved PC
|
inst_sfgtu_w: // l.sfgtu
|
`SPR_REG_EPCR:
|
|
begin
|
begin
|
r_epc <= v_reg_rb;
|
if (reg_ra_r > reg_rb_r)
|
|
compare_result_r = 1'b1;
|
|
else
|
|
compare_result_r = 1'b0;
|
end
|
end
|
|
|
// ESR - Exception saved SR
|
inst_sfgtui_w: // l.sfgtui
|
`SPR_REG_ESR:
|
|
begin
|
begin
|
r_esr <= v_reg_rb;
|
if (reg_ra_r > int32_r)
|
|
compare_result_r = 1'b1;
|
|
else
|
|
compare_result_r = 1'b0;
|
end
|
end
|
|
|
default:
|
inst_sfles_w: // l.sfles
|
begin
|
begin
|
fault_o <= 1'b1;
|
if (less_than_equal_signed(reg_ra_r, reg_rb_r) == 1'b1)
|
v_exception = 1'b1;
|
compare_result_r = 1'b1;
|
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
|
else
|
end
|
compare_result_r = 1'b0;
|
endcase
|
|
end
|
end
|
|
|
`INST_OR32_MOVHI: // l.movhi
|
inst_sflesi_w: // l.sflesi
|
begin
|
begin
|
r_e_alu_a <= {v_imm,16'h0000};
|
if (less_than_equal_signed(reg_ra_r, int32_r) == 1'b1)
|
v_write_rd = 1'b1;
|
compare_result_r = 1'b1;
|
|
else
|
|
compare_result_r = 1'b0;
|
end
|
end
|
|
|
`INST_OR32_NOP: // l.nop
|
inst_sfleu_w: // l.sfleu
|
begin
|
begin
|
`ifdef SIMULATION
|
if (reg_ra_r <= reg_rb_r)
|
case (v_imm)
|
compare_result_r = 1'b1;
|
// NOP_PUTC
|
else
|
16'h0004: $write("%c", v_reg_ra[7:0]);
|
compare_result_r = 1'b0;
|
// NOP
|
|
16'h0000: ;
|
|
endcase
|
|
`endif
|
|
end
|
end
|
|
|
`INST_OR32_ORI: // l.ori
|
inst_sfleui_w: // l.sfleui
|
begin
|
begin
|
r_e_alu_func <= `ALU_OR;
|
if (reg_ra_r <= int32_r)
|
r_e_alu_a <= v_reg_ra;
|
compare_result_r = 1'b1;
|
r_e_alu_b <= v_imm_uint32;
|
else
|
v_write_rd = 1'b1;
|
compare_result_r = 1'b0;
|
end
|
end
|
|
|
`INST_OR32_RFE: // l.rfe
|
inst_sflts_w: // l.sflts
|
begin
|
begin
|
v_pc = r_epc;
|
if (less_than_signed(reg_ra_r, reg_rb_r) == 1'b1)
|
v_sr = r_esr;
|
compare_result_r = 1'b1;
|
v_jmp = 1;
|
else
|
|
compare_result_r = 1'b0;
|
end
|
end
|
|
|
`INST_OR32_SHIFTI :
|
inst_sfltsi_w: // l.sfltsi
|
begin
|
begin
|
case (v_shift_op)
|
if (less_than_signed(reg_ra_r, int32_r) == 1'b1)
|
`INST_OR32_SLLI: // l.slli
|
compare_result_r = 1'b1;
|
begin
|
else
|
r_e_alu_func <= `ALU_SHIFTL;
|
compare_result_r = 1'b0;
|
r_e_alu_a <= v_reg_ra;
|
|
r_e_alu_b <= v_shift_imm;
|
|
v_write_rd = 1'b1;
|
|
end
|
end
|
|
|
`INST_OR32_SRAI: // l.srai
|
inst_sfltu_w: // l.sfltu
|
begin
|
begin
|
r_e_alu_func <= `ALU_SHIRTR_ARITH;
|
if (reg_ra_r < reg_rb_r)
|
r_e_alu_a <= v_reg_ra;
|
compare_result_r = 1'b1;
|
r_e_alu_b <= v_shift_imm;
|
else
|
v_write_rd = 1'b1;
|
compare_result_r = 1'b0;
|
end
|
end
|
|
|
`INST_OR32_SRLI: // l.srli
|
inst_sfltui_w: // l.sfltui
|
begin
|
begin
|
r_e_alu_func <= `ALU_SHIFTR;
|
if (reg_ra_r < int32_r)
|
r_e_alu_a <= v_reg_ra;
|
compare_result_r = 1'b1;
|
r_e_alu_b <= v_shift_imm;
|
else
|
v_write_rd = 1'b1;
|
compare_result_r = 1'b0;
|
end
|
end
|
|
|
default:
|
inst_sfne_w: // l.sfne
|
begin
|
begin
|
fault_o <= 1'b1;
|
if (reg_ra_r != reg_rb_r)
|
v_exception = 1'b1;
|
compare_result_r = 1'b1;
|
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
|
else
|
end
|
compare_result_r = 1'b0;
|
endcase
|
|
end
|
end
|
|
|
`INST_OR32_SB:
|
inst_sfnei_w: // l.sfnei
|
begin
|
|
v_mem_addr = (v_reg_ra + v_store_imm);
|
|
dmem_addr_o <= v_mem_addr;
|
|
r_mem_access <= 1'b1;
|
|
case (v_mem_addr[1:0])
|
|
2'b00 :
|
|
begin
|
|
dmem_data_out_o <= {v_reg_rb[7:0],24'h000000};
|
|
dmem_wr_o <= 4'b1000;
|
|
v_store_pending = 1'b1;
|
|
end
|
|
2'b01 :
|
|
begin
|
|
dmem_data_out_o <= {{8'h00,v_reg_rb[7:0]},16'h0000};
|
|
dmem_wr_o <= 4'b0100;
|
|
v_store_pending = 1'b1;
|
|
end
|
|
2'b10 :
|
|
begin
|
begin
|
dmem_data_out_o <= {{16'h0000,v_reg_rb[7:0]},8'h00};
|
if (reg_ra_r != int32_r)
|
dmem_wr_o <= 4'b0010;
|
compare_result_r = 1'b1;
|
v_store_pending = 1'b1;
|
else
|
end
|
compare_result_r = 1'b0;
|
2'b11 :
|
|
begin
|
|
dmem_data_out_o <= {24'h000000,v_reg_rb[7:0]};
|
|
dmem_wr_o <= 4'b0001;
|
|
v_store_pending = 1'b1;
|
|
end
|
end
|
default :
|
default :
|
begin
|
;
|
dmem_data_out_o <= 32'h00000000;
|
|
dmem_wr_o <= 4'b0000;
|
|
end
|
|
endcase
|
endcase
|
end
|
end
|
|
|
`INST_OR32_SFXX, `INST_OR32_SFXXI:
|
//-----------------------------------------------------------------
|
begin
|
// Load/Store operation?
|
case (v_sfxx_op)
|
//-----------------------------------------------------------------
|
`INST_OR32_SFEQ: // l.sfeq
|
reg load_inst_r;
|
begin
|
reg store_inst_r;
|
if (v_reg_ra == v_reg_rb)
|
reg [31:0] mem_addr_r;
|
v_sr[`OR32_SR_F] = 1'b1;
|
always @ *
|
else
|
begin
|
v_sr[`OR32_SR_F] = 1'b0;
|
load_inst_r = inst_lbs_w | inst_lhs_w | inst_lws_w |
|
end
|
inst_lbz_w | inst_lhz_w | inst_lwz_w;
|
|
store_inst_r = inst_sb_w | inst_sh_w | inst_sw_w;
|
|
|
`INST_OR32_SFEQI: // l.sfeqi
|
// Memory address is relative to RA
|
begin
|
mem_addr_r = reg_ra_r + (store_inst_r ? store_int32_r : int32_r);
|
if (v_reg_ra == v_imm_int32)
|
|
v_sr[`OR32_SR_F] = 1'b1;
|
|
else
|
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
end
|
|
|
`INST_OR32_SFGES: // l.sfges
|
//-----------------------------------------------------------------
|
begin
|
// Branches
|
if (greater_than_equal_signed(v_reg_ra, v_reg_rb) == 1'b1)
|
//-----------------------------------------------------------------
|
v_sr[`OR32_SR_F] = 1'b1;
|
reg branch_r;
|
else
|
reg branch_link_r;
|
v_sr[`OR32_SR_F] = 1'b0;
|
reg [31:0] branch_target_r;
|
end
|
reg branch_except_r;
|
|
|
`INST_OR32_SFGESI: // l.sfgesi
|
always @ *
|
begin
|
begin
|
if (greater_than_equal_signed(v_reg_ra, v_imm_int32) == 1'b1)
|
|
v_sr[`OR32_SR_F] = 1'b1;
|
|
else
|
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
|
|
|
`INST_OR32_SFGEU: // l.sfgeu
|
branch_r = 1'b0;
|
begin
|
branch_link_r = 1'b0;
|
if (v_reg_ra >= v_reg_rb)
|
branch_except_r = 1'b0;
|
v_sr[`OR32_SR_F] = 1'b1;
|
|
else
|
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
|
|
|
`INST_OR32_SFGEUI: // l.sfgeui
|
// Default branch target is relative to current PC
|
begin
|
branch_target_r = (opcode_pc_i + {target_int26_r[29:0],2'b00});
|
if (v_reg_ra >= v_imm_int32)
|
|
v_sr[`OR32_SR_F] = 1'b1;
|
|
else
|
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
|
|
|
`INST_OR32_SFGTS: // l.sfgts
|
case (1'b1)
|
begin
|
inst_bf_w: // l.bf
|
if (greater_than_signed(v_reg_ra, v_reg_rb) == 1'b1)
|
branch_r = r_sr[`OR32_SR_F];
|
v_sr[`OR32_SR_F] = 1'b1;
|
|
else
|
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
|
|
|
`INST_OR32_SFGTSI: // l.sfgtsi
|
inst_bnf_w: // l.bnf
|
begin
|
branch_r = ~r_sr[`OR32_SR_F];
|
if (greater_than_signed(v_reg_ra, v_imm_int32) == 1'b1)
|
|
v_sr[`OR32_SR_F] = 1'b1;
|
|
else
|
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
|
|
|
`INST_OR32_SFGTU: // l.sfgtu
|
inst_j_w: // l.j
|
begin
|
branch_r = 1'b1;
|
if (v_reg_ra > v_reg_rb)
|
|
v_sr[`OR32_SR_F] = 1'b1;
|
|
else
|
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
|
|
|
`INST_OR32_SFGTUI: // l.sfgtui
|
inst_jal_w: // l.jal
|
begin
|
begin
|
if (v_reg_ra > v_imm_int32)
|
// Write to REG_9_LR
|
v_sr[`OR32_SR_F] = 1'b1;
|
branch_link_r = 1'b1;
|
else
|
branch_r = 1'b1;
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
end
|
|
|
`INST_OR32_SFLES: // l.sfles
|
inst_jalr_w: // l.jalr
|
begin
|
begin
|
if (less_than_equal_signed(v_reg_ra, v_reg_rb) == 1'b1)
|
// Write to REG_9_LR
|
v_sr[`OR32_SR_F] = 1'b1;
|
branch_link_r = 1'b1;
|
else
|
branch_r = 1'b1;
|
v_sr[`OR32_SR_F] = 1'b0;
|
branch_target_r = reg_rb_r;
|
end
|
end
|
|
|
`INST_OR32_SFLESI: // l.sflesi
|
inst_jr_w: // l.jr
|
begin
|
begin
|
if (less_than_equal_signed(v_reg_ra, v_imm_int32) == 1'b1)
|
branch_r = 1'b1;
|
v_sr[`OR32_SR_F] = 1'b1;
|
branch_target_r = reg_rb_r;
|
else
|
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
end
|
|
|
`INST_OR32_SFLEU: // l.sfleu
|
inst_rfe_w: // l.rfe
|
begin
|
begin
|
if (v_reg_ra <= v_reg_rb)
|
branch_r = 1'b1;
|
v_sr[`OR32_SR_F] = 1'b1;
|
branch_target_r = r_epc;
|
else
|
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
end
|
|
|
`INST_OR32_SFLEUI: // l.sfleui
|
inst_sys_w: // l.sys
|
begin
|
begin
|
if (v_reg_ra <= v_imm_int32)
|
branch_r = 1'b1;
|
v_sr[`OR32_SR_F] = 1'b1;
|
branch_except_r = 1'b1;
|
else
|
branch_target_r = ISR_VECTOR + `VECTOR_SYSCALL;
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
end
|
|
|
`INST_OR32_SFLTS: // l.sflts
|
inst_trap_w: // l.trap
|
begin
|
begin
|
if (less_than_signed(v_reg_ra, v_reg_rb) == 1'b1)
|
branch_r = 1'b1;
|
v_sr[`OR32_SR_F] = 1'b1;
|
branch_except_r = 1'b1;
|
else
|
branch_target_r = ISR_VECTOR + `VECTOR_TRAP;
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
end
|
|
|
`INST_OR32_SFLTSI: // l.sfltsi
|
default:
|
begin
|
;
|
if (less_than_signed(v_reg_ra, v_imm_int32) == 1'b1)
|
endcase
|
v_sr[`OR32_SR_F] = 1'b1;
|
|
else
|
|
v_sr[`OR32_SR_F] = 1'b0;
|
|
end
|
end
|
|
|
`INST_OR32_SFLTU: // l.sfltu
|
//-----------------------------------------------------------------
|
|
// Invalid instruction
|
|
//-----------------------------------------------------------------
|
|
reg invalid_inst_r;
|
|
|
|
always @ *
|
begin
|
begin
|
if (v_reg_ra < v_reg_rb)
|
case (1'b1)
|
v_sr[`OR32_SR_F] = 1'b1;
|
inst_add_w,
|
else
|
inst_addc_w,
|
v_sr[`OR32_SR_F] = 1'b0;
|
inst_and_w,
|
|
inst_or_w,
|
|
inst_sll_w,
|
|
inst_sra_w,
|
|
inst_srl_w,
|
|
inst_sub_w,
|
|
inst_xor_w,
|
|
inst_addi_w,
|
|
inst_andi_w,
|
|
inst_bf_w,
|
|
inst_bnf_w,
|
|
inst_j_w,
|
|
inst_jal_w,
|
|
inst_jalr_w,
|
|
inst_jr_w,
|
|
inst_lbs_w,
|
|
inst_lhs_w,
|
|
inst_lws_w,
|
|
inst_lbz_w,
|
|
inst_lhz_w,
|
|
inst_lwz_w,
|
|
inst_mfspr_w,
|
|
inst_mtspr_w,
|
|
inst_movhi_w,
|
|
inst_nop_w,
|
|
inst_ori_w,
|
|
inst_rfe_w,
|
|
inst_sb_w,
|
|
inst_sh_w,
|
|
inst_sw_w,
|
|
inst_xori_w,
|
|
inst_slli_w,
|
|
inst_srai_w,
|
|
inst_srli_w,
|
|
inst_sfeq_w,
|
|
inst_sfeqi_w,
|
|
inst_sfges_w,
|
|
inst_sfgesi_w,
|
|
inst_sfgeu_w,
|
|
inst_sfgeui_w,
|
|
inst_sfgts_w,
|
|
inst_sfgtsi_w,
|
|
inst_sfgtu_w,
|
|
inst_sfgtui_w,
|
|
inst_sfles_w,
|
|
inst_sflesi_w,
|
|
inst_sfleu_w,
|
|
inst_sfleui_w,
|
|
inst_sflts_w,
|
|
inst_sfltsi_w,
|
|
inst_sfltu_w,
|
|
inst_sfltui_w,
|
|
inst_sfne_w,
|
|
inst_sfnei_w,
|
|
inst_sys_w,
|
|
inst_trap_w:
|
|
invalid_inst_r = 1'b0;
|
|
default:
|
|
invalid_inst_r = 1'b1;
|
|
endcase
|
end
|
end
|
|
|
`INST_OR32_SFLTUI: // l.sfltui
|
//-----------------------------------------------------------------
|
|
// Execute: ALU control
|
|
//-----------------------------------------------------------------
|
|
always @ (posedge clk_i or posedge rst_i)
|
begin
|
begin
|
if (v_reg_ra < v_imm_int32)
|
if (rst_i == 1'b1)
|
v_sr[`OR32_SR_F] = 1'b1;
|
begin
|
else
|
r_e_alu_func <= `ALU_NONE;
|
v_sr[`OR32_SR_F] = 1'b0;
|
r_e_alu_a <= 32'h00000000;
|
|
r_e_alu_b <= 32'h00000000;
|
|
r_e_rd <= 5'b00000;
|
end
|
end
|
|
else
|
`INST_OR32_SFNE: // l.sfne
|
begin
|
|
//---------------------------------------------------------------
|
|
// Instruction not ready
|
|
//---------------------------------------------------------------
|
|
if (~execute_inst_r | stall_inst_r)
|
begin
|
begin
|
if (v_reg_ra != v_reg_rb)
|
// Insert load result?
|
v_sr[`OR32_SR_F] = 1'b1;
|
if (load_insert)
|
|
begin
|
|
// Feed load result into pipeline
|
|
r_e_alu_func <= `ALU_NONE;
|
|
r_e_alu_a <= load_result;
|
|
r_e_alu_b <= 32'b0;
|
|
r_e_rd <= r_load_rd;
|
|
end
|
else
|
else
|
v_sr[`OR32_SR_F] = 1'b0;
|
begin
|
|
// No ALU operation (output == input_a)
|
|
r_e_alu_func <= `ALU_NONE;
|
|
r_e_alu_a <= 32'b0;
|
|
r_e_alu_b <= 32'b0;
|
|
r_e_rd <= 5'b0;
|
end
|
end
|
|
end
|
`INST_OR32_SFNEI: // l.sfnei
|
//---------------------------------------------------------------
|
|
// Valid instruction
|
|
//---------------------------------------------------------------
|
|
else if (~invalid_inst_r)
|
begin
|
begin
|
if (v_reg_ra != v_imm_int32)
|
// Update ALU input flops
|
v_sr[`OR32_SR_F] = 1'b1;
|
r_e_alu_func <= alu_func_r;
|
|
r_e_alu_a <= alu_input_a_r;
|
|
r_e_alu_b <= alu_input_b_r;
|
|
|
|
// Branch and link (Rd = LR/R9)
|
|
if (branch_link_r)
|
|
r_e_rd <= 5'd9;
|
|
// Instruction with register writeback
|
|
else if (write_rd_r)
|
|
r_e_rd <= reg_rd_i;
|
else
|
else
|
v_sr[`OR32_SR_F] = 1'b0;
|
r_e_rd <= 5'b0;
|
end
|
end
|
|
|
default:
|
|
begin
|
|
fault_o <= 1'b1;
|
|
v_exception = 1'b1;
|
|
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
|
|
end
|
end
|
endcase
|
|
end
|
end
|
|
|
`INST_OR32_SH: // l.sh
|
//-----------------------------------------------------------------
|
|
// Execute: Update executed PC / opcode
|
|
//-----------------------------------------------------------------
|
|
always @ (posedge clk_i or posedge rst_i)
|
begin
|
begin
|
v_mem_addr = (v_reg_ra + v_store_imm);
|
if (rst_i == 1'b1)
|
dmem_addr_o <= v_mem_addr;
|
|
r_mem_access <= 1'b1;
|
|
case (v_mem_addr[1:0])
|
|
2'b00 :
|
|
begin
|
begin
|
dmem_data_out_o <= {v_reg_rb[15:0],16'h0000};
|
r_e_opcode <= 32'h00000000;
|
dmem_wr_o <= 4'b1100;
|
r_e_opcode_pc <= 32'h00000000;
|
v_store_pending = 1'b1;
|
|
|
r_stall <= 1'b0;
|
end
|
end
|
2'b10 :
|
else
|
begin
|
begin
|
dmem_data_out_o <= {16'h0000,v_reg_rb[15:0]};
|
r_stall <= stall_inst_r;
|
dmem_wr_o <= 4'b0011;
|
|
v_store_pending = 1'b1;
|
// Instruction not ready
|
end
|
if (~execute_inst_r | stall_inst_r)
|
default :
|
|
begin
|
begin
|
dmem_data_out_o <= 32'h00000000;
|
// Store bubble opcode
|
dmem_wr_o <= 4'b0000;
|
r_e_opcode <= `OPCODE_INST_BUBBLE;
|
end
|
r_e_opcode_pc <= opcode_pc_i;
|
endcase
|
|
end
|
end
|
|
// Valid instruction
|
`INST_OR32_SW: // l.sw
|
else if (~invalid_inst_r)
|
begin
|
begin
|
v_mem_addr = (v_reg_ra + v_store_imm);
|
// Store opcode
|
dmem_addr_o <= v_mem_addr;
|
r_e_opcode <= opcode_i;
|
dmem_data_out_o <= v_reg_rb;
|
r_e_opcode_pc <= opcode_pc_i;
|
dmem_wr_o <= 4'b1111;
|
|
r_mem_access <= 1'b1;
|
|
v_store_pending = 1'b1;
|
|
|
|
`ifdef CONF_CORE_DEBUG
|
`ifdef CONF_CORE_TRACE
|
$display(" Store R%d to 0x%08x = 0x%08x", reg_rb_i, {v_mem_addr[31:2],2'b00}, v_reg_rb);
|
$display("%08x: Execute 0x%08x", opcode_pc_i, opcode_i);
|
|
$display(" rA[%d] = 0x%08x", reg_ra_i, reg_ra_r);
|
|
$display(" rB[%d] = 0x%08x", reg_rb_i, reg_rb_r);
|
`endif
|
`endif
|
end
|
end
|
|
end
|
|
end
|
|
|
`INST_OR32_MISC:
|
//-----------------------------------------------------------------
|
|
// Execute: Branch / exceptions
|
|
//-----------------------------------------------------------------
|
|
always @ (posedge clk_i or posedge rst_i)
|
begin
|
begin
|
case (v_mem_data_in[31:24])
|
if (rst_i == 1'b1)
|
`INST_OR32_SYS: // l.sys
|
|
begin
|
begin
|
v_exception = 1'b1;
|
r_pc_branch <= 32'h00000000;
|
v_vector = ISR_VECTOR + `VECTOR_SYSCALL;
|
r_pc_fetch <= 1'b0;
|
end
|
|
|
|
`INST_OR32_TRAP: // l.trap
|
// Status registers
|
begin
|
r_epc <= 32'h00000000;
|
v_exception = 1'b1;
|
r_sr <= 32'h00000000;
|
v_vector = ISR_VECTOR + `VECTOR_TRAP;
|
r_esr <= 32'h00000000;
|
break_o <= 1'b1;
|
|
end
|
|
|
|
default :
|
fault_o <= 1'b0;
|
begin
|
|
fault_o <= 1'b1;
|
|
v_exception = 1'b1;
|
|
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
`INST_OR32_XORI: // l.xori
|
r_nmi <= 1'b0;
|
begin
|
|
r_e_alu_func <= `ALU_XOR;
|
|
r_e_alu_a <= v_reg_ra;
|
|
r_e_alu_b <= v_imm_int32;
|
|
v_write_rd = 1'b1;
|
|
end
|
end
|
|
else
|
default :
|
|
begin
|
begin
|
fault_o <= 1'b1;
|
// Record NMI in-case it can't be processed this cycle
|
v_exception = 1'b1;
|
if (nmi_i)
|
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
|
r_nmi <= 1'b1;
|
end
|
|
endcase
|
|
|
|
//---------------------------------------------------------------
|
// Reset branch request
|
// Branch logic
|
r_pc_fetch <= 1'b0;
|
//---------------------------------------------------------------
|
|
|
|
// If relative branch, calculate target before possible interrupt/exception
|
// Update SR
|
if (v_branch == 1'b1)
|
r_sr <= next_sr_r;
|
begin
|
|
v_offset = {v_target[29:0],2'b00};
|
|
v_pc = (opcode_pc_i + v_offset);
|
|
end
|
|
|
|
// Pipeline stall due to load result not ready
|
// Instruction ready
|
if (v_stall == 1'b1)
|
if (execute_inst_r & ~stall_inst_r)
|
|
begin
|
|
// Exception: Instruction opcode not valid / supported, invalid PC
|
|
if (invalid_inst_r || (opcode_pc_i[1:0] != 2'b00))
|
begin
|
begin
|
// No exceptions whilst stalled
|
// Save PC of next instruction
|
|
r_epc <= next_pc_r;
|
|
r_esr <= next_sr_r;
|
|
|
|
// Disable further interrupts
|
|
r_sr <= 32'b0;
|
|
|
|
// Set PC to exception vector
|
|
if (invalid_inst_r)
|
|
r_pc_branch <= ISR_VECTOR + `VECTOR_ILLEGAL_INST;
|
|
else
|
|
r_pc_branch <= ISR_VECTOR + `VECTOR_BUS_ERROR;
|
|
r_pc_fetch <= 1'b1;
|
|
|
|
fault_o <= 1'b1;
|
end
|
end
|
// Exception (Fault/Syscall/Break)
|
// Exception: Syscall / Break
|
else if (v_exception == 1'b1)
|
else if (branch_except_r)
|
begin
|
begin
|
// Save PC of next instruction
|
// Save PC of next instruction
|
r_epc <= v_pc;
|
r_epc <= next_pc_r;
|
|
r_esr <= next_sr_r;
|
|
|
// Disable further interrupts
|
// Disable further interrupts
|
r_esr <= v_sr;
|
r_sr <= 32'b0;
|
v_sr = 0;
|
|
|
|
// Set PC to exception vector
|
// Set PC to exception vector
|
v_pc = v_vector;
|
r_pc_branch <= branch_target_r;
|
r_pc_branch <= v_pc;
|
|
r_pc_fetch <= 1'b1;
|
r_pc_fetch <= 1'b1;
|
|
|
`ifdef CONF_CORE_DEBUG
|
`ifdef CONF_CORE_DEBUG
|
$display(" Exception 0x%08x", v_vector);
|
$display(" Exception 0x%08x", branch_target_r);
|
`endif
|
`endif
|
end
|
end
|
// Non-maskable interrupt
|
// Non-maskable interrupt
|
else if (nmi_i | r_nmi)
|
else if (nmi_i | r_nmi)
|
begin
|
begin
|
r_nmi <= 1'b0;
|
r_nmi <= 1'b0;
|
|
|
// Save PC of next instruction
|
// Save PC of next instruction
|
r_epc <= v_pc;
|
if (branch_r)
|
|
r_epc <= branch_target_r;
|
|
// Next expected PC (current PC + 4)
|
|
else
|
|
r_epc <= next_pc_r;
|
|
|
|
r_esr <= next_sr_r;
|
|
|
// Disable further interrupts
|
// Disable further interrupts
|
r_esr <= v_sr;
|
r_sr <= 32'b0;
|
v_sr = 0;
|
|
|
|
// Set PC to exception vector
|
// Set PC to exception vector
|
v_pc = ISR_VECTOR + `VECTOR_NMI;
|
r_pc_branch <= ISR_VECTOR + `VECTOR_NMI;
|
r_pc_branch <= v_pc;
|
|
r_pc_fetch <= 1'b1;
|
r_pc_fetch <= 1'b1;
|
|
|
`ifdef CONF_CORE_DEBUG
|
`ifdef CONF_CORE_DEBUG
|
$display(" NMI 0x%08x", v_pc);
|
$display(" NMI 0x%08x", ISR_VECTOR + `VECTOR_NMI);
|
`endif
|
`endif
|
end
|
end
|
// External interrupt
|
// External interrupt
|
else if (v_no_intr == 1'b0 &&
|
else if (intr_i && next_sr_r[`OR32_SR_IEE])
|
((intr_i && v_sr[`OR32_SR_IEE])))
|
|
begin
|
begin
|
// Save PC of next instruction & SR
|
// Save PC of next instruction & SR
|
r_epc <= v_pc;
|
if (branch_r)
|
|
r_epc <= branch_target_r;
|
|
// Next expected PC (current PC + 4)
|
|
else
|
|
r_epc <= next_pc_r;
|
|
|
|
r_esr <= next_sr_r;
|
|
|
// Disable further interrupts
|
// Disable further interrupts
|
r_esr <= v_sr;
|
r_sr <= 32'b0;
|
v_sr = 0;
|
|
|
|
// Set PC to external interrupt vector
|
// Set PC to external interrupt vector
|
v_pc = ISR_VECTOR + `VECTOR_EXTINT;
|
r_pc_branch <= ISR_VECTOR + `VECTOR_EXTINT;
|
|
|
r_pc_branch <= v_pc;
|
|
r_pc_fetch <= 1'b1;
|
r_pc_fetch <= 1'b1;
|
|
|
`ifdef CONF_CORE_DEBUG
|
`ifdef CONF_CORE_DEBUG
|
$display(" External Interrupt 0x%08x", v_pc);
|
$display(" External Interrupt 0x%08x", ISR_VECTOR + `VECTOR_EXTINT);
|
`endif
|
`endif
|
end
|
end
|
// Handle relative branches (l.bf, l.bnf, l.j, l.jal)
|
// Branch (l.bf, l.bnf, l.j, l.jal, l.jr, l.jalr, l.rfe)
|
else if (v_branch == 1'b1)
|
else if (branch_r)
|
begin
|
begin
|
// Perform branch (already in v_pc)
|
// Perform branch
|
r_pc_branch <= v_pc;
|
r_pc_branch <= branch_target_r;
|
r_pc_fetch <= 1'b1;
|
r_pc_fetch <= 1'b1;
|
|
|
`ifdef CONF_CORE_DEBUG
|
`ifdef CONF_CORE_DEBUG
|
$display(" Branch to 0x%08x", v_pc);
|
$display(" Branch to 0x%08x", branch_target_r);
|
`endif
|
`endif
|
end
|
end
|
// Handle absolute jumps (l.jr, l.jalr, l.rfe)
|
// Non branch
|
else if (v_jmp == 1'b1)
|
else
|
|
begin
|
|
// Update EPC / ESR which may have been updated
|
|
// by an MTSPR write
|
|
r_epc <= next_epc_r;
|
|
r_esr <= next_esr_r;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
//-----------------------------------------------------------------
|
|
// Execute: Memory operations
|
|
//-----------------------------------------------------------------
|
|
always @ (posedge clk_i or posedge rst_i)
|
begin
|
begin
|
// Perform branch
|
if (rst_i == 1'b1)
|
r_pc_branch <= v_pc;
|
begin
|
r_pc_fetch <= 1'b1;
|
// Data memory
|
|
dmem_addr_o <= 32'h00000000;
|
|
dmem_data_out_o <= 32'h00000000;
|
|
dmem_rd_o <= 1'b0;
|
|
dmem_wr_o <= 4'b0000;
|
|
|
`ifdef CONF_CORE_DEBUG
|
r_mem_load <= 1'b0;
|
$display(" Jump to 0x%08x", v_pc);
|
r_mem_store <= 1'b0;
|
`endif
|
r_mem_access <= 1'b0;
|
|
|
|
r_load_rd <= 5'b00000;
|
|
r_load_inst <= 8'h00;
|
|
r_load_offset <= 2'b00;
|
|
|
|
d_mem_load <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
|
|
// If memory access accepted by slave
|
|
if (dmem_accept_i)
|
|
begin
|
|
dmem_rd_o <= 1'b0;
|
|
dmem_wr_o <= 4'b0000;
|
end
|
end
|
|
|
|
r_mem_access <= 1'b0;
|
|
d_mem_load <= r_mem_access & r_mem_load;
|
|
|
// Update other registers with variable values
|
// Pending accesses
|
r_stall <= v_stall;
|
r_mem_load <= load_pending;
|
r_sr <= v_sr;
|
r_mem_store <= store_pending;
|
|
|
// Memory access?
|
|
r_mem_load <= v_load_pending;
|
|
r_mem_store<= v_store_pending;
|
|
|
|
// No writeback required?
|
//---------------------------------------------------------------
|
if (v_write_rd == 1'b0)
|
// Valid instruction
|
|
//---------------------------------------------------------------
|
|
if (execute_inst_r & ~stall_inst_r & ~invalid_inst_r)
|
begin
|
begin
|
// Target register is R0 which is read-only
|
// Branch and link (Rd = LR/R9)
|
r_e_rd <= 5'b00000;
|
if (branch_link_r)
|
|
begin
|
|
// Load outstanding, check if result target is being
|
|
// overwritten (to avoid WAR hazard)
|
|
if (r_load_rd == 5'd9)
|
|
// Ditch load result when it arrives
|
|
r_load_rd <= 5'b00000;
|
end
|
end
|
// Writeback required
|
// Instruction with register writeback
|
else
|
else if (write_rd_r)
|
begin
|
begin
|
// Load outstanding, check if result target is being
|
// Load outstanding, check if result target is being
|
// overwritten (to avoid WAR hazard)
|
// overwritten (to avoid WAR hazard)
|
if (v_check_load_rd && v_rd == r_load_rd)
|
if (reg_rd_i == r_load_rd && ~load_inst_r)
|
|
// Ditch load result when it arrives
|
|
r_load_rd <= 5'b00000;
|
|
end
|
|
|
|
case (1'b1)
|
|
|
|
// l.lbs l.lhs l.lws l.lbz l.lhz l.lwz
|
|
load_inst_r:
|
begin
|
begin
|
|
dmem_addr_o <= mem_addr_r;
|
|
dmem_data_out_o <= 32'h00000000;
|
|
dmem_rd_o <= 1'b1;
|
|
|
|
// Mark load as pending
|
|
r_mem_load <= 1'b1;
|
|
r_mem_access <= 1'b1;
|
|
|
|
// Record target register
|
|
r_load_rd <= reg_rd_i;
|
|
r_load_inst <= inst_r;
|
|
r_load_offset <= mem_addr_r[1:0];
|
|
|
`ifdef CONF_CORE_DEBUG
|
`ifdef CONF_CORE_DEBUG
|
if (v_rd != 5'b0)
|
$display(" Load from 0x%08x to R%d", mem_addr_r, reg_rd_i);
|
$display("%08x: Load target overwrite, clear target (R%d)", opcode_pc_i, r_load_rd);
|
|
`endif
|
`endif
|
|
end
|
|
|
// Ditch load result when it arrives
|
inst_sb_w: // l.sb
|
r_load_rd <= 5'b00000;
|
begin
|
|
dmem_addr_o <= mem_addr_r;
|
|
r_mem_access <= 1'b1;
|
|
case (mem_addr_r[1:0])
|
|
2'b00 :
|
|
begin
|
|
dmem_data_out_o <= {reg_rb_r[7:0],24'h000000};
|
|
dmem_wr_o <= 4'b1000;
|
|
r_mem_store <= 1'b1;
|
|
end
|
|
2'b01 :
|
|
begin
|
|
dmem_data_out_o <= {{8'h00,reg_rb_r[7:0]},16'h0000};
|
|
dmem_wr_o <= 4'b0100;
|
|
r_mem_store <= 1'b1;
|
|
end
|
|
2'b10 :
|
|
begin
|
|
dmem_data_out_o <= {{16'h0000,reg_rb_r[7:0]},8'h00};
|
|
dmem_wr_o <= 4'b0010;
|
|
r_mem_store <= 1'b1;
|
|
end
|
|
2'b11 :
|
|
begin
|
|
dmem_data_out_o <= {24'h000000,reg_rb_r[7:0]};
|
|
dmem_wr_o <= 4'b0001;
|
|
r_mem_store <= 1'b1;
|
|
end
|
|
default :
|
|
begin
|
|
dmem_data_out_o <= 32'h00000000;
|
|
dmem_wr_o <= 4'b0000;
|
|
end
|
|
endcase
|
end
|
end
|
|
|
// Target Rd
|
inst_sh_w: // l.sh
|
r_e_rd <= v_rd;
|
begin
|
|
dmem_addr_o <= mem_addr_r;
|
|
r_mem_access <= 1'b1;
|
|
case (mem_addr_r[1:0])
|
|
2'b00 :
|
|
begin
|
|
dmem_data_out_o <= {reg_rb_r[15:0],16'h0000};
|
|
dmem_wr_o <= 4'b1100;
|
|
r_mem_store <= 1'b1;
|
|
end
|
|
2'b10 :
|
|
begin
|
|
dmem_data_out_o <= {16'h0000,reg_rb_r[15:0]};
|
|
dmem_wr_o <= 4'b0011;
|
|
r_mem_store <= 1'b1;
|
|
end
|
|
default :
|
|
begin
|
|
dmem_data_out_o <= 32'h00000000;
|
|
dmem_wr_o <= 4'b0000;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
inst_sw_w: // l.sw
|
|
begin
|
|
dmem_addr_o <= mem_addr_r;
|
|
dmem_data_out_o <= reg_rb_r;
|
|
dmem_wr_o <= 4'b1111;
|
|
r_mem_access <= 1'b1;
|
|
r_mem_store <= 1'b1;
|
|
|
|
`ifdef CONF_CORE_DEBUG
|
|
$display(" Store R%d to 0x%08x = 0x%08x", reg_rb_i, {mem_addr_r[31:2],2'b00}, reg_rb_r);
|
|
`endif
|
|
end
|
|
default:
|
|
;
|
|
endcase
|
|
end
|
|
end
|
|
end
|
|
|
|
//-----------------------------------------------------------------
|
|
// Execute: Misc operations
|
|
//-----------------------------------------------------------------
|
|
always @ (posedge clk_i or posedge rst_i)
|
|
begin
|
|
if (rst_i == 1'b1)
|
|
begin
|
|
break_o <= 1'b0;
|
|
icache_flush_o <= 1'b0;
|
|
dcache_flush_o <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
break_o <= 1'b0;
|
|
icache_flush_o <= 1'b0;
|
|
dcache_flush_o <= 1'b0;
|
|
|
|
//---------------------------------------------------------------
|
|
// Valid instruction
|
|
//---------------------------------------------------------------
|
|
if (execute_inst_r & ~stall_inst_r & ~invalid_inst_r)
|
|
begin
|
|
case (1'b1)
|
|
inst_mtspr_w: // l.mtspr
|
|
begin
|
|
case (mxspr_uint16_r)
|
|
// SR - Supervision register
|
|
`SPR_REG_SR:
|
|
begin
|
|
// Cache flush request?
|
|
icache_flush_o <= reg_rb_r[`OR32_SR_ICACHE_FLUSH];
|
|
dcache_flush_o <= reg_rb_r[`OR32_SR_DCACHE_FLUSH];
|
|
end
|
|
endcase
|
|
end
|
|
|
|
inst_trap_w: // l.trap
|
|
break_o <= 1'b1;
|
|
default:
|
|
;
|
|
endcase
|
end
|
end
|
end
|
end
|
end
|
end
|
|
|
|
//-----------------------------------------------------------------
|
|
// Execute: NOP (simulation) operations
|
|
//-----------------------------------------------------------------
|
|
`ifdef SIMULATION
|
|
always @ (posedge clk_i or posedge rst_i)
|
|
begin
|
|
if (rst_i == 1'b1)
|
|
begin
|
|
`ifdef SIM_EXT_PUTC
|
|
r_putc <= 8'b0;
|
|
`endif
|
|
end
|
|
else
|
|
begin
|
|
`ifdef SIM_EXT_PUTC
|
|
r_putc <= 8'b0;
|
|
`endif
|
|
//---------------------------------------------------------------
|
|
// Valid instruction
|
|
//---------------------------------------------------------------
|
|
if (execute_inst_r & ~stall_inst_r & ~invalid_inst_r)
|
|
begin
|
|
|
|
case (1'b1)
|
|
inst_nop_w: // l.nop
|
|
begin
|
|
case (uint16_r)
|
|
// NOP_PUTC
|
|
16'h0004:
|
|
begin
|
|
`ifdef SIM_EXT_PUTC
|
|
r_putc <= reg_ra_r[7:0];
|
|
`else
|
|
$write("%c", reg_ra_r[7:0]);
|
|
`endif
|
|
end
|
|
// NOP
|
|
16'h0000: ;
|
|
endcase
|
|
end
|
|
default:
|
|
;
|
|
endcase
|
|
end
|
|
end
|
|
end
|
|
`endif
|
|
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
// Assignments
|
// Assignments
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
|
|
assign branch_pc_o = r_pc_branch;
|
assign branch_pc_o = r_pc_branch;
|
assign branch_o = r_pc_fetch;
|
assign branch_o = r_pc_fetch;
|
assign stall_o = r_stall;
|
assign stall_o = r_stall;
|
|
|
assign opcode_o = r_e_opcode;
|
assign opcode_o = r_e_opcode;
|
|
|
assign reg_rd_o = r_e_rd;
|
assign reg_rd_o = r_e_rd;
|
assign reg_rd_value_o = r_e_result;
|
assign reg_rd_value_o = r_e_result;
|
|
|
assign mult_o = 1'b0;
|
assign mult_o = 1'b0;
|
assign mult_res_o = 32'b0;
|
assign mult_res_o = 32'b0;
|
|
|
`include "altor32_funcs.v"
|
`include "altor32_funcs.v"
|
|
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
// Hooks for debug
|
// Hooks for debug
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
`ifdef verilator
|
`ifdef verilator
|
function [31:0] get_opcode_ex;
|
function [31:0] get_opcode_ex;
|
// verilator public
|
// verilator public
|
get_opcode_ex = r_e_opcode;
|
get_opcode_ex = r_e_opcode;
|
endfunction
|
endfunction
|
function [31:0] get_pc_ex;
|
function [31:0] get_pc_ex;
|
// verilator public
|
// verilator public
|
get_pc_ex = r_e_opcode_pc;
|
get_pc_ex = r_e_opcode_pc;
|
endfunction
|
endfunction
|
|
function [7:0] get_putc;
|
|
// verilator public
|
|
`ifdef SIM_EXT_PUTC
|
|
get_putc = r_putc;
|
|
`else
|
|
get_putc = 8'b0;
|
|
`endif
|
|
endfunction
|
`endif
|
`endif
|
|
|
endmodule
|
endmodule
|
|
|