doujiazong0322 2016-07-21 16:15
浏览 302
已采纳

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

I'm hacking together a rough ISS of a processor and I wonder if there is a more efficient way to to what I am doing (ideally without resorting to the unsafe library). (Simplified) I'm representing memory by:

type DataMem []uint8

a register by:

type Register uint16

Memory needs to be in byte sized units and the processor works in larger units as above. This means to store the data we do:

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)
}

And so on for all sorts of different data types and transfers.

The annoying thing for me is I know the processor that the go code will be running on will have a single load instruction that could do all of the above in a single transfer. I'd expect a good c compiler to optimise into that for me, but without breaking out the unsafe library and going straight to the pointers I don't think I can get around this?

I'm open for suggestions including better ways to model the data memory...

  • 写回答

2条回答 默认 最新

  • doujiyun8846 2016-07-21 17:03
    关注

    Because of the type safety of Go, there's not much you can do differently here without using the unsafe package.

    The simplest solution, and probably the most performant, is to do the conversion on the target address:

    // convert the target address to *uint16
    srcData = uint16(0xeeee)
    *(*uint16)(unsafe.Pointer(&dataMem[targetAddress])) = srcData
    

    Similarly, another option is to shadow the []uint8 slice with a []uint16 slice pointing to the same memory region. This looks even more hairy, and you have to check your offsets and alignment yourself.

    dataMem16 := (*(*[1<<30 - 1]uint16)(unsafe.Pointer(&dataMem[0])))[:len(dataMem)/2 : len(dataMem)/2]
    dataMem16[targetAddress/2] = srcData
    

    One other option to try is using the builtin copy to move the bytes. Since copy is implemented in assembly by the compiler, it may do what you want (though I haven't checked what the assembly of the conversion actually produces, so it could be a wash)

    copy(dataMem[targetAddress:], (*(*[2]uint8)(unsafe.Pointer(&srcData)))[:])
    

    Or as an inline-able function as @OneOfOne shows:

    func regToMem(reg uint16) *[2]uint8 {
        return (*[2]uint8)(unsafe.Pointer(&reg))
    }
    
    copy(mem[targetAddress:], regToMem(0xffff)[:])
    

    https://play.golang.org/p/0c1UywVuzj

    If performance is critical, and you want to use architecture specific instructions, the "proper" way to do this would be to implement what you want directly in assembly, but the code generated from the first solution would probably be hard to beat.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥50 求解vmware的网络模式问题 别拿AI回答
  • ¥24 EFS加密后,在同一台电脑解密出错,证书界面找不到对应指纹的证书,未备份证书,求在原电脑解密的方法,可行即采纳
  • ¥15 springboot 3.0 实现Security 6.x版本集成
  • ¥15 PHP-8.1 镜像无法用dockerfile里的CMD命令启动 只能进入容器启动,如何解决?(操作系统-ubuntu)
  • ¥30 请帮我解决一下下面六个代码
  • ¥15 关于资源监视工具的e-care有知道的嘛
  • ¥35 MIMO天线稀疏阵列排布问题
  • ¥60 用visual studio编写程序,利用间接平差求解水准网
  • ¥15 Llama如何调用shell或者Python
  • ¥20 谁能帮我挨个解读这个php语言编的代码什么意思?