Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: GlasgowEmbedded/glasgow
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6a54b6e339e1
Choose a base ref
...
head repository: GlasgowEmbedded/glasgow
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1f04203b8854
Choose a head ref
  • 4 commits
  • 4 files changed
  • 1 contributor

Commits on Oct 15, 2019

  1. applet.debug.mips: restrict Rocc handshaking to EJTAG >2.0.

    BMIPS seems to support it, but Lexra does not, even though both are
    EJTAG 2.0, so disable it on EJTAG 2.0 completely.
    
    Also, print every CONTROL bit, instead of only the overridden one.
    whitequark committed Oct 15, 2019

    Unverified

    This user has not yet uploaded their public signing key.
    Copy the full SHA
    1b830bc View commit details
  2. applet.debug.mips: make sure DMAAcc bit is set before writing ADDRESS.

    On BMIPS ADDRESS is writable if NoDMA=0, on Lexra ADDRESS is only
    writable if DMAAcc=1.
    whitequark committed Oct 15, 2019
    Copy the full SHA
    7d658cd View commit details
  3. Copy the full SHA
    19497ce View commit details
  4. applet.interface.jtag_openocd: new applet.

    Our first nMigen applet!
    whitequark committed Oct 15, 2019
    Copy the full SHA
    1f04203 View commit details
1 change: 1 addition & 0 deletions software/glasgow/applet/all.py
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
from .interface.i2c_master import I2CMasterApplet
from .interface.jtag_pinout import JTAGPinoutApplet
from .interface.jtag_probe import JTAGProbeApplet
from .interface.jtag_openocd import JTAGOpenOCDApplet
from .interface.jtag_svf import JTAGSVFApplet
from .interface.ps2_host import PS2HostApplet
from .interface.sbw_probe import SpyBiWireProbeApplet
23 changes: 14 additions & 9 deletions software/glasgow/applet/debug/mips/__init__.py
Original file line number Diff line number Diff line change
@@ -58,23 +58,24 @@ async def _read_impcode(self):
self._log("read IMPCODE %s", self._impcode.bits_repr())

async def _exchange_control(self, **fields):
field_desc = " ".join("{}={:b}".format(field, value)
for field, value in fields.items())
self._log("write CONTROL %s", field_desc)

control = self._control.copy()
control.Rocc = 1
control.PrAcc = 1
if self._impcode.EJTAGver > 0:
# Some (but not all) EJTAG 1.x/2.0 cores implement Rocc handshaking. We ignore it,
# since there's no easy way to tell which one it is (on some Lexra cores, Rocc appears
# to be R/W, which breaks the handshaking mechanism.)
control.Rocc = 1
for field, value in fields.items():
setattr(control, field, value)

self._log("write CONTROL %s", control.bits_repr(omit_zero=True))
control_bits = control.to_bits()
await self.lower.write_ir(IR_CONTROL)

control_bits = await self.lower.exchange_dr(control_bits)
new_control = DR_CONTROL.from_bits(control_bits)
self._log("read CONTROL %s", new_control.bits_repr(omit_zero=True))

if new_control.Rocc and control.Rocc:
if self._impcode.EJTAGver > 0 and control.Rocc and new_control.Rocc:
raise EJTAGError("target has been unexpectedly reset")

return new_control
@@ -126,6 +127,8 @@ async def _write_data(self, data):

async def _dmaacc_read(self, address, size):
self._log("DMAAcc: read address=%#0.*x size=%d", self._prec, address, size)
# Make sure DMAAcc is set, or ADDRESS DR is not writable.
await self._exchange_control(DMAAcc=1)
await self._write_address(address)
await self._exchange_control(DMAAcc=1, DRWn=1, Dsz=size, DStrt=1)
for _ in range(3):
@@ -141,9 +144,11 @@ async def _dmaacc_read(self, address, size):
await self._exchange_control(DMAAcc=0)
return data

async def _dma_accwrite(self, address, size, data):
async def _dmaacc_write(self, address, size, data):
self._log("DMAAcc: write address=%#0.*x size=%d data=%#0.*x",
self._prec, address, size, self._prec, data)
# Make sure DMAAcc is set, or ADDRESS DR is not writable.
await self._exchange_control(DMAAcc=1)
await self._write_address(address)
await self._write_data(data)
await self._exchange_control(DMAAcc=1, DRWn=0, Dsz=size, DStrt=1)
@@ -210,7 +215,7 @@ async def _probe(self):
# to clear it via DMAAcc because PrAcc requires debug mode to already work.
dcr = await self._dmaacc_read(DRSEG_DCR_addr, 2)
dcr &= ~(1<<2)
await self._dma_accwrite(DRSEG_DCR_addr, 2, dcr)
await self._dmaacc_write(DRSEG_DCR_addr, 2, dcr)

await self._enable_probe()
self._change_state("Running")
145 changes: 145 additions & 0 deletions software/glasgow/applet/interface/jtag_openocd/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import struct
import logging
import asyncio
from nmigen import *

from ....support.bits import *
from ....support.logging import *
from ....support.endpoint import *
from ....gateware.pads import *
from ....database.jedec import *
from ....arch.jtag import *
from ... import *
from ..jtag_probe import JTAGProbeBus


