我在一起处理处理器的粗略ISS,我想知道是否有更有效的方法来处理我正在做的事情(理想情况下不使用不安全的库)。 (简体)我代表记忆:
type DataMem []uint8
寄存器:
type Register uint16
内存需要采用字节大小的单位,处理器的工作方式如上所述。这意味着存储我们所做的数据:
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\n",target_address,src_data)
}
等等各种不同的数据类型和转移。
令我恼火的是,我知道运行代码的处理器将有一条加载指令,可以在一次传输中完成上述所有操作。我希望有一个好的编译器可以为我优化,但是如果没有打破不安全的库并直接指向我不认为我可以解决这个问题吗?
我愿意接受建议,包括更好的数据存储建模方法......
答案 0 :(得分:3)
由于Go的类型安全性,如果不使用不安全的软件包,你可以做的不同。
最简单的解决方案,也许是最高效的解决方案是在目标地址上进行转换:
// convert the target address to *uint16
srcData = uint16(0xeeee)
*(*uint16)(unsafe.Pointer(&dataMem[targetAddress])) = srcData
类似地,另一个选项是使用[]uint8
切片指向同一内存区域来遮蔽[]uint16
切片。这看起来更加毛茸茸,你必须自己检查你的偏移和对齐。
dataMem16 := (*(*[1<<30 - 1]uint16)(unsafe.Pointer(&dataMem[0])))[:len(dataMem)/2 : len(dataMem)/2]
dataMem16[targetAddress/2] = srcData
尝试的另一个选项是使用内置copy
来移动字节。由于复制是由编译器在汇编中实现的,它可能会做你想要的(虽然我没有检查转换的程序集实际产生了什么,所以它可能是一个清洗)
copy(dataMem[targetAddress:], (*(*[2]uint8)(unsafe.Pointer(&srcData)))[:])
或者作为@OneOfOne的内联函数显示:
func regToMem(reg uint16) *[2]uint8 {
return (*[2]uint8)(unsafe.Pointer(®))
}
copy(mem[targetAddress:], regToMem(0xffff)[:])
https://play.golang.org/p/0c1UywVuzj
如果性能至关重要,并且您希望使用特定于体系结构的指令,那么“正确”执行此操作的方法是直接在汇编中实现您想要的内容,但是从第一个解决方案生成的代码可能很难被击败
答案 1 :(得分:0)
由于我关心的是模拟的效率,另一种选择是以不同方式声明数据存储器,例如
type DataMem []uint32
给定地址的提供方法提取字节
func (dm *DataMem) StoreB (address int) uint8 {...}
func (dm *DataMem) Store16 (address int) uint16 {...}
鉴于这是在PC上运行,那里会有一个数据缓存,因此在现代处理器上获取太大的数据字不会花费任何成本。
我需要一个新的基本规则,当你遇到棘手的问题时,请查看数据结构和平台; - )