之前写了一个很简单的 Program Loader,
现在就来真正的实作它,让它能够把编译好的程序放到指定位置吧。
主要参考对象是我们的老朋友:RISC-V-TLM
大部分的 SOC 都会有一些开机的流程,
例如先把程序烧进去指定装置的指定位置上,
然後就是多个阶段的 Boot Loader,
第一阶段被 Hardware 的机制 Load 起来,
第二阶段被第一阶段 Loader Load 起来,
每一阶段都做一点准备 (设定 Externam Device Register, 启动 MMU 等),
最後把主程序 Load 进记忆体开始执行,
大概会有个 2~3 阶段。
目前这个模拟器规划比较简单,
因为模拟环境目前没有需要提前设定的设计,
也没有 Binary Code 大小的限制,
一开机就可以直接跳进主程序执行,
所以只要有办法把主程序放到指定位置,
再让 Cpu 从那边开始执行就可以了!
github 页面 Tag: ITDay27
开场先处理 Load File 失败的问题,
让 Simulator 在读到非法指令的时後就结束。
//executor.cpp
default:
cpu->raise_exception(CPU_INTERFACE::ILLEGAL_INSTRUCTION_EXCEPTION_CAUSE);
break;
为简化开发流程,
loadBinaeyFromHex
目前只支援特定档名与档案格式,
之後扩充的时候再支援指定路径的部分。
//memory.h
...
void loadBinaeyFromHex(std::string filePath = "./binary.hex");
...
Loader 大致上跟 RISC-V-TLM 的做法一样,
这边将 hexFile.is_open()
和 line[0] != ':'
改成判断完先处理,
而不是一层一层包起来,稍微提升可读性。
尝试用 std::map + Switch Statement 简化每次比较字串的流程,
不需要每次都写 else if(std::stoul(line.substr(7, 2)) == "02")
,
但看起来可读性没有比较好,反而是执行效率有机会变好一点。
修掉了奇怪的 * 16
,
RISC-V-TLM 在 "03" 的 case 有一段程序码:
code_segment = stol(line.substr(9, 4), nullptr, 16) * 16; /* ? */
最後那段 * 16; /* ? */
看起来是不小心把某个 Memory 的位置放错了,
导致需要用特别行为的处理,
但在这边没有这个问题,改回正常运算流程。
//memory.cpp
...
void MEMORY::loadBinaeyFromHex(std::string filePath)
{
std::ifstream hexFile(filePath);
std::string line = "";
if(!hexFile.is_open()) {
std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
std::cout << "Binary File Open Failed!!" << std::endl;
std::cout << "Cause: " << std::strerror(errno) << std::endl;
std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
return;
}
uint32_t extended_address = 0;
uint32_t memory_offset = 0;
uint32_t program_counter = 0;
dataMemory.assign(0x100000, 0);
while(std::getline(hexFile, line)) {
if(line[0] != ':') {
continue; //skip this line
}
switch (std::stoul(line.substr(7, 2))) {
case 0: { //Data
auto byteCount = std::stol(line.substr(1, 2), nullptr, 16);
auto address = extended_address + std::stoul(line.substr(3, 4), nullptr, 16);
for(int i=0; i < byteCount; i++) {
auto value = std::stoul(line.substr(9 + (i*2), 2), nullptr, 16);
dataMemory[address + i] = value;
std::cout << "00" << " address: 0x" << address + i << " value: 0x" << std::hex << value << std::endl;
}
}
break;
case 2: { //Extended segment address
extended_address = std::stoul(line.substr(9, 4), nullptr, 16);
}
break;
case 3: { //Start segment address
uint32_t code_segment = stoul(line.substr(9, 4), nullptr, 16);
program_counter = code_segment + stoul(line.substr(13, 4), nullptr, 16);
std::cout << "03 " << "program counter should be: 0x" << std::hex << program_counter << std::endl;
}
break;
case 4: { //Start srgmant address
memory_offset = stoul(line.substr(9, 4), nullptr, 16) << 16;
extended_address = 0;
}
break;
case 5: { //Get start program counter
program_counter = stol(line.substr(9, 8), nullptr, 16);
std::cout << "05 " << "program counter should be: 0x" << std::hex << program_counter << std::endl;
}
break;
default:
break;
}
}
}
...
这次测试直接把 Program Counter 写死到指定位置,
预计把 Program Loader 从 Memory 独立出去之後,再让 Cpu 可以从正确位置开始执行。
程序码来源则是之前先做好的 Cross Compiler 编译结果,
之後会再开一篇说明,
有兴趣的可以先照 RISC-V-TLM 的流程建立编译环境。
另外注意如果是虚拟环境(VMware等等),要记得把容量和记忆体调高,
不然会载不下 gcc + 编译 gcc 的过程会因为记忆体不足碰到奇怪的问题。
现在才发现 RISC-V-TLM 有点奇怪,
我们从从第一道指令执行结果就不一样了!
导致我的第二道指令存取到不合法的位置。
看来要找一下 RISC-V-TLM 一开始到底做了些什麽,
不然没道理 ADDI 一开始 x2 - 32
会变成 0x3ffffdf
,
x2
到底存了什麽神奇数字?又是从哪边来的呢?
我们明天好好研究一下吧!
//RISCV-SIM by hsufit
current_pc: 0x1054 target_pc: 0x1058 ADDI 2 0 2 rs1Value: 0xffffffe0 rs2Value: 0x0 rdValue: 0xffffffe0 immValue: 0xffffffe0
error at address: 0xfffffffc!!
current_pc: 0x1058 target_pc: 0x105c SW 2 8 28 rs1Value: 0xffffffe0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x1c
//RISC-V-TLM by mariusmm
time 0 s: PC: 0x10054. time 0 s: ADDI: x2 + -32 -> x2(0x3ffffdf)
time 10 ns: PC: 0x10058. time 10 ns: SW: x8(0x0) -> x2 + 0x1c (@0x3fffffb)
<<: DAY 28:Command Pattern,将动作已指令一个一个完成
ConstraintLayout(约束布局) ConstraintLayout为Android St...
好的,经过了前两篇的中场休息後 今天我们要来把我们的code架到服务器上面 也就代表我们要进入第二主...
所谓的程序码签章,就是一个指一个数位的签章,在编译好的软件上签章。软件一旦被重新编译、修改,上面的签...
前言 昨天分享了远距工作的好处,今天紧接着来看它带来的挑战,以及我们有什麽方式可以去改善它。 远距工...
一般而言,网站程序大多会是这样的架构: https://developer.mozilla.org/...