Search code examples
hardware

How does hardware device (peripherals) implement the RO/WO registers?


Hardware devices expose their registers to CPU side using MMIO. And there are so many types of registers (written in some hardware manuals/device drivers) which are used for different usages. How do these hardware devices check the register access permissions?

I tested on a Development Board using busybox devmem, there are some MMIO registers (DEVICE_ID, DEVICE_FEATURE, etc.) which are not writable from CPU side. I wonder how does hardware implement read-only/write-only permissions on this registers?


Solution

  • These design rules would be implemented at the peripheral. The cpu has no clue what a peripheral is much less any details of any peripheral or registers or bits within a register.

    Take a timer for example and let's say I design it such that the register you use to read the current count is read only (manipulating the start or rollover count, etc I have implemented through some other register/mechanism).

    I have a control register that enables or disables the counter. Once the address is decoded down to the specific peripheral the offsets are.

    0x00   bit[0] = 0 for disable 1 for enable
    0x04   read only current count
    

    From the programmers side these might be

    0x40010300  control
    0x40010304  timer count
    

    Some registers in a pseudo language (8 bit interface)

    reg timer_count[7:0]
    reg enable[1]
    

    Then the logic implements, for each clock cycle:

    if(enable) timer_count = timer_count + 1
    
    //assume processor side bus decodes the full address and aims it ultimately
    //at this peripheral through other buses
    if(bus_enable)
    {
      if(bus_cycle_write)
      {
       if(address == 0x00)
         enable = bus_write_data[0]
      }
      else //read
      {
        if(address == 0x00)
           bus_read_data = {7b0,enable}
        if(address == 0x04)
           bus_read_data = timer_count
      }
    }
    

    but using real syntax for a real HDL. No magic, no mystery. I could do your whole question and make one WO and one RO

    if(bus_enable)
    {
      if(bus_cycle_write)
      {
       if(address == 0x00)
         enable = bus_write_data[0]
      }
      else //read
      {
        if(address == 0x04)
           bus_read_data = timer_count
      }
    }
    

    The control register is write only the timer count register is read only. There is no read path to the control register and no write path to the timer count register.