Welcome to Qi-U Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others


0 votes
in Technique[技术] by (71.8m points)

arm - How to accurately read a 64 bit register value using a method that can only read 32 bits at a time?

Came across this question during a past interview, but got no feedback.

Since its a register, would I need to disable interrupts before accessing the register inorder to prevent data corruption? Thought of using two buffers, 32 bit and 64 bit, and sending the 32 bit buffer into a read32() and shifting it over accordingly to the 64 bit buffer. Lets just assume this is little-endian architecture.

I wrote a quick sample code on repl.it (Output does not match register value)

#include <stdio.h>
#include <string.h>
#include <stdint.h>

void read32(uint64_t *reg, uint32_t *buffer){
  memcpy(buffer, reg, 4);

int main(void) {
  uint64_t reg = 0xAAAAAAAAFFFFFFFF;
  uint32_t buf_32 = 0;
  uint64_t buf_64 = 0;

  //read LSW
  read32(&reg, &buf_32);
  buf_64 |= buf_32; //add LSW

  //read MSW
  read32(&reg+4, &buf_32);
  buf_64 |= ((uint64_t)buf_32 << 32);
  printf("64 bit register value: 0x%lx
", buf_64);
  return 0;


64 bit register value: 0x1ffffffff

Welcome To Ask or Share your Answers For Others

Please log in or register to answer this question.

1 Answer

0 votes
by (71.8m points)

Disabling interrupts will not prevent an I/O register that may change independently of the code sequence from changing.

Often where data consistency is required between two hardware registers that are larger than the architecture width, the hardware data sheet or reference manual will advise on how to read the data - usually by specifying the order in which the registers must be read to work with hardware mechanisms that make that "safe".

In other cases the method might be dictated by the nature of the registers and their function/behaviour. For example if you have two 32bit timer/counters, with the overflow of one triggering an increment of the other, to form a 64 bit counter, then clearly the high-order counter will only change when the low-order counter overflows. In that case you can simply read the low, then the high and repeat if the low has since wrapped :

uint32_t low_word = 0, high_word = 0;

    low_word = *low_reg_addr ;
    high_word = *high_reg_addr ;

} while( *low_reg_addr > low_word ) ;  // If low has wrapped, re-read

uint64_t full_word = (uint64_t)high_word << 32 | low_word;

So if the low-order register not wrapped after the high-order register has been read, then the data must be consistent, and the loop exit. If it has wrapped, the data may not be consistent, and must be re-read.

Welcome to Qi-U Community for programmer and developer-Open, Learning and Share