Skip to content

Commit dab4f76

Browse files
committed
very messy and broken - v2 applet attempt
1 parent 839cbae commit dab4f76

File tree

2 files changed

+145
-105
lines changed

2 files changed

+145
-105
lines changed

software/glasgow/applet/interface/gpib_controller/__init__.py

Lines changed: 110 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
from enum import IntEnum
66
from amaranth import *
77
from amaranth.lib import io, data, cdc, wiring, enum
8+
from amaranth.lib import wiring, stream, io
9+
from amaranth.lib.wiring import In, Out
810

9-
from ... import *
11+
12+
# from ... import *
13+
from ... import GlasgowAppletV2
1014

1115
"""
1216
GPIB / IEEE-488 is a 16 line bus, with a single controller (in this case, the
@@ -109,12 +113,15 @@ class GPIBStatus(enum.Enum, shape=8):
109113
Error = 16
110114

111115

112-
class GPIBSubtarget(Elaboratable):
113-
def __init__(self, ports, in_fifo, out_fifo, status):
116+
class GPIBComponent(wiring.Component):
117+
i_stream: In(stream.Signature(8))
118+
o_stream: Out(stream.Signature(8))
119+
120+
def __init__(self, ports):
114121
self.ports = ports
115-
self.in_fifo = in_fifo
116-
self.out_fifo = out_fifo
117-
self.status = status
122+
# self.status = status
123+
124+
self.status = Signal(8)
118125

119126
self.dio_i = Signal(8) # Data Lines Listen
120127
self.dio_o = Signal(8) # Talk
@@ -134,18 +141,20 @@ def __init__(self, ports, in_fifo, out_fifo, status):
134141
self.talking = Signal()
135142
self.listening = Signal()
136143

144+
super().__init__()
145+
137146
def elaborate(self, platform):
138147
m = Module()
139148

140-
m.submodules.dio_buffer = dio_buffer = io.Buffer("io", ~self.ports.dio)
141-
m.submodules.eoi_buffer = eoi_buffer = io.Buffer("io", ~self.ports.eoi)
142-
m.submodules.dav_buffer = dav_buffer = io.Buffer("io", ~self.ports.dav)
143-
m.submodules.nrfd_buffer = nrfd_buffer = io.Buffer("io", ~self.ports.nrfd)
144-
m.submodules.ndac_buffer = ndac_buffer = io.Buffer("io", ~self.ports.ndac)
145-
m.submodules.srq_buffer = srq_buffer = io.Buffer("i", ~self.ports.srq)
146-
m.submodules.ifc_buffer = ifc_buffer = io.Buffer("o", ~self.ports.ifc)
147-
m.submodules.atn_buffer = atn_buffer = io.Buffer("o", ~self.ports.atn)
148-
m.submodules.ren_buffer = ren_buffer = io.Buffer("o", ~self.ports.ren)
149+
m.submodules.dio_buffer = dio_buffer = io.Buffer("io", self.ports.dio)
150+
m.submodules.eoi_buffer = eoi_buffer = io.Buffer("io", self.ports.eoi)
151+
m.submodules.dav_buffer = dav_buffer = io.Buffer("io", self.ports.dav)
152+
m.submodules.nrfd_buffer = nrfd_buffer = io.Buffer("io", self.ports.nrfd)
153+
m.submodules.ndac_buffer = ndac_buffer = io.Buffer("io", self.ports.ndac)
154+
m.submodules.srq_buffer = srq_buffer = io.Buffer("i", self.ports.srq)
155+
m.submodules.ifc_buffer = ifc_buffer = io.Buffer("o", self.ports.ifc)
156+
m.submodules.atn_buffer = atn_buffer = io.Buffer("o", self.ports.atn)
157+
m.submodules.ren_buffer = ren_buffer = io.Buffer("o", self.ports.ren)
149158

150159
m.submodules += [
151160
cdc.FFSynchronizer(dio_buffer.i, self.dio_i),
@@ -177,16 +186,17 @@ def elaborate(self, platform):
177186
ren_buffer.o.eq(self.ren_o),
178187
]
179188

180-
settle_delay = math.ceil(platform.default_clk_frequency * 1e-6)
189+
# settle_delay = math.ceil(platform.default_clk_frequency * 1e-6)
190+
settle_delay = 1000
181191
timer = Signal(range(1 + settle_delay))
182192

183-
m.d.comb += [
184-
platform.request("led", 0).o.eq(self.status == 0),
185-
platform.request("led", 1).o.eq(self.status == 1),
186-
platform.request("led", 2).o.eq(self.status == 2),
187-
platform.request("led", 3).o.eq(self.status == 4),
188-
platform.request("led", 4).o.eq(self.status == 8),
189-
]
193+
# m.d.comb += [
194+
# platform.request("led", 0).o.eq(self.status == 0),
195+
# platform.request("led", 1).o.eq(self.status == 1),
196+
# platform.request("led", 2).o.eq(self.status == 2),
197+
# platform.request("led", 3).o.eq(self.status == 4),
198+
# platform.request("led", 4).o.eq(self.status == 8),
199+
# ]
190200

191201
l_control = Signal(data.StructLayout({
192202
"tx": 1,
@@ -203,9 +213,9 @@ def elaborate(self, platform):
203213
with m.FSM():
204214
with m.State("Control: Begin"):
205215
m.d.sync += self.status.eq(GPIBStatus.Idle)
206-
m.d.comb += self.out_fifo.r_en.eq(1)
207-
with m.If(self.out_fifo.r_rdy):
208-
m.d.sync += l_control.eq(self.out_fifo.r_data)
216+
m.d.comb += self.i_stream.ready.eq(1)
217+
with m.If(self.i_stream.valid):
218+
m.d.sync += l_control.eq(self.i_stream.payload)
209219
m.next = "Control: Read data"
210220

211221
with m.State("Control: Read data"):
@@ -216,9 +226,9 @@ def elaborate(self, platform):
216226
m.next = "Control: Parse"
217227
with m.Else():
218228
m.d.sync += self.status.eq(GPIBStatus.Control)
219-
m.d.comb += self.out_fifo.r_en.eq(1)
220-
with m.If(self.out_fifo.r_rdy):
221-
m.d.sync += l_data.eq(self.out_fifo.r_data)
229+
m.d.comb += self.i_stream.ready.eq(1)
230+
with m.If(self.i_stream.valid):
231+
m.d.sync += l_data.eq(self.i_stream.payload)
222232
m.next = "Control: Parse"
223233

224234
with m.State("Control: Parse"):
@@ -248,10 +258,10 @@ def elaborate(self, platform):
248258
# resistor configuration from changing
249259
# mid-transaction.
250260
m.d.comb += [
251-
self.in_fifo.w_en.eq(1),
252-
self.in_fifo.w_data.eq(GPIBMessage._Acknowledge),
261+
self.o_stream.valid.eq(1),
262+
self.o_stream.payload.eq(GPIBMessage._Acknowledge),
253263
]
254-
with m.If(self.in_fifo.w_rdy):
264+
with m.If(self.o_stream.ready):
255265
m.next = "Control: Begin"
256266

257267
with m.State("Talk: Begin"):
@@ -297,18 +307,18 @@ def elaborate(self, platform):
297307

298308
with m.State("Listen: Management lines"):
299309
m.d.comb += [
300-
self.in_fifo.w_en.eq(1),
301-
self.in_fifo.w_data.eq(Cat(1, self.eoi_i))
310+
self.o_stream.valid.eq(1),
311+
self.o_stream.payload.eq(Cat(1, self.eoi_i)),
302312
]
303-
with m.If(self.in_fifo.w_rdy):
313+
with m.If(self.o_stream.ready):
304314
m.next = "Listen: DIO lines"
305315

306316
with m.State("Listen: DIO lines"):
307317
m.d.comb += [
308-
self.in_fifo.w_en.eq(1),
309-
self.in_fifo.w_data.eq(self.dio_i),
318+
self.o_stream.valid.eq(1),
319+
self.o_stream.payload.eq(self.dio_i),
310320
]
311-
with m.If(self.in_fifo.w_rdy):
321+
with m.If(self.o_stream.ready):
312322
m.d.sync += self.nrfd_o.eq(0)
313323
m.next = "Listen: DAV unassert"
314324

@@ -321,35 +331,59 @@ def elaborate(self, platform):
321331

322332

323333
class GPIBControllerInterface:
324-
def __init__(self, interface, logger, port_spec, listen_pull_high, talk_pull_high):
325-
self.interface = interface
334+
def __init__(self, logger, assembly, *, dio, eoi, dav, nrfd, ndac, srq, ifc, atn, ren):
326335
self.logger = logger
336+
self.assembly = assembly
337+
338+
# These are used for pull ups, so we need them later.
339+
self._dio = dio
340+
self._eoi = eoi
341+
self._dav = dav
342+
self._nrfd = nrfd
343+
self._ndac = ndac
344+
self._srq = srq
345+
346+
ports = assembly.add_port_group(dio=dio, eoi=eoi, dav=dav, nrfd=nrfd,
347+
ndac=ndac, srq=srq, ifc=ifc, atn=atn, ren=ren)
348+
component = assembly.add_submodule(GPIBComponent(ports))
349+
self._pipe = assembly.add_inout_pipe(component.o_stream, component.i_stream)
350+
351+
self._sys_clk_period = assembly.sys_clk_period
327352

328-
self.port_spec = port_spec
329-
self.listen_pull_high = listen_pull_high
330-
self.talk_pull_high = talk_pull_high
331353

332354
async def write(self, message: GPIBMessage, data=bytes([0])):
333-
await self.interface.device.set_pulls(self.port_spec, high={pin.number for pin in self.talk_pull_high})
355+
self.assembly.use_pulls({
356+
self._dio: "high",
357+
self._eoi: "high",
358+
self._dav: "high",
359+
360+
})
361+
await self.assembly.configure_ports()
334362

335363
for b in data:
336-
await self.interface.write(bytes([message.value]))
337-
await self.interface.write(bytes([b]))
338-
ack = (await self.interface.read(1))[0]
364+
await self._pipe.send(bytes([message.value]))
365+
await self._pipe.send(bytes([b]))
366+
ack = (await self._pipe.recv(1))[0]
339367
assert GPIBMessage(ack) == GPIBMessage._Acknowledge
340368

341369
async def read(self, *, to_eoi=True):
342-
await self.interface.device.set_pulls(self.port_spec, high={pin.number for pin in self.listen_pull_high})
370+
self.assembly.use_pulls({
371+
372+
self._nrfd: "high",
373+
self._ndac: "high",
374+
self._srq: "high",
375+
})
376+
await self.assembly.configure_ports()
343377

344378
eoi = False
345379
while not eoi:
346-
await self.interface.write(bytes([GPIBMessage.Listen.value]))
380+
await self._pipe.send(bytes([GPIBMessage.Listen.value]))
347381

348-
eoi = bool((await self.interface.read(1))[0] & 2)
382+
eoi = bool((await self._pipe.recv(1))[0] & 2)
349383
if not to_eoi:
350384
eoi = True
351385

352-
yield (await self.interface.read(1))
386+
yield (await self.interface.recv(1))
353387

354388
async def send_to(self, address, data):
355389
await self.cmd_talk(address)
@@ -360,13 +394,13 @@ async def send_to(self, address, data):
360394
async def read_from(self, address, *, to_eoi=True):
361395
await self.cmd_listen(address)
362396
all = bytes([])
363-
async for data in self.read(to_eoi=to_eoi):
397+
async for data in self.recv(to_eoi=to_eoi):
364398
all += data
365399
return all
366400

367401
async def iter_from(self, address, *, to_eoi=True):
368402
await self.cmd_listen(address)
369-
async for data in self.read(to_eoi=to_eoi):
403+
async for data in self.recv(to_eoi=to_eoi):
370404
yield data
371405

372406
async def cmd_talk(self, address):
@@ -400,7 +434,7 @@ async def ifc(self):
400434
await self.write(GPIBMessage.InterfaceClear)
401435

402436

403-
class GPIBControllerApplet(GlasgowApplet):
437+
class GPIBControllerApplet(GlasgowAppletV2):
404438
logger = logging.getLogger(__name__)
405439
help = "talk to a gpib device"
406440
description = """
@@ -412,56 +446,29 @@ class GPIBControllerApplet(GlasgowApplet):
412446
def add_build_arguments(cls, parser, access):
413447
super().add_build_arguments(parser, access)
414448

