1

I need to set 63rd bit(MSB) of a 64-bit MMIO register in MIPS assembly language.

Currently I am doing this

ldi $2,0x8000000000123456 #This is the address of the register which i want to set 63 rd bit 
ld $3,0($2) # read current value from the register 
dli $4,0x8000000000000000  # set 63rd bit as 1 and load in to register $4
dadd $4,$3,$4    # add mask value and current value to set 63rd bit 
sd $4,0($2)

But this is very lengthy code. I want to do it in most optimized way. Is there any other way to do it?

Peter Cordes
  • 286,368
  • 41
  • 520
  • 731
Chinna
  • 3,792
  • 4
  • 24
  • 48
  • 1
    Why do you use "dadd" and not "or" instruction? If you want to set a bit in memory you may read one byte only, then do an "ori" and save the byte back. – Martin Rosenau Sep 28 '13 at 14:15

1 Answers1

2

Your program is wrong. It's technically doing this

uint64_t p = *((uint64_t*)0x8000000000123456ULL);
p += 0x8000000000000000ULL;

which actually toggles the top bits and won't give you the correct value if the value has the top bit set. In fact it'll trap if the top bit is set since this is dadd and not daddu

You should read more about bitwise operations: To clear a bit, use and; use or to set and xor to toggle a bit

In MIPS you can do like this

ldi  $2, 0x8000000000123456
ld   $3, 0($2)
lui  $4, 0x8000 # $4 = 0x80000000
dsll $4, $4, 32 # $4 = 0x8000000000000000
or   $4, $3, $4
sd   $3, 0($2)

The lui/dsll pair is for loading the immediate. It can be replaced with any equivalent sequences that load a power of 2 to the low half then shift it to the high part

Note that there's nothing called "register address" unless you're using MMIO. It's the register that contains the address to a memory location. If you're accessing real memory or a MMIO device that allows partial register access then you have an alternative solution by simply loading the specific byte, halfword or word and edit it, which saves you several instructions to load the 64-bit immediate

# byte
ldi $2, 0x8000000000123456 # assume big endian
lbu $3, 0($2)
ori $3, 0x80
sb  $3, 0($2)

# halfword
ldi $2, 0x8000000000123456
lhu $3, 0($2)
ori $3, 0x8000
sh  $3, 0($2)

# word
ldi $2, 0x8000000000123456
lbu $3, 0($2)
lui $4, 0x8000
or  $3, $4, $3
sd  $3, 0($2)
phuclv
  • 32,499
  • 12
  • 130
  • 417
  • Poorly worded question, but the OP is pretty clearly talking about an MMIO register given that comment. (Real MIPS CPUs are typically only used in embedded systems these days). IDK if partial reads/writes typically work or not on MMIO regs, or if you need a 64-bit load/store from the right base address? – Peter Cordes Aug 03 '18 at 21:51
  • `0x8000 << 31` isn't the top bit, it's only the 2nd-highest bit. https://godbolt.org/g/Tgt9bL shows that compilers choose `daddiu $1, $zero, 1` / `dsll $1, $1, 63`. – Peter Cordes Aug 03 '18 at 23:19