Golang中的大小数据加载(将uint16放入uint8片)

Golang中的大小数据加载(将uint16放入uint8片),go,Go,我正在整理一个粗糙的处理器ISS,我想知道是否有更有效的方法来完成我的工作(理想情况下不必求助于不安全的库)。 (简化)我通过以下方式表示内存: type DataMem []uint8 注册人: type Register uint16 内存需要以字节大小为单位,处理器以更大的单位工作,如上所述。这意味着要存储我们所做的数据: func (m *Machine) ExecuteST (ins Instruction) { // Store to memory // Data to

我正在整理一个粗糙的处理器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)
}
等等,用于各种不同的数据类型和传输

让我恼火的是,我知道运行go代码的处理器将有一条加载指令,可以在一次传输中完成上述所有操作。我希望一个好的c编译器能为我优化这一点,但如果不破坏不安全的库并直接指向指针,我想我无法解决这个问题


我愿意接受建议,包括更好的数据内存建模方法…

由于Go的类型安全性,如果不使用不安全的软件包,您在这里做的事情不会有太多不同

最简单的解决方案,也可能是最有效的,是对目标地址进行转换:

// convert the target address to *uint16
srcData = uint16(0xeeee)
*(*uint16)(unsafe.Pointer(&dataMem[targetAddress])) = srcData
类似地,另一个选项是使用指向相同内存区域的
[]uint16
片对
[]uint8
片进行阴影处理。这看起来更毛茸茸的,你必须自己检查你的偏移和对齐

dataMem16 := (*(*[1<<30 - 1]uint16)(unsafe.Pointer(&dataMem[0])))[:len(dataMem)/2 : len(dataMem)/2]
dataMem16[targetAddress/2] = srcData
或者作为@OneOfOne显示的内联函数:

func regToMem(reg uint16) *[2]uint8 {
    return (*[2]uint8)(unsafe.Pointer(&reg))
}

copy(mem[targetAddress:], regToMem(0xffff)[:])


如果性能至关重要,并且您希望使用特定于体系结构的指令,那么“正确”的方法是直接在汇编中实现您想要的功能,但是从第一个解决方案生成的代码可能很难打败。

因为我关心的是模拟的效率,另一个选择是以不同的方式声明数据内存,例如

type DataMem []uint32
提供的方法将给定的地址转换为字节

func (dm *DataMem) StoreB (address int) uint8 {...}
func (dm *DataMem) Store16 (address int) uint16 {...}
考虑到这是在PC上运行的,那里将有一个数据缓存,因此在现代处理器上获取太大的数据字不会花费任何费用


我需要一个新的基本规则,当您遇到棘手的问题时,请查看数据结构和您的平台;-)

我不知道有什么更好的方法来做你正在做的事情,但是你的面具错了。第一个应该是
0xff
,另一个应该是
0xff00
。哎呀,谢谢!我重新编写了我正在运行的代码来简化问题-看起来我简化得不正确/太快了!该死,别再把我的答案从脑子里抹掉了,吉姆!anywho@OneOfOne:谢谢,第一个案例看起来有点不错。非常感谢这个TBH,我更喜欢切片阴影,因为它应该可以工作,不会有在移动顶部添加额外操作的风险。复制可能会添加其他东西。但这是一个很有用的工具,可以添加到技巧包中。@ChrisHopkins:我错过了最简单的解决方案,将目标地址转换为uint16,而不是复制2个字节。它本质上与转换整个切片相同,但我认为它不太容易出错,也更容易推理。我只会使用最后一个选项,你必须在内存区域内进行大量随机访问。
func (dm *DataMem) StoreB (address int) uint8 {...}
func (dm *DataMem) Store16 (address int) uint16 {...}