// ============================================================================
|
// ============================================================================
|
// __
|
// __
|
// \\__/ o\ (C) 2013 Robert Finch, Stratford
|
// \\__/ o\ (C) 2013 Robert Finch, Stratford
|
// \ __ / All rights reserved.
|
// \ __ / All rights reserved.
|
// \/_// robfinch<remove>@opencores.org
|
// \/_// robfinch<remove>@opencores.org
|
// ||
|
// ||
|
//
|
//
|
// 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/>.
|
//
|
//
|
// ============================================================================
|
// ============================================================================
|
//
|
//
|
// Cache controller
|
// Cache controller
|
// Also takes care of loading the instruction buffer for non-cached access
|
// Also takes care of loading the instruction buffer for non-cached access
|
//
|
//
|
case(cstate)
|
case(cstate)
|
IDLE:
|
IDLE:
|
begin
|
begin
|
if (!cyc_o) begin
|
if (!cyc_o) begin
|
|
`ifdef SUPPORT_DCACHE
|
// A write to a cacheable address does not cause a cache load
|
// A write to a cacheable address does not cause a cache load
|
if (dmiss) begin
|
if (dmiss) begin
|
isDataCacheLoad <= `TRUE;
|
isDataCacheLoad <= `TRUE;
|
if (isRMW)
|
if (isRMW)
|
lock_o <= 1'b1;
|
lock_o <= 1'b1;
|
cti_o <= 3'b001;
|
cti_o <= 3'b001;
|
bl_o <= 6'd3;
|
bl_o <= 6'd3;
|
cyc_o <= 1'b1;
|
cyc_o <= 1'b1;
|
stb_o <= 1'b1;
|
stb_o <= 1'b1;
|
sel_o <= 4'hF;
|
sel_o <= 4'hF;
|
adr_o <= {radr[31:2],4'h0};
|
adr_o <= {radr[31:2],4'h0};
|
cstate <= LOAD_DCACHE;
|
cstate <= LOAD_DCACHE;
|
end
|
end
|
else if (!unCachedInsn && imiss && !hit0) begin
|
else
|
|
`endif
|
|
`ifdef SUPPORT_ICACHE
|
|
if (!unCachedInsn && imiss && !hit0) begin
|
isInsnCacheLoad <= `TRUE;
|
isInsnCacheLoad <= `TRUE;
|
bte_o <= 2'b00;
|
bte_o <= 2'b00;
|
cti_o <= 3'd001;
|
cti_o <= 3'd001;
|
bl_o <= 6'd3;
|
bl_o <= 6'd3;
|
cyc_o <= 1'b1;
|
cyc_o <= 1'b1;
|
stb_o <= 1'b1;
|
stb_o <= 1'b1;
|
sel_o <= 4'hF;
|
sel_o <= 4'hF;
|
adr_o <= {pc[31:4],4'h0};
|
adr_o <= {pc[31:4],4'h0};
|
cstate <= LOAD_ICACHE;
|
cstate <= LOAD_ICACHE;
|
end
|
end
|
else if (!unCachedInsn && imiss && !hit1) begin
|
else if (!unCachedInsn && imiss && !hit1) begin
|
isInsnCacheLoad <= `TRUE;
|
isInsnCacheLoad <= `TRUE;
|
bte_o <= 2'b00;
|
bte_o <= 2'b00;
|
cti_o <= 3'd001;
|
cti_o <= 3'd001;
|
bl_o <= 6'd3;
|
bl_o <= 6'd3;
|
cyc_o <= 1'b1;
|
cyc_o <= 1'b1;
|
stb_o <= 1'b1;
|
stb_o <= 1'b1;
|
sel_o <= 4'hF;
|
sel_o <= 4'hF;
|
adr_o <= {pcp8[31:4],4'h0};
|
adr_o <= {pcp8[31:4],4'h0};
|
cstate <= LOAD_ICACHE;
|
cstate <= LOAD_ICACHE;
|
end
|
end
|
else if (unCachedInsn && imiss) begin
|
else
|
|
`endif
|
|
if (unCachedInsn && imiss) begin
|
bte_o <= 2'b00;
|
bte_o <= 2'b00;
|
cti_o <= 3'b001;
|
cti_o <= 3'b001;
|
bl_o <= 6'd2;
|
bl_o <= 6'd2;
|
cyc_o <= 1'b1;
|
cyc_o <= 1'b1;
|
stb_o <= 1'b1;
|
stb_o <= 1'b1;
|
sel_o <= 4'hf;
|
sel_o <= 4'hf;
|
adr_o <= {pc[31:2],2'b00};
|
adr_o <= {pc[31:2],2'b00};
|
cstate <= LOAD_IBUF1;
|
cstate <= LOAD_IBUF1;
|
end
|
end
|
end
|
end
|
end
|
end
|
|
`ifdef SUPPORT_DCACHE
|
LOAD_DCACHE:
|
LOAD_DCACHE:
|
if (ack_i) begin
|
if (ack_i) begin
|
if (adr_o[3:2]==2'b11) begin
|
if (adr_o[3:2]==2'b11) begin
|
dmiss <= `FALSE;
|
dmiss <= `FALSE;
|
isDataCacheLoad <= `FALSE;
|
isDataCacheLoad <= `FALSE;
|
cti_o <= 3'b000;
|
cti_o <= 3'b000;
|
bl_o <= 6'd0;
|
bl_o <= 6'd0;
|
cyc_o <= 1'b0;
|
cyc_o <= 1'b0;
|
stb_o <= 1'b0;
|
stb_o <= 1'b0;
|
sel_o <= 4'h0;
|
sel_o <= 4'h0;
|
adr_o <= 34'h0;
|
adr_o <= 34'h0;
|
cstate <= IDLE;
|
cstate <= IDLE;
|
end
|
end
|
adr_o <= adr_o + 34'd4;
|
adr_o <= adr_o + 34'd4;
|
end
|
end
|
// What to do here
|
// What to do here
|
|
`ifdef SUPPORT_BERR
|
else if (err_i) begin
|
else if (err_i) begin
|
if (adr_o[3:2]==2'b11) begin
|
if (adr_o[3:2]==2'b11) begin
|
dmiss <= `FALSE;
|
dmiss <= `FALSE;
|
isDataCacheLoad <= `FALSE;
|
isDataCacheLoad <= `FALSE;
|
cti_o <= 3'b000;
|
cti_o <= 3'b000;
|
bl_o <= 6'd0;
|
bl_o <= 6'd0;
|
cyc_o <= 1'b0;
|
cyc_o <= 1'b0;
|
stb_o <= 1'b0;
|
stb_o <= 1'b0;
|
sel_o <= 4'h0;
|
sel_o <= 4'h0;
|
adr_o <= 34'h0;
|
adr_o <= 34'h0;
|
cstate <= IDLE;
|
cstate <= IDLE;
|
// The state machine will be waiting for a dhit.
|
// The state machine will be waiting for a dhit.
|
// Override the next state and send the processor to the bus error state.
|
// Override the next state and send the processor to the bus error state.
|
state <= BUS_ERROR;
|
state <= BUS_ERROR;
|
end
|
end
|
adr_o <= adr_o + 34'd4;
|
adr_o <= adr_o + 34'd4;
|
end
|
end
|
|
`endif
|
|
`endif
|
|
`ifdef SUPPORT_ICACHE
|
LOAD_ICACHE:
|
LOAD_ICACHE:
|
if (ack_i) begin
|
if (ack_i) begin
|
if (adr_o[3:2]==2'b11) begin
|
if (adr_o[3:2]==2'b11) begin
|
imiss <= `FALSE;
|
imiss <= `FALSE;
|
isInsnCacheLoad <= `FALSE;
|
isInsnCacheLoad <= `FALSE;
|
cti_o <= 3'b000;
|
cti_o <= 3'b000;
|
bl_o <= 6'd0;
|
bl_o <= 6'd0;
|
cyc_o <= 1'b0;
|
cyc_o <= 1'b0;
|
stb_o <= 1'b0;
|
stb_o <= 1'b0;
|
sel_o <= 4'h0;
|
sel_o <= 4'h0;
|
adr_o <= 34'd0;
|
adr_o <= 34'd0;
|
cstate <= IDLE;
|
cstate <= IDLE;
|
end
|
end
|
adr_o <= adr_o + 34'd4;
|
adr_o <= adr_o + 34'd4;
|
end
|
end
|
|
`ifdef SUPPORT_BERR
|
else if (err_i) begin
|
else if (err_i) begin
|
if (adr_o[3:2]==2'b11) begin
|
if (adr_o[3:2]==2'b11) begin
|
imiss <= `FALSE;
|
imiss <= `FALSE;
|
isInsnCacheLoad <= `FALSE;
|
isInsnCacheLoad <= `FALSE;
|
cti_o <= 3'b000;
|
cti_o <= 3'b000;
|
bl_o <= 6'd0;
|
bl_o <= 6'd0;
|
cyc_o <= 1'b0;
|
cyc_o <= 1'b0;
|
stb_o <= 1'b0;
|
stb_o <= 1'b0;
|
sel_o <= 4'h0;
|
sel_o <= 4'h0;
|
adr_o <= 34'd0;
|
adr_o <= 34'd0;
|
state <= INSN_BUS_ERROR;
|
state <= INSN_BUS_ERROR;
|
cstate <= IDLE;
|
cstate <= IDLE;
|
end
|
end
|
adr_o <= adr_o + 34'd4;
|
adr_o <= adr_o + 34'd4;
|
end
|
end
|
|
`endif
|
|
`endif
|
LOAD_IBUF1:
|
LOAD_IBUF1:
|
if (ack_i|err_i) begin
|
if (ack_i|err_i) begin
|
case(pc[1:0])
|
case(pc[1:0])
|
2'd0: ibuf <= dat_i;
|
2'd0: ibuf <= dat_i;
|
2'd1: ibuf <= dat_i[31:8];
|
2'd1: ibuf <= dat_i[31:8];
|
2'd2: ibuf <= dat_i[31:16];
|
2'd2: ibuf <= dat_i[31:16];
|
2'd3: ibuf <= dat_i[31:24];
|
2'd3: ibuf <= dat_i[31:24];
|
endcase
|
endcase
|
cstate <= LOAD_IBUF2;
|
cstate <= LOAD_IBUF2;
|
adr_o <= adr_o + 34'd4;
|
adr_o <= adr_o + 34'd4;
|
end
|
end
|
LOAD_IBUF2:
|
LOAD_IBUF2:
|
if (ack_i|err_i) begin
|
if (ack_i|err_i) begin
|
case(pc[1:0])
|
case(pc[1:0])
|
2'd0: ibuf[55:32] <= dat_i[23:0];
|
2'd0: ibuf[55:32] <= dat_i[23:0];
|
2'd1: ibuf[55:24] <= dat_i;
|
2'd1: ibuf[55:24] <= dat_i;
|
2'd2: ibuf[47:16] <= dat_i;
|
2'd2: ibuf[47:16] <= dat_i;
|
2'd3: ibuf[39:8] <= dat_i;
|
2'd3: ibuf[39:8] <= dat_i;
|
endcase
|
endcase
|
cstate <= LOAD_IBUF3;
|
cstate <= LOAD_IBUF3;
|
adr_o <= adr_o + 34'd4;
|
adr_o <= adr_o + 34'd4;
|
end
|
end
|
LOAD_IBUF3:
|
LOAD_IBUF3:
|
if (ack_i) begin
|
if (ack_i) begin
|
case(pc[1:0])
|
case(pc[1:0])
|
2'd0: ;
|
2'd0: ;
|
2'd1: ;
|
2'd1: ;
|
2'd2: ibuf[55:48] <= dat_i[7:0];
|
2'd2: ibuf[55:48] <= dat_i[7:0];
|
2'd3: ibuf[55:40] <= dat_i[15:0];
|
2'd3: ibuf[55:40] <= dat_i[15:0];
|
endcase
|
endcase
|
cti_o <= 3'd0;
|
cti_o <= 3'd0;
|
bl_o <= 6'd0;
|
bl_o <= 6'd0;
|
cyc_o <= 1'b0;
|
cyc_o <= 1'b0;
|
stb_o <= 1'b0;
|
stb_o <= 1'b0;
|
sel_o <= 4'h0;
|
sel_o <= 4'h0;
|
adr_o <= 34'd0;
|
adr_o <= 34'd0;
|
cstate <= IDLE;
|
cstate <= IDLE;
|
imiss <= `FALSE;
|
imiss <= `FALSE;
|
bufadr <= pc; // clears the miss
|
bufadr <= pc; // clears the miss
|
end
|
end
|
|
`ifdef SUPPORT_BERR
|
else if (err_i) begin
|
else if (err_i) begin
|
case(pc[1:0])
|
case(pc[1:0])
|
2'd0: ;
|
2'd0: ;
|
2'd1: ;
|
2'd1: ;
|
2'd2: ibuf[55:48] <= dat_i[7:0];
|
2'd2: ibuf[55:48] <= dat_i[7:0];
|
2'd3: ibuf[55:40] <= dat_i[15:0];
|
2'd3: ibuf[55:40] <= dat_i[15:0];
|
endcase
|
endcase
|
cti_o <= 3'd0;
|
cti_o <= 3'd0;
|
bl_o <= 6'd0;
|
bl_o <= 6'd0;
|
cyc_o <= 1'b0;
|
cyc_o <= 1'b0;
|
stb_o <= 1'b0;
|
stb_o <= 1'b0;
|
sel_o <= 4'h0;
|
sel_o <= 4'h0;
|
adr_o <= 34'd0;
|
adr_o <= 34'd0;
|
cstate <= IDLE;
|
cstate <= IDLE;
|
state <= INSN_BUS_ERROR;
|
state <= INSN_BUS_ERROR;
|
imiss <= `FALSE;
|
imiss <= `FALSE;
|
bufadr <= pc; // clears the miss
|
bufadr <= pc; // clears the miss
|
end
|
end
|
|
`endif
|
|
|
endcase
|
endcase
|
|
|