Skip to content

Hardcaml-Mini-Course-at-Stevens/hardcaml_hobby_boards

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hobby Board Infrastructure

The Hardcaml_hobby_board library provides a simple for for targeting demo designs on FPGA boards.

We currently support two Xilinx boards:

  1. Nexys-A7 100t.
  2. Arty-A7 35t and 100t.

The framework coordinates access to the FPGA pins, provides some useful peripheral designs, and generates scripts to drive the FPGA build process.

Understanding Subsystems

The FPGA pins are split up into logical units according to their function. A group of pins, which we refer to as a subsystem, might be used to drive a SPI interface, or ethernet or VGA or something else.

This grouping of pins may consist of:

  • Inputs into the FPGA
  • Outputs driven from the FPGA
  • Tristate signals which are both read and driven within the FPGA.

It is not necessarily the case that a particular subsystem has all 3 types of pin - a bank of LEDs for example will only have outputs driven by the FPGA.

At it's most general, we interact with a subsystem via two functions which are defined in Board_intf.M_IOT. The first is the create:

val create : board -> Signal.t I.t * Signal.t T.t

This returns the inputs coming into the FPGA for this subsystem and the value of any tristate pins. It also registers the subsystem with the board infrastructure so it knows how to generate constraints and project files for FPGA vendor tools.

The second function is complete:

val complete : board -> Signal.t O.t -> Signal.t T_enabled.t -> unit

This takes the values which with we want to drive subsystem outputs and a type T_enabled.t which controls how tristate values are to be driven.

Tristate details

Looking more closely at T_enabled it has type 'a With_valid.t T.t'. So each tristate pin is defined using With_valid.t. Digging into With_valid.t we see it is an interface type with two fields

  • A 1-bit valid signal
  • An arbitrary width value signal

For tristates we interpret this to mean:

  • if valid is high, then we drive value on the tristate output pin
  • otherwise, we drive high-impedance (ie Z)

Simplified Subsystem Interfaces

As noted before, subsystems will often not use inputs and outputs and tristates. In this case we can simplify the above create and complete functions.

For example if we do not have any tristates, we can define our create and complete functions as per Board_info.M_IO.

val create : board -> Signal.t I.t
val complete : board -> Signal.t O.t -> unit

As we can see the tristate types are not mentioned. Another example is something like LEDs which only have outputs. These have an even more cut-down API.

val complete : board -> Signal.t O.t -> unit

Using the Board API

The module Nexys_a7_100t defines a bunch of subsystems according the the resources provided by the board. Support is provided for buttons and leds, vga, ethernet and more.

To use subsystems we must first create a Board.t type. Once we have defined our required logic we can call generate_top to construct a RTL project suitable for running through Xilinx Vivado.

The following is basic example which simply maps switches through to LEDs.

let () =
  let board = Board.create () in
  Nexys_a7_100t.Leds.complete board (Nexys_a7_100t.Switches.create board);
  Nexys_a7_100t.generate_top board
;;

What Gets Generated

RTL design

A verilog file containing the a special top level module generated by the board infrastructure, and whatever verilog modules that were defined by the user logic.

Technically, the top most module is built using Hardcaml.Structural which allows us to instantiate tristates (if any) appropriately. A standard hierarchical Hardcaml.Circuit is constructed for the user design.

Note that one may obtain Scope.t from the board type to implement hierarchical designs:

let scope = Board.scope board in

XDC file

A Xilinx Design Constraints (.xdc) file is generated with the mapping on of top level ports to physical pins.

In addition, the top level clock period is constrained and some custom properties related to configuration file generation and configuration modes are added.

TCL file

A TCL file is produced to drive Vivado. It will load the RTL and constraints then perform synthesis, placement, routing, timing analysis, bitstream generation.

This is done using an in-memory project with Vivado.

After each step we have commented out a line like:

#write_checkpoint ...

You may uncomment that line and then load the resulting dcp file into Vivado to perform the rest of the build process manually.

About

Latest mirror of hardcaml_hobby_boards

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors