// ============================================================================
|
// ============================================================================
|
// __
|
// __
|
// \\__/ o\ (C) 2018-2019 Robert Finch, Waterloo
|
// \\__/ o\ (C) 2018-2019 Robert Finch, Waterloo
|
// \ __ / All rights reserved.
|
// \ __ / All rights reserved.
|
// \/_// robfinch<remove>@finitron.ca
|
// \/_// robfinch<remove>@finitron.ca
|
// ||
|
// ||
|
//
|
//
|
// FT64_fetchbuf_x1.v
|
// FT64_fetchbuf_x1.v
|
//
|
//
|
// This source file is free software: you can redistribute it and/or modify
|
// 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
|
// 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
|
// by the Free Software Foundation, either version 3 of the License, or
|
// (at your option) any later version.
|
// (at your option) any later version.
|
//
|
//
|
// This source file is distributed in the hope that it will be useful,
|
// This source file is distributed in the hope that it will be useful,
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
//
|
//
|
// ============================================================================
|
// ============================================================================
|
//
|
//
|
`include "FT64_config.vh"
|
`include "FT64_config.vh"
|
`include "FT64_defines.vh"
|
`include "FT64_defines.vh"
|
|
|
// FETCH
|
// FETCH
|
//
|
//
|
// fetch exactly one instructions from memory into the fetch buffer
|
// fetch exactly one instructions from memory into the fetch buffer
|
// unless either one of the buffers is still full, in which case we
|
// unless either one of the buffers is still full, in which case we
|
// do nothing (kinda like alpha approach)
|
// do nothing (kinda like alpha approach)
|
//
|
//
|
module FT64_fetchbuf_x1(rst, clk4x, clk, fcu_clk,
|
module FT64_fetchbuf_x1(rst, clk4x, clk, fcu_clk,
|
cs_i, cyc_i, stb_i, ack_o, we_i, adr_i, dat_i,
|
cs_i, cyc_i, stb_i, ack_o, we_i, adr_i, dat_i,
|
cmpgrp,
|
cmpgrp,
|
freezePC, thread_en, pred_on,
|
freezePC, thread_en, pred_on,
|
regLR,
|
regLR,
|
insn0, phit,
|
insn0, phit,
|
threadx,
|
threadx,
|
branchmiss, misspc, branchmiss_thrd, predict_taken0,
|
branchmiss, misspc, branchmiss_thrd, predict_taken0,
|
predict_takenA, predict_takenB,
|
predict_takenA, predict_takenB,
|
queued1, queuedNop,
|
queued1, queuedNop,
|
pc0, fetchbuf, fetchbufA_v, fetchbufB_v,
|
pc0, fetchbuf, fetchbufA_v, fetchbufB_v,
|
fetchbufA_instr, fetchbufA_pc, fetchbufA_pbyte,
|
fetchbufA_instr, fetchbufA_pc, fetchbufA_pbyte,
|
fetchbufB_instr, fetchbufB_pc, fetchbufB_pbyte,
|
fetchbufB_instr, fetchbufB_pc, fetchbufB_pbyte,
|
fetchbuf0_instr, fetchbuf0_insln,
|
fetchbuf0_instr, fetchbuf0_insln,
|
fetchbuf0_thrd,
|
fetchbuf0_thrd,
|
fetchbuf0_pc,
|
fetchbuf0_pc,
|
fetchbuf0_v,
|
fetchbuf0_v,
|
fetchbuf0_pbyte,
|
fetchbuf0_pbyte,
|
codebuf0,
|
codebuf0,
|
btgtA, btgtB,
|
btgtA, btgtB,
|
nop_fetchbuf,
|
nop_fetchbuf,
|
take_branch0,
|
take_branch0,
|
stompedRets,
|
stompedRets,
|
panic
|
panic
|
);
|
);
|
parameter AMSB = `AMSB;
|
parameter AMSB = `AMSB;
|
parameter RSTPC = 64'hFFFFFFFFFFFC0100;
|
parameter RSTPC = 64'hFFFFFFFFFFFC0100;
|
parameter TRUE = 1'b1;
|
parameter TRUE = 1'b1;
|
parameter FALSE = 1'b0;
|
parameter FALSE = 1'b0;
|
input rst;
|
input rst;
|
input clk4x;
|
input clk4x;
|
input clk;
|
input clk;
|
input fcu_clk;
|
input fcu_clk;
|
input cs_i;
|
input cs_i;
|
input cyc_i;
|
input cyc_i;
|
input stb_i;
|
input stb_i;
|
output ack_o;
|
output ack_o;
|
input we_i;
|
input we_i;
|
input [15:0] adr_i;
|
input [15:0] adr_i;
|
input [55:0] dat_i;
|
input [55:0] dat_i;
|
input [2:0] cmpgrp;
|
input [2:0] cmpgrp;
|
input freezePC;
|
input freezePC;
|
input thread_en;
|
input thread_en;
|
input pred_on;
|
input pred_on;
|
input [4:0] regLR;
|
input [4:0] regLR;
|
input [55:0] insn0;
|
input [55:0] insn0;
|
input phit;
|
input phit;
|
output threadx;
|
output threadx;
|
input branchmiss;
|
input branchmiss;
|
input [AMSB:0] misspc;
|
input [AMSB:0] misspc;
|
input branchmiss_thrd;
|
input branchmiss_thrd;
|
output predict_taken0;
|
output predict_taken0;
|
input predict_takenA;
|
input predict_takenA;
|
input predict_takenB;
|
input predict_takenB;
|
input queued1;
|
input queued1;
|
input queuedNop;
|
input queuedNop;
|
output reg [AMSB:0] pc0;
|
output reg [AMSB:0] pc0;
|
output reg fetchbuf;
|
output reg fetchbuf;
|
output reg fetchbufA_v;
|
output reg fetchbufA_v;
|
output reg fetchbufB_v;
|
output reg fetchbufB_v;
|
output fetchbuf0_thrd;
|
output fetchbuf0_thrd;
|
output reg [47:0] fetchbufA_instr;
|
output reg [47:0] fetchbufA_instr;
|
output reg [7:0] fetchbufA_pbyte;
|
output reg [7:0] fetchbufA_pbyte;
|
output reg [47:0] fetchbufB_instr;
|
output reg [47:0] fetchbufB_instr;
|
output reg [7:0] fetchbufB_pbyte;
|
output reg [7:0] fetchbufB_pbyte;
|
output reg [AMSB:0] fetchbufA_pc;
|
output reg [AMSB:0] fetchbufA_pc;
|
output reg [AMSB:0] fetchbufB_pc;
|
output reg [AMSB:0] fetchbufB_pc;
|
output [47:0] fetchbuf0_instr;
|
output [47:0] fetchbuf0_instr;
|
output [AMSB:0] fetchbuf0_pc;
|
output [AMSB:0] fetchbuf0_pc;
|
output [2:0] fetchbuf0_insln;
|
output [2:0] fetchbuf0_insln;
|
output fetchbuf0_v;
|
output fetchbuf0_v;
|
output [7:0] fetchbuf0_pbyte;
|
output [7:0] fetchbuf0_pbyte;
|
input [55:0] codebuf0;
|
input [55:0] codebuf0;
|
input [AMSB:0] btgtA;
|
input [AMSB:0] btgtA;
|
input [AMSB:0] btgtB;
|
input [AMSB:0] btgtB;
|
input [3:0] nop_fetchbuf;
|
input [3:0] nop_fetchbuf;
|
output take_branch0;
|
output take_branch0;
|
input [3:0] stompedRets;
|
input [3:0] stompedRets;
|
output reg [3:0] panic;
|
output reg [3:0] panic;
|
integer n;
|
integer n;
|
|
|
reg [55:0] cinsn0;
|
reg [55:0] cinsn0;
|
|
|
|
wire iclk = clk;
|
|
//BUFH ucb1 (.I(clk), .O(iclk));
|
|
|
//`include "FT64_decode.vh"
|
//`include "FT64_decode.vh"
|
|
|
function IsBranch;
|
function IsBranch;
|
input [47:0] isn;
|
input [47:0] isn;
|
casex(isn[`INSTRUCTION_OP])
|
casex(isn[`INSTRUCTION_OP])
|
`Bcc: IsBranch = TRUE;
|
`Bcc: IsBranch = TRUE;
|
`BLcc: IsBranch = TRUE;
|
`BLcc: IsBranch = TRUE;
|
`BBc: IsBranch = TRUE;
|
`BBc: IsBranch = TRUE;
|
`BEQI: IsBranch = TRUE;
|
`BEQI: IsBranch = TRUE;
|
`BNEI: IsBranch = TRUE;
|
`BNEI: IsBranch = TRUE;
|
`BCHK: IsBranch = TRUE;
|
`BCHK: IsBranch = TRUE;
|
default: IsBranch = FALSE;
|
default: IsBranch = FALSE;
|
endcase
|
endcase
|
endfunction
|
endfunction
|
|
|
function IsJAL;
|
function IsJAL;
|
input [47:0] isn;
|
input [47:0] isn;
|
IsJAL = isn[`INSTRUCTION_OP]==`JAL;
|
IsJAL = isn[`INSTRUCTION_OP]==`JAL;
|
endfunction
|
endfunction
|
|
|
function IsJmp;
|
function IsJmp;
|
input [47:0] isn;
|
input [47:0] isn;
|
IsJmp = isn[`INSTRUCTION_OP]==`JMP && isn[7]==1'b0;
|
IsJmp = isn[`INSTRUCTION_OP]==`JMP && isn[7]==1'b0;
|
endfunction
|
endfunction
|
|
|
function IsCall;
|
function IsCall;
|
input [47:0] isn;
|
input [47:0] isn;
|
IsCall = isn[`INSTRUCTION_OP]==`CALL && isn[7]==1'b0;
|
IsCall = isn[`INSTRUCTION_OP]==`CALL && isn[7]==1'b0;
|
endfunction
|
endfunction
|
|
|
function IsRet;
|
function IsRet;
|
input [47:0] isn;
|
input [47:0] isn;
|
IsRet = isn[`INSTRUCTION_OP]==`RET;
|
IsRet = isn[`INSTRUCTION_OP]==`RET;
|
endfunction
|
endfunction
|
|
|
function IsBrk;
|
function IsBrk;
|
input [47:0] isn;
|
input [47:0] isn;
|
IsBrk = isn[`INSTRUCTION_OP]==`BRK;
|
IsBrk = isn[`INSTRUCTION_OP]==`BRK;
|
endfunction
|
endfunction
|
|
|
function IsRTI;
|
function IsRTI;
|
input [47:0] isn;
|
input [47:0] isn;
|
IsRTI = isn[`INSTRUCTION_OP]==`R2 && isn[`INSTRUCTION_S2]==`RTI;
|
IsRTI = isn[`INSTRUCTION_OP]==`R2 && isn[`INSTRUCTION_S2]==`RTI;
|
endfunction
|
endfunction
|
|
|
function IsExec;
|
function IsExec;
|
input [47:0] isn;
|
input [47:0] isn;
|
if (isn[7:6]==2'b00)
|
if (isn[7:6]==2'b00)
|
case(isn[`INSTRUCTION_OP])
|
case(isn[`INSTRUCTION_OP])
|
`R2:
|
`R2:
|
case(isn[`INSTRUCTION_S2])
|
case(isn[`INSTRUCTION_S2])
|
`R1:
|
`R1:
|
case(isn[22:18])
|
case(isn[22:18])
|
`EXEC: IsExec = TRUE;
|
`EXEC: IsExec = TRUE;
|
default: IsExec = FALSE;
|
default: IsExec = FALSE;
|
endcase
|
endcase
|
default: IsExec = FALSE;
|
default: IsExec = FALSE;
|
endcase
|
endcase
|
default: IsExec = FALSE;
|
default: IsExec = FALSE;
|
endcase
|
endcase
|
else
|
else
|
IsExec = FALSE;
|
IsExec = FALSE;
|
endfunction
|
endfunction
|
|
|
function [2:0] fnInsLength;
|
function [2:0] fnInsLength;
|
input [47:0] ins;
|
input [47:0] ins;
|
`ifdef SUPPORT_DCI
|
`ifdef SUPPORT_DCI
|
if (ins[`INSTRUCTION_OP]==`CMPRSSD)
|
if (ins[`INSTRUCTION_OP]==`CMPRSSD)
|
fnInsLength = 3'd2 | pred_on;
|
fnInsLength = 3'd2 | pred_on;
|
else
|
else
|
`endif
|
`endif
|
case(ins[7:6])
|
case(ins[7:6])
|
2'd0: fnInsLength = 3'd4 | pred_on;
|
2'd0: fnInsLength = 3'd4 | pred_on;
|
2'd1: fnInsLength = 3'd6 | pred_on;
|
2'd1: fnInsLength = 3'd6 | pred_on;
|
default: fnInsLength = 3'd2 | pred_on;
|
default: fnInsLength = 3'd2 | pred_on;
|
endcase
|
endcase
|
endfunction
|
endfunction
|
|
|
wire [2:0] fetchbufA_inslen;
|
wire [2:0] fetchbufA_inslen;
|
wire [2:0] fetchbufB_inslen;
|
wire [2:0] fetchbufB_inslen;
|
FT64_InsLength uilA (fetchbufA_instr, fetchbufA_inslen, pred_on);
|
FT64_InsLength uilA (fetchbufA_instr, fetchbufA_inslen, pred_on);
|
FT64_InsLength uilB (fetchbufB_instr, fetchbufB_inslen, pred_on);
|
FT64_InsLength uilB (fetchbufB_instr, fetchbufB_inslen, pred_on);
|
|
|
wire [47:0] xinsn0;
|
wire [47:0] xinsn0;
|
|
|
FT64_iexpander ux1
|
FT64_iexpander ux1
|
(
|
(
|
.cinstr(pred_on ? insn0[23:8] : insn0[15:0]),
|
.cinstr(pred_on ? insn0[23:8] : insn0[15:0]),
|
.expand(xinsn0)
|
.expand(xinsn0)
|
);
|
);
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// Table of decompressed instructions.
|
// Table of decompressed instructions.
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
assign ack_o = cs_i & cyc_i & stb_i;
|
assign ack_o = cs_i & cyc_i & stb_i;
|
`ifdef SUPPORT_DCI
|
`ifdef SUPPORT_DCI
|
reg [47:0] DecompressTable [0:2047];
|
reg [47:0] DecompressTable [0:2047];
|
always @(posedge clk)
|
always @(posedge clk)
|
if (cs_i & cyc_i & stb_i & we_i)
|
if (cs_i & cyc_i & stb_i & we_i)
|
DecompressTable[adr_i[12:3]] <= dat_i[47:0];
|
DecompressTable[adr_i[12:3]] <= dat_i[47:0];
|
wire [47:0] expand0 = DecompressTable[{cmpgrp,pred_on ? insn0[23:16]:insn0[15:8]}];
|
wire [47:0] expand0 = DecompressTable[{cmpgrp,pred_on ? insn0[23:16]:insn0[15:8]}];
|
`endif
|
`endif
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
reg thread;
|
reg thread;
|
reg stompedRet;
|
reg stompedRet;
|
reg ret0Counted;
|
reg ret0Counted;
|
wire [AMSB:0] retpc0;
|
wire [AMSB:0] retpc0;
|
|
|
assign predict_taken0 = (fetchbuf==1'b0) ? ({fetchbufA_v, IsBranch(fetchbufA_instr), predict_takenA} == {`VAL, `TRUE, `TRUE})
|
assign predict_taken0 = (fetchbuf==1'b0) ? ({fetchbufA_v, IsBranch(fetchbufA_instr), predict_takenA} == {`VAL, `TRUE, `TRUE})
|
: ({fetchbufB_v, IsBranch(fetchbufB_instr), predict_takenB} == {`VAL, `TRUE, `TRUE});
|
: ({fetchbufB_v, IsBranch(fetchbufB_instr), predict_takenB} == {`VAL, `TRUE, `TRUE});
|
|
|
reg [AMSB:0] branch_pcA;
|
reg [AMSB:0] branch_pcA;
|
reg [AMSB:0] branch_pcB;
|
reg [AMSB:0] branch_pcB;
|
|
|
always @*
|
always @*
|
begin
|
begin
|
case(fetchbufA_instr[`INSTRUCTION_OP])
|
case(fetchbufA_instr[`INSTRUCTION_OP])
|
`RET: branch_pcA = retpc0;
|
`RET: branch_pcA = retpc0;
|
`JMP,`CALL:
|
`JMP,`CALL:
|
begin
|
begin
|
`ifdef JMP40
|
`ifdef JMP40
|
branch_pcA[39:0] = fetchbufA_instr[6] ? {fetchbufA_instr[47:8]} : {fetchbufA_pc[39:24],fetchbufA_instr[31:8]};
|
branch_pcA[39:0] = fetchbufA_instr[6] ? {fetchbufA_instr[47:8]} : {fetchbufA_pc[39:24],fetchbufA_instr[31:8]};
|
`else
|
`else
|
branch_pcA[39:0] = {fetchbufA_pc[39:24],fetchbufA_instr[31:8]};
|
branch_pcA[39:0] = {fetchbufA_pc[39:24],fetchbufA_instr[31:8]};
|
`endif
|
`endif
|
branch_pcA[63:40] = fetchbufA_pc[63:40];
|
branch_pcA[63:40] = fetchbufA_pc[63:40];
|
end
|
end
|
`R2: branch_pcA = btgtA; // RTI
|
`R2: branch_pcA = btgtA; // RTI
|
`BRK,`JAL: branch_pcA = btgtA;
|
`BRK,`JAL: branch_pcA = btgtA;
|
default:
|
default:
|
begin
|
begin
|
branch_pcA[31:0] = fetchbufA_pc[31:0] +
|
branch_pcA[31:0] = fetchbufA_pc[31:0] +
|
((fetchbufA_instr[7:6]==2'b01) ? {{4{fetchbufA_instr[47]}},fetchbufA_instr[47:23],fetchbufA_instr[17:16],1'b0} : {{20{fetchbufA_instr[31]}},fetchbufA_instr[31:23],fetchbufA_instr[17:16],1'b0});
|
((fetchbufA_instr[7:6]==2'b01) ? {{4{fetchbufA_instr[47]}},fetchbufA_instr[47:23],fetchbufA_instr[17:16],1'b0} : {{20{fetchbufA_instr[31]}},fetchbufA_instr[31:23],fetchbufA_instr[17:16],1'b0});
|
branch_pcA[63:32] = fetchbufA_pc[63:32];
|
branch_pcA[63:32] = fetchbufA_pc[63:32];
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
|
|
always @*
|
always @*
|
begin
|
begin
|
case(fetchbufB_instr[`INSTRUCTION_OP])
|
case(fetchbufB_instr[`INSTRUCTION_OP])
|
`RET: branch_pcB = retpc0;
|
`RET: branch_pcB = retpc0;
|
`JMP,`CALL:
|
`JMP,`CALL:
|
begin
|
begin
|
`ifdef JMP40
|
`ifdef JMP40
|
branch_pcB[39:0] = fetchbufB_instr[6] ? {fetchbufB_instr[47:8]} : {fetchbufB_pc[39:24],fetchbufB_instr[31:8]};
|
branch_pcB[39:0] = fetchbufB_instr[6] ? {fetchbufB_instr[47:8]} : {fetchbufB_pc[39:24],fetchbufB_instr[31:8]};
|
`else
|
`else
|
branch_pcB[39:0] = {fetchbufB_pc[39:24],fetchbufB_instr[31:8]};
|
branch_pcB[39:0] = {fetchbufB_pc[39:24],fetchbufB_instr[31:8]};
|
`endif
|
`endif
|
branch_pcB[63:40] = fetchbufB_pc[63:40];
|
branch_pcB[63:40] = fetchbufB_pc[63:40];
|
end
|
end
|
`R2: branch_pcB = btgtB; // RTI
|
`R2: branch_pcB = btgtB; // RTI
|
`BRK,`JAL: branch_pcB = btgtB;
|
`BRK,`JAL: branch_pcB = btgtB;
|
default:
|
default:
|
begin
|
begin
|
branch_pcB[31:0] = fetchbufB_pc[31:0] +
|
branch_pcB[31:0] = fetchbufB_pc[31:0] +
|
((fetchbufB_instr[7:6]==2'b01) ? {{4{fetchbufB_instr[47]}},fetchbufB_instr[47:23],fetchbufB_instr[17:16],1'b0} : {{20{fetchbufB_instr[31]}},fetchbufB_instr[31:23],fetchbufB_instr[17:16],1'b0});
|
((fetchbufB_instr[7:6]==2'b01) ? {{4{fetchbufB_instr[47]}},fetchbufB_instr[47:23],fetchbufB_instr[17:16],1'b0} : {{20{fetchbufB_instr[31]}},fetchbufB_instr[31:23],fetchbufB_instr[17:16],1'b0});
|
branch_pcB[63:32] = fetchbufB_pc[63:32];
|
branch_pcB[63:32] = fetchbufB_pc[63:32];
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
|
|
wire take_branchA = ({fetchbufA_v, IsBranch(fetchbufA_instr), predict_takenA} == {`VAL, `TRUE, `TRUE}) || ((
|
wire take_branchA = ({fetchbufA_v, IsBranch(fetchbufA_instr), predict_takenA} == {`VAL, `TRUE, `TRUE}) || ((
|
`ifdef FCU_ENH
|
`ifdef FCU_ENH
|
IsRet(fetchbufA_instr)
|
IsRet(fetchbufA_instr)
|
|| IsRTI(fetchbufA_instr)|| IsBrk(fetchbufA_instr) || IsJAL(fetchbufA_instr) ||
|
|| IsRTI(fetchbufA_instr)|| IsBrk(fetchbufA_instr) || IsJAL(fetchbufA_instr) ||
|
`endif
|
`endif
|
IsJmp(fetchbufA_instr)||IsCall(fetchbufA_instr)) &&
|
IsJmp(fetchbufA_instr)||IsCall(fetchbufA_instr)) &&
|
fetchbufA_v);
|
fetchbufA_v);
|
wire take_branchB = ({fetchbufB_v, IsBranch(fetchbufB_instr), predict_takenB} == {`VAL, `TRUE, `TRUE}) || ((
|
wire take_branchB = ({fetchbufB_v, IsBranch(fetchbufB_instr), predict_takenB} == {`VAL, `TRUE, `TRUE}) || ((
|
`ifdef FCU_ENH
|
`ifdef FCU_ENH
|
IsRet(fetchbufB_instr)
|
IsRet(fetchbufB_instr)
|
|| IsRTI(fetchbufB_instr)|| IsBrk(fetchbufB_instr) || IsJAL(fetchbufB_instr) ||
|
|| IsRTI(fetchbufB_instr)|| IsBrk(fetchbufB_instr) || IsJAL(fetchbufB_instr) ||
|
`endif
|
`endif
|
IsJmp(fetchbufB_instr)||IsCall(fetchbufB_instr)) &&
|
IsJmp(fetchbufB_instr)||IsCall(fetchbufB_instr)) &&
|
fetchbufB_v);
|
fetchbufB_v);
|
|
|
wire take_branch = (fetchbuf==1'b0) ? take_branchA : take_branchB;
|
wire take_branch = (fetchbuf==1'b0) ? take_branchA : take_branchB;
|
assign take_branch0 = take_branch;
|
assign take_branch0 = take_branch;
|
|
|
/*
|
/*
|
always @*
|
always @*
|
begin
|
begin
|
pc0 <= thread_en ? (fetchbuf ? pc0b : pc0a) : pc0a;
|
pc0 <= thread_en ? (fetchbuf ? pc0b : pc0a) : pc0a;
|
pc1 <= thread_en ? (fetchbuf ? pc1b : pc1a) : pc1a;
|
pc1 <= thread_en ? (fetchbuf ? pc1b : pc1a) : pc1a;
|
end
|
end
|
*/
|
*/
|
assign threadx = fetchbuf;
|
assign threadx = fetchbuf;
|
|
|
`ifdef FCU_ENH
|
`ifdef FCU_ENH
|
FT64_RSB #(AMSB) ursb1
|
FT64_RSB #(AMSB) ursb1
|
(
|
(
|
.rst(rst),
|
.rst(rst),
|
.clk(fcu_clk),
|
.clk(fcu_clk),
|
.regLR(regLR),
|
.regLR(regLR),
|
.queued1(queued1),
|
.queued1(queued1),
|
.queued2(1'b0),
|
.queued2(1'b0),
|
.fetchbuf0_v(fetchbuf0_v),
|
.fetchbuf0_v(fetchbuf0_v),
|
.fetchbuf0_pc(fetchbuf0_pc),
|
.fetchbuf0_pc(fetchbuf0_pc),
|
.fetchbuf0_instr(fetchbuf0_instr),
|
.fetchbuf0_instr(fetchbuf0_instr),
|
.fetchbuf1_v(1'b0),
|
.fetchbuf1_v(1'b0),
|
.fetchbuf1_pc(RSTPC),
|
.fetchbuf1_pc(RSTPC),
|
.fetchbuf1_instr(`NOP_INSN),
|
.fetchbuf1_instr(`NOP_INSN),
|
.stompedRets(stompedRets),
|
.stompedRets(stompedRets),
|
.stompedRet(stompedRet),
|
.stompedRet(stompedRet),
|
.pc(retpc0)
|
.pc(retpc0)
|
);
|
);
|
|
|
`else
|
`else
|
assign retpc0 = RSTPC;
|
assign retpc0 = RSTPC;
|
assign retpc1 = RSTPC;
|
assign retpc1 = RSTPC;
|
`endif
|
`endif
|
|
|
wire peclk, neclk;
|
wire peclk, neclk;
|
edge_det ued1 (.rst(rst), .clk(clk4x), .ce(1'b1), .i(clk), .pe(peclk), .ne(neclk), .ee());
|
edge_det ued1 (.rst(rst), .clk(clk4x), .ce(1'b1), .i(clk), .pe(peclk), .ne(neclk), .ee());
|
|
|
reg did_branch;
|
reg did_branch;
|
|
|
always @(posedge clk)
|
always @(posedge iclk)
|
if (rst) begin
|
if (rst) begin
|
pc0 <= RSTPC;
|
pc0 <= RSTPC;
|
fetchbufA_v <= 1'b0;
|
fetchbufA_v <= 1'b0;
|
fetchbufB_v <= 1'b0;
|
fetchbufB_v <= 1'b0;
|
fetchbuf <= 1'b0;
|
fetchbuf <= 1'b0;
|
panic <= `PANIC_NONE;
|
panic <= `PANIC_NONE;
|
did_branch <= 1'b0;
|
did_branch <= 1'b0;
|
end
|
end
|
else begin
|
else begin
|
|
|
did_branch <= take_branch & ~branchmiss;
|
did_branch <= take_branch & ~branchmiss;
|
|
|
begin
|
begin
|
|
|
// On a branch miss with threading enabled all fectch buffers are
|
// On a branch miss with threading enabled all fectch buffers are
|
// invalidated even though the data in the fetch buffer would be valid
|
// invalidated even though the data in the fetch buffer would be valid
|
// for the thread that isn't in a branchmiss state. This is done to
|
// for the thread that isn't in a branchmiss state. This is done to
|
// keep things simple. For the thread that doesn't miss the current
|
// keep things simple. For the thread that doesn't miss the current
|
// data for the fetch buffer needs to be retrieved again, so the pc
|
// data for the fetch buffer needs to be retrieved again, so the pc
|
// for that thread is assigned the current fetchbuf pc.
|
// for that thread is assigned the current fetchbuf pc.
|
// For the thread that misses the pc is simply assigned the misspc.
|
// For the thread that misses the pc is simply assigned the misspc.
|
if (branchmiss) begin
|
if (branchmiss) begin
|
pc0 <= misspc;
|
pc0 <= misspc;
|
fetchbufA_v <= `INV;
|
fetchbufA_v <= `INV;
|
fetchbufB_v <= `INV;
|
fetchbufB_v <= `INV;
|
fetchbuf <= 1'b0;
|
fetchbuf <= 1'b0;
|
$display("********************");
|
$display("********************");
|
$display("********************");
|
$display("********************");
|
$display("********************");
|
$display("********************");
|
$display("Branch miss");
|
$display("Branch miss");
|
$display("misspc=%h", misspc);
|
$display("misspc=%h", misspc);
|
$display("********************");
|
$display("********************");
|
$display("********************");
|
$display("********************");
|
$display("********************");
|
$display("********************");
|
end
|
end
|
// else if (cinsn0[`INSTRUCTION_OP]==`CALL || cinsn0[`INSTRUCTION_OP]==`JMP) begin
|
// else if (cinsn0[`INSTRUCTION_OP]==`CALL || cinsn0[`INSTRUCTION_OP]==`JMP) begin
|
// pc0[31:0] = cinsn0[6] ? {cinsn0[47:8]} : {pc0[31:24],cinsn0[31:8]};
|
// pc0[31:0] = cinsn0[6] ? {cinsn0[47:8]} : {pc0[31:24],cinsn0[31:8]};
|
// fetchbufA_v <= `INV;
|
// fetchbufA_v <= `INV;
|
// fetchbufB_v <= `INV;
|
// fetchbufB_v <= `INV;
|
// fetchbuf <= 1'b0;
|
// fetchbuf <= 1'b0;
|
// end
|
// end
|
else if (take_branch) begin
|
else if (take_branch) begin
|
if (fetchbuf == 1'b0) begin
|
if (fetchbuf == 1'b0) begin
|
// In this case fetchbufA must be valid, or take_branch wouldn't be.
|
// In this case fetchbufA must be valid, or take_branch wouldn't be.
|
case(fetchbufB_v)
|
case(fetchbufB_v)
|
1'b0:
|
1'b0:
|
begin
|
begin
|
pc0 <= branch_pcA;
|
pc0 <= branch_pcA;
|
fetchbufA_v <= !(queued1|queuedNop); // if it can be queued, it will
|
fetchbufA_v <= !(queued1|queuedNop); // if it can be queued, it will
|
fetchbuf <= (queued1|queuedNop);
|
fetchbuf <= (queued1|queuedNop);
|
end
|
end
|
1'b1:
|
1'b1:
|
if (did_branch) begin
|
if (did_branch) begin
|
fetchbufA_v <= !(queued1|queuedNop); // if it can be queued, it will
|
fetchbufA_v <= !(queued1|queuedNop); // if it can be queued, it will
|
fetchbuf <= (queued1|queuedNop);
|
fetchbuf <= (queued1|queuedNop);
|
FetchB();
|
FetchB();
|
end
|
end
|
else
|
else
|
begin
|
begin
|
pc0 <= branch_pcA;
|
pc0 <= branch_pcA;
|
fetchbufA_v <= !(queued1|queuedNop); // if it can be queued, it will
|
fetchbufA_v <= !(queued1|queuedNop); // if it can be queued, it will
|
fetchbufB_v <= `INV;
|
fetchbufB_v <= `INV;
|
fetchbuf <= (queued1|queuedNop);
|
fetchbuf <= (queued1|queuedNop);
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
else begin
|
else begin
|
case(fetchbufA_v)
|
case(fetchbufA_v)
|
1'b0:
|
1'b0:
|
begin
|
begin
|
pc0 <= branch_pcB;
|
pc0 <= branch_pcB;
|
fetchbufB_v <= !(queued1|queuedNop);
|
fetchbufB_v <= !(queued1|queuedNop);
|
fetchbuf <= !(queued1|queuedNop);
|
fetchbuf <= !(queued1|queuedNop);
|
end
|
end
|
1'b1:
|
1'b1:
|
if (did_branch) begin
|
if (did_branch) begin
|
fetchbufB_v <= !(queued1|queuedNop);
|
fetchbufB_v <= !(queued1|queuedNop);
|
fetchbuf <= ~(queued1|queuedNop);
|
fetchbuf <= ~(queued1|queuedNop);
|
FetchA();
|
FetchA();
|
end
|
end
|
else
|
else
|
begin
|
begin
|
pc0 <= branch_pcB;
|
pc0 <= branch_pcB;
|
fetchbufB_v <= !(queued1|queuedNop);
|
fetchbufB_v <= !(queued1|queuedNop);
|
fetchbufA_v <= `INV;
|
fetchbufA_v <= `INV;
|
fetchbuf <= !(queued1|queuedNop);
|
fetchbuf <= !(queued1|queuedNop);
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
end // if branch
|
end // if branch
|
|
|
else begin // there is no branchback in the system
|
else begin // there is no branchback in the system
|
// update fetchbufX_v and fetchbuf ... relatively simple, as
|
// update fetchbufX_v and fetchbuf ... relatively simple, as
|
// there are no backwards branches in the mix
|
// there are no backwards branches in the mix
|
if (fetchbuf == 1'b0) case ({fetchbufA_v, (queued1|queuedNop)})
|
if (fetchbuf == 1'b0) case ({fetchbufA_v, (queued1|queuedNop)})
|
2'b00: ; // do nothing
|
2'b00: ; // do nothing
|
2'b10: ;
|
2'b10: ;
|
2'b11: begin fetchbufA_v <= `INV; fetchbuf <= ~fetchbuf; end
|
2'b11: begin fetchbufA_v <= `INV; fetchbuf <= ~fetchbuf; end
|
default: panic <= `PANIC_INVALIDIQSTATE;
|
default: panic <= `PANIC_INVALIDIQSTATE;
|
endcase
|
endcase
|
else case ({fetchbufB_v, (queued1|queuedNop)})
|
else case ({fetchbufB_v, (queued1|queuedNop)})
|
2'b00: ; // do nothing
|
2'b00: ; // do nothing
|
2'b10: ;
|
2'b10: ;
|
2'b11: begin fetchbufB_v <= `INV; fetchbuf <= ~fetchbuf; end
|
2'b11: begin fetchbufB_v <= `INV; fetchbuf <= ~fetchbuf; end
|
default: panic <= `PANIC_INVALIDIQSTATE;
|
default: panic <= `PANIC_INVALIDIQSTATE;
|
endcase
|
endcase
|
//
|
//
|
// get data iff the fetch buffers are empty
|
// get data iff the fetch buffers are empty
|
//
|
//
|
if (fetchbufA_v == `INV) begin
|
if (fetchbufA_v == `INV) begin
|
FetchA();
|
FetchA();
|
// fetchbuf steering logic correction
|
// fetchbuf steering logic correction
|
if (fetchbufB_v==`INV && phit)
|
if (fetchbufB_v==`INV && phit)
|
fetchbuf <= 1'b0;
|
fetchbuf <= 1'b0;
|
end
|
end
|
else if (fetchbufB_v == `INV) begin
|
else if (fetchbufB_v == `INV) begin
|
FetchB();
|
FetchB();
|
end
|
end
|
end
|
end
|
//
|
//
|
// get data iff the fetch buffers are empty
|
// get data iff the fetch buffers are empty
|
//
|
//
|
if (fetchbufA_v == `INV && fetchbufB_v == `INV) begin
|
if (fetchbufA_v == `INV && fetchbufB_v == `INV) begin
|
FetchA();
|
FetchA();
|
fetchbuf <= 1'b0;
|
fetchbuf <= 1'b0;
|
end
|
end
|
// // Steer fetchbuf to the valid buffer.
|
// // Steer fetchbuf to the valid buffer.
|
// else if (fetchbufB_v == `INV)
|
// else if (fetchbufB_v == `INV)
|
// fetchbuf <= 1'b0;
|
// fetchbuf <= 1'b0;
|
// else if (fetchbufA_v == `INV)
|
// else if (fetchbufA_v == `INV)
|
// fetchbuf <= 1'b1;
|
// fetchbuf <= 1'b1;
|
// else if (fetchbufA_v == `INV) begin
|
// else if (fetchbufA_v == `INV) begin
|
// FetchA();
|
// FetchA();
|
// end
|
// end
|
// else if (fetchbufB_v == `INV) begin
|
// else if (fetchbufB_v == `INV) begin
|
// FetchB();
|
// FetchB();
|
// end
|
// end
|
end
|
end
|
|
|
// The fetchbuffer is invalidated at the end of a vector instruction
|
// The fetchbuffer is invalidated at the end of a vector instruction
|
// queue.
|
// queue.
|
if (nop_fetchbuf[0]) fetchbufA_v <= `INV;
|
if (nop_fetchbuf[0]) fetchbufA_v <= `INV;
|
if (nop_fetchbuf[1]) fetchbufB_v <= `INV;
|
if (nop_fetchbuf[1]) fetchbufB_v <= `INV;
|
end
|
end
|
|
|
assign fetchbuf0_instr = (fetchbuf == 1'b0) ? fetchbufA_instr : fetchbufB_instr;
|
assign fetchbuf0_instr = (fetchbuf == 1'b0) ? fetchbufA_instr : fetchbufB_instr;
|
assign fetchbuf0_insln = (fetchbuf == 1'b0) ? fetchbufA_inslen: fetchbufB_inslen;
|
assign fetchbuf0_insln = (fetchbuf == 1'b0) ? fetchbufA_inslen: fetchbufB_inslen;
|
assign fetchbuf0_v = (fetchbuf == 1'b0) ? fetchbufA_v : fetchbufB_v ;
|
assign fetchbuf0_v = (fetchbuf == 1'b0) ? fetchbufA_v : fetchbufB_v ;
|
assign fetchbuf0_pc = (fetchbuf == 1'b0) ? fetchbufA_pc : fetchbufB_pc ;
|
assign fetchbuf0_pc = (fetchbuf == 1'b0) ? fetchbufA_pc : fetchbufB_pc ;
|
assign fetchbuf0_thrd = 1'b0;
|
assign fetchbuf0_thrd = 1'b0;
|
assign fetchbuf0_pbyte = (fetchbuf == 1'b0) ? fetchbufA_pbyte : fetchbufB_pbyte;
|
assign fetchbuf0_pbyte = (fetchbuf == 1'b0) ? fetchbufA_pbyte : fetchbufB_pbyte;
|
|
|
reg [2:0] insln0;
|
reg [2:0] insln0;
|
always @*
|
always @*
|
begin
|
begin
|
`ifdef SUPPORT_DCI
|
`ifdef SUPPORT_DCI
|
if (insn0[5:0]==`CMPRSSD)
|
if (insn0[5:0]==`CMPRSSD)
|
insln0 <= 3'd2 | pred_on;
|
insln0 <= 3'd2 | pred_on;
|
else
|
else
|
`endif
|
`endif
|
if (IsExec(insn0))
|
if (IsExec(insn0))
|
insln0 <= fnInsLength(codebuf0); //???? should be 4?
|
insln0 <= fnInsLength(codebuf0); //???? should be 4?
|
else
|
else
|
insln0 <= fnInsLength(insn0);
|
insln0 <= fnInsLength(insn0);
|
end
|
end
|
|
|
|
|
always @*
|
always @*
|
begin
|
begin
|
`ifdef SUPPORT_DCI
|
`ifdef SUPPORT_DCI
|
if (insn0[13:8]==`CMPRSSD && pred_on)
|
if (insn0[13:8]==`CMPRSSD && pred_on)
|
cinsn0 <= expand0;
|
cinsn0 <= expand0;
|
else if (insn0[5:0]==`CMPRSSD && !pred_on)
|
else if (insn0[5:0]==`CMPRSSD && !pred_on)
|
cinsn0 <= expand0;
|
cinsn0 <= expand0;
|
else
|
else
|
`endif
|
`endif
|
if (IsExec(insn0) && !pred_on)
|
if (IsExec(insn0) && !pred_on)
|
cinsn0 <= codebuf0;
|
cinsn0 <= codebuf0;
|
else if (IsExec(insn0[55:8]) && pred_on)
|
else if (IsExec(insn0[55:8]) && pred_on)
|
cinsn0 <= codebuf0;
|
cinsn0 <= codebuf0;
|
else if (insn0[15] & pred_on)
|
else if (insn0[15] & pred_on)
|
cinsn0 <= {xinsn0,insn0[7:0]};
|
cinsn0 <= {xinsn0,insn0[7:0]};
|
else if (insn0[7] & ~pred_on)
|
else if (insn0[7] & ~pred_on)
|
cinsn0 <= xinsn0;
|
cinsn0 <= xinsn0;
|
else
|
else
|
cinsn0 <= insn0;
|
cinsn0 <= insn0;
|
end
|
end
|
|
|
task FetchA;
|
task FetchA;
|
begin
|
begin
|
fetchbufA_instr <= pred_on ? cinsn0[55:8] : cinsn0[47:0];
|
fetchbufA_instr <= pred_on ? cinsn0[55:8] : cinsn0[47:0];
|
fetchbufA_pbyte = cinsn0[7:0];
|
fetchbufA_pbyte = cinsn0[7:0];
|
fetchbufA_v <= `VAL;
|
fetchbufA_v <= `VAL;
|
fetchbufA_pc <= pc0;
|
fetchbufA_pc <= pc0;
|
if (phit && ~freezePC)
|
if (phit && ~freezePC)
|
pc0 <= pc0 + insln0;
|
pc0[31:0] <= pc0[31:0] + insln0;
|
else
|
// else
|
pc0 <= pc0;
|
// pc0 <= pc0;
|
end
|
end
|
endtask
|
endtask
|
|
|
task FetchB;
|
task FetchB;
|
begin
|
begin
|
fetchbufB_instr <= pred_on ? cinsn0[55:8] : cinsn0[47:0];
|
fetchbufB_instr <= pred_on ? cinsn0[55:8] : cinsn0[47:0];
|
fetchbufB_pbyte = cinsn0[7:0];
|
fetchbufB_pbyte = cinsn0[7:0];
|
fetchbufB_v <= `VAL;
|
fetchbufB_v <= `VAL;
|
fetchbufB_pc <= pc0;
|
fetchbufB_pc <= pc0;
|
if (phit && ~freezePC)
|
if (phit && ~freezePC)
|
pc0 <= pc0 + insln0;
|
pc0[31:0] <= pc0[31:0] + insln0;
|
else
|
// else
|
pc0 <= pc0;
|
// pc0 <= pc0;
|
end
|
end
|
endtask
|
endtask
|
|
|
endmodule
|
endmodule
|
|
|