-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updates to the PCIe interface to allow for shared control signals #234
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
#use-added-syntax(jitx) | ||
defpackage jsl/examples/protocols/pcie/pcie-conn : | ||
import core | ||
import jitx | ||
import jitx/commands | ||
|
||
import jsl | ||
|
||
; This is primarily just a placeholder for a | ||
; real PCIe connector. | ||
val SSOP-pkg = SOP( | ||
num-leads = 32, | ||
lead-profile = Lead-Profile( | ||
span = min-max(6.2, 6.6), | ||
pitch = 0.65, | ||
lead = SOP-Lead( | ||
length = min-max(0.5, 0.75), | ||
width = min-max(0.19, 0.3) | ||
) | ||
), | ||
package-body = PackageBody( | ||
width = min-max(4.3, 4.5) | ||
length = min-max(4.9, 5.1) | ||
height = min-max(1.0, 1.2) | ||
), | ||
density-level = DensityLevelC | ||
) | ||
|
||
|
||
|
||
public pcb-component component : | ||
reference-prefix = "J" | ||
mpn = "JITX002" | ||
description = "Dummy PCIe Connector with multiple PCIe supports" | ||
|
||
port REFCLK : diff-pair | ||
port LANE : lane-pair[4] | ||
|
||
pin-properties : | ||
[pin:Ref | pads:Int ... ] | ||
|
||
[REFCLK.N | 1 ] | ||
[REFCLK.P | 2 ] | ||
[GND[0] | 3 ] | ||
|
||
[LANE[0].TX.P | 4 ] | ||
[LANE[0].TX.N | 5 ] | ||
[GND[1] | 6 ] | ||
[LANE[0].RX.P | 7 ] | ||
[LANE[0].RX.N | 8 ] | ||
[GND[2] | 9 ] | ||
|
||
[LANE[1].TX.P | 10 ] | ||
[LANE[1].TX.N | 11 ] | ||
[GND[3] | 12 ] | ||
[LANE[1].RX.P | 13] | ||
[LANE[1].RX.N | 14 ] | ||
[GND[4] | 15 ] | ||
[PRSNT# | 16 ] | ||
|
||
[GND[5] | 17 ] | ||
[LANE[2].TX.P | 18 ] | ||
[LANE[2].TX.N | 19 ] | ||
[GND[6] | 20 ] | ||
[LANE[2].RX.P | 21 ] | ||
[LANE[2].RX.N | 22 ] | ||
[GND[7] | 23 ] | ||
|
||
[LANE[3].TX.P | 24 ] | ||
[LANE[3].TX.N | 25 ] | ||
[GND[8] | 26 ] | ||
[LANE[3].RX.P | 27 ] | ||
[LANE[3].RX.N | 28 ] | ||
[GND[9] | 29 ] | ||
|
||
[PERST# | 30 ] | ||
[PEWAKE# | 31 ] | ||
[CLKREQ# | 32 ] | ||
|
||
|
||
|
||
val box = BoxSymbol(self) | ||
|
||
set-side(Left, self.GND, self.PERST#, self.PEWAKE#, self.CLKREQ#, self.PRSNT#) | ||
set-side(Right, self.LANE, self.REFCLK) | ||
|
||
assign-symbol $ create-symbol(box) | ||
|
||
val lp = create-landpattern(SSOP-pkg) | ||
assign-landpattern(lp) | ||
|
||
|
||
for i in 0 to 4 do : | ||
diff-pin-model(self.LANE[i].TX.P, LANE[i].TX.N, delay = typ(10.0e-15) loss = typ(0.1)) | ||
diff-pin-model(self.LANE[i].RX.P, LANE[i].RX.N, delay = typ(10.0e-15) loss = typ(0.1)) | ||
|
||
diff-pin-model(self.REFCLK.P, self.REFCLK.N, delay = typ(10.0e-15) loss = typ(0.1)) | ||
|
||
|
||
doc: \<DOC> | ||
Helper function for creating the necessary PCIe Supports Statements | ||
|
||
The user must pass a bundle type, such as `pcie-std(<N>)` and | ||
this will construct a supports statement that will connect | ||
the bundle ports to the predefined `self.sw` instance of the | ||
`compponent` connector. | ||
<DOC> | ||
defn connect_lanes (b:Bundle): | ||
inside pcb-module: | ||
supports b: | ||
for i in indices(b.data.lane) do : | ||
b.data.lane[i].RX.P => self.sw.LANE[i].RX.P | ||
b.data.lane[i].RX.N => self.sw.LANE[i].RX.N | ||
b.data.lane[i].TX.P => self.sw.LANE[i].TX.P | ||
b.data.lane[i].TX.N => self.sw.LANE[i].TX.N | ||
b.data.refclk.P => self.sw.REFCLK.P | ||
b.data.refclk.N => self.sw.REFCLK.N | ||
|
||
b.control.PEWAKE# => self.sw.PEWAKE# | ||
b.control.PERST# => self.sw.PERST# | ||
b.control.CLKREQ# => self.sw.CLKREQ# | ||
|
||
if has-PRSNT#(b): | ||
b.control.PRSNT# => self.sw.PRSNT# | ||
|
||
|
||
doc: \<DOC> | ||
PCIe Connector Module with Exposed Pin-Assigned PCIe ports | ||
|
||
User must use: | ||
|
||
``` | ||
inst dut : jsl/examples/protocols/pcie/pcie-conn/module | ||
require pcie-1x:pcie-std(1) from dut | ||
``` | ||
|
||
To access one of the PCIe interface. | ||
<DOC> | ||
public pcb-module module : | ||
|
||
public inst sw : component | ||
|
||
val bundle-types = [ | ||
pcie-std(4), | ||
pcie-std(2), | ||
pcie-std(1), | ||
pcie-with-hotplug(4), | ||
pcie-with-hotplug(2), | ||
pcie-with-hotplug(1), | ||
] | ||
|
||
for btype in bundle-types do: | ||
connect_lanes(btype) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#use-added-syntax(jitx) | ||
defpackage jsl/examples/protocols/pcie/main: | ||
import core | ||
import collections | ||
import jitx | ||
import jitx/commands | ||
|
||
|
||
import jsl | ||
|
||
import jsl/examples/protocols/common/example-board | ||
import jsl/examples/protocols/common/example-components | ||
import jsl/examples/protocols/pcie/pcie-src | ||
|
||
|
||
pcb-module pcie-example : | ||
|
||
inst dut1 : jsl/examples/protocols/pcie/pcie-src/module | ||
inst dut2 : jsl/examples/protocols/pcie/pcie-conn/module | ||
inst dut3 : jsl/examples/protocols/pcie/pcie-conn/module | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dut3 not used? likely intended to be inst dut2 : jsl/examples/protocols/pcie/pcie-conn/module[2] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch 👍 |
||
|
||
val version = PCIE-V4 | ||
val trace-imped = pcie-get-trace-impedance(version) | ||
val cst = PCIe-Constraint(version, diff(trace-imped)) | ||
|
||
val b-cap = block-cap(220.0e-9) | ||
|
||
; Construct a typical passive connector setup | ||
; for a 2 lane configuration. This means a | ||
; straight through `tx => tx` and `rx => rx` | ||
; configuration. | ||
; | ||
; The two connectors share the one wake pin from the IC source module | ||
|
||
require src-ep : pcie-std(2) from dut1 | ||
require dst-ep : pcie-std(2)[2] from dut2 | ||
|
||
for i in 0 to 2 do: | ||
within [src, dst] = constrain-topology(src-ep, dst-ep[i], cst): | ||
; Here we construct the circuit topology for the link | ||
; Note that we don't need to worry about any of the constraint | ||
; application, as that is handled by the `PCIe-Constraint` type. | ||
; You can add other components in the topology as you wish - below | ||
; is a typical basic implementation. | ||
for i in indices(src.data.lane) do: | ||
inst tx-coupler : dp-coupler(b-cap) | ||
topo-pair(src.data.lane[i].TX => tx-coupler => dst.data.lane[i].TX) | ||
; No Blocking Caps on the Receive side. | ||
topo-net(src.data.lane[i].RX => dst.data.lane[i].RX) | ||
|
||
topo-net(src.data.refclk => dst.data.refclk) | ||
; The control signals do not demand a topology so | ||
; we just use a straight net connection. | ||
net (src.control, dst.control) | ||
|
||
|
||
|
||
|
||
set-current-design("pcie-example-2") | ||
setup-board() | ||
; Set the schematic sheet size | ||
set-paper(ANSI-A) | ||
|
||
; Set the top level module (the module to be compile into a schematic and PCB) | ||
set-main-module(pcie-example) | ||
|
||
; View the results | ||
view-board() | ||
view-schematic() | ||
view-design-explorer() | ||
; view-bom(BOM-STD) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -139,7 +139,7 @@ public pcb-module module : | |
|
||
public inst sw : component | ||
|
||
val bd-4x = pcie(4) | ||
val bd-4x = pcie-std(4) | ||
supports bd-4x : | ||
for i in 0 to 4 do : | ||
bd-4x.data.lane[i].RX.P => sw.PRXP[i] | ||
|
@@ -153,7 +153,7 @@ public pcb-module module : | |
bd-4x.control.PERST# => sw.PERST#[0] | ||
bd-4x.control.CLKREQ# => sw.GPIO[1] | ||
|
||
val bd-4x-prsnt = pcie(4, PCIe-PRSNT#) | ||
val bd-4x-prsnt = pcie-with-hotplug(4) | ||
supports bd-4x-prsnt : | ||
for i in 0 to 4 do : | ||
bd-4x-prsnt.data.lane[i].RX.P => sw.PRXP[i] | ||
|
@@ -168,29 +168,58 @@ public pcb-module module : | |
bd-4x-prsnt.control.PRSNT# => sw.GPIO[12] | ||
bd-4x-prsnt.control.CLKREQ# => sw.GPIO[1] | ||
|
||
; For the PCIe-2X, I'm going to demonstrate | ||
; how to use a shared port WAKE pin across | ||
; the different. This is common situation where | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the different. => the different endpoints. |
||
; if we are not careful, we can run into an unsat | ||
; condition. The key is to just not include the shared | ||
; port in the pin assignment solution and backfill it | ||
; in an external port where the fanout happens. | ||
|
||
val pcie-2x-shared-wake = sw.GPIO[7] | ||
val ctls-2x = [ | ||
[sw.GPIO[6], sw.GPIO[12], sw.GPIO[1]] | ||
[sw.GPIO[7], sw.GPIO[13], sw.GPIO[2]] | ||
[pcie-2x-shared-wake, sw.GPIO[12], sw.GPIO[1]] | ||
[pcie-2x-shared-wake, sw.GPIO[13], sw.GPIO[2]] | ||
] | ||
val bd-2x = pcie(2) | ||
; The internal bundle contains reset, and clock request | ||
; but does not include the WAKE | ||
val bd-2x-int = pcie(2, PCIe-PERST#, PCIe-CLKREQ#) | ||
for j in 0 to 2 do: | ||
supports bd-2x: | ||
supports bd-2x-int: | ||
val ch-offset = (2 * j) | ||
for i in 0 to 2 do : | ||
bd-2x.data.lane[i].RX.P => sw.PRXP[i + ch-offset] | ||
bd-2x.data.lane[i].RX.N => sw.PRXN[i + ch-offset] | ||
bd-2x.data.lane[i].TX.P => sw.PTXP[i + ch-offset] | ||
bd-2x.data.lane[i].TX.N => sw.PTXN[i + ch-offset] | ||
bd-2x.data.refclk.P => sw.REFCLKP[ch-offset] | ||
bd-2x.data.refclk.N => sw.REFCLKN[ch-offset] | ||
bd-2x-int.data.lane[i].RX.P => sw.PRXP[i + ch-offset] | ||
bd-2x-int.data.lane[i].RX.N => sw.PRXN[i + ch-offset] | ||
bd-2x-int.data.lane[i].TX.P => sw.PTXP[i + ch-offset] | ||
bd-2x-int.data.lane[i].TX.N => sw.PTXN[i + ch-offset] | ||
bd-2x-int.data.refclk.P => sw.REFCLKP[ch-offset] | ||
bd-2x-int.data.refclk.N => sw.REFCLKN[ch-offset] | ||
|
||
val [wake, present, clkreq] = ctls-2x[j] | ||
val [_, present, clkreq] = ctls-2x[j] | ||
|
||
bd-2x-int.control.PERST# => sw.PERST#[ch-offset] | ||
bd-2x-int.control.CLKREQ# => clkreq | ||
|
||
val bd-2x-ext = pcie-std(2) | ||
|
||
; The external interface for the PCIe with Shared Wake is different | ||
; from the other interfaces because it has to be implemented as an | ||
; externally facing port instead of a `supports` statement. | ||
; Fortunately, it still takes advantage of pin assignment and hides | ||
; the details of the connection but requires a different connection | ||
; method at the top-level. | ||
port pcie-2x : bd-2x-ext[2] | ||
|
||
for pt in indices(pcie-2x) do: | ||
net (pcie-2x[pt].control.PEWAKE#, pcie-2x-shared-wake) | ||
|
||
require pt-int : bd-2x-int from self | ||
topo-net(pcie-2x[pt].data => pt-int.data) | ||
net (pcie-2x[pt].control.PERST#, pt-int.control.PERST#) | ||
net (pcie-2x[pt].control.CLKREQ#, pt-int.control.CLKREQ#) | ||
|
||
bd-2x.control.PEWAKE# => wake | ||
bd-2x.control.PERST# => sw.PERST#[ch-offset] | ||
bd-2x.control.CLKREQ# => clkreq | ||
|
||
val bd-2x-prsnt = pcie(2, PCIe-PRSNT#) | ||
val bd-2x-prsnt = pcie-with-hotplug(2) | ||
for j in 0 to 2 do: | ||
supports bd-2x-prsnt: | ||
val ch-offset = (2 * j) | ||
|
@@ -209,7 +238,7 @@ public pcb-module module : | |
bd-2x-prsnt.control.PRSNT# => present | ||
bd-2x-prsnt.control.CLKREQ# => clkreq | ||
|
||
val bd-1x = pcie(1) | ||
val bd-1x = pcie-std(1) | ||
val ctls-1x = [ | ||
[sw.GPIO[8], sw.GPIO[12], sw.GPIO[1]], | ||
[sw.GPIO[9], sw.GPIO[14], sw.GPIO[3]], | ||
|
@@ -230,7 +259,7 @@ public pcb-module module : | |
bd-1x.control.PEWAKE# => wake | ||
bd-1x.control.CLKREQ# => clkreq | ||
|
||
val bd-1x-prsnt = pcie(1, PCIe-PRSNT#) | ||
val bd-1x-prsnt = pcie-with-hotplug(1) | ||
for j in 0 to 4 do: | ||
supports bd-1x-prsnt: | ||
bd-1x-prsnt.data.lane[0].RX.P => sw.PRXP[j] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, neat way to reduce typing.