
 * Constants can't be bigger than 32 bits.  For example: 
    constants mcg_ctl_val "Global MC control values" {
	mc_enable	= 0xffffffffffffffff;
	mc_disable	= 0x0;
    };
    - again. 

 * Required additional checks are now:
    - Constant values all fit into the bit width specified

 * How will we do device inheritance?  Clearly the new device is a
   new type, but it also needs a new operation for every register,
   even those inherited from the base device type.  This suggests that
   register definitions should always be copied from the base type,
   but register type definitions (and constant declarations) should
   simply be referenced. 

   New syntax for inheritance: 
     1) extends(xapic) as an extra device attribute. 
     2) override register foo ... to override a register definition. 
     3) elide register bar; removes defn of bar from the new device. 

 * Generalize register field attributes.  Specify fixed values
   properly, as either a literal, or a constant value name, or
   (possibly) a compile-time expression.  Split up whether the driver
   can read or write the field, and in what way, from what
   consequences there are of reading or writing the field.

   What is the difference between the read cycles permissible by the
   hardware, and the read operations that the user might want to be able
   to initiate?

   Well, whether the hardware allows reads or not is simply a bit. 
     Hardware-readable: boolean. False => never generate a read
     cycle.   This is a property of a register, not a field!

   What reads the user is allowed to perform is always one of:
     R : 'read_value' :  Return any value to user (expose a read operation)
     RF: 'read_as' Always same constant value (expose sanity check to drivers)
     RC: 'read_clears' Reads as some value, and also clears. 
     RN: 'no_read' Can't be read.
    These are properties of fields; register properties are templates
     for these. 

   Can you allow a hardware write or not? 
     If you can, what are the constraints on this? These are field
     properties, but might apply to the register as a whole. 

   Options for writing:
     W : 'write_value' Set to any value of a type (expose a write operation)
     WN: 'no_write' Cannot be written/writes ignored (not exposed to user)
     WF: 'write_as' Must write a specific value (not exposed to user)
     WP: 'preserve' Must preserve previous value (not exposed to user)
     WC: 'write_to_clear(v)' Must write a specific value to clear register
     WS: 'write_to_set(v)' Must write a specific value to set register

   Options for other actions:
     sticky: once written, value will never change. 

   Shorthand:
     rw		=> read_value write_value
     ro		=> readable no_write
     wo		=> no_read writeable
     always(v)	=> read_as(v) write_as(v)
     mbz	=> no_read write_as(0)
     mb1	=> no_read write_as(1s)
     rsvd	=> no_read preserve
     ros	=> readable no_write sticky
     rwc	=> readable writeable write_to_clear(1s)
     rwzc	=> readable writeable write_to_clear(0)
     rws	=> readable writeable sticky

  Functions to generate for a field: 
     readable, read_as => read_field
     read_as => check_field
     read_clears, write_to_clear(v) => clear_field
     writeable => write_field

 * Register fields that can be given an initial value: initial(val)

 * Variant format types.  A format can have several different
   variants.  Some fields are common to all variants, others only
   appear in some variants.  There must be a way of determining which
   variant a format is
 
 * Back-end to print out memory map of device, or even pictures. 
 * Selectively enable/disable specific checks
 * Collect all parse errors before exiting. 
 * Generate device models.

 * Devil's notion of 'values', derived from registers (e.g. by
   concatenating two fields from different registers together).  This
   should allow constant parts of values: for example, in PTEs, one
   needs to concat a bit field with a bunch of zeros to get an
   address. 
 
 * Preconditions and postconditions, e.g. for handling register select
   registers.  These also tend to imply software state variables used
   to track the state of the hardware for the driver.

 * Higher-level state machine constraints on how to program the
   hardware.  For example, to read the ESR below you must first
   write once to it.  To clear it you need to perform two
   back-to-back writes.   Don't ask....

 * Messages, as opposed to addresses.  Composing access to devices
   that can only be accessed by sending messages using writes to

 * Register overlap checks should allow non-'also' registers to
   overlap if one is non-writeable and the other is non-readable.

  * Compile time checks:
    - Duplicate register names
    - Duplicate register type names
    - Overlapping address spaces
    - Type mismatch between device arg and register base
    - Undefined register types

 * What are the name spaces?
    - Register and constant types
    - Register names
    - Constant value names
    - Fields within a particular format
    - Device parameters

 * Good (bad) test cases for Mackerel:
    - PageTableEntries for x86, with alternative values
      (e.g. superpages)
    - ARM coprocessor registers
    - x86 CPUID instructions, including clockout of cache params
    - Access modes for LPC PIC, DMAC, and Clock hardware