415-
access.add_pin_set_argument(parser, "dio", width=range(0, 8), default=(0,1,2,3,15,14,13,12))
416-
access.add_pin_argument(parser, "eoi", default=4)
417-
access.add_pin_argument(parser, "dav", default=5)
418-
access.add_pin_argument(parser, "nrfd", default=6)
419-
access.add_pin_argument(parser, "ndac", default=7)
420-
access.add_pin_argument(parser, "srq", default=9)
421-
access.add_pin_argument(parser, "ifc", default=10)
422-
access.add_pin_argument(parser, "atn", default=8)
423-
access.add_pin_argument(parser, "ren", default=11)
424-
425-
def build(self, target, args):
426-
status, self.__addr_status = target.registers.add_ro(8)
427-
428-
self.mux_interface = iface = target.multiplexer.claim_interface(self, args)
429-
subtarget = iface.add_subtarget(GPIBSubtarget(
430-
ports=iface.get_port_group(
431-
dio = args.pin_set_dio,
432-
eoi = args.pin_eoi,
433-
dav = args.pin_dav,
434-
nrfd = args.pin_nrfd,
435-
ndac = args.pin_ndac,
436-
srq = args.pin_srq,
437-
ifc = args.pin_ifc,
438-
atn = args.pin_atn,
439-
ren = args.pin_ren,
440-
),
441-
in_fifo=iface.get_in_fifo(),
442-
out_fifo=iface.get_out_fifo(),
443-
status=status
444-
))
445-
446-
self._sample_freq = target.sys_clk_freq
449+
access.add_pins_argument(parser, "dio", width=8, default="A0,A1,A2,A3,B7,B6,B5,B4")
450+
access.add_pins_argument(parser, "eoi", default="A4")
451+
access.add_pins_argument(parser, "dav", default="A5")
452+
access.add_pins_argument(parser, "nrfd", default="A6")
453+
access.add_pins_argument(parser, "ndac", default="A7")
454+
access.add_pins_argument(parser, "srq", default="B1")
455+
access.add_pins_argument(parser, "ifc", default="B2")
456+
access.add_pins_argument(parser, "atn", default="B0")
457+
access.add_pins_argument(parser, "ren", default="B3")
458+
459+
def build(self, args):
460+
with self.assembly.add_applet(self):
461+
self.assembly.use_voltage(args.voltage)
462+
self.gpib_iface = GPIBControllerInterface(self.logger, self.assembly,
463+
dio=args.dio, eoi=args.eoi, dav=args.dav, nrfd=args.nrfd, ndac=args.ndac,
464+
srq=args.srq, ifc=args.ifc, atn=args.atn, ren=args.ren)
447465

