af27add3b45805e18d7d9950778790eff246f643
3 from enum
import Enum
, auto
5 from nmigen
import (Elaboratable
, Signal
, Module
, ClockDomain
, Cat
, Record
,
7 from nmigen
.hdl
.rec
import Direction
, Layout
8 from nmigen
.tracer
import get_var_name
10 from nmigen_soc
.wishbone
import Interface
as WishboneInterface
12 from .bus
import Interface
, DMIInterface
15 "TAP", "ShiftReg", "IOType", "IOConn",
19 class _FSM(Elaboratable
):
20 """TAP subblock for the FSM"""
21 def __init__(self
, *, bus
):
24 self
.capture
= Signal()
26 self
.update
= Signal()
28 self
.posjtag
= ClockDomain("posjtag", local
=True)
29 self
.negjtag
= ClockDomain("negjtag", local
=True, clk_edge
="neg")
33 def elaborate(self
, platform
):
38 self
.posjtag
.clk
.eq(self
._bus
.tck
),
39 self
.posjtag
.rst
.eq(rst
),
40 self
.negjtag
.clk
.eq(self
._bus
.tck
),
41 self
.negjtag
.rst
.eq(rst
),
44 # Make local clock domain optionally using trst of JTAG bus as reset
45 if hasattr(self
._bus
, "trst"):
46 m
.domains
.local
= local
= ClockDomain(local
=True)
47 m
.d
.comb
+= local
.rst
.eq(self
._bus
.trst
)
49 m
.domains
.local
= local
= ClockDomain(local
=True, reset_less
=True)
50 m
.d
.comb
+= local
.clk
.eq(self
._bus
.tck
)
52 with m
.FSM(domain
="local") as fsm
:
53 with m
.State("TestLogicReset"):
54 # Be sure to reset isir, isdr
59 with m
.If(self
._bus
.tms
== 0):
60 m
.next
= "RunTestIdle"
61 with m
.State("RunTestIdle"):
62 # Be sure to reset isir, isdr
67 with m
.If(self
._bus
.tms
== 1):
68 m
.next
= "SelectDRScan"
69 with m
.State("SelectDRScan"):
70 with m
.If(self
._bus
.tms
== 0):
71 m
.d
.local
+= self
.isdr
.eq(1)
72 m
.next
= "CaptureState"
74 m
.next
= "SelectIRScan"
75 with m
.State("SelectIRScan"):
76 with m
.If(self
._bus
.tms
== 0):
77 m
.d
.local
+= self
.isir
.eq(1)
78 m
.next
= "CaptureState"
80 m
.next
= "TestLogicReset"
81 with m
.State("CaptureState"):
82 with m
.If(self
._bus
.tms
== 0):
86 with m
.State("ShiftState"):
87 with m
.If(self
._bus
.tms
== 1):
89 with m
.State("Exit1"):
90 with m
.If(self
._bus
.tms
== 0):
93 m
.next
= "UpdateState"
94 with m
.State("Pause"):
95 with m
.If(self
._bus
.tms
== 1):
97 with m
.State("Exit2"):
98 with m
.If(self
._bus
.tms
== 0):
101 m
.next
= "UpdateState"
102 with m
.State("UpdateState"):
107 with m
.If(self
._bus
.tms
== 0):
108 m
.next
= "RunTestIdle"
110 m
.next
= "SelectDRScan"
113 rst
.eq(fsm
.ongoing("TestLogicReset")),
114 self
.capture
.eq(fsm
.ongoing("CaptureState")),
115 self
.shift
.eq(fsm
.ongoing("ShiftState")),
116 self
.update
.eq(fsm
.ongoing("UpdateState")),
121 class _IRBlock(Elaboratable
):
122 """TAP subblock for handling the IR shift register"""
123 def __init__(self
, *, ir_width
, cmd_idcode
,
124 tdi
, capture
, shift
, update
,
127 self
.ir
= Signal(ir_width
, reset
=cmd_idcode
)
131 self
._capture
= capture
133 self
._update
= update
135 def elaborate(self
, platform
):
138 shift_ir
= Signal(len(self
.ir
), reset_less
=True)
140 m
.d
.comb
+= self
.tdo
.eq(self
.ir
[0])
141 with m
.If(self
._capture
):
142 m
.d
.posjtag
+= shift_ir
.eq(self
.ir
)
143 with m
.Elif(self
._shift
):
144 m
.d
.posjtag
+= shift_ir
.eq(Cat(shift_ir
[1:], self
._tdi
))
145 with m
.Elif(self
._update
):
146 # For ir we only update it on the rising edge of clock
147 # to avoid that we already have the new ir value when still in
149 m
.d
.posjtag
+= self
.ir
.eq(shift_ir
)
159 class IOConn(Record
):
167 """TAP subblock representing the interface for an JTAG IO cell.
168 It contains signal to connect to the core and to the pad
170 This object is normally only allocated and returned from ``TAP.add_io``
171 It is a Record subclass.
175 core: subrecord with signals for the core
176 i: Signal(1), present only for IOType.In and IOType.InTriOut.
177 Signal input to core with pad input value.
178 o: Signal(1), present only for IOType.Out, IOType.TriOut and
180 Signal output from core with the pad output value.
181 oe: Signal(1), present only for IOType.TriOut and IOType.InTriOut.
182 Signal output from core with the pad output enable value.
183 pad: subrecord with for the pad
184 i: Signal(1), present only for IOType.In and IOType.InTriOut
185 Output from pad with pad input value for core.
186 o: Signal(1), present only for IOType.Out, IOType.TriOut and
188 Input to pad with pad output value.
189 oe: Signal(1), present only for IOType.TriOut and IOType.InTriOut.
190 Input to pad with pad output enable value.
195 if iotype
in (IOType
.In
, IOType
.InTriOut
):
196 sigs
.append(("i", 1))
197 if iotype
in (IOType
.Out
, IOType
.TriOut
, IOType
.InTriOut
):
198 sigs
.append(("o", 1))
199 if iotype
in (IOType
.TriOut
, IOType
.InTriOut
):
200 sigs
.append(("oe", 1))
202 return Layout((("core", sigs
), ("pad", sigs
)))
204 def __init__(self
, *, iotype
, name
=None, src_loc_at
=0):
205 super().__init
__(self
.__class
__.layout(iotype
), name
=name
,
206 src_loc_at
=src_loc_at
+1)
208 self
._iotype
= iotype
210 class _IDBypassBlock(Elaboratable
):
211 """TAP subblock for the ID shift register"""
212 def __init__(self
, *, manufacturer_id
, part_number
, version
,
213 tdi
, capture
, shift
, update
, bypass
,
216 if (not isinstance(manufacturer_id
, Const
) and
217 len(manufacturer_id
) != 11):
218 raise ValueError("manufacturer_id has to be Const of length 11")
219 if not isinstance(part_number
, Const
) and len(manufacturer_id
) != 16:
220 raise ValueError("part_number has to be Const of length 16")
221 if not isinstance(version
, Const
) and len(version
) != 4:
222 raise ValueError("version has to be Const of length 4")
223 self
._id
= Cat(Const(1,1), manufacturer_id
, part_number
, version
)
225 self
.tdo
= Signal(name
=name
+"_tdo")
228 self
._capture
= capture
230 self
._update
= update
231 self
._bypass
= bypass
233 def elaborate(self
, platform
):
236 sr
= Signal(32, reset_less
=True, name
=self
.name
+"_sr")
238 # Local signals for the module
247 _capture
.eq(self
._capture
),
248 _shift
.eq(self
._shift
),
249 _update
.eq(self
._update
),
250 _bypass
.eq(self
._bypass
),
255 m
.d
.posjtag
+= sr
.eq(self
._id
)
258 m
.d
.posjtag
+= sr
[0].eq(_tdi
)
260 m
.d
.posjtag
+= sr
.eq(Cat(sr
[1:], _tdi
))
265 class ShiftReg(Record
):
266 """Object with interface for extra shift registers on a TAP.
271 cmds : int, default=1
272 The number of corresponding JTAG instructions
274 This object is normally only allocated and returned from ``TAP.add_shiftreg``
275 It is a Record subclass.
279 i: length=sr_length, FANIN
280 The input data sampled during capture state of the TAP
281 ie: length=cmds, FANOUT
282 Indicates that data is to be sampled by the JTAG TAP and
283 should be held stable. The bit indicates the corresponding
284 instruction for which data is asked.
285 This signal is kept high for a whole JTAG TAP clock cycle
286 and may thus be kept higher for more than one clock cycle
287 on the domain where ShiftReg is used.
288 The JTAG protocol does not allow insertion of wait states
289 so data need to be provided before ie goes down. The speed
290 of the response will determine the max. frequency for the
292 o: length=sr_length, FANOUT
293 The value of the shift register.
294 oe: length=cmds, FANOUT
295 Indicates that output is stable and can be sampled downstream because
296 JTAG TAP is in the Update state. The bit indicates the corresponding
297 instruction. The bit is only kept high for one clock cycle.
299 def __init__(self
, *, sr_length
, cmds
=1, name
=None, src_loc_at
=0):
301 ("i", sr_length
, Direction
.FANIN
),
302 ("ie", cmds
, Direction
.FANOUT
),
303 ("o", sr_length
, Direction
.FANOUT
),
304 ("oe", cmds
, Direction
.FANOUT
),
306 super().__init
__(layout
, name
=name
, src_loc_at
=src_loc_at
+1)
308 class TAP(Elaboratable
):
310 def __init__(self
, *, with_reset
=False, ir_width
=None,
311 manufacturer_id
=Const(0b10001111111, 11),
312 part_number
=Const(1, 16),
314 name
=None, src_loc_at
=0):
315 assert((ir_width
is None) or (isinstance(ir_width
, int) and
317 assert(len(version
) == 4)
320 name
= get_var_name(depth
=src_loc_at
+2, default
="TAP")
322 self
.bus
= Interface(with_reset
=with_reset
, name
=self
.name
+"_bus",
323 src_loc_at
=src_loc_at
+1)
327 self
._ir
_width
= ir_width
328 self
._manufacturer
_id
= manufacturer_id
329 self
._part
_number
= part_number
330 self
._version
= version
332 self
._ircodes
= [0, 1, 2] # Already taken codes, all ones added at end
339 def elaborate(self
, platform
):
342 # Determine ir_width if not fixed.
343 ir_max
= max(self
._ircodes
) + 1 # One extra code needed with all ones
344 ir_width
= len("{:b}".format(ir_max
))
345 if self
._ir
_width
is not None:
346 assert self
._ir
_width
>= ir_width
, "Specified JTAG IR width " \
347 "not big enough for allocated shiift registers"
348 ir_width
= self
._ir
_width
350 # TODO: Make commands numbers configurable
356 cmd_bypass
= 2**ir_width
- 1 # All ones
358 m
.submodules
._fsm
= fsm
= _FSM(bus
=self
.bus
)
359 m
.domains
.posjtag
= fsm
.posjtag
360 m
.domains
.negjtag
= fsm
.negjtag
364 m
.submodules
._irblock
= irblock
= _IRBlock(
365 ir_width
=ir_width
, cmd_idcode
=cmd_idcode
, tdi
=self
.bus
.tdi
,
366 capture
=(fsm
.isir
& fsm
.capture
),
367 shift
=(fsm
.isir
& fsm
.shift
),
368 update
=(fsm
.isir
& fsm
.update
),
369 name
=self
.name
+"_ir",
374 select_id
= fsm
.isdr
& ((ir
== cmd_idcode
) |
(ir
== cmd_bypass
))
375 m
.submodules
._idblock
= idblock
= _IDBypassBlock(
376 manufacturer_id
=self
._manufacturer
_id
,
377 part_number
=self
._part
_number
,
378 version
=self
._version
, tdi
=self
.bus
.tdi
,
379 capture
=(select_id
& fsm
.capture
),
380 shift
=(select_id
& fsm
.shift
),
381 update
=(select_id
& fsm
.update
),
382 bypass
=(ir
== cmd_bypass
),
383 name
=self
.name
+"_id",
386 # IO (Boundary scan) block
387 io_capture
= Signal()
391 io_bd2core
= Signal()
392 sample
= (ir
== cmd_extest
) |
(ir
== cmd_sample
)
393 preload
= (ir
== cmd_preload
)
394 select_io
= fsm
.isdr
& (sample | preload
)
396 io_capture
.eq(sample
& fsm
.capture
), # Don't capture if not sample
398 io_shift
.eq(select_io
& fsm
.shift
),
399 io_update
.eq(select_io
& fsm
.update
),
400 io_bd2io
.eq(ir
== cmd_extest
),
401 io_bd2core
.eq(ir
== cmd_intest
),
403 io_tdo
= self
._elaborate
_ios
(
405 capture
=io_capture
, shift
=io_shift
, update
=io_update
,
406 bd2io
=io_bd2io
, bd2core
=io_bd2core
,
409 # chain tdo: select as appropriate, to go into into shiftregs
410 tdo
= Signal(name
=self
.name
+"_tdo")
411 with m
.If(select_ir
):
412 m
.d
.comb
+= tdo
.eq(irblock
.tdo
)
413 with m
.Elif(select_id
):
414 m
.d
.comb
+= tdo
.eq(idblock
.tdo
)
415 if io_tdo
is not None:
416 with m
.Elif(select_io
):
417 m
.d
.comb
+= tdo
.eq(io_tdo
)
420 self
._elaborate
_shiftregs
(
421 m
, capture
=fsm
.capture
, shift
=fsm
.shift
, update
=fsm
.update
,
422 ir
=irblock
.ir
, tdo_jtag
=tdo
426 self
._elaborate
_wishbones
(m
)
428 # DMI (Debug Memory Interface)
429 self
._elaborate
_dmis
(m
)
433 def add_dmi(self
, *, ircodes
, address_width
=8, data_width
=64,
434 domain
="sync", name
=None):
435 """Add a DMI interface
437 * writing to DMIADDR will automatically trigger a DMI READ.
438 the DMI address does not alter (so writes can be done at that addr)
439 * reading from DMIREAD triggers a DMI READ at the current DMI addr
440 the address is automatically incremented by 1 after.
441 * writing to DMIWRITE triggers a DMI WRITE at the current DMI addr
442 the address is automatically incremented by 1 after.
446 ircodes: sequence of three integer for the JTAG IR codes;
447 they represent resp. DMIADDR, DMIREAD and DMIWRITE.
448 First code has a shift register of length 'address_width',
449 the two other codes share a shift register of length
452 address_width: width of the address
453 data_width: width of the data
456 dmi: soc.debug.dmi.DMIInterface
459 if len(ircodes
) != 3:
460 raise ValueError("3 IR Codes have to be provided")
463 name
= "dmi" + str(len(self
._dmis
))
465 # add 2 shift registers: one for addr, one for data.
466 sr_addr
= self
.add_shiftreg(ircode
=ircodes
[0], length
=address_width
,
467 domain
=domain
, name
=name
+"_addrsr")
468 sr_data
= self
.add_shiftreg(ircode
=ircodes
[1:], length
=data_width
,
469 domain
=domain
, name
=name
+"_datasr")
471 dmi
= DMIInterface(name
=name
)
472 self
._dmis
.append((sr_addr
, sr_data
, dmi
, domain
))
476 def _elaborate_dmis(self
, m
):
477 for sr_addr
, sr_data
, dmi
, domain
in self
._dmis
:
479 m
.d
.comb
+= sr_addr
.i
.eq(dmi
.addr_i
)
481 with m
.FSM(domain
=domain
) as ds
:
483 # detect mode based on whether jtag addr or data read/written
484 with m
.State("IDLE"):
485 with m
.If(sr_addr
.oe
): # DMIADDR code
486 cd
+= dmi
.addr_i
.eq(sr_addr
.o
)
488 with m
.Elif(sr_data
.oe
[0]): # DMIREAD code
490 cd
+= dmi
.addr_i
.eq(dmi
.addr_i
+ 1)
492 with m
.Elif(sr_data
.oe
[1]): # DMIWRITE code
493 cd
+= dmi
.din
.eq(sr_data
.o
)
496 # req_i raises for 1 clock
497 with m
.State("READ"):
501 with m
.State("READACK"):
502 with m
.If(dmi
.ack_o
):
503 # Store read data in sr_data.i hold till next read
504 cd
+= sr_data
.i
.eq(dmi
.dout
)
507 # req_i raises for 1 clock
508 with m
.State("WRRD"):
512 with m
.State("WRRDACK"):
513 with m
.If(dmi
.ack_o
):
514 cd
+= dmi
.addr_i
.eq(dmi
.addr_i
+ 1)
515 m
.next
= "READ" # for readwrite
517 # set DMI req and write-enable based on ongoing FSM states
519 dmi
.req_i
.eq(ds
.ongoing("READ") | ds
.ongoing("WRRD")),
520 dmi
.we_i
.eq(ds
.ongoing("WRRD")),
523 def add_io(self
, *, iotype
, name
=None, src_loc_at
=0):
524 """Add a io cell to the boundary scan chain
527 - iotype: :class:`IOType` enum.
533 name
= "ioconn" + str(len(self
._ios
))
535 ioconn
= IOConn(iotype
=iotype
, name
=name
, src_loc_at
=src_loc_at
+1)
536 self
._ios
.append(ioconn
)
539 def _elaborate_ios(self
, *, m
, capture
, shift
, update
, bd2io
, bd2core
):
540 length
= sum(IOConn
.lengths
[conn
._iotype
] for conn
in self
._ios
)
542 io_sr
= Signal(length
)
543 io_bd
= Signal(length
)
545 # Boundary scan "capture" mode. makes I/O status available via SR
549 for conn
in self
._ios
:
550 # in appropriate sequence: In/TriOut has pad.i,
551 # Out.InTriOut has everything, Out and TriOut have core.o
552 if conn
._iotype
in [IOType
.In
, IOType
.InTriOut
]:
553 iol
.append(conn
.pad
.i
)
554 if conn
._iotype
in [IOType
.Out
, IOType
.InTriOut
]:
555 iol
.append(conn
.core
.o
)
556 if conn
._iotype
in [IOType
.TriOut
, IOType
.InTriOut
]:
557 iol
.append(conn
.core
.oe
)
558 # length double-check
559 idx
+= IOConn
.lengths
[conn
._iotype
] # fails if wrong type
560 assert idx
== length
, "Internal error"
561 m
.d
.posjtag
+= io_sr
.eq(Cat(*iol
)) # assigns all io_sr in one hit
563 # "Shift" mode (sends out captured data on tdo, sets incoming from tdi)
565 m
.d
.posjtag
+= io_sr
.eq(Cat(self
.bus
.tdi
, io_sr
[:-1]))
569 m
.d
.negjtag
+= io_bd
.eq(io_sr
)
571 # sets up IO (pad<->core) or in testing mode depending on requested
572 # mode, via Muxes controlled by bd2core and bd2io
574 for conn
in self
._ios
:
575 if conn
._iotype
== IOType
.In
:
576 m
.d
.comb
+= conn
.core
.i
.eq(Mux(bd2core
, io_bd
[idx
], conn
.pad
.i
))
578 elif conn
._iotype
== IOType
.Out
:
579 m
.d
.comb
+= conn
.pad
.o
.eq(Mux(bd2io
, io_bd
[idx
], conn
.core
.o
))
581 elif conn
._iotype
== IOType
.TriOut
:
583 conn
.pad
.o
.eq(Mux(bd2io
, io_bd
[idx
], conn
.core
.o
)),
584 conn
.pad
.oe
.eq(Mux(bd2io
, io_bd
[idx
+1], conn
.core
.oe
)),
587 elif conn
._iotype
== IOType
.InTriOut
:
589 conn
.core
.i
.eq(Mux(bd2core
, io_bd
[idx
], conn
.pad
.i
)),
590 conn
.pad
.o
.eq(Mux(bd2io
, io_bd
[idx
+1], conn
.core
.o
)),
591 conn
.pad
.oe
.eq(Mux(bd2io
, io_bd
[idx
+2], conn
.core
.oe
)),
595 raise("Internal error")
596 assert idx
== length
, "Internal error"
601 def add_shiftreg(self
, *, ircode
, length
, domain
="sync", name
=None,
603 """Add a shift register to the JTAG interface
606 - ircode: code(s) for the IR; int or sequence of ints. In the latter
607 case this shiftreg is shared between different IR codes.
608 - length: the length of the shift register
609 - domain: the domain on which the signal will be used"""
615 ir_it
= ircodes
= (ircode
,)
616 for _ircode
in ir_it
:
617 if not isinstance(_ircode
, int) or _ircode
<= 0:
618 raise ValueError("IR code '{}' is not an int "
619 "greater than 0".format(_ircode
))
620 if _ircode
in self
._ircodes
:
621 raise ValueError("IR code '{}' already taken".format(_ircode
))
623 self
._ircodes
.extend(ircodes
)
626 name
= "sr{}".format(len(self
._srs
))
627 sr
= ShiftReg(sr_length
=length
, cmds
=len(ircodes
), name
=name
,
628 src_loc_at
=src_loc_at
+1)
629 self
._srs
.append((ircodes
, domain
, sr
))
633 def _elaborate_shiftregs(self
, m
, capture
, shift
, update
, ir
, tdo_jtag
):
634 # tdos is tuple of (tdo, tdo_en) for each shiftreg
636 for ircodes
, domain
, sr
in self
._srs
:
637 reg
= Signal(len(sr
.o
), name
=sr
.name
+"_reg")
638 m
.d
.comb
+= sr
.o
.eq(reg
)
640 isir
= Signal(len(ircodes
), name
=sr
.name
+"_isir")
641 sr_capture
= Signal(name
=sr
.name
+"_capture")
642 sr_shift
= Signal(name
=sr
.name
+"_shift")
643 sr_update
= Signal(name
=sr
.name
+"_update")
645 isir
.eq(Cat(ir
== ircode
for ircode
in ircodes
)),
646 sr_capture
.eq((isir
!= 0) & capture
),
647 sr_shift
.eq((isir
!= 0) & shift
),
648 sr_update
.eq((isir
!= 0) & update
),
651 # update signal is on the JTAG clockdomain, sr.oe is on `domain`
652 # clockdomain latch update in `domain` clockdomain and see when
653 # it has falling edge.
654 # At that edge put isir in sr.oe for one `domain` clockdomain
655 update_core
= Signal(name
=sr
.name
+"_update_core")
656 update_core_prev
= Signal(name
=sr
.name
+"_update_core_prev")
658 update_core
.eq(sr_update
), # This is CDC from JTAG domain
660 update_core_prev
.eq(update_core
)
662 with m
.If(update_core_prev
& ~update_core
):
663 # Falling edge of update
664 m
.d
[domain
] += sr
.oe
.eq(isir
)
666 m
.d
[domain
] += sr
.oe
.eq(0)
669 m
.d
.posjtag
+= reg
.eq(Cat(reg
[1:], self
.bus
.tdi
))
670 with m
.If(sr_capture
):
671 m
.d
.posjtag
+= reg
.eq(sr
.i
)
673 # tdo = reg[0], tdo_en = shift
674 tdos
.append((reg
[0], sr_shift
))
677 # Assign the right tdo to the bus tdo
678 for i
, (tdo
, tdo_en
) in enumerate(tdos
):
681 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo
)
684 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo
)
688 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo_jtag
)
690 # Always connect tdo_jtag to
691 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo_jtag
)
694 def add_wishbone(self
, *, ircodes
, address_width
, data_width
,
695 granularity
=None, domain
="sync", features
=None,
696 name
=None, src_loc_at
=0):
697 """Add a wishbone interface
699 In order to allow high JTAG clock speed, data will be cached.
700 This means that if data is output the value of the next address
701 will be read automatically.
705 ircodes: sequence of three integer for the JTAG IR codes;
706 they represent resp. WBADDR, WBREAD and WBREADWRITE. First code
707 has a shift register of length 'address_width', the two other codes
708 share a shift register of length data_width.
709 address_width: width of the address
710 data_width: width of the data
711 features: features required. defaults to stall, lock, err, rty
714 wb: nmigen_soc.wishbone.bus.Interface
715 The Wishbone interface, is pipelined and has stall field.
717 if len(ircodes
) != 3:
718 raise ValueError("3 IR Codes have to be provided")
721 features
={"stall", "lock", "err", "rty"}
723 name
= "wb" + str(len(self
._wbs
))
724 sr_addr
= self
.add_shiftreg(
725 ircode
=ircodes
[0], length
=address_width
, domain
=domain
,
728 sr_data
= self
.add_shiftreg(
729 ircode
=ircodes
[1:], length
=data_width
, domain
=domain
,
733 wb
= WishboneInterface(data_width
=data_width
, addr_width
=address_width
,
734 granularity
=granularity
, features
=features
,
735 name
=name
, src_loc_at
=src_loc_at
+1)
737 self
._wbs
.append((sr_addr
, sr_data
, wb
, domain
))
741 def _elaborate_wishbones(self
, m
):
742 for sr_addr
, sr_data
, wb
, domain
in self
._wbs
:
743 m
.d
.comb
+= sr_addr
.i
.eq(wb
.adr
)
745 if hasattr(wb
, "sel"):
747 m
.d
.comb
+= [s
.eq(1) for s
in wb
.sel
]
749 with m
.FSM(domain
=domain
) as fsm
:
750 with m
.State("IDLE"):
751 with m
.If(sr_addr
.oe
): # WBADDR code
752 m
.d
[domain
] += wb
.adr
.eq(sr_addr
.o
)
754 with m
.Elif(sr_data
.oe
[0]): # WBREAD code
756 m
.d
[domain
] += wb
.adr
.eq(wb
.adr
+ 1)
758 with m
.Elif(sr_data
.oe
[1]): # WBWRITE code
759 m
.d
[domain
] += wb
.dat_w
.eq(sr_data
.o
)
761 with m
.State("READ"):
762 if not hasattr(wb
, "stall"):
765 with m
.If(~wb
.stall
):
767 with m
.State("READACK"):
769 # Store read data in sr_data.i
770 # and keep it there til next read
771 m
.d
[domain
] += sr_data
.i
.eq(wb
.dat_r
)
773 with m
.State("WRITEREAD"):
774 if not hasattr(wb
, "stall"):
775 m
.next
= "WRITEREADACK"
777 with m
.If(~wb
.stall
):
778 m
.next
= "WRITEREADACK"
779 with m
.State("WRITEREADACK"):
781 m
.d
[domain
] += wb
.adr
.eq(wb
.adr
+ 1)
785 wb
.cyc
.eq(~fsm
.ongoing("IDLE")),
786 wb
.stb
.eq(fsm
.ongoing("READ") | fsm
.ongoing("WRITEREAD")),
787 wb
.we
.eq(fsm
.ongoing("WRITEREAD")),