go - Sized Data Load in Golang (Getting uint16 into a uint8 slice) -


i'm hacking rough iss of processor , wonder if there more efficient way to doing (ideally without resorting unsafe library). (simplified) i'm representing memory by:

type datamem []uint8 

a register by:

type register uint16 

memory needs in byte sized units , processor works in larger units above. means store data do:

func (m *machine) executest (ins instruction) {   // store memory   // data store specified in 1 register   // address store specified 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 address %x, data %x\n",target_address,src_data) } 

and on sorts of different data types , transfers.

the annoying thing me know processor go code running on have single load instruction could of above in single transfer. i'd expect c compiler optimise me, without breaking out unsafe library , going straight pointers don't think can around this?

i'm open suggestions including better ways model data memory...

because of type safety of go, there's not can differently here without using unsafe package.

the simplest solution, , performant, conversion on target address:

// convert target address *uint16 srcdata = uint16(0xeeee) *(*uint16)(unsafe.pointer(&datamem[targetaddress])) = srcdata 

similarly, option shadow []uint8 slice []uint16 slice pointing same memory region. looks more hairy, , have check offsets , alignment yourself.

datamem16 := (*(*[1<<30 - 1]uint16)(unsafe.pointer(&datamem[0])))[:len(datamem)/2 : len(datamem)/2] datamem16[targetaddress/2] = srcdata 

one other option try using builtin copy move bytes. since copy implemented in assembly compiler, may want (though haven't checked assembly of conversion produces, wash)

copy(datamem[targetaddress:], (*(*[2]uint8)(unsafe.pointer(&srcdata)))[:]) 

or inline-able function @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 critical, , want use architecture specific instructions, "proper" way implement want directly in assembly, code generated first solution hard beat.


Comments