ram.cpp 12.9 KB
Newer Older
1 2
#include <sys/mman.h>

Z
Zihao Yu 已提交
3
#include "common.h"
4
#include "ram.h"
5
#include "compress.h"
Z
Zihao Yu 已提交
6

Z
ZhangZifei 已提交
7
// #define TLB_UNITTEST
Z
Zihao Yu 已提交
8

9 10 11 12 13
#ifdef WITH_DRAMSIM3
#include "cosimulation.h"
CoDRAMsim3 *dram = NULL;
#endif

14
static uint64_t *ram;
Z
Zihao Yu 已提交
15
static long img_size = 0;
16 17
static pthread_mutex_t ram_mutex;

18
void* get_img_start() { return &ram[0]; }
Z
Zihao Yu 已提交
19
long get_img_size() { return img_size; }
Z
Zihao Yu 已提交
20
void* get_ram_start() { return &ram[0]; }
Y
Yinan Xu 已提交
21
long get_ram_size() { return EMU_RAM_SIZE; }
Z
Zihao Yu 已提交
22

23
#ifdef TLB_UNITTEST
24 25 26 27 28
void addpageSv39() {
//three layers
//addr range: 0x0000000080000000 - 0x0000000088000000 for 128MB from 2GB - 2GB128MB
//the first layer: one entry for 1GB. (512GB in total by 512 entries). need the 2th entries
//the second layer: one entry for 2MB. (1GB in total by 512 entries). need the 0th-63rd entries
29 30
//the third layer: one entry for 4KB (2MB in total by 512 entries). need 64 with each one all
#define TOPSIZE (128 * 1024 * 1024)
31 32 33
#define PAGESIZE (4 * 1024)  // 4KB = 2^12B
#define ENTRYNUM (PAGESIZE / 8) //512 2^9
#define PTEVOLUME (PAGESIZE * ENTRYNUM) // 2MB
34
#define PTENUM (TOPSIZE / PTEVOLUME) // 128MB / 2MB = 64
35 36 37 38 39
#define PDDENUM 1
#define PDENUM 1
#define PDDEADDR (0x88000000 - (PAGESIZE * (PTENUM + 2))) //0x88000000 - 0x1000*66
#define PDEADDR (0x88000000 - (PAGESIZE * (PTENUM + 1))) //0x88000000 - 0x1000*65
#define PTEADDR(i) (0x88000000 - (PAGESIZE * PTENUM) + (PAGESIZE * i)) //0x88000000 - 0x100*64
40 41
#define PTEMMIONUM 128
#define PDEMMIONUM 1
42 43
#define PTEDEVNUM 128
#define PDEDEVNUM 1
44 45 46 47

  uint64_t pdde[ENTRYNUM];
  uint64_t pde[ENTRYNUM];
  uint64_t pte[PTENUM][ENTRYNUM];
48

49
  // special addr for mmio 0x40000000 - 0x4fffffff
50
  uint64_t pdemmio[ENTRYNUM];
51
  uint64_t ptemmio[PTEMMIONUM][ENTRYNUM];
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

  // special addr for internal devices 0x30000000-0x3fffffff
  uint64_t pdedev[ENTRYNUM];
  uint64_t ptedev[PTEDEVNUM][ENTRYNUM];

  // dev: 0x30000000-0x3fffffff
  pdde[0] = (((PDDEADDR-PAGESIZE*(PDEMMIONUM+PTEMMIONUM+PDEDEVNUM)) & 0xfffff000) >> 2) | 0x1;

  for (int i = 0; i < PTEDEVNUM; i++) {
    pdedev[ENTRYNUM-PTEDEVNUM+i] = (((PDDEADDR-PAGESIZE*(PDEMMIONUM+PTEMMIONUM+PDEDEVNUM+PTEDEVNUM-i)) & 0xfffff000) >> 2) | 0x1;
  }

  for(int outidx = 0; outidx < PTEDEVNUM; outidx++) {
    for(int inidx = 0; inidx < ENTRYNUM; inidx++) {
      ptedev[outidx][inidx] = (((0x30000000 + outidx*PTEVOLUME + inidx*PAGESIZE) & 0xfffff000) >> 2) | 0xf;
    }
  }

  // mmio: 0x40000000 - 0x4fffffff
  pdde[1] = (((PDDEADDR-PAGESIZE*PDEMMIONUM) & 0xfffff000) >> 2) | 0x1;
72

73
  for(int i = 0; i < PTEMMIONUM; i++) {
Z
zhangzifei 已提交
74
    pdemmio[i] = (((PDDEADDR-PAGESIZE*(PTEMMIONUM+PDEMMIONUM-i)) & 0xfffff000) >> 2) | 0x1;
75
  }
76

77 78
  for(int outidx = 0; outidx < PTEMMIONUM; outidx++) {
    for(int inidx = 0; inidx < ENTRYNUM; inidx++) {
79
      ptemmio[outidx][inidx] = (((0x40000000 + outidx*PTEVOLUME + inidx*PAGESIZE) & 0xfffff000) >> 2) | 0xf;
80 81
    }
  }
82

83
  //0x800000000 - 0x87ffffff
Z
zhangzifei 已提交
84 85 86
  pdde[2] = ((PDEADDR & 0xfffff000) >> 2) | 0x1;
  //pdde[2] = ((0x80000000&0xc0000000) >> 2) | 0xf;

87
  for(int i = 0; i < PTENUM ;i++) {
88 89
    // pde[i] = ((PTEADDR(i)&0xfffff000)>>2) | 0x1;
    pde[i] = (((0x80000000+i*2*1024*1024)&0xffe00000)>>2) | 0xf;
90 91 92 93
  }

  for(int outidx = 0; outidx < PTENUM; outidx++ ) {
    for(int inidx = 0; inidx < ENTRYNUM; inidx++ ) {
94
      pte[outidx][inidx] = (((0x80000000 + outidx*PTEVOLUME + inidx*PAGESIZE) & 0xfffff000)>>2) | 0xf;
95 96
    }
  }
97

98
  printf("try to add identical tlb page to ram\n");
99 100 101 102 103 104 105
  memcpy((char *)ram+(TOPSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM+PTEMMIONUM+PDEDEVNUM+PTEDEVNUM)),ptedev,PAGESIZE*PTEDEVNUM);
  memcpy((char *)ram+(TOPSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM+PTEMMIONUM+PDEDEVNUM)),pdedev,PAGESIZE*PDEDEVNUM);
  memcpy((char *)ram+(TOPSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM+PTEMMIONUM)),ptemmio, PAGESIZE*PTEMMIONUM);
  memcpy((char *)ram+(TOPSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM)), pdemmio, PAGESIZE*PDEMMIONUM);
  memcpy((char *)ram+(TOPSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM)), pdde, PAGESIZE*PDDENUM);
  memcpy((char *)ram+(TOPSIZE-PAGESIZE*(PTENUM+PDENUM)), pde, PAGESIZE*PDENUM);
  memcpy((char *)ram+(TOPSIZE-PAGESIZE*PTENUM), pte, PAGESIZE*PTENUM);
106
}
107
#endif
Z
zhangzifei 已提交
108

Z
Zihao Yu 已提交
109
void init_ram(const char *img) {
Z
Zihao Yu 已提交
110 111 112 113
  assert(img != NULL);

  printf("The image is %s\n", img);

114
  // initialize memory using Linux mmap
Y
Yinan Xu 已提交
115 116
  printf("Using simulated %luMB RAM\n", EMU_RAM_SIZE / (1024 * 1024));
  ram = (uint64_t *)mmap(NULL, EMU_RAM_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
117
  if (ram == (uint64_t *)MAP_FAILED) {
Y
Yinan Xu 已提交
118
    printf("Cound not mmap 0x%lx bytes\n", EMU_RAM_SIZE);
119 120 121
    assert(0);
  }

122 123 124 125 126 127
#ifdef TLB_UNITTEST
  //new add
  addpageSv39();
  //new end
#endif

Z
zoujr 已提交
128 129
  int ret;
  if (isGzFile(img)) {
130
    printf("Gzip file detected and loading image from extracted gz file\n");
Y
Yinan Xu 已提交
131
    img_size = readFromGz(ram, img, EMU_RAM_SIZE, LOAD_RAM);
Z
zoujr 已提交
132
    assert(img_size >= 0);
Y
Yinan Xu 已提交
133
  }
Z
zoujr 已提交
134 135 136 137 138 139 140 141 142
  else {
    FILE *fp = fopen(img, "rb");
    if (fp == NULL) {
      printf("Can not open '%s'\n", img);
      assert(0);
    }

    fseek(fp, 0, SEEK_END);
    img_size = ftell(fp);
Y
Yinan Xu 已提交
143 144
    if (img_size > EMU_RAM_SIZE) {
      img_size = EMU_RAM_SIZE;
Z
zoujr 已提交
145 146 147 148 149 150
    }

    fseek(fp, 0, SEEK_SET);
    ret = fread(ram, img_size, 1, fp);

    assert(ret == 1);
151
    fclose(fp);
Z
zoujr 已提交
152
  }
Z
Zihao Yu 已提交
153

154 155 156 157 158
#ifdef WITH_DRAMSIM3
  #if !defined(DRAMSIM3_CONFIG) || !defined(DRAMSIM3_OUTDIR)
  #error DRAMSIM3_CONFIG or DRAMSIM3_OUTDIR is not defined
  #endif
  assert(dram == NULL);
Y
Yinan Xu 已提交
159 160
  // dram = new ComplexCoDRAMsim3(DRAMSIM3_CONFIG, DRAMSIM3_OUTDIR);
  dram = new SimpleCoDRAMsim3(10);
161 162
#endif

163 164
  pthread_mutex_init(&ram_mutex, 0);

Z
Zihao Yu 已提交
165 166
}

167
void ram_finish() {
Y
Yinan Xu 已提交
168
  munmap(ram, EMU_RAM_SIZE);
169 170 171
#ifdef WITH_DRAMSIM3
  dramsim3_finish();
#endif
172
  pthread_mutex_destroy(&ram_mutex);
173 174
}

175

Y
Yinan Xu 已提交
176
extern "C" uint64_t ram_read_helper(uint8_t en, uint64_t rIdx) {
Y
Yinan Xu 已提交
177 178
  if (en && rIdx >= EMU_RAM_SIZE / sizeof(uint64_t)) {
    rIdx %= EMU_RAM_SIZE / sizeof(uint64_t);
179
  }
180 181 182 183
  pthread_mutex_lock(&ram_mutex);
  uint64_t rdata = (en) ? ram[rIdx] : 0;
  pthread_mutex_unlock(&ram_mutex);
  return rdata;
184 185 186
}

extern "C" void ram_write_helper(uint64_t wIdx, uint64_t wdata, uint64_t wmask, uint8_t wen) {
187
  if (wen) {
Y
Yinan Xu 已提交
188
    if (wIdx >= EMU_RAM_SIZE / sizeof(uint64_t)) {
Y
Yinan Xu 已提交
189
      printf("ERROR: ram wIdx = 0x%lx out of bound!\n", wIdx);
Y
Yinan Xu 已提交
190
      assert(wIdx < EMU_RAM_SIZE / sizeof(uint64_t));
Y
Yinan Xu 已提交
191
    }
192
    pthread_mutex_lock(&ram_mutex);
193
    ram[wIdx] = (ram[wIdx] & ~wmask) | (wdata & wmask);
194
    pthread_mutex_unlock(&ram_mutex);
195
  }
Z
Zihao Yu 已提交
196
}
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211

#ifdef WITH_DRAMSIM3
#include <iostream>

void dramsim3_finish() {
  delete dram;
}

#define MAX_AXI_DATA_LEN 8

// currently does not support masked read or write
struct dramsim3_meta {
  uint8_t  len;
  uint8_t  size;
  uint8_t  offset;
Y
Yinan Xu 已提交
212
  uint8_t  id;
213 214 215 216
  uint64_t data[MAX_AXI_DATA_LEN];
};

void axi_read_data(const axi_ar_channel &ar, dramsim3_meta *meta) {
Y
Yinan Xu 已提交
217
  uint64_t address = ar.addr % EMU_RAM_SIZE;
218 219 220 221 222 223
  uint64_t beatsize = 1 << ar.size;
  uint8_t  beatlen  = ar.len + 1;
  uint64_t transaction_size = beatsize * beatlen;
  assert((transaction_size % sizeof(uint64_t)) == 0);
  // axi burst FIXED
  if (ar.burst == 0x0) {
Y
Yinan Xu 已提交
224 225
    std::cout << "axi burst FIXED not supported!" << std::endl;
    assert(0);
226 227 228
  }
  // axi burst INCR
  else if (ar.burst == 1) {
Y
Yinan Xu 已提交
229 230 231 232 233
    assert(transaction_size / sizeof(uint64_t) <= MAX_AXI_DATA_LEN);
    for (int i = 0; i < transaction_size / sizeof(uint64_t); i++) {
      meta->data[i] = ram[address / sizeof(uint64_t)];
      address += sizeof(uint64_t);
    }
234 235 236 237 238
  }
  // axi burst WRAP
  else if (ar.burst == 2) {
    uint64_t low = (address / transaction_size) * transaction_size;
    uint64_t high = low + transaction_size;
Y
Yinan Xu 已提交
239 240
    assert(transaction_size / sizeof(uint64_t) <= MAX_AXI_DATA_LEN);
    for (int i = 0; i < transaction_size / sizeof(uint64_t); i++) {
241 242 243 244 245 246 247 248 249 250 251 252 253 254
      if (address == high) {
        address = low;
      }
      meta->data[i] = ram[address / sizeof(uint64_t)];
      address += sizeof(uint64_t);
    }
  }
  else {
    std::cout << "reserved arburst!" << std::endl;
    assert(0);
  }
  meta->len = beatlen;
  meta->size = beatsize;
  meta->offset = 0;
Y
Yinan Xu 已提交
255
  meta->id = ar.id;
256 257 258 259 260 261 262 263
}

CoDRAMRequest *dramsim3_request(const axi_channel &axi, bool is_write) {
  uint64_t address = (is_write) ? axi.aw.addr : axi.ar.addr;
  dramsim3_meta *meta = new dramsim3_meta;
  // WRITE
  if (is_write) {
    meta->len = axi.aw.len + 1;
264
    meta->size = 1 << axi.aw.size;
265
    meta->offset = 0;
Y
Yinan Xu 已提交
266
    meta->id = axi.aw.id;
267 268 269 270 271 272 273 274 275 276 277
  }
  else {
    axi_read_data(axi.ar, meta);
  }
  CoDRAMRequest *req = new CoDRAMRequest();
  req->address = address;
  req->is_write = is_write;
  req->meta = meta;
  return req;
}

278 279 280 281 282 283 284 285
static CoDRAMResponse *wait_resp_r = NULL;
static CoDRAMResponse *wait_resp_b = NULL;
static CoDRAMRequest *wait_req_w = NULL;
// currently only accept one in-flight read + one in-flight write
static uint64_t raddr, roffset = 0, rlen;
static uint64_t waddr, woffset = 0, wlen;

void dramsim3_helper_rising(const axi_channel &axi) {
286 287 288
  // ticks DRAMsim3 according to CPU_FREQ:DRAM_FREQ
  dram->tick();

289 290 291 292 293 294
  // read data fire: check the last read request
  if (axi_check_rdata_fire(axi)) {
    if (wait_resp_r == NULL) {
      printf("ERROR: There's no in-flight read request.\n");
      assert(wait_resp_r != NULL);
    }
295 296
    dramsim3_meta *meta = static_cast<dramsim3_meta *>(wait_resp_r->req->meta);
    meta->offset++;
297
    // check whether the last rdata response has finished
298 299 300 301 302 303
    if (meta->offset == meta->len) {
      delete meta;
      delete wait_resp_r->req;
      delete wait_resp_r;
      wait_resp_r = NULL;
    }
Y
Yinan Xu 已提交
304
  }
305 306 307

  // read address fire: accept a new request
  if (axi_check_raddr_fire(axi)) {
308 309 310
    dram->add_request(dramsim3_request(axi, false));
  }

311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
  // the last write transaction is acknowledged
  if (axi_check_wack_fire(axi)) {
    if (wait_resp_b == NULL) {
      printf("ERROR: write response fire for nothing in-flight.\n");
      assert(wait_resp_b != NULL);
    }
    // flush data to memory
    uint64_t waddr = wait_resp_b->req->address % EMU_RAM_SIZE;
    dramsim3_meta *meta = static_cast<dramsim3_meta *>(wait_resp_b->req->meta);
    void *start_addr = ram + (waddr / sizeof(uint64_t));
    memcpy(start_addr, meta->data, meta->len * meta->size);
    for (int i = 0; i < meta->len; i++) {
    //   uint64_t address = wait_resp_b->req->address % EMU_RAM_SIZE;
    //   ram[address / sizeof(uint64_t) + i] = meta->data[i];
      // printf("flush write to memory[0x%ld] = 0x%lx\n", address)
    }
    delete meta;
    delete wait_resp_b->req;
    delete wait_resp_b;
    wait_resp_b = NULL;
  }

  // write address fire: accept a new write request
  if (axi_check_waddr_fire(axi)) {
    if (wait_req_w != NULL) {
      printf("ERROR: The last write request has not finished.\n");
      assert(wait_req_w == NULL);
    }
339
    wait_req_w = dramsim3_request(axi, true);
340
    // printf("accept a new write request to addr = 0x%lx, len = %d\n", axi.aw.addr, axi.aw.len);
341 342
  }

343 344 345 346 347 348
  // write data fire: for the last write transaction
  if (axi_check_wdata_fire(axi)) {
    if (wait_req_w == NULL) {
      printf("ERROR: wdata fire for nothing in-flight.\n");
      assert(wait_req_w != NULL);
    }
349
    dramsim3_meta *meta = static_cast<dramsim3_meta *>(wait_req_w->meta);
350 351
    void *data_start = meta->data + meta->offset * meta->size / sizeof(uint64_t);
    axi_get_wdata(axi, data_start, meta->size);
352
    meta->offset++;
353
    // if this is the last beat
354 355 356 357 358
    if (meta->offset == meta->len) {
      assert(dram->will_accept(wait_req_w->address, true));
      dram->add_request(wait_req_w);
      wait_req_w = NULL;
    }
359
    // printf("accept a new write data\n");
360
  }
361 362 363 364 365 366 367 368 369
}

void dramsim3_helper_falling(axi_channel &axi) {
  // default branch to avoid wrong handshake
  axi.aw.ready = 0;
  axi.w.ready  = 0;
  axi.b.valid  = 0;
  axi.ar.ready = 0;
  axi.r.valid  = 0;
370

371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
  // RDATA: if finished, we try the next rdata response
  if (!wait_resp_r)
    wait_resp_r = dram->check_read_response();
  // if there's some data response, put it onto axi bus
  if (wait_resp_r) {
    dramsim3_meta *meta = static_cast<dramsim3_meta *>(wait_resp_r->req->meta);
    // printf("meta->size %d offset %d\n", meta->size, meta->offset*meta->size/sizeof(uint64_t));
    void *data_start = meta->data + meta->offset*meta->size / sizeof(uint64_t);
    axi_put_rdata(axi, data_start, meta->size, meta->offset == meta->len - 1, meta->id);
  }

  // RADDR: check whether the read request can be accepted
  axi_addr_t raddr;
  if (axi_get_raddr(axi, raddr) && dram->will_accept(raddr, false)) {
    axi_accept_raddr(axi);
    // printf("try to accept read request to 0x%lx\n", raddr);
  }

  // WREQ: check whether the write request can be accepted
  // Note: block the next write here to simplify logic
  axi_addr_t waddr;
  if (wait_req_w == NULL && axi_get_waddr(axi, waddr) && dram->will_accept(waddr, false)) {
    axi_accept_waddr(axi);
    axi_accept_wdata(axi);
    // printf("try to accept write request to 0x%lx\n", waddr);
  }

  // WDATA: check whether the write data can be accepted
  if (wait_req_w != NULL) {
    axi_accept_wdata(axi);
  }

  // WRESP: if finished, we try the next write response
404 405
  if (!wait_resp_b)
    wait_resp_b = dram->check_write_response();
406
  // if there's some write response, put it onto axi bus
407 408
  if (wait_resp_b) {
    dramsim3_meta *meta = static_cast<dramsim3_meta *>(wait_resp_b->req->meta);
409
    axi_put_wack(axi, meta->id);
410 411 412 413
  }
}

#endif