class JTAGOpenOCDSubtarget(Elaboratable):
def __init__(self, pads, out_fifo, in_fifo, period_cyc):
self.pads = pads
self.out_fifo = out_fifo
self.in_fifo = in_fifo
self.period_cyc = period_cyc

def elaborate(self, platform):
m = Module()

out_fifo = self.out_fifo
in_fifo = self.in_fifo

m.submodules.bus = bus = JTAGProbeBus(self.pads)
m.d.comb += [
bus.trst_z.eq(0),
]

blink = Signal()

timer = Signal(range(self.period_cyc))

with m.If(timer != 0):
m.d.sync += timer.eq(timer - 1)
with m.Else():
with m.If(out_fifo.r_rdy):
with m.Switch(out_fifo.r_data):
# remote_bitbang_write(int tck, int tms, int tdi)
with m.Case(*b"01234567"):
m.d.comb += out_fifo.r_en.eq(1)
m.d.sync += Cat(bus.tdi, bus.tms, bus.tck).eq(out_fifo.r_data[:3])
# remote_bitbang_reset(int trst, int srst)
with m.Case(*b"rs"):
m.d.comb += out_fifo.r_en.eq(1)
m.d.sync += Cat(bus.trst_o).eq(0b0)
with m.Case(*b"tu"):
m.d.comb += out_fifo.r_en.eq(1)
m.d.sync += Cat(bus.trst_o).eq(0b1)
# remote_bitbang_sample(void)
with m.Case(*b"R"):
m.d.comb += out_fifo.r_en.eq(in_fifo.w_rdy)
m.d.comb += in_fifo.w_en.eq(1)
m.d.comb += in_fifo.w_data.eq(b"0"[0] | Cat(bus.tdo))
# remote_bitbang_blink(int on)
with m.Case(*b"Bb"):
m.d.comb += out_fifo.r_en.eq(1)
m.d.sync += blink.eq(~out_fifo.r_data[5])
with m.If(out_fifo.r_en):
m.d.sync += timer.eq(self.period_cyc - 1)

return m


class JTAGOpenOCDApplet(GlasgowApplet, name="jtag-openocd"):
logger = logging.getLogger(__name__)
help = "expose JTAG via OpenOCD remote bitbang interface"
description = """
Expose JTAG via a socket using the OpenOCD remote bitbang protocol.
Usage with TCP sockets:
::
glasgow run jtag-openocd tcp:localhost:2222
openocd -c -c 'interface remote_bitbang; remote_bitbang_port 2222'
Usage with Unix domain sockets:
::
glasgow run jtag-openocd unix:/tmp/jtag.sock
openocd -c -c 'interface remote_bitbang; remote_bitbang_host /tmp/jtag.sock'
"""

__pins = ("tck", "tms", "tdi", "tdo", "trst")

@classmethod
def add_build_arguments(cls, parser, access):
super().add_build_arguments(parser, access)

for pin in ("tck", "tms", "tdi", "tdo"):
access.add_pin_argument(parser, pin, default=True)
access.add_pin_argument(parser, "trst")

parser.add_argument(
"-f", "--frequency", metavar="FREQ", type=int, default=100,
help="set TCK frequency to FREQ kHz (default: %(default)s)")

def build(self, target, args):
self.mux_interface = iface = target.multiplexer.claim_interface(self, args)
iface.add_subtarget(JTAGOpenOCDSubtarget(
pads=iface.get_pads(args, pins=self.__pins),
out_fifo=iface.get_out_fifo(),
in_fifo=iface.get_in_fifo(),
period_cyc=int(target.sys_clk_freq // (args.frequency * 1000)),
))

async def run(self, device, args):
return await device.demultiplexer.claim_interface(self, self.mux_interface, args)

@classmethod
def add_interact_arguments(cls, parser):
ServerEndpoint.add_argument(parser, "endpoint")

async def interact(self, device, args, iface):
endpoint = await ServerEndpoint("socket", self.logger, args.endpoint)
async def forward_out():
while True:
try:
data = await endpoint.recv()
await iface.write(data)
await iface.flush()
except asyncio.CancelledError:
pass
async def forward_in():
while True:
try:
data = await iface.read()
await endpoint.send(data)
except asyncio.CancelledError:
pass
forward_out_fut = asyncio.ensure_future(forward_out())
forward_in_fut = asyncio.ensure_future(forward_in())
await asyncio.wait([forward_out_fut, forward_in_fut],
return_when=asyncio.FIRST_EXCEPTION)

# -------------------------------------------------------------------------------------------------

class JTAGOpenOCDAppletTestCase(GlasgowAppletTestCase, applet=JTAGOpenOCDApplet):
@synthesis_test
def test_build(self):
self.assertBuilds()
2 changes: 1 addition & 1 deletion software/glasgow/applet/interface/jtag_probe/__init__.py
Original file line number Diff line number Diff line change
@@ -804,7 +804,7 @@ def add_build_arguments(cls, parser, access):

parser.add_argument(
"-f", "--frequency", metavar="FREQ", type=int, default=100,
help="set clock frequency to FREQ kHz (default: %(default)s)")
help="set TCK frequency to FREQ kHz (default: %(default)s)")

def build(self, target, args):
self.mux_interface = iface = target.multiplexer.claim_interface(self, args)