OpenCores
URL https://opencores.org/ocsvn/zap/zap/trunk

Subversion Repositories zap

[/] [zap/] [trunk/] [src/] [rtl/] [cpu/] [zap_alu_main.v] - Diff between revs 37 and 43

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 37 Rev 43
Line 36... Line 36...
        parameter [31:0] SHIFT_OPS = 32'd5,  // Number of shift operations.
        parameter [31:0] SHIFT_OPS = 32'd5,  // Number of shift operations.
        parameter [31:0] ALU_OPS   = 32'd32, // Number of arithmetic operations.
        parameter [31:0] ALU_OPS   = 32'd32, // Number of arithmetic operations.
        parameter [31:0] FLAG_WDT  = 32'd32  // Width of active CPSR.
        parameter [31:0] FLAG_WDT  = 32'd32  // Width of active CPSR.
)
)
(
(
        /**********************************************************************
 
         *
 
         *                              INPUTS
 
         *
 
         *********************************************************************/
 
 
 
 
 
        // ------------------------------------------------------------------
        // ------------------------------------------------------------------
        // Decompile Interface. Only for debug.
        // Decompile Interface. Only for debug.
        // ------------------------------------------------------------------
        // ------------------------------------------------------------------
 
 
        input wire      [64*8-1:0]              i_decompile,
        input wire      [64*8-1:0]              i_decompile,
Line 129... Line 122...
        input wire  [3:0]                       i_condition_code_ff,            // CC associated with instr.
        input wire  [3:0]                       i_condition_code_ff,            // CC associated with instr.
        input wire  [zap_clog2(PHY_REGS)-1:0]   i_destination_index_ff,         // Target register index.
        input wire  [zap_clog2(PHY_REGS)-1:0]   i_destination_index_ff,         // Target register index.
        input wire  [zap_clog2(ALU_OPS)-1:0]    i_alu_operation_ff,             // Operation to perform.
        input wire  [zap_clog2(ALU_OPS)-1:0]    i_alu_operation_ff,             // Operation to perform.
        input wire                              i_flag_update_ff,               // Update flags if 1.
        input wire                              i_flag_update_ff,               // Update flags if 1.
 
 
        /**********************************************************************
 
         *
 
         *                              OUTPUTS
 
         *
 
         *********************************************************************/
 
 
 
        // -----------------------------------------------------------------
        // -----------------------------------------------------------------
        // ALU result
        // ALU result
        // -----------------------------------------------------------------
        // -----------------------------------------------------------------
 
 
        output reg [31:0]                       o_alu_result_nxt,           // For feedback. ALU result _nxt version.
        output reg [31:0]                       o_alu_result_nxt,           // For feedback. ALU result _nxt version.
Line 200... Line 187...
        output reg [31:0]                       o_data_wb_dat_ff,
        output reg [31:0]                       o_data_wb_dat_ff,
        output reg [3:0]                        o_data_wb_sel_ff
        output reg [3:0]                        o_data_wb_sel_ff
);
);
 
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
// Includes
 
// ----------------------------------------------------------------------------
 
 
`include "zap_defines.vh"
`include "zap_defines.vh"
`include "zap_localparams.vh"
`include "zap_localparams.vh"
`include "zap_functions.vh"
`include "zap_functions.vh"
 
 
wire [31:0] mem_srcdest_value_nxt;
// -----------------------------------------------------------------------------
wire [3:0] ben_nxt;
// Localparams
 
// -----------------------------------------------------------------------------
// Address about to be output. Used to drive tag RAMs etc.
 
reg [31:0]                      mem_address_nxt;
 
 
 
/*
/*
   For memory stores, we must generate correct byte enables. This is done
 *  These override global N,Z,C,V definitions which are on CPSR. These params
   by examining access type inputs. For loads, always 1111 is generated.
 *  are localized over the 4-bit flag structure.
   If there is neither a load or a store, the old value is preserved.
 
*/
 
assign ben_nxt = /*i_mem_store_ff ?*/ generate_ben (
 
                                                 i_mem_unsigned_byte_enable_ff,
 
                                                 i_mem_signed_byte_enable_ff,
 
                                                 i_mem_unsigned_halfword_enable_ff,
 
                                                 i_mem_unsigned_halfword_enable_ff,
 
                                                 mem_address_nxt) /*: i_mem_load_ff ? 4'b1111 : o_ben_ff*/;
 
 
 
assign mem_srcdest_value_nxt =  duplicate (
 
                                                 i_mem_unsigned_byte_enable_ff,
 
                                                 i_mem_signed_byte_enable_ff,
 
                                                 i_mem_unsigned_halfword_enable_ff,
 
                                                 i_mem_unsigned_halfword_enable_ff,
 
                                                 i_mem_srcdest_value_ff );
 
 
 
