Creating a New Physical Device

Elvis Dowson edited this page Jun 15, 2016 · 4 revisions

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
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.