-------------------------
Experiences:

 - In contrast to Devil, accessing device registers is easier these
   days since there is lots of address space.  Consequently,
   pre-conditions on registers and indexes are much less of an issue,
   and Mackerel doesn't support them

 - Mackerel specs are intended to be as close as possible to the data
   sheets.  While Devil wanted manufacturers to publish Devil specs
   along with data sheets, we are less idealistic.  We want to make it
   as easy as possible for a programmer to type in a spec from teh
   data sheet. 

 - What is hard these days is that registers have lots of fields, and
   reserved fields which must be read before being written. 

 - HyperV MSR problem: RSVD registers.

 - It was invaluable having working driver for APIC while debugging
   the Mackerel version.  Hopefully this is not the case once Mackerel
   is debugging and reliable. 

 - It has got to be reliable: you need to feel comfortable Mackeral
   isn't crashing your code. 

 - Mackerel code is transparent: it's readable, and intuitive. 

 - Most existing code uses (a) mapped structs, (b) bitfields, (c)
   Macros giving masks and shifts

 - We can do full device dumps

 - Source code inline is shorter and more intuitive.

 - Specs are easier to write than structs or macros.

 - Mackerel errors do get caught (esp. register widths catch incorrect
   field sizes).

 - We build all our drivers using Mackerel now, plus MSRs.

 - Haskell was good.  Parsing, etc.  Formatting. 

 - Generated code is remarkably efficient.  Assembly looks almost the
   same. 

 - Same file used for user and kernel space. 

 - Lots of volatile errors.  Fix once in Mackerel.h, and then done.
   Programmer is saved from having to deal with them further. 

 - Still dependent on GCC features, but fewer of them appear in inline
   code and those that do (e.g. inline struct literals) are more
   syntactic sugar than code directives like volatile.  This makes us
   more compiler independent.  
 
 - Descriptions are really nice.  Lots of ad-hoc code got written to
   do this.   snprintf is the right way. 

 - Mackerel-generated files are large, with many types, and many
   inlined functions.   Generated code, however, is very compact. 

 - List devices so far.

 - RWCS, RWS, etc. can be supported (e.g. device models).

 - Code inflates by approx.  10x (.dev -> .h)
 
 - Takes a while to type in all the registers, but (1) it's easier
   than working out struct formats, (2) it's basically transcribing
   the data sheet, so a good way of getting acquainted with the
   device. 

-----------------------

acpi_ec.dev:1:1: File acpi_ec.dev describes dev EC not acpi_ec
arm_icp_pic.dev:1:1: File arm_icp_pic.dev describes dev arm_icp_pic0 not arm_icp_pic
hpet.dev:1:1: File hpet.dev describes dev HPET not hpet
ixp2800_icp_pic.dev:1:1: File ixp2800_icp_pic.dev describes dev ixp2800_icp_pic0 not ixp2800_icp_pic
ixp2800_uart.dev:1:1: File ixp2800_uart.dev describes dev IXP2800_UART not ixp2800_uart
lpc_dma.dev:1:1: File lpc_dma.dev describes dev LPC_dma not lpc_dma
lpc_ioapic.dev:1:1: File lpc_ioapic.dev describes dev LPC_IOAPIC not lpc_ioapic
lpc_pic.dev:1:1: File lpc_pic.dev describes dev LPC_PIC not lpc_pic
lpc_rtc.dev:1:1: File lpc_rtc.dev describes dev LPC_rtc not lpc_rtc
lpc_rtc_spaces.dev:1:1: File lpc_rtc_spaces.dev describes dev LPC_rtc not lpc_rtc_spaces
lpc_timer.dev:1:1: File lpc_timer.dev describes dev LPC_timer not lpc_timer
pc16550d_uart.dev:1:1: File pc16550d_uart.dev describes dev PC16550D_UART not pc16550d_uart
pl011_uart.dev:1:1: File pl011_uart.dev describes dev PL011_UART not pl011_uart
