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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
import os
import subprocess
from amaranth.build import *
from amaranth.vendor import XilinxPlatform
from .resources import *
__all__ = ["MercuryPlatform"]
class MercuryPlatform(XilinxPlatform):
"""
Original Mercury Board from Micro-Nova: https://www.micro-nova.com
Mercury Manual: https://www.micro-nova.com/s/mercury_rm.pdf
Mercury Schematic: https://www.micro-nova.com/s/mercury_schematic.pdf
The Mercury board is often paired with an extension board called the
Baseboard, which provides an ample set of I/O for FPGA beginners.
Baseboard Manual: https://www.micro-nova.com/s/baseboard_rm.pdf
Baseboard Schematics: https://www.micro-nova.com/s/baseboard_schematic.pdf
Mercury and Baseboard Resources: https://www.micro-nova.com/resources-mercury
"""
device = "xc3s200a"
package = "vq100"
speed = "4"
default_clk = "clk50"
resources = [
Resource("clk50", 0, Pins("P43", dir="i"),
Attrs(IOSTANDARD="LVCMOS33"), Clock(50e6)),
Resource("button", 0, Pins("P41", dir="i"),
Attrs(IOSTANDARD="LVTTL")),
# The serial interface and flash memory have a shared SPI bus.
# FPGA is secondary.
SPIResource("spi_serial", 0, role="peripheral",
cs_n="P39", clk="P53", copi="P46", cipo="P51",
attrs=Attrs(IOSTANDARD="LVTTL"),
),
# FPGA is primary.
*SPIFlashResources(0,
cs_n="P27", clk="P53", copi="P46", cipo="P51",
attrs=Attrs(IOSTANDARD="LVTTL")
),
# ADC over SPI- FPGA is primary.
SPIResource("spi_adc", 0, role="controller",
cs_n="P12", clk="P9", copi="P10", cipo="P21",
attrs=Attrs(IOSTANDARD="LVTTL"),
),
# GPIO/SRAM Control
# 5V tolerant GPIO is shared w/ the SRAM (on 200k gate devices) using
# this pin. All GPIO except gpio:30 (and gpio:20, though see comment
# under SRAMResource) interface to the SRAM. On assertion, this signal
# will tristate the level-shifters, preventing any output on the 5V
# GPIO pins (including gpio:30 and gpio:20).
Resource("bussw_oe", 0, PinsN("P30N", dir="o"),
Attrs(IOSTANDARD="LVTTL"))
]
# Perhaps define some connectors as having a specific purpose- i.e. a 5V GPIO
# bus with data, peripheral-select, and control signals?
connectors = [
Connector("gpio", 0, """P59 P60 P61 P62 P64 P57
P56 P52 P50 P49 P85 P84
P83 P78 P77 P65 P70 P71
P72 P73 P5 P4 P6 P98
P94 P93 P90 P89 P88 P86"""), # 5V I/O- LVTTL.
Connector("dio", 0, "P20 P32 P33 P34 P35 P36 P37"), # Fast 3.3V IO
# (Directly attached to FPGA)- LVCMOS33.
Connector("clkio", 0, "P40 P44"), # Clock IO (Can be used as GPIO)-
# LVCMOS33.
Connector("input", 0, "P68 P97 P7 P82"), # Input-only pins- LVCMOS33.
Connector("led", 0, "P13 P15 P16 P19"), # LEDs can be used as pins
# as well- LVTTL.
Connector("pmod", 0, "P5 P4 P6 P98 P94 P93 P90 P89") # Baseboard PMOD.
# Overlaps w/ GPIO bus.
]
# Some default useful extensions. Attach to platform using:
# p.add_resources(p.leds)
# pmod_btn = plat.request("led")
leds = [
Resource("led", 0, Pins("1", dir="o", conn=("led", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("led", 1, Pins("2", dir="o", conn=("led", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("led", 2, Pins("3", dir="o", conn=("led", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("led", 3, Pins("4", dir="o", conn=("led", 0)),
Attrs(IOSTANDARD="LVTTL")),
]
sram = [
SRAMResource(0,
cs_n="P3", we_n="gpio_0:29",
# According to the schematic, A19/Pin 25 on the SRAM is wired to
# gpio-0:20. However, according to the SRAM's datasheet, pin 25 is
# a NC. Do not expose for now.
a=""" gpio_0:1 gpio_0:2 gpio_0:3 gpio_0:4 gpio_0:5 gpio_0:6
gpio_0:7 gpio_0:8 gpio_0:9 gpio_0:10 gpio_0:11 gpio_0:12
gpio_0:13 gpio_0:14 gpio_0:15 gpio_0:16 gpio_0:17 gpio_0:18
gpio_0:19""",
d="""gpio_0:21 gpio_0:22 gpio_0:23 gpio_0:24 gpio_0:25 gpio_0:26
gpio_0:27 gpio_0:28""",
attrs=Attrs(IOSTANDARD="LVTTL", SLEW="FAST")
)
]
# The "serial port" is in fact over SPI. The creators of the board provide
# a VHDL file for talking over this interface. In light of space
# constraints and the fact that both the FT245RL and FPGA can BOTH be
# SPI primaries, however, it may be necessary to sacrifice two "high-speed"
# (DIO, INPUT) pins instead.
serial = [
# RX: FTDI D0, TX: FTDI D1
UARTResource(0, rx="input_0:1", tx="dio_0:1",
attrs=Attrs(IOSTANDARD="LVCMOS33"))
]
# The remaining peripherals only make sense w/ the Baseboard installed.
# See: http://www.micro-nova.com/mercury-baseboard/
_switches = [
Resource("switch", 0, Pins("1", dir="i", conn=("gpio", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("switch", 1, Pins("2", dir="i", conn=("gpio", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("switch", 2, Pins("3", dir="i", conn=("gpio", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("switch", 3, Pins("4", dir="i", conn=("gpio", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("switch", 4, Pins("5", dir="i", conn=("gpio", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("switch", 5, Pins("6", dir="i", conn=("gpio", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("switch", 6, Pins("7", dir="i", conn=("gpio", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("switch", 7, Pins("8", dir="i", conn=("gpio", 0)),
Attrs(IOSTANDARD="LVTTL"))
]
_buttons = [
Resource("button", 1, Pins("1", dir="i", conn=("input", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("button", 2, Pins("2", dir="i", conn=("input", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("button", 3, Pins("3", dir="i", conn=("input", 0)),
Attrs(IOSTANDARD="LVTTL")),
Resource("button", 4, Pins("4", dir="i", conn=("input", 0)),
Attrs(IOSTANDARD="LVTTL"))
]
_vga = [
VGAResource(0,
r="dio_0:1 dio_0:2 dio_0:3",
g="dio_0:4 dio_0:5 dio_0:6",
b="dio_0:7 clkio_0:1",
hs="led_0:3", vs="led_0:4", invert_sync=True,
attrs=Attrs(IOSTANDARD="LVCMOS33", SLEW="FAST"))
]
_extclk = [
Resource("extclk", 0, Pins("1", dir="i", conn=("clkio", 1)),
Attrs(IOSTANDARD="LVCMOS33"))
]
_sevenseg = [
Display7SegResource(0,
a="gpio_0:13", b="gpio_0:14", c="gpio_0:15", d="gpio_0:16",
e="gpio_0:17", f="gpio_0:18", g="gpio_0:19", dp="gpio_0:20",
invert=True, attrs=Attrs(IOSTANDARD="LVTTL")
),
Resource("display_7seg_ctrl", 0,
Subsignal("en", Pins("9 10 11 12", dir="o", conn=("gpio", 0))),
Attrs(IOSTANDARD="LVTTL")
)
]
_ps2 = [
PS2Resource(0,
clk="2", dat="1", conn=("led", 0), attrs=Attrs(IOSTANDARD="LVTTL")),
]
_audio = [
Resource("audio", 0,
Subsignal("l", Pins("30", dir="o", conn=("gpio", 0))),
Subsignal("r", Pins("29", dir="o", conn=("gpio", 0))),
Attrs(IOSTANDARD="LVTTL")
)
]
baseboard_sram = _buttons + _vga + _extclk + _ps2
baseboard_no_sram = baseboard_sram + _switches + _sevenseg + _audio
def toolchain_program(self, products, name):
# https://github.com/cr1901/mercpcl
mercpcl = os.environ.get("MERCPCL", "mercpcl")
with products.extract("{}.bin".format(name)) as bitstream_filename:
subprocess.check_call([mercpcl, bitstream_filename])
if __name__ == "__main__":
from .test.blinky import *
plat = MercuryPlatform()
plat.add_resources(plat.leds)
plat.build(Blinky(), do_program=True)
|