-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
78 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# μHAL Design | ||
|
||
A [primer on the hardware](hardware.md) with which this project interfaces | ||
should be useful in understanding the design choices made. | ||
|
||
## Low level interface | ||
|
||
The low level interface consists simply of a `struct pcie_bars` object, which | ||
allows its user to read and write from BARs 2 and 4 (`BAR0` is considered an | ||
implementation detail) using the functions defined in `util/pcie.h`. | ||
|
||
`BAR4` can also be accessed when `struct pcie_bars` points to a serial port, | ||
which is used when debugging boards outside of a μTCA crate. The serial port | ||
doesn't allow access to `BAR2`, though. | ||
|
||
All other functionality of this project depends on this low level interface. | ||
|
||
## Basic abstractions | ||
|
||
### SDB access | ||
|
||
SDB access is provided by the functions in `util/util_sdb.h`. These functions | ||
are higher level abstractions on top of the `libsdbfs` project. | ||
|
||
Unlike HALCS, which iterated through the SBD and launched a handler for each | ||
core it found, the only function in this library which iterates over the SDB is | ||
the one which prints its contents. For any other use, users of the library will | ||
search for specific cores (with their index in depth-first traversal) with | ||
`read_sdb()`. In order to know which cores should be available in a given | ||
board, users should consult the build information provided by | ||
`get_synthesis_info()`. | ||
|
||
While this implementation might seem less flexible at first, when using this | ||
library on an IOC, it's impossible to escape from the need to know what cores | ||
are available: records for them must be instantiated and have the proper names. | ||
Therefore, this isn't adding any new limitations to an IOC. | ||
|
||
### FPGA core access | ||
|
||
For the most part, acess to each FPGA core is split into two classes under the | ||
core's namespace (e.g. `afc_timing`): one is the "decoder", `afc_timing::Core`, | ||
the other is the "controller", `afc_timing::Controller`. Usually, the decoder | ||
implements read-only access, while the controller has to be read-write. | ||
|
||
The base classes involved in this are `class RegisterDecoderBase`, `class | ||
RegisterDecoder`, `class RegisterController` and `class | ||
RegisterDecoderController`. The implementation for each core is under the | ||
`modules/` directory. | ||
|
||
#### Register maps | ||
|
||
The register map for each module is encoded as a C struct, which is provided by | ||
the header generated by `cheby`. Headers generated by `wbgen2` don't include a | ||
C struct, so it is necessary to define this struct ourselves. | ||
|
||
These register fields are decoded using bitmasks provided by the generated | ||
headers, using the functions from `util/util-bits.h`. | ||
|
||
#### RegisterController and RegisterDecoderController | ||
|
||
Before `class RegisterDecoderController` was created, controllers were mostly | ||
developed manually, duplicating the correspondence between the register fields | ||
we are interested in and their location in the register map, the mask used to | ||
obtain them, and how to interpret their data. This also made it necessary for | ||
library users to address differently when reading or writing them. | ||
|
||
`class RegisterDecoderController` removes this need, requiring only a small | ||
amount of boilerplate to expose writing into register fields under a common | ||
interface. | ||
|
||
#### Unconventional controllers | ||
|
||
Some FPGA cores couldn't be implemented simply by decoding and encoding | ||
register fields. We list some of them here: | ||
|
||
- `acq::Controller` | ||
- `ad9510::Controller` | ||
- `si57x_ctrl::Controller` |