We may need to recompile the hardware/software interface when compiling for TLM model as compared to the device driver installed in an OS or ROM firmware.
For a 'mid-level model', differences might be minor and so implemented in C preprocessor.
Device driver access to a DMA controller might be changed as follows:
#define DMACONT_BASE (0xFFFFCD00) // Or other memory map value. #define DMACONT_SRC_REG 0 #define DMACONT_DEST_REG 4 #define DMACONT_LENGTH_REG 8 // These are the offsets of the addressable registers #define DMACONT_STATUS_REG 12 #ifdef ACTUAL_FIRMWARE // For real system and lower-level models: // Store via processor bus to DMACONT device register #define DMACONT_WRITE(A, D) (*(DMACONT_BASE+A*4)) = (D) #define DMACONT_READ(A) (*(DMACONT_BASE+A*4)) #else // For high-level TLM modelling: // Make a direct subroutine call from the firmware to the DMACONT model. #define DMACONT_WRITE(A, D) dmaunit.slave_write(A, D) #define DMACONT_READ(A) dmaunit.slave_read(A) #endif // The device driver will make all hardware accesses to the unit using these macros. // When compiled native, the calls will directly invoke the behavioural model, bypassing the bus model.Behavioural model example (the one-channel DMA controller from earlier):
|   // Behavioural model of 
  // slave side: operand register r/w. 
  uint32 src, dest, length; 
  bool busy, int_enable;
  u32_t status() { return (busy << 31)
            | (int_enable << 30); }    
  u32_t slave_read(u32_t a) 
  { 
    return (a==0)? src: (a==4) ? dest: 
     (a==8) ? (length) : status();
  }
  void slave_write(u32_t1 a, u32_t d) 
  { 
     if (a==0) src=d; 
     else if (a==4) dest=d; 
     else if (a==8) length = d; 
     else if (a==12)
     { busy = d >> 31; 
       int_enable = d >> 30; }
  }
 |   // Bev model of bus mastering portion.
  while(1)
  { 
    waituntil(busy);
    while (length-- > 0)
      mem.write(dest++, mem.read(src++));
    busy = 0;
  }
 | 
Like to make interrupt output with an RTL-like continuous assignment:
interrupt = int_enable & !busy;But this will need a thread to run it, so this code must be placed in its own C macro that is inlined at all points where the supporting expressions might change.
A full example is in the `ethercrc.zip' folder on the course web site (and unzipped on PWF).
Alternatively, it is also possible to use the workstation VM system to trap calls from natively-compiled firmware to hardware.
| 21: (C) 2008-15, DJ Greaves, University of Cambridge, Computer Laboratory. |