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

报告相同问题?

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?