WF_XXX Internal Pin Aliases (and @MAP_IO Help)

Intro

First, I want to clarify that there are two sets of pins when discussing the main FPGA device.

  1. EXTERNAL The physical pins that run along the perimeter of the FPGA device’s PCB.
  2. INTERNAL The small pins that surround the FPGA QFN chip itself.

The synthesis engine expects that all pins referenced are INTERNAL, as in, they are part of the FPGA chip itself. It has no knowledge of the outside world (the rest of the PCB).

However, for our use cases, it’s nice to be able to look at the FPGA device and say "I want to blink an LED using pin 1" and see that it toggles the pin at that physical location (instead of merely pin 1 on the FPGA chip).

When using @MAP_IO, our backend replaces the EXTERNAL pins with their corresponding INTERNAL pin. I’ll will post the full lookup table at the end of this post. You won’t need this table unless you decide to write your own .pcf files when using IceStorm or Lattice’s iCECube.

Automated Aliases

There are certain FPGA chip pins that are wired directly to certain peripherals. For example, the LED is always wired to FPGA pin 31.

If you are using an external toolchain (IceStorm or iCECube), you might want to set these in your pinmap.pcf.

Name         FPGA pin
---------------------
WF_LED       31
WF_CLK       35
WF_BUTTON    42
WF_NEO       32
WF_CPU1      11
WF_CPU2      12
WF_CPU3      13
WF_CPU4      10

@MAP_IO Usage

The syntax is // @MAP_IO <name> <pin_number>, where pin_number is denoted by the silk-screen EXTERNAL pin number on the main FPGA board.

For example,

// @MAP_IO EXTERNAL_LED 5
module top(output wire EXTERNAL_LED);
    assign EXTERNAL_LED = 1;
endmodule

EXTERNAL to INTERNAL Pin Lookup

# Given an EXTERNAL pin number, return the INTERNAL pin
# number that is wired to it.
def internal_pin_map(external_pin)
    map = []
    map[0]  = 17

    map[1]  = 16
    map[2]  = 14
    map[3]  = 23
    map[4]  = 20
    map[5]  = 19
    map[6]  = 18
    map[7]  = 21
    map[8]  = 25
    map[9]  = 26
    map[10] = 28
    map[11] = 27
    map[12] = 34
    map[13] = 35
    map[14] = 36

    map[15] = 37
    map[16] = 40
    map[17] = 44
    map[18] = 46
    map[19] = 47
    map[20] = 45
    map[21] = 48
    map[22] = 2

    map[23] = 3
    map[24] = 4
    map[25] = 9
    map[26] = 6
    map[27] = 43
    map[28] = 41
    map[29] = 39
    map[30] = 38
    map[31] = 15

    return map[external_pin]
end

Ryan,

Thanks for this clarification. However, is there a way you could make this work:

// @MAP_IO d[0] 14
// @MAP_IO d[1] 15
// @MAP_IO q[0] 16
// @MAP_IO q[1] 17

module test(d, q );

input [1:0] d;
output reg [1:0] q;

endmodule

Right now the compiler complains because the backend assumes “d[0]” is an missing identifier and not an indexed variable.

So I have to do this (which is a really a pain with 8-bit inputs and outputs ):

// @MAP_IO d0 14
// @MAP_IO d1 15
// @MAP_IO q0 16
// @MAP_IO q1 17

module test(d, q );

input [1:0] d;
output reg [1:0] q;

wire d0, d1, q0, q1;

assign d0 = d[0];
assign d1 = d[1];
assign q0 = q[0];
assign q1 = q[1];

endmodule

Hi, yes I see what you’re saying. I’ll try my best to implement that over this weekend. Cheers :slight_smile:

We’re looking to open source a lot of these parsing components very soon.

Is there a list of // #CAS_<> directives somewhere? It is a bit of work to comb through the examples to find them (and I will never know if I have found them all).

David

Hi sorry, the #CAS directives are an old holdover from our previous parser. Those are ignored.

The WF directives are valid.

There are two WF directives: MAP_IO and FPGA_TOP.

In addition to those, certain IO constants are defined. For example, WF_LED maps to the onboard LED.

# append our hard-coded aliases (in other words, these IOs have physical traces
# between the FPGA and their destination)
traces = {
    "WF_LED"    => 31, # on-board yellow LED
    "WF_CLK"    => 35, # on-board precision oscillator
    "WF_BUTTON" => 42, # on-board toggle-button
    "WF_NEO"    => 32, # on-board neopixel RGB LED
    "WF_CPU1"   => 11, # microcontroller gpio, PA0
    "WF_CPU2"   => 12, # microcontroller gpio, PA2
    "WF_CPU3"   => 13, # microcontroller gpio, PA3
    "WF_CPU4"   => 10, # microcontroller gpio, PB0
}

It was #CAS_NAME that got me looking through the sample files. It appears to still work. If I am not supposed to use it, what is the corresponding WF directive for:

// #CAS_NAME CTR_74LS469 // top level module

never mind this works as well

// @FPGA_TOP CTR_74LS469