2014-09-12 19:15:04 +02:00
|
|
|
// See LICENSE for license details.
|
|
|
|
|
2012-12-04 16:04:26 +01:00
|
|
|
#include "mm.h"
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cassert>
|
|
|
|
|
2015-10-14 20:33:18 +02:00
|
|
|
void mm_t::write(uint64_t addr, uint8_t *data, uint64_t strb, uint64_t size)
|
|
|
|
{
|
2016-04-02 02:53:59 +02:00
|
|
|
strb &= ((1 << size) - 1) << (addr % word_size);
|
2016-05-03 03:34:27 +02:00
|
|
|
addr %= this->size;
|
2015-10-14 20:33:18 +02:00
|
|
|
|
2016-04-02 02:53:59 +02:00
|
|
|
uint8_t *base = this->data + (addr / word_size) * word_size;
|
|
|
|
for (int i = 0; i < word_size; i++) {
|
2015-10-14 20:33:18 +02:00
|
|
|
if (strb & 1)
|
|
|
|
base[i] = data[i];
|
|
|
|
strb >>= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-02 02:53:59 +02:00
|
|
|
std::vector<char> mm_t::read(uint64_t addr)
|
2015-10-14 20:33:18 +02:00
|
|
|
{
|
2016-05-03 03:34:27 +02:00
|
|
|
addr %= this->size;
|
2015-10-14 20:33:18 +02:00
|
|
|
|
|
|
|
uint8_t *base = this->data + addr;
|
2016-04-02 02:53:59 +02:00
|
|
|
return std::vector<char>(base, base + word_size);
|
2015-10-14 20:33:18 +02:00
|
|
|
}
|
|
|
|
|
2013-05-02 13:58:43 +02:00
|
|
|
void mm_t::init(size_t sz, int wsz, int lsz)
|
2012-12-04 16:04:26 +01:00
|
|
|
{
|
2013-05-02 13:58:43 +02:00
|
|
|
assert(wsz > 0 && lsz > 0 && (lsz & (lsz-1)) == 0 && lsz % wsz == 0);
|
|
|
|
word_size = wsz;
|
|
|
|
line_size = lsz;
|
2015-10-14 20:33:18 +02:00
|
|
|
data = new uint8_t[sz];
|
2012-12-04 16:04:26 +01:00
|
|
|
size = sz;
|
|
|
|
}
|
|
|
|
|
|
|
|
mm_t::~mm_t()
|
|
|
|
{
|
|
|
|
delete [] data;
|
|
|
|
}
|
|
|
|
|
2013-05-02 13:58:43 +02:00
|
|
|
void mm_magic_t::init(size_t sz, int wsz, int lsz)
|
2012-12-04 16:04:26 +01:00
|
|
|
{
|
2013-05-02 13:58:43 +02:00
|
|
|
mm_t::init(sz, wsz, lsz);
|
|
|
|
dummy_data.resize(word_size);
|
2012-12-04 16:04:26 +01:00
|
|
|
}
|
|
|
|
|
2015-10-14 20:33:18 +02:00
|
|
|
void mm_magic_t::tick(
|
|
|
|
bool ar_valid,
|
|
|
|
uint64_t ar_addr,
|
|
|
|
uint64_t ar_id,
|
|
|
|
uint64_t ar_size,
|
|
|
|
uint64_t ar_len,
|
2012-12-04 16:04:26 +01:00
|
|
|
|
2015-10-14 20:33:18 +02:00
|
|
|
bool aw_valid,
|
|
|
|
uint64_t aw_addr,
|
|
|
|
uint64_t aw_id,
|
|
|
|
uint64_t aw_size,
|
|
|
|
uint64_t aw_len,
|
2012-12-04 16:04:26 +01:00
|
|
|
|
2015-10-14 20:33:18 +02:00
|
|
|
bool w_valid,
|
|
|
|
uint64_t w_strb,
|
|
|
|
void *w_data,
|
|
|
|
bool w_last,
|
2012-12-04 16:04:26 +01:00
|
|
|
|
2015-10-14 20:33:18 +02:00
|
|
|
bool r_ready,
|
|
|
|
bool b_ready)
|
|
|
|
{
|
|
|
|
bool ar_fire = ar_valid && ar_ready();
|
|
|
|
bool aw_fire = aw_valid && aw_ready();
|
|
|
|
bool w_fire = w_valid && w_ready();
|
|
|
|
bool r_fire = r_valid() && r_ready;
|
|
|
|
bool b_fire = b_valid() && b_ready;
|
|
|
|
|
|
|
|
if (ar_fire) {
|
2016-04-02 02:53:59 +02:00
|
|
|
uint64_t start_addr = (ar_addr / word_size) * word_size;
|
2015-10-14 20:33:18 +02:00
|
|
|
for (int i = 0; i <= ar_len; i++) {
|
2016-04-02 02:53:59 +02:00
|
|
|
auto dat = read(start_addr + i * word_size);
|
2015-10-14 20:33:18 +02:00
|
|
|
rresp.push(mm_rresp_t(ar_id, dat, i == ar_len));
|
|
|
|
}
|
2012-12-04 16:04:26 +01:00
|
|
|
}
|
|
|
|
|
2015-10-14 20:33:18 +02:00
|
|
|
if (aw_fire) {
|
|
|
|
store_addr = aw_addr;
|
|
|
|
store_id = aw_id;
|
|
|
|
store_count = aw_len + 1;
|
2016-04-02 02:53:59 +02:00
|
|
|
store_size = 1 << aw_size;
|
|
|
|
store_inflight = true;
|
2015-10-14 20:33:18 +02:00
|
|
|
}
|
2012-12-04 16:04:26 +01:00
|
|
|
|
2015-10-14 20:33:18 +02:00
|
|
|
if (w_fire) {
|
|
|
|
write(store_addr, (uint8_t *) w_data, w_strb, store_size);
|
|
|
|
store_addr += store_size;
|
|
|
|
store_count--;
|
|
|
|
|
|
|
|
if (store_count == 0) {
|
|
|
|
store_inflight = false;
|
|
|
|
bresp.push(store_id);
|
|
|
|
assert(w_last);
|
2012-12-04 16:04:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-14 20:33:18 +02:00
|
|
|
if (b_fire)
|
|
|
|
bresp.pop();
|
|
|
|
|
|
|
|
if (r_fire)
|
|
|
|
rresp.pop();
|
|
|
|
|
2012-12-04 16:04:26 +01:00
|
|
|
cycle++;
|
|
|
|
}
|
|
|
|
|
2015-11-05 19:15:02 +01:00
|
|
|
void load_mem(void** mems, const char* fn, int line_size, int nchannels)
|
2012-12-04 16:04:26 +01:00
|
|
|
{
|
2015-11-03 07:46:52 +01:00
|
|
|
char* m;
|
|
|
|
ssize_t start = 0;
|
2012-12-04 16:04:26 +01:00
|
|
|
std::ifstream in(fn);
|
|
|
|
if (!in)
|
|
|
|
{
|
|
|
|
std::cerr << "could not open " << fn << std::endl;
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string line;
|
|
|
|
while (std::getline(in, line))
|
|
|
|
{
|
|
|
|
#define parse_nibble(c) ((c) >= 'a' ? (c)-'a'+10 : (c)-'0')
|
2015-11-03 07:46:52 +01:00
|
|
|
for (ssize_t i = line.length()-2, j = 0; i >= 0; i -= 2, j++) {
|
|
|
|
char data = (parse_nibble(line[i]) << 4) | parse_nibble(line[i+1]);
|
|
|
|
ssize_t addr = start + j;
|
2015-11-05 19:15:02 +01:00
|
|
|
int channel = (addr / line_size) % nchannels;
|
2015-11-03 07:46:52 +01:00
|
|
|
m = (char *) mems[channel];
|
2015-11-05 19:15:02 +01:00
|
|
|
addr = (addr / line_size / nchannels) * line_size + (addr % line_size);
|
2015-11-03 07:46:52 +01:00
|
|
|
m[addr] = data;
|
|
|
|
}
|
|
|
|
start += line.length()/2;
|
2012-12-04 16:04:26 +01:00
|
|
|
}
|
|
|
|
}
|