Line 1... |
Line 1... |
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// AltOR32
|
// AltOR32
|
// Alternative Lightweight OpenRisc
|
// Alternative Lightweight OpenRisc
|
// V2.0
|
// V2.1
|
// Ultra-Embedded.com
|
// Ultra-Embedded.com
|
// Copyright 2011 - 2013
|
// Copyright 2011 - 2014
|
//
|
//
|
// Email: admin@ultra-embedded.com
|
// Email: admin@ultra-embedded.com
|
//
|
//
|
// License: LGPL
|
// License: LGPL
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
Line 89... |
Line 89... |
parameter CACHE_TAG_DIRTY_BIT = 14;
|
parameter CACHE_TAG_DIRTY_BIT = 14;
|
parameter CACHE_TAG_VALID_BIT = 15;
|
parameter CACHE_TAG_VALID_BIT = 15;
|
parameter ADDR_NO_CACHE_BIT = 25;
|
parameter ADDR_NO_CACHE_BIT = 25;
|
parameter ADDR_CACHE_BYPASS_BIT = 31;
|
parameter ADDR_CACHE_BYPASS_BIT = 31;
|
|
|
|
parameter FLUSH_INITIAL = 0;
|
|
|
// 31 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
|
// 31 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
|
// |--------------| | | | | | | | | | | | | | | | |
|
// |--------------| | | | | | | | | | | | | | | | |
|
// +--------------------+ +-------------------+ +-----------+
|
// +--------------------+ +-------------------+ +-----------+
|
// Tag entry Line address Address
|
// Tag entry Line address Address
|
// (15-bits) (8-bits) within line
|
// (15-bits) (8-bits) within line
|
Line 131... |
Line 133... |
reg req_ack;
|
reg req_ack;
|
reg [31:0] req_address;
|
reg [31:0] req_address;
|
reg [31:0] req_data;
|
reg [31:0] req_data;
|
|
|
reg req_flush;
|
reg req_flush;
|
|
reg req_init;
|
reg flush_single;
|
reg flush_single;
|
|
|
wire [31:0] line_address;
|
wire [31:0] line_address;
|
|
|
wire [31:0] muxed_address = (state == STATE_IDLE) ? address_i : req_address;
|
wire [31:0] muxed_address = (state == STATE_IDLE) ? address_i : req_address;
|
Line 158... |
Line 161... |
|
|
assign tag_entry = muxed_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH];
|
assign tag_entry = muxed_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH];
|
assign cache_address = {tag_entry, muxed_address[CACHE_LINE_SIZE_WIDTH-1:2]};
|
assign cache_address = {tag_entry, muxed_address[CACHE_LINE_SIZE_WIDTH-1:2]};
|
|
|
assign data_o = (state == STATE_SINGLE_READY) ? data_r : cache_data_r;
|
assign data_o = (state == STATE_SINGLE_READY) ? data_r : cache_data_r;
|
assign stall_o = (state != STATE_IDLE) | req_flush;
|
assign stall_o = (state != STATE_IDLE) | req_flush | flush_i;
|
|
|
wire valid = tag_data_out[CACHE_TAG_VALID_BIT];
|
wire valid = tag_data_out[CACHE_TAG_VALID_BIT];
|
wire dirty = tag_data_out[CACHE_TAG_DIRTY_BIT];
|
wire dirty = tag_data_out[CACHE_TAG_DIRTY_BIT];
|
|
|
// Access is cacheable?
|
// Access is cacheable?
|
Line 174... |
Line 177... |
// Cache hit?
|
// Cache hit?
|
wire hit = cacheable & valid & addr_hit & (state == STATE_CHECK);
|
wire hit = cacheable & valid & addr_hit & (state == STATE_CHECK);
|
|
|
assign ack_o = ack | hit;
|
assign ack_o = ack | hit;
|
|
|
|
assign line_address[31:CACHE_TAG_ADDR_HIGH+1] = {(31-CACHE_TAG_ADDR_HIGH){1'b0}};
|
assign line_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] = tag_entry;
|
assign line_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] = tag_entry;
|
assign line_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] = tag_data_out[13:0];
|
assign line_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] = tag_data_out[13:0];
|
assign line_address[CACHE_LINE_SIZE_WIDTH-1:0] = {CACHE_LINE_SIZE_WIDTH{1'b0}};
|
assign line_address[CACHE_LINE_SIZE_WIDTH-1:0] = {CACHE_LINE_SIZE_WIDTH{1'b0}};
|
|
|
|
// Only allow cache write when same line present in the write state
|
|
wire cache_wr_enable = (state == STATE_WRITE) ? valid & addr_hit : 1'b1;
|
|
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Next State Logic
|
// Next State Logic
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
reg [3:0] next_state_r;
|
reg [3:0] next_state_r;
|
Line 210... |
Line 216... |
// Write (cacheable)
|
// Write (cacheable)
|
else if (stb_i & we_i)
|
else if (stb_i & we_i)
|
next_state_r = STATE_WRITE;
|
next_state_r = STATE_WRITE;
|
end
|
end
|
//-----------------------------------------
|
//-----------------------------------------
|
// WRITE - Wait for write-thru to complete
|
// WRITE
|
//-----------------------------------------
|
//-----------------------------------------
|
STATE_WRITE :
|
STATE_WRITE :
|
begin
|
begin
|
// Cache hit
|
// Cache hit (line already dirty)
|
if (valid & addr_hit)
|
if (valid & addr_hit & dirty)
|
|
next_state_r = STATE_IDLE;
|
|
// Cache hit, make line dirty
|
|
else if (valid & addr_hit & ~dirty)
|
next_state_r = STATE_WAIT2;
|
next_state_r = STATE_WAIT2;
|
// Cache dirty
|
// Cache dirty
|
else if (valid & dirty)
|
else if (valid & dirty)
|
next_state_r = STATE_EVICTING;
|
next_state_r = STATE_EVICTING;
|
// Cache miss
|
// Cache miss
|
Line 341... |
Line 350... |
// FLUSH3 - Check if line dirty & flush
|
// FLUSH3 - Check if line dirty & flush
|
//-----------------------------------------
|
//-----------------------------------------
|
STATE_FLUSH3 :
|
STATE_FLUSH3 :
|
begin
|
begin
|
// Dirty line? Evict line first
|
// Dirty line? Evict line first
|
if (dirty)
|
if (dirty && ~req_init)
|
next_state_r = STATE_FLUSH4;
|
next_state_r = STATE_FLUSH4;
|
// Not dirty? Just invalidate
|
// Not dirty? Just invalidate
|
else
|
else
|
begin
|
begin
|
if (flush_single)
|
if (flush_single)
|
Line 397... |
Line 406... |
begin
|
begin
|
tag_wr <= 1'b0;
|
tag_wr <= 1'b0;
|
|
|
case (state)
|
case (state)
|
//-----------------------------------------
|
//-----------------------------------------
|
// WRITE - Wait for write-thru to complete
|
// WRITE
|
//-----------------------------------------
|
//-----------------------------------------
|
STATE_WRITE :
|
STATE_WRITE :
|
begin
|
begin
|
// Cache hit
|
// Cache hit
|
if (valid & addr_hit)
|
if (valid & addr_hit)
|
begin
|
begin
|
// Mark line as dirty
|
// Mark line as dirty
|
|
if (~dirty)
|
|
begin
|
tag_data_in <= tag_data_out;
|
tag_data_in <= tag_data_out;
|
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b1;
|
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b1;
|
tag_wr <= 1'b1;
|
tag_wr <= 1'b1;
|
end
|
end
|
|
end
|
// Cache miss / cache line doesn't require write back
|
// Cache miss / cache line doesn't require write back
|
else if (~valid | ~dirty)
|
else if (~valid | ~dirty)
|
begin
|
begin
|
// Update tag memory with this line's details
|
// Update tag memory with this line's details
|
tag_data_in <= {1'b1, 1'b1, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
|
tag_data_in <= {1'b1, 1'b1, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
|
Line 497... |
Line 509... |
// FLUSH3 - Check if line dirty & flush
|
// FLUSH3 - Check if line dirty & flush
|
//-----------------------------------------
|
//-----------------------------------------
|
STATE_FLUSH3 :
|
STATE_FLUSH3 :
|
begin
|
begin
|
// Not dirty? Just invalidate
|
// Not dirty? Just invalidate
|
if (~dirty)
|
if (~dirty | req_init)
|
begin
|
begin
|
tag_data_in <= tag_data_out;
|
tag_data_in <= 16'b0;
|
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0;
|
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0;
|
tag_wr <= 1'b1;
|
tag_wr <= 1'b1;
|
end
|
end
|
end
|
end
|
//-----------------------------------------
|
//-----------------------------------------
|
Line 513... |
Line 525... |
begin
|
begin
|
// Cache line filled?
|
// Cache line filled?
|
if (done)
|
if (done)
|
begin
|
begin
|
// Invalidate line
|
// Invalidate line
|
tag_data_in <= tag_data_out;
|
tag_data_in <= 16'b0;
|
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0;
|
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0;
|
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b0;
|
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b0;
|
tag_wr <= 1'b1;
|
tag_wr <= 1'b1;
|
end
|
end
|
end
|
end
|
Line 537... |
Line 549... |
req_address <= 32'h00000000;
|
req_address <= 32'h00000000;
|
req_data <= 32'h00000000;
|
req_data <= 32'h00000000;
|
req_ack <= 1'b0;
|
req_ack <= 1'b0;
|
req_wr <= 4'h0;
|
req_wr <= 4'h0;
|
req_rd <= 1'b0;
|
req_rd <= 1'b0;
|
req_flush <= 1'b0;
|
req_flush <= 1'b1;
|
|
req_init <= FLUSH_INITIAL;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
if (flush_i)
|
if (flush_i)
|
req_flush <= 1'b1;
|
req_flush <= 1'b1;
|
Line 605... |
Line 618... |
STATE_FLUSH1 :
|
STATE_FLUSH1 :
|
begin
|
begin
|
if (req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] == {CACHE_LINE_ADDR_WIDTH{1'b1}})
|
if (req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] == {CACHE_LINE_ADDR_WIDTH{1'b1}})
|
begin
|
begin
|
req_ack <= 1'b0;
|
req_ack <= 1'b0;
|
|
req_init <= 1'b0;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
// Increment flush line address
|
// Increment flush line address
|
req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] <=
|
req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] <=
|
Line 635... |
Line 649... |
begin
|
begin
|
cache_wr <= 4'b0;
|
cache_wr <= 4'b0;
|
|
|
case (state)
|
case (state)
|
//-----------------------------------------
|
//-----------------------------------------
|
// WRITE - Wait for write-thru to complete
|
// IDLE
|
//-----------------------------------------
|
//-----------------------------------------
|
STATE_WRITE :
|
STATE_IDLE:
|
begin
|
begin
|
// Cache hit
|
// Write (cacheable)
|
if (valid & addr_hit)
|
if (stb_i & we_i & cacheable & ~(flush_i | req_flush))
|
begin
|
begin
|
// Update line already in cache
|
// Early write which is gated on line match
|
cache_data_w <= req_data;
|
cache_data_w <= data_i;
|
cache_wr <= req_wr;
|
cache_wr <= sel_i;
|
end
|
end
|
end
|
end
|
//-----------------------------------------
|
//-----------------------------------------
|
// UPDATE - Update fetched cache line
|
// UPDATE - Update fetched cache line
|
//-----------------------------------------
|
//-----------------------------------------
|
Line 713... |
Line 727... |
// Perform write single
|
// Perform write single
|
wr_single <= sel_i;
|
wr_single <= sel_i;
|
end
|
end
|
end
|
end
|
//-----------------------------------------
|
//-----------------------------------------
|
// WRITE - Wait for write-thru to complete
|
// WRITE
|
//-----------------------------------------
|
//-----------------------------------------
|
STATE_WRITE :
|
STATE_WRITE :
|
begin
|
begin
|
// Cache hit
|
// Cache hit
|
if (valid & addr_hit)
|
if (valid & addr_hit)
|
Line 947... |
Line 961... |
(
|
(
|
.aclk_i(clk_i),
|
.aclk_i(clk_i),
|
.aadr_i(cache_address),
|
.aadr_i(cache_address),
|
.adat_o(cache_data_r[7:0]),
|
.adat_o(cache_data_r[7:0]),
|
.adat_i(cache_data_w[7:0]),
|
.adat_i(cache_data_w[7:0]),
|
.awr_i(cache_wr[0]),
|
.awr_i(cache_wr[0] & cache_wr_enable),
|
|
|
.bclk_i(clk_i),
|
.bclk_i(clk_i),
|
.badr_i(cache_update_addr[CACHE_DWIDTH+2-1:2]),
|
.badr_i(cache_update_addr[CACHE_DWIDTH+2-1:2]),
|
.bdat_o(cache_update_data_r[7:0]),
|
.bdat_o(cache_update_data_r[7:0]),
|
.bdat_i(cache_update_data_w[7:0]),
|
.bdat_i(cache_update_data_w[7:0]),
|
Line 967... |
Line 981... |
(
|
(
|
.aclk_i(clk_i),
|
.aclk_i(clk_i),
|
.aadr_i(cache_address),
|
.aadr_i(cache_address),
|
.adat_o(cache_data_r[15:8]),
|
.adat_o(cache_data_r[15:8]),
|
.adat_i(cache_data_w[15:8]),
|
.adat_i(cache_data_w[15:8]),
|
.awr_i(cache_wr[1]),
|
.awr_i(cache_wr[1] & cache_wr_enable),
|
|
|
.bclk_i(clk_i),
|
.bclk_i(clk_i),
|
.badr_i(cache_update_addr[CACHE_DWIDTH+2-1:2]),
|
.badr_i(cache_update_addr[CACHE_DWIDTH+2-1:2]),
|
.bdat_o(cache_update_data_r[15:8]),
|
.bdat_o(cache_update_data_r[15:8]),
|
.bdat_i(cache_update_data_w[15:8]),
|
.bdat_i(cache_update_data_w[15:8]),
|
Line 987... |
Line 1001... |
(
|
(
|
.aclk_i(clk_i),
|
.aclk_i(clk_i),
|
.aadr_i(cache_address),
|
.aadr_i(cache_address),
|
.adat_o(cache_data_r[23:16]),
|
.adat_o(cache_data_r[23:16]),
|
.adat_i(cache_data_w[23:16]),
|
.adat_i(cache_data_w[23:16]),
|
.awr_i(cache_wr[2]),
|
.awr_i(cache_wr[2] & cache_wr_enable),
|
|
|
.bclk_i(clk_i),
|
.bclk_i(clk_i),
|
.badr_i(cache_update_addr[CACHE_DWIDTH+2-1:2]),
|
.badr_i(cache_update_addr[CACHE_DWIDTH+2-1:2]),
|
.bdat_o(cache_update_data_r[23:16]),
|
.bdat_o(cache_update_data_r[23:16]),
|
.bdat_i(cache_update_data_w[23:16]),
|
.bdat_i(cache_update_data_w[23:16]),
|
Line 1007... |
Line 1021... |
(
|
(
|
.aclk_i(clk_i),
|
.aclk_i(clk_i),
|
.aadr_i(cache_address),
|
.aadr_i(cache_address),
|
.adat_o(cache_data_r[31:24]),
|
.adat_o(cache_data_r[31:24]),
|
.adat_i(cache_data_w[31:24]),
|
.adat_i(cache_data_w[31:24]),
|
.awr_i(cache_wr[3]),
|
.awr_i(cache_wr[3] & cache_wr_enable),
|
|
|
.bclk_i(clk_i),
|
.bclk_i(clk_i),
|
.badr_i(cache_update_addr[CACHE_DWIDTH+2-1:2]),
|
.badr_i(cache_update_addr[CACHE_DWIDTH+2-1:2]),
|
.bdat_o(cache_update_data_r[31:24]),
|
.bdat_o(cache_update_data_r[31:24]),
|
.bdat_i(cache_update_data_w[31:24]),
|
.bdat_i(cache_update_data_w[31:24]),
|