/*
 
   These override global N,Z,C,V definitions which are on CPSR. These params
 
   are localized over the 4-bit flag structure.
 
*/
*/
localparam [1:0] _N  = 2'd3;
localparam [1:0] _N  = 2'd3;
localparam [1:0] _Z  = 2'd2;
localparam [1:0] _Z  = 2'd2;
localparam [1:0] _C  = 2'd1;
localparam [1:0] _C  = 2'd1;
localparam [1:0] _V  = 2'd0;
localparam [1:0] _V  = 2'd0;
Line 245... Line 213...
localparam [1:0] SNT = 2'd0;
localparam [1:0] SNT = 2'd0;
localparam [1:0] WNT = 2'd1;
localparam [1:0] WNT = 2'd1;
localparam [1:0] WT  = 2'd2;
localparam [1:0] WT  = 2'd2;
localparam [1:0] ST  = 2'd3;
localparam [1:0] ST  = 2'd3;
 
 
 
// ------------------------------------------------------------------------------
 
// Variables
 
// ------------------------------------------------------------------------------
 
 
 
// Memory srcdest value (i.e., data)
 
wire [31:0]                     mem_srcdest_value_nxt;
 
 
 
// Byte enable generator.
 
wire [3:0]                      ben_nxt;
 
 
 
// Address about to be output. Used to drive tag RAMs etc.
 
reg [31:0]                      mem_address_nxt;
 
 
/*
/*
   Sleep flop. When 1 unit sleeps i.e., does not produce any output except on
   Sleep flop. When 1 unit sleeps i.e., does not produce any output except on
   the first clock cycle where LR is calculated using the ALU.
   the first clock cycle where LR is calculated using the ALU.
*/
*/
reg                             sleep_ff, sleep_nxt;
reg                             sleep_ff, sleep_nxt;
Line 266... Line 247...
                                        // values and not indices.
                                        // values and not indices.
 
 
 
 
reg [5:0]                       clz_rm; // Count leading zeros in Rm.
reg [5:0]                       clz_rm; // Count leading zeros in Rm.
 
 
 
// Destination index about to be output.
 
reg [zap_clog2(PHY_REGS)-1:0]      o_destination_index_nxt;
 
 
 
// 1s complement of Rm and Rn.
 
wire [31:0]                     not_rm = ~rm;
 
wire [31:0]                     not_rn = ~rn;
 
 
 
// Wires which connect to an adder.
 
reg [31:0]                      op1, op2;
 
reg                             cin;
 
 
 
// 32-bit adder with carry input and carry output.
 
