Mackerel now allows "noaddr" registers, which can model co-processors, etc.
authorMothy <troscoe@inf.ethz.ch>
Mon, 12 Dec 2011 16:03:18 +0000 (17:03 +0100)
committerMothy <troscoe@inf.ethz.ch>
Mon, 12 Dec 2011 16:03:18 +0000 (17:03 +0100)
This allows considerable cleanup in the x86 code; 32-bit on the way soon.
Redundant ia32_spaces header, since this was not used.
Documented extensions to Mackerel syntax.

12 files changed:
devices/amd64.dev
devices/ia32.dev
doc/002-mackerel/Mackerel.tex
kernel/arch/x86/mcheck.c
kernel/arch/x86_64/init.c
kernel/include/arch/x86/x86.h
kernel/include/arch/x86_64/ia32_spaces.h [deleted file]
tools/mackerel/Checks.hs
tools/mackerel/MackerelParser.hs
tools/mackerel/RegisterTable.hs
tools/mackerel/ShiftDriver.hs
tools/mackerel/Space.hs

index 376cb5e..15e6c9c 100644 (file)
@@ -21,7 +21,7 @@ device amd64 msbfirst ( ) "Intel64 and AMD 64-bit architecture definitions" {
     //
     // Section 2.5: Control registers
     //
-    regtype cr0 "Control register 0" {
+    register cr0 noaddr "Control register 0" {
        pg      1 "Paging";
        cd      1 "Cache disable";
        nw      1 "Not write-through";
@@ -40,9 +40,9 @@ device amd64 msbfirst ( ) "Intel64 and AMD 64-bit architecture definitions" {
 
     // Control register 1 is reserved.
     
-    // Control register 2 == Page-fault linear address
+    register cr2 noaddr "Page-fault linear address" type(uint64);
        
-    regtype cr3 "Control register 3 (PDBR)" {
+    register cr3 noaddr "Control register 3 (PDBR)" {
        pdb     52 "Page-directory base";
        _       7;
        pcd     1 "Page-level cache disable";
@@ -50,7 +50,7 @@ device amd64 msbfirst ( ) "Intel64 and AMD 64-bit architecture definitions" {
        _       3;
     };
 
-    regtype cr4 "Control register 4" {
+    register cr4 noaddr "Control register 4" {
        _               49 mbz;
        smxe            1 "SMX enable";
        vmxe            1 "VMX enable";
index 2a841d2..152ac4c 100644 (file)
@@ -157,8 +157,7 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        mc_disable      = 0x0;
     };
     register mcg_ctl rw msr(0x17b) "Global machine check control" 
-       type(uint64);
-       // type(mcg_ctl_val);
+       type(mcg_ctl_val);
 
     // 14.3.2.5
     register mcg_rax rwzc msr(0x180) "State of RAX at MC" type(uint64);
@@ -327,7 +326,8 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        _       7;
        lme     1 rw "Long mode enable";
        _       1;
-       lma     1 ro "Long mode active";
+       lma     1 rw "Long mode active"; // Should be rw, but must be
+                                        // preserved in practice!
        nxe     1 rw "No-execute enable";
        _       52;
     };
index f6de042..5cae845 100644 (file)
@@ -321,10 +321,12 @@ declaration must be one of the following:
 
 \section{Address spaces}\label{sec:spaces}
 
-Registers defined in a \Mac file (see Section~\ref{sec:registers})
-reside at specified addresses in an \emph{address space}.   There are
-currently 3 built-in address spaces that \Mac understands, and
-addresses in these spaces require both a base and an offset.  Base
+Registers defined in a \Mac file
+reside at specified addresses in an \emph{address space} (unless they
+are specified as \texttt{noaddr}, see Section~\ref{sec:registers}). 
+
+There are currently 3 built-in address spaces that \Mac understands,
+and addresses in these spaces require both a base and an offset.  Base 
 values are given as an arguments to the device specification, and so
 each device argument must be declared as being of one of the following
 types: 
@@ -606,7 +608,7 @@ on the device.
 
 \begin{syntax}
 register \synit{name} [\synit{attr}] [also] 
-             \synit{space}( \synit{address} ) ["\synit{description}"] \synit{type} ;
+             \{ noaddr | \synit{space}( \synit{address} ) \} ["\synit{description}"] \synit{type} ;
 \end{syntax}
 
 \begin{description}
@@ -634,6 +636,14 @@ register \synit{name} [\synit{attr}] [also]
   preceding the address specifier with the \texttt{also} keyword, you
   can allow registers to coexist at the same location. 
 
+\item[noaddr] is an alternative to the address space definition, and
+  is used for registers which have no address (or, alternatively, an
+  implicit address).  A good example of this kind of register is a
+  coprocessor register which requires custom assembler instructions to
+  read and write.  Mackerel generates slightly different access code
+  for this type of register, specified later in this document, and
+  requires the developer to supply the raw register access functions. 
+
 \item[description] is an optional string in double quotes, giving a
   description of the register, for example \texttt{"Error status"}. 
   If not present, it defaults to the name identifier.  
@@ -664,20 +674,38 @@ register \synit{name} [\synit{attr}] [also]
 Here are some examples of \texttt{register} definitions:
 
 \begin{example}
-  register dfr rw at (base, 0x00e0) 
-              "Destination Format" \verb+{+
-    _          28 mb1;
-    model      4 type(model_type) "Model";
-\verb+  };+
+  register dfr rw at (base, 0x00e0) "Destination Format" \{
+    _           28 mb1;
+    model       4 type(model_type) "Model";
+  \};
 \end{example}
 \begin{example}
-  register apr ro at (base, 0x0090) 
-              "Arbitration priority" type(priority);
+  register apr ro at (base, 0x0090) "Arbitration priority" type(priority);
 \end{example}
 \begin{example}
-  register isr0 ro at (base, 0x0100) 
-              "ISR bits 0-31" type(uint32);
+  register isr0 ro at (base, 0x0100) "ISR bits 0-31" type(uint32);
 \end{example}
+\begin{example}
+  register cr4 noaddr "Control register 4" \{
+    _           49 mbz;
+    smxe        1 "SMX enable";
+    vmxe        1 "VMX enable";
+    _           2 mbz;
+    osxmmexcpt  1 "OS support for unmasked SIMD FP exceptions";
+    osfxsr      1 "OS support for FXSAVE and FXRSTOR instructions";
+    pce         1 "Performance-monitoring counter enable";
+    pge         1 "Page global enable";
+    mce         1 "Machine-check enable";
+    pae         1 "Physical address extensions";
+    pse         1 "Page size extensions";
+    de          1 "Debugging extensions";
+    tsd         1 "Time stamp disable";
+    pvi         1 "Protected-mode virtual interrupts";
+    vme         1 "Virtual 8086 mode extensions";
+  \};
+\end{example}
+
+
 
 \section{Register Arrays}\label{sec:regarrays}
 
@@ -1179,6 +1207,16 @@ generate some of the following:
     \texttt{DP\_REGTYPE\_t DP\_REG\_rd( DN\_t *dev );}
   \end{quote}
 
+\item If the register address is not given as \texttt{noaddr}, a function to
+  read the raw contents of the register:
+  \begin{quote}
+    \texttt{DP\_REGTYPE\_t DP\_REG\_rawrd( DN\_t *dev );}
+  \end{quote}
+  On the other hand, if the register address is given as
+  \texttt{noaddr}, the developer is required to supply this function
+  herself -- Mackerel-generated code will use it to access the
+  register. 
+
 \item If the register has fields which are writeable, a function to
   write the contents of the register:
   \begin{quote}
@@ -1192,6 +1230,23 @@ generate some of the following:
   However, this function will not perform a read from the register
   unless the register contains reserved fields. 
 
+\item If the register address is not given as \texttt{noaddr}, a function to
+  write raw values to the register:
+  \begin{quote}
+    \texttt{DP\_REGTYPE\_t DP\_REG\_rawwr( DN\_t *dev, DP\_REGTYPE\_t val );}
+  \end{quote}
+  This function is potentially dangerous, since it makes no guarantees
+  that certain fields of the register are set to zero or one, or
+  preserves the contents of reserved fields.  Use with caution. 
+
+  On the other hand, if the register address is given as
+  \texttt{noaddr}, the developer is required to supply this function
+  herself -- Mackerel-generated code will use it to access the
+  register.  Again, in this case, the function should not try to
+  preserve fields, since Mackerel will make sure that the
+  ``sanitized'' register and field writing functions will do this
+  correctly. 
+
 \item For every readable field \texttt{FLD} (of type \texttt{FLDTYPE})
   of the register, a function to read just that single field from the
   register: 
index f85e404..b4fc2bb 100644 (file)
 #include <dev/ia32_dev.h>
 #include <dev/amd64_dev.h>
 
-/// Sets the MCE bit (bit 6) in CR4 register to enable machine-check exceptions
-static inline void enable_cr4_mce(void)
-{
-    amd64_cr4_t cr4;
-    __asm volatile("mov %%cr4, %[cr4]" : [cr4] "=r" (cr4));
-    amd64_cr4_mce_insert(cr4, 1);     // was: cr4 |= (1 << 6);
-    __asm volatile("mov %[cr4], %%cr4" :: [cr4] "r" (cr4));
-}
-
-// XXX FIXME: works around a current bug in Mackerel to do with not
-// supporting 64-bit enums or constants. 
-//
-// Remove this and replace with the lower-case version from ia32_dev.h
-// when the bug is fixed.
-#define IA32_MC_ENABLE ((uint64_t)(-1L))
-
 /**
  * \brief Enable machine check reporting, if supported
  *
@@ -67,13 +51,13 @@ void mcheck_init(void)
        int num_banks = ia32_mcg_cap_count_extract(mcg_cap);
 
         if (ia32_mcg_cap_ctl_p_extract(mcg_cap)) {
-            ia32_mcg_ctl_wr(NULL, IA32_MC_ENABLE);
+            ia32_mcg_ctl_wr(NULL, ia32_mc_enable);
         }
 
         if (proc_family == 0x6) {
             // enable logging of all errors except for mc0_ctl register
             for (int i = 1; i < num_banks; i++) {
-                ia32_mc_ctl_wr(NULL, i, IA32_MC_ENABLE);
+                ia32_mc_ctl_wr(NULL, i, ia32_mc_enable);
             }
 
             // clear all errors
@@ -83,7 +67,7 @@ void mcheck_init(void)
         } else if (proc_family == 0xf) { // any processor extended family
             // enable logging of all errors including mc0_ctl
             for (int i = 0; i < num_banks; i++) {
-                ia32_mc_ctl_wr(NULL, i, IA32_MC_ENABLE);
+                ia32_mc_ctl_wr(NULL, i, ia32_mc_enable);
             }
 
             // clear all errors
@@ -94,5 +78,5 @@ void mcheck_init(void)
     }
 
     // enable machine-check exceptions
-    enable_cr4_mce();
+    amd64_cr4_mce_wrf(NULL,1);
 }
index 2e92541..6449e12 100644 (file)
@@ -39,7 +39,9 @@
 #include <barrelfish_kpi/cpu_arch.h>
 #include <target/x86_64/barrelfish_kpi/cpu_target.h>
 
-#include "xapic_dev.h" // XXX
+#include <dev/xapic_dev.h> // XXX
+#include <dev/ia32_dev.h>
+#include <dev/amd64_dev.h>
 
 /**
  * Used to store the address of global struct passed during boot across kernel
 static uint64_t addr_global;
 
 /**
- * RFLAGS mask for fast system calls. Put values to mask out here.
- * We mask out everything (including interrupts).
- */
-#define SYSCALL_FMASK   (~(RFLAGS_ALWAYS1) & 0xffffffff)
-
-/**
- * Segment selector bases for both kernel- and user-space for fast
- * system calls
- */
-#define SYSCALL_STAR \
-    ((((uint64_t)GSEL(KSTACK_SEL, SEL_UPL)) << 48) | \
-     ((uint64_t)GSEL(KCODE_SEL, SEL_KPL) << 32))
-
-/**
  * \brief Kernel stack.
  *
  * This is the one and only kernel stack for a kernel instance.
@@ -363,29 +351,22 @@ relocate_stack(lvaddr_t offset)
  */
 static inline void enable_fast_syscalls(void)
 {
-    // Set IA32_STAR MSR to point to user-space base selector
-    wrmsr(MSR_IA32_STAR, SYSCALL_STAR);
+    // Segment selector bases for both kernel- and user-space for fast
+    // system calls 
+    ia32_star_t star = ia32_star_rd(NULL);
+    star = ia32_star_call_insert(star, GSEL(KCODE_SEL,  SEL_KPL));
+    star = ia32_star_ret_insert( star, GSEL(KSTACK_SEL, SEL_UPL));
+    ia32_star_wr(NULL, star);
 
-    // Set IA32_LSTAR MSR to point to kernel-space system call multiplexer
-    wrmsr(MSR_IA32_LSTAR, (lvaddr_t)syscall_entry);
+    // Set ia32_lstar MSR to point to kernel-space system call multiplexer
+    ia32_lstar_wr(NULL, (lvaddr_t)syscall_entry);
 
     // Set IA32_FMASK MSR for our OSes EFLAGS mask
-    wrmsr(MSR_IA32_FMASK, SYSCALL_FMASK);
+    // We mask out everything (including interrupts).
+    ia32_fmask_v_wrf(NULL, ~(RFLAGS_ALWAYS1) );
 
     // Enable fast system calls
-    addmsr(MSR_IA32_EFER, IA32_EFER_SCE);
-}
-
-#define CR4_PCE (1 << 8)
-#define CR4_PGE (1 << 7)
-
-static inline void enable_user_rdpmc(void)
-{
-    uint64_t cr4;
-
-    __asm volatile("mov %%cr4, %[cr4]" : [cr4] "=r" (cr4));
-    cr4 |= CR4_PCE;
-    __asm volatile("mov %[cr4], %%cr4" :: [cr4] "r" (cr4));
+    ia32_efer_sce_wrf(NULL, 1);
 }
 
 static inline void enable_tlb_flush_filter(void)
@@ -405,18 +386,7 @@ static inline void enable_tlb_flush_filter(void)
     }
 
     debug(SUBSYS_STARTUP, "Enabling TLB flush filter\n");
-    uint64_t hwcr = rdmsr(MSR_AMD_HWCR);
-    hwcr &= ~AMD_HWCR_FFDIS;
-    wrmsr(MSR_AMD_HWCR, hwcr);
-}
-
-static inline void enable_pge(void)
-{
-    uint64_t cr4;
-
-    __asm volatile("mov %%cr4, %[cr4]" : [cr4] "=r" (cr4));
-    cr4 |= CR4_PGE;
-    __asm volatile("mov %[cr4], %%cr4" :: [cr4] "r" (cr4));
+    ia32_amd_hwcr_ffdis_wrf(NULL, 1);
 }
 
 static inline void enable_monitor_mwait(void)
@@ -541,19 +511,19 @@ static void  __attribute__ ((noreturn, noinline)) text_init(void)
     enable_fast_syscalls();
 
     // Enable "no execute" page-level protection bit
-    addmsr(MSR_IA32_EFER, IA32_EFER_NXE);
+    ia32_efer_nxe_wrf(NULL, 1);
 
     // Enable FPU and MMX
     enable_fpu();
 
     // Enable user-mode RDPMC opcode
-    enable_user_rdpmc();
+    amd64_cr4_pce_wrf(NULL, 1);
 
     // AMD64: Check if TLB flush filter is enabled
     enable_tlb_flush_filter();
 
     // Enable global pages
-    enable_pge();
+    amd64_cr4_pge_wrf(NULL, 1);
 
     // Check/Enable MONITOR/MWAIT opcodes
     enable_monitor_mwait();
index 18a7120..3733c61 100644 (file)
 /*** AMD_VMCR flags ***/
 #define AMD_VMCR_SVMDIS (1 << 4)        ///< SVM disabled indicator
 
-
 // Register space access functions, needed by ia32_dev.h (since
 // ia23_dev.h is generated by Mackerel, and expects these functions to
 // be available). 
 
-#define ia32_msr_read_64(_d,_r) rdmsr(_r)
+#define ia32_msr_read_64(_d,_r)     rdmsr(_r)
 #define ia32_msr_write_64(_d,_r,_v) wrmsr(_r,_v)
-#define ia32_msr_read_32(_d,_r) ((uint32_t)rdmsr(_r))
+#define ia32_msr_read_32(_d,_r)     ((uint32_t)rdmsr(_r))
 #define ia32_msr_write_32(_d,_r,_v) wrmsr(_r,_v)
 
+#define amd64_cr0_rawrd(_d)     rdcr0()
+#define amd64_cr0_rawwr(_d,_v)  wrcr0(_v)
+#define amd64_cr2_rawrd(_d)     rdcr2()
+#define amd64_cr2_rawwr(_d,_v)  wrcr2(_v)
+#define amd64_cr3_rawrd(_d)     rdcr3()
+#define amd64_cr3_rawwr(_d,_v)  wrcr3(_v)
+#define amd64_cr4_rawrd(_d)     rdcr4()
+#define amd64_cr4_rawwr(_d,_v)  wrcr4(_v)
 
 #ifndef __ASSEMBLER__
 
+static inline uint64_t rdcr0(void)
+{
+    uint64_t cr0;
+    __asm volatile("mov %%cr0, %[cr0]" : [cr0] "=r" (cr0));
+    return cr0;
+}
+
+static inline void wrcr0(uint64_t cr0)
+{
+    __asm volatile("mov %[cr0], %%cr0" :: [cr0] "r" (cr0));
+}
+
+static inline uint64_t rdcr2(void)
+{
+    uint64_t cr2;
+    __asm volatile("mov %%cr2, %[cr2]" : [cr2] "=r" (cr2));
+    return cr2;
+}
+
+static inline void wrcr2(uint64_t cr2)
+{
+    __asm volatile("mov %[cr2], %%cr2" :: [cr2] "r" (cr2));
+}
+
+static inline uint64_t rdcr3(void)
+{
+    uint64_t cr3;
+    __asm volatile("mov %%cr3, %[cr3]" : [cr3] "=r" (cr3));
+    return cr3;
+}
+
+static inline void wrcr3(uint64_t cr3)
+{
+    __asm volatile("mov %[cr3], %%cr3" :: [cr3] "r" (cr3));
+}
+
+static inline uint64_t rdcr4(void)
+{
+    uint64_t cr4;
+    __asm volatile("mov %%cr4, %[cr4]" : [cr4] "=r" (cr4));
+    return cr4;
+}
+
+static inline void wrcr4(uint64_t cr4)
+{
+    __asm volatile("mov %[cr4], %%cr4" :: [cr4] "r" (cr4));
+}
+
 static inline uint8_t inb(uint16_t port)
 {
     uint8_t  data;
diff --git a/kernel/include/arch/x86_64/ia32_spaces.h b/kernel/include/arch/x86_64/ia32_spaces.h
deleted file mode 100644 (file)
index 95bb8ae..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * \file
- * \brief X86 inline asm utilities and defines
- */
-
-/*
- * Copyright (c) 2007, 2008, ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#ifndef __IA32_MSR_H
-#define __IA32_MSR_H
-
-typedef int mackerel_msr_t;
-
-/*
- * Reading from Model-Specific Registers
- *
- * You might be tempted, gentle reader, to wonder why one should
- * bother with the apparently pointless volatile declaration here,
- * particularly if (as is the case with Barrelfish) rdmsr is an asm
- * volatile inline function anyway.   If you don't understand why,
- * you're not qualified to change this code.  If you do, you'll
- * understand why it should not be changed, as long as we are
- * compiling with GCC.
- */
-static inline uint32_t ia32_msr_read_32(ia32_t *base, mackerel_msr_t index)
-{
-    volatile uint32_t r = rdmsr(index);
-    return r;
-}
-static inline uint64_t ia32_msr_read_64(ia32_t *base, mackerel_msr_t index)
-{
-    volatile uint64_t r = rdmsr(index);
-    return r;
-}
-
-/*
- * Writing to Model-Specific Registers
- */
-static inline void ia32_msr_write_32(ia32_t *base, mackerel_msr_t index, uint32_t v)
-{
-    wrmsr(index, v);
-}
-static inline void ia32_msr_write_64(ia32_t *base, mackerel_msr_t index, uint64_t v)
-{
-    wrmsr(index, v);
-}
-
-#endif // __IA32_MSR_H
index 3558715..ee10f88 100644 (file)
@@ -210,7 +210,7 @@ make_dup_val_error cvl n =
 check_undef_spaces :: Dev.Rec -> [MacError ]
 check_undef_spaces d =
     let l = [ (RT.spc_id r, RT.pos r) 
-              | r <- (Dev.registers d), (Space.t (RT.spc r)) == Space.UNDEF ]
+              | r <- (Dev.registers d), (RT.spc r) == Space.UndefinedSpace ]
     in
       [ MacError p (printf "Undefined address space '%s'" n) 
         | (n,p) <- l ]
index 46803a4..c3eca72 100644 (file)
@@ -78,6 +78,7 @@ commaSep1 = P.commaSep1 lexer
 op = P.reservedOp lexer
 
 data RegLoc = RegLoc String String Integer 
+            | RegNoLoc
               deriving Show
 
 data ArrayLoc = ArrayListLoc [ Integer ]
@@ -320,7 +321,11 @@ binarySpace = do { reserved "addr" ; return "addr" }
               <|> do { reserved "io" ; return "io" }
               <|> do { reserved "pci" ; return "pci" }
 
-regLoc = do { sp <- binarySpace 
+regLoc = do { reserved "noaddr"
+            ; return RegNoLoc 
+            }
+         <|>
+         do { sp <- binarySpace 
             ; ( base, offset ) <- parens binLoc 
             ; return ( RegLoc sp base offset )
             }
index f802ee5..ea8de5e 100644 (file)
@@ -128,6 +128,8 @@ make_reginfo rtinfo (Register n atrv als rloc dsc tr@(TypeRef tname dname) p) dn
 make_reginfo rtinfo _ _ _ _ = []
 
 get_location :: RegLoc -> [Space.Rec] -> ( String, Space.Rec, String, Integer )
+get_location RegNoLoc _ = 
+    ( "", Space.NoSpace, "", 0)
 get_location (RegLoc s b o) spt = 
     ( s, Space.lookup s spt, b, o)
 
@@ -139,8 +141,10 @@ overlap r1 r2
         any extent_overlap [ (e1, e2) | e1 <- extents r1, e2 <- extents r2 ]
 
 extents :: Rec -> [ (Integer, Integer) ]
-extents r = [ ((offset r) + o, (extentsz (Space.t (spc r)) (size r)))
-                  | o <- arrayoffsets (arr r) (size r)]
+extents r 
+  | spc r == Space.NoSpace = []
+  | otherwise = [ ((offset r) + o, (extentsz (Space.t (spc r)) (size r)))
+                | o <- arrayoffsets (arr r) (size r)]
 extentsz :: Space.SpaceType -> Integer -> Integer
 extentsz (Space.BYTEWISE s) sz = sz `div` 8 `div` s
 extentsz _ sz = 1
@@ -203,6 +207,10 @@ is_array :: Rec -> Bool
 is_array (Rec { arr = (ArrayListLoc []) } ) = False
 is_array r = True
 
+is_noaddr :: Rec -> Bool
+is_noaddr (Rec { spc = Space.NoSpace } ) = True
+is_noaddr _ = False
+
 num_elements :: Rec -> Integer
 num_elements Rec { arr = (ArrayListLoc l) } = toInteger (length l)
 num_elements Rec { arr = (ArrayStepLoc num _) } = num
index 46620d0..7e2a096 100644 (file)
@@ -135,6 +135,12 @@ register_read_fn_name r = qual_register r ["rd"]
 register_write_fn_name :: RT.Rec -> String
 register_write_fn_name r = qual_register r ["wr"]
 
+register_rawread_fn_name :: RT.Rec -> String
+register_rawread_fn_name r = qual_register r ["rawrd"]
+
+register_rawwrite_fn_name :: RT.Rec -> String
+register_rawwrite_fn_name r = qual_register r ["rawwr"]
+
 register_shadow_name :: RT.Rec -> String
 register_shadow_name r = qual_register r ["shadow"]
 
@@ -923,10 +929,12 @@ regarray_shadow_ref rt
 register_decl :: RT.Rec -> [ C.Unit ]
 register_decl r = [ register_dump_comment r,
                     regarray_length_macro r,
+                    register_rawread_fn r,
                     register_read_fn r,
+                    register_rawwrite_fn r,
                     register_write_fn r
                   ] 
-                  ++ 
+                  ++
                   ( register_print_fn r)
                   ++ 
                   (if not $ TT.is_primitive $ RT.tpe r then
@@ -972,6 +980,22 @@ regarray_length_macro r
                (Just $ C.NumConstant $ RT.num_elements r))
     | otherwise = C.NoOp
 
+-- 
+-- Do a raw read from a register, if the address is available.
+-- 
+register_rawread_fn :: RT.Rec -> C.Unit
+register_rawread_fn r =
+    let 
+      rtn = regtype_c_type $ RT.tpe r
+      args = (register_arg_list [] r [])
+      n = register_rawread_fn_name r    
+    in
+     if RT.is_noaddr r then
+       C.Comment (printf "%s has no address, user must supply %s" 
+                 (RT.name r) n)
+     else
+       C.StaticInline rtn n args [ C.Return (loc_read r) ]
+
 --
 -- Read from the register, or from a shadow copy if it's not readable. 
 -- 
@@ -986,6 +1010,21 @@ register_read_fn r =
       else 
           C.StaticInline rtn name args [ C.Return (register_shadow_ref r) ]
 
+-- 
+-- Do a write read top a register, if the address is available.
+-- 
+register_rawwrite_fn :: RT.Rec -> C.Unit
+register_rawwrite_fn r =
+    let 
+      args = register_arg_list [] r [ C.Param (regtype_c_type $ RT.tpe r) cv_regval ]
+      n = register_rawwrite_fn_name r    
+    in
+     if RT.is_noaddr r then
+       C.Comment (printf "%s has no address, user must supply %s" 
+                 (RT.name r) n)
+     else
+       C.StaticInline C.Void n args [ C.Ex $ loc_write r cv_regval ]
+
 --
 -- Write to register.  Harder than it sounds. 
 -- 
@@ -1067,13 +1106,26 @@ register_arg_list pre r post
        )
        ++ post)
 
+register_callarg_list :: [C.Param] -> RT.Rec -> [C.Param] -> [C.Param]
+register_callarg_list pre r post 
+    = (pre ++ [ C.Param (C.Ptr device_c_type) cv_dev ] 
+       ++ 
+       (if RT.is_array r then 
+            [ C.Param (C.TypeName "int") cv_i ]
+        else [] 
+       )
+       ++ post)
+
 --
 -- Generate an expression for a read or write of a register,
 -- regardless of address space or whether it's an array or not.
 -- 
 loc_read :: RT.Rec -> C.Expr
 loc_read r = 
-    case RT.spc r of
+  case RT.spc r of
+      Space.NoSpace -> 
+          C.Call (register_rawread_fn_name r)
+            [ C.Variable cv_dev ]
       Space.Builtin { Space.n = name } -> 
           C.Call (mackerel_read_fn_name name (RT.size r))
             [ C.DerefField (C.Variable cv_dev) (RT.base r), loc_array_offset r ]
@@ -1084,6 +1136,9 @@ loc_read r =
 loc_write :: RT.Rec -> String -> C.Expr
 loc_write r val = 
     case RT.spc r of
+      Space.NoSpace -> 
+          C.Call (register_rawwrite_fn_name r)
+            [ C.Variable cv_dev, C.Variable val ]
       Space.Builtin { Space.n = name } -> 
           C.Call (mackerel_write_fn_name name (RT.size r))
                 [ C.DerefField (C.Variable cv_dev) (RT.base r),
index 98f863c..16f342d 100644 (file)
@@ -27,17 +27,16 @@ data Rec = Builtin { n :: String,
                      devname :: String,
                      t :: SpaceType,
                      p :: SourcePos }
-           deriving Show
+         | UndefinedSpace
+         | NoSpace
+           deriving (Eq,Show)
 
 make :: String -> [String] -> String -> SpaceType -> SourcePos -> Rec
 make name args desc tpe pos = 
     Defined { n = name, a = args, d = desc, devname = "", t = tpe, p = pos }
 
 builtins :: [ Rec ]
-builtins = [ Builtin { n = "",
-                       d = "Undefined / unknown space",
-                       t = UNDEF },
-             Builtin { n = "addr",
+builtins = [ Builtin { n = "addr",
                        d = "Physical address space", 
                        t = BYTEWISE 1},
              Builtin { n = "io", 
@@ -51,7 +50,7 @@ builtins = [ Builtin { n = "",
 lookup :: String -> [Rec] -> Rec
 lookup sn spt = 
     let rl = [ s | s <- spt, (n s) == sn ]
-    in if length rl == 0 then head builtins else head rl
+    in if length rl == 0 then UndefinedSpace else head rl
 
 is_builtin :: Rec -> Bool
 is_builtin (Builtin _ _ _) = True