我正在一起研究处理器的大致ISS,我想知道是否有一种更有效的方法来执行我的工作(理想情况下不求助于不安全的库)。
(简化)我通过以下方式表示内存:
1 | type DataMem []uint8 |
注册人:
1 | type Register uint16 |
内存需要以字节大小为单位,而处理器则以更大的单位工作,如上所述。 这意味着存储我们要做的数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | func (m *Machine) ExecuteST (ins Instruction) { // Store to memory // Data to store specified in one register // Address to store to specified by another register target_address := m.RegBank[ins.Dst] src_data := m.RegBank[ins.Src] ///////// Start of annoying section//////// var target_0 uint8 var target_1 uint8 target_0 = src_data & 0x0f target_1 = (src_data & 0xf0)>>8 m.data_mem[target_address ] = target_0 m.data_mem[target_address+1] = target_1 /////////// End of annoying section ///////// m.logger.Printf("ST To Address %x, Data %x\ ",target_address,src_data) } |
对于各种不同的数据类型和传输,依此类推。
对我来说,令人烦恼的是,我知道将在其上运行go代码的处理器将具有单个加载指令,该指令可以在一次传输中完成所有上述操作。 我希望一个好的c编译器可以为我优化它,但是如果不破坏不安全的库并直接使用指针,我认为我无法解决这个问题吗?
我愿意征求建议,包括建立数据存储器模型的更好方法。
-
我不知道有什么更好的方法来做您的工作,但是您的口罩是错误的。 第一个应该是
0xff ,另一个应该是0xff00 。 - 糟糕,谢谢! ID从我正在运行的代码中重新编写了代码以简化问题-好像我错误地/太快地简化了!
由于Go具有类型安全性,因此在不使用不安全软件包的情况下,您可以做很多不同的事情。
最简单的解决方案,也许也是性能最高的解决方案,是对目标地址进行转换:
1 2 3 | // convert the target address to *uint16 srcData = uint16(0xeeee) *(*uint16)(unsafe.Pointer(&dataMem[targetAddress])) = srcData |
类似地,另一个选择是用指向同一内存区域的
1 2 | dataMem16 := (*(*[1<<30 - 1]uint16)(unsafe.Pointer(&dataMem[0])))[:len(dataMem)/2 : len(dataMem)/2] dataMem16[targetAddress/2] = srcData |
另一个尝试的方法是使用内置的
1 | copy(dataMem[targetAddress:], (*(*[2]uint8)(unsafe.Pointer(&srcData)))[:]) |
或作为@OneOfOne显示的内联函数:
1 2 3 4 5 | func regToMem(reg uint16) *[2]uint8 { return (*[2]uint8)(unsafe.Pointer(®)) } copy(mem[targetAddress:], regToMem(0xffff)[:]) |
https://play.golang.org/p/0c1UywVuzj
如果性能至关重要,并且您要使用特定于体系结构的指令,则"正确"的方法是直接在汇编中实现您想要的功能,但是从第一个解决方案生成的代码可能很难克服。
- 该死的,别再让Jim忍不住回答我的问题了! 任何人play.golang.org/p/C8jo2Jk59R
- @OneOfOne:谢谢,寻找第一种情况要好一些
- 非常感谢这个TBH,我更喜欢切片阴影,因为它应该可以工作而不会在移动顶部添加额外操作的任何风险-复制可能会添加其他内容。 但是,这是增加技巧的有用工具。
- @ChrisHopkins:我可能错过了最简单的解决方案,将目标地址转换为uint16而不是复制2个字节。 它与转换整个片段基本上相同,但是我认为它的错误倾向少一些,并且更容易推理。 我只使用最后一个选项,您必须在该内存区域内进行大量随机访问。
由于我关心的是模拟的效率,因此另一个选择是声明数据存储器的不同方式,例如
1 | type DataMem []uint32 |
给定地址的提供方法提取字节
1 2 | func (dm *DataMem) StoreB (address int) uint8 {...} func (dm *DataMem) Store16 (address int) uint16 {...} |
鉴于它是在PC上运行的,因此那里会有一个数据缓存,因此,获取太大的数据字不会在现代处理器上花费任何费用。
我需要一个新的基本规则,当您遇到棘手的问题时,请查看数据结构和您的平台;-)