wire [32:0]                     sum = {1'd0, op1} + {1'd0, op2} + {32'd0, cin};
 
 
 
reg [31:0]                      tmp_flags, tmp_sum;
 
 
 
// Opcode.
 
wire [zap_clog2(ALU_OPS)-1:0]   opcode = i_alu_operation_ff;
 
 
 
// -------------------------------------------------------------------------------
 
// Assigns
 
// -------------------------------------------------------------------------------
 
 
 
/*
 
   For memory stores, we must generate correct byte enables. This is done
 
   by examining access type inputs. For loads, always 1111 is generated.
 
   If there is neither a load or a store, the old value is preserved.
 
*/
 
assign ben_nxt =                generate_ben (
 
                                                 i_mem_unsigned_byte_enable_ff,
 
                                                 i_mem_signed_byte_enable_ff,
 
                                                 i_mem_unsigned_halfword_enable_ff,
 
                                                 i_mem_unsigned_halfword_enable_ff,
 
                                                 mem_address_nxt);
 
 
 
assign mem_srcdest_value_nxt =  duplicate (
 
                                                 i_mem_unsigned_byte_enable_ff,
 
                                                 i_mem_signed_byte_enable_ff,
 
                                                 i_mem_unsigned_halfword_enable_ff,
 
                                                 i_mem_unsigned_halfword_enable_ff,
 
                                                 i_mem_srcdest_value_ff );
 
 
 
/*
 
   Hijack interface. Data aborts use the hijack interface to find return
 
   address. The writeback drives the ALU inputs to find the final output.
 
*/
 
assign o_hijack_sum = sum;
 
 
 
// -------------------------------------------------------------------------------
 
// CLZ logic.
 
// -------------------------------------------------------------------------------
 
 
always @* // CLZ implementation.
always @* // CLZ implementation.
begin
begin
        casez(rm)
        casez(rm)
        32'b1???????????????????????????????:   clz_rm = 6'd00;
        32'b1???????????????????????????????:   clz_rm = 6'd00;
        32'b01??????????????????????????????:   clz_rm = 6'd01;
        32'b01??????????????????????????????:   clz_rm = 6'd01;
Line 305... Line 338...
        32'b00000000000000000000000000000001:   clz_rm = 6'd31;
        32'b00000000000000000000000000000001:   clz_rm = 6'd31;
        default:                                clz_rm = 6'd32; // All zeros.
        default:                                clz_rm = 6'd32; // All zeros.
        endcase
        endcase
end
end
 
 
// Destination index about to be output.
// ----------------------------------------------------------------------------
reg [zap_clog2(PHY_REGS)-1:0]      o_destination_index_nxt;
// Aliases
 
 
// 1s complement of Rm and Rn.
 
wire [31:0]                     not_rm = ~rm;
 
wire [31:0]                     not_rn = ~rn;
 
 
 
// Wires which connect to an adder.
 
reg [31:0]      op1, op2;
 
reg             cin;
 
 
 
// 32-bit adder with carry input and carry output.
 
wire [32:0]     sum = {1'd0, op1} + {1'd0, op2} + {32'd0, cin};
 
 
 
reg [31:0] tmp_flags, tmp_sum;
 
 
 
// Opcode.
 
wire [zap_clog2(ALU_OPS)-1:0] opcode = i_alu_operation_ff;
 
 
 
/*
 
   Hijack interface. Data aborts use the hijack interface to find return
 
   address. The writeback drives the ALU inputs to find the final output.
 
*/
 
assign o_hijack_sum = sum;
 
 
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
 
always @*
always @*
begin
begin
        rm          = i_shifted_source_value_ff;
        rm          = i_shifted_source_value_ff;
        rn          = i_alu_source_value_ff;
        rn          = i_alu_source_value_ff;
        o_flags_ff  = flags_ff;
        o_flags_ff  = flags_ff;
        o_flags_nxt = flags_nxt;
        o_flags_nxt = flags_nxt;
end
end
 
 
 
// -----------------------------------------------------------------------------
// Sequential logic.
// Sequential logic.
 
// -----------------------------------------------------------------------------
 
 
always @ (posedge i_clk)
always @ (posedge i_clk)
begin
begin
        if ( i_reset )
        if ( i_reset )
        begin
        begin
                //
 
                // On reset, processor enters supervisory mode with interrupts
                // On reset, processor enters supervisory mode with interrupts
                // masked.
                // masked.
                //
 
                clear ( {1'd1,1'd1,1'd0,SVC} );
                clear ( {1'd1,1'd1,1'd0,SVC} );
        end
        end
        else if ( i_clear_from_writeback )
        else if ( i_clear_from_writeback )
        begin
        begin
                // Clear but take CPSR from writeback.
                // Clear but take CPSR from writeback.
Line 424... Line 435...
                o_data_wb_dat_ff                <= o_data_wb_dat_nxt;
                o_data_wb_dat_ff                <= o_data_wb_dat_nxt;
                o_data_wb_sel_ff                <= o_data_wb_sel_nxt;
                o_data_wb_sel_ff                <= o_data_wb_sel_nxt;
                o_mem_address_ff                <= o_address_nxt;
                o_mem_address_ff                <= o_address_nxt;
end
end
 
 
always @* // Wishbone next state logic.
// -----------------------------------------------------------------------------
 
// WB next state logic.
 
// -----------------------------------------------------------------------------
 
 
 
always @*
begin
begin
        // Preserve values.
        // Preserve values.
        o_data_wb_cyc_nxt = o_data_wb_cyc_ff;
        o_data_wb_cyc_nxt = o_data_wb_cyc_ff;
        o_data_wb_stb_nxt = o_data_wb_stb_ff;
        o_data_wb_stb_nxt = o_data_wb_stb_ff;
        o_data_wb_we_nxt  = o_data_wb_we_ff;
        o_data_wb_we_nxt  = o_data_wb_we_ff;
Line 444... Line 459...
        else if ( i_clear_from_writeback )
        else if ( i_clear_from_writeback )
        begin
        begin
                o_data_wb_cyc_nxt = 0;
                o_data_wb_cyc_nxt = 0;
                o_data_wb_stb_nxt = 0;
                o_data_wb_stb_nxt = 0;
        end
        end
        else if ( i_data_stall ) begin end
        else if ( i_data_stall )
 
        begin
 
                // Save state.
 
        end
        else if ( i_data_mem_fault || sleep_ff )
        else if ( i_data_mem_fault || sleep_ff )
        begin
        begin
                o_data_wb_cyc_nxt = 0;
                o_data_wb_cyc_nxt = 0;
                o_data_wb_stb_nxt = 0;
                o_data_wb_stb_nxt = 0;
        end
        end
Line 462... Line 480...
                o_address_nxt     = mem_address_nxt;
                o_address_nxt     = mem_address_nxt;
        end
        end
end
end
 
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
// Used to generate access address.
 
// ----------------------------------------------------------------------------
 
 
always @*
always @ (*)
begin:pre_post_index
begin:pre_post_index_address_generator
        // Memory address output based on pre or post index.
        /*
        if ( i_mem_pre_index_ff == 0 ) // Post-index. Update is done after memory access.
         * Do not change address if not needed.
                mem_address_nxt = rn;
         * If not a load OR a store. Preserve this value. Power saving.
        else                           // Pre-index. Update is done before memory access.
         */
                mem_address_nxt = o_alu_result_nxt;
        if (!( (i_mem_load_ff || i_mem_store_ff) && o_dav_nxt ))
 
                mem_address_nxt = o_mem_address_ff;
 
        else
 
        begin
 
                /*
 
                 * Memory address output based on pre or post index.
 
                 * For post-index, update is done after memory access.
 
                 * For pre-index, update is done before memory access.
 
                 */
 
                if ( i_mem_pre_index_ff == 0 )
 
                        mem_address_nxt = rn;               // Postindex; 
 
                else
 
                        mem_address_nxt = o_alu_result_nxt; // Preindex.
 
 
        //
 
        // If a force 32 align is set, make the lower 2 bits as zero.
        // If a force 32 align is set, make the lower 2 bits as zero.
        // Force 32 align is valid for Thumb.
 
        //
 
        if ( i_force32align_ff )
        if ( i_force32align_ff )
                mem_address_nxt[1:0] = 2'b00;
                mem_address_nxt[1:0] = 2'b00;
 
        end
        //
 
        // Do not change address if not needed.
 
        // If not a load OR a store. Preserve this value. Power saving.
 
        //
 
        if (!( (i_mem_load_ff || i_mem_store_ff) && o_dav_nxt ))
 
                mem_address_nxt = o_mem_address_ff;
 
end
end
 
 
// ----------------------------------------------------------------------------
// ---------------------------------------------------------------------------------
 
// Used to generate ALU result + Flags
`ifndef SYNTHESIS
// ---------------------------------------------------------------------------------
 
 
reg [64*8-1:0] OPCODE;
 
 
 
always @*
 
case(opcode)
 
AND:begin       OPCODE = "AND";    end
 
EOR:begin       OPCODE = "EOR";    end
 
MOV:begin       OPCODE = "MOV";    end
 
MVN:begin       OPCODE = "MVN";    end
 
BIC:begin       OPCODE = "BIC";    end
 
ORR:begin       OPCODE = "ORR";    end
 
TST:begin       OPCODE = "TST";    end
 
TEQ:begin       OPCODE = "TEQ";    end
 
CLZ:begin       OPCODE = "CLZ";    end
 
FMOV:begin      OPCODE = "FMOV";   end
 
ADD:begin       OPCODE = "ADD";    end
 
ADC:begin       OPCODE = "ADC";    end
 
SUB:begin       OPCODE = "SUB";    end
 
RSB:begin       OPCODE = "RSB";    end
 
SBC:begin       OPCODE = "SBC";    end
 
RSC:begin       OPCODE = "RSC";    end
 
CMP:begin       OPCODE = "CMP";    end
 
CMN:begin       OPCODE = "CMN";    end
 
endcase
 
 
 
`endif
 
 
 
always @*
always @*
begin: alu_result
begin: alu_result
 
 
        // Default value.
        // Default value.
Line 541... Line 538...
                        rn, rm, flags_ff[31:28],
                        rn, rm, flags_ff[31:28],
                        opcode, i_flag_update_ff, i_nozero_ff
                        opcode, i_flag_update_ff, i_nozero_ff
                );
                );
        end
        end
 
 
        //
        /*
        // Flag MOV i.e., MOV to CPSR or MMOV.
         * Flag MOV(FMOV) i.e., MOV to CPSR and MMOV handler.
        // FMOV moves to CPSR and flushes the pipeline.
         * FMOV moves to CPSR and flushes the pipeline.
        // MMOV moves to SPSR and does not flush the pipeline.
         * MMOV moves to SPSR and does not flush the pipeline.
        //
         */
        else if ( opcode == FMOV || opcode == MMOV )
        else if ( opcode == FMOV || opcode == MMOV )
        begin: fmov_mmov
        begin: fmov_mmov
                integer i;
                integer i;
                reg [31:0] exp_mask;
                reg [31:0] exp_mask;
 
 
Line 564... Line 561...
                begin
                begin
                        if ( exp_mask[i] )
                        if ( exp_mask[i] )
                                tmp_sum[i] = rm[i];
                                tmp_sum[i] = rm[i];
                end
                end
 
 
                //
                /*
                // FMOV moves to the CPSR in ALU and writeback. 
                 * FMOV moves to the CPSR in ALU and writeback.
                // No register is changed. The MSR out of this will have
                 * No register is changed. The MSR out of this will have
                // a target to CPSR.
                 * a target to CPSR.
                //
                 */
                if ( opcode == FMOV )
                if ( opcode == FMOV )
                begin
                begin
                        tmp_flags = tmp_sum;
                        tmp_flags = tmp_sum;
                end
                end
        end
        end
Line 582... Line 579...
                reg [zap_clog2(ALU_OPS)-1:0] op;
                reg [zap_clog2(ALU_OPS)-1:0] op;
                reg n,z,c,v;
                reg n,z,c,v;
 
 
                op         = opcode;
                op         = opcode;
 
 
                // Assign output of adder to flags.
                // Assign output of adder to flags after some minimal logic.
                c = sum[32];
                c = sum[32];
                z = (sum[31:0] == 0);
                z = (sum[31:0] == 0);
                n = sum[31];
                n = sum[31];
 
 
                // Overflow.
                // Overflow.
                if ( ( op == ADD || op == ADC || op == CMN ) && (rn[31] == rm[31]) && (sum[31] != rn[31]) )
                if ( ( op == ADD || op == ADC || op == CMN ) && (rn[31] == rm[31]) && (sum[31] != rn[31]) )
                begin
 
                        v = 1;
                        v = 1;
                end
 
                else if ( (op == RSB || op == RSC) && (rm[31] == !rn[31]) && (sum[31] != rm[31] ) )
                else if ( (op == RSB || op == RSC) && (rm[31] == !rn[31]) && (sum[31] != rm[31] ) )
                begin
 
                        v = 1;
                        v = 1;
                end
 
                else if ( (op == SUB || op == SBC || op == CMP) && (rn[31] == !rm[31]) && (sum[31] != rn[31]) )
                else if ( (op == SUB || op == SBC || op == CMP) && (rn[31] == !rm[31]) && (sum[31] != rn[31]) )
                begin
 
                        v = 1;
                        v = 1;
                end
 
                else
                else
                begin
 
                        v = 0;
                        v = 0;
                end
 
 
 
                //       
                //       
                // If you choose not to update flags, do not change the flags.
                // If you choose not to update flags, do not change the flags.
                // Otherwise, they will contain their newly computed values.
                // Otherwise, they will contain their newly computed values.
                //
                //
Line 621... Line 610...
        // Drive nxt pin of result register.
        // Drive nxt pin of result register.
        o_alu_result_nxt = tmp_sum;
        o_alu_result_nxt = tmp_sum;
end
end
 
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
// Flag propagation and branch prediction feedback unit
 
// ----------------------------------------------------------------------------
 
 
always @*
always @*
begin: flags_bp_feedback
begin: flags_bp_feedback
 
 
       o_clear_from_alu         = 1'd0;
       o_clear_from_alu         = 1'd0;
Line 639... Line 630...
 
 
        if ( i_irq_ff || i_fiq_ff || i_abt_ff || i_swi_ff || i_und_ff )
        if ( i_irq_ff || i_fiq_ff || i_abt_ff || i_swi_ff || i_und_ff )
        begin
        begin
                //
                //
                // Any sign of an interrupt is present, put unit to sleep.
                // Any sign of an interrupt is present, put unit to sleep.
                // The current instruction will not be executed ultimately
                // The current instruction will not be executed ultimately.
                // but rather a SUB LR, PC, 4 will be which will be stored in
                // However o_dav_nxt = 1 since interrupt must be carried on.
                // the link register.
 
                //
                //
                o_dav_nxt = 1'd1;
                o_dav_nxt = 1'd1;
                sleep_nxt = 1'd1;
                sleep_nxt = 1'd1;
        end
        end
        else if ( (opcode == FMOV) && o_dav_nxt ) // Writes to CPSR...
        else if ( (opcode == FMOV) && o_dav_nxt ) // Writes to CPSR...
Line 656... Line 646...
                // USR cannot change mode. Will silently fail.
                // USR cannot change mode. Will silently fail.
                flags_nxt[`CPSR_MODE]   = (flags_nxt[`CPSR_MODE] == USR) ? USR : flags_nxt[`CPSR_MODE]; // Security.
                flags_nxt[`CPSR_MODE]   = (flags_nxt[`CPSR_MODE] == USR) ? USR : flags_nxt[`CPSR_MODE]; // Security.
        end
        end
        else if ( i_destination_index_ff == ARCH_PC && (i_condition_code_ff != NV))
        else if ( i_destination_index_ff == ARCH_PC && (i_condition_code_ff != NV))
        begin
        begin
                if ( i_flag_update_ff && o_dav_nxt )
                if ( i_flag_update_ff && o_dav_nxt ) // PC update with S bit. Context restore. 
                // PC update with S bit.
 
                // Will restore CPU mode from SPSR. USR no change.
 
                begin
                begin
 
                        $display($time, " - %m :: Saw PC update with S bit set. Context restore initiated.");
 
 
                        o_destination_index_nxt = PHY_RAZ_REGISTER;
                        o_destination_index_nxt = PHY_RAZ_REGISTER;
                        o_clear_from_alu        = 1'd1;
                        o_clear_from_alu        = 1'd1;
                        o_pc_from_alu           = tmp_sum;
                        o_pc_from_alu           = tmp_sum;
                        flags_nxt               = i_mem_srcdest_value_ff;                                       // Restore CPSR from SPSR.
                        flags_nxt               = i_mem_srcdest_value_ff;                                       // Restore CPSR from SPSR.
                        flags_nxt[`CPSR_MODE]   = (flags_nxt[`CPSR_MODE] == USR) ? USR : flags_nxt[`CPSR_MODE]; // Security.
                        flags_nxt[`CPSR_MODE]   = (flags_nxt[`CPSR_MODE] == USR) ? USR : flags_nxt[`CPSR_MODE]; // Security.
                end
                end
                else if ( o_dav_nxt ) // Branch taken and no flag update.
                else if ( o_dav_nxt ) // Branch taken and no flag update.
                begin
                begin
                        if ( i_taken_ff == SNT || i_taken_ff == WNT )
                        if ( i_taken_ff == SNT || i_taken_ff == WNT ) // Incorrectly predicted. 
                        // Incorrectly predicted as not-taken.
 
                        begin
                        begin
                                // Quick branches - Flush everything before.
                                // Quick branches - Flush everything before.
 
                                // Dumping ground since PC change is done. Jump to branch target for fast switching.
                                // Dumping ground since PC change is done.
 
                                o_destination_index_nxt = PHY_RAZ_REGISTER;
                                o_destination_index_nxt = PHY_RAZ_REGISTER;
                                o_clear_from_alu        = 1'd1;
                                o_clear_from_alu        = 1'd1;
                                o_pc_from_alu           = tmp_sum;
                                o_pc_from_alu           = tmp_sum;
                                flags_nxt[T]            = i_switch_ff ? tmp_sum[0] : flags_ff[T]; // Thumb/ARM state if i_switch_ff = 1.
 
 
                                if ( i_switch_ff )
 
                                begin
 
                                        flags_nxt[T]            = tmp_sum[0];
 
 
 
                                        if ( tmp_sum[0] )
 
                                                $display($time, " - %m :: Entering T state.");
 
                                        else
 
                                                $display($time, " - %m :: Entering A state.");
 
                                end
                        end
                        end
                        else    // Correctly predicted.
                        else    // Correctly predicted.
                        begin
                        begin
                                // If thumb bit changes, flush everything before
                                // If thumb bit changes, flush everything before
                                if ( i_switch_ff )
                                if ( i_switch_ff )
                                begin
                                begin
                                        //
 
                                        // Quick branches! PC goes to RAZ register since
                                        // Quick branches! PC goes to RAZ register since
                                        // change is done.
                                        // change is done.
                                        //
 
                                        o_destination_index_nxt = PHY_RAZ_REGISTER;
 
 
 
 
                                        o_destination_index_nxt = PHY_RAZ_REGISTER;
                                        o_clear_from_alu        = 1'd1;
                                        o_clear_from_alu        = 1'd1;
                                        o_pc_from_alu           = tmp_sum;
                                        o_pc_from_alu           = tmp_sum; // Jump to branch target.
                                        flags_nxt[T]            = i_switch_ff ? tmp_sum[0] : flags_ff[T];
                                        flags_nxt[T]            = tmp_sum[0];
                                        // Thumb/ARM state if i_switch_ff = 1.
 
 
                                        if ( tmp_sum[0] )
 
                                                $display($time, " - %m :: Entering T state.");
 
                                        else
 
                                                $display($time, " - %m :: Entering A state.");
                                end
                                end
                                else
                                else
                                begin
                                begin
                                        //
                                        // No mode change, do not change anything.
                                        // No mode change, do not change 
 
                                        // anything.
 
                                        //
 
                                        o_destination_index_nxt = PHY_RAZ_REGISTER;
                                        o_destination_index_nxt = PHY_RAZ_REGISTER;
                                        o_clear_from_alu = 1'd0;
                                        o_clear_from_alu = 1'd0;
                                        flags_nxt[T]     = i_switch_ff ? tmp_sum[0]: flags_ff[T];
 
 
 
                                        //
                                        // Send confirmation message to branch predictor.
                                        // Send confirmation message to branch 
 
                                        // predictor.
 
                                        //
 
                                        o_pc_from_alu      = 32'd0;
                                        o_pc_from_alu      = 32'd0;
                                        o_confirm_from_alu = 1'd1;
                                        o_confirm_from_alu = 1'd1;
                                end
                                end
                        end
                        end
                end
                end
                else    // Branch not taken
                else    // Branch not taken
                begin
                begin
                        if ( i_taken_ff == WT || i_taken_ff == ST )
                        if ( i_taken_ff == WT || i_taken_ff == ST )
                        // Wrong prediction as taken...
                        // Wrong prediction as taken. Go back to the same
 
                        // branch. Non branches are always predicted as not-taken.
 
                        // GO BACK TO THE SAME BRANCH AND INFORM PREDICTOR OF ITS   
 
                        // MISTAKE - THE NEXT TIME THE PREDICTION WILL BE NOT-TAKEN.
                        begin
                        begin
                                // Go to the same branch.
 
                                o_clear_from_alu = 1'd1;
                                o_clear_from_alu = 1'd1;
                                o_pc_from_alu    = i_pc_ff;
                                o_pc_from_alu    = i_pc_ff;
                        end
                        end
                        else
                        else // Correct prediction.
                        begin
                        begin
                                // Correct prediction.
 
                                o_clear_from_alu = 1'd0;
                                o_clear_from_alu = 1'd0;
                                o_pc_from_alu    = 32'd0;
                                o_pc_from_alu    = 32'd0;
                        end
                        end
                end
                end
        end
        end
        else if ( i_mem_srcdest_index_ff == ARCH_PC && o_dav_nxt && i_mem_load_ff)
        else if ( i_mem_srcdest_index_ff == ARCH_PC && o_dav_nxt && i_mem_load_ff)
        begin
        begin
                // Loads to PC also puts the unit to sleep.
                // Loads to PC also puts the unit to sleep.
 
                $display($time, " - %m :: ALU saw a load to R15. Sleeping to prevent further instructions from executing.");
                sleep_nxt = 1'd1;
                sleep_nxt = 1'd1;
        end
        end
 
 
        // If the current instruction is invalid, do not update flags.
        // If the current instruction is invalid, do not update flags.
        if ( o_dav_nxt == 1'd0 )
        if ( o_dav_nxt == 1'd0 )
                flags_nxt = flags_ff;
                flags_nxt = flags_ff;
end
end
 
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
// MUX structure on the inputs of the adder.
 
// ----------------------------------------------------------------------------
 
 
// These are adder connections. Data processing and FMOV use these.
// These are adder connections. Data processing and FMOV use these.
always @*
always @*
begin: adder_ip_mux
begin: adder_ip_mux
        reg [zap_clog2(ALU_OPS)-1:0] op;
        reg [zap_clog2(ALU_OPS)-1:0] op;
Line 772... Line 770...
        RSC: begin op1 = rm             ; op2 = not_rn ; cin =   !flags[_C];end
        RSC: begin op1 = rm             ; op2 = not_rn ; cin =   !flags[_C];end
 
 
        // Target is not written.
        // Target is not written.
        CMP: begin op1 = rn             ; op2 = not_rm ; cin =   32'd1;     end
        CMP: begin op1 = rn             ; op2 = not_rm ; cin =   32'd1;     end
        CMN: begin op1 = rn             ; op2 = rm     ; cin =   32'd0;     end
        CMN: begin op1 = rn             ; op2 = rm     ; cin =   32'd0;     end
 
 
        default:
        default:
        begin
        begin
                op1 = 0;
                op1 = 0;
                op2 = 0;
                op2 = 0;
                cin = 0;
                cin = 0;
        end
        end
        endcase
        endcase
end
end
 
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
// Functions
 
// ----------------------------------------------------------------------------
 
 
// Process logical instructions.
// Process logical instructions.
function [35:0] process_logical_instructions
function [35:0] process_logical_instructions
( input [31:0] rn, rm, input [3:0] flags, input [zap_clog2(ALU_OPS)-1:0] op,
(
  input i_flag_upd, input nozero );
                input [31:0] rn,
 
                input [31:0] rm,
 
                input [3:0]  flags,
 
                input [zap_clog2(ALU_OPS)-1:0] op,
 
                input i_flag_upd, input nozero
 
);
begin: blk2
begin: blk2
        reg [31:0] rd;
        reg [31:0] rd;
        reg [3:0] flags_out;
        reg [3:0] flags_out;
 
 
        // Avoid accidental latch inference.
        // Avoid accidental latch inference.
Line 823... Line 829...
        begin
        begin
                // V is preserved since flags_out = flags assignment.
                // V is preserved since flags_out = flags assignment.
                flags_out[_C] = i_shift_carry_ff;
                flags_out[_C] = i_shift_carry_ff;
 
 
                if ( nozero )
                if ( nozero )
                        //
 
                        // This specifically states that we must NOT set the 
                        // This specifically states that we must NOT set the 
                        // ZERO flag under any circumstance. 
                        // ZERO flag under any circumstance. 
                        //
 
                        flags_out[_Z] = 1'd0;
                        flags_out[_Z] = 1'd0;
                else
                else
                        flags_out[_Z] = (rd == 0);
                        flags_out[_Z] = (rd == 0);
 
 
                flags_out[_N] = rd[31];
                flags_out[_N] = rd[31];
Line 838... Line 842...
 
 
        process_logical_instructions = {flags_out, rd};
        process_logical_instructions = {flags_out, rd};
end
end
endfunction
endfunction
 
 
// ----------------------------------------------------------------------------
/*
 
 * This task clears out the flip-flops in this module.
 
 * The flag input is used to preserve/force flags to
 
 * a specific state.
 
 */
task clear ( input [31:0] flags );
task clear ( input [31:0] flags );
begin
begin
                o_dav_ff                         <= 0;
                o_dav_ff                         <= 0;
                flags_ff                         <= flags;
                flags_ff                         <= flags;
                o_abt_ff                         <= 0;
                o_abt_ff                         <= 0;
Line 855... Line 862...
                o_mem_load_ff                    <= 0;
                o_mem_load_ff                    <= 0;
                o_mem_store_ff                   <= 0;
                o_mem_store_ff                   <= 0;
end
end
endtask
endtask
 
 
// ----------------------------------------------------------------------------
/*
 
 * The reason we use the duplicate function is to copy value over the memory
// The reason we use the duplicate function is to copy value over the memory
 * bus for memory stores. If we have a byte write to address 1, then the
// bus for memory stores. If we have a byte write to address 1, then the
 * memory controller basically takes address 0 and byte enable 0010 and writes
// memory controller basically takes address 0 and byte enable 0010 and writes
 * to address 1. This enables implementation of a 32-bit memory controller
// to address 1. This enables implementation of a 32-bit memory controller
 * with byte enables to control updates as is commonly done. Basically this
// with byte enables to control updates as is common.
 * is to faciliate byte and halfword based writes on a 32-bit aligned memory
 
 * bus using byte enables. The rules are simple:
 
 * For a byte access - duplicate the lower byte of the register 4 times.
 
 * For halfword access - duplicate the lower 16-bit of the register twice.
 
 */
 
 
function [31:0] duplicate (     input ub, // Unsigned byte. 
function [31:0] duplicate (     input ub, // Unsigned byte. 
                                input sb, // Signed byte.
                                input sb, // Signed byte.
                                input uh, // Unsigned halfword.
                                input uh, // Unsigned halfword.
                                input sh, // Signed halfword.
                                input sh, // Signed halfword.
Line 889... Line 900...
 
 
        duplicate = x;
        duplicate = x;
end
end
endfunction
endfunction
 
 
// ----------------------------------------------------------------------------
/*
 
 *  Generate byte enables based on access mode.
// Generate byte enables based on access mode.
 *  This function is similar in spirit to the previous one. The
 
 *  byte enables are generated in such a way that along with
 
 *  duplicate - byte and halfword accesses are possible.
 
 *  Rules -
 
 *  For a byte access, generate a byte enable with a 1 at the
 
 *  position that the lower 2-bits read (0,1,2,3).
 
 *  For a halfword access, based on lower 2-bits, if it is 00,
 
 *  make no change to byte enable (0011) else if it is 10, then
 
 *  make byte enable as (1100) which is basically the 32-bit
 
 *  address + 2 (and 3) which will be written.
 
 */
function [3:0] generate_ben (   input ub, // Unsigned byte. 
function [3:0] generate_ben (   input ub, // Unsigned byte. 
                                input sb, // Signed byte.
                                input sb, // Signed byte.
                                input uh, // Unsigned halfword.
                                input uh, // Unsigned halfword.
                                input sh, // Signed halfword.
                                input sh, // Signed halfword.
                                input [31:0] addr       );
                                input [31:0] addr       );
Line 924... Line 945...
 
 
        generate_ben = x;
        generate_ben = x;
end
end
endfunction // generate_ben
endfunction // generate_ben
 
 
`ifndef SYNTHESIS
// assertions_start
 
 
 
        /*
 
         * This assertion ensures that no privilege escalation is possible.
 
         * It does so by ensuring that the flag register cannot change out
 
         * of USR during normal operation.
 
         */
        always @*
        always @*
        begin
        begin
                if ( flags_nxt[`CPSR_MODE] != USR && flags_ff[`CPSR_MODE] == USR )
                if ( flags_nxt[`CPSR_MODE] != USR && flags_ff[`CPSR_MODE] == USR )
                begin
                begin
                        $display($time, "Error: %m CPU is changing out of USR mode without an exception...");
                        $display($time, " - %m :: Error: Privilege Escalation Error.");
                        $stop;
                        $stop;
                end
                end
        end
        end
 
 
`endif
        reg [64*8-1:0] OPCODE;
 
 
 
        always @*
 
        case(opcode)
 
        AND:begin       OPCODE = "AND";    end
 
        EOR:begin       OPCODE = "EOR";    end
 
        MOV:begin       OPCODE = "MOV";    end
 
        MVN:begin       OPCODE = "MVN";    end
 
        BIC:begin       OPCODE = "BIC";    end
 
        ORR:begin       OPCODE = "ORR";    end
 
        TST:begin       OPCODE = "TST";    end
 
        TEQ:begin       OPCODE = "TEQ";    end
 
        CLZ:begin       OPCODE = "CLZ";    end
 
        FMOV:begin      OPCODE = "FMOV";   end
 
        ADD:begin       OPCODE = "ADD";    end
 
        ADC:begin       OPCODE = "ADC";    end
 
        SUB:begin       OPCODE = "SUB";    end
 
        RSB:begin       OPCODE = "RSB";    end
 
        SBC:begin       OPCODE = "SBC";    end
 
        RSC:begin       OPCODE = "RSC";    end
 
        CMP:begin       OPCODE = "CMP";    end
 
        CMN:begin       OPCODE = "CMN";    end
 
        endcase
 
 
 
// assertions_end
 
 
endmodule // zap_alu_main.v
endmodule // zap_alu_main.v
 
 
`default_nettype wire
`default_nettype wire
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

© copyright 1999-2022 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.