`include "FT64_defines.vh"
|
`include "FT64_defines.vh"
|
`include "FT64_config.vh"
|
`include "FT64_config.vh"
|
//=============================================================================
|
//=============================================================================
|
// __
|
// __
|
// \\__/ o\ (C) 2011-2018 Robert Finch, Waterloo
|
// \\__/ o\ (C) 2011-2019 Robert Finch, Waterloo
|
// \ __ / All rights reserved.
|
// \ __ / All rights reserved.
|
// \/_// robfinch<remove>@finitron.ca
|
// \/_// robfinch<remove>@finitron.ca
|
// ||
|
// ||
|
//
|
//
|
// FT64_TLB.v
|
// FT64_TLB.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/>.
|
//
|
//
|
//
|
//
|
// TLB
|
// TLB
|
// The TLB contains 256 entries, that are 16 way set associative.
|
// The TLB contains 256 entries, that are 16 way set associative.
|
// The TLB is shared between the instruction and data streams.
|
// The TLB is shared between the instruction and data streams.
|
|
// The code is carefully constructed to not require reset signals.
|
//
|
//
|
//=============================================================================
|
//=============================================================================
|
//
|
//
|
`define TLBMissPage {DBW-13{1'b1}}
|
`define TLBMissPage {DBW-13{1'b1}}
|
|
|
module FT64_TLB(rst, clk, ld, done, idle, ol,
|
module FT64_TLB(clk, ld, done, idle, ol,
|
ASID, op, regno, dati, dato,
|
ASID, op, regno, dati, dato,
|
uncached,
|
uncached,
|
icl_i, cyc_i, we_i, vadr_i, cyc_o, we_o, padr_o,
|
icl_i, cyc_i, we_i, vadr_i, cyc_o, we_o, padr_o,
|
wrv_o, rdv_o, exv_o,
|
wrv_o, rdv_o, exv_o,
|
TLBMiss, HTLBVirtPageo);
|
TLBMiss, HTLBVirtPageo);
|
parameter DBW=64;
|
parameter DBW=64;
|
parameter ABW=32;
|
parameter ABW=32;
|
parameter ENTRIES=256;
|
parameter ENTRIES=256;
|
parameter IDLE = 4'd0;
|
parameter IDLE = 4'd0;
|
parameter ONE = 4'd1;
|
parameter ONE = 4'd1;
|
parameter TWO = 4'd2;
|
parameter TWO = 4'd2;
|
parameter READ = 4'd1;
|
parameter READ = 4'd1;
|
parameter INC1 = 4'd2;
|
parameter INC1 = 4'd2;
|
parameter INC2 = 4'd3;
|
parameter INC2 = 4'd3;
|
parameter INC3 = 4'd4;
|
parameter INC3 = 4'd4;
|
parameter AGE1 = 4'd5;
|
parameter AGE1 = 4'd5;
|
parameter AGE2 = 4'd6;
|
parameter AGE2 = 4'd6;
|
input rst;
|
|
input clk;
|
input clk;
|
input ld;
|
input ld;
|
output done;
|
output done;
|
output idle;
|
output idle;
|
input [1:0] ol; // operating level
|
input [1:0] ol; // operating level
|
input [ABW-1:0] vadr_i;
|
input [ABW-1:0] vadr_i;
|
output reg [ABW-1:0] padr_o;
|
output reg [ABW-1:0] padr_o = 64'hFFFFFFFFFFFC0100;
|
output uncached;
|
output uncached;
|
|
|
input icl_i;
|
input icl_i;
|
input cyc_i;
|
input cyc_i;
|
input we_i;
|
input we_i;
|
output reg cyc_o;
|
output reg cyc_o;
|
output reg we_o;
|
output reg we_o;
|
output reg exv_o;
|
output reg exv_o;
|
output reg wrv_o;
|
output reg wrv_o;
|
output reg rdv_o;
|
output reg rdv_o;
|
input [7:0] ASID;
|
input [7:0] ASID;
|
input [3:0] op;
|
input [3:0] op;
|
input [3:0] regno;
|
input [3:0] regno;
|
input [DBW-1:0] dati;
|
input [DBW-1:0] dati;
|
output reg [DBW-1:0] dato;
|
output reg [DBW-1:0] dato;
|
output TLBMiss;
|
output TLBMiss;
|
output [DBW-1:0] HTLBVirtPageo;
|
output [DBW-1:0] HTLBVirtPageo;
|
|
|
integer n;
|
integer n;
|
|
|
reg [3:0] state;
|
reg [1:0] state = IDLE;
|
assign done = state==(IDLE && !ld) || state==TWO;
|
assign done = state==(IDLE && !ld) || state==TWO;
|
assign idle = state==IDLE && !ld;
|
assign idle = state==IDLE && !ld;
|
|
|
// Holding registers
|
// Holding registers
|
// These allow the TLB to updated in a single cycle as a unit
|
// These allow the TLB to updated in a single cycle as a unit
|
reg [DBW-1:0] HTLBVirtPage;
|
reg [DBW-1:0] HTLBVirtPage;
|
assign HTLBVirtPageo = {HTLBVirtPage,13'b0};
|
assign HTLBVirtPageo = {HTLBVirtPage,13'b0};
|
reg [DBW-1:0] HTLBPhysPage;
|
reg [DBW-1:0] HTLBPhysPage;
|
reg [7:0] HTLBASID;
|
reg [7:0] HTLBASID;
|
reg HTLBG;
|
reg HTLBG;
|
reg HTLBD;
|
reg HTLBD;
|
reg HTLBR, HTLBW, HTLBX, HTLBA, HTLBU, HTLBS;
|
reg HTLBR, HTLBW, HTLBX, HTLBA, HTLBU, HTLBS;
|
reg [2:0] HTLBC;
|
reg [2:0] HTLBC;
|
reg [7:0] HTLBPL;
|
reg [7:0] HTLBPL;
|
reg [2:0] HTLBPageSize;
|
reg [2:0] HTLBPageSize;
|
reg HTLBValid;
|
reg HTLBValid;
|
reg [ABW-1:0] miss_addr;
|
reg [ABW-1:0] miss_addr;
|
|
|
reg TLBenabled;
|
reg TLBenabled = 1'b0;
|
reg [7:0] i;
|
reg [7:0] i = 8'h00;
|
reg [DBW-1:0] Index;
|
reg [DBW-1:0] Index;
|
reg [3:0] Random;
|
reg [3:0] Random = 4'hF;
|
reg [3:0] Wired;
|
reg [3:0] Wired = 4'd0;
|
reg [2:0] PageSize;
|
reg [2:0] PageSize;
|
reg [15:0] Match;
|
reg [15:0] Match;
|
|
|
reg [4:0] q;
|
reg [4:0] q;
|
wire doddpage;
|
wire doddpage;
|
reg [DBW-1:0] TLBVirtPage [ENTRIES-1:0];
|
reg [DBW-1:0] TLBVirtPage [ENTRIES-1:0];
|
reg [ENTRIES-1:0] TLBG;
|
reg [ENTRIES-1:0] TLBG;
|
reg [ENTRIES-1:0] TLBD;
|
reg [ENTRIES-1:0] TLBD;
|
reg [ENTRIES-1:0] TLBU;
|
reg [ENTRIES-1:0] TLBU;
|
reg [ENTRIES-1:0] TLBS;
|
reg [ENTRIES-1:0] TLBS;
|
reg [ENTRIES-1:0] TLBA;
|
reg [ENTRIES-1:0] TLBA;
|
reg [2:0] TLBC [ENTRIES-1:0];
|
reg [2:0] TLBC [ENTRIES-1:0];
|
reg [7:0] TLBASID [ENTRIES-1:0];
|
reg [7:0] TLBASID [ENTRIES-1:0];
|
reg [7:0] TLBPL [ENTRIES-1:0];
|
reg [7:0] TLBPL [ENTRIES-1:0];
|
reg [2:0] TLBPageSize [255:0];
|
reg [2:0] TLBPageSize [255:0];
|
reg [ENTRIES-1:0] TLBValid;
|
reg [ENTRIES-1:0] TLBValid;
|
reg [DBW-1:0] imiss_addr;
|
reg [DBW-1:0] imiss_addr;
|
reg [DBW-1:0] dmiss_addr;
|
reg [DBW-1:0] dmiss_addr;
|
reg [DBW-1:0] PageTblAddr;
|
reg [DBW-1:0] PageTblAddr = {DBW{1'b0}};
|
reg [DBW-1:0] PageTblCtrl;
|
reg [DBW-1:0] PageTblCtrl = {DBW{1'b0}};
|
|
|
reg [23:0] age_lmt;
|
reg [23:0] age_lmt = 24'd20000;
|
reg [23:0] age_ctr;
|
reg [23:0] age_ctr = 24'd0;
|
wire age_tick = age_ctr < 24'd5;
|
wire age_tick = age_ctr < 24'd5;
|
reg cyc_en, age_en;
|
reg cyc_en = 1'b1, age_en = 1'b1;
|
reg [3:0] ar_state;
|
reg [3:0] ar_state = IDLE;
|
reg ar_wr;
|
reg ar_wr = 1'b0;
|
reg [7:0] age_adr, ar_adr;
|
reg [7:0] age_adr = 8'h00, ar_adr = 8'h00;
|
reg [32:0] count;
|
reg [32:0] count;
|
reg [31:0] ar_dati;
|
reg [31:0] ar_dati;
|
wire [31:0] ar_dato;
|
wire [31:0] ar_dato;
|
reg [31:0] ar_cdato;
|
reg [31:0] ar_cdato;
|
reg getset_age;
|
reg getset_age;
|
reg doLoad;
|
reg doLoad = 1'b0;
|
|
|
/*
|
/*
|
initial begin
|
initial begin
|
for (n = 0; n < ENTRIES; n = n + 1)
|
for (n = 0; n < ENTRIES; n = n + 1)
|
begin
|
begin
|
TLBVirtPage[n] = 0;
|
TLBVirtPage[n] = 0;
|
TLBG[n] = 0;
|
TLBG[n] = 0;
|
TLBASID[n] = 0;
|
TLBASID[n] = 0;
|
TLBD[n] = 0;
|
TLBD[n] = 0;
|
TLBC[n] = 0;
|
TLBC[n] = 0;
|
TLBA[n] = 0;
|
TLBA[n] = 0;
|
TLBR[n] = 0;
|
TLBR[n] = 0;
|
TLBW[n] = 0;
|
TLBW[n] = 0;
|
TLBX[n] = 0;
|
TLBX[n] = 0;
|
TLBS[n] = 0;
|
TLBS[n] = 0;
|
TLBU[n] = 0;
|
TLBU[n] = 0;
|
TLBValid[n] = 0;
|
TLBValid[n] = 0;
|
end
|
end
|
end
|
end
|
*/
|
*/
|
|
|
// Assume the instruction doesn't overlap between a mapped and unmapped area.
|
// Assume the instruction doesn't overlap between a mapped and unmapped area.
|
wire unmappedArea = vadr_i[ABW-1:ABW-8]==8'hFF || !TLBenabled;
|
wire unmappedArea = vadr_i[ABW-1:ABW-8]==8'hFF || !TLBenabled;
|
wire m1UnmappedArea = padr_o[ABW-1:ABW-8]==8'hFF || !TLBenabled;
|
wire m1UnmappedArea = padr_o[ABW-1:ABW-8]==8'hFF || !TLBenabled;
|
wire hitIOPage = vadr_i[ABW-1:ABW-12]==12'hFFD;
|
wire hitIOPage = vadr_i[ABW-1:ABW-12]==12'hFFD;
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
PageSize <= TLBPageSize[ASID];
|
PageSize <= TLBPageSize[ASID];
|
|
|
wire [ABW-1:0] vadrs = vadr_i[ABW-1:13] >> {PageSize,1'b0};
|
wire [ABW-1:0] vadrs = vadr_i[ABW-1:13] >> {PageSize,1'b0};
|
wire [DBW-1:0] TLBPhysPage_rdo;
|
wire [DBW-1:0] TLBPhysPage_rdo;
|
wire [ABW-1:0] PFN;
|
wire [ABW-1:0] PFN;
|
|
|
// Toolset didn't like the simpler distributed code where the RAM was inferred.
|
// Toolset didn't like the simpler distributed code where the RAM was inferred.
|
// Resulted in combinatorial loop error message. Even though there weren't any
|
// Resulted in combinatorial loop error message. Even though there weren't any
|
// combinatorial loops.
|
// combinatorial loops.
|
|
|
TLBPhysPageRam #(DBW) upgrm1
|
TLBPhysPageRam #(DBW) upgrm1
|
(
|
(
|
.clk(clk),
|
.clk(clk),
|
.we(state==TWO && (op==`TLB_WR || op==`TLB_WI)),
|
.we(state==TWO && (op==`TLB_WR || op==`TLB_WI)),
|
.wa(i),
|
.wa(i),
|
.i(HTLBPhysPage),
|
.i(HTLBPhysPage),
|
.ra0(i),
|
.ra0(i),
|
.ra1({q[3:0],vadrs[3:0]}),
|
.ra1({q[3:0],vadrs[3:0]}),
|
.o0(TLBPhysPage_rdo),
|
.o0(TLBPhysPage_rdo),
|
.o1(PFN)
|
.o1(PFN)
|
);
|
);
|
|
|
wire tlbRo0,tlbRo1;
|
wire tlbRo0,tlbRo1;
|
TLBRam #(1) uR
|
TLBRam #(1) uR
|
(
|
(
|
.clk(clk),
|
.clk(clk),
|
.we(state==TWO && (op==`TLB_WR || op==`TLB_WI)),
|
.we(state==TWO && (op==`TLB_WR || op==`TLB_WI)),
|
.wa(i),
|
.wa(i),
|
.i(HTLBR),
|
.i(HTLBR),
|
.ra0(i),
|
.ra0(i),
|
.ra1({q[3:0],vadrs[3:0]}),
|
.ra1({q[3:0],vadrs[3:0]}),
|
.o0(tlbRo0),
|
.o0(tlbRo0),
|
.o1(tlbRo1)
|
.o1(tlbRo1)
|
);
|
);
|
|
|
wire tlbWo0,tlbWo1;
|
wire tlbWo0,tlbWo1;
|
TLBRam #(1) uW
|
TLBRam #(1) uW
|
(
|
(
|
.clk(clk),
|
.clk(clk),
|
.we(state==TWO && (op==`TLB_WR || op==`TLB_WI)),
|
.we(state==TWO && (op==`TLB_WR || op==`TLB_WI)),
|
.wa(i),
|
.wa(i),
|
.i(HTLBW),
|
.i(HTLBW),
|
.ra0(i),
|
.ra0(i),
|
.ra1({q[3:0],vadrs[3:0]}),
|
.ra1({q[3:0],vadrs[3:0]}),
|
.o0(tlbWo0),
|
.o0(tlbWo0),
|
.o1(tlbWo1)
|
.o1(tlbWo1)
|
);
|
);
|
|
|
wire tlbXo0,tlbXo1;
|
wire tlbXo0,tlbXo1;
|
TLBRam #(1) uX
|
TLBRam #(1) uX
|
(
|
(
|
.clk(clk),
|
.clk(clk),
|
.we(state==TWO && (op==`TLB_WR || op==`TLB_WI)),
|
.we(state==TWO && (op==`TLB_WR || op==`TLB_WI)),
|
.wa(i),
|
.wa(i),
|
.i(HTLBX),
|
.i(HTLBX),
|
.ra0(i),
|
.ra0(i),
|
.ra1({q[3:0],vadrs[3:0]}),
|
.ra1({q[3:0],vadrs[3:0]}),
|
.o0(tlbXo0),
|
.o0(tlbXo0),
|
.o1(tlbXo1)
|
.o1(tlbXo1)
|
);
|
);
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
if (rst) begin
|
begin
|
age_ctr <= 24'd0;
|
// age_ctr > age_lmt when counter hits -1, saves comparing to zero as well
|
end
|
if (age_ctr > age_lmt)
|
else begin
|
|
if (age_ctr==24'd0)
|
|
age_ctr <= age_lmt;
|
age_ctr <= age_lmt;
|
else
|
else
|
age_ctr <= age_ctr - 4'd1;
|
age_ctr <= age_ctr - 4'd1;
|
end
|
end
|
|
|
// Handle Random register
|
// Handle Random register
|
always @(posedge clk)
|
always @(posedge clk)
|
if (rst) begin
|
begin
|
Random <= 4'hF;
|
|
end
|
|
else begin
|
|
if (Random==Wired)
|
if (Random==Wired)
|
Random <= 4'hF;
|
Random <= 4'hF;
|
else
|
else
|
Random <= Random - 4'd1;
|
Random <= Random - 4'd1;
|
// Why would we want to update since random changes on the next clock
|
// Why would we want to update since random changes on the next clock
|
// anyways ?
|
// anyways ?
|
if (state==ONE) begin
|
if (state==ONE) begin
|
if (op==`TLB_WRREG && regno==`TLBRandom)
|
if (op==`TLB_WRREG && regno==`TLBRandom)
|
Random <= dati[3:0];
|
Random <= dati[3:0];
|
end
|
end
|
end
|
end
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
if (rst) begin
|
begin
|
state <= IDLE;
|
|
end
|
|
else begin
|
|
case(state)
|
case(state)
|
IDLE:
|
IDLE:
|
if (ld)
|
if (ld)
|
state <= ONE;
|
state <= ONE;
|
ONE:
|
ONE:
|
if (op==`TLB_RDAGE || op==`TLB_WRAGE) begin
|
if (op==`TLB_RDAGE || op==`TLB_WRAGE) begin
|
if (getset_age)
|
if (getset_age)
|
state <= TWO;
|
state <= TWO;
|
end
|
end
|
else
|
else
|
state <= TWO;
|
state <= TWO;
|
TWO:
|
TWO:
|
state <= IDLE;
|
state <= IDLE;
|
default:
|
default:
|
state <= IDLE;
|
state <= IDLE;
|
endcase
|
endcase
|
end
|
end
|
|
|
// Set index to page table
|
// Set index to page table
|
always @(posedge clk)
|
always @(posedge clk)
|
if (rst) begin
|
|
i <= 8'd0;
|
|
end
|
|
else begin
|
|
if (state==ONE) begin
|
if (state==ONE) begin
|
case(op)
|
case(op)
|
`TLB_RD,`TLB_WI:
|
`TLB_RD,`TLB_WI:
|
i <= {Index[7:4],(HTLBVirtPage >> {HTLBPageSize,1'b0}) & 4'hF};
|
i <= {Index[7:4],(HTLBVirtPage >> {HTLBPageSize,1'b0}) & 4'hF};
|
`TLB_WR:
|
`TLB_WR:
|
i <= {Random,(HTLBVirtPage >> {HTLBPageSize,1'b0}) & 4'hF};
|
i <= {Random,(HTLBVirtPage >> {HTLBPageSize,1'b0}) & 4'hF};
|
endcase
|
endcase
|
end
|
end
|
end
|
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
if (rst) begin
|
begin
|
TLBenabled <= 1'b0;
|
|
Wired <= 4'd0;
|
|
PageTblAddr <= {DBW{1'b0}};
|
|
PageTblCtrl <= {DBW{1'b0}};
|
|
age_lmt <= 24'd20000;
|
|
end
|
|
else begin
|
|
if (miss_addr == {DBW{1'b0}} && TLBMiss)
|
if (miss_addr == {DBW{1'b0}} && TLBMiss)
|
miss_addr <= vadr_i;
|
miss_addr <= vadr_i;
|
|
|
if (state==ONE) begin
|
if (state==ONE) begin
|
case(op)
|
case(op)
|
`TLB_WRREG:
|
`TLB_WRREG:
|
begin
|
begin
|
case(regno)
|
case(regno)
|
`TLBWired: Wired <= dati[2:0];
|
`TLBWired: Wired <= dati[2:0];
|
`TLBIndex: Index <= dati[5:0];
|
`TLBIndex: Index <= dati[5:0];
|
//`TLBPageSize: PageSize <= dati[2:0];
|
//`TLBPageSize: PageSize <= dati[2:0];
|
`TLBVirtPage: HTLBVirtPage <= dati;
|
`TLBVirtPage: HTLBVirtPage <= dati;
|
`TLBPhysPage: HTLBPhysPage <= dati;
|
`TLBPhysPage: HTLBPhysPage <= dati;
|
`TLBASID: begin
|
`TLBASID: begin
|
HTLBValid <= |dati[2:0];
|
HTLBValid <= |dati[2:0];
|
HTLBX <= dati[0];
|
HTLBX <= dati[0];
|
HTLBW <= dati[1];
|
HTLBW <= dati[1];
|
HTLBR <= dati[2];
|
HTLBR <= dati[2];
|
HTLBC <= dati[5:3];
|
HTLBC <= dati[5:3];
|
HTLBA <= dati[6];
|
HTLBA <= dati[6];
|
HTLBS <= dati[7];
|
HTLBS <= dati[7];
|
HTLBU <= dati[8];
|
HTLBU <= dati[8];
|
HTLBD <= dati[9];
|
HTLBD <= dati[9];
|
HTLBG <= dati[10];
|
HTLBG <= dati[10];
|
HTLBPageSize <= dati[13:11];
|
HTLBPageSize <= dati[13:11];
|
HTLBASID <= dati[23:16];
|
HTLBASID <= dati[23:16];
|
HTLBPL <= dati[31:24];
|
HTLBPL <= dati[31:24];
|
end
|
end
|
`TLBMissAdr: miss_addr <= dati;
|
`TLBMissAdr: miss_addr <= dati;
|
`TLBPageTblAddr: PageTblAddr <= dati;
|
`TLBPageTblAddr: PageTblAddr <= dati;
|
`TLBPageTblCtrl: PageTblCtrl <= dati;
|
`TLBPageTblCtrl: PageTblCtrl <= dati;
|
`TLBAFC: age_lmt <= dati[23:0];
|
`TLBAFC: age_lmt <= dati[23:0];
|
default: ;
|
default: ;
|
endcase
|
endcase
|
end
|
end
|
`TLB_EN:
|
`TLB_EN:
|
TLBenabled <= 1'b1;
|
TLBenabled <= 1'b1;
|
`TLB_DIS:
|
`TLB_DIS:
|
TLBenabled <= 1'b0;
|
TLBenabled <= 1'b0;
|
`TLB_INVALL:
|
`TLB_INVALL:
|
TLBValid <= 256'd0;
|
TLBValid <= 256'd0;
|
default: ;
|
default: ;
|
endcase
|
endcase
|
end
|
end
|
else if (state==TWO) begin
|
else if (state==TWO) begin
|
case(op)
|
case(op)
|
`TLB_P:
|
`TLB_P:
|
begin
|
begin
|
Index[DBW-1] <= ~|Match;
|
Index[DBW-1] <= ~|Match;
|
end
|
end
|
`TLB_RD:
|
`TLB_RD:
|
begin
|
begin
|
HTLBVirtPage <= TLBVirtPage[i];
|
HTLBVirtPage <= TLBVirtPage[i];
|
HTLBPhysPage <= TLBPhysPage_rdo;
|
HTLBPhysPage <= TLBPhysPage_rdo;
|
HTLBASID <= TLBASID[i];
|
HTLBASID <= TLBASID[i];
|
HTLBPL <= TLBPL[i];
|
HTLBPL <= TLBPL[i];
|
HTLBPageSize <= TLBPageSize[i];
|
HTLBPageSize <= TLBPageSize[i];
|
HTLBG <= TLBG[i];
|
HTLBG <= TLBG[i];
|
HTLBD <= TLBD[i];
|
HTLBD <= TLBD[i];
|
HTLBC <= TLBC[i];
|
HTLBC <= TLBC[i];
|
HTLBR <= tlbRo0;
|
HTLBR <= tlbRo0;
|
HTLBW <= tlbWo0;
|
HTLBW <= tlbWo0;
|
HTLBX <= tlbXo0;
|
HTLBX <= tlbXo0;
|
HTLBU <= TLBU[i];
|
HTLBU <= TLBU[i];
|
HTLBS <= TLBS[i];
|
HTLBS <= TLBS[i];
|
HTLBA <= TLBA[i];
|
HTLBA <= TLBA[i];
|
HTLBValid <= TLBValid[i];
|
HTLBValid <= TLBValid[i];
|
end
|
end
|
`TLB_WR,`TLB_WI:
|
`TLB_WR,`TLB_WI:
|
begin
|
begin
|
TLBVirtPage[i] <= HTLBVirtPage;
|
TLBVirtPage[i] <= HTLBVirtPage;
|
TLBASID[i] <= HTLBASID;
|
TLBASID[i] <= HTLBASID;
|
TLBPL[i] <= HTLBPL;
|
TLBPL[i] <= HTLBPL;
|
TLBPageSize[i] <= HTLBPageSize;
|
TLBPageSize[i] <= HTLBPageSize;
|
TLBG[i] <= HTLBG;
|
TLBG[i] <= HTLBG;
|
TLBD[i] <= HTLBD;
|
TLBD[i] <= HTLBD;
|
TLBC[i] <= HTLBC;
|
TLBC[i] <= HTLBC;
|
TLBA[i] <= HTLBA;
|
TLBA[i] <= HTLBA;
|
TLBU[i] <= HTLBU;
|
TLBU[i] <= HTLBU;
|
TLBS[i] <= HTLBS;
|
TLBS[i] <= HTLBS;
|
TLBValid[i] <= HTLBValid;
|
TLBValid[i] <= HTLBValid;
|
end
|
end
|
default: ;
|
default: ;
|
endcase
|
endcase
|
end
|
end
|
|
|
// Set the dirty bit on a store
|
// Set the dirty bit on a store
|
if (we_i)
|
if (we_i)
|
if (!m1UnmappedArea & !q[4]) begin
|
if (!m1UnmappedArea & !q[4]) begin
|
TLBD[{q[3:0],vadrs[3:0]}] <= 1'b1;
|
TLBD[{q[3:0],vadrs[3:0]}] <= 1'b1;
|
end
|
end
|
end
|
end
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
case(regno)
|
case(regno)
|
`TLBWired: dato <= Wired;
|
`TLBWired: dato <= Wired;
|
`TLBIndex: dato <= Index;
|
`TLBIndex: dato <= Index;
|
`TLBRandom: dato <= Random;
|
`TLBRandom: dato <= Random;
|
`TLBPhysPage: dato <= HTLBPhysPage;
|
`TLBPhysPage: dato <= HTLBPhysPage;
|
`TLBVirtPage: dato <= HTLBVirtPage;
|
`TLBVirtPage: dato <= HTLBVirtPage;
|
`TLBPageSize: dato <= PageSize;
|
`TLBPageSize: dato <= PageSize;
|
`TLBASID: begin
|
`TLBASID: begin
|
dato <= {DBW{1'b0}};
|
dato <= {DBW{1'b0}};
|
dato[0] <= HTLBX;
|
dato[0] <= HTLBX;
|
dato[1] <= HTLBW;
|
dato[1] <= HTLBW;
|
dato[2] <= HTLBR;
|
dato[2] <= HTLBR;
|
dato[5:3] <= HTLBC;
|
dato[5:3] <= HTLBC;
|
dato[6] <= HTLBA;
|
dato[6] <= HTLBA;
|
dato[7] <= HTLBS;
|
dato[7] <= HTLBS;
|
dato[8] <= HTLBU;
|
dato[8] <= HTLBU;
|
dato[9] <= HTLBD;
|
dato[9] <= HTLBD;
|
dato[10] <= HTLBG;
|
dato[10] <= HTLBG;
|
dato[13:11] <= HTLBPageSize;
|
dato[13:11] <= HTLBPageSize;
|
dato[23:16] <= HTLBASID;
|
dato[23:16] <= HTLBASID;
|
dato[31:24] <= HTLBPL;
|
dato[31:24] <= HTLBPL;
|
end
|
end
|
`TLBMissAdr: dato <= miss_addr;
|
`TLBMissAdr: dato <= miss_addr;
|
`TLBPageTblAddr: dato <= PageTblAddr;
|
`TLBPageTblAddr: dato <= PageTblAddr;
|
`TLBPageTblCtrl: dato <= PageTblCtrl;
|
`TLBPageTblCtrl: dato <= PageTblCtrl;
|
`TLBPageCount: dato <= {16'd0,ar_cdato};
|
`TLBPageCount: dato <= {16'd0,ar_cdato};
|
default: dato <= {DBW{1'b0}};
|
default: dato <= {DBW{1'b0}};
|
endcase
|
endcase
|
|
|
TLBAgeRam uar1(clk,ar_wr,ar_adr,ar_dati,ar_dato);
|
TLBAgeRam uar1(clk,ar_wr,ar_adr,ar_dati,ar_dato);
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
if (rst) begin
|
begin
|
age_adr <= 4'd0;
|
|
ar_wr <= 1'b0;
|
|
ar_adr <= 4'd0;
|
|
ar_state <= IDLE;
|
|
cyc_en <= 1'b1;
|
|
age_en <= 1'b1;
|
|
doLoad <= 1'b0;
|
|
end
|
|
else begin
|
|
ar_wr <= 1'b0;
|
ar_wr <= 1'b0;
|
getset_age <= 1'b0;
|
getset_age <= 1'b0;
|
if (ld)
|
if (ld)
|
doLoad <= 1'b1;
|
doLoad <= 1'b1;
|
case(ar_state)
|
case(ar_state)
|
IDLE:
|
IDLE:
|
begin
|
begin
|
if (~cyc_i)
|
if (~cyc_i)
|
cyc_en <= 1'b1;
|
cyc_en <= 1'b1;
|
if (~age_tick)
|
if (~age_tick)
|
age_en <= 1'b1;
|
age_en <= 1'b1;
|
if ((ld|doLoad) && (op==`TLB_RDAGE || op==`TLB_WRAGE)) begin
|
if ((ld|doLoad) && (op==`TLB_RDAGE || op==`TLB_WRAGE)) begin
|
doLoad <= 1'b0;
|
doLoad <= 1'b0;
|
ar_wr <= op==`TLB_WRAGE;
|
ar_wr <= op==`TLB_WRAGE;
|
ar_adr <= i;
|
ar_adr <= i;
|
ar_dati <= dati[31:0];
|
ar_dati <= dati[31:0];
|
ar_state <= READ;
|
ar_state <= READ;
|
end
|
end
|
else if (cyc_i & |Match & cyc_en) begin
|
else if (cyc_i & |Match & cyc_en) begin
|
cyc_en <= 1'b0;
|
cyc_en <= 1'b0;
|
ar_adr <= {q[3:0],vadrs[3:0]};
|
ar_adr <= {q[3:0],vadrs[3:0]};
|
ar_state <= INC1;
|
ar_state <= INC1;
|
end
|
end
|
else if (age_tick & age_en) begin
|
else if (age_tick & age_en) begin
|
age_en <= 1'b0;
|
age_en <= 1'b0;
|
ar_adr <= age_adr;
|
ar_adr <= age_adr;
|
age_adr <= age_adr + 4'd1;
|
age_adr <= age_adr + 4'd1;
|
ar_state <= AGE1;
|
ar_state <= AGE1;
|
end
|
end
|
end
|
end
|
READ:
|
READ:
|
begin
|
begin
|
getset_age <= 1'b1;
|
getset_age <= 1'b1;
|
ar_cdato <= ar_dato;
|
ar_cdato <= ar_dato;
|
ar_state <= IDLE;
|
ar_state <= IDLE;
|
end
|
end
|
INC1:
|
INC1:
|
begin
|
begin
|
count <= ar_dato;
|
count <= ar_dato;
|
ar_state <= INC2;
|
ar_state <= INC2;
|
end
|
end
|
INC2:
|
INC2:
|
begin
|
begin
|
count <= {count[31:8] + 4'd1,count[7:0]};
|
count <= {count[31:8] + 4'd1,count[7:0]};
|
ar_state <= INC3;
|
ar_state <= INC3;
|
end
|
end
|
INC3:
|
INC3:
|
begin
|
begin
|
ar_wr <= 1'b1;
|
ar_wr <= 1'b1;
|
ar_dati <= {count[32] ? 24'hFFFFFF :count[31:8],count[7:0]};
|
ar_dati <= {count[32] ? 24'hFFFFFF :count[31:8],count[7:0]};
|
ar_state <= IDLE;
|
ar_state <= IDLE;
|
end
|
end
|
AGE1:
|
AGE1:
|
begin
|
begin
|
count <= ar_dato;
|
count <= ar_dato;
|
ar_state <= AGE2;
|
ar_state <= AGE2;
|
end
|
end
|
AGE2:
|
AGE2:
|
begin
|
begin
|
ar_wr <= 1'b1;
|
ar_wr <= 1'b1;
|
ar_dati <= count >> 1;
|
ar_dati <= count >> 1;
|
ar_state <= IDLE;
|
ar_state <= IDLE;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
|
|
always @*
|
always @*
|
for (n = 0; n < 16; n = n + 1)
|
for (n = 0; n < 16; n = n + 1)
|
Match[n[3:0]] = (vadrs[ABW-1:4]==TLBVirtPage[{n[3:0],vadrs[3:0]}]) &&
|
Match[n[3:0]] = (vadrs[ABW-1:4]==TLBVirtPage[{n[3:0],vadrs[3:0]}]) &&
|
((TLBASID[{n[3:0],vadrs[3:0]}]==ASID) || TLBG[{n[3:0],vadrs[3:0]}]) &&
|
((TLBASID[{n[3:0],vadrs[3:0]}]==ASID) || TLBG[{n[3:0],vadrs[3:0]}]) &&
|
TLBValid[{q[3:0],vadrs[3:0]}];
|
TLBValid[{q[3:0],vadrs[3:0]}];
|
|
|
always @*
|
always @*
|
begin
|
begin
|
q = 5'd31;
|
q = 5'd31;
|
for (n = 15; n >= 0; n = n - 1)
|
for (n = 15; n >= 0; n = n - 1)
|
if (Match[n]) q = n;
|
if (Match[n]) q = n;
|
end
|
end
|
|
|
assign uncached = TLBC[{q[3:0],vadrs[3:0]}]==3'd1;// || unmappedDataArea;
|
assign uncached = TLBC[{q[3:0],vadrs[3:0]}]==3'd1;// || unmappedDataArea;
|
|
|
assign TLBMiss = TLBenabled & (!unmappedArea & (q[4] | ~TLBValid[{q[3:0],vadrs[3:0]}]) ||
|
assign TLBMiss = (ol!=2'b00) && TLBenabled && (!unmappedArea & (q[4] | ~TLBValid[{q[3:0],vadrs[3:0]}]) ||
|
(ol!=2'b00 && hitIOPage));
|
(ol!=2'b00 && hitIOPage));
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
cyc_o <= cyc_i & (~TLBMiss | ~TLBenabled);
|
cyc_o <= cyc_i && (!TLBMiss || !TLBenabled || (ol == 2'b00));
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
we_o <= we_i & ((~TLBMiss & tlbWo1) | ~TLBenabled);
|
we_o <= we_i & ((~TLBMiss & tlbWo1) | ~TLBenabled || (ol==2'b00));
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
wrv_o <= we_i & ~TLBMiss & ~tlbWo1 & TLBenabled;
|
wrv_o <= we_i & ~TLBMiss & ~tlbWo1 & TLBenabled && (ol != 2'b00);
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
rdv_o <= ~we_i & ~TLBMiss & ~tlbRo1 & TLBenabled;
|
rdv_o <= ~we_i & ~TLBMiss & ~tlbRo1 & TLBenabled && (ol != 2'b00);
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
exv_o <= icl_i & ~TLBMiss & ~tlbXo1 & TLBenabled;
|
exv_o <= icl_i & ~TLBMiss & ~tlbXo1 & TLBenabled && (ol != 2'b00);
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
if (rst)
|
|
padr_o <= 32'hFFFC0100;
|
|
else begin
|
|
if (TLBenabled && ol != 2'b00) begin
|
if (TLBenabled && ol != 2'b00) begin
|
case(PageSize)
|
case(PageSize)
|
3'd0: padr_o[ABW-1:13] <= unmappedArea ? vadr_i[ABW-1:13] : TLBMiss ? `TLBMissPage: PFN;
|
3'd0: padr_o[ABW-1:13] <= unmappedArea ? vadr_i[ABW-1:13] : TLBMiss ? `TLBMissPage: PFN;
|
3'd1: padr_o[ABW-1:13] <= {unmappedArea ? vadr_i[ABW-1:15] : TLBMiss ? `TLBMissPage: PFN,vadr_i[14:13]};
|
3'd1: padr_o[ABW-1:13] <= {unmappedArea ? vadr_i[ABW-1:15] : TLBMiss ? `TLBMissPage: PFN,vadr_i[14:13]};
|
3'd2: padr_o[ABW-1:13] <= {unmappedArea ? vadr_i[ABW-1:17] : TLBMiss ? `TLBMissPage: PFN,vadr_i[16:13]};
|
3'd2: padr_o[ABW-1:13] <= {unmappedArea ? vadr_i[ABW-1:17] : TLBMiss ? `TLBMissPage: PFN,vadr_i[16:13]};
|
3'd3: padr_o[ABW-1:13] <= {unmappedArea ? vadr_i[ABW-1:19] : TLBMiss ? `TLBMissPage: PFN,vadr_i[18:13]};
|
3'd3: padr_o[ABW-1:13] <= {unmappedArea ? vadr_i[ABW-1:19] : TLBMiss ? `TLBMissPage: PFN,vadr_i[18:13]};
|
3'd4: padr_o[ABW-1:13] <= {unmappedArea ? vadr_i[ABW-1:21] : TLBMiss ? `TLBMissPage: PFN,vadr_i[20:13]};
|
3'd4: padr_o[ABW-1:13] <= {unmappedArea ? vadr_i[ABW-1:21] : TLBMiss ? `TLBMissPage: PFN,vadr_i[20:13]};
|
3'd5: padr_o[ABW-1:13] <= {unmappedArea ? vadr_i[ABW-1:23] : TLBMiss ? `TLBMissPage: PFN,vadr_i[22:13]};
|
3'd5: padr_o[ABW-1:13] <= {unmappedArea ? vadr_i[ABW-1:23] : TLBMiss ? `TLBMissPage: PFN,vadr_i[22:13]};
|
default: padr_o[ABW-1:13] <= vadr_i[ABW-1:13];
|
default: padr_o[ABW-1:13] <= vadr_i[ABW-1:13];
|
endcase
|
endcase
|
padr_o[12:0] <= vadr_i[12:0];
|
padr_o[12:0] <= vadr_i[12:0];
|
end
|
end
|
else
|
else
|
padr_o <= vadr_i;
|
padr_o <= vadr_i;
|
end
|
|
|
|
endmodule
|
endmodule
|
|
|
module TLBRam(clk,we,wa,i,ra0,ra1,o0,o1);
|
module TLBRam(clk,we,wa,i,ra0,ra1,o0,o1);
|
parameter DBW=1;
|
parameter DBW=1;
|
input clk;
|
input clk;
|
input we;
|
input we;
|
input [7:0] wa;
|
input [7:0] wa;
|
input [DBW-1:0] i;
|
input [DBW-1:0] i;
|
input [7:0] ra0;
|
input [7:0] ra0;
|
input [7:0] ra1;
|
input [7:0] ra1;
|
output [DBW-1:0] o0;
|
output [DBW-1:0] o0;
|
output [DBW-1:0] o1;
|
output [DBW-1:0] o1;
|
|
|
reg [DBW-1:0] mem [0:255];
|
reg [DBW-1:0] mem [0:255];
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
if (we)
|
if (we)
|
mem[wa] <= i;
|
mem[wa] <= i;
|
|
|
assign o0 = mem[ra0];
|
assign o0 = mem[ra0];
|
assign o1 = mem[ra1];
|
assign o1 = mem[ra1];
|
|
|
endmodule
|
endmodule
|
|
|
module TLBPhysPageRam(clk,we,wa,i,ra0,ra1,o0,o1);
|
module TLBPhysPageRam(clk,we,wa,i,ra0,ra1,o0,o1);
|
parameter DBW=64;
|
parameter DBW=64;
|
input clk;
|
input clk;
|
input we;
|
input we;
|
input [7:0] wa;
|
input [7:0] wa;
|
input [DBW-1:0] i;
|
input [DBW-1:0] i;
|
input [7:0] ra0;
|
input [7:0] ra0;
|
input [7:0] ra1;
|
input [7:0] ra1;
|
output [DBW-1:0] o0;
|
output [DBW-1:0] o0;
|
output [DBW-1:0] o1;
|
output [DBW-1:0] o1;
|
|
|
reg [DBW-1:0] mem [0:255];
|
reg [DBW-1:0] mem [0:255];
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
if (we)
|
if (we)
|
mem[wa] <= i;
|
mem[wa] <= i;
|
|
|
assign o0 = mem[ra0];
|
assign o0 = mem[ra0];
|
assign o1 = mem[ra1];
|
assign o1 = mem[ra1];
|
|
|
endmodule
|
endmodule
|
|
|
module TLBAgeRam(clk,we,a,i,o);
|
module TLBAgeRam(clk,we,a,i,o);
|
parameter DBW=32;
|
parameter DBW=32;
|
input clk;
|
input clk;
|
input we;
|
input we;
|
input [7:0] a;
|
input [7:0] a;
|
input [DBW-1:0] i;
|
input [DBW-1:0] i;
|
output [DBW-1:0] o;
|
output [DBW-1:0] o;
|
|
|
reg [DBW-1:0] mem [0:255];
|
reg [DBW-1:0] mem [0:255];
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
if (we)
|
if (we)
|
mem[a] <= i;
|
mem[a] <= i;
|
|
|
assign o = mem[a];
|
assign o = mem[a];
|
|
|
endmodule
|
endmodule
|
|
|
|
|