448466
@classmethod
449-
def add_run_arguments(cls, parser, access):
450-
super().add_run_arguments(parser, access)
451-
452-
async def run(self, device, args):
453-
iface = await device.demultiplexer.claim_interface(self, self.mux_interface, args)
454-
gpib_interface = GPIBControllerInterface(
455-
interface=iface,
456-
logger=self.logger,
457-
port_spec=args.port_spec,
458-
listen_pull_high={*args.pin_set_dio, args.pin_eoi, args.pin_dav},
459-
talk_pull_high={args.pin_nrfd, args.pin_ndac, args.pin_srq}
460-
)
461-
return gpib_interface
467+
def add_run_arguments(cls, parser):
468+
super().add_run_arguments(parser)
462469

463470
@classmethod
464-
def add_interact_arguments(cls, parser):
471+
def add_setup_arguments(cls, parser):
465472
def check_address(value):
466473
address = int(value)
467474
if address < 0 or address > 30:
@@ -478,12 +485,12 @@ def check_address(value):
478485
"--read-eoi", action="store_true",
479486
help="read until EOI, omit if no response expected")
480487

481-
async def interact(self, device, args, iface):
488+
async def run(self, args):
482489
if args.command:
483-
await iface.send_to(args.address, args.command.encode("ascii"))
490+
await self.gpib_iface.send_to(args.address, args.command.encode("ascii"))
484491

485492
if args.read_eoi:
486-
async for data in iface.iter_from(args.address, to_eoi=True):
493+
async for data in self.gpib_iface.iter_from(args.address, to_eoi=True):
487494
sys.stdout.buffer.write(data)
488495
sys.stdout.buffer.flush()
489496

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,42 @@
1+
import logging
2+
13
from amaranth import *
24

35
from ... import *
4-
from . import GPIBControllerApplet
56

6-
class GPIBControllerAppletTestCase(GlasgowAppletTestCase, applet=GPIBControllerApplet):
7+
from glasgow.simulation.assembly import SimulationAssembly
8+
from glasgow.gateware.ports import PortGroup
9+
from . import GPIBControllerApplet, GPIBControllerInterface
10+
11+
logger = logging.getLogger(__name__)
12+
13+
class GPIBControllerAppletTestCase(GlasgowAppletV2TestCase, applet=GPIBControllerApplet):
714
@synthesis_test
815
def test_build(self):
916
self.assertBuilds()
17+
18+
def test_two_can_talk(self):
19+
assembly = SimulationAssembly()
20+
iface0 = GPIBControllerInterface(logger, assembly,
21+
dio="A0:7", eoi="B0", dav="B1", nrfd="B2", ndac="B3", srq="B4", ifc="B5", atn="B6", ren="B7")
22+
23+
iface1 = GPIBControllerInterface(logger, assembly,
24+
dio="A0:7", eoi="B0", dav="B1", nrfd="B2", ndac="B3", srq="B4", ifc="B5", atn="B6", ren="B7")
25+
26+
27+
# assembly.add_testbench(self.testbench_thing())
28+
29+
async def do_it(ctx):
30+
x = iface1.read_from(10)
31+
await iface0.send_to(10, b'*IDN?')
32+
print(await x)
33+
# await iface0.capture()
34+
35+
assembly.run(do_it, vcd_file="test.vcd")
36+
37+
38+
# def __init__(self, logger, assembly, *, dio, eoi, dav, nrfd, ndac, srq, ifc, atn, ren):
39+
# pg_one = PortGroup()
40+
# pg_one.dio = assemb
41+
42+
# one = GPIBControllerInterface(logger, assembly, cs="A0", sck="A1", copi="A2", cipo="A3")

0 commit comments

Comments
 (0)