2069 lines
79 KiB
TeX
2069 lines
79 KiB
TeX
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% Copyright (c) 2011-2013, 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, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group.
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\documentclass[a4paper,11pt,twoside]{report}
|
|
\usepackage{bftn}
|
|
\usepackage{calc}
|
|
\usepackage{verbatim}
|
|
\usepackage{xspace}
|
|
\usepackage{pifont}
|
|
\usepackage{textcomp}
|
|
\usepackage{amsmath}
|
|
\usepackage{multirow}
|
|
|
|
\title{Mackerel User Guide}
|
|
\author{Barrelfish project}
|
|
% \date{\today} % Uncomment (if needed) - date is automatic
|
|
\tnnumber{2}
|
|
\tnkey{Mackerel}
|
|
|
|
\begin{document}
|
|
\maketitle % Uncomment for final draft
|
|
|
|
\begin{versionhistory}
|
|
\vhEntry{1.2}{31.05.2010}{TR}{Initial version under new formatting}
|
|
\vhEntry{1.3}{15.08.2011}{TR}{Added support for imports and new
|
|
command-line options}
|
|
\vhEntry{1.4}{09.12.2011}{TR}{New mapping for constants}
|
|
\vhEntry{1.5}{11.03.2013}{TR}{Added quick reference, corrected errors,
|
|
and clarified field insertions}
|
|
\end{versionhistory}
|
|
|
|
% \intro{Abstract} % Insert abstract here
|
|
% \intro{Acknowledgements} % Uncomment (if needed) for acknowledgements
|
|
\tableofcontents % Uncomment (if needed) for final draft
|
|
% \listoffigures % Uncomment (if needed) for final draft
|
|
% \listoftables % Uncomment (if needed) for final draft
|
|
\cleardoublepage
|
|
\setcounter{secnumdepth}{2}
|
|
|
|
\newcommand{\fnname}[1]{\textit{\texttt{#1}}}%
|
|
\newcommand{\datatype}[1]{\textit{\texttt{#1}}}%
|
|
\newcommand{\varname}[1]{\texttt{#1}}%
|
|
\newcommand{\keywname}[1]{\textbf{\texttt{#1}}}%
|
|
\newcommand{\tabindent}{\hspace*{3ex}}%
|
|
\newcommand{\Mac}{Mackerel\xspace}
|
|
|
|
|
|
%-------INTRODUCTION
|
|
|
|
|
|
\chapter{Introduction and Usage}
|
|
|
|
\Mac is a domain-specific language used to describe hardware devices
|
|
and the in-memory formats of registers and data structures like
|
|
descriptor lists, page-table entries, etc.
|
|
|
|
The \Mac language itself is designed to be easy to transcribe into
|
|
from a hardware data book or similar description - most of the
|
|
constructs correspond to the kinds of concepts one finds in hardware
|
|
descriptions.
|
|
|
|
A feature of the \Mac language is that, while traditional comments in
|
|
\Mac specifications are allowed, explanatory text in English is
|
|
included as part of a \Mac specification itself, and used to generate
|
|
debugging code which explains the meaning of register values.
|
|
|
|
Typically, it takes as input a specification written in the
|
|
Mackerel language and outputs a C header file consisting of a large
|
|
number of C inline function definitions to access and manipulate
|
|
registers and in-memory data structures, format them for printing in
|
|
human-readable form, etc.
|
|
|
|
The \Mac compiler is written in Haskell using the Parsec parsing
|
|
library. A quick roadmap of the source code files is provided in
|
|
Chapter \ref{chap:sourcetree}.
|
|
|
|
To manually invoke \Mac, run:
|
|
|
|
\verb~> mackerel --shift-driver -c devFile.dev -o devFile.h~
|
|
|
|
This will translate a device file into a single C header file containing all
|
|
relevant functions for accessing the device, as described in
|
|
Chapter~\ref{chap:shiftdriver}.
|
|
|
|
If you wish to use the (deprecated) bitfield-based back-end instead,
|
|
you can use:
|
|
|
|
\verb~> mackerel --bitfield-driver -c devFile.dev -o devFile.h~
|
|
|
|
This backend should not be used for new code, as it is not portable
|
|
across compilers. It is described in
|
|
Chapter~\ref{chap:bitfielddriver}.
|
|
|
|
\section{Command-line options}
|
|
|
|
The complete list of comand-line options supported by the current
|
|
Mackerel compiler is as follows:
|
|
\begin{itemize}
|
|
\item \texttt{-c} \textit{filename} or
|
|
\texttt{--input-file=}\textit{filename}: This option is mandatory
|
|
and specifies the pathname to be read. This pathname must specify
|
|
the file: the main input file will not be searched for along the
|
|
search path.
|
|
|
|
\item \texttt{-I} \textit{dir} or \texttt{--include-dir}
|
|
\textit{dir}: this option can be supplied multiple times and
|
|
specifies the search path for imported files.
|
|
|
|
\item \texttt{-v} or \texttt{--verbose}: Increases the verbosity level
|
|
of the compiler.
|
|
|
|
\item \texttt{-o} \textit{filename} or \texttt{--output-file}
|
|
\textit{filename}: this option, if supplied, specifies the name of
|
|
the C header file which will be written by the compiler. If not
|
|
given, the filename will be derived from the input filename by
|
|
removing all the directory components (i.e. it will reside in the
|
|
current working directory) and appending \texttt{.h}.
|
|
|
|
\item \texttt{-S} or \texttt{shift-driver}: Specifies the shift driver
|
|
backend; this is the default.
|
|
|
|
\item \texttt{-B} or \texttt{bitfield-driver}: Specifies the bitfield
|
|
driver backend; this is deprecated. Furthermore, imports are
|
|
(deliberately) not supported by the bitfield driver. If multiple
|
|
\texttt{-S} and \texttt{-B} options are specified, the last one
|
|
determines the compiler output.
|
|
|
|
\end{itemize}
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
\chapter{Lexical Conventions}\label{chap:lexical}
|
|
The following convention has been adopted for Mackerel. It is similar to
|
|
the convention opted by modern day programming languages like C and Java.\\
|
|
|
|
\begin{description}
|
|
\item[Whitespace:] As in C and Java, \Mac considers sequences of
|
|
space, newline, tab, and carriage return characters to be
|
|
whitespace. Whitespace is generally not significant.
|
|
|
|
\item[Comments:] \Mac supports C-style comments. Single line comments
|
|
start with \texttt{//} and continue until the end of the line.
|
|
Multiline comments are enclosed between \texttt{/*} and \texttt{*/};
|
|
anything inbetween is ignored and treated as white space.
|
|
|
|
\item[Identifiers:] Valid \Mac identifiers are sequences of numbers
|
|
(0-9), letters (a-z, A-Z) and the underscore character ``\texttt{\_}''. They
|
|
must start with a letter or ``\texttt{\_}''.
|
|
\begin{align*}
|
|
identifier & \rightarrow ( letter \mid \_ ) (letter \mid digit \mid \_)^{\textrm{*}} \\
|
|
letter & \rightarrow (\textsf{A \ldots Z} \mid \textsf{a \ldots z})\\
|
|
digit & \rightarrow (\textsf{0 \ldots 9})
|
|
\end{align*}
|
|
|
|
Note that a single underscore ``\texttt{\_}'' by itself is a special,
|
|
``don't care'' or anonymous identifier which is treated differently
|
|
inside the language.
|
|
|
|
\item[Integer Literals:] A \Mac integer literal is a sequence of
|
|
digits, optionally preceded by a radix specifier. As in C, decimal (base 10)
|
|
literals have no specifier and hexadecimal literals start with
|
|
\texttt{0x}. Binary literals start with \texttt{0b}.
|
|
|
|
In addition, as a special case the string \texttt{1s} can be used to
|
|
indicate an integer which is composed entirely of binary 1's.
|
|
|
|
\begin{align*}
|
|
digit & \rightarrow (\textsf{0 \ldots 9})^{\textrm{1}}\\
|
|
hexadecimal & \rightarrow (\textsf{0x})(\textsf{0 \ldots 9} \mid \textsf{A \ldots F} \mid \textsf{a \ldots f})^{\textrm{1}}\\
|
|
binary & \rightarrow (\textsf{0b})(\textsf{0, 1})^{\textrm{1}}\\
|
|
allones & \rightarrow \textsf{1s}\\
|
|
\end{align*}
|
|
|
|
|
|
\item[Reserved words:] The following are reserved words in \Mac:
|
|
\begin{alltt}
|
|
\begin{tabbing}
|
|
xxxxxxxxx \= xxxxxxxxx \= xxxxxxxxx \= xxxxxxxxx \= xxxxxxxxx \= xxxxxxxxx \kill
|
|
addr \> also \> bytewise \> constants \> datatype \> device \\
|
|
io \> lsbfirst \> many \> msbfirst \> pci \> regarray \\
|
|
register \> regtype \> space \> stepwise \> type \> valuewise \\
|
|
import
|
|
\end{tabbing}
|
|
\end{alltt}
|
|
|
|
\item[Special characters:] The following characters are used as operators,
|
|
separators, terminators or other special purposes in \Mac:
|
|
\begin{alltt}
|
|
|
|
\{ \} [ ] ( ) + - * / ; , . _ =
|
|
|
|
\end{alltt}
|
|
|
|
\end{description}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
\chapter{Declarations}\label{chap:declarations}
|
|
|
|
A \Mac source file must consist of zero or more \textit{import}
|
|
declarations, followed by a single \textit{device
|
|
specification}, which itself consists of further specifications of
|
|
registers, register types, etc.
|
|
|
|
\section{Imports}\label{sec:imports}
|
|
|
|
An import declaration makes the definitions in a different device file
|
|
available in the current device definition, as described below. The
|
|
syntax of an import declaration is as follows:
|
|
|
|
\begin{syntax}
|
|
import \synit{device};
|
|
\end{syntax}
|
|
|
|
\begin{description}
|
|
\item[device] is the name of a device from which to import
|
|
definitions.
|
|
\end{description}
|
|
|
|
The \Mac compiler will search for a file with the appropriate name and
|
|
parse this at the same time as the main file, along with this file's
|
|
imports, and so on. Cyclic dependencies between device files will not
|
|
cause errors, but at present are unlikely to result in C header files
|
|
which will successfully compile.
|
|
|
|
\section{Devices}\label{sec:devices}
|
|
|
|
A device declaration in \Mac specifies a particular type of hardware
|
|
device (such as an ioAPIC or a particular Ethernet controller). The
|
|
syntax is as follows:
|
|
|
|
\begin{syntax}
|
|
device \synit{name} [lsbfirst|msbfirst] ( \synit{args} ) "\synit{description}"
|
|
\verb+{+
|
|
\synit{declaration};
|
|
\ldots
|
|
\verb+}+;
|
|
\end{syntax}
|
|
|
|
\begin{description}
|
|
\item[name] is an identifier for the device type, and will be used to
|
|
generate identifiers in the target language (typically C).
|
|
The name of the name of the device \emph{must} correspond to the
|
|
filename of the file, including case sensitivity: for example,
|
|
the file \texttt{xapic.dev} will define a device type
|
|
of name \texttt{xapic}.
|
|
|
|
\item[lsbfirst or msbfirst] optionally specifies the \emph{bit order}
|
|
of the declarations
|
|
inside the device file; if specified, it must be \texttt{lsbfirst}
|
|
(the default) or \texttt{msbfirst}.
|
|
|
|
Note that this does not say \emph{anything} about the endianness of
|
|
the hardware device, or the host platform, or the execution
|
|
environment. It simply says which order the bitfields in particular
|
|
registers are listed in the declarations which follow --
|
|
least-significant bits first or most-sigificant bits first.
|
|
|
|
The reason for this feature is that \Mac specifications are
|
|
typically transcribed from chip datasheets, and while these are
|
|
generally unambiguous there is no clear convention on which order to
|
|
list a hardware register bitfields in a datasheet. This feature
|
|
means that the \Mac specification can more closely resemble to text
|
|
in the datasheet.
|
|
|
|
When transcribing a datasheet into a \Mac specification, if the
|
|
fields in a register or register type are listed starting with the
|
|
one which includes bit 0, specify \texttt{lsbfirst}. If the fields
|
|
are listed starting with the one which includes the high bit in the
|
|
register, specify \texttt{msbfirst}. In both cases type the fields
|
|
in the order they are printed in the datasheet.
|
|
|
|
\item[args] are the arguments that specify how to access the device.
|
|
They are treated as base addresses in one of several \emph{address
|
|
spaces} supported by \Mac (see Section~\ref{sec:spaces}
|
|
below). Typical devices have a single base address in either memory
|
|
or I/O space, though some device types (of which only one instance
|
|
ever exists, and at a fixed address) have no arguments, and others
|
|
may have more if they have multiple register sets which can appear
|
|
at different addresses.
|
|
|
|
The arguments will become arguments to the function that intializes
|
|
the struct used to represent the device in \Mac-generated C.
|
|
They are also used within the device declaration to specify the
|
|
locations of individual registers or groups of registers.
|
|
|
|
Arguments are declared in C-style type notation as either of type
|
|
\texttt{address} (in memory space) or \texttt{io} (in I/O
|
|
space). By convention a single device argument is named
|
|
\texttt{base}.
|
|
|
|
\item [description] is a string literal in double quotes, which
|
|
describes the device type being specified, for example \texttt{"AC97
|
|
Baseline Audio"}.
|
|
|
|
\end{description}
|
|
|
|
After the description string follows in curly brackets a series of
|
|
declarations which specify details of the device hardware. Each
|
|
declaration must be one of the following:
|
|
|
|
\begin{itemize}
|
|
|
|
\item A \texttt{space} declaration, describing a device-specific
|
|
address space for registers in addition to the built-in address
|
|
spaces.
|
|
|
|
\item A \texttt{constants} list, analogous to a C enumeration type
|
|
|
|
\item A \texttt{register} declaration, describing a particular
|
|
hardware register or group of registers
|
|
|
|
\item A \texttt{regtype} definition, giving the type and format of
|
|
other hardware register values.
|
|
|
|
\end{itemize}
|
|
|
|
\section{Address spaces}\label{sec:spaces}
|
|
|
|
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:
|
|
|
|
\begin{description}
|
|
|
|
\item[addr]: Physical memory, for memory-mapped I/O. Register
|
|
locations in physical address space are given as offsets relative to
|
|
a base address which is an argument to the device definition.
|
|
|
|
\item[io]: I/O port space, for \texttt{ia32} machines. An I/O address
|
|
is a 16-bit port number, and register locations in I/O port space
|
|
are given as offsets relative to a base address which is an argument
|
|
to the device definition.
|
|
|
|
\item[pci]: PCI Configuration space. A PCI configuration space
|
|
address is a 4-tuple of \textit{(bus, device, function, offset)}, however,
|
|
\Mac only deals in integer offsets from an opaque ``base'' address,
|
|
allowing for different addressing schemes depending on hardware.
|
|
|
|
\end{description}
|
|
|
|
In addition, \Mac allows the specification of per-device address
|
|
spaces. This feature can express a variety of hardware features, for
|
|
example processor model-specific registers, co-processor registers,
|
|
device registers that must be accessed indirectly through another
|
|
index registers, etc.
|
|
|
|
The syntax for defining a new address space is:
|
|
|
|
\begin{syntax}
|
|
space \synit{name}(\synit{index}) bytewise|valuewise|stepwise(\textit{step})|registerwise
|
|
"\synit{description}";
|
|
\end{syntax}
|
|
|
|
\begin{description}
|
|
\item[name] is an identifier for the address space, and is used in
|
|
register declarations instead of a builtin space such as
|
|
\texttt{addr} or \texttt{io}.
|
|
|
|
\item [index] is an identifier for the argument giving the address for
|
|
the registers
|
|
|
|
\item [bytewise, valuewise or registerwise] defines how registers in the new
|
|
space are addressed. Bytewise addresses are like conventional
|
|
memory addresses, for example two adjacent 32-bit registers in a
|
|
bytewise-addressed space will have offsets that differ by 4. All
|
|
the built-in address spaces (\texttt{addr}, \texttt{pci}, and
|
|
\texttt{io}) are bytewise-addressed.
|
|
|
|
In contrast, registers in a valuewise-addressed space are indexed by
|
|
a simple integer regardless of size, meaning that two adjacent
|
|
32-bit registers will have addresses that differ only by 1.
|
|
A good example of a valuewise address space is the set of ia32
|
|
model-specific registers (MSRs).
|
|
|
|
If neither of these is sufficient, \texttt{stepwise} allows you to
|
|
explicitly specify how many bytes are occupied by each address in
|
|
the address space. \texttt{bytewise} is therefore a synonym for
|
|
\texttt{stepwise(1)}, but \texttt{stepwise(4)} might be useful for
|
|
devices (such as some IOAPICs) where registers are indexed by 32-bit
|
|
values but can be accessed as 64-bit quantities.
|
|
|
|
Alternatively, \texttt{registerwise} gives more freedom by calling a
|
|
custom function to access each register. For a 32-bit register \texttt{R} in the
|
|
registerwise address space \texttt{S}, the read and write functions are
|
|
declared as follows:
|
|
%
|
|
\begin{syntax}
|
|
uint32_t __DN(S_read_32_R)(void);
|
|
void __DN(S_write_32_R)(uint32_t _regval);
|
|
\end{syntax}
|
|
|
|
|
|
\item [``description''] is a string literal in double quotes, which
|
|
describes the constant type being specified, for example
|
|
\texttt{"PHY control registers"}.
|
|
|
|
\end{description}
|
|
|
|
Register addresses in user-defined address spaces are always given
|
|
simply as offsets, since the base is implicit in the device
|
|
definition.
|
|
|
|
\Mac files cannot currently say how registers in a particular space
|
|
are accessed; this functionality must be provided externally by the
|
|
programmer (typically by short inline functions).
|
|
|
|
Here is how ia32 MSRs are defined:
|
|
|
|
\begin{example}
|
|
space msr valuewise "Model-specific Registers";
|
|
register platform\_id ro msr(0x17) "Platform ID" \verb+{+
|
|
\_ 50;
|
|
id 3 "platform id";
|
|
\_ 11;
|
|
\verb+}+;
|
|
\ldots
|
|
\end{example}
|
|
|
|
As a second example, here is a set of space declarations (and
|
|
associated index and data registers) from the legacy PC real-time
|
|
clock (RTC) definition:
|
|
|
|
\begin{example}
|
|
space std(idx) valuewise "Standard register space";
|
|
register ndx rw io(base, 0x70) "Standard index"
|
|
type(uint8);
|
|
register target rw io(base, 0x71) "Standard target"
|
|
type(uint8);
|
|
regarray standard rw std(0x00)[256] type(uint8);
|
|
|
|
space ext(idx) valuewise "Extended register space";
|
|
register endx rw io(base, 0x72) "Extended index"
|
|
type(uint8);
|
|
register etarget rw io(base, 0x73) "Extended target''
|
|
type(uint8);
|
|
regarray extended rw std(0x00)[256] type(uint8);
|
|
\end{example}
|
|
|
|
\section{Constants}\label{sec:constants}
|
|
|
|
A \texttt{constant} declaration defines a series of related values,
|
|
for example, the possible values of a given register field. Each
|
|
constant type consists of an identifier for the type, a textual
|
|
description, and a series of possible values. Each value in turn
|
|
consists of an identifier for the value, the numerical value itself,
|
|
and a textual description of its meaning.
|
|
|
|
The syntax is:
|
|
|
|
\begin{syntax}
|
|
constants \synit{name} [width( \synit{width} )] "\synit{description}" \verb+{+
|
|
\synit{name\(\sb{1}\)} = \synit{value\(\sb{1}\)} ["\synit{description\(\sb{1}\)}"] ;
|
|
\ldots
|
|
\verb+}+;
|
|
\end{syntax}
|
|
|
|
|
|
\begin{description}
|
|
\item[name] is an identifier for the constant type, and will be used to
|
|
generate identifiers in the target language (typically C). The
|
|
scope of this identifier is the enclosing device specification.
|
|
|
|
\item[width] is optional, and specifies the width of the constant
|
|
value in bits. This is useful, for example, when the type is used
|
|
as the type of a register.
|
|
|
|
\item [``description''] is a string literal in double quotes, which
|
|
describes the constant type being specified, for example
|
|
\texttt{"Vector delivery mode"}.
|
|
\end{description}
|
|
|
|
Each constant value is given as follows:
|
|
|
|
\begin{description}
|
|
|
|
\item[name$_i$] is an identifier for the particular value of the
|
|
constant type. The scope of this identifier is the enclosing
|
|
constant declaration, not the device declaration as a whole.
|
|
|
|
\item[value$_i$] is an expression giving the corresponding numerical
|
|
value. This will usually be a literal like \texttt{0b1101} or
|
|
\texttt{0xf}, though it can potentially be any arithmetic expression
|
|
supported by \Mac.
|
|
|
|
\item[``description$_i$''] is an optional string literal in double
|
|
quotes, which describes the meaning of the value being specified,
|
|
for example \texttt{"Lowest priority"}. If not specified, it
|
|
defaults to the identifier name$_i$.
|
|
|
|
\end{description}
|
|
|
|
Here is a complete example of a constants declaration, taken from the
|
|
xAPIC definition:
|
|
|
|
\begin{example}
|
|
constants vdm "Vector delivery mode" \verb+{+
|
|
fixed = 0b000 "Fixed";
|
|
lowest = 0b001 "Lowest priority";
|
|
smi = 0b010 "SMI";
|
|
nmi = 0b100 "NMI";
|
|
init = 0b101 "INIT";
|
|
startup = 0b110 "Start Up";
|
|
extint = 0b111 "ExtINT";
|
|
\verb+}+;
|
|
\end{example}
|
|
|
|
Note that the collection of constant values does not have to be
|
|
complete or contiguous.
|
|
|
|
\section{Register types}\label{sec:regtypes}
|
|
|
|
A \texttt{regtype} declaration defines a data type corresponding to the
|
|
format of one or more registers; it can be thought of as a translation
|
|
of the bitfield descriptions typically found in data sheets. A
|
|
\texttt{regtype} doesn't define any particular hardware registers
|
|
(see \texttt{register} declarations below), merely a data type for
|
|
representing their contents.
|
|
The syntax is as follows:
|
|
|
|
\begin{syntax}
|
|
regtype \synit{name} ["\synit{description}"] \verb+{+
|
|
\synit{fieldname}\(\sb{1}\) \synit{width} [type(\synit{fieldtype})] [\synit{attr}] ["\synit{description}"];
|
|
\ldots
|
|
\verb+}+;
|
|
\end{syntax}
|
|
|
|
\begin{description}
|
|
|
|
\item[name] is an identifier for the register type. Its scope is the
|
|
enclosing device declaration.
|
|
|
|
\item[description] is an optional string in double quotes, giving a
|
|
description of the register type, for example \texttt{"LVT
|
|
monitor"}. If not present, it defaults to the identifier.
|
|
|
|
\end{description}
|
|
|
|
The field descriptions declare the individual bitfields which make up
|
|
the register type. The order in which these are given is determined
|
|
by the \texttt{lsbfirst} or \texttt{msbfirst} declaration in the
|
|
\texttt{device} specification: if \texttt{lsbfirst}, the first field
|
|
given starts at bit 0, etc.
|
|
|
|
\begin{description}
|
|
|
|
\item[fieldname] is an identifier for the bit field. It can be
|
|
given as an underscore (\texttt{\_}) to indicate ``don't care'' or
|
|
``reserved'' fields, in which case the field is
|
|
assumed to have an attributed of \texttt{rsvd} (see below), and no
|
|
description is needed.
|
|
|
|
\item[width] is an integer giving the width of the field in bits.
|
|
|
|
\item[fieldtype] is an optional identifier giving the type of this field.
|
|
This must be either the identifier of a \texttt{constants} declaration
|
|
somewhere in the enclosing \texttt{device} declaration, for example
|
|
\texttt{type(vdm)}, or a qualified name of the form
|
|
\textit{device}\texttt{.}\textit{constdef}, where \textit{device} is
|
|
the name of a device definition previously imported.
|
|
|
|
\item[attr] is an optional field
|
|
attribute. See section~\ref{sec:fieldattrs} for more information.
|
|
|
|
\item[description] is an optional string in double quotes, giving a
|
|
description of the field, for example \texttt{"Logical APIC ID"}.
|
|
If not present, it defaults to the identifier.
|
|
|
|
\end{description}
|
|
|
|
% feature from old version:
|
|
% There is another variation for defining the bit-width for register layout in
|
|
% bit-fields, called {\it location based width}, besides {\it normal mode}. It
|
|
% may be more error prone and tiresome process for the user, to manually
|
|
% calculate the bit width. Mackerel can do this for users. To automate the
|
|
% process of calculating bit-width, user can specify exact register layout and
|
|
% Mackerel will put appropriate bit-width. User just has to put bit location
|
|
% it into (), to distuinguish it from normal mode.
|
|
%
|
|
% \verb+(startbit - endbit)+
|
|
%
|
|
% A number 8 in field declaration, in normal mode, represents 8 bits but (8)
|
|
% represents single bit. Like wise, (9-11) (which are starting and ending
|
|
% location of that particular field) represents 3 bits in register layout. By
|
|
% using this mode of specifying the register layout, user can copy bit location
|
|
% as it is from the hardware specificaion to dev file avoiding any confusions.
|
|
|
|
|
|
Here is a complete example of a \texttt{regtype} declaration, taken from the
|
|
xAPIC definition:
|
|
\begin{example}
|
|
regtype lvt_lint "LVT Int" \verb+{+
|
|
vector\verb+ +8 "Vector";
|
|
dlv_mode\verb+ +4 type(vdm) "Delivery mode";
|
|
_\verb+ +1;
|
|
status\verb+ +1 "Delivery status";
|
|
pinpol\verb+ +1 "Pin polarity";
|
|
rirr\verb+ +1 "Remote IRR";
|
|
trig_mode\verb+ +1 "Trigger mode";
|
|
mask\verb+ +1 "Mask";
|
|
_\verb+ +15;
|
|
\verb+}+;
|
|
\end{example}
|
|
|
|
\section{Registers}\label{sec:registers}
|
|
|
|
A \texttt{register} declaration defines a particular hardware register
|
|
on the device.
|
|
|
|
\begin{syntax}
|
|
register \synit{name} [\synit{attr}] [also]
|
|
\{ noaddr | \synit{space}( \synit{address} ) \} ["\synit{description}"] \synit{type} ;
|
|
\end{syntax}
|
|
|
|
\begin{description}
|
|
|
|
\item[name] is an identifier for the register. Its scope is the
|
|
enclosing \texttt{device} declaration.
|
|
|
|
\item[attr] is an (optional) attribute. See
|
|
Section~\ref{sec:fieldattrs} for more information.
|
|
|
|
\item[space] gives the address space of this register
|
|
(e.g. \texttt{addr}, \texttt{io}, \texttt{pci}, or a per-device
|
|
user-defined address space).
|
|
|
|
\item[address] gives the address of the register in the address
|
|
space. For builtin address spaces this is given as a
|
|
comma-separated pair of \textit{(base, offset)} where \textit{base}
|
|
is a device argument of the correct type and \textit{offset} is an
|
|
integer-valued \Mac expression. For user-defined address spaces,
|
|
the address is a single \Mac integer expression giving the register
|
|
index.
|
|
|
|
By default, it is an error to specify more than one
|
|
register at the same location, or at locations which overlap. By
|
|
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.
|
|
|
|
\item[type] gives the format of the register. It can consist of
|
|
\texttt{type(}\textit{name}\texttt{)}, where \textit{name} is
|
|
either:
|
|
\begin{itemize}
|
|
\item the identifier of a register type previously declared with a
|
|
\texttt{regtype} declaration;
|
|
\item the identifier of a constants type previously declared with a
|
|
\texttt{constants} declaration which included an explicit
|
|
\texttt{width()} specifier;
|
|
\item one of the built in register types \texttt{uint8},
|
|
\texttt{uint16}, \texttt{uint32}, or \texttt{uint64}; or
|
|
\item a qualified name of the form
|
|
\textit{device}\texttt{.}\textit{type}, where \textit{device}
|
|
is the name of a device definition previously imported.
|
|
\end{itemize}
|
|
|
|
Alternatively, the type can be given as a sequence of fields in
|
|
braces, exactly as in a \texttt{regtype} declaration. In effect,
|
|
this latter form defines both a register type and a register at the
|
|
same time, with the same name.
|
|
|
|
\end{description}
|
|
|
|
Here are some examples of \texttt{register} definitions:
|
|
|
|
\begin{example}
|
|
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);
|
|
\end{example}
|
|
\begin{example}
|
|
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}
|
|
|
|
A \texttt{regarray} declaration defines an array of hardware registers
|
|
on the device, all of which have the same type and attributes.
|
|
|
|
\begin{syntax}
|
|
regarray \synit{name} [\synit{attr}] [also]
|
|
\synit{space}( \synit{address} ) ["\synit{description}"] \synit{type} ;
|
|
\end{syntax}
|
|
|
|
All fields are as for register declarations, except:
|
|
|
|
\begin{description}
|
|
|
|
\item[address] gives the address of the registers which form the array
|
|
in the address space. This is given as for a single
|
|
\texttt{register} declaration, followed by an array specifier in
|
|
square brackets.
|
|
|
|
There are three forms of array specifier. The simplest looks like
|
|
this:
|
|
\begin{example}
|
|
regarray ier ro addr(base, 0x0480) [ 8 ]
|
|
"IER" type(uint32);
|
|
\end{example}
|
|
This specifies a contiguous array of 8 32-bit registers starting at
|
|
\texttt{base + 0x0480}. This example therefore occupies 32 bytes of
|
|
IO space. Alternatively:
|
|
\begin{example}
|
|
regarray ier ro addr(base, 0x0480) [ 8; 0x10 ]
|
|
"IER" type(uint32);
|
|
\end{example}
|
|
This second example specifies 8 32-bit registers, which occur every 16 bytes,
|
|
starting at \texttt{base + 0x0480}. Finally, one can explicitly
|
|
list the individual locations for the array (note: the back-end does
|
|
not yet generate correct code for this case):
|
|
\begin{example}
|
|
regarray ier ro addr(base, 0x0480) [ 0, 0x10, 0x18 ]
|
|
"IER" type(uint32);
|
|
\end{example}
|
|
This third example specifies 3 32-bit registers, at offsets of
|
|
\texttt{0x480}, \texttt{0x490}, and \texttt{0x498} from
|
|
\texttt{base}.
|
|
|
|
\end{description}
|
|
|
|
\section{Data types}\label{sec:datatypes}
|
|
|
|
A \texttt{datatype} declaration defines a data type corresponding to the
|
|
format of a structure in memory; it can be used to represent in-memory
|
|
hardware-defined datastructures like page table entries or DMA
|
|
descriptors.
|
|
|
|
The syntax is as follows:
|
|
|
|
\begin{syntax}
|
|
datatype \synit{name} [lsbfirst|msbfirst (\synit{wordsize})] ["\synit{descr}"] \verb+{+
|
|
\synit{fieldname}\(\sb{1}\) \synit{width} [type(\synit{fieldtype})] [\synit{attr}] ["\synit{description}"];
|
|
\ldots
|
|
\verb+}+;
|
|
\end{syntax}
|
|
|
|
\begin{description}
|
|
|
|
\item[name] is an identifier for the data type. Its scope is the
|
|
enclosing device declaration.
|
|
|
|
\item[lsbfirst or msbfirst] together with a (required) word size
|
|
specify how the fields in the specification are ordered. This is
|
|
described in more detail below.
|
|
|
|
\item[description] is an optional string in double quotes, giving a
|
|
description of the register type, for example \texttt{"LVT
|
|
monitor"}. If not present, it defaults to the identifier.
|
|
|
|
\end{description}
|
|
|
|
The field descriptions declare the individual bitfields which make up
|
|
the data type.
|
|
|
|
The order in which these are given is determined
|
|
by the \texttt{lsbfirst} or \texttt{msbfirst} declaration. Data
|
|
structures in memory are sometimes listed in data books as a sequence
|
|
of words, each of which is formatted into bit fields. In order for
|
|
authors of device specifications to easily translate these
|
|
descriptions into Mackerel, one can specify the ``word size'' used in
|
|
the description along with the order in which bit fields within a
|
|
word are listed. For example, ``\texttt{msbfirst(32)}'' means that
|
|
the bit fields are to be grouped into words of 32 bits each, and
|
|
within each word the fields are listed most-significant-bit (i.e. the
|
|
field containing bit 31) first. On an Intel architecture machine,
|
|
this will cause the resulting C declaration to be derived by taking
|
|
the first set of fields whose width adds up to 32, reversing their
|
|
order in the struct declaration, then the next group, etc.
|
|
|
|
Specifying a word size of 0 will cause the entire set of fields to be
|
|
reordered (if necessary) in one go. If no bit order and word size are
|
|
specified, the default is that of the device itself, with a word size
|
|
of 0.
|
|
|
|
\begin{description}
|
|
|
|
\item[fieldname] is an identifier for the bit field. It can be
|
|
given as an underscore (\texttt{\_}) to indicate ``don't care'' or
|
|
``reserved'' fields, in which case the field is
|
|
assumed to have an attributed of \texttt{rsvd} (see below), and no
|
|
description is needed.
|
|
|
|
\item[width] is an integer giving the width of the field in bits.
|
|
|
|
\item[fieldtype] is an optional identifier giving the type of this field.
|
|
This must be the identifier of a \texttt{constants} declaration
|
|
somewhere in the enclosing \texttt{device} declaration, for example
|
|
\texttt{type(vdm)}.
|
|
|
|
\item[attr] is an optional field
|
|
attribute. See section~\ref{sec:fieldattrs} for more information.
|
|
The only field attributes allowed for data types are \texttt{rsvd},
|
|
\texttt{mbz}, \texttt{mb1}, or \texttt{rw}. ``Don't care'' fields
|
|
default to \texttt{rsvd}; others default to \texttt{rw}.
|
|
|
|
\item[description] is an optional string in double quotes, giving a
|
|
description of the field, for example \texttt{"Command header"}.
|
|
If not present, it defaults to the identifier.
|
|
|
|
\end{description}
|
|
|
|
Here is a complete example of a \texttt{regtype} declaration, taken from the
|
|
a SATA AHCI port definition:
|
|
\begin{example}
|
|
datatype cls msbfirst(32) "Command list structure" \verb+{+
|
|
prdtl\verb+ +16 "Physical region descriptor table length";
|
|
pmp\verb+ +4 "Port multiplier port";
|
|
\_\verb+ +1;
|
|
c\verb+ +1 "Clear busy upon R\_OK";
|
|
b\verb+ +1 "BIST";
|
|
r\verb+ +1 "Reset";
|
|
p\verb+ +1 "Prefetchable";
|
|
w\verb+ +1 "Write";
|
|
a\verb+ +1 "ATAPI";
|
|
cfl\verb+ +5 "Command FIS length";
|
|
prdbc\verb+ +32 "Physical region descriptor byte count";
|
|
ctba\verb+ +32 "Command table descriptor base addr";
|
|
ctbau\verb+ +32 "Command table descriptor base addr upper";
|
|
\_\verb+ +32;
|
|
\_\verb+ +32;
|
|
\_\verb+ +32;
|
|
\_\verb+ +32;
|
|
\verb+}+;
|
|
\end{example}
|
|
|
|
\section{Field and register attributes}\label{sec:fieldattrs}
|
|
|
|
This section lists the various attributes that can be applied to
|
|
register fields or entire registers. Some of these values can only be
|
|
applied to register fields, and not to entire registers. Some of
|
|
these attributes are functionally equivalent from the point of view of
|
|
client code generated by \Mac, but the aim is to facilitate typing in
|
|
information from data sheets.
|
|
|
|
\begin{description}
|
|
|
|
\item[rw] Read/write. The value is readable and writable. This is
|
|
the default.
|
|
|
|
\item[ro] Read-only. The value is readable, but not writeable. No
|
|
code will be generated to handle writes to this value.
|
|
|
|
\item[wo] Write-only. The value is writable, but not readable. No
|
|
code will be generated to handle reads from this value, but
|
|
generated code may keep a ``shadow'' copy of the last value written
|
|
to aid in debugging.
|
|
|
|
\item[rc] Read to clear. The value is readable, but not writeable,
|
|
and a read operation will clear the value (this is sometimes seen
|
|
with statistical count registers, for example). Driver code
|
|
generated for registers will behave as if the register was
|
|
\textbf{ro}, so care must be taken if extra reads are inserted. In
|
|
particular, remember that printing the value of the register in
|
|
debugging code will clear it.
|
|
|
|
\item[rwzc] Read/write zero to clear. The value is readable. A write of 0
|
|
clears (sets to 0) the corresponding bit, and a write of 1 has no effect.
|
|
|
|
\item[rw1c] Read/write one to clear. The value is readable. A write of 1
|
|
clears (sets to 0) the corresponding bit, and a write of 0 has no
|
|
effect.
|
|
|
|
\item[rwc] Read/write clear. A synonmym for \textbf{rw1c}.
|
|
|
|
\item[ros] Read-only sticky. Value is readable and not writeable. In
|
|
Intel nomenclature, the bits can only be reset with a power cycle;
|
|
in \Mac this attribute is simply a synonym for \texttt{ro}.
|
|
|
|
\item[rw1cs] Read and write one to clear and sticky. In Intel
|
|
nomenclature, this is equivalent to \texttt{rwc} but bits can only
|
|
be reset on a power cycle.
|
|
|
|
\item[rwcs] Read, write to clear and sticky. A synonym for \textbf{rw1cs}.
|
|
|
|
\item[rwo] Read/write once. Can be written to precisely once after
|
|
reset, and thereafter is read-only.
|
|
|
|
\item[rws] Read/write and sticky. Software can read and write to this
|
|
bit, but the bit can only be reset after a power cycle.
|
|
|
|
\item[rsvd] Reserved. \Mac generates code to allow clients to read
|
|
reserved bits, but when writing a register value, code generated by \Mac
|
|
will ensure the bit values are preserved, if necessary by performing
|
|
a read before the write.
|
|
|
|
\item[mbz] Must be zero. \Mac will generate no code to read the
|
|
value, but will ensure that it is always written as 0.
|
|
|
|
\item[mb1] Must be one. \Mac will generate no code to read the
|
|
value, but will ensure that it is always written as 1.
|
|
|
|
\end{description}
|
|
|
|
Register attributes can be \texttt{rw}, \texttt{ro}, or \texttt{wo},
|
|
and provide a default attribute for each field of the register. If
|
|
no attributes at all are specified, \texttt{rw} is assumed, except in
|
|
the case of an anonymous register field (denoted by an underscore
|
|
``\texttt{\_}''), which defaults to
|
|
\texttt{rsvd} regardless of the register attribute. The motivation for
|
|
this design choice is that unused fields of registers are frequently
|
|
``reserved'' rather than ``don't care''. The default behaviour will
|
|
therefore result in potential inefficiency (due to reading the value
|
|
before writing it), but never incorrect behaviour (due to writing the
|
|
wrong values to a reserved field).
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
\chapter{C mapping for device drivers}\label{chap:shiftdriver}
|
|
|
|
For each device specification, \Mac generates a single C header file
|
|
giving all the necessary definitions and declarations. While
|
|
developers are not expected to look at this file in normal use, it is
|
|
designed to be fairly readable to curious humans, and is worth
|
|
examining to understand what \Mac is generating (and to find bugs in
|
|
\Mac).
|
|
|
|
The file for a device called, say, \texttt{apic} is conventionally named
|
|
\texttt{apic\_dev.h}, and in Barrelfish is usually found in
|
|
the \texttt{dev} subdirectory of the main include directory; thus a C
|
|
file would include it with:
|
|
|
|
\begin{alltt}
|
|
#include <dev/apic\_dev.h>
|
|
\end{alltt}
|
|
|
|
This chapter will describe the contents of this header file.
|
|
|
|
\section{Preamble}
|
|
|
|
The header file is protected by the customary macro to ensure that it
|
|
is only included once - for example, for a device called \texttt{DEV} this is
|
|
``\texttt{\_\_DEV\_H}''.
|
|
|
|
The file includes only one other header file: \texttt{mackerel.h}.
|
|
This latter header file includes declarations for the low-level read
|
|
and write functions that \Mac code requires, and some other
|
|
preprocessor macros to ensure correct C code generation.
|
|
|
|
|
|
%% \Mac prefixes all declarations in the file with the
|
|
%% name of the file plus an underscore (``\texttt{DEV\_}''). However, for
|
|
%% most (though not all) declarations this prefix can be overridden by
|
|
%% defining the macro ``\texttt{DEV\_PREFIX}'' before including the file.
|
|
|
|
%% This is at first sight a little confusing. Suppose we have a device
|
|
%% called \texttt{pc16550d\_uart}. By default, any declaration
|
|
%% \texttt{foo} in \Mac file will correspond to
|
|
%% \texttt{pc16550d\_uart\_foo} in the header file.
|
|
|
|
%% If, however, we include a line:
|
|
|
|
%% \begin{quote}
|
|
%% \texttt{\#define pc16550d\_uart\_PREFIX uart}
|
|
%% \end{quote}
|
|
|
|
%% -- before including the header file, that declaration is likely to now
|
|
%% be \texttt{uart\_foo}.
|
|
|
|
In the rest of this chapter, we'll use ``\texttt{DN\_}'' as the
|
|
device prefix that cannot be redefined in this manner, and ``\texttt{DP\_}''
|
|
as device prefix that can.
|
|
|
|
\section{Device-level declarations}
|
|
|
|
For the device, \Mac generates:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item a C structure type to represent what it knows about the
|
|
device, called \texttt{DN\_t}. To access a device from C via \Mac,
|
|
you first need to declare one of these, and then call a function
|
|
(see below) to initialize it.
|
|
|
|
The struct contains fields which correspond to each of the arguments
|
|
which define the addresses of the device, plus a ``shadow'' copy of
|
|
every register on the device which has at least one write-only field -
|
|
this is used to keep track of the last value written to the register.
|
|
|
|
\item The initialization function \texttt{DN\_initialize}. For a
|
|
device type with an argment of ``\texttt{io base}'', the
|
|
initialization function looks like:
|
|
|
|
\begin{quote}
|
|
\texttt{void DN\_initialize( DN\_t *\_dev, mackerel\_io\_t base );}
|
|
\end{quote}
|
|
|
|
The idiom for accessing a device at IO address \texttt{ia} would be:
|
|
|
|
\begin{quote}
|
|
\texttt{DN\_t dev;}\\
|
|
\texttt{DN\_initialize( \&dev, ia );}\\
|
|
\ldots\\
|
|
\textit{code to access registers via \texttt{dev}}
|
|
\end{quote}
|
|
|
|
\item An enumeration declaration \texttt{enum
|
|
DN\_initials}, with a field \texttt{DN\_REG\_initial} for each
|
|
register \texttt{REG} defined in the device. Currently, all these
|
|
enumeration fields are set to \texttt{0x00}, and are used inside the
|
|
generated initialization function to initialize any shadow copies of
|
|
registers in the device struct.
|
|
|
|
\item An \texttt{snprintf}-like function to
|
|
pretty-print \emph{all} the register contents of the device, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DN\_pr(char *s, size\_t sz, DN\_t *v);}
|
|
\end{quote}
|
|
For a complex device, this is a lot of information, and may require a
|
|
large buffer to fully capture. This is also potentially a large
|
|
function to inline. It will result in reads from all readable device
|
|
registers, including ``read to clear'' (\textbf{rc}) registers and
|
|
fields. For write-only registers, this function will print the shadow
|
|
copy of the register maintained in the device structure, which holds
|
|
the last value written to the register (or 0 if the register has not
|
|
been written since the initialization function was called). The
|
|
output identifies which values are ``real'' and which are shadow
|
|
copies, includes descriptions of all register fields, and translates
|
|
symbolic values into their names and descriptions.
|
|
\end{enumerate}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
\section{Constants}
|
|
|
|
For a constants declaration of type \texttt{CNSTS}, having fields
|
|
\texttt{FIELD1} and \texttt{FIELD2}, \Mac will generate the following:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item A type definition which defines type \texttt{DP\_CNSTS\_t} to be
|
|
an unsigned integer type (e.g.\ \texttt{uint8\_t} or
|
|
\texttt{uint64\_t}). The type is the smallest such type large
|
|
enough to hold the largest value in the constants declaration, or
|
|
(if the width is explicitly given) the smallest such type wider than
|
|
the given width.
|
|
|
|
\item A set of CPP macro definitions \texttt{DP\_FIELD1} and
|
|
\texttt{DP\_FIELD2}, each of which expands to a C expression
|
|
consisting of the field value cast to type \texttt{DP\_CNSTS\_t}.
|
|
|
|
If the field value is specified as \texttt{1s}, the macro will
|
|
expand to the C value \texttt{-1LL} cast to type
|
|
\texttt{DP\_CNSTS\_t}.
|
|
|
|
Note that the field names are not prefixed by the constants name,
|
|
only the device prefix.
|
|
|
|
The motivation for using CPP macros (rather than C enumerations, as
|
|
in an earlier version of Mackerel) is that \texttt{enum} types are
|
|
only the size of C \texttt{int}s, whereas Mackerel can specify
|
|
values in \texttt{constants} declarations which are larger than
|
|
this (such as 64-bit values).
|
|
|
|
The motivation for not using constant unsigned integer declarations
|
|
is that macros allow us to only generate a header file, without
|
|
cluttering up the data segment with multiple copies of constants if
|
|
the generated header file is included more than once.
|
|
|
|
\item A function which takes an argument of type \texttt{DP\_CNSTS\_t}
|
|
and returns a pointer to a string containing the description of the
|
|
field value, or NULL if the argument does not correspond to a field
|
|
value:
|
|
\begin{quote}
|
|
\texttt{char *DP\_CNSTS\_describe(DP\_CNSTS\_t e);}
|
|
\end{quote}
|
|
Note that this function can also simply be used as a test of whether
|
|
the value is valid.
|
|
|
|
\item An \texttt{snprintf}-like function to pretty-print values of
|
|
type \texttt{DP\_CNSTS\_t}, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DP\_CNSTS\_prtval(char *s, size\_t sz, DP\_CNSTS\_t e);}
|
|
\end{quote}
|
|
|
|
\end{enumerate}
|
|
|
|
\section{Register types}\label{sec:c-regtype}.
|
|
|
|
For a \texttt{regtype} declaration \texttt{REGTYPE}, \Mac will
|
|
generate the following:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item A type definition \texttt{DP\_REGTYPE\_t}, which is an unsigned
|
|
integer of the same size as the register.
|
|
|
|
\item A CPP macro \texttt{DP\_REGTYPE\_default}, which is an integer
|
|
literal giving the ``default'' value for the register type. Note
|
|
that since this is a macro, the prefix of the name cannot be
|
|
overridden using the trick mentioned above.
|
|
|
|
\item An \texttt{snprintf}-like function to pretty-print values of the
|
|
register type, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DP\_REGTYPE\_prtval(char *s, size\_t sz, DP\_REGTYPE\_t v);}
|
|
\end{quote}
|
|
|
|
\item For every field \texttt{FLD} (of type \texttt{FLDTYPE\_t}) of the
|
|
register type, a function to insert a value into that field of a value
|
|
of type \texttt{DP\_REGTYPE\_t}:
|
|
\begin{quote}
|
|
\texttt{DP\_REGTYPE\_t DP\_REGTYPE\_FLD\_insert(DP\_REGTYPE\_t r, FLDTYPE\_t val );}
|
|
\end{quote}
|
|
Note that this insertion is \textit{not} in place, in contrast to
|
|
the function generated for \texttt{datatype} declarations (see
|
|
below). Instead, this it returns a new value of the register type
|
|
with the specified field modified, and so is intended to be used in
|
|
a ``functional'' style.
|
|
|
|
\item For every field \texttt{FLD} (of type \texttt{FLDTYPE\_t}) of the
|
|
register type, a function to extract a single field from a value
|
|
of type \texttt{DP\_REGTYPE\_t}:
|
|
\begin{quote}
|
|
\texttt{FLDTYPE\_t DP\_REGTYPE\_FLD\_extract(DP\_REGTYPE\_t r);}
|
|
\end{quote}
|
|
|
|
\end{enumerate}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
\section{Data types}\label{sec:c-datatype}.
|
|
|
|
For a \texttt{datatype} declaration
|
|
\texttt{DATATYPE}, \Mac will generate the following:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item A type definition \texttt{DP\_DATATYPE\_t}, which is of type
|
|
\texttt{uint8\_t *}. This is the canonical way to refer to values
|
|
of the datatype in memory.
|
|
|
|
\item A \texttt{static const size\_t DP\_DATATYPE\_size}, which is the
|
|
size in bytes of the data type. This should be used in place of
|
|
\texttt{sizeof(DP\_DATATYPE\_t)}, which will the wrong result in
|
|
general.
|
|
|
|
\item A type definition \texttt{DP\_DATATYPE\_array\_t}, which is of type
|
|
\texttt{uint8\_t[sz]}, where \texttt{sz} is the size in bytes of the
|
|
datatype. This should be used sparingly, for example to allocate a
|
|
value of the datatype on the stack.
|
|
|
|
\item An \texttt{snprintf}-like function to pretty-print values of the
|
|
datatype, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DP\_DATATYPE\_prtval(char *s, size\_t sz, DP\_DATATYPE\_t v);}
|
|
\end{quote}
|
|
|
|
\item For every field \texttt{FLD} (of type \texttt{FLDTYPE\_t}) of the
|
|
datatype, a function to insert a value into that field of a value
|
|
of type \texttt{DP\_DATATYPE\_t}:
|
|
\begin{quote}
|
|
\texttt{void DP\_DATATYPE\_FLD\_insert(DP\_DATATYPE\_t r, FLDTYPE\_t val );}
|
|
\end{quote}
|
|
Note that this insertion is \textit{in place}, in contrast to the
|
|
``functional'' style used for register types.
|
|
|
|
\item For every field \texttt{FLD} (of type \texttt{FLDTYPE\_t}) of the
|
|
datatype, a function to extract a single field from a value
|
|
of type \texttt{DP\_DATATYPE\_t}:
|
|
\begin{quote}
|
|
\texttt{FLDTYPE\_t DP\_DATATYPE\_FLD\_extract(DP\_DATATYPE\_t r);}
|
|
\end{quote}
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
\section{Registers}
|
|
|
|
For a register \texttt{REG} that defines its own type, \Mac defines
|
|
a register type with the same name and generates the declarations
|
|
defined in section~\ref{sec:c-regtype}.
|
|
|
|
For each register \texttt{REG} with type \texttt{REGTYPE}, \Mac will
|
|
generate some of the following:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item If the register has fields which are readable, a function to
|
|
read the contents of the register:
|
|
\begin{quote}
|
|
\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}
|
|
\texttt{void DP\_REG\_wr( DN\_t *dev, DP\_REGTYPE\_t val );}
|
|
\end{quote}
|
|
Note that this is \emph{not} a simple write of the value: any fields
|
|
which must be 1 or 0 are set accordingly, and reserved fields are
|
|
read from the register before writing back the value. Therefore,
|
|
this function will only write the bit fields of \texttt{val} which
|
|
are meaningful to write according to the register specification.
|
|
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:
|
|
\begin{quote}
|
|
\texttt{FLDTYPE DP\_REG\_FLD\_rdf( DN\_t *dev );}
|
|
\end{quote}
|
|
|
|
\item For every writeable field \texttt{FLD} of the register, a function to
|
|
write just that single field to the register:
|
|
\begin{quote}
|
|
\texttt{void DP\_REG\_FLD\_wrf( DN\_t *dev, \texttt{FLDTYPE} val );}
|
|
\end{quote}
|
|
|
|
These functions should be used with care. It is of
|
|
course impossible to write only one field, hence a complete write to
|
|
the register will occur. Furthermore, the values of the other
|
|
read/writeable or reserved register fields will be determined first
|
|
by doing a hidden read from the register. Any write-only
|
|
fields will then be initialized from the shadow copy. Any ``must be
|
|
zero'' or ``must be 1'' fields will be set to their respective values.
|
|
|
|
\item For every write-only field \texttt{FLD} (of type \texttt{FLDTYPE})
|
|
of the register, a function to read just that single field from the
|
|
shadow copy of the register contents:
|
|
\begin{quote}
|
|
\texttt{FLDTYPE DP\_REG\_FLD\_rd\_shadow( DN\_t *dev );}
|
|
\end{quote}
|
|
|
|
\item An \texttt{snprintf}-like function to pretty-print the
|
|
current value of the register, or its shadow copy if the register is
|
|
not readable, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DP\_REG\_pr( char *s, size\_t sz, DN\_t *dev );}
|
|
\end{quote}
|
|
|
|
\end{enumerate}
|
|
|
|
\section{Register Arrays}\label{sec:c-regarray}
|
|
|
|
For a register array \texttt{RARR} that defines its own type, \Mac defines
|
|
a register type with the same name and generates the declarations
|
|
defined in section~\ref{sec:c-regtype}.
|
|
|
|
For each register array \texttt{RARR} with type \texttt{REGTYPE}, \Mac will
|
|
generate some of the following:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item A CPP macro \texttt{DP\_DATATYPE\_size}, which is an integer
|
|
literal cast to a \texttt{size\_t} giving the length in bytes of the
|
|
data type.
|
|
|
|
\item If the register array has fields which are readable, a function to
|
|
read the contents of a register:
|
|
\begin{quote}
|
|
\texttt{DP\_REGTYPE\_t DP\_REG\_rd( DN\_t *dev, int i );}
|
|
\end{quote}
|
|
|
|
\item If the register array has fields which are writeable, a function to
|
|
write the contents of a register:
|
|
\begin{quote}
|
|
\texttt{void DP\_REG\_wr( DN\_t *dev, int i, DP\_REGTYPE\_t val );}
|
|
\end{quote}
|
|
Note that this is \emph{not} a simple write of the value: any fields
|
|
which must be 1 or 0 are set accordingly, and reserved fields are
|
|
read from the register before writing back the value. Therefore,
|
|
this function will only write the bit fields of \texttt{val} which
|
|
are meaningful to write according to the register specification.
|
|
However, this function will not perform a read from the register
|
|
unless the register contains reserved fields.
|
|
|
|
\item For every readable field \texttt{FLD} (of type \texttt{FLDTYPE})
|
|
of the register array, a function to read just that single field
|
|
from a register:
|
|
\begin{quote}
|
|
\texttt{FLDTYPE DP\_REG\_FLD\_rdf( DN\_t *dev, int i );}
|
|
\end{quote}
|
|
|
|
\item For every writeable field \texttt{FLD} of the register array, a
|
|
function to write just that single field to a register:
|
|
\begin{quote}
|
|
\texttt{void DP\_REG\_FLD\_wrf( DN\_t *dev, int i, \texttt{FLDTYPE} val );}
|
|
\end{quote}
|
|
|
|
These functions should be used with care. It is of
|
|
course impossible to write only one field, hence a complete write to
|
|
the register will occur. Furthermore, the values of the other
|
|
read/writeable or reserved register fields will be determined first
|
|
by doing a hidden read from the register. Any write-only
|
|
fields will then be initialized from the shadow copy. Any ``must be
|
|
zero'' or ``must be 1'' fields will be set to their respective values.
|
|
|
|
\item For every write-only field \texttt{FLD} (of type \texttt{FLDTYPE})
|
|
of the register array, a function to read just that single field from the
|
|
shadow copy of a register's contents:
|
|
\begin{quote}
|
|
\texttt{FLDTYPE DP\_REG\_FLD\_rd\_shadow( DN\_t *dev );}
|
|
\end{quote}
|
|
|
|
\item An \texttt{snprintf}-like function to pretty-print the
|
|
current value of one register in the array, or its shadow copy
|
|
if the field is write-only, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DP\_REG\_pri( char *s, size\_t sz, DN\_t *dev, int i );}
|
|
\end{quote}
|
|
|
|
\item An \texttt{snprintf}-like function to pretty-print the
|
|
current value of all registers in the array, or their shadow copies
|
|
if the field is write-only, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DP\_REG\_pr( char *s, size\_t sz, DN\_t *dev );}
|
|
\end{quote}
|
|
|
|
\end{enumerate}
|
|
|
|
\section{Address spaces}\label{sec:c-spaces}
|
|
|
|
It is the responsibility of the programmer to supply functions to
|
|
access registers in user-defined address spaces (though it's common to
|
|
call \Mac{}-generated code in turn to do this). The register access
|
|
code generated by \Mac for a 32-bit wide register declared in an
|
|
address space \texttt{SPACE} will call the following function for a
|
|
read:
|
|
\begin{quote}
|
|
\texttt{uint32\_t DP\_SPACE\_read\_32( DN\_t *dev, size\_t offset );}
|
|
\end{quote}
|
|
-- and the following function for a write:
|
|
\begin{quote}
|
|
\texttt{void DP\_SPACE\_write\_32( DN\_t *dev, size\_t offset,
|
|
uint32\_t value );}
|
|
\end{quote}
|
|
|
|
These functions must be supplied by the programmer in a file named
|
|
\texttt{DP\_spaces.h}, which is included by the generated header file
|
|
\emph{if and only if} the device specification defines new address
|
|
spaces. Note that only one header file is required, rather than one
|
|
for each user-defined address space.
|
|
|
|
Since the device is passed as an argument, the functions can access
|
|
any device fields (including device arguments and shadow copies of
|
|
write-only registers)
|
|
|
|
They are not
|
|
declared anywhere in the generated header file, which means that not
|
|
all the read/write functions for an
|
|
address space need to be supplied, only the ones actually used.
|
|
Furthermore, these can be declared to be \texttt{static inline}, or
|
|
\texttt{extern}, etc.\ according to taste.
|
|
|
|
\section{Overall header file structure}
|
|
|
|
The generated header file is not too difficult to read, and doing so
|
|
can be useful for debugging purposes. The declarations emitted by
|
|
\Mac occur in the file in the following order (to minimise the need
|
|
for forward declarations):
|
|
|
|
\begin{enumerate}
|
|
\item Preamble, naturally.
|
|
\item Type, print, and check declarations for each ``constants''
|
|
clause.
|
|
\item Type, union, and print declarations for each register type
|
|
(including implicit types).
|
|
\item The device structure, and its initialization function.
|
|
\item Read, write, and print functions for each register
|
|
\item The device print function.
|
|
\end{enumerate}
|
|
|
|
In addition, comments in the generated file are intended to help you
|
|
find the relevant declarations quickly if you need to.
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
\chapter{Bitfield C mapping for device drivers}\label{chap:bitfielddriver}
|
|
|
|
\section*{Important}
|
|
This appendix contains the deprecated C mapping which uses bitfield
|
|
structures to represent registers. This back end should not be used,
|
|
since it is not portable across architectures and does not guarantee
|
|
that register accesses will be of the same size as the register, which
|
|
breaks some architectures (such as Rock Creek). It is included here
|
|
to help understand legacy code. Such code should be converted as soon
|
|
as possible.
|
|
|
|
For each device specification, \Mac generates a single C header file
|
|
giving all the necessary definitions and declarations. While
|
|
developers are not expected to look at this file in normal use, it is
|
|
designed to be fairly readable to curious humans, and is worth
|
|
examining to understand what \Mac is generating (and to find bugs in
|
|
\Mac).
|
|
|
|
This chapter will describe the contents of this header file.
|
|
|
|
\section{Preamble}
|
|
|
|
The header file is protected by the customary macro to ensure that it
|
|
is only included once - for example, for a device called \texttt{DEV} this is
|
|
``\texttt{\_\_DEV\_H}''.
|
|
|
|
The file includes only one other header file: \texttt{mackerel.h}.
|
|
This latter header file includes declarations for the low-level read
|
|
and write functions that \Mac code requires, and some other
|
|
preprocessor macros to ensure correct C code generation.
|
|
|
|
\Mac prefixes all declarations in the file with the
|
|
name of the file plus an underscore (``\texttt{DEV\_}'').
|
|
|
|
|
|
%% However, for
|
|
%% most (though not all) declarations this prefix can be overridden by
|
|
%% defining the macro ``\texttt{DEV\_PREFIX}'' before including the file.
|
|
|
|
%% This is at first sight a little confusing. Suppose we have a device
|
|
%% called \texttt{pc16550d\_uart}. By default, any declaration
|
|
%% \texttt{foo} in \Mac file will correspond to
|
|
%% \texttt{pc16550d\_uart\_foo} in the header file.
|
|
|
|
%% If, however, we include a line:
|
|
|
|
%% \begin{quote}
|
|
%% \texttt{\#define pc16550d\_uart\_PREFIX uart}
|
|
%% \end{quote}
|
|
|
|
%% -- before including the header file, that declaration is likely to now
|
|
%% be \texttt{uart\_foo}.
|
|
|
|
In the rest of this chapter, we'll use ``\texttt{DN\_}'' as the
|
|
device prefix that cannot be redefined in this manner, and ``\texttt{DP\_}''
|
|
as device prefix that can.
|
|
|
|
\section{Device-level declarations}
|
|
|
|
\Mac provides a C structure type to represent what it knows about the
|
|
device, called \texttt{DN\_t}. To access a device from C via \Mac,
|
|
you first need to declare one of these, and the call a function to
|
|
initialize it.
|
|
|
|
The initialize function is called \texttt{DN\_initialize}. For a
|
|
device type with an argment of ``\texttt{io base}'', the
|
|
initialization function looks like:
|
|
|
|
\begin{quote}
|
|
\texttt{void DN\_initialize( DN\_t *\_dev, mackerel\_io\_t base );}
|
|
\end{quote}
|
|
|
|
The idiom for accessing a device at IO address \texttt{ia} would be:
|
|
|
|
\begin{quote}
|
|
\texttt{DN\_t dev;}\\
|
|
\texttt{DN\_initialize( \&dev, ia );}\\
|
|
\ldots\\
|
|
\textit{code to access registers via \texttt{dev}}
|
|
\end{quote}
|
|
|
|
In addition, \Mac generates an \texttt{snprintf}-like function to
|
|
pretty-print \emph{all} the register contents of the device, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DN\_pr(char *s, size\_t sz, DP\_CNSTS\_t v);}
|
|
\end{quote}
|
|
For a complex device, this is a lot of information, and may require a
|
|
large buffer to fully capture. This is also potentially a large
|
|
function to inline. It will result in reads from all readable device
|
|
registers, including ``read to clear'' (\textbf{rc}) registers and
|
|
fields. For write-only registers, this function will print the shadow
|
|
copy of the register maintained in the device structure, which holds
|
|
the last value written to the register (or 0 if the register has not
|
|
been written since the initialization function was called). The
|
|
output identifies which values are ``real'' and which are shadow
|
|
copies, includes descriptions of all register fields, and translates
|
|
symbolic values into their names and descriptions.
|
|
|
|
\section{Constants}
|
|
|
|
For a constants declaration of type \texttt{CNSTS}, having fields
|
|
\texttt{FIELD1} and \texttt{FIELD2}, \Mac will generate the following:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item An enumeration type \texttt{DP\_CNSTS\_t} with fields
|
|
\texttt{DP\_FIELD1} and \texttt{DP\_FIELD2}. Note that the field
|
|
names are not prefixed by the enumeration name, only the device
|
|
prefix.
|
|
|
|
\item An \texttt{snprintf}-like function to pretty-print values of the
|
|
enumeration, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DP\_CNSTS\_prt(char *s, size\_t sz, DP\_CNSTS\_t e);}
|
|
\end{quote}
|
|
|
|
\item A function which returns 1 if an enumeration value is valid, 0
|
|
if otherwise:
|
|
\begin{quote}
|
|
\texttt{int DP\_CNSTS\_chk(DP\_CNSTS\_t e);}
|
|
\end{quote}
|
|
|
|
\end{enumerate}
|
|
|
|
\section{Register types}\label{sec:old:c-regtype}.
|
|
|
|
For a \texttt{regtype} declaration \texttt{REGTYPE}, \Mac will generate the following:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item A bitfield structure type \texttt{DP\_REGTYPE\_t}, whose field
|
|
names are those of the fields specified in the \Mac file, with no
|
|
prefix, and whose physical layout corresponds to the hardware
|
|
register type.
|
|
|
|
\item A union type \texttt{DP\_REGTYPE\_un}, whose members are the
|
|
bitfield struct above (as ``\texttt{val}'') and the smallest
|
|
enclosing unsigned integer type (as ``\texttt{raw}''),.
|
|
|
|
\item An \texttt{snprintf}-like function to pretty-print values of the
|
|
register type, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DP\_REGTYPE\_prtval(char *s, size\_t sz, DP\_CNSTS\_t v);}
|
|
\end{quote}
|
|
|
|
\end{enumerate}
|
|
|
|
This functionality is being replaced by one based on shifts and masks,
|
|
rather than using bitfields, which have portability issues.
|
|
For a \texttt{regtype} declaration \texttt{REGTYPE}, \Mac will soon
|
|
generate the following:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item A type definition \texttt{DP\_REGTYPE\_t} which is an unsigned
|
|
integer of the same size as the register.
|
|
|
|
\item For every field \texttt{FLD} (of type \texttt{FLDTYPE}) of the
|
|
register type, a function to insert a value into that field of a value
|
|
of type \texttt{DP\_REGTYPE\_t}:
|
|
\begin{quote}
|
|
\texttt{DP\_REGTYPE\_t DP\_REGTYPE\_FLD\_ins(DP\_REGTYPE\_t r, FLD\_TYPE val );}
|
|
\end{quote}
|
|
|
|
\item For every field \texttt{FLD} (of type \texttt{FLDTYPE}) of the
|
|
register type, a function to extract a single field from a value
|
|
of type \texttt{DP\_REGTYPE\_t}:
|
|
\begin{quote}
|
|
\texttt{FLDTYPE DP\_REGTYPE\_FLD\_ext(DP\_REGTYPE\_t r);}
|
|
\end{quote}
|
|
|
|
\end{enumerate}
|
|
|
|
\section{Data types}\label{sec:old:c-datatype}.
|
|
|
|
For a \texttt{datatype} declaration
|
|
\texttt{DATATYPE}, \Mac will generate the following:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item A bitfield structure type \texttt{DP\_DATATYPE\_t}, whose field
|
|
names are those of the fields specified in the \Mac file, with no
|
|
prefix, and whose physical layout corresponds to the hardware data type.
|
|
|
|
\item An \texttt{snprintf}-like function to pretty-print values of the
|
|
data type, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DP\_DATATYPE\_prtval(char *s, size\_t sz, DP\_CNSTS\_t v);}
|
|
\end{quote}
|
|
|
|
\end{enumerate}
|
|
|
|
\section{Registers}
|
|
|
|
For a register \texttt{REG} that defines its own type, \Mac defines
|
|
a register type with the same name and generates the declarations
|
|
defined in section~\ref{sec:old:c-regtype}.
|
|
|
|
For each register \texttt{REG} with type \texttt{REGTYPE}, \Mac will
|
|
generate some of the following:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item If the register has fields which are readable, a function to
|
|
read a ``raw'' (integer) value from the register:
|
|
\begin{quote}
|
|
\texttt{uint$x$\_t DP\_REG\_rd\_raw( DN\_t *dev );}
|
|
\end{quote}
|
|
-- where \texttt{uint$x$\_t} is a standard C unsigned integer type
|
|
with a fixed size, such as \texttt{uint32\_t}.,
|
|
|
|
\item If the register has fields which are readable, a function to
|
|
read a bitfield value from the register:
|
|
\begin{quote}
|
|
\texttt{DP\_REGTYPE\_t DP\_REG\_rd( DN\_t *dev );}
|
|
\end{quote}
|
|
|
|
\item If the register has fields which are not readable, a function to
|
|
read a bitfield value from a saved copy of the last value written to
|
|
the register using this device struct:
|
|
\begin{quote}
|
|
\texttt{DP\_REGTYPE\_t DP\_REG\_rd\_shadow( DN\_t *dev );}
|
|
\end{quote}
|
|
|
|
\item If the register has fields which are writeable, a function to
|
|
write a ``raw'' (integer) value to the register:
|
|
\begin{quote}
|
|
\texttt{void DP\_REG\_wr\_raw( DN\_t *dev, uint$x$\_t val );}
|
|
\end{quote}
|
|
-- where \texttt{uint$x$\_t} is smallest suitable standard C
|
|
unsigned integer type with a fixed size, such as
|
|
\texttt{uint32\_t}.
|
|
|
|
\item If the register has fields which are writeable, a function to
|
|
write a bitfield value to the register:
|
|
\begin{quote}
|
|
\texttt{void DP\_REG\_wr( DN\_t *dev, DP\_REGTYPE val );}
|
|
\end{quote}
|
|
|
|
Unlike the raw write function, this will (only if necessary) perform
|
|
a read first from the register to ensure that ``reserved'' fields
|
|
will be written back with their correct values. It will also force
|
|
any ``must be zero'' or ``must be 1'' fields to be their respective
|
|
values.
|
|
|
|
\item For every writeable field \texttt{FLD} of the register, a function to
|
|
write just that single field to the register:
|
|
\begin{quote}
|
|
\texttt{void DP\_REG\_FLD\_wrf( DN\_t *dev, \texttt{uint$x$\_t} val );}
|
|
\end{quote}
|
|
-- where \texttt{uint$x$\_t} is smallest suitable standard C
|
|
unsigned integer type with a fixed size, such as
|
|
\texttt{uint8\_t}.
|
|
|
|
These functions should be used with care. It is of
|
|
course impossible to write only one field, hence a complete write to
|
|
the register will occur. Furthermore, the values of the other
|
|
read/writeable or reserved register fields will be determined first
|
|
by doing a hidden read from the register. Any write-only
|
|
fields will then be initialized from the shadow copy. Any ``must be
|
|
zero'' or ``must be 1'' fields will be set to their respective values.
|
|
|
|
\item An \texttt{snprintf}-like function to pretty-print the
|
|
current value of the register, or its shadow copy if the register is
|
|
not readable, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DP\_REG\_pr( char *s, size\_t sz, DN\_t *dev );}
|
|
\end{quote}
|
|
|
|
\end{enumerate}
|
|
|
|
\section{Register Arrays}\label{sec:old:c-regarray}
|
|
|
|
For a register array \texttt{RARR} that defines its own type, \Mac defines
|
|
a register type with the same name and generates the declarations
|
|
defined in section~\ref{sec:old:c-regtype}.
|
|
|
|
For each register array \texttt{RARR} with type \texttt{REGTYPE}, \Mac will
|
|
generate some of the following:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item A static constant giving the length of the array (42 in this example):
|
|
\begin{quote}
|
|
\texttt{static const int DP\_RARR\_length = 0x26;}
|
|
\end{quote}
|
|
|
|
\item If the registers have fields which are readable, a function to
|
|
read a ``raw'' (integer) value from a register:
|
|
\begin{quote}
|
|
\texttt{uint$x$\_t DP\_RARR\_rd\_raw( DN\_t *dev, int i );}
|
|
\end{quote}
|
|
-- where \texttt{uint$x$\_t} is a standard C unsigned integer type
|
|
with a fixed size, such as \texttt{uint32\_t}, and \texttt{i} is an
|
|
index into the array.
|
|
|
|
\item If the registers have fields which are readable, a function to
|
|
read a bitfield value from a register:
|
|
\begin{quote}
|
|
\texttt{DP\_REGTYPE\_t DP\_RARR\_rd( DN\_t *dev, int i );}
|
|
\end{quote}
|
|
|
|
\item If the registers have fields which are not readable, a function to
|
|
read a bitfield value from a saved copy of the last value written to
|
|
each register using this device struct:
|
|
\begin{quote}
|
|
\texttt{DP\_REGTYPE\_t DP\_RARR\_rd\_shadow( DN\_t *dev, int i );}
|
|
\end{quote}
|
|
|
|
\item If the registers have fields which are writeable, a function to
|
|
write a ``raw'' (integer) value to a register:
|
|
\begin{quote}
|
|
\texttt{void DP\_RARRG\_wr\_raw( DN\_t *dev, int i, uint$x$\_t val );}
|
|
\end{quote}
|
|
-- where \texttt{uint$x$\_t} is smallest suitable standard C
|
|
unsigned integer type with a fixed size, such as
|
|
\texttt{uint32\_t}.
|
|
|
|
\item If the registers have fields which are writeable, a function to
|
|
write a bitfield value to a register:
|
|
\begin{quote}
|
|
\texttt{void DP\_RARR\_wr( DN\_t *dev, int i, DP\_REGTYPE val );}
|
|
\end{quote}
|
|
-- where \texttt{uint$x$\_t} is smallest suitable standard C
|
|
unsigned integer type with a fixed size, such as
|
|
\texttt{uint32\_t}.
|
|
|
|
Unlike the raw write function, this will (only if necessary) perform
|
|
a read first from the register to ensure that ``reserved'' fields
|
|
will be written back with their correct values. It will also force
|
|
any ``must be zero'' or ``must be 1'' fields to be their respective
|
|
values.
|
|
|
|
\item An \texttt{snprintf}-like function to pretty-print the
|
|
current value of one element of the array, or its shadow copy if the
|
|
register is not readable, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DP\_RARR\_pri( char *s, size\_t sz, DN\_t *dev, int i );}
|
|
\end{quote}
|
|
|
|
\item An \texttt{snprintf}-like function to pretty-print the
|
|
entire register array, or its shadow copies if the registers in the
|
|
array are not readable, with prototype:
|
|
\begin{quote}
|
|
\texttt{int DP\_RARR\_pr( char *s, size\_t sz, DN\_t *dev );}
|
|
\end{quote}
|
|
|
|
\end{enumerate}
|
|
|
|
\section{Address spaces}\label{sec:old:c-spaces}
|
|
|
|
It is the responsibility of the programmer to supply functions to
|
|
access registers in user-defined address spaces (though it's common to
|
|
call \Mac{}-generated code in turn to do this). The register access
|
|
code generated by \Mac for a 32-bit wide register declared in an
|
|
address space \texttt{SPACE} will call the following function for a
|
|
read:
|
|
\begin{quote}
|
|
\texttt{uint32\_t DP\_SPACE\_read\_32( DN\_t *dev, size\_t offset );}
|
|
\end{quote}
|
|
-- and the following function for a write:
|
|
\begin{quote}
|
|
\texttt{void DP\_SPACE\_write\_32( DN\_t *dev, size\_t offset,
|
|
uint32\_t value );}
|
|
\end{quote}
|
|
|
|
These functions must be supplied by the programmer in a file named
|
|
\texttt{DP\_spaces.h}, which is included by the generated header file
|
|
\emph{if and only if} the device specification defines new address
|
|
spaces. Note that only one header file is required, rather than one
|
|
for each user-defined address space.
|
|
|
|
Since the device is passed as an argument, the functions can access
|
|
any device fields (including device arguments and shadow copies of
|
|
write-only registers)
|
|
|
|
They are not
|
|
declared anywhere in the generated header file, which means that not
|
|
all the read/write functions for an
|
|
address space need to be supplied, only the ones actually used.
|
|
Furthermore, these can be declared to be \texttt{static inline}, or
|
|
\texttt{extern}, etc.\ according to taste.
|
|
|
|
\section{Overall header file structure}
|
|
|
|
The generated header file is not too difficult to read, and doing so
|
|
can be useful for debugging purposes. The declarations emitted by
|
|
\Mac occur in the file in the following order (to minimise the need
|
|
for forward declarations):
|
|
|
|
\begin{enumerate}
|
|
\item Preamble, naturally.
|
|
\item Type, print, and check declarations for each ``constants''
|
|
clause.
|
|
\item Type, union, and print declarations for each register type
|
|
(including implicit types).
|
|
\item The device structure, and its initialization function.
|
|
\item Read, write, and print functions for each register
|
|
\item The device print function.
|
|
\end{enumerate}
|
|
|
|
In addition, comments in the generated file are intended to help you
|
|
find the relevant declarations quickly if you need to.
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
\chapter{Migrating from the bit-field based version of Mackerel}
|
|
\label{chap:migrating}
|
|
|
|
Previous versions of Mackerel generated a C API by defining packed C
|
|
bitfield structs for register types. This version of Mackerel avoids
|
|
this in favor of masks and shifts, hidden behind inline functions.
|
|
This chapter gives some hints for migrating code written using the old
|
|
Mackerel to the new version.
|
|
|
|
\begin{itemize}
|
|
|
|
\item The initialize function for a device structure remains the same.
|
|
|
|
\item \texttt{DEV\_REG\_wr\_raw()} and \texttt{DEV\_REG\_rd\_raw()}
|
|
functions should be replaced with \texttt{DEV\_REG\_wr()} and
|
|
\texttt{DEV\_REG\_rd()} with the same arguments.
|
|
|
|
\item The following code to set individual register fields:
|
|
|
|
\begin{verbatim}
|
|
//deassert PHY_RESET
|
|
{
|
|
e1000_ctrl_t c = e1000_ctrl_rd(d);
|
|
c.phy_rst = 0;
|
|
e1000_ctrl_wr(d, c);
|
|
e1000_status_t s = e1000_status_rd(d);
|
|
s.phyra = 0;
|
|
e1000_status_wr(d, s);
|
|
}
|
|
\end{verbatim}
|
|
|
|
-- must be replaced with:
|
|
|
|
\begin{verbatim}
|
|
//deassert PHY_RESET
|
|
e1000_ctrl_phy_rst_wrf(d, 0);
|
|
e1000_status_phyra_wrf(d, 0);
|
|
\end{verbatim}
|
|
|
|
\item The following code to read individual register fields:
|
|
|
|
\begin{verbatim}
|
|
speed = e1000_status_rd(d).speed;
|
|
\end{verbatim}
|
|
|
|
-- must be replaced by:
|
|
|
|
\begin{verbatim}
|
|
speed = e1000_status_speed_rdf(d);
|
|
\end{verbatim}
|
|
|
|
\item The following code to access a field from a register:
|
|
|
|
\begin{verbatim}
|
|
// test LAN ID to see if we need to modify the MAC from EEPROM
|
|
{
|
|
e1000_status_t s = e1000_status_rd(d);
|
|
if (s.lan_id == e1000_lan_b) {
|
|
mac_word2 ^= e1000_lan_b_mask;
|
|
}
|
|
}
|
|
\end{verbatim}
|
|
|
|
-- must be replaced by:
|
|
|
|
\begin{verbatim}
|
|
// test LAN ID to see if we need to modify the MAC from EEPROM
|
|
{
|
|
e1000_status_t s = e1000_status_rd(d);
|
|
if (e1000_status_lan_id_extract(s) == e1000_lan_b) {
|
|
mac_word2 ^= e1000_lan_b_mask;
|
|
}
|
|
}
|
|
\end{verbatim}
|
|
|
|
\item The following idiom for setting fields using struct literals:
|
|
|
|
\begin{verbatim}
|
|
e1000_rxdctl_wr(d, 0, (e1000_rxdctl_t){ .gran=1, .wthresh=1 } );
|
|
\end{verbatim}
|
|
|
|
-- should be replaced by:
|
|
|
|
\begin{verbatim}
|
|
e1000_rxdctl_t tmp = e1000_rxdctl_default;
|
|
tmp = e1000_rxdctl_gran_insert(tmp,1);
|
|
tmp = e1000_rxdctl_wthresh_insert(tmp,1);
|
|
e1000_rxdctl_wr(d, 0, tmp);
|
|
\end{verbatim}
|
|
\end{itemize}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
\chapter{Source code structure}\label{chap:sourcetree}
|
|
|
|
The \Mac source directory contains the files listed below.
|
|
|
|
\begin{description}
|
|
|
|
\item[Attr.hs] Dealing with register field attributes.
|
|
\item[BitFieldDriver.hs] Old code generator for device drivers using
|
|
bitfields, deprecated.
|
|
\item[CAbsSyntax.hs] Contains combinators for rendering C code.
|
|
\item[CSyntax.hs] Old-style C combinators, deprecated.
|
|
\item[Checks.hs] Compile-time checks.
|
|
\item[Dev.hs] Overall device representation.
|
|
\item[Fields.hs] Representing register fields.
|
|
\item[MackerelParser.hs] ParSec parser for language.
|
|
\item[Main.hs] Top level file, which is used to run \Mac.
|
|
\item[Poly.hs] Polynomial arithmetic for compile-time expression
|
|
reduction (currently unused)
|
|
\item[RegisterTable.hs] Representing registers and register arrays.
|
|
\item[ShiftDriver.hs] Code generator for device drivers using shifts and masks.
|
|
\item[Space.hs] Representing address spaces.
|
|
\item[TypeName.hs] Data type for scoping type names when importing.
|
|
\item[TypeTable.hs] Representing register, data, and constants types.
|
|
\end{description}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
\chapter{Quick reference}\label{chap:quickref}
|
|
|
|
In the following quick reference, the following identifiers are used
|
|
as examples, assuming a Mackerel file named \texttt{dev1.dev}:
|
|
|
|
\begin{description}
|
|
\item[dev1] A device definition.\\
|
|
\item[const1] A constants definition.
|
|
\item[cval1] One value of the constants definition.\\
|
|
\item[rtype2] A register type definition.
|
|
\item[field2] A field in the above register type.
|
|
\item[ftype2] The type of this field.\\
|
|
\item[dtype3] A data type definition.
|
|
\item[field3] A field in the above data type.
|
|
\item[ftype3] The type of this field.\\
|
|
\item[reg4] A register definition with its own type.
|
|
\item[rtype4] Type of the above register.
|
|
\item[field4] A field in the above register.
|
|
\item[ftype4] The type of this field.\\
|
|
\item[array5] A register array.
|
|
\item[field5] A field in the elements of the above array.
|
|
\item[ftype5] The type of this field.
|
|
\end{description}
|
|
|
|
\clearpage
|
|
\section*{Quick list of Mackerel C declarations:}
|
|
{\footnotesize
|
|
\begin{tabular}{|l|l|}
|
|
\hline
|
|
\textbf{C declaration} & \textbf{Description} \\ \hline
|
|
\multicolumn{2}{|l|}{Device declarations} \\ \hline
|
|
\texttt{struct dev1\_t} & Device structure \\
|
|
\texttt{typedef dev1\_t} & Device type defintion (as above) \\
|
|
\texttt{enum dev1\_initials} & Initial register values \\
|
|
\texttt{void dev1\_initialize( dev1\_t *dev, ... )} & Initialization \\
|
|
\texttt{int dev1\_pr( char *s, size\_t sz, device\_t *v )} & Print \\
|
|
\hline
|
|
|
|
\multicolumn{2}{|l|}{Constants declarations} \\ \hline
|
|
\texttt{typedef dev1\_const1\_t} & Integer type \\
|
|
\texttt{\#define dev1\_cval1} & Macro giving integer value \\
|
|
\texttt{char *dev1\_const1\_describe( dev1\_const1\_t e )} & Description \\
|
|
\texttt{int dev1\_const1\_prtval( char *s, size\_t sz,
|
|
dev1\_const1\_t e )} & Print \\
|
|
\texttt{int dev1\_const1\_chk( dev1\_const1\_t e)} & Check value \\
|
|
\hline
|
|
|
|
\multicolumn{2}{|l|}{Register type declarations} \\ \hline
|
|
\texttt{typedef dev1\_rtype2\_t} & Type defintion \\
|
|
\texttt{\#define dev1\_rtype2\_default} & Default value \\
|
|
\texttt{int dev1\_rtype2\_prtval( char *s, size\_t sz,
|
|
dev1\_rtype2\_t v )} & Print \\
|
|
\texttt{dev1\_rtype2\_t dev1\_rtype2\_field2\_insert( dev1\_rtype2\_t r, ftype2\_t val )} & Insert a field value \\
|
|
\texttt{ftype2\_t dev1\_rtype2\_field2\_extract( dev1\_rtype2\_t r )} & Extract field value\\
|
|
\hline
|
|
|
|
\multicolumn{2}{|l|}{Datatype declarations} \\ \hline
|
|
\texttt{typedef dev1\_dtype3\_t} & Pointer to datatype \\
|
|
\texttt{const size\_t dev1\_dtype3\_size} & Size \\
|
|
\texttt{typedef dev1\_dtype3\_array\_t} & Byte array of the same size \\
|
|
\texttt{int dev1\_dtype3\_prtval( char *s, size t sz, dev1\_dtype3\_t
|
|
v )} & Print \\
|
|
\texttt{void dev1\_dtype3\_field3\_insert( dev1\_dtype3\_t r, ftype3\_t val )} & Insert field \\
|
|
\texttt{ftype3\_t dev1\_dtype3\_field3\_extract( dev1\_dtype3\_t r )} & Extract field \\
|
|
\hline
|
|
|
|
\multicolumn{2}{|l|}{Register declarations} \\ \hline
|
|
\texttt{dev1\_rtype4\_t dev1\_reg4\_rd( dev1\_t *dev )} & Read register \\
|
|
\texttt{dev1\_rtype4\_t dev1\_reg4\_rawrd( dev1\_t *dev )} & Raw read \\
|
|
\texttt{void dev1\_reg4\_wr( dev1\_t *dev, dev1\_rtype4\_t val )} & Write register \\
|
|
\texttt{void dev1\_reg4\_rawwr( dev1\_t *dev, dev1\_rtype4\_t val )} & Raw write \\
|
|
\texttt{ftype4\_t dev1\_reg4\_field4\_rdf( dev1\_t *dev )} & Read field \\
|
|
\texttt{void dev1\_reg4\_field4\_wrf( dev1\_t *dev, ftype4 val )} & Write field \\
|
|
\texttt{ftype4\_t dev1\_reg4\_field4\_rd\_shaddow( dev1\_t *dev )} & Read shadow \\
|
|
\texttt{int dev1\_reg4\_pr( char *s, size\_t sz, dev1\_t *dev )} & Print \\
|
|
\hline
|
|
|
|
\multicolumn{2}{|l|}{Register array declarations} \\ \hline
|
|
\texttt{const int dev1\_array5\_length} & Num. registers \\
|
|
\texttt{dev1\_rtype5\_t dev1\_reg5\_rd( dev1\_t *dev, int i )} & Read register \\
|
|
\texttt{dev1\_rtype5\_t dev1\_reg5\_rawrd( dev1\_t *dev, int i )} & Raw read \\
|
|
\texttt{void dev1\_reg5\_wr( dev1\_t *dev, int i, dev1\_rtype5\_t val )} & Write register \\
|
|
\texttt{void dev1\_reg5\_rawwr( dev1\_t *dev, int i, dev1\_rtype5\_t val )} & Raw write \\
|
|
|
|
\texttt{ftype5\_t dev1\_reg5\_field5\_rdf( dev1\_t *dev, int i )} & Read field \\
|
|
\texttt{void dev1\_reg5\_field5\_wrf( dev1\_t *dev, int i, ftype5 val )} & Write field \\
|
|
\texttt{ftype5\_t dev1\_reg5\_field5\_rd\_shaddow( dev1\_t *dev, int i
|
|
)} & Read shadow \\
|
|
\texttt{int dev1\_reg5\_pri( char *s, size\_t sz, dev1\_t *dev, int i )} & Print \\
|
|
\texttt{int dev1\_reg5\_pr( char *s, size\_t sz, dev1\_t *dev )} &
|
|
Print array \\
|
|
\hline
|
|
|
|
\multicolumn{2}{|l|}{Space access functions} \\ \hline
|
|
\texttt{uint\textit{x}\_t dev1\_space6\_read\_\textit{x}(
|
|
dev1\_t *dev, size\_t offset )} & Read a value \\
|
|
\texttt{void dev1\_space6\_write\textit{x}(
|
|
dev1\_t *dev, size\_t offset, uint\textit{x}\_t value )} & Write a
|
|
value \\
|
|
\hline
|
|
|
|
\end{tabular}}
|
|
|
|
\end{document}
|