/**
|
/*
|
* @file
|
* Copyright 2018 Sergey Khabarov, sergeykhbr@gmail.com
|
* @copyright Copyright 2017 GNSS Sensor Ltd. All right reserved.
|
*
|
* @author Sergey Khabarov - sergeykhbr@gmail.com
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* @brief Instruction Cache.
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
*/
|
*/
|
|
|
#include "icache.h"
|
#include "icache.h"
|
|
|
namespace debugger {
|
namespace debugger {
|
|
|
ICache::ICache(sc_module_name name_) : sc_module(name_) {
|
ICache::ICache(sc_module_name name_) : sc_module(name_) {
|
SC_METHOD(comb);
|
SC_METHOD(comb);
|
sensitive << i_nrst;
|
sensitive << i_nrst;
|
sensitive << i_req_ctrl_valid;
|
sensitive << i_req_ctrl_valid;
|
sensitive << i_req_ctrl_addr;
|
sensitive << i_req_ctrl_addr;
|
sensitive << i_resp_mem_data_valid;
|
sensitive << i_resp_mem_data_valid;
|
sensitive << i_resp_mem_data;
|
sensitive << i_resp_mem_data;
|
sensitive << i_resp_ctrl_ready;
|
sensitive << i_resp_ctrl_ready;
|
sensitive << i_req_mem_ready;
|
sensitive << i_req_mem_ready;
|
sensitive << r.iline_addr;
|
sensitive << r.iline[0].addr;
|
sensitive << r.iline_data;
|
sensitive << r.iline[0].data;
|
sensitive << r.iline_addr_hit;
|
sensitive << r.iline[1].addr;
|
sensitive << r.iline_data_hit;
|
sensitive << r.iline[1].data;
|
sensitive << r.iline_addr_req;
|
sensitive << r.iline_addr_req;
|
sensitive << r.hit_line;
|
sensitive << r.addr_processing;
|
|
sensitive << r.double_req;
|
|
sensitive << r.delay_valid;
|
|
sensitive << r.delay_data;
|
sensitive << r.state;
|
sensitive << r.state;
|
|
|
SC_METHOD(registers);
|
SC_METHOD(registers);
|
sensitive << i_clk.pos();
|
sensitive << i_clk.pos();
|
};
|
};
|
|
|
void ICache::generateVCD(sc_trace_file *i_vcd, sc_trace_file *o_vcd) {
|
void ICache::generateVCD(sc_trace_file *i_vcd, sc_trace_file *o_vcd) {
|
if (o_vcd) {
|
if (o_vcd) {
|
sc_trace(o_vcd, i_nrst, "/top/cache0/i0/i_nrst");
|
sc_trace(o_vcd, i_nrst, "/top/cache0/i0/i_nrst");
|
sc_trace(o_vcd, i_req_ctrl_valid, "/top/cache0/i0/i_req_ctrl_valid");
|
sc_trace(o_vcd, i_req_ctrl_valid, "/top/cache0/i0/i_req_ctrl_valid");
|
sc_trace(o_vcd, i_req_ctrl_addr, "/top/cache0/i0/i_req_ctrl_addr");
|
sc_trace(o_vcd, i_req_ctrl_addr, "/top/cache0/i0/i_req_ctrl_addr");
|
sc_trace(o_vcd, o_req_ctrl_ready, "/top/cache0/i0/o_req_ctrl_ready");
|
sc_trace(o_vcd, o_req_ctrl_ready, "/top/cache0/i0/o_req_ctrl_ready");
|
sc_trace(o_vcd, o_req_mem_valid, "/top/cache0/i0/o_req_mem_valid");
|
sc_trace(o_vcd, o_req_mem_valid, "/top/cache0/i0/o_req_mem_valid");
|
sc_trace(o_vcd, o_req_mem_addr, "/top/cache0/i0/o_req_mem_addr");
|
sc_trace(o_vcd, o_req_mem_addr, "/top/cache0/i0/o_req_mem_addr");
|
sc_trace(o_vcd, i_req_mem_ready, "/top/cache0/i0/i_req_mem_ready");
|
sc_trace(o_vcd, i_req_mem_ready, "/top/cache0/i0/i_req_mem_ready");
|
sc_trace(o_vcd, i_resp_mem_data_valid, "/top/cache0/i0/i_resp_mem_data_valid");
|
sc_trace(o_vcd, i_resp_mem_data_valid, "/top/cache0/i0/i_resp_mem_data_valid");
|
sc_trace(o_vcd, i_resp_mem_data, "/top/cache0/i0/i_resp_mem_data");
|
sc_trace(o_vcd, i_resp_mem_data, "/top/cache0/i0/i_resp_mem_data");
|
sc_trace(o_vcd, o_resp_ctrl_valid, "/top/cache0/i0/o_resp_ctrl_valid");
|
sc_trace(o_vcd, o_resp_ctrl_valid, "/top/cache0/i0/o_resp_ctrl_valid");
|
sc_trace(o_vcd, i_resp_ctrl_ready, "/top/cache0/i0/i_resp_ctrl_ready");
|
sc_trace(o_vcd, i_resp_ctrl_ready, "/top/cache0/i0/i_resp_ctrl_ready");
|
sc_trace(o_vcd, o_resp_ctrl_addr, "/top/cache0/i0/o_resp_ctrl_addr");
|
sc_trace(o_vcd, o_resp_ctrl_addr, "/top/cache0/i0/o_resp_ctrl_addr");
|
sc_trace(o_vcd, o_resp_ctrl_data, "/top/cache0/i0/o_resp_ctrl_data");
|
sc_trace(o_vcd, o_resp_ctrl_data, "/top/cache0/i0/o_resp_ctrl_data");
|
sc_trace(o_vcd, r.iline_addr, "/top/cache0/i0/r_iline_addr");
|
sc_trace(o_vcd, r.iline[0].addr, "/top/cache0/i0/r_iline(0)_addr");
|
sc_trace(o_vcd, r.iline_data, "/top/cache0/i0/r_iline_data");
|
sc_trace(o_vcd, r.iline[0].data, "/top/cache0/i0/r_iline(0)_data");
|
sc_trace(o_vcd, r.iline_addr_hit, "/top/cache0/i0/r_iline_addr_hit");
|
sc_trace(o_vcd, r.iline[1].addr, "/top/cache0/i0/r_iline(1)_addr");
|
sc_trace(o_vcd, r.iline_data_hit, "/top/cache0/i0/r_iline_data_hit");
|
sc_trace(o_vcd, r.iline[1].data, "/top/cache0/i0/r_iline(1)_data");
|
sc_trace(o_vcd, r.iline_addr_req, "/top/cache0/i0/r_iline_addr_req");
|
sc_trace(o_vcd, r.iline_addr_req, "/top/cache0/i0/r_iline_addr_req");
|
sc_trace(o_vcd, r.hit_line, "/top/cache0/i0/r_hit_line");
|
sc_trace(o_vcd, r.addr_processing, "/top/cache0/i0/r_addr_processing");
|
|
sc_trace(o_vcd, r.double_req, "/top/cache0/i0/double_req");
|
|
sc_trace(o_vcd, r.delay_valid, "/top/cache0/i0/r_delay_valid");
|
|
sc_trace(o_vcd, r.delay_data, "/top/cache0/i0/r_delay_valid");
|
sc_trace(o_vcd, r.state, "/top/cache0/i0/r_state");
|
sc_trace(o_vcd, r.state, "/top/cache0/i0/r_state");
|
sc_trace(o_vcd, w_hit, "/top/cache0/i0/w_hit");
|
sc_trace(o_vcd, w_need_mem_req, "/top/cache0/i0/w_need_mem_req");
|
sc_trace(o_vcd, w_hit_line, "/top/cache0/i0/w_hit_line");
|
sc_trace(o_vcd, wb_l[0].hit, "/top/cache0/i0/wb_l(0)_hit");
|
sc_trace(o_vcd, w_hit_req, "/top/cache0/i0/w_hit_req");
|
sc_trace(o_vcd, wb_l[1].hit, "/top/cache0/i0/wb_l(1)_hit");
|
//sc_trace(o_vcd, wb_req_line, "/top/cache0/i0/wb_req_line");
|
sc_trace(o_vcd, wb_l[0].hit_data, "/top/cache0/i0/wb_l(0)_hit_data");
|
//sc_trace(o_vcd, wb_cached_addr, "/top/cache0/i0/wb_cached_addr");
|
sc_trace(o_vcd, wb_l[1].hit_data, "/top/cache0/i0/wb_l(1)_hit_data");
|
//sc_trace(o_vcd, wb_cached_data, "/top/cache0/i0/wb_cached_data");
|
sc_trace(o_vcd, wb_hit_word, "/top/cache0/i0/wb_hit_word");
|
|
sc_trace(o_vcd, wb_l[0].hit_hold, "/top/cache0/i0/wb_l(0).hit_hold");
|
|
sc_trace(o_vcd, wb_l[1].hit_hold, "/top/cache0/i0/wb_l(1).hit_hold");
|
|
sc_trace(o_vcd, w_reuse_lastline, "/top/cache0/i0/w_reuse_lastline");
|
|
sc_trace(o_vcd, w_wait_response, "/top/cache0/i0/w_wait_response");
|
}
|
}
|
}
|
}
|
|
|
void ICache::comb() {
|
void ICache::comb() {
|
// Instruction cache:
|
// Instruction cache:
|
bool w_o_req_ctrl_ready;
|
bool w_o_req_ctrl_ready;
|
bool w_o_req_mem_valid;
|
bool w_o_req_mem_valid;
|
sc_uint<BUS_ADDR_WIDTH> wb_o_req_mem_addr;
|
sc_uint<BUS_ADDR_WIDTH> wb_o_req_mem_addr;
|
|
bool w_req_ctrl_valid;
|
bool w_req_fire;
|
bool w_req_fire;
|
bool w_o_resp_valid;
|
bool w_o_resp_valid;
|
sc_uint<BUS_ADDR_WIDTH> wb_o_resp_addr;
|
sc_uint<BUS_ADDR_WIDTH> wb_o_resp_addr;
|
sc_uint<32> wb_o_resp_data;
|
sc_uint<32> wb_o_resp_data;
|
sc_uint<BUS_ADDR_WIDTH - 3> wb_req_line;
|
sc_uint<BUS_ADDR_WIDTH> wb_req_addr[2];
|
|
sc_uint<BUS_ADDR_WIDTH> wb_hold_addr[2];
|
|
|
v = r;
|
v = r;
|
w_hit_req = 0;
|
|
w_hit_line = 0;
|
w_wait_response = 0;
|
w_hit = 0;
|
if (r.state.read() == State_WaitResp && i_resp_mem_data_valid.read() == 0) {
|
|
w_wait_response = 1;
|
wb_req_line = i_req_ctrl_addr.read()(BUS_ADDR_WIDTH-1, 3);
|
}
|
if (i_resp_mem_data_valid.read()
|
w_req_ctrl_valid = !w_wait_response
|
&& (wb_req_line == r.iline_addr_req.read()(BUS_ADDR_WIDTH-1, 3))) {
|
&& (i_req_ctrl_valid.read() || r.double_req.read());
|
w_hit_req = 1;
|
wb_req_addr[0] = i_req_ctrl_addr.read();
|
}
|
wb_req_addr[1] = i_req_ctrl_addr.read() + 2;
|
if (wb_req_line == r.iline_addr.read()) {
|
|
w_hit_line = 1;
|
wb_hold_addr[0] = r.addr_processing.read();
|
}
|
wb_hold_addr[1] = r.addr_processing.read() + 2;
|
w_hit = w_hit_req || w_hit_line;
|
|
|
for (int i = 0; i < ILINE_TOTAL; i++) {
|
w_o_req_mem_valid = !w_hit & i_req_ctrl_valid.read();
|
wb_l[i].hit = 0;
|
wb_o_req_mem_addr = i_req_ctrl_addr.read()(BUS_ADDR_WIDTH-1, 3) << 3;
|
wb_l[i].hit_data = 0;
|
w_o_req_ctrl_ready = w_hit | i_req_mem_ready.read();
|
if (wb_req_addr[i](BUS_ADDR_WIDTH-1, 3) == r.iline[0].addr.read()) {
|
w_req_fire = i_req_ctrl_valid.read() && w_o_req_ctrl_ready;
|
wb_l[i].hit[Hit_Line1] = w_req_ctrl_valid;
|
|
wb_l[i].hit_data = r.iline[0].data.read();
|
|
} else if (wb_req_addr[i](BUS_ADDR_WIDTH-1, 3) ==
|
|
r.iline[1].addr.read()) {
|
|
wb_l[i].hit[Hit_Line2] = w_req_ctrl_valid;
|
|
wb_l[i].hit_data = r.iline[1].data.read();
|
|
} else if (wb_req_addr[i](BUS_ADDR_WIDTH-1, 3) ==
|
|
r.iline_addr_req.read()(BUS_ADDR_WIDTH-1, 3)) {
|
|
wb_l[i].hit[Hit_Response] = i_resp_mem_data_valid.read();
|
|
wb_l[i].hit_data = i_resp_mem_data.read();
|
|
}
|
|
|
|
wb_l[i].hit_hold = 0;
|
|
wb_l[i].hold_data = 0;
|
|
if (wb_hold_addr[i](BUS_ADDR_WIDTH-1, 3) == r.iline[0].addr.read()) {
|
|
wb_l[i].hit_hold[Hit_Line1] = 1;
|
|
wb_l[i].hold_data = r.iline[0].data.read();
|
|
} else if (wb_hold_addr[i](BUS_ADDR_WIDTH-1, 3) ==
|
|
r.iline[1].addr.read()) {
|
|
wb_l[i].hit_hold[Hit_Line2] = 1;
|
|
wb_l[i].hold_data = r.iline[1].data.read();
|
|
} else if (wb_hold_addr[i](BUS_ADDR_WIDTH-1, 3) ==
|
|
r.iline_addr_req.read()(BUS_ADDR_WIDTH-1, 3)) {
|
|
wb_l[i].hold_data = i_resp_mem_data.read();
|
|
}
|
|
}
|
|
|
|
wb_hit_word = 0;
|
|
w_need_mem_req = 1;
|
|
if (wb_l[0].hit != 0 && wb_l[1].hit != 0) {
|
|
w_need_mem_req = 0;
|
|
}
|
|
switch (r.addr_processing.read()(2, 1)) {
|
|
case 0:
|
|
wb_hit_word = wb_l[0].hold_data(31, 0);
|
|
break;
|
|
case 1:
|
|
wb_hit_word = wb_l[0].hold_data(47, 16);
|
|
break;
|
|
case 2:
|
|
wb_hit_word = wb_l[0].hold_data(63, 32);
|
|
break;
|
|
default:
|
|
wb_hit_word = (wb_l[1].hold_data(15, 0) << 16)
|
|
| wb_l[0].hold_data(63, 48);
|
|
}
|
|
|
|
if (w_req_ctrl_valid && !w_need_mem_req) {
|
|
v.delay_valid = 1;
|
|
switch (i_req_ctrl_addr.read()(2, 1)) {
|
|
case 0:
|
|
v.delay_data = wb_l[0].hit_data(31, 0);
|
|
break;
|
|
case 1:
|
|
v.delay_data = wb_l[0].hit_data(47, 16);
|
|
break;
|
|
case 2:
|
|
v.delay_data = wb_l[0].hit_data(63, 32);
|
|
break;
|
|
default:
|
|
v.delay_data = (wb_l[1].hit_data(15, 0) << 16)
|
|
| wb_l[0].hit_data(63, 48);
|
|
}
|
|
} else if (i_resp_ctrl_ready.read()) {
|
|
v.delay_valid = 0;
|
|
v.delay_data = 0;
|
|
}
|
|
|
|
w_o_req_mem_valid = w_need_mem_req & w_req_ctrl_valid;
|
|
if (r.double_req.read()) {
|
|
if ((r.addr_processing.read()(BUS_ADDR_WIDTH-1, 3) ==
|
|
r.iline_addr_req.read()(BUS_ADDR_WIDTH-1, 3))
|
|
|| (r.addr_processing.read()(BUS_ADDR_WIDTH-1, 3) ==
|
|
wb_hold_addr[0](BUS_ADDR_WIDTH-1, 3))
|
|
) {
|
|
wb_o_req_mem_addr = wb_hold_addr[1](BUS_ADDR_WIDTH-1, 3) << 3;
|
|
} else {
|
|
wb_o_req_mem_addr = wb_hold_addr[0](BUS_ADDR_WIDTH-1, 3) << 3;
|
|
}
|
|
} else if (wb_l[0].hit == 0) {
|
|
wb_o_req_mem_addr = wb_req_addr[0](BUS_ADDR_WIDTH-1, 3) << 3;
|
|
} else {
|
|
wb_o_req_mem_addr = wb_req_addr[1](BUS_ADDR_WIDTH-1, 3) << 3;
|
|
}
|
|
|
|
w_o_req_ctrl_ready = !w_need_mem_req
|
|
| (i_req_mem_ready.read() & !w_wait_response);
|
|
w_req_fire = w_req_ctrl_valid && w_o_req_ctrl_ready;
|
|
|
|
if ((w_o_req_mem_valid && i_req_mem_ready.read() && !w_wait_response)
|
|
|| r.double_req.read()) {
|
|
v.iline_addr_req = wb_o_req_mem_addr;
|
|
}
|
|
|
switch (r.state.read()) {
|
switch (r.state.read()) {
|
case State_Idle:
|
case State_Idle:
|
if (i_req_ctrl_valid.read()) {
|
if (w_req_ctrl_valid) {
|
if (w_hit_line) {
|
if (!w_need_mem_req) {
|
v.state = State_WaitAccept;
|
v.state = State_WaitAccept;
|
} else if (i_req_mem_ready.read()) {
|
} else if (i_req_mem_ready.read()) {
|
v.state = State_WaitResp;
|
v.state = State_WaitResp;
|
} else {
|
} else {
|
v.state = State_WaitGrant;
|
v.state = State_WaitGrant;
|
}
|
}
|
}
|
}
|
break;
|
break;
|
case State_WaitGrant:
|
case State_WaitGrant:
|
if (i_req_mem_ready.read()) {
|
if (i_req_mem_ready.read()) {
|
v.state = State_WaitResp;
|
v.state = State_WaitResp;
|
} else if (w_hit) {
|
} else if (!w_need_mem_req) {
|
/** Fetcher can change request address while request wasn't
|
/** Fetcher can change request address while request wasn't
|
* accepteed. */
|
* accepteed. */
|
v.state = State_WaitAccept;
|
v.state = State_WaitAccept;
|
}
|
}
|
break;
|
break;
|
case State_WaitResp:
|
case State_WaitResp:
|
if (i_resp_mem_data_valid.read()) {
|
if (i_resp_mem_data_valid.read()) {
|
if (!i_resp_ctrl_ready.read()) {
|
if (!i_resp_ctrl_ready.read()) {
|
v.state = State_WaitAccept;
|
v.state = State_WaitAccept;
|
} else if (!i_req_ctrl_valid.read()) {
|
} else if (!w_req_ctrl_valid) {
|
v.state = State_Idle;
|
v.state = State_Idle;
|
} else {
|
} else {
|
// New request
|
// New request
|
if (w_hit) {
|
if (!w_need_mem_req) {
|
v.state = State_WaitAccept;
|
v.state = State_WaitAccept;
|
} else if (i_req_mem_ready.read()) {
|
} else if (i_req_mem_ready.read()) {
|
v.state = State_WaitResp;
|
v.state = State_WaitResp;
|
} else {
|
} else {
|
v.state = State_WaitGrant;
|
v.state = State_WaitGrant;
|
}
|
}
|
}
|
}
|
}
|
}
|
break;
|
break;
|
case State_WaitAccept:
|
case State_WaitAccept:
|
if (i_resp_ctrl_ready.read()) {
|
if (i_resp_ctrl_ready.read()) {
|
if (!i_req_ctrl_valid.read()) {
|
if (!w_req_ctrl_valid) {
|
v.state = State_Idle;
|
v.state = State_Idle;
|
} else {
|
} else {
|
if (w_hit) {
|
if (!w_need_mem_req) {
|
v.state = State_WaitAccept;
|
v.state = State_WaitAccept;
|
} else if (i_req_mem_ready.read()) {
|
} else if (i_req_mem_ready.read()) {
|
v.state = State_WaitResp;
|
v.state = State_WaitResp;
|
} else {
|
} else {
|
v.state = State_WaitGrant;
|
v.state = State_WaitGrant;
|
}
|
}
|
}
|
}
|
}
|
}
|
break;
|
break;
|
default:;
|
default:;
|
}
|
}
|
|
|
if (w_req_fire) {
|
if (w_req_fire) {
|
v.iline_addr_req = i_req_ctrl_addr;
|
v.double_req = 0;
|
v.hit_line = 0;
|
if (i_req_ctrl_addr.read()(2, 1) == 0x3
|
if (w_hit_line) {
|
&& wb_l[0].hit == 0 && wb_l[1].hit == 0
|
v.hit_line = 1;
|
&& r.double_req.read() == 0) {
|
v.iline_addr_hit = i_req_ctrl_addr;
|
v.double_req = 1;
|
if (i_req_ctrl_addr.read()[2] == 0) {
|
|
v.iline_data_hit = r.iline_data.read()(31, 0);
|
|
} else {
|
|
v.iline_data_hit = r.iline_data.read()(63, 32);
|
|
}
|
}
|
|
if (!r.double_req.read()) {
|
|
v.addr_processing = i_req_ctrl_addr;
|
}
|
}
|
}
|
}
|
|
|
|
w_reuse_lastline = 0;
|
|
|
if (i_resp_mem_data_valid.read()) {
|
if (i_resp_mem_data_valid.read()) {
|
v.iline_addr = r.iline_addr_req.read()(BUS_ADDR_WIDTH-1, 3);
|
/** Condition to avoid removing the last line:
|
v.iline_data = i_resp_mem_data;
|
*/
|
|
if (i_resp_ctrl_ready.read()) {
|
|
if ((wb_l[0].hit[Hit_Line2] || wb_l[1].hit[Hit_Line2]) == 1
|
|
&& r.iline[1].addr.read()
|
|
!= i_req_ctrl_addr.read()(BUS_ADDR_WIDTH-1, 3)) {
|
|
w_reuse_lastline = w_need_mem_req;
|
}
|
}
|
|
|
wb_o_resp_addr = r.iline_addr_req;
|
|
if (r.state.read() == State_WaitAccept) {
|
|
w_o_resp_valid = 1;
|
|
if (r.hit_line) {
|
|
wb_o_resp_addr = r.iline_addr_hit;
|
|
wb_o_resp_data = r.iline_data_hit;
|
|
} else {
|
} else {
|
if (r.iline_addr_req.read()[2] == 0) {
|
if ((wb_l[0].hit_hold[Hit_Line2] || wb_l[1].hit_hold[Hit_Line2]) == 1
|
wb_o_resp_data = r.iline_data.read()(31, 0);
|
&& (wb_l[0].hit_hold[Hit_Line1] || wb_l[1].hit_hold[Hit_Line1]) == 0
|
} else {
|
&& r.iline[1].addr.read()
|
wb_o_resp_data = r.iline_data.read()(63, 32);
|
!= r.iline_addr_req.read()(BUS_ADDR_WIDTH-1, 3)) {
|
|
w_reuse_lastline = 1;
|
}
|
}
|
}
|
}
|
|
if (!w_reuse_lastline) {
|
|
v.iline[1].addr = r.iline[0].addr;
|
|
v.iline[1].data = r.iline[0].data;
|
|
}
|
|
|
|
v.iline[0].addr = r.iline_addr_req.read()(BUS_ADDR_WIDTH-1, 3);
|
|
v.iline[0].data = i_resp_mem_data;
|
|
}
|
|
|
|
if (r.state.read() == State_WaitAccept) {
|
|
w_o_resp_valid = !r.double_req.read();
|
} else {
|
} else {
|
w_o_resp_valid = i_resp_mem_data_valid;
|
w_o_resp_valid = i_resp_mem_data_valid && !r.double_req.read();
|
if (r.iline_addr_req.read()[2] == 0) {
|
|
wb_o_resp_data = i_resp_mem_data.read()(31, 0);
|
|
} else {
|
|
wb_o_resp_data = i_resp_mem_data.read()(63, 32);
|
|
}
|
}
|
|
if (r.delay_valid.read()) {
|
|
wb_o_resp_data = r.delay_data.read();
|
|
} else {
|
|
wb_o_resp_data = wb_hit_word;
|
}
|
}
|
|
wb_o_resp_addr = r.addr_processing;
|
|
|
|
|
if (!i_nrst.read()) {
|
if (!i_nrst.read()) {
|
|
v.iline[0].addr = ~0;
|
|
v.iline[0].data = 0;
|
|
v.iline[1].addr = ~0;
|
|
v.iline[1].data = 0;
|
v.iline_addr_req = 0;
|
v.iline_addr_req = 0;
|
v.iline_addr = ~0;
|
v.addr_processing = 0;
|
v.iline_data = 0;
|
|
v.iline_addr_hit = ~0;
|
|
v.iline_data_hit = 0;
|
|
v.hit_line = 0;
|
|
v.state = State_Idle;
|
v.state = State_Idle;
|
|
v.double_req = 0;
|
|
v.delay_valid = 0;
|
|
v.delay_data = 0;
|
}
|
}
|
|
|
o_req_ctrl_ready = w_o_req_ctrl_ready;
|
o_req_ctrl_ready = w_o_req_ctrl_ready;
|
|
|
o_req_mem_valid = w_o_req_mem_valid;
|
o_req_mem_valid = w_o_req_mem_valid;
|
o_req_mem_addr = wb_o_req_mem_addr;
|
o_req_mem_addr = wb_o_req_mem_addr;
|
o_req_mem_write = false;
|
o_req_mem_write = false;
|
o_req_mem_strob = 0;
|
o_req_mem_strob = 0;
|
o_req_mem_data = 0;
|
o_req_mem_data = 0;
|
|
|
o_resp_ctrl_valid = w_o_resp_valid;
|
o_resp_ctrl_valid = w_o_resp_valid;
|
o_resp_ctrl_data = wb_o_resp_data;
|
o_resp_ctrl_data = wb_o_resp_data;
|
o_resp_ctrl_addr = wb_o_resp_addr;
|
o_resp_ctrl_addr = wb_o_resp_addr;
|
o_istate = r.state;
|
o_istate = r.state;
|
}
|
}
|
|
|
void ICache::registers() {
|
void ICache::registers() {
|
r = v;
|
r = v;
|
}
|
}
|
|
|
#ifdef DBG_ICACHE_TB
|
#ifdef DBG_ICACHE_TB
|
void ICache_tb::comb0() {
|
void ICache_tb::comb0() {
|
v = r;
|
v = r;
|
v.clk_cnt = r.clk_cnt.read() + 1;
|
v.clk_cnt = r.clk_cnt.read() + 1;
|
|
|
if (r.clk_cnt.read() < 10) {
|
if (r.clk_cnt.read() < 10) {
|
w_nrst = 0;
|
w_nrst = 0;
|
v.mem_state = 0;
|
v.mem_state = 0;
|
v.mem_cnt = 0;
|
v.mem_cnt = 0;
|
v.fetch_state = 0;
|
v.fetch_state = 0;
|
v.fetch_cnt = 0;
|
v.fetch_cnt = 0;
|
return;
|
return;
|
}
|
}
|
w_nrst = 1;
|
w_nrst = 1;
|
|
|
w_req_ctrl_valid = 0;
|
w_req_ctrl_valid = 0;
|
wb_req_ctrl_addr = 0;
|
wb_req_ctrl_addr = 0;
|
w_resp_ctrl_ready = 0;
|
w_resp_ctrl_ready = 0;
|
|
|
struct FetchDelayType {
|
struct FetchDelayType {
|
uint32_t raddr;
|
uint32_t raddr;
|
int req_wait;
|
int req_wait;
|
int accept_wait;
|
int accept_wait;
|
};
|
};
|
static const FetchDelayType RADDR[4] = {{0x100008f4, 0, 0}, {0x100007b0, 0, 0}, {0x100008f0, 2, 0}, {0x100007b4, 0, 0}};
|
static const FetchDelayType RADDR[4] = {{0x100008f4, 0, 0}, {0x100007b0, 0, 0}, {0x100008f0, 2, 0}, {0x100007b4, 0, 0}};
|
struct MemDelayType {
|
struct MemDelayType {
|
unsigned rdy_wait;
|
unsigned rdy_wait;
|
unsigned valid_wait;
|
unsigned valid_wait;
|
};
|
};
|
//static const MemDelayType MEM_DELAY[4] = {{2,3}, {2,3}, {0,0}, {0,0}};
|
//static const MemDelayType MEM_DELAY[4] = {{2,3}, {2,3}, {0,0}, {0,0}};
|
static const MemDelayType MEM_DELAY[4] = {{0,0}, {0,0}, {5,0}, {5,0}};
|
static const MemDelayType MEM_DELAY[4] = {{0,0}, {0,0}, {5,0}, {5,0}};
|
|
|
|
|
// fetch model:
|
// fetch model:
|
w_resp_ctrl_ready = 0;
|
w_resp_ctrl_ready = 0;
|
if (r.clk_cnt.read() >= 15) {
|
if (r.clk_cnt.read() >= 15) {
|
switch (r.fetch_state.read()) {
|
switch (r.fetch_state.read()) {
|
case 0:
|
case 0:
|
if (r.fetch_cnt.read() < 4) {
|
if (r.fetch_cnt.read() < 4) {
|
if (RADDR[r.fetch_cnt.read()].req_wait == 0) {
|
if (RADDR[r.fetch_cnt.read()].req_wait == 0) {
|
w_req_ctrl_valid = 1;
|
w_req_ctrl_valid = 1;
|
wb_req_ctrl_addr = RADDR[r.fetch_cnt.read()].raddr;
|
wb_req_ctrl_addr = RADDR[r.fetch_cnt.read()].raddr;
|
if (w_req_ctrl_ready) {
|
if (w_req_ctrl_ready) {
|
v.fetch_state = 3;
|
v.fetch_state = 3;
|
v.fetch_cnt = r.fetch_cnt.read() + 1;
|
v.fetch_cnt = r.fetch_cnt.read() + 1;
|
v.fetch_wait_cnt = RADDR[r.fetch_cnt.read()].accept_wait;
|
v.fetch_wait_cnt = RADDR[r.fetch_cnt.read()].accept_wait;
|
} else {
|
} else {
|
v.fetch_state = 2;
|
v.fetch_state = 2;
|
}
|
}
|
} else {
|
} else {
|
if (RADDR[r.fetch_cnt.read()].req_wait == 1) {
|
if (RADDR[r.fetch_cnt.read()].req_wait == 1) {
|
v.fetch_state = 2;
|
v.fetch_state = 2;
|
} else {
|
} else {
|
v.fetch_state = 1;
|
v.fetch_state = 1;
|
}
|
}
|
v.fetch_wait_cnt = RADDR[r.fetch_cnt.read()].req_wait;
|
v.fetch_wait_cnt = RADDR[r.fetch_cnt.read()].req_wait;
|
}
|
}
|
}
|
}
|
break;
|
break;
|
case 1:
|
case 1:
|
// wait to request:
|
// wait to request:
|
v.fetch_wait_cnt = r.fetch_wait_cnt.read() - 1;
|
v.fetch_wait_cnt = r.fetch_wait_cnt.read() - 1;
|
if (r.fetch_wait_cnt.read() == 1) {
|
if (r.fetch_wait_cnt.read() == 1) {
|
v.fetch_state = 2;
|
v.fetch_state = 2;
|
}
|
}
|
break;
|
break;
|
case 2:// wait ready signal
|
case 2:// wait ready signal
|
w_req_ctrl_valid = 1;
|
w_req_ctrl_valid = 1;
|
wb_req_ctrl_addr = RADDR[r.fetch_cnt.read()].raddr;
|
wb_req_ctrl_addr = RADDR[r.fetch_cnt.read()].raddr;
|
if (w_req_ctrl_ready) {
|
if (w_req_ctrl_ready) {
|
v.fetch_state = 3;
|
v.fetch_state = 3;
|
v.fetch_cnt = r.fetch_cnt.read() + 1;
|
v.fetch_cnt = r.fetch_cnt.read() + 1;
|
v.fetch_wait_cnt = RADDR[r.fetch_cnt.read()].accept_wait;
|
v.fetch_wait_cnt = RADDR[r.fetch_cnt.read()].accept_wait;
|
}
|
}
|
break;
|
break;
|
case 3: // wait valid signal:
|
case 3: // wait valid signal:
|
if (w_resp_ctrl_valid) {
|
if (w_resp_ctrl_valid) {
|
w_resp_ctrl_ready = 1;
|
w_resp_ctrl_ready = 1;
|
if (r.fetch_wait_cnt.read()) {
|
if (r.fetch_wait_cnt.read()) {
|
v.fetch_wait_cnt = r.fetch_wait_cnt.read() - 1;
|
v.fetch_wait_cnt = r.fetch_wait_cnt.read() - 1;
|
w_resp_ctrl_ready = 0;
|
w_resp_ctrl_ready = 0;
|
} else if (r.fetch_cnt.read() < 4) {
|
} else if (r.fetch_cnt.read() < 4) {
|
if (RADDR[r.fetch_cnt.read()].req_wait == 0) {
|
if (RADDR[r.fetch_cnt.read()].req_wait == 0) {
|
w_req_ctrl_valid = 1;
|
w_req_ctrl_valid = 1;
|
wb_req_ctrl_addr = RADDR[r.fetch_cnt.read()].raddr;
|
wb_req_ctrl_addr = RADDR[r.fetch_cnt.read()].raddr;
|
if (w_req_ctrl_ready) {
|
if (w_req_ctrl_ready) {
|
v.fetch_state = 3;
|
v.fetch_state = 3;
|
v.fetch_cnt = r.fetch_cnt.read() + 1;
|
v.fetch_cnt = r.fetch_cnt.read() + 1;
|
v.fetch_wait_cnt = RADDR[r.fetch_cnt.read()].accept_wait;
|
v.fetch_wait_cnt = RADDR[r.fetch_cnt.read()].accept_wait;
|
} else {
|
} else {
|
v.fetch_state = 2;
|
v.fetch_state = 2;
|
}
|
}
|
} else {
|
} else {
|
if (RADDR[r.fetch_cnt.read()].req_wait == 1) {
|
if (RADDR[r.fetch_cnt.read()].req_wait == 1) {
|
v.fetch_state = 2;
|
v.fetch_state = 2;
|
} else {
|
} else {
|
v.fetch_state = 1;
|
v.fetch_state = 1;
|
}
|
}
|
v.fetch_wait_cnt = RADDR[r.fetch_cnt.read()].req_wait;
|
v.fetch_wait_cnt = RADDR[r.fetch_cnt.read()].req_wait;
|
}
|
}
|
} else {
|
} else {
|
v.fetch_state = 0;
|
v.fetch_state = 0;
|
}
|
}
|
}
|
}
|
break;
|
break;
|
default:;
|
default:;
|
}
|
}
|
}
|
}
|
|
|
if (r.clk_cnt.read() == 21) {
|
if (r.clk_cnt.read() == 21) {
|
wb_req_ctrl_addr = 0x100008f8;
|
wb_req_ctrl_addr = 0x100008f8;
|
} else if (r.clk_cnt.read() == 22) {
|
} else if (r.clk_cnt.read() == 22) {
|
wb_req_ctrl_addr = 0x100007b4;
|
wb_req_ctrl_addr = 0x100007b4;
|
}
|
}
|
|
|
|
|
// Memory model:
|
// Memory model:
|
w_req_mem_ready = 0;
|
w_req_mem_ready = 0;
|
w_resp_mem_data_valid = 0;
|
w_resp_mem_data_valid = 0;
|
|
|
switch (r.mem_state.read()) {
|
switch (r.mem_state.read()) {
|
case 0: // MemIdle
|
case 0: // MemIdle
|
if (w_req_mem_valid && r.mem_cnt.read() < 4) {
|
if (w_req_mem_valid && r.mem_cnt.read() < 4) {
|
if (MEM_DELAY[r.mem_cnt.read()].rdy_wait == 0) {
|
if (MEM_DELAY[r.mem_cnt.read()].rdy_wait == 0) {
|
if (MEM_DELAY[r.mem_cnt.read()].valid_wait == 0) {
|
if (MEM_DELAY[r.mem_cnt.read()].valid_wait == 0) {
|
v.mem_state = 3;
|
v.mem_state = 3;
|
v.mem_raddr = wb_req_mem_addr;
|
v.mem_raddr = wb_req_mem_addr;
|
w_req_mem_ready = 1;
|
w_req_mem_ready = 1;
|
v.mem_cnt = r.mem_cnt.read() + 1;
|
v.mem_cnt = r.mem_cnt.read() + 1;
|
} else {
|
} else {
|
v.mem_state = 2;
|
v.mem_state = 2;
|
v.mem_wait_cnt = MEM_DELAY[r.mem_cnt.read()].valid_wait;
|
v.mem_wait_cnt = MEM_DELAY[r.mem_cnt.read()].valid_wait;
|
}
|
}
|
} else {
|
} else {
|
v.mem_state = 1;
|
v.mem_state = 1;
|
v.mem_wait_cnt = MEM_DELAY[r.mem_cnt.read()].rdy_wait;
|
v.mem_wait_cnt = MEM_DELAY[r.mem_cnt.read()].rdy_wait;
|
}
|
}
|
}
|
}
|
break;
|
break;
|
case 1:
|
case 1:
|
v.mem_wait_cnt = r.mem_wait_cnt.read() - 1;
|
v.mem_wait_cnt = r.mem_wait_cnt.read() - 1;
|
if (r.mem_wait_cnt.read() == 1) {
|
if (r.mem_wait_cnt.read() == 1) {
|
if (w_req_mem_valid) {
|
if (w_req_mem_valid) {
|
v.mem_raddr = wb_req_mem_addr;
|
v.mem_raddr = wb_req_mem_addr;
|
w_req_mem_ready = 1;
|
w_req_mem_ready = 1;
|
v.mem_cnt = r.mem_cnt.read() + 1;
|
v.mem_cnt = r.mem_cnt.read() + 1;
|
if (MEM_DELAY[r.mem_cnt.read()].valid_wait == 0) {
|
if (MEM_DELAY[r.mem_cnt.read()].valid_wait == 0) {
|
v.mem_state = 3;
|
v.mem_state = 3;
|
} else {
|
} else {
|
v.mem_state = 2;
|
v.mem_state = 2;
|
v.mem_wait_cnt = MEM_DELAY[r.mem_cnt.read()].valid_wait;
|
v.mem_wait_cnt = MEM_DELAY[r.mem_cnt.read()].valid_wait;
|
}
|
}
|
} else {
|
} else {
|
v.mem_state = 0;
|
v.mem_state = 0;
|
}
|
}
|
}
|
}
|
break;
|
break;
|
case 2:
|
case 2:
|
v.mem_wait_cnt = r.mem_wait_cnt.read() - 1;
|
v.mem_wait_cnt = r.mem_wait_cnt.read() - 1;
|
if (r.mem_wait_cnt.read() == 1) {
|
if (r.mem_wait_cnt.read() == 1) {
|
v.mem_state = 3;
|
v.mem_state = 3;
|
}
|
}
|
break;
|
break;
|
case 3:
|
case 3:
|
w_resp_mem_data_valid = 1;
|
w_resp_mem_data_valid = 1;
|
if (r.mem_raddr.read() == 0x100008f0) {
|
if (r.mem_raddr.read() == 0x100008f0) {
|
wb_resp_mem_data = 0xffdff06fea9ff0efull;
|
wb_resp_mem_data = 0xffdff06fea9ff0efull;
|
} else if (r.mem_raddr.read() == 0x100007b0) {
|
} else if (r.mem_raddr.read() == 0x100007b0) {
|
wb_resp_mem_data = 0xfa0a0a1300004a17;
|
wb_resp_mem_data = 0xfa0a0a1300004a17;
|
}
|
}
|
|
|
if (w_req_mem_valid && r.mem_cnt.read() < 4) {
|
if (w_req_mem_valid && r.mem_cnt.read() < 4) {
|
if (MEM_DELAY[r.mem_cnt.read()].rdy_wait == 0) {
|
if (MEM_DELAY[r.mem_cnt.read()].rdy_wait == 0) {
|
if (MEM_DELAY[r.mem_cnt.read()].valid_wait == 0) {
|
if (MEM_DELAY[r.mem_cnt.read()].valid_wait == 0) {
|
v.mem_state = 3;
|
v.mem_state = 3;
|
v.mem_raddr = wb_req_mem_addr;
|
v.mem_raddr = wb_req_mem_addr;
|
w_req_mem_ready = 1;
|
w_req_mem_ready = 1;
|
v.mem_cnt = r.mem_cnt.read() + 1;
|
v.mem_cnt = r.mem_cnt.read() + 1;
|
} else {
|
} else {
|
v.mem_state = 2;
|
v.mem_state = 2;
|
v.mem_wait_cnt = MEM_DELAY[r.mem_cnt.read()].valid_wait;
|
v.mem_wait_cnt = MEM_DELAY[r.mem_cnt.read()].valid_wait;
|
}
|
}
|
} else {
|
} else {
|
v.mem_state = 1;
|
v.mem_state = 1;
|
v.mem_wait_cnt = MEM_DELAY[r.mem_cnt.read()].rdy_wait;
|
v.mem_wait_cnt = MEM_DELAY[r.mem_cnt.read()].rdy_wait;
|
}
|
}
|
} else {
|
} else {
|
v.mem_state = 0;
|
v.mem_state = 0;
|
}
|
}
|
break;
|
break;
|
default:;
|
default:;
|
}
|
}
|
|
|
|
|
}
|
}
|
#endif
|
#endif
|
|
|
} // namespace debugger
|
} // namespace debugger
|
|
|
|
|