URL
https://opencores.org/ocsvn/altor32/altor32/trunk
Subversion Repositories altor32
Compare Revisions
- This comparison shows the changes necessary to convert path
/altor32/trunk/rtl/cpu
- from Rev 31 to Rev 32
- ↔ Reverse comparison
Rev 31 → Rev 32
/altor32_dcache.v
49,9 → 49,10
input [31:0] address_i /*verilator public*/, |
output [31:0] data_o /*verilator public*/, |
input [31:0] data_i /*verilator public*/, |
input rd_i /*verilator public*/, |
input [3:0] wr_i /*verilator public*/, |
output accept_o /*verilator public*/, |
input we_i /*verilator public*/, |
input stb_i /*verilator public*/, |
input [3:0] sel_i /*verilator public*/, |
output stall_o /*verilator public*/, |
output ack_o /*verilator public*/, |
|
// Output (Memory) |
58,10 → 59,12
output [31:0] mem_addr_o /*verilator public*/, |
input [31:0] mem_data_i /*verilator public*/, |
output [31:0] mem_data_o /*verilator public*/, |
output mem_burst_o /*verilator public*/, |
output mem_rd_o /*verilator public*/, |
output [3:0] mem_wr_o /*verilator public*/, |
input mem_accept_i/*verilator public*/, |
output [2:0] mem_cti_o /*verilator public*/, |
output mem_cyc_o /*verilator public*/, |
output mem_stb_o /*verilator public*/, |
output mem_we_o /*verilator public*/, |
output [3:0] mem_sel_o /*verilator public*/, |
input mem_stall_i/*verilator public*/, |
input mem_ack_i/*verilator public*/ |
); |
|
119,15 → 122,15
reg evict; |
wire done; |
|
reg [31:0] data_w; |
wire [31:0] data_r; |
reg data_rd; |
reg [3:0] data_wr; |
reg rd_single; |
reg [3:0] wr_single; |
|
reg req_rd; |
reg [3:0] req_wr; |
reg req_ack; |
reg [31:0] req_address; |
reg [31:0] req_data; |
|
reg req_flush; |
reg flush_single; |
157,9 → 160,8
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 accept_o = (state == STATE_IDLE); |
assign stall_o = (state != STATE_IDLE) | req_flush; |
|
|
wire valid = tag_data_out[CACHE_TAG_VALID_BIT]; |
wire dirty = tag_data_out[CACHE_TAG_DIRTY_BIT]; |
|
166,8 → 168,11
// Access is cacheable? |
wire cacheable = ~muxed_address[ADDR_NO_CACHE_BIT] & ~muxed_address[ADDR_CACHE_BYPASS_BIT]; |
|
// Address matches cache tag |
wire addr_hit = (req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] == tag_data_out[13:0]); |
|
// Cache hit? |
wire hit = cacheable & valid & (muxed_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] == tag_data_out[13:0]) & (state == STATE_CHECK); |
wire hit = cacheable & valid & addr_hit & (state == STATE_CHECK); |
|
assign ack_o = ack | hit; |
|
175,43 → 180,514
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}}; |
|
|
//----------------------------------------------------------------- |
// Control logic |
// Next State Logic |
//----------------------------------------------------------------- |
reg [3:0] next_state_r; |
always @ * |
begin |
next_state_r = state; |
|
case (state) |
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
// Cache flush request |
if (flush_i | req_flush) |
next_state_r = STATE_FLUSH2; |
// Read (uncacheable) |
else if (stb_i & ~we_i & ~cacheable) |
next_state_r = STATE_SINGLE; |
// Read (cacheable) |
else if (stb_i & ~we_i) |
next_state_r = STATE_CHECK; |
// Write (uncacheable) |
else if (stb_i & we_i & ~cacheable) |
next_state_r = STATE_SINGLE; |
// Write (cacheable) |
else if (stb_i & we_i) |
next_state_r = STATE_WRITE; |
end |
//----------------------------------------- |
// WRITE - Wait for write-thru to complete |
//----------------------------------------- |
STATE_WRITE : |
begin |
// Cache hit |
if (valid & addr_hit) |
next_state_r = STATE_WAIT2; |
// Cache dirty |
else if (valid & dirty) |
next_state_r = STATE_EVICTING; |
// Cache miss |
else |
next_state_r = STATE_UPDATE; |
end |
//----------------------------------------- |
// EVICTING - Evicting cache line |
//----------------------------------------- |
STATE_EVICTING: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Evict for read? |
if (req_rd) |
next_state_r = STATE_FETCH; |
// Evict for write |
else |
next_state_r = STATE_UPDATE; |
end |
end |
//----------------------------------------- |
// UPDATE - Update fetched cache line |
//----------------------------------------- |
STATE_UPDATE: |
begin |
// Data ready from memory? |
if (done) |
next_state_r = STATE_WAIT2; |
end |
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache hit |
if (valid & addr_hit) |
next_state_r = STATE_IDLE; |
// Cache dirty |
else if (valid & dirty) |
next_state_r = STATE_EVICTING; |
// Cache miss |
else |
next_state_r = STATE_FETCH; |
end |
//----------------------------------------- |
// FETCH_SINGLE - Single access to memory |
//----------------------------------------- |
STATE_SINGLE: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Single WRITE? |
if (~req_rd) |
next_state_r = STATE_SINGLE_READY; |
// Dirty? Write back |
else if (valid & dirty & addr_hit) |
next_state_r = STATE_FLUSH4; |
// Valid line, invalidate |
else if (valid & addr_hit) |
next_state_r = STATE_SINGLE_READY; |
else |
next_state_r = STATE_SINGLE_READY; |
end |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Cache line filled? |
if (done) |
next_state_r = STATE_WAIT; |
end |
//----------------------------------------- |
// WAIT - Wait cycle |
//----------------------------------------- |
STATE_WAIT : |
begin |
// Allow extra wait state to handle write & read collision |
next_state_r = STATE_WAIT2; |
end |
//----------------------------------------- |
// WAIT2 - Wait cycle |
//----------------------------------------- |
STATE_WAIT2 : |
begin |
next_state_r = STATE_IDLE; |
end |
//----------------------------------------- |
// SINGLE_READY - Uncached access ready |
//----------------------------------------- |
STATE_SINGLE_READY : |
begin |
// Allow extra wait state to handle write & read collision |
next_state_r = STATE_IDLE; |
end |
//----------------------------------------- |
// FLUSHx - Flush dirty lines & invalidate |
//----------------------------------------- |
STATE_FLUSH1 : |
begin |
if (req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] == {CACHE_LINE_ADDR_WIDTH{1'b1}}) |
next_state_r = STATE_WAIT; |
else |
next_state_r = STATE_FLUSH2; |
end |
//----------------------------------------- |
// FLUSH2 - Wait state |
//----------------------------------------- |
STATE_FLUSH2 : |
begin |
// Allow a cycle to read line state |
next_state_r = STATE_FLUSH3; |
end |
//----------------------------------------- |
// FLUSH3 - Check if line dirty & flush |
//----------------------------------------- |
STATE_FLUSH3 : |
begin |
// Dirty line? Evict line first |
if (dirty) |
next_state_r = STATE_FLUSH4; |
// Not dirty? Just invalidate |
else |
begin |
if (flush_single) |
next_state_r = STATE_WAIT; |
else |
next_state_r = STATE_FLUSH1; |
end |
end |
//----------------------------------------- |
// FLUSH4 - Wait for line flush to complete |
//----------------------------------------- |
STATE_FLUSH4 : |
begin |
// Cache line filled? |
if (done) |
begin |
if (flush_single) |
next_state_r = STATE_SINGLE_READY; |
else |
next_state_r = STATE_FLUSH1; |
end |
end |
|
default: |
; |
endcase |
end |
|
// Update state |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
state <= STATE_IDLE; |
else |
state <= next_state_r; |
end |
|
//----------------------------------------------------------------- |
// Tag Write |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
data_w <= 32'h00000000; |
data_wr <= 4'h0; |
data_rd <= 1'b0; |
tag_data_in <= 16'b0; |
tag_wr <= 1'b0; |
end |
else |
begin |
tag_wr <= 1'b0; |
|
case (state) |
//----------------------------------------- |
// WRITE - Wait for write-thru to complete |
//----------------------------------------- |
STATE_WRITE : |
begin |
// Cache hit |
if (valid & addr_hit) |
begin |
// Mark line as dirty |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b1; |
tag_wr <= 1'b1; |
end |
// Cache miss / cache line doesn't require write back |
else if (~valid | ~dirty) |
begin |
// 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_wr <= 1'b1; |
end |
end |
//----------------------------------------- |
// EVICTING - Evicting cache line |
//----------------------------------------- |
STATE_EVICTING: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Update tag memory with this new line's details |
tag_data_in <= {1'b1, 1'b0, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
end |
end |
//----------------------------------------- |
// UPDATE - Update fetched cache line |
//----------------------------------------- |
STATE_UPDATE: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Mark line as dirty |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b1; |
tag_wr <= 1'b1; |
end |
end |
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache hit |
if (valid & addr_hit) |
begin |
|
end |
// Cache miss / cache line doesn't require write back |
else if (~valid | ~dirty) |
begin |
// Update tag memory with this line's details |
tag_data_in <= {1'b1, 1'b0, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
end |
end |
//----------------------------------------- |
// FETCH_SINGLE - Single access to memory |
//----------------------------------------- |
STATE_SINGLE: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Single WRITE? |
if (~req_rd) |
begin |
// Invalidate cached version |
if (valid & addr_hit) |
begin |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
end |
end |
// Valid line (not dirty), just invalidate |
else if (valid & ~dirty & addr_hit) |
begin |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
end |
end |
end |
|
//----------------------------------------- |
// FLUSH3 - Check if line dirty & flush |
//----------------------------------------- |
STATE_FLUSH3 : |
begin |
// Not dirty? Just invalidate |
if (~dirty) |
begin |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
end |
end |
//----------------------------------------- |
// FLUSH4 - Wait for line flush to complete |
//----------------------------------------- |
STATE_FLUSH4 : |
begin |
// Cache line filled? |
if (done) |
begin |
// Invalidate line |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
end |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Register requests |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
req_address <= 32'h00000000; |
req_data <= 32'h00000000; |
req_ack <= 1'b0; |
req_wr <= 4'h0; |
req_rd <= 1'b0; |
tag_wr <= 1'b0; |
req_flush <= 1'b0; |
end |
else |
begin |
if (flush_i) |
req_flush <= 1'b1; |
|
case (state) |
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
// Cache flush request |
if (flush_i | req_flush) |
begin |
// Set to first line address |
req_address <= 32'h00000000; |
req_flush <= 1'b0; |
req_ack <= 1'b0; |
end |
// Read (uncacheable) |
else if (stb_i & ~we_i & ~cacheable) |
begin |
// Start read single from memory |
req_address <= address_i; |
req_address[ADDR_CACHE_BYPASS_BIT] <= 1'b0; |
req_rd <= 1'b1; |
req_wr <= 4'b0; |
req_ack <= 1'b1; |
end |
// Read (cacheable) |
else if (stb_i & ~we_i) |
begin |
req_address <= address_i; |
req_rd <= 1'b1; |
req_wr <= 4'b0; |
req_ack <= 1'b1; |
end |
// Write (uncacheable) |
else if (stb_i & we_i & ~cacheable) |
begin |
// Perform write single |
req_address <= address_i; |
req_address[ADDR_CACHE_BYPASS_BIT] <= 1'b0; |
req_data <= data_i; |
req_wr <= sel_i; |
req_rd <= 1'b0; |
req_ack <= 1'b1; |
end |
// Write (cacheable) |
else if (stb_i & we_i) |
begin |
req_address <= address_i; |
req_data <= data_i; |
req_wr <= sel_i; |
req_rd <= 1'b0; |
req_ack <= 1'b0; |
end |
end |
//----------------------------------------- |
// FLUSHx - Flush dirty lines & invalidate |
//----------------------------------------- |
STATE_FLUSH1 : |
begin |
if (req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] == {CACHE_LINE_ADDR_WIDTH{1'b1}}) |
begin |
req_ack <= 1'b0; |
end |
else |
begin |
// 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] + 1; |
end |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Cache Data Write |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
cache_data_w <= 32'h00000000; |
cache_wr <= 4'b0; |
end |
else |
begin |
cache_wr <= 4'b0; |
|
case (state) |
//----------------------------------------- |
// WRITE - Wait for write-thru to complete |
//----------------------------------------- |
STATE_WRITE : |
begin |
// Cache hit |
if (valid & addr_hit) |
begin |
// Update line already in cache |
cache_data_w <= req_data; |
cache_wr <= req_wr; |
end |
end |
//----------------------------------------- |
// UPDATE - Update fetched cache line |
//----------------------------------------- |
STATE_UPDATE: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Update line already in cache |
cache_data_w <= req_data; |
cache_wr <= req_wr; |
end |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Control |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
wr_single <= 4'h0; |
rd_single <= 1'b0; |
flush_single <= 1'b0; |
fill <= 1'b0; |
evict <= 1'b0; |
cache_data_w <= 32'h00000000; |
cache_wr <= 4'b0; |
ack <= 1'b0; |
state <= STATE_IDLE; |
end |
else |
begin |
ack <= 1'b0; |
tag_wr <= 1'b0; |
fill <= 1'b0; |
evict <= 1'b0; |
cache_wr <= 4'b0; |
data_wr <= 4'b0; |
data_rd <= 1'b0; |
wr_single <= 4'b0; |
rd_single <= 1'b0; |
|
if (flush_i) |
req_flush <= 1'b1; |
|
case (state) |
|
//----------------------------------------- |
218,65 → 694,25
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
begin |
// Cache flush request |
if (flush_i | req_flush) |
begin |
// Set to first line address |
flush_single<= 1'b0; |
end |
// Read (uncacheable) |
if (rd_i & ~cacheable) |
else if (stb_i & ~we_i & ~cacheable) |
begin |
// Start read single from memory |
req_address <= address_i; |
req_address[ADDR_CACHE_BYPASS_BIT] <= 1'b0; |
data_rd <= 1'b1; |
req_rd <= 1'b1; |
req_wr <= 4'b0; |
req_ack <= 1'b1; |
state <= STATE_SINGLE; |
end |
// Read (cacheable) |
else if (rd_i) |
begin |
req_address <= address_i; |
req_rd <= 1'b1; |
req_wr <= 4'b0; |
req_ack <= 1'b1; |
state <= STATE_CHECK; |
end |
rd_single <= 1'b1; |
end |
// Write (uncacheable) |
else if (wr_i != 4'b0000 & ~cacheable) |
else if (stb_i & we_i & ~cacheable) |
begin |
// Perform write single |
req_address <= address_i; |
req_address[ADDR_CACHE_BYPASS_BIT] <= 1'b0; |
data_w <= data_i; |
data_wr <= wr_i; |
req_wr <= wr_i; |
req_rd <= 1'b0; |
req_ack <= 1'b1; |
state <= STATE_SINGLE; |
end |
// Write (cacheable) |
else if (wr_i != 4'b0000) |
begin |
req_address <= address_i; |
data_w <= data_i; |
req_wr <= wr_i; |
req_rd <= 1'b0; |
req_ack <= 1'b0; |
|
// Early ACK |
ack <= 1'b1; |
|
state <= STATE_WRITE; |
end |
// Cache flush request |
else if (flush_i | req_flush) |
begin |
// Set to first line address |
req_address <= 32'h00000000; |
req_flush <= 1'b0; |
req_ack <= 1'b0; |
flush_single<= 1'b0; |
state <= STATE_FLUSH2; |
end |
wr_single <= sel_i; |
end |
end |
//----------------------------------------- |
// WRITE - Wait for write-thru to complete |
284,19 → 720,9
STATE_WRITE : |
begin |
// Cache hit |
if (valid && |
(req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] == tag_data_out[13:0])) |
if (valid & addr_hit) |
begin |
// Update line already in cache |
cache_data_w <= data_w; |
cache_wr <= req_wr; |
|
// Mark line as dirty |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b1; |
tag_wr <= 1'b1; |
|
state <= STATE_WAIT2; |
end |
// Cache dirty |
else if (valid & dirty) |
303,18 → 729,12
begin |
// Evict cache line |
evict <= 1'b1; |
state <= STATE_EVICTING; |
end |
// Cache miss |
else |
begin |
// 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_wr <= 1'b1; |
|
// Fill cache line |
fill <= 1'b1; |
state <= STATE_UPDATE; |
end |
end |
//----------------------------------------- |
325,51 → 745,19
// Data ready from memory? |
if (done) |
begin |
// Update tag memory with this new line's details |
tag_data_in <= {1'b1, 1'b0, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
|
// Fill cache line |
fill <= 1'b1; |
|
// Evict for read? |
if (req_rd) |
state <= STATE_FETCH; |
// Evict for write |
else |
state <= STATE_UPDATE; |
end |
end |
end |
//----------------------------------------- |
// UPDATE - Update fetched cache line |
//----------------------------------------- |
STATE_UPDATE: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Update line already in cache |
cache_data_w <= data_w; |
cache_wr <= req_wr; |
|
// Mark line as dirty |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b1; |
tag_wr <= 1'b1; |
|
state <= STATE_WAIT2; |
end |
end |
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache hit |
if (valid && |
(req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] == tag_data_out[13:0])) |
if (valid & addr_hit) |
begin |
state <= STATE_IDLE; |
|
end |
// Cache dirty |
else if (valid & dirty) |
376,18 → 764,12
begin |
// Evict cache line |
evict <= 1'b1; |
state <= STATE_EVICTING; |
end |
// Cache miss |
else |
begin |
// Update tag memory with this line's details |
tag_data_in <= {1'b1, 1'b0, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
|
// Fill cache line |
fill <= 1'b1; |
state <= STATE_FETCH; |
end |
end |
//----------------------------------------- |
401,95 → 783,18
// Single WRITE? |
if (~req_rd) |
begin |
state <= STATE_SINGLE_READY; |
ack <= req_ack; |
|
end |
// Dirty? Write back |
else if (valid & dirty) |
else if (valid & dirty & addr_hit) |
begin |
// Evict cache line |
evict <= 1'b1; |
flush_single<= 1'b1; |
state <= STATE_FLUSH4; |
end |
// Valid line, invalidate |
else if (valid) |
begin |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
|
state <= STATE_SINGLE_READY; |
ack <= req_ack; |
end |
else |
begin |
state <= STATE_SINGLE_READY; |
ack <= req_ack; |
end |
end |
end |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Cache line filled? |
if (done) |
state <= STATE_WAIT; |
end |
//----------------------------------------- |
// WAIT - Wait cycle |
//----------------------------------------- |
STATE_WAIT : |
begin |
// Allow extra wait state to handle write & read collision |
state <= STATE_WAIT2; |
end |
//----------------------------------------- |
// WAIT2 - Wait cycle |
//----------------------------------------- |
STATE_WAIT2 : |
begin |
state <= STATE_IDLE; |
ack <= req_ack; |
end |
//----------------------------------------- |
// SINGLE_READY - Uncached access ready |
//----------------------------------------- |
STATE_SINGLE_READY : |
begin |
// Allow extra wait state to handle write & read collision |
state <= STATE_IDLE; |
end |
//----------------------------------------- |
// FLUSHx - Flush dirty lines & invalidate |
//----------------------------------------- |
STATE_FLUSH1 : |
begin |
if (req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] == {CACHE_LINE_ADDR_WIDTH{1'b1}}) |
begin |
req_ack <= 1'b0; |
state <= STATE_WAIT; |
end |
else |
begin |
// 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] + 1; |
|
state <= STATE_FLUSH2; |
end |
end |
//----------------------------------------- |
// FLUSH2 - Wait state |
//----------------------------------------- |
STATE_FLUSH2 : |
begin |
// Allow a cycle to read line state |
state <= STATE_FLUSH3; |
end |
//----------------------------------------- |
// FLUSH3 - Check if line dirty & flush |
//----------------------------------------- |
STATE_FLUSH3 : |
499,47 → 804,77
begin |
// Evict cache line |
evict <= 1'b1; |
state <= STATE_FLUSH4; |
end |
// Not dirty? Just invalidate |
else |
begin |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
end |
default: |
; |
endcase |
end |
end |
|
if (flush_single) |
state <= STATE_WAIT; |
else |
state <= STATE_FLUSH1; |
end |
end |
//----------------------------------------- |
// FLUSH4 - Wait for line flush to complete |
//----------------------------------------- |
STATE_FLUSH4 : |
//----------------------------------------------------------------- |
// ACK |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
ack <= 1'b0; |
else |
begin |
ack <= 1'b0; |
|
case (state) |
|
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
// Write (cacheable), early acknowledge |
if (~(flush_i | req_flush) & stb_i & we_i & cacheable) |
ack <= 1'b1; |
end |
//----------------------------------------- |
// FETCH_SINGLE - Single access to memory |
//----------------------------------------- |
STATE_SINGLE: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Cache line filled? |
if (done) |
// Single WRITE? |
if (~req_rd) |
ack <= req_ack; |
// Dirty? Write back |
else if (valid & dirty & addr_hit) |
begin |
// Invalidate line |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
|
if (flush_single) |
begin |
state <= STATE_SINGLE_READY; |
ack <= req_ack; |
end |
else |
state <= STATE_FLUSH1; |
end |
end |
default: |
; |
endcase |
// Valid line, invalidate |
else if (valid & addr_hit) |
ack <= req_ack; |
else |
ack <= req_ack; |
end |
end |
//----------------------------------------- |
// WAIT2 - Wait cycle |
//----------------------------------------- |
STATE_WAIT2 : |
begin |
ack <= req_ack; |
end |
//----------------------------------------- |
// FLUSH4 - Wait for line flush to complete |
//----------------------------------------- |
STATE_FLUSH4 : |
begin |
if (done & flush_single) |
ack <= req_ack; |
end |
default: |
; |
endcase |
end |
end |
|
559,13 → 894,13
|
// Cache interface |
.address_i(muxed_address), |
.data_i(data_w), |
.data_i(req_data), |
.data_o(data_r), |
.fill_i(fill), |
.evict_i(evict), |
.evict_addr_i(line_address), |
.rd_single_i(data_rd), |
.wr_single_i(data_wr), |
.rd_single_i(rd_single), |
.wr_single_i(wr_single), |
.done_o(done), |
|
// Cache memory (fill/evict) |
578,10 → 913,12
.mem_addr_o(mem_addr_o), |
.mem_data_i(mem_data_i), |
.mem_data_o(mem_data_o), |
.mem_burst_o(mem_burst_o), |
.mem_rd_o(mem_rd_o), |
.mem_wr_o(mem_wr_o), |
.mem_accept_i(mem_accept_i), |
.mem_cti_o(mem_cti_o), |
.mem_cyc_o(mem_cyc_o), |
.mem_stb_o(mem_stb_o), |
.mem_we_o(mem_we_o), |
.mem_sel_o(mem_sel_o), |
.mem_stall_i(mem_stall_i), |
.mem_ack_i(mem_ack_i) |
); |
|
/altor32_noicache.v
54,13 → 54,14
output [31:0] instruction_o /*verilator public*/, |
output valid_o /*verilator public*/, |
|
// Memory interface (slave) |
output reg [31:0] mem_addr_o /*verilator public*/, |
input [31:0] mem_data_i /*verilator public*/, |
output reg mem_burst_o /*verilator public*/, |
output reg mem_rd_o /*verilator public*/, |
input mem_accept_i/*verilator public*/, |
input mem_ack_i/*verilator public*/ |
// Memory interface |
output reg [31:0] wbm_addr_o /*verilator public*/, |
input [31:0] wbm_dat_i /*verilator public*/, |
output [2:0] wbm_cti_o /*verilator public*/, |
output reg wbm_cyc_o /*verilator public*/, |
output reg wbm_stb_o /*verilator public*/, |
input wbm_stall_i/*verilator public*/, |
input wbm_ack_i/*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
70,11 → 71,13
// Current state |
parameter STATE_CHECK = 0; |
parameter STATE_FETCH = 1; |
reg [1:0] state; |
reg state; |
|
assign valid_o = mem_ack_i; |
assign instruction_o = mem_data_i; |
reg ignore_resp; |
|
assign valid_o = wbm_ack_i & ~ignore_resp & ~rd_i; |
assign instruction_o = wbm_dat_i; |
|
//----------------------------------------------------------------- |
// Control logic |
//----------------------------------------------------------------- |
82,16 → 85,17
begin |
if (rst_i == 1'b1) |
begin |
mem_addr_o <= 32'h00000000; |
mem_rd_o <= 1'b0; |
mem_burst_o <= 1'b0; |
wbm_addr_o <= 32'h00000000; |
wbm_stb_o <= 1'b0; |
wbm_cyc_o <= 1'b0; |
ignore_resp <= 1'b0; |
state <= STATE_CHECK; |
end |
else |
begin |
|
if (mem_accept_i) |
mem_rd_o <= 1'b0; |
if (~wbm_stall_i) |
wbm_stb_o <= 1'b0; |
|
case (state) |
|
101,9 → 105,10
STATE_CHECK : |
begin |
// Start fetch from memory |
mem_addr_o <= pc_i; |
mem_rd_o <= 1'b1; |
mem_burst_o <= 1'b0; |
wbm_addr_o <= pc_i; |
wbm_stb_o <= 1'b1; |
wbm_cyc_o <= 1'b1; |
ignore_resp <= 1'b0; |
state <= STATE_FETCH; |
end |
//----------------------------------------- |
111,9 → 116,16
//----------------------------------------- |
STATE_FETCH : |
begin |
// Read whilst waiting for previous response? |
if (rd_i) |
ignore_resp <= 1'b1; |
|
// Data ready from memory? |
if (mem_ack_i) |
state <= STATE_CHECK; |
if (wbm_ack_i) |
begin |
wbm_cyc_o <= 1'b0; |
state <= STATE_CHECK; |
end |
end |
|
default: |
122,5 → 134,7
end |
end |
|
assign wbm_cti_o = 3'b111; |
|
endmodule |
|
/altor32_icache.v
43,7 → 43,7
//----------------------------------------------------------------- |
// Module - Instruction Cache |
//----------------------------------------------------------------- |
module altor32_icache |
module altor32_icache |
( |
input clk_i /*verilator public*/, |
input rst_i /*verilator public*/, |
59,13 → 59,14
output miss_o /*verilator public*/, |
output busy_o /*verilator public*/, |
|
// Memory interface (slave) |
output reg [31:0] mem_addr_o /*verilator public*/, |
input [31:0] mem_data_i /*verilator public*/, |
output reg mem_burst_o /*verilator public*/, |
output reg mem_rd_o /*verilator public*/, |
input mem_accept_i/*verilator public*/, |
input mem_ack_i/*verilator public*/ |
// Memory interface |
output reg [31:0] wbm_addr_o /*verilator public*/, |
input [31:0] wbm_dat_i /*verilator public*/, |
output reg [2:0] wbm_cti_o /*verilator public*/, |
output reg wbm_cyc_o /*verilator public*/, |
output reg wbm_stb_o /*verilator public*/, |
input wbm_stall_i/*verilator public*/, |
input wbm_ack_i/*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
100,28 → 101,36
//----------------------------------------------------------------- |
// Registers / Wires |
//----------------------------------------------------------------- |
|
// Tag read / write data |
wire [CACHE_TAG_WIDTH-1:0] tag_data_out; |
reg [CACHE_TAG_WIDTH-1:0] tag_data_in; |
reg tag_wr; |
|
// Tag address |
wire [CACHE_LINE_ADDR_WIDTH-1:0] tag_entry; |
|
// Data memory read / write |
wire [CACHE_DWIDTH-1:0] cache_address_rd; |
|
reg [CACHE_DWIDTH-1:0] cache_address_wr; |
reg [31:0] cache_data_w; |
reg [31:0] cache_data_in; |
reg cache_wr; |
|
reg [CACHE_LINE_SIZE_WIDTH-3:0] fetch_word; |
// Word currently being fetched within a line |
reg [CACHE_LINE_SIZE_WIDTH-3:0] mem_fetch_word; |
reg [CACHE_LINE_SIZE_WIDTH-3:0] mem_resp_idx; |
|
// Current / Miss PC |
reg [31:0] last_pc; |
reg [31:0] miss_pc; |
|
reg initial_fetch; |
// Flush state |
reg flush_req; |
|
reg [CACHE_LINE_ADDR_WIDTH-1:0] flush_addr; |
reg flush_wr; |
|
// Other state |
reg initial_fetch; |
reg read_while_busy; |
|
// Current state |
130,38 → 139,259
parameter STATE_WAIT = 2; |
parameter STATE_WAIT2 = 3; |
parameter STATE_FLUSH = 4; |
reg [3:0] state; |
reg [3:0] state; |
|
assign tag_entry = (state != STATE_CHECK) ? miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] : pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH]; |
assign cache_address_rd = pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:2]; |
// Tag address from input PC or flopped version of it |
assign tag_entry = (state != STATE_CHECK) ? |
miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] : |
pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH]; |
|
assign miss_o = (!tag_data_out[CACHE_TAG_VALID_BIT] || (last_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] != tag_data_out[14:0])) ? 1'b1: 1'b0; |
// Cache read address |
assign cache_address_rd = pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:2]; |
|
// Cache miss output if requested PC is not in the tag memory |
assign miss_o = (!tag_data_out[CACHE_TAG_VALID_BIT] || |
(last_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] != tag_data_out[14:0])) ? 1'b1: 1'b0; |
|
// Cache output valid |
assign valid_o = !miss_o && !busy_o; |
|
// Stall the CPU if cache state machine is not idle! |
assign busy_o = (state == STATE_CHECK & ~read_while_busy) ? 1'b0 : 1'b1; |
|
// Final word to fetch from memory |
wire mem_fetch_final_word = (mem_fetch_word == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}); |
|
// Flushing: Last line to flush |
wire flush_final_line = (flush_addr == {CACHE_LINE_ADDR_WIDTH{1'b0}}); |
|
// Is this a cache miss? |
wire cache_miss = (miss_o && // Tag lookup failed |
!initial_fetch && // NOT initial fetch after reset |
!rd_i && // NOT new read request cycle |
!read_while_busy && // NOT pending read whilst busy |
!flush_req && // NOT flush request |
!invalidate_i); |
|
//----------------------------------------------------------------- |
// Control logic |
// Next State Logic |
//----------------------------------------------------------------- |
reg [CACHE_LINE_SIZE_WIDTH-3:0] v_line_word; |
reg [3:0] next_state_r; |
always @ * |
begin |
next_state_r = state; |
|
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache flush request pending? |
if (flush_req || invalidate_i) |
next_state_r = STATE_FLUSH; |
// Cache miss (& new read request not pending) |
else if (cache_miss) |
next_state_r = STATE_FETCH; |
// Cache hit (or new read request) |
else |
next_state_r = STATE_CHECK; |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Line fetch complete? |
if (mem_resp_idx == {CACHE_LINE_SIZE_WIDTH-2{1'b1}} && wbm_ack_i) |
next_state_r = STATE_WAIT; |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
if (flush_final_line) |
next_state_r = STATE_FETCH; |
else |
next_state_r = STATE_FLUSH; |
end |
//----------------------------------------- |
// WAIT - Wait cycle |
//----------------------------------------- |
STATE_WAIT : |
// Allow extra wait state to handle write & read collision |
next_state_r = STATE_WAIT2; |
//----------------------------------------- |
// WAIT2 - Wait cycle |
//----------------------------------------- |
STATE_WAIT2 : |
next_state_r = STATE_CHECK; |
default: |
; |
endcase |
end |
|
// Update state |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
state <= STATE_CHECK; |
else |
state <= next_state_r; |
end |
|
|
//----------------------------------------------------------------- |
// Check for cache misses |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
mem_addr_o <= 32'h00000000; |
mem_rd_o <= 1'b0; |
mem_burst_o <= 1'b0; |
tag_wr <= 1'b0; |
cache_address_wr<= {CACHE_DWIDTH{1'b0}}; |
cache_data_w <= 32'h00000000; |
cache_wr <= 1'b0; |
miss_pc <= BOOT_VECTOR + `VECTOR_RESET; |
last_pc <= 32'h00000000; |
state <= STATE_CHECK; |
last_pc <= 32'h00000000; |
initial_fetch <= 1'b1; |
read_while_busy <= 1'b0; |
end |
else |
begin |
initial_fetch <= 1'b0; |
last_pc <= pc_i; |
|
// New request whilst cache busy? |
if (rd_i) |
read_while_busy <= 1'b1; |
|
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache miss (& new read request not pending) |
if (cache_miss) |
begin |
read_while_busy <= 1'b0; |
|
`ifdef CONF_CORE_DEBUG |
$display("Fetch: Cache miss at 0x%x (last=%x, current=%x)", miss_pc, last_pc, pc_i); |
`endif |
end |
// Cache hit (or new read request) |
else |
begin |
`ifdef CONF_CORE_DEBUG |
$display("Fetch: Cache hit at PC=%x (current=%x)", last_pc, pc_i); |
if (read_while_busy) |
$display("Fetch: Read request whilst busy PC=%x (current=%x)", last_pc, pc_i); |
`endif |
// Store fetch PC |
miss_pc <= pc_i; |
read_while_busy <= 1'b0; |
end |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
// Last line, clear pending reads whilst busy |
if (flush_final_line) |
read_while_busy <= 1'b0; |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Cache Tag Write |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
tag_data_in <= {CACHE_TAG_WIDTH{1'b0}}; |
tag_wr <= 1'b0; |
end |
else |
begin |
tag_wr <= 1'b0; |
|
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache miss (& new read request not pending) |
if (cache_miss) |
begin |
// Update tag memory with this line's details |
tag_data_in <= {1'b1, miss_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
end |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
if (flush_final_line) |
begin |
// Update tag memory with this line's details |
tag_data_in <= {1'b1, pc_i[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
end |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Cache Data Write |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
cache_address_wr<= {CACHE_DWIDTH{1'b0}}; |
cache_data_in <= 32'h00000000; |
cache_wr <= 1'b0; |
end |
else |
begin |
cache_wr <= 1'b0; |
|
// FETCH - Fetch row from memory |
if (state == STATE_FETCH) |
begin |
// Data ready from memory? |
if (wbm_ack_i) |
begin |
// Write data into cache |
cache_address_wr <= {miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH], mem_resp_idx}; |
cache_data_in <= wbm_dat_i; |
cache_wr <= 1'b1; |
end |
end |
end |
end |
|
//----------------------------------------------------------------- |
// Flush Logic |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
flush_addr <= {CACHE_LINE_ADDR_WIDTH{1'b0}}; |
flush_wr <= 1'b0; |
flush_req <= 1'b0; |
168,176 → 398,236
end |
else |
begin |
|
if (mem_accept_i) |
mem_rd_o <= 1'b0; |
tag_wr <= 1'b0; |
cache_wr <= 1'b0; |
initial_fetch <= 1'b0; |
flush_wr <= 1'b0; |
last_pc <= pc_i; |
|
// Latch invalidate request even if can't be actioned now... |
if (invalidate_i) |
flush_req <= 1'b1; |
|
// New request whilst cache busy? |
if (rd_i) |
read_while_busy <= 1'b1; |
|
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache flush request pending? |
if (flush_req || invalidate_i) |
begin |
// Cache flush request pending? |
if (flush_req || invalidate_i) |
begin |
flush_req <= 1'b0; |
flush_addr <= {CACHE_LINE_ADDR_WIDTH{1'b1}}; |
flush_wr <= 1'b1; |
state <= STATE_FLUSH; |
flush_req <= 1'b0; |
flush_addr <= {CACHE_LINE_ADDR_WIDTH{1'b1}}; |
flush_wr <= 1'b1; |
|
`ifdef CONF_CORE_DEBUG |
$display("Fetch: Cache flush request"); |
`endif |
end |
// Cache miss (& new read request not pending) |
else if ((miss_o && !initial_fetch) && !rd_i && !read_while_busy) |
begin |
read_while_busy <= 1'b0; |
$display("Fetch: Cache flush request"); |
`endif |
end |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
if (~flush_final_line) |
begin |
flush_addr <= flush_addr - 1; |
flush_wr <= 1'b1; |
end |
end |
default: |
; |
endcase |
end |
end |
|
fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
//----------------------------------------------------------------- |
// External Mem Access |
//----------------------------------------------------------------- |
|
`ifdef CONF_CORE_DEBUG |
$display("Fetch: Cache miss at 0x%x (last=%x, current=%x)", miss_pc, last_pc, pc_i); |
`endif |
|
// Start fetch from memory |
mem_addr_o <= {miss_pc[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}}; |
mem_rd_o <= 1'b1; |
mem_burst_o <= 1'b1; |
state <= STATE_FETCH; |
|
// Update tag memory with this line's details |
tag_data_in <= {1'b1, miss_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
end |
// Cache hit (or new read request) |
else |
begin |
`ifdef CONF_CORE_DEBUG |
$display("Fetch: Cache hit at PC=%x (current=%x)", last_pc, pc_i); |
if (read_while_busy) |
$display("Fetch: Read request whilst busy PC=%x (current=%x)", last_pc, pc_i); |
`endif |
// Next fetch address |
wire [CACHE_LINE_SIZE_WIDTH-3:0] mem_next_word = mem_fetch_word + 1; |
|
// Store fetch PC |
miss_pc <= pc_i; |
state <= STATE_CHECK; |
read_while_busy <= 1'b0; |
end |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
// Last word to fetch |
wire mem_resp_idx_word = (mem_fetch_word == ({CACHE_LINE_WORDS_IDX_MAX{1'b1}}-1)); |
|
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
wbm_addr_o <= 32'h00000000; |
wbm_cti_o <= 3'b0; |
wbm_stb_o <= 1'b0; |
|
mem_fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
end |
else |
begin |
if (~wbm_stall_i) |
wbm_stb_o <= 1'b0; |
|
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache miss (& new read request not pending) |
if (cache_miss) |
begin |
// Data ready from memory? |
if (mem_ack_i) |
begin |
// Write data into cache |
cache_address_wr<= {miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH], fetch_word}; |
cache_data_w <= mem_data_i; |
cache_wr <= 1'b1; |
// Start fetch from memory |
wbm_addr_o <= {miss_pc[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}}; |
|
// Line fetch complete? |
if (fetch_word == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
begin |
state <= STATE_WAIT; |
end |
// Fetch next word for line |
else |
begin |
v_line_word = fetch_word + 1'b1; |
fetch_word <= v_line_word; |
|
mem_addr_o <= {mem_addr_o[31:CACHE_LINE_SIZE_WIDTH], v_line_word, 2'b00}; |
mem_rd_o <= 1'b1; |
|
if (fetch_word == ({CACHE_LINE_WORDS_IDX_MAX{1'b1}}-1)) |
begin |
mem_burst_o <= 1'b0; |
end |
end |
end |
// Incrementing linear burst |
wbm_cti_o <= 3'b010; |
|
// Start of cycle |
wbm_stb_o <= 1'b1; |
|
mem_fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
if (flush_addr == {CACHE_LINE_ADDR_WIDTH{1'b0}}) |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Command accepted |
if (~wbm_stall_i) |
begin |
// Fetch next word for line |
if (!mem_fetch_final_word) |
begin |
// Fetch current PC line again |
mem_addr_o <= {pc_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}}; |
mem_rd_o <= 1'b1; |
mem_burst_o <= 1'b1; |
state <= STATE_FETCH; |
|
// Update tag memory with this line's details |
tag_data_in <= {1'b1, pc_i[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
wbm_addr_o <= {wbm_addr_o[31:CACHE_LINE_SIZE_WIDTH], mem_next_word, 2'b00}; |
|
// Final word to read? |
if (mem_resp_idx_word) |
wbm_cti_o <= 3'b111; |
|
// Start of line |
fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
mem_fetch_word <= mem_next_word; |
|
// Clear pending reads whilst busy |
read_while_busy <= 1'b0; |
end |
else |
begin |
flush_addr <= flush_addr - 1; |
flush_wr <= 1'b1; |
state <= STATE_FLUSH; |
end |
end |
//----------------------------------------- |
// WAIT - Wait cycle |
//----------------------------------------- |
STATE_WAIT : |
begin |
// Allow extra wait state to handle write & read collision |
state <= STATE_WAIT2; |
end |
//----------------------------------------- |
// WAIT2 - Wait cycle |
//----------------------------------------- |
STATE_WAIT2 : |
begin |
`ifdef CONF_CORE_DEBUG |
$display("Fetch: Filled line containing PC=%x", miss_pc); |
`endif |
state <= STATE_CHECK; |
end |
|
|
default: |
; |
endcase |
// Still fetching... |
wbm_stb_o <= 1'b1; |
end |
end |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
// Fetch current PC line again |
if (flush_final_line) |
begin |
wbm_addr_o <= {pc_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}}; |
|
// Incrementing linear burst |
wbm_cti_o <= 3'b010; |
|
// Start of cycle |
wbm_stb_o <= 1'b1; |
|
// Start of line |
mem_fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
end |
end |
default: |
; |
endcase |
end |
end |
|
// Stall the CPU if cache state machine is not idle! |
assign busy_o = (state == STATE_CHECK & ~read_while_busy) ? 1'b0 : 1'b1; |
//----------------------------------------------------------------- |
// CYC_O |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
wbm_cyc_o <= 1'b0; |
else |
begin |
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache miss (& new read request not pending) |
if (cache_miss) |
wbm_cyc_o <= 1'b1; |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
// Fetch current PC line again |
if (flush_final_line) |
wbm_cyc_o <= 1'b1; |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Last response? |
if (wbm_ack_i && (mem_resp_idx == {CACHE_LINE_SIZE_WIDTH-2{1'b1}})) |
wbm_cyc_o <= 1'b0; |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Instantiation |
// Memory response counter |
//----------------------------------------------------------------- |
|
// Tag memory |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
mem_resp_idx <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
else |
begin |
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache miss (& new read request not pending) |
if (cache_miss) |
mem_resp_idx <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
// Fetch current PC line again |
if (flush_final_line) |
mem_resp_idx <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Response |
if (wbm_ack_i) |
mem_resp_idx <= mem_resp_idx + 1; |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Tag memory |
//----------------------------------------------------------------- |
altor32_ram_dp |
#( |
.WIDTH(CACHE_TAG_WIDTH), |
345,6 → 635,7
) |
u1_tag_mem |
( |
// Tag read/write port |
.aclk_i(clk_i), |
.adat_o(tag_data_out), |
.adat_i(tag_data_in), |
351,6 → 642,7
.aadr_i(tag_entry), |
.awr_i(tag_wr), |
|
// Tag invalidate port |
.bclk_i(clk_i), |
.badr_i(flush_addr), |
.bdat_o(/*open*/), |
357,8 → 649,10
.bdat_i({CACHE_TAG_WIDTH{1'b0}}), |
.bwr_i(flush_wr) |
); |
|
|
//----------------------------------------------------------------- |
// Data memory |
//----------------------------------------------------------------- |
altor32_ram_dp |
#( |
.WIDTH(32), |
366,6 → 660,7
) |
u2_data_mem |
( |
// Data read port |
.aclk_i(clk_i), |
.aadr_i(cache_address_rd), |
.adat_o(instruction_o), |
372,10 → 667,11
.adat_i(32'h00), |
.awr_i(1'b0), |
|
// Data write port |
.bclk_i(clk_i), |
.badr_i(cache_address_wr), |
.bdat_o(/*open*/), |
.bdat_i(cache_data_w), |
.bdat_i(cache_data_in), |
.bwr_i(cache_wr) |
); |
|
/altor32.v
41,7 → 41,7
`include "altor32_defs.v" |
|
//----------------------------------------------------------------- |
// Module - AltOR32 CPU |
// Module - AltOR32 CPU (Pipelined Wishbone Interfaces) |
//----------------------------------------------------------------- |
module cpu |
( |
56,21 → 56,24
|
// Instruction memory |
output [31:0] imem_addr_o /*verilator public*/, |
output imem_rd_o /*verilator public*/, |
output imem_burst_o /*verilator public*/, |
input [31:0] imem_data_in_i /*verilator public*/, |
input imem_accept_i /*verilator public*/, |
input imem_ack_i /*verilator public*/, |
input [31:0] imem_dat_i /*verilator public*/, |
output [2:0] imem_cti_o /*verilator public*/, |
output imem_cyc_o /*verilator public*/, |
output imem_stb_o /*verilator public*/, |
input imem_stall_i/*verilator public*/, |
input imem_ack_i/*verilator public*/, |
|
// Data memory |
output [31:0] dmem_addr_o /*verilator public*/, |
output [31:0] dmem_data_out_o /*verilator public*/, |
input [31:0] dmem_data_in_i /*verilator public*/, |
output [3:0] dmem_wr_o /*verilator public*/, |
output dmem_rd_o /*verilator public*/, |
output dmem_burst_o /*verilator public*/, |
input dmem_accept_i /*verilator public*/, |
input dmem_ack_i /*verilator public*/ |
output [31:0] dmem_dat_o /*verilator public*/, |
input [31:0] dmem_dat_i /*verilator public*/, |
output [3:0] dmem_sel_o /*verilator public*/, |
output [2:0] dmem_cti_o /*verilator public*/, |
output dmem_cyc_o /*verilator public*/, |
output dmem_we_o /*verilator public*/, |
output dmem_stb_o /*verilator public*/, |
input dmem_stall_i/*verilator public*/, |
input dmem_ack_i/*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
140,10 → 143,12
wire [31:0] dcache_addr; |
wire [31:0] dcache_data_o; |
wire [31:0] dcache_data_i; |
wire [3:0] dcache_wr; |
wire dcache_rd; |
wire [3:0] dcache_sel; |
wire dcache_we; |
wire dcache_stb; |
wire dcache_cyc; |
wire dcache_ack; |
wire dcache_accept; |
wire dcache_stall; |
wire dcache_flush; |
|
//----------------------------------------------------------------- |
176,16 → 181,17
.busy_o(icache_busy), |
|
// Instruction memory |
.mem_addr_o(imem_addr_o), |
.mem_data_i(imem_data_in_i), |
.mem_burst_o(imem_burst_o), |
.mem_rd_o(imem_rd_o), |
.mem_accept_i(imem_accept_i), |
.mem_ack_i(imem_ack_i) |
.wbm_addr_o(imem_addr_o), |
.wbm_dat_i(imem_dat_i), |
.wbm_cti_o(imem_cti_o), |
.wbm_cyc_o(imem_cyc_o), |
.wbm_stb_o(imem_stb_o), |
.wbm_stall_i(imem_stall_i), |
.wbm_ack_i(imem_ack_i) |
); |
end |
else |
begin |
begin : NO_ICACHE |
// No instruction cache |
altor32_noicache |
u_icache |
200,12 → 206,13
.valid_o(icache_valid), |
|
// Instruction memory |
.mem_addr_o(imem_addr_o), |
.mem_data_i(imem_data_in_i), |
.mem_burst_o(imem_burst_o), |
.mem_rd_o(imem_rd_o), |
.mem_accept_i(imem_accept_i), |
.mem_ack_i(imem_ack_i) |
.wbm_addr_o(imem_addr_o), |
.wbm_dat_i(imem_dat_i), |
.wbm_cti_o(imem_cti_o), |
.wbm_cyc_o(imem_cyc_o), |
.wbm_stb_o(imem_stb_o), |
.wbm_stall_i(imem_stall_i), |
.wbm_ack_i(imem_ack_i) |
); |
end |
endgenerate |
246,7 → 253,7
// Register file |
generate |
if (REGISTER_FILE_TYPE == "XILINX") |
begin |
begin : REGFILE_XIL |
altor32_regfile_xil |
#( |
.SUPPORT_32REGS(SUPPORT_32REGS) |
268,7 → 275,7
); |
end |
else if (REGISTER_FILE_TYPE == "ALTERA") |
begin |
begin : REGFILE_ALT |
altor32_regfile_alt |
#( |
.SUPPORT_32REGS(SUPPORT_32REGS) |
290,7 → 297,7
); |
end |
else |
begin |
begin : REGFILE_SIM |
altor32_regfile_sim |
#( |
.SUPPORT_32REGS(SUPPORT_32REGS) |
315,7 → 322,7
|
generate |
if (ENABLE_DCACHE == "ENABLED") |
begin |
begin : DCACHE |
// Data cache |
altor32_dcache |
u_dcache |
329,34 → 336,39
.address_i({dcache_addr[31:2], 2'b00}), |
.data_o(dcache_data_i), |
.data_i(dcache_data_o), |
.wr_i(dcache_wr), |
.rd_i(dcache_rd), |
.accept_o(dcache_accept), |
.we_i(dcache_we), |
.stb_i(dcache_stb), |
.sel_i(dcache_sel), |
.stall_o(dcache_stall), |
.ack_o(dcache_ack), |
|
// Memory interface (slave) |
.mem_addr_o(dmem_addr_o), |
.mem_data_i(dmem_data_in_i), |
.mem_data_o(dmem_data_out_o), |
.mem_burst_o(dmem_burst_o), |
.mem_rd_o(dmem_rd_o), |
.mem_wr_o(dmem_wr_o), |
.mem_accept_i(dmem_accept_i), |
.mem_data_i(dmem_dat_i), |
.mem_data_o(dmem_dat_o), |
.mem_sel_o(dmem_sel_o), |
.mem_we_o(dmem_we_o), |
.mem_stb_o(dmem_stb_o), |
.mem_cyc_o(dmem_cyc_o), |
.mem_cti_o(dmem_cti_o), |
.mem_stall_i(dmem_stall_i), |
.mem_ack_i(dmem_ack_i) |
); |
end |
else |
begin |
begin: NO_DCACHE |
|
// No data cache |
assign dmem_addr_o = {dcache_addr[31:2], 2'b00}; |
assign dmem_data_out_o = dcache_data_o; |
assign dcache_data_i = dmem_data_in_i; |
assign dmem_rd_o = dcache_rd; |
assign dmem_wr_o = dcache_wr; |
assign dmem_burst_o = 1'b0; |
assign dmem_dat_o = dcache_data_o; |
assign dcache_data_i = dmem_dat_i; |
assign dmem_sel_o = dcache_sel; |
assign dmem_cyc_o = dcache_cyc; |
assign dmem_we_o = dcache_we; |
assign dmem_stb_o = dcache_stb; |
assign dmem_cti_o = 3'b111; |
assign dcache_ack = dmem_ack_i; |
assign dcache_accept = dmem_accept_i; |
assign dcache_stall = dmem_stall_i; |
end |
endgenerate |
|
416,9 → 428,11
.dmem_addr_o(dcache_addr), |
.dmem_data_out_o(dcache_data_o), |
.dmem_data_in_i(dcache_data_i), |
.dmem_wr_o(dcache_wr), |
.dmem_rd_o(dcache_rd), |
.dmem_accept_i(dcache_accept), |
.dmem_sel_o(dcache_sel), |
.dmem_we_o(dcache_we), |
.dmem_stb_o(dcache_stb), |
.dmem_cyc_o(dcache_cyc), |
.dmem_stall_i(dcache_stall), |
.dmem_ack_i(dcache_ack) |
); |
|
/altor32_dcache_mem_if.v
62,13 → 62,15
|
// Memory interface (slave) |
output reg [31:0] mem_addr_o /*verilator public*/, |
input [31:0] mem_data_i /*verilator public*/, |
input [31:0] mem_data_i /*verilator public*/, |
output reg [31:0] mem_data_o /*verilator public*/, |
output reg mem_burst_o /*verilator public*/, |
output reg mem_rd_o /*verilator public*/, |
output reg [3:0] mem_wr_o /*verilator public*/, |
input mem_accept_i/*verilator public*/, |
input mem_ack_i/*verilator public*/ |
output reg [2:0] mem_cti_o /*verilator public*/, |
output reg mem_cyc_o /*verilator public*/, |
output reg mem_stb_o /*verilator public*/, |
output reg mem_we_o /*verilator public*/, |
output reg [3:0] mem_sel_o /*verilator public*/, |
input mem_stall_i/*verilator public*/, |
input mem_ack_i/*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
82,53 → 84,195
//----------------------------------------------------------------- |
|
reg [31:CACHE_LINE_SIZE_WIDTH] line_address; |
reg [CACHE_LINE_SIZE_WIDTH-3:0] line_word; |
|
reg [CACHE_LINE_WORDS_IDX_MAX-1:0] response_idx; |
|
reg [CACHE_LINE_WORDS_IDX_MAX-1:0] request_idx; |
wire [CACHE_LINE_WORDS_IDX_MAX-1:0] next_request_idx = request_idx + 1'b1; |
|
reg [CACHE_LINE_WORDS_IDX_MAX-1:0] cache_idx; |
wire [CACHE_LINE_WORDS_IDX_MAX-1:0] next_cache_idx = cache_idx + 1'b1; |
|
|
// Current state |
parameter STATE_IDLE = 0; |
parameter STATE_FETCH = 1; |
parameter STATE_READ_WAIT = 2; |
parameter STATE_WRITE_SETUP = 2; |
parameter STATE_WRITE = 3; |
parameter STATE_WRITE_WAIT = 4; |
parameter STATE_READ_SINGLE = 5; |
parameter STATE_WRITE_SINGLE= 6; |
parameter STATE_MEM_SINGLE = 5; |
parameter STATE_FETCH_WAIT = 6; |
|
reg [3:0] state; |
|
//----------------------------------------------------------------- |
// Control logic |
// Next State Logic |
//----------------------------------------------------------------- |
reg [CACHE_LINE_SIZE_WIDTH-3:0] v_line_word; |
reg [3:0] next_state_r; |
always @ * |
begin |
next_state_r = state; |
|
case (state) |
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
// Perform cache evict (write) |
if (evict_i) |
next_state_r = STATE_WRITE_SETUP; |
// Perform cache fill (read) |
else if (fill_i) |
next_state_r = STATE_FETCH; |
// Read/Write single |
else if (rd_single_i | (|wr_single_i)) |
next_state_r = STATE_MEM_SINGLE; |
end |
//----------------------------------------- |
// FETCH - Fetch line from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Line fetch complete? |
if (~mem_stall_i && request_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
next_state_r = STATE_FETCH_WAIT; |
end |
//----------------------------------------- |
// FETCH_WAIT - Wait for read responses |
//----------------------------------------- |
STATE_FETCH_WAIT: |
begin |
// Read from memory complete |
if (mem_ack_i && response_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
next_state_r = STATE_IDLE; |
end |
//----------------------------------------- |
// WRITE_SETUP - Wait for data from cache |
//----------------------------------------- |
STATE_WRITE_SETUP : |
next_state_r = STATE_WRITE; |
//----------------------------------------- |
// WRITE - Write word to memory |
//----------------------------------------- |
STATE_WRITE : |
begin |
// Line write complete? |
if (~mem_stall_i && request_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
next_state_r = STATE_WRITE_WAIT; |
// Fetch next word for line |
else if (~mem_stall_i | ~mem_stb_o) |
next_state_r = STATE_WRITE_SETUP; |
end |
//----------------------------------------- |
// WRITE_WAIT - Wait for write to complete |
//----------------------------------------- |
STATE_WRITE_WAIT: |
begin |
// Write to memory complete |
if (mem_ack_i && response_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
next_state_r = STATE_IDLE; |
end |
//----------------------------------------- |
// MEM_SINGLE - Single access to memory |
//----------------------------------------- |
STATE_MEM_SINGLE: |
begin |
// Data ready from memory? |
if (mem_ack_i) |
next_state_r = STATE_IDLE; |
end |
default: |
; |
endcase |
end |
|
// Update state |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
state <= STATE_IDLE; |
else |
state <= next_state_r; |
end |
|
//----------------------------------------------------------------- |
// Control logic |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
line_address <= {32-CACHE_LINE_SIZE_WIDTH{1'b0}}; |
line_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
mem_addr_o <= 32'h00000000; |
mem_data_o <= 32'h00000000; |
mem_wr_o <= 4'h0; |
mem_rd_o <= 1'b0; |
mem_burst_o <= 1'b0; |
cache_addr_o <= 30'h00000000; |
cache_data_o <= 32'h00000000; |
cache_wr_o <= 1'b0; |
done_o <= 1'b0; |
data_o <= 32'h00000000; |
state <= STATE_IDLE; |
end |
else |
begin |
|
if (mem_accept_i) |
begin |
mem_rd_o <= 1'b0; |
mem_wr_o <= 4'h0; |
end |
done_o <= 1'b0; |
|
case (state) |
|
done_o <= 1'b0; |
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
// Perform cache evict (write) |
if (evict_i) |
line_address <= evict_addr_i[31:CACHE_LINE_SIZE_WIDTH]; |
// Perform cache fill (read) |
else if (fill_i) |
line_address <= address_i[31:CACHE_LINE_SIZE_WIDTH]; |
end |
//----------------------------------------- |
// FETCH/WRITE_WAIT - Wait for oustanding responses |
//----------------------------------------- |
STATE_WRITE_WAIT, |
STATE_FETCH_WAIT: |
begin |
// Write to memory complete |
if (mem_ack_i) |
begin |
// Line write complete? |
if (response_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
done_o <= 1'b1; |
end |
end |
//----------------------------------------- |
// MEM_SINGLE - Single access to memory |
//----------------------------------------- |
STATE_MEM_SINGLE: |
begin |
// Data ready from memory? |
if (mem_ack_i) |
begin |
data_o <= mem_data_i; |
done_o <= 1'b1; |
end |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Cache Read / Write |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
cache_addr_o <= 30'h00000000; |
cache_data_o <= 32'h00000000; |
cache_wr_o <= 1'b0; |
|
cache_idx <= {CACHE_LINE_WORDS_IDX_MAX{1'b0}}; |
end |
else |
begin |
cache_wr_o <= 1'b0; |
|
case (state) |
|
137,27 → 281,114
//----------------------------------------- |
STATE_IDLE : |
begin |
cache_idx <= {CACHE_LINE_WORDS_IDX_MAX{1'b0}}; |
|
// Perform cache evict (write) |
if (evict_i) |
begin |
line_address <= evict_addr_i[31:CACHE_LINE_SIZE_WIDTH]; |
line_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
|
// Read data from cache |
cache_addr_o <= {evict_addr_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH-2{1'b0}}}; |
state <= STATE_READ_WAIT; |
cache_addr_o <= {evict_addr_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_WORDS_IDX_MAX{1'b0}}}; |
end |
end |
//----------------------------------------- |
// FETCH - Fetch line from memory |
//----------------------------------------- |
STATE_FETCH, |
STATE_FETCH_WAIT: |
begin |
// Data ready from memory? |
if (mem_ack_i) |
begin |
// Write data into cache |
cache_addr_o <= {line_address, cache_idx}; |
cache_data_o <= mem_data_i; |
cache_wr_o <= 1'b1; |
|
cache_idx <= next_cache_idx; |
end |
end |
//----------------------------------------- |
// WRITE - Write word to memory |
//----------------------------------------- |
STATE_WRITE_SETUP: |
begin |
|
end |
STATE_WRITE, |
STATE_WRITE_WAIT: |
begin |
if (~mem_stall_i | ~mem_stb_o) |
begin |
// Setup next word read from cache |
cache_addr_o <= {line_address, next_cache_idx}; |
cache_idx <= next_cache_idx; |
end |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Request |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
mem_addr_o <= 32'h00000000; |
mem_data_o <= 32'h00000000; |
mem_sel_o <= 4'h0; |
mem_cti_o <= 3'b0; |
mem_stb_o <= 1'b0; |
mem_we_o <= 1'b0; |
request_idx <= {CACHE_LINE_WORDS_IDX_MAX{1'b0}}; |
end |
else |
begin |
if (~mem_stall_i) |
begin |
mem_stb_o <= 1'b0; |
|
// TMP |
if (mem_cti_o == 3'b111) |
begin |
//mem_addr_o <= 32'h00000000; |
mem_data_o <= 32'h00000000; |
mem_sel_o <= 4'h0; |
mem_cti_o <= 3'b0; |
mem_stb_o <= 1'b0; |
mem_we_o <= 1'b0; |
end |
end |
|
case (state) |
|
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
request_idx <= {CACHE_LINE_WORDS_IDX_MAX{1'b0}}; |
|
// Perform cache evict (write) |
if (evict_i) |
begin |
|
end |
// Perform cache fill (read) |
else if (fill_i) |
begin |
line_address <= address_i[31:CACHE_LINE_SIZE_WIDTH]; |
line_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
|
// Start fetch from memory |
mem_addr_o <= {address_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}}; |
mem_rd_o <= 1'b1; |
mem_burst_o <= 1'b1; |
state <= STATE_FETCH; |
mem_data_o <= 32'h00000000; |
mem_sel_o <= 4'b1111; |
mem_cti_o <= 3'b010; |
mem_stb_o <= 1'b1; |
mem_we_o <= 1'b0; |
|
request_idx <= next_request_idx; |
end |
// Read single |
else if (rd_single_i) |
164,10 → 395,11
begin |
// Start fetch from memory |
mem_addr_o <= address_i; |
mem_data_o <= 32'b0; |
mem_rd_o <= 1'b1; |
mem_burst_o <= 1'b0; |
state <= STATE_READ_SINGLE; |
mem_data_o <= 32'h00000000; |
mem_sel_o <= 4'b1111; |
mem_cti_o <= 3'b111; |
mem_stb_o <= 1'b1; |
mem_we_o <= 1'b0; |
end |
// Write single |
else if (|wr_single_i) |
175,9 → 407,10
// Start fetch from memory |
mem_addr_o <= address_i; |
mem_data_o <= data_i; |
mem_wr_o <= wr_single_i; |
mem_burst_o <= 1'b0; |
state <= STATE_WRITE_SINGLE; |
mem_sel_o <= wr_single_i; |
mem_cti_o <= 3'b111; |
mem_stb_o <= 1'b1; |
mem_we_o <= 1'b1; |
end |
end |
//----------------------------------------- |
185,110 → 418,160
//----------------------------------------- |
STATE_FETCH : |
begin |
// Data ready from memory? |
if (mem_ack_i && mem_rd_o == 1'b0) |
// Previous request accepted? |
if (~mem_stall_i) |
begin |
// Write data into cache |
cache_addr_o <= {line_address, line_word}; |
cache_data_o <= mem_data_i; |
cache_wr_o <= 1'b1; |
|
// Line fetch complete? |
if (line_word == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
begin |
done_o <= 1'b1; |
state <= STATE_IDLE; |
end |
// Fetch next word for line |
else |
begin |
v_line_word = line_word + 1'b1; |
line_word <= v_line_word; |
|
mem_addr_o <= {line_address, v_line_word, 2'b00}; |
mem_rd_o <= 1'b1; |
|
if (line_word == ({CACHE_LINE_WORDS_IDX_MAX{1'b1}}-1)) |
begin |
mem_burst_o <= 1'b0; |
end |
end |
mem_addr_o <= {line_address, request_idx, 2'b00}; |
mem_stb_o <= 1'b1; |
|
if (request_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
mem_cti_o <= 3'b111; |
|
request_idx <= next_request_idx; |
end |
end |
//----------------------------------------- |
// READ_WAIT - Wait for data from cache |
//----------------------------------------- |
STATE_READ_WAIT : |
begin |
// Not used yet, but set for start of burst |
mem_burst_o <= 1'b1; |
state <= STATE_WRITE; |
end |
//----------------------------------------- |
// WRITE - Write word to memory |
//----------------------------------------- |
STATE_WRITE : |
begin |
// Write data into memory from cache |
mem_addr_o <= {line_address, line_word, 2'b00}; |
mem_data_o <= cache_data_i; |
mem_wr_o <= 4'b1111; |
// Memory interface can request command? |
if (~mem_stall_i | ~mem_stb_o) |
begin |
// Write data into memory from cache |
mem_addr_o <= {line_address, request_idx, 2'b00}; |
mem_data_o <= cache_data_i; |
mem_sel_o <= 4'b1111; |
mem_stb_o <= 1'b1; |
mem_we_o <= 1'b1; |
|
if (request_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
mem_cti_o <= 3'b111; |
else |
mem_cti_o <= 3'b010; |
|
// Setup next word read from cache |
v_line_word = line_word + 1'b1; |
cache_addr_o <= {line_address, v_line_word}; |
request_idx <= next_request_idx; |
end |
end |
default: |
; |
endcase |
end |
end |
|
state <= STATE_WRITE_WAIT; |
end |
//----------------------------------------------------------------- |
// Memory Response Counter |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
response_idx <= {CACHE_LINE_WORDS_IDX_MAX{1'b0}}; |
else |
begin |
case (state) |
|
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
response_idx <= {CACHE_LINE_WORDS_IDX_MAX{1'b0}}; |
end |
//----------------------------------------- |
// FETCH - Fetch line from memory |
//----------------------------------------- |
STATE_FETCH, |
STATE_FETCH_WAIT : |
begin |
// Data ready from memory? |
if (mem_ack_i) |
response_idx <= response_idx + 1'b1; |
end |
//----------------------------------------- |
// WRITE_WAIT - Wait for write to complete |
//----------------------------------------- |
STATE_WRITE, |
STATE_WRITE_SETUP, |
STATE_WRITE_WAIT: |
begin |
// Write to memory complete |
if (mem_ack_i && mem_wr_o == 4'b0) |
if (mem_ack_i) |
response_idx <= response_idx + 1'b1; |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// CYC_O |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
mem_cyc_o <= 1'b0; |
else |
begin |
case (state) |
|
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
// Perform cache evict (write) |
if (evict_i) |
begin |
// Line write complete? |
if (line_word == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
begin |
done_o <= 1'b1; |
state <= STATE_IDLE; |
end |
// Fetch next word for line |
else |
begin |
line_word <= line_word + 1'b1; |
state <= STATE_WRITE; |
|
if (line_word == ({CACHE_LINE_WORDS_IDX_MAX{1'b1}}-1)) |
mem_burst_o <= 1'b0; |
end |
|
end |
end |
// Perform cache fill (read) |
else if (fill_i) |
mem_cyc_o <= 1'b1; |
// Read single |
else if (rd_single_i) |
mem_cyc_o <= 1'b1; |
// Write single |
else if (|wr_single_i) |
mem_cyc_o <= 1'b1; |
end |
//----------------------------------------- |
// READ_SINGLE - Single access to memory |
// FETCH - Fetch line from memory |
//----------------------------------------- |
STATE_READ_SINGLE: |
STATE_FETCH : |
begin |
// Data ready from memory? |
if (mem_ack_i && mem_rd_o == 1'b0) |
begin |
data_o <= mem_data_i; |
done_o <= 1'b1; |
state <= STATE_IDLE; |
end |
if (mem_ack_i && response_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
mem_cyc_o <= 1'b0; |
end |
//----------------------------------------- |
// WRITE_SINGLE - Single access to memory |
// WRITE - Write word to memory |
//----------------------------------------- |
STATE_WRITE_SINGLE: |
STATE_WRITE : |
begin |
if (mem_ack_i && mem_wr_o == 4'b0) |
begin |
done_o <= 1'b1; |
state <= STATE_IDLE; |
end |
end |
// Write data into memory from cache |
mem_cyc_o <= 1'b1; |
end |
//----------------------------------------- |
// FETCH/WRITE_WAIT - Wait for responses |
//----------------------------------------- |
STATE_WRITE_WAIT, |
STATE_FETCH_WAIT: |
begin |
// Write to memory complete |
if (mem_ack_i && response_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
mem_cyc_o <= 1'b0; |
end |
//----------------------------------------- |
// MEM_SINGLE - Single access to memory |
//----------------------------------------- |
STATE_MEM_SINGLE: |
begin |
// Data ready from memory? |
if (mem_ack_i) |
mem_cyc_o <= 1'b0; |
end |
default: |
; |
endcase |
/altor32_exec.v
36,9 → 36,7
//----------------------------------------------------------------- |
|
//`define CONF_CORE_DEBUG |
//`define CONF_CORE_DEBUG_BUBBLE |
//`define CONF_CORE_TRACE |
//`define CONF_CORE_FAULT_ON_OPCODE0 |
|
//----------------------------------------------------------------- |
// Includes |
106,9 → 104,11
output reg [31:0] dmem_addr_o /*verilator public*/, |
output reg [31:0] dmem_data_out_o /*verilator public*/, |
input [31:0] dmem_data_in_i /*verilator public*/, |
output reg [3:0] dmem_wr_o /*verilator public*/, |
output reg dmem_rd_o /*verilator public*/, |
input dmem_accept_i /*verilator public*/, |
output reg [3:0] dmem_sel_o /*verilator public*/, |
output reg dmem_we_o /*verilator public*/, |
output reg dmem_stb_o /*verilator public*/, |
output reg dmem_cyc_o /*verilator public*/, |
input dmem_stall_i /*verilator public*/, |
input dmem_ack_i /*verilator public*/ |
); |
|
749,170 → 749,106
//----------------------------------------------------------------- |
// Comparisons |
//----------------------------------------------------------------- |
reg [31:0] compare_a_r; |
reg [31:0] compare_b_r; |
always @ * |
begin |
compare_a_r = reg_ra_r; |
compare_b_r = reg_rb_r; |
|
case (1'b1) |
inst_sfeqi_w, // l.sfeqi |
inst_sfgesi_w, // l.sfgesi |
inst_sfgeui_w, // l.sfgeui |
inst_sfgtsi_w, // l.sfgtsi |
inst_sfgtui_w, // l.sfgtui |
inst_sflesi_w, // l.sflesi |
inst_sfleui_w, // l.sfleui |
inst_sfltsi_w, // l.sfltsi |
inst_sfltui_w, // l.sfltui |
inst_sfnei_w: // l.sfnei |
compare_b_r = int32_r; |
default: |
; |
endcase |
end |
|
reg compare_equal_r; |
reg compare_gts_r; |
reg compare_gt_r; |
reg compare_lts_r; |
reg compare_lt_r; |
always @ * |
begin |
if (compare_a_r == compare_b_r) |
compare_equal_r = 1'b1; |
else |
compare_equal_r = 1'b0; |
|
compare_lts_r = less_than_signed(compare_a_r, compare_b_r); |
|
if (compare_a_r < compare_b_r) |
compare_lt_r = 1'b1; |
else |
compare_lt_r = 1'b0; |
|
// Greater than (signed) |
compare_gts_r = ~(compare_lts_r | compare_equal_r); |
|
if (compare_a_r > compare_b_r) |
compare_gt_r = 1'b1; |
else |
compare_gt_r = 1'b0; |
end |
|
always @ * |
begin |
compare_result_r = 1'b0; |
|
case (1'b1) |
inst_sfeq_w: // l.sfeq |
begin |
if (reg_ra_r == reg_rb_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
|
inst_sfeq_w, // l.sfeq |
inst_sfeqi_w: // l.sfeqi |
begin |
if (reg_ra_r == int32_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_equal_r; |
|
inst_sfges_w: // l.sfges |
begin |
if (greater_than_equal_signed(reg_ra_r, reg_rb_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
|
inst_sfges_w, // l.sfges |
inst_sfgesi_w: // l.sfgesi |
begin |
if (greater_than_equal_signed(reg_ra_r, int32_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_gts_r | compare_equal_r; |
|
inst_sfgeu_w: // l.sfgeu |
begin |
if (reg_ra_r >= reg_rb_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
|
inst_sfgeu_w, // l.sfgeu |
inst_sfgeui_w: // l.sfgeui |
begin |
if (reg_ra_r >= int32_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_gt_r | compare_equal_r; |
|
inst_sfgts_w: // l.sfgts |
begin |
if (greater_than_signed(reg_ra_r, reg_rb_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
|
inst_sfgts_w, // l.sfgts |
inst_sfgtsi_w: // l.sfgtsi |
begin |
if (greater_than_signed(reg_ra_r, int32_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_gts_r; |
|
inst_sfgtu_w: // l.sfgtu |
begin |
if (reg_ra_r > reg_rb_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
|
inst_sfgtu_w, // l.sfgtu |
inst_sfgtui_w: // l.sfgtui |
begin |
if (reg_ra_r > int32_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_gt_r; |
|
inst_sfles_w: // l.sfles |
begin |
if (less_than_equal_signed(reg_ra_r, reg_rb_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
|
inst_sfles_w, // l.sfles |
inst_sflesi_w: // l.sflesi |
begin |
if (less_than_equal_signed(reg_ra_r, int32_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_lts_r | compare_equal_r; |
|
inst_sfleu_w: // l.sfleu |
begin |
if (reg_ra_r <= reg_rb_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
inst_sfleu_w, // l.sfleu |
|
inst_sfleui_w: // l.sfleui |
begin |
if (reg_ra_r <= int32_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_lt_r | compare_equal_r; |
|
inst_sflts_w: // l.sflts |
begin |
if (less_than_signed(reg_ra_r, reg_rb_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
inst_sflts_w, // l.sflts |
|
inst_sfltsi_w: // l.sfltsi |
begin |
if (less_than_signed(reg_ra_r, int32_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_lts_r; |
|
inst_sfltu_w: // l.sfltu |
begin |
if (reg_ra_r < reg_rb_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
inst_sfltu_w, // l.sfltu |
|
inst_sfltui_w: // l.sfltui |
begin |
if (reg_ra_r < int32_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_lt_r; |
|
inst_sfne_w: // l.sfne |
begin |
if (reg_ra_r != reg_rb_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
inst_sfne_w, // l.sfne |
|
inst_sfnei_w: // l.sfnei |
begin |
if (reg_ra_r != int32_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = ~compare_equal_r; |
default: |
; |
endcase |
1330,8 → 1266,10
// Data memory |
dmem_addr_o <= 32'h00000000; |
dmem_data_out_o <= 32'h00000000; |
dmem_rd_o <= 1'b0; |
dmem_wr_o <= 4'b0000; |
dmem_we_o <= 1'b0; |
dmem_sel_o <= 4'b0000; |
dmem_stb_o <= 1'b0; |
dmem_cyc_o <= 1'b0; |
|
r_mem_load <= 1'b0; |
r_mem_store <= 1'b0; |
1347,12 → 1285,11
begin |
|
// If memory access accepted by slave |
if (dmem_accept_i) |
begin |
dmem_rd_o <= 1'b0; |
dmem_wr_o <= 4'b0000; |
end |
|
if (~dmem_stall_i) |
dmem_stb_o <= 1'b0; |
|
if (dmem_ack_i) |
dmem_cyc_o <= 1'b0; |
r_mem_access <= 1'b0; |
d_mem_load <= r_mem_access & r_mem_load; |
|
1391,7 → 1328,10
begin |
dmem_addr_o <= mem_addr_r; |
dmem_data_out_o <= 32'h00000000; |
dmem_rd_o <= 1'b1; |
dmem_sel_o <= 4'b1111; |
dmem_we_o <= 1'b0; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
|
// Mark load as pending |
r_mem_load <= 1'b1; |
1415,32 → 1355,41
2'b00 : |
begin |
dmem_data_out_o <= {reg_rb_r[7:0],24'h000000}; |
dmem_wr_o <= 4'b1000; |
dmem_sel_o <= 4'b1000; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_store <= 1'b1; |
end |
2'b01 : |
begin |
dmem_data_out_o <= {{8'h00,reg_rb_r[7:0]},16'h0000}; |
dmem_wr_o <= 4'b0100; |
dmem_sel_o <= 4'b0100; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_store <= 1'b1; |
end |
2'b10 : |
begin |
dmem_data_out_o <= {{16'h0000,reg_rb_r[7:0]},8'h00}; |
dmem_wr_o <= 4'b0010; |
dmem_sel_o <= 4'b0010; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_store <= 1'b1; |
end |
2'b11 : |
begin |
dmem_data_out_o <= {24'h000000,reg_rb_r[7:0]}; |
dmem_wr_o <= 4'b0001; |
dmem_sel_o <= 4'b0001; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_store <= 1'b1; |
end |
default : |
begin |
dmem_data_out_o <= 32'h00000000; |
dmem_wr_o <= 4'b0000; |
end |
; |
endcase |
end |
|
1452,20 → 1401,23
2'b00 : |
begin |
dmem_data_out_o <= {reg_rb_r[15:0],16'h0000}; |
dmem_wr_o <= 4'b1100; |
dmem_sel_o <= 4'b1100; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_store <= 1'b1; |
end |
2'b10 : |
begin |
dmem_data_out_o <= {16'h0000,reg_rb_r[15:0]}; |
dmem_wr_o <= 4'b0011; |
dmem_sel_o <= 4'b0011; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_store <= 1'b1; |
end |
default : |
begin |
dmem_data_out_o <= 32'h00000000; |
dmem_wr_o <= 4'b0000; |
end |
; |
endcase |
end |
|
1473,7 → 1425,10
begin |
dmem_addr_o <= mem_addr_r; |
dmem_data_out_o <= reg_rb_r; |
dmem_wr_o <= 4'b1111; |
dmem_sel_o <= 4'b1111; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_access <= 1'b1; |
r_mem_store <= 1'b1; |
|
1619,6 → 1574,26
get_putc = 8'b0; |
`endif |
endfunction |
function [0:0] get_reg_valid; |
// verilator public |
get_reg_valid = ~(resolve_failed | load_stall); |
endfunction |
function [4:0] get_reg_ra; |
// verilator public |
get_reg_ra = reg_ra_i; |
endfunction |
function [31:0] get_reg_ra_value; |
// verilator public |
get_reg_ra_value = ra_value_resolved; |
endfunction |
function [4:0] get_reg_rb; |
// verilator public |
get_reg_rb = reg_rb_i; |
endfunction |
function [31:0] get_reg_rb_value; |
// verilator public |
get_reg_rb_value = rb_value_resolved; |
endfunction |
`endif |
|
endmodule |
/altor32_regfile_sim.v
45,15 → 45,15
//----------------------------------------------------------------- |
module altor32_regfile_sim |
( |
input clk_i /*verilator public*/, |
input rst_i /*verilator public*/, |
input wr_i /*verilator public*/, |
input [4:0] rs_i /*verilator public*/, |
input [4:0] rt_i /*verilator public*/, |
input [4:0] rd_i /*verilator public*/, |
output [31:0] reg_rs_o /*verilator public*/, |
output [31:0] reg_rt_o /*verilator public*/, |
input [31:0] reg_rd_i /*verilator public*/ |
input clk_i /*verilator public*/, |
input rst_i /*verilator public*/, |
input wr_i /*verilator public*/, |
input [4:0] rs_i /*verilator public*/, |
input [4:0] rt_i /*verilator public*/, |
input [4:0] rd_i /*verilator public*/, |
output reg [31:0] reg_rs_o /*verilator public*/, |
output reg [31:0] reg_rt_o /*verilator public*/, |
input [31:0] reg_rd_i /*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
98,9 → 98,6
reg [31:0] reg_r30; |
reg [31:0] reg_r31; |
|
reg [31:0] reg_rs_o; |
reg [31:0] reg_rt_o; |
|
//----------------------------------------------------------------- |
// Register File (for simulation) |
//----------------------------------------------------------------- |