blob: 768ffb836d469e7f5776fb93dd87f4d6c76887e9 [file] [log] [blame]
//////////////////////////////////////////////////////////////////
// //
// Decode stage of Amber 2 Core //
// //
// This file is part of the Amber project //
// http://www.opencores.org/project,amber //
// //
// Description //
// This module is the most complex part of the Amber core //
// It decodes and sequences all instructions and handles all //
// interrupts //
// //
// Author(s): //
// - Conor Santifort, csantifort.amber@gmail.com //
// //
//////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2010 Authors and OPENCORES.ORG //
// //
// This source file may be used and distributed without //
// restriction provided that this copyright statement is not //
// removed from the file and that any derivative work contains //
// the original copyright notice and the associated disclaimer. //
// //
// This source file is free software; you can redistribute it //
// and/or modify it under the terms of the GNU Lesser General //
// Public License as published by the Free Software Foundation; //
// either version 2.1 of the License, or (at your option) any //
// later version. //
// //
// This source is distributed in the hope that it will be //
// useful, but WITHOUT ANY WARRANTY; without even the implied //
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
// PURPOSE. See the GNU Lesser General Public License for more //
// details. //
// //
// You should have received a copy of the GNU Lesser General //
// Public License along with this source; if not, download it //
// from http://www.opencores.org/lgpl.shtml //
// //
//////////////////////////////////////////////////////////////////
`include "global_defines.v"
module a23_decode
(
input i_clk,
input [31:0] i_read_data,
input i_fetch_stall, // stall all stages of the cpu at the same time
input i_irq, // interrupt request
input i_firq, // Fast interrupt request
input i_dabt, // data abort interrupt request
input i_iabt, // instruction pre-fetch abort flag
input i_adex, // Address Exception
input [31:0] i_execute_address, // Registered address output by execute stage
// 2 LSBs of read address used for calculating
// shift in LDRB ops
input [7:0] i_abt_status, // Abort status
input [31:0] i_execute_status_bits, // current status bits values in execute stage
input i_multiply_done, // multiply unit is nearly done
// --------------------------------------------------
// Control signals to execute stage
// --------------------------------------------------
output reg [31:0] o_read_data = 1'd0,
output reg [4:0] o_read_data_alignment = 1'd0, // 2 LSBs of read address used for calculating shift in LDRB ops
output reg [31:0] o_imm32 = 'd0,
output reg [4:0] o_imm_shift_amount = 'd0,
output reg o_shift_imm_zero = 'd0,
output reg [3:0] o_condition = 4'he, // 4'he = al
output reg o_exclusive_exec = 'd0, // exclusive access request ( swap instruction )
output reg o_data_access_exec = 'd0, // high means the memory access is a read
// read or write, low for instruction
output reg [1:0] o_status_bits_mode = 2'b11, // SVC
output reg o_status_bits_irq_mask = 1'd1,
output reg o_status_bits_firq_mask = 1'd1,
output reg [3:0] o_rm_sel = 'd0,
output reg [3:0] o_rds_sel = 'd0,
output reg [3:0] o_rn_sel = 'd0,
output [3:0] o_rm_sel_nxt,
output [3:0] o_rds_sel_nxt,
output [3:0] o_rn_sel_nxt,
output reg [1:0] o_barrel_shift_amount_sel = 'd0,
output reg [1:0] o_barrel_shift_data_sel = 'd0,
output reg [1:0] o_barrel_shift_function = 'd0,
output reg [8:0] o_alu_function = 'd0,
output reg [1:0] o_multiply_function = 'd0,
output reg [2:0] o_interrupt_vector_sel = 'd0,
output reg [3:0] o_address_sel = 4'd2,
output reg [1:0] o_pc_sel = 2'd2,
output reg [1:0] o_byte_enable_sel = 'd0, // byte, halfword or word write
output reg [2:0] o_status_bits_sel = 'd0,
output reg [2:0] o_reg_write_sel,
output reg o_user_mode_regs_load,
output reg o_user_mode_regs_store_nxt,
output reg o_firq_not_user_mode,
output reg o_write_data_wen = 'd0,
output reg o_base_address_wen = 'd0, // save LDM base address register
// in case of data abort
output reg o_pc_wen = 1'd1,
output reg [14:0] o_reg_bank_wen = 'd0,
output reg [3:0] o_reg_bank_wsel = 'd0,
output reg o_status_bits_flags_wen = 'd0,
output reg o_status_bits_mode_wen = 'd0,
output reg o_status_bits_irq_mask_wen = 'd0,
output reg o_status_bits_firq_mask_wen = 'd0,
// --------------------------------------------------
// Co-Processor interface
// --------------------------------------------------
output reg [2:0] o_copro_opcode1 = 'd0,
output reg [2:0] o_copro_opcode2 = 'd0,
output reg [3:0] o_copro_crn = 'd0,
output reg [3:0] o_copro_crm = 'd0,
output reg [3:0] o_copro_num = 'd0,
output reg [1:0] o_copro_operation = 'd0, // 0 = no operation,
// 1 = Move to Amber Core Register from Coprocessor
// 2 = Move to Coprocessor from Amber Core Register
output reg o_copro_write_data_wen = 'd0,
output o_iabt_trigger,
output [31:0] o_iabt_address,
output [7:0] o_iabt_status,
output o_dabt_trigger,
output [31:0] o_dabt_address,
output [7:0] o_dabt_status
);
`include "a23_localparams.v"
`include "a23_functions.v"
localparam [4:0] RST_WAIT1 = 5'd0,
RST_WAIT2 = 5'd1,
INT_WAIT1 = 5'd2,
INT_WAIT2 = 5'd3,
EXECUTE = 5'd4,
PRE_FETCH_EXEC = 5'd5, // Execute the Pre-Fetched Instruction
MEM_WAIT1 = 5'd6, // conditionally decode current instruction, in case
// previous instruction does not execute in S2
MEM_WAIT2 = 5'd7,
PC_STALL1 = 5'd8, // Program Counter altered
// conditionally decude current instruction, in case
// previous instruction does not execute in S2
PC_STALL2 = 5'd9,
MTRANS_EXEC1 = 5'd10,
MTRANS_EXEC2 = 5'd11,
MTRANS_EXEC3 = 5'd12,
MTRANS_EXEC3B = 5'd13,
MTRANS_EXEC4 = 5'd14,
MTRANS5_ABORT = 5'd15,
MULT_PROC1 = 5'd16, // first cycle, save pre fetch instruction
MULT_PROC2 = 5'd17, // do multiplication
MULT_STORE = 5'd19, // save RdLo
MULT_ACCUMU = 5'd20, // Accumulate add lower 32 bits
SWAP_WRITE = 5'd22,
SWAP_WAIT1 = 5'd23,
SWAP_WAIT2 = 5'd24,
COPRO_WAIT = 5'd25;
// ========================================================
// Internal signals
// ========================================================
wire [31:0] instruction;
wire instruction_iabt; // abort flag, follows the instruction
wire instruction_adex; // address exception flag, follows the instruction
wire [31:0] instruction_address; // instruction virtual address, follows
// the instruction
wire [7:0] instruction_iabt_status; // abort status, follows the instruction
wire [1:0] instruction_sel;
reg [3:0] type;
wire [3:0] opcode;
wire [7:0] imm8;
wire [31:0] offset12;
wire [31:0] offset24;
wire [4:0] shift_imm;
wire opcode_compare;
wire mem_op;
wire load_op;
wire store_op;
wire write_pc;
wire immediate_shifter_operand;
wire rds_use_rs;
wire branch;
wire mem_op_pre_indexed;
wire mem_op_post_indexed;
// Flop inputs
wire [31:0] imm32_nxt;
wire [4:0] imm_shift_amount_nxt;
wire shift_imm_zero_nxt;
wire [3:0] condition_nxt;
reg exclusive_exec_nxt;
reg data_access_exec_nxt;
reg [1:0] barrel_shift_function_nxt;
wire [8:0] alu_function_nxt;
reg [1:0] multiply_function_nxt;
reg [1:0] status_bits_mode_nxt;
reg status_bits_irq_mask_nxt;
reg status_bits_firq_mask_nxt;
reg [1:0] barrel_shift_amount_sel_nxt;
reg [1:0] barrel_shift_data_sel_nxt;
reg [3:0] address_sel_nxt;
reg [1:0] pc_sel_nxt;
reg [1:0] byte_enable_sel_nxt;
reg [2:0] status_bits_sel_nxt;
reg [2:0] reg_write_sel_nxt;
reg user_mode_regs_load_nxt;
wire firq_not_user_mode_nxt;
// ALU Function signals
reg alu_swap_sel_nxt;
reg alu_not_sel_nxt;
reg [1:0] alu_cin_sel_nxt;
reg alu_cout_sel_nxt;
reg [3:0] alu_out_sel_nxt;
reg write_data_wen_nxt;
reg copro_write_data_wen_nxt;
reg base_address_wen_nxt;
reg pc_wen_nxt;
reg [3:0] reg_bank_wsel_nxt;
reg status_bits_flags_wen_nxt;
reg status_bits_mode_wen_nxt;
reg status_bits_irq_mask_wen_nxt;
reg status_bits_firq_mask_wen_nxt;
reg saved_current_instruction_wen; // saved load instruction
reg pre_fetch_instruction_wen; // pre-fetch instruction
reg [4:0] control_state = RST_WAIT1;
reg [4:0] control_state_nxt;
wire dabt;
reg dabt_reg = 'd0;
reg dabt_reg_d1;
reg iabt_reg = 'd0;
reg adex_reg = 'd0;
reg [31:0] abt_address_reg = 'd0;
reg [7:0] abt_status_reg = 'd0;
reg [31:0] saved_current_instruction = 'd0;
reg saved_current_instruction_iabt = 'd0; // access abort flag
reg saved_current_instruction_adex = 'd0; // address exception
reg [31:0] saved_current_instruction_address = 'd0; // virtual address of abort instruction
reg [7:0] saved_current_instruction_iabt_status = 'd0; // status of abort instruction
reg [31:0] pre_fetch_instruction = 'd0;
reg pre_fetch_instruction_iabt = 'd0; // access abort flag
reg pre_fetch_instruction_adex = 'd0; // address exception
reg [31:0] pre_fetch_instruction_address = 'd0; // virtual address of abort instruction
reg [7:0] pre_fetch_instruction_iabt_status = 'd0; // status of abort instruction
wire instruction_valid;
wire instruction_execute;
reg [3:0] mtrans_reg; // the current register being accessed as part of STM/LDM
reg [3:0] mtrans_reg_d1 = 'd0; // delayed by 1 period
reg [3:0] mtrans_reg_d2 = 'd0; // delayed by 2 periods
reg [31:0] mtrans_instruction_nxt;
wire [31:0] mtrans_base_reg_change;
wire [4:0] mtrans_num_registers;
wire use_saved_current_instruction;
wire use_pre_fetch_instruction;
wire interrupt;
wire [1:0] interrupt_mode;
wire [2:0] next_interrupt;
reg irq = 'd0;
reg firq = 'd0;
wire firq_request;
wire irq_request;
wire swi_request;
wire und_request;
wire dabt_request;
reg [1:0] copro_operation_nxt;
reg mtrans_r15 = 'd0;
reg mtrans_r15_nxt;
reg restore_base_address = 'd0;
reg restore_base_address_nxt;
wire regop_set_flags;
// ========================================================
// Instruction Abort and Data Abort outputs
// ========================================================
assign o_iabt_trigger = instruction_iabt && o_status_bits_mode == SVC && control_state == INT_WAIT1;
assign o_iabt_address = instruction_address;
assign o_iabt_status = instruction_iabt_status;
assign o_dabt_trigger = dabt_reg && !dabt_reg_d1;
assign o_dabt_address = abt_address_reg;
assign o_dabt_status = abt_status_reg;
// ========================================================
// Instruction Decode
// ========================================================
// for instructions that take more than one cycle
// the instruction is saved in the 'saved_mem_instruction'
// register and then that register is used for the rest of
// the execution of the instruction.
// But if the instruction does not execute because of the
// condition, then need to select the next instruction to
// decode
assign use_saved_current_instruction = instruction_execute &&
( control_state == MEM_WAIT1 ||
control_state == MEM_WAIT2 ||
control_state == MTRANS_EXEC1 ||
control_state == MTRANS_EXEC2 ||
control_state == MTRANS_EXEC3 ||
control_state == MTRANS_EXEC3B ||
control_state == MTRANS_EXEC4 ||
control_state == MTRANS5_ABORT ||
control_state == MULT_PROC1 ||
control_state == MULT_PROC2 ||
control_state == MULT_ACCUMU ||
control_state == MULT_STORE ||
control_state == INT_WAIT1 ||
control_state == INT_WAIT2 ||
control_state == SWAP_WRITE ||
control_state == SWAP_WAIT1 ||
control_state == SWAP_WAIT2 ||
control_state == COPRO_WAIT );
assign use_pre_fetch_instruction = control_state == PRE_FETCH_EXEC;
assign instruction_sel = use_saved_current_instruction ? 2'd1 : // saved_current_instruction
use_pre_fetch_instruction ? 2'd2 : // pre_fetch_instruction
2'd0 ; // o_read_data
assign instruction = instruction_sel == 2'd0 ? o_read_data :
instruction_sel == 2'd1 ? saved_current_instruction :
pre_fetch_instruction ;
// abort flag
assign instruction_iabt = instruction_sel == 2'd0 ? iabt_reg :
instruction_sel == 2'd1 ? saved_current_instruction_iabt :
pre_fetch_instruction_iabt ;
assign instruction_address = instruction_sel == 2'd0 ? abt_address_reg :
instruction_sel == 2'd1 ? saved_current_instruction_address :
pre_fetch_instruction_address ;
assign instruction_iabt_status = instruction_sel == 2'd0 ? abt_status_reg :
instruction_sel == 2'd1 ? saved_current_instruction_iabt_status :
pre_fetch_instruction_iabt_status ;
// instruction address exception
assign instruction_adex = instruction_sel == 2'd0 ? adex_reg :
instruction_sel == 2'd1 ? saved_current_instruction_adex :
pre_fetch_instruction_adex ;
// Instruction Decode - Order is important!
always @*
casez ({instruction[27:20], instruction[7:4]})
12'b00010?001001 : type = SWAP;
12'b000000??1001 : type = MULT;
12'b00?????????? : type = REGOP;
12'b01?????????? : type = TRANS;
12'b100????????? : type = MTRANS;
12'b101????????? : type = BRANCH;
12'b110????????? : type = CODTRANS;
12'b1110???????0 : type = COREGOP;
12'b1110???????1 : type = CORTRANS;
default: type = SWI;
endcase
// ========================================================
// Fixed fields within the instruction
// ========================================================
assign opcode = instruction[24:21];
assign condition_nxt = instruction[31:28];
assign o_rm_sel_nxt = instruction[3:0];
assign o_rn_sel_nxt = branch ? 4'd15 : // Use PC to calculate branch destination
instruction[19:16] ;
assign o_rds_sel_nxt = control_state == SWAP_WRITE ? instruction[3:0] : // Rm gets written out to memory
type == MTRANS ? mtrans_reg :
branch ? 4'd15 : // Update the PC
rds_use_rs ? instruction[11:8] :
instruction[15:12] ;
assign shift_imm = instruction[11:7];
assign offset12 = { 20'h0, instruction[11:0]};
assign offset24 = {{6{instruction[23]}}, instruction[23:0], 2'd0 }; // sign extend
assign imm8 = instruction[7:0];
assign immediate_shifter_operand = instruction[25];
assign rds_use_rs = (type == REGOP && !instruction[25] && instruction[4]) ||
(type == MULT &&
(control_state == MULT_PROC1 ||
control_state == MULT_PROC2 ||
instruction_valid && !interrupt )) ;
assign branch = type == BRANCH;
assign opcode_compare =
opcode == CMP ||
opcode == CMN ||
opcode == TEQ ||
opcode == TST ;
assign mem_op = type == TRANS;
assign load_op = mem_op && instruction[20];
assign store_op = mem_op && !instruction[20];
assign write_pc = pc_wen_nxt && pc_sel_nxt != 2'd0;
assign regop_set_flags = type == REGOP && instruction[20];
assign mem_op_pre_indexed = instruction[24] && instruction[21];
assign mem_op_post_indexed = !instruction[24];
assign imm32_nxt = // add 0 to Rm
type == MULT ? { 32'd0 } :
// 4 x number of registers
type == MTRANS ? { mtrans_base_reg_change } :
type == BRANCH ? { offset24 } :
type == TRANS ? { offset12 } :
instruction[11:8] == 4'h0 ? { 24'h0, imm8[7:0] } :
instruction[11:8] == 4'h1 ? { imm8[1:0], 24'h0, imm8[7:2] } :
instruction[11:8] == 4'h2 ? { imm8[3:0], 24'h0, imm8[7:4] } :
instruction[11:8] == 4'h3 ? { imm8[5:0], 24'h0, imm8[7:6] } :
instruction[11:8] == 4'h4 ? { imm8[7:0], 24'h0 } :
instruction[11:8] == 4'h5 ? { 2'h0, imm8[7:0], 22'h0 } :
instruction[11:8] == 4'h6 ? { 4'h0, imm8[7:0], 20'h0 } :
instruction[11:8] == 4'h7 ? { 6'h0, imm8[7:0], 18'h0 } :
instruction[11:8] == 4'h8 ? { 8'h0, imm8[7:0], 16'h0 } :
instruction[11:8] == 4'h9 ? { 10'h0, imm8[7:0], 14'h0 } :
instruction[11:8] == 4'ha ? { 12'h0, imm8[7:0], 12'h0 } :
instruction[11:8] == 4'hb ? { 14'h0, imm8[7:0], 10'h0 } :
instruction[11:8] == 4'hc ? { 16'h0, imm8[7:0], 8'h0 } :
instruction[11:8] == 4'hd ? { 18'h0, imm8[7:0], 6'h0 } :
instruction[11:8] == 4'he ? { 20'h0, imm8[7:0], 4'h0 } :
{ 22'h0, imm8[7:0], 2'h0 } ;
assign imm_shift_amount_nxt = shift_imm ;
// This signal is encoded in the decode stage because
// it is on the critical path in the execute stage
assign shift_imm_zero_nxt = imm_shift_amount_nxt == 5'd0 && // immediate amount = 0
barrel_shift_amount_sel_nxt == 2'd2; // shift immediate amount
assign alu_function_nxt = { alu_swap_sel_nxt,
alu_not_sel_nxt,
alu_cin_sel_nxt,
alu_cout_sel_nxt,
alu_out_sel_nxt };
// ========================================================
// MTRANS Operations
// ========================================================
// Bit 15 = r15
// Bit 0 = R0
// In LDM and STM instructions R0 is loaded or stored first
always @*
casez (instruction[15:0])
16'b???????????????1 : mtrans_reg = 4'h0 ;
16'b??????????????10 : mtrans_reg = 4'h1 ;
16'b?????????????100 : mtrans_reg = 4'h2 ;
16'b????????????1000 : mtrans_reg = 4'h3 ;
16'b???????????10000 : mtrans_reg = 4'h4 ;
16'b??????????100000 : mtrans_reg = 4'h5 ;
16'b?????????1000000 : mtrans_reg = 4'h6 ;
16'b????????10000000 : mtrans_reg = 4'h7 ;
16'b???????100000000 : mtrans_reg = 4'h8 ;
16'b??????1000000000 : mtrans_reg = 4'h9 ;
16'b?????10000000000 : mtrans_reg = 4'ha ;
16'b????100000000000 : mtrans_reg = 4'hb ;
16'b???1000000000000 : mtrans_reg = 4'hc ;
16'b??10000000000000 : mtrans_reg = 4'hd ;
16'b?100000000000000 : mtrans_reg = 4'he ;
default : mtrans_reg = 4'hf ;
endcase
always @*
casez (instruction[15:0])
16'b???????????????1 : mtrans_instruction_nxt = {instruction[31:16], instruction[15: 1], 1'd0};
16'b??????????????10 : mtrans_instruction_nxt = {instruction[31:16], instruction[15: 2], 2'd0};
16'b?????????????100 : mtrans_instruction_nxt = {instruction[31:16], instruction[15: 3], 3'd0};
16'b????????????1000 : mtrans_instruction_nxt = {instruction[31:16], instruction[15: 4], 4'd0};
16'b???????????10000 : mtrans_instruction_nxt = {instruction[31:16], instruction[15: 5], 5'd0};
16'b??????????100000 : mtrans_instruction_nxt = {instruction[31:16], instruction[15: 6], 6'd0};
16'b?????????1000000 : mtrans_instruction_nxt = {instruction[31:16], instruction[15: 7], 7'd0};
16'b????????10000000 : mtrans_instruction_nxt = {instruction[31:16], instruction[15: 8], 8'd0};
16'b???????100000000 : mtrans_instruction_nxt = {instruction[31:16], instruction[15: 9], 9'd0};
16'b??????1000000000 : mtrans_instruction_nxt = {instruction[31:16], instruction[15:10], 10'd0};
16'b?????10000000000 : mtrans_instruction_nxt = {instruction[31:16], instruction[15:11], 11'd0};
16'b????100000000000 : mtrans_instruction_nxt = {instruction[31:16], instruction[15:12], 12'd0};
16'b???1000000000000 : mtrans_instruction_nxt = {instruction[31:16], instruction[15:13], 13'd0};
16'b??10000000000000 : mtrans_instruction_nxt = {instruction[31:16], instruction[15:14], 14'd0};
16'b?100000000000000 : mtrans_instruction_nxt = {instruction[31:16], instruction[15 ], 15'd0};
default : mtrans_instruction_nxt = {instruction[31:16], 16'd0};
endcase
// number of registers to be stored
assign mtrans_num_registers = {4'd0, instruction[15]} +
{4'd0, instruction[14]} +
{4'd0, instruction[13]} +
{4'd0, instruction[12]} +
{4'd0, instruction[11]} +
{4'd0, instruction[10]} +
{4'd0, instruction[ 9]} +
{4'd0, instruction[ 8]} +
{4'd0, instruction[ 7]} +
{4'd0, instruction[ 6]} +
{4'd0, instruction[ 5]} +
{4'd0, instruction[ 4]} +
{4'd0, instruction[ 3]} +
{4'd0, instruction[ 2]} +
{4'd0, instruction[ 1]} +
{4'd0, instruction[ 0]} ;
// 4 x number of registers to be stored
assign mtrans_base_reg_change = {25'd0, mtrans_num_registers, 2'd0};
// ========================================================
// Interrupts
// ========================================================
assign firq_request = firq && !i_execute_status_bits[26];
assign irq_request = irq && !i_execute_status_bits[27];
assign swi_request = type == SWI;
assign dabt_request = dabt_reg;
// copro15 and copro13 only supports reg trans opcodes
// all other opcodes involving co-processors cause an
// undefined instrution interrupt
assign und_request = type == CODTRANS ||
type == COREGOP ||
( type == CORTRANS && instruction[11:8] != 4'd15 );
// in order of priority !!
// Highest
// 1 Reset
// 2 Data Abort (including data TLB miss)
// 3 FIRQ
// 4 IRQ
// 5 Prefetch Abort (including prefetch TLB miss)
// 6 Undefined instruction, SWI
// Lowest
assign next_interrupt = dabt_request ? 3'd1 : // Data Abort
firq_request ? 3'd2 : // FIRQ
irq_request ? 3'd3 : // IRQ
instruction_adex ? 3'd4 : // Address Exception
instruction_iabt ? 3'd5 : // PreFetch Abort, only triggered
// if the instruction is used
und_request ? 3'd6 : // Undefined Instruction
swi_request ? 3'd7 : // SWI
3'd0 ; // none
// SWI and undefined instructions do not cause an interrupt in the decode
// stage. They only trigger interrupts if they arfe executed, so the
// interrupt is triggered if the execute condition is met in the execute stage
assign interrupt = next_interrupt != 3'd0 &&
next_interrupt != 3'd7 && // SWI
next_interrupt != 3'd6 ; // undefined interrupt
assign interrupt_mode = next_interrupt == 3'd2 ? FIRQ :
next_interrupt == 3'd3 ? IRQ :
next_interrupt == 3'd4 ? SVC :
next_interrupt == 3'd5 ? SVC :
next_interrupt == 3'd6 ? SVC :
next_interrupt == 3'd7 ? SVC :
next_interrupt == 3'd1 ? SVC :
USR ;
// ========================================================
// Generate control signals
// ========================================================
always @*
begin
// default mode
status_bits_mode_nxt = i_execute_status_bits[1:0]; // change to mode in execute stage get reflected
// back to this stage automatically
status_bits_irq_mask_nxt = o_status_bits_irq_mask;
status_bits_firq_mask_nxt = o_status_bits_firq_mask;
exclusive_exec_nxt = 1'd0;
data_access_exec_nxt = 1'd0;
copro_operation_nxt = 'd0;
// Save an instruction to use later
saved_current_instruction_wen = 1'd0;
pre_fetch_instruction_wen = 1'd0;
mtrans_r15_nxt = mtrans_r15;
restore_base_address_nxt = restore_base_address;
// default Mux Select values
barrel_shift_amount_sel_nxt = 'd0; // don't shift the input
barrel_shift_data_sel_nxt = 'd0; // immediate value
barrel_shift_function_nxt = 'd0;
multiply_function_nxt = 'd0;
address_sel_nxt = 'd0;
pc_sel_nxt = 'd0;
byte_enable_sel_nxt = 'd0;
status_bits_sel_nxt = 'd0;
reg_write_sel_nxt = 'd0;
user_mode_regs_load_nxt = 'd0;
o_user_mode_regs_store_nxt = 'd0;
// ALU Muxes
alu_swap_sel_nxt = 'd0;
alu_not_sel_nxt = 'd0;
alu_cin_sel_nxt = 'd0;
alu_cout_sel_nxt = 'd0;
alu_out_sel_nxt = 'd0;
// default Flop Write Enable values
write_data_wen_nxt = 'd0;
copro_write_data_wen_nxt = 'd0;
base_address_wen_nxt = 'd0;
pc_wen_nxt = 'd1;
reg_bank_wsel_nxt = 'hF; // Don't select any
status_bits_flags_wen_nxt = 'd0;
status_bits_mode_wen_nxt = 'd0;
status_bits_irq_mask_wen_nxt = 'd0;
status_bits_firq_mask_wen_nxt = 'd0;
if ( instruction_valid && !interrupt )
begin
if ( type == REGOP )
begin
if ( !opcode_compare )
begin
// Check is the load destination is the PC
if (instruction[15:12] == 4'd15)
begin
pc_sel_nxt = 2'd1; // alu_out
address_sel_nxt = 4'd1; // alu_out
end
else
reg_bank_wsel_nxt = instruction[15:12];
end
if ( !immediate_shifter_operand )
barrel_shift_function_nxt = instruction[6:5];
if ( !immediate_shifter_operand )
barrel_shift_data_sel_nxt = 2'd2; // Shift value from Rm register
if ( !immediate_shifter_operand && instruction[4] )
barrel_shift_amount_sel_nxt = 2'd1; // Shift amount from Rs registter
if ( !immediate_shifter_operand && !instruction[4] )
barrel_shift_amount_sel_nxt = 2'd2; // Shift immediate amount
if ( opcode == ADD || opcode == CMN ) // CMN is just like an ADD
begin
alu_out_sel_nxt = 4'd1; // Add
end
if ( opcode == ADC ) // Add with Carry
begin
alu_out_sel_nxt = 4'd1; // Add
alu_cin_sel_nxt = 2'd2; // carry in from status_bits
end
if ( opcode == SUB || opcode == CMP ) // Subtract
begin
alu_out_sel_nxt = 4'd1; // Add
alu_cin_sel_nxt = 2'd1; // cin = 1
alu_not_sel_nxt = 1'd1; // invert B
end
// SBC (Subtract with Carry) subtracts the value of its
// second operand and the value of NOT(Carry flag) from
// the value of its first operand.
// Rd = Rn - shifter_operand - NOT(C Flag)
if ( opcode == SBC ) // Subtract with Carry
begin
alu_out_sel_nxt = 4'd1; // Add
alu_cin_sel_nxt = 2'd2; // carry in from status_bits
alu_not_sel_nxt = 1'd1; // invert B
end
if ( opcode == RSB ) // Reverse Subtract
begin
alu_out_sel_nxt = 4'd1; // Add
alu_cin_sel_nxt = 2'd1; // cin = 1
alu_not_sel_nxt = 1'd1; // invert B
alu_swap_sel_nxt = 1'd1; // swap A and B
end
if ( opcode == RSC ) // Reverse Subtract with carry
begin
alu_out_sel_nxt = 4'd1; // Add
alu_cin_sel_nxt = 2'd2; // carry in from status_bits
alu_not_sel_nxt = 1'd1; // invert B
alu_swap_sel_nxt = 1'd1; // swap A and B
end
if ( opcode == AND || opcode == TST ) // Logical AND, Test (using AND operator)
begin
alu_out_sel_nxt = 4'd8; // AND
alu_cout_sel_nxt = 1'd1; // i_barrel_shift_carry
end
if ( opcode == EOR || opcode == TEQ ) // Logical Exclusive OR, Test Equivalence (using EOR operator)
begin
alu_out_sel_nxt = 4'd6; // XOR
alu_cout_sel_nxt = 1'd1; // i_barrel_shift_carry
end
if ( opcode == ORR )
begin
alu_out_sel_nxt = 4'd7; // OR
alu_cout_sel_nxt = 1'd1; // i_barrel_shift_carry
end
if ( opcode == BIC ) // Bit Clear (using AND & NOT operators)
begin
alu_out_sel_nxt = 4'd8; // AND
alu_not_sel_nxt = 1'd1; // invert B
alu_cout_sel_nxt = 1'd1; // i_barrel_shift_carry
end
if ( opcode == MOV ) // Move
begin
alu_cout_sel_nxt = 1'd1; // i_barrel_shift_carry
end
if ( opcode == MVN ) // Move NOT
begin
alu_not_sel_nxt = 1'd1; // invert B
alu_cout_sel_nxt = 1'd1; // i_barrel_shift_carry
end
end
// Load & Store instructions
if ( mem_op )
begin
saved_current_instruction_wen = 1'd1; // Save the memory access instruction to refer back to later
pc_wen_nxt = 1'd0; // hold current PC value
data_access_exec_nxt = 1'd1; // indicate that its a data read or write,
// rather than an instruction fetch
alu_out_sel_nxt = 4'd1; // Add
if ( !instruction[23] ) // U: Subtract offset
begin
alu_cin_sel_nxt = 2'd1; // cin = 1
alu_not_sel_nxt = 1'd1; // invert B
end
if ( store_op )
begin
write_data_wen_nxt = 1'd1;
if ( type == TRANS && instruction[22] )
byte_enable_sel_nxt = 2'd1; // Save byte
end
// need to update the register holding the address ?
// This is Rn bits [19:16]
if ( mem_op_pre_indexed || mem_op_post_indexed )
begin
// Check is the load destination is the PC
if ( o_rn_sel_nxt == 4'd15 )
pc_sel_nxt = 2'd1;
else
reg_bank_wsel_nxt = o_rn_sel_nxt;
end
// if post-indexed, then use Rn rather than ALU output, as address
if ( mem_op_post_indexed )
address_sel_nxt = 4'd4; // Rn
else
address_sel_nxt = 4'd1; // alu out
if ( instruction[25] && type == TRANS )
barrel_shift_data_sel_nxt = 2'd2; // Shift value from Rm register
if ( type == TRANS && instruction[25] && shift_imm != 5'd0 )
begin
barrel_shift_function_nxt = instruction[6:5];
barrel_shift_amount_sel_nxt = 2'd2; // imm_shift_amount
end
end
if ( type == BRANCH )
begin
pc_sel_nxt = 2'd1; // alu_out
address_sel_nxt = 4'd1; // alu_out
alu_out_sel_nxt = 4'd1; // Add
if ( instruction[24] ) // Link
begin
reg_bank_wsel_nxt = 4'd14; // Save PC to LR
reg_write_sel_nxt = 3'd1; // pc - 32'd4
end
end
if ( type == MTRANS )
begin
saved_current_instruction_wen = 1'd1; // Save the memory access instruction to refer back to later
pc_wen_nxt = 1'd0; // hold current PC value
data_access_exec_nxt = 1'd1; // indicate that its a data read or write,
// rather than an instruction fetch
alu_out_sel_nxt = 4'd1; // Add
mtrans_r15_nxt = instruction[15]; // load or save r15 ?
base_address_wen_nxt = 1'd1; // Save the value of the register used for the base address,
// in case of a data abort, and need to restore the value
// The spec says -
// If the instruction would have overwritten the base with data
// (that is, it has the base in the transfer list), the overwriting is prevented.
// This is true even when the abort occurs after the base word gets loaded
restore_base_address_nxt = instruction[20] &&
(instruction[15:0] & (1'd1 << instruction[19:16]));
// Increment or Decrement
if ( instruction[23] ) // increment
begin
if ( instruction[24] ) // increment before
address_sel_nxt = 4'd7; // Rn + 4
else
address_sel_nxt = 4'd4; // Rn
end
else // decrement
begin
alu_cin_sel_nxt = 2'd1; // cin = 1
alu_not_sel_nxt = 1'd1; // invert B
if ( !instruction[24] ) // decrement after
address_sel_nxt = 4'd6; // alu out + 4
else
address_sel_nxt = 4'd1; // alu out
end
// Load or store ?
if ( !instruction[20] ) // Store
write_data_wen_nxt = 1'd1;
// LDM: load into user mode registers, when in priviledged mode
// DOnt use mtrans_r15 here because its not loaded yet
if ( {instruction[22:20],instruction[15]} == 4'b1010 )
user_mode_regs_load_nxt = 1'd1;
// SDM: store the user mode registers, when in priviledged mode
if ( {instruction[22:20]} == 3'b100 )
o_user_mode_regs_store_nxt = 1'd1;
// update the base register ?
if ( instruction[21] ) // the W bit
reg_bank_wsel_nxt = o_rn_sel_nxt;
end
if ( type == MULT )
begin
multiply_function_nxt[0] = 1'd1; // set enable
// some bits can be changed just below
saved_current_instruction_wen = 1'd1; // Save the Multiply instruction to
// refer back to later
pc_wen_nxt = 1'd0; // hold current PC value
if ( instruction[21] )
multiply_function_nxt[1] = 1'd1; // accumulate
end
// swp - do read part first
if ( type == SWAP )
begin
saved_current_instruction_wen = 1'd1; // Save the memory access instruction to refer back to later
pc_wen_nxt = 1'd0; // hold current PC value
data_access_exec_nxt = 1'd1; // indicate that its a data read or write,
// rather than an instruction fetch
barrel_shift_data_sel_nxt = 2'd2; // Shift value from Rm register
address_sel_nxt = 4'd4; // Rn
exclusive_exec_nxt = 1'd1; // signal an exclusive access
end
// mcr & mrc - takes two cycles
if ( type == CORTRANS && !und_request )
begin
saved_current_instruction_wen = 1'd1; // Save the memory access instruction to refer back to later
pc_wen_nxt = 1'd0; // hold current PC value
address_sel_nxt = 4'd3; // pc (not pc + 4)
if ( instruction[20] ) // MRC
copro_operation_nxt = 2'd1; // Register transfer from Co-Processor
else // MCR
begin
// Don't enable operation to Co-Processor until next period
// So it gets the Rd value from the execution stage at the same time
copro_operation_nxt = 2'd0;
copro_write_data_wen_nxt = 1'd1; // Rd register value to co-processor
end
end
if ( type == SWI || und_request )
begin
// save address of next instruction to Supervisor Mode LR
reg_write_sel_nxt = 3'd1; // pc -4
reg_bank_wsel_nxt = 4'd14; // LR
address_sel_nxt = 4'd2; // interrupt_vector
pc_sel_nxt = 2'd2; // interrupt_vector
status_bits_mode_nxt = interrupt_mode; // e.g. Supervisor mode
status_bits_mode_wen_nxt = 1'd1;
// disable normal interrupts
status_bits_irq_mask_nxt = 1'd1;
status_bits_irq_mask_wen_nxt = 1'd1;
end
if ( regop_set_flags )
begin
status_bits_flags_wen_nxt = 1'd1;
// If <Rd> is r15, the ALU output is copied to the Status Bits.
// Not allowed to use r15 for mul or lma instructions
if ( instruction[15:12] == 4'd15 )
begin
status_bits_sel_nxt = 3'd1; // alu out
// Priviledged mode? Then also update the other status bits
if ( i_execute_status_bits[1:0] != USR )
begin
status_bits_mode_wen_nxt = 1'd1;
status_bits_irq_mask_wen_nxt = 1'd1;
status_bits_firq_mask_wen_nxt = 1'd1;
end
end
end
end
// Handle asynchronous interrupts.
// interrupts are processed only during execution states
// multicycle instructions must complete before the interrupt starts
// SWI, Address Exception and Undefined Instruction interrupts are only executed if the
// instruction that causes the interrupt is conditionally executed so
// its not handled here
if ( instruction_valid && interrupt && next_interrupt != 3'd6 )
begin
// Save the interrupt causing instruction to refer back to later
// This also saves the instruction abort vma and status, in the case of an
// instruction abort interrupt
saved_current_instruction_wen = 1'd1;
// save address of next instruction to Supervisor Mode LR
// Address Exception ?
if ( next_interrupt == 3'd4 )
reg_write_sel_nxt = 3'd7; // pc
else
reg_write_sel_nxt = 3'd1; // pc -4
reg_bank_wsel_nxt = 4'd14; // LR
address_sel_nxt = 4'd2; // interrupt_vector
pc_sel_nxt = 2'd2; // interrupt_vector
status_bits_mode_nxt = interrupt_mode; // e.g. Supervisor mode
status_bits_mode_wen_nxt = 1'd1;
// disable normal interrupts
status_bits_irq_mask_nxt = 1'd1;
status_bits_irq_mask_wen_nxt = 1'd1;
// disable fast interrupts
if ( next_interrupt == 3'd2 ) // FIRQ
begin
status_bits_firq_mask_nxt = 1'd1;
status_bits_firq_mask_wen_nxt = 1'd1;
end
end
// previous instruction was either ldr or sdr
// if it is currently executing in the execute stage do the following
if ( control_state == MEM_WAIT1 )
begin
// Save the next instruction to execute later
// Do this even if this instruction does not execute because of Condition
pre_fetch_instruction_wen = 1'd1;
if ( instruction_execute ) // conditional execution state
begin
address_sel_nxt = 4'd3; // pc (not pc + 4)
pc_wen_nxt = 1'd0; // hold current PC value
end
end
// completion of load operation
if ( control_state == MEM_WAIT2 && load_op )
begin
barrel_shift_data_sel_nxt = 2'd1; // load word from memory
barrel_shift_amount_sel_nxt = 2'd3; // shift by address[1:0] x 8
// shift needed
if ( i_execute_address[1:0] != 2'd0 )
barrel_shift_function_nxt = ROR;
// load a byte
if ( type == TRANS && instruction[22] )
alu_out_sel_nxt = 4'd3; // zero_extend8
if ( !dabt ) // dont load data there is an abort on the data read
begin
// Check if the load destination is the PC
if (instruction[15:12] == 4'd15)
begin
pc_sel_nxt = 2'd1; // alu_out
address_sel_nxt = 4'd1; // alu_out
end
else
reg_bank_wsel_nxt = instruction[15:12];
end
end
// second cycle of multiple load or store
if ( control_state == MTRANS_EXEC1 )
begin
// Save the next instruction to execute later
// Do this even if this instruction does not execute because of Condition
pre_fetch_instruction_wen = 1'd1;
if ( instruction_execute ) // conditional execution state
begin
address_sel_nxt = 4'd5; // o_address
pc_wen_nxt = 1'd0; // hold current PC value
data_access_exec_nxt = 1'd1; // indicate that its a data read or write,
// rather than an instruction fetch
if ( !instruction[20] ) // Store
write_data_wen_nxt = 1'd1;
// LDM: load into user mode registers, when in priviledged mode
if ( {instruction[22:20],mtrans_r15} == 4'b1010 )
user_mode_regs_load_nxt = 1'd1;
// SDM: store the user mode registers, when in priviledged mode
if ( {instruction[22:20]} == 3'b100 )
o_user_mode_regs_store_nxt = 1'd1;
end
end
// third cycle of multiple load or store
if ( control_state == MTRANS_EXEC2 )
begin
address_sel_nxt = 4'd5; // o_address
pc_wen_nxt = 1'd0; // hold current PC value
data_access_exec_nxt = 1'd1; // indicate that its a data read or write,
// rather than an instruction fetch
barrel_shift_data_sel_nxt = 2'd1; // load word from memory
// Load or Store
if ( instruction[20] ) // Load
begin
// Can never be loading the PC in this state, as the PC is always
// the last register in the set to be loaded
if ( !dabt )
reg_bank_wsel_nxt = mtrans_reg_d2;
end
else // Store
write_data_wen_nxt = 1'd1;
// LDM: load into user mode registers, when in priviledged mode
if ( {instruction[22:20],mtrans_r15} == 4'b1010 )
user_mode_regs_load_nxt = 1'd1;
// SDM: store the user mode registers, when in priviledged mode
if ( {instruction[22:20]} == 3'b100 )
o_user_mode_regs_store_nxt = 1'd1;
end
// second or fourth cycle of multiple load or store
if ( control_state == MTRANS_EXEC3 && instruction_execute )
begin
address_sel_nxt = 4'd3; // pc (not pc + 4)
pc_wen_nxt = 1'd0; // hold current PC value
barrel_shift_data_sel_nxt = 2'd1; // load word from memory
// Can never be loading the PC in this state, as the PC is always
// the last register in the set to be loaded
if ( instruction[20] && !dabt ) // Load
reg_bank_wsel_nxt = mtrans_reg_d2;
// LDM: load into user mode registers, when in priviledged mode
if ( {instruction[22:20],mtrans_r15} == 4'b1010 )
user_mode_regs_load_nxt = 1'd1;
// SDM: store the user mode registers, when in priviledged mode
if ( {instruction[22:20]} == 3'b100 )
o_user_mode_regs_store_nxt = 1'd1;
end
// state is used for LMD/STM of a single register
if ( control_state == MTRANS_EXEC3B && instruction_execute )
begin
// Save the next instruction to execute later
// Do this even if this instruction does not execute because of Condition
pre_fetch_instruction_wen = 1'd1;
address_sel_nxt = 4'd3; // pc (not pc + 4)
pc_wen_nxt = 1'd0; // hold current PC value
// LDM: load into user mode registers, when in priviledged mode
if ( {instruction[22:20],mtrans_r15} == 4'b1010 )
user_mode_regs_load_nxt = 1'd1;
// SDM: store the user mode registers, when in priviledged mode
if ( {instruction[22:20]} == 3'b100 )
o_user_mode_regs_store_nxt = 1'd1;
end
if ( control_state == MTRANS_EXEC4 )
begin
barrel_shift_data_sel_nxt = 2'd1; // load word from memory
if ( instruction[20] ) // Load
begin
if (!dabt) // dont overwrite registers or status if theres a data abort
begin
if ( mtrans_reg_d2 == 4'd15 ) // load new value into PC
begin
address_sel_nxt = 4'd1; // alu_out - read instructions using new PC value
pc_sel_nxt = 2'd1; // alu_out
pc_wen_nxt = 1'd1; // write PC
// ldm with S bit and pc: the Status bits are updated
// Node this must be done only at the end
// so the register set is the set in the mode before it
// gets changed.
if ( instruction[22] )
begin
status_bits_sel_nxt = 3'd1; // alu out
status_bits_flags_wen_nxt = 1'd1;
// Can't change the mode or mask bits in User mode
if ( i_execute_status_bits[1:0] != USR )
begin
status_bits_mode_wen_nxt = 1'd1;
status_bits_irq_mask_wen_nxt = 1'd1;
status_bits_firq_mask_wen_nxt = 1'd1;
end
end
end
else
begin
reg_bank_wsel_nxt = mtrans_reg_d2;
end
end
end
// we have a data abort interrupt
if ( dabt )
begin
pc_wen_nxt = 1'd0; // hold current PC value
end
// LDM: load into user mode registers, when in priviledged mode
if ( {instruction[22:20],mtrans_r15} == 4'b1010 )
user_mode_regs_load_nxt = 1'd1;
// SDM: store the user mode registers, when in priviledged mode
if ( {instruction[22:20]} == 3'b100 )
o_user_mode_regs_store_nxt = 1'd1;
end
// state is for when a data abort interrupt is triggered during an LDM
if ( control_state == MTRANS5_ABORT )
begin
// Restore the Base Address, if the base register is included in the
// list of registers being loaded
if (restore_base_address) // LDM with base address in register list
begin
reg_write_sel_nxt = 3'd6; // write base_register
reg_bank_wsel_nxt = instruction[19:16]; // to Rn
end
end
// Multiply or Multiply-Accumulate
if ( control_state == MULT_PROC1 && instruction_execute )
begin
// Save the next instruction to execute later
// Do this even if this instruction does not execute because of Condition
pre_fetch_instruction_wen = 1'd1;
pc_wen_nxt = 1'd0; // hold current PC value
multiply_function_nxt = o_multiply_function;
end
// Multiply or Multiply-Accumulate
// Do multiplication
// Wait for done or accumulate signal
if ( control_state == MULT_PROC2 )
begin
// Save the next instruction to execute later
// Do this even if this instruction does not execute because of Condition
pc_wen_nxt = 1'd0; // hold current PC value
address_sel_nxt = 4'd3; // pc (not pc + 4)
multiply_function_nxt = o_multiply_function;
end
// Save RdLo
// always last cycle of all multiply or multiply accumulate operations
if ( control_state == MULT_STORE )
begin
reg_write_sel_nxt = 3'd2; // multiply_out
multiply_function_nxt = o_multiply_function;
if ( type == MULT ) // 32-bit
reg_bank_wsel_nxt = instruction[19:16]; // Rd
else // 64-bit / Long
reg_bank_wsel_nxt = instruction[15:12]; // RdLo
if ( instruction[20] ) // the 'S' bit
begin
status_bits_sel_nxt = 3'd4; // { multiply_flags, status_bits_flags[1:0] }
status_bits_flags_wen_nxt = 1'd1;
end
end
// Add lower 32 bits to multiplication product
if ( control_state == MULT_ACCUMU )
begin
multiply_function_nxt = o_multiply_function;
pc_wen_nxt = 1'd0; // hold current PC value
address_sel_nxt = 4'd3; // pc (not pc + 4)
end
// swp - do write request in 2nd cycle
if ( control_state == SWAP_WRITE && instruction_execute )
begin
barrel_shift_data_sel_nxt = 2'd2; // Shift value from Rm register
address_sel_nxt = 4'd4; // Rn
write_data_wen_nxt = 1'd1;
data_access_exec_nxt = 1'd1; // indicate that its a data read or write,
// rather than an instruction fetch
if ( instruction[22] )
byte_enable_sel_nxt = 2'd1; // Save byte
if ( instruction_execute ) // conditional execution state
pc_wen_nxt = 1'd0; // hold current PC value
// Save the next instruction to execute later
// Do this even if this instruction does not execute because of Condition
pre_fetch_instruction_wen = 1'd1;
end
// swp - receive read response in 3rd cycle
if ( control_state == SWAP_WAIT1 )
begin
barrel_shift_data_sel_nxt = 2'd1; // load word from memory
barrel_shift_amount_sel_nxt = 2'd3; // shift by address[1:0] x 8
// shift needed
if ( i_execute_address[1:0] != 2'd0 )
barrel_shift_function_nxt = ROR;
if ( instruction_execute ) // conditional execution state
begin
address_sel_nxt = 4'd3; // pc (not pc + 4)
pc_wen_nxt = 1'd0; // hold current PC value
end
// load a byte
if ( instruction[22] )
alu_out_sel_nxt = 4'd3; // zero_extend8
if ( !dabt )
begin
// Check is the load destination is the PC
if ( instruction[15:12] == 4'd15 )
begin
pc_sel_nxt = 2'd1; // alu_out
address_sel_nxt = 4'd1; // alu_out
end
else
reg_bank_wsel_nxt = instruction[15:12];
end
end
// 1 cycle delay for Co-Processor Register access
if ( control_state == COPRO_WAIT && instruction_execute )
begin
pre_fetch_instruction_wen = 1'd1;
if ( instruction[20] ) // mrc instruction
begin
// Check is the load destination is the PC
if ( instruction[15:12] == 4'd15 )
begin
// If r15 is specified for <Rd>, the condition code flags are
// updated instead of a general-purpose register.
status_bits_sel_nxt = 3'd3; // i_copro_data
status_bits_flags_wen_nxt = 1'd1;
// Can't change these in USR mode
if ( i_execute_status_bits[1:0] != USR )
begin
status_bits_mode_wen_nxt = 1'd1;
status_bits_irq_mask_wen_nxt = 1'd1;
status_bits_firq_mask_wen_nxt = 1'd1;
end
end
else
reg_bank_wsel_nxt = instruction[15:12];
reg_write_sel_nxt = 3'd5; // i_copro_data
end
else // mcr instruction
begin
copro_operation_nxt = 2'd2; // Register transfer to Co-Processor
end
end
// Have just changed the status_bits mode but this
// creates a 1 cycle gap with the old mode
// coming back from execute into instruction_decode
// So squash that old mode value during this
// cycle of the interrupt transition
if ( control_state == INT_WAIT1 )
status_bits_mode_nxt = o_status_bits_mode; // Supervisor mode
end
// Speed up the long path from u_decode/o_read_data to u_register_bank/r8_firq
// This pre-encodes the firq_s3 signal thats used in u_register_bank
assign firq_not_user_mode_nxt = !user_mode_regs_load_nxt && status_bits_mode_nxt == FIRQ;
// ========================================================
// Next State Logic
// ========================================================
// this replicates the current value of the execute signal in the execute stage
assign instruction_execute = conditional_execute ( o_condition, i_execute_status_bits[31:28] );
assign instruction_valid = (control_state == EXECUTE || control_state == PRE_FETCH_EXEC) ||
// when last instruction was multi-cycle instruction but did not execute
// because condition was false then act like you're in the execute state
(!instruction_execute && (control_state == PC_STALL1 ||
control_state == MEM_WAIT1 ||
control_state == COPRO_WAIT ||
control_state == SWAP_WRITE ||
control_state == MULT_PROC1 ||
control_state == MTRANS_EXEC1 ||
control_state == MTRANS_EXEC3 ||
control_state == MTRANS_EXEC3B ) );
always @*
begin
// default is to hold the current state
control_state_nxt = control_state;
// Note: The order is important here
if ( control_state == RST_WAIT1 ) control_state_nxt = RST_WAIT2;
if ( control_state == RST_WAIT2 ) control_state_nxt = EXECUTE;
if ( control_state == INT_WAIT1 ) control_state_nxt = INT_WAIT2;
if ( control_state == INT_WAIT2 ) control_state_nxt = EXECUTE;
if ( control_state == COPRO_WAIT ) control_state_nxt = PRE_FETCH_EXEC;
if ( control_state == PC_STALL1 ) control_state_nxt = PC_STALL2;
if ( control_state == PC_STALL2 ) control_state_nxt = EXECUTE;
if ( control_state == SWAP_WRITE ) control_state_nxt = SWAP_WAIT1;
if ( control_state == SWAP_WAIT1 ) control_state_nxt = SWAP_WAIT2;
if ( control_state == MULT_STORE ) control_state_nxt = PRE_FETCH_EXEC;
if ( control_state == MTRANS5_ABORT ) control_state_nxt = PRE_FETCH_EXEC;
if ( control_state == MEM_WAIT1 )
control_state_nxt = MEM_WAIT2;
if ( control_state == MEM_WAIT2 ||
control_state == SWAP_WAIT2 )
begin
if ( write_pc ) // writing to the PC!!
control_state_nxt = PC_STALL1;
else
control_state_nxt = PRE_FETCH_EXEC;
end
if ( control_state == MTRANS_EXEC1 )
begin
if (mtrans_instruction_nxt[15:0] != 16'd0)
control_state_nxt = MTRANS_EXEC2;
else // if the register list holds a single register
control_state_nxt = MTRANS_EXEC3;
end
// Stay in State MTRANS_EXEC2 until the full list of registers to
// load or store has been processed
if ( control_state == MTRANS_EXEC2 && mtrans_num_registers == 5'd1 )
control_state_nxt = MTRANS_EXEC3;
if ( control_state == MTRANS_EXEC3 ) control_state_nxt = MTRANS_EXEC4;
if ( control_state == MTRANS_EXEC3B ) control_state_nxt = MTRANS_EXEC4;
if ( control_state == MTRANS_EXEC4 )
begin
if ( dabt ) // data abort
control_state_nxt = MTRANS5_ABORT;
else if (write_pc) // writing to the PC!!
control_state_nxt = PC_STALL1;
else
control_state_nxt = PRE_FETCH_EXEC;
end
if ( control_state == MULT_PROC1 )
begin
if (!instruction_execute)
control_state_nxt = PRE_FETCH_EXEC;
else
control_state_nxt = MULT_PROC2;
end
if ( control_state == MULT_PROC2 )
begin
if ( i_multiply_done )
if ( o_multiply_function[1] ) // Accumulate ?
control_state_nxt = MULT_ACCUMU;
else
control_state_nxt = MULT_STORE;
end
if ( control_state == MULT_ACCUMU )
begin
control_state_nxt = MULT_STORE;
end
// This should come at the end, so that conditional execution works
// correctly
if ( instruction_valid )
begin
// default is to stay in execute state, or to move into this
// state from a conditional execute state
control_state_nxt = EXECUTE;
if ( mem_op ) // load or store word or byte
control_state_nxt = MEM_WAIT1;
if ( write_pc )
control_state_nxt = PC_STALL1;
if ( type == MTRANS )
begin
if ( mtrans_num_registers != 5'd0 )
begin
// check for LDM/STM of a single register
if ( mtrans_num_registers == 5'd1 )
control_state_nxt = MTRANS_EXEC3B;
else
control_state_nxt = MTRANS_EXEC1;
end
else
control_state_nxt = MTRANS_EXEC3;
end
if ( type == MULT )
control_state_nxt = MULT_PROC1;
if ( type == SWAP )
control_state_nxt = SWAP_WRITE;
if ( type == CORTRANS && !und_request )
control_state_nxt = COPRO_WAIT;
// interrupt overrides everything else so its last
if ( interrupt )
control_state_nxt = INT_WAIT1;
end
end
// ========================================================
// Register Update
// ========================================================
always @ ( posedge i_clk )
if (!i_fetch_stall)
begin
o_read_data <= i_read_data;
o_read_data_alignment <= {i_execute_address[1:0], 3'd0};
abt_address_reg <= i_execute_address;
iabt_reg <= i_iabt;
adex_reg <= i_adex;
abt_status_reg <= i_abt_status;
o_status_bits_mode <= status_bits_mode_nxt;
o_status_bits_irq_mask <= status_bits_irq_mask_nxt;
o_status_bits_firq_mask <= status_bits_firq_mask_nxt;
o_imm32 <= imm32_nxt;
o_imm_shift_amount <= imm_shift_amount_nxt;
o_shift_imm_zero <= shift_imm_zero_nxt;
// when have an interrupt, execute the interrupt operation
// unconditionally in the execute stage
// ensures that status_bits register gets updated correctly
// Likewise when in middle of multi-cycle instructions
// execute them unconditionally
o_condition <= instruction_valid && !interrupt ? condition_nxt : AL;
o_exclusive_exec <= exclusive_exec_nxt;
o_data_access_exec <= data_access_exec_nxt;
o_rm_sel <= o_rm_sel_nxt;
o_rds_sel <= o_rds_sel_nxt;
o_rn_sel <= o_rn_sel_nxt;
o_barrel_shift_amount_sel <= barrel_shift_amount_sel_nxt;
o_barrel_shift_data_sel <= barrel_shift_data_sel_nxt;
o_barrel_shift_function <= barrel_shift_function_nxt;
o_alu_function <= alu_function_nxt;
o_multiply_function <= multiply_function_nxt;
o_interrupt_vector_sel <= next_interrupt;
o_address_sel <= address_sel_nxt;
o_pc_sel <= pc_sel_nxt;
o_byte_enable_sel <= byte_enable_sel_nxt;
o_status_bits_sel <= status_bits_sel_nxt;
o_reg_write_sel <= reg_write_sel_nxt;
o_user_mode_regs_load <= user_mode_regs_load_nxt;
o_firq_not_user_mode <= firq_not_user_mode_nxt;
o_write_data_wen <= write_data_wen_nxt;
o_base_address_wen <= base_address_wen_nxt;
o_pc_wen <= pc_wen_nxt;
o_reg_bank_wsel <= reg_bank_wsel_nxt;
o_reg_bank_wen <= decode ( reg_bank_wsel_nxt );
o_status_bits_flags_wen <= status_bits_flags_wen_nxt;
o_status_bits_mode_wen <= status_bits_mode_wen_nxt;
o_status_bits_irq_mask_wen <= status_bits_irq_mask_wen_nxt;
o_status_bits_firq_mask_wen <= status_bits_firq_mask_wen_nxt;
o_copro_opcode1 <= instruction[23:21];
o_copro_opcode2 <= instruction[7:5];
o_copro_crn <= instruction[19:16];
o_copro_crm <= instruction[3:0];
o_copro_num <= instruction[11:8];
o_copro_operation <= copro_operation_nxt;
o_copro_write_data_wen <= copro_write_data_wen_nxt;
mtrans_r15 <= mtrans_r15_nxt;
restore_base_address <= restore_base_address_nxt;
control_state <= control_state_nxt;
mtrans_reg_d1 <= mtrans_reg;
mtrans_reg_d2 <= mtrans_reg_d1;
end
always @ ( posedge i_clk )
if ( !i_fetch_stall )
begin
// sometimes this is a pre-fetch instruction
// e.g. two ldr instructions in a row. The second ldr will be saved
// to the pre-fetch instruction register
// then when its decoded, a copy is saved to the saved_current_instruction
// register
if (type == MTRANS)
begin
saved_current_instruction <= mtrans_instruction_nxt;
saved_current_instruction_iabt <= instruction_iabt;
saved_current_instruction_adex <= instruction_adex;
saved_current_instruction_address <= instruction_address;
saved_current_instruction_iabt_status <= instruction_iabt_status;
end
else if (saved_current_instruction_wen)
begin
saved_current_instruction <= instruction;
saved_current_instruction_iabt <= instruction_iabt;
saved_current_instruction_adex <= instruction_adex;
saved_current_instruction_address <= instruction_address;
saved_current_instruction_iabt_status <= instruction_iabt_status;
end
if (pre_fetch_instruction_wen)
begin
pre_fetch_instruction <= o_read_data;
pre_fetch_instruction_iabt <= iabt_reg;
pre_fetch_instruction_adex <= adex_reg;
pre_fetch_instruction_address <= abt_address_reg;
pre_fetch_instruction_iabt_status <= abt_status_reg;
end
end
always @ ( posedge i_clk )
if ( !i_fetch_stall )
begin
irq <= i_irq;
firq <= i_firq;
if ( control_state == INT_WAIT1 && o_status_bits_mode == SVC )
begin
dabt_reg <= 1'd0;
end
else
begin
dabt_reg <= dabt_reg || i_dabt;
end
dabt_reg_d1 <= dabt_reg;
end
assign dabt = dabt_reg || i_dabt;
// ========================================================
// Decompiler for debugging core - not synthesizable
// ========================================================
`ifdef A23_SIMULATION
//synopsys translate_off
`include "debug_functions.v"
a23_decompile u_decompile (
.i_clk ( i_clk ),
.i_fetch_stall ( i_fetch_stall ),
.i_instruction ( instruction ),
.i_instruction_valid ( instruction_valid ),
.i_instruction_execute ( instruction_execute ),
.i_instruction_address ( instruction_address ),
.i_interrupt ( {3{interrupt}} & next_interrupt ),
.i_interrupt_state ( control_state == INT_WAIT2 ),
.i_instruction_undefined ( und_request ),
.i_pc_sel ( o_pc_sel ),
.i_pc_wen ( o_pc_wen )
);
wire [(15*8)-1:0] xCONTROL_STATE;
wire [(15*8)-1:0] xMODE;
assign xCONTROL_STATE =
control_state == RST_WAIT1 ? "RST_WAIT1" :
control_state == RST_WAIT2 ? "RST_WAIT2" :
control_state == INT_WAIT1 ? "INT_WAIT1" :
control_state == INT_WAIT2 ? "INT_WAIT2" :
control_state == EXECUTE ? "EXECUTE" :
control_state == PRE_FETCH_EXEC ? "PRE_FETCH_EXEC" :
control_state == MEM_WAIT1 ? "MEM_WAIT1" :
control_state == MEM_WAIT2 ? "MEM_WAIT2" :
control_state == PC_STALL1 ? "PC_STALL1" :
control_state == PC_STALL2 ? "PC_STALL2" :
control_state == MTRANS_EXEC1 ? "MTRANS_EXEC1" :
control_state == MTRANS_EXEC2 ? "MTRANS_EXEC2" :
control_state == MTRANS_EXEC3 ? "MTRANS_EXEC3" :
control_state == MTRANS_EXEC3B ? "MTRANS_EXEC3B" :
control_state == MTRANS_EXEC4 ? "MTRANS_EXEC4" :
control_state == MTRANS5_ABORT ? "MTRANS5_ABORT" :
control_state == MULT_PROC1 ? "MULT_PROC1" :
control_state == MULT_PROC2 ? "MULT_PROC2" :
control_state == MULT_STORE ? "MULT_STORE" :
control_state == MULT_ACCUMU ? "MULT_ACCUMU" :
control_state == SWAP_WRITE ? "SWAP_WRITE" :
control_state == SWAP_WAIT1 ? "SWAP_WAIT1" :
control_state == SWAP_WAIT2 ? "SWAP_WAIT2" :
control_state == COPRO_WAIT ? "COPRO_WAIT" :
"UNKNOWN " ;
assign xMODE = mode_name ( o_status_bits_mode );
always @( posedge i_clk )
if (control_state == EXECUTE && ((instruction[0] === 1'bx) || (instruction[31] === 1'bx)))
begin
`TB_ERROR_MESSAGE
$display("Instruction with x's =%08h", instruction);
end
//synopsys translate_on
`endif
endmodule