ram.cpp 10.3 KB
Newer Older
Z
Zihao Yu 已提交
1
#include "common.h"
2
#include "ram.h"
Z
Zihao Yu 已提交
3

Z
Zihao Yu 已提交
4
#define RAMSIZE (128 * 1024 * 1024)
Z
Zihao Yu 已提交
5

6 7 8 9 10
#ifdef WITH_DRAMSIM3
#include "cosimulation.h"
CoDRAMsim3 *dram = NULL;
#endif

11
static uint64_t ram[RAMSIZE / sizeof(uint64_t)];
Z
Zihao Yu 已提交
12
static long img_size = 0;
13
void* get_img_start() { return &ram[0]; }
Z
Zihao Yu 已提交
14
long get_img_size() { return img_size; }
Z
Zihao Yu 已提交
15 16
void* get_ram_start() { return &ram[0]; }
long get_ram_size() { return RAMSIZE; }
Z
Zihao Yu 已提交
17

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
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
//the third layer: one entry for 4KB (2MB in total by 512 entries). need 64 with each one all  

#define PAGESIZE (4 * 1024)  // 4KB = 2^12B
#define ENTRYNUM (PAGESIZE / 8) //512 2^9
#define PTEVOLUME (PAGESIZE * ENTRYNUM) // 2MB
#define PTENUM (RAMSIZE / PTEVOLUME) // 128MB / 2MB = 64
#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
34 35
#define PTEMMIONUM 128
#define PDEMMIONUM 1
36 37
#define PTEDEVNUM 128
#define PDEDEVNUM 1
38 39 40 41 42

  uint64_t pdde[ENTRYNUM];
  uint64_t pde[ENTRYNUM];
  uint64_t pte[PTENUM][ENTRYNUM];
  
43
  // special addr for mmio 0x40000000 - 0x4fffffff
44
  uint64_t pdemmio[ENTRYNUM];
45
  uint64_t ptemmio[PTEMMIONUM][ENTRYNUM];
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

  // 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;
66

67
  for(int i = 0; i < PTEMMIONUM; i++) {
Z
zhangzifei 已提交
68
    pdemmio[i] = (((PDDEADDR-PAGESIZE*(PTEMMIONUM+PDEMMIONUM-i)) & 0xfffff000) >> 2) | 0x1;
69 70 71 72
  }
  
  for(int outidx = 0; outidx < PTEMMIONUM; outidx++) {
    for(int inidx = 0; inidx < ENTRYNUM; inidx++) {
73
      ptemmio[outidx][inidx] = (((0x40000000 + outidx*PTEVOLUME + inidx*PAGESIZE) & 0xfffff000) >> 2) | 0xf;
74 75 76 77
    }
  }
  
  //0x800000000 - 0x87ffffff
Z
zhangzifei 已提交
78 79 80
  pdde[2] = ((PDEADDR & 0xfffff000) >> 2) | 0x1;
  //pdde[2] = ((0x80000000&0xc0000000) >> 2) | 0xf;

81
  for(int i = 0; i < PTENUM ;i++) {
Z
zhangzifei 已提交
82 83
    pde[i] = ((PTEADDR(i)&0xfffff000)>>2) | 0x1;
    //pde[i] = (((0x8000000+i*2*1024*1024)&0xffe00000)>>2) | 0xf;
84 85 86 87
  }

  for(int outidx = 0; outidx < PTENUM; outidx++ ) {
    for(int inidx = 0; inidx < ENTRYNUM; inidx++ ) {
88
      pte[outidx][inidx] = (((0x80000000 + outidx*PTEVOLUME + inidx*PAGESIZE) & 0xfffff000)>>2) | 0xf;
89 90
    }
  }
91

92 93
  memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM+PTEMMIONUM+PDEDEVNUM+PTEDEVNUM)),ptedev,PAGESIZE*PTEDEVNUM);
  memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM+PTEMMIONUM+PDEDEVNUM)),pdedev,PAGESIZE*PDEDEVNUM);
94 95
  memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM+PTEMMIONUM)),ptemmio, PAGESIZE*PTEMMIONUM);
  memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM)), pdemmio, PAGESIZE*PDEMMIONUM);
96 97 98 99
  memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM)), pdde, PAGESIZE*PDDENUM);
  memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDENUM)), pde, PAGESIZE*PDENUM);
  memcpy((char *)ram+(RAMSIZE-PAGESIZE*PTENUM), pte, PAGESIZE*PTENUM);
}
Z
zhangzifei 已提交
100

Z
Zihao Yu 已提交
101
void init_ram(const char *img) {
Z
Zihao Yu 已提交
102 103 104 105 106 107 108 109 110 111 112 113 114
  assert(img != NULL);
  FILE *fp = fopen(img, "rb");
  if (fp == NULL) {
    printf("Can not open '%s'\n", img);
    assert(0);
  }

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

  fseek(fp, 0, SEEK_END);
  img_size = ftell(fp);

  fseek(fp, 0, SEEK_SET);
115
  int ret = fread(ram, img_size, 1, fp);
Z
Zihao Yu 已提交
116 117
  assert(ret == 1);
  fclose(fp);
Z
Zihao Yu 已提交
118

Z
zhangzifei 已提交
119
  //new add
120
  addpageSv39();
Z
zhangzifei 已提交
121
  //new end
122 123 124 125 126 127 128 129 130

#ifdef WITH_DRAMSIM3
  #if !defined(DRAMSIM3_CONFIG) || !defined(DRAMSIM3_OUTDIR)
  #error DRAMSIM3_CONFIG or DRAMSIM3_OUTDIR is not defined
  #endif
  assert(dram == NULL);
  dram = new CoDRAMsim3(DRAMSIM3_CONFIG, DRAMSIM3_OUTDIR);
#endif

Z
Zihao Yu 已提交
131 132
}

Y
Yinan Xu 已提交
133 134
extern "C" uint64_t ram_read_helper(uint8_t en, uint64_t rIdx) {
  if (en && rIdx >= RAMSIZE / sizeof(uint64_t)) {
135
    printf("ERROR: ram idx = 0x%lx out of bound!\n", rIdx);
136
    assert(rIdx < RAMSIZE / sizeof(uint64_t));
137
  }
Y
Yinan Xu 已提交
138
  return (en) ? ram[rIdx] : 0;
139 140 141
}

extern "C" void ram_write_helper(uint64_t wIdx, uint64_t wdata, uint64_t wmask, uint8_t wen) {
142 143 144 145
  if (wen) {
    assert(wIdx < RAMSIZE / sizeof(uint64_t));
    ram[wIdx] = (ram[wIdx] & ~wmask) | (wdata & wmask);
  }
Z
Zihao Yu 已提交
146
}
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161

#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 已提交
162
  uint8_t  id;
163 164 165 166 167 168 169 170 171 172 173
  uint64_t data[MAX_AXI_DATA_LEN];
};

void axi_read_data(const axi_ar_channel &ar, dramsim3_meta *meta) {
  uint64_t address = ar.addr % RAMSIZE;
  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 已提交
174 175
    std::cout << "axi burst FIXED not supported!" << std::endl;
    assert(0);
176 177 178
  }
  // axi burst INCR
  else if (ar.burst == 1) {
Y
Yinan Xu 已提交
179 180 181 182 183
    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);
    }
184 185 186 187 188
  }
  // 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 已提交
189 190
    assert(transaction_size / sizeof(uint64_t) <= MAX_AXI_DATA_LEN);
    for (int i = 0; i < transaction_size / sizeof(uint64_t); i++) {
191 192 193 194 195 196 197 198 199 200 201 202 203 204
      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 已提交
205
  meta->id = ar.id;
206 207 208 209 210 211 212 213 214
}

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;
    meta->offset = 0;
Y
Yinan Xu 已提交
215
    meta->id = axi.aw.id;
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
  }
  else {
    axi_read_data(axi.ar, meta);
  }
  CoDRAMRequest *req = new CoDRAMRequest();
  req->address = address;
  req->is_write = is_write;
  req->meta = meta;
  return req;
}

void dramsim3_helper(axi_channel &axi) {
  // ticks DRAMsim3 according to CPU_FREQ:DRAM_FREQ
  dram->tick();

  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;

  // default branch to avoid wrong handshake
  axi.aw.ready = 0;
  axi.w.ready  = 1;
  axi.b.valid  = 0;
  axi.ar.ready = 0;
  // axi.r.valid  = 0;

  // AXI read
  // first, check rdata in the last cycle
  if (axi.r.ready && axi.r.valid) {
Y
Yinan Xu 已提交
248
    // printf("axi r channel fired data = %lx\n", axi.r.data[0]);
249 250 251 252 253 254 255 256 257 258 259 260
    dramsim3_meta *meta = static_cast<dramsim3_meta *>(wait_resp_r->req->meta);
    meta->offset++;
    axi.r.valid = 0;
  }
  if (wait_resp_r) {
    dramsim3_meta *meta = static_cast<dramsim3_meta *>(wait_resp_r->req->meta);
    if (meta->offset == meta->len) {
      delete meta;
      delete wait_resp_r->req;
      delete wait_resp_r;
      wait_resp_r = NULL;
    }
Y
Yinan Xu 已提交
261 262 263 264 265 266 267 268 269 270 271 272
  }
  // second, check whether we response data in this cycle
  if (!wait_resp_r)
    wait_resp_r = dram->check_read_response();
  if (wait_resp_r) {
    dramsim3_meta *meta = static_cast<dramsim3_meta *>(wait_resp_r->req->meta);
    // axi.r.data = meta->data[meta->offset];
    // printf("meta->size %d offset %d\n", meta->size, meta->offset*meta->size/sizeof(uint64_t));
    memcpy(axi.r.data, meta->data + meta->offset*meta->size/sizeof(uint64_t), meta->size);
    axi.r.valid = 1;
    axi.r.last = (meta->offset == meta->len - 1) ? 1 : 0;
    axi.r.id = meta->id;
273 274 275 276
  }
  // third, check ar for next request's address
  // put ar in the last since it should be at least one-cycle latency
  if (axi.ar.valid && dram->will_accept(axi.ar.addr, false)) {
Y
Yinan Xu 已提交
277
    // printf("axi ar channel fired %lx\n", axi.ar.addr);
278 279 280 281 282 283 284 285 286 287 288
    dram->add_request(dramsim3_request(axi, false));
    axi.ar.ready = 1;
  }

  // AXI write
  // first, check wdata in the last cycle
  // aw channel
  if (axi.aw.valid && dram->will_accept(axi.aw.addr, true)) {
    assert(wait_req_w == NULL); // the last request has not finished
    wait_req_w = dramsim3_request(axi, true);
    axi.aw.ready = 1;
Y
Yinan Xu 已提交
289 290
    // printf("axi aw channel fired %lx\n", axi.aw.addr);
    assert(axi.aw.burst == 1 || (axi.aw.burst == 2 && ((axi.aw.addr & 0x3f) == 0)));
291 292 293 294
  }

  // w channel: ack write data
  if (axi.w.valid && axi.w.ready) {
Y
Yinan Xu 已提交
295
    // printf("axi w channel fired\n");
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
    assert(wait_req_w);
    dramsim3_meta *meta = static_cast<dramsim3_meta *>(wait_req_w->meta);
    // meta->data[meta->offset] = axi.w.data;
    meta->offset++;
    if (meta->offset == meta->len) {
      assert(dram->will_accept(wait_req_w->address, true));
      dram->add_request(wait_req_w);
      wait_req_w = NULL;
    }
  }

  // b channel: ack write
  if (!wait_resp_b)
    wait_resp_b = dram->check_write_response();
  if (wait_resp_b) {
    dramsim3_meta *meta = static_cast<dramsim3_meta *>(wait_resp_b->req->meta);
    axi.b.valid = 1;
Y
Yinan Xu 已提交
313
    axi.b.id = meta->id;
314 315 316 317 318 319 320 321 322 323 324 325 326 327
    // assert(axi.b.ready == 1);
    for (int i = 0; i < meta->len; i++) {
      uint64_t address = wait_resp_b->req->address % RAMSIZE;
      ram[address / sizeof(uint64_t) + i] = meta->data[i];
    }
    // printf("axi b channel fired\n");
    delete meta;
    delete wait_resp_b->req;
    delete wait_resp_b;
    wait_resp_b = NULL;
  }
}

#endif