-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbasic_endpoint.py
More file actions
135 lines (108 loc) · 4.22 KB
/
basic_endpoint.py
File metadata and controls
135 lines (108 loc) · 4.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env python3
"""Basic PCIe Endpoint Example
Demonstrates creating a minimal PCIe endpoint with:
- SimPCIePHY for simulation
- PCIeEndpoint connecting PHY ↔ TLP ↔ Crossbar
- PCIeWishboneMaster for host CSR access
- PCIeDMA with reader (Host→FPGA) and writer (FPGA→Host)
This example elaborates the design and prints the hierarchy to verify
that all components are correctly instantiated.
Usage:
cd amaranth-pcie/
pdm run python examples/basic_endpoint.py
"""
from amaranth import *
from amaranth.back.rtlil import convert
from amaranth_pcie.phy.sim import SimPCIePHY
from amaranth_pcie.core.endpoint import PCIeEndpoint
from amaranth_pcie.frontend.wishbone import PCIeWishboneMaster
from amaranth_pcie.frontend.dma import PCIeDMA
class BasicPCIeDesign(Elaboratable):
"""A minimal PCIe endpoint design with Wishbone bridge and DMA.
Architecture::
Host ←──PCIe──→ SimPCIePHY
│
PCIeEndpoint
┌───┴───┐
│Crossbar│
└┬──┬──┬┘
│ │ │
WishboneMaster │ DMA (reader + writer)
│
TLP layer
"""
def __init__(self):
# Create PHY (simulation — no vendor IP needed)
self.phy = SimPCIePHY(
data_width=64,
bar0_size=1 * 1024 * 1024, # 1 MB BAR0
max_request_size=512,
max_payload_size=128,
with_loopback=False, # We'll drive RX externally in tests
)
# Create endpoint (connects PHY ↔ TLP ↔ Crossbar)
self.endpoint = PCIeEndpoint(
phy=self.phy,
max_pending_requests=4,
endianness="big",
)
def elaborate(self, platform):
m = Module()
# Instantiate PHY and endpoint
m.submodules.phy = self.phy
m.submodules.endpoint = self.endpoint
# Add Wishbone bridge for host CSR access
# The host can read/write FPGA registers through BAR0
m.submodules.wb_master = wb_master = PCIeWishboneMaster(
endpoint=self.endpoint,
base_address=0x00000000,
wb_addr_width=16, # 64K address space
wb_data_width=32,
)
# Add DMA with loopback for testing
m.submodules.dma = dma = PCIeDMA(
endpoint=self.endpoint,
data_width=64,
with_loopback=True, # Enable loopback for testing
)
# --- User logic example: simple data counter ---
# When loopback is disabled, this counter feeds data to the writer
# and the reader output goes to a sink.
counter = Signal(64)
m.d.sync += counter.eq(counter + 1)
# Connect DMA IRQ to PHY MSI (simplified)
# In a real design, you'd connect through a PCIeMSI controller
# m.d.comb += msi.irqs[0].eq(dma.irq)
# Print design info
print(f"PHY data width: {self.phy.data_width} bits")
print(f"BAR0 mask: 0x{self.phy.bar0_mask:08X}")
print(f"Max request size: {self.phy._max_request_size_val} bytes")
print(f"Max payload size: {self.phy._max_payload_size_val} bytes")
print(f"DMA data width: {dma.data_width} bits")
return m
def main():
print("=" * 60)
print("Basic PCIe Endpoint Example")
print("=" * 60)
print()
design = BasicPCIeDesign()
# Elaborate to verify the design compiles
from amaranth.hdl import Fragment
fragment = Fragment.get(design, platform=None)
print()
print("Design elaborated successfully!")
print()
print("Components:")
print(" - SimPCIePHY (64-bit, simulation)")
print(" - PCIeEndpoint (shared channel, big-endian)")
print(" - PCIeWishboneMaster (host → FPGA CSR access)")
print(" - PCIeDMA (reader + writer + loopback)")
print()
print("To generate RTLIL output, uncomment the convert() call below.")
# Uncomment to generate RTLIL:
# output = convert(design)
# with open("basic_endpoint.il", "w") as f:
# f.write(output)
# print("Wrote basic_endpoint.il")
if __name__ == "__main__":
main()