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 |