CPU指令可以分成两大类,一是操作CPU内部暂存器的算术逻辑指令,一是存取记忆体,也就是所谓的load/store指令。要模拟算术逻辑指令,用先前所定义的Core资料结构即可,因为内部已经包含了暂存器,而load/store指令则需要与core外部的元件沟通,常见的有l1 cache、l2 cache、bus等,目前为了简化实作,先统一由一个memory model来代表core外部的系统。memory model很单纯,就是一块可以读写的记忆体,以64位元系统为例,位址空间就是0 ~ 2**64-1
这麽大。
memory model中使用HashMap来存放资料,此处引入block的概念,将整个记忆体空间以32 bytes为单位进行分割,HashMap的key为block base address,value为长度32的u8阵列,当CPU存取某个address时,memory model会先查看此address所属的block是否存在,是的话直接从HashMap中取得资料,否则创建新的block加入HashMap。使用HashMap的好处是可以动态的增加记忆体空间,效能方面虽然比array或vector略差,但可以有很好的弹性。
首先实作写1 byte的逻辑:
pub fn write_byte(&mut self, addr: AddressType, value: u8) {
let block_base = addr & (!(0x1f as AddressType));
let block_offset = addr - block_base;
if !self.data.contains_key(&block_base) {
self.data.insert(block_base, [0; 32]); // 插入新block
}
let block = self.data.get_mut(&block_base).unwrap();
block[block_offset as usize] = value;
}
pub fn read_byte(&mut self, addr: AddressType) -> u8 {
let block_base = addr & (!(0x1f as AddressType));
let block_offset = addr - block_base;
if !self.data.contains_key(&block_base) {
self.data.insert(block_base, [0; 32]);
}
let block = self.data.get(&block_base).unwrap();
block[block_offset as usize]
}
由於存取memory的长度不是固定的,因此需要实作一个比较general的interface:
fn access_memory(&mut self, payload: &mut Payload) {
match payload.op {
MemoryOperation::READ => {
for i in 0..payload.data.len() {
payload.data[i] = self.read_byte(payload.addr + i as AddressType);
}
}
MemoryOperation::WRITE => {
for i in 0..payload.data.len() {
self.write_byte(payload.addr + i as AddressType, payload.data[i]);
}
}
MemoryOperation::INVALID => panic!("Invalid mem op"),
}
}
此处的payload类似网路的封包,实际上硬体也是利用类似的方式互相沟通。
接着core就可以呼叫access_memory来读写记忆体:
fn write_memory(&mut self, address: AddressType, data: &[u8]) {
let mut payload = Payload {
addr: address,
data: data.to_vec(),
op: MemoryOperation::WRITE,
};
self.mem_if.as_mut().unwrap().access_memory(&mut payload);
}
fn read_memory(&mut self, address: AddressType, data: &mut [u8]) {
let mut payload = Payload {
addr: address,
data: data.to_vec(),
op: MemoryOperation::READ,
};
self.mem_if.as_mut().unwrap().access_memory(&mut payload);
for i in 0..data.len() {
data[i] = payload.data[i];
}
}
有了memory model之後,就可以来实作load/store指令了。完整程序码可以参考:rv-sim
<<: 开源的WebPC让你使用浏览器远程控制 linux or windows
>>: cv2播Video+声音 cv2+ffpyPlayer 【附码】
今天研究的攻击威胁类型是恶意程序和密码破解。 恶意程序 恶意程序是攻击者设计用来破坏目标对象的电脑设...
很难得,有一件事情能持续以恒地坚持一个月(除了变胖这件事以外),最後的分享就来讲讲本地推播吧: 本地...
前言 上一篇教学实作了一个简单的爬虫并成功的爬到了 PTT 的文章列表 这次就继续将 PTT 文章内...
上周我跟大家分享了系统分析师必须具备的「观察」、「商业思维」、「聆听」共3个软实力,但在讲述下一个主...
Header元件 第一个元件先从 Header.js 开始 Header要负责 显示标题 待办事项 ...