Creating a New Physical Device - LEAP-FPGA/leap-documentation GitHub Wiki
Physical devices are those latency-insensitive modules which, in addition to having latency-insensitive channel I/O also have physical wires, typically to an external chip. There are two methods of incorporating a new device into LEAP: the old "physical platform" method and the new, experimental "user-level device" method.
Physical Platform
At its lowest level, LEAP views the FPGA as a collection of physical device: PCI-e, DDR, SERDES, RF, etc.
An example "physical platform":https://github.com/LEAP-Core/leap-platforms/tree/master/modules/bluespec/common/fpgaenv/physical-platform/pci-express-generic is shown here:
// PHYSICAL_DRIVERS
// This represents the collection of all platform capabilities which the
// rest of the FPGA uses to interact with the outside world.
// We use other modules to actually do the work.
interface PHYSICAL_DRIVERS;
interface CLOCKS_DRIVER clocksDriver;
interface PCIE_DRIVER pcieDriver;
interface DDR_DRIVER ddrDriver;
interface AURORA_COMPLEX_DRIVERS auroraDriver;
endinterface
// TOP_LEVEL_WIRES
// The TOP_LEVEL_WIRES is the datatype which gets passed to the top level
// and output as input/output wires. These wires are then connected to
// physical pins on the FPGA as specified in the accompanying UCF file.
// These wires are defined in the individual devices.
interface TOP_LEVEL_WIRES;
// wires from devices
interface CLOCKS_WIRES clocksWires;
interface PCIE_WIRES pcieWires;
interface DDR_WIRES ddrWires;
interface AURORA_COMPLEX_WIRES auroraWires;
endinterface
// PHYSICAL_PLATFORM
// The platform is the aggregation of wires and drivers.
interface PHYSICAL_PLATFORM;
interface PHYSICAL_DRIVERS physicalDrivers;
interface TOP_LEVEL_WIRES topLevelWires;
endinterface
// mkPhysicalPlatform
// This is a convenient way for the outside world to instantiate all the devices
// and an aggregation of all the wires.
module [CONNECTED_MODULE] mkPhysicalPlatform
//interface:
(PHYSICAL_PLATFORM);
// The Platform is instantiated inside a NULL clock domain. Our first course of
// action should be to instantiate the Clocks Physical Device and obtain interfaces
// to clock and reset the other devices with.
CLOCKS_DEVICE clocks <- mkClocksDevice();
Clock clk = clocks.driver.clock;
Reset rst = clocks.driver.reset;
// There is a strong assumption that the clock for this module is the 200MHz
// differential clock.
let ddrConfig = defaultValue;
ddrConfig.internalClock = clocks.driver.rawClock;
ddrConfig.internalReset = clocks.driver.rawReset;
ddrConfig.modelResetNeedsFanout = True;
case (\`DRAM_CLOCK_MECHANISM) matches
"InternalUnbuffered": ddrConfig.clockArchitecture = CLOCK_INTERNAL_UNBUFFERED;
"ExternalDifferential": ddrConfig.clockArchitecture = CLOCK_EXTERNAL_DIFFERENTIAL;
default: ddrConfig.clockArchitecture = CLOCK_INTERNAL_BUFFERED;
endcase
// Set the ddr clock source by parameter.
DDR_DEVICE sdram <- mkDDRDevice(ddrConfig,
clocked_by clk,
reset_by clocks.driver.baseReset);
// Next, create the physical device that can trigger a soft reset. Pass along the
// interface to the trigger module that the clocks device has given us.
let pcieRst <- mkResetFanout(clocks.driver.baseReset, clocked_by clk);
PCIE_DEVICE pcie <- mkPCIEDevice(clocks.driver.rawClock,
clocks.driver.rawReset,
clocked_by clk,
reset_by pcieRst);
//
// Pass reset from PCIe to the model. The host holds reset long enough that
// a crossing wire to the model clock domain is sufficient.
//
Reg#(Bool) pcieInReset <- mkReg(True,
clocked_by pcie.driver.clock,
reset_by pcie.driver.reset);
ReadOnly#(Bool) assertModelReset <-
mkNullCrossingWire(clocks.driver.clock,
pcieInReset,
clocked_by pcie.driver.clock,
reset_by pcie.driver.reset);
(* fire_when_enabled, no_implicit_conditions *)
rule exitResetPCIe (pcieInReset);
pcieInReset <= False;
endrule
(* fire_when_enabled *)
rule triggerModelReset (assertModelReset);
clocks.softResetTrigger.reset();
endrule
AURORA_COMPLEX aurora_device <- mkAuroraDevice(clocks.driver.rawClock,
clocks.driver.rawReset,
clocked_by clk, reset_by rst);
//
// Aggregate the drivers
//
interface PHYSICAL_DRIVERS physicalDrivers;
interface clocksDriver = clocks.driver;
interface pcieDriver = pcie.driver;
interface ddrDriver = sdram.driver;
interface auroraDriver = aurora_device.drivers;
endinterface
//
// Aggregate the wires
//
interface TOP_LEVEL_WIRES topLevelWires;
interface clocksWires = clocks.wires;
interface pcieWires = pcie.wires;
interface ddrWires = sdram.wires;
interface auroraWires = aurora_device.wires;
endinterface
endmodule