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

Subversion Repositories thor

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /thor
    from Rev 2 to Rev 3
    Reverse comparison

Rev 2 → Rev 3

/trunk/rtl/verilog/Thor_BranchHistory.v
0,0 → 1,82
//=============================================================================
// __
// \\__/ o\ (C) 2013 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// Thor_BranchHistory.v
//
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
//=============================================================================
//
module Thor_BranchHistory(rst, clk, advanceX, xisBranch, pc, xpc, takb, predict_taken);
parameter DBW=64;
input rst;
input clk;
input advanceX;
input xisBranch;
input [DBW-1:0] pc;
input [DBW-1:0] xpc;
input takb;
output predict_taken;
 
integer n;
reg [2:0] gbl_branch_hist;
reg [1:0] branch_history_table [255:0];
// For simulation only, initialize the history table to zeros.
// In the real world we don't care.
initial begin
for (n = 0; n < 256; n = n + 1)
branch_history_table[n] = 0;
end
wire [7:0] bht_wa = {xpc[7:2],gbl_branch_hist[2:1]}; // write address
wire [7:0] bht_ra = {pc[7:2],gbl_branch_hist[2:1]}; // read address (IF stage)
wire [1:0] bht_xbits = branch_history_table[bht_wa];
wire [1:0] bht_ibits = branch_history_table[bht_ra];
assign predict_taken = bht_ibits==2'd0 || bht_ibits==2'd1;
 
// Two bit saturating counter
reg [1:0] xbits_new;
always @(takb or bht_xbits)
if (takb) begin
if (bht_xbits != 2'd1)
xbits_new <= bht_xbits + 2'd1;
else
xbits_new <= bht_xbits;
end
else begin
if (bht_xbits != 2'd2)
xbits_new <= bht_xbits - 2'd1;
else
xbits_new <= bht_xbits;
end
 
always @(posedge clk)
if (rst)
gbl_branch_hist <= 3'b000;
else begin
if (advanceX) begin
if (xisBranch) begin
gbl_branch_hist <= {gbl_branch_hist[1:0],takb};
branch_history_table[bht_wa] <= xbits_new;
end
end
end
 
endmodule
 
/trunk/rtl/verilog/Thor_dcachemem_1w1r.v
0,0 → 1,114
// ============================================================================
// __
// \\__/ o\ (C) 2013 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Tri-ported data cache memory. (2 read, 1 write)
//
// ============================================================================
//
module Thor_dcachemem_1w1r(wclk, wce, wr, sel, wa, wd, rclk, rce, ra, o);
parameter DBW=64;
input wclk;
input wce;
input wr;
input [DBW/8-1:0] sel;
input [DBW-1:0] wa;
input [DBW-1:0] wd;
input rclk;
input rce;
input [DBW-1:0] ra;
output [DBW-1:0] o;
 
wire [DBW-1:0] o0, o1, o2;
genvar n;
 
generate
 
for (n = 0; n < DBW/8; n = n + 1)
begin : BRAMS
if (DBW==64)
syncRam2kx8_1rw1r uga (
.wclk(wclk),
.wce(wce),
.wr(wr & sel[n]),
.wa(wa[13:3]),
.wd(wd[n*8+7:n*8]),
.rclk(rclk),
.rce(rce),
.ra(ra[13:3]),
.o(o[n*8+7:n*8])
);
else begin
syncRam2kx8_1rw1r uga (
.wclk(wclk),
.wce(wce),
.wr(wr & sel[n]),
.wa(wa[12:2]),
.wd(wd[n*8+7:n*8]),
.rclk(rclk),
.rce(rce),
.ra(ra[12:2]),
.o(o0[n*8+7:n*8])
);
end
end
endgenerate
 
assign o = o0;
always @(posedge wclk)
begin
if (wce & wr & |sel) begin
$display("*************************");
$display("*************************");
$display("Writing to DCACHE %h=%h", wa, wd);
$display("*************************");
$display("*************************");
end
end
 
endmodule
 
module syncRam2kx8_1rw1r (wclk, wce, wr, wa, wd, rclk, rce, ra, o);
input wclk;
input wce;
input wr;
input [10:0] wa;
input [7:0] wd;
input rclk;
input rce;
input [10:0] ra;
output [7:0] o;
 
reg [7:0] mem [0:2047];
reg [10:0] rra;
integer n;
initial begin
for (n = 0; n < 2048; n = n + 1)
mem[n] <= 0;
end
 
always @(posedge wclk)
if (wce & wr) mem[wa] <= wd;
always @(posedge rclk)
if (rce) rra <= ra;
 
assign o = mem[rra];
 
endmodule
/trunk/rtl/verilog/Thor.v
0,0 → 1,5804
//
// COPYRIGHT 2000 by Bruce L. Jacob
// (contact info: http://www.ece.umd.edu/~blj/)
//
// You are welcome to use, modify, copy, and/or redistribute this implementation, provided:
// 1. you share with the author (Bruce Jacob) any changes you make;
// 2. you properly credit the author (Bruce Jacob) if used within a larger work; and
// 3. you do not modify, delete, or in any way obscure the implementation's copyright
// notice or following comments (i.e. the first 3-4 dozen lines of this file).
//
// RiSC-16
//
// This is an out-of-order implementation of the RiSC-16, a teaching instruction-set used by
// the author at the University of Maryland, and which is a blatant (but sanctioned) rip-off
// of the Little Computer (LC-896) developed by Peter Chen at the University of Michigan.
// The primary differences include the following:
// 1. a move from 17-bit to 16-bit instructions; and
// 2. the replacement of the NOP and HALT opcodes by ADDI and LUI ... HALT and NOP are
// now simply special instances of other instructions: NOP is a do-nothing ADD, and
// HALT is a subset of JALR.
//
// RiSC stands for Ridiculously Simple Computer, which makes sense in the context in which
// the instruction-set is normally used -- to teach simple organization and architecture to
// undergraduates who do not yet know how computers work. This implementation was targetted
// towards more advanced undergraduates doing design & implementation and was intended to
// demonstrate some high-performance concepts on a small scale -- an 8-entry reorder buffer,
// eight opcodes, two ALUs, two-way issue, two-way commit, etc. However, the out-of-order
// core is much more complex than I anticipated, and I hope that its complexity does not
// obscure its underlying structure. We'll see how well it flies in class ...
//
// CAVEAT FREELOADER: This Verilog implementation was developed and debugged in a (somewhat
// frantic) 2-week period before the start of the Fall 2000 semester. Not surprisingly, it
// still contains many bugs and some horrible, horrible logic. The logic is also written so
// as to be debuggable and/or explain its function, rather than to be efficient -- e.g. in
// several places, signals are over-constrained so that they are easy to read in the debug
// output ... also, you will see statements like
//
// if (xyz[`INSTRUCTION_OP] == `BEQ || xyz[`INSTRUCTION_OP] == `SW)
//
// instead of and/nand combinations of bits ... sorry; can't be helped. Use at your own risk.
//
// DOCUMENTATION: Documents describing the RiSC-16 in all its forms (sequential, pipelined,
// as well as out-of-order) can be found on the author's website at the following URL:
//
// http://www.ece.umd.edu/~blj/RiSC/
//
// If you do not find what you are looking for, please feel free to email me with suggestions
// for more/different/modified documents. Same goes for bug fixes.
//
//
// KNOWN PROBLEMS (i.e., bugs I haven't got around to fixing yet)
//
// - If the target of a backwards branch is a backwards branch, the fetchbuf steering logic
// will get confused. This can be fixed by having a separate did_branchback status register
// for each of the fetch buffers.
//
// ============================================================================
// __
// \\__/ o\ (C) 2013,2015 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Thor Superscaler
//
// This work is starting with the RiSC-16 as noted in the copyright statement
// above. Hopefully it will be possible to run this processor in real hardware
// (FPGA) as opposed to just simulation. To the RiSC-16 are added:
//
// 64/32 bit datapath rather than 16 bit
// 64 general purpose registers
// 16 code address registers
// 16 predicate registers / predicated instruction execution
// 8 segment registers
// A branch history table, and a (2,2) correlating branch predictor added
// variable length instruction encodings (code density)
// support for interrupts
// The instruction set is changed completely with many new instructions.
// An instruction and data cache were added.
// A WISHBONE bus interface was added,
//
// 52,635 (84,500 LC's)
// with segmentation
// no bitfield, stack or FP ops
//
// ============================================================================
//
`include "Thor_defines.v"
 
module Thor(corenum, rst_i, clk_i, clk_o, km, nmi_i, irq_i, vec_i, bte_o, cti_o, bl_o, lock_o, resv_o, resv_i, cres_o,
cyc_o, stb_o, ack_i, err_i, we_o, sel_o, adr_o, dat_i, dat_o);
parameter DBW = 32; // databus width
parameter ABW = 32; // address bus width
parameter RSTADDR = 64'hFFFFFFFFFFFFEFF0;
localparam AMSB = ABW-1;
parameter QENTRIES = 8;
parameter ALU1BIG = 0;
parameter RESET1 = 4'd0;
parameter RESET2 = 4'd1;
parameter IDLE = 4'd2;
parameter ICACHE1 = 4'd3;
parameter DCACHE1 = 4'd4;
parameter IBUF1 = 4'd5;
parameter IBUF2 = 4'd6;
parameter IBUF3 = 4'd7;
parameter IBUF4 = 4'd8;
parameter IBUF5 = 4'd9;
parameter NREGS = 127;
parameter PF = 4'd0;
parameter PT = 4'd1;
parameter PEQ = 4'd2;
parameter PNE = 4'd3;
parameter PLE = 4'd4;
parameter PGT = 4'd5;
parameter PGE = 4'd6;
parameter PLT = 4'd7;
parameter PLEU = 4'd8;
parameter PGTU = 4'd9;
parameter PGEU = 4'd10;
parameter PLTU = 4'd11;
input [63:0] corenum;
input rst_i;
input clk_i;
output clk_o;
output km;
input nmi_i;
input irq_i;
input [7:0] vec_i;
output reg [1:0] bte_o;
output reg [2:0] cti_o;
output reg [4:0] bl_o;
output reg lock_o;
output reg resv_o;
input resv_i;
output reg cres_o;
output reg cyc_o;
output reg stb_o;
input ack_i;
input err_i;
output reg we_o;
output reg [DBW/8-1:0] sel_o;
output reg [ABW-1:0] adr_o;
input [DBW-1:0] dat_i;
output reg [DBW-1:0] dat_o;
 
integer n,i;
reg [DBW/8-1:0] rsel;
reg [3:0] cstate;
reg [ABW+3:0] pc; // program counter (virtual)
wire [DBW-1:0] ppc; // physical pc address
reg [ABW-1:0] interrupt_pc; // working register for interrupt pc
reg [DBW-1:0] vadr; // data virtual address
reg [3:0] panic; // indexes the message structure
reg [128:0] message [0:15]; // indexed by panic
reg [DBW-1:0] cregs [0:15]; // code address registers
reg [ 3:0] pregs [0:15]; // predicate registers
`ifdef SEGMENTATION
reg [DBW-1:12] sregs [0:7]; // segment registers
reg [DBW-1:12] sregs_lmt [0:7];
`endif
reg [2:0] rrmapno; // register rename map number
wire ITLBMiss;
wire DTLBMiss;
wire uncached;
wire [DBW-1:0] cdat;
reg pwe;
wire [DBW-1:0] pea;
reg [DBW-1:0] tick;
reg [DBW-1:0] lc; // loop counter
reg [DBW-1:0] rfoa0,rfoa1;
reg [DBW-1:0] rfob0,rfob1;
reg [DBW-1:0] rfoc0,rfoc1;
reg [DBW-1:0] rfot0,rfot1;
reg ic_invalidate,dc_invalidate;
reg ic_invalidate_line,dc_invalidate_line;
reg [ABW-1:0] ic_lineno,dc_lineno;
reg ierr,derr; // err_i during icache load
wire insnerr; // err_i during icache load
wire [127:0] insn;
wire iuncached;
reg [NREGS:0] rf_v;
//reg [15:0] pf_v;
reg im,imb;
reg fxe;
reg nmi1,nmi_edge;
reg StatusHWI;
reg [7:0] StatusEXL;
assign km = StatusHWI | |StatusEXL;
reg [7:0] GM; // register group mask
reg [7:0] GMB;
wire [63:0] sr = {32'd0,imb,7'b0,GMB,im,1'b0,km,fxe,4'b0,GM};
wire int_commit;
wire int_pending;
wire sys_commit;
`ifdef SEGMENTATION
wire [DBW-1:0] spc = (pc[ABW+3:ABW]==4'hF) ? pc[ABW-1:0] :
(pc[ABW-1:ABW-4]==4'hF) ? pc[ABW-1:0] : {sregs[7],12'h000} + pc[ABW-1:0];
`else
wire [DBW-1:0] spc = pc;
`endif
wire [DBW-1:0] ppcp16 = ppc + 64'd16;
reg [DBW-1:0] string_pc;
reg stmv_flag;
reg [7:0] asid;
 
wire clk;
 
// Operand registers
wire take_branch;
wire take_branch0;
wire take_branch1;
 
reg [3:0] rf_source [0:NREGS];
//reg [3:0] pf_source [15:0];
 
// instruction queue (ROB)
reg iq_cmt[0:7];
reg [7:0] iqentry_v; // entry valid? -- this should be the first bit
reg iqentry_out [0:7]; // instruction has been issued to an ALU ...
reg iqentry_done [0:7]; // instruction result valid
reg [7:0] iqentry_cmt; // commit result to machine state
reg iqentry_bt [0:7]; // branch-taken (used only for branches)
reg iqentry_agen [0:7]; // memory address is generated
reg iqentry_mem [0:7]; // touches memory: 1 if LW/SW
reg iqentry_jmp [0:7]; // changes control flow: 1 if BEQ/JALR
reg iqentry_fp [0:7]; // is an floating point operation
reg iqentry_rfw [0:7]; // writes to register file
reg [DBW-1:0] iqentry_res [0:7]; // instruction result
reg [3:0] iqentry_insnsz [0:7]; // the size of the instruction
reg [3:0] iqentry_cond [0:7]; // predicating condition
reg [3:0] iqentry_pred [0:7]; // predicate value
reg iqentry_p_v [0:7]; // predicate is valid
reg [3:0] iqentry_p_s [0:7]; // predicate source
reg [7:0] iqentry_op [0:7]; // instruction opcode
reg [5:0] iqentry_fn [0:7]; // instruction function
reg [2:0] iqentry_renmapno [0:7]; // register rename map number
reg [6:0] iqentry_tgt [0:7]; // Rt field or ZERO -- this is the instruction's target (if any)
reg [DBW-1:0] iqentry_a0 [0:7]; // argument 0 (immediate)
reg [DBW-1:0] iqentry_a1 [0:7]; // argument 1
reg iqentry_a1_v [0:7]; // arg1 valid
reg [3:0] iqentry_a1_s [0:7]; // arg1 source (iq entry # with top bit representing ALU/DRAM bus)
reg [DBW-1:0] iqentry_a2 [0:7]; // argument 2
reg iqentry_a2_v [0:7]; // arg2 valid
reg [3:0] iqentry_a2_s [0:7]; // arg2 source (iq entry # with top bit representing ALU/DRAM bus)
reg [DBW-1:0] iqentry_a3 [0:7]; // argument 3
reg iqentry_a3_v [0:7]; // arg3 valid
reg [3:0] iqentry_a3_s [0:7]; // arg3 source (iq entry # with top bit representing ALU/DRAM bus)
reg [DBW-1:0] iqentry_T [0:7];
reg iqentry_T_v [0:7];
reg [3:0] iqentry_T_s [0:7];
reg [DBW-1:0] iqentry_pc [0:7]; // program counter for this instruction
 
wire iqentry_source [0:7];
wire iqentry_imm [0:7];
wire iqentry_memready [0:7];
wire iqentry_memopsvalid [0:7];
reg qstomp;
 
wire stomp_all;
reg [7:0] iqentry_fpissue;
reg [7:0] iqentry_memissue;
wire iqentry_memissue_head0;
wire iqentry_memissue_head1;
wire iqentry_memissue_head2;
wire iqentry_memissue_head3;
wire iqentry_memissue_head4;
wire iqentry_memissue_head5;
wire iqentry_memissue_head6;
wire iqentry_memissue_head7;
wire [7:0] iqentry_stomp;
reg [7:0] iqentry_issue;
wire [1:0] iqentry_0_islot;
wire [1:0] iqentry_1_islot;
wire [1:0] iqentry_2_islot;
wire [1:0] iqentry_3_islot;
wire [1:0] iqentry_4_islot;
wire [1:0] iqentry_5_islot;
wire [1:0] iqentry_6_islot;
wire [1:0] iqentry_7_islot;
reg [1:0] iqentry_islot[0:7];
reg [1:0] iqentry_fpislot[0:7];
 
reg queued1,queued2;
reg queued3; // for three-way config
reg allowq;
 
wire [NREGS:1] livetarget;
wire [NREGS:1] iqentry_0_livetarget;
wire [NREGS:1] iqentry_1_livetarget;
wire [NREGS:1] iqentry_2_livetarget;
wire [NREGS:1] iqentry_3_livetarget;
wire [NREGS:1] iqentry_4_livetarget;
wire [NREGS:1] iqentry_5_livetarget;
wire [NREGS:1] iqentry_6_livetarget;
wire [NREGS:1] iqentry_7_livetarget;
wire [NREGS:1] iqentry_0_latestID;
wire [NREGS:1] iqentry_1_latestID;
wire [NREGS:1] iqentry_2_latestID;
wire [NREGS:1] iqentry_3_latestID;
wire [NREGS:1] iqentry_4_latestID;
wire [NREGS:1] iqentry_5_latestID;
wire [NREGS:1] iqentry_6_latestID;
wire [NREGS:1] iqentry_7_latestID;
wire [NREGS:1] iqentry_0_cumulative;
wire [NREGS:1] iqentry_1_cumulative;
wire [NREGS:1] iqentry_2_cumulative;
wire [NREGS:1] iqentry_3_cumulative;
wire [NREGS:1] iqentry_4_cumulative;
wire [NREGS:1] iqentry_5_cumulative;
wire [NREGS:1] iqentry_6_cumulative;
wire [NREGS:1] iqentry_7_cumulative;
 
 
reg [2:0] tail0;
reg [2:0] tail1;
reg [2:0] tail2; // used only for three-way config
reg [2:0] head0;
reg [2:0] head1;
reg [2:0] head2; // used only to determine memory-access ordering
reg [2:0] head3; // used only to determine memory-access ordering
reg [2:0] head4; // used only to determine memory-access ordering
reg [2:0] head5; // used only to determine memory-access ordering
reg [2:0] head6; // used only to determine memory-access ordering
reg [2:0] head7; // used only to determine memory-access ordering
reg [2:0] headinc;
 
wire [2:0] missid;
reg fetchbuf; // determines which pair to read from & write to
 
reg [63:0] fetchbuf0_instr;
reg [DBW-1:0] fetchbuf0_pc;
reg fetchbuf0_v;
wire fetchbuf0_mem;
wire fetchbuf0_jmp;
wire fetchbuf0_fp;
wire fetchbuf0_rfw;
wire fetchbuf0_pfw;
reg [63:0] fetchbuf1_instr;
reg [DBW-1:0] fetchbuf1_pc;
reg fetchbuf1_v;
wire fetchbuf1_mem;
wire fetchbuf1_jmp;
wire fetchbuf1_fp;
wire fetchbuf1_rfw;
wire fetchbuf1_pfw;
wire fetchbuf1_bfw;
reg [63:0] fetchbuf2_instr;
reg [DBW-1:0] fetchbuf2_pc;
reg fetchbuf2_v;
wire fetchbuf2_mem;
wire fetchbuf2_jmp;
wire fetchbuf2_fp;
wire fetchbuf2_rfw;
wire fetchbuf2_pfw;
wire fetchbuf2_bfw;
 
reg [63:0] fetchbufA_instr;
reg [DBW-1:0] fetchbufA_pc;
reg fetchbufA_v;
reg [63:0] fetchbufB_instr;
reg [DBW-1:0] fetchbufB_pc;
reg fetchbufB_v;
reg [63:0] fetchbufC_instr;
reg [DBW-1:0] fetchbufC_pc;
reg fetchbufC_v;
reg [63:0] fetchbufD_instr;
reg [DBW-1:0] fetchbufD_pc;
reg fetchbufD_v;
 
reg did_branchback;
reg did_branchback0;
reg did_branchback1;
 
reg alu0_ld;
reg alu0_available;
reg alu0_dataready;
reg [3:0] alu0_sourceid;
reg [3:0] alu0_insnsz;
reg [7:0] alu0_op;
reg [5:0] alu0_fn;
reg [3:0] alu0_cond;
reg alu0_bt;
reg alu0_cmt;
reg [DBW-1:0] alu0_argA;
reg [DBW-1:0] alu0_argB;
reg [DBW-1:0] alu0_argC;
reg [DBW-1:0] alu0_argT;
reg [DBW-1:0] alu0_argI;
reg [3:0] alu0_pred;
reg [DBW-1:0] alu0_pc;
reg [DBW-1:0] alu0_bus;
reg [3:0] alu0_id;
wire [3:0] alu0_exc;
reg alu0_v;
wire alu0_branchmiss;
reg [ABW+3:0] alu0_misspc;
 
reg alu1_ld;
reg alu1_available;
reg alu1_dataready;
reg [3:0] alu1_sourceid;
reg [3:0] alu1_insnsz;
reg [7:0] alu1_op;
reg [5:0] alu1_fn;
reg [3:0] alu1_cond;
reg alu1_bt;
reg alu1_cmt;
reg [DBW-1:0] alu1_argA;
reg [DBW-1:0] alu1_argB;
reg [DBW-1:0] alu1_argC;
reg [DBW-1:0] alu1_argT;
reg [DBW-1:0] alu1_argI;
reg [3:0] alu1_pred;
reg [DBW-1:0] alu1_pc;
reg [DBW-1:0] alu1_bus;
reg [3:0] alu1_id;
wire [3:0] alu1_exc;
reg alu1_v;
wire alu1_branchmiss;
reg [ABW+3:0] alu1_misspc;
 
wire mem_stringmiss;
wire branchmiss;
wire [ABW+3:0] misspc;
 
`ifdef FLOATING_POINT
reg fp0_ld;
reg fp0_available;
reg fp0_dataready;
reg [3:0] fp0_sourceid;
reg [7:0] fp0_op;
reg [5:0] fp0_fn;
reg [3:0] fp0_cond;
wire fp0_cmt;
reg fp0_done;
reg [DBW-1:0] fp0_argA;
reg [DBW-1:0] fp0_argB;
reg [DBW-1:0] fp0_argC;
reg [DBW-1:0] fp0_argI;
reg [3:0] fp0_pred;
reg [DBW-1:0] fp0_pc;
wire [DBW-1:0] fp0_bus;
wire [3:0] fp0_id;
wire [7:0] fp0_exc;
wire fp0_v;
`endif
 
wire dram_avail;
reg [2:0] dram0; // state of the DRAM request (latency = 4; can have three in pipeline)
reg [2:0] dram1; // state of the DRAM request (latency = 4; can have three in pipeline)
reg [2:0] dram2; // state of the DRAM request (latency = 4; can have three in pipeline)
reg [2:0] tlb_state;
reg [3:0] tlb_id;
reg [3:0] tlb_op;
reg [3:0] tlb_regno;
reg [8:0] tlb_tgt;
reg [DBW-1:0] tlb_data;
 
wire [DBW-1:0] tlb_dato;
reg dram0_owns_bus;
reg [DBW-1:0] dram0_data;
reg [DBW-1:0] dram0_datacmp;
reg [DBW-1:0] dram0_addr;
reg [DBW-1:0] dram0_seg; // value of segment register associated with memory operation
reg [ABW-1:12] dram0_lmt; // value of segment limit associated with memory operation
reg [7:0] dram0_op;
reg [5:0] dram0_fn;
reg [8:0] dram0_tgt;
reg [3:0] dram0_id;
reg [3:0] dram0_exc;
reg dram1_owns_bus;
reg [DBW-1:0] dram1_data;
reg [DBW-1:0] dram1_datacmp;
reg [DBW-1:0] dram1_addr;
reg [7:0] dram1_op;
reg [5:0] dram1_fn;
reg [6:0] dram1_tgt;
reg [3:0] dram1_id;
reg [3:0] dram1_exc;
reg [DBW-1:0] dram2_data;
reg [DBW-1:0] dram2_datacmp;
reg [DBW-1:0] dram2_addr;
reg [7:0] dram2_op;
reg [5:0] dram2_fn;
reg [6:0] dram2_tgt;
reg [3:0] dram2_id;
reg [3:0] dram2_exc;
 
reg [DBW-1:0] dram_bus;
reg [6:0] dram_tgt;
reg [3:0] dram_id;
reg [3:0] dram_exc;
reg dram_v;
 
reg [DBW-1:0] index;
reg [DBW-1:0] src_addr,dst_addr;
wire mem_issue;
 
wire outstanding_stores;
reg [DBW-1:0] I; // instruction count
 
wire commit0_v;
wire [3:0] commit0_id;
wire [6:0] commit0_tgt;
wire [DBW-1:0] commit0_bus;
wire commit1_v;
wire [3:0] commit1_id;
wire [6:0] commit1_tgt;
wire [DBW-1:0] commit1_bus;
wire limit_cmt;
wire committing2;
wire [63:0] alu0_divq;
wire [63:0] alu0_rem;
wire alu0_div_done;
 
wire [63:0] alu1_divq;
wire [63:0] alu1_rem;
wire alu1_div_done;
 
wire [127:0] alu0_prod;
wire alu0_mult_done;
wire [127:0] alu1_prod;
wire alu1_mult_done;
 
//-----------------------------------------------------------------------------
// Debug
//-----------------------------------------------------------------------------
 
wire [DBW-1:0] dbg_stat;
reg [DBW-1:0] dbg_ctrl;
reg [ABW-1:0] dbg_adr0;
reg [ABW-1:0] dbg_adr1;
reg [ABW-1:0] dbg_adr2;
reg [ABW-1:0] dbg_adr3;
reg dbg_imatchA0,dbg_imatchA1,dbg_imatchA2,dbg_imatchA3,dbg_imatchA;
reg dbg_imatchB0,dbg_imatchB1,dbg_imatchB2,dbg_imatchB3,dbg_imatchB;
 
wire dbg_lmatch0 =
dbg_ctrl[0] && dbg_ctrl[17:16]==2'b11 && dram0_addr[AMSB:3]==dbg_adr0[AMSB:3] &&
((dbg_ctrl[19:18]==2'b00 && dram0_addr[2:0]==dbg_adr0[2:0]) ||
(dbg_ctrl[19:18]==2'b01 && dram0_addr[2:1]==dbg_adr0[2:1]) ||
(dbg_ctrl[19:18]==2'b10 && dram0_addr[2]==dbg_adr0[2]) ||
dbg_ctrl[19:18]==2'b11)
;
wire dbg_lmatch1 =
dbg_ctrl[1] && dbg_ctrl[21:20]==2'b11 && dram0_addr[AMSB:3]==dbg_adr1[AMSB:3] &&
((dbg_ctrl[23:22]==2'b00 && dram0_addr[2:0]==dbg_adr1[2:0]) ||
(dbg_ctrl[23:22]==2'b01 && dram0_addr[2:1]==dbg_adr1[2:1]) ||
(dbg_ctrl[23:22]==2'b10 && dram0_addr[2]==dbg_adr1[2]) ||
dbg_ctrl[23:22]==2'b11)
;
wire dbg_lmatch2 =
dbg_ctrl[2] && dbg_ctrl[25:24]==2'b11 && dram0_addr[AMSB:3]==dbg_adr2[AMSB:3] &&
((dbg_ctrl[27:26]==2'b00 && dram0_addr[2:0]==dbg_adr2[2:0]) ||
(dbg_ctrl[27:26]==2'b01 && dram0_addr[2:1]==dbg_adr2[2:1]) ||
(dbg_ctrl[27:26]==2'b10 && dram0_addr[2]==dbg_adr2[2]) ||
dbg_ctrl[27:26]==2'b11)
;
wire dbg_lmatch3 =
dbg_ctrl[3] && dbg_ctrl[29:28]==2'b11 && dram0_addr[AMSB:3]==dbg_adr3[AMSB:3] &&
((dbg_ctrl[31:30]==2'b00 && dram0_addr[2:0]==dbg_adr3[2:0]) ||
(dbg_ctrl[31:30]==2'b01 && dram0_addr[2:1]==dbg_adr3[2:1]) ||
(dbg_ctrl[31:30]==2'b10 && dram0_addr[2]==dbg_adr3[2]) ||
dbg_ctrl[31:30]==2'b11)
;
wire dbg_lmatch = dbg_lmatch0|dbg_lmatch1|dbg_lmatch2|dbg_lmatch3;
 
wire dbg_smatch0 =
dbg_ctrl[0] && dbg_ctrl[17:16]==2'b11 && dram0_addr[AMSB:3]==dbg_adr0[AMSB:3] &&
((dbg_ctrl[19:18]==2'b00 && dram0_addr[2:0]==dbg_adr0[2:0]) ||
(dbg_ctrl[19:18]==2'b01 && dram0_addr[2:1]==dbg_adr0[2:1]) ||
(dbg_ctrl[19:18]==2'b10 && dram0_addr[2]==dbg_adr0[2]) ||
dbg_ctrl[19:18]==2'b11)
;
wire dbg_smatch1 =
dbg_ctrl[1] && dbg_ctrl[21:20]==2'b11 && dram0_addr[AMSB:3]==dbg_adr1[AMSB:3] &&
((dbg_ctrl[23:22]==2'b00 && dram0_addr[2:0]==dbg_adr1[2:0]) ||
(dbg_ctrl[23:22]==2'b01 && dram0_addr[2:1]==dbg_adr1[2:1]) ||
(dbg_ctrl[23:22]==2'b10 && dram0_addr[2]==dbg_adr1[2]) ||
dbg_ctrl[23:22]==2'b11)
;
wire dbg_smatch2 =
dbg_ctrl[2] && dbg_ctrl[25:24]==2'b11 && dram0_addr[AMSB:3]==dbg_adr2[AMSB:3] &&
((dbg_ctrl[27:26]==2'b00 && dram0_addr[2:0]==dbg_adr2[2:0]) ||
(dbg_ctrl[27:26]==2'b01 && dram0_addr[2:1]==dbg_adr2[2:1]) ||
(dbg_ctrl[27:26]==2'b10 && dram0_addr[2]==dbg_adr2[2]) ||
dbg_ctrl[27:26]==2'b11)
;
wire dbg_smatch3 =
dbg_ctrl[3] && dbg_ctrl[29:28]==2'b11 && dram0_addr[AMSB:3]==dbg_adr3[AMSB:3] &&
((dbg_ctrl[31:30]==2'b00 && dram0_addr[2:0]==dbg_adr3[2:0]) ||
(dbg_ctrl[31:30]==2'b01 && dram0_addr[2:1]==dbg_adr3[2:1]) ||
(dbg_ctrl[31:30]==2'b10 && dram0_addr[2]==dbg_adr3[2]) ||
dbg_ctrl[31:30]==2'b11)
;
wire dbg_smatch = dbg_smatch0|dbg_smatch1|dbg_smatch2|dbg_smatch3;
 
wire dbg_stat0 = dbg_imatchA0 | dbg_imatchB0 | dbg_lmatch0 | dbg_smatch0;
wire dbg_stat1 = dbg_imatchA1 | dbg_imatchB1 | dbg_lmatch1 | dbg_smatch1;
wire dbg_stat2 = dbg_imatchA2 | dbg_imatchB2 | dbg_lmatch2 | dbg_smatch2;
wire dbg_stat3 = dbg_imatchA3 | dbg_imatchB3 | dbg_lmatch3 | dbg_smatch3;
assign dbg_stat = {dbg_stat3,dbg_stat2,dbg_stat1,dbg_stat0};
 
 
reg [11:0] spr_bir;
 
//
// BRANCH-MISS LOGIC: livetarget
//
// livetarget implies that there is a not-to-be-stomped instruction that targets the register in question
// therefore, if it is zero it implies the rf_v value should become VALID on a branchmiss
//
 
Thor_livetarget #(NREGS) ultgt1
(
iqentry_v,
iqentry_stomp,
iqentry_cmt,
iqentry_tgt[0],
iqentry_tgt[1],
iqentry_tgt[2],
iqentry_tgt[3],
iqentry_tgt[4],
iqentry_tgt[5],
iqentry_tgt[6],
iqentry_tgt[7],
livetarget,
iqentry_0_livetarget,
iqentry_1_livetarget,
iqentry_2_livetarget,
iqentry_3_livetarget,
iqentry_4_livetarget,
iqentry_5_livetarget,
iqentry_6_livetarget,
iqentry_7_livetarget
);
 
//
// BRANCH-MISS LOGIC: latestID
//
// latestID is the instruction queue ID of the newest instruction (latest) that targets
// a particular register. looks a lot like scheduling logic, but in reverse.
//
 
assign iqentry_0_latestID = ((missid == 3'd0)|| ((iqentry_0_livetarget & iqentry_1_cumulative) == {NREGS{1'b0}}))
? iqentry_0_livetarget
: {NREGS{1'b0}};
assign iqentry_0_cumulative = (missid == 3'd0)
? iqentry_0_livetarget
: iqentry_0_livetarget | iqentry_1_cumulative;
 
assign iqentry_1_latestID = ((missid == 3'd1)|| ((iqentry_1_livetarget & iqentry_2_cumulative) == {NREGS{1'b0}}))
? iqentry_1_livetarget
: {NREGS{1'b0}};
assign iqentry_1_cumulative = (missid == 3'd1)
? iqentry_1_livetarget
: iqentry_1_livetarget | iqentry_2_cumulative;
 
assign iqentry_2_latestID = ((missid == 3'd2) || ((iqentry_2_livetarget & iqentry_3_cumulative) == {NREGS{1'b0}}))
? iqentry_2_livetarget
: {NREGS{1'b0}};
assign iqentry_2_cumulative = (missid == 3'd2)
? iqentry_2_livetarget
: iqentry_2_livetarget | iqentry_3_cumulative;
 
assign iqentry_3_latestID = ((missid == 3'd3)|| ((iqentry_3_livetarget & iqentry_4_cumulative) == {NREGS{1'b0}}))
? iqentry_3_livetarget
: {NREGS{1'b0}};
assign iqentry_3_cumulative = (missid == 3'd3)
? iqentry_3_livetarget
: iqentry_3_livetarget | iqentry_4_cumulative;
 
assign iqentry_4_latestID = ((missid == 3'd4) || ((iqentry_4_livetarget & iqentry_5_cumulative) == {NREGS{1'b0}}))
? iqentry_4_livetarget
: {NREGS{1'b0}};
assign iqentry_4_cumulative = (missid == 3'd4)
? iqentry_4_livetarget
: iqentry_4_livetarget | iqentry_5_cumulative;
 
assign iqentry_5_latestID = ((missid == 3'd5)|| ((iqentry_5_livetarget & iqentry_6_cumulative) == {NREGS{1'b0}}))
? iqentry_5_livetarget
: 287'd0;
assign iqentry_5_cumulative = (missid == 3'd5)
? iqentry_5_livetarget
: iqentry_5_livetarget | iqentry_6_cumulative;
 
assign iqentry_6_latestID = ((missid == 3'd6) || ((iqentry_6_livetarget & iqentry_7_cumulative) == {NREGS{1'b0}}))
? iqentry_6_livetarget
: {NREGS{1'b0}};
assign iqentry_6_cumulative = (missid == 3'd6)
? iqentry_6_livetarget
: iqentry_6_livetarget | iqentry_7_cumulative;
 
assign iqentry_7_latestID = ((missid == 3'd7) || ((iqentry_7_livetarget & iqentry_0_cumulative) == {NREGS{1'b0}}))
? iqentry_7_livetarget
: {NREGS{1'b0}};
assign iqentry_7_cumulative = (missid==3'd7)
? iqentry_7_livetarget
: iqentry_7_livetarget | iqentry_0_cumulative;
 
assign
iqentry_source[0] = | iqentry_0_latestID,
iqentry_source[1] = | iqentry_1_latestID,
iqentry_source[2] = | iqentry_2_latestID,
iqentry_source[3] = | iqentry_3_latestID,
iqentry_source[4] = | iqentry_4_latestID,
iqentry_source[5] = | iqentry_5_latestID,
iqentry_source[6] = | iqentry_6_latestID,
iqentry_source[7] = | iqentry_7_latestID;
 
 
//assign iqentry_0_islot = iqentry_islot[0];
//assign iqentry_1_islot = iqentry_islot[1];
//assign iqentry_2_islot = iqentry_islot[2];
//assign iqentry_3_islot = iqentry_islot[3];
//assign iqentry_4_islot = iqentry_islot[4];
//assign iqentry_5_islot = iqentry_islot[5];
//assign iqentry_6_islot = iqentry_islot[6];
//assign iqentry_7_islot = iqentry_islot[7];
 
// A single instruction can require 3 read ports. Only a total of four read
// ports are supported because most of the time that's enough.
// If there aren't enough read ports available then the second instruction
// isn't enqueued (it'll be enqueued in the next cycle).
reg [1:0] ports_avail; // available read ports for instruction #3.
reg [6:0] pRa0,pRb0,pRa1,pRb1,pRt0,pRt1;
wire [DBW-1:0] prfoa0,prfob0,prfoa1,prfob1;
wire [DBW-1:0] prfot0,prfot1;
 
wire [6:0] Ra0 = fnRa(fetchbuf0_instr);
wire [6:0] Rb0 = fnRb(fetchbuf0_instr);
wire [6:0] Rc0 = fnRc(fetchbuf0_instr);
wire [6:0] Ra1 = fnRa(fetchbuf1_instr);
wire [6:0] Rb1 = fnRb(fetchbuf1_instr);
wire [6:0] Rc1 = fnRc(fetchbuf1_instr);
wire [6:0] Rt0 = fnTargetReg(fetchbuf0_instr);
wire [6:0] Rt1 = fnTargetReg(fetchbuf1_instr);
always @*
begin
pRt0 = Rt0;
pRt1 = Rt1;
rfot0 = prfot0;
rfot1 = prfot1;
case(fetchbuf0_v ? fnNumReadPorts(fetchbuf0_instr) : 2'd0)
2'd0: begin
pRa0 = 7'd0;
pRb0 = Rc1;
pRa1 = Ra1;
pRb1 = Rb1;
rfoa0 = 64'd0;
rfob0 = 64'd0;
rfoc0 = 64'd0;
rfoa1 = prfoa1;
rfob1 = prfob1;
rfoc1 = prfob0;
ports_avail = 2'd3;
end
2'd1: begin
pRa0 = Ra0;
pRb0 = Rc1;
pRa1 = Ra1;
pRb1 = Rb1;
rfoa0 = prfoa0;
rfob0 = 64'd0;
rfoc0 = 64'd0;
rfoa1 = prfoa1;
rfob1 = prfob1;
rfoc1 = prfob0;
ports_avail = 2'd3;
end
2'd2: begin
pRa0 = Ra0;
pRb0 = Rb0;
pRa1 = Ra1;
pRb1 = Rb1;
rfoa0 = prfoa0;
rfob0 = prfob0;
rfoc0 = 64'd0;
rfoa1 = prfoa1;
rfob1 = prfob1;
rfoc1 = 64'd0;
ports_avail = 2'd2;
end
2'd3: begin
pRa0 = Ra0;
pRb0 = Rb0;
pRa1 = Rc0;
pRb1 = Ra1;
rfoa0 = prfoa0;
rfob0 = prfob0;
rfoc0 = prfoa1;
rfoa1 = prfob1;
rfob1 = 64'd0;
rfoc1 = 64'd0;
ports_avail = 2'd1;
end
endcase
end
 
/*
wire [8:0] Rb0 = ((fnNumReadPorts(fetchbuf0_instr) < 3'd2) || !fetchbuf0_v) ? {1'b0,fetchbuf1_instr[`INSTRUCTION_RC]} :
fnRb(fetchbuf0_instr);
wire [8:0] Ra1 = (!fetchbuf0_v || fnNumReadPorts(fetchbuf0_instr) < 3'd3) ? fnRa(fetchbuf1_instr) :
fetchbuf0_instr[`INSTRUCTION_RC];
wire [8:0] Rb1 = (fnNumReadPorts(fetchbuf1_instr) < 3'd2 && fetchbuf0_v) ? fnRa(fetchbuf1_instr):fnRb(fetchbuf1_instr);
*/
function [7:0] fnOpcode;
input [63:0] ins;
fnOpcode = (ins[3:0]==4'h0 && ins[7:4] > 4'h1 && ins[7:4] < 4'h9) ? `IMM :
ins[7:0]==8'h10 ? `NOP :
ins[7:0]==8'h11 ? `RTS : ins[15:8];
endfunction
 
wire [7:0] opcode0 = fnOpcode(fetchbuf0_instr);
wire [7:0] opcode1 = fnOpcode(fetchbuf1_instr);
wire [3:0] cond0 = fetchbuf0_instr[3:0];
wire [3:0] cond1 = fetchbuf1_instr[3:0];
wire [3:0] Pn0 = fetchbuf0_instr[7:4];
wire [3:0] Pt0 = fetchbuf0_instr[11:8];
wire [3:0] Pn1 = fetchbuf1_instr[7:4];
wire [3:0] Pt1 = fetchbuf1_instr[11:8];
 
function [6:0] fnRa;
input [63:0] insn;
case(insn[7:0])
8'h11: fnRa = 7'h51; // RTS short form
default:
case(insn[15:8])
`RTI: fnRa = 7'h5E;
`RTD: fnRa = 7'h5B;
`RTE: fnRa = 7'h5D;
`JSR,`JSRS,`JSRZ,`SYS,`INT,`RTS,`RTS2:
fnRa = {3'h5,insn[23:20]};
`TLB: fnRa = {1'b0,insn[29:24]};
`P: fnRa = 7'h70;
// `PUSH,`PEA,`POP,`LINK: fnRa = 7'd27;
default: fnRa = {1'b0,insn[`INSTRUCTION_RA]};
endcase
endcase
endfunction
 
function [6:0] fnRb;
input [63:0] insn;
if (insn[7:0]==8'h11) // RTS short form
fnRb = 7'h51;
else
case(insn[15:8])
`RTI: fnRb = 7'h5E;
`RTD: fnRb = 7'h5B;
`RTE: fnRb = 7'h5D;
`RTS2: fnRb = 7'd27;
`RTS,`STP,`TLB,`POP: fnRb = 7'd0;
`LOOP: fnRb = 7'h73;
`JSR,`JSRS,`JSRZ,`SYS,`INT:
fnRb = {3'h5,insn[23:20]};
`SWS: fnRb = {1'b1,insn[27:22]};
`ifdef STACKOPS
`PUSH: fnRb = insn[22:16];
`LINK: fnRb = {1'b0,insn[27:22]};
`PEA: fnRb = {1'b0,insn[21:16]};
`endif
default: fnRb = {1'b0,insn[`INSTRUCTION_RB]};
endcase
endfunction
 
function [6:0] fnRc;
input [63:0] insn;
fnRc = {1'b0,insn[`INSTRUCTION_RC]};
endfunction
 
function [3:0] fnCar;
input [63:0] insn;
if (insn[7:0]==8'h11) // RTS short form
fnCar = 4'h1;
else
case(insn[15:8])
`RTI: fnCar = 4'hE;
`RTD: fnCar = 4'hB;
`RTE: fnCar = 4'hD;
`JSR,`JSRS,`JSRZ,`SYS,`INT,`RTS,`RTS2:
fnCar = {insn[23:20]};
default: fnCar = 4'h0;
endcase
endfunction
 
function [5:0] fnFunc;
input [63:0] insn;
if (insn[7:0]==8'h11) // RTS short form
fnFunc = 6'h00; // func is used as a small immediate
else
casex(insn[15:8])
`BITFIELD: fnFunc = insn[43:40];
`CMP: fnFunc = insn[31:28];
`TST: fnFunc = insn[23:22];
`INC: fnFunc = insn[24:22];
`RTS,`RTS2: fnFunc = insn[19:16]; // used to pass a small immediate
`CACHE: fnFunc = insn[31:26];
default:
fnFunc = insn[39:34];
endcase
endfunction
 
// Returns true if the operation is limited to ALU #0
function fnIsAlu0Op;
input [7:0] opcode;
input [5:0] func;
case(opcode)
`R:
case(func)
`CNTLZ,`CNTLO,`CNTPOP: fnIsAlu0Op = `TRUE;
`ABS,`SGN,`ZXB,`ZXC,`ZXH,`SXB,`SXC,`SXH: fnIsAlu0Op = `TRUE;
default: fnIsAlu0Op = `FALSE;
endcase
`RR:
case(func)
`DIV,`DIVU: fnIsAlu0Op = `TRUE;
`MIN,`MAX: fnIsAlu0Op = `TRUE;
default: fnIsAlu0Op = `FALSE;
endcase
`BCD: fnIsAlu0Op = `TRUE;
`DIVI,`DIVUI: fnIsAlu0Op = `TRUE;
//`DOUBLE: fnIsAlu0Op = `TRUE;
`SHIFT: fnIsAlu0Op = `TRUE;
`BITFIELD: fnIsAlu0Op = `TRUE;
default: fnIsAlu0Op = `FALSE;
endcase
endfunction
 
// Returns TRUE if the alu will be valid immediately
//
function fnAluValid;
input [7:0] opcode;
input [5:0] func;
case(opcode)
`R: fnAluValid = `TRUE;
`RR:
case(func)
`MUL,`MULU,`DIV,`DIVU: fnAluValid = `FALSE;
default: fnAluValid = `TRUE;
endcase
`MULI,`MULUI,`DIVI,`DIVUI: fnAluValid = `FALSE;
default: fnAluValid = `TRUE;
endcase
endfunction
 
Thor_regfile2w6r #(DBW) urf1
(
.clk(clk),
.rclk(~clk),
.wr0(commit0_v && ~commit0_tgt[6] && iqentry_op[head0]!=`MTSPR),
.wr1(commit1_v && ~commit1_tgt[6] && iqentry_op[head1]!=`MTSPR),
.wa0(commit0_tgt[5:0]),
.wa1(commit1_tgt[5:0]),
.ra0(pRa0[5:0]),
.ra1(pRb0[5:0]),
.ra2(pRa1[5:0]),
.ra3(pRb1[5:0]),
.ra4(pRt0[5:0]),
.ra5(pRt1[5:0]),
.i0(commit0_bus),
.i1(commit1_bus),
.o0(prfoa0),
.o1(prfob0),
.o2(prfoa1),
.o3(prfob1),
.o4(prfot0),
.o5(prfot1)
);
 
wire [63:0] cregs0 = fnCar(fetchbuf0_instr)==4'd0 ? 64'd0 : fnCar(fetchbuf0_instr)==4'hF ? fetchbuf0_pc : cregs[fnCar(fetchbuf0_instr)];
wire [63:0] cregs1 = fnCar(fetchbuf1_instr)==4'd0 ? 64'd0 : fnCar(fetchbuf1_instr)==4'hF ? fetchbuf1_pc : cregs[fnCar(fetchbuf1_instr)];
//
// 1 if the the operand is automatically valid,
// 0 if we need a RF value
function fnSource1_v;
input [7:0] opcode;
casex(opcode)
`SEI,`CLI,`MEMSB,`MEMDB,`SYNC,`NOP,`STP:
fnSource1_v = 1'b1;
`BR,`LOOP: fnSource1_v = 1'b1;
`LDI,`LDIS,`IMM: fnSource1_v = 1'b1;
default: fnSource1_v = 1'b0;
endcase
endfunction
 
//
// 1 if the the operand is automatically valid,
// 0 if we need a RF value
function fnSource2_v;
input [7:0] opcode;
input [5:0] func;
casex(opcode)
`R,`P: fnSource2_v = 1'b1;
`LDI,`STI,`LDIS,`IMM,`NOP,`STP: fnSource2_v = 1'b1;
`SEI,`CLI,`MEMSB,`MEMDB,`SYNC:
fnSource2_v = 1'b1;
`RTI,`RTD,`RTE: fnSource2_v = 1'b1;
`TST: fnSource2_v = 1'b1;
`ADDI,`ADDUI,`ADDUIS:
fnSource2_v = 1'b1;
`_2ADDUI,`_4ADDUI,`_8ADDUI,`_16ADDUI:
fnSource2_v = 1'b1;
`SUBI,`SUBUI: fnSource2_v = 1'b1;
`CMPI: fnSource2_v = 1'b1;
`MULI,`MULUI,`DIVI,`DIVUI:
fnSource2_v = 1'b1;
`ANDI,`BITI: fnSource2_v = 1'b1;
`ORI: fnSource2_v = 1'b1;
`EORI: fnSource2_v = 1'b1;
`SHIFT:
if (func>=6'h10)
fnSource2_v = `TRUE;
else
fnSource2_v = `FALSE;
`CACHE,`LCL,`TLB,
`LVB,`LVC,`LVH,`LVW,`LVWAR,
`LB,`LBU,`LC,`LCU,`LH,`LHU,`LW,`LWS,`LEA,`STI,`INC:
fnSource2_v = 1'b1;
`JSR,`JSRS,`JSRZ,`SYS,`INT,`RTS,`BR:
fnSource2_v = 1'b1;
`MTSPR,`MFSPR,`POP,`UNLINK:
fnSource2_v = 1'b1;
// `BFSET,`BFCLR,`BFCHG,`BFEXT,`BFEXTU: // but not BFINS
// fnSource2_v = 1'b1;
default: fnSource2_v = 1'b0;
endcase
endfunction
 
 
// Source #3 valid
// Since most instructions don't use a third source the default it to return
// a valid status.
// 1 if the the operand is automatically valid,
// 0 if we need a RF value
function fnSource3_v;
input [7:0] opcode;
casex(opcode)
`SBX,`SCX,`SHX,`SWX,`CAS,`STMV,`STCMP,`STFND: fnSource3_v = 1'b0;
`MUX: fnSource3_v = 1'b0;
default: fnSource3_v = 1'b1;
endcase
endfunction
 
function fnSourceT_v;
input [7:0] opcode;
casex(opcode)
`BR,
`SB,`SC,`SH,`SW,`SBX,`SCX,`SHX,`SWX,`SWS,
`CACHE,
`SEI,`CLI,`NOP,`STP,
`MEMSB,`MEMDB,`SYNC:
fnSourceT_v = 1'b1;
default: fnSourceT_v = 1'b0;
endcase
endfunction
 
// Return the number of register read ports required for an instruction.
function [2:0] fnNumReadPorts;
input [63:0] ins;
casex(fnOpcode(ins))
`SEI,`CLI,`MEMSB,`MEMDB,`SYNC,`NOP,`MOVS,`STP:
fnNumReadPorts = 3'd0;
`BR: fnNumReadPorts = 3'd0;
`LOOP: fnNumReadPorts = 3'd0;
`LDI,`LDIS,`IMM: fnNumReadPorts = 3'd0;
`R,`P,`STI: fnNumReadPorts = 3'd1;
`RTI,`RTD,`RTE: fnNumReadPorts = 3'd1;
`TST: fnNumReadPorts = 3'd1;
`ADDI,`ADDUI,`ADDUIS:
fnNumReadPorts = 3'd1;
`_2ADDUI,`_4ADDUI,`_8ADDUI,`_16ADDUI:
fnNumReadPorts = 3'd1;
`SUBI,`SUBUI: fnNumReadPorts = 3'd1;
`CMPI: fnNumReadPorts = 3'd1;
`MULI,`MULUI,`DIVI,`DIVUI:
fnNumReadPorts = 3'd1;
`BITI,
`ANDI,`ORI,`EORI: fnNumReadPorts = 3'd1;
`SHIFT:
if (ins[39:38]==2'h1) // shift immediate
fnNumReadPorts = 3'd1;
else
fnNumReadPorts = 3'd2;
`RTS2,`CACHE,`LCL,`TLB,
`LB,`LBU,`LC,`LCU,`LH,`LHU,`LW,`LVB,`LVC,`LVH,`LVW,`LVWAR,`LWS,`LEA,`INC:
fnNumReadPorts = 3'd1;
`JSR,`JSRS,`JSRZ,`SYS,`INT,`RTS,`BR,`LOOP:
fnNumReadPorts = 3'd1;
`SBX,`SCX,`SHX,`SWX,
`MUX,`CAS,`STMV,`STCMP:
fnNumReadPorts = 3'd3;
`MTSPR,`MFSPR,`POP,`UNLINK: fnNumReadPorts = 3'd1;
`STFND: fnNumReadPorts = 3'd2; // *** TLB reads on Rb we say 2 for simplicity
`BITFIELD:
case(ins[43:40])
`BFSET,`BFCLR,`BFCHG,`BFEXT,`BFEXTU:
fnNumReadPorts = 3'd1;
`BFINS: fnNumReadPorts = 3'd2;
default: fnNumReadPorts = 3'd0;
endcase
default: fnNumReadPorts = 3'd2;
endcase
endfunction
 
function fnIsBranch;
input [7:0] opcode;
casex(opcode)
`BR: fnIsBranch = `TRUE;
default: fnIsBranch = `FALSE;
endcase
endfunction
 
function fnIsPush;
input [63:0] insn;
fnIsPush = insn[15:8]==`PUSH || insn[15:8]==`PEA;
endfunction
 
function fnIsPop;
input [63:0] insn;
fnIsPop = insn[15:8]==`POP;
endfunction
 
function fnIsStoreString;
input [7:0] opcode;
fnIsStoreString =
opcode==`STS;
endfunction
 
wire xbr = (iqentry_op[head0]==`BR) || (iqentry_op[head1]==`BR);
wire takb = (iqentry_op[head0]==`BR) ? commit0_v : commit1_v;
wire [DBW-1:0] xbrpc = (iqentry_op[head0]==`BR) ? iqentry_pc[head0] : iqentry_pc[head1];
 
wire predict_takenA,predict_takenB,predict_takenC,predict_takenD;
 
// There are really only two branch tables required one for fetchbuf0 and one
// for fetchbuf1. Synthesis removes the extra tables.
//
Thor_BranchHistory #(DBW) ubhtA
(
.rst(rst_i),
.clk(clk),
.advanceX(xbr),
.xisBranch(xbr),
.pc(pc),
.xpc(xbrpc),
.takb(takb),
.predict_taken(predict_takenA)
);
 
Thor_BranchHistory #(DBW) ubhtB
(
.rst(rst_i),
.clk(clk),
.advanceX(xbr),
.xisBranch(xbr),
.pc(pc+fnInsnLength(insn)),
.xpc(xbrpc),
.takb(takb),
.predict_taken(predict_takenB)
);
 
Thor_BranchHistory #(DBW) ubhtC
(
.rst(rst_i),
.clk(clk),
.advanceX(xbr),
.xisBranch(xbr),
.pc(pc),
.xpc(xbrpc),
.takb(takb),
.predict_taken(predict_takenC)
);
 
Thor_BranchHistory #(DBW) ubhtD
(
.rst(rst_i),
.clk(clk),
.advanceX(xbr),
.xisBranch(xbr),
.pc(pc+fnInsnLength(insn)),
.xpc(xbrpc),
.takb(takb),
.predict_taken(predict_takenD)
);
 
`ifdef THREEWAY
Thor_BranchHistory #(DBW) ubhtE
(
.rst(rst_i),
.clk(clk),
.advanceX(xbr),
.xisBranch(xbr),
.pc(pc+fnInsnLength(insn)+fnInsnLength1(insn)),
.xpc(xbrpc),
.takb(takb),
.predict_taken(predict_takenE)
);
Thor_BranchHistory #(DBW) ubhtF
(
.rst(rst_i),
.clk(clk),
.advanceX(xbr),
.xisBranch(xbr),
.pc(pc+fnInsnLength(insn)+fnInsnLength1(insn)),
.xpc(xbrpc),
.takb(takb),
.predict_taken(predict_takenF)
);
`endif
 
Thor_icachemem #(DBW) uicm1
(
.wclk(clk),
.wce(cstate==ICACHE1),
.wr(ack_i|err_i),
.wa(adr_o),
.wd({err_i,dat_i}),
.rclk(~clk),
.pc(ppc),
.insn(insn)
);
 
wire hit0,hit1;
reg ic_ld;
reg [31:0] ic_ld_cntr;
Thor_itagmem #(DBW-1) uitm1
(
.wclk(clk),
.wce((cstate==ICACHE1 && cti_o==3'b111)|ic_ld),
.wr(ack_i|err_i|ic_ld),
.wa(adr_o|ic_ld_cntr),
.err_i(err_i|ierr),
.invalidate(ic_invalidate),
.invalidate_line(ic_invalidate_line),
.invalidate_lineno(ic_lineno),
.rclk(~clk),
.rce(1'b1),
.pc(ppc),
.hit0(hit0),
.hit1(hit1),
.err_o(insnerr)
);
 
wire ihit = hit0 & hit1;
wire do_pcinc = ihit;// && !((nmi_edge & ~StatusHWI & ~int_commit) || (irq_i & ~im & ~StatusHWI & ~int_commit));
wire ld_fetchbuf = ihit || (nmi_edge & !StatusHWI)||(irq_i & ~im & !StatusHWI);
 
wire whit;
 
Thor_dcachemem_1w1r #(DBW) udcm1
(
.wclk(clk),
.wce(whit || cstate==DCACHE1),
.wr(ack_i|err_i),
.sel(whit ? sel_o : 8'hFF),
.wa(adr_o),
.wd(whit ? dat_o : dat_i),
.rclk(~clk),
.rce(1'b1),
.ra(pea),
.o(cdat)
);
 
Thor_dtagmem #(DBW-1) udtm1
(
.wclk(clk),
.wce(cstate==DCACHE1 && cti_o==3'b111),
.wr(ack_i|err_i),
.wa(adr_o),
.err_i(err_i|derr),
.invalidate(dc_invalidate),
.invalidate_line(dc_invalidate_line),
.invalidate_lineno(dc_lineno),
.rclk(~clk),
.rce(1'b1),
.ra(pea),
.whit(whit),
.rhit(rhit),
.err_o()
);
 
wire [DBW-1:0] shfto0,shfto1;
 
function fnIsShiftiop;
input [63:0] insn;
fnIsShiftiop = insn[15:8]==`SHIFT && (
insn[39:34]==`SHLI || insn[39:34]==`SHLUI ||
insn[39:34]==`SHRI || insn[39:34]==`SHRUI ||
insn[39:34]==`ROLI || insn[39:34]==`RORI
)
;
endfunction
 
function fnIsShiftop;
input [7:0] opcode;
fnIsShiftop = opcode==`SHL || opcode==`SHLI || opcode==`SHLU || opcode==`SHLUI ||
opcode==`SHR || opcode==`SHRI || opcode==`SHRU || opcode==`SHRUI ||
opcode==`ROL || opcode==`ROLI || opcode==`ROR || opcode==`RORI
;
endfunction
 
function fnIsFP;
input [7:0] opcode;
fnIsFP = opcode==`DOUBLE_R||opcode==`FLOAT||opcode==`SINGLE_R;
// opcode==`ITOF || opcode==`FTOI || opcode==`FNEG || opcode==`FSIGN || /*opcode==`FCMP || */ opcode==`FABS ||
// opcode==`FADD || opcode==`FSUB || opcode==`FMUL || opcode==`FDIV
// ;
endfunction
 
function fnIsFPCtrl;
input [63:0] insn;
fnIsFPCtrl = (insn[15:8]==`SINGLE_R && (insn[31:28]==`FTX||insn[31:28]==`FCX||insn[31:28]==`FDX||insn[31:28]==`FEX)) ||
(insn[15:8]==`DOUBLE_R && (insn[31:28]==`FRM))
;
endfunction
 
function fnIsBitfield;
input [7:0] opcode;
fnIsBitfield = opcode==`BFSET || opcode==`BFCLR || opcode==`BFCHG || opcode==`BFINS || opcode==`BFEXT || opcode==`BFEXTU;
endfunction
 
//wire [3:0] Pn = ir[7:4];
 
// Set the target register
// 00-3F = general register file
// 40-4F = predicate register
// 50-5F = code address register
// 60-67 = segment base register
// 70 = predicate register horizontal
// 73 = loop counter
function [6:0] fnTargetReg;
input [63:0] ir;
begin
if (ir[3:0]==4'h0) // Process special predicates
fnTargetReg = 7'h000;
else
casex(fnOpcode(ir))
`POP: fnTargetReg = ir[22:16];
`LDI,`ADDUIS,`STS,`LINK,`UNLINK:
fnTargetReg = {1'b0,ir[21:16]};
`LDIS:
fnTargetReg = {1'b1,ir[21:16]};
`RR:
fnTargetReg = {1'b0,ir[33:28]};
`BCD,
`LOGIC,`FLOAT,
`LWX,`LBX,`LBUX,`LCX,`LCUX,`LHX,`LHUX,`STMV,`STCMP,`STFND:
fnTargetReg = {1'b0,ir[33:28]};
`SHIFT:
fnTargetReg = {1'b0,ir[33:28]};
`R,`DOUBLE_R,`SINGLE_R,
`ADDI,`ADDUI,`SUBI,`SUBUI,`MULI,`MULUI,`DIVI,`DIVUI,
`_2ADDUI,`_4ADDUI,`_8ADDUI,`_16ADDUI,
`ANDI,`ORI,`EORI,
`LVB,`LVC,`LVH,`LVW,`LVWAR,
`LB,`LBU,`LC,`LCU,`LH,`LHU,`LW,`LEA,`LINK:
fnTargetReg = {1'b0,ir[27:22]};
`CAS:
fnTargetReg = {1'b0,ir[39:34]};
`BITFIELD:
fnTargetReg = {1'b0,ir[27:22]};
`TLB:
if (ir[19:16]==`TLB_RDREG)
fnTargetReg = {1'b0,ir[29:24]};
else
fnTargetReg = 7'h00;
`MFSPR:
fnTargetReg = {1'b0,ir[27:22]};
`BITI:
fnTargetReg = {3'h4,ir[25:22]};
`CMP,`CMPI,`TST:
begin
fnTargetReg = {3'h4,ir[11:8]};
end
`SWCR: fnTargetReg = {3'h4,4'h0};
`JSR,`JSRZ,`JSRS,`SYS,`INT:
fnTargetReg = {3'h5,ir[19:16]};
`MTSPR,`MOVS,`LWS:
fnTargetReg = {1'b1,ir[27:22]};
/*
if (ir[27:26]==2'h1) // Move to code address register
fnTargetReg = {3'h5,ir[25:22]};
else if (ir[27:26]==2'h2) // Move to seg. reg.
fnTargetReg = {3'h6,ir[25:22]};
else if (ir[27:22]==6'h04)
fnTargetReg = 7'h70;
else
fnTargetReg = 7'h00;
*/
`RTS2: fnTargetReg = 7'd27;
`LOOP: fnTargetReg = 7'h73;
`STP: fnTargetReg = 7'h7F;
`P: fnTargetReg = 7'h70;
default: fnTargetReg = 7'h00;
endcase
end
endfunction
/*
function fnAllowedReg;
input [8:0] regno;
fnAllowedReg = allowedRegs[regno] ? regno : 9'h000;
endfunction
*/
function fnTargetsCa;
input [63:0] ir;
begin
if (ir[3:0]==4'h0)
fnTargetsCa = `FALSE;
else begin
case(fnOpcode(ir))
`JSR,`JSRZ,`JSRS,`SYS,`INT:
fnTargetsCa = `TRUE;
`LWS:
if (ir[27:26]==2'h1)
fnTargetsCa = `TRUE;
else
fnTargetsCa = `FALSE;
`LDIS:
if (ir[21:20]==2'h1)
fnTargetsCa = `TRUE;
else
fnTargetsCa = `FALSE;
`MTSPR,`MOVS:
begin
if (ir[27:26]==2'h1)
fnTargetsCa = `TRUE;
else
fnTargetsCa = `FALSE;
end
default: fnTargetsCa = `FALSE;
endcase
end
end
endfunction
 
function fnTargetsSegreg;
input [63:0] ir;
if (ir[3:0]==4'h0)
fnTargetsSegreg = `FALSE;
else
case(fnOpcode(ir))
`LWS:
if (ir[27:26]==2'h2)
fnTargetsSegreg = `TRUE;
else
fnTargetsSegreg = `FALSE;
`LDIS:
if (ir[21:20]==2'h2)
fnTargetsSegreg = `TRUE;
else
fnTargetsSegreg = `FALSE;
`MTSPR,`MOVS:
if (ir[27:26]==2'h2)
fnTargetsSegreg = `TRUE;
else
fnTargetsSegreg = `FALSE;
default: fnTargetsSegreg = `FALSE;
endcase
endfunction
 
function fnHasConst;
input [7:0] opcode;
casex(opcode)
`BFCLR,`BFSET,`BFCHG,`BFEXT,`BFEXTU,`BFINS,
`LDI,`LDIS,`ADDUIS,
`ADDI,`SUBI,`ADDUI,`SUBUI,`MULI,`MULUI,`DIVI,`DIVUI,
`_2ADDUI,`_4ADDUI,`_8ADDUI,`_16ADDUI,
`CMPI,
`ANDI,`ORI,`EORI,`BITI,
// `SHLI,`SHLUI,`SHRI,`SHRUI,`ROLI,`RORI,
`LB,`LBU,`LC,`LCU,`LH,`LHU,`LW,`LWS,`LEA,`INC,
`LVB,`LVC,`LVH,`LVW,`LVWAR,`STI,
`SB,`SC,`SH,`SW,`SWCR,`CAS,`SWS,
`JSR,`JSRS,`SYS,`INT,`BR,`RTS2,`LOOP,`PEA,`LINK,`UNLINK:
fnHasConst = 1'b1;
default:
fnHasConst = 1'b0;
endcase
endfunction
 
function fnIsFlowCtrl;
input [7:0] opcode;
begin
casex(opcode)
`JSR,`JSRS,`JSRZ,`SYS,`INT,`LOOP,`BR,`RTS,`RTS2,`RTI,`RTD,`RTE:
fnIsFlowCtrl = 1'b1;
default: fnIsFlowCtrl = 1'b0;
endcase
end
endfunction
 
// fnCanException
// Used by issue logic.
// Returns TRUE if the instruction can cause an exception
//
function fnCanException;
input [7:0] op;
input [5:0] func;
case(op)
`FLOAT:
case(func)
`FDIVS,`FMULS,`FADDS,`FSUBS,
`FDIV,`FMUL,`FADD,`FSUB:
fnCanException = `TRUE;
endcase
`SINGLE_R:
if (func==`FTX) fnCanException = `TRUE;
`ADD,`ADDI,`SUB,`SUBI,`DIV,`DIVI,`MUL,`MULI:
fnCanException = `TRUE;
`TLB,`RTI,`RTD,`RTE,`CLI,`SEI:
fnCanException = `TRUE;
default:
fnCanException = fnIsMem(op);
endcase
endfunction
 
// fnInsnLength
// Used by fetch logic.
// Return the length of an instruction.
//
function [3:0] fnInsnLength;
input [127:0] insn;
casex(insn[15:0])
16'bxxxxxxxx00000000: fnInsnLength = 4'd1; // BRK
16'bxxxxxxxx00010000: fnInsnLength = 4'd1; // NOP
16'bxxxxxxxx00100000: fnInsnLength = 4'd2;
16'bxxxxxxxx00110000: fnInsnLength = 4'd3;
16'bxxxxxxxx01000000: fnInsnLength = 4'd4;
16'bxxxxxxxx01010000: fnInsnLength = 4'd5;
16'bxxxxxxxx01100000: fnInsnLength = 4'd6;
16'bxxxxxxxx01110000: fnInsnLength = 4'd7;
16'bxxxxxxxx10000000: fnInsnLength = 4'd8;
16'bxxxxxxxx00010001: fnInsnLength = 4'd1; // RTS short form
default:
casex(insn[15:8])
`NOP,`SEI,`CLI,`RTI,`RTD,`RTE,`MEMSB,`MEMDB,`SYNC:
fnInsnLength = 4'd2;
`TST,`BR,`JSRZ,`RTS,`CACHE,`LOOP,`PUSH,`POP,`UNLINK:
fnInsnLength = 4'd3;
`SYS,`CMP,`CMPI,`MTSPR,`MFSPR,`LDI,`LDIS,`ADDUIS,`R,`TLB,`MOVS,`RTS2,`STP:
fnInsnLength = 4'd4;
`BITFIELD,`JSR,`MUX,`BCD,`INC:
fnInsnLength = 4'd6;
`CAS:
fnInsnLength = 4'd6;
default:
fnInsnLength = 4'd5;
endcase
endcase
endfunction
 
function [3:0] fnInsnLength1;
input [127:0] insn;
case(fnInsnLength(insn))
4'd1: fnInsnLength1 = fnInsnLength(insn[127: 8]);
4'd2: fnInsnLength1 = fnInsnLength(insn[127:16]);
4'd3: fnInsnLength1 = fnInsnLength(insn[127:24]);
4'd4: fnInsnLength1 = fnInsnLength(insn[127:32]);
4'd5: fnInsnLength1 = fnInsnLength(insn[127:40]);
4'd6: fnInsnLength1 = fnInsnLength(insn[127:48]);
4'd7: fnInsnLength1 = fnInsnLength(insn[127:56]);
4'd8: fnInsnLength1 = fnInsnLength(insn[127:64]);
default: fnInsnLength1 = 4'd0;
endcase
endfunction
 
function [3:0] fnInsnLength2;
input [127:0] insn;
case(fnInsnLength(insn)+fnInsnLength1(insn))
4'd2: fnInsnLength2 = fnInsnLength(insn[127:16]);
4'd3: fnInsnLength2 = fnInsnLength(insn[127:24]);
4'd4: fnInsnLength2 = fnInsnLength(insn[127:32]);
4'd5: fnInsnLength2 = fnInsnLength(insn[127:40]);
4'd6: fnInsnLength2 = fnInsnLength(insn[127:48]);
4'd7: fnInsnLength2 = fnInsnLength(insn[127:56]);
4'd8: fnInsnLength2 = fnInsnLength(insn[127:64]);
4'd9: fnInsnLength2 = fnInsnLength(insn[127:72]);
4'd10: fnInsnLength2 = fnInsnLength(insn[127:80]);
4'd11: fnInsnLength2 = fnInsnLength(insn[127:88]);
4'd12: fnInsnLength2 = fnInsnLength(insn[127:96]);
4'd13: fnInsnLength2 = fnInsnLength(insn[127:104]);
4'd14: fnInsnLength2 = fnInsnLength(insn[127:112]);
4'd15: fnInsnLength2 = fnInsnLength(insn[127:120]);
default: fnInsnLength2 = 4'd0;
endcase
endfunction
 
wire [5:0] total_insn_length = fnInsnLength(insn) + fnInsnLength1(insn) + fnInsnLength2(insn);
wire [5:0] insn_length12 = fnInsnLength(insn) + fnInsnLength1(insn);
wire insn3_will_fit = total_insn_length < 6'd16;
 
always @(fetchbuf or fetchbufA_instr or fetchbufA_v or fetchbufA_pc
or fetchbufB_instr or fetchbufB_v or fetchbufB_pc
or fetchbufC_instr or fetchbufC_v or fetchbufC_pc
or fetchbufD_instr or fetchbufD_v or fetchbufD_pc
`ifdef THREEWAY
or fetchbufE_instr or fetchbufE_v or fetchbufE_pc
or fetchbufF_instr or fetchbufF_v or fetchbufF_pc
`endif
)
begin
fetchbuf0_instr <= (fetchbuf == 1'b0) ? fetchbufA_instr : fetchbufC_instr;
fetchbuf0_v <= (fetchbuf == 1'b0) ? fetchbufA_v : fetchbufC_v ;
if (int_pending && string_pc!=64'd0)
fetchbuf0_pc <= string_pc;
else
fetchbuf0_pc <= (fetchbuf == 1'b0) ? fetchbufA_pc : fetchbufC_pc ;
 
fetchbuf1_instr <= (fetchbuf == 1'b0) ? fetchbufB_instr : fetchbufD_instr;
fetchbuf1_v <= (fetchbuf == 1'b0) ? fetchbufB_v : fetchbufD_v ;
 
if (int_pending && string_pc != 64'd0)
fetchbuf1_pc <= string_pc;
else
fetchbuf1_pc <= (fetchbuf == 1'b0) ? fetchbufB_pc : fetchbufD_pc ;
end
 
wire [7:0] opcodeA = fetchbufA_instr[`OPCODE];
wire [7:0] opcodeB = fetchbufB_instr[`OPCODE];
wire [7:0] opcodeC = fetchbufC_instr[`OPCODE];
wire [7:0] opcodeD = fetchbufD_instr[`OPCODE];
 
function fnIsMem;
input [7:0] opcode;
fnIsMem = opcode==`LB || opcode==`LBU || opcode==`LC || opcode==`LCU || opcode==`LH || opcode==`LHU || opcode==`LW ||
opcode==`LBX || opcode==`LWX || opcode==`LBUX || opcode==`LHX || opcode==`LHUX || opcode==`LCX || opcode==`LCUX ||
opcode==`SB || opcode==`SC || opcode==`SH || opcode==`SW ||
opcode==`SBX || opcode==`SCX || opcode==`SHX || opcode==`SWX ||
opcode==`STS || opcode==`LCL ||
opcode==`LVB || opcode==`LVC || opcode==`LVH || opcode==`LVW || opcode==`LVWAR || opcode==`SWCR ||
opcode==`TLB || opcode==`CAS || opcode==`STMV || opcode==`STCMP || opcode==`STFND ||
opcode==`LWS || opcode==`SWS || opcode==`STI ||
opcode==`INC ||
opcode==`PUSH || opcode==`POP || opcode==`PEA || opcode==`LINK || opcode==`UNLINK
;
endfunction
 
function fnIsNdxd;
input [7:0] opcode;
fnIsNdxd = opcode==`LBX || opcode==`LWX || opcode==`LBUX || opcode==`LHX || opcode==`LHUX || opcode==`LCX || opcode==`LCUX ||
opcode==`SBX || opcode==`SCX || opcode==`SHX || opcode==`SWX
;
endfunction
 
// Determines which instruction write to the register file
function fnIsRFW;
input [7:0] opcode;
input [63:0] ir;
begin
fnIsRFW = // General registers
opcode==`LB || opcode==`LBU || opcode==`LC || opcode==`LCU || opcode==`LH || opcode==`LHU || opcode==`LW ||
opcode==`LBX || opcode==`LBUX || opcode==`LCX || opcode==`LCUX || opcode==`LHX || opcode==`LHUX || opcode==`LWX ||
opcode==`LVB || opcode==`LVH || opcode==`LVC || opcode==`LVW || opcode==`LVWAR || opcode==`SWCR ||
opcode==`RTS2 || opcode==`STP ||
opcode==`CAS || opcode==`LWS || opcode==`STMV || opcode==`STCMP || opcode==`STFND ||
opcode==`STS || opcode==`POP || opcode==`LINK || opcode==`UNLINK ||
opcode==`ADDI || opcode==`SUBI || opcode==`ADDUI || opcode==`SUBUI || opcode==`MULI || opcode==`MULUI || opcode==`DIVI || opcode==`DIVUI ||
opcode==`ANDI || opcode==`ORI || opcode==`EORI ||
opcode==`ADD || opcode==`SUB || opcode==`ADDU || opcode==`SUBU || opcode==`MUL || opcode==`MULU || opcode==`DIV || opcode==`DIVU ||
opcode==`AND || opcode==`OR || opcode==`EOR || opcode==`NAND || opcode==`NOR || opcode==`ENOR || opcode==`ANDC || opcode==`ORC ||
opcode==`SHIFT ||
opcode==`R || opcode==`RR || opcode==`LEA || opcode==`P ||
opcode==`LDI || opcode==`LDIS || opcode==`ADDUIS || opcode==`MFSPR ||
// Branch registers / Segment registers
((opcode==`MTSPR || opcode==`MOVS) /*&& (fnTargetsCa(ir) || fnTargetsSegreg(ir))*/) ||
opcode==`JSR || opcode==`JSRS || opcode==`JSRZ || opcode==`SYS || opcode==`INT ||
// predicate registers
(opcode[7:4] < 4'h3) ||
(opcode==`TLB && ir[19:16]==`TLB_RDREG) ||
opcode==`BCD
;
end
endfunction
 
function fnIsStore;
input [7:0] opcode;
fnIsStore = opcode==`SB || opcode==`SC || opcode==`SH || opcode==`SW ||
opcode==`SBX || opcode==`SCX || opcode==`SHX || opcode==`SWX ||
opcode==`STS || opcode==`SWCR ||
opcode==`SWS || opcode==`STI ||
opcode==`PUSH || opcode==`PEA || opcode==`LINK;
endfunction
 
function fnIsLoad;
input [7:0] opcode;
fnIsLoad = opcode==`LB || opcode==`LBU || opcode==`LC || opcode==`LCU || opcode==`LH || opcode==`LHU || opcode==`LW ||
opcode==`LBX || opcode==`LBUX || opcode==`LCX || opcode==`LCUX || opcode==`LHX || opcode==`LHUX || opcode==`LWX ||
opcode==`LVB || opcode==`LVC || opcode==`LVH || opcode==`LVW || opcode==`LVWAR || opcode==`LCL ||
opcode==`LWS || opcode==`UNLINK ||
opcode==`POP;
endfunction
 
function fnIsLoadV;
input [7:0] opcode;
fnIsLoadV = opcode==`LVB || opcode==`LVC || opcode==`LVH || opcode==`LVW || opcode==`LVWAR || opcode==`LCL;
endfunction
 
function fnIsIndexed;
input [7:0] opcode;
fnIsIndexed = opcode==`LBX || opcode==`LBUX || opcode==`LCX || opcode==`LCUX || opcode==`LHX || opcode==`LHUX || opcode==`LWX ||
opcode==`SBX || opcode==`SCX || opcode==`SHX || opcode==`SWX;
endfunction
 
// *** check these
function fnIsPFW;
input [7:0] opcode;
fnIsPFW = opcode[7:4]<4'h3 || opcode==`BITI || opcode==`P;//opcode==`CMP || opcode==`CMPI || opcode==`TST;
endfunction
 
function [7:0] fnSelect;
input [7:0] opcode;
input [5:0] fn;
input [DBW-1:0] adr;
begin
if (DBW==32)
case(opcode)
`STS,`STMV,`STCMP,`STFND,`INC:
case(fn[2:0])
3'd0:
case(adr[1:0])
3'd0: fnSelect = 8'h11;
3'd1: fnSelect = 8'h22;
3'd2: fnSelect = 8'h44;
3'd3: fnSelect = 8'h88;
endcase
3'd1:
case(adr[1])
1'd0: fnSelect = 8'h33;
1'd1: fnSelect = 8'hCC;
endcase
3'd2:
fnSelect = 8'hFF;
default: fnSelect = 8'h00;
endcase
`LB,`LBU,`LBX,`LBUX,`SB,`SBX,`LVB:
case(adr[1:0])
3'd0: fnSelect = 8'h11;
3'd1: fnSelect = 8'h22;
3'd2: fnSelect = 8'h44;
3'd3: fnSelect = 8'h88;
endcase
`LC,`LCU,`SC,`LVC,`LCX,`LCUX,`SCX:
case(adr[1])
1'd0: fnSelect = 8'h33;
1'd1: fnSelect = 8'hCC;
endcase
`LH,`LHU,`SH,`LVH,`LHX,`LHUX,`SHX:
fnSelect = 8'hFF;
`LW,`LWX,`SW,`SWCR,`LVW,`LVWAR,`SWX,`CAS,`LWS,`SWS,`STI,`LCL,
`PUSH,`PEA,`POP,`LINK,`UNLINK:
fnSelect = 8'hFF;
default: fnSelect = 8'h00;
endcase
else
case(opcode)
`STS,`STMV,`STCMP,`STFND,`INC:
case(fn[2:0])
3'd0:
case(adr[2:0])
3'd0: fnSelect = 8'h01;
3'd1: fnSelect = 8'h02;
3'd2: fnSelect = 8'h04;
3'd3: fnSelect = 8'h08;
3'd4: fnSelect = 8'h10;
3'd5: fnSelect = 8'h20;
3'd6: fnSelect = 8'h40;
3'd7: fnSelect = 8'h80;
endcase
3'd1:
case(adr[2:1])
2'd0: fnSelect = 8'h03;
2'd1: fnSelect = 8'h0C;
2'd2: fnSelect = 8'h30;
2'd3: fnSelect = 8'hC0;
endcase
3'd2:
case(adr[2])
1'b0: fnSelect = 8'h0F;
1'b1: fnSelect = 8'hF0;
endcase
3'd3:
fnSelect = 8'hFF;
default: fnSelect = 8'h00;
endcase
`LB,`LBU,`LBX,`SB,`LVB,`LBUX,`SBX:
case(adr[2:0])
3'd0: fnSelect = 8'h01;
3'd1: fnSelect = 8'h02;
3'd2: fnSelect = 8'h04;
3'd3: fnSelect = 8'h08;
3'd4: fnSelect = 8'h10;
3'd5: fnSelect = 8'h20;
3'd6: fnSelect = 8'h40;
3'd7: fnSelect = 8'h80;
endcase
`LC,`LCU,`SC,`LVC,`LCX,`LCUX,`SCX:
case(adr[2:1])
2'd0: fnSelect = 8'h03;
2'd1: fnSelect = 8'h0C;
2'd2: fnSelect = 8'h30;
2'd3: fnSelect = 8'hC0;
endcase
`LH,`LHU,`SH,`LVH,`LHX,`LHUX,`SHX:
case(adr[2])
1'b0: fnSelect = 8'h0F;
1'b1: fnSelect = 8'hF0;
endcase
`LW,`LWX,`SW,`SWCR,`LVW,`LVWAR,`SWX,`CAS,`LWS,`SWS,`STI,`LCL,
`PUSH,`PEA,`POP,`LINK,`UNLINK:
fnSelect = 8'hFF;
default: fnSelect = 8'h00;
endcase
end
endfunction
 
function [DBW-1:0] fnDatai;
input [7:0] opcode;
input [5:0] func;
input [DBW-1:0] dat;
input [7:0] sel;
begin
if (DBW==32)
case(opcode)
`STMV,`STCMP,`STFND,`INC:
case(func[2:0])
3'd0,3'd4:
case(sel[3:0])
4'h1: fnDatai = dat[7:0];
4'h2: fnDatai = dat[15:8];
4'h4: fnDatai = dat[23:16];
4'h8: fnDatai = dat[31:24];
default: fnDatai = {DBW{1'b1}};
endcase
3'd1,3'd5:
case(sel[3:0])
4'h3: fnDatai = dat[15:0];
4'hC: fnDatai = dat[31:16];
default: fnDatai = {DBW{1'b1}};
endcase
default:
fnDatai = dat[31:0];
endcase
`LB,`LBX,`LVB:
case(sel[3:0])
8'h1: fnDatai = {{24{dat[7]}},dat[7:0]};
8'h2: fnDatai = {{24{dat[15]}},dat[15:8]};
8'h4: fnDatai = {{24{dat[23]}},dat[23:16]};
8'h8: fnDatai = {{24{dat[31]}},dat[31:24]};
default: fnDatai = {DBW{1'b1}};
endcase
`LBU,`LBUX:
case(sel[3:0])
4'h1: fnDatai = dat[7:0];
4'h2: fnDatai = dat[15:8];
4'h4: fnDatai = dat[23:16];
4'h8: fnDatai = dat[31:24];
default: fnDatai = {DBW{1'b1}};
endcase
`LC,`LVC,`LCX:
case(sel[3:0])
4'h3: fnDatai = {{16{dat[15]}},dat[15:0]};
4'hC: fnDatai = {{16{dat[31]}},dat[31:16]};
default: fnDatai = {DBW{1'b1}};
endcase
`LCU,`LCUX:
case(sel[3:0])
4'h3: fnDatai = dat[15:0];
4'hC: fnDatai = dat[31:16];
default: fnDatai = {DBW{1'b1}};
endcase
`LH,`LHU,`LW,`LWX,`LVH,`LVW,`LVWAR,`LHX,`LHUX,`CAS,`LWS,`LCL,`POP,`UNLINK:
fnDatai = dat[31:0];
default: fnDatai = {DBW{1'b1}};
endcase
else
case(opcode)
`STMV,`STCMP,`STFND,`INC:
case(func[2:0])
3'd0,3'd4:
case(sel)
8'h01: fnDatai = dat[DBW*1/8-1:0];
8'h02: fnDatai = dat[DBW*2/8-1:DBW*1/8];
8'h04: fnDatai = dat[DBW*3/8-1:DBW*2/8];
8'h08: fnDatai = dat[DBW*4/8-1:DBW*3/8];
8'h10: fnDatai = dat[DBW*5/8-1:DBW*4/8];
8'h20: fnDatai = dat[DBW*6/8-1:DBW*5/8];
8'h40: fnDatai = dat[DBW*7/8-1:DBW*6/8];
8'h80: fnDatai = dat[DBW-1:DBW*7/8];
default: fnDatai = {DBW{1'b1}};
endcase
3'd1,3'd5:
case(sel)
8'h03: fnDatai = dat[DBW/4-1:0];
8'h0C: fnDatai = dat[DBW/2-1:DBW/4];
8'h30: fnDatai = dat[DBW*3/4-1:DBW/2];
8'hC0: fnDatai = dat[DBW-1:DBW*3/4];
default: fnDatai = {DBW{1'b1}};
endcase
3'd2,3'd6:
case(sel)
8'h0F: fnDatai = dat[DBW/2-1:0];
8'hF0: fnDatai = dat[DBW-1:DBW/2];
default: fnDatai = {DBW{1'b1}};
endcase
3'd3,3'd7: fnDatai = dat;
endcase
`LB,`LBX,`LVB:
case(sel)
8'h01: fnDatai = {{DBW*7/8{dat[DBW*1/8-1]}},dat[DBW*1/8-1:0]};
8'h02: fnDatai = {{DBW*7/8{dat[DBW*2/8-1]}},dat[DBW*2/8-1:DBW*1/8]};
8'h04: fnDatai = {{DBW*7/8{dat[DBW*3/8-1]}},dat[DBW*3/8-1:DBW*2/8]};
8'h08: fnDatai = {{DBW*7/8{dat[DBW*4/8-1]}},dat[DBW*4/8-1:DBW*3/8]};
8'h10: fnDatai = {{DBW*7/8{dat[DBW*5/8-1]}},dat[DBW*5/8-1:DBW*4/8]};
8'h20: fnDatai = {{DBW*7/8{dat[DBW*6/8-1]}},dat[DBW*6/8-1:DBW*5/8]};
8'h40: fnDatai = {{DBW*7/8{dat[DBW*7/8-1]}},dat[DBW*7/8-1:DBW*6/8]};
8'h80: fnDatai = {{DBW*7/8{dat[DBW-1]}},dat[DBW-1:DBW*7/8]};
default: fnDatai = {DBW{1'b1}};
endcase
`LBU,`LBUX:
case(sel)
8'h01: fnDatai = dat[DBW*1/8-1:0];
8'h02: fnDatai = dat[DBW*2/8-1:DBW*1/8];
8'h04: fnDatai = dat[DBW*3/8-1:DBW*2/8];
8'h08: fnDatai = dat[DBW*4/8-1:DBW*3/8];
8'h10: fnDatai = dat[DBW*5/8-1:DBW*4/8];
8'h20: fnDatai = dat[DBW*6/8-1:DBW*5/8];
8'h40: fnDatai = dat[DBW*7/8-1:DBW*6/8];
8'h80: fnDatai = dat[DBW-1:DBW*7/8];
default: fnDatai = {DBW{1'b1}};
endcase
`LC,`LVC,`LCX:
case(sel)
8'h03: fnDatai = {{DBW*3/4{dat[DBW/4-1]}},dat[DBW/4-1:0]};
8'h0C: fnDatai = {{DBW*3/4{dat[DBW/2-1]}},dat[DBW/2-1:DBW/4]};
8'h30: fnDatai = {{DBW*3/4{dat[DBW*3/4-1]}},dat[DBW*3/4-1:DBW/2]};
8'hC0: fnDatai = {{DBW*3/4{dat[DBW-1]}},dat[DBW-1:DBW*3/4]};
default: fnDatai = {DBW{1'b1}};
endcase
`LCU,`LCUX:
case(sel)
8'h03: fnDatai = dat[DBW/4-1:0];
8'h0C: fnDatai = dat[DBW/2-1:DBW/4];
8'h30: fnDatai = dat[DBW*3/4-1:DBW/2];
8'hC0: fnDatai = dat[DBW-1:DBW*3/4];
default: fnDatai = {DBW{1'b1}};
endcase
`LH,`LVH,`LHX:
case(sel)
8'h0F: fnDatai = {{DBW/2{dat[DBW/2-1]}},dat[DBW/2-1:0]};
8'hF0: fnDatai = {{DBW/2{dat[DBW-1]}},dat[DBW-1:DBW/2]};
default: fnDatai = {DBW{1'b1}};
endcase
`LHU,`LHUX:
case(sel)
8'h0F: fnDatai = dat[DBW/2-1:0];
8'hF0: fnDatai = dat[DBW-1:DBW/2];
default: fnDatai = {DBW{1'b1}};
endcase
`LW,`LWX,`LVW,`LVWAR,`CAS,`LWS,`LCL,`POP,`UNLINK:
case(sel)
8'hFF: fnDatai = dat;
default: fnDatai = {DBW{1'b1}};
endcase
default: fnDatai = {DBW{1'b1}};
endcase
end
endfunction
 
function [DBW-1:0] fnDatao;
input [7:0] opcode;
input [5:0] func;
input [DBW-1:0] dat;
if (DBW==32)
case(opcode)
`STMV,`INC:
case(func[2:0])
3'd0,3'd4: fnDatao = {4{dat[7:0]}};
3'd1,3'd5: fnDatao = {2{dat[15:8]}};
default: fnDatao = dat;
endcase
`SW,`SWCR,`SWX,`CAS,`SWS,`STI,
`PUSH,`PEA,`LINK: fnDatao = dat;
`SH,`SHX: fnDatao = dat;
`SC,`SCX: fnDatao = {2{dat[15:0]}};
`SB,`SBX: fnDatao = {4{dat[7:0]}};
default: fnDatao = dat;
endcase
else
case(opcode)
`STMV,`INC:
case(func[2:0])
3'd0,3'd4: fnDatao = {8{dat[DBW/8-1:0]}};
3'd1,3'd5: fnDatao = {4{dat[DBW/4-1:0]}};
3'd2,3'd6: fnDatao = {2{dat[DBW/2-1:0]}};
3'd3,3'd7: fnDatao = dat;
endcase
`SW,`SWCR,`SWX,`CAS,`SWS,`STI,
`PUSH,`PEA,`LINK: fnDatao = dat;
`SH,`SHX: fnDatao = {2{dat[DBW/2-1:0]}};
`SC,`SCX: fnDatao = {4{dat[DBW/4-1:0]}};
`SB,`SBX: fnDatao = {8{dat[DBW/8-1:0]}};
default: fnDatao = dat;
endcase
endfunction
 
assign fetchbuf0_mem = fetchbuf ? fnIsMem(opcodeC) : fnIsMem(opcodeA);
assign fetchbuf0_jmp = fnIsFlowCtrl(opcode0);
assign fetchbuf0_fp = fnIsFP(opcode0);
assign fetchbuf0_rfw = fetchbuf ? fnIsRFW(opcodeC,fetchbufC_instr) : fnIsRFW(opcodeA,fetchbufA_instr);
assign fetchbuf0_pfw = fetchbuf ? fnIsPFW(opcodeC) : fnIsPFW(opcodeA);
assign fetchbuf1_mem = fetchbuf ? fnIsMem(opcodeD) : fnIsMem(opcodeB);
assign fetchbuf1_jmp = fnIsFlowCtrl(opcode1);
assign fetchbuf1_fp = fnIsFP(opcode1);
assign fetchbuf1_rfw = fetchbuf ? fnIsRFW(opcodeD,fetchbufD_instr) : fnIsRFW(opcodeB,fetchbufB_instr);
assign fetchbuf1_pfw = fetchbuf ? fnIsPFW(opcodeD) : fnIsPFW(opcodeB);
 
wire predict_taken0 = fetchbuf ? predict_takenC : predict_takenA;
wire predict_taken1 = fetchbuf ? predict_takenD : predict_takenB;
//
// set branchback and backpc values ... ignore branches in fetchbuf slots not ready for enqueue yet
//
assign take_branch0 = ({fetchbuf0_v, fnIsBranch(opcode0), predict_taken0} == {`VAL, `TRUE, `TRUE}) ||
({fetchbuf0_v, opcode0==`LOOP} == {`VAL, `TRUE})
;
assign take_branch1 = ({fetchbuf1_v, fnIsBranch(opcode1), predict_taken1} == {`VAL, `TRUE, `TRUE}) ||
({fetchbuf1_v, opcode1==`LOOP} == {`VAL, `TRUE})
;
assign take_branch = take_branch0 || take_branch1
;
 
reg [DBW-1:0] branch_pc;// =
// ({fetchbuf0_v, fnIsBranch(opcode0), predict_taken0} == {`VAL, `TRUE, `TRUE}) ? (ihit ?
// fetchbuf0_pc + {{DBW-12{fetchbuf0_instr[11]}},fetchbuf0_instr[11:8],fetchbuf0_instr[23:16]} + 64'd3 : fetchbuf0_pc):
// (ihit ? fetchbuf1_pc + {{DBW-12{fetchbuf1_instr[11]}},fetchbuf1_instr[11:8],fetchbuf1_instr[23:16]} + 64'd3 : fetchbuf1_pc);
always @*
if (fnIsBranch(opcode0) && fetchbuf0_v && predict_taken0) begin
if (ihit)
branch_pc <= fetchbuf0_pc + {{ABW-12{fetchbuf0_instr[11]}},fetchbuf0_instr[11:8],fetchbuf0_instr[23:16]} + 64'd3;
else
branch_pc <= fetchbuf0_pc;
end
else if (opcode0==`LOOP && fetchbuf0_v) begin
if (ihit)
branch_pc <= fetchbuf0_pc + {{ABW-8{fetchbuf0_instr[23]}},fetchbuf0_instr[23:16]} + 64'd3;
else
branch_pc <= fetchbuf0_pc;
end
else if (fnIsBranch(opcode1) && fetchbuf1_v && predict_taken1) begin
if (ihit)
branch_pc <= fetchbuf1_pc + {{ABW-12{fetchbuf1_instr[11]}},fetchbuf1_instr[11:8],fetchbuf1_instr[23:16]} + 64'd3;
else
branch_pc <= fetchbuf1_pc;
end
else if (opcode1==`LOOP && fetchbuf1_v) begin
if (ihit)
branch_pc <= fetchbuf1_pc + {{ABW-8{fetchbuf1_instr[23]}},fetchbuf1_instr[23:16]} + 64'd3;
else
branch_pc <= fetchbuf1_pc;
end
else begin
branch_pc <= {{ABW-8{1'b1}},8'h80}; // set to something to prevent a latch
end
 
assign int_pending = (nmi_edge & ~StatusHWI & ~int_commit) || (irq_i & ~im & ~StatusHWI & ~int_commit);
 
assign mem_stringmiss = ((dram0_op==`STS || dram0_op==`STFND) && int_pending && lc != 0) ||
((dram0_op==`STMV || dram0_op==`STCMP) && int_pending && lc != 0 && stmv_flag);
 
// "Stream" interrupt instructions into the instruction stream until an INT
// instruction commits. This avoids the problem of an INT instruction being
// stomped on by a previous branch instruction.
// Populate the instruction buffers with INT instructions for a hardware interrupt
// Also populate the instruction buffers with a call to the instruction error vector
// if an error occurred during instruction load time.
// Translate the BRK opcode to a syscall.
 
// There is a one cycle delay in setting the StatusHWI that allowed an extra INT
// instruction to sneek into the queue. This is NOPped out by the int_commit
// signal.
 
// On a cache miss the instruction buffers are loaded with NOPs this prevents
// the PC from being trashed by invalid branch instructions.
reg [63:0] insn1a,insn2a;
reg [63:0] insn0,insn1,insn2;
always @*
//if (int_commit)
// insn0 <= {8{8'h10}}; // load with NOPs
//else
if (nmi_edge & ~StatusHWI & ~int_commit)
insn0 <= {8'hFE,8'hCE,8'hA6,8'h01,8'hFE,8'hCE,8'hA6,8'h01};
else if (ITLBMiss)
insn0 <= {8'hF9,8'hCE,8'hA6,8'h01,8'hF9,8'hCE,8'hA6,8'h01};
else if (insnerr)
insn0 <= {8'hFC,8'hCE,8'hA6,8'h01,8'hFC,8'hCE,8'hA6,8'h01};
else if (irq_i & ~im & ~StatusHWI & ~int_commit)
insn0 <= {vec_i,8'hCE,8'hA6,8'h01,vec_i,8'hCE,8'hA6,8'h01};
else if (ihit) begin
if (insn[7:0]==8'h00)
insn0 <= {8'h00,8'hCD,8'hA5,8'h01,8'h00,8'hCD,8'hA5,8'h01};
else
insn0 <= insn[63:0];
end
else
insn0 <= {8{8'h10}}; // load with NOPs
 
 
always @*
//if (int_commit)
// insn1 <= {8{8'h10}}; // load with NOPs
//else
if (nmi_edge & ~StatusHWI & ~int_commit)
insn1 <= {8'hFE,8'hCE,8'hA6,8'h01,8'hFE,8'hCE,8'hA6,8'h01};
else if (ITLBMiss)
insn1 <= {8'hF9,8'hCE,8'hA6,8'h01,8'hF9,8'hCE,8'hA6,8'h01};
else if (insnerr)
insn1 <= {8'hFC,8'hCE,8'hA6,8'h01,8'hFC,8'hCE,8'hA6,8'h01};
else if (irq_i & ~im & ~StatusHWI & ~int_commit)
insn1 <= {vec_i,8'hCE,8'hA6,8'h01,vec_i,8'hCE,8'hA6,8'h01};
else if (ihit) begin
if (insn1a[7:0]==8'h00)
insn1 <= {8'h00,8'hCD,8'hA5,8'h01,8'h00,8'hCD,8'hA5,8'h01};
else
insn1 <= insn1a;
end
else
insn1 <= {8{8'h10}}; // load with NOPs
 
 
// Find the second instruction in the instruction line.
always @(insn)
case(fnInsnLength(insn))
4'd1: insn1a <= insn[71: 8];
4'd2: insn1a <= insn[79:16];
4'd3: insn1a <= insn[87:24];
4'd4: insn1a <= insn[95:32];
4'd5: insn1a <= insn[103:40];
4'd6: insn1a <= insn[111:48];
4'd7: insn1a <= insn[119:56];
4'd8: insn1a <= insn[127:64];
default: insn1a <= {8{8'h10}}; // NOPs
endcase
 
// Return the immediate field of an instruction
function [63:0] fnImm;
input [127:0] insn;
casex(insn[15:0])
16'bxxxxxxxx00010001: // RTS short form
fnImm = 64'd0;
default:
casex(insn[15:8])
`P: fnImm = insn[33:16];
`CAS: fnImm = {{56{insn[47]}},insn[47:40]};
`BCD: fnImm = insn[47:40];
`TLB: fnImm = insn[23:16];
`LOOP: fnImm = {{56{insn[23]}},insn[23:16]};
`STP: fnImm = insn[31:16];
`JSR: fnImm = {{40{insn[47]}},insn[47:24]};
`JSRS: fnImm = {{48{insn[39]}},insn[39:24]};
`BITFIELD: fnImm = insn[47:32];
`SYS,`INT: fnImm = insn[31:24];
`RTS2: fnImm = {insn[31:27],3'b000};
`CMPI,`LDI,`LDIS,`ADDUIS:
fnImm = {{54{insn[31]}},insn[31:22]};
`RTS: fnImm = insn[19:16];
`RTD,`RTE,`RTI,`JSRZ,`STMV,`STCMP,`STFND,`CACHE,`STS: fnImm = 8'h00;
`STI: fnImm = {{58{insn[33]}},insn[33:28]};
//`LINK: fnImm = {insn[39:28],3'b000};
`LB,`LBU,`LC,`LCU,`LH,`LHU,`LW,`LVB,`LVC,`LVH,`LVW,`LVWAR,
`SB,`SC,`SH,`SW,`SWCR,`LWS,`SWS,`INC,`LCL,`PEA:
fnImm = {{55{insn[36]}},insn[36:28]};
default:
fnImm = {{52{insn[39]}},insn[39:28]};
endcase
endcase
 
endfunction
 
function [7:0] fnImm8;
input [127:0] insn;
if (insn[7:0]==8'h11)
fnImm8 = 8'h00;
else
casex(insn[15:8])
`CAS: fnImm8 = insn[47:40];
`BCD: fnImm8 = insn[47:40];
`TLB: fnImm8 = insn[23:16];
`LOOP: fnImm8 = insn[23:16];
`STP: fnImm8 = insn[23:16];
`JSR,`JSRS,`RTS2: fnImm8 = insn[31:24];
`BITFIELD: fnImm8 = insn[39:32];
`SYS,`INT: fnImm8 = insn[31:24];
`CMPI,`LDI,`LDIS,`ADDUIS: fnImm8 = insn[29:22];
`RTS: fnImm8 = insn[19:16];
`RTD,`RTE,`RTI,`JSRZ,`STMV,`STCMP,`STFND,`CACHE,`STS: fnImm8 = 8'h00;
`STI: fnImm8 = insn[35:28];
//`LINK: fnImm8 = {insn[32:28],3'b000};
`LB,`LBU,`LC,`LCU,`LH,`LHU,`LW,`LVB,`LVC,`LVH,`LVW,`LVWAR,
`SB,`SC,`SH,`SW,`SWCR,`LWS,`SWS,`INC,`LCL,`PEA:
fnImm8 = insn[35:28];
default: fnImm8 = insn[35:28];
endcase
endfunction
 
// Return MSB of immediate value for instruction
function fnImmMSB;
input [127:0] insn;
if (insn[7:0]==8'h11)
fnImmMSB = 1'b0;
else
casex(insn[15:8])
`CAS: fnImmMSB = insn[47];
`TLB,`BCD,`STP:
fnImmMSB = 1'b0; // TLB regno is unsigned
`LOOP:
fnImmMSB = insn[23];
`JSR:
fnImmMSB = insn[47];
`JSRS:
fnImmMSB = insn[39];
`CMPI,`LDI,`LDIS,`ADDUIS:
fnImmMSB = insn[31];
`SYS,`INT,`CACHE,`LINK:
fnImmMSB = 1'b0; // SYS,INT are unsigned
`RTS,`RTD,`RTE,`RTI,`JSRZ,`STMV,`STCMP,`STFND,`RTS2,`STS:
fnImmMSB = 1'b0; // RTS is unsigned
`LBX,`LBUX,`LCX,`LCUX,`LHX,`LHUX,`LWX,
`SBX,`SCX,`SHX,`SWX:
fnImmMSB = insn[47];
`LB,`LBU,`LC,`LCU,`LH,`LHU,`LW,`LVB,`LVC,`LVH,`LVW,
`SB,`SC,`SH,`SW,`SWCR,`STI,`LWS,`SWS,`INC,`LCL,`PEA:
fnImmMSB = insn[36];
default:
fnImmMSB = insn[39];
endcase
 
endfunction
 
function [63:0] fnImmImm;
input [63:0] insn;
case(insn[7:4])
4'd2: fnImmImm = {{48{insn[15]}},insn[15:8],8'h00};
4'd3: fnImmImm = {{40{insn[23]}},insn[23:8],8'h00};
4'd4: fnImmImm = {{32{insn[31]}},insn[31:8],8'h00};
4'd5: fnImmImm = {{24{insn[39]}},insn[39:8],8'h00};
4'd6: fnImmImm = {{16{insn[47]}},insn[47:8],8'h00};
4'd7: fnImmImm = {{ 8{insn[55]}},insn[55:8],8'h00};
4'd8: fnImmImm = {insn[63:8],8'h00};
default: fnImmImm = 64'd0;
endcase
endfunction
 
function [63:0] fnOpa;
input [7:0] opcode;
input [63:0] ins;
input [63:0] rfo;
input [63:0] epc;
begin
`ifdef BITFIELDOPS
if (opcode==`BITFIELD && ins[43:40]==4'd6) // BFINSI
fnOpa = ins[21:16];
else
`endif
if (opcode==`RTS) begin
fnOpa = (commit1_v && commit1_tgt[6:0]==7'h51) ? commit1_bus :
(commit0_v && commit0_tgt[6:0]==7'h51) ? commit0_bus :
cregs[3'd1];
end
else if (opcode==`LOOP)
fnOpa = epc;
else if (fnIsFlowCtrl(opcode))
fnOpa = fnCar(ins)==4'd0 ? 64'd0 : fnCar(ins)==4'd15 ? epc :
(commit1_v && commit1_tgt[6:4]==3'h5 && commit1_tgt[3:0]==fnCar(ins)) ? commit1_bus :
(commit0_v && commit0_tgt[6:4]==3'h5 && commit0_tgt[3:0]==fnCar(ins)) ? commit0_bus :
cregs[fnCar(ins)];
else if (opcode==`P)
fnOpa = fnSpr(6'h30,epc);
else if (opcode==`MFSPR || opcode==`MOVS)
fnOpa = fnSpr(ins[`INSTRUCTION_RA],epc);
/*
casex(ins[21:16])
`TICK: fnOpa = tick;
`LCTR: fnOpa = lc;
`PREGS_ALL:
begin
fnOpa[3:0] = pregs[0];
fnOpa[7:4] = pregs[1];
fnOpa[11:8] = pregs[2];
fnOpa[15:12] = pregs[3];
fnOpa[19:16] = pregs[4];
fnOpa[23:20] = pregs[5];
fnOpa[27:24] = pregs[6];
fnOpa[31:28] = pregs[7];
fnOpa[35:32] = pregs[8];
fnOpa[39:36] = pregs[9];
fnOpa[43:40] = pregs[10];
fnOpa[47:44] = pregs[11];
fnOpa[51:48] = pregs[12];
fnOpa[55:52] = pregs[13];
fnOpa[59:56] = pregs[14];
fnOpa[63:60] = pregs[15];
end
`ASID: fnOpa = asid;
`SR: fnOpa = sr;
6'h1x: fnOpa = ins[19:16]==4'h0 ? 64'd0 : ins[19:16]==4'hF ? epc :
(commit0_v && commit0_tgt[6:4]==3'h5 && commit0_tgt[3:0]==ins[19:16]) ? commit0_bus :
cregs[ins[19:16]];
`ifdef SEGMENTATION
6'h2x: fnOpa =
(commit0_v && commit0_tgt[6:4]==3'h6 && commit0_tgt[3:0]==ins[18:16]) ? {commit0_bus[DBW-1:12],12'h000} :
{sregs[ins[18:16]],12'h000};
`endif
default: fnOpa = 64'h0;
endcase
*/
else
fnOpa = rfo;
end
endfunction
 
function fnIsKMOnly;
input [7:0] op;
fnIsKMOnly = op==`RTI || op==`RTE || op==`RTD || op==`TLB || op==`CLI || op==`SEI ||
op==`STP
;
endfunction
 
function [15:0] fnRegstrGrp;
input [6:0] Rn;
if (!Rn[6]) begin
fnRegstrGrp="GP";
end
else
case(Rn[5:4])
2'h0: fnRegstrGrp="PR";
2'h1: fnRegstrGrp="CA";
2'h2: fnRegstrGrp="SG";
2'h3:
case(Rn[3:0])
3'h0: fnRegstrGrp="PA";
3'h3: fnRegstrGrp="LC";
endcase
endcase
 
endfunction
 
function [7:0] fnRegstr;
input [6:0] Rn;
begin
if (!Rn[6]) begin
fnRegstr = Rn[5:0];
end
else
fnRegstr = Rn[3:0];
end
endfunction
 
initial begin
//
// set up panic messages
message[ `PANIC_NONE ] = "NONE ";
message[ `PANIC_FETCHBUFBEQ ] = "FETCHBUFBEQ ";
message[ `PANIC_INVALIDISLOT ] = "INVALIDISLOT ";
message[ `PANIC_IDENTICALDRAMS ] = "IDENTICALDRAMS ";
message[ `PANIC_OVERRUN ] = "OVERRUN ";
message[ `PANIC_HALTINSTRUCTION ] = "HALTINSTRUCTION ";
message[ `PANIC_INVALIDMEMOP ] = "INVALIDMEMOP ";
message[ `PANIC_INVALIDFBSTATE ] = "INVALIDFBSTATE ";
message[ `PANIC_INVALIDIQSTATE ] = "INVALIDIQSTATE ";
message[ `PANIC_BRANCHBACK ] = "BRANCHBACK ";
message[ `PANIC_MEMORYRACE ] = "MEMORYRACE ";
end
 
//`include "Thor_issue_combo.v"
/*
assign iqentry_imm[0] = fnHasConst(iqentry_op[0]),
iqentry_imm[1] = fnHasConst(iqentry_op[1]),
iqentry_imm[2] = fnHasConst(iqentry_op[2]),
iqentry_imm[3] = fnHasConst(iqentry_op[3]),
iqentry_imm[4] = fnHasConst(iqentry_op[4]),
iqentry_imm[5] = fnHasConst(iqentry_op[5]),
iqentry_imm[6] = fnHasConst(iqentry_op[6]),
iqentry_imm[7] = fnHasConst(iqentry_op[7]);
*/
//
// additional logic for ISSUE
//
// for the moment, we look at ALU-input buffers to allow back-to-back issue of
// dependent instructions ... we do not, however, look ahead for DRAM requests
// that will become valid in the next cycle. instead, these have to propagate
// their results into the IQ entry directly, at which point it becomes issue-able
//
 
always @*
for (n = 0; n < QENTRIES; n = n + 1)
iq_cmt[n] <= fnPredicate(iqentry_pred[n], iqentry_cond[n]) ||
(iqentry_cond[n] < 4'h2 && ({iqentry_pred[n],iqentry_cond[n]}!=8'h90));
 
wire [QENTRIES-1:0] args_valid;
wire [QENTRIES-1:0] could_issue;
 
genvar g;
generate
begin : argsv
 
for (g = 0; g < QENTRIES; g = g + 1)
begin
assign iqentry_imm[g] = fnHasConst(iqentry_op[g]);
 
assign args_valid[g] =
(iqentry_p_v[g]
|| (iqentry_p_s[g]==alu0_sourceid && alu0_v)
|| (iqentry_p_s[g]==alu1_sourceid && alu1_v))
&& (iqentry_a1_v[g]
// || (iqentry_mem[g] && !iqentry_agen[g] && iqentry_op[g]!=`TLB)
|| (iqentry_a1_s[g] == alu0_sourceid && alu0_v)
|| (iqentry_a1_s[g] == alu1_sourceid && alu1_v))
&& (iqentry_a2_v[g]
|| (iqentry_a2_s[g] == alu0_sourceid && alu0_v)
|| (iqentry_a2_s[g] == alu1_sourceid && alu1_v))
&& (iqentry_a3_v[g]
|| (iqentry_a3_s[g] == alu0_sourceid && alu0_v)
|| (iqentry_a3_s[g] == alu1_sourceid && alu1_v))
&& (iqentry_T_v[g]
|| (iqentry_T_s[g] == alu0_sourceid && alu0_v)
|| (iqentry_T_s[g] == alu1_sourceid && alu1_v))
;
 
assign could_issue[g] = iqentry_v[g] && !iqentry_done[g] && !iqentry_out[g] && args_valid[g] &&
(iqentry_mem[g] ? !iqentry_agen[g] : 1'b1);// && iq_cmt[g];
 
end
end
endgenerate
 
// The (old) simulator didn't handle the asynchronous race loop properly in the
// original code. It would issue two instructions to the same islot. So the
// issue logic has been re-written to eliminate the asynchronous loop.
always @*//(could_issue or head0 or head1 or head2 or head3 or head4 or head5 or head6 or head7)
begin
iqentry_issue = 8'h00;
iqentry_islot[0] = 2'b00;
iqentry_islot[1] = 2'b00;
iqentry_islot[2] = 2'b00;
iqentry_islot[3] = 2'b00;
iqentry_islot[4] = 2'b00;
iqentry_islot[5] = 2'b00;
iqentry_islot[6] = 2'b00;
iqentry_islot[7] = 2'b00;
if (could_issue[head0] & !iqentry_fp[head0]) begin
iqentry_issue[head0] = `TRUE;
iqentry_islot[head0] = 2'b00;
end
else if (could_issue[head1] & !iqentry_fp[head1]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC))
begin
iqentry_issue[head1] = `TRUE;
iqentry_islot[head1] = 2'b00;
end
else if (could_issue[head2] & !iqentry_fp[head2]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
)
begin
iqentry_issue[head2] = `TRUE;
iqentry_islot[head2] = 2'b00;
end
else if (could_issue[head3] & !iqentry_fp[head3]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
) begin
iqentry_issue[head3] = `TRUE;
iqentry_islot[head3] = 2'b00;
end
else if (could_issue[head4] & !iqentry_fp[head4]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
&& !(iqentry_v[head3] && iqentry_op[head3]==`SYNC)
) begin
iqentry_issue[head4] = `TRUE;
iqentry_islot[head4] = 2'b00;
end
else if (could_issue[head5] & !iqentry_fp[head5]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
&& !(iqentry_v[head3] && iqentry_op[head3]==`SYNC)
&& !(iqentry_v[head4] && iqentry_op[head4]==`SYNC)
) begin
iqentry_issue[head5] = `TRUE;
iqentry_islot[head5] = 2'b00;
end
else if (could_issue[head6] & !iqentry_fp[head6]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
&& !(iqentry_v[head3] && iqentry_op[head3]==`SYNC)
&& !(iqentry_v[head4] && iqentry_op[head4]==`SYNC)
&& !(iqentry_v[head5] && iqentry_op[head5]==`SYNC)
) begin
iqentry_issue[head6] = `TRUE;
iqentry_islot[head6] = 2'b00;
end
else if (could_issue[head7] & !iqentry_fp[head7]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
&& !(iqentry_v[head3] && iqentry_op[head3]==`SYNC)
&& !(iqentry_v[head4] && iqentry_op[head4]==`SYNC)
&& !(iqentry_v[head5] && iqentry_op[head5]==`SYNC)
&& !(iqentry_v[head6] && iqentry_op[head6]==`SYNC)
) begin
iqentry_issue[head7] = `TRUE;
iqentry_islot[head7] = 2'b00;
end
 
// Don't bother checking head0, it should have issued to the first
// instruction.
if (could_issue[head1] && !iqentry_fp[head1] && !iqentry_issue[head1]
&& !fnIsAlu0Op(iqentry_op[head1],iqentry_fn[head1])
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC))
begin
iqentry_issue[head1] = `TRUE;
iqentry_islot[head1] = 2'b01;
end
else if (could_issue[head2] && !iqentry_fp[head2] && !iqentry_issue[head2]
&& !fnIsAlu0Op(iqentry_op[head2],iqentry_fn[head2])
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
)
begin
iqentry_issue[head2] = `TRUE;
iqentry_islot[head2] = 2'b01;
end
else if (could_issue[head3] & !iqentry_fp[head3] && !iqentry_issue[head3]
&& !fnIsAlu0Op(iqentry_op[head3],iqentry_fn[head3])
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
) begin
iqentry_issue[head3] = `TRUE;
iqentry_islot[head3] = 2'b01;
end
else if (could_issue[head4] & !iqentry_fp[head4] && !iqentry_issue[head4]
&& !fnIsAlu0Op(iqentry_op[head4],iqentry_fn[head4])
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
&& !(iqentry_v[head3] && iqentry_op[head3]==`SYNC)
) begin
iqentry_issue[head4] = `TRUE;
iqentry_islot[head4] = 2'b01;
end
else if (could_issue[head5] & !iqentry_fp[head5] && !iqentry_issue[head5]
&& !fnIsAlu0Op(iqentry_op[head5],iqentry_fn[head5])
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
&& !(iqentry_v[head3] && iqentry_op[head3]==`SYNC)
&& !(iqentry_v[head4] && iqentry_op[head4]==`SYNC)
) begin
iqentry_issue[head5] = `TRUE;
iqentry_islot[head5] = 2'b01;
end
else if (could_issue[head6] & !iqentry_fp[head6] && !iqentry_issue[head6]
&& !fnIsAlu0Op(iqentry_op[head6],iqentry_fn[head6])
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
&& !(iqentry_v[head3] && iqentry_op[head3]==`SYNC)
&& !(iqentry_v[head4] && iqentry_op[head4]==`SYNC)
&& !(iqentry_v[head5] && iqentry_op[head5]==`SYNC)
) begin
iqentry_issue[head6] = `TRUE;
iqentry_islot[head6] = 2'b01;
end
else if (could_issue[head7] & !iqentry_fp[head7] && !iqentry_issue[head7]
&& !fnIsAlu0Op(iqentry_op[head7],iqentry_fn[head7])
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
&& !(iqentry_v[head3] && iqentry_op[head3]==`SYNC)
&& !(iqentry_v[head4] && iqentry_op[head4]==`SYNC)
&& !(iqentry_v[head5] && iqentry_op[head5]==`SYNC)
&& !(iqentry_v[head6] && iqentry_op[head6]==`SYNC)
) begin
iqentry_issue[head7] = `TRUE;
iqentry_islot[head7] = 2'b01;
end
end
 
 
`ifdef FLOATING_POINT
reg [3:0] fpispot;
always @(could_issue or head0 or head1 or head2 or head3 or head4 or head5 or head6 or head7)
begin
iqentry_fpissue = 8'h00;
iqentry_fpislot[0] = 2'b00;
iqentry_fpislot[1] = 2'b00;
iqentry_fpislot[2] = 2'b00;
iqentry_fpislot[3] = 2'b00;
iqentry_fpislot[4] = 2'b00;
iqentry_fpislot[5] = 2'b00;
iqentry_fpislot[6] = 2'b00;
iqentry_fpislot[7] = 2'b00;
fpispot = head0;
if (could_issue[head0] & iqentry_fp[head0]) begin
iqentry_fpissue[head0] = `TRUE;
iqentry_fpislot[head0] = 2'b00;
fpispot = head0;
end
else if (could_issue[head1] & iqentry_fp[head1]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC))
begin
iqentry_fpissue[head1] = `TRUE;
iqentry_fpislot[head1] = 2'b00;
fpispot = head1;
end
else if (could_issue[head2] & iqentry_fp[head2]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
)
begin
iqentry_fpissue[head2] = `TRUE;
iqentry_fpislot[head2] = 2'b00;
fpispot = head2;
end
else if (could_issue[head3] & iqentry_fp[head3]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
) begin
iqentry_fpissue[head3] = `TRUE;
iqentry_fpislot[head3] = 2'b00;
fpispot = head3;
end
else if (could_issue[head4] & iqentry_fp[head4]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
&& !(iqentry_v[head3] && iqentry_op[head3]==`SYNC)
) begin
iqentry_fpissue[head4] = `TRUE;
iqentry_fpislot[head4] = 2'b00;
fpispot = head4;
end
else if (could_issue[head5] & iqentry_fp[head5]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
&& !(iqentry_v[head3] && iqentry_op[head3]==`SYNC)
&& !(iqentry_v[head4] && iqentry_op[head4]==`SYNC)
) begin
iqentry_fpissue[head5] = `TRUE;
iqentry_fpislot[head5] = 2'b00;
fpispot = head5;
end
else if (could_issue[head6] & iqentry_fp[head6]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
&& !(iqentry_v[head3] && iqentry_op[head3]==`SYNC)
&& !(iqentry_v[head4] && iqentry_op[head4]==`SYNC)
&& !(iqentry_v[head5] && iqentry_op[head5]==`SYNC)
) begin
iqentry_fpissue[head6] = `TRUE;
iqentry_fpislot[head6] = 2'b00;
fpispot = head6;
end
else if (could_issue[head7] & iqentry_fp[head7]
&& !(iqentry_v[head0] && iqentry_op[head0]==`SYNC)
&& !(iqentry_v[head1] && iqentry_op[head1]==`SYNC)
&& !(iqentry_v[head2] && iqentry_op[head2]==`SYNC)
&& !(iqentry_v[head3] && iqentry_op[head3]==`SYNC)
&& !(iqentry_v[head4] && iqentry_op[head4]==`SYNC)
&& !(iqentry_v[head5] && iqentry_op[head5]==`SYNC)
&& !(iqentry_v[head6] && iqentry_op[head6]==`SYNC)
) begin
iqentry_fpissue[head7] = `TRUE;
iqentry_fpislot[head7] = 2'b00;
fpispot = head7;
end
else
fpispot = 4'd8;
 
end
`endif
 
//
// additional logic for handling a branch miss (STOMP logic)
//
assign iqentry_stomp[0] = branchmiss & (iqentry_v[0] && head0 != 3'd0 && (missid == 3'd7 || iqentry_stomp[7]));
assign iqentry_stomp[1] = branchmiss & (iqentry_v[1] && head0 != 3'd1 && (missid == 3'd0 || iqentry_stomp[0]));
assign iqentry_stomp[2] = branchmiss & (iqentry_v[2] && head0 != 3'd2 && (missid == 3'd1 || iqentry_stomp[1]));
assign iqentry_stomp[3] = branchmiss & (iqentry_v[3] && head0 != 3'd3 && (missid == 3'd2 || iqentry_stomp[2]));
assign iqentry_stomp[4] = branchmiss & (iqentry_v[4] && head0 != 3'd4 && (missid == 3'd3 || iqentry_stomp[3]));
assign iqentry_stomp[5] = branchmiss & (iqentry_v[5] && head0 != 3'd5 && (missid == 3'd4 || iqentry_stomp[4]));
assign iqentry_stomp[6] = branchmiss & (iqentry_v[6] && head0 != 3'd6 && (missid == 3'd5 || iqentry_stomp[5]));
assign iqentry_stomp[7] = branchmiss & (iqentry_v[7] && head0 != 3'd7 && (missid == 3'd6 || iqentry_stomp[6]));
 
assign alu0_issue = (!(iqentry_v[0] && iqentry_stomp[0]) && iqentry_issue[0] && iqentry_islot[0]==2'd0) ||
(!(iqentry_v[1] && iqentry_stomp[1]) && iqentry_issue[1] && iqentry_islot[1]==2'd0) ||
(!(iqentry_v[2] && iqentry_stomp[2]) && iqentry_issue[2] && iqentry_islot[2]==2'd0) ||
(!(iqentry_v[3] && iqentry_stomp[3]) && iqentry_issue[3] && iqentry_islot[3]==2'd0) ||
(!(iqentry_v[4] && iqentry_stomp[4]) && iqentry_issue[4] && iqentry_islot[4]==2'd0) ||
(!(iqentry_v[5] && iqentry_stomp[5]) && iqentry_issue[5] && iqentry_islot[5]==2'd0) ||
(!(iqentry_v[6] && iqentry_stomp[6]) && iqentry_issue[6] && iqentry_islot[6]==2'd0) ||
(!(iqentry_v[7] && iqentry_stomp[7]) && iqentry_issue[7] && iqentry_islot[7]==2'd0)
;
 
assign alu1_issue = (!(iqentry_v[0] && iqentry_stomp[0]) && iqentry_issue[0] && iqentry_islot[0]==2'd1) ||
(!(iqentry_v[1] && iqentry_stomp[1]) && iqentry_issue[1] && iqentry_islot[1]==2'd1) ||
(!(iqentry_v[2] && iqentry_stomp[2]) && iqentry_issue[2] && iqentry_islot[2]==2'd1) ||
(!(iqentry_v[3] && iqentry_stomp[3]) && iqentry_issue[3] && iqentry_islot[3]==2'd1) ||
(!(iqentry_v[4] && iqentry_stomp[4]) && iqentry_issue[4] && iqentry_islot[4]==2'd1) ||
(!(iqentry_v[5] && iqentry_stomp[5]) && iqentry_issue[5] && iqentry_islot[5]==2'd1) ||
(!(iqentry_v[6] && iqentry_stomp[6]) && iqentry_issue[6] && iqentry_islot[6]==2'd1) ||
(!(iqentry_v[7] && iqentry_stomp[7]) && iqentry_issue[7] && iqentry_islot[7]==2'd1)
;
 
`ifdef FLOATING_POINT
assign fp0_issue = (!(iqentry_v[0] && iqentry_stomp[0]) && iqentry_fpissue[0] && iqentry_islot[0]==2'd0) ||
(!(iqentry_v[1] && iqentry_stomp[1]) && iqentry_fpissue[1] && iqentry_islot[1]==2'd0) ||
(!(iqentry_v[2] && iqentry_stomp[2]) && iqentry_fpissue[2] && iqentry_islot[2]==2'd0) ||
(!(iqentry_v[3] && iqentry_stomp[3]) && iqentry_fpissue[3] && iqentry_islot[3]==2'd0) ||
(!(iqentry_v[4] && iqentry_stomp[4]) && iqentry_fpissue[4] && iqentry_islot[4]==2'd0) ||
(!(iqentry_v[5] && iqentry_stomp[5]) && iqentry_fpissue[5] && iqentry_islot[5]==2'd0) ||
(!(iqentry_v[6] && iqentry_stomp[6]) && iqentry_fpissue[6] && iqentry_islot[6]==2'd0) ||
(!(iqentry_v[7] && iqentry_stomp[7]) && iqentry_fpissue[7] && iqentry_islot[7]==2'd0)
;
`endif
 
wire dcache_access_pending = dram0 == 3'd6 && (!rhit || (dram0_op==`LCL && dram0_tgt==7'd1));
 
//
// determine if the instructions ready to issue can, in fact, issue.
// "ready" means that the instruction has valid operands but has not gone yet
//
// Stores can only issue if there is no possibility of a change of program flow.
// That means no flow control operations or instructions that can cause an
// exception can be before the store.
assign iqentry_memissue_head0 = iqentry_memready[ head0 ] && cstate==IDLE && !dcache_access_pending && dram0==0; // first in line ... go as soon as ready
 
assign iqentry_memissue_head1 = ~iqentry_stomp[head1] && iqentry_memready[ head1 ] // addr and data are valid
// ... and no preceding instruction is ready to go
&& ~iqentry_memready[head0]
// ... and there is no address-overlap with any preceding instruction
&& (!iqentry_mem[head0] || (iqentry_agen[head0] & iqentry_out[head0])
|| (iqentry_a1_v[head0] && iqentry_a1[head1][DBW-1:3] != iqentry_a1[head0][DBW-1:3]))
// ... and, if it is a SW, there is no chance of it being undone
&& (fnIsStore(iqentry_op[head1]) ? !fnIsFlowCtrl(iqentry_op[head0])
&& !fnCanException(iqentry_op[head0],iqentry_fn[head0]) : `TRUE)
&& (iqentry_op[head1]!=`CAS)
&& !(iqentry_v[head0] && fnIsMem(iqentry_op[head0]) && iqentry_op[head0]==`MEMDB)
&& !(iqentry_v[head0] && iqentry_op[head0]==`MEMSB)
&& cstate==IDLE && !dcache_access_pending && dram0==0
;
 
assign iqentry_memissue_head2 = ~iqentry_stomp[head2] && iqentry_memready[ head2 ] // addr and data are valid
// ... and no preceding instruction is ready to go
&& ~iqentry_memready[head0]
&& ~iqentry_memready[head1]
// ... and there is no address-overlap with any preceding instruction
&& (!iqentry_mem[head0] || (iqentry_agen[head0] & iqentry_out[head0])
|| (iqentry_a1_v[head0] && iqentry_a1[head2][DBW-1:3] != iqentry_a1[head0][DBW-1:3]))
&& (!iqentry_mem[head1] || (iqentry_agen[head1] & iqentry_out[head1])
|| (iqentry_a1_v[head1] && iqentry_a1[head2][DBW-1:3] != iqentry_a1[head1][DBW-1:3]))
// ... and, if it is a SW, there is no chance of it being undone
&& (fnIsStore(iqentry_op[head2]) ?
!fnIsFlowCtrl(iqentry_op[head0]) && !fnCanException(iqentry_op[head0],iqentry_fn[head0]) &&
!fnIsFlowCtrl(iqentry_op[head1]) && !fnCanException(iqentry_op[head1],iqentry_fn[head1])
: `TRUE)
&& (iqentry_op[head2]!=`CAS)
&& !(iqentry_v[head0] && fnIsMem(iqentry_op[head0]) && iqentry_op[head0]==`MEMDB)
&& !(iqentry_v[head1] && fnIsMem(iqentry_op[head1]) && iqentry_op[head1]==`MEMDB)
// ... and there is no instruction barrier
&& !(iqentry_v[head0] && iqentry_op[head0]==`MEMSB)
&& !(iqentry_v[head1] && iqentry_op[head1]==`MEMSB)
&& cstate==IDLE && !dcache_access_pending && dram0==0
;
// ( !fnIsFlowCtrl(iqentry_op[head0])
// && !fnIsFlowCtrl(iqentry_op[head1])));
 
assign iqentry_memissue_head3 = ~iqentry_stomp[head3] && iqentry_memready[ head3 ] // addr and data are valid
// ... and no preceding instruction is ready to go
&& ~iqentry_memready[head0]
&& ~iqentry_memready[head1]
&& ~iqentry_memready[head2]
// ... and there is no address-overlap with any preceding instruction
&& (!iqentry_mem[head0] || (iqentry_agen[head0] & iqentry_out[head0])
|| (iqentry_a1_v[head0] && iqentry_a1[head3][DBW-1:3] != iqentry_a1[head0][DBW-1:3]))
&& (!iqentry_mem[head1] || (iqentry_agen[head1] & iqentry_out[head1])
|| (iqentry_a1_v[head1] && iqentry_a1[head3][DBW-1:3] != iqentry_a1[head1][DBW-1:3]))
&& (!iqentry_mem[head2] || (iqentry_agen[head2] & iqentry_out[head2])
|| (iqentry_a1_v[head2] && iqentry_a1[head3][DBW-1:3] != iqentry_a1[head2][DBW-1:3]))
// ... and, if it is a SW, there is no chance of it being undone
&& (fnIsStore(iqentry_op[head3]) ?
!fnIsFlowCtrl(iqentry_op[head0]) && !fnCanException(iqentry_op[head0],iqentry_fn[head0]) &&
!fnIsFlowCtrl(iqentry_op[head1]) && !fnCanException(iqentry_op[head1],iqentry_fn[head1]) &&
!fnIsFlowCtrl(iqentry_op[head2]) && !fnCanException(iqentry_op[head2],iqentry_fn[head2])
: `TRUE)
&& (iqentry_op[head3]!=`CAS)
// ... and there is no memory barrier
&& !(iqentry_v[head0] && fnIsMem(iqentry_op[head0]) && iqentry_op[head0]==`MEMDB)
&& !(iqentry_v[head1] && fnIsMem(iqentry_op[head1]) && iqentry_op[head1]==`MEMDB)
&& !(iqentry_v[head2] && fnIsMem(iqentry_op[head2]) && iqentry_op[head2]==`MEMDB)
// ... and there is no instruction barrier
&& !(iqentry_v[head0] && iqentry_op[head0]==`MEMSB)
&& !(iqentry_v[head1] && iqentry_op[head1]==`MEMSB)
&& !(iqentry_v[head2] && iqentry_op[head2]==`MEMSB)
&& cstate==IDLE && !dcache_access_pending && dram0==0
;
/* ( !fnIsFlowCtrl(iqentry_op[head0])
&& !fnIsFlowCtrl(iqentry_op[head1])
&& !fnIsFlowCtrl(iqentry_op[head2])));
*/
assign iqentry_memissue_head4 = ~iqentry_stomp[head4] && iqentry_memready[ head4 ] // addr and data are valid
// ... and no preceding instruction is ready to go
&& ~iqentry_memready[head0]
&& ~iqentry_memready[head1]
&& ~iqentry_memready[head2]
&& ~iqentry_memready[head3]
// ... and there is no address-overlap with any preceding instruction
&& (!iqentry_mem[head0] || (iqentry_agen[head0] & iqentry_out[head0])
|| (iqentry_a1_v[head0] && iqentry_a1[head4][DBW-1:3] != iqentry_a1[head0][DBW-1:3]))
&& (!iqentry_mem[head1] || (iqentry_agen[head1] & iqentry_out[head1])
|| (iqentry_a1_v[head1] && iqentry_a1[head4][DBW-1:3] != iqentry_a1[head1][DBW-1:3]))
&& (!iqentry_mem[head2] || (iqentry_agen[head2] & iqentry_out[head2])
|| (iqentry_a1_v[head2] && iqentry_a1[head4][DBW-1:3] != iqentry_a1[head2][DBW-1:3]))
&& (!iqentry_mem[head3] || (iqentry_agen[head3] & iqentry_out[head3])
|| (iqentry_a1_v[head3] && iqentry_a1[head4][DBW-1:3] != iqentry_a1[head3][DBW-1:3]))
// ... and, if it is a SW, there is no chance of it being undone
&& (fnIsStore(iqentry_op[head4]) ?
!fnIsFlowCtrl(iqentry_op[head0]) && !fnCanException(iqentry_op[head0],iqentry_fn[head0]) &&
!fnIsFlowCtrl(iqentry_op[head1]) && !fnCanException(iqentry_op[head1],iqentry_fn[head1]) &&
!fnIsFlowCtrl(iqentry_op[head2]) && !fnCanException(iqentry_op[head2],iqentry_fn[head2]) &&
!fnIsFlowCtrl(iqentry_op[head3]) && !fnCanException(iqentry_op[head3],iqentry_fn[head3])
: `TRUE)
&& (iqentry_op[head4]!=`CAS)
// ... and there is no memory barrier
&& !(iqentry_v[head0] && fnIsMem(iqentry_op[head0]) && iqentry_op[head0]==`MEMDB)
&& !(iqentry_v[head1] && fnIsMem(iqentry_op[head1]) && iqentry_op[head1]==`MEMDB)
&& !(iqentry_v[head2] && fnIsMem(iqentry_op[head2]) && iqentry_op[head2]==`MEMDB)
&& !(iqentry_v[head3] && fnIsMem(iqentry_op[head3]) && iqentry_op[head3]==`MEMDB)
// ... and there is no instruction barrier
&& !(iqentry_v[head0] && iqentry_op[head0]==`MEMSB)
&& !(iqentry_v[head1] && iqentry_op[head1]==`MEMSB)
&& !(iqentry_v[head2] && iqentry_op[head2]==`MEMSB)
&& !(iqentry_v[head3] && iqentry_op[head3]==`MEMSB)
&& cstate==IDLE && !dcache_access_pending && dram0==0
;
/* ||
( !fnIsFlowCtrl(iqentry_op[head0])
&& !fnIsFlowCtrl(iqentry_op[head1])
&& !fnIsFlowCtrl(iqentry_op[head2])
&& !fnIsFlowCtrl(iqentry_op[head3])));
*/
assign iqentry_memissue_head5 = ~iqentry_stomp[head5] && iqentry_memready[ head5 ] // addr and data are valid
// ... and no preceding instruction is ready to go
&& ~iqentry_memready[head0]
&& ~iqentry_memready[head1]
&& ~iqentry_memready[head2]
&& ~iqentry_memready[head3]
&& ~iqentry_memready[head4]
// ... and there is no address-overlap with any preceding instruction
&& (!iqentry_mem[head0] || (iqentry_agen[head0] & iqentry_out[head0])
|| (iqentry_a1_v[head0] && iqentry_a1[head5][DBW-1:3] != iqentry_a1[head0][DBW-1:3]))
&& (!iqentry_mem[head1] || (iqentry_agen[head1] & iqentry_out[head1])
|| (iqentry_a1_v[head1] && iqentry_a1[head5][DBW-1:3] != iqentry_a1[head1][DBW-1:3]))
&& (!iqentry_mem[head2] || (iqentry_agen[head2] & iqentry_out[head2])
|| (iqentry_a1_v[head2] && iqentry_a1[head5][DBW-1:3] != iqentry_a1[head2][DBW-1:3]))
&& (!iqentry_mem[head3] || (iqentry_agen[head3] & iqentry_out[head3])
|| (iqentry_a1_v[head3] && iqentry_a1[head5][DBW-1:3] != iqentry_a1[head3][DBW-1:3]))
&& (!iqentry_mem[head4] || (iqentry_agen[head4] & iqentry_out[head4])
|| (iqentry_a1_v[head4] && iqentry_a1[head5][DBW-1:3] != iqentry_a1[head4][DBW-1:3]))
// ... and, if it is a SW, there is no chance of it being undone
&& (fnIsStore(iqentry_op[head5]) ?
!fnIsFlowCtrl(iqentry_op[head0]) && !fnCanException(iqentry_op[head0],iqentry_fn[head0]) &&
!fnIsFlowCtrl(iqentry_op[head1]) && !fnCanException(iqentry_op[head1],iqentry_fn[head1]) &&
!fnIsFlowCtrl(iqentry_op[head2]) && !fnCanException(iqentry_op[head2],iqentry_fn[head2]) &&
!fnIsFlowCtrl(iqentry_op[head3]) && !fnCanException(iqentry_op[head3],iqentry_fn[head3]) &&
!fnIsFlowCtrl(iqentry_op[head4]) && !fnCanException(iqentry_op[head4],iqentry_fn[head4])
: `TRUE)
&& (iqentry_op[head5]!=`CAS)
// ... and there is no memory barrier
&& !(iqentry_v[head0] && fnIsMem(iqentry_op[head0]) && iqentry_op[head0]==`MEMDB)
&& !(iqentry_v[head1] && fnIsMem(iqentry_op[head1]) && iqentry_op[head1]==`MEMDB)
&& !(iqentry_v[head2] && fnIsMem(iqentry_op[head2]) && iqentry_op[head2]==`MEMDB)
&& !(iqentry_v[head3] && fnIsMem(iqentry_op[head3]) && iqentry_op[head3]==`MEMDB)
&& !(iqentry_v[head4] && fnIsMem(iqentry_op[head4]) && iqentry_op[head4]==`MEMDB)
// ... and there is no instruction barrier
&& !(iqentry_v[head0] && iqentry_op[head0]==`MEMSB)
&& !(iqentry_v[head1] && iqentry_op[head1]==`MEMSB)
&& !(iqentry_v[head2] && iqentry_op[head2]==`MEMSB)
&& !(iqentry_v[head3] && iqentry_op[head3]==`MEMSB)
&& !(iqentry_v[head4] && iqentry_op[head4]==`MEMSB)
&& cstate==IDLE && !dcache_access_pending && dram0==0
;
/*||
( !fnIsFlowCtrl(iqentry_op[head0])
&& !fnIsFlowCtrl(iqentry_op[head1])
&& !fnIsFlowCtrl(iqentry_op[head2])
&& !fnIsFlowCtrl(iqentry_op[head3])
&& !fnIsFlowCtrl(iqentry_op[head4])));
*/
assign iqentry_memissue_head6 = ~iqentry_stomp[head6] && iqentry_memready[ head6 ] // addr and data are valid
// ... and no preceding instruction is ready to go
&& ~iqentry_memready[head0]
&& ~iqentry_memready[head1]
&& ~iqentry_memready[head2]
&& ~iqentry_memready[head3]
&& ~iqentry_memready[head4]
&& ~iqentry_memready[head5]
// ... and there is no address-overlap with any preceding instruction
&& (!iqentry_mem[head0] || (iqentry_agen[head0] & iqentry_out[head0])
|| (iqentry_a1_v[head0] && iqentry_a1[head6][DBW-1:3] != iqentry_a1[head0][DBW-1:3]))
&& (!iqentry_mem[head1] || (iqentry_agen[head1] & iqentry_out[head1])
|| (iqentry_a1_v[head1] && iqentry_a1[head6][DBW-1:3] != iqentry_a1[head1][DBW-1:3]))
&& (!iqentry_mem[head2] || (iqentry_agen[head2] & iqentry_out[head2])
|| (iqentry_a1_v[head2] && iqentry_a1[head6][DBW-1:3] != iqentry_a1[head2][DBW-1:3]))
&& (!iqentry_mem[head3] || (iqentry_agen[head3] & iqentry_out[head3])
|| (iqentry_a1_v[head3] && iqentry_a1[head6][DBW-1:3] != iqentry_a1[head3][DBW-1:3]))
&& (!iqentry_mem[head4] || (iqentry_agen[head4] & iqentry_out[head4])
|| (iqentry_a1_v[head4] && iqentry_a1[head6][DBW-1:3] != iqentry_a1[head4][DBW-1:3]))
&& (!iqentry_mem[head5] || (iqentry_agen[head5] & iqentry_out[head5])
|| (iqentry_a1_v[head5] && iqentry_a1[head6][DBW-1:3] != iqentry_a1[head5][DBW-1:3]))
// ... and, if it is a SW, there is no chance of it being undone
&& (fnIsStore(iqentry_op[head6]) ?
!fnIsFlowCtrl(iqentry_op[head0]) && !fnCanException(iqentry_op[head0],iqentry_fn[head0]) &&
!fnIsFlowCtrl(iqentry_op[head1]) && !fnCanException(iqentry_op[head1],iqentry_fn[head1]) &&
!fnIsFlowCtrl(iqentry_op[head2]) && !fnCanException(iqentry_op[head2],iqentry_fn[head2]) &&
!fnIsFlowCtrl(iqentry_op[head3]) && !fnCanException(iqentry_op[head3],iqentry_fn[head3]) &&
!fnIsFlowCtrl(iqentry_op[head4]) && !fnCanException(iqentry_op[head4],iqentry_fn[head4]) &&
!fnIsFlowCtrl(iqentry_op[head5]) && !fnCanException(iqentry_op[head5],iqentry_fn[head5])
: `TRUE)
&& (iqentry_op[head6]!=`CAS)
// ... and there is no memory barrier
&& !(iqentry_v[head0] && fnIsMem(iqentry_op[head0]) && iqentry_op[head0]==`MEMDB)
&& !(iqentry_v[head1] && fnIsMem(iqentry_op[head1]) && iqentry_op[head1]==`MEMDB)
&& !(iqentry_v[head2] && fnIsMem(iqentry_op[head2]) && iqentry_op[head2]==`MEMDB)
&& !(iqentry_v[head3] && fnIsMem(iqentry_op[head3]) && iqentry_op[head3]==`MEMDB)
&& !(iqentry_v[head4] && fnIsMem(iqentry_op[head4]) && iqentry_op[head4]==`MEMDB)
&& !(iqentry_v[head5] && fnIsMem(iqentry_op[head5]) && iqentry_op[head5]==`MEMDB)
// ... and there is no instruction barrier
&& !(iqentry_v[head0] && iqentry_op[head0]==`MEMSB)
&& !(iqentry_v[head1] && iqentry_op[head1]==`MEMSB)
&& !(iqentry_v[head2] && iqentry_op[head2]==`MEMSB)
&& !(iqentry_v[head3] && iqentry_op[head3]==`MEMSB)
&& !(iqentry_v[head4] && iqentry_op[head4]==`MEMSB)
&& !(iqentry_v[head5] && iqentry_op[head5]==`MEMSB)
&& cstate==IDLE && !dcache_access_pending && dram0==0
;
/*||
( !fnIsFlowCtrl(iqentry_op[head0])
&& !fnIsFlowCtrl(iqentry_op[head1])
&& !fnIsFlowCtrl(iqentry_op[head2])
&& !fnIsFlowCtrl(iqentry_op[head3])
&& !fnIsFlowCtrl(iqentry_op[head4])
&& !fnIsFlowCtrl(iqentry_op[head5])));
*/
assign iqentry_memissue_head7 = ~iqentry_stomp[head7] && iqentry_memready[ head7 ] // addr and data are valid
// ... and no preceding instruction is ready to go
&& ~iqentry_memready[head0]
&& ~iqentry_memready[head1]
&& ~iqentry_memready[head2]
&& ~iqentry_memready[head3]
&& ~iqentry_memready[head4]
&& ~iqentry_memready[head5]
&& ~iqentry_memready[head6]
// ... and there is no address-overlap with any preceding instruction
&& (!iqentry_mem[head0] || (iqentry_agen[head0] & iqentry_out[head0])
|| (iqentry_a1_v[head0] && iqentry_a1[head7][DBW-1:3] != iqentry_a1[head0][DBW-1:3]))
&& (!iqentry_mem[head1] || (iqentry_agen[head1] & iqentry_out[head1])
|| (iqentry_a1_v[head1] && iqentry_a1[head7][DBW-1:3] != iqentry_a1[head1][DBW-1:3]))
&& (!iqentry_mem[head2] || (iqentry_agen[head2] & iqentry_out[head2])
|| (iqentry_a1_v[head2] && iqentry_a1[head7][DBW-1:3] != iqentry_a1[head2][DBW-1:3]))
&& (!iqentry_mem[head3] || (iqentry_agen[head3] & iqentry_out[head3])
|| (iqentry_a1_v[head3] && iqentry_a1[head7][DBW-1:3] != iqentry_a1[head3][DBW-1:3]))
&& (!iqentry_mem[head4] || (iqentry_agen[head4] & iqentry_out[head4])
|| (iqentry_a1_v[head4] && iqentry_a1[head7][DBW-1:3] != iqentry_a1[head4][DBW-1:3]))
&& (!iqentry_mem[head5] || (iqentry_agen[head5] & iqentry_out[head5])
|| (iqentry_a1_v[head5] && iqentry_a1[head7][DBW-1:3] != iqentry_a1[head5][DBW-1:3]))
&& (!iqentry_mem[head6] || (iqentry_agen[head6] & iqentry_out[head6])
|| (iqentry_a1_v[head6] && iqentry_a1[head7][DBW-1:3] != iqentry_a1[head6][DBW-1:3]))
// ... and, if it is a SW, there is no chance of it being undone
&& (fnIsStore(iqentry_op[head7]) ?
!fnIsFlowCtrl(iqentry_op[head0]) && !fnCanException(iqentry_op[head0],iqentry_fn[head0]) &&
!fnIsFlowCtrl(iqentry_op[head1]) && !fnCanException(iqentry_op[head1],iqentry_fn[head1]) &&
!fnIsFlowCtrl(iqentry_op[head2]) && !fnCanException(iqentry_op[head2],iqentry_fn[head2]) &&
!fnIsFlowCtrl(iqentry_op[head3]) && !fnCanException(iqentry_op[head3],iqentry_fn[head3]) &&
!fnIsFlowCtrl(iqentry_op[head4]) && !fnCanException(iqentry_op[head4],iqentry_fn[head4]) &&
!fnIsFlowCtrl(iqentry_op[head5]) && !fnCanException(iqentry_op[head5],iqentry_fn[head5]) &&
!fnIsFlowCtrl(iqentry_op[head6]) && !fnCanException(iqentry_op[head6],iqentry_fn[head6])
: `TRUE)
&& (iqentry_op[head7]!=`CAS)
// ... and there is no memory barrier
&& !(iqentry_v[head0] && fnIsMem(iqentry_op[head0]) && iqentry_op[head0]==`MEMDB)
&& !(iqentry_v[head1] && fnIsMem(iqentry_op[head1]) && iqentry_op[head1]==`MEMDB)
&& !(iqentry_v[head2] && fnIsMem(iqentry_op[head2]) && iqentry_op[head2]==`MEMDB)
&& !(iqentry_v[head3] && fnIsMem(iqentry_op[head3]) && iqentry_op[head3]==`MEMDB)
&& !(iqentry_v[head4] && fnIsMem(iqentry_op[head4]) && iqentry_op[head4]==`MEMDB)
&& !(iqentry_v[head5] && fnIsMem(iqentry_op[head5]) && iqentry_op[head5]==`MEMDB)
&& !(iqentry_v[head6] && fnIsMem(iqentry_op[head6]) && iqentry_op[head6]==`MEMDB)
// ... and there is no instruction barrier
&& !(iqentry_v[head0] && iqentry_op[head0]==`MEMSB)
&& !(iqentry_v[head1] && iqentry_op[head1]==`MEMSB)
&& !(iqentry_v[head2] && iqentry_op[head2]==`MEMSB)
&& !(iqentry_v[head3] && iqentry_op[head3]==`MEMSB)
&& !(iqentry_v[head4] && iqentry_op[head4]==`MEMSB)
&& !(iqentry_v[head5] && iqentry_op[head5]==`MEMSB)
&& !(iqentry_v[head6] && iqentry_op[head6]==`MEMSB)
&& cstate==IDLE && !dcache_access_pending && dram0==0
;
 
`include "Thor_execute_combo.v"
//`include "Thor_memory_combo.v"
// additional DRAM-enqueue logic
 
Thor_TLB #(DBW) utlb1
(
.rst(rst_i),
.clk(clk),
.km(km),
.pc(spc),
.ea(dram0_addr),
.ppc(ppc),
.pea(pea),
.iuncached(iuncached),
.uncached(uncached),
.m1IsStore(we_o),
.ASID(asid),
.op(tlb_op),
.state(tlb_state),
.regno(tlb_regno),
.dati(tlb_data),
.dato(tlb_dato),
.ITLBMiss(ITLBMiss),
.DTLBMiss(DTLBMiss),
.HTLBVirtPageo()
);
assign dram_avail = (dram0 == `DRAMSLOT_AVAIL || dram1 == `DRAMSLOT_AVAIL || dram2 == `DRAMSLOT_AVAIL);
 
generate
begin : memr
for (g = 0; g < QENTRIES; g = g + 1)
begin
assign iqentry_memopsvalid[g] = (iqentry_mem[g] & iqentry_a2_v[g] & iqentry_a3_v[g] & iqentry_agen[g]);
assign iqentry_memready[g] = (iqentry_v[g] & iqentry_memopsvalid[g] & ~iqentry_memissue[g] & !iqentry_issue[g] & ~iqentry_done[g] & ~iqentry_out[g] & ~iqentry_stomp[g]);
end
end
endgenerate
 
/*
assign
iqentry_memopsvalid[0] = (iqentry_mem[0] & iqentry_a2_v[0] & iqentry_a3_v[0] & iqentry_agen[0]),
iqentry_memopsvalid[1] = (iqentry_mem[1] & iqentry_a2_v[1] & iqentry_a3_v[1] & iqentry_agen[1]),
iqentry_memopsvalid[2] = (iqentry_mem[2] & iqentry_a2_v[2] & iqentry_a3_v[2] & iqentry_agen[2]),
iqentry_memopsvalid[3] = (iqentry_mem[3] & iqentry_a2_v[3] & iqentry_a3_v[3] & iqentry_agen[3]),
iqentry_memopsvalid[4] = (iqentry_mem[4] & iqentry_a2_v[4] & iqentry_a3_v[4] & iqentry_agen[4]),
iqentry_memopsvalid[5] = (iqentry_mem[5] & iqentry_a2_v[5] & iqentry_a3_v[5] & iqentry_agen[5]),
iqentry_memopsvalid[6] = (iqentry_mem[6] & iqentry_a2_v[6] & iqentry_a3_v[6] & iqentry_agen[6]),
iqentry_memopsvalid[7] = (iqentry_mem[7] & iqentry_a2_v[7] & iqentry_a3_v[7] & iqentry_agen[7]);
 
assign
iqentry_memready[0] = (iqentry_v[0] & iqentry_memopsvalid[0] & ~iqentry_memissue[0] & ~iqentry_done[0] & ~iqentry_out[0] & ~iqentry_stomp[0]),
iqentry_memready[1] = (iqentry_v[1] & iqentry_memopsvalid[1] & ~iqentry_memissue[1] & ~iqentry_done[1] & ~iqentry_out[1] & ~iqentry_stomp[1]),
iqentry_memready[2] = (iqentry_v[2] & iqentry_memopsvalid[2] & ~iqentry_memissue[2] & ~iqentry_done[2] & ~iqentry_out[2] & ~iqentry_stomp[2]),
iqentry_memready[3] = (iqentry_v[3] & iqentry_memopsvalid[3] & ~iqentry_memissue[3] & ~iqentry_done[3] & ~iqentry_out[3] & ~iqentry_stomp[3]),
iqentry_memready[4] = (iqentry_v[4] & iqentry_memopsvalid[4] & ~iqentry_memissue[4] & ~iqentry_done[4] & ~iqentry_out[4] & ~iqentry_stomp[4]),
iqentry_memready[5] = (iqentry_v[5] & iqentry_memopsvalid[5] & ~iqentry_memissue[5] & ~iqentry_done[5] & ~iqentry_out[5] & ~iqentry_stomp[5]),
iqentry_memready[6] = (iqentry_v[6] & iqentry_memopsvalid[6] & ~iqentry_memissue[6] & ~iqentry_done[6] & ~iqentry_out[6] & ~iqentry_stomp[6]),
iqentry_memready[7] = (iqentry_v[7] & iqentry_memopsvalid[7] & ~iqentry_memissue[7] & ~iqentry_done[7] & ~iqentry_out[7] & ~iqentry_stomp[7]);
*/
assign outstanding_stores = (dram0 && fnIsStore(dram0_op)) || (dram1 && fnIsStore(dram1_op)) || (dram2 && fnIsStore(dram2_op));
 
// This signal needed to stave off an instruction cache access.
assign mem_issue =
iqentry_memissue_head0 |
iqentry_memissue_head1 |
iqentry_memissue_head2 |
iqentry_memissue_head3 |
iqentry_memissue_head4 |
iqentry_memissue_head5 |
iqentry_memissue_head6 |
iqentry_memissue_head7
;
 
wire [DBW-1:0] argA = iqentry_a1_v[n] ? iqentry_a1[n]
: (iqentry_a1_s[n] == alu0_id) ? alu0_bus
: (iqentry_a1_s[n] == alu1_id) ? alu1_bus
: (iqentry_a1_s[n] == commit1_id) ? commit1_bus
: (iqentry_a1_s[n] == commit0_id) ? commit0_bus
: 64'hDEADDEADDEADDEAD;
 
//`include "Thor_commit_combo.v"
// If trying to write to two branch registers at once, or trying to write
// to two predicate registers at once, then limit the processor to single
// commit.
// The processor does not support writing two registers in the same register
// group at the same time for anything other than the general purpose
// registers. It is possible for the processor to write to two diffent groups
// at the same time.
//assign limit_cmt = (iqentry_rfw[head0] && iqentry_rfw[head1] && iqentry_tgt[head0][8]==1'b1 && iqentry_tgt[head1][8]==1'b1);
assign limit_cmt = 1'b0;
//assign committing2 = (iqentry_v[head0] && iqentry_v[head1] && !limit_cmt) || (head0 != tail0 && head1 != tail0);
 
assign commit0_v = ({iqentry_v[head0], iqentry_done[head0]} == 2'b11 && ~|panic);
assign commit1_v = ({iqentry_v[head0], iqentry_done[head0]} != 2'b10
&& {iqentry_v[head1], iqentry_done[head1]} == 2'b11 && ~|panic && !limit_cmt);
 
assign commit0_id = {iqentry_mem[head0], head0}; // if a memory op, it has a DRAM-bus id
assign commit1_id = {iqentry_mem[head1], head1}; // if a memory op, it has a DRAM-bus id
 
assign commit0_tgt = iqentry_tgt[head0];
assign commit1_tgt = iqentry_tgt[head1];
 
assign commit0_bus = iqentry_res[head0];
assign commit1_bus = iqentry_res[head1];
 
// If the target register is code address register #13 or #11 (0Dh) then we really wanted a SYS not an INT.
// The difference is that and INT returns to the interrupted instruction, and a SYS returns to the
// next instruction. In the case of hardware determined software exceptions we want to be able to
// return to the interrupted instruction, hence an INT is forced targeting code address reg #13.
assign int_commit = (iqentry_op[head0]==`INT && commit0_v && iqentry_tgt[head0][3:0]==4'hE) ||
(commit0_v && iqentry_op[head1]==`INT && commit1_v && iqentry_tgt[head1][3:0]==4'hE);
assign sys_commit = ((iqentry_op[head0]==`SYS || (iqentry_op[head0]==`INT &&
(iqentry_tgt[head0][3:0]==4'hD || iqentry_tgt[head0][3:0]==4'hB))) && commit0_v) ||
(commit0_v && (iqentry_op[head1]==`SYS || (iqentry_op[head1]==`INT &&
(iqentry_tgt[head1][3:0]==4'hD || iqentry_tgt[head1][3:0]==4'hB))) && commit1_v);
 
always @(posedge clk)
if (rst_i)
tick <= 64'd0;
else
tick <= tick + 64'd1;
 
always @(posedge clk)
if (rst_i)
nmi1 <= 1'b0;
else
nmi1 <= nmi_i;
 
//-----------------------------------------------------------------------------
// Clock control
// - reset or NMI reenables the clock
// - this circuit must be under the clk_i domain
//-----------------------------------------------------------------------------
//
reg cpu_clk_en;
reg [15:0] clk_throttle;
reg [15:0] clk_throttle_new;
reg ld_clk_throttle;
 
//BUFGCE u20 (.CE(cpu_clk_en), .I(clk_i), .O(clk) );
 
reg lct1;
always @(posedge clk_i)
if (rst_i) begin
cpu_clk_en <= 1'b1;
lct1 <= 1'b0;
clk_throttle <= 16'hAAAA; // 50% power
end
else begin
lct1 <= ld_clk_throttle;
clk_throttle <= {clk_throttle[14:0],clk_throttle[15]};
if (ld_clk_throttle && !lct1) begin
clk_throttle <= clk_throttle_new;
end
if (nmi_i)
clk_throttle <= 16'hAAAA;
cpu_clk_en <= clk_throttle[15];
end
 
// Clock throttling bypassed for now
assign clk_o = clk;
assign clk = clk_i;
 
//-----------------------------------------------------------------------------
// Note that everything clocked has to be in the same always block. This is a
// limitation of some toolsets. Simulation / synthesis may get confused if the
// logic isn't placed in the same always block.
//-----------------------------------------------------------------------------
 
always @(posedge clk) begin
 
if (nmi_i & !nmi1)
nmi_edge <= 1'b1;
ld_clk_throttle <= `FALSE;
dram_v <= `INV;
alu0_ld <= 1'b0;
alu1_ld <= 1'b0;
`ifdef FLOATING_POINT
fp0_ld <= 1'b0;
`endif
 
ic_invalidate <= `FALSE;
dc_invalidate <= `FALSE;
ic_invalidate_line <= `FALSE;
dc_invalidate_line <= `FALSE;
alu0_dataready <= `FALSE;
alu1_dataready <= `FALSE;
 
// Reset segmentation flag once operating in non-segmented area.
if (pc[ABW-1:ABW-4]==4'hF)
pc[ABW+3:ABW] <= 4'h0;
 
if (rst_i)
cstate <= RESET1;
if (rst_i||cstate==RESET1||cstate==RESET2) begin
wb_nack();
ierr <= 1'b0;
GM <= 8'hFF;
nmi_edge <= 1'b0;
pc <= RSTADDR[ABW-1:0];
StatusHWI <= `TRUE; // disables interrupts at startup until an RTI instruction is executed.
im <= 1'b1;
imb <= 1'b1;
ic_invalidate <= `TRUE;
dc_invalidate <= `TRUE;
fetchbuf <= 1'b0;
fetchbufA_v <= `INV;
fetchbufB_v <= `INV;
fetchbufC_v <= `INV;
fetchbufD_v <= `INV;
fetchbufA_instr <= {8{8'h10}};
fetchbufB_instr <= {8{8'h10}};
fetchbufC_instr <= {8{8'h10}};
fetchbufD_instr <= {8{8'h10}};
fetchbufA_pc <= {{DBW-4{1'b1}},4'h0};
fetchbufB_pc <= {{DBW-4{1'b1}},4'h0};
fetchbufC_pc <= {{DBW-4{1'b1}},4'h0};
fetchbufD_pc <= {{DBW-4{1'b1}},4'h0};
for (i=0; i< QENTRIES; i=i+1) begin
iqentry_v[i] <= `INV;
iqentry_agen[i] <= `FALSE;
iqentry_op[i] <= `NOP;
iqentry_memissue[i] <= `FALSE;
iqentry_a1[i] <= 64'd0;
iqentry_a2[i] <= 64'd0;
iqentry_a3[i] <= 64'd0;
iqentry_T[i] <= 64'd0;
iqentry_a1_v[i] <= `INV;
iqentry_a2_v[i] <= `INV;
iqentry_a3_v[i] <= `INV;
iqentry_T_v[i] <= `INV;
iqentry_a1_s[i] <= 4'd0;
iqentry_a2_s[i] <= 4'd0;
iqentry_a3_s[i] <= 4'd0;
iqentry_T_s[i] <= 4'd0;
end
// All the register are flagged as valid on startup even though they
// may not contain valid data. Otherwise the processor will stall
// waiting for the registers to become valid. Ideally the registers
// should be initialized with valid values before use. But who knows
// what someone will do in boot code and we don't want the processor
// to stall.
for (n = 1; n < NREGS; n = n + 1) begin
rf_v[n] = `VAL;
`ifdef SIMULATION
rf_source[n] <= 4'd0;
`endif
dbg_ctrl <= {DBW{1'b0}};
`ifdef SIMULATION
dbg_adr0 <= 0;
dbg_adr1 <= 0;
dbg_adr2 <= 0;
dbg_adr3 <= 0;
`endif
end
if (ABW==32)
sregs_lmt[7] = 20'hFFFFF;
else
sregs_lmt[7] = 52'hFFFFFFFFFFFFF;
rf_source[0] <= 4'd0;
// rf_v[0] = `VAL;
// rf_v[7'h50] = `VAL;
// rf_v[7'h5F] = `VAL;
alu0_available <= `TRUE;
alu1_available <= `TRUE;
reset_tail_pointers(1);
head0 <= 3'd0;
head1 <= 3'd1;
head2 <= 3'd2;
head3 <= 3'd3;
head4 <= 3'd4;
head5 <= 3'd5;
head6 <= 3'd6;
head7 <= 3'd7;
dram0 <= 3'b00;
dram1 <= 3'b00;
dram2 <= 3'b00;
tlb_state <= 3'd0;
panic <= `PANIC_NONE;
string_pc <= 64'd0;
// The pc wraps around to address zero while fetching the reset vector.
// This causes the processor to use the code segement register so the
// CS has to be defined for reset.
sregs[7] <= 52'd0;
for (i=0; i < 16; i=i+1)
pregs[i] <= 4'd0;
asid <= 8'h00;
rrmapno <= 3'd0;
dram0_id <= 0;
alu1_sourceid <= 0;
end
 
// The following registers are always valid
rf_v[7'h00] = `VAL;
rf_v[7'h50] = `VAL; // C0
rf_v[7'h5F] = `VAL; // C15 (PC)
rf_v[7'h72] = `VAL; // tick
queued1 = `FALSE;
queued2 = `FALSE;
allowq = `TRUE;
 
did_branchback <= take_branch;
did_branchback0 <= take_branch0;
did_branchback1 <= take_branch1;
 
if (branchmiss) begin
for (n = 1; n < NREGS; n = n + 1)
if (rf_v[n] == `INV && ~livetarget[n]) begin
$display("brmiss: rf_v[%d] <= VAL",n);
rf_v[n] = `VAL;
end
 
if (|iqentry_0_latestID[NREGS:1]) rf_source[ iqentry_tgt[0] ] <= { iqentry_mem[0], 3'd0 };
if (|iqentry_1_latestID[NREGS:1]) rf_source[ iqentry_tgt[1] ] <= { iqentry_mem[1], 3'd1 };
if (|iqentry_2_latestID[NREGS:1]) rf_source[ iqentry_tgt[2] ] <= { iqentry_mem[2], 3'd2 };
if (|iqentry_3_latestID[NREGS:1]) rf_source[ iqentry_tgt[3] ] <= { iqentry_mem[3], 3'd3 };
if (|iqentry_4_latestID[NREGS:1]) rf_source[ iqentry_tgt[4] ] <= { iqentry_mem[4], 3'd4 };
if (|iqentry_5_latestID[NREGS:1]) rf_source[ iqentry_tgt[5] ] <= { iqentry_mem[5], 3'd5 };
if (|iqentry_6_latestID[NREGS:1]) rf_source[ iqentry_tgt[6] ] <= { iqentry_mem[6], 3'd6 };
if (|iqentry_7_latestID[NREGS:1]) rf_source[ iqentry_tgt[7] ] <= { iqentry_mem[7], 3'd7 };
 
end
 
if (ihit) begin
$display("\r\n");
$display("TIME %0d", $time);
end
// COMMIT PHASE (register-file update only ... dequeue is elsewhere)
//
// look at head0 and head1 and let 'em write the register file if they are ready
//
// why is it happening here and not in another phase?
// want to emulate a pass-through register file ... i.e. if we are reading
// out of r3 while writing to r3, the value read is the value written.
// requires BLOCKING assignments, so that we can read from rf[i] later.
//
if (commit0_v) begin
if (!rf_v[ commit0_tgt ]) begin
rf_v[ commit0_tgt ] = (rf_source[ commit0_tgt ] == commit0_id) || (branchmiss && iqentry_source[ commit0_id[2:0] ]);
end
if (commit0_tgt != 7'd0) $display("r%d <- %h", commit0_tgt, commit0_bus);
end
if (commit1_v) begin
if (!rf_v[ commit1_tgt ]) begin
rf_v[ commit1_tgt ] = (rf_source[ commit1_tgt ] == commit1_id)|| (branchmiss && iqentry_source[ commit1_id[2:0] ]);
end
if (commit1_tgt != 7'd0) $display("r%d <- %h", commit1_tgt, commit1_bus);
end
 
// This chunk of code has to be before the enqueue stage so that the agen bit
// can be reset to zero by enqueue.
// put results into the appropriate instruction entries
//
if ((alu0_op==`RR && (alu0_fn==`MUL || alu0_fn==`MULU)) || alu0_op==`MULI || alu0_op==`MULUI) begin
if (alu0_done) begin
alu0_dataready <= `TRUE;
alu0_op <= `NOP;
end
end
else if ((alu0_op==`RR && (alu0_fn==`DIV || alu0_fn==`DIVU)) || alu0_op==`DIVI || alu0_op==`DIVUI) begin
if (alu0_done) begin
alu0_dataready <= `TRUE;
alu0_op <= `NOP;
end
end
 
if (alu0_v) begin
if (|alu0_exc)
set_exception(alu0_id, alu0_exc==`EXC_DBZ ? 8'd241 : 8'h00);
else begin
if (iqentry_op[alu0_id[2:0]]!=`IMM)
iqentry_done[ alu0_id[2:0] ] <= (!iqentry_mem[ alu0_id[2:0] ] || !alu0_cmt);
iqentry_res [ alu0_id[2:0] ] <= alu0_bus;
iqentry_out [ alu0_id[2:0] ] <= `FALSE;
iqentry_cmt [ alu0_id[2:0] ] <= alu0_cmt;
iqentry_agen[ alu0_id[2:0] ] <= `TRUE;
iqentry_out [ alu0_id[2:0] ] <= `FALSE;
end
end
 
 
if (((alu1_op==`RR && (alu1_fn==`MUL || alu1_fn==`MULU)) || alu1_op==`MULI || alu1_op==`MULUI) && ALU1BIG) begin
if (alu1_done) begin
alu1_dataready <= `TRUE;
alu1_op <= `NOP;
end
end
else if (((alu1_op==`RR && (alu1_fn==`DIV || alu1_fn==`DIVU)) || alu1_op==`DIVI || alu1_op==`DIVUI) && ALU1BIG) begin
if (alu1_done) begin
alu1_dataready <= `TRUE;
alu1_op <= `NOP;
end
end
 
if (alu1_v) begin
if (|alu1_exc)
set_exception(alu1_id, alu1_exc==`EXC_DBZ ? 8'd241 : 8'h00);
else begin
if (iqentry_op[alu1_id[2:0]]!=`IMM)
iqentry_done[ alu1_id[2:0] ] <= (!iqentry_mem[ alu1_id[2:0] ] || !alu1_cmt);
iqentry_res [ alu1_id[2:0] ] <= alu1_bus;
iqentry_out [ alu1_id[2:0] ] <= `FALSE;
iqentry_cmt [ alu1_id[2:0] ] <= alu1_cmt;
iqentry_agen[ alu1_id[2:0] ] <= `TRUE;
iqentry_out [ alu1_id[2:0] ] <= `FALSE;
end
end
 
`ifdef FLOATING_POINT
if (fp0_v) begin
$display("0results to iq[%d]=%h", fp0_id[2:0],fp0_bus);
if (|fp0_exc)
set_exception(fp0_id, fp0_exc);
else begin
iqentry_res [ fp0_id[2:0] ] <= fp0_bus;
iqentry_done[ fp0_id[2:0] ] <= fp0_done || !fp0_cmt;
iqentry_out [ fp0_id[2:0] ] <= `FALSE;
iqentry_cmt [ fp0_id[2:0] ] <= fp0_cmt;
iqentry_agen[ fp0_id[2:0] ] <= `TRUE;
end
end
`endif
 
//-------------------------------------------------------------------------------
// ENQUEUE
//
// place up to three instructions from the fetch buffer into slots in the IQ.
// note: they are placed in-order, and they are expected to be executed
// 0, 1, or 2 of the fetch buffers may have valid data
// 0, 1, or 2 slots in the instruction queue may be available.
// if we notice that one of the instructions in the fetch buffer is a predicted
// branch, (set branchback/backpc and delete any instructions after it in
// fetchbuf)
//
// We place the queue logic before the fetch to allow the tools to do the work
// for us. The fetch logic needs to know how many entries were queued, this is
// tracked in the queue stage by variables queued1,queued2,queued3. Blocking
// assignments are used for these vars.
//-------------------------------------------------------------------------------
//
queued1 = `FALSE;
queued2 = `FALSE;
allowq = `TRUE;
qstomp = `FALSE;
if (branchmiss) // don't bother doing anything if there's been a branch miss
reset_tail_pointers(0);
else begin
case ({fetchbuf0_v, fetchbuf1_v && fnNumReadPorts(fetchbuf1_instr) <= ports_avail})
2'b00: ; // do nothing
2'b01: enque1(tail0,1,0,1);
2'b10: enque0(tail0,1,0,1);
2'b11: begin
enque0(tail0,1,1,1);
if (allowq)
enque1(tail1,2,0,0);
validate_args();
end
endcase
end
 
//------------------------------------------------------------------------------
// FETCH
//
// fetch at least two instructions from memory into the fetch buffer unless
// either one of the buffers is still full, in which case we do nothing (kinda
// like alpha approach)
//------------------------------------------------------------------------------
//
if (branchmiss) begin
$display("pc <= %h", misspc);
pc <= misspc;
fetchbuf <= 1'b0;
fetchbufA_v <= 1'b0;
fetchbufB_v <= 1'b0;
fetchbufC_v <= 1'b0;
fetchbufD_v <= 1'b0;
end
else if (take_branch) begin
if (fetchbuf == 1'b0) begin
case ({fetchbufA_v,fetchbufB_v,fetchbufC_v,fetchbufD_v})
4'b0000:
begin
fetchCD();
if (do_pcinc) pc[31:0] <= pc[31:0] + fnInsnLength(insn) + fnInsnLength1(insn);
fetchbuf <= 1'b1;
end
4'b0100:
begin
fetchCD();
if (do_pcinc) pc[31:0] <= pc[31:0] + fnInsnLength(insn) + fnInsnLength1(insn);
fetchbufB_v <= !queued1;
if (queued1) begin
fetchbufB_instr <= 64'd0;
fetchbuf <= 1'b1;
end
if (queued2|queued3)
panic <= `PANIC_INVALIDIQSTATE;
end
4'b0111:
begin
fetchbufB_v <= !queued1;
if (queued1) begin
fetchbuf <= 1'b1;
fetchbufB_instr <= 64'd0;
end
if (queued2|queued3)
panic <= `PANIC_INVALIDIQSTATE;
end
4'b1000:
begin
fetchCD();
if (do_pcinc) pc[31:0] <= pc[31:0] + fnInsnLength(insn) + fnInsnLength1(insn);
fetchbufA_v <= !queued1;
if (queued1) begin
fetchbuf <= 1'b1;
fetchbufA_instr <= 64'd0;
end
if (queued2|queued3)
panic <= `PANIC_INVALIDIQSTATE;
end
4'b1011:
begin
fetchbufA_v <= !queued1;
if (queued1) begin
fetchbuf <= 1'b1;
fetchbufB_instr <= 64'd0;
end
if (queued2|queued3)
panic <= `PANIC_INVALIDIQSTATE;
end
4'b1100:
// Note that there is no point to loading C,D here because
// there is a predicted taken branch that would stomp on the
// instructions anyways.
if ((fnIsBranch(opcodeA) && predict_takenA)||opcodeA==`LOOP) begin
pc <= branch_pc;
fetchbufA_v <= !(queued1|queued2);
fetchbufB_v <= `INV; // stomp on it
// may as well stick with same fetchbuf
end
else begin
if (did_branchback0) begin
fetchCD();
if (do_pcinc) pc[31:0] <= pc[31:0] + fnInsnLength(insn) + fnInsnLength1(insn);
fetchbufA_v <= !(queued1|queued2);
fetchbufB_v <= !queued2;
if (queued2)
fetchbuf <= 1'b1;
end
else begin
pc[ABW-1:0] <= branch_pc;
fetchbufA_v <= !(queued1|queued2);
fetchbufB_v <= !queued2;
// may as well keep the same fetchbuffer
end
end
4'b1111:
begin
fetchbufA_v <= !(queued1|queued2);
fetchbufB_v <= !queued2;
if (queued2) begin
fetchbuf <= 1'b1;
fetchbufA_instr <= 64'd0;
fetchbufB_instr <= 64'd0;
end
end
default: panic <= `PANIC_INVALIDFBSTATE;
endcase
end
else begin // fetchbuf==1'b1
case ({fetchbufC_v,fetchbufD_v,fetchbufA_v,fetchbufB_v})
4'b0000:
begin
fetchAB();
if (do_pcinc) pc[31:0] <= pc[31:0] + fnInsnLength(insn) + fnInsnLength1(insn);
fetchbuf <= 1'b0;
end
4'b0100:
begin
fetchAB();
if (do_pcinc) pc[31:0] <= pc[31:0] + fnInsnLength(insn) + fnInsnLength1(insn);
fetchbufD_v <= !queued1;
if (queued1)
fetchbuf <= 1'b0;
if (queued2|queued3)
panic <= `PANIC_INVALIDIQSTATE;
end
4'b0111:
begin
fetchbufD_v <= !queued1;
if (queued1)
fetchbuf <= 1'b0;
if (queued2|queued3)
panic <= `PANIC_INVALIDIQSTATE;
end
4'b1000:
begin
fetchAB();
if (do_pcinc) pc[31:0] <= pc[31:0] + fnInsnLength(insn) + fnInsnLength1(insn);
fetchbufC_v <= !queued1;
if (queued1)
fetchbuf <= 1'b0;
if (queued2|queued3)
panic <= `PANIC_INVALIDIQSTATE;
end
4'b1011:
begin
fetchbufC_v <= !queued1;
if (queued1)
fetchbuf <= 1'b0;
if (queued2|queued3)
panic <= `PANIC_INVALIDIQSTATE;
end
4'b1100:
if ((fnIsBranch(opcodeC) && predict_takenC)||opcodeC==`LOOP) begin
pc <= branch_pc;
fetchbufC_v <= !(queued1|queued2);
fetchbufD_v <= `INV; // stomp on it
// may as well stick with same fetchbuf
end
else begin
if (did_branchback1) begin
fetchAB();
if (do_pcinc) pc[31:0] <= pc[31:0] + fnInsnLength(insn) + fnInsnLength1(insn);
fetchbufC_v <= !(queued1|queued2);
fetchbufD_v <= !queued2;
if (queued2)
fetchbuf <= 1'b0;
end
else begin
pc[ABW-1:0] <= branch_pc;
fetchbufC_v <= !(queued1|queued2);
fetchbufD_v <= !queued2;
// may as well keep the same fetchbuffer
end
end
4'b1111:
begin
fetchbufC_v <= !(queued1|queued2);
fetchbufD_v <= !queued2;
if (queued2)
fetchbuf <= 1'b0;
end
default: panic <= `PANIC_INVALIDFBSTATE;
endcase
end
end
else begin
if (fetchbuf == 1'b0)
case ({fetchbufA_v, fetchbufB_v})
2'b00: ;
2'b01: begin
fetchbufB_v <= !(queued2|queued1);
fetchbuf <= queued2|queued1;
end
2'b10: begin
fetchbufA_v <= !(queued2|queued1);
fetchbuf <= queued2|queued1;
end
2'b11: begin
fetchbufA_v <= !(queued1|queued2);
fetchbufB_v <= !queued2;
fetchbuf <= queued2;
end
endcase
else
case ({fetchbufC_v, fetchbufD_v})
2'b00: ;
2'b01: begin
fetchbufD_v <= !(queued2|queued1);
fetchbuf <= !(queued2|queued1);
end
2'b10: begin
fetchbufC_v <= !(queued2|queued1);
fetchbuf <= !(queued2|queued1);
end
2'b11: begin
fetchbufC_v <= !(queued2|queued1);
fetchbufD_v <= !queued2;
fetchbuf <= !queued2;
end
endcase
if (fetchbufA_v == `INV && fetchbufB_v == `INV) begin
fetchAB();
if (do_pcinc) pc[31:0] <= pc[31:0] + fnInsnLength(insn) + fnInsnLength1(insn);
// fetchbuf steering logic correction
if (fetchbufC_v==`INV && fetchbufD_v==`INV && do_pcinc)
fetchbuf <= 1'b0;
$display("hit %b 1pc <= %h", do_pcinc, pc[31:0] + fnInsnLength(insn) + fnInsnLength1(insn));
end
else if (fetchbufC_v == `INV && fetchbufD_v == `INV) begin
fetchCD();
if (do_pcinc) pc[31:0] <= pc[31:0] + fnInsnLength(insn) + fnInsnLength1(insn);
$display("2pc <= %h", pc[31:0] + fnInsnLength(insn) + fnInsnLength1(insn));
end
end
 
if (ihit) begin
$display("%h %h hit0=%b hit1=%b#", spc, pc, hit0, hit1);
$display("insn=%h", insn);
$display("%c insn0=%h insn1=%h", nmi_edge ? "*" : " ",insn0, insn1);
$display("takb=%d br_pc=%h #", take_branch, branch_pc);
$display("%c%c A: %d %h %h #",
45, fetchbuf?45:62, fetchbufA_v, fetchbufA_instr, fetchbufA_pc);
$display("%c%c B: %d %h %h #",
45, fetchbuf?45:62, fetchbufB_v, fetchbufB_instr, fetchbufB_pc);
$display("%c%c C: %d %h %h #",
45, fetchbuf?62:45, fetchbufC_v, fetchbufC_instr, fetchbufC_pc);
$display("%c%c D: %d %h %h #",
45, fetchbuf?62:45, fetchbufD_v, fetchbufD_instr, fetchbufD_pc);
$display("fetchbuf=%d",fetchbuf);
end
 
// if (ihit) begin
for (i=0; i<QENTRIES; i=i+1)
$display("%c%c %d: %c%c%c%c%c%c%c%c%c %d %c %c%h %d%s %h %h %h %c %o %h %c %o %h %c %o %h %c %o %h #",
(i[2:0]==head0)?72:46, (i[2:0]==tail0)?84:46, i,
iqentry_v[i]?"v":"-", iqentry_done[i]?"d":"-",
iqentry_cmt[i]?"c":"-", iq_cmt[i]?"C":"-",iqentry_out[i]?"o":"-", iqentry_bt[i]?"b":"-", iqentry_memissue[i]?"m":"-",
iqentry_agen[i]?"a":"-", iqentry_issue[i]?"i":"-",
iqentry_islot[i],
// ((i==0) ? iqentry_0_islot : (i==1) ? iqentry_1_islot : (i==2) ? iqentry_2_islot : (i==3) ? iqentry_3_islot :
// (i==4) ? iqentry_4_islot : (i==5) ? iqentry_5_islot : (i==6) ? iqentry_6_islot : iqentry_7_islot),
iqentry_stomp[i] ? "s" : "-",
(fnIsFlowCtrl(iqentry_op[i]) ? 98 : fnIsMem(iqentry_op[i]) ? 109 : 97),
iqentry_op[i],
fnRegstr(iqentry_tgt[i]),fnRegstrGrp(iqentry_tgt[i]),
iqentry_res[i], iqentry_a0[i],
iqentry_a1[i], iqentry_a1_v[i]?"v":"-", iqentry_a1_s[i],
iqentry_a2[i], iqentry_a2_v[i]?"v":"-", iqentry_a2_s[i],
iqentry_a3[i], iqentry_a3_v[i]?"v":"-", iqentry_a3_s[i],
iqentry_pred[i], iqentry_p_v[i]?"v":"-", iqentry_p_s[i],
iqentry_pc[i]);
$display("com0:%c%c %d r%d %h", commit0_v?"v":"-", iqentry_cmt[head0]?"c":"-", commit0_id, commit0_tgt, commit0_bus);
$display("com1:%c%c %d r%d %h", commit1_v?"v":"-", iqentry_cmt[head1]?"c":"-", commit1_id, commit1_tgt, commit1_bus);
// end
//`include "Thor_dataincoming.v"
// DATAINCOMING
//
// wait for operand/s to appear on alu busses and puts them into
// the iqentry_a1 and iqentry_a2 slots (if appropriate)
// as well as the appropriate iqentry_res slots (and setting valid bits)
//
//
if (dram_v && iqentry_v[ dram_id[2:0] ] && iqentry_mem[ dram_id[2:0] ] ) begin // if data for stomped instruction, ignore
$display("dram results to iq[%d]=%h", dram_id[2:0],dram_bus);
iqentry_res [ dram_id[2:0] ] <= dram_bus;
// If an exception occurred, stuff an interrupt instruction into the queue
// slot. The instruction will re-issue as an ALU operation. We can change
// the queued instruction because it isn't finished yet.
if (|dram_exc)
set_exception(dram_id,
dram_exc==`EXC_DBE ? 8'hFB :
dram_exc==`EXC_DBG ? 8'd243 :
dram_exc==`EXC_SEGV ? 8'd244 :
8'hF8); // F8 = TLBMiss exception 243 = debug
else begin
// Note that the predicate was already evaluated to TRUE before the
// dram operation started.
iqentry_cmt[dram_id[2:0]] <= `TRUE;
iqentry_done[ dram_id[2:0] ] <= `TRUE;
if (iqentry_op[dram_id[2:0]]==`STS && lc==64'd0) begin
string_pc <= 64'd0;
end
end
end
 
// What if there's a databus error during the store ?
// set the IQ entry == DONE as soon as the SW is let loose to the memory system
//
if (dram0 == 2'd2 && fnIsStore(dram0_op) && dram0_op != `STS) begin
if ((alu0_v && dram0_id[2:0] == alu0_id[2:0]) || (alu1_v && dram0_id[2:0] == alu1_id[2:0])) panic <= `PANIC_MEMORYRACE;
iqentry_done[ dram0_id[2:0] ] <= `TRUE;
iqentry_cmt [ dram0_id[2:0]] <= `TRUE;
iqentry_out[ dram0_id[2:0] ] <= `FALSE;
end
if (dram1 == 2'd2 && fnIsStore(dram1_op) && dram1_op != `STS) begin
if ((alu0_v && dram1_id[2:0] == alu0_id[2:0]) || (alu1_v && dram1_id[2:0] == alu1_id[2:0])) panic <= `PANIC_MEMORYRACE;
iqentry_done[ dram1_id[2:0] ] <= `TRUE;
iqentry_cmt [ dram1_id[2:0]] <= `TRUE;
iqentry_out[ dram1_id[2:0] ] <= `FALSE;
end
if (dram2 == 2'd2 && fnIsStore(dram2_op) && dram2_op != `STS) begin
if ((alu0_v && dram2_id[2:0] == alu0_id[2:0]) || (alu1_v && dram2_id[2:0] == alu1_id[2:0])) panic <= `PANIC_MEMORYRACE;
iqentry_done[ dram2_id[2:0] ] <= `TRUE;
iqentry_cmt [ dram2_id[2:0]] <= `TRUE;
iqentry_out[ dram2_id[2:0] ] <= `FALSE;
end
 
//
// see if anybody else wants the results ... look at lots of buses:
// - alu0_bus
// - alu1_bus
// - fp0_bus
// - dram_bus
// - commit0_bus
// - commit1_bus
//
 
for (n = 0; n < QENTRIES; n = n + 1)
begin
if (iqentry_p_v[n] == `INV && iqentry_p_s[n]==alu0_id && iqentry_v[n] == `VAL && alu0_v == `VAL) begin
iqentry_pred[n] <= alu0_bus[3:0];
iqentry_p_v[n] <= `VAL;
end
if (iqentry_a1_v[n] == `INV && iqentry_a1_s[n] == alu0_id && iqentry_v[n] == `VAL && alu0_v == `VAL) begin
iqentry_a1[n] <= alu0_bus;
iqentry_a1_v[n] <= `VAL;
end
if (iqentry_a2_v[n] == `INV && iqentry_a2_s[n] == alu0_id && iqentry_v[n] == `VAL && alu0_v == `VAL) begin
iqentry_a2[n] <= alu0_bus;
iqentry_a2_v[n] <= `VAL;
end
if (iqentry_a3_v[n] == `INV && iqentry_a3_s[n] == alu0_id && iqentry_v[n] == `VAL && alu0_v == `VAL) begin
iqentry_a3[n] <= alu0_bus;
iqentry_a3_v[n] <= `VAL;
end
if (iqentry_T_v[n] == `INV && iqentry_T_s[n] == alu0_id && iqentry_v[n] == `VAL && alu0_v == `VAL) begin
iqentry_T[n] <= alu0_bus;
iqentry_T_v[n] <= `VAL;
end
if (iqentry_p_v[n] == `INV && iqentry_p_s[n] == alu1_id && iqentry_v[n] == `VAL && alu1_v == `VAL) begin
iqentry_pred[n] <= alu1_bus[3:0];
iqentry_p_v[n] <= `VAL;
end
if (iqentry_a1_v[n] == `INV && iqentry_a1_s[n] == alu1_id && iqentry_v[n] == `VAL && alu1_v == `VAL) begin
iqentry_a1[n] <= alu1_bus;
iqentry_a1_v[n] <= `VAL;
end
if (iqentry_a2_v[n] == `INV && iqentry_a2_s[n] == alu1_id && iqentry_v[n] == `VAL && alu1_v == `VAL) begin
iqentry_a2[n] <= alu1_bus;
iqentry_a2_v[n] <= `VAL;
end
if (iqentry_a3_v[n] == `INV && iqentry_a3_s[n] == alu1_id && iqentry_v[n] == `VAL && alu1_v == `VAL) begin
iqentry_a3[n] <= alu1_bus;
iqentry_a3_v[n] <= `VAL;
end
if (iqentry_T_v[n] == `INV && iqentry_T_s[n] == alu1_id && iqentry_v[n] == `VAL && alu1_v == `VAL) begin
iqentry_T[n] <= alu1_bus;
iqentry_T_v[n] <= `VAL;
end
`ifdef FLOATING_POINT
/*
if (iqentry_p_v[n] == `INV && iqentry_p_s[n] == fp0_id && iqentry_v[n] == `VAL && fp0_v == `VAL) begin
iqentry_pred[n] <= fp0_bus[3:0];
iqentry_p_v[n] <= `VAL;
end
*/
if (iqentry_a1_v[n] == `INV && iqentry_a1_s[n] == fp0_id && iqentry_v[n] == `VAL && fp0_v == `VAL) begin
iqentry_a1[n] <= fp0_bus;
iqentry_a1_v[n] <= `VAL;
end
if (iqentry_a2_v[n] == `INV && iqentry_a2_s[n] == fp0_id && iqentry_v[n] == `VAL && fp0_v == `VAL) begin
iqentry_a2[n] <= fp0_bus;
iqentry_a2_v[n] <= `VAL;
end
if (iqentry_a3_v[n] == `INV && iqentry_a3_s[n] == fp0_id && iqentry_v[n] == `VAL && fp0_v == `VAL) begin
iqentry_a3[n] <= fp0_bus;
iqentry_a3_v[n] <= `VAL;
end
if (iqentry_T_v[n] == `INV && iqentry_T_s[n] == fp0_id && iqentry_v[n] == `VAL && fp0_v == `VAL) begin
iqentry_T[n] <= fp0_bus;
iqentry_T_v[n] <= `VAL;
end
`endif
// For SWCR
if (iqentry_p_v[n] == `INV && iqentry_p_s[n]==dram_id && iqentry_v[n] == `VAL && dram_v == `VAL) begin
iqentry_pred[n] <= dram_bus[3:0];
iqentry_p_v[n] <= `VAL;
end
if (iqentry_a1_v[n] == `INV && iqentry_a1_s[n] == dram_id && iqentry_v[n] == `VAL && dram_v == `VAL) begin
iqentry_a1[n] <= dram_bus;
iqentry_a1_v[n] <= `VAL;
end
if (iqentry_a2_v[n] == `INV && iqentry_a2_s[n] == dram_id && iqentry_v[n] == `VAL && dram_v == `VAL) begin
iqentry_a2[n] <= dram_bus;
iqentry_a2_v[n] <= `VAL;
end
if (iqentry_a3_v[n] == `INV && iqentry_a3_s[n] == dram_id && iqentry_v[n] == `VAL && dram_v == `VAL) begin
iqentry_a3[n] <= dram_bus;
iqentry_a3_v[n] <= `VAL;
end
if (iqentry_T_v[n] == `INV && iqentry_T_s[n] == dram_id && iqentry_v[n] == `VAL && dram_v == `VAL) begin
iqentry_T[n] <= dram_bus;
iqentry_T_v[n] <= `VAL;
end
if (iqentry_p_v[n] == `INV && iqentry_p_s[n]==commit0_id && iqentry_v[n] == `VAL && commit0_v == `VAL) begin
iqentry_pred[n] <= commit0_bus[3:0];
iqentry_p_v[n] <= `VAL;
end
if (iqentry_a1_v[n] == `INV && iqentry_a1_s[n] == commit0_id && iqentry_v[n] == `VAL && commit0_v == `VAL) begin
iqentry_a1[n] <= commit0_bus;
iqentry_a1_v[n] <= `VAL;
end
if (iqentry_a2_v[n] == `INV && iqentry_a2_s[n] == commit0_id && iqentry_v[n] == `VAL && commit0_v == `VAL) begin
iqentry_a2[n] <= commit0_bus;
iqentry_a2_v[n] <= `VAL;
end
if (iqentry_a3_v[n] == `INV && iqentry_a3_s[n] == commit0_id && iqentry_v[n] == `VAL && commit0_v == `VAL) begin
iqentry_a3[n] <= commit0_bus;
iqentry_a3_v[n] <= `VAL;
end
if (iqentry_T_v[n] == `INV && iqentry_T_s[n] == commit0_id && iqentry_v[n] == `VAL && commit0_v == `VAL) begin
iqentry_T[n] <= commit0_bus;
iqentry_T_v[n] <= `VAL;
end
if (iqentry_p_v[n] == `INV && iqentry_p_s[n] == commit1_id && iqentry_v[n] == `VAL && commit1_v == `VAL) begin
iqentry_pred[n] <= commit1_bus[3:0];
iqentry_p_v[n] <= `VAL;
end
if (iqentry_a1_v[n] == `INV && iqentry_a1_s[n] == commit1_id && iqentry_v[n] == `VAL && commit1_v == `VAL) begin
iqentry_a1[n] <= commit1_bus;
iqentry_a1_v[n] <= `VAL;
end
if (iqentry_a2_v[n] == `INV && iqentry_a2_s[n] == commit1_id && iqentry_v[n] == `VAL && commit1_v == `VAL) begin
iqentry_a2[n] <= commit1_bus;
iqentry_a2_v[n] <= `VAL;
end
if (iqentry_a3_v[n] == `INV && iqentry_a3_s[n] == commit1_id && iqentry_v[n] == `VAL && commit1_v == `VAL) begin
iqentry_a3[n] <= commit1_bus;
iqentry_a3_v[n] <= `VAL;
end
if (iqentry_T_v[n] == `INV && iqentry_T_s[n] == commit1_id && iqentry_v[n] == `VAL && commit1_v == `VAL) begin
iqentry_T[n] <= commit1_bus;
iqentry_T_v[n] <= `VAL;
end
end
 
//`include "Thor_issue.v"
// ISSUE
//
// determines what instructions are ready to go, then places them
// in the various ALU queues.
// also invalidates instructions following a branch-miss BEQ or any JALR (STOMP logic)
//
//alu0_dataready <= alu0_available && alu0_issue;
/*
&& ((iqentry_issue[0] && iqentry_islot[0] == 4'd0 && !iqentry_stomp[0])
|| (iqentry_issue[1] && iqentry_islot[1] == 4'd0 && !iqentry_stomp[1])
|| (iqentry_issue[2] && iqentry_islot[2] == 4'd0 && !iqentry_stomp[2])
|| (iqentry_issue[3] && iqentry_islot[3] == 4'd0 && !iqentry_stomp[3])
|| (iqentry_issue[4] && iqentry_islot[4] == 4'd0 && !iqentry_stomp[4])
|| (iqentry_issue[5] && iqentry_islot[5] == 4'd0 && !iqentry_stomp[5])
|| (iqentry_issue[6] && iqentry_islot[6] == 4'd0 && !iqentry_stomp[6])
|| (iqentry_issue[7] && iqentry_islot[7] == 4'd0 && !iqentry_stomp[7]));
*/
//alu1_dataready <= alu1_available && alu1_issue;
/*
&& ((iqentry_issue[0] && iqentry_islot[0] == 4'd1 && !iqentry_stomp[0])
|| (iqentry_issue[1] && iqentry_islot[1] == 4'd1 && !iqentry_stomp[1])
|| (iqentry_issue[2] && iqentry_islot[2] == 4'd1 && !iqentry_stomp[2])
|| (iqentry_issue[3] && iqentry_islot[3] == 4'd1 && !iqentry_stomp[3])
|| (iqentry_issue[4] && iqentry_islot[4] == 4'd1 && !iqentry_stomp[4])
|| (iqentry_issue[5] && iqentry_islot[5] == 4'd1 && !iqentry_stomp[5])
|| (iqentry_issue[6] && iqentry_islot[6] == 4'd1 && !iqentry_stomp[6])
|| (iqentry_issue[7] && iqentry_islot[7] == 4'd1 && !iqentry_stomp[7]));
*/
`ifdef FLOATING_POINT
fp0_dataready <= 1'b1
&& ((iqentry_fpissue[0] && iqentry_islot[0] == 4'd0 && !iqentry_stomp[0])
|| (iqentry_fpissue[1] && iqentry_islot[1] == 4'd0 && !iqentry_stomp[1])
|| (iqentry_fpissue[2] && iqentry_islot[2] == 4'd0 && !iqentry_stomp[2])
|| (iqentry_fpissue[3] && iqentry_islot[3] == 4'd0 && !iqentry_stomp[3])
|| (iqentry_fpissue[4] && iqentry_islot[4] == 4'd0 && !iqentry_stomp[4])
|| (iqentry_fpissue[5] && iqentry_islot[5] == 4'd0 && !iqentry_stomp[5])
|| (iqentry_fpissue[6] && iqentry_islot[6] == 4'd0 && !iqentry_stomp[6])
|| (iqentry_fpissue[7] && iqentry_islot[7] == 4'd0 && !iqentry_stomp[7]));
`endif
 
for (n = 0; n < QENTRIES; n = n + 1)
begin
if (iqentry_v[n] && iqentry_stomp[n]) begin
iqentry_v[n] <= `INV;
if (dram0_id[2:0] == n[2:0]) dram0 <= `DRAMSLOT_AVAIL;
if (dram1_id[2:0] == n[2:0]) dram1 <= `DRAMSLOT_AVAIL;
if (dram2_id[2:0] == n[2:0]) dram2 <= `DRAMSLOT_AVAIL;
end
else if (iqentry_issue[n]) begin
case (iqentry_islot[n])
2'd0: if (alu0_available) begin
alu0_ld <= 1'b1;
alu0_sourceid <= n[3:0];
alu0_insnsz <= iqentry_insnsz[n];
alu0_op <= iqentry_op[n];
alu0_fn <= iqentry_fn[n];
alu0_cond <= iqentry_cond[n];
alu0_bt <= iqentry_bt[n];
alu0_pc <= iqentry_pc[n];
alu0_pred <= iqentry_p_v[n] ? iqentry_pred[n] :
(iqentry_p_s[n] == alu0_id) ? alu0_bus[3:0] :
(iqentry_p_s[n] == alu1_id) ? alu1_bus[3:0] : 4'h0;
alu0_argA <= iqentry_a1_v[n] ? iqentry_a1[n]
: (iqentry_a1_s[n] == alu0_id) ? alu0_bus
: (iqentry_a1_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
alu0_argB <= iqentry_a2_v[n] ? iqentry_a2[n]
: (iqentry_a2_s[n] == alu0_id) ? alu0_bus
: (iqentry_a2_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
alu0_argC <= (iqentry_op[n]==`POP || iqentry_op[n]==`PUSH || iqentry_op[n]==`PEA) ? {sregs[3'd6],12'h000} :
iqentry_mem[n] ? {sregs[iqentry_fn[n][5:3]],12'h000} :
iqentry_a3_v[n] ? iqentry_a3[n]
: (iqentry_a3_s[n] == alu0_id) ? alu0_bus
: (iqentry_a3_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
alu0_argT <= iqentry_T_v[n] ? iqentry_T[n]
: (iqentry_T_s[n] == alu0_id) ? alu0_bus
: (iqentry_T_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
alu0_argI <= iqentry_a0[n];
alu0_dataready <= fnAluValid(iqentry_op[n],iqentry_fn[n]);
end
2'd1: if (alu1_available) begin
alu1_ld <= 1'b1;
alu1_sourceid <= n[3:0];
alu1_insnsz <= iqentry_insnsz[n];
alu1_op <= iqentry_op[n];
alu1_fn <= iqentry_fn[n];
alu1_cond <= iqentry_cond[n];
alu1_bt <= iqentry_bt[n];
alu1_pc <= iqentry_pc[n];
alu1_pred <= iqentry_p_v[n] ? iqentry_pred[n] :
(iqentry_p_s[n] == alu0_id) ? alu0_bus[3:0] :
(iqentry_p_s[n] == alu1_id) ? alu1_bus[3:0] : 4'h0;
alu1_argA <= iqentry_a1_v[n] ? iqentry_a1[n]
: (iqentry_a1_s[n] == alu0_id) ? alu0_bus
: (iqentry_a1_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
alu1_argB <= iqentry_a2_v[n] ? iqentry_a2[n]
: (iqentry_a2_s[n] == alu0_id) ? alu0_bus
: (iqentry_a2_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
alu1_argC <= (iqentry_op[n]==`POP || iqentry_op[n]==`PUSH || iqentry_op[n]==`PEA) ? {sregs[3'd6],12'h000} :
iqentry_mem[n] ? {sregs[iqentry_fn[n][5:3]],12'h000} :
iqentry_a3_v[n] ? iqentry_a3[n]
: (iqentry_a3_s[n] == alu0_id) ? alu0_bus
: (iqentry_a3_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
alu1_argT <= iqentry_T_v[n] ? iqentry_T[n]
: (iqentry_T_s[n] == alu0_id) ? alu0_bus
: (iqentry_T_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
alu1_argI <= iqentry_a0[n];
alu1_dataready <= fnAluValid(iqentry_op[n],iqentry_fn[n]);
end
default: panic <= `PANIC_INVALIDISLOT;
endcase
iqentry_out[n] <= `TRUE;
// if it is a memory operation, this is the address-generation step ... collect result into arg1
if (iqentry_mem[n] && iqentry_op[n]!=`TLB) begin
iqentry_a1_v[n] <= `INV;
iqentry_a1_s[n] <= n[3:0];
end
end
end
 
 
`ifdef FLOATING_POINT
for (n = 0; n < QENTRIES; n = n + 1)
begin
if (iqentry_v[n] && iqentry_stomp[n])
;
else if (iqentry_fpissue[n]) begin
case (iqentry_fpislot[n])
2'd0: if (1'b1) begin
fp0_ld <= 1'b1;
fp0_sourceid <= n[3:0];
fp0_op <= iqentry_op[n];
fp0_fn <= iqentry_fn[n];
fp0_cond <= iqentry_cond[n];
fp0_pred <= iqentry_p_v[n] ? iqentry_pred[n] :
(iqentry_p_s[n] == alu0_id) ? alu0_bus[3:0] :
(iqentry_p_s[n] == alu1_id) ? alu1_bus[3:0] : 4'h0;
fp0_argA <= iqentry_a1_v[n] ? iqentry_a1[n]
: (iqentry_a1_s[n] == alu0_id) ? alu0_bus
: (iqentry_a1_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
fp0_argB <= iqentry_a2_v[n] ? iqentry_a2[n]
: (iqentry_a2_s[n] == alu0_id) ? alu0_bus
: (iqentry_a2_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
fp0_argC <= iqentry_a3_v[n] ? iqentry_a3[n]
: (iqentry_a3_s[n] == alu0_id) ? alu0_bus
: (iqentry_a3_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
fp0_argT <= iqentry_T_v[n] ? iqentry_T[n]
: (iqentry_T_s[n] == alu0_id) ? alu0_bus
: (iqentry_T_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
fp0_argI <= iqentry_a0[n];
end
default: panic <= `PANIC_INVALIDISLOT;
endcase
iqentry_out[n] <= `TRUE;
end
end
`endif
 
// MEMORY
//
// update the memory queues and put data out on bus if appropriate
// Always puts data on the bus even for stores. In the case of
// stores, the data is ignored.
//
//
// dram0, dram1, dram2 are the "state machines" that keep track
// of three pipelined DRAM requests. if any has the value "00",
// then it can accept a request (which bumps it up to the value "01"
// at the end of the cycle). once it hits the value "10" the request
// and the bus is acknowledged the dram request
// is finished and the dram_bus takes the value. if it is a store, the
// dram_bus value is not used, but the dram_v value along with the
// dram_id value signals the waiting memq entry that the store is
// completed and the instruction can commit.
//
if (tlb_state != 3'd0 && tlb_state < 3'd3)
tlb_state <= tlb_state + 3'd1;
if (tlb_state==3'd3) begin
dram_v <= `TRUE;
dram_id <= tlb_id;
dram_tgt <= tlb_tgt;
dram_exc <= `EXC_NONE;
dram_bus <= tlb_dato;
tlb_op <= 4'h0;
tlb_state <= 3'd0;
end
 
case(dram0)
// The first state is to translate the virtual to physical address.
3'd1:
begin
$display("0MEM %c:%h %h cycle started",fnIsLoad(dram0_op)?"L" : "S", dram0_addr, dram0_data);
if (dbg_lmatch|dbg_smatch) begin
dram_v <= `TRUE;
dram_id <= dram0_id;
dram_tgt <= dram0_tgt;
dram_exc <= `EXC_DBG;
dram_bus <= 64'h0;
dram0 <= 3'd0;
end
`ifdef SEGMENTATION
else if (dram0_addr[ABW-1:12] >= dram0_lmt) begin
dram_v <= `TRUE; // we are finished the memory cycle
dram_id <= dram0_id;
dram_tgt <= dram0_tgt;
dram_exc <= `EXC_SEGV; //dram0_exc;
dram_bus <= 64'h0;
dram0 <= 3'd0;
end
`endif
else if (!cyc_o) dram0 <= dram0 + 3'd1;
end
 
// State 2:
// Check for a TLB miss on the translated address, and
// Initiate a bus transfer
3'd2:
if (DTLBMiss) begin
dram_v <= `TRUE; // we are finished the memory cycle
dram_id <= dram0_id;
dram_tgt <= dram0_tgt;
dram_exc <= `EXC_TLBMISS; //dram0_exc;
dram_bus <= 64'h0;
dram0 <= 3'd0;
end
else if (dram0_exc!=`EXC_NONE) begin
dram_v <= `TRUE; // we are finished the memory cycle
dram_id <= dram0_id;
dram_tgt <= dram0_tgt;
dram_exc <= dram0_exc;
dram_bus <= 64'h0;
dram0 <= 3'd0;
end
else begin
if (dram0_op==`LCL) begin
if (dram0_tgt==7'd0) begin
ic_invalidate_line <= `TRUE;
ic_lineno <= dram0_addr;
end
dram0 <= 3'd6;
end
else if (uncached || fnIsStore(dram0_op) || fnIsLoadV(dram0_op) || dram0_op==`CAS ||
((dram0_op==`STMV || dram0_op==`INC) && stmv_flag)) begin
if (cstate==IDLE) begin // make sure an instruction load isn't taking place
dram0_owns_bus <= `TRUE;
resv_o <= dram0_op==`LVWAR;
cres_o <= dram0_op==`SWCR;
lock_o <= dram0_op==`CAS;
cyc_o <= 1'b1;
stb_o <= 1'b1;
we_o <= fnIsStore(dram0_op) || ((dram0_op==`STMV || dram0_op==`INC) && stmv_flag);
sel_o <= fnSelect(dram0_op,dram0_fn,pea);
rsel <= fnSelect(dram0_op,dram0_fn,pea);
adr_o <= pea;
if (dram0_op==`INC)
dat_o <= fnDatao(dram0_op,dram0_fn,dram0_data) + index;
else
dat_o <= fnDatao(dram0_op,dram0_fn,dram0_data);
dram0 <= dram0 + 3'd1;
end
end
else begin // cached read
dram0 <= 3'd6;
rsel <= fnSelect(dram0_op,dram0_fn,pea);
end
end
 
// State 3:
// Wait for a memory ack
3'd3:
if (ack_i|err_i) begin
$display("MEM ack");
dram_v <= dram0_op != `CAS && dram0_op != `INC && dram0_op != `STS && dram0_op != `STMV && dram0_op != `STCMP && dram0_op != `STFND;
dram_id <= dram0_id;
dram_tgt <= dram0_tgt;
dram_exc <= (err_i & dram0_tgt!=7'd0) ? `EXC_DBE : `EXC_NONE;//dram0_exc;
if (dram0_op==`SWCR)
dram_bus <= {63'd0,resv_i};
else
dram_bus <= fnDatai(dram0_op,dram0_fn,dat_i,rsel);
dram0_owns_bus <= `FALSE;
wb_nack();
dram0 <= 3'd7;
case(dram0_op)
`ifdef STRINGOPS
`STS:
if (lc != 0 && !int_pending) begin
dram0_owns_bus <= `TRUE;
dram0_addr <= dram0_addr +
(dram0_fn[2:0]==3'd0 ? 64'd1 :
dram0_fn[2:0]==3'd1 ? 64'd2 :
dram0_fn[2:0]==3'd2 ? 64'd4 :
64'd8);
lc <= lc - 64'd1;
dram0 <= 3'd1;
dram_bus <= dram0_addr +
(dram0_fn[2:0]==3'd0 ? 64'd1 :
dram0_fn[2:0]==3'd1 ? 64'd2 :
dram0_fn[2:0]==3'd2 ? 64'd4 :
64'd8);
end
else begin
dram_bus <= dram0_addr +
(dram0_fn[2:0]==3'd0 ? 64'd1 :
dram0_fn[2:0]==3'd1 ? 64'd2 :
dram0_fn[2:0]==3'd2 ? 64'd4 :
64'd8) - dram0_seg;
dram_v <= `VAL;
end
`STMV,`STCMP:
if (lc != 0 && !(int_pending && stmv_flag)) begin
dram0 <= 3'd1;
dram0_owns_bus <= `TRUE;
if (stmv_flag) begin
dram0_addr <= src_addr + index;
if (dram0_op==`STCMP) begin
if (dram0_data != fnDatai(dram0_op,dram0_fn,dat_i,rsel)) begin
lc <= 64'd0;
dram0 <= 3'd7;
dram_v <= `VAL;
dram_bus <= index;
end
end
end
else begin
dram0_addr <= dst_addr + index;
dram0_data <= fnDatai(dram0_op,dram0_fn,dat_i,rsel);
end
if (!stmv_flag)
inc_index(dram0_fn);
stmv_flag <= ~stmv_flag;
end
else begin
dram_bus <= index;
dram_v <= `VAL;
end
`STFND:
if (lc != 0 && !int_pending) begin
dram0_addr <= src_addr + index;
inc_index(dram0_fn);
if (dram0_data == dram_bus) begin
lc <= 64'd0;
dram0 <= 3'd7;
dram_v <= `VAL;
dram_bus <= index;
end
else
dram0 <= 3'd1;
end
else begin
dram_bus <= index;
dram_v <= `VAL;
end
`endif
`CAS:
if (dram0_datacmp == dat_i) begin
$display("CAS match");
dram0_owns_bus <= `TRUE;
cyc_o <= 1'b1; // hold onto cyc_o
dram0 <= dram0 + 3'd1;
end
else
dram_v <= `VAL;
`INC:
begin
if (stmv_flag) begin
dram_v <= `VAL;
end
else begin
dram0_data <= fnDatai(dram0_op,dram0_fn,dat_i,rsel);
stmv_flag <= ~stmv_flag;
dram0 <= 3'd2;
end
end
default: ;
endcase
end
 
// State 4:
// Start a second bus transaction for the CAS instruction
3'd4:
begin
stb_o <= 1'b1;
we_o <= 1'b1;
sel_o <= fnSelect(dram0_op,dram0_fn,pea);
adr_o <= pea;
dat_o <= fnDatao(dram0_op,dram0_fn,dram0_data);
dram0 <= dram0 + 3'd1;
end
 
// State 5:
// Wait for a memory ack for the second bus transaction of a CAS
//
3'd5:
if (ack_i|err_i) begin
$display("MEM ack2");
dram_v <= `VAL;
dram_id <= dram0_id;
dram_tgt <= dram0_tgt;
dram_exc <= (err_i & dram0_tgt!=7'd0) ? `EXC_DBE : `EXC_NONE;
dram0_owns_bus <= `FALSE;
wb_nack();
lock_o <= 1'b0;
dram0 <= 3'd7;
end
 
// State 6:
// Wait for a data cache read hit
3'd6:
if (rhit && dram0_op!=`LCL) begin
case(dram0_op)
`ifdef STRINGOPS
// The read portion of the STMV was just done, go back and do
// the write portion.
`STMV:
begin
stmv_flag <= `TRUE;
dram0_addr <= dst_addr + index;
dram0_data <= fnDatai(dram0_op,dram0_fn,cdat,rsel);
dram0 <= 3'd2;
end
`STCMP:
if (lc != 0 && !int_pending && stmv_flag) begin
dram0_addr <= src_addr + index;
stmv_flag <= ~stmv_flag;
if (dram0_data != dram_bus) begin
lc <= 64'd0;
dram0 <= 3'd7;
dram_v <= `VAL;
dram_bus <= index;
dram_id <= dram0_id;
dram_tgt <= dram0_tgt;
end
end
else if (!stmv_flag) begin
stmv_flag <= ~stmv_flag;
dram0_addr <= dst_addr + index;
dram0_data <= fnDatai(dram0_op,dram0_fn,cdat,rsel);
dram0 <= 3'd2;
inc_index(dram0_fn);
end
else begin
dram_id <= dram0_id;
dram_tgt <= dram0_tgt;
dram_bus <= index;
dram_v <= `VAL;
dram0 <= 3'd7;
end
`STFND:
if (lc != 0 && !int_pending) begin
dram0_addr <= src_addr + index;
inc_index(dram0_fn);
if (dram0_data == dram_bus) begin
lc <= 64'd0;
dram_id <= dram0_id;
dram_tgt <= dram0_tgt;
dram0 <= 3'd7;
dram_v <= `VAL;
dram_bus <= index;
end
end
else begin
dram_id <= dram0_id;
dram_tgt <= dram0_tgt;
dram_bus <= index;
dram_v <= `VAL;
dram0 <= 3'd7;
end
`endif
`INC:
begin
dram0_data <= fnDatai(dram0_op,dram0_fn,cdat,rsel);
stmv_flag <= `TRUE;
dram0 <= 3'd2;
end
default: begin
$display("Read hit [%h]",dram0_addr);
dram_v <= `TRUE;
dram_id <= dram0_id;
dram_tgt <= dram0_tgt;
dram_exc <= `EXC_NONE;
dram_bus <= fnDatai(dram0_op,dram0_fn,cdat,rsel);
dram0 <= 3'd0;
end
endcase
end
3'd7:
dram0 <= 3'd0;
endcase
 
//
// determine if the instructions ready to issue can, in fact, issue.
// "ready" means that the instruction has valid operands but has not gone yet
//
// Stores can only issue if there is no possibility of a change of program flow.
// That means no flow control operations or instructions that can cause an
// exception can be before the store.
iqentry_memissue[ head0 ] <= iqentry_memissue_head0;
iqentry_memissue[ head1 ] <= iqentry_memissue_head1;
iqentry_memissue[ head2 ] <= iqentry_memissue_head2;
iqentry_memissue[ head3 ] <= iqentry_memissue_head3;
iqentry_memissue[ head4 ] <= iqentry_memissue_head4;
iqentry_memissue[ head5 ] <= iqentry_memissue_head5;
iqentry_memissue[ head6 ] <= iqentry_memissue_head6;
iqentry_memissue[ head7 ] <= iqentry_memissue_head7;
/* ||
( !fnIsFlowCtrl(iqentry_op[head0])
&& !fnIsFlowCtrl(iqentry_op[head1])
&& !fnIsFlowCtrl(iqentry_op[head2])
&& !fnIsFlowCtrl(iqentry_op[head3])
&& !fnIsFlowCtrl(iqentry_op[head4])
&& !fnIsFlowCtrl(iqentry_op[head5])
&& !fnIsFlowCtrl(iqentry_op[head6])));
*/
//
// take requests that are ready and put them into DRAM slots
 
if (dram0 == `DRAMSLOT_AVAIL) dram0_exc <= `EXC_NONE;
 
// Memory should also wait until segment registers are valid. The segment
// registers are essentially static registers while a program runs. They are
// setup by only the operating system. The system software must ensure the
// segment registers are stable before they get used. We don't bother checking
// for rf_v[].
//
for (n = 0; n < QENTRIES; n = n + 1)
if (!iqentry_stomp[n] && iqentry_memissue[n] && iqentry_agen[n] && iqentry_op[n]==`TLB && !iqentry_out[n]) begin
$display("TLB issue");
if (!iq_cmt[n]) begin
iqentry_cmt[n] <= `FALSE;
iqentry_done[n] <= `TRUE;
iqentry_out[n] <= `FALSE;
iqentry_agen[n] <= `FALSE;
iqentry_res[n] <= iqentry_T_v[n] ? iqentry_T[n]
: (iqentry_T_s[n] == alu0_id) ? alu0_bus
: (iqentry_T_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
end
else if (tlb_state==3'd0) begin
tlb_state <= 3'd1;
tlb_id <= {1'b1, n[2:0]};
tlb_op <= iqentry_a0[n][3:0];
tlb_regno <= iqentry_a0[n][7:4];
tlb_tgt <= iqentry_tgt[n];
tlb_data <= iqentry_a1[n];
iqentry_out[n] <= `TRUE;
end
end
else if (!iqentry_stomp[n] && iqentry_memissue[n] && iqentry_agen[n] && !iqentry_out[n]) begin
if (!iq_cmt[n]) begin
iqentry_cmt[n] <= `FALSE;
iqentry_done[n] <= `TRUE;
iqentry_out[n] <= `FALSE;
iqentry_agen[n] <= `FALSE;
iqentry_res[n] <= iqentry_T_v[n] ? iqentry_T[n]
: (iqentry_T_s[n] == alu0_id) ? alu0_bus
: (iqentry_T_s[n] == alu1_id) ? alu1_bus
: 64'hDEADDEADDEADDEAD;
end
else begin
if (fnIsStoreString(iqentry_op[n]))
string_pc <= iqentry_pc[n];
$display("issued memory cycle");
if (dram0 == `DRAMSLOT_AVAIL) begin
dram0 <= 3'd1;
dram0_id <= { 1'b1, n[2:0] };
dram0_op <= iqentry_op[n];
dram0_fn <= iqentry_fn[n];
dram0_tgt <= iqentry_tgt[n];
dram0_data <= (fnIsIndexed(iqentry_op[n]) || iqentry_op[n]==`CAS) ? iqentry_a3[n] :
`ifdef STACKOPS
iqentry_op[n]==`PEA ? iqentry_a2[n] + iqentry_a0[n] :
`endif
iqentry_a2[n];
dram0_datacmp <= iqentry_a2[n];
`ifdef SEGMENTATION
dram0_addr <= iqentry_a1[n];
dram0_seg <= {sregs[iqentry_fn[n][5:3]],12'h000};
dram0_lmt <= sregs[iqentry_fn[n][5:3]] + sregs_lmt[iqentry_fn[n][5:3]];
// dram0_exc <= (iqentry_a1[n][ABW-1:12] >= sregs_lmt[iqentry_fn[n][5:3]]) ? `EXC_SEGV : `EXC_NONE;
`ifdef STRINGOPS
src_addr <= iqentry_a1[n] + {sregs[iqentry_fn[n][5:3]],12'h000};
dst_addr <= iqentry_a2[n] + {sregs[iqentry_fn[n][5:3]],12'h000};
`endif
`else
dram0_addr <= iqentry_a1[n];
`ifdef STRINGOPS
src_addr <= iqentry_a1[n];
dst_addr <= iqentry_a2[n];
`endif
`endif
stmv_flag <= `FALSE;
index <= iqentry_op[n]==`INC ? iqentry_a2[n] : iqentry_a3[n];
iqentry_out[n] <= `TRUE;
end
end
end
 
for (n = 0; n < QENTRIES; n = n + 1)
begin
if (iqentry_op[n]==`IMM && iqentry_v[(n+1)&7] &&
((iqentry_pc[(n+1)&7]==iqentry_pc[n]+iqentry_insnsz[n]) ||
(iqentry_pc[(n+1)&7]==iqentry_pc[n]))) // address inherited due to interrupt
iqentry_done[n] <= `TRUE;
/*
if (iqentry_v[n] && args_valid[n] && !iqentry_out[n] && !iq_cmt[n] && iqentry_op[n]!=`IMM) begin
iqentry_done[n] <= `TRUE;
iqentry_res[n] <= iqentry_T[n];
end
*/
if (!iqentry_v[n])
iqentry_done[n] <= `FALSE;
/*
if (iqentry_v[n] && !iqentry_done[n]) begin
if (!iqentry_a1_v[n] && iqentry_v[iqentry_a1_s[n][2:0]] && iqentry_done[iqentry_a1_s[n][2:0]]) begin
iqentry_a1_v[n] <= `VAL;
iqentry_a1[n] <= iqentry_res[iqentry_a1_s[n][2:0]];
end
if (!iqentry_a2_v[n] && iqentry_v[iqentry_a2_s[n][2:0]] && iqentry_done[iqentry_a2_s[n][2:0]]) begin
iqentry_a2_v[n] <= `VAL;
iqentry_a2[n] <= iqentry_res[iqentry_a2_s[n][2:0]];
end
if (!iqentry_a3_v[n] && iqentry_v[iqentry_a3_s[n][2:0]] && iqentry_done[iqentry_a3_s[n][2:0]]) begin
iqentry_a3_v[n] <= `VAL;
iqentry_a3[n] <= iqentry_res[iqentry_a3_s[n][2:0]];
end
end
*/
end
 
// $display("TLB: en=%b imatch=%b pgsz=%d pcs=%h phys=%h", utlb1.TLBenabled,utlb1.IMatch,utlb1.PageSize,utlb1.pcs,utlb1.IPFN);
// for (i = 0; i < 64; i = i + 1)
// $display("vp=%h G=%b",utlb1.TLBVirtPage[i],utlb1.TLBG[i]);
//`include "Thor_commit.v"
// It didn't work in simulation when the following was declared under an
// independant always clk block
//
commit_spr(commit0_v,commit0_tgt,commit0_bus);
commit_spr(commit1_v,commit1_tgt,commit1_bus);
// When the INT instruction commits set the hardware interrupt status to disable further interrupts.
if (int_commit)
begin
$display("*********************");
$display("*********************");
$display("Interrupt committing");
$display("*********************");
$display("*********************");
StatusHWI <= `TRUE;
imb <= im;
im <= 1'b0;
// Reset the nmi edge sense circuit but only for an NMI
if ((iqentry_a0[head0][7:0]==8'hFE && commit0_v && iqentry_op[head0]==`INT) ||
(iqentry_a0[head1][7:0]==8'hFE && commit1_v && iqentry_op[head1]==`INT))
nmi_edge <= 1'b0;
string_pc <= 64'd0;
end
 
if (sys_commit)
begin
if (StatusEXL!=8'hFF)
StatusEXL <= StatusEXL + 8'd1;
end
 
oddball_commit(commit0_v,head0);
oddball_commit(commit1_v,head1);
 
//
// COMMIT PHASE (dequeue only ... not register-file update)
//
// If the third instruction is invalidated or if it doesn't update the register
// file then it is allowed to commit too.
// The head pointer might advance by three.
//
if (~|panic)
casex ({ iqentry_v[head0],
iqentry_done[head0],
iqentry_v[head1],
iqentry_done[head1],
iqentry_v[head2],
iqentry_done[head2]})
 
// retire 3
6'b0x_0x_0x:
if (head0 != tail0 && head1 != tail0 && head2 != tail0) begin
head_inc(3);
end
else if (head0 != tail0 && head1 != tail0) begin
head_inc(2);
end
else if (head0 != tail0) begin
head_inc(1);
end
 
// retire 2 (wait for regfile for head2)
6'b0x_0x_10:
begin
head_inc(2);
end
 
// retire 2 or 3 (wait for regfile for head2)
6'b0x_0x_11:
begin
if (iqentry_tgt[head2]==7'd0) begin
iqentry_v[head2] <= `INV;
head_inc(3);
end
else begin
head_inc(2);
end
end
 
// retire 3
6'b0x_11_0x:
if (head1 != tail0 && head2 != tail0) begin
iqentry_v[head1] <= `INV;
head_inc(3);
end
else begin
iqentry_v[head1] <= `INV;
head_inc(2);
end
 
// retire 2 (wait on head2 or wait on register file for head2)
6'b0x_11_10:
begin
iqentry_v[head1] <= `INV;
head_inc(2);
end
6'b0x_11_11:
begin
if (iqentry_tgt[head2]==7'd0) begin
iqentry_v[head1] <= `INV;
iqentry_v[head2] <= `INV;
head_inc(3);
end
else begin
iqentry_v[head1] <= `INV;
head_inc(2);
end
end
 
// 4'b00_00 - neither valid; skip both
// 4'b00_01 - neither valid; skip both
// 4'b00_10 - skip head0, wait on head1
// 4'b00_11 - skip head0, commit head1
// 4'b01_00 - neither valid; skip both
// 4'b01_01 - neither valid; skip both
// 4'b01_10 - skip head0, wait on head1
// 4'b01_11 - skip head0, commit head1
// 4'b10_00 - wait on head0
// 4'b10_01 - wait on head0
// 4'b10_10 - wait on head0
// 4'b10_11 - wait on head0
// 4'b11_00 - commit head0, skip head1
// 4'b11_01 - commit head0, skip head1
// 4'b11_10 - commit head0, wait on head1
// 4'b11_11 - commit head0, commit head1
 
//
// retire 0 (stuck on head0)
6'b10_xx_xx: ;
// retire 3
6'b11_0x_0x:
if (head1 != tail0 && head2 != tail0) begin
iqentry_v[head0] <= `INV;
head_inc(3);
end
else if (head1 != tail0) begin
iqentry_v[head0] <= `INV;
head_inc(2);
end
else begin
iqentry_v[head0] <= `INV;
head_inc(1);
end
 
// retire 2 (wait for regfile for head2)
6'b11_0x_10:
begin
iqentry_v[head0] <= `INV;
head_inc(2);
end
 
// retire 2 or 3 (wait for regfile for head2)
6'b11_0x_11:
if (iqentry_tgt[head2]==7'd0) begin
iqentry_v[head0] <= `INV;
iqentry_v[head2] <= `INV;
head_inc(3);
end
else begin
iqentry_v[head0] <= `INV;
head_inc(2);
end
 
//
// retire 1 (stuck on head1)
6'b00_10_xx,
6'b01_10_xx,
6'b11_10_xx:
if (iqentry_v[head0] || head0 != tail0) begin
iqentry_v[head0] <= `INV;
head_inc(1);
end
 
// retire 2 or 3
6'b11_11_0x:
if (head2 != tail0) begin
iqentry_v[head0] <= `INV; // may conflict with STOMP, but since both are setting to 0, it is okay
iqentry_v[head1] <= `INV;
head_inc(3);
end
else begin
iqentry_v[head0] <= `INV;
iqentry_v[head1] <= `INV;
head_inc(2);
end
 
// retire 2 (wait on regfile for head2)
6'b11_11_10:
begin
iqentry_v[head0] <= `INV; // may conflict with STOMP, but since both are setting to 0, it is okay
iqentry_v[head1] <= `INV; // may conflict with STOMP, but since both are setting to 0, it is okay
head_inc(2);
end
6'b11_11_11:
if (iqentry_tgt[head2]==7'd0) begin
iqentry_v[head0] <= `INV; // may conflict with STOMP, but since both are setting to 0, it is okay
iqentry_v[head1] <= `INV; // may conflict with STOMP, but since both are setting to 0, it is okay
iqentry_v[head2] <= `INV; // may conflict with STOMP, but since both are setting to 0, it is okay
head_inc(3);
end
else begin
iqentry_v[head0] <= `INV; // may conflict with STOMP, but since both are setting to 0, it is okay
iqentry_v[head1] <= `INV; // may conflict with STOMP, but since both are setting to 0, it is okay
head_inc(2);
end
endcase
 
if (branchmiss)
rrmapno <= iqentry_renmapno[missid];
 
case(cstate)
RESET1:
begin
ic_ld <= `TRUE;
ic_ld_cntr <= 32'd0;
cstate <= RESET2;
end
RESET2:
begin
ic_ld_cntr <= ic_ld_cntr + 32'd32;
if (ic_ld_cntr >= 32'd32768) begin
ic_ld <= `FALSE;
ic_ld_cntr <= 32'd0;
cstate <= IDLE;
end;
end
IDLE:
if (dcache_access_pending) begin
$display("********************");
$display("DCache access to: %h",{pea[DBW-1:5],5'b00000});
$display("********************");
derr <= 1'b0;
bte_o <= 2'b00;
cti_o <= 3'b001;
bl_o <= DBW==32 ? 5'd7 : 5'd3;
cyc_o <= 1'b1;
stb_o <= 1'b1;
we_o <= 1'b0;
sel_o <= {DBW/8{1'b1}};
adr_o <= {pea[DBW-1:5],5'b00000};
dat_o <= {DBW{1'b0}};
cstate <= DCACHE1;
end
else if ((!ihit && !mem_issue && dram0==3'd0)||(dram0==3'd6 && (dram0_op==`LCL && dram0_tgt==7'd0))) begin
if ((dram0!=2'd0 || dram1!=2'd0 || dram2!=2'd0) && !(dram0==3'd6 && (dram0_op==`LCL && dram0_tgt==7'd0)))
$display("drams non-zero");
else begin
$display("********************");
$display("ICache access to: %h",
(dram0==3'd6 && (dram0_op==`LCL && dram0_tgt==7'd0)) ? {dram0_addr[ABW-1:5],5'h00} :
!hit0 ? {ppc[DBW-1:5],5'b00000} : {ppcp16[DBW-1:5],5'b00000});
$display("********************");
ierr <= 1'b0;
bte_o <= 2'b00;
cti_o <= 3'b001;
bl_o <= DBW==32 ? 5'd7 : 5'd3;
cyc_o <= 1'b1;
stb_o <= 1'b1;
we_o <= 1'b0;
sel_o <= {DBW/8{1'b1}};
adr_o <= (dram0==3'd6 && (dram0_op==`LCL && dram0_tgt==7'd0)) ? {dram0_addr[ABW-1:5],5'h00} : !hit0 ? {ppc[DBW-1:5],5'b00000} : {ppcp16[DBW-1:5],5'b00000};
dat_o <= {DBW{1'b0}};
cstate <= ICACHE1;
end
end
ICACHE1:
begin
if (ack_i|err_i) begin
ierr <= ierr | err_i; // cumulate an error status
if (DBW==32) begin
adr_o[4:2] <= adr_o[4:2] + 3'd1;
if (adr_o[4:2]==3'b110)
cti_o <= 3'b111;
if (adr_o[4:2]==3'b111) begin
wb_nack();
cstate <= IDLE;
if (dram0==3'd6 && dram0_op==`LCL) begin
dram0_op<=`NOP;
end
end
end
else begin
adr_o[4:3] <= adr_o[4:3] + 2'd1;
if (adr_o[4:3]==2'b10)
cti_o <= 3'b111;
if (adr_o[4:3]==2'b11) begin
wb_nack();
cstate <= IDLE;
if (dram0==3'd6 && dram0_op==`LCL) begin
dram0_op<=`NOP;
end
end
end
end
end
DCACHE1:
begin
if (ack_i|err_i) begin
derr <= derr | err_i; // cumulate an error status
if (DBW==32) begin
adr_o[4:2] <= adr_o[4:2] + 3'd1;
if (adr_o[4:2]==3'b110)
cti_o <= 3'b111;
if (adr_o[4:2]==3'b111) begin
wb_nack();
cstate <= IDLE;
if (dram0_op==`LCL) begin
dram0_op <= `NOP;
dram0_tgt <= 7'd0;
end
end
end
else begin
adr_o[4:3] <= adr_o[4:3] + 2'd1;
if (adr_o[4:3]==2'b10)
cti_o <= 3'b111;
if (adr_o[4:3]==2'b11) begin
wb_nack();
cstate <= IDLE;
if (dram0_op==`LCL) begin
dram0_op <= `NOP;
dram0_tgt <= 7'd0;
end
end
end
end
end
default: cstate <= IDLE;
endcase
 
// for (i=0; i<8; i=i+1)
// $display("%d: %h %d %o #", i, urf1.regs0[i], rf_v[i], rf_source[i]);
 
if (ihit) begin
$display("dr=%d I=%h A=%h B=%h op=%c%d bt=%d src=%o pc=%h #",
alu0_dataready, alu0_argI, alu0_argA, alu0_argB,
(fnIsFlowCtrl(alu0_op) ? 98 : (fnIsMem(alu0_op)) ? 109 : 97),
alu0_op, alu0_bt, alu0_sourceid, alu0_pc);
$display("dr=%d I=%h A=%h B=%h op=%c%d bt=%d src=%o pc=%h #",
alu1_dataready, alu1_argI, alu1_argA, alu1_argB,
(fnIsFlowCtrl(alu1_op) ? 98 : (fnIsMem(alu1_op)) ? 109 : 97),
alu1_op, alu1_bt, alu1_sourceid, alu1_pc);
$display("v=%d bus=%h id=%o 0 #", alu0_v, alu0_bus, alu0_id);
$display("bmiss0=%b src=%o mpc=%h #", alu0_branchmiss, alu0_sourceid, alu0_misspc);
$display("cmt=%b cnd=%d prd=%d", alu0_cmt, alu0_cond, alu0_pred);
$display("bmiss1=%b src=%o mpc=%h #", alu1_branchmiss, alu1_sourceid, alu1_misspc);
$display("cmt=%b cnd=%d prd=%d", alu1_cmt, alu1_cond, alu1_pred);
$display("bmiss=%b mpc=%h", branchmiss, misspc);
 
$display("0: %d %h %o 0%d #", commit0_v, commit0_bus, commit0_id, commit0_tgt);
$display("1: %d %h %o 0%d #", commit1_v, commit1_bus, commit1_id, commit1_tgt);
end
if (|panic) begin
$display("");
$display("-----------------------------------------------------------------");
$display("-----------------------------------------------------------------");
$display("--------------- PANIC:%s -----------------", message[panic]);
$display("-----------------------------------------------------------------");
$display("-----------------------------------------------------------------");
$display("");
$display("instructions committed: %d", I);
$display("total execution cycles: %d", $time / 10);
$display("");
end
if (|panic && ~outstanding_stores) begin
$finish;
end
end
 
task wb_nack;
begin
resv_o <= 1'b0;
cres_o <= 1'b0;
bte_o <= 2'b00;
cti_o <= 3'b000;
bl_o <= 5'd0;
cyc_o <= 1'b0;
stb_o <= 1'b0;
we_o <= 1'b0;
sel_o <= 8'h00;
adr_o <= {DBW{1'b0}};
dat_o <= {DBW{1'b0}};
end
endtask
 
task commit_spr;
input commit_v;
input [6:0] commit_tgt;
input [DBW-1:0] commit_bus;
begin
if (commit_v && commit_tgt[6]) begin
casex(commit_tgt[5:0])
6'b00xxxx: begin
pregs[commit_tgt[3:0]] <= commit_bus[3:0];
$display("pregs[%d]<=%h", commit_tgt[3:0], commit_bus[3:0]);
// $stop;
end
6'b01xxxx: begin
cregs[commit_tgt[3:0]] <= commit_bus;
$display("cregs[%d]<=%h", commit_tgt[3:0], commit_bus);
end
`ifdef SEGMENTATION
6'b100xxx: begin
sregs[commit_tgt[2:0]] <= commit_bus[DBW-1:12];
$display("sregs[%d]<=%h", commit_tgt[2:0], commit_bus);
end
6'b101xxx: sregs_lmt[commit_tgt[2:0]] <= commit_bus[DBW-1:12];
`endif
6'b110000:
begin
pregs[0] <= commit_bus[3:0];
pregs[1] <= commit_bus[7:4];
pregs[2] <= commit_bus[11:8];
pregs[3] <= commit_bus[15:12];
pregs[4] <= commit_bus[19:16];
pregs[5] <= commit_bus[23:20];
pregs[6] <= commit_bus[27:24];
pregs[7] <= commit_bus[31:28];
if (DBW==64) begin
pregs[8] <= commit_bus[35:32];
pregs[9] <= commit_bus[39:36];
pregs[10] <= commit_bus[43:40];
pregs[11] <= commit_bus[47:44];
pregs[12] <= commit_bus[51:48];
pregs[13] <= commit_bus[55:52];
pregs[14] <= commit_bus[59:56];
pregs[15] <= commit_bus[63:60];
end
end
`LCTR: begin lc <= commit_bus; $display("LC <= %h", commit_bus); end
`ASID: asid <= commit_bus;
`SR: begin
GM <= commit_bus[7:0];
GMB <= commit_bus[23:16];
imb <= commit_bus[31];
im <= commit_bus[15];
fxe <= commit_bus[12];
end
6'd60: spr_bir <= commit_bus[11:0];
6'd61:
case(spr_bir[5:0])
6'd0: dbg_adr0 <= commit_bus;
6'd1: dbg_adr1 <= commit_bus;
6'd2: dbg_adr2 <= commit_bus;
6'd3: dbg_adr3 <= commit_bus;
6'd4: dbg_ctrl <= commit_bus;
endcase
6'b111111:
begin
ld_clk_throttle <= `TRUE;
clk_throttle_new <= commit_bus[15:0];
end
endcase
end
end
endtask
 
// For string memory operations.
//
task inc_index;
input [5:0] fn;
begin
case(fn[2:0])
3'd0: index <= index + 64'd1;
3'd1: index <= index + 64'd2;
3'd2: index <= index + 64'd4;
3'd3: index <= index + 64'd8;
3'd4: index <= index - 64'd1;
3'd5: index <= index - 64'd2;
3'd6: index <= index - 64'd4;
3'd7: index <= index - 64'd8;
endcase
lc <= lc - 64'd1;
end
endtask
 
function [DBW-1:0] fnSpr;
input [5:0] regno;
input [63:0] epc;
begin
// Read from the special registers unless overridden by the
// value on the commit bus.
casex(regno)
6'b00xxxx: fnSpr = pregs[regno[3:0]];
6'b01xxxx: fnSpr = cregs[regno[3:0]];
6'b100xxx: fnSpr = {sregs[regno[2:0]],12'h000};
6'b101xxx: fnSpr = {sregs_lmt[regno[2:0]],12'h000};
6'b110000: if (DBW==64)
fnSpr = {pregs[15],pregs[14],pregs[13],pregs[12],
pregs[11],pregs[10],pregs[9],pregs[8],
pregs[7],pregs[6],pregs[5],pregs[4],
pregs[3],pregs[2],pregs[1],pregs[0]};
else
fnSpr = {pregs[7],pregs[6],pregs[5],pregs[4],
pregs[3],pregs[2],pregs[1],pregs[0]};
`TICK: fnSpr = tick;
`LCTR: fnSpr = lc;
`ASID: fnSpr = asid;
`SR: begin
fnSpr[7:0] = GM;
fnSpr[23:16] = GMB;
fnSpr[31] = imb;
fnSpr[15] = im;
fnSpr[12] = fxe;
end
6'd60: fnSpr = spr_bir;
6'd61:
case(spr_bir[5:0])
6'd0: fnSpr = dbg_adr0;
6'd1: fnSpr = dbg_adr1;
6'd2: fnSpr = dbg_adr2;
6'd3: fnSpr = dbg_adr3;
6'd4: fnSpr = dbg_ctrl;
6'd5: fnSpr = dbg_stat;
default: fnSpr = 64'd0;
endcase
default: fnSpr = 64'd0;
endcase
// If an spr is committing...
if (commit0_v && commit0_tgt=={1'b1,regno})
fnSpr = commit0_bus;
if (commit1_v && commit1_tgt=={1'b1,regno})
fnSpr = commit1_bus;
// Special cases where the register would not be read from the commit bus
case(regno)
`TICK: fnSpr = tick;
6'b010000: fnSpr = 64'd0; // code address zero
6'b011111: fnSpr = epc; // current program counter from fetchbufx_pc
default: ;
endcase
end
endfunction
 
// "oddball" instruction commit cases.
//
task oddball_commit;
input commit_v;
input [2:0] head;
begin
if (commit_v)
case(iqentry_op[head])
`CLI: begin im <= 1'b0; imb <= 1'b0; end
`SEI: begin im <= 1'b1; imb <= 1'b1; end
// When the RTI instruction commits clear the hardware interrupt status to enable interrupts.
`RTI: begin
StatusHWI <= `FALSE;
im <= imb;
end
`RTE,`RTD:
begin
if (StatusEXL!=8'h00)
StatusEXL <= StatusEXL - 8'd1;
end
`CACHE:
begin
case(iqentry_fn[head])
6'd0: ic_invalidate <= `TRUE;
6'd1: begin
ic_invalidate_line <= `TRUE;
ic_lineno <= iqentry_a1[head] + {sregs[3'd7],12'h000};
end
6'd32: dc_invalidate <= `TRUE;
6'd33: begin
dc_invalidate_line <= `TRUE;
dc_lineno <= iqentry_a1[head] + {sregs[iqentry_fn[head][5:3]],12'h000};
end
default: ; // do nothing
endcase
end
default: ;
endcase
end
endtask
 
task enque0a;
input [2:0] tail;
input [2:0] inc;
input unlink;
begin
// If segment limit exceeded and not in the non-segmented area.
if (fetchbuf0_pc >= {sregs_lmt[7],12'h000} && fetchbuf0_pc[ABW-1:ABW-4]!=4'hF)
set_exception(tail,8'd244);
else begin
`ifdef DEBUG_LOGIC
if (dbg_ctrl[0] && dbg_ctrl[17:16]==2'b00 && fetchbuf0_pc==dbg_adr0)
dbg_imatchA0 = `TRUE;
if (dbg_ctrl[1] && dbg_ctrl[21:20]==2'b00 && fetchbuf0_pc==dbg_adr1)
dbg_imatchA1 = `TRUE;
if (dbg_ctrl[2] && dbg_ctrl[25:24]==2'b00 && fetchbuf0_pc==dbg_adr2)
dbg_imatchA2 = `TRUE;
if (dbg_ctrl[3] && dbg_ctrl[29:28]==2'b00 && fetchbuf0_pc==dbg_adr3)
dbg_imatchA3 = `TRUE;
if (dbg_imatchA0|dbg_imatchA1|dbg_imatchA2|dbg_imatchA3)
dbg_imatchA = `TRUE;
if (dbg_imatchA)
set_exception(tail,8'd243); // Debug exception
else begin
`endif
interrupt_pc =
// If the previous instruction was an interrupt, then inherit the address
(iqentry_op[(tail-3'd1)&7]==`INT && iqentry_v[(tail-3'd1)&7]==`VAL && iqentry_tgt[(tail-3'd1)&7][3:0]==4'hE) ?
(string_pc != 0 ? string_pc : iqentry_pc[(tail-3'd1)&7]) :
// Otherwise inherit the address of any preceding immediate prefix.
(iqentry_op[(tail-3'd1)&7]==`IMM && iqentry_v[(tail-3'd1)&7]==`VAL) ?
(string_pc != 0 ? string_pc : iqentry_pc[(tail-3'd1)&7]) :
// Otherwise use the address of the interrupted instruction
(string_pc != 0 ? string_pc : fetchbuf0_pc);
iqentry_v [tail] <= `VAL;
iqentry_done [tail] <= `INV;
iqentry_cmt [tail] <= `TRUE;
iqentry_out [tail] <= `INV;
iqentry_res [tail] <= `ZERO;
iqentry_insnsz[tail] <= fnInsnLength(fetchbuf0_instr);
iqentry_op [tail] <= opcode0;
iqentry_fn [tail] <= opcode0==`MLO ? rfoc0[5:0] : fnFunc(fetchbuf0_instr);
iqentry_cond [tail] <= cond0;
iqentry_bt [tail] <= fnIsFlowCtrl(opcode0) && predict_taken0;
iqentry_agen [tail] <= `INV;
iqentry_pc [tail] <= (opcode0==`INT && Rt0[3:0]==4'hE) ? interrupt_pc : fetchbuf0_pc;
iqentry_mem [tail] <= fetchbuf0_mem;
iqentry_jmp [tail] <= fetchbuf0_jmp;
iqentry_fp [tail] <= fetchbuf0_fp;
iqentry_rfw [tail] <= fetchbuf0_rfw;
iqentry_tgt [tail] <= Rt0;
iqentry_pred [tail] <= pregs[Pn0];
// Look at the previous queue slot to see if an immediate prefix is enqueued
iqentry_a0[tail] <= opcode0==`INT ? fnImm(fetchbuf0_instr) :
fnIsBranch(opcode0) ? {{DBW-12{fetchbuf0_instr[11]}},fetchbuf0_instr[11:8],fetchbuf0_instr[23:16]} :
iqentry_op[(tail-3'd1)&7]==`IMM && iqentry_v[tail-3'd1] ? {iqentry_a0[(tail-3'd1)&7][DBW-1:8],fnImm8(fetchbuf0_instr)}:
opcode0==`IMM ? fnImmImm(fetchbuf0_instr) :
fnImm(fetchbuf0_instr);
iqentry_a1 [tail] <= fnOpa(opcode0,fetchbuf0_instr,rfoa0,fetchbuf0_pc);
iqentry_a2 [tail] <= fnIsShiftiop(fetchbuf0_instr) ? {{DBW-6{1'b0}},fetchbuf0_instr[`INSTRUCTION_RB]} :
fnIsFPCtrl(fetchbuf0_instr) ? {{DBW-6{1'b0}},fetchbuf0_instr[`INSTRUCTION_RB]} :
opcode0==`INC ? {{56{fetchbuf0_instr[47]}},fetchbuf0_instr[47:40]} :
opcode0==`STI ? fetchbuf0_instr[27:22] :
Rb0[6] ? fnSpr(Rb0[5:0],fetchbuf0_pc) :
rfob0;
iqentry_a3 [tail] <= rfoc0;
iqentry_T [tail] <= rfot0;
// The source is set even though the arg might be automatically valid (less logic).
// This is harmless to do. Note there is no source for the 'I' argument.
iqentry_p_s [tail] <= rf_source[{1'b1,2'h0,Pn0}];
iqentry_a1_s [tail] <= //unlink ? {1'b0, (tail-1)&7} :
rf_source[Ra0];
iqentry_a2_s [tail] <= rf_source[Rb0];
iqentry_a3_s [tail] <= rf_source[Rc0];
iqentry_T_s [tail] <= rf_source[Rt0];
// Always do this because it's the first queue slot.
validate_args10(tail);
`ifdef DEBUG_LOGIC
end
`endif
end
tail0 <= tail0 + inc;
tail1 <= tail1 + inc;
tail2 <= tail2 + inc;
queued1 = `TRUE;
rrmapno <= rrmapno + 3'd1;
end
endtask
 
task enquePushpopAdd;
input [2:0] tail;
input pushpop;
input link;
input unlink;
input which;
begin
$display("Pushpop add");
iqentry_v [tail] <= `VAL;
iqentry_done [tail] <= `INV;
iqentry_cmt [tail] <= `TRUE;
iqentry_out [tail] <= `INV;
iqentry_res [tail] <= 64'd0;
iqentry_insnsz[tail] <= 4'd0;
iqentry_op [tail] <= `ADDUI;
iqentry_fn [tail] <= 6'b0;
iqentry_cond [tail] <= which ? cond1 :cond0;
iqentry_bt [tail] <= 1'b0;
iqentry_agen [tail] <= `INV;
iqentry_pc [tail] <= which ? fetchbuf1_pc : fetchbuf0_pc;
iqentry_mem [tail] <= 1'b0;
iqentry_jmp [tail] <= 1'b0;
iqentry_fp [tail] <= 1'b0;
iqentry_rfw [tail] <= 1'b1;
iqentry_tgt [tail] <= 7'd27;
iqentry_pred [tail] <= pregs[which ? Pn1 : Pn0];
// Look at the previous queue slot to see if an immediate prefix is enqueued
iqentry_a0 [tail] <= link ? (which ? {{46{fetchbuf1_instr[39]}},fetchbuf1_instr[21:16],fetchbuf1_instr[39:28],3'b000} :
{{46{fetchbuf0_instr[39]}},fetchbuf0_instr[21:16],fetchbuf0_instr[39:28],3'b000}) :
(pushpop|unlink) ? 64'd8 : -64'd8;
iqentry_a1 [tail] <= which ? rfoa1 : rfoa0;
iqentry_a2 [tail] <= 64'd0;
iqentry_a3 [tail] <= 64'd0;
iqentry_T [tail] <= //unlink ? (which ? rfot1 : rfot0) :
(which ? rfoa1 : rfoa0);
// The source is set even though the arg might be automatically valid (less logic).
// This is harmless to do. Note there is no source for the 'I' argument.
iqentry_p_s [tail] <= rf_source[{1'b1,2'h0,which ? Pn1 : Pn0}];
iqentry_a1_s [tail] <= rf_source[Ra0];
iqentry_a2_s [tail] <= rf_source[Rb0];
iqentry_a3_s [tail] <= rf_source[Rc0];
iqentry_T_s [tail] <= rf_source[Ra0];
// Always do this because it's the first queue slot.
iqentry_p_v [tail] <= rf_v [{1'b1,2'h0,which ? Pn1:Pn0}] || ((which ? cond1 : cond0) < 4'h2);
iqentry_a1_v [tail] <= rf_v[ which ? Ra1 : Ra0 ];
iqentry_a2_v [tail] <= 1'b1;
iqentry_a3_v [tail] <= 1'b1;
iqentry_T_v [tail] <= //unlink ? rf_v[which ? Rt1 : Rt0] :
rf_v[ which ? Ra1 : Ra0 ];
rf_v[ 7'd27 ] = `INV;
rf_source[ 7'd27 ] <= { 1'b0, tail }; // top bit indicates ALU/MEM bus
end
endtask
 
// enque 0 on tail0 or tail1
task enque0;
input [2:0] tail;
input [2:0] inc;
input test_stomp;
input validate_args;
begin
if (opcode0==`NOP)
queued1 = `TRUE; // to update fetch buffers
`ifdef STACKOPS
// A pop instruction takes 2 queue entries.
else if (fnIsPop(fetchbuf0_instr)|fnIsPush(fetchbuf0_instr)|opcode0==`LINK) begin
$display("0 found push/pop");
if (iqentry_v[tail]==`INV && iqentry_v[tail+1]==`INV) begin
$display("enqueing2");
enque0a(tail,3'd2,1'b0);
enquePushpopAdd((tail+1)&7,fnIsPop(fetchbuf0_instr),opcode0==`LINK,0,0);
allowq = `FALSE;
end
end
else if (opcode0==`UNLINK) begin
if (iqentry_v[tail]==`INV && iqentry_v[(tail+1)&7]==`INV) begin
enquePushpopAdd(tail,1'b0,1'b0,1'b1,0);
enque0a((tail+1)&7,3'd2,1'b1);
allowq = `FALSE;
end
end
`endif
else if (iqentry_v[tail] == `INV) begin
if ((({fnIsBranch(opcode0), predict_taken0} == {`TRUE, `TRUE})||(opcode0==`LOOP)) && test_stomp)
qstomp = `TRUE;
enque0a(tail,inc,0);
end
end
endtask
 
task enque1a;
input [2:0] tail;
input [2:0] inc;
input validate_args;
input unlink;
begin
if (fetchbuf1_pc >= {sregs_lmt[7],12'h000} && fetchbuf1_pc[ABW-1:ABW-4]!=4'hF)
set_exception(tail,8'd244);
else begin
`ifdef DEBUG_LOGIC
if (dbg_ctrl[0] && dbg_ctrl[17:16]==2'b00 && fetchbuf1_pc==dbg_adr0)
dbg_imatchB0 = `TRUE;
if (dbg_ctrl[1] && dbg_ctrl[21:20]==2'b00 && fetchbuf1_pc==dbg_adr1)
dbg_imatchB1 = `TRUE;
if (dbg_ctrl[2] && dbg_ctrl[25:24]==2'b00 && fetchbuf1_pc==dbg_adr2)
dbg_imatchB2 = `TRUE;
if (dbg_ctrl[3] && dbg_ctrl[29:28]==2'b00 && fetchbuf1_pc==dbg_adr3)
dbg_imatchB3 = `TRUE;
if (dbg_imatchB0|dbg_imatchB1|dbg_imatchB2|dbg_imatchB3)
dbg_imatchB = `TRUE;
if (dbg_imatchB)
set_exception(tail,8'd243); // debug excpetion
else begin
`endif
// If an instruction wasn't enqueued or it wasn't an interrupt instruction then
// the interrupt pc will need to be set. Othersise this enqueue will inherit
// from the previous one.
if (!queued1 || !(opcode0==`INT && Rt0[3:0]==4'hE))
interrupt_pc = (iqentry_op[(tail-3'd1)&7]==`INT && iqentry_v[(tail-3'd1)&7]==`VAL && iqentry_tgt[(tail-3'd1)&7][3:0]==4'hE) ?
(string_pc != 0 ? string_pc : iqentry_pc[(tail-3'd1)&7]) :
(iqentry_op[(tail-3'd1)&7]==`IMM && iqentry_v[(tail-3'd1)&7]==`VAL) ? (string_pc != 0 ? string_pc :
iqentry_pc[(tail-3'd1)&7]) : (string_pc != 0 ? string_pc : fetchbuf1_pc);
iqentry_v [tail] <= `VAL;
iqentry_done [tail] <= `INV;
iqentry_cmt [tail] <= `TRUE;
iqentry_out [tail] <= `INV;
iqentry_res [tail] <= `ZERO;
iqentry_insnsz[tail] <= fnInsnLength(fetchbuf1_instr);
iqentry_op [tail] <= opcode1;
iqentry_fn [tail] <= opcode1==`MLO ? rfoc1[5:0] : fnFunc(fetchbuf1_instr);
iqentry_cond [tail] <= cond1;
iqentry_bt [tail] <= fnIsFlowCtrl(opcode1) && predict_taken1;
iqentry_agen [tail] <= `INV;
// If an interrupt is being enqueued and the previous instruction was an immediate prefix, then
// inherit the address of the previous instruction, so that the prefix will be executed on return
// from interrupt.
// If a string operation was in progress then inherit the address of the string operation so that
// it can be continued.
iqentry_pc [tail] <= (opcode1==`INT && Rt1[3:0]==4'hE) ? interrupt_pc : fetchbuf1_pc;
iqentry_mem [tail] <= fetchbuf1_mem;
iqentry_jmp [tail] <= fetchbuf1_jmp;
iqentry_fp [tail] <= fetchbuf1_fp;
iqentry_rfw [tail] <= fetchbuf1_rfw;
iqentry_tgt [tail] <= Rt1;
iqentry_pred [tail] <= pregs[Pn1];
// Look at the previous queue slot to see if an immediate prefix is enqueued
// But don't allow it for a branch
iqentry_a0[tail] <= opcode1==`INT ? fnImm(fetchbuf1_instr) :
fnIsBranch(opcode1) ? {{DBW-12{fetchbuf1_instr[11]}},fetchbuf1_instr[11:8],fetchbuf1_instr[23:16]} :
(queued1 && opcode0==`IMM) ? {fnImmImm(fetchbuf0_instr)|fnImm8(fetchbuf1_instr)} :
(!queued1 && iqentry_op[(tail-3'd1)&7]==`IMM) && iqentry_v[(tail-3'd1)&7] ? {iqentry_a0[(tail-3'd1)&7][DBW-1:8],fnImm8(fetchbuf1_instr)} :
opcode1==`IMM ? fnImmImm(fetchbuf1_instr) :
fnImm(fetchbuf1_instr);
iqentry_a1 [tail] <= fnOpa(opcode1,fetchbuf1_instr,rfoa1,fetchbuf1_pc);
iqentry_a2 [tail] <= fnIsShiftiop(fetchbuf1_instr) ? {{DBW-6{1'b0}},fetchbuf1_instr[`INSTRUCTION_RB]} :
fnIsFPCtrl(fetchbuf1_instr) ? {{DBW-6{1'b0}},fetchbuf1_instr[`INSTRUCTION_RB]} :
opcode1==`INC ? {{56{fetchbuf1_instr[47]}},fetchbuf1_instr[47:40]} :
opcode1==`STI ? fetchbuf1_instr[27:22] :
Rb1[6] ? fnSpr(Rb1[5:0],fetchbuf1_pc) :
rfob1;
iqentry_a3 [tail] <= rfoc1;
iqentry_T [tail] <= rfot1;
// The source is set even though the arg might be automatically valid (less logic). If
// queueing two entries the source settings may be overridden in the argument valudation.
iqentry_p_s [tail] <= rf_source[{1'b1,2'h0,Pn1}];
iqentry_a1_s [tail] <= //unlink ? {1'b0, (tail-3'd1)&7} :
rf_source[Ra1];
iqentry_a2_s [tail] <= rf_source[Rb1];
iqentry_a3_s [tail] <= rf_source[Rc1];
iqentry_T_s [tail] <= rf_source[Rt1];
if (validate_args)
validate_args11(tail);
`ifdef DEBUG_LOGIC
end
`endif
end
tail0 <= tail0 + inc;
tail1 <= tail1 + inc;
tail2 <= tail2 + inc;
end
endtask
 
// enque 1 on tail0 or tail1
task enque1;
input [2:0] tail;
input [2:0] inc;
input test_stomp;
input validate_args;
begin
if (opcode1==`NOP) begin
if (queued1==`TRUE) queued2 = `TRUE;
queued1 = `TRUE;
end
`ifdef STACKOPS
else if (fnIsPop(fetchbuf1_instr)|fnIsPush(fetchbuf1_instr)|opcode1==`LINK) begin
$display("1 found push/pop");
$display("iqv[%d]:%d", tail,iqentry_v[tail]);
$display("iqv[%d+1]:%d", tail, iqentry_v[tail+1]);
$display("valargs:%d", validate_args);
$display("qd1:%d", queued1);
if (iqentry_v[tail]==`INV && iqentry_v[(tail+1)&7]==`INV && validate_args && !queued1) begin
$display("1 enq 2 ");
enque1a(tail,3'd2,1,0);
enquePushpopAdd((tail+1)&7,fnIsPop(fetchbuf1_instr),opcode1==`LINK,0,1);
allowq = `FALSE;
end
end
else if (opcode1==`UNLINK) begin
if (iqentry_v[tail]==`INV && iqentry_v[(tail+1)&7]==`INV) begin
enquePushpopAdd(tail,1'b0,1'b0,1'b1,1);
enque1a((tail+1)&7,3'd2,1,1);
allowq = `FALSE;
end
end
`endif
else if (iqentry_v[tail] == `INV && !qstomp) begin
if ((({fnIsBranch(opcode1), predict_taken1} == {`TRUE, `TRUE})||(opcode1==`LOOP)) && test_stomp)
qstomp = `TRUE;
enque1a(tail,inc,validate_args,0);
if (queued1==`TRUE) queued2 = `TRUE;
else queued1 = `TRUE;
end
end
endtask
 
task validate_args10;
input [2:0] tail;
begin
iqentry_p_v [tail] <= rf_v [{1'b1,2'h0,Pn0}] || cond0 < 4'h2;
iqentry_a1_v [tail] <= fnSource1_v( opcode0 ) | rf_v[ Ra0 ];
iqentry_a2_v [tail] <= fnSource2_v( opcode0, fnFunc(fetchbuf0_instr)) | rf_v[Rb0];
iqentry_a3_v [tail] <= fnSource3_v( opcode0 ) | rf_v[ Rc0 ];
iqentry_T_v [tail] <= fnSourceT_v( opcode0 ) | rf_v[ Rt0 ];
if (fetchbuf0_rfw|fetchbuf0_pfw) begin
$display("regv[%d] = %d", Rt0,rf_v[ Rt0 ]);
rf_v[ Rt0 ] = Rt0==7'd0;
$display("reg[%d] <= INV",Rt0);
rf_source[ Rt0 ] <= { fetchbuf0_mem, tail }; // top bit indicates ALU/MEM bus
$display("10:rf_src[%d] <= %d, insn=%h", Rt0, tail,fetchbuf0_instr);
end
end
endtask
 
task validate_args11;
input [2:0] tail;
begin
// The predicate is automatically valid for condiitions 0 and 1 (always false or always true).
iqentry_p_v [tail] <= rf_v [{1'b1,2'h0,Pn1}] || cond1 < 4'h2;
iqentry_a1_v [tail] <= fnSource1_v( opcode1 ) | rf_v[ Ra1 ];
iqentry_a2_v [tail] <= fnSource2_v( opcode1, fnFunc(fetchbuf1_instr) ) | rf_v[ Rb1 ];
iqentry_a3_v [tail] <= fnSource3_v( opcode1 ) | rf_v[ Rc1 ];
iqentry_T_v [tail] <= fnSourceT_v( opcode1 ) | rf_v[ Rt1 ];
if (fetchbuf1_rfw|fetchbuf1_pfw) begin
$display("1:regv[%d] = %d", Rt1,rf_v[ Rt1 ]);
rf_v[ Rt1 ] = Rt1==7'd0;
$display("reg[%d] <= INV",Rt1);
rf_source[ Rt1 ] <= { fetchbuf1_mem, tail }; // top bit indicates ALU/MEM bus
$display("11:rf_src[%d] <= %d, insn=%h", Rt1, tail,fetchbuf0_instr);
end
end
endtask
 
// If two entries were queued then validate the arguments for the second entry.
//
task validate_args;
begin
if (queued2) begin
// SOURCE 1 ... this is relatively straightforward, because all instructions
// that have a source (i.e. every instruction but LUI) read from RB
//
// if the argument is an immediate or not needed, we're done
if (fnSource1_v( opcode1 ) == `VAL) begin
$display("fnSource1_v=1 iq[%d]", tail1);
iqentry_a1_v [tail1] <= `VAL;
iqentry_a1_s [tail1] <= 4'hF;
// iqentry_a1_s [tail1] <= 4'd0;
end
// if previous instruction writes nothing to RF, then get info from rf_v and rf_source
else if (!fetchbuf0_rfw) begin
iqentry_a1_v [tail1] <= rf_v [Ra1];
iqentry_a1_s [tail1] <= rf_source [Ra1];
end
// otherwise, previous instruction does write to RF ... see if overlap
else if (Rt0 != 7'd0 && Ra1 == Rt0) begin
// if the previous instruction is a LW, then grab result from memq, not the iq
$display("invalidating iqentry_a1_v[%d]", tail1);
iqentry_a1_v [tail1] <= `INV;
iqentry_a1_s [tail1] <= {fetchbuf0_mem, tail0};
end
// if no overlap, get info from rf_v and rf_source
else begin
iqentry_a1_v [tail1] <= rf_v [Ra1];
iqentry_a1_s [tail1] <= rf_source [Ra1];
$display("2:iqentry_a1_s[%d] <= %d", tail1, rf_source [Ra1]);
end
 
if (!fetchbuf0_pfw) begin
iqentry_p_v [tail1] <= rf_v [{1'b1,2'h0,Pn1}] || cond1 < 4'h2;
iqentry_p_s [tail1] <= rf_source [{1'b1,2'h0,Pn1}];
end
else if ((Rt0 != 7'd0 && Pn1==Rt0[3:0]) && (Rt0 & 7'h70)==7'h40) begin
iqentry_p_v [tail1] <= cond1 < 4'h2;
iqentry_p_s [tail1] <= {fetchbuf0_mem, tail0};
end
else begin
iqentry_p_v [tail1] <= rf_v[{1'b1,2'h0,Pn1}] || cond1 < 4'h2;
iqentry_p_s [tail1] <= rf_source[{1'b1,2'h0,Pn1}];
end
 
//
// SOURCE 2 ... this is more contorted than the logic for SOURCE 1 because
// some instructions (NAND and ADD) read from RC and others (SW, BEQ) read from RA
//
// if the argument is an immediate or not needed, we're done
if (fnSource2_v( opcode1,fnFunc(fetchbuf1_instr) ) == `VAL) begin
iqentry_a2_v [tail1] <= `VAL;
iqentry_a2_s [tail1] <= 4'hF;
end
// if previous instruction writes nothing to RF, then get info from rf_v and rf_source
else if (!fetchbuf0_rfw) begin
iqentry_a2_v [tail1] <= rf_v[ Rb1 ];
iqentry_a2_s [tail1] <= rf_source[Rb1];
end
// otherwise, previous instruction does write to RF ... see if overlap
else if (Rt0 != 7'd0 && Rb1 == Rt0) begin
// if the previous instruction is a LW, then grab result from memq, not the iq
iqentry_a2_v [tail1] <= `INV;
iqentry_a2_s [tail1] <= {fetchbuf0_mem,tail0};
end
// if no overlap, get info from rf_v and rf_source
else begin
iqentry_a2_v [tail1] <= rf_v[ Rb1 ];
iqentry_a2_s [tail1] <= rf_source[Rb1];
end
 
//
// SOURCE 3 ... this is relatively straightforward, because all instructions
// that have a source (i.e. every instruction but LUI) read from RC
//
// if the argument is an immediate or not needed, we're done
if (fnSource3_v( opcode1 ) == `VAL) begin
iqentry_a3_v [tail1] <= `VAL;
iqentry_a3_v [tail1] <= 4'hF;
// iqentry_a1_s [tail1] <= 4'd0;
end
// if previous instruction writes nothing to RF, then get info from rf_v and rf_source
else if (!fetchbuf0_rfw) begin
iqentry_a3_v [tail1] <= rf_v [Rc1];
iqentry_a3_s [tail1] <= rf_source [Rc1];
end
// otherwise, previous instruction does write to RF ... see if overlap
else if (Rt0 != 7'd0 && Rc1 == Rt0) begin
// if the previous instruction is a LW, then grab result from memq, not the iq
iqentry_a3_v [tail1] <= `INV;
iqentry_a3_s [tail1] <= {fetchbuf0_mem,tail0};
end
// if no overlap, get info from rf_v and rf_source
else begin
iqentry_a3_v [tail1] <= rf_v [Rc1];
iqentry_a3_s [tail1] <= rf_source [Rc1];
end
 
 
//
// Target 3 ... this is relatively straightforward, because all instructions
// that have a source (i.e. every instruction but LUI) read from RC
//
// if the argument is an immediate or not needed, we're done
if (fnSourceT_v( opcode1 ) == `VAL) begin
iqentry_T_v [tail1] <= `VAL;
iqentry_T_v [tail1] <= 4'hF;
end
// if previous instruction writes nothing to RF, then get info from rf_v and rf_source
else if (!fetchbuf0_rfw) begin
iqentry_T_v [tail1] <= rf_v [Rt1];
iqentry_T_s [tail1] <= rf_source [Rt1];
end
// otherwise, previous instruction does write to RF ... see if overlap
else if (Rt0 != 7'd0 && Rt1 == Rt0) begin
// if the previous instruction is a LW, then grab result from memq, not the iq
iqentry_T_v [tail1] <= `INV;
iqentry_T_s [tail1] <= {fetchbuf0_mem,tail0};
end
// if no overlap, get info from rf_v and rf_source
else begin
iqentry_T_v [tail1] <= rf_v [Rt1];
iqentry_T_s [tail1] <= rf_source [Rt1];
end
end
if (queued1|queued2) begin
if (fetchbuf0_rfw|fetchbuf0_pfw) begin
$display("regv[%d] = %d", Rt0,rf_v[ Rt0 ]);
rf_v[ Rt0 ] = Rt0==7'd0;
$display("reg[%d] <= INV",Rt0);
rf_source[ Rt0 ] <= { fetchbuf0_mem, tail0 }; // top bit indicates ALU/MEM bus
$display("12:rf_src[%d] <= %d, insn=%h", Rt0, tail0,fetchbuf0_instr);
end
end
if (queued2) begin
if (fetchbuf1_rfw|fetchbuf1_pfw) begin
$display("1:regv[%d] = %d", Rt1,rf_v[ Rt1 ]);
rf_v[ Rt1 ] = Rt1==7'd0;
$display("reg[%d] <= INV",Rt1);
rf_source[ Rt1 ] <= { fetchbuf1_mem, tail1 }; // top bit indicates ALU/MEM bus
end
end
end
endtask
 
task fetchAB;
begin
fetchbufA_instr <= insn0;
fetchbufA_pc <= pc;
fetchbufA_v <= ld_fetchbuf;
fetchbufB_instr <= insn1;
fetchbufB_pc <= pc + fnInsnLength(insn);
fetchbufB_v <= ld_fetchbuf;
end
endtask
 
task fetchCD;
begin
fetchbufC_instr <= insn0;
fetchbufC_pc <= pc;
fetchbufC_v <= ld_fetchbuf;
fetchbufD_instr <= insn1;
fetchbufD_pc <= pc + fnInsnLength(insn);
fetchbufD_v <= ld_fetchbuf;
end
endtask
 
// Reset the tail pointers.
// Used by the enqueue logic
//
task reset_tail_pointers;
input first;
begin
if ((iqentry_stomp[0] & ~iqentry_stomp[7]) | first) begin
tail0 <= 0;
tail1 <= 1;
end
else if (iqentry_stomp[1] & ~iqentry_stomp[0]) begin
tail0 <= 1;
tail1 <= 2;
end
else if (iqentry_stomp[2] & ~iqentry_stomp[1]) begin
tail0 <= 2;
tail1 <= 3;
end
else if (iqentry_stomp[3] & ~iqentry_stomp[2]) begin
tail0 <= 3;
tail1 <= 4;
end
else if (iqentry_stomp[4] & ~iqentry_stomp[3]) begin
tail0 <= 4;
tail1 <= 5;
end
else if (iqentry_stomp[5] & ~iqentry_stomp[4]) begin
tail0 <= 5;
tail1 <= 6;
end
else if (iqentry_stomp[6] & ~iqentry_stomp[5]) begin
tail0 <= 6;
tail1 <= 7;
end
else if (iqentry_stomp[7] & ~iqentry_stomp[6]) begin
tail0 <= 7;
tail1 <= 0;
end
// otherwise, it is the last instruction in the queue that has been mispredicted ... do nothing
end
endtask
 
// Increment the head pointers
// Also increments the instruction counter
// Used when instructions are committed.
// Also clear any outstanding state bits that foul things up.
//
task head_inc;
input [2:0] amt;
begin
head0 <= head0 + amt;
head1 <= head1 + amt;
head2 <= head2 + amt;
head3 <= head3 + amt;
head4 <= head4 + amt;
head5 <= head5 + amt;
head6 <= head6 + amt;
head7 <= head7 + amt;
I <= I + amt;
if (amt==3'd3) begin
iqentry_agen[head0] <= `INV;
iqentry_agen[head1] <= `INV;
iqentry_agen[head2] <= `INV;
end else if (amt==3'd2) begin
iqentry_agen[head0] <= `INV;
iqentry_agen[head1] <= `INV;
end else if (amt==3'd1)
iqentry_agen[head0] <= `INV;
end
endtask
 
 
// set_exception:
// Used to requeue the instruction as an exception if an exception occurs.
 
task set_exception;
input [2:0] id; // instruction queue id
input [7:0] exc; // exception number
begin
iqentry_op [id[2:0] ] <= `INT;
iqentry_cond [id[2:0]] <= 4'd1; // always execute
iqentry_mem[id[2:0]] <= `FALSE;
iqentry_rfw[id[2:0]] <= `TRUE; // writes to IPC
iqentry_a0 [id[2:0]] <= exc;
iqentry_p_v [id[2:0]] <= `TRUE;
iqentry_a1 [id[2:0]] <= cregs[4'hC]; // *** assumes BR12 is static
iqentry_a1_v [id[2:0]] <= `TRUE; // Flag arguments as valid
iqentry_a2_v [id[2:0]] <= `TRUE;
iqentry_a3_v [id[2:0]] <= `TRUE;
iqentry_T_v [id[2:0]] <= `TRUE;
iqentry_out [id[2:0]] <= `FALSE;
iqentry_agen [id[2:0]] <= `FALSE;
iqentry_tgt[id[2:0]] <= {1'b1,2'h1,(exc==8'd243)?4'hB:4'hD}; // Target EPC
end
endtask
 
endmodule
/trunk/rtl/verilog/Thor_execute_combo.v
0,0 → 1,260
// ============================================================================
// __
// \\__/ o\ (C) 2013,2015 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Thor SuperScalar
// Execute combinational logic
//
// ============================================================================
//
wire [DBW-1:0] alu0_out, alu1_out;
wire alu0_done,alu1_done;
wire alu0_divByZero, alu1_divByZero;
 
Thor_alu #(.DBW(DBW),.BIG(1)) ualu0
(
.corenum(corenum),
.rst(rst),
.clk(clk),
.alu_ld(alu0_ld),
.alu_op(alu0_op),
.alu_fn(alu0_fn),
.alu_argA(alu0_argA),
.alu_argB(alu0_argB),
.alu_argC(alu0_argC),
.alu_argI(alu0_argI),
.alu_pc(alu0_pc),
.insnsz(alu0_insnsz),
.o(alu0_out),
.alu_done(alu0_done),
.alu_divByZero(alu0_divByZero)
);
 
Thor_alu #(.DBW(DBW),.BIG(ALU1BIG)) ualu1
(
.corenum(corenum),
.rst(rst),
.clk(clk),
.alu_ld(alu1_ld),
.alu_op(alu1_op),
.alu_fn(alu1_fn),
.alu_argA(alu1_argA),
.alu_argB(alu1_argB),
.alu_argC(alu1_argC),
.alu_argI(alu1_argI),
.alu_pc(alu1_pc),
.insnsz(alu1_insnsz),
.o(alu1_out),
.alu_done(alu1_done),
.alu_divByZero(alu1_divByZero)
);
 
function fnPredicate;
input [3:0] pr;
input [3:0] cond;
 
case(cond)
PF: fnPredicate = 1'b0;
PT: fnPredicate = 1'b1;
PEQ: fnPredicate = pr[0];
PNE: fnPredicate = !pr[0];
PLE: fnPredicate = pr[0]|pr[1];
PGT: fnPredicate = !(pr[0]|pr[1]);
PLT: fnPredicate = pr[1];
PGE: fnPredicate = !pr[1];
PLEU: fnPredicate = pr[0]|pr[2];
PGTU: fnPredicate = !(pr[0]|pr[2]);
PLTU: fnPredicate = pr[2];
PGEU: fnPredicate = !pr[2];
default: fnPredicate = 1'b1;
endcase
 
endfunction
 
wire alu0_cmtw = fnPredicate(alu0_pred, alu0_cond);
wire alu1_cmtw = fnPredicate(alu1_pred, alu1_cond);
 
always @*
begin
alu0_cmt <= alu0_cmtw;
alu1_cmt <= alu1_cmtw;
 
alu0_bus <= alu0_cmtw ? alu0_out : alu0_argT;
alu1_bus <= alu1_cmtw ? alu1_out : alu1_argT;
 
alu0_v <= alu0_dataready;
alu1_v <= alu1_dataready;
 
alu0_id <= alu0_sourceid;
alu1_id <= alu1_sourceid;
end
 
// Special flag nybble is used for INT and SYS instructions in order to turn off
// segmentation while the vector jump is taking place.
 
always @(alu0_op or alu0_fn or alu0_argA or alu0_argI or alu0_insnsz or alu0_pc or alu0_bt)
case(alu0_op)
`JSR,`JSRS,`JSRZ,`RTD,`RTE,`RTI:
alu0_misspc <= alu0_argA + alu0_argI;
`LOOP,`SYNC:
alu0_misspc <= alu0_pc + alu0_insnsz;
`RTS,`RTS2:
alu0_misspc <= alu0_argA + alu0_fn[3:0];
`SYS,`INT:
alu0_misspc <= {4'hF,alu0_argA + {alu0_argI[DBW-5:0],4'b0}};
default:
alu0_misspc <= (alu0_bt ? alu0_pc + alu0_insnsz : alu0_pc + alu0_insnsz + alu0_argI);
endcase
 
always @(alu1_op or alu1_fn or alu1_argA or alu1_argI or alu1_insnsz or alu1_pc or alu1_bt)
case(alu1_op)
`JSR,`JSRS,`JSRZ,`RTD,`RTE,`RTI:
alu1_misspc <= alu1_argA + alu1_argI;
`LOOP,`SYNC:
alu1_misspc <= alu1_pc + alu1_insnsz;
`RTS,`RTS2:
alu1_misspc <= alu1_argA + alu1_fn[3:0];
`SYS,`INT:
alu1_misspc <= {4'hF,alu1_argA + {alu1_argI[DBW-5:0],4'b0}};
default:
alu1_misspc <= (alu1_bt ? alu1_pc + alu1_insnsz : alu1_pc + alu1_insnsz + alu1_argI);
endcase
/*
assign alu0_misspc = (alu0_op == `JSR || alu0_op==`JSRS || alu0_op==`JSRZ ||
alu0_op==`RTS || alu0_op==`RTS2 || alu0_op == `RTE || alu0_op==`RTI || alu0_op==`LOOP) ? alu0_argA + alu0_argI :
(alu0_op == `SYS || alu0_op==`INT) ? alu0_argA + {alu0_argI[DBW-5:0],4'b0} :
(alu0_bt ? alu0_pc + alu0_insnsz : alu0_pc + alu0_insnsz + alu0_argI),
alu1_misspc = (alu1_op == `JSR || alu1_op==`JSRS || alu1_op==`JSRZ ||
alu1_op==`RTS || alu1_op == `RTE || alu1_op==`RTI || alu1_op==`LOOP) ? alu1_argA + alu1_argI :
(alu1_op == `SYS || alu1_op==`INT) ? alu1_argA + {alu1_argI[DBW-5:0],4'b0} :
(alu1_bt ? alu1_pc + alu1_insnsz : alu1_pc + alu1_insnsz + alu1_argI);
*/
assign alu0_exc = (fnIsKMOnly(alu0_op) && !km) ? `EXC_PRIV :
(alu0_done && alu0_divByZero) ? `EXC_DBZ : `EXC_NONE;
 
// ? `EXC_NONE
// : (alu0_argB[`INSTRUCTION_S1] == `SYS_NONE) ? `EXC_NONE
// : (alu0_argB[`INSTRUCTION_S1] == `SYS_CALL) ? alu0_argB[`INSTRUCTION_S2]
// : (alu0_argB[`INSTRUCTION_S1] == `SYS_MFSR) ? `EXC_NONE
// : (alu0_argB[`INSTRUCTION_S1] == `SYS_MTSR) ? `EXC_NONE
// : (alu0_argB[`INSTRUCTION_S1] == `SYS_RFU1) ? `EXC_INVALID
// : (alu0_argB[`INSTRUCTION_S1] == `SYS_RFU2) ? `EXC_INVALID
// : (alu0_argB[`INSTRUCTION_S1] == `SYS_RFU3) ? `EXC_INVALID
// : (alu0_argB[`INSTRUCTION_S1] == `SYS_EXC) ? alu0_argB[`INSTRUCTION_S2]
// : `EXC_INVALID;
 
assign alu1_exc = (fnIsKMOnly(alu1_op) && !km) ? `EXC_PRIV :
(alu1_done && alu1_divByZero) ? `EXC_DBZ : `EXC_NONE;
 
// ? `EXC_NONE
// : (alu1_argB[`INSTRUCTION_S1] == `SYS_NONE) ? `EXC_NONE
// : (alu1_argB[`INSTRUCTION_S1] == `SYS_CALL) ? alu1_argB[`INSTRUCTION_S2]
// : (alu1_argB[`INSTRUCTION_S1] == `SYS_MFSR) ? `EXC_NONE
// : (alu1_argB[`INSTRUCTION_S1] == `SYS_MTSR) ? `EXC_NONE
// : (alu1_argB[`INSTRUCTION_S1] == `SYS_RFU1) ? `EXC_INVALID
// : (alu1_argB[`INSTRUCTION_S1] == `SYS_RFU2) ? `EXC_INVALID
// : (alu1_argB[`INSTRUCTION_S1] == `SYS_RFU3) ? `EXC_INVALID
// : (alu1_argB[`INSTRUCTION_S1] == `SYS_EXC) ? alu1_argB[`INSTRUCTION_S2]
// : `EXC_INVALID;
 
assign alu0_branchmiss = alu0_dataready &&
((fnIsBranch(alu0_op)) ? ((alu0_cmt && !alu0_bt) || (!alu0_cmt && alu0_bt))
: (alu0_cmtw && (alu0_op==`SYNC || alu0_op == `JSR || alu0_op == `JSRS || alu0_op == `JSRZ ||
alu0_op==`SYS || alu0_op==`INT ||
alu0_op==`RTS || alu0_op==`RTS2 || alu0_op==`RTD || alu0_op == `RTE || alu0_op==`RTI || ((alu0_op==`LOOP) && (alu0_argB == 64'd0)))));
 
assign alu1_branchmiss = alu1_dataready &&
((fnIsBranch(alu1_op)) ? ((alu1_cmt && !alu1_bt) || (!alu1_cmt && alu1_bt))
: (alu1_cmtw && (alu1_op==`SYNC || alu1_op == `JSR || alu1_op == `JSRS || alu1_op == `JSRZ ||
alu1_op==`SYS || alu1_op==`INT ||
alu1_op==`RTS || alu1_op==`RTS2 || alu1_op==`RTD || alu1_op == `RTE || alu1_op==`RTI || ((alu1_op==`LOOP) && (alu1_argB == 64'd0)))));
 
assign branchmiss = (alu0_branchmiss | alu1_branchmiss),
misspc = (alu0_branchmiss ? alu0_misspc : alu1_misspc),
missid = (alu0_branchmiss ? alu0_sourceid : alu1_sourceid);
 
`ifdef FLOATING_POINT
wire fp0_exception;
fpUnit ufp0
(
.rst(rst_i),
.clk(clk),
.ce(1'b1),
.op(fp0_op),
.fn(fp0_fn),
.ld(fp0_ld),
.a(fp0_argA),
.b(fp0_argB),
.o(fp0_bus),
.exception(fp0_exception)
);
 
reg [7:0] cnt;
always @(posedge clk)
if (rst_i)
cnt <= 8'h00;
else begin
if (fp0_ld)
cnt <= 8'h00;
else begin
if (cnt < 8'hff)
cnt <= cnt + 8'd1;
end
end
 
always @*
begin
case(fp0_op)
`FLOAT:
case(fp0_fn)
`FCMP,`FCMPS: fp0_done = 1'b1; // These ops are done right away
`FADD,`FSUB,`FMUL,`FADDS,`FSUBS,`FMULS:
fp0_done = cnt > 8'd4;
`FDIV: fp0_done = cnt > 8'h70;
`FDIVS: fp0_done = cnt > 8'h37;
default: fp0_done = 1'b1;
endcase
`SINGLE_R:
case(fp0_fn)
`FNEGS,`FABSS,`FSIGNS,`FMOVS,
`FNABSS,`FMANS:
fp0_done = 1'b1; // These ops are done right away
`FTOIS,`ITOFS: fp0_done = cnt > 8'd1;
default: fp0_done = 1'b1;
endcase
`DOUBLE_R:
case(fp0_fn)
`FMOV,`FNEG,`FABS,`FNABS,`FSIGN,`FMAN:
fp0_done = 1'b1; // These ops are done right away
`FTOI,`ITOF: fp0_done = cnt > 8'd1;
default: fp0_done = 1'b1;
endcase
default: fp0_done = 1'b1;
endcase
end
 
assign fp0_cmt = fnPredicate(fp0_pred, fp0_cond);
assign fp0_exc = fp0_exception ? 8'd242 : 8'd0;
 
assign fp0_v = fp0_dataready;
assign fp0_id = fp0_sourceid;
`endif
 
/trunk/rtl/verilog/Thor_alu.v
0,0 → 1,439
// ============================================================================
// __
// \\__/ o\ (C) 2013,2015 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Thor SuperScaler
// ALU
//
// ============================================================================
//
`include "Thor_defines.v"
 
module Thor_alu(corenum, rst, clk, alu_ld, alu_op, alu_fn, alu_argA, alu_argB, alu_argC, alu_argI, alu_pc, insnsz, o, alu_done, alu_divByZero);
parameter DBW=64;
parameter BIG=1;
parameter FEATURES = 0;
input [63:0] corenum;
input rst;
input clk;
input alu_ld;
input [7:0] alu_op;
input [5:0] alu_fn;
input [DBW-1:0] alu_argA;
input [DBW-1:0] alu_argB;
input [DBW-1:0] alu_argC;
input [DBW-1:0] alu_argI;
input [DBW-1:0] alu_pc;
input [3:0] insnsz;
output reg [DBW-1:0] o;
output reg alu_done;
output alu_divByZero;
 
wire signed [DBW-1:0] alu_argAs = alu_argA;
wire signed [DBW-1:0] alu_argBs = alu_argB;
wire signed [DBW-1:0] alu_argIs = alu_argI;
wire [DBW-1:0] andi_res = alu_argA & alu_argI;
wire [127:0] alu_prod;
wire [63:0] alu_divq;
wire [63:0] alu_rem;
wire [7:0] bcdao,bcdso;
wire [15:0] bcdmo;
wire [DBW-1:0] bf_out;
wire [DBW-1:0] shfto;
wire alu_mult_done,alu_div_done;
wire [DBW-1:0] p_out;
 
integer n;
 
Thor_multiplier #(DBW) umult1
(
.rst(rst),
.clk(clk),
.ld(alu_ld && ((alu_op==`RR && (alu_fn==`MUL || alu_fn==`MULU)) || alu_op==`MULI || alu_op==`MULUI)),
.sgn((alu_op==`RR && alu_op==`MUL) || alu_op==`MULI),
.isMuli(alu_op==`MULI || alu_op==`MULUI),
.a(alu_argA),
.b(alu_argB),
.imm(alu_argI),
.o(alu_prod),
.done(alu_mult_done)
);
 
Thor_divider #(DBW) udiv1
(
.rst(rst),
.clk(clk),
.ld(alu_ld && ((alu_op==`RR && (alu_fn==`DIV || alu_fn==`DIVU)) || alu_op==`DIVI || alu_op==`DIVUI)),
.sgn((alu_op==`RR && alu_fn==`DIV) || alu_op==`DIVI),
.isDivi(alu_op==`DIVI || alu_op==`DIVUI),
.a(alu_argA),
.b(alu_argB),
.imm(alu_argI),
.qo(alu_divq),
.ro(alu_rem),
.dvByZr(alu_divByZero),
.done(alu_div_done)
);
 
Thor_shifter #(DBW) ushft0
(
.func(alu_fn),
.a(alu_argA),
.b(alu_argB),
.o(shfto)
);
 
BCDAdd ubcda
(
.ci(1'b0),
.a(alu_argA[7:0]),
.b(alu_argB[7:0]),
.o(bcdao),
.c()
);
 
BCDSub ubcds
(
.ci(1'b0),
.a(alu_argA[7:0]),
.b(alu_argB[7:0]),
.o(bcdso),
.c()
);
 
BCDMul2 ubcdm
(
.a(alu_argA),
.b(alu_argB),
.o(bcdmo)
);
 
Thor_bitfield #(DBW) ubf1
(
.op(alu_fn),
.a(alu_argA),
.b(alu_argB),
.m(alu_argI[11:0]),
.o(bf_out),
.masko()
);
 
Thor_P #(DBW) upr1
(
.fn(alu_fn),
.ra(alu_argI[5:0]),
.rb(alu_argI[11:6]),
.rt(alu_argI[17:12]),
.pregs_i(alu_argA),
.pregs_o(p_out)
);
 
wire [DBW-1:0] cntlzo;
wire [DBW-1:0] cntloo;
wire [DBW-1:0] cntpopo;
 
generate
begin : clzg
if (DBW==64) begin
cntlz64 u12 ( .i(alu_argA), .o(cntlzo) );
cntlo64 u13 ( .i(alu_argA), .o(cntloo) );
cntpop64 u14 ( .i(alu_argA), .o(cntpopo) );
end
else begin
cntlz32 u12 ( .i(alu_argA), .o(cntlzo) );
cntlo32 u13 ( .i(alu_argA), .o(cntloo) );
cntpop32 u14 ( .i(alu_argA), .o(cntpopo) );
end
end
endgenerate
 
wire faz = alu_argA[DBW-2:0]==63'd0;
wire fbz = alu_argB[DBW-2:0]==63'd0;
wire feq = (faz & fbz) || (alu_argA==alu_argB); // special test for zero
wire fgt1 = alu_argA[DBW-2:0] > alu_argB[DBW-2:0];
wire flt1 = alu_argA[DBW-2:0] < alu_argB[DBW-2:0];
wire flt = alu_argA[DBW] ^ alu_argB[DBW] ? alu_argA[DBW] & !(faz & fbz): alu_argA[DBW] ? fgt1 : flt1;
wire nanA = DBW==32 ? alu_argA[30:23]==8'hFF && (alu_argA[22:0]!=23'd0) : alu_argA[62:52]==11'h7FF && (alu_argA[51:0]!=52'd0);
wire nanB = DBW==32 ? alu_argB[30:23]==8'hFF && (alu_argB[22:0]!=23'd0) : alu_argB[62:52]==11'h7FF && (alu_argB[51:0]!=52'd0);
 
wire fsaz = alu_argA[30:0]==31'd0;
wire fsbz = alu_argB[30:0]==31'd0;
wire fseq = (fsaz & fsbz) || (alu_argA[31:0]==alu_argB[31:0]); // special test for zero
wire fsgt1 = alu_argA[30:0] > alu_argB[30:0];
wire fslt1 = alu_argA[30:0] < alu_argB[30:0];
wire fslt = alu_argA[31] ^ alu_argB[31] ? alu_argA[31] & !(fsaz & fsbz): alu_argA[31] ? fsgt1 : fslt1;
wire snanA = alu_argA[30:23]==8'hFF && (alu_argA[22:0]!=23'd0);
wire snanB = alu_argB[30:23]==8'hFF && (alu_argB[22:0]!=23'd0);
 
always @*
begin
casex(alu_op)
`LDI,`LDIS: o <= alu_argI;
`RR:
case(alu_fn)
`ADD,`ADDU: o <= alu_argA + alu_argB;
`SUB,`SUBU: o <= alu_argA - alu_argB;
`_2ADDU: o <= {alu_argA[DBW-2:0],1'b0} + alu_argB;
`_4ADDU: o <= {alu_argA[DBW-3:0],2'b0} + alu_argB;
`_8ADDU: o <= {alu_argA[DBW-4:0],3'b0} + alu_argB;
`_16ADDU: o <= {alu_argA[DBW-5:0],4'b0} + alu_argB;
`MIN: o <= BIG ? (alu_argA < alu_argB ? alu_argA : alu_argB) : 64'hDEADDEADDEADDEAD;
`MAX: o <= BIG ? (alu_argA < alu_argB ? alu_argB : alu_argA) : 64'hDEADDEADDEADDEAD;
`MUL,`MULU: o <= BIG ? alu_prod[63:0] : 64'hDEADDEADDEADDEAD;
`DIV,`DIVU: o <= BIG ? alu_divq : 64'hDEADDEADDEADDEAD;
default: o <= 64'hDEADDEADDEADDEAD;
endcase
`MULI,`MULUI: o <= BIG ? alu_prod[63:0] : 64'hDEADDEADDEADDEAD;
`DIVI,`DIVUI: o <= BIG ? alu_divq : 64'hDEADDEADDEADDEAD;
`_2ADDUI: o <= {alu_argA[DBW-2:0],1'b0} + alu_argI;
`_4ADDUI: o <= {alu_argA[DBW-3:0],2'b0} + alu_argI;
`_8ADDUI: o <= {alu_argA[DBW-4:0],3'b0} + alu_argI;
`_16ADDUI: o <= {alu_argA[DBW-5:0],4'b0} + alu_argI;
`R:
case(alu_fn[3:0])
`MOV: o <= alu_argA;
`NEG: o <= -alu_argA;
`NOT: o <= |alu_argA ? 64'd0 : 64'd1;
`ABS: o <= BIG ? (alu_argA[DBW] ? -alu_argA : alu_argA) : 64'hDEADDEADDEADDEAD;
`SGN: o <= BIG ? (alu_argA[DBW] ? 64'hFFFFFFFFFFFFFFFF : alu_argA==64'd0 ? 64'd0 : 64'd1) : 64'hDEADDEADDEADDEAD;
`CNTLZ: o <= BIG ? cntlzo : 64'hDEADDEADDEADDEAD;
`CNTLO: o <= BIG ? cntloo : 64'hDEADDEADDEADDEAD;
`CNTPOP: o <= BIG ? cntpopo : 64'hDEADDEADDEADDEAD;
`ZXB: o <= BIG ? {56'd0,alu_argA[7:0]} : 64'hDEADDEADDEADDEAD;
`ZXC: o <= BIG ? {48'd0,alu_argA[15:0]} : 64'hDEADDEADDEADDEAD;
`ZXH: o <= BIG ? {32'd0,alu_argA[31:0]} : 64'hDEADDEADDEADDEAD;
`COM: o <= ~alu_argA;
`SXB: o <= BIG ? {{56{alu_argA[7]}},alu_argA[7:0]} : 64'hDEADDEADDEADDEAD;
`SXC: o <= BIG ? {{48{alu_argA[15]}},alu_argA[15:0]} : 64'hDEADDEADDEADDEAD;
`SXH: o <= BIG ? {{32{alu_argA[31]}},alu_argA[31:0]} : 64'hDEADDEADDEADDEAD;
default: o <= 64'hDEADDEADDEADDEAD;
endcase
`R2:
case(alu_fn)
`CPUID:
if (BIG)
case(alu_argA[4:0])
5'd0: o <= corenum;
5'd2: o <= "Finitron";
5'd3: o <= ""; // vendor ID
5'd4: o <= "64BitSS"; // class
5'd6: o <= "Thor"; // Name
5'd8: o <= "M1"; // model
5'd9: o <= "1234"; // serial num
5'd10: o <= FEATURES;
5'd11: o <= {32'd16384,32'd32768}; // Cache D,I
default: o <= 64'hDEADDEADDEADDEAD;
endcase
else o <= 64'hDEADDEADDEADDEAD;
`REDOR: o <= BIG ? |alu_argA : 64'hDEADDEADDEADDEAD;
`REDAND: o <= BIG ? &alu_argA : 64'hDEADDEADDEADDEAD;
`PAR: o <= BIG ? ^alu_argA : 64'hDEADDEADDEADDEAD;
default: o <= 64'hDEADDEADDEADDEAD;
endcase
`P: o <= p_out;
/*
`DOUBLE:
if (BIG) begin
if (alu_fn[5:4]==2'b00)
case (alu_fn)
`FMOV: o <= alu_argA;
`FNEG: o <= {~alu_argA[DBW-1],alu_argA[DBW-2:0]};
`FABS: o <= {1'b0,alu_argA[DBW-2:0]};
`FSIGN: if (DBW==64)
o <= alu_argA[DBW-2:0]==0 ? {DBW{1'b0}} : {alu_argA[DBW-1],1'b0,{10{1'b1}},{52{1'b0}}};
else
o <= alu_argA[DBW-2:0]==0 ? {DBW{1'b0}} : {alu_argA[DBW-1],1'b0,{7{1'b1}},{23{1'b0}}};
`FMAN: o <= alu_argA[(DBW==64?51:22):0];
default: o <= 64'hDEADDEADDEADDEAD;
endcase
else
case (alu_fn)
`FMOV: o <= alu_argA;
`FSNEG: o <= {~alu_argA[31],alu_argA[30:0]};
`FSABS: o <= {1'b0,alu_argA[30:0]};
`FSSIGN: o <= alu_argA[30:0]==0 ? {DBW{1'b0}} : {alu_argA[31],1'b0,{7{1'b1}},{23{1'b0}}};
`FSMAN: o <= alu_argA[22:0];
default: o <= 64'hDEADDEADDEADDEAD;
endcase
end
else
o <= 64'hDEADDEADDEADDEAD;
*/
 
`ADDI,`ADDUI,`ADDUIS:
o <= alu_argA + alu_argI;
`SUBI,`SUBUI:
o <= alu_argA - alu_argI;
`ANDI: o <= alu_argA & alu_argI;
`ORI: o <= alu_argA | alu_argI;
`EORI: o <= alu_argA ^ alu_argI;
`LOGIC,`MLO:
case(alu_fn)
`AND: o <= alu_argA & alu_argB;
`ANDC: o <= alu_argA & ~alu_argB;
`OR: o <= alu_argA | alu_argB;
`ORC: o <= alu_argA | ~alu_argB;
`EOR: o <= alu_argA ^ alu_argB;
`NAND: o <= ~(alu_argA & alu_argB);
`NOR: o <= ~(alu_argA | alu_argB);
`ENOR: o <= ~(alu_argA ^ alu_argB);
default: o <= 64'd0;
endcase
`BITI:
begin
o[0] <= andi_res==64'd0;
o[1] <= andi_res[DBW-1];
o[2] <= andi_res[0];
o[3] <= 1'b0;
o[DBW-1:4] <= 60'd0;
end
`TST:
case(alu_fn)
6'd0: // TST - integer
begin
o[0] <= alu_argA == 64'd0;
o[1] <= alu_argA[DBW-1];
o[2] <= 1'b0;
o[3] <= 1'b0;
o[DBW-1:4] <= 60'd0;
end
`ifdef FLOATING_POINT
6'd1: // FSTST - float single
begin
o[0] <= alu_argA[30:0]==31'd0; // + or - zero
o[1] <= alu_argA[31]; // signed less than
o[2] <= alu_argA[31];
// unordered
o[3] <= alu_argA[30:23]==8'hFF && alu_argA[22:0]!=23'd0; // NaN
o[DBW-1:4] <= 60'd0;
end
6'd2: // FTST - float double
begin
o[0] <= alu_argA[DBW-2:0]==63'd0; // + or - zero
o[1] <= alu_argA[DBW-1]; // signed less than
o[2] <= alu_argA[DBW-1];
// unordered
if (DBW==64)
o[3] <= alu_argA[62:52]==11'h7FF && alu_argA[51:0]!=52'd0; // NaN
else
o[3] <= 1'b0;
o[DBW-1:4] <= 60'd0;
end
`endif
default: o <= 64'd0;
endcase
`CMP: begin
case(alu_fn)
2'd0: begin // ICMP
o[0] <= alu_argA == alu_argB;
o[1] <= alu_argAs < alu_argBs;
o[2] <= alu_argA < alu_argB;
o[3] <= 1'b0;
o[DBW-1:4] <= 60'd0;
end
`ifdef FLOATING_POINT
2'd1: begin // FSCMP
o[0] <= fseq;
o[1] <= fslt;
o[2] <= fslt1;
o[3] <= snanA | snanB;
o[DBW-1:4] <= 60'd0;
end
2'd2: begin // FCMP
o[0] <= feq;
o[1] <= flt;
o[2] <= flt1;
o[3] <= nanA | nanB;
o[DBW-1:4] <= 60'd0;
end
`endif
default: o <= 64'hDEADDEADDEADDEAD;
endcase
end
`CMPI: begin
o[0] <= alu_argA == alu_argI;
o[1] <= alu_argAs < alu_argIs;
o[2] <= alu_argA < alu_argI;
o[3] <= 1'b0;
o[DBW-1:4] <= 64'd0;
end
`LB,`LBU,`LC,`LCU,`LH,`LHU,`LW,`SB,`SC,`SH,`SW,`CAS,`LVB,`LVC,`LVH,`LVH,`STI,
`LWS,`SWS,`LEA,`RTS2,`STS,`STFND,`STCMP:
begin
o <= alu_argA + alu_argC + alu_argI;
end
`LBX,`LBUX,`SBX,
`LCX,`LCUX,`SCX,
`LHX,`LHUX,`SHX,
`LWX,`SWX:
case(alu_fn[1:0])
2'd0: o <= alu_argA + alu_argC + alu_argB;
2'd1: o <= alu_argA + alu_argC + {alu_argB,1'b0};
2'd2: o <= alu_argA + alu_argC + {alu_argB,2'b0};
2'd3: o <= alu_argA + alu_argC + {alu_argB,3'b0};
endcase
`ifdef STACKOPS
`PUSH,`PEA,`LINK: o <= alu_argA + alu_argC - 64'd8;
`UNLINK: o <= alu_argA + alu_argC + 64'd8;
`POP: o <= alu_argA + alu_argC;
`endif
`JSR,`JSRS,`JSRZ,`SYS: o <= alu_pc + insnsz;
`INT: o <= alu_pc;
`MFSPR,`MTSPR: begin
o <= alu_argA;
end
`MUX: begin
for (n = 0; n < DBW; n = n + 1)
o[n] <= alu_argA[n] ? alu_argB[n] : alu_argC[n];
end
`BCD:
if (BIG)
case(alu_fn)
`BCDADD: o <= bcdao;
`BCDSUB: o <= bcdso;
`BCDMUL: o <= bcdmo;
default: o <= 64'hDEADDEADDEADDEAD;
endcase
else
o <= 64'hDEADDEADDEADDEAD;
`SHIFT: o <= BIG ? shfto : 64'hDEADDEADDEADDEAD;
`ifdef BITFIELDOPS
`BITFIELD: o <= BIG ? bf_out : 64'hDEADDEADDEADDEAD;
`endif
`LOOP: o <= alu_argB > 0 ? alu_argB - 64'd1 : alu_argB;
default: o <= 64'hDEADDEADDEADDEAD;
endcase
end
 
// Generate done signal
always @*
case(alu_op)
`RR:
case(alu_fn)
`MUL,`MULU: alu_done <= alu_mult_done;
`DIV,`DIVU: alu_done <= alu_div_done;
default: alu_done <= `TRUE;
endcase
`MULI,`MULUI: alu_done <= alu_mult_done;
`DIVI,`DIVUI: alu_done <= alu_div_done;
default: alu_done <= `TRUE;
endcase
 
endmodule
/trunk/rtl/verilog/Thor_TLB.v
0,0 → 1,307
`include "Thor_defines.v"
//=============================================================================
// __
// \\__/ o\ (C) 2011,2012,2013 Robert Finch
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// Thor_TLB.v
//
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// TLB
// The TLB contains 64 entries, that are 8 way set associative.
// The TLB is dual ported and shared between the instruction and data streams.
//
//=============================================================================
//
`define TLBMissPage {DBW-12{1'b1}}
 
module Thor_TLB(rst, clk, km, pc, ea, ppc, pea,
iuncached, uncached,
m1IsStore, ASID, state, op, regno, dati, dato,
ITLBMiss, DTLBMiss, HTLBVirtPageo);
parameter DBW=64;
input rst;
input clk;
input km; // kernel mode
input [DBW-1:0] pc;
input [DBW-1:0] ea;
output reg [DBW-1:0] ppc;
output reg [DBW-1:0] pea;
output iuncached;
output uncached;
input m1IsStore;
input [7:0] ASID;
input [2:0] state;
input [3:0] op;
input [3:0] regno;
input [DBW-1:0] dati;
output [DBW-1:0] dato;
reg [DBW-1:0] dato;
output ITLBMiss;
output DTLBMiss;
output [DBW-1:0] HTLBVirtPageo;
 
integer n;
 
// Holding registers
// These allow the TLB to updated in a single cycle
reg [DBW-1:0] HTLBVirtPage;
assign HTLBVirtPageo = {HTLBVirtPage,12'b0};
reg [DBW-1:0] HTLBPhysPage;
reg [7:0] HTLBASID;
reg HTLBG;
reg HTLBD;
reg [2:0] HTLBC;
reg HTLBValid;
 
reg TLBenabled;
reg [5:0] i;
reg [DBW-1:0] Index;
reg [2:0] Random;
reg [2:0] Wired;
reg [2:0] PageSize;
reg [7:0] IMatch,DMatch;
 
reg [3:0] m;
reg [3:0] q;
wire doddpage;
reg [DBW-1:0] TLBVirtPage [63:0];
reg [DBW-1:0] TLBPhysPage [63:0];
reg [63:0] TLBG;
reg [63:0] TLBD;
reg [2:0] TLBC [63:0];
reg [7:0] TLBASID [63:0];
reg [63:0] TLBValid;
reg [DBW-1:0] imiss_addr;
reg [DBW-1:0] dmiss_addr;
reg [DBW-1:0] PageTblAddr;
reg [DBW-1:0] PageTblCtrl;
 
initial begin
for (n = 0; n < 64; n = n + 1)
begin
TLBVirtPage[n] = 0;
TLBPhysPage[n] = 0;
TLBG[n] = 0;
TLBASID[n] = 0;
TLBD[n] = 0;
TLBC[n] = 0;
TLBValid[n] = 0;
end
end
 
// Assume the instruction doesn't overlap between a mapped and unmapped area.
wire unmappedArea = pc[DBW-1:DBW-4]==4'hF || !TLBenabled;
wire unmappedDataArea = ea[DBW-1:DBW-4]==4'hF || !TLBenabled;
wire m1UnmappedDataArea = pea[DBW-1:DBW-4]==4'hF || !TLBenabled;
wire hitIOPage = ea[DBW-1:DBW-12]==12'hFFD;
 
always @(posedge clk)
if (rst) begin
TLBenabled <= 1'b0;
Random <= 3'h7;
Wired <= 3'd0;
PageSize <= 3'd0;
PageTblAddr <= {DBW{1'b0}};
PageTblCtrl <= {DBW{1'b0}};
end
else begin
if (dmiss_addr == {DBW{1'b0}} && DTLBMiss)
dmiss_addr <= ea;
if (imiss_addr == {DBW{1'b0}} && ITLBMiss)
imiss_addr <= pc;
 
if (Random==Wired)
Random <= 3'd7;
else
Random <= Random - 3'd1;
 
if (state==3'd1) begin
case(op)
`TLB_RD,`TLB_WI:
i <= {Index[5:3],(HTLBVirtPage >> {PageSize,1'b0}) & 3'h7};
`TLB_WR:
i <= {Random,(HTLBVirtPage >> {PageSize,1'b0}) & 3'h7};
`TLB_WRREG:
begin
case(regno)
`TLBWired: Wired <= dati[2:0];
`TLBIndex: Index <= dati[5:0];
`TLBRandom: Random <= dati[2:0];
`TLBPageSize: PageSize <= dati[2:0];
`TLBVirtPage: HTLBVirtPage <= dati;
`TLBPhysPage: HTLBPhysPage <= dati;
`TLBASID: begin
HTLBValid <= dati[0];
HTLBD <= dati[1];
HTLBC <= dati[4:2];
HTLBASID <= dati[23:16];
HTLBG <= dati[31];
end
`TLBDMissAdr: dmiss_addr <= dati;
`TLBIMissAdr: imiss_addr <= dati;
`TLBPageTblAddr: PageTblAddr <= dati;
`TLBPageTblCtrl: PageTblCtrl <= dati;
endcase
end
`TLB_EN:
TLBenabled <= 1'b1;
`TLB_DIS:
TLBenabled <= 1'b0;
`TLB_INVALL:
TLBValid <= 64'd0;
endcase
end
else if (state==3'd2) begin
case(op)
`TLB_P:
begin
Index[DBW-1] <= ~|DMatch;
end
`TLB_RD:
begin
HTLBVirtPage <= TLBVirtPage[i];
HTLBPhysPage <= TLBPhysPage[i];
HTLBASID <= TLBASID[i];
HTLBG <= TLBG[i];
HTLBD <= TLBD[i];
HTLBC <= TLBC[i];
HTLBValid <= TLBValid[i];
end
`TLB_WR,`TLB_WI:
begin
TLBVirtPage[i] <= HTLBVirtPage;
TLBPhysPage[i] <= HTLBPhysPage;
TLBASID[i] <= HTLBASID;
TLBG[i] <= HTLBG;
TLBD[i] <= HTLBD;
TLBC[i] <= HTLBC;
TLBValid[i] <= HTLBValid;
end
default: ;
endcase
end
 
// Set the dirty bit on a store
if (m1IsStore)
if (!m1UnmappedDataArea & !q[3]) begin
TLBD[{q[2:0],(pea[DBW-1:12]>>{PageSize,1'b0})&3'd7}] <= 1'b1;
end
end
 
always @*
case(regno)
`TLBWired: dato = Wired;
`TLBIndex: dato = Index;
`TLBRandom: dato = Random;
`TLBPhysPage: dato = HTLBPhysPage;
`TLBVirtPage: dato = HTLBVirtPage;
`TLBPageSize: dato = PageSize;
`TLBASID: begin
dato = {DBW{1'b0}};
dato[0] = HTLBValid;
dato[1] = HTLBD;
dato[4:2] = HTLBC;
dato[23:16] = HTLBASID;
dato[31] = HTLBG;
end
`TLBDMissAdr: dato = dmiss_addr;
`TLBIMissAdr: dato = imiss_addr;
`TLBPageTblAddr: dato = PageTblAddr;
`TLBPageTblCtrl: dato = PageTblCtrl;
default: dato = {DBW{1'b0}};
endcase
 
wire [DBW-1:0] pcs = pc[DBW-1:12] >> {PageSize,1'b0};
always @*
for (n = 0; n < 8; n = n + 1)
begin
IMatch[n[2:0]] = (pcs[DBW-1:3]==TLBVirtPage[{n[2:0],pcs[2:0]}][DBW-1:3]) &&
((TLBASID[{n,pcs[2:0]}]==ASID) || TLBG[{n,pcs[2:0]}]) &&
TLBValid[{n[2:0],pcs[2:0]}];
end
 
always @(IMatch)
if (IMatch[0]) m <= 4'd0;
else if (IMatch[1]) m <= 4'd1;
else if (IMatch[2]) m <= 4'd2;
else if (IMatch[3]) m <= 4'd3;
else if (IMatch[4]) m <= 4'd4;
else if (IMatch[5]) m <= 4'd5;
else if (IMatch[6]) m <= 4'd6;
else if (IMatch[7]) m <= 4'd7;
else m <= 4'd15;
 
 
wire [DBW-1:0] IPFN = TLBPhysPage[{m[2:0],pcs[2:0]}];
assign iuncached = TLBC[{m[2:0],pcs[2:0]}]==3'd1;
 
assign ITLBMiss = TLBenabled & (!unmappedArea & (m[3] | ~TLBValid[{m[2:0],pcs[2:0]}]));
 
always @*
begin
ppc[11:0] = pc[11:0];
case(PageSize)
3'd0: ppc[DBW-1:12] = unmappedArea ? pc[DBW-1:12] : ITLBMiss ? `TLBMissPage: IPFN; // 4KiB
3'd1: ppc[DBW-1:12] = {unmappedArea ? pc[DBW-1:14] : ITLBMiss ? `TLBMissPage: IPFN,pc[13:12]}; // 16KiB
3'd2: ppc[DBW-1:12] = {unmappedArea ? pc[DBW-1:16] : ITLBMiss ? `TLBMissPage: IPFN,pc[15:12]}; // 64KiB
3'd3: ppc[DBW-1:12] = {unmappedArea ? pc[DBW-1:18] : ITLBMiss ? `TLBMissPage: IPFN,pc[17:12]}; // 256 KiB
3'd4: ppc[DBW-1:12] = {unmappedArea ? pc[DBW-1:20] : ITLBMiss ? `TLBMissPage: IPFN,pc[19:12]}; // 1 MiB
default: ppc[DBW-1:12] = pc[DBW-1:12];
endcase
end
 
wire [DBW-1:0] eas = ea[DBW-1:12] >> {PageSize,1'b0};
always @(ea)
for (n = 0; n < 8; n = n + 1)
DMatch[n[2:0]] = (eas[DBW-1:3]==TLBVirtPage[{n,eas[2:0]}]) &&
((TLBASID[{n,eas[2:0]}]==ASID) || TLBG[{n,eas[2:0]}]) &&
TLBValid[{q[2:0],eas[2:0]}];
always @(DMatch)
if (DMatch[0]) q <= 4'd0;
else if (DMatch[1]) q <= 4'd1;
else if (DMatch[2]) q <= 4'd2;
else if (DMatch[3]) q <= 4'd3;
else if (DMatch[4]) q <= 4'd4;
else if (DMatch[5]) q <= 4'd5;
else if (DMatch[6]) q <= 4'd6;
else if (DMatch[7]) q <= 4'd7;
else q <= 4'd15;
 
wire [DBW-1:0] DPFN = TLBPhysPage[{q[2:0],eas[2:0]}];
assign uncached = TLBC[{q[2:0],eas[2:0]}]==3'd1;// || unmappedDataArea;
 
assign DTLBMiss = TLBenabled & (!unmappedDataArea & (q[3] | ~TLBValid[{q[2:0],eas[2:0]}]) ||
(!km && hitIOPage));
 
always @*
begin
case(PageSize)
3'd0: pea[DBW-1:12] = unmappedDataArea ? ea[DBW-1:12] : DTLBMiss ? `TLBMissPage: DPFN;
3'd1: pea[DBW-1:12] = {unmappedDataArea ? ea[DBW-1:14] : DTLBMiss ? `TLBMissPage: DPFN,ea[13:12]};
3'd2: pea[DBW-1:12] = {unmappedDataArea ? ea[DBW-1:16] : DTLBMiss ? `TLBMissPage: DPFN,ea[15:12]};
3'd3: pea[DBW-1:12] = {unmappedDataArea ? ea[DBW-1:18] : DTLBMiss ? `TLBMissPage: DPFN,ea[17:12]};
3'd4: pea[DBW-1:12] = {unmappedDataArea ? ea[DBW-1:20] : DTLBMiss ? `TLBMissPage: DPFN,ea[19:12]};
default: pea[DBW-1:12] = ea[DBW-1:12];
endcase
pea[11:0] = ea[11:0];
end
 
endmodule
 
/trunk/rtl/verilog/Thor_bitfield.v
0,0 → 1,85
`include "Thor_defines.v"
`timescale 1ns / 1ps
//=============================================================================
// __
// \\__/ o\ (C) 2012,2013 Robert Finch
// \ __ / All rights reserved.
// \/_// robfinch<remove>@opencores.org
// ||
//
// Thor_bitfield.v
// - bitfield datapath operations
//
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
//=============================================================================
//
//`define I_BFEXTS 1
//`define I_SEXT 1
 
module Thor_bitfield(op, a, b, m, o, masko);
parameter DWIDTH=64;
input [3:0] op;
input [DWIDTH-1:0] a;
input [DWIDTH-1:0] b;
input [15:0] m;
output [DWIDTH-1:0] o;
reg [DWIDTH-1:0] o;
output [DWIDTH-1:0] masko;
 
reg [DWIDTH-1:0] o1;
reg [DWIDTH-1:0] o2;
 
// generate mask
reg [DWIDTH-1:0] mask;
assign masko = mask;
wire [5:0] mb = m[ 5:0];
wire [5:0] me = m[11:6];
wire [5:0] ml = me-mb; // mask length-1
 
integer nn,n;
always @(mb or me or nn)
for (nn = 0; nn < DWIDTH; nn = nn + 1)
mask[nn] <= (nn >= mb) ^ (nn <= me) ^ (me >= mb);
 
always @(op,mask,b,a,mb)
case (op)
`BFINS: begin
o2 = a << mb;
for (n = 0; n < DWIDTH; n = n + 1) o[n] = mask[n] ? o2[n] : b[n];
end
`BFSET: begin for (n = 0; n < DWIDTH; n = n + 1) o[n] = mask[n] ? 1'b1 : a[n]; end
`BFCLR: begin for (n = 0; n < DWIDTH; n = n + 1) o[n] = mask[n] ? 1'b0 : a[n]; end
`BFCHG: begin for (n = 0; n < DWIDTH; n = n + 1) o[n] = mask[n] ? ~a[n] : a[n]; end
`BFEXTU: begin
for (n = 0; n < DWIDTH; n = n + 1)
o1[n] = mask[n] ? a[n] : 1'b0;
o = o1 >> mb;
end
`BFEXT: begin
for (n = 0; n < DWIDTH; n = n + 1)
o1[n] = mask[n] ? a[n] : 1'b0;
o2 = o1 >> mb;
for (n = 0; n < DWIDTH; n = n + 1)
o[n] = n > ml ? o2[ml] : o2[n];
end
`ifdef I_SEXT
`SEXT: begin for (n = 0; n < DWIDTH; n = n + 1) o[n] = mask[n] ? a[mb] : a[n]; end
`endif
default: o = {DWIDTH{1'b0}};
endcase
 
endmodule
/trunk/rtl/verilog/Thor_itagmem.v
0,0 → 1,74
// ============================================================================
// __
// \\__/ o\ (C) 2013 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Thor SuperScalar
// Instruction cache tag memory
//
// ============================================================================
//
module Thor_itagmem(wclk, wce, wr, wa, err_i, invalidate, invalidate_line, invalidate_lineno,
rclk, rce, pc, hit0, hit1, err_o);
parameter AMSB=63;
input wclk;
input wce;
input wr;
input [AMSB:0] wa;
input err_i;
input invalidate;
input invalidate_line;
input [AMSB:0] invalidate_lineno;
input rclk;
input rce;
input [AMSB:0] pc;
output hit0;
output hit1;
output err_o;
 
reg [AMSB:15] mem [0:1023];
reg [0:1023] tvalid;
reg [0:1023] errmem;
reg [AMSB:0] rpc,rpcp16;
wire [AMSB-13:0] tag0,tag1;
 
integer n;
initial begin
for (n = 0; n < 1024; n = n + 1)
mem[n] <= 0;
end
 
always @(posedge wclk)
if (wce & wr) mem[wa[14:5]] <= wa[AMSB:15];
always @(posedge wclk)
if (invalidate) begin tvalid <= 1024'd0; errmem <= 1024'd0; end
else if (invalidate_line) tvalid[invalidate_lineno[14:5]] <= 1'b0;
else if (wce & wr) begin tvalid[wa[14:5]] <= 1'b1; errmem[wa[14:5]] <= err_i; end
always @(posedge rclk)
if (rce) rpc <= pc;
always @(posedge rclk)
if (rce) rpcp16 <= pc + 64'd16;
assign tag0 = {mem[rpc[14:5]],tvalid[rpc[14:5]]};
assign tag1 = {mem[rpcp16[14:5]],tvalid[rpcp16[14:5]]};
 
assign hit0 = tag0 == {rpc[AMSB:15],1'b1};
assign hit1 = tag1 == {rpcp16[AMSB:15],1'b1};
assign err_o = errmem[rpc[14:5]]|errmem[rpcp16[14:5]];
 
endmodule
/trunk/rtl/verilog/Thor_multiplier.v
0,0 → 1,150
// ============================================================================
// __
// \\__/ o\ (C) 2013 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Thor Superscaler
// Thor_multiplier.v
// - 64 bit multiplier
//
// ============================================================================
//
module Thor_multiplier(rst, clk, ld, sgn, isMuli, a, b, imm, o, done);
parameter WID=64;
parameter SGNADJO=3'd2;
parameter MULT=3'd3;
parameter IDLE=3'd4;
parameter DONE=3'd5;
input clk;
input rst;
input ld;
input sgn;
input isMuli;
input [WID-1:0] a;
input [WID-1:0] b;
input [WID-1:0] imm;
output [WID*2-1:0] o;
reg [WID*2-1:0] o;
output done;
 
reg [WID-1:0] aa,bb;
reg so;
reg [2:0] state;
reg [7:0] cnt;
wire cnt_done = cnt==8'd0;
assign done = state==DONE;
reg ce1;
reg [WID*2-1:0] prod;
//wire [64:0] p1 = aa[0] ? prod[127:64] + b : prod[127:64];
//wire [65:0] p2 = aa[1] ? p1 + {b,1'b0} : p1;
wire [WID+WID/4-1:0] p1 = bb * aa[WID/4-1:0] + prod[WID*2-1:WID];
 
initial begin
prod = 64'd0;
o = 64'd0;
end
 
always @(posedge clk)
if (rst) begin
aa <= {WID{1'b0}};
bb <= {WID{1'b0}};
prod <= {WID*2{1'b0}};
o <= {WID*2{1'b0}};
state <= IDLE;
end
else
begin
if (!cnt_done)
cnt <= cnt - 8'd1;
 
case(state)
IDLE:
if (ld) begin
if (sgn) begin
aa <= a[WID-1] ? -a : a;
bb <= isMuli ? (imm[WID-1] ? -imm : imm) :(b[WID-1] ? -b : b);
so <= isMuli ? a[WID-1] ^ imm[WID-1] : a[WID-1] ^ b[WID-1];
end
else begin
aa <= a;
bb <= isMuli ? imm : b;
so <= 1'b0;
end
prod <= {WID*2{1'b0}};
cnt <= 8'd4;
state <= MULT;
end
MULT:
if (!cnt_done) begin
aa <= {16'b0,aa[WID-1:WID/4]};
prod <= {16'b0,prod[WID*2-1:WID/4]};
prod[WID*2-1:WID*3/4] <= p1;
end
else begin
if (sgn) begin
if (so)
o <= -prod;
else
o <= prod;
end
else
o <= prod;
state <= DONE;
end
default:
state <= IDLE;
endcase
end
 
endmodule
 
module Thor_multiplier_tb();
 
reg rst;
reg clk;
reg ld;
wire [127:0] o;
 
initial begin
clk = 1;
rst = 0;
#100 rst = 1;
#100 rst = 0;
#100 ld = 1;
#150 ld = 0;
end
 
always #10 clk = ~clk; // 50 MHz
 
 
Thor_multiplier u1
(
.rst(rst),
.clk(clk),
.ld(ld),
.sgn(1'b0),
.isMuli(1'b1),
.a(64'd56),
.b(64'd0),
.imm(64'd27),
.o(o)
);
 
endmodule
 
/trunk/rtl/verilog/Thor_divider.v
0,0 → 1,171
// ============================================================================
// __
// \\__/ o\ (C) 2013 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Thor Superscaler
// Thor_divider.v
// - 64 bit divider
//
// ============================================================================
//
module Thor_divider(rst, clk, ld, sgn, isDivi, a, b, imm, qo, ro, dvByZr, done);
parameter WID=64;
parameter DIV=3'd3;
parameter IDLE=3'd4;
parameter DONE=3'd5;
input clk;
input rst;
input ld;
input sgn;
input isDivi;
input [WID-1:0] a;
input [WID-1:0] b;
input [WID-1:0] imm;
output [WID-1:0] qo;
reg [WID-1:0] qo;
output [WID-1:0] ro;
reg [WID-1:0] ro;
output done;
output dvByZr;
reg dvByZr;
 
reg [WID-1:0] aa,bb;
reg so;
reg [2:0] state;
reg [7:0] cnt;
wire cnt_done = cnt==8'd0;
assign done = state==DONE;
reg ce1;
reg [WID-1:0] q;
reg [WID:0] r;
wire b0 = bb <= r;
wire [WID-1:0] r1 = b0 ? r - bb : r;
 
initial begin
q = 64'd0;
r = 64'd0;
qo = 64'd0;
ro = 64'd0;
end
 
always @(posedge clk)
if (rst) begin
aa <= {WID{1'b0}};
bb <= {WID{1'b0}};
q <= {WID{1'b0}};
r <= {WID{1'b0}};
qo <= {WID{1'b0}};
ro <= {WID{1'b0}};
cnt <= 8'd0;
state <= IDLE;
end
else
begin
if (!cnt_done)
cnt <= cnt - 8'd1;
 
case(state)
IDLE:
if (ld) begin
if (sgn) begin
q <= a[WID-1] ? -a : a;
bb <= isDivi ? (imm[WID-1] ? -imm : imm) :(b[WID-1] ? -b : b);
so <= isDivi ? a[WID-1] ^ imm[WID-1] : a[WID-1] ^ b[WID-1];
end
else begin
q <= a;
bb <= isDivi ? imm : b;
so <= 1'b0;
$display("bb=%d", isDivi ? imm : b);
end
dvByZr <= isDivi ? imm=={WID{1'b0}} : b=={WID{1'b0}};
r <= {WID{1'b0}};
cnt <= WID+1;
state <= DIV;
end
DIV:
if (!cnt_done) begin
$display("cnt:%d r1=%h q[63:0]=%h", cnt,r1,q);
q <= {q[WID-2:0],b0};
r <= {r1,q[WID-1]};
end
else begin
$display("cnt:%d r1=%h q[63:0]=%h", cnt,r1,q);
if (sgn) begin
if (so) begin
qo <= -q;
ro <= -r[WID:1];
end
else begin
qo <= q;
ro <= r[WID:1];
end
end
else begin
qo <= q;
ro <= r[WID:1];
end
state <= DONE;
end
DONE:
state <= IDLE;
endcase
end
 
endmodule
 
module Thor_divider_tb();
parameter WID=64;
reg rst;
reg clk;
reg ld;
wire done;
wire [WID-1:0] qo,ro;
 
initial begin
clk = 1;
rst = 0;
#100 rst = 1;
#100 rst = 0;
#100 ld = 1;
#150 ld = 0;
end
 
always #10 clk = ~clk; // 50 MHz
 
 
Thor_divider #(WID) u1
(
.rst(rst),
.clk(clk),
.ld(ld),
.sgn(1'b1),
.isDivi(1'b0),
.a(64'd10005),
.b(64'd27),
.imm(64'd123),
.qo(qo),
.ro(ro),
.dvByZr(),
.done(done)
);
 
endmodule
 
/trunk/rtl/verilog/Thor_regfile2w6r.v
0,0 → 1,128
`timescale 1ns / 1ps
// ============================================================================
// __
// \\__/ o\ (C) 2013,2015 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Register file with two write ports and six read ports.
// ============================================================================
//
module Thor_regfile2w6r(clk, wr0, wr1, wa0, wa1, i0, i1,
rclk, ra0, ra1, ra2, ra3, ra4, ra5, o0, o1, o2, o3, o4, o5);
parameter WID=64;
input clk;
input wr0;
input wr1;
input [5:0] wa0;
input [5:0] wa1;
input [WID-1:0] i0;
input [WID-1:0] i1;
input rclk;
input [5:0] ra0;
input [5:0] ra1;
input [5:0] ra2;
input [5:0] ra3;
input [5:0] ra4;
input [5:0] ra5;
output [WID-1:0] o0;
output [WID-1:0] o1;
output [WID-1:0] o2;
output [WID-1:0] o3;
output [WID-1:0] o4;
output [WID-1:0] o5;
 
reg [WID-1:0] regs0 [0:63];
reg [WID-1:0] regs1 [0:63];
reg [5:0] rra0,rra1,rra2,rra3,rra4,rra5;
 
reg whichreg [0:63]; // tracks which register file is the valid one for a given register
 
// We only care about what's in the regs to begin with in simulation. In sim
// the 'x' values propagate screwing things up. In real hardware there's no such
// thing as an 'x'.
`define SIMULATION
`ifdef SIMULATION
integer n;
initial begin
for (n = 0; n < 64; n = n + 1)
begin
regs0[n] = 0;
regs1[n] = 0;
whichreg[n] = 0;
end
end
`endif
 
 
assign o0 = rra0==6'd0 ? {WID{1'b0}} :
(wr1 && (rra0==wa1)) ? i1 :
(wr0 && (rra0==wa0)) ? i0 :
whichreg[rra0]==1'b0 ? regs0[rra0] : regs1[rra0];
assign o1 = rra1==6'd0 ? {WID{1'b0}} :
(wr1 && (rra1==wa1)) ? i1 :
(wr0 && (rra1==wa0)) ? i0 :
whichreg[rra1]==1'b0 ? regs0[rra1] : regs1[rra1];
assign o2 = rra2==6'd0 ? {WID{1'b0}} :
(wr1 && (rra2==wa1)) ? i1 :
(wr0 && (rra2==wa0)) ? i0 :
whichreg[rra2]==1'b0 ? regs0[rra2] : regs1[rra2];
assign o3 = rra3==6'd0 ? {WID{1'b0}} :
(wr1 && (rra3==wa1)) ? i1 :
(wr0 && (rra3==wa0)) ? i0 :
whichreg[rra3]==1'b0 ? regs0[rra3] : regs1[rra3];
assign o4 = rra4==6'd0 ? {WID{1'b0}} :
(wr1 && (rra4==wa1)) ? i1 :
(wr0 && (rra4==wa0)) ? i0 :
whichreg[rra4]==1'b0 ? regs0[rra4] : regs1[rra4];
assign o5 = rra5==6'd0 ? {WID{1'b0}} :
(wr1 && (rra5==wa1)) ? i1 :
(wr0 && (rra5==wa0)) ? i0 :
whichreg[rra5]==1'b0 ? regs0[rra5] : regs1[rra5];
 
always @(posedge clk)
if (wr0)
regs0[wa0] <= i0;
 
always @(posedge clk)
if (wr1)
regs1[wa1] <= i1;
 
always @(posedge rclk) rra0 <= ra0;
always @(posedge rclk) rra1 <= ra1;
always @(posedge rclk) rra2 <= ra2;
always @(posedge rclk) rra3 <= ra3;
always @(posedge rclk) rra4 <= ra4;
always @(posedge rclk) rra5 <= ra5;
 
always @(posedge clk)
// writing three registers at once
if (wr0 && wr1 && wa0==wa1) // Two ports writing the same address
whichreg[wa0] <= 1'b1; // port one is the valid one
// writing two registers
else if (wr0 && wr1) begin
whichreg[wa0] <= 1'b0;
whichreg[wa1] <= 1'b1;
end
// writing a single register
else if (wr0)
whichreg[wa0] <= 1'b0;
else if (wr1)
whichreg[wa1] <= 1'b1;
 
endmodule
/trunk/rtl/verilog/Thor_P.v
0,0 → 1,53
// ============================================================================
// __
// \\__/ o\ (C) 2015 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Thor SuperScaler
// ALU
//
// ============================================================================
//
`include "Thor_defines.v"
 
module Thor_P(fn, ra, rb, rt, pregs_i, pregs_o);
parameter DBW=64;
input [5:0] fn;
input [5:0] ra;
input [5:0] rb;
input [5:0] rt;
input [DBW-1:0] pregs_i;
output reg [DBW-1:0] pregs_o;
 
always @*
begin
pregs_o = pregs_i;
case (fn)
`PAND: pregs_o[rt] = pregs_i[ra] & pregs_i[rb];
`POR: pregs_o[rt] = pregs_i[ra] | pregs_i[rb];
`PEOR: pregs_o[rt] = pregs_i[ra] ^ pregs_i[rb];
`PNAND: pregs_o[rt] = ~(pregs_i[ra] & pregs_i[rb]);
`PNOR: pregs_o[rt] = ~(pregs_i[ra] | pregs_i[rb]);
`PENOR: pregs_o[rt] = ~(pregs_i[ra] ^ pregs_i[rb]);
`PANDC: pregs_o[rt] = pregs_i[ra] & ~pregs_i[rb];
`PORC: pregs_o[rt] = pregs_i[ra] | ~pregs_i[rb];
default: pregs_o = pregs_i;
endcase
end
endmodule
/trunk/rtl/verilog/Thor_shifter.v
0,0 → 1,56
// ============================================================================
// __
// \\__/ o\ (C) 2013 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Thor SuperScalar
// Shift logic
//
// ============================================================================
//
`include "Thor_defines.v"
 
module Thor_shifter(func, a, b, o);
parameter DBW=64;
input [5:0] func;
input [DBW-1:0] a;
input [DBW-1:0] b;
output reg [DBW-1:0] o;
 
wire [DBW*2-1:0] shlo = {{DBW{1'd0}},a} << b[5:0];
wire [DBW*2-1:0] shruo = {a,{DBW{1'b0}}} >> b[5:0];
wire signed [DBW-1:0] as = a;
wire signed [DBW-1:0] shro = as >> b[5:0];
 
always @(func or shlo or shro or shruo)
case(func)
`SHL,`SHLU,`SHLI,`SHLUI:
o <= shlo[DBW-1:0];
`SHR,`SHRI:
o <= shro;
`SHRU,`SHRUI:
o <= shruo[DBW*2-1:DBW];
`ROL,`ROLI:
o <= shlo[DBW*2-1:DBW]|shlo[DBW-1:0];
`ROR,`RORI:
o <= shruo[DBW*2-1:DBW]|shruo[DBW-1:0];
default: o <= 64'hDEADDEADDEADDEAD;
endcase
 
endmodule
/trunk/rtl/verilog/Thor_livetarget.v
0,0 → 1,117
// ============================================================================
// __
// \\__/ o\ (C) 2013,2015 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Thor SuperScalar
// Live Target logic
//
// ============================================================================
//
//1675 LUTs
module Thor_livetarget(iqentry_v,iqentry_stomp,iqentry_cmt,tgt0,tgt1,tgt2,tgt3,tgt4,tgt5,tgt6,tgt7,livetarget,
iqentry_0_livetarget,
iqentry_1_livetarget,
iqentry_2_livetarget,
iqentry_3_livetarget,
iqentry_4_livetarget,
iqentry_5_livetarget,
iqentry_6_livetarget,
iqentry_7_livetarget
);
parameter NREGS = 111;
input [7:0] iqentry_v;
input [7:0] iqentry_stomp;
input [7:0] iqentry_cmt;
input [6:0] tgt0;
input [6:0] tgt1;
input [6:0] tgt2;
input [6:0] tgt3;
input [6:0] tgt4;
input [6:0] tgt5;
input [6:0] tgt6;
input [6:0] tgt7;
output [NREGS:1] livetarget;
output [NREGS:1] iqentry_0_livetarget;
output [NREGS:1] iqentry_1_livetarget;
output [NREGS:1] iqentry_2_livetarget;
output [NREGS:1] iqentry_3_livetarget;
output [NREGS:1] iqentry_4_livetarget;
output [NREGS:1] iqentry_5_livetarget;
output [NREGS:1] iqentry_6_livetarget;
output [NREGS:1] iqentry_7_livetarget;
 
wire [6:0] iqentry_tgt [0:7];
assign iqentry_tgt[0] = tgt0;
assign iqentry_tgt[1] = tgt1;
assign iqentry_tgt[2] = tgt2;
assign iqentry_tgt[3] = tgt3;
assign iqentry_tgt[4] = tgt4;
assign iqentry_tgt[5] = tgt5;
assign iqentry_tgt[6] = tgt6;
assign iqentry_tgt[7] = tgt7;
 
wire [NREGS:1] iq0_out;
wire [NREGS:1] iq1_out;
wire [NREGS:1] iq2_out;
wire [NREGS:1] iq3_out;
wire [NREGS:1] iq4_out;
wire [NREGS:1] iq5_out;
wire [NREGS:1] iq6_out;
wire [NREGS:1] iq7_out;
 
reg [NREGS:1] livetarget;
 
decoder7 iq0(.num(iqentry_tgt[0]), .out(iq0_out));
decoder7 iq1(.num(iqentry_tgt[1]), .out(iq1_out));
decoder7 iq2(.num(iqentry_tgt[2]), .out(iq2_out));
decoder7 iq3(.num(iqentry_tgt[3]), .out(iq3_out));
decoder7 iq4(.num(iqentry_tgt[4]), .out(iq4_out));
decoder7 iq5(.num(iqentry_tgt[5]), .out(iq5_out));
decoder7 iq6(.num(iqentry_tgt[6]), .out(iq6_out));
decoder7 iq7(.num(iqentry_tgt[7]), .out(iq7_out));
 
integer n;
always @*
for (n = 1; n < NREGS+1; n = n + 1)
livetarget[n] <= iqentry_0_livetarget[n] | iqentry_1_livetarget[n] | iqentry_2_livetarget[n] | iqentry_3_livetarget[n] |
iqentry_4_livetarget[n] | iqentry_5_livetarget[n] | iqentry_6_livetarget[n] | iqentry_7_livetarget[n]
;
assign
iqentry_0_livetarget = {NREGS{iqentry_v[0]}} & {NREGS{~iqentry_stomp[0]}} & iq0_out,
iqentry_1_livetarget = {NREGS{iqentry_v[1]}} & {NREGS{~iqentry_stomp[1]}} & iq1_out,
iqentry_2_livetarget = {NREGS{iqentry_v[2]}} & {NREGS{~iqentry_stomp[2]}} & iq2_out,
iqentry_3_livetarget = {NREGS{iqentry_v[3]}} & {NREGS{~iqentry_stomp[3]}} & iq3_out,
iqentry_4_livetarget = {NREGS{iqentry_v[4]}} & {NREGS{~iqentry_stomp[4]}} & iq4_out,
iqentry_5_livetarget = {NREGS{iqentry_v[5]}} & {NREGS{~iqentry_stomp[5]}} & iq5_out,
iqentry_6_livetarget = {NREGS{iqentry_v[6]}} & {NREGS{~iqentry_stomp[6]}} & iq6_out,
iqentry_7_livetarget = {NREGS{iqentry_v[7]}} & {NREGS{~iqentry_stomp[7]}} & iq7_out;
 
endmodule
 
module decoder7 (num, out);
input [6:0] num;
output [127:1] out;
 
wire [127:0] out1;
 
assign out1 = 127'd1 << num;
assign out = out1[127:1];
 
endmodule
/trunk/rtl/verilog/Thor_pic.v
0,0 → 1,200
`timescale 1ns / 1ps
//=============================================================================
// (C) 2013,2015 Robert Finch
// All rights reserved.
// robfinch<remove>@Finitron.ca
//
// Thor_pic.v
//
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Encodes discrete interrupt request signals into four
// bit code using a priority encoder.
//
// reg
// 0x00 - encoded request number (read only)
// This register contains the number identifying
// the current requester.
// the actual number is shifted left three times
// before being placed into this register so it may
// be used directly as an index in OS software. The
// index may be a mailbox id or index into a jump
// table as desired by the OS. If there is no
// active request, then this number will be
// zero.
// 0x08 - request enable (read / write)
// this register contains request enable bits
// for each request line. 1 = request
// enabled, 0 = request disabled. On reset this
// register is set to zero (disable all ints).
// bit zero is specially reserved for nmi
//
// 0x10 - write only
// this register disables the interrupt indicated
// by the low order four bits of the input data
//
// 0x18 - write only
// this register enables the interrupt indicated
// by the low order four bits of the input data
//
// 0x20 - write only
// this register indicates which interrupt inputs are
// edge sensitive
//
// 0x28 - write only
// This register resets the edge sense circuitry
// indicated by the low order four bits of the input data.
//
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |WISHBONE Datasheet
// |WISHBONE SoC Architecture Specification, Revision B.3
// |
// |Description: Specifications:
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |General Description: simple programmable interrupt controller
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Supported Cycles: SLAVE,READ/WRITE
// | SLAVE,BLOCK READ/WRITE
// | SLAVE,RMW
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Data port, size: 32 bit
// |Data port, granularity: 32 bit
// |Data port, maximum operand size: 32 bit
// |Data transfer ordering: Undefined
// |Data transfer sequencing: Undefined
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Clock frequency constraints: none
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Supported signal list and Signal Name WISHBONE equiv.
// |cross reference to equivalent ack_o ACK_O
// |WISHBONE signals adr_i(2:1) ADR_I()
// | clk_i CLK_I
// | dat_i(15:0) DAT_I()
// | dat_o(15:0) DAT_O()
// | cyc_i CYC_I
// | stb_i STB_I
// | we_i WE_I
// |
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Special requirements:
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//
// Spartan3-4
// 105 LUTs / 58 slices / 163MHz
//=============================================================================
 
module Thor_pic
(
input rst_i, // reset
input clk_i, // system clock
input cyc_i, // cycle valid
input stb_i, // strobe
output ack_o, // transfer acknowledge
input we_i, // write
input [31:0] adr_i, // address
input [31:0] dat_i,
output reg [31:0] dat_o,
output vol_o, // volatile register selected
input i1, i2, i3, i4, i5, i6, i7,
i8, i9, i10, i11, i12, i13, i14, i15,
output irqo, // normally connected to the processor irq
input nmii, // nmi input connected to nmi requester
output nmio, // normally connected to the nmi of cpu
output [7:0] vecno
);
parameter pVECNO = 8'd192;
parameter pIOAddress = 32'hFFDC_0FC0;
 
reg [15:0] ie; // interrupt enable register
reg ack1;
reg [3:0] irqenc;
wire [15:0] i = {i15,i14,i13,i12,i11,i10,i9,i8,i7,i6,i5,i4,i3,i2,i1,nmii};
reg [15:0] ib;
reg [15:0] iedge;
reg [15:0] rste;
reg [15:0] es;
 
wire cs = cyc_i && stb_i && adr_i[31:6]==pIOAddress[31:6];
assign vol_o = cs;
 
always @(posedge clk_i)
ack1 <= cs;
assign ack_o = cs ? (we_i ? 1'b1 : ack1) : 1'b0;
 
// write registers
always @(posedge clk_i)
if (rst_i) begin
ie <= 16'h0;
rste <= 16'h0;
end
else begin
rste <= 16'h0;
if (cs & we_i) begin
case (adr_i[5:3])
3'd0,3'd1:
begin
ie[15:0] <= dat_i[15:0];
end
3'd2,3'd3:
ie[dat_i[3:0]] <= adr_i[2];
3'd4: es <= dat_i[15:0];
3'd5: rste[dat_i[3:0]] <= 1'b1;
endcase
end
end
 
// read registers
always @(posedge clk_i)
begin
if (irqenc!=4'd0)
$display("PIC: %d",irqenc);
if (cs)
case (adr_i[4:3])
2'd0: dat_o <= {28'b0,irqenc};
default: dat_o <= ie;
endcase
else
dat_o <= 32'h0000;
end
 
assign irqo = irqenc != 4'h0;
assign nmio = nmii & ie[0];
 
// Edge detect circuit
integer n;
always @(posedge clk_i)
begin
for (n = 1; n < 16; n = n + 1)
begin
ib[n] <= i[n];
if (i[n] & !ib[n]) iedge[n] <= 1'b1;
if (rste[n]) iedge[n] <= 1'b0;
end
end
 
// irq requests are latched on every rising clock edge to prevent
// misreads
// nmi is not encoded
always @(posedge clk_i)
begin
irqenc <= 4'd0;
for (n = 15; n > 0; n = n - 1)
if (ie[n] & (es[n] ? iedge[n] : i[n])) irqenc <= n;
end
 
assign vecno = pVECNO|irqenc;
 
endmodule
/trunk/rtl/verilog/Thor_icachemem.v
0,0 → 1,161
// ============================================================================
// __
// \\__/ o\ (C) 2013,2015 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Thor SuperScalar
//
// ============================================================================
//
module Thor_icachemem(wclk, wce, wr, wa, wd, rclk, pc, insn);
parameter DBW=64;
input wclk;
input wce;
input wr;
input [DBW-1:0] wa;
input [DBW-1:0] wd;
input rclk;
input [DBW-1:0] pc;
output reg [127:0] insn;
 
wire [127:0] mem0a;
wire [127:0] mem1a;
reg [14:0] pcp16;
 
generate
begin : gen1
if (DBW==32) begin
syncRam2kx32_1w1r uicm0a0 (
.wclk(wclk),
.wce(wce && wa[3:2]==2'b00),
.wr({4{wr}}),
.wa(wa[14:4]),
.wd(wd),
.rclk(rclk),
.rce(1'b1),
.ra(pc[14:4]),
.o(mem0a[31:0])
);
syncRam2kx32_1w1r uicm0a1 (
.wclk(wclk),
.wce(wce && wa[3:2]==2'b01),
.wr({4{wr}}),
.wa(wa[14:4]),
.wd(wd),
.rclk(rclk),
.rce(1'b1),
.ra(pc[14:4]),
.o(mem0a[63:32])
);
syncRam2kx32_1w1r uicm0a2 (
.wclk(wclk),
.wce(wce && wa[3:2]==2'b10),
.wr({4{wr}}),
.wa(wa[14:4]),
.wd(wd),
.rclk(rclk),
.rce(1'b1),
.ra(pc[14:4]),
.o(mem0a[95:64])
);
syncRam2kx32_1w1r uicm0a3 (
.wclk(wclk),
.wce(wce && wa[3:2]==2'b11),
.wr({4{wr}}),
.wa(wa[14:4]),
.wd(wd),
.rclk(rclk),
.rce(1'b1),
.ra(pc[14:4]),
.o(mem0a[127:96])
);
 
syncRam2kx32_1w1r uicm1a0 (
.wclk(wclk),
.wce(wce && wa[3:2]==2'b00),
.wr({4{wr}}),
.wa(wa[14:4]),
.wd(wd),
.rclk(rclk),
.rce(1'b1),
.ra(pcp16[14:4]),
.o(mem1a[31:0])
);
syncRam2kx32_1w1r uicm1a1 (
.wclk(wclk),
.wce(wce && wa[3:2]==2'b01),
.wr({4{wr}}),
.wa(wa[14:4]),
.wd(wd),
.rclk(rclk),
.rce(1'b1),
.ra(pcp16[14:4]),
.o(mem1a[63:32])
);
syncRam2kx32_1w1r uicm1a2 (
.wclk(wclk),
.wce(wce && wa[3:2]==2'b10),
.wr({4{wr}}),
.wa(wa[14:4]),
.wd(wd),
.rclk(rclk),
.rce(1'b1),
.ra(pcp16[14:4]),
.o(mem1a[95:64])
);
syncRam2kx32_1w1r uicm1a3 (
.wclk(wclk),
.wce(wce && wa[3:2]==2'b11),
.wr({4{wr}}),
.wa(wa[14:4]),
.wd(wd),
.rclk(rclk),
.rce(1'b1),
.ra(pcp16[14:4]),
.o(mem1a[127:96])
);
end
end
endgenerate
 
always @(pc)
pcp16 <= pc[14:0] + 15'd16;
wire [127:0] insn0 = mem0a;
wire [127:0] insn1 = mem1a;
always @(pc or insn0 or insn1)
case(pc[3:0])
4'd0: insn <= insn0;
4'd1: insn <= {insn1[7:0],insn0[127:8]};
4'd2: insn <= {insn1[15:0],insn0[127:16]};
4'd3: insn <= {insn1[23:0],insn0[127:24]};
4'd4: insn <= {insn1[31:0],insn0[127:32]};
4'd5: insn <= {insn1[39:0],insn0[127:40]};
4'd6: insn <= {insn1[47:0],insn0[127:48]};
4'd7: insn <= {insn1[55:0],insn0[127:56]};
4'd8: insn <= {insn1[63:0],insn0[127:64]};
4'd9: insn <= {insn1[71:0],insn0[127:72]};
4'd10: insn <= {insn1[79:0],insn0[127:80]};
4'd11: insn <= {insn1[87:0],insn0[127:88]};
4'd12: insn <= {insn1[95:0],insn0[127:96]};
4'd13: insn <= {insn1[103:0],insn0[127:104]};
4'd14: insn <= {insn1[111:0],insn0[127:112]};
4'd15: insn <= {insn1[119:0],insn0[127:120]};
endcase
 
endmodule
/trunk/rtl/verilog/Thor_defines.v
0,0 → 1,358
// ============================================================================
// __
// \\__/ o\ (C) 2013,2015 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Thor Scaler
//
// ============================================================================
//
`ifndef THOR_DEFINES
`define THOR_DEFINES 1'b1
 
`define SIMULATION 1'b1
`define SEGMENTATION 1'b1
//`define STACKOPS 1'b1
//`define BITFIELDOPS 1'b1
//`define FLOATING_POINT 1'b1
`define STRINGOPS 1'b1
`define DEBUG_LOGIC 1'b1
//`define THREEWAY 1'b1
 
`define TRUE 1'b1
`define FALSE 1'b0
`define INV 1'b0
`define VAL 1'b1
`define ZERO 64'd0
 
 
`define TST 8'b0000xxxx
`define CMP 8'b0001xxxx
`define CMPI 8'b0010xxxx
`define BR 8'b0011xxxx
 
`define RR 8'h40
`define ADD 6'h00
`define SUB 6'h01
`define MUL 6'h02
`define DIV 6'h03
`define ADDU 6'h04
`define SUBU 6'h05
`define MULU 6'h06
`define DIVU 6'h07
`define _2ADDU 6'h08
`define _4ADDU 6'h09
`define _8ADDU 6'h0A
`define _16ADDU 6'h0B
`define MIN 6'h10
`define MAX 6'h11
`define R2 8'h41
`define CPUID 4'h0
`define REDOR 4'h1 // reduction or
`define REDAND 4'h2 // reduction and
`define PAR 4'h3 // parity
`define P 8'h42
`define PAND 6'd0
`define POR 6'd1
`define PEOR 6'd2
`define PNAND 6'd3
`define PNOR 6'd4
`define PENOR 6'd5
`define PANDC 6'd6
`define PORC 6'd7
`define BITI 8'h46
`define ADDUIS 8'h47
`define ADDI 8'h48
`define SUBI 8'h49
`define MULI 8'h4A
`define DIVI 8'h4B
`define ADDUI 8'h4C
`define SUBUI 8'h4D
`define MULUI 8'h4E
`define DIVUI 8'h4F
`define LOGIC 8'h50
`define AND 6'h0
`define OR 6'h1
`define EOR 6'h2
`define NAND 6'h3
`define NOR 6'h4
`define ENOR 6'h5
`define ANDC 6'h6
`define ORC 6'h7
`define MLO 8'h51
`define ANDI 8'h53
`define ORI 8'h54
`define EORI 8'h55
 
`define SHIFT 8'h58
`define SHL 6'h00
`define SHR 6'h01
`define SHLU 6'h02
`define SHRU 6'h03
`define ROL 6'h04
`define ROR 6'h05
`define SHLI 6'h10
`define SHRI 6'h11
`define SHLUI 6'h12
`define SHRUI 6'h13
`define ROLI 6'h14
`define RORI 6'h15
 
`define _2ADDUI 8'h6B
`define _4ADDUI 8'h6C
`define _8ADDUI 8'h6D
`define _16ADDUI 8'h6E
`define LDI 8'h6F
 
`define MUX 8'h72
 
`define FSTAT 8'h73
`define FRM 8'h74
`define FTX 8'h75
`define DOUBLE_R 8'h77
`define FMOV 4'h00
`define FTOI 4'h02
`define ITOF 4'h03
`define FNEG 4'h04
`define FABS 4'h05
`define FSIGN 4'h06
`define FMAN 4'h07
`define FNABS 4'h08
`define FSTAT 4'h0C
`define FRM 4'h0D
`define FLOAT 8'h78
`define FCMP 6'h07
`define FADD 6'h08
`define FSUB 6'h09
`define FMUL 6'h0A
`define FDIV 6'h0B
`define FCMPS 6'h17
`define FADDS 6'h18
`define FSUBS 6'h19
`define FMULS 6'h1A
`define FDIVS 6'h1B
`define SINGLE_R 8'h79
`define FMOVS 4'h00
`define FTOIS 4'h02
`define ITOFS 4'h03
`define FNEGS 4'h04
`define FABSS 4'h05
`define FSIGNS 4'h06
`define FMANS 4'h07
`define FNABSS 4'h08
`define FTX 4'h0C
`define FCX 4'h0D
`define FEX 4'h0E
`define FDX 4'h0F
 
`define LB 8'h80
`define LBU 8'h81
`define LC 8'h82
`define LCU 8'h83
`define LH 8'h84
`define LHU 8'h85
`define LW 8'h86
`define LFS 8'h87
`define LFD 8'h88
`define LVWAR 8'h8B
`define SWCR 8'h8C
`define LEA 8'h8D
`define LWS 8'h8E
`define LCL 8'h8F
 
`define SB 8'h90
`define SC 8'h91
`define SH 8'h92
`define SW 8'h93
`define SFS 8'h94
`define SFD 8'h95
`define STI 8'h96
`define CAS 8'h97
`define STS 8'h98
`define STMV 8'h99
`define STCMP 8'h9A
`define STFND 8'h9B
 
`define LDIT10 8'h9C
`define LDIS 8'h9D
`define SWS 8'h9E
`define CACHE 8'h9F
 
// Flow control Opcodes
`define JSRZ 8'hA0
`define JSRS 8'hA1
`define JSR 8'hA2
`define RTS 8'hA3
`define LOOP 8'hA4
`define SYS 8'hA5
`define INT 8'hA6
`define R 8'hA7
`define MOV 4'h0
`define NEG 4'h1
`define NOT 4'h2
`define ABS 4'h3
`define SGN 4'h4
`define CNTLZ 4'h5
`define CNTLO 4'h6
`define CNTPOP 4'h7
`define SXB 4'h8
`define SXC 4'h9
`define SXH 4'hA
`define COM 4'hB
`define ZXB 4'hC
`define ZXC 4'hD
`define ZXH 4'hE
`define MFSPR 8'hA8
`define MTSPR 8'hA9
 
`define BITFIELD 8'hAA
`define BFINS 4'h0
`define BFSET 4'h1
`define BFCLR 4'h2
`define BFCHG 4'h3
`define BFEXTU 4'h4
`define BFEXT 4'h5
 
`define MOVS 8'hAB
// Uncached access instructions
`define LVB 8'hAC
`define LVC 8'hAD
`define LVH 8'hAE
`define LVW 8'hAF
 
`define LBX 8'hB0
`define LBUX 8'hB1
`define LCX 8'hB2
`define LCUX 8'hB3
`define LHX 8'hB4
`define LHUX 8'hB5
`define LWX 8'hB6
 
`define SBX 8'hC0
`define SCX 8'hC1
`define SHX 8'hC2
`define SWX 8'hC3
`define STIX 8'hC6
`define INC 8'hC7
`define PUSH 8'hC8
`define PEA 8'hC9
`define POP 8'hCA
`define LINK 8'hCB
`define UNLINK 8'hCC
 
`define TLB 8'hF0
`define TLB_NOP 4'd0
`define TLB_P 4'd1
`define TLB_RD 4'd2
`define TLB_WR 4'd3
`define TLB_WI 4'd4
`define TLB_EN 4'd5
`define TLB_DIS 4'd6
`define TLB_RDREG 4'd7
`define TLB_WRREG 4'd8
`define TLB_INVALL 4'd9
`define NOP 8'hF1
 
`define TLBWired 4'h0
`define TLBIndex 4'h1
`define TLBRandom 4'h2
`define TLBPageSize 4'h3
`define TLBVirtPage 4'h4
`define TLBPhysPage 4'h5
`define TLBASID 4'h7
`define TLBDMissAdr 4'd8
`define TLBIMissAdr 4'd9
`define TLBPageTblAddr 4'd10
`define TLBPageTblCtrl 4'd11
 
`define RTS2 8'hF2
`define RTE 8'hF3
`define RTI 8'hF4
`define BCD 8'hF5
`define BCDADD 8'h00
`define BCDSUB 8'h01
`define BCDMUL 8'h02
`define STP 8'hF6
`define SYNC 8'hF7
`define MEMSB 8'hF8 // synchronization barrier
`define MEMDB 8'hF9 // data barrier
`define CLI 8'hFA
`define SEI 8'hFB
`define RTD 8'hFC
`define IMM 8'hFF
 
`define PREDC 3:0
`define PREDR 7:4
`define OPCODE 15:8
`define RA 21:16
`define RB 27:22
`define INSTRUCTION_RA 21:16
`define INSTRUCTION_RB 27:22
`define INSTRUCTION_RC 33:28
 
`define XTBL 4'd12
`define EPC 4'd13
`define IPC 4'd14
 
// Special Registers
`define PREGS 6'h0x
`define CREGS 6'h1x
`define SREGS 6'h2x
`define PREGS_ALL 6'h30
`define TICK 6'h32
`define LCTR 6'h33
`define ASID 6'h36
`define SR 6'h37
`define FPSCR 6'h38
`define CLK_THROTTLE 6'h3F
// exception types:
`define EXC_NONE 4'd0
`define EXC_HALT 4'd1
`define EXC_TLBMISS 4'd2
`define EXC_SEGV 4'd3
`define EXC_INVALID 4'd4
`define EXC_SYS 4'd5
`define EXC_INT 4'd6
`define EXC_OFL 4'd7
`define EXC_DBE 4'd8 // databus error
`define EXC_DBZ 4'd9 // divide by zero
`define EXC_FLT 4'd10 // floating point exception
`define EXC_DBG 4'd11
`define EXC_PRIV 4'd12
//
// define PANIC types
//
`define PANIC_NONE 4'd0
`define PANIC_FETCHBUFBEQ 4'd1
`define PANIC_INVALIDISLOT 4'd2
`define PANIC_MEMORYRACE 4'd3
`define PANIC_IDENTICALDRAMS 4'd4
`define PANIC_OVERRUN 4'd5
`define PANIC_HALTINSTRUCTION 4'd6
`define PANIC_INVALIDMEMOP 4'd7
`define PANIC_INVALIDFBSTATE 4'd9
`define PANIC_INVALIDIQSTATE 4'd10
`define PANIC_BRANCHBACK 4'd11
`define PANIC_BADTARGETID 4'd12
 
`define DRAMSLOT_AVAIL 2'b00
`define DRAMREQ_READY 2'b11
 
`endif
/trunk/rtl/verilog/Thor_dtagmem.v
0,0 → 1,81
// ============================================================================
// __
// \\__/ o\ (C) 2013 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Thor SuperScalar
// Instruction cache tag memory
//
// ============================================================================
//
module Thor_dtagmem(wclk, wce, wr, wa, err_i, invalidate, invalidate_line, invalidate_lineno,
rclk, rce, ra, whit, rhit, err_o);
parameter AMSB=63;
input wclk;
input wce;
input wr;
input [AMSB:0] wa;
input err_i;
input invalidate;
input invalidate_line;
input [AMSB:0] invalidate_lineno;
input rclk;
input rce;
input [AMSB:0] ra;
output whit;
output rhit;
output err_o;
 
reg [AMSB:13] mem [0:255];
reg [0:255] tvalid;
reg [0:255] errmem;
reg [AMSB:0] rwa,rra;
wire [AMSB-12:0] tag,wtag;
 
integer n;
initial begin
for (n = 0; n < 256; n = n + 1)
mem[n] <= 0;
end
 
always @(posedge wclk)
if (wce & wr) begin
$display("*******************");
$display("*******************");
$display("Writint %h to %h ",wa[AMSB:13],wa[12:5]);
mem[wa[12:5]] <= wa[AMSB:13];
$display("*******************");
$display("*******************");
end
always @(posedge wclk)
if (invalidate) begin tvalid <= 256'd0; errmem <= 256'd0; end
else if (invalidate_line) tvalid[invalidate_lineno[12:5]] <= 1'b0;
else if (wce & wr) begin tvalid[wa[12:5]] <= 1'b1; errmem[wa[12:5]] <= err_i; end
always @(posedge rclk)
if (rce) rwa <= wa;
always @(posedge rclk)
if (rce) rra <= ra;
assign wtag = {mem[rwa[12:5]],tvalid[rwa[12:5]]};
assign tag = {mem[rra[12:5]],tvalid[rra[12:5]]};
 
assign whit = wtag == {rwa[AMSB:13],1'b1};
assign rhit = tag == {rra[AMSB:13],1'b1};
assign err_o = errmem[rra[12:5]];
 
endmodule

powered by: WebSVN 2.1.0

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