山东大学RISC-V公共开放平台开发记录9

山东大学RISC-V公共开放平台开发记录

risc-V模拟器-2

1 内存管理模块MemoryManager

MemoryManager的功能是为模拟器提供一个简单易使用的内存访问接口,必须支持任意内存大小、内存地址的访存,还要能检测到非法内存地址访问。事实上,这非常类似于操作系统中虚拟内存的机制。因此,MemoryManager的内部实现采用了类似x86体系结构中使用的二级页表的机制。具体地说,将32位内存空间在逻辑上划分为大小为4KB(2^12)的页,并且采用内存地址的前10位作为一级页表的索引,紧接着10位作为二级页表的索引,最后12位作为一个内存页里的下标。

页表结构可以如下声明

uint8_t **memory[1024];

其中,memory指向一个长度为1024的一级页表数组,memory[i]指向长度为1024的二级页表数组,memory[i][j]指向具体的内存页,memory[i][j][k]可以取出内存地址为(i<<22)|(j<<12)|k的一个字节。可以在需要的时候对memory进行动态内存分配和释放。模拟器对memory的一个访存过程的示例如下

uint8_t MemoryManager::getByte(uint32_t addr) {
  if (!this->isAddrExist(addr)) {
    dbgprintf("Byte read to invalid addr 0x%x!\n", addr);
    return false;
  }
  uint32_t i = this->getFirstEntryId(addr);
  uint32_t j = this->getSecondEntryId(addr);
  uint32_t k = this->getPageOffset(addr);
  return this->memory[i][j][k];
}

2 可执行文件的装载、初始化

本模拟器的可执行文件加载部分采用了GitHub上的开源库ELFIO(https://github.com/serge1/ELFIO),由于这个库只有头文件,所以导入工程相当容易,相关头文件在include/文件夹下。

使用这个库进行ELF文件加载相当容易

// Read ELF file
ELFIO::elfio reader;
if (!reader.load(elfFile)) {
  fprintf(stderr, "Fail to load ELF file %s!\n", elfFile);
  return -1;
}

加载ELF文件进内存的代码如下,直接按照ELF文件头的信息将每个数据段拷贝到指定的内存位置即可,唯一需要注意的是文件内数据长度可能小于指定的内存长度,需要用0填充。值得一提的是本模拟器在设计时并未考虑支持32位以上的内存,因为内存占用如此之大的用户程序是比较罕见的,在我们用的测试程序中不会出现这种情况。

void loadElfToMemory(ELFIO::elfio *reader, MemoryManager *memory) {
  ELFIO::Elf_Half seg_num = reader->segments.size();
  for (int i = 0; i < seg_num; ++i) {
    const ELFIO::segment *pseg = reader->segments[i];

    uint64_t fullmemsz = pseg->get_memory_size();
    uint64_t fulladdr = pseg->get_virtual_address();
    // Our 32bit simulator cannot handle this
    if (fulladdr + fullmemsz > 0xFFFFFFFF) {
      dbgprintf(
          "ELF address space larger than 32bit! Seg %d has max addr of 0x%lx\n",
          i, fulladdr + fullmemsz);
      exit(-1);
    }

    uint32_t filesz = pseg->get_file_size();
    uint32_t memsz = pseg->get_memory_size();
    uint32_t addr = (uint32_t)pseg->get_virtual_address();

    for (uint32_t p = addr; p < addr + memsz; ++p) {
      if (!memory->isPageExist(p)) {
        memory->addPage(p);
      }

      if (p < addr + filesz) {
        memory->setByte(p, pseg->get_data()[p - addr]);
      } else {
        memory->setByte(p, 0);
      }
    }
  }
}

最后,需要在模拟器初始化时手动设置PC的值。

simulator.pc = reader.get_entry();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值