Merge branch 'master' into update

Change-Id: I2cd34ed5bb1903736ae8ce109acebaf13bf49805
This commit is contained in:
Tim Newsome 2018-02-02 13:36:58 -08:00
commit 706af27eee
83 changed files with 3490 additions and 883 deletions

View File

@ -216,7 +216,7 @@ OPTIMIZE_OUTPUT_VHDL = NO
# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), # .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C # use: inc=Fortran f=C
EXTENSION_MAPPING = EXTENSION_MAPPING = no_extension=C
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should # to include (a tag file for) the STL sources as input, then you should

View File

@ -13,8 +13,11 @@
# GNU General Public License for more details. # GNU General Public License for more details.
# #
from migen import * import unittest
from migen.build.generic_platform import *
import migen as mg
import migen.build.generic_platform as mb
from migen.genlib import io
from migen.build import xilinx from migen.build import xilinx
@ -25,59 +28,256 @@ behind FPGAs.
Bitstream binaries built with this script are available at: Bitstream binaries built with this script are available at:
https://github.com/jordens/bscan_spi_bitstreams https://github.com/jordens/bscan_spi_bitstreams
JTAG signalling is connected directly to SPI signalling. CS_N is A JTAG2SPI transfer consists of:
asserted when the JTAG IR contains the USER1 instruction and the state is
SHIFT-DR. Xilinx bscan cells sample TDO on falling TCK and forward it. 1. an arbitrary number of 0 bits (from BYPASS registers in front of the
MISO requires sampling on rising CLK and leads to one cycle of latency. JTAG2SPI DR)
2. a marker bit (1) indicating the start of the JTAG2SPI transaction
3. 32 bits (big endian) describing the length of the SPI transaction
4. a number of SPI clock cycles (corresponding to 3.) with CS_N asserted
5. an arbitrary number of cycles (to shift MISO/TDO data through subsequent
BYPASS registers)
Notes:
* The JTAG2SPI DR is 1 bit long (due to different sampling edges of
{MISO,MOSI}/{TDO,TDI}).
* MOSI is TDI with half a cycle delay.
* TDO is MISO with half a cycle delay.
* CAPTURE-DR needs to be performed before SHIFT-DR on the BYPASSed TAPs in
JTAG chain to clear the BYPASS registers to 0.
https://github.com/m-labs/migen https://github.com/m-labs/migen
""" """
class Spartan3(Module): class JTAG2SPI(mg.Module):
def __init__(self, spi=None, bits=32):
self.jtag = mg.Record([
("sel", 1),
("shift", 1),
("capture", 1),
("tck", 1),
("tdi", 1),
("tdo", 1),
])
self.cs_n = mg.TSTriple()
self.clk = mg.TSTriple()
self.mosi = mg.TSTriple()
self.miso = mg.TSTriple()
# # #
self.cs_n.o.reset = mg.Constant(1)
self.mosi.o.reset_less = True
bits = mg.Signal(bits, reset_less=True)
head = mg.Signal(max=len(bits), reset=len(bits) - 1)
self.clock_domains.cd_sys = mg.ClockDomain()
self.submodules.fsm = mg.FSM("IDLE")
if spi is not None:
self.specials += [
self.cs_n.get_tristate(spi.cs_n),
self.mosi.get_tristate(spi.mosi),
self.miso.get_tristate(spi.miso),
]
if hasattr(spi, "clk"): # 7 Series drive it fixed
self.specials += self.clk.get_tristate(spi.clk)
# self.specials += io.DDROutput(1, 0, spi.clk, self.clk.o)
self.comb += [
self.cd_sys.rst.eq(self.jtag.sel & self.jtag.capture),
self.cd_sys.clk.eq(self.jtag.tck),
self.cs_n.oe.eq(self.jtag.sel),
self.clk.oe.eq(self.jtag.sel),
self.mosi.oe.eq(self.jtag.sel),
self.miso.oe.eq(0),
# Do not suppress CLK toggles outside CS_N asserted.
# Xilinx USRCCLK0 requires three dummy cycles to do anything
# https://www.xilinx.com/support/answers/52626.html
# This is fine since CS_N changes only on falling CLK.
self.clk.o.eq(~self.jtag.tck),
self.jtag.tdo.eq(self.miso.i),
]
# Latency calculation (in half cycles):
# 0 (falling TCK, rising CLK):
# JTAG adapter: set TDI
# 1 (rising TCK, falling CLK):
# JTAG2SPI: sample TDI -> set MOSI
# SPI: set MISO
# 2 (falling TCK, rising CLK):
# SPI: sample MOSI
# JTAG2SPI (BSCAN primitive): sample MISO -> set TDO
# 3 (rising TCK, falling CLK):
# JTAG adapter: sample TDO
self.fsm.act("IDLE",
mg.If(self.jtag.tdi & self.jtag.sel & self.jtag.shift,
mg.NextState("HEAD")
)
)
self.fsm.act("HEAD",
mg.If(head == 0,
mg.NextState("XFER")
)
)
self.fsm.act("XFER",
mg.If(bits == 0,
mg.NextState("IDLE")
),
)
self.sync += [
self.mosi.o.eq(self.jtag.tdi),
self.cs_n.o.eq(~self.fsm.ongoing("XFER")),
mg.If(self.fsm.ongoing("HEAD"),
bits.eq(mg.Cat(self.jtag.tdi, bits)),
head.eq(head - 1)
),
mg.If(self.fsm.ongoing("XFER"),
bits.eq(bits - 1)
)
]
class JTAG2SPITest(unittest.TestCase):
def setUp(self):
self.bits = 8
self.dut = JTAG2SPI(bits=self.bits)
def test_instantiate(self):
pass
def test_initial_conditions(self):
def check():
yield
self.assertEqual((yield self.dut.cs_n.oe), 0)
self.assertEqual((yield self.dut.mosi.oe), 0)
self.assertEqual((yield self.dut.miso.oe), 0)
self.assertEqual((yield self.dut.clk.oe), 0)
mg.run_simulation(self.dut, check())
def test_enable(self):
def check():
yield self.dut.jtag.sel.eq(1)
yield self.dut.jtag.shift.eq(1)
yield
self.assertEqual((yield self.dut.cs_n.oe), 1)
self.assertEqual((yield self.dut.mosi.oe), 1)
self.assertEqual((yield self.dut.miso.oe), 0)
self.assertEqual((yield self.dut.clk.oe), 1)
mg.run_simulation(self.dut, check())
def run_seq(self, tdi, tdo, spi=None):
yield self.dut.jtag.sel.eq(1)
yield
yield self.dut.jtag.shift.eq(1)
for di in tdi:
yield self.dut.jtag.tdi.eq(di)
yield
tdo.append((yield self.dut.jtag.tdo))
if spi is not None:
v = []
for k in "cs_n clk mosi miso".split():
t = getattr(self.dut, k)
v.append("{}>".format((yield t.o)) if (yield t.oe)
else "<{}".format((yield t.i)))
spi.append(" ".join(v))
yield self.dut.jtag.sel.eq(0)
yield
yield self.dut.jtag.shift.eq(0)
yield
def test_shift(self):
bits = 8
data = 0x81
tdi = [0, 0, 1] # dummy from BYPASS TAPs and marker
tdi += [((bits - 1) >> j) & 1 for j in range(self.bits - 1, -1, -1)]
tdi += [(data >> j) & 1 for j in range(bits)]
tdi += [0, 0, 0, 0] # dummy from BYPASS TAPs
tdo = []
spi = []
mg.run_simulation(self.dut, self.run_seq(tdi, tdo, spi))
# print(tdo)
for l in spi:
print(l)
class Spartan3(mg.Module):
macro = "BSCAN_SPARTAN3" macro = "BSCAN_SPARTAN3"
toolchain = "ise" toolchain = "ise"
def __init__(self, platform): def __init__(self, platform):
platform.toolchain.bitgen_opt += " -g compress -g UnusedPin:Pullup" platform.toolchain.bitgen_opt += " -g compress -g UnusedPin:Pullup"
self.clock_domains.cd_jtag = ClockDomain(reset_less=True) self.submodules.j2s = j2s = JTAG2SPI(platform.request("spiflash"))
spi = platform.request("spiflash") self.specials += [
shift = Signal() mg.Instance(
tdo = Signal() self.macro,
sel1 = Signal() o_SHIFT=j2s.jtag.shift, o_SEL1=j2s.jtag.sel,
self.comb += [ o_CAPTURE=j2s.jtag.capture,
self.cd_jtag.clk.eq(spi.clk), o_DRCK1=j2s.jtag.tck,
spi.cs_n.eq(~shift | ~sel1), o_TDI=j2s.jtag.tdi, i_TDO1=j2s.jtag.tdo,
i_TDO2=0),
] ]
self.sync.jtag += tdo.eq(spi.miso) platform.add_period_constraint(j2s.jtag.tck, 6)
self.specials += Instance(self.macro,
o_DRCK1=spi.clk, o_SHIFT=shift,
o_TDI=spi.mosi, i_TDO1=tdo, i_TDO2=0,
o_SEL1=sel1)
class Spartan3A(Spartan3): class Spartan3A(Spartan3):
macro = "BSCAN_SPARTAN3A" macro = "BSCAN_SPARTAN3A"
class Spartan6(Module): class Spartan6(mg.Module):
toolchain = "ise" toolchain = "ise"
def __init__(self, platform): def __init__(self, platform):
platform.toolchain.bitgen_opt += " -g compress -g UnusedPin:Pullup" platform.toolchain.bitgen_opt += " -g compress -g UnusedPin:Pullup"
self.clock_domains.cd_jtag = ClockDomain(reset_less=True) self.submodules.j2s = j2s = JTAG2SPI(platform.request("spiflash"))
spi = platform.request("spiflash") # clk = mg.Signal()
shift = Signal() self.specials += [
tdo = Signal() mg.Instance(
sel = Signal() "BSCAN_SPARTAN6", p_JTAG_CHAIN=1,
self.comb += self.cd_jtag.clk.eq(spi.clk), spi.cs_n.eq(~shift | ~sel) o_SHIFT=j2s.jtag.shift, o_SEL=j2s.jtag.sel,
self.sync.jtag += tdo.eq(spi.miso) o_CAPTURE=j2s.jtag.capture,
self.specials += Instance("BSCAN_SPARTAN6", p_JTAG_CHAIN=1, o_DRCK=j2s.jtag.tck,
o_TCK=spi.clk, o_SHIFT=shift, o_SEL=sel, o_TDI=j2s.jtag.tdi, i_TDO=j2s.jtag.tdo),
o_TDI=spi.mosi, i_TDO=tdo) # mg.Instance("BUFG", i_I=clk, o_O=j2s.jtag.tck)
]
platform.add_period_constraint(j2s.jtag.tck, 6)
class Series7(Module): class Series7(mg.Module):
toolchain = "vivado"
def __init__(self, platform):
platform.toolchain.bitstream_commands.extend([
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
"set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design]"
])
self.submodules.j2s = j2s = JTAG2SPI(platform.request("spiflash"))
# clk = mg.Signal()
self.specials += [
mg.Instance(
"BSCANE2", p_JTAG_CHAIN=1,
o_SHIFT=j2s.jtag.shift, o_SEL=j2s.jtag.sel,
o_CAPTURE=j2s.jtag.capture,
o_DRCK=j2s.jtag.tck,
o_TDI=j2s.jtag.tdi, i_TDO=j2s.jtag.tdo),
mg.Instance(
"STARTUPE2", i_CLK=0, i_GSR=0, i_GTS=0,
i_KEYCLEARB=0, i_PACK=1,
i_USRCCLKO=j2s.clk.o, i_USRCCLKTS=~j2s.clk.oe,
i_USRDONEO=1, i_USRDONETS=1),
# mg.Instance("BUFG", i_I=clk, o_O=j2s.jtag.tck)
]
platform.add_period_constraint(j2s.jtag.tck, 6)
try:
self.comb += [
platform.request("user_sma_gpio_p").eq(j2s.cs_n.i),
platform.request("user_sma_gpio_n").eq(j2s.clk.o),
platform.request("user_sma_clock_p").eq(j2s.mosi.o),
platform.request("user_sma_clock_n").eq(j2s.miso.i),
]
except mb.ConstraintError:
pass
class Ultrascale(mg.Module):
toolchain = "vivado" toolchain = "vivado"
def __init__(self, platform): def __init__(self, platform):
@ -85,20 +285,33 @@ class Series7(Module):
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]", "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
"set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design]", "set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design]",
]) ])
self.clock_domains.cd_jtag = ClockDomain(reset_less=True) self.submodules.j2s0 = j2s0 = JTAG2SPI()
spi = platform.request("spiflash") self.submodules.j2s1 = j2s1 = JTAG2SPI(platform.request("spiflash"))
clk = Signal() di = mg.Signal(4)
shift = Signal() self.comb += mg.Cat(j2s0.mosi.i, j2s0.miso.i).eq(di)
tdo = Signal() self.specials += [
sel = Signal() mg.Instance("BSCANE2", p_JTAG_CHAIN=1,
self.comb += self.cd_jtag.clk.eq(clk), spi.cs_n.eq(~shift | ~sel) o_SHIFT=j2s0.jtag.shift, o_SEL=j2s0.jtag.sel,
self.sync.jtag += tdo.eq(spi.miso) o_CAPTURE=j2s0.jtag.capture,
self.specials += Instance("BSCANE2", p_JTAG_CHAIN=1, o_DRCK=j2s0.jtag.tck,
o_SHIFT=shift, o_TCK=clk, o_SEL=sel, o_TDI=j2s0.jtag.tdi, i_TDO=j2s0.jtag.tdo),
o_TDI=spi.mosi, i_TDO=tdo) mg.Instance("BSCANE2", p_JTAG_CHAIN=2,
self.specials += Instance("STARTUPE2", i_CLK=0, i_GSR=0, i_GTS=0, o_SHIFT=j2s1.jtag.shift, o_SEL=j2s1.jtag.sel,
i_KEYCLEARB=0, i_PACK=1, i_USRCCLKO=clk, o_CAPTURE=j2s1.jtag.capture,
i_USRCCLKTS=0, i_USRDONEO=1, i_USRDONETS=1) o_DRCK=j2s1.jtag.tck,
o_TDI=j2s1.jtag.tdi, i_TDO=j2s1.jtag.tdo),
mg.Instance("STARTUPE3", i_GSR=0, i_GTS=0,
i_KEYCLEARB=0, i_PACK=1,
i_USRDONEO=1, i_USRDONETS=1,
i_USRCCLKO=mg.Mux(j2s0.clk.oe, j2s0.clk.o, j2s1.clk.o),
i_USRCCLKTS=~(j2s0.clk.oe | j2s1.clk.oe),
i_FCSBO=j2s0.cs_n.o, i_FCSBTS=~j2s0.cs_n.oe,
o_DI=di,
i_DO=mg.Cat(j2s0.mosi.o, j2s0.miso.o, 0, 0),
i_DTS=mg.Cat(~j2s0.mosi.oe, ~j2s0.miso.oe, 1, 1))
]
platform.add_period_constraint(j2s0.jtag.tck, 6)
platform.add_period_constraint(j2s1.jtag.tck, 6)
class XilinxBscanSpi(xilinx.XilinxPlatform): class XilinxBscanSpi(xilinx.XilinxPlatform):
@ -124,6 +337,7 @@ class XilinxBscanSpi(xilinx.XilinxPlatform):
("fbg484-1", 2): ["L16", None, "H18", "H19", "G18", "F19"], ("fbg484-1", 2): ["L16", None, "H18", "H19", "G18", "F19"],
("fbg676-1", 1): ["C23", None, "B24", "A25", "B22", "A22"], ("fbg676-1", 1): ["C23", None, "B24", "A25", "B22", "A22"],
("ffg901-1", 1): ["V26", None, "R30", "T30", "R28", "T28"], ("ffg901-1", 1): ["V26", None, "R30", "T30", "R28", "T28"],
("ffg900-1", 1): ["U19", None, "P24", "R25", "R20", "R21"],
("ffg1156-1", 1): ["V30", None, "AA33", "AA34", "Y33", "Y34"], ("ffg1156-1", 1): ["V30", None, "AA33", "AA34", "Y33", "Y34"],
("ffg1157-1", 1): ["AL33", None, "AN33", "AN34", "AK34", "AL34"], ("ffg1157-1", 1): ["AL33", None, "AN33", "AN34", "AK34", "AL34"],
("ffg1158-1", 1): ["C24", None, "A23", "A24", "B26", "A26"], ("ffg1158-1", 1): ["C24", None, "A23", "A24", "B26", "A26"],
@ -132,6 +346,9 @@ class XilinxBscanSpi(xilinx.XilinxPlatform):
("flg1155-1", 1): ["AL28", None, "AE28", "AF28", "AJ29", "AJ30"], ("flg1155-1", 1): ["AL28", None, "AE28", "AF28", "AJ29", "AJ30"],
("flg1932-1", 1): ["V32", None, "T33", "R33", "U31", "T31"], ("flg1932-1", 1): ["V32", None, "T33", "R33", "U31", "T31"],
("flg1926-1", 1): ["AK33", None, "AN34", "AN35", "AJ34", "AK34"], ("flg1926-1", 1): ["AK33", None, "AN34", "AN35", "AJ34", "AK34"],
("ffva1156-2-e", 1): ["G26", None, "M20", "L20", "R21", "R22"],
("ffva1156-2-e", "sayma"): ["K21", None, "M20", "L20", "R21", "R22"],
} }
pinouts = { pinouts = {
@ -181,6 +398,7 @@ class XilinxBscanSpi(xilinx.XilinxPlatform):
"xc7a75t": ("csg324-1", 1, "LVCMOS25", Series7), "xc7a75t": ("csg324-1", 1, "LVCMOS25", Series7),
"xc7k160t": ("fbg484-1", 2, "LVCMOS25", Series7), "xc7k160t": ("fbg484-1", 2, "LVCMOS25", Series7),
"xc7k325t": ("fbg676-1", 1, "LVCMOS25", Series7), "xc7k325t": ("fbg676-1", 1, "LVCMOS25", Series7),
"xc7k325t-debug": ("ffg900-1", 1, "LVCMOS25", Series7),
"xc7k355t": ("ffg901-1", 1, "LVCMOS25", Series7), "xc7k355t": ("ffg901-1", 1, "LVCMOS25", Series7),
"xc7k410t": ("fbg676-1", 1, "LVCMOS25", Series7), "xc7k410t": ("fbg676-1", 1, "LVCMOS25", Series7),
"xc7k420t": ("ffg1156-1", 1, "LVCMOS25", Series7), "xc7k420t": ("ffg1156-1", 1, "LVCMOS25", Series7),
@ -197,35 +415,53 @@ class XilinxBscanSpi(xilinx.XilinxPlatform):
"xc7vx550t": ("ffg1158-1", 1, "LVCMOS18", Series7), "xc7vx550t": ("ffg1158-1", 1, "LVCMOS18", Series7),
"xc7vx690t": ("ffg1157-1", 1, "LVCMOS18", Series7), "xc7vx690t": ("ffg1157-1", 1, "LVCMOS18", Series7),
"xc7vx980t": ("ffg1926-1", 1, "LVCMOS18", Series7), "xc7vx980t": ("ffg1926-1", 1, "LVCMOS18", Series7),
"xcku040": ("ffva1156-2-e", 1, "LVCMOS18", Ultrascale),
"xcku040-sayma": ("ffva1156-2-e", "sayma", "LVCMOS18", Ultrascale),
} }
def __init__(self, device, pins, std, toolchain="ise"): def __init__(self, device, pins, std, toolchain="ise"):
ios = [self.make_spi(0, pins, std, toolchain)]
if device == "xc7k325t-ffg900-1": # debug
ios += [
("user_sma_clock_p", 0, mb.Pins("L25"), mb.IOStandard("LVCMOS25")),
("user_sma_clock_n", 0, mb.Pins("K25"), mb.IOStandard("LVCMOS25")),
("user_sma_gpio_p", 0, mb.Pins("Y23"), mb.IOStandard("LVCMOS25")),
("user_sma_gpio_n", 0, mb.Pins("Y24"), mb.IOStandard("LVCMOS25")),
]
xilinx.XilinxPlatform.__init__(self, device, ios, toolchain=toolchain)
@staticmethod
def make_spi(i, pins, std, toolchain):
pu = "PULLUP" if toolchain == "ise" else "PULLUP TRUE"
pd = "PULLDOWN" if toolchain == "ise" else "PULLDOWN TRUE"
cs_n, clk, mosi, miso = pins[:4] cs_n, clk, mosi, miso = pins[:4]
io = ["spiflash", 0, io = ["spiflash", i,
Subsignal("cs_n", Pins(cs_n)), mb.Subsignal("cs_n", mb.Pins(cs_n), mb.Misc(pu)),
Subsignal("mosi", Pins(mosi)), mb.Subsignal("mosi", mb.Pins(mosi), mb.Misc(pu)),
Subsignal("miso", Pins(miso), Misc("PULLUP")), mb.Subsignal("miso", mb.Pins(miso), mb.Misc(pu)),
IOStandard(std), mb.IOStandard(std),
] ]
if clk: if clk:
io.append(Subsignal("clk", Pins(clk))) io.append(mb.Subsignal("clk", mb.Pins(clk), mb.Misc(pd)))
for i, p in enumerate(pins[4:]): for i, p in enumerate(pins[4:]):
io.append(Subsignal("pullup{}".format(i), Pins(p), Misc("PULLUP"))) io.append(mb.Subsignal("pullup{}".format(i), mb.Pins(p),
xilinx.XilinxPlatform.__init__(self, device, [io], toolchain=toolchain) mb.Misc(pu)))
return io
@classmethod @classmethod
def make(cls, device, errors=False): def make(cls, target, errors=False):
pkg, id, std, Top = cls.pinouts[device] pkg, id, std, Top = cls.pinouts[target]
pins = cls.packages[(pkg, id)] pins = cls.packages[(pkg, id)]
device = target.split("-", 1)[0]
platform = cls("{}-{}".format(device, pkg), pins, std, Top.toolchain) platform = cls("{}-{}".format(device, pkg), pins, std, Top.toolchain)
top = Top(platform) top = Top(platform)
name = "bscan_spi_{}".format(device) name = "bscan_spi_{}".format(target)
dir = "build_{}".format(device)
try: try:
platform.build(top, build_name=name, build_dir=dir) platform.build(top, build_name=name)
except Exception as e: except Exception as e:
print(("ERROR: xilinx_bscan_spi build failed " print(("ERROR: xilinx_bscan_spi build failed "
"for {}: {}").format(device, e)) "for {}: {}").format(target, e))
if errors: if errors:
raise raise

View File

@ -302,7 +302,7 @@ static void process_remote_protocol(void)
break; break;
else if (c == 'b' || c == 'B') /* Blink */ else if (c == 'b' || c == 'B') /* Blink */
continue; continue;
else if (c >= 'r' && c <= 'r' + 2) { /* Reset */ else if (c >= 'r' && c <= 'r' + 3) { /* Reset */
char d = c - 'r'; char d = c - 'r';
sysfsgpio_reset(!!(d & 2), sysfsgpio_reset(!!(d & 2),
(d & 1)); (d & 1));

View File

@ -176,10 +176,10 @@ comments.
* @returns The value(s) returned, or possible error conditions. * @returns The value(s) returned, or possible error conditions.
*/ */
@endverbatim @endverbatim
-# The block should start on the line following the opening @c /**. -# The block should start on the line following the opening @c /\**.
-# The end of the block, \f$*/\f$, should also be on its own line. -# The end of the block, @c *&zwj;/, should also be on its own line.
-# Every line in the block should have a @c '*' in-line with its start: -# Every line in the block should have a @c '*' in-line with its start:
- A leading space is required to align the @c '*' with the @c /** line. - A leading space is required to align the @c '*' with the @c /\** line.
- A single "empty" line should separate the function documentation - A single "empty" line should separate the function documentation
from the block of parameter and return value descriptions. from the block of parameter and return value descriptions.
- Except to separate paragraphs of documentation, other extra - Except to separate paragraphs of documentation, other extra

View File

@ -4913,19 +4913,62 @@ functionality is available through the @command{flash write_bank},
@item @var{ir} ... is loaded into the JTAG IR to map the flash as the JTAG DR. @item @var{ir} ... is loaded into the JTAG IR to map the flash as the JTAG DR.
For the bitstreams generated from @file{xilinx_bscan_spi.py} this is the For the bitstreams generated from @file{xilinx_bscan_spi.py} this is the
@var{USER1} instruction. @var{USER1} instruction.
@item @var{dr_length} ... is the length of the DR register. This will be 1 for
@file{xilinx_bscan_spi.py} bitstreams and most other cases.
@end itemize @end itemize
@example @example
target create $_TARGETNAME testee -chain-position $_CHIPNAME.fpga target create $_TARGETNAME testee -chain-position $_CHIPNAME.fpga
set _XILINX_USER1 0x02 set _XILINX_USER1 0x02
set _DR_LENGTH 1
flash bank $_FLASHNAME spi 0x0 0 0 0 \ flash bank $_FLASHNAME spi 0x0 0 0 0 \
$_TARGETNAME $_XILINX_USER1 $_DR_LENGTH $_TARGETNAME $_XILINX_USER1
@end example @end example
@end deffn @end deffn
@deffn {Flash Driver} xcf
@cindex Xilinx Platform flash driver
@cindex xcf
Xilinx FPGAs can be configured from specialized flash ICs named Platform Flash.
It is (almost) regular NOR flash with erase sectors, program pages, etc. The
only difference is special registers controlling its FPGA specific behavior.
They must be properly configured for successful FPGA loading using
additional @var{xcf} driver command:
@deffn Command {xcf ccb} <bank_id>
command accepts additional parameters:
@itemize
@item @var{external|internal} ... selects clock source.
@item @var{serial|parallel} ... selects serial or parallel data bus mode.
@item @var{slave|master} ... selects slave of master mode for flash device.
@item @var{40|20} ... selects clock frequency in MHz for internal clock
in master mode.
@end itemize
@example
xcf ccb 0 external parallel slave 40
@end example
All of them must be specified even if clock frequency is pointless
in slave mode. If only bank id specified than command prints current
CCB register value. Note: there is no need to write this register
every time you erase/program data sectors because it stores in
dedicated sector.
@end deffn
@deffn Command {xcf configure} <bank_id>
Initiates FPGA loading procedure. Useful if your board has no "configure"
button.
@example
xcf configure 0
@end example
@end deffn
Additional driver notes:
@itemize
@item Only single revision supported.
@item Driver automatically detects need of bit reverse, but
only "bin" (raw binary, do not confuse it with "bit") and "mcs"
(Intel hex) file types supported.
@item For additional info check xapp972.pdf and ug380.pdf.
@end itemize
@end deffn
@deffn {Flash Driver} lpcspifi @deffn {Flash Driver} lpcspifi
@cindex NXP SPI Flash Interface @cindex NXP SPI Flash Interface
@cindex SPIFI @cindex SPIFI
@ -5358,7 +5401,7 @@ from NXP (former Freescale) include
internal flash and use ARM Cortex-M0+ or M4 cores. The driver automatically internal flash and use ARM Cortex-M0+ or M4 cores. The driver automatically
recognizes flash size and a number of flash banks (1-4) using the chip recognizes flash size and a number of flash banks (1-4) using the chip
identification register, and autoconfigures itself. identification register, and autoconfigures itself.
Use kinetis_ke driver for KE0x devices. Use kinetis_ke driver for KE0x and KEAx devices.
The @var{kinetis} driver defines option: The @var{kinetis} driver defines option:
@itemize @itemize
@ -5451,7 +5494,7 @@ Command disables watchdog timer.
@deffn {Flash Driver} kinetis_ke @deffn {Flash Driver} kinetis_ke
@cindex kinetis_ke @cindex kinetis_ke
KE0x members of the Kinetis microcontroller family from Freescale include KE0x and KEAx members of the Kinetis microcontroller family from NXP include
internal flash and use ARM Cortex-M0+. The driver automatically recognizes internal flash and use ARM Cortex-M0+. The driver automatically recognizes
the KE0x sub-family using the chip identification register, and the KE0x sub-family using the chip identification register, and
autoconfigures itself. autoconfigures itself.
@ -8375,6 +8418,11 @@ halting or resuming of all cores in the group. The command @code{target smp} def
group. With SMP handling disabled, all targets need to be treated individually. group. With SMP handling disabled, all targets need to be treated individually.
@end deffn @end deffn
@deffn Command {aarch64 maskisr} [@option{on}|@option{off}]
Selects whether interrupts will be processed when single stepping. The default configuration is
@option{on}.
@end deffn
@section Intel Architecture @section Intel Architecture
Intel Quark X10xx is the first product in the Quark family of SoCs. It is an IA-32 Intel Quark X10xx is the first product in the Quark family of SoCs. It is an IA-32
@ -8779,11 +8827,27 @@ way to represent JTAG test patterns in text files.
In a debug session using JTAG for its transport protocol, In a debug session using JTAG for its transport protocol,
OpenOCD supports running such test files. OpenOCD supports running such test files.
@deffn Command {svf} filename [@option{quiet}] @deffn Command {svf} @file{filename} [@option{-tap @var{tapname}}] [@option{[-]quiet}] @
[@option{[-]nil}] [@option{[-]progress}] [@option{[-]ignore_error}]
This issues a JTAG reset (Test-Logic-Reset) and then This issues a JTAG reset (Test-Logic-Reset) and then
runs the SVF script from @file{filename}. runs the SVF script from @file{filename}.
Unless the @option{quiet} option is specified,
each command is logged before it is executed. Arguments can be specified in any order; the optional dash doesn't
affect their semantics.
Command options:
@itemize @minus
@item @option{-tap @var{tapname}} ignore IR and DR headers and footers
specified by the SVF file with HIR, TIR, HDR and TDR commands;
instead, calculate them automatically according to the current JTAG
chain configuration, targetting @var{tapname};
@item @option{[-]quiet} do not log every command before execution;
@item @option{[-]nil} ``dry run'', i.e., do not perform any operations
on the real interface;
@item @option{[-]progress} enable progress indication;
@item @option{[-]ignore_error} continue execution despite TDO check
errors.
@end itemize
@end deffn @end deffn
@section XSVF: Xilinx Serial Vector Format @section XSVF: Xilinx Serial Vector Format

View File

@ -56,6 +56,7 @@ NOR_DRIVERS = \
%D%/str9xpec.c \ %D%/str9xpec.c \
%D%/tms470.c \ %D%/tms470.c \
%D%/virtual.c \ %D%/virtual.c \
%D%/xcf.c \
%D%/xmc1xxx.c \ %D%/xmc1xxx.c \
%D%/xmc4xxx.c %D%/xmc4xxx.c

View File

@ -68,6 +68,7 @@ extern struct flash_driver str9x_flash;
extern struct flash_driver str9xpec_flash; extern struct flash_driver str9xpec_flash;
extern struct flash_driver tms470_flash; extern struct flash_driver tms470_flash;
extern struct flash_driver virtual_flash; extern struct flash_driver virtual_flash;
extern struct flash_driver xcf_flash;
extern struct flash_driver xmc1xxx_flash; extern struct flash_driver xmc1xxx_flash;
extern struct flash_driver xmc4xxx_flash; extern struct flash_driver xmc4xxx_flash;
@ -124,6 +125,7 @@ static struct flash_driver *flash_drivers[] = {
&str9xpec_flash, &str9xpec_flash,
&tms470_flash, &tms470_flash,
&virtual_flash, &virtual_flash,
&xcf_flash,
&xmc1xxx_flash, &xmc1xxx_flash,
&xmc4xxx_flash, &xmc4xxx_flash,
NULL, NULL,

View File

@ -32,14 +32,13 @@ struct jtagspi_flash_bank {
const struct flash_device *dev; const struct flash_device *dev;
int probed; int probed;
uint32_t ir; uint32_t ir;
uint32_t dr_len;
}; };
FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command) FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
{ {
struct jtagspi_flash_bank *info; struct jtagspi_flash_bank *info;
if (CMD_ARGC < 8) if (CMD_ARGC < 7)
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
info = malloc(sizeof(struct jtagspi_flash_bank)); info = malloc(sizeof(struct jtagspi_flash_bank));
@ -52,7 +51,6 @@ FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
info->tap = NULL; info->tap = NULL;
info->probed = 0; info->probed = 0;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->ir); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->ir);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], info->dr_len);
return ERROR_OK; return ERROR_OK;
} }
@ -63,9 +61,6 @@ static void jtagspi_set_ir(struct flash_bank *bank)
struct scan_field field; struct scan_field field;
uint8_t buf[4]; uint8_t buf[4];
if (buf_get_u32(info->tap->cur_instr, 0, info->tap->ir_length) == info->ir)
return;
LOG_DEBUG("loading jtagspi ir"); LOG_DEBUG("loading jtagspi ir");
buf_set_u32(buf, 0, info->tap->ir_length, info->ir); buf_set_u32(buf, 0, info->tap->ir_length, info->ir);
field.num_bits = info->tap->ir_length; field.num_bits = info->tap->ir_length;
@ -84,28 +79,53 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
uint32_t *addr, uint8_t *data, int len) uint32_t *addr, uint8_t *data, int len)
{ {
struct jtagspi_flash_bank *info = bank->driver_priv; struct jtagspi_flash_bank *info = bank->driver_priv;
struct scan_field fields[3]; struct scan_field fields[6];
uint8_t cmd_buf[4]; uint8_t marker = 1;
uint8_t xfer_bits_buf[4];
uint8_t addr_buf[3];
uint8_t *data_buf; uint8_t *data_buf;
uint32_t xfer_bits;
int is_read, lenb, n; int is_read, lenb, n;
/* LOG_DEBUG("cmd=0x%02x len=%i", cmd, len); */ /* LOG_DEBUG("cmd=0x%02x len=%i", cmd, len); */
n = 0;
fields[n].num_bits = 8;
cmd_buf[0] = cmd;
if (addr) {
h_u24_to_be(cmd_buf + 1, *addr);
fields[n].num_bits += 24;
}
flip_u8(cmd_buf, cmd_buf, 4);
fields[n].out_value = cmd_buf;
fields[n].in_value = NULL;
n++;
is_read = (len < 0); is_read = (len < 0);
if (is_read) if (is_read)
len = -len; len = -len;
n = 0;
fields[n].num_bits = 1;
fields[n].out_value = &marker;
fields[n].in_value = NULL;
n++;
xfer_bits = 8 + len - 1;
/* cmd + read/write - 1 due to the counter implementation */
if (addr)
xfer_bits += 24;
h_u32_to_be(xfer_bits_buf, xfer_bits);
flip_u8(xfer_bits_buf, xfer_bits_buf, 4);
fields[n].num_bits = 32;
fields[n].out_value = xfer_bits_buf;
fields[n].in_value = NULL;
n++;
cmd = flip_u32(cmd, 8);
fields[n].num_bits = 8;
fields[n].out_value = &cmd;
fields[n].in_value = NULL;
n++;
if (addr) {
h_u24_to_be(addr_buf, *addr);
flip_u8(addr_buf, addr_buf, 3);
fields[n].num_bits = 24;
fields[n].out_value = addr_buf;
fields[n].in_value = NULL;
n++;
}
lenb = DIV_ROUND_UP(len, 8); lenb = DIV_ROUND_UP(len, 8);
data_buf = malloc(lenb); data_buf = malloc(lenb);
if (lenb > 0) { if (lenb > 0) {
@ -114,10 +134,11 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
return ERROR_FAIL; return ERROR_FAIL;
} }
if (is_read) { if (is_read) {
fields[n].num_bits = info->dr_len; fields[n].num_bits = jtag_tap_count_enabled();
fields[n].out_value = NULL; fields[n].out_value = NULL;
fields[n].in_value = NULL; fields[n].in_value = NULL;
n++; n++;
fields[n].out_value = NULL; fields[n].out_value = NULL;
fields[n].in_value = data_buf; fields[n].in_value = data_buf;
} else { } else {
@ -130,6 +151,7 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
} }
jtagspi_set_ir(bank); jtagspi_set_ir(bank);
/* passing from an IR scan to SHIFT-DR clears BYPASS registers */
jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE); jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE);
jtag_execute_queue(); jtag_execute_queue();
@ -202,9 +224,10 @@ static int jtagspi_probe(struct flash_bank *bank)
static void jtagspi_read_status(struct flash_bank *bank, uint32_t *status) static void jtagspi_read_status(struct flash_bank *bank, uint32_t *status)
{ {
uint8_t buf; uint8_t buf;
jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8); if (jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8) == ERROR_OK) {
*status = buf; *status = buf;
/* LOG_DEBUG("status=0x%08" PRIx32, *status); */ /* LOG_DEBUG("status=0x%08" PRIx32, *status); */
}
} }
static int jtagspi_wait(struct flash_bank *bank, int timeout_ms) static int jtagspi_wait(struct flash_bank *bank, int timeout_ms)

View File

@ -287,6 +287,7 @@ struct kinetis_chip {
FS_NO_CMD_BLOCKSTAT = 0x40, FS_NO_CMD_BLOCKSTAT = 0x40,
FS_WIDTH_256BIT = 0x80, FS_WIDTH_256BIT = 0x80,
FS_ECC = 0x100,
} flash_support; } flash_support;
enum { enum {
@ -388,6 +389,7 @@ static const struct kinetis_type kinetis_types_old[] = {
static bool allow_fcf_writes; static bool allow_fcf_writes;
static uint8_t fcf_fopt = 0xff; static uint8_t fcf_fopt = 0xff;
static bool fcf_fopt_configured;
static bool create_banks; static bool create_banks;
@ -1881,9 +1883,13 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer,
{ {
int result; int result;
bool set_fcf = false; bool set_fcf = false;
bool fcf_in_data_valid = false;
int sect = 0; int sect = 0;
struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_flash_bank *k_bank = bank->driver_priv;
struct kinetis_chip *k_chip = k_bank->k_chip; struct kinetis_chip *k_chip = k_bank->k_chip;
uint8_t fcf_buffer[FCF_SIZE];
uint8_t fcf_current[FCF_SIZE];
uint8_t fcf_in_data[FCF_SIZE];
result = kinetis_check_run_mode(k_chip); result = kinetis_check_run_mode(k_chip);
if (result != ERROR_OK) if (result != ERROR_OK)
@ -1904,11 +1910,41 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer,
} }
if (set_fcf) { if (set_fcf) {
uint8_t fcf_buffer[FCF_SIZE];
uint8_t fcf_current[FCF_SIZE];
kinetis_fill_fcf(bank, fcf_buffer); kinetis_fill_fcf(bank, fcf_buffer);
fcf_in_data_valid = offset <= FCF_ADDRESS
&& offset + count >= FCF_ADDRESS + FCF_SIZE;
if (fcf_in_data_valid) {
memcpy(fcf_in_data, buffer + FCF_ADDRESS - offset, FCF_SIZE);
if (memcmp(fcf_in_data + FCF_FPROT, fcf_buffer, 4)) {
fcf_in_data_valid = false;
LOG_INFO("Flash protection requested in programmed file differs from current setting.");
}
if (fcf_in_data[FCF_FDPROT] != fcf_buffer[FCF_FDPROT]) {
fcf_in_data_valid = false;
LOG_INFO("Data flash protection requested in programmed file differs from current setting.");
}
if ((fcf_in_data[FCF_FSEC] & 3) != 2) {
fcf_in_data_valid = false;
LOG_INFO("Device security requested in programmed file!");
} else if (k_chip->flash_support & FS_ECC
&& fcf_in_data[FCF_FSEC] != fcf_buffer[FCF_FSEC]) {
fcf_in_data_valid = false;
LOG_INFO("Strange unsecure mode 0x%02" PRIx8
"requested in programmed file!",
fcf_in_data[FCF_FSEC]);
}
if ((k_chip->flash_support & FS_ECC || fcf_fopt_configured)
&& fcf_in_data[FCF_FOPT] != fcf_fopt) {
fcf_in_data_valid = false;
LOG_INFO("FOPT requested in programmed file differs from current setting.");
}
if (!fcf_in_data_valid)
LOG_INFO("Expect verify errors at FCF (0x408-0x40f).");
}
}
if (set_fcf && !fcf_in_data_valid) {
if (offset < FCF_ADDRESS) { if (offset < FCF_ADDRESS) {
/* write part preceding FCF */ /* write part preceding FCF */
result = kinetis_write_inner(bank, buffer, offset, FCF_ADDRESS - offset); result = kinetis_write_inner(bank, buffer, offset, FCF_ADDRESS - offset);
@ -1937,9 +1973,10 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer,
} }
return result; return result;
} else } else {
/* no FCF fiddling, normal write */ /* no FCF fiddling, normal write */
return kinetis_write_inner(bank, buffer, offset, count); return kinetis_write_inner(bank, buffer, offset, count);
}
} }
@ -2146,10 +2183,21 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
k_chip->nvm_sector_size = 4<<10; k_chip->nvm_sector_size = 4<<10;
k_chip->max_flash_prog_size = 1<<10; k_chip->max_flash_prog_size = 1<<10;
num_blocks = 4; num_blocks = 4;
k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_ECC;
cpu_mhz = 180; cpu_mhz = 180;
break; break;
case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX7:
/* K27FN2M0 */
case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX8:
/* K28FN2M0 */
k_chip->pflash_sector_size = 4<<10;
k_chip->max_flash_prog_size = 1<<10;
num_blocks = 4;
k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_ECC;
cpu_mhz = 150;
break;
case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX0: case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX0:
case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX1: case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX1:
case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX2: case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX2:
@ -2300,7 +2348,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
k_chip->max_flash_prog_size = 1<<10; k_chip->max_flash_prog_size = 1<<10;
num_blocks = 1; num_blocks = 1;
maxaddr_shift = 14; maxaddr_shift = 14;
k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_WIDTH_256BIT; k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_WIDTH_256BIT | FS_ECC;
k_chip->pflash_base = 0x10000000; k_chip->pflash_base = 0x10000000;
k_chip->progr_accel_ram = 0x18000000; k_chip->progr_accel_ram = 0x18000000;
cpu_mhz = 240; cpu_mhz = 240;
@ -2959,10 +3007,12 @@ COMMAND_HANDLER(kinetis_fopt_handler)
if (CMD_ARGC > 1) if (CMD_ARGC > 1)
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
if (CMD_ARGC == 1) if (CMD_ARGC == 1) {
fcf_fopt = (uint8_t)strtoul(CMD_ARGV[0], NULL, 0); fcf_fopt = (uint8_t)strtoul(CMD_ARGV[0], NULL, 0);
else fcf_fopt_configured = true;
} else {
command_print(CMD_CTX, "FCF_FOPT 0x%02" PRIx8, fcf_fopt); command_print(CMD_CTX, "FCF_FOPT 0x%02" PRIx8, fcf_fopt);
}
return ERROR_OK; return ERROR_OK;
} }

View File

@ -168,6 +168,7 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = {
/* nRF51822 Devices (IC rev 3). */ /* nRF51822 Devices (IC rev 3). */
NRF5_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), NRF5_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256),
NRF5_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256),
NRF5_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), NRF5_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128),
NRF5_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), NRF5_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256),
NRF5_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), NRF5_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256),

View File

@ -652,6 +652,9 @@ static int stm32l4_probe(struct flash_bank *bank)
/* get options to for DUAL BANK. */ /* get options to for DUAL BANK. */
retval = target_read_u32(target, STM32_FLASH_OPTR, &options); retval = target_read_u32(target, STM32_FLASH_OPTR, &options);
if (retval != ERROR_OK)
return retval;
/* only devices with < 1024 kiB may be set to single bank dual banks */ /* only devices with < 1024 kiB may be set to single bank dual banks */
if ((flash_size_in_kb == 1024) || !(options & OPT_DUALBANK)) if ((flash_size_in_kb == 1024) || !(options & OPT_DUALBANK))
stm32l4_info->option_bytes.bank_b_start = 256; stm32l4_info->option_bytes.bank_b_start = 256;

897
src/flash/nor/xcf.c Normal file
View File

@ -0,0 +1,897 @@
/***************************************************************************
* Copyright (C) 2016 by Uladzimir Pylinski aka barthess *
* barthess@yandex.ru *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "imp.h"
#include <jtag/jtag.h>
#include <helper/time_support.h>
/*
******************************************************************************
* DEFINES
******************************************************************************
*/
#define SECTOR_ERASE_TIMEOUT_MS (35 * 1000)
#define XCF_PAGE_SIZE 32
#define XCF_DATA_SECTOR_SIZE (1024 * 1024)
#define ID_XCF01S 0x05044093
#define ID_XCF02S 0x05045093
#define ID_XCF04S 0x05046093
#define ID_XCF08P 0x05057093
#define ID_XCF16P 0x05058093
#define ID_XCF32P 0x05059093
#define ID_MEANINGFUL_MASK 0x0FFFFFFF
const char *xcf_name_list[] = {
"XCF08P",
"XCF16P",
"XCF32P",
"unknown"
};
struct xcf_priv {
bool probed;
};
struct xcf_status {
bool isc_error; /* false == OK, true == error */
bool prog_error; /* false == OK, true == error */
bool prog_busy; /* false == idle, true == busy */
bool isc_mode; /* false == normal mode, true == ISC mode */
};
/*
******************************************************************************
* GLOBAL VARIABLES
******************************************************************************
*/
static const uint8_t CMD_BYPASS[2] = {0xFF, 0xFF};
static const uint8_t CMD_ISC_ADDRESS_SHIFT[2] = {0xEB, 0x00};
static const uint8_t CMD_ISC_DATA_SHIFT[2] = {0xED, 0x00};
static const uint8_t CMD_ISC_DISABLE[2] = {0xF0, 0x00};
static const uint8_t CMD_ISC_ENABLE[2] = {0xE8, 0x00};
static const uint8_t CMD_ISC_ERASE[2] = {0xEC, 0x00};
static const uint8_t CMD_ISC_PROGRAM[2] = {0xEA, 0x00};
static const uint8_t CMD_XSC_BLANK_CHECK[2] = {0x0D, 0x00};
static const uint8_t CMD_XSC_CONFIG[2] = {0xEE, 0x00};
static const uint8_t CMD_XSC_DATA_BTC[2] = {0xF2, 0x00};
static const uint8_t CMD_XSC_DATA_CCB[2] = {0x0C, 0x00};
static const uint8_t CMD_XSC_DATA_DONE[2] = {0x09, 0x00};
static const uint8_t CMD_XSC_DATA_SUCR[2] = {0x0E, 0x00};
static const uint8_t CMD_XSC_DATA_WRPT[2] = {0xF7, 0x00};
static const uint8_t CMD_XSC_OP_STATUS[2] = {0xE3, 0x00};
static const uint8_t CMD_XSC_READ[2] = {0xEF, 0x00};
static const uint8_t CMD_XSC_UNLOCK[2] = {0x55, 0xAA};
/*
******************************************************************************
* LOCAL FUNCTIONS
******************************************************************************
*/
static const char *product_name(const struct flash_bank *bank)
{
switch (bank->target->tap->idcode & ID_MEANINGFUL_MASK) {
case ID_XCF08P:
return xcf_name_list[0];
case ID_XCF16P:
return xcf_name_list[1];
case ID_XCF32P:
return xcf_name_list[2];
default:
return xcf_name_list[3];
}
}
static void fill_sector_table(struct flash_bank *bank)
{
/* Note: is_erased and is_protected fields must be set here to an unknown
* state, they will be correctly filled from other API calls. */
int i = 0;
for (i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = -1;
}
for (i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].size = XCF_DATA_SECTOR_SIZE;
bank->sectors[i].offset = i * XCF_DATA_SECTOR_SIZE;
}
bank->size = bank->num_sectors * XCF_DATA_SECTOR_SIZE;
}
static struct xcf_status read_status(struct flash_bank *bank)
{
struct xcf_status ret;
uint8_t irdata[2];
struct scan_field scan;
scan.check_mask = NULL;
scan.check_value = NULL;
scan.num_bits = 16;
scan.out_value = CMD_BYPASS;
scan.in_value = irdata;
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
jtag_execute_queue();
ret.isc_error = ((irdata[0] >> 7) & 3) == 0b01;
ret.prog_error = ((irdata[0] >> 5) & 3) == 0b01;
ret.prog_busy = ((irdata[0] >> 4) & 1) == 0;
ret.isc_mode = ((irdata[0] >> 3) & 1) == 1;
return ret;
}
static int isc_enter(struct flash_bank *bank)
{
struct xcf_status status = read_status(bank);
if (true == status.isc_mode)
return ERROR_OK;
else {
struct scan_field scan;
scan.check_mask = NULL;
scan.check_value = NULL;
scan.num_bits = 16;
scan.out_value = CMD_ISC_ENABLE;
scan.in_value = NULL;
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
jtag_execute_queue();
status = read_status(bank);
if (false == status.isc_mode) {
LOG_ERROR("*** XCF: FAILED to enter ISC mode");
return ERROR_FLASH_OPERATION_FAILED;
}
return ERROR_OK;
}
}
static int isc_leave(struct flash_bank *bank)
{
struct xcf_status status = read_status(bank);
if (false == status.isc_mode)
return ERROR_OK;
else {
struct scan_field scan;
scan.check_mask = NULL;
scan.check_value = NULL;
scan.num_bits = 16;
scan.out_value = CMD_ISC_DISABLE;
scan.in_value = NULL;
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
jtag_execute_queue();
alive_sleep(1); /* device needs 50 uS to leave ISC mode */
status = read_status(bank);
if (true == status.isc_mode) {
LOG_ERROR("*** XCF: FAILED to leave ISC mode");
return ERROR_FLASH_OPERATION_FAILED;
}
return ERROR_OK;
}
}
static int sector_state(uint8_t wrpt, int sector)
{
if (((wrpt >> sector) & 1) == 1)
return 0;
else
return 1;
}
static uint8_t fill_select_block(int first, int last)
{
uint8_t ret = 0;
for (int i = first; i <= last; i++)
ret |= 1 << i;
return ret;
}
static int isc_read_register(struct flash_bank *bank, const uint8_t *cmd,
uint8_t *data_buf, int num_bits)
{
struct scan_field scan;
scan.check_mask = NULL;
scan.check_value = NULL;
scan.out_value = cmd;
scan.in_value = NULL;
scan.num_bits = 16;
jtag_add_ir_scan(bank->target->tap, &scan, TAP_DRSHIFT);
scan.out_value = NULL;
scan.in_value = data_buf;
scan.num_bits = num_bits;
jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE);
return jtag_execute_queue();
}
static int isc_wait_erase_program(struct flash_bank *bank, int64_t timeout_ms)
{
uint8_t isc_default;
int64_t t0 = timeval_ms();
int64_t dt;
do {
isc_read_register(bank, CMD_XSC_OP_STATUS, &isc_default, 8);
if (((isc_default >> 2) & 1) == 1)
return ERROR_OK;
dt = timeval_ms() - t0;
} while (dt <= timeout_ms);
return ERROR_FLASH_OPERATION_FAILED;
}
/*
* helper function for procedures without program jtag command at the end
*/
static int isc_set_register(struct flash_bank *bank, const uint8_t *cmd,
const uint8_t *data_buf, int num_bits, int64_t timeout_ms)
{
struct scan_field scan;
scan.check_mask = NULL;
scan.check_value = NULL;
scan.num_bits = 16;
scan.out_value = cmd;
scan.in_value = NULL;
jtag_add_ir_scan(bank->target->tap, &scan, TAP_DRSHIFT);
scan.num_bits = num_bits;
scan.out_value = data_buf;
scan.in_value = NULL;
jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE);
if (0 == timeout_ms)
return jtag_execute_queue();
else
return isc_wait_erase_program(bank, timeout_ms);
}
/*
* helper function for procedures required program jtag command at the end
*/
static int isc_program_register(struct flash_bank *bank, const uint8_t *cmd,
const uint8_t *data_buf, int num_bits, int64_t timeout_ms)
{
struct scan_field scan;
scan.check_mask = NULL;
scan.check_value = NULL;
scan.num_bits = 16;
scan.out_value = cmd;
scan.in_value = NULL;
jtag_add_ir_scan(bank->target->tap, &scan, TAP_DRSHIFT);
scan.num_bits = num_bits;
scan.out_value = data_buf;
scan.in_value = NULL;
jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IRSHIFT);
scan.num_bits = 16;
scan.out_value = CMD_ISC_PROGRAM;
scan.in_value = NULL;
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
if (0 == timeout_ms)
return jtag_execute_queue();
else
return isc_wait_erase_program(bank, timeout_ms);
}
static int isc_clear_protect(struct flash_bank *bank, int first, int last)
{
uint8_t select_block[3] = {0x0, 0x0, 0x0};
select_block[0] = fill_select_block(first, last);
return isc_set_register(bank, CMD_XSC_UNLOCK, select_block, 24, 0);
}
static int isc_set_protect(struct flash_bank *bank, int first, int last)
{
uint8_t wrpt[2] = {0xFF, 0xFF};
for (int i = first; i <= last; i++)
wrpt[0] &= ~(1 << i);
return isc_program_register(bank, CMD_XSC_DATA_WRPT, wrpt, 16, 0);
}
static int isc_erase_sectors(struct flash_bank *bank, int first, int last)
{
uint8_t select_block[3] = {0, 0, 0};
select_block[0] = fill_select_block(first, last);
int64_t timeout = SECTOR_ERASE_TIMEOUT_MS * (last - first + 1);
return isc_set_register(bank, CMD_ISC_ERASE, select_block, 24, timeout);
}
static int isc_adr_shift(struct flash_bank *bank, int adr)
{
uint8_t adr_buf[3];
h_u24_to_le(adr_buf, adr);
return isc_set_register(bank, CMD_ISC_ADDRESS_SHIFT, adr_buf, 24, 0);
}
static int isc_program_data_page(struct flash_bank *bank, const uint8_t *page_buf)
{
return isc_program_register(bank, CMD_ISC_DATA_SHIFT, page_buf, 8 * XCF_PAGE_SIZE, 100);
}
static void isc_data_read_out(struct flash_bank *bank, uint8_t *buffer, uint32_t count)
{
struct scan_field scan;
/* Do not change this code with isc_read_register() call because it needs
* transition to IDLE state before data retrieving. */
scan.check_mask = NULL;
scan.check_value = NULL;
scan.num_bits = 16;
scan.out_value = CMD_XSC_READ;
scan.in_value = NULL;
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
scan.num_bits = 8 * count;
scan.out_value = NULL;
scan.in_value = buffer;
jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE);
jtag_execute_queue();
}
static int isc_set_data_done(struct flash_bank *bank, int sector)
{
uint8_t done = 0xFF;
done &= ~(1 << sector);
return isc_program_register(bank, CMD_XSC_DATA_DONE, &done, 8, 100);
}
static void flip_u8(uint8_t *out, const uint8_t *in, int len)
{
for (int i = 0; i < len; i++)
out[i] = flip_u32(in[i], 8);
}
/*
* Xilinx bin file contains simple fixed header for automatic bus width detection:
* 16 bytes of 0xFF
* 4 byte sync word 0xAA995566 or (bit reversed) 0x5599AA66 in MSC file
*
* Function presumes need of bit reversing if it can not exactly detects
* the opposite.
*/
bool need_bit_reverse(const uint8_t *buffer)
{
const size_t L = 20;
uint8_t reference[L];
memset(reference, 0xFF, 16);
reference[16] = 0x55;
reference[17] = 0x99;
reference[18] = 0xAA;
reference[19] = 0x66;
if (0 == memcmp(reference, buffer, L))
return false;
else
return true;
}
/*
* The page address to be programmed is determined by loading the
* internal ADDRESS Register using an ISC_ADDRESS_SHIFT instruction sequence.
* The page address automatically increments to the next 256-bit
* page address after each programming sequence until the last address
* in the 8 Mb block is reached. To continue programming the next block,
* the next 8 Mb block's starting address must be loaded into the
* internal ADDRESS register.
*/
static int read_write_data(struct flash_bank *bank, const uint8_t *w_buffer,
uint8_t *r_buffer, bool write_flag, uint32_t offset, uint32_t count)
{
int dbg_count = count;
int dbg_written = 0;
int ret = ERROR_OK;
uint8_t *page_buf = malloc(XCF_PAGE_SIZE);
bool revbit = true;
isc_enter(bank);
if (offset % XCF_PAGE_SIZE != 0) {
ret = ERROR_FLASH_DST_BREAKS_ALIGNMENT;
goto EXIT;
}
if ((offset + count) > (uint32_t)(bank->num_sectors * XCF_DATA_SECTOR_SIZE)) {
ret = ERROR_FLASH_DST_OUT_OF_BANK;
goto EXIT;
}
if ((write_flag) && (0 == offset) && (count >= XCF_PAGE_SIZE))
revbit = need_bit_reverse(w_buffer);
while (count > 0) {
uint32_t sector_num = offset / XCF_DATA_SECTOR_SIZE;
uint32_t sector_offset = offset - sector_num * XCF_DATA_SECTOR_SIZE;
uint32_t sector_bytes = XCF_DATA_SECTOR_SIZE - sector_offset;
if (count < sector_bytes)
sector_bytes = count;
isc_adr_shift(bank, offset);
offset += sector_bytes;
count -= sector_bytes;
if (write_flag) {
while (sector_bytes > 0) {
int len;
if (sector_bytes < XCF_PAGE_SIZE) {
len = sector_bytes;
memset(page_buf, 0xFF, XCF_PAGE_SIZE);
} else
len = XCF_PAGE_SIZE;
if (revbit)
flip_u8(page_buf, w_buffer, len);
else
memcpy(page_buf, w_buffer, len);
w_buffer += len;
sector_bytes -= len;
ret = isc_program_data_page(bank, page_buf);
if (ERROR_OK != ret)
goto EXIT;
else {
LOG_DEBUG("written %d bytes from %d", dbg_written, dbg_count);
dbg_written += len;
}
}
} else {
isc_data_read_out(bank, r_buffer, sector_bytes);
flip_u8(r_buffer, r_buffer, sector_bytes);
r_buffer += sector_bytes;
}
}
/* Set 'done' flags for all data sectors because driver supports
* only single revision. */
if (write_flag) {
for (int i = 0; i < bank->num_sectors; i++) {
ret = isc_set_data_done(bank, i);
if (ERROR_OK != ret)
goto EXIT;
}
}
EXIT:
free(page_buf);
isc_leave(bank);
return ret;
}
static uint16_t isc_read_ccb(struct flash_bank *bank)
{
uint8_t ccb[2];
isc_read_register(bank, CMD_XSC_DATA_CCB, ccb, 16);
return le_to_h_u16(ccb);
}
static int gucr_num(const struct flash_bank *bank)
{
return bank->num_sectors;
}
static int sucr_num(const struct flash_bank *bank)
{
return bank->num_sectors + 1;
}
static int isc_program_ccb(struct flash_bank *bank, uint16_t ccb)
{
uint8_t buf[2];
h_u16_to_le(buf, ccb);
return isc_program_register(bank, CMD_XSC_DATA_CCB, buf, 16, 100);
}
static int isc_program_singe_revision_sucr(struct flash_bank *bank)
{
uint8_t sucr[2] = {0xFC, 0xFF};
return isc_program_register(bank, CMD_XSC_DATA_SUCR, sucr, 16, 100);
}
static int isc_program_single_revision_btc(struct flash_bank *bank)
{
uint8_t buf[4];
uint32_t btc = 0xFFFFFFFF;
btc &= ~0b1111;
btc |= ((bank->num_sectors - 1) << 2);
btc &= ~(1 << 4);
h_u32_to_le(buf, btc);
return isc_program_register(bank, CMD_XSC_DATA_BTC, buf, 32, 100);
}
static int fpga_configure(struct flash_bank *bank)
{
struct scan_field scan;
scan.check_mask = NULL;
scan.check_value = NULL;
scan.num_bits = 16;
scan.out_value = CMD_XSC_CONFIG;
scan.in_value = NULL;
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
jtag_execute_queue();
return ERROR_OK;
}
/*
******************************************************************************
* EXPORTED FUNCTIONS
******************************************************************************
*/
FLASH_BANK_COMMAND_HANDLER(xcf_flash_bank_command)
{
struct xcf_priv *priv;
priv = malloc(sizeof(struct xcf_priv));
if (priv == NULL) {
LOG_ERROR("no memory for flash bank info");
return ERROR_FAIL;
}
bank->driver_priv = priv;
priv->probed = false;
return ERROR_OK;
}
static int xcf_info(struct flash_bank *bank, char *buf, int buf_size)
{
const struct xcf_priv *priv = bank->driver_priv;
if (false == priv->probed) {
snprintf(buf, buf_size, "\nXCF flash bank not probed yet\n");
return ERROR_OK;
}
snprintf(buf, buf_size, "%s", product_name(bank));
return ERROR_OK;
}
static int xcf_probe(struct flash_bank *bank)
{
struct xcf_priv *priv = bank->driver_priv;
uint32_t id;
if (true == priv->probed)
free(bank->sectors);
priv->probed = false;
if (bank->target->tap == NULL) {
LOG_ERROR("Target has no JTAG tap");
return ERROR_FAIL;
}
/* check idcode and alloc memory for sector table */
if (!bank->target->tap->hasidcode)
return ERROR_FLASH_OPERATION_FAILED;
/* guess number of blocks using chip ID */
id = bank->target->tap->idcode;
switch (id & ID_MEANINGFUL_MASK) {
case ID_XCF08P:
bank->num_sectors = 1;
break;
case ID_XCF16P:
bank->num_sectors = 2;
break;
case ID_XCF32P:
bank->num_sectors = 4;
break;
default:
LOG_ERROR("Unknown flash device ID 0x%X", id);
return ERROR_FAIL;
break;
}
bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector));
if (NULL == bank->sectors) {
LOG_ERROR("No memory for sector table");
return ERROR_FAIL;
}
fill_sector_table(bank);
priv->probed = true;
bank->driver_priv = priv;
LOG_INFO("product name: %s", product_name(bank));
LOG_INFO("device id = 0x%X ", bank->target->tap->idcode);
LOG_INFO("flash size = %d configuration bits",
bank->num_sectors * XCF_DATA_SECTOR_SIZE * 8);
LOG_INFO("number of sectors = %d", bank->num_sectors);
return ERROR_OK;
}
static int xcf_auto_probe(struct flash_bank *bank)
{
struct xcf_priv *priv = bank->driver_priv;
if (true == priv->probed)
return ERROR_OK;
else
return xcf_probe(bank);
}
static int xcf_protect_check(struct flash_bank *bank)
{
uint8_t wrpt[2];
isc_enter(bank);
isc_read_register(bank, CMD_XSC_DATA_WRPT, wrpt, 16);
isc_leave(bank);
for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_protected = sector_state(wrpt[0], i);
return ERROR_OK;
}
static int xcf_erase_check(struct flash_bank *bank)
{
uint8_t blankreg;
struct scan_field scan;
isc_enter(bank);
/* Do not change this code with isc_read_register() call because it needs
* transition to IDLE state and pause before data retrieving. */
scan.check_mask = NULL;
scan.check_value = NULL;
scan.num_bits = 16;
scan.out_value = CMD_XSC_BLANK_CHECK;
scan.in_value = NULL;
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
jtag_execute_queue();
alive_sleep(500); /* device needs at least 0.5s to self check */
scan.num_bits = 8;
scan.in_value = &blankreg;
jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE);
jtag_execute_queue();
isc_leave(bank);
for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = sector_state(blankreg, i);
return ERROR_OK;
}
static int xcf_erase(struct flash_bank *bank, int first, int last)
{
if ((first >= bank->num_sectors)
|| (last >= bank->num_sectors)
|| (last < first))
return ERROR_FLASH_SECTOR_INVALID;
else {
isc_enter(bank);
isc_clear_protect(bank, first, last);
int ret = isc_erase_sectors(bank, first, last);
isc_leave(bank);
return ret;
}
}
static int xcf_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
return read_write_data(bank, NULL, buffer, false, offset, count);
}
static int xcf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset,
uint32_t count)
{
return read_write_data(bank, buffer, NULL, true, offset, count);
}
static int xcf_protect(struct flash_bank *bank, int set, int first, int last)
{
int ret;
isc_enter(bank);
if (set)
ret = isc_set_protect(bank, first, last);
else {
/* write protection may be removed only with following erase */
isc_clear_protect(bank, first, last);
ret = isc_erase_sectors(bank, first, last);
}
isc_leave(bank);
return ret;
}
COMMAND_HANDLER(xcf_handle_ccb_command) {
if (!((CMD_ARGC == 1) || (CMD_ARGC == 5)))
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
uint16_t ccb = 0xFFFF;
isc_enter(bank);
uint16_t old_ccb = isc_read_ccb(bank);
isc_leave(bank);
if (CMD_ARGC == 1) {
LOG_INFO("current CCB = 0x%X", old_ccb);
return ERROR_OK;
} else {
/* skip over flash bank */
CMD_ARGC--;
CMD_ARGV++;
while (CMD_ARGC) {
if (strcmp("external", CMD_ARGV[0]) == 0)
ccb |= (1 << 0);
else if (strcmp("internal", CMD_ARGV[0]) == 0)
ccb &= ~(1 << 0);
else if (strcmp("serial", CMD_ARGV[0]) == 0)
ccb |= (3 << 1);
else if (strcmp("parallel", CMD_ARGV[0]) == 0)
ccb &= ~(3 << 1);
else if (strcmp("slave", CMD_ARGV[0]) == 0)
ccb |= (1 << 3);
else if (strcmp("master", CMD_ARGV[0]) == 0)
ccb &= ~(1 << 3);
else if (strcmp("40", CMD_ARGV[0]) == 0)
ccb |= (3 << 4);
else if (strcmp("20", CMD_ARGV[0]) == 0)
ccb &= ~(1 << 5);
else
return ERROR_COMMAND_SYNTAX_ERROR;
CMD_ARGC--;
CMD_ARGV++;
}
isc_enter(bank);
int sector;
/* GUCR sector */
sector = gucr_num(bank);
isc_clear_protect(bank, sector, sector);
int ret = isc_erase_sectors(bank, sector, sector);
if (ERROR_OK != ret)
goto EXIT;
ret = isc_program_ccb(bank, ccb);
if (ERROR_OK != ret)
goto EXIT;
ret = isc_program_single_revision_btc(bank);
if (ERROR_OK != ret)
goto EXIT;
ret = isc_set_data_done(bank, sector);
if (ERROR_OK != ret)
goto EXIT;
/* SUCR sector */
sector = sucr_num(bank);
isc_clear_protect(bank, sector, sector);
ret = isc_erase_sectors(bank, sector, sector);
if (ERROR_OK != ret)
goto EXIT;
ret = isc_program_singe_revision_sucr(bank);
if (ERROR_OK != ret)
goto EXIT;
ret = isc_set_data_done(bank, sector);
if (ERROR_OK != ret)
goto EXIT;
EXIT:
isc_leave(bank);
return ret;
}
}
COMMAND_HANDLER(xcf_handle_configure_command) {
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
return fpga_configure(bank);
}
static const struct command_registration xcf_exec_command_handlers[] = {
{
.name = "configure",
.handler = xcf_handle_configure_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.help = "Initiate FPGA loading procedure."
},
{
.name = "ccb",
.handler = xcf_handle_ccb_command,
.mode = COMMAND_EXEC,
.usage = "bank_id [('external'|'internal') "
"('serial'|'parallel') "
"('slave'|'master') "
"('40'|'20')]",
.help = "Write CCB register with supplied options and (silently) BTC "
"register with single revision options. Display current "
"CCB value when only bank_id supplied. "
"Following options available: "
"1) external or internal clock source; "
"2) serial or parallel bus mode; "
"3) slave or master mode; "
"4) clock frequency in MHz for internal clock in master mode;"
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration xcf_command_handlers[] = {
{
.name = "xcf",
.mode = COMMAND_ANY,
.help = "Xilinx platform flash command group",
.usage = "",
.chain = xcf_exec_command_handlers
},
COMMAND_REGISTRATION_DONE
};
struct flash_driver xcf_flash = {
.name = "xcf",
.usage = NULL,
.commands = xcf_command_handlers,
.flash_bank_command = xcf_flash_bank_command,
.erase = xcf_erase,
.protect = xcf_protect,
.write = xcf_write,
.read = xcf_read,
.probe = xcf_probe,
.auto_probe = xcf_auto_probe,
.erase_check = xcf_erase_check,
.protect_check = xcf_protect_check,
.info = xcf_info
};

View File

@ -42,6 +42,7 @@ proc program {filename args} {
# start programming phase # start programming phase
echo "** Programming Started **" echo "** Programming Started **"
set filename \{$filename\}
if {[info exists address]} { if {[info exists address]} {
set flash_args "$filename $address" set flash_args "$filename $address"
} else { } else {
@ -62,8 +63,10 @@ proc program {filename args} {
if {[info exists reset]} { if {[info exists reset]} {
# reset target if requested # reset target if requested
if {$exit == 1} {
# also disable target polling, we are shutting down anyway # also disable target polling, we are shutting down anyway
poll off poll off
}
echo "** Resetting Target **" echo "** Resetting Target **"
reset run reset run
} }

View File

@ -1339,6 +1339,15 @@ struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp
return context; return context;
} }
void command_exit(struct command_context *context)
{
if (!context)
return;
Jim_FreeInterp(context->interp);
command_done(context);
}
int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode) int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode)
{ {
if (!cmd_ctx) if (!cmd_ctx)

View File

@ -307,6 +307,14 @@ struct command_context *current_command_context(Jim_Interp *interp);
* creates a command interpreter. * creates a command interpreter.
*/ */
struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp); struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp);
/**
* Shutdown a command context.
*
* Free the command context and the associated Jim interpreter.
*
* @param context The command_context that will be destroyed.
*/
void command_exit(struct command_context *context);
/** /**
* Creates a copy of an existing command context. This does not create * Creates a copy of an existing command context. This does not create
* a deep copy of the command list, so modifications in one context will * a deep copy of the command list, so modifications in one context will

View File

@ -62,6 +62,21 @@ int timeval_add_time(struct timeval *result, long sec, long usec)
return 0; return 0;
} }
/* compare two timevals and return -1/0/+1 accordingly */
int timeval_compare(const struct timeval *x, const struct timeval *y)
{
if (x->tv_sec < y->tv_sec)
return -1;
else if (x->tv_sec > y->tv_sec)
return 1;
else if (x->tv_usec < y->tv_usec)
return -1;
else if (x->tv_usec > y->tv_usec)
return 1;
else
return 0;
}
int duration_start(struct duration *duration) int duration_start(struct duration *duration)
{ {
return gettimeofday(&duration->start, NULL); return gettimeofday(&duration->start, NULL);

View File

@ -38,6 +38,7 @@
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y); int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
int timeval_add_time(struct timeval *result, long sec, long usec); int timeval_add_time(struct timeval *result, long sec, long usec);
int timeval_compare(const struct timeval *x, const struct timeval *y);
/** @returns gettimeofday() timeval as 64-bit in ms */ /** @returns gettimeofday() timeval as 64-bit in ms */
int64_t timeval_ms(void); int64_t timeval_ms(void);

View File

@ -109,9 +109,9 @@ static uint32_t *pio_base;
/* low level command set /* low level command set
*/ */
static int at91rm9200_read(void); static bb_value_t at91rm9200_read(void);
static void at91rm9200_write(int tck, int tms, int tdi); static int at91rm9200_write(int tck, int tms, int tdi);
static void at91rm9200_reset(int trst, int srst); static int at91rm9200_reset(int trst, int srst);
static int at91rm9200_init(void); static int at91rm9200_init(void);
static int at91rm9200_quit(void); static int at91rm9200_quit(void);
@ -123,12 +123,12 @@ static struct bitbang_interface at91rm9200_bitbang = {
.blink = 0 .blink = 0
}; };
static int at91rm9200_read(void) static bb_value_t at91rm9200_read(void)
{ {
return (pio_base[device->TDO_PIO + PIO_PDSR] & device->TDO_MASK) != 0; return (pio_base[device->TDO_PIO + PIO_PDSR] & device->TDO_MASK) ? BB_HIGH : BB_LOW;
} }
static void at91rm9200_write(int tck, int tms, int tdi) static int at91rm9200_write(int tck, int tms, int tdi)
{ {
if (tck) if (tck)
pio_base[device->TCK_PIO + PIO_SODR] = device->TCK_MASK; pio_base[device->TCK_PIO + PIO_SODR] = device->TCK_MASK;
@ -144,10 +144,12 @@ static void at91rm9200_write(int tck, int tms, int tdi)
pio_base[device->TDI_PIO + PIO_SODR] = device->TDI_MASK; pio_base[device->TDI_PIO + PIO_SODR] = device->TDI_MASK;
else else
pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK; pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK;
return ERROR_OK;
} }
/* (1) assert or (0) deassert reset lines */ /* (1) assert or (0) deassert reset lines */
static void at91rm9200_reset(int trst, int srst) static int at91rm9200_reset(int trst, int srst)
{ {
if (trst == 0) if (trst == 0)
pio_base[device->TRST_PIO + PIO_SODR] = device->TRST_MASK; pio_base[device->TRST_PIO + PIO_SODR] = device->TRST_MASK;
@ -158,6 +160,8 @@ static void at91rm9200_reset(int trst, int srst)
pio_base[device->SRST_PIO + PIO_SODR] = device->SRST_MASK; pio_base[device->SRST_PIO + PIO_SODR] = device->SRST_MASK;
else if (srst == 1) else if (srst == 1)
pio_base[device->SRST_PIO + PIO_CODR] = device->SRST_MASK; pio_base[device->SRST_PIO + PIO_CODR] = device->SRST_MASK;
return ERROR_OK;
} }
COMMAND_HANDLER(at91rm9200_handle_device_command) COMMAND_HANDLER(at91rm9200_handle_device_command)

View File

@ -49,9 +49,9 @@ uint32_t bcm2835_peri_base = 0x20000000;
static int dev_mem_fd; static int dev_mem_fd;
static volatile uint32_t *pio_base; static volatile uint32_t *pio_base;
static int bcm2835gpio_read(void); static bb_value_t bcm2835gpio_read(void);
static void bcm2835gpio_write(int tck, int tms, int tdi); static int bcm2835gpio_write(int tck, int tms, int tdi);
static void bcm2835gpio_reset(int trst, int srst); static int bcm2835gpio_reset(int trst, int srst);
static int bcm2835_swdio_read(void); static int bcm2835_swdio_read(void);
static void bcm2835_swdio_drive(bool is_output); static void bcm2835_swdio_drive(bool is_output);
@ -91,12 +91,12 @@ static int speed_coeff = 113714;
static int speed_offset = 28; static int speed_offset = 28;
static unsigned int jtag_delay; static unsigned int jtag_delay;
static int bcm2835gpio_read(void) static bb_value_t bcm2835gpio_read(void)
{ {
return !!(GPIO_LEV & 1<<tdo_gpio); return (GPIO_LEV & 1<<tdo_gpio) ? BB_HIGH : BB_LOW;
} }
static void bcm2835gpio_write(int tck, int tms, int tdi) static int bcm2835gpio_write(int tck, int tms, int tdi)
{ {
uint32_t set = tck<<tck_gpio | tms<<tms_gpio | tdi<<tdi_gpio; uint32_t set = tck<<tck_gpio | tms<<tms_gpio | tdi<<tdi_gpio;
uint32_t clear = !tck<<tck_gpio | !tms<<tms_gpio | !tdi<<tdi_gpio; uint32_t clear = !tck<<tck_gpio | !tms<<tms_gpio | !tdi<<tdi_gpio;
@ -106,9 +106,11 @@ static void bcm2835gpio_write(int tck, int tms, int tdi)
for (unsigned int i = 0; i < jtag_delay; i++) for (unsigned int i = 0; i < jtag_delay; i++)
asm volatile (""); asm volatile ("");
return ERROR_OK;
} }
static void bcm2835gpio_swd_write(int tck, int tms, int tdi) static int bcm2835gpio_swd_write(int tck, int tms, int tdi)
{ {
uint32_t set = tck<<swclk_gpio | tdi<<swdio_gpio; uint32_t set = tck<<swclk_gpio | tdi<<swdio_gpio;
uint32_t clear = !tck<<swclk_gpio | !tdi<<swdio_gpio; uint32_t clear = !tck<<swclk_gpio | !tdi<<swdio_gpio;
@ -118,10 +120,12 @@ static void bcm2835gpio_swd_write(int tck, int tms, int tdi)
for (unsigned int i = 0; i < jtag_delay; i++) for (unsigned int i = 0; i < jtag_delay; i++)
asm volatile (""); asm volatile ("");
return ERROR_OK;
} }
/* (1) assert or (0) deassert reset lines */ /* (1) assert or (0) deassert reset lines */
static void bcm2835gpio_reset(int trst, int srst) static int bcm2835gpio_reset(int trst, int srst)
{ {
uint32_t set = 0; uint32_t set = 0;
uint32_t clear = 0; uint32_t clear = 0;
@ -138,6 +142,8 @@ static void bcm2835gpio_reset(int trst, int srst)
GPIO_SET = set; GPIO_SET = set;
GPIO_CLR = clear; GPIO_CLR = clear;
return ERROR_OK;
} }
static void bcm2835_swdio_drive(bool is_output) static void bcm2835_swdio_drive(bool is_output)
@ -432,10 +438,6 @@ static int bcm2835gpio_init(void)
LOG_INFO("JTAG and SWD modes enabled"); LOG_INFO("JTAG and SWD modes enabled");
else else
LOG_INFO("JTAG only mode enabled (specify swclk and swdio gpio to add SWD mode)"); LOG_INFO("JTAG only mode enabled (specify swclk and swdio gpio to add SWD mode)");
if (!is_gpio_valid(trst_gpio) && !is_gpio_valid(srst_gpio)) {
LOG_ERROR("Require at least one of trst or srst gpios to be specified");
return ERROR_JTAG_INIT_FAILED;
}
} else if (bcm2835gpio_swd_mode_possible()) { } else if (bcm2835gpio_swd_mode_possible()) {
LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)"); LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)");
} else { } else {

View File

@ -41,7 +41,7 @@ extern struct jtag_interface *jtag_interface;
* this function checks the current stable state to decide on the value of TMS * this function checks the current stable state to decide on the value of TMS
* to use. * to use.
*/ */
static void bitbang_stableclocks(int num_cycles); static int bitbang_stableclocks(int num_cycles);
static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk); static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk);
@ -70,15 +70,11 @@ struct bitbang_interface *bitbang_interface;
/* The bitbang driver leaves the TCK 0 when in idle */ /* The bitbang driver leaves the TCK 0 when in idle */
static void bitbang_end_state(tap_state_t state) static void bitbang_end_state(tap_state_t state)
{ {
if (tap_is_state_stable(state)) assert(tap_is_state_stable(state));
tap_set_end_state(state); tap_set_end_state(state);
else {
LOG_ERROR("BUG: %i is not a valid end state", state);
exit(-1);
}
} }
static void bitbang_state_move(int skip) static int bitbang_state_move(int skip)
{ {
int i = 0, tms = 0; int i = 0, tms = 0;
uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state());
@ -86,12 +82,16 @@ static void bitbang_state_move(int skip)
for (i = skip; i < tms_count; i++) { for (i = skip; i < tms_count; i++) {
tms = (tms_scan >> i) & 1; tms = (tms_scan >> i) & 1;
bitbang_interface->write(0, tms, 0); if (bitbang_interface->write(0, tms, 0) != ERROR_OK)
bitbang_interface->write(1, tms, 0); return ERROR_FAIL;
if (bitbang_interface->write(1, tms, 0) != ERROR_OK)
return ERROR_FAIL;
} }
bitbang_interface->write(CLOCK_IDLE(), tms, 0); if (bitbang_interface->write(CLOCK_IDLE(), tms, 0) != ERROR_OK)
return ERROR_FAIL;
tap_set_state(tap_get_end_state()); tap_set_state(tap_get_end_state());
return ERROR_OK;
} }
/** /**
@ -108,15 +108,18 @@ static int bitbang_execute_tms(struct jtag_command *cmd)
int tms = 0; int tms = 0;
for (unsigned i = 0; i < num_bits; i++) { for (unsigned i = 0; i < num_bits; i++) {
tms = ((bits[i/8] >> (i % 8)) & 1); tms = ((bits[i/8] >> (i % 8)) & 1);
bitbang_interface->write(0, tms, 0); if (bitbang_interface->write(0, tms, 0) != ERROR_OK)
bitbang_interface->write(1, tms, 0); return ERROR_FAIL;
if (bitbang_interface->write(1, tms, 0) != ERROR_OK)
return ERROR_FAIL;
} }
bitbang_interface->write(CLOCK_IDLE(), tms, 0); if (bitbang_interface->write(CLOCK_IDLE(), tms, 0) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK; return ERROR_OK;
} }
static void bitbang_path_move(struct pathmove_command *cmd) static int bitbang_path_move(struct pathmove_command *cmd)
{ {
int num_states = cmd->num_states; int num_states = cmd->num_states;
int state_count; int state_count;
@ -135,20 +138,24 @@ static void bitbang_path_move(struct pathmove_command *cmd)
exit(-1); exit(-1);
} }
bitbang_interface->write(0, tms, 0); if (bitbang_interface->write(0, tms, 0) != ERROR_OK)
bitbang_interface->write(1, tms, 0); return ERROR_FAIL;
if (bitbang_interface->write(1, tms, 0) != ERROR_OK)
return ERROR_FAIL;
tap_set_state(cmd->path[state_count]); tap_set_state(cmd->path[state_count]);
state_count++; state_count++;
num_states--; num_states--;
} }
bitbang_interface->write(CLOCK_IDLE(), tms, 0); if (bitbang_interface->write(CLOCK_IDLE(), tms, 0) != ERROR_OK)
return ERROR_FAIL;
tap_set_end_state(tap_get_state()); tap_set_end_state(tap_get_state());
return ERROR_OK;
} }
static void bitbang_runtest(int num_cycles) static int bitbang_runtest(int num_cycles)
{ {
int i; int i;
@ -157,35 +164,46 @@ static void bitbang_runtest(int num_cycles)
/* only do a state_move when we're not already in IDLE */ /* only do a state_move when we're not already in IDLE */
if (tap_get_state() != TAP_IDLE) { if (tap_get_state() != TAP_IDLE) {
bitbang_end_state(TAP_IDLE); bitbang_end_state(TAP_IDLE);
bitbang_state_move(0); if (bitbang_state_move(0) != ERROR_OK)
return ERROR_FAIL;
} }
/* execute num_cycles */ /* execute num_cycles */
for (i = 0; i < num_cycles; i++) { for (i = 0; i < num_cycles; i++) {
bitbang_interface->write(0, 0, 0); if (bitbang_interface->write(0, 0, 0) != ERROR_OK)
bitbang_interface->write(1, 0, 0); return ERROR_FAIL;
if (bitbang_interface->write(1, 0, 0) != ERROR_OK)
return ERROR_FAIL;
} }
bitbang_interface->write(CLOCK_IDLE(), 0, 0); if (bitbang_interface->write(CLOCK_IDLE(), 0, 0) != ERROR_OK)
return ERROR_FAIL;
/* finish in end_state */ /* finish in end_state */
bitbang_end_state(saved_end_state); bitbang_end_state(saved_end_state);
if (tap_get_state() != tap_get_end_state()) if (tap_get_state() != tap_get_end_state())
bitbang_state_move(0); if (bitbang_state_move(0) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
} }
static void bitbang_stableclocks(int num_cycles) static int bitbang_stableclocks(int num_cycles)
{ {
int tms = (tap_get_state() == TAP_RESET ? 1 : 0); int tms = (tap_get_state() == TAP_RESET ? 1 : 0);
int i; int i;
/* send num_cycles clocks onto the cable */ /* send num_cycles clocks onto the cable */
for (i = 0; i < num_cycles; i++) { for (i = 0; i < num_cycles; i++) {
bitbang_interface->write(1, tms, 0); if (bitbang_interface->write(1, tms, 0) != ERROR_OK)
bitbang_interface->write(0, tms, 0); return ERROR_FAIL;
if (bitbang_interface->write(0, tms, 0) != ERROR_OK)
return ERROR_FAIL;
} }
return ERROR_OK;
} }
static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, static int bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
unsigned scan_size) unsigned scan_size)
{ {
tap_state_t saved_end_state = tap_get_end_state(); tap_state_t saved_end_state = tap_get_end_state();
@ -199,7 +217,8 @@ static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
else else
bitbang_end_state(TAP_DRSHIFT); bitbang_end_state(TAP_DRSHIFT);
bitbang_state_move(0); if (bitbang_state_move(0) != ERROR_OK)
return ERROR_FAIL;
bitbang_end_state(saved_end_state); bitbang_end_state(saved_end_state);
} }
@ -218,31 +237,45 @@ static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
if ((type != SCAN_IN) && (buffer[bytec] & bcval)) if ((type != SCAN_IN) && (buffer[bytec] & bcval))
tdi = 1; tdi = 1;
bitbang_interface->write(0, tms, tdi); if (bitbang_interface->write(0, tms, tdi) != ERROR_OK)
return ERROR_FAIL;
if (type != SCAN_OUT) { if (type != SCAN_OUT) {
if (bitbang_interface->buf_size) { if (bitbang_interface->buf_size) {
bitbang_interface->sample(); if (bitbang_interface->sample() != ERROR_OK)
return ERROR_FAIL;
buffered++; buffered++;
} else { } else {
int val = bitbang_interface->read(); switch (bitbang_interface->read()) {
if (val) case BB_LOW:
buffer[bytec] |= bcval;
else
buffer[bytec] &= ~bcval; buffer[bytec] &= ~bcval;
break;
case BB_HIGH:
buffer[bytec] |= bcval;
break;
default:
return ERROR_FAIL;
}
} }
} }
bitbang_interface->write(1, tms, tdi); if (bitbang_interface->write(1, tms, tdi) != ERROR_OK)
return ERROR_FAIL;
if (type != SCAN_OUT && bitbang_interface->buf_size && if (type != SCAN_OUT && bitbang_interface->buf_size &&
(buffered == bitbang_interface->buf_size || (buffered == bitbang_interface->buf_size ||
bit_cnt == scan_size - 1)) { bit_cnt == scan_size - 1)) {
for (unsigned i = bit_cnt + 1 - buffered; i <= bit_cnt; i++) { for (unsigned i = bit_cnt + 1 - buffered; i <= bit_cnt; i++) {
if (bitbang_interface->read_sample()) switch (bitbang_interface->read_sample()) {
buffer[i/8] |= 1 << (i % 8); case BB_LOW:
else
buffer[i/8] &= ~(1 << (i % 8)); buffer[i/8] &= ~(1 << (i % 8));
break;
case BB_HIGH:
buffer[i/8] |= 1 << (i % 8);
break;
default:
return ERROR_FAIL;
}
} }
buffered = 0; buffered = 0;
} }
@ -253,8 +286,10 @@ static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
* the shift state, so we skip the first state * the shift state, so we skip the first state
* and move directly to the end state. * and move directly to the end state.
*/ */
bitbang_state_move(1); if (bitbang_state_move(1) != ERROR_OK)
return ERROR_FAIL;
} }
return ERROR_OK;
} }
int bitbang_execute_queue(void) int bitbang_execute_queue(void)
@ -275,8 +310,10 @@ int bitbang_execute_queue(void)
*/ */
retval = ERROR_OK; retval = ERROR_OK;
if (bitbang_interface->blink) if (bitbang_interface->blink) {
bitbang_interface->blink(1); if (bitbang_interface->blink(1) != ERROR_OK)
return ERROR_FAIL;
}
while (cmd) { while (cmd) {
switch (cmd->type) { switch (cmd->type) {
@ -289,7 +326,9 @@ int bitbang_execute_queue(void)
if ((cmd->cmd.reset->trst == 1) || if ((cmd->cmd.reset->trst == 1) ||
(cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
tap_set_state(TAP_RESET); tap_set_state(TAP_RESET);
bitbang_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); if (bitbang_interface->reset(cmd->cmd.reset->trst,
cmd->cmd.reset->srst) != ERROR_OK)
return ERROR_FAIL;
break; break;
case JTAG_RUNTEST: case JTAG_RUNTEST:
#ifdef _DEBUG_JTAG_IO_ #ifdef _DEBUG_JTAG_IO_
@ -298,14 +337,16 @@ int bitbang_execute_queue(void)
tap_state_name(cmd->cmd.runtest->end_state)); tap_state_name(cmd->cmd.runtest->end_state));
#endif #endif
bitbang_end_state(cmd->cmd.runtest->end_state); bitbang_end_state(cmd->cmd.runtest->end_state);
bitbang_runtest(cmd->cmd.runtest->num_cycles); if (bitbang_runtest(cmd->cmd.runtest->num_cycles) != ERROR_OK)
return ERROR_FAIL;
break; break;
case JTAG_STABLECLOCKS: case JTAG_STABLECLOCKS:
/* this is only allowed while in a stable state. A check for a stable /* this is only allowed while in a stable state. A check for a stable
* state was done in jtag_add_clocks() * state was done in jtag_add_clocks()
*/ */
bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles); if (bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles) != ERROR_OK)
return ERROR_FAIL;
break; break;
case JTAG_TLR_RESET: case JTAG_TLR_RESET:
@ -314,7 +355,8 @@ int bitbang_execute_queue(void)
tap_state_name(cmd->cmd.statemove->end_state)); tap_state_name(cmd->cmd.statemove->end_state));
#endif #endif
bitbang_end_state(cmd->cmd.statemove->end_state); bitbang_end_state(cmd->cmd.statemove->end_state);
bitbang_state_move(0); if (bitbang_state_move(0) != ERROR_OK)
return ERROR_FAIL;
break; break;
case JTAG_PATHMOVE: case JTAG_PATHMOVE:
#ifdef _DEBUG_JTAG_IO_ #ifdef _DEBUG_JTAG_IO_
@ -322,7 +364,8 @@ int bitbang_execute_queue(void)
cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->num_states,
tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]));
#endif #endif
bitbang_path_move(cmd->cmd.pathmove); if (bitbang_path_move(cmd->cmd.pathmove) != ERROR_OK)
return ERROR_FAIL;
break; break;
case JTAG_SCAN: case JTAG_SCAN:
bitbang_end_state(cmd->cmd.scan->end_state); bitbang_end_state(cmd->cmd.scan->end_state);
@ -334,7 +377,9 @@ int bitbang_execute_queue(void)
tap_state_name(cmd->cmd.scan->end_state)); tap_state_name(cmd->cmd.scan->end_state));
#endif #endif
type = jtag_scan_type(cmd->cmd.scan); type = jtag_scan_type(cmd->cmd.scan);
bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); if (bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer,
scan_size) != ERROR_OK)
return ERROR_FAIL;
if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
retval = ERROR_JTAG_QUEUE_FAILED; retval = ERROR_JTAG_QUEUE_FAILED;
if (buffer) if (buffer)
@ -355,8 +400,10 @@ int bitbang_execute_queue(void)
} }
cmd = cmd->next; cmd = cmd->next;
} }
if (bitbang_interface->blink) if (bitbang_interface->blink) {
bitbang_interface->blink(0); if (bitbang_interface->blink(0) != ERROR_OK)
return ERROR_FAIL;
}
return retval; return retval;
} }

View File

@ -24,30 +24,35 @@
#include <jtag/swd.h> #include <jtag/swd.h>
typedef enum {
BB_LOW,
BB_HIGH,
BB_ERROR
} bb_value_t;
/** Low level callbacks (for bitbang).
*
* Either read(), or sample() and read_sample() must be implemented.
*
* The sample functions allow an interface to batch a number of writes and
* sample requests together. Not waiting for a value to come back can greatly
* increase throughput. */
struct bitbang_interface { struct bitbang_interface {
/* low level callbacks (for bitbang) /** Sample TDO. */
*/ bb_value_t (*read)(void);
/* Either read() or sample()/read_sample() must be implemented. */ /** The number of TDO samples that can be buffered up before the caller has
/* Sample TDO and return 0 or 1. */
int (*read)(void);
/* The sample functions allow an interface to batch a number of writes and
* sample requests together. Not waiting for a value to come back can
* greatly increase throughput. */
/* The number of TDO samples that can be buffered up before the caller has
* to call read_sample. */ * to call read_sample. */
size_t buf_size; size_t buf_size;
/* Sample TDO and put the result in a buffer. */ /** Sample TDO and put the result in a buffer. */
void (*sample)(void); int (*sample)(void);
/* Return the next unread value from the buffer. */ /** Return the next unread value from the buffer. */
int (*read_sample)(void); bb_value_t (*read_sample)(void);
/* Set TCK, TMS, and TDI to the given values. */ /** Set TCK, TMS, and TDI to the given values. */
void (*write)(int tck, int tms, int tdi); int (*write)(int tck, int tms, int tdi);
void (*reset)(int trst, int srst); int (*reset)(int trst, int srst);
void (*blink)(int on); int (*blink)(int on);
int (*swdio_read)(void); int (*swdio_read)(void);
void (*swdio_drive)(bool on); void (*swdio_drive)(bool on);
}; };

View File

@ -206,6 +206,8 @@ static uint8_t queued_seq_buf[1024]; /* TODO: make dynamic / move into cmsis obj
static int queued_retval; static int queued_retval;
static uint8_t output_pins = SWJ_PIN_SRST | SWJ_PIN_TRST;
static struct cmsis_dap *cmsis_dap_handle; static struct cmsis_dap *cmsis_dap_handle;
static int cmsis_dap_usb_open(void) static int cmsis_dap_usb_open(void)
@ -790,6 +792,11 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
unsigned int s_len; unsigned int s_len;
int retval; int retval;
if ((output_pins & (SWJ_PIN_SRST | SWJ_PIN_TRST)) == (SWJ_PIN_SRST | SWJ_PIN_TRST)) {
/* Following workaround deasserts reset on most adapters.
* Do not reconnect if a reset line is active!
* Reconnecting would break connecting under reset. */
/* First disconnect before connecting, Atmel EDBG needs it for SAMD/R/L/C */ /* First disconnect before connecting, Atmel EDBG needs it for SAMD/R/L/C */
cmsis_dap_cmd_DAP_Disconnect(); cmsis_dap_cmd_DAP_Disconnect();
@ -799,6 +806,7 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
CONNECT_SWD : CONNECT_JTAG); CONNECT_SWD : CONNECT_JTAG);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
}
switch (seq) { switch (seq) {
case LINE_RESET: case LINE_RESET:
@ -1010,14 +1018,14 @@ static void cmsis_dap_execute_reset(struct jtag_command *cmd)
{ {
/* Set both TRST and SRST even if they're not enabled as /* Set both TRST and SRST even if they're not enabled as
* there's no way to tristate them */ * there's no way to tristate them */
uint8_t pins = 0;
output_pins = 0;
if (!cmd->cmd.reset->srst) if (!cmd->cmd.reset->srst)
pins |= SWJ_PIN_SRST; output_pins |= SWJ_PIN_SRST;
if (!cmd->cmd.reset->trst) if (!cmd->cmd.reset->trst)
pins |= SWJ_PIN_TRST; output_pins |= SWJ_PIN_TRST;
int retval = cmsis_dap_cmd_DAP_SWJ_Pins(pins, int retval = cmsis_dap_cmd_DAP_SWJ_Pins(output_pins,
SWJ_PIN_TRST | SWJ_PIN_SRST, 0, NULL); SWJ_PIN_TRST | SWJ_PIN_SRST, 0, NULL);
if (retval != ERROR_OK) if (retval != ERROR_OK)
LOG_ERROR("CMSIS-DAP: Interface reset failed"); LOG_ERROR("CMSIS-DAP: Interface reset failed");

View File

@ -33,14 +33,14 @@ static int clock_count; /* count clocks in any stable state, only stable states
static uint32_t dummy_data; static uint32_t dummy_data;
static int dummy_read(void) static bb_value_t dummy_read(void)
{ {
int data = 1 & dummy_data; int data = 1 & dummy_data;
dummy_data = (dummy_data >> 1) | (1 << 31); dummy_data = (dummy_data >> 1) | (1 << 31);
return data; return data ? BB_HIGH : BB_LOW;
} }
static void dummy_write(int tck, int tms, int tdi) static int dummy_write(int tck, int tms, int tdi)
{ {
/* TAP standard: "state transitions occur on rising edge of clock" */ /* TAP standard: "state transitions occur on rising edge of clock" */
if (tck != dummy_clock) { if (tck != dummy_clock) {
@ -69,9 +69,10 @@ static void dummy_write(int tck, int tms, int tdi)
} }
dummy_clock = tck; dummy_clock = tck;
} }
return ERROR_OK;
} }
static void dummy_reset(int trst, int srst) static int dummy_reset(int trst, int srst)
{ {
dummy_clock = 0; dummy_clock = 0;
@ -79,10 +80,12 @@ static void dummy_reset(int trst, int srst)
dummy_state = TAP_RESET; dummy_state = TAP_RESET;
LOG_DEBUG("reset to: %s", tap_state_name(dummy_state)); LOG_DEBUG("reset to: %s", tap_state_name(dummy_state));
return ERROR_OK;
} }
static void dummy_led(int on) static int dummy_led(int on)
{ {
return ERROR_OK;
} }
static struct bitbang_interface dummy_bitbang = { static struct bitbang_interface dummy_bitbang = {

View File

@ -41,9 +41,9 @@ static volatile uint8_t *gpio_data_direction_register;
/* low level command set /* low level command set
*/ */
static int ep93xx_read(void); static bb_value_t ep93xx_read(void);
static void ep93xx_write(int tck, int tms, int tdi); static int ep93xx_write(int tck, int tms, int tdi);
static void ep93xx_reset(int trst, int srst); static int ep93xx_reset(int trst, int srst);
static int ep93xx_init(void); static int ep93xx_init(void);
static int ep93xx_quit(void); static int ep93xx_quit(void);
@ -67,12 +67,12 @@ static struct bitbang_interface ep93xx_bitbang = {
.blink = 0, .blink = 0,
}; };
static int ep93xx_read(void) static bb_value_t ep93xx_read(void)
{ {
return !!(*gpio_data_register & TDO_BIT); return (*gpio_data_register & TDO_BIT) ? BB_HIGH : BB_LOW;
} }
static void ep93xx_write(int tck, int tms, int tdi) static int ep93xx_write(int tck, int tms, int tdi)
{ {
if (tck) if (tck)
output_value |= TCK_BIT; output_value |= TCK_BIT;
@ -91,10 +91,12 @@ static void ep93xx_write(int tck, int tms, int tdi)
*gpio_data_register = output_value; *gpio_data_register = output_value;
nanosleep(&ep93xx_zzzz, NULL); nanosleep(&ep93xx_zzzz, NULL);
return ERROR_OK;
} }
/* (1) assert or (0) deassert reset lines */ /* (1) assert or (0) deassert reset lines */
static void ep93xx_reset(int trst, int srst) static int ep93xx_reset(int trst, int srst)
{ {
if (trst == 0) if (trst == 0)
output_value |= TRST_BIT; output_value |= TRST_BIT;
@ -108,6 +110,8 @@ static void ep93xx_reset(int trst, int srst)
*gpio_data_register = output_value; *gpio_data_register = output_value;
nanosleep(&ep93xx_zzzz, NULL); nanosleep(&ep93xx_zzzz, NULL);
return ERROR_OK;
} }
static int set_gonk_mode(void) static int set_gonk_mode(void)

View File

@ -1064,8 +1064,19 @@ static int ftdi_swd_init(void)
static void ftdi_swd_swdio_en(bool enable) static void ftdi_swd_swdio_en(bool enable)
{ {
struct signal *oe = find_signal_by_name("SWDIO_OE"); struct signal *oe = find_signal_by_name("SWDIO_OE");
if (oe) if (oe) {
if (oe->data_mask)
ftdi_set_signal(oe, enable ? '1' : '0'); ftdi_set_signal(oe, enable ? '1' : '0');
else {
/* Sets TDI/DO pin (pin 2) to input during rx when both pins are connected
to SWDIO */
if (enable)
direction |= jtag_direction_init & 0x0002U;
else
direction &= ~0x0002U;
mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 0xff);
}
}
} }
/** /**

View File

@ -82,9 +82,9 @@ static inline bool gpio_level(int g)
return pio_base[g / 32].dr >> (g & 0x1F) & 1; return pio_base[g / 32].dr >> (g & 0x1F) & 1;
} }
static int imx_gpio_read(void); static bb_value_t imx_gpio_read(void);
static void imx_gpio_write(int tck, int tms, int tdi); static int imx_gpio_write(int tck, int tms, int tdi);
static void imx_gpio_reset(int trst, int srst); static int imx_gpio_reset(int trst, int srst);
static int imx_gpio_swdio_read(void); static int imx_gpio_swdio_read(void);
static void imx_gpio_swdio_drive(bool is_output); static void imx_gpio_swdio_drive(bool is_output);
@ -128,12 +128,12 @@ static int speed_coeff = 50000;
static int speed_offset = 100; static int speed_offset = 100;
static unsigned int jtag_delay; static unsigned int jtag_delay;
static int imx_gpio_read(void) static bb_value_t imx_gpio_read(void)
{ {
return gpio_level(tdo_gpio); return gpio_level(tdo_gpio) ? BB_HIGH : BB_LOW;
} }
static void imx_gpio_write(int tck, int tms, int tdi) static int imx_gpio_write(int tck, int tms, int tdi)
{ {
tms ? gpio_set(tms_gpio) : gpio_clear(tms_gpio); tms ? gpio_set(tms_gpio) : gpio_clear(tms_gpio);
tdi ? gpio_set(tdi_gpio) : gpio_clear(tdi_gpio); tdi ? gpio_set(tdi_gpio) : gpio_clear(tdi_gpio);
@ -141,25 +141,31 @@ static void imx_gpio_write(int tck, int tms, int tdi)
for (unsigned int i = 0; i < jtag_delay; i++) for (unsigned int i = 0; i < jtag_delay; i++)
asm volatile (""); asm volatile ("");
return ERROR_OK;
} }
static void imx_gpio_swd_write(int tck, int tms, int tdi) static int imx_gpio_swd_write(int tck, int tms, int tdi)
{ {
tdi ? gpio_set(swdio_gpio) : gpio_clear(swdio_gpio); tdi ? gpio_set(swdio_gpio) : gpio_clear(swdio_gpio);
tck ? gpio_set(swclk_gpio) : gpio_clear(swclk_gpio); tck ? gpio_set(swclk_gpio) : gpio_clear(swclk_gpio);
for (unsigned int i = 0; i < jtag_delay; i++) for (unsigned int i = 0; i < jtag_delay; i++)
asm volatile (""); asm volatile ("");
return ERROR_OK;
} }
/* (1) assert or (0) deassert reset lines */ /* (1) assert or (0) deassert reset lines */
static void imx_gpio_reset(int trst, int srst) static int imx_gpio_reset(int trst, int srst)
{ {
if (trst_gpio != -1) if (trst_gpio != -1)
trst ? gpio_set(trst_gpio) : gpio_clear(trst_gpio); trst ? gpio_set(trst_gpio) : gpio_clear(trst_gpio);
if (srst_gpio != -1) if (srst_gpio != -1)
srst ? gpio_set(srst_gpio) : gpio_clear(srst_gpio); srst ? gpio_set(srst_gpio) : gpio_clear(srst_gpio);
return ERROR_OK;
} }
static void imx_gpio_swdio_drive(bool is_output) static void imx_gpio_swdio_drive(bool is_output)
@ -469,7 +475,7 @@ static int imx_gpio_init(void)
LOG_INFO("imx_gpio mmap: pagesize: %u, regionsize: %u", LOG_INFO("imx_gpio mmap: pagesize: %u, regionsize: %u",
sysconf(_SC_PAGE_SIZE), IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE); (unsigned int) sysconf(_SC_PAGE_SIZE), IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE);
pio_base = mmap(NULL, IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE, pio_base = mmap(NULL, IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE,
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
MAP_SHARED, dev_mem_fd, imx_gpio_peri_base); MAP_SHARED, dev_mem_fd, imx_gpio_peri_base);

View File

@ -681,7 +681,7 @@ static int kitprog_swd_run_queue(void)
uint8_t *buffer = kitprog_handle->packet_buffer; uint8_t *buffer = kitprog_handle->packet_buffer;
do { do {
LOG_DEBUG("Executing %d queued transactions", pending_transfer_count); LOG_DEBUG_IO("Executing %d queued transactions", pending_transfer_count);
if (queued_retval != ERROR_OK) { if (queued_retval != ERROR_OK) {
LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
@ -714,12 +714,10 @@ static int kitprog_swd_run_queue(void)
data &= ~CORUNDETECT; data &= ~CORUNDETECT;
} }
#if 0 LOG_DEBUG_IO("%s %s reg %x %"PRIx32,
LOG_DEBUG("%s %s reg %x %"PRIx32,
cmd & SWD_CMD_APnDP ? "AP" : "DP", cmd & SWD_CMD_APnDP ? "AP" : "DP",
cmd & SWD_CMD_RnW ? "read" : "write", cmd & SWD_CMD_RnW ? "read" : "write",
(cmd & SWD_CMD_A32) >> 1, data); (cmd & SWD_CMD_A32) >> 1, data);
#endif
buffer[write_count++] = (cmd | SWD_CMD_START | SWD_CMD_PARK) & ~SWD_CMD_STOP; buffer[write_count++] = (cmd | SWD_CMD_START | SWD_CMD_PARK) & ~SWD_CMD_STOP;
read_count++; read_count++;
@ -764,9 +762,7 @@ static int kitprog_swd_run_queue(void)
if (pending_transfers[i].cmd & SWD_CMD_RnW) { if (pending_transfers[i].cmd & SWD_CMD_RnW) {
uint32_t data = le_to_h_u32(&buffer[read_index]); uint32_t data = le_to_h_u32(&buffer[read_index]);
#if 0 LOG_DEBUG_IO("Read result: %"PRIx32, data);
LOG_DEBUG("Read result: %"PRIx32, data);
#endif
if (pending_transfers[i].buffer) if (pending_transfers[i].buffer)
*(uint32_t *)pending_transfers[i].buffer = data; *(uint32_t *)pending_transfers[i].buffer = data;

View File

@ -116,7 +116,7 @@ static unsigned long dataport;
static unsigned long statusport; static unsigned long statusport;
#endif #endif
static int parport_read(void) static bb_value_t parport_read(void)
{ {
int data = 0; int data = 0;
@ -127,9 +127,9 @@ static int parport_read(void)
#endif #endif
if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK) if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK)
return 1; return BB_HIGH;
else else
return 0; return BB_LOW;
} }
static inline void parport_write_data(void) static inline void parport_write_data(void)
@ -148,7 +148,7 @@ static inline void parport_write_data(void)
#endif #endif
} }
static void parport_write(int tck, int tms, int tdi) static int parport_write(int tck, int tms, int tdi)
{ {
int i = wait_states + 1; int i = wait_states + 1;
@ -169,10 +169,12 @@ static void parport_write(int tck, int tms, int tdi)
while (i-- > 0) while (i-- > 0)
parport_write_data(); parport_write_data();
return ERROR_OK;
} }
/* (1) assert or (0) deassert reset lines */ /* (1) assert or (0) deassert reset lines */
static void parport_reset(int trst, int srst) static int parport_reset(int trst, int srst)
{ {
LOG_DEBUG("trst: %i, srst: %i", trst, srst); LOG_DEBUG("trst: %i, srst: %i", trst, srst);
@ -187,10 +189,12 @@ static void parport_reset(int trst, int srst)
dataport_value &= ~cable->SRST_MASK; dataport_value &= ~cable->SRST_MASK;
parport_write_data(); parport_write_data();
return ERROR_OK;
} }
/* turn LED on parport adapter on (1) or off (0) */ /* turn LED on parport adapter on (1) or off (0) */
static void parport_led(int on) static int parport_led(int on)
{ {
if (on) if (on)
dataport_value |= cable->LED_MASK; dataport_value |= cable->LED_MASK;
@ -198,6 +202,8 @@ static void parport_led(int on)
dataport_value &= ~cable->LED_MASK; dataport_value &= ~cable->LED_MASK;
parport_write_data(); parport_write_data();
return ERROR_OK;
} }
static int parport_speed(int speed) static int parport_speed(int speed)
@ -365,9 +371,12 @@ static int parport_init(void)
#endif /* PARPORT_USE_PPDEV */ #endif /* PARPORT_USE_PPDEV */
parport_reset(0, 0); if (parport_reset(0, 0) != ERROR_OK)
parport_write(0, 0, 0); return ERROR_FAIL;
parport_led(1); if (parport_write(0, 0, 0) != ERROR_OK)
return ERROR_FAIL;
if (parport_led(1) != ERROR_OK)
return ERROR_FAIL;
bitbang_interface = &parport_bitbang; bitbang_interface = &parport_bitbang;
@ -376,7 +385,8 @@ static int parport_init(void)
static int parport_quit(void) static int parport_quit(void)
{ {
parport_led(0); if (parport_led(0) != ERROR_OK)
return ERROR_FAIL;
if (parport_exit) { if (parport_exit) {
dataport_value = cable->PORT_EXIT; dataport_value = cable->PORT_EXIT;

View File

@ -117,8 +117,7 @@ static int presto_read(uint8_t *buf, uint32_t size)
ftbytes += presto->retval; ftbytes += presto->retval;
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
if ((now.tv_sec > timeout.tv_sec) || if (timeval_compare(&now, &timeout) > 0)
((now.tv_sec == timeout.tv_sec) && (now.tv_usec > timeout.tv_usec)))
break; break;
} }

View File

@ -30,18 +30,10 @@
/* arbitrary limit on host name length: */ /* arbitrary limit on host name length: */
#define REMOTE_BITBANG_HOST_MAX 255 #define REMOTE_BITBANG_HOST_MAX 255
#define REMOTE_BITBANG_RAISE_ERROR(expr ...) \
do { \
LOG_ERROR(expr); \
LOG_ERROR("Terminating openocd."); \
exit(-1); \
} while (0)
static char *remote_bitbang_host; static char *remote_bitbang_host;
static char *remote_bitbang_port; static char *remote_bitbang_port;
static FILE *remote_bitbang_in; static FILE *remote_bitbang_file;
static FILE *remote_bitbang_out;
static int remote_bitbang_fd; static int remote_bitbang_fd;
/* Circular buffer. When start == end, the buffer is empty. */ /* Circular buffer. When start == end, the buffer is empty. */
@ -57,7 +49,7 @@ static int remote_bitbang_buf_full(void)
} }
/* Read any incoming data, placing it into the buffer. */ /* Read any incoming data, placing it into the buffer. */
static void remote_bitbang_fill_buf(void) static int remote_bitbang_fill_buf(void)
{ {
socket_nonblock(remote_bitbang_fd); socket_nonblock(remote_bitbang_fd);
while (!remote_bitbang_buf_full()) { while (!remote_bitbang_buf_full()) {
@ -79,39 +71,45 @@ static void remote_bitbang_fill_buf(void)
if (remote_bitbang_end == sizeof(remote_bitbang_buf)) if (remote_bitbang_end == sizeof(remote_bitbang_buf))
remote_bitbang_end = 0; remote_bitbang_end = 0;
} else if (count == 0) { } else if (count == 0) {
return; return ERROR_OK;
} else if (count < 0) { } else if (count < 0) {
if (errno == EAGAIN) { if (errno == EAGAIN) {
return; return ERROR_OK;
} else { } else {
REMOTE_BITBANG_RAISE_ERROR("remote_bitbang_fill_buf: %s (%d)", LOG_ERROR("remote_bitbang_fill_buf: %s (%d)",
strerror(errno), errno); strerror(errno), errno);
return ERROR_FAIL;
} }
} }
} }
return ERROR_OK;
} }
static void remote_bitbang_putc(int c) static int remote_bitbang_putc(int c)
{ {
if (EOF == fputc(c, remote_bitbang_out)) if (EOF == fputc(c, remote_bitbang_file)) {
REMOTE_BITBANG_RAISE_ERROR("remote_bitbang_putc: %s", strerror(errno)); LOG_ERROR("remote_bitbang_putc: %s", strerror(errno));
return ERROR_FAIL;
}
return ERROR_OK;
} }
static int remote_bitbang_quit(void) static int remote_bitbang_quit(void)
{ {
if (EOF == fputc('Q', remote_bitbang_out)) { if (EOF == fputc('Q', remote_bitbang_file)) {
LOG_ERROR("fputs: %s", strerror(errno)); LOG_ERROR("fputs: %s", strerror(errno));
return ERROR_FAIL; return ERROR_FAIL;
} }
if (EOF == fflush(remote_bitbang_out)) { if (EOF == fflush(remote_bitbang_file)) {
LOG_ERROR("fflush: %s", strerror(errno)); LOG_ERROR("fflush: %s", strerror(errno));
return ERROR_FAIL; return ERROR_FAIL;
} }
/* We only need to close one of the FILE*s, because they both use the same */ /* We only need to close one of the FILE*s, because they both use the same */
/* underlying file descriptor. */ /* underlying file descriptor. */
if (EOF == fclose(remote_bitbang_out)) { if (EOF == fclose(remote_bitbang_file)) {
LOG_ERROR("fclose: %s", strerror(errno)); LOG_ERROR("fclose: %s", strerror(errno));
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -123,26 +121,27 @@ static int remote_bitbang_quit(void)
return ERROR_OK; return ERROR_OK;
} }
static int char_to_int(int c) static bb_value_t char_to_int(int c)
{ {
switch (c) { switch (c) {
case '0': case '0':
return 0; return BB_LOW;
case '1': case '1':
return 1; return BB_HIGH;
default: default:
remote_bitbang_quit(); remote_bitbang_quit();
REMOTE_BITBANG_RAISE_ERROR( LOG_ERROR("remote_bitbang: invalid read response: %c(%i)", c, c);
"remote_bitbang: invalid read response: %c(%i)", c, c); return BB_ERROR;
} }
} }
/* Get the next read response. */ /* Get the next read response. */
static int remote_bitbang_rread(void) static bb_value_t remote_bitbang_rread(void)
{ {
if (EOF == fflush(remote_bitbang_out)) { if (EOF == fflush(remote_bitbang_file)) {
remote_bitbang_quit(); remote_bitbang_quit();
REMOTE_BITBANG_RAISE_ERROR("fflush: %s", strerror(errno)); LOG_ERROR("fflush: %s", strerror(errno));
return BB_ERROR;
} }
/* Enable blocking access. */ /* Enable blocking access. */
@ -153,19 +152,20 @@ static int remote_bitbang_rread(void)
return char_to_int(c); return char_to_int(c);
} else { } else {
remote_bitbang_quit(); remote_bitbang_quit();
REMOTE_BITBANG_RAISE_ERROR("read: count=%d, error=%s", (int) count, LOG_ERROR("read: count=%d, error=%s", (int) count, strerror(errno));
strerror(errno)); return BB_ERROR;
} }
} }
static void remote_bitbang_sample(void) static int remote_bitbang_sample(void)
{ {
remote_bitbang_fill_buf(); if (remote_bitbang_fill_buf() != ERROR_OK)
return ERROR_FAIL;
assert(!remote_bitbang_buf_full()); assert(!remote_bitbang_buf_full());
remote_bitbang_putc('R'); return remote_bitbang_putc('R');
} }
static int remote_bitbang_read_sample(void) static bb_value_t remote_bitbang_read_sample(void)
{ {
if (remote_bitbang_start != remote_bitbang_end) { if (remote_bitbang_start != remote_bitbang_end) {
int c = remote_bitbang_buf[remote_bitbang_start]; int c = remote_bitbang_buf[remote_bitbang_start];
@ -176,22 +176,22 @@ static int remote_bitbang_read_sample(void)
return remote_bitbang_rread(); return remote_bitbang_rread();
} }
static void remote_bitbang_write(int tck, int tms, int tdi) static int remote_bitbang_write(int tck, int tms, int tdi)
{ {
char c = '0' + ((tck ? 0x4 : 0x0) | (tms ? 0x2 : 0x0) | (tdi ? 0x1 : 0x0)); char c = '0' + ((tck ? 0x4 : 0x0) | (tms ? 0x2 : 0x0) | (tdi ? 0x1 : 0x0));
remote_bitbang_putc(c); return remote_bitbang_putc(c);
} }
static void remote_bitbang_reset(int trst, int srst) static int remote_bitbang_reset(int trst, int srst)
{ {
char c = 'r' + ((trst ? 0x2 : 0x0) | (srst ? 0x1 : 0x0)); char c = 'r' + ((trst ? 0x2 : 0x0) | (srst ? 0x1 : 0x0));
remote_bitbang_putc(c); return remote_bitbang_putc(c);
} }
static void remote_bitbang_blink(int on) static int remote_bitbang_blink(int on)
{ {
char c = on ? 'B' : 'b'; char c = on ? 'B' : 'b';
remote_bitbang_putc(c); return remote_bitbang_putc(c);
} }
static struct bitbang_interface remote_bitbang_bitbang = { static struct bitbang_interface remote_bitbang_bitbang = {
@ -289,17 +289,10 @@ static int remote_bitbang_init(void)
if (remote_bitbang_fd < 0) if (remote_bitbang_fd < 0)
return remote_bitbang_fd; return remote_bitbang_fd;
remote_bitbang_in = fdopen(remote_bitbang_fd, "r"); remote_bitbang_file = fdopen(remote_bitbang_fd, "w+");
if (remote_bitbang_in == NULL) { if (remote_bitbang_file == NULL) {
LOG_ERROR("fdopen: failed to open read stream");
close(remote_bitbang_fd);
return ERROR_FAIL;
}
remote_bitbang_out = fdopen(remote_bitbang_fd, "w");
if (remote_bitbang_out == NULL) {
LOG_ERROR("fdopen: failed to open write stream"); LOG_ERROR("fdopen: failed to open write stream");
fclose(remote_bitbang_in); close(remote_bitbang_fd);
return ERROR_FAIL; return ERROR_FAIL;
} }

View File

@ -1,4 +1,8 @@
/*************************************************************************** /***************************************************************************
* SWIM contributions by Ake Rehnman *
* Copyright (C) 2017 Ake Rehnman *
* ake.rehnman(at)gmail.com *
* *
* Copyright (C) 2011-2012 by Mathias Kuester * * Copyright (C) 2011-2012 by Mathias Kuester *
* Mathias Kuester <kesmtp@freenet.de> * * Mathias Kuester <kesmtp@freenet.de> *
* * * *
@ -130,6 +134,8 @@ struct stlink_usb_handle_s {
bool reconnect_pending; bool reconnect_pending;
}; };
#define STLINK_SWIM_ERR_OK 0x00
#define STLINK_SWIM_BUSY 0x01
#define STLINK_DEBUG_ERR_OK 0x80 #define STLINK_DEBUG_ERR_OK 0x80
#define STLINK_DEBUG_ERR_FAULT 0x81 #define STLINK_DEBUG_ERR_FAULT 0x81
#define STLINK_SWD_AP_WAIT 0x10 #define STLINK_SWD_AP_WAIT 0x10
@ -167,8 +173,36 @@ struct stlink_usb_handle_s {
#define STLINK_DFU_EXIT 0x07 #define STLINK_DFU_EXIT 0x07
/*
STLINK_SWIM_ENTER_SEQ
1.3ms low then 750Hz then 1.5kHz
STLINK_SWIM_GEN_RST
STM8 DM pulls reset pin low 50us
STLINK_SWIM_SPEED
uint8_t (0=low|1=high)
STLINK_SWIM_WRITEMEM
uint16_t length
uint32_t address
STLINK_SWIM_RESET
send syncronization seq (16us low, response 64 clocks low)
*/
#define STLINK_SWIM_ENTER 0x00 #define STLINK_SWIM_ENTER 0x00
#define STLINK_SWIM_EXIT 0x01 #define STLINK_SWIM_EXIT 0x01
#define STLINK_SWIM_READ_CAP 0x02
#define STLINK_SWIM_SPEED 0x03
#define STLINK_SWIM_ENTER_SEQ 0x04
#define STLINK_SWIM_GEN_RST 0x05
#define STLINK_SWIM_RESET 0x06
#define STLINK_SWIM_ASSERT_RESET 0x07
#define STLINK_SWIM_DEASSERT_RESET 0x08
#define STLINK_SWIM_READSTATUS 0x09
#define STLINK_SWIM_WRITEMEM 0x0a
#define STLINK_SWIM_READMEM 0x0b
#define STLINK_SWIM_READBUF 0x0c
#define STLINK_DEBUG_ENTER_JTAG 0x00 #define STLINK_DEBUG_ENTER_JTAG 0x00
#define STLINK_DEBUG_GETSTATUS 0x01 #define STLINK_DEBUG_GETSTATUS 0x01
@ -252,6 +286,7 @@ static const struct {
}; };
static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size); static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size);
static int stlink_swim_status(void *handle);
/** */ /** */
static int stlink_usb_xfer_v1_get_status(void *handle) static int stlink_usb_xfer_v1_get_status(void *handle)
@ -342,7 +377,11 @@ static int stlink_usb_xfer_v1_get_sense(void *handle)
return ERROR_OK; return ERROR_OK;
} }
/** */ /*
transfers block in cmdbuf
<size> indicates number of bytes in the following
data phase.
*/
static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size) static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size)
{ {
int err, cmdsize = STLINK_CMD_SIZE_V2; int err, cmdsize = STLINK_CMD_SIZE_V2;
@ -350,8 +389,11 @@ static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size)
assert(handle != NULL); assert(handle != NULL);
if (h->version.stlink == 1) if (h->version.stlink == 1) {
cmdsize = STLINK_SG_SIZE; cmdsize = STLINK_SG_SIZE;
/* put length in bCBWCBLength */
h->cmdbuf[14] = h->cmdidx-15;
}
err = stlink_usb_xfer_rw(handle, cmdsize, buf, size); err = stlink_usb_xfer_rw(handle, cmdsize, buf, size);
@ -373,7 +415,6 @@ static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size)
return ERROR_OK; return ERROR_OK;
} }
/** /**
Converts an STLINK status code held in the first byte of a response Converts an STLINK status code held in the first byte of a response
to an openocd error, logs any error/wait status as debug output. to an openocd error, logs any error/wait status as debug output.
@ -384,6 +425,18 @@ static int stlink_usb_error_check(void *handle)
assert(handle != NULL); assert(handle != NULL);
if (h->transport == HL_TRANSPORT_SWIM) {
switch (h->databuf[0]) {
case STLINK_SWIM_ERR_OK:
return ERROR_OK;
case STLINK_SWIM_BUSY:
return ERROR_WAIT;
default:
LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]);
return ERROR_FAIL;
}
}
/* TODO: no error checking yet on api V1 */ /* TODO: no error checking yet on api V1 */
if (h->jtag_api == STLINK_JTAG_API_V1) if (h->jtag_api == STLINK_JTAG_API_V1)
h->databuf[0] = STLINK_DEBUG_ERR_OK; h->databuf[0] = STLINK_DEBUG_ERR_OK;
@ -448,7 +501,7 @@ static int stlink_usb_error_check(void *handle)
/** Issue an STLINK command via USB transfer, with retries on any wait status responses. /** Issue an STLINK command via USB transfer, with retries on any wait status responses.
Works for commands where the STLINK_DEBUG status is returned in the first Works for commands where the STLINK_DEBUG status is returned in the first
byte of the response packet. byte of the response packet. For SWIM a SWIM_READSTATUS is requested instead.
Returns an openocd result code. Returns an openocd result code.
*/ */
@ -456,10 +509,21 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size)
{ {
int retries = 0; int retries = 0;
int res; int res;
struct stlink_usb_handle_s *h = handle;
while (1) { while (1) {
if ((h->transport != HL_TRANSPORT_SWIM) || !retries) {
res = stlink_usb_xfer(handle, buf, size); res = stlink_usb_xfer(handle, buf, size);
if (res != ERROR_OK) if (res != ERROR_OK)
return res; return res;
}
if (h->transport == HL_TRANSPORT_SWIM) {
res = stlink_swim_status(handle);
if (res != ERROR_OK)
return res;
}
res = stlink_usb_error_check(handle); res = stlink_usb_error_check(handle);
if (res == ERROR_WAIT && retries < MAX_WAIT_RETRIES) { if (res == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
usleep((1<<retries++) * 1000); usleep((1<<retries++) * 1000);
@ -487,7 +551,17 @@ static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size)
return ERROR_OK; return ERROR_OK;
} }
/** */ /*
this function writes transfer length in
the right place in the cb
*/
static void stlink_usb_set_cbw_transfer_datalength(void *handle, uint32_t size)
{
struct stlink_usb_handle_s *h = handle;
buf_set_u32(h->cmdbuf+8, 0, 32, size);
}
static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint32_t size) static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint32_t size)
{ {
struct stlink_usb_handle_s *h = handle; struct stlink_usb_handle_s *h = handle;
@ -496,12 +570,16 @@ static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint3
strcpy((char *)h->cmdbuf, "USBC"); strcpy((char *)h->cmdbuf, "USBC");
h->cmdidx += 4; h->cmdidx += 4;
/* csw tag not used */ /* csw tag not used */
buf_set_u32(h->cmdbuf+h->cmdidx, 0, 32, 0);
h->cmdidx += 4; h->cmdidx += 4;
/* cbw data transfer length (in the following data phase in or out) */
buf_set_u32(h->cmdbuf+h->cmdidx, 0, 32, size); buf_set_u32(h->cmdbuf+h->cmdidx, 0, 32, size);
h->cmdidx += 4; h->cmdidx += 4;
/* cbw flags */
h->cmdbuf[h->cmdidx++] = (direction == h->rx_ep ? ENDPOINT_IN : ENDPOINT_OUT); h->cmdbuf[h->cmdidx++] = (direction == h->rx_ep ? ENDPOINT_IN : ENDPOINT_OUT);
h->cmdbuf[h->cmdidx++] = 0; /* lun */ h->cmdbuf[h->cmdidx++] = 0; /* lun */
h->cmdbuf[h->cmdidx++] = STLINK_CMD_SIZE_V1; /* cdb clength (is filled in at xfer) */
h->cmdbuf[h->cmdidx++] = 0;
} }
/** */ /** */
@ -681,6 +759,8 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type)
case STLINK_MODE_DEBUG_SWIM: case STLINK_MODE_DEBUG_SWIM:
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER;
/* no answer for this function... */
rx_size = 0;
break; break;
case STLINK_MODE_DFU: case STLINK_MODE_DFU:
case STLINK_MODE_MASS: case STLINK_MODE_MASS:
@ -824,17 +904,29 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset)
return ERROR_FAIL; return ERROR_FAIL;
} }
/* preliminary SRST assert:
* We want SRST is asserted before activating debug signals (mode_enter).
* As the required mode has not been set, the adapter may not know what pin to use.
* Tested firmware STLINK v2 JTAG v29 API v2 SWIM v0 uses T_NRST pin by default
* Tested firmware STLINK v2 JTAG v27 API v2 SWIM v6 uses T_NRST pin by default
* after power on, SWIM_RST stays unchanged */
if (connect_under_reset && emode != STLINK_MODE_DEBUG_SWIM)
stlink_usb_assert_srst(handle, 0);
/* do not check the return status here, we will
proceed and enter the desired mode below
and try asserting srst again. */
res = stlink_usb_mode_enter(handle, emode);
if (res != ERROR_OK)
return res;
/* assert SRST again: a little bit late but now the adapter knows for sure what pin to use */
if (connect_under_reset) { if (connect_under_reset) {
res = stlink_usb_assert_srst(handle, 0); res = stlink_usb_assert_srst(handle, 0);
if (res != ERROR_OK) if (res != ERROR_OK)
return res; return res;
} }
res = stlink_usb_mode_enter(handle, emode);
if (res != ERROR_OK)
return res;
res = stlink_usb_current_mode(handle, &mode); res = stlink_usb_current_mode(handle, &mode);
if (res != ERROR_OK) if (res != ERROR_OK)
@ -845,6 +937,199 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset)
return ERROR_OK; return ERROR_OK;
} }
/* request status from last swim request */
static int stlink_swim_status(void *handle)
{
struct stlink_usb_handle_s *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 4);
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READSTATUS;
res = stlink_usb_xfer(handle, h->databuf, 4);
if (res != ERROR_OK)
return res;
return ERROR_OK;
}
/*
the purpose of this function is unknown...
capabilites? anyway for swim v6 it returns
0001020600000000
*/
__attribute__((unused))
static int stlink_swim_cap(void *handle, uint8_t *cap)
{
struct stlink_usb_handle_s *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 8);
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READ_CAP;
h->cmdbuf[h->cmdidx++] = 0x01;
res = stlink_usb_xfer(handle, h->databuf, 8);
if (res != ERROR_OK)
return res;
memcpy(cap, h->databuf, 8);
return ERROR_OK;
}
/* debug dongle assert/deassert sreset line */
static int stlink_swim_assert_reset(void *handle, int reset)
{
struct stlink_usb_handle_s *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 0);
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
if (!reset)
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ASSERT_RESET;
else
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_DEASSERT_RESET;
res = stlink_cmd_allow_retry(handle, h->databuf, 0);
if (res != ERROR_OK)
return res;
return ERROR_OK;
}
/*
send swim enter seq
1.3ms low then 750Hz then 1.5kHz
*/
static int stlink_swim_enter(void *handle)
{
struct stlink_usb_handle_s *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 0);
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER_SEQ;
res = stlink_cmd_allow_retry(handle, h->databuf, 0);
if (res != ERROR_OK)
return res;
return ERROR_OK;
}
/* switch high/low speed swim */
static int stlink_swim_speed(void *handle, int speed)
{
struct stlink_usb_handle_s *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 0);
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_SPEED;
if (speed)
h->cmdbuf[h->cmdidx++] = 1;
else
h->cmdbuf[h->cmdidx++] = 0;
res = stlink_cmd_allow_retry(handle, h->databuf, 0);
if (res != ERROR_OK)
return res;
return ERROR_OK;
}
/*
initiate srst from swim.
nrst is pulled low for 50us.
*/
static int stlink_swim_generate_rst(void *handle)
{
struct stlink_usb_handle_s *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 0);
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_GEN_RST;
res = stlink_cmd_allow_retry(handle, h->databuf, 0);
if (res != ERROR_OK)
return res;
return ERROR_OK;
}
/*
send resyncronize sequence
swim is pulled low for 16us
reply is 64 clks low
*/
static int stlink_swim_resync(void *handle)
{
struct stlink_usb_handle_s *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 0);
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_RESET;
res = stlink_cmd_allow_retry(handle, h->databuf, 0);
if (res != ERROR_OK)
return res;
return ERROR_OK;
}
static int stlink_swim_writebytes(void *handle, uint32_t addr, uint32_t len, const uint8_t *data)
{
struct stlink_usb_handle_s *h = handle;
int res;
unsigned int i;
unsigned int datalen = 0;
int cmdsize = STLINK_CMD_SIZE_V2;
if (len > STLINK_DATA_SIZE)
return ERROR_FAIL;
if (h->version.stlink == 1)
cmdsize = STLINK_SG_SIZE;
stlink_usb_init_buffer(handle, h->tx_ep, 0);
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_WRITEMEM;
h_u16_to_be(h->cmdbuf+h->cmdidx, len);
h->cmdidx += 2;
h_u32_to_be(h->cmdbuf+h->cmdidx, addr);
h->cmdidx += 4;
for (i = 0; i < len; i++) {
if (h->cmdidx == cmdsize)
h->databuf[datalen++] = *(data++);
else
h->cmdbuf[h->cmdidx++] = *(data++);
}
if (h->version.stlink == 1)
stlink_usb_set_cbw_transfer_datalength(handle, datalen);
res = stlink_cmd_allow_retry(handle, h->databuf, datalen);
if (res != ERROR_OK)
return res;
return ERROR_OK;
}
static int stlink_swim_readbytes(void *handle, uint32_t addr, uint32_t len, uint8_t *data)
{
struct stlink_usb_handle_s *h = handle;
int res;
if (len > STLINK_DATA_SIZE)
return ERROR_FAIL;
stlink_usb_init_buffer(handle, h->rx_ep, 0);
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READMEM;
h_u16_to_be(h->cmdbuf+h->cmdidx, len);
h->cmdidx += 2;
h_u32_to_be(h->cmdbuf+h->cmdidx, addr);
h->cmdidx += 4;
res = stlink_cmd_allow_retry(handle, h->databuf, 0);
if (res != ERROR_OK)
return res;
stlink_usb_init_buffer(handle, h->rx_ep, len);
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READBUF;
res = stlink_usb_xfer(handle, data, len);
if (res != ERROR_OK)
return res;
return ERROR_OK;
}
/** */ /** */
static int stlink_usb_idcode(void *handle, uint32_t *idcode) static int stlink_usb_idcode(void *handle, uint32_t *idcode)
{ {
@ -853,6 +1138,12 @@ static int stlink_usb_idcode(void *handle, uint32_t *idcode)
assert(handle != NULL); assert(handle != NULL);
/* there is no swim read core id cmd */
if (h->transport == HL_TRANSPORT_SWIM) {
*idcode = 0;
return ERROR_OK;
}
stlink_usb_init_buffer(handle, h->rx_ep, 4); stlink_usb_init_buffer(handle, h->rx_ep, 4);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
@ -971,6 +1262,18 @@ static enum target_state stlink_usb_state(void *handle)
assert(handle != NULL); assert(handle != NULL);
if (h->transport == HL_TRANSPORT_SWIM) {
res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport));
if (res != ERROR_OK)
return TARGET_UNKNOWN;
res = stlink_swim_resync(handle);
if (res != ERROR_OK)
return TARGET_UNKNOWN;
return ERROR_OK;
}
if (h->reconnect_pending) { if (h->reconnect_pending) {
LOG_INFO("Previous state query failed, trying to reconnect"); LOG_INFO("Previous state query failed, trying to reconnect");
res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport)); res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport));
@ -1014,6 +1317,9 @@ static int stlink_usb_assert_srst(void *handle, int srst)
assert(handle != NULL); assert(handle != NULL);
if (h->transport == HL_TRANSPORT_SWIM)
return stlink_swim_assert_reset(handle, srst);
if (h->version.stlink == 1) if (h->version.stlink == 1)
return ERROR_COMMAND_NOTFOUND; return ERROR_COMMAND_NOTFOUND;
@ -1088,6 +1394,9 @@ static int stlink_usb_reset(void *handle)
assert(handle != NULL); assert(handle != NULL);
if (h->transport == HL_TRANSPORT_SWIM)
return stlink_swim_generate_rst(handle);
stlink_usb_init_buffer(handle, h->rx_ep, 2); stlink_usb_init_buffer(handle, h->rx_ep, 2);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
@ -1440,6 +1749,11 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
if (count < bytes_remaining) if (count < bytes_remaining)
bytes_remaining = count; bytes_remaining = count;
if (h->transport == HL_TRANSPORT_SWIM) {
retval = stlink_swim_readbytes(handle, addr, bytes_remaining, buffer);
if (retval != ERROR_OK)
return retval;
} else
/* the stlink only supports 8/32bit memory read/writes /* the stlink only supports 8/32bit memory read/writes
* honour 32bit, all others will be handled as 8bit access */ * honour 32bit, all others will be handled as 8bit access */
if (size == 4) { if (size == 4) {
@ -1510,6 +1824,11 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
if (count < bytes_remaining) if (count < bytes_remaining)
bytes_remaining = count; bytes_remaining = count;
if (h->transport == HL_TRANSPORT_SWIM) {
retval = stlink_swim_writebytes(handle, addr, bytes_remaining, buffer);
if (retval != ERROR_OK)
return retval;
} else
/* the stlink only supports 8/32bit memory read/writes /* the stlink only supports 8/32bit memory read/writes
* honour 32bit, all others will be handled as 8bit access */ * honour 32bit, all others will be handled as 8bit access */
if (size == 4) { if (size == 4) {
@ -1574,6 +1893,20 @@ static int stlink_speed(void *handle, int khz, bool query)
int speed_diff = INT_MAX; int speed_diff = INT_MAX;
struct stlink_usb_handle_s *h = handle; struct stlink_usb_handle_s *h = handle;
if (h && (h->transport == HL_TRANSPORT_SWIM)) {
/*
we dont care what the khz rate is
we only have low and high speed...
before changing speed the SWIM_CSR HS bit
must be updated
*/
if (khz == 0)
stlink_swim_speed(handle, 0);
else
stlink_swim_speed(handle, 1);
return khz;
}
/* only supported by stlink/v2 and for firmware >= 22 */ /* only supported by stlink/v2 and for firmware >= 22 */
if (h && (h->version.stlink == 1 || h->version.jtag < 22)) if (h && (h->version.stlink == 1 || h->version.jtag < 22))
return khz; return khz;
@ -1622,8 +1955,43 @@ static int stlink_speed(void *handle, int khz, bool query)
/** */ /** */
static int stlink_usb_close(void *handle) static int stlink_usb_close(void *handle)
{ {
int res;
uint8_t mode;
enum stlink_mode emode;
struct stlink_usb_handle_s *h = handle; struct stlink_usb_handle_s *h = handle;
if (h && h->fd)
res = stlink_usb_current_mode(handle, &mode);
else
res = ERROR_FAIL;
/* do not exit if return code != ERROR_OK,
it prevents us from closing jtag_libusb */
if (res == ERROR_OK) {
/* try to exit current mode */
switch (mode) {
case STLINK_DEV_DFU_MODE:
emode = STLINK_MODE_DFU;
break;
case STLINK_DEV_DEBUG_MODE:
emode = STLINK_MODE_DEBUG_SWD;
break;
case STLINK_DEV_SWIM_MODE:
emode = STLINK_MODE_DEBUG_SWIM;
break;
case STLINK_DEV_BOOTLOADER_MODE:
case STLINK_DEV_MASS_MODE:
default:
emode = STLINK_MODE_UNKNOWN;
break;
}
if (emode != STLINK_MODE_UNKNOWN)
stlink_usb_mode_leave(handle, emode);
/* do not check return code, it prevent
us from closing jtag_libusb */
}
if (h && h->fd) if (h && h->fd)
jtag_libusb_close(h->fd); jtag_libusb_close(h->fd);
@ -1778,6 +2146,17 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
goto error_open; goto error_open;
} }
if (h->transport == HL_TRANSPORT_SWIM) {
err = stlink_swim_enter(h);
if (err != ERROR_OK) {
LOG_ERROR("stlink_swim_enter_failed (unable to connect to the target)");
goto error_open;
}
*fd = h;
h->max_mem_packet = STLINK_DATA_SIZE;
return ERROR_OK;
}
/* clock speed only supported by stlink/v2 and for firmware >= 22 */ /* clock speed only supported by stlink/v2 and for firmware >= 22 */
if (h->version.stlink >= 2 && h->version.jtag >= 22) { if (h->version.stlink >= 2 && h->version.jtag >= 22) {
LOG_DEBUG("Supported clock speeds are:"); LOG_DEBUG("Supported clock speeds are:");

View File

@ -244,7 +244,7 @@ static void sysfsgpio_swdio_write(int swclk, int swdio)
* The sysfs value will read back either '0' or '1'. The trick here is to call * The sysfs value will read back either '0' or '1'. The trick here is to call
* lseek to bypass buffering in the sysfs kernel driver. * lseek to bypass buffering in the sysfs kernel driver.
*/ */
static int sysfsgpio_read(void) static bb_value_t sysfsgpio_read(void)
{ {
char buf[1]; char buf[1];
@ -257,7 +257,7 @@ static int sysfsgpio_read(void)
return 0; return 0;
} }
return buf[0] != '0'; return buf[0] == '0' ? BB_LOW : BB_HIGH;
} }
/* /*
@ -266,11 +266,11 @@ static int sysfsgpio_read(void)
* Seeing as this is the only function where the outputs are changed, * Seeing as this is the only function where the outputs are changed,
* we can cache the old value to avoid needlessly writing it. * we can cache the old value to avoid needlessly writing it.
*/ */
static void sysfsgpio_write(int tck, int tms, int tdi) static int sysfsgpio_write(int tck, int tms, int tdi)
{ {
if (swd_mode) { if (swd_mode) {
sysfsgpio_swdio_write(tck, tdi); sysfsgpio_swdio_write(tck, tdi);
return; return ERROR_OK;
} }
const char one[] = "1"; const char one[] = "1";
@ -312,6 +312,8 @@ static void sysfsgpio_write(int tck, int tms, int tdi)
last_tdi = tdi; last_tdi = tdi;
last_tms = tms; last_tms = tms;
last_tck = tck; last_tck = tck;
return ERROR_OK;
} }
/* /*
@ -319,7 +321,7 @@ static void sysfsgpio_write(int tck, int tms, int tdi)
* *
* (1) assert or (0) deassert reset lines * (1) assert or (0) deassert reset lines
*/ */
static void sysfsgpio_reset(int trst, int srst) static int sysfsgpio_reset(int trst, int srst)
{ {
LOG_DEBUG("sysfsgpio_reset"); LOG_DEBUG("sysfsgpio_reset");
const char one[] = "1"; const char one[] = "1";
@ -339,6 +341,8 @@ static void sysfsgpio_reset(int trst, int srst)
if (bytes_written != 1) if (bytes_written != 1)
LOG_WARNING("writing trst failed"); LOG_WARNING("writing trst failed");
} }
return ERROR_OK;
} }
COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums) COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums)
@ -592,10 +596,6 @@ static int sysfsgpio_init(void)
LOG_INFO("JTAG and SWD modes enabled"); LOG_INFO("JTAG and SWD modes enabled");
else else
LOG_INFO("JTAG only mode enabled (specify swclk and swdio gpio to add SWD mode)"); LOG_INFO("JTAG only mode enabled (specify swclk and swdio gpio to add SWD mode)");
if (!is_gpio_valid(trst_gpio) && !is_gpio_valid(srst_gpio)) {
LOG_ERROR("Require at least one of trst or srst gpios to be specified");
return ERROR_JTAG_INIT_FAILED;
}
} else if (sysfsgpio_swd_mode_possible()) { } else if (sysfsgpio_swd_mode_possible()) {
LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)"); LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)");
} else { } else {

View File

@ -839,26 +839,30 @@ static int ublast_init(void)
{ {
int ret, i; int ret, i;
for (i = 0; lowlevel_drivers_map[i].name; i++) {
if (info.lowlevel_name) { if (info.lowlevel_name) {
for (i = 0; lowlevel_drivers_map[i].name; i++) if (!strcmp(lowlevel_drivers_map[i].name, info.lowlevel_name)) {
if (!strcmp(lowlevel_drivers_map[i].name, info.lowlevel_name))
break;
if (lowlevel_drivers_map[i].name)
info.drv = lowlevel_drivers_map[i].drv_register(); info.drv = lowlevel_drivers_map[i].drv_register();
if (!info.drv) { if (!info.drv) {
LOG_ERROR("no lowlevel driver found for %s or lowlevel driver opening error", LOG_ERROR("Error registering lowlevel driver \"%s\"",
info.lowlevel_name); info.lowlevel_name);
return ERROR_JTAG_DEVICE_ERROR; return ERROR_JTAG_DEVICE_ERROR;
} }
} else { break;
LOG_INFO("No lowlevel driver configured, will try them all");
for (i = 0; !info.drv && lowlevel_drivers_map[i].name; i++)
info.drv = lowlevel_drivers_map[i].drv_register();
if (!info.drv) {
LOG_ERROR("no lowlevel driver found");
return ERROR_JTAG_DEVICE_ERROR;
} }
info.lowlevel_name = strdup(lowlevel_drivers_map[i-1].name); } else {
info.drv = lowlevel_drivers_map[i].drv_register();
if (info.drv) {
info.lowlevel_name = strdup(lowlevel_drivers_map[i].name);
LOG_INFO("No lowlevel driver configured, using %s", info.lowlevel_name);
break;
}
}
}
if (!info.drv) {
LOG_ERROR("No lowlevel driver available");
return ERROR_JTAG_DEVICE_ERROR;
} }
/* /*

View File

@ -344,8 +344,8 @@ int openocd_main(int argc, char *argv[])
unregister_all_commands(cmd_ctx, NULL); unregister_all_commands(cmd_ctx, NULL);
/* free commandline interface */ /* Shutdown commandline interface */
command_done(cmd_ctx); command_exit(cmd_ctx);
adapter_quit(); adapter_quit();

View File

@ -991,7 +991,9 @@ static int gdb_new_connection(struct connection *connection)
} }
gdb_actual_connections++; gdb_actual_connections++;
LOG_DEBUG("New GDB Connection: %d, Target %s, state: %s", log_printf_lf(all_targets->next != NULL ? LOG_LVL_INFO : LOG_LVL_DEBUG,
__FILE__, __LINE__, __func__,
"New GDB Connection: %d, Target %s, state: %s",
gdb_actual_connections, gdb_actual_connections,
target_name(target), target_name(target),
target_state_name(target)); target_state_name(target));
@ -3122,7 +3124,7 @@ static int gdb_target_add_one(struct target *target)
} else { } else {
/* Don't increment if gdb_port is 0, since we're just /* Don't increment if gdb_port is 0, since we're just
* trying to allocate an unused port. */ * trying to allocate an unused port. */
gdb_port_next = alloc_printf("0"); gdb_port_next = strdup("0");
} }
} }
} }

View File

@ -301,9 +301,10 @@ int add_service(char *name,
} }
struct sockaddr_in addr_in; struct sockaddr_in addr_in;
addr_in.sin_port = 0;
socklen_t addr_in_size = sizeof(addr_in); socklen_t addr_in_size = sizeof(addr_in);
getsockname(c->fd, (struct sockaddr *)&addr_in, &addr_in_size); if (getsockname(c->fd, (struct sockaddr *)&addr_in, &addr_in_size) == 0)
LOG_INFO("Listening on port %d for %s connections", LOG_INFO("Listening on port %hu for %s connections",
ntohs(addr_in.sin_port), name); ntohs(addr_in.sin_port), name);
} else if (c->type == CONNECTION_STDINOUT) { } else if (c->type == CONNECTION_STDINOUT) {
c->fd = fileno(stdin); c->fd = fileno(stdin);

View File

@ -54,7 +54,7 @@ static int telnet_write(struct connection *connection, const void *data,
if (connection_write(connection, data, len) == len) if (connection_write(connection, data, len) == len)
return ERROR_OK; return ERROR_OK;
t_con->closed = 1; t_con->closed = true;
return ERROR_SERVER_REMOTE_CLOSED; return ERROR_SERVER_REMOTE_CLOSED;
} }
@ -101,29 +101,36 @@ static void telnet_log_callback(void *priv, const char *file, unsigned line,
{ {
struct connection *connection = priv; struct connection *connection = priv;
struct telnet_connection *t_con = connection->priv; struct telnet_connection *t_con = connection->priv;
int i; size_t i;
size_t tmp;
/* if there is no prompt, simply output the message */ /* If the prompt is not visible, simply output the message. */
if (t_con->line_cursor < 0) { if (!t_con->prompt_visible) {
telnet_outputline(connection, string); telnet_outputline(connection, string);
return; return;
} }
/* clear the command line */ /* Clear the command line. */
for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16) tmp = strlen(t_con->prompt) + t_con->line_size;
telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i > 16 ? 16 : i);
for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16) for (i = 0; i < tmp; i += 16)
telnet_write(connection, " ", i > 16 ? 16 : i); telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16) MIN(tmp - i, 16));
telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i > 16 ? 16 : i);
for (i = 0; i < tmp; i += 16)
telnet_write(connection, " ", MIN(tmp - i, 16));
for (i = 0; i < tmp; i += 16)
telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
MIN(tmp - i, 16));
/* output the message */
telnet_outputline(connection, string); telnet_outputline(connection, string);
/* put the command line to its previous state */ /* Put the command line to its previous state. */
telnet_prompt(connection); telnet_prompt(connection);
telnet_write(connection, t_con->line, t_con->line_size); telnet_write(connection, t_con->line, t_con->line_size);
for (i = t_con->line_size; i > t_con->line_cursor; i--)
for (i = t_con->line_cursor; i < t_con->line_size; i++)
telnet_write(connection, "\b", 1); telnet_write(connection, "\b", 1);
} }
@ -219,10 +226,11 @@ static int telnet_new_connection(struct connection *connection)
connection->priv = telnet_connection; connection->priv = telnet_connection;
/* initialize telnet connection information */ /* initialize telnet connection information */
telnet_connection->closed = 0; telnet_connection->closed = false;
telnet_connection->line_size = 0; telnet_connection->line_size = 0;
telnet_connection->line_cursor = 0; telnet_connection->line_cursor = 0;
telnet_connection->prompt = strdup("> "); telnet_connection->prompt = strdup("> ");
telnet_connection->prompt_visible = true;
telnet_connection->state = TELNET_STATE_DATA; telnet_connection->state = TELNET_STATE_DATA;
/* output goes through telnet connection */ /* output goes through telnet connection */
@ -289,7 +297,7 @@ static void telnet_history_up(struct connection *connection)
{ {
struct telnet_connection *t_con = connection->priv; struct telnet_connection *t_con = connection->priv;
int last_history = (t_con->current_history > 0) ? size_t last_history = (t_con->current_history > 0) ?
t_con->current_history - 1 : t_con->current_history - 1 :
TELNET_LINE_HISTORY_SIZE-1; TELNET_LINE_HISTORY_SIZE-1;
telnet_history_go(connection, last_history); telnet_history_go(connection, last_history);
@ -298,11 +306,36 @@ static void telnet_history_up(struct connection *connection)
static void telnet_history_down(struct connection *connection) static void telnet_history_down(struct connection *connection)
{ {
struct telnet_connection *t_con = connection->priv; struct telnet_connection *t_con = connection->priv;
size_t next_history;
int next_history = (t_con->current_history + 1) % TELNET_LINE_HISTORY_SIZE; next_history = (t_con->current_history + 1) % TELNET_LINE_HISTORY_SIZE;
telnet_history_go(connection, next_history); telnet_history_go(connection, next_history);
} }
static void telnet_move_cursor(struct connection *connection, size_t pos)
{
struct telnet_connection *tc;
size_t tmp;
tc = connection->priv;
if (pos < tc->line_cursor) {
tmp = tc->line_cursor - pos;
for (size_t i = 0; i < tmp; i += 16)
telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
MIN(tmp - i, 16));
} else {
tmp = pos - tc->line_cursor;
for (size_t i = 0; i < tmp; i += 16)
telnet_write(connection, tc->line + tc->line_cursor + i,
MIN(tmp - i, 16));
}
tc->line_cursor = pos;
}
static int telnet_input(struct connection *connection) static int telnet_input(struct connection *connection)
{ {
int bytes_read; int bytes_read;
@ -339,7 +372,7 @@ static int telnet_input(struct connection *connection)
t_con->line[t_con->line_size++] = *buf_p; t_con->line[t_con->line_size++] = *buf_p;
t_con->line_cursor++; t_con->line_cursor++;
} else { } else {
int i; size_t i;
memmove(t_con->line + t_con->line_cursor + 1, memmove(t_con->line + t_con->line_cursor + 1,
t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor,
t_con->line_size - t_con->line_cursor); t_con->line_size - t_con->line_cursor);
@ -374,7 +407,7 @@ static int telnet_input(struct connection *connection)
telnet_write(connection, "\r\n\x00", 3); telnet_write(connection, "\r\n\x00", 3);
if (strcmp(t_con->line, "history") == 0) { if (strcmp(t_con->line, "history") == 0) {
int i; size_t i;
for (i = 1; i < TELNET_LINE_HISTORY_SIZE; i++) { for (i = 1; i < TELNET_LINE_HISTORY_SIZE; i++) {
/* the t_con->next_history line contains empty string /* the t_con->next_history line contains empty string
* (unless NULL), thus it is not printed */ * (unless NULL), thus it is not printed */
@ -420,7 +453,7 @@ static int telnet_input(struct connection *connection)
t_con->line_size = 0; t_con->line_size = 0;
/* to suppress prompt in log callback during command execution */ /* to suppress prompt in log callback during command execution */
t_con->line_cursor = -1; t_con->prompt_visible = false;
if (strcmp(t_con->line, "shutdown") == 0) if (strcmp(t_con->line, "shutdown") == 0)
telnet_save_history(t_con); telnet_save_history(t_con);
@ -428,6 +461,7 @@ static int telnet_input(struct connection *connection)
retval = command_run_line(command_context, t_con->line); retval = command_run_line(command_context, t_con->line);
t_con->line_cursor = 0; t_con->line_cursor = 0;
t_con->prompt_visible = true;
if (retval == ERROR_COMMAND_CLOSE_CONNECTION) if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
return ERROR_SERVER_REMOTE_CLOSED; return ERROR_SERVER_REMOTE_CLOSED;
@ -442,7 +476,7 @@ static int telnet_input(struct connection *connection)
} else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) { /* delete character */ } else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) { /* delete character */
if (t_con->line_cursor > 0) { if (t_con->line_cursor > 0) {
if (t_con->line_cursor != t_con->line_size) { if (t_con->line_cursor != t_con->line_size) {
int i; size_t i;
telnet_write(connection, "\b", 1); telnet_write(connection, "\b", 1);
t_con->line_cursor--; t_con->line_cursor--;
t_con->line_size--; t_con->line_size--;
@ -482,6 +516,10 @@ static int telnet_input(struct connection *connection)
telnet_history_up(connection); telnet_history_up(connection);
else if (*buf_p == CTRL('N')) /* cursor down */ else if (*buf_p == CTRL('N')) /* cursor down */
telnet_history_down(connection); telnet_history_down(connection);
else if (*buf_p == CTRL('A'))
telnet_move_cursor(connection, 0);
else if (*buf_p == CTRL('E'))
telnet_move_cursor(connection, t_con->line_size);
else else
LOG_DEBUG("unhandled nonprintable: %2.2x", *buf_p); LOG_DEBUG("unhandled nonprintable: %2.2x", *buf_p);
} }
@ -538,7 +576,7 @@ static int telnet_input(struct connection *connection)
/* Remove character */ /* Remove character */
if (*buf_p == '~') { if (*buf_p == '~') {
if (t_con->line_cursor < t_con->line_size) { if (t_con->line_cursor < t_con->line_size) {
int i; size_t i;
t_con->line_size--; t_con->line_size--;
/* remove char from line buffer */ /* remove char from line buffer */
memmove(t_con->line + t_con->line_cursor, memmove(t_con->line + t_con->line_cursor,

View File

@ -46,15 +46,16 @@ enum telnet_states {
struct telnet_connection { struct telnet_connection {
char *prompt; char *prompt;
bool prompt_visible;
enum telnet_states state; enum telnet_states state;
char line[TELNET_LINE_MAX_SIZE]; char line[TELNET_LINE_MAX_SIZE];
int line_size; size_t line_size;
int line_cursor; size_t line_cursor;
char last_escape; char last_escape;
char *history[TELNET_LINE_HISTORY_SIZE]; char *history[TELNET_LINE_HISTORY_SIZE];
int next_history; size_t next_history;
int current_history; size_t current_history;
int closed; bool closed;
}; };
struct telnet_service { struct telnet_service {

View File

@ -54,7 +54,7 @@ static int aarch64_unset_breakpoint(struct target *target,
static int aarch64_mmu(struct target *target, int *enabled); static int aarch64_mmu(struct target *target, int *enabled);
static int aarch64_virt2phys(struct target *target, static int aarch64_virt2phys(struct target *target,
target_addr_t virt, target_addr_t *phys); target_addr_t virt, target_addr_t *phys);
static int aarch64_read_apb_ap_memory(struct target *target, static int aarch64_read_cpu_memory(struct target *target,
uint64_t address, uint32_t size, uint32_t count, uint8_t *buffer); uint64_t address, uint32_t size, uint32_t count, uint8_t *buffer);
#define foreach_smp_target(pos, head) \ #define foreach_smp_target(pos, head) \
@ -161,8 +161,16 @@ static int aarch64_mmu_modify(struct target *target, int enable)
case ARMV8_64_EL3T: case ARMV8_64_EL3T:
instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL3, 0); instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL3, 0);
break; break;
case ARM_MODE_SVC:
case ARM_MODE_ABT:
case ARM_MODE_FIQ:
case ARM_MODE_IRQ:
instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0);
break;
default: default:
LOG_DEBUG("unknown cpu state 0x%x" PRIx32, armv8->arm.core_state); LOG_DEBUG("unknown cpu state 0x%" PRIx32, armv8->arm.core_mode);
break; break;
} }
@ -180,7 +188,7 @@ static int aarch64_init_debug_access(struct target *target)
int retval; int retval;
uint32_t dummy; uint32_t dummy;
LOG_DEBUG(" "); LOG_DEBUG("%s", target_name(target));
retval = mem_ap_write_atomic_u32(armv8->debug_ap, retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_OSLAR, 0); armv8->debug_base + CPUV8_DBG_OSLAR, 0);
@ -634,9 +642,11 @@ static int aarch64_prepare_restart_one(struct target *target)
armv8->debug_base + CPUV8_DBG_DSCR, dscr); armv8->debug_base + CPUV8_DBG_DSCR, dscr);
} }
if (retval == ERROR_OK) {
/* clear sticky bits in PRSR, SDR is now 0 */ /* clear sticky bits in PRSR, SDR is now 0 */
retval = mem_ap_read_atomic_u32(armv8->debug_ap, retval = mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_PRSR, &tmp); armv8->debug_base + CPUV8_DBG_PRSR, &tmp);
}
return retval; return retval;
} }
@ -770,6 +780,9 @@ static int aarch64_step_restart_smp(struct target *target)
if (curr == target) if (curr == target)
continue; continue;
if (!target_was_examined(curr))
continue;
retval = aarch64_check_state_one(curr, retval = aarch64_check_state_one(curr,
PRSR_SDR, PRSR_SDR, &resumed, &prsr); PRSR_SDR, PRSR_SDR, &resumed, &prsr);
if (retval != ERROR_OK || (!resumed && (prsr & PRSR_HALT))) { if (retval != ERROR_OK || (!resumed && (prsr & PRSR_HALT))) {
@ -1046,6 +1059,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
int handle_breakpoints) int handle_breakpoints)
{ {
struct armv8_common *armv8 = target_to_armv8(target); struct armv8_common *armv8 = target_to_armv8(target);
struct aarch64_common *aarch64 = target_to_aarch64(target);
int saved_retval = ERROR_OK; int saved_retval = ERROR_OK;
int retval; int retval;
uint32_t edecr; uint32_t edecr;
@ -1066,7 +1080,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
armv8->debug_base + CPUV8_DBG_EDECR, (edecr|0x4)); armv8->debug_base + CPUV8_DBG_EDECR, (edecr|0x4));
} }
/* disable interrupts while stepping */ /* disable interrupts while stepping */
if (retval == ERROR_OK) if (retval == ERROR_OK && aarch64->isrmasking_mode == AARCH64_ISRMASK_ON)
retval = aarch64_set_dscr_bits(target, 0x3 << 22, 0x3 << 22); retval = aarch64_set_dscr_bits(target, 0x3 << 22, 0x3 << 22);
/* bail out if stepping setup has failed */ /* bail out if stepping setup has failed */
if (retval != ERROR_OK) if (retval != ERROR_OK)
@ -1110,7 +1124,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
if (retval != ERROR_OK || stepped) if (retval != ERROR_OK || stepped)
break; break;
if (timeval_ms() > then + 1000) { if (timeval_ms() > then + 100) {
LOG_ERROR("timeout waiting for target %s halt after step", LOG_ERROR("timeout waiting for target %s halt after step",
target_name(target)); target_name(target));
retval = ERROR_TARGET_TIMEOUT; retval = ERROR_TARGET_TIMEOUT;
@ -1118,8 +1132,14 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
} }
} }
/*
* At least on one SoC (Renesas R8A7795) stepping over a WFI instruction
* causes a timeout. The core takes the step but doesn't complete it and so
* debug state is never entered. However, you can manually halt the core
* as an external debug even is also a WFI wakeup event.
*/
if (retval == ERROR_TARGET_TIMEOUT) if (retval == ERROR_TARGET_TIMEOUT)
saved_retval = retval; saved_retval = aarch64_halt_one(target, HALT_SYNC);
/* restore EDECR */ /* restore EDECR */
retval = mem_ap_write_atomic_u32(armv8->debug_ap, retval = mem_ap_write_atomic_u32(armv8->debug_ap,
@ -1128,9 +1148,11 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
return retval; return retval;
/* restore interrupts */ /* restore interrupts */
if (aarch64->isrmasking_mode == AARCH64_ISRMASK_ON) {
retval = aarch64_set_dscr_bits(target, 0x3 << 22, 0); retval = aarch64_set_dscr_bits(target, 0x3 << 22, 0);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return ERROR_OK; return ERROR_OK;
}
if (saved_retval != ERROR_OK) if (saved_retval != ERROR_OK)
return saved_retval; return saved_retval;
@ -1668,7 +1690,99 @@ static int aarch64_deassert_reset(struct target *target)
return aarch64_init_debug_access(target); return aarch64_init_debug_access(target);
} }
static int aarch64_write_apb_ap_memory(struct target *target, static int aarch64_write_cpu_memory_slow(struct target *target,
uint32_t size, uint32_t count, const uint8_t *buffer, uint32_t *dscr)
{
struct armv8_common *armv8 = target_to_armv8(target);
struct arm_dpm *dpm = &armv8->dpm;
struct arm *arm = &armv8->arm;
int retval;
armv8_reg_current(arm, 1)->dirty = true;
/* change DCC to normal mode if necessary */
if (*dscr & DSCR_MA) {
*dscr &= ~DSCR_MA;
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, *dscr);
if (retval != ERROR_OK)
return retval;
}
while (count) {
uint32_t data, opcode;
/* write the data to store into DTRRX */
if (size == 1)
data = *buffer;
else if (size == 2)
data = target_buffer_get_u16(target, buffer);
else
data = target_buffer_get_u32(target, buffer);
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DTRRX, data);
if (retval != ERROR_OK)
return retval;
if (arm->core_state == ARM_STATE_AARCH64)
retval = dpm->instr_execute(dpm, ARMV8_MRS(SYSTEM_DBG_DTRRX_EL0, 1));
else
retval = dpm->instr_execute(dpm, ARMV4_5_MRC(14, 0, 1, 0, 5, 0));
if (retval != ERROR_OK)
return retval;
if (size == 1)
opcode = armv8_opcode(armv8, ARMV8_OPC_STRB_IP);
else if (size == 2)
opcode = armv8_opcode(armv8, ARMV8_OPC_STRH_IP);
else
opcode = armv8_opcode(armv8, ARMV8_OPC_STRW_IP);
retval = dpm->instr_execute(dpm, opcode);
if (retval != ERROR_OK)
return retval;
/* Advance */
buffer += size;
--count;
}
return ERROR_OK;
}
static int aarch64_write_cpu_memory_fast(struct target *target,
uint32_t count, const uint8_t *buffer, uint32_t *dscr)
{
struct armv8_common *armv8 = target_to_armv8(target);
struct arm *arm = &armv8->arm;
int retval;
armv8_reg_current(arm, 1)->dirty = true;
/* Step 1.d - Change DCC to memory mode */
*dscr |= DSCR_MA;
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, *dscr);
if (retval != ERROR_OK)
return retval;
/* Step 2.a - Do the write */
retval = mem_ap_write_buf_noincr(armv8->debug_ap,
buffer, 4, count, armv8->debug_base + CPUV8_DBG_DTRRX);
if (retval != ERROR_OK)
return retval;
/* Step 3.a - Switch DTR mode back to Normal mode */
*dscr &= ~DSCR_MA;
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, *dscr);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
static int aarch64_write_cpu_memory(struct target *target,
uint64_t address, uint32_t size, uint64_t address, uint32_t size,
uint32_t count, const uint8_t *buffer) uint32_t count, const uint8_t *buffer)
{ {
@ -1677,144 +1791,213 @@ static int aarch64_write_apb_ap_memory(struct target *target,
struct armv8_common *armv8 = target_to_armv8(target); struct armv8_common *armv8 = target_to_armv8(target);
struct arm_dpm *dpm = &armv8->dpm; struct arm_dpm *dpm = &armv8->dpm;
struct arm *arm = &armv8->arm; struct arm *arm = &armv8->arm;
int total_bytes = count * size;
int total_u32;
int start_byte = address & 0x3;
int end_byte = (address + total_bytes) & 0x3;
struct reg *reg;
uint32_t dscr; uint32_t dscr;
uint8_t *tmp_buff = NULL;
if (target->state != TARGET_HALTED) { if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted"); LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED; return ERROR_TARGET_NOT_HALTED;
} }
total_u32 = DIV_ROUND_UP((address & 3) + total_bytes, 4); /* Mark register X0 as dirty, as it will be used
/* Mark register R0 as dirty, as it will be used
* for transferring the data. * for transferring the data.
* It will be restored automatically when exiting * It will be restored automatically when exiting
* debug mode * debug mode
*/ */
reg = armv8_reg_current(arm, 1); armv8_reg_current(arm, 0)->dirty = true;
reg->dirty = true;
reg = armv8_reg_current(arm, 0);
reg->dirty = true;
/* This algorithm comes from DDI0487A.g, chapter J9.1 */ /* This algorithm comes from DDI0487A.g, chapter J9.1 */
/* The algorithm only copies 32 bit words, so the buffer
* should be expanded to include the words at either end.
* The first and last words will be read first to avoid
* corruption if needed.
*/
tmp_buff = malloc(total_u32 * 4);
if ((start_byte != 0) && (total_u32 > 1)) {
/* First bytes not aligned - read the 32 bit word to avoid corrupting
* the other bytes in the word.
*/
retval = aarch64_read_apb_ap_memory(target, (address & ~0x3), 4, 1, tmp_buff);
if (retval != ERROR_OK)
goto error_free_buff_w;
}
/* If end of write is not aligned, or the write is less than 4 bytes */
if ((end_byte != 0) ||
((total_u32 == 1) && (total_bytes != 4))) {
/* Read the last word to avoid corruption during 32 bit write */
int mem_offset = (total_u32-1) * 4;
retval = aarch64_read_apb_ap_memory(target, (address & ~0x3) + mem_offset, 4, 1, &tmp_buff[mem_offset]);
if (retval != ERROR_OK)
goto error_free_buff_w;
}
/* Copy the write buffer over the top of the temporary buffer */
memcpy(&tmp_buff[start_byte], buffer, total_bytes);
/* We now have a 32 bit aligned buffer that can be written */
/* Read DSCR */ /* Read DSCR */
retval = mem_ap_read_atomic_u32(armv8->debug_ap, retval = mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, &dscr); armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
if (retval != ERROR_OK) if (retval != ERROR_OK)
goto error_free_buff_w; return retval;
/* Set Normal access mode */ /* Set Normal access mode */
dscr = (dscr & ~DSCR_MA); dscr = (dscr & ~DSCR_MA);
retval = mem_ap_write_atomic_u32(armv8->debug_ap, retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, dscr); armv8->debug_base + CPUV8_DBG_DSCR, dscr);
if (retval != ERROR_OK)
return retval;
if (arm->core_state == ARM_STATE_AARCH64) { if (arm->core_state == ARM_STATE_AARCH64) {
/* Write X0 with value 'address' using write procedure */ /* Write X0 with value 'address' using write procedure */
/* Step 1.a+b - Write the address for read access into DBGDTR_EL0 */ /* Step 1.a+b - Write the address for read access into DBGDTR_EL0 */
/* Step 1.c - Copy value from DTR to R0 using instruction mrs DBGDTR_EL0, x0 */ /* Step 1.c - Copy value from DTR to R0 using instruction mrs DBGDTR_EL0, x0 */
retval = dpm->instr_write_data_dcc_64(dpm, retval = dpm->instr_write_data_dcc_64(dpm,
ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), address & ~0x3ULL); ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), address);
} else { } else {
/* Write R0 with value 'address' using write procedure */ /* Write R0 with value 'address' using write procedure */
/* Step 1.a+b - Write the address for read access into DBGDTRRX */ /* Step 1.a+b - Write the address for read access into DBGDTRRX */
/* Step 1.c - Copy value from DTR to R0 using instruction mrc DBGDTRTXint, r0 */ /* Step 1.c - Copy value from DTR to R0 using instruction mrc DBGDTRTXint, r0 */
dpm->instr_write_data_dcc(dpm, retval = dpm->instr_write_data_dcc(dpm,
ARMV4_5_MRC(14, 0, 0, 0, 5, 0), address & ~0x3ULL); ARMV4_5_MRC(14, 0, 0, 0, 5, 0), address);
} }
/* Step 1.d - Change DCC to memory mode */
dscr = dscr | DSCR_MA; if (retval != ERROR_OK)
retval += mem_ap_write_atomic_u32(armv8->debug_ap, return retval;
if (size == 4 && (address % 4) == 0)
retval = aarch64_write_cpu_memory_fast(target, count, buffer, &dscr);
else
retval = aarch64_write_cpu_memory_slow(target, size, count, buffer, &dscr);
if (retval != ERROR_OK) {
/* Unset DTR mode */
mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
dscr &= ~DSCR_MA;
mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, dscr); armv8->debug_base + CPUV8_DBG_DSCR, dscr);
if (retval != ERROR_OK) }
goto error_unset_dtr_w;
/* Step 2.a - Do the write */
retval = mem_ap_write_buf_noincr(armv8->debug_ap,
tmp_buff, 4, total_u32, armv8->debug_base + CPUV8_DBG_DTRRX);
if (retval != ERROR_OK)
goto error_unset_dtr_w;
/* Step 3.a - Switch DTR mode back to Normal mode */
dscr = (dscr & ~DSCR_MA);
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
if (retval != ERROR_OK)
goto error_unset_dtr_w;
/* Check for sticky abort flags in the DSCR */ /* Check for sticky abort flags in the DSCR */
retval = mem_ap_read_atomic_u32(armv8->debug_ap, retval = mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, &dscr); armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
if (retval != ERROR_OK) if (retval != ERROR_OK)
goto error_free_buff_w; return retval;
dpm->dscr = dscr; dpm->dscr = dscr;
if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) { if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) {
/* Abort occurred - clear it and exit */ /* Abort occurred - clear it and exit */
LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr); LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr);
armv8_dpm_handle_exception(dpm); armv8_dpm_handle_exception(dpm);
goto error_free_buff_w; return ERROR_FAIL;
} }
/* Done */ /* Done */
free(tmp_buff);
return ERROR_OK; return ERROR_OK;
error_unset_dtr_w:
/* Unset DTR mode */
mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
dscr = (dscr & ~DSCR_MA);
mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
error_free_buff_w:
LOG_ERROR("error");
free(tmp_buff);
return ERROR_FAIL;
} }
static int aarch64_read_apb_ap_memory(struct target *target, static int aarch64_read_cpu_memory_slow(struct target *target,
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t *dscr)
{
struct armv8_common *armv8 = target_to_armv8(target);
struct arm_dpm *dpm = &armv8->dpm;
struct arm *arm = &armv8->arm;
int retval;
armv8_reg_current(arm, 1)->dirty = true;
/* change DCC to normal mode (if necessary) */
if (*dscr & DSCR_MA) {
*dscr &= DSCR_MA;
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, *dscr);
if (retval != ERROR_OK)
return retval;
}
while (count) {
uint32_t opcode, data;
if (size == 1)
opcode = armv8_opcode(armv8, ARMV8_OPC_LDRB_IP);
else if (size == 2)
opcode = armv8_opcode(armv8, ARMV8_OPC_LDRH_IP);
else
opcode = armv8_opcode(armv8, ARMV8_OPC_LDRW_IP);
retval = dpm->instr_execute(dpm, opcode);
if (retval != ERROR_OK)
return retval;
if (arm->core_state == ARM_STATE_AARCH64)
retval = dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DTRTX_EL0, 1));
else
retval = dpm->instr_execute(dpm, ARMV4_5_MCR(14, 0, 1, 0, 5, 0));
if (retval != ERROR_OK)
return retval;
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DTRTX, &data);
if (retval != ERROR_OK)
return retval;
if (size == 1)
*buffer = (uint8_t)data;
else if (size == 2)
target_buffer_set_u16(target, buffer, (uint16_t)data);
else
target_buffer_set_u32(target, buffer, data);
/* Advance */
buffer += size;
--count;
}
return ERROR_OK;
}
static int aarch64_read_cpu_memory_fast(struct target *target,
uint32_t count, uint8_t *buffer, uint32_t *dscr)
{
struct armv8_common *armv8 = target_to_armv8(target);
struct arm_dpm *dpm = &armv8->dpm;
struct arm *arm = &armv8->arm;
int retval;
uint32_t value;
/* Mark X1 as dirty */
armv8_reg_current(arm, 1)->dirty = true;
if (arm->core_state == ARM_STATE_AARCH64) {
/* Step 1.d - Dummy operation to ensure EDSCR.Txfull == 1 */
retval = dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, 0));
} else {
/* Step 1.d - Dummy operation to ensure EDSCR.Txfull == 1 */
retval = dpm->instr_execute(dpm, ARMV4_5_MCR(14, 0, 0, 0, 5, 0));
}
if (retval != ERROR_OK)
return retval;
/* Step 1.e - Change DCC to memory mode */
*dscr |= DSCR_MA;
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, *dscr);
if (retval != ERROR_OK)
return retval;
/* Step 1.f - read DBGDTRTX and discard the value */
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DTRTX, &value);
if (retval != ERROR_OK)
return retval;
count--;
/* Read the data - Each read of the DTRTX register causes the instruction to be reissued
* Abort flags are sticky, so can be read at end of transactions
*
* This data is read in aligned to 32 bit boundary.
*/
if (count) {
/* Step 2.a - Loop n-1 times, each read of DBGDTRTX reads the data from [X0] and
* increments X0 by 4. */
retval = mem_ap_read_buf_noincr(armv8->debug_ap, buffer, 4, count,
armv8->debug_base + CPUV8_DBG_DTRTX);
if (retval != ERROR_OK)
return retval;
}
/* Step 3.a - set DTR access mode back to Normal mode */
*dscr &= ~DSCR_MA;
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, *dscr);
if (retval != ERROR_OK)
return retval;
/* Step 3.b - read DBGDTRTX for the final value */
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DTRTX, &value);
if (retval != ERROR_OK)
return retval;
target_buffer_set_u32(target, buffer + count * 4, value);
return retval;
}
static int aarch64_read_cpu_memory(struct target *target,
target_addr_t address, uint32_t size, target_addr_t address, uint32_t size,
uint32_t count, uint8_t *buffer) uint32_t count, uint8_t *buffer)
{ {
@ -1823,126 +2006,74 @@ static int aarch64_read_apb_ap_memory(struct target *target,
struct armv8_common *armv8 = target_to_armv8(target); struct armv8_common *armv8 = target_to_armv8(target);
struct arm_dpm *dpm = &armv8->dpm; struct arm_dpm *dpm = &armv8->dpm;
struct arm *arm = &armv8->arm; struct arm *arm = &armv8->arm;
int total_bytes = count * size;
int total_u32;
int start_byte = address & 0x3;
int end_byte = (address + total_bytes) & 0x3;
struct reg *reg;
uint32_t dscr; uint32_t dscr;
uint8_t *tmp_buff = NULL;
uint8_t *u8buf_ptr; LOG_DEBUG("Reading CPU memory address 0x%016" PRIx64 " size %" PRIu32 " count %" PRIu32,
uint32_t value; address, size, count);
if (target->state != TARGET_HALTED) { if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted"); LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED; return ERROR_TARGET_NOT_HALTED;
} }
total_u32 = DIV_ROUND_UP((address & 3) + total_bytes, 4); /* Mark register X0 as dirty, as it will be used
/* Mark register X0, X1 as dirty, as it will be used
* for transferring the data. * for transferring the data.
* It will be restored automatically when exiting * It will be restored automatically when exiting
* debug mode * debug mode
*/ */
reg = armv8_reg_current(arm, 1); armv8_reg_current(arm, 0)->dirty = true;
reg->dirty = true;
reg = armv8_reg_current(arm, 0);
reg->dirty = true;
/* Read DSCR */ /* Read DSCR */
retval = mem_ap_read_atomic_u32(armv8->debug_ap, retval = mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, &dscr); armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
if (retval != ERROR_OK)
return retval;
/* This algorithm comes from DDI0487A.g, chapter J9.1 */ /* This algorithm comes from DDI0487A.g, chapter J9.1 */
/* Set Normal access mode */ /* Set Normal access mode */
dscr = (dscr & ~DSCR_MA); dscr &= ~DSCR_MA;
retval += mem_ap_write_atomic_u32(armv8->debug_ap, retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, dscr); armv8->debug_base + CPUV8_DBG_DSCR, dscr);
if (retval != ERROR_OK)
return retval;
if (arm->core_state == ARM_STATE_AARCH64) { if (arm->core_state == ARM_STATE_AARCH64) {
/* Write X0 with value 'address' using write procedure */ /* Write X0 with value 'address' using write procedure */
/* Step 1.a+b - Write the address for read access into DBGDTR_EL0 */ /* Step 1.a+b - Write the address for read access into DBGDTR_EL0 */
/* Step 1.c - Copy value from DTR to R0 using instruction mrs DBGDTR_EL0, x0 */ /* Step 1.c - Copy value from DTR to R0 using instruction mrs DBGDTR_EL0, x0 */
retval += dpm->instr_write_data_dcc_64(dpm, retval = dpm->instr_write_data_dcc_64(dpm,
ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), address & ~0x3ULL); ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), address);
/* Step 1.d - Dummy operation to ensure EDSCR.Txfull == 1 */
retval += dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, 0));
/* Step 1.e - Change DCC to memory mode */
dscr = dscr | DSCR_MA;
retval += mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
/* Step 1.f - read DBGDTRTX and discard the value */
retval += mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DTRTX, &value);
} else { } else {
/* Write R0 with value 'address' using write procedure */ /* Write R0 with value 'address' using write procedure */
/* Step 1.a+b - Write the address for read access into DBGDTRRXint */ /* Step 1.a+b - Write the address for read access into DBGDTRRXint */
/* Step 1.c - Copy value from DTR to R0 using instruction mrc DBGDTRTXint, r0 */ /* Step 1.c - Copy value from DTR to R0 using instruction mrc DBGDTRTXint, r0 */
retval += dpm->instr_write_data_dcc(dpm, retval = dpm->instr_write_data_dcc(dpm,
ARMV4_5_MRC(14, 0, 0, 0, 5, 0), address & ~0x3ULL); ARMV4_5_MRC(14, 0, 0, 0, 5, 0), address);
/* Step 1.d - Dummy operation to ensure EDSCR.Txfull == 1 */
retval += dpm->instr_execute(dpm, ARMV4_5_MCR(14, 0, 0, 0, 5, 0));
/* Step 1.e - Change DCC to memory mode */
dscr = dscr | DSCR_MA;
retval += mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
/* Step 1.f - read DBGDTRTX and discard the value */
retval += mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DTRTX, &value);
} }
if (retval != ERROR_OK) if (retval != ERROR_OK)
goto error_unset_dtr_r; return retval;
/* Optimize the read as much as we can, either way we read in a single pass */ if (size == 4 && (address % 4) == 0)
if ((start_byte) || (end_byte)) { retval = aarch64_read_cpu_memory_fast(target, count, buffer, &dscr);
/* The algorithm only copies 32 bit words, so the buffer else
* should be expanded to include the words at either end. retval = aarch64_read_cpu_memory_slow(target, size, count, buffer, &dscr);
* The first and last words will be read into a temp buffer
* to avoid corruption
*/
tmp_buff = malloc(total_u32 * 4);
if (!tmp_buff)
goto error_unset_dtr_r;
/* use the tmp buffer to read the entire data */ if (dscr & DSCR_MA) {
u8buf_ptr = tmp_buff; dscr &= ~DSCR_MA;
} else mem_ap_write_atomic_u32(armv8->debug_ap,
/* address and read length are aligned so read directly into the passed buffer */
u8buf_ptr = buffer;
/* Read the data - Each read of the DTRTX register causes the instruction to be reissued
* Abort flags are sticky, so can be read at end of transactions
*
* This data is read in aligned to 32 bit boundary.
*/
/* Step 2.a - Loop n-1 times, each read of DBGDTRTX reads the data from [X0] and
* increments X0 by 4. */
retval = mem_ap_read_buf_noincr(armv8->debug_ap, u8buf_ptr, 4, total_u32-1,
armv8->debug_base + CPUV8_DBG_DTRTX);
if (retval != ERROR_OK)
goto error_unset_dtr_r;
/* Step 3.a - set DTR access mode back to Normal mode */
dscr = (dscr & ~DSCR_MA);
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, dscr); armv8->debug_base + CPUV8_DBG_DSCR, dscr);
if (retval != ERROR_OK) }
goto error_free_buff_r;
/* Step 3.b - read DBGDTRTX for the final value */ if (retval != ERROR_OK)
retval = mem_ap_read_atomic_u32(armv8->debug_ap, return retval;
armv8->debug_base + CPUV8_DBG_DTRTX, &value);
memcpy(u8buf_ptr + (total_u32-1) * 4, &value, 4);
/* Check for sticky abort flags in the DSCR */ /* Check for sticky abort flags in the DSCR */
retval = mem_ap_read_atomic_u32(armv8->debug_ap, retval = mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, &dscr); armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
if (retval != ERROR_OK) if (retval != ERROR_OK)
goto error_free_buff_r; return retval;
dpm->dscr = dscr; dpm->dscr = dscr;
@ -1950,29 +2081,11 @@ static int aarch64_read_apb_ap_memory(struct target *target,
/* Abort occurred - clear it and exit */ /* Abort occurred - clear it and exit */
LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr); LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr);
armv8_dpm_handle_exception(dpm); armv8_dpm_handle_exception(dpm);
goto error_free_buff_r; return ERROR_FAIL;
}
/* check if we need to copy aligned data by applying any shift necessary */
if (tmp_buff) {
memcpy(buffer, tmp_buff + start_byte, total_bytes);
free(tmp_buff);
} }
/* Done */ /* Done */
return ERROR_OK; return ERROR_OK;
error_unset_dtr_r:
/* Unset DTR mode */
mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
dscr = (dscr & ~DSCR_MA);
mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
error_free_buff_r:
LOG_ERROR("error");
free(tmp_buff);
return ERROR_FAIL;
} }
static int aarch64_read_phys_memory(struct target *target, static int aarch64_read_phys_memory(struct target *target,
@ -1986,7 +2099,7 @@ static int aarch64_read_phys_memory(struct target *target,
retval = aarch64_mmu_modify(target, 0); retval = aarch64_mmu_modify(target, 0);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
retval = aarch64_read_apb_ap_memory(target, address, size, count, buffer); retval = aarch64_read_cpu_memory(target, address, size, count, buffer);
} }
return retval; return retval;
} }
@ -2008,7 +2121,7 @@ static int aarch64_read_memory(struct target *target, target_addr_t address,
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
} }
return aarch64_read_apb_ap_memory(target, address, size, count, buffer); return aarch64_read_cpu_memory(target, address, size, count, buffer);
} }
static int aarch64_write_phys_memory(struct target *target, static int aarch64_write_phys_memory(struct target *target,
@ -2022,7 +2135,7 @@ static int aarch64_write_phys_memory(struct target *target,
retval = aarch64_mmu_modify(target, 0); retval = aarch64_mmu_modify(target, 0);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
return aarch64_write_apb_ap_memory(target, address, size, count, buffer); return aarch64_write_cpu_memory(target, address, size, count, buffer);
} }
return retval; return retval;
@ -2045,7 +2158,7 @@ static int aarch64_write_memory(struct target *target, target_addr_t address,
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
} }
return aarch64_write_apb_ap_memory(target, address, size, count, buffer); return aarch64_write_cpu_memory(target, address, size, count, buffer);
} }
static int aarch64_handle_target_request(void *priv) static int aarch64_handle_target_request(void *priv)
@ -2090,7 +2203,7 @@ static int aarch64_examine_first(struct target *target)
int retval = ERROR_OK; int retval = ERROR_OK;
uint64_t debug, ttypr; uint64_t debug, ttypr;
uint32_t cpuid; uint32_t cpuid;
uint32_t tmp0, tmp1; uint32_t tmp0, tmp1, tmp2, tmp3;
debug = ttypr = cpuid = 0; debug = ttypr = cpuid = 0;
retval = dap_dp_init(swjdp); retval = dap_dp_init(swjdp);
@ -2130,32 +2243,6 @@ static int aarch64_examine_first(struct target *target)
} else } else
armv8->debug_base = target->dbgbase; armv8->debug_base = target->dbgbase;
uint32_t prsr;
int64_t then = timeval_ms();
do {
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_PRSR, &prsr);
if (retval == ERROR_OK) {
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_PRCR, PRCR_COREPURQ|PRCR_CORENPDRQ);
if (retval != ERROR_OK) {
LOG_DEBUG("write to PRCR failed");
break;
}
}
if (timeval_ms() > then + 1000) {
retval = ERROR_TARGET_TIMEOUT;
break;
}
} while ((prsr & PRSR_PU) == 0);
if (retval != ERROR_OK) {
LOG_ERROR("target %s: failed to set power state of the core.", target_name(target));
return retval;
}
retval = mem_ap_write_atomic_u32(armv8->debug_ap, retval = mem_ap_write_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_OSLAR, 0); armv8->debug_base + CPUV8_DBG_OSLAR, 0);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
@ -2163,34 +2250,40 @@ static int aarch64_examine_first(struct target *target)
return retval; return retval;
} }
retval = mem_ap_read_atomic_u32(armv8->debug_ap, retval = mem_ap_read_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_MAINID0, &cpuid); armv8->debug_base + CPUV8_DBG_MAINID0, &cpuid);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_DEBUG("Examine %s failed", "CPUID"); LOG_DEBUG("Examine %s failed", "CPUID");
return retval; return retval;
} }
retval = mem_ap_read_atomic_u32(armv8->debug_ap, retval = mem_ap_read_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_MEMFEATURE0, &tmp0); armv8->debug_base + CPUV8_DBG_MEMFEATURE0, &tmp0);
retval += mem_ap_read_atomic_u32(armv8->debug_ap, retval += mem_ap_read_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_MEMFEATURE0 + 4, &tmp1); armv8->debug_base + CPUV8_DBG_MEMFEATURE0 + 4, &tmp1);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_DEBUG("Examine %s failed", "Memory Model Type"); LOG_DEBUG("Examine %s failed", "Memory Model Type");
return retval; return retval;
} }
ttypr |= tmp1; retval = mem_ap_read_u32(armv8->debug_ap,
ttypr = (ttypr << 32) | tmp0; armv8->debug_base + CPUV8_DBG_DBGFEATURE0, &tmp2);
retval += mem_ap_read_u32(armv8->debug_ap,
retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DBGFEATURE0 + 4, &tmp3);
armv8->debug_base + CPUV8_DBG_DBGFEATURE0, &tmp0);
retval += mem_ap_read_atomic_u32(armv8->debug_ap,
armv8->debug_base + CPUV8_DBG_DBGFEATURE0 + 4, &tmp1);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_DEBUG("Examine %s failed", "ID_AA64DFR0_EL1"); LOG_DEBUG("Examine %s failed", "ID_AA64DFR0_EL1");
return retval; return retval;
} }
debug |= tmp1;
debug = (debug << 32) | tmp0; retval = dap_run(armv8->debug_ap->dap);
if (retval != ERROR_OK) {
LOG_ERROR("%s: examination failed\n", target_name(target));
return retval;
}
ttypr |= tmp1;
ttypr = (ttypr << 32) | tmp0;
debug |= tmp3;
debug = (debug << 32) | tmp2;
LOG_DEBUG("cpuid = 0x%08" PRIx32, cpuid); LOG_DEBUG("cpuid = 0x%08" PRIx32, cpuid);
LOG_DEBUG("ttypr = 0x%08" PRIx64, ttypr); LOG_DEBUG("ttypr = 0x%08" PRIx64, ttypr);
@ -2229,9 +2322,9 @@ static int aarch64_examine_first(struct target *target)
LOG_DEBUG("Configured %i hw breakpoints", aarch64->brp_num); LOG_DEBUG("Configured %i hw breakpoints", aarch64->brp_num);
target->state = TARGET_RUNNING; target->state = TARGET_UNKNOWN;
target->debug_reason = DBG_REASON_NOTHALTED; target->debug_reason = DBG_REASON_NOTHALTED;
aarch64->isrmasking_mode = AARCH64_ISRMASK_ON;
target_set_examined(target); target_set_examined(target);
return ERROR_OK; return ERROR_OK;
} }
@ -2369,6 +2462,34 @@ COMMAND_HANDLER(aarch64_handle_smp_on_command)
return ERROR_OK; return ERROR_OK;
} }
COMMAND_HANDLER(aarch64_mask_interrupts_command)
{
struct target *target = get_current_target(CMD_CTX);
struct aarch64_common *aarch64 = target_to_aarch64(target);
static const Jim_Nvp nvp_maskisr_modes[] = {
{ .name = "off", .value = AARCH64_ISRMASK_OFF },
{ .name = "on", .value = AARCH64_ISRMASK_ON },
{ .name = NULL, .value = -1 },
};
const Jim_Nvp *n;
if (CMD_ARGC > 0) {
n = Jim_Nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
if (n->name == NULL) {
LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]);
return ERROR_COMMAND_SYNTAX_ERROR;
}
aarch64->isrmasking_mode = n->value;
}
n = Jim_Nvp_value2name_simple(nvp_maskisr_modes, aarch64->isrmasking_mode);
command_print(CMD_CTX, "aarch64 interrupt mask %s", n->name);
return ERROR_OK;
}
static const struct command_registration aarch64_exec_command_handlers[] = { static const struct command_registration aarch64_exec_command_handlers[] = {
{ {
.name = "cache_info", .name = "cache_info",
@ -2397,6 +2518,13 @@ static const struct command_registration aarch64_exec_command_handlers[] = {
.help = "Restart smp handling", .help = "Restart smp handling",
.usage = "", .usage = "",
}, },
{
.name = "maskisr",
.handler = aarch64_mask_interrupts_command,
.mode = COMMAND_ANY,
.help = "mask aarch64 interrupts during single-step",
.usage = "['on'|'off']",
},
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
}; };

View File

@ -36,6 +36,11 @@
#define AARCH64_PADDRDBG_CPU_SHIFT 13 #define AARCH64_PADDRDBG_CPU_SHIFT 13
enum aarch64_isrmasking_mode {
AARCH64_ISRMASK_OFF,
AARCH64_ISRMASK_ON,
};
struct aarch64_brp { struct aarch64_brp {
int used; int used;
int type; int type;
@ -58,6 +63,8 @@ struct aarch64_common {
struct aarch64_brp *brp_list; struct aarch64_brp *brp_list;
struct armv8_common armv8_common; struct armv8_common armv8_common;
enum aarch64_isrmasking_mode isrmasking_mode;
}; };
static inline struct aarch64_common * static inline struct aarch64_common *

View File

@ -124,7 +124,7 @@ static int swd_connect(struct adiv5_dap *dap)
/* Clear link state, including the SELECT cache. */ /* Clear link state, including the SELECT cache. */
dap->do_reconnect = false; dap->do_reconnect = false;
dap->select = DP_SELECT_INVALID; dap_invalidate_cache(dap);
swd_queue_dp_read(dap, DP_DPIDR, &dpidr); swd_queue_dp_read(dap, DP_DPIDR, &dpidr);

View File

@ -66,14 +66,13 @@ enum arm_mode {
ARM_MODE_USER_THREAD = 1, ARM_MODE_USER_THREAD = 1,
ARM_MODE_HANDLER = 2, ARM_MODE_HANDLER = 2,
/* shift left 4 bits for armv8 64 */ ARMV8_64_EL0T = 0x0,
ARMV8_64_EL0T = 0x0F, ARMV8_64_EL1T = 0x4,
ARMV8_64_EL1T = 0x4F, ARMV8_64_EL1H = 0x5,
ARMV8_64_EL1H = 0x5F, ARMV8_64_EL2T = 0x8,
ARMV8_64_EL2T = 0x8F, ARMV8_64_EL2H = 0x9,
ARMV8_64_EL2H = 0x9F, ARMV8_64_EL3T = 0xC,
ARMV8_64_EL3T = 0xCF, ARMV8_64_EL3H = 0xD,
ARMV8_64_EL3H = 0xDF,
ARM_MODE_ANY = -1 ARM_MODE_ANY = -1
}; };

View File

@ -111,17 +111,68 @@ static int mem_ap_setup_csw(struct adiv5_ap *ap, uint32_t csw)
static int mem_ap_setup_tar(struct adiv5_ap *ap, uint32_t tar) static int mem_ap_setup_tar(struct adiv5_ap *ap, uint32_t tar)
{ {
if (tar != ap->tar_value || if (!ap->tar_valid || tar != ap->tar_value) {
(ap->csw_value & CSW_ADDRINC_MASK)) {
/* LOG_DEBUG("DAP: Set TAR %x",tar); */ /* LOG_DEBUG("DAP: Set TAR %x",tar); */
int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR, tar); int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR, tar);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
ap->tar_value = tar; ap->tar_value = tar;
ap->tar_valid = true;
} }
return ERROR_OK; return ERROR_OK;
} }
static int mem_ap_read_tar(struct adiv5_ap *ap, uint32_t *tar)
{
int retval = dap_queue_ap_read(ap, MEM_AP_REG_TAR, tar);
if (retval != ERROR_OK) {
ap->tar_valid = false;
return retval;
}
retval = dap_run(ap->dap);
if (retval != ERROR_OK) {
ap->tar_valid = false;
return retval;
}
ap->tar_value = *tar;
ap->tar_valid = true;
return ERROR_OK;
}
static uint32_t mem_ap_get_tar_increment(struct adiv5_ap *ap)
{
switch (ap->csw_value & CSW_ADDRINC_MASK) {
case CSW_ADDRINC_SINGLE:
switch (ap->csw_value & CSW_SIZE_MASK) {
case CSW_8BIT:
return 1;
case CSW_16BIT:
return 2;
case CSW_32BIT:
return 4;
}
case CSW_ADDRINC_PACKED:
return 4;
}
return 0;
}
/* mem_ap_update_tar_cache is called after an access to MEM_AP_REG_DRW
*/
static void mem_ap_update_tar_cache(struct adiv5_ap *ap)
{
if (!ap->tar_valid)
return;
uint32_t inc = mem_ap_get_tar_increment(ap);
if (inc >= max_tar_block_size(ap->tar_autoincr_block, ap->tar_value))
ap->tar_valid = false;
else
ap->tar_value += inc;
}
/** /**
* Queue transactions setting up transfer parameters for the * Queue transactions setting up transfer parameters for the
* currently selected MEM-AP. * currently selected MEM-AP.
@ -170,7 +221,8 @@ int mem_ap_read_u32(struct adiv5_ap *ap, uint32_t address,
/* Use banked addressing (REG_BDx) to avoid some link traffic /* Use banked addressing (REG_BDx) to avoid some link traffic
* (updating TAR) when reading several consecutive addresses. * (updating TAR) when reading several consecutive addresses.
*/ */
retval = mem_ap_setup_transfer(ap, CSW_32BIT | CSW_ADDRINC_OFF, retval = mem_ap_setup_transfer(ap,
CSW_32BIT | (ap->csw_value & CSW_ADDRINC_MASK),
address & 0xFFFFFFF0); address & 0xFFFFFFF0);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
@ -221,7 +273,8 @@ int mem_ap_write_u32(struct adiv5_ap *ap, uint32_t address,
/* Use banked addressing (REG_BDx) to avoid some link traffic /* Use banked addressing (REG_BDx) to avoid some link traffic
* (updating TAR) when writing several consecutive addresses. * (updating TAR) when writing several consecutive addresses.
*/ */
retval = mem_ap_setup_transfer(ap, CSW_32BIT | CSW_ADDRINC_OFF, retval = mem_ap_setup_transfer(ap,
CSW_32BIT | (ap->csw_value & CSW_ADDRINC_MASK),
address & 0xFFFFFFF0); address & 0xFFFFFFF0);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
@ -272,7 +325,7 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz
const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF; const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF;
uint32_t csw_size; uint32_t csw_size;
uint32_t addr_xor; uint32_t addr_xor;
int retval; int retval = ERROR_OK;
/* TI BE-32 Quirks mode: /* TI BE-32 Quirks mode:
* Writes on big-endian TMS570 behave very strangely. Observed behavior: * Writes on big-endian TMS570 behave very strangely. Observed behavior:
@ -303,10 +356,6 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz
if (ap->unaligned_access_bad && (address % size != 0)) if (ap->unaligned_access_bad && (address % size != 0))
return ERROR_TARGET_UNALIGNED_ACCESS; return ERROR_TARGET_UNALIGNED_ACCESS;
retval = mem_ap_setup_tar(ap, address ^ addr_xor);
if (retval != ERROR_OK)
return retval;
while (nbytes > 0) { while (nbytes > 0) {
uint32_t this_size = size; uint32_t this_size = size;
@ -322,36 +371,41 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz
if (retval != ERROR_OK) if (retval != ERROR_OK)
break; break;
retval = mem_ap_setup_tar(ap, address ^ addr_xor);
if (retval != ERROR_OK)
return retval;
/* How many source bytes each transfer will consume, and their location in the DRW, /* How many source bytes each transfer will consume, and their location in the DRW,
* depends on the type of transfer and alignment. See ARM document IHI0031C. */ * depends on the type of transfer and alignment. See ARM document IHI0031C. */
uint32_t outvalue = 0; uint32_t outvalue = 0;
uint32_t drw_byte_idx = address;
if (dap->ti_be_32_quirks) { if (dap->ti_be_32_quirks) {
switch (this_size) { switch (this_size) {
case 4: case 4:
outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (address++ & 3) ^ addr_xor); outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor);
outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (address++ & 3) ^ addr_xor); outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor);
outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (address++ & 3) ^ addr_xor); outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor);
outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (address++ & 3) ^ addr_xor); outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx & 3) ^ addr_xor);
break; break;
case 2: case 2:
outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (address++ & 3) ^ addr_xor); outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (drw_byte_idx++ & 3) ^ addr_xor);
outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (address++ & 3) ^ addr_xor); outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (drw_byte_idx & 3) ^ addr_xor);
break; break;
case 1: case 1:
outvalue |= (uint32_t)*buffer++ << 8 * (0 ^ (address++ & 3) ^ addr_xor); outvalue |= (uint32_t)*buffer++ << 8 * (0 ^ (drw_byte_idx & 3) ^ addr_xor);
break; break;
} }
} else { } else {
switch (this_size) { switch (this_size) {
case 4: case 4:
outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3);
outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3);
/* fallthrough */ /* fallthrough */
case 2: case 2:
outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3);
/* fallthrough */ /* fallthrough */
case 1: case 1:
outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx & 3);
} }
} }
@ -361,12 +415,9 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz
if (retval != ERROR_OK) if (retval != ERROR_OK)
break; break;
/* Rewrite TAR if it wrapped or we're xoring addresses */ mem_ap_update_tar_cache(ap);
if (addrinc && (addr_xor || (address % ap->tar_autoincr_block < size && nbytes > 0))) { if (addrinc)
retval = mem_ap_setup_tar(ap, address ^ addr_xor); address += this_size;
if (retval != ERROR_OK)
break;
}
} }
/* REVISIT: Might want to have a queued version of this function that does not run. */ /* REVISIT: Might want to have a queued version of this function that does not run. */
@ -375,8 +426,7 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
uint32_t tar; uint32_t tar;
if (dap_queue_ap_read(ap, MEM_AP_REG_TAR, &tar) == ERROR_OK if (mem_ap_read_tar(ap, &tar) == ERROR_OK)
&& dap_run(dap) == ERROR_OK)
LOG_ERROR("Failed to write memory at 0x%08"PRIx32, tar); LOG_ERROR("Failed to write memory at 0x%08"PRIx32, tar);
else else
LOG_ERROR("Failed to write memory and, additionally, failed to find out where"); LOG_ERROR("Failed to write memory and, additionally, failed to find out where");
@ -405,7 +455,7 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint
const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF; const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF;
uint32_t csw_size; uint32_t csw_size;
uint32_t address = adr; uint32_t address = adr;
int retval; int retval = ERROR_OK;
/* TI BE-32 Quirks mode: /* TI BE-32 Quirks mode:
* Reads on big-endian TMS570 behave strangely differently than writes. * Reads on big-endian TMS570 behave strangely differently than writes.
@ -429,19 +479,14 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint
/* Allocate buffer to hold the sequence of DRW reads that will be made. This is a significant /* Allocate buffer to hold the sequence of DRW reads that will be made. This is a significant
* over-allocation if packed transfers are going to be used, but determining the real need at * over-allocation if packed transfers are going to be used, but determining the real need at
* this point would be messy. */ * this point would be messy. */
uint32_t *read_buf = malloc(count * sizeof(uint32_t)); uint32_t *read_buf = calloc(count, sizeof(uint32_t));
/* Multiplication count * sizeof(uint32_t) may overflow, calloc() is safe */
uint32_t *read_ptr = read_buf; uint32_t *read_ptr = read_buf;
if (read_buf == NULL) { if (read_buf == NULL) {
LOG_ERROR("Failed to allocate read buffer"); LOG_ERROR("Failed to allocate read buffer");
return ERROR_FAIL; return ERROR_FAIL;
} }
retval = mem_ap_setup_tar(ap, address);
if (retval != ERROR_OK) {
free(read_buf);
return retval;
}
/* Queue up all reads. Each read will store the entire DRW word in the read buffer. How many /* Queue up all reads. Each read will store the entire DRW word in the read buffer. How many
* useful bytes it contains, and their location in the word, depends on the type of transfer * useful bytes it contains, and their location in the word, depends on the type of transfer
* and alignment. */ * and alignment. */
@ -459,19 +504,19 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint
if (retval != ERROR_OK) if (retval != ERROR_OK)
break; break;
retval = mem_ap_setup_tar(ap, address);
if (retval != ERROR_OK)
break;
retval = dap_queue_ap_read(ap, MEM_AP_REG_DRW, read_ptr++); retval = dap_queue_ap_read(ap, MEM_AP_REG_DRW, read_ptr++);
if (retval != ERROR_OK) if (retval != ERROR_OK)
break; break;
nbytes -= this_size; nbytes -= this_size;
if (addrinc)
address += this_size; address += this_size;
/* Rewrite TAR if it wrapped */ mem_ap_update_tar_cache(ap);
if (addrinc && address % ap->tar_autoincr_block < size && nbytes > 0) {
retval = mem_ap_setup_tar(ap, address);
if (retval != ERROR_OK)
break;
}
} }
if (retval == ERROR_OK) if (retval == ERROR_OK)
@ -486,8 +531,8 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint
* at least give the caller what we have. */ * at least give the caller what we have. */
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
uint32_t tar; uint32_t tar;
if (dap_queue_ap_read(ap, MEM_AP_REG_TAR, &tar) == ERROR_OK if (mem_ap_read_tar(ap, &tar) == ERROR_OK) {
&& dap_run(dap) == ERROR_OK) { /* TAR is incremented after failed transfer on some devices (eg Cortex-M4) */
LOG_ERROR("Failed to read memory at 0x%08"PRIx32, tar); LOG_ERROR("Failed to read memory at 0x%08"PRIx32, tar);
if (nbytes > tar - address) if (nbytes > tar - address)
nbytes = tar - address; nbytes = tar - address;
@ -596,6 +641,22 @@ struct adiv5_dap *dap_init(void)
return dap; return dap;
} }
/**
* Invalidate cached DP select and cached TAR and CSW of all APs
*/
void dap_invalidate_cache(struct adiv5_dap *dap)
{
dap->select = DP_SELECT_INVALID;
dap->last_read = NULL;
int i;
for (i = 0; i <= 255; i++) {
/* force csw and tar write on the next mem-ap access */
dap->ap[i].tar_valid = false;
dap->ap[i].csw_value = 0;
}
}
/** /**
* Initialize a DAP. This sets up the power domains, prepares the DP * Initialize a DAP. This sets up the power domains, prepares the DP
* for further use and activates overrun checking. * for further use and activates overrun checking.
@ -615,8 +676,7 @@ int dap_dp_init(struct adiv5_dap *dap)
if (!dap->ops) if (!dap->ops)
dap->ops = &jtag_dp_ops; dap->ops = &jtag_dp_ops;
dap->select = DP_SELECT_INVALID; dap_invalidate_cache(dap);
dap->last_read = NULL;
for (size_t i = 0; i < 30; i++) { for (size_t i = 0; i < 30; i++) {
/* DP initialization */ /* DP initialization */
@ -688,6 +748,8 @@ int mem_ap_init(struct adiv5_ap *ap)
int retval; int retval;
struct adiv5_dap *dap = ap->dap; struct adiv5_dap *dap = ap->dap;
ap->tar_valid = false;
ap->csw_value = 0; /* force csw and tar write */
retval = mem_ap_setup_transfer(ap, CSW_8BIT | CSW_ADDRINC_PACKED, 0); retval = mem_ap_setup_transfer(ap, CSW_8BIT | CSW_ADDRINC_PACKED, 0);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
@ -979,12 +1041,14 @@ static const struct {
{ ARM_ID, 0x4a2, "Cortex-A57 ROM", "(ROM Table)", }, { ARM_ID, 0x4a2, "Cortex-A57 ROM", "(ROM Table)", },
{ ARM_ID, 0x4a3, "Cortex-A53 ROM", "(v7 Memory Map ROM Table)", }, { ARM_ID, 0x4a3, "Cortex-A53 ROM", "(v7 Memory Map ROM Table)", },
{ ARM_ID, 0x4a4, "Cortex-A72 ROM", "(ROM Table)", }, { ARM_ID, 0x4a4, "Cortex-A72 ROM", "(ROM Table)", },
{ ARM_ID, 0x4a9, "Cortex-A9 ROM", "(ROM Table)", },
{ ARM_ID, 0x4af, "Cortex-A15 ROM", "(ROM Table)", }, { ARM_ID, 0x4af, "Cortex-A15 ROM", "(ROM Table)", },
{ ARM_ID, 0x4c0, "Cortex-M0+ ROM", "(ROM Table)", }, { ARM_ID, 0x4c0, "Cortex-M0+ ROM", "(ROM Table)", },
{ ARM_ID, 0x4c3, "Cortex-M3 ROM", "(ROM Table)", }, { ARM_ID, 0x4c3, "Cortex-M3 ROM", "(ROM Table)", },
{ ARM_ID, 0x4c4, "Cortex-M4 ROM", "(ROM Table)", }, { ARM_ID, 0x4c4, "Cortex-M4 ROM", "(ROM Table)", },
{ ARM_ID, 0x4c7, "Cortex-M7 PPB ROM", "(Private Peripheral Bus ROM Table)", }, { ARM_ID, 0x4c7, "Cortex-M7 PPB ROM", "(Private Peripheral Bus ROM Table)", },
{ ARM_ID, 0x4c8, "Cortex-M7 ROM", "(ROM Table)", }, { ARM_ID, 0x4c8, "Cortex-M7 ROM", "(ROM Table)", },
{ ARM_ID, 0x4b5, "Cortex-R5 ROM", "(ROM Table)", },
{ ARM_ID, 0x470, "Cortex-M1 ROM", "(ROM Table)", }, { ARM_ID, 0x470, "Cortex-M1 ROM", "(ROM Table)", },
{ ARM_ID, 0x471, "Cortex-M0 ROM", "(ROM Table)", }, { ARM_ID, 0x471, "Cortex-M0 ROM", "(ROM Table)", },
{ ARM_ID, 0x906, "CoreSight CTI", "(Cross Trigger)", }, { ARM_ID, 0x906, "CoreSight CTI", "(Cross Trigger)", },
@ -1025,7 +1089,7 @@ static const struct {
{ ARM_ID, 0x9a9, "Cortex-M7 TPIU", "(Trace Port Interface Unit)", }, { ARM_ID, 0x9a9, "Cortex-M7 TPIU", "(Trace Port Interface Unit)", },
{ ARM_ID, 0x9ae, "Cortex-A17 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9ae, "Cortex-A17 PMU", "(Performance Monitor Unit)", },
{ ARM_ID, 0x9af, "Cortex-A15 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9af, "Cortex-A15 PMU", "(Performance Monitor Unit)", },
{ ARM_ID, 0x9b7, "Cortex-R7 PMU", "(Performance Monitoring Unit)", }, { ARM_ID, 0x9b7, "Cortex-R7 PMU", "(Performance Monitor Unit)", },
{ ARM_ID, 0x9d3, "Cortex-A53 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d3, "Cortex-A53 PMU", "(Performance Monitor Unit)", },
{ ARM_ID, 0x9d7, "Cortex-A57 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d7, "Cortex-A57 PMU", "(Performance Monitor Unit)", },
{ ARM_ID, 0x9d8, "Cortex-A72 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d8, "Cortex-A72 PMU", "(Performance Monitor Unit)", },
@ -1048,6 +1112,11 @@ static const struct {
{ 0x0c1, 0x1ed, "XMC1000 ROM", "(ROM Table)" }, { 0x0c1, 0x1ed, "XMC1000 ROM", "(ROM Table)" },
{ 0x0E5, 0x000, "SHARC+/Blackfin+", "", }, { 0x0E5, 0x000, "SHARC+/Blackfin+", "", },
{ 0x0F0, 0x440, "Qualcomm QDSS Component v1", "(Qualcomm Designed CoreSight Component v1)", }, { 0x0F0, 0x440, "Qualcomm QDSS Component v1", "(Qualcomm Designed CoreSight Component v1)", },
{ 0x3eb, 0x181, "Tegra 186 ROM", "(ROM Table)", },
{ 0x3eb, 0x211, "Tegra 210 ROM", "(ROM Table)", },
{ 0x3eb, 0x202, "Denver ETM", "(Denver Embedded Trace)", },
{ 0x3eb, 0x302, "Denver Debug", "(Debug Unit)", },
{ 0x3eb, 0x402, "Denver PMU", "(Performance Monitor Unit)", },
/* legacy comment: 0x113: what? */ /* legacy comment: 0x113: what? */
{ ANY_ID, 0x120, "TI SDTI", "(System Debug Trace Interface)", }, /* from OMAP3 memmap */ { ANY_ID, 0x120, "TI SDTI", "(System Debug Trace Interface)", }, /* from OMAP3 memmap */
{ ANY_ID, 0x343, "TI DAPCTL", "", }, /* from OMAP3 memmap */ { ANY_ID, 0x343, "TI DAPCTL", "", }, /* from OMAP3 memmap */

View File

@ -102,6 +102,7 @@
#define AP_REG_IDR 0xFC /* RO: Identification Register */ #define AP_REG_IDR 0xFC /* RO: Identification Register */
/* Fields of the MEM-AP's CSW register */ /* Fields of the MEM-AP's CSW register */
#define CSW_SIZE_MASK 7
#define CSW_8BIT 0 #define CSW_8BIT 0
#define CSW_16BIT 1 #define CSW_16BIT 1
#define CSW_32BIT 2 #define CSW_32BIT 2
@ -180,6 +181,9 @@ struct adiv5_ap {
/* true if unaligned memory access is not supported by the MEM-AP */ /* true if unaligned memory access is not supported by the MEM-AP */
bool unaligned_access_bad; bool unaligned_access_bad;
/* true if tar_value is in sync with TAR register */
bool tar_valid;
}; };
@ -476,6 +480,9 @@ struct adiv5_dap *dap_init(void);
int dap_dp_init(struct adiv5_dap *dap); int dap_dp_init(struct adiv5_dap *dap);
int mem_ap_init(struct adiv5_ap *ap); int mem_ap_init(struct adiv5_ap *ap);
/* Invalidate cached DP select and cached TAR and CSW of all APs */
void dap_invalidate_cache(struct adiv5_dap *dap);
/* Probe the AP for ROM Table location */ /* Probe the AP for ROM Table location */
int dap_get_debugbase(struct adiv5_ap *ap, int dap_get_debugbase(struct adiv5_ap *ap,
uint32_t *dbgbase, uint32_t *apid); uint32_t *dbgbase, uint32_t *apid);

View File

@ -129,6 +129,59 @@ static int evaluate_pld(uint32_t opcode,
return ERROR_OK; return ERROR_OK;
} }
/* DSB */
if ((opcode & 0x07f000f0) == 0x05700040) {
instruction->type = ARM_DSB;
char *opt;
switch (opcode & 0x0000000f) {
case 0xf:
opt = "SY";
break;
case 0xe:
opt = "ST";
break;
case 0xb:
opt = "ISH";
break;
case 0xa:
opt = "ISHST";
break;
case 0x7:
opt = "NSH";
break;
case 0x6:
opt = "NSHST";
break;
case 0x3:
opt = "OSH";
break;
case 0x2:
opt = "OSHST";
break;
default:
opt = "UNK";
}
snprintf(instruction->text,
128,
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDSB %s",
address, opcode, opt);
return ERROR_OK;
}
/* ISB */
if ((opcode & 0x07f000f0) == 0x05700060) {
instruction->type = ARM_ISB;
snprintf(instruction->text,
128,
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tISB %s",
address, opcode,
((opcode & 0x0000000f) == 0xf) ? "SY" : "UNK");
return ERROR_OK;
}
return evaluate_unknown(opcode, address, instruction); return evaluate_unknown(opcode, address, instruction);
} }
@ -1562,6 +1615,33 @@ static int evaluate_misc_instr(uint32_t opcode,
return ERROR_OK; return ERROR_OK;
} }
static int evaluate_mov_imm(uint32_t opcode,
uint32_t address, struct arm_instruction *instruction)
{
uint16_t immediate;
uint8_t Rd;
bool T;
Rd = (opcode & 0xf000) >> 12;
T = opcode & 0x00400000;
immediate = (opcode & 0xf0000) >> 4 | (opcode & 0xfff);
instruction->type = ARM_MOV;
instruction->info.data_proc.Rd = Rd;
snprintf(instruction->text,
128,
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMOV%s%s r%i, #0x%" PRIx16,
address,
opcode,
T ? "T" : "W",
COND(opcode),
Rd,
immediate);
return ERROR_OK;
}
static int evaluate_data_proc(uint32_t opcode, static int evaluate_data_proc(uint32_t opcode,
uint32_t address, struct arm_instruction *instruction) uint32_t address, struct arm_instruction *instruction)
{ {
@ -1838,16 +1918,9 @@ int arm_evaluate_opcode(uint32_t opcode, uint32_t address,
/* catch opcodes with [27:25] = b001 */ /* catch opcodes with [27:25] = b001 */
if ((opcode & 0x0e000000) == 0x02000000) { if ((opcode & 0x0e000000) == 0x02000000) {
/* Undefined instruction */ /* 16-bit immediate load */
if ((opcode & 0x0fb00000) == 0x03000000) { if ((opcode & 0x0fb00000) == 0x03000000)
instruction->type = ARM_UNDEFINED_INSTRUCTION; return evaluate_mov_imm(opcode, address, instruction);
snprintf(instruction->text,
128,
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
address,
opcode);
return ERROR_OK;
}
/* Move immediate to status register */ /* Move immediate to status register */
if ((opcode & 0x0fb00000) == 0x03200000) if ((opcode & 0x0fb00000) == 0x03200000)
@ -2896,12 +2969,26 @@ static int t2ev_b_bl(uint32_t opcode, uint32_t address,
address += 4; address += 4;
address += offset << 1; address += offset << 1;
instruction->type = (opcode & (1 << 14)) ? ARM_BL : ARM_B; char *inst;
switch ((opcode >> 12) & 0x5) {
case 0x1:
inst = "B.W";
instruction->type = ARM_B;
break;
case 0x4:
inst = "BLX";
instruction->type = ARM_BLX;
break;
case 0x5:
inst = "BL";
instruction->type = ARM_BL;
break;
default:
return ERROR_COMMAND_SYNTAX_ERROR;
}
instruction->info.b_bl_bx_blx.reg_operand = -1; instruction->info.b_bl_bx_blx.reg_operand = -1;
instruction->info.b_bl_bx_blx.target_address = address; instruction->info.b_bl_bx_blx.target_address = address;
sprintf(cp, "%s\t%#8.8" PRIx32, sprintf(cp, "%s\t%#8.8" PRIx32, inst, address);
(opcode & (1 << 14)) ? "BL" : "B.W",
address);
return ERROR_OK; return ERROR_OK;
} }
@ -3078,10 +3165,9 @@ static int t2ev_b_misc(uint32_t opcode, uint32_t address,
switch ((opcode >> 12) & 0x5) { switch ((opcode >> 12) & 0x5) {
case 0x1: case 0x1:
case 0x4:
case 0x5: case 0x5:
return t2ev_b_bl(opcode, address, instruction, cp); return t2ev_b_bl(opcode, address, instruction, cp);
case 0x4:
goto undef;
case 0: case 0:
if (((opcode >> 23) & 0x07) != 0x07) if (((opcode >> 23) & 0x07) != 0x07)
return t2ev_cond_b(opcode, address, instruction, cp); return t2ev_cond_b(opcode, address, instruction, cp);

View File

@ -106,6 +106,8 @@ enum arm_instruction_type {
ARM_MCRR, ARM_MCRR,
ARM_MRRC, ARM_MRRC,
ARM_PLD, ARM_PLD,
ARM_DSB,
ARM_ISB,
ARM_QADD, ARM_QADD,
ARM_QDADD, ARM_QDADD,
ARM_QSUB, ARM_QSUB,

View File

@ -45,8 +45,6 @@ static const struct {
const char *name; const char *name;
unsigned psr; unsigned psr;
} armv8_mode_data[] = { } armv8_mode_data[] = {
/* These special modes are currently only supported
* by ARMv6M and ARMv7M profiles */
{ {
.name = "USR", .name = "USR",
.psr = ARM_MODE_USR, .psr = ARM_MODE_USR,
@ -112,48 +110,6 @@ const char *armv8_mode_name(unsigned psr_mode)
return "UNRECOGNIZED"; return "UNRECOGNIZED";
} }
int armv8_mode_to_number(enum arm_mode mode)
{
switch (mode) {
case ARM_MODE_ANY:
/* map MODE_ANY to user mode */
case ARM_MODE_USR:
return 0;
case ARM_MODE_FIQ:
return 1;
case ARM_MODE_IRQ:
return 2;
case ARM_MODE_SVC:
return 3;
case ARM_MODE_ABT:
return 4;
case ARM_MODE_UND:
return 5;
case ARM_MODE_SYS:
return 6;
case ARM_MODE_MON:
return 7;
case ARMV8_64_EL0T:
return 8;
case ARMV8_64_EL1T:
return 9;
case ARMV8_64_EL1H:
return 10;
case ARMV8_64_EL2T:
return 11;
case ARMV8_64_EL2H:
return 12;
case ARMV8_64_EL3T:
return 13;
case ARMV8_64_EL3H:
return 14;
default:
LOG_ERROR("invalid mode value encountered %d", mode);
return -1;
}
}
static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval) static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval)
{ {
struct arm_dpm *dpm = &armv8->dpm; struct arm_dpm *dpm = &armv8->dpm;
@ -533,9 +489,8 @@ void armv8_set_cpsr(struct arm *arm, uint32_t cpsr)
/* Older ARMs won't have the J bit */ /* Older ARMs won't have the J bit */
enum arm_state state = 0xFF; enum arm_state state = 0xFF;
if (((cpsr & 0x10) >> 4) == 0) { if ((cpsr & 0x10) != 0) {
state = ARM_STATE_AARCH64; /* Aarch32 state */
} else {
if (cpsr & (1 << 5)) { /* T */ if (cpsr & (1 << 5)) { /* T */
if (cpsr & (1 << 24)) { /* J */ if (cpsr & (1 << 24)) { /* J */
LOG_WARNING("ThumbEE -- incomplete support"); LOG_WARNING("ThumbEE -- incomplete support");
@ -549,11 +504,12 @@ void armv8_set_cpsr(struct arm *arm, uint32_t cpsr)
} else } else
state = ARM_STATE_ARM; state = ARM_STATE_ARM;
} }
} else {
/* Aarch64 state */
state = ARM_STATE_AARCH64;
} }
arm->core_state = state; arm->core_state = state;
if (arm->core_state == ARM_STATE_AARCH64)
arm->core_mode = (mode << 4) | 0xf;
else
arm->core_mode = mode; arm->core_mode = mode;
LOG_DEBUG("set CPSR %#8.8x: %s mode, %s state", (unsigned) cpsr, LOG_DEBUG("set CPSR %#8.8x: %s mode, %s state", (unsigned) cpsr,

View File

@ -270,7 +270,7 @@ static inline unsigned int armv8_curel_from_core_mode(enum arm_mode core_mode)
return 3; return 3;
/* all Aarch64 modes */ /* all Aarch64 modes */
default: default:
return (core_mode >> 6) & 3; return (core_mode >> 2) & 3;
} }
} }

View File

@ -561,12 +561,7 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
} else { } else {
LOG_DEBUG("setting mode 0x%"PRIx32, mode); LOG_DEBUG("setting mode 0x%"PRIx32, mode);
/* else force to the specified mode */
if (is_arm_mode(mode))
cpsr = mode; cpsr = mode;
else
cpsr = mode >> 4;
} }
switch (cpsr & 0x1f) { switch (cpsr & 0x1f) {

View File

@ -42,6 +42,12 @@ static const uint32_t a64_opcodes[ARMV8_OPC_NUM] = {
[ARMV8_OPC_DCCIVAC] = ARMV8_SYS(SYSTEM_DCCIVAC, 0), [ARMV8_OPC_DCCIVAC] = ARMV8_SYS(SYSTEM_DCCIVAC, 0),
[ARMV8_OPC_ICIVAU] = ARMV8_SYS(SYSTEM_ICIVAU, 0), [ARMV8_OPC_ICIVAU] = ARMV8_SYS(SYSTEM_ICIVAU, 0),
[ARMV8_OPC_HLT] = ARMV8_HLT(11), [ARMV8_OPC_HLT] = ARMV8_HLT(11),
[ARMV8_OPC_LDRB_IP] = ARMV8_LDRB_IP(1, 0),
[ARMV8_OPC_LDRH_IP] = ARMV8_LDRH_IP(1, 0),
[ARMV8_OPC_LDRW_IP] = ARMV8_LDRW_IP(1, 0),
[ARMV8_OPC_STRB_IP] = ARMV8_STRB_IP(1, 0),
[ARMV8_OPC_STRH_IP] = ARMV8_STRH_IP(1, 0),
[ARMV8_OPC_STRW_IP] = ARMV8_STRW_IP(1, 0),
}; };
static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = { static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = {
@ -63,6 +69,12 @@ static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = {
[ARMV8_OPC_DCCIVAC] = ARMV4_5_MCR(15, 0, 0, 7, 14, 1), [ARMV8_OPC_DCCIVAC] = ARMV4_5_MCR(15, 0, 0, 7, 14, 1),
[ARMV8_OPC_ICIVAU] = ARMV4_5_MCR(15, 0, 0, 7, 5, 1), [ARMV8_OPC_ICIVAU] = ARMV4_5_MCR(15, 0, 0, 7, 5, 1),
[ARMV8_OPC_HLT] = ARMV8_HLT_A1(11), [ARMV8_OPC_HLT] = ARMV8_HLT_A1(11),
[ARMV8_OPC_LDRB_IP] = ARMV4_5_LDRB_IP(1, 0),
[ARMV8_OPC_LDRH_IP] = ARMV4_5_LDRH_IP(1, 0),
[ARMV8_OPC_LDRW_IP] = ARMV4_5_LDRW_IP(1, 0),
[ARMV8_OPC_STRB_IP] = ARMV4_5_STRB_IP(1, 0),
[ARMV8_OPC_STRH_IP] = ARMV4_5_STRH_IP(1, 0),
[ARMV8_OPC_STRW_IP] = ARMV4_5_STRW_IP(1, 0),
}; };
void armv8_select_opcodes(struct armv8_common *armv8, bool state_is_aarch64) void armv8_select_opcodes(struct armv8_common *armv8, bool state_is_aarch64)

View File

@ -159,6 +159,14 @@
#define ARMV8_MOVFSP_32(Rt) (0x11000000 | (0x1f << 5) | (Rt)) #define ARMV8_MOVFSP_32(Rt) (0x11000000 | (0x1f << 5) | (Rt))
#define ARMV8_MOVTSP_32(Rt) (0x11000000 | (Rt << 5) | (0x1F)) #define ARMV8_MOVTSP_32(Rt) (0x11000000 | (Rt << 5) | (0x1F))
#define ARMV8_LDRB_IP(Rd, Rn) (0x38401400 | (Rn << 5) | Rd)
#define ARMV8_LDRH_IP(Rd, Rn) (0x78402400 | (Rn << 5) | Rd)
#define ARMV8_LDRW_IP(Rd, Rn) (0xb8404400 | (Rn << 5) | Rd)
#define ARMV8_STRB_IP(Rd, Rn) (0x38001400 | (Rn << 5) | Rd)
#define ARMV8_STRH_IP(Rd, Rn) (0x78002400 | (Rn << 5) | Rd)
#define ARMV8_STRW_IP(Rd, Rn) (0xb8004400 | (Rn << 5) | Rd)
#define ARMV8_SYS(System, Rt) (0xD5080000 | ((System) << 5) | Rt) #define ARMV8_SYS(System, Rt) (0xD5080000 | ((System) << 5) | Rt)
enum armv8_opcode { enum armv8_opcode {
@ -180,6 +188,12 @@ enum armv8_opcode {
ARMV8_OPC_DCCIVAC, ARMV8_OPC_DCCIVAC,
ARMV8_OPC_ICIVAU, ARMV8_OPC_ICIVAU,
ARMV8_OPC_HLT, ARMV8_OPC_HLT,
ARMV8_OPC_STRB_IP,
ARMV8_OPC_STRH_IP,
ARMV8_OPC_STRW_IP,
ARMV8_OPC_LDRB_IP,
ARMV8_OPC_LDRH_IP,
ARMV8_OPC_LDRW_IP,
ARMV8_OPC_NUM, ARMV8_OPC_NUM,
}; };

View File

@ -1707,6 +1707,97 @@ void cortex_m_deinit_target(struct target *target)
free(cortex_m); free(cortex_m);
} }
int cortex_m_profiling(struct target *target, uint32_t *samples,
uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds)
{
struct timeval timeout, now;
struct armv7m_common *armv7m = target_to_armv7m(target);
uint32_t reg_value;
bool use_pcsr = false;
int retval = ERROR_OK;
struct reg *reg;
gettimeofday(&timeout, NULL);
timeval_add_time(&timeout, seconds, 0);
retval = target_read_u32(target, DWT_PCSR, &reg_value);
if (retval != ERROR_OK) {
LOG_ERROR("Error while reading PCSR");
return retval;
}
if (reg_value != 0) {
use_pcsr = true;
LOG_INFO("Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can...");
} else {
LOG_INFO("Starting profiling. Halting and resuming the"
" target as often as we can...");
reg = register_get_by_name(target->reg_cache, "pc", 1);
}
/* Make sure the target is running */
target_poll(target);
if (target->state == TARGET_HALTED)
retval = target_resume(target, 1, 0, 0, 0);
if (retval != ERROR_OK) {
LOG_ERROR("Error while resuming target");
return retval;
}
uint32_t sample_count = 0;
for (;;) {
if (use_pcsr) {
if (armv7m && armv7m->debug_ap) {
uint32_t read_count = max_num_samples - sample_count;
if (read_count > 1024)
read_count = 1024;
retval = mem_ap_read_buf_noincr(armv7m->debug_ap,
(void *)&samples[sample_count],
4, read_count, DWT_PCSR);
sample_count += read_count;
} else {
target_read_u32(target, DWT_PCSR, &samples[sample_count++]);
}
} else {
target_poll(target);
if (target->state == TARGET_HALTED) {
reg_value = buf_get_u32(reg->value, 0, 32);
/* current pc, addr = 0, do not handle breakpoints, not debugging */
retval = target_resume(target, 1, 0, 0, 0);
samples[sample_count++] = reg_value;
target_poll(target);
alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */
} else if (target->state == TARGET_RUNNING) {
/* We want to quickly sample the PC. */
retval = target_halt(target);
} else {
LOG_INFO("Target not halted or running");
retval = ERROR_OK;
break;
}
}
if (retval != ERROR_OK) {
LOG_ERROR("Error while reading %s", use_pcsr ? "PCSR" : "target pc");
return retval;
}
gettimeofday(&now, NULL);
if (sample_count >= max_num_samples || timeval_compare(&now, &timeout) > 0) {
LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
break;
}
}
*num_samples = sample_count;
return retval;
}
/* REVISIT cache valid/dirty bits are unmaintained. We could set "valid" /* REVISIT cache valid/dirty bits are unmaintained. We could set "valid"
* on r/w if the core is not running, and clear on resume or reset ... or * on r/w if the core is not running, and clear on resume or reset ... or
* at least, in a post_restore_context() method. * at least, in a post_restore_context() method.
@ -2451,4 +2542,6 @@ struct target_type cortexm_target = {
.init_target = cortex_m_init_target, .init_target = cortex_m_init_target,
.examine = cortex_m_examine, .examine = cortex_m_examine,
.deinit_target = cortex_m_deinit_target, .deinit_target = cortex_m_deinit_target,
.profiling = cortex_m_profiling,
}; };

View File

@ -48,6 +48,7 @@
#define DWT_CTRL 0xE0001000 #define DWT_CTRL 0xE0001000
#define DWT_CYCCNT 0xE0001004 #define DWT_CYCCNT 0xE0001004
#define DWT_PCSR 0xE000101C
#define DWT_COMP0 0xE0001020 #define DWT_COMP0 0xE0001020
#define DWT_MASK0 0xE0001024 #define DWT_MASK0 0xE0001024
#define DWT_FUNCTION0 0xE0001028 #define DWT_FUNCTION0 0xE0001028
@ -212,5 +213,7 @@ void cortex_m_enable_breakpoints(struct target *target);
void cortex_m_enable_watchpoints(struct target *target); void cortex_m_enable_watchpoints(struct target *target);
void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target); void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target);
void cortex_m_deinit_target(struct target *target); void cortex_m_deinit_target(struct target *target);
int cortex_m_profiling(struct target *target, uint32_t *samples,
uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds);
#endif /* OPENOCD_TARGET_CORTEX_M_H */ #endif /* OPENOCD_TARGET_CORTEX_M_H */

View File

@ -28,6 +28,7 @@
#include "embeddedice.h" #include "embeddedice.h"
#include "register.h" #include "register.h"
#include <helper/time_support.h>
/** /**
* @file * @file
@ -576,8 +577,8 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou
uint8_t field2_out[1]; uint8_t field2_out[1];
int retval; int retval;
uint32_t hsact; uint32_t hsact;
struct timeval lap;
struct timeval now; struct timeval now;
struct timeval timeout_end;
if (hsbit == EICE_COMM_CTRL_WBIT) if (hsbit == EICE_COMM_CTRL_WBIT)
hsact = 1; hsact = 1;
@ -610,7 +611,8 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou
fields[2].in_value = NULL; fields[2].in_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
gettimeofday(&lap, NULL); gettimeofday(&timeout_end, NULL);
timeval_add_time(&timeout_end, 0, timeout * 1000);
do { do {
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
retval = jtag_execute_queue(); retval = jtag_execute_queue();
@ -621,8 +623,7 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou
return ERROR_OK; return ERROR_OK;
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
} while ((uint32_t)((now.tv_sec - lap.tv_sec) * 1000 } while (timeval_compare(&now, &timeout_end) <= 0);
+ (now.tv_usec - lap.tv_usec) / 1000) <= timeout);
LOG_ERROR("embeddedice handshake timeout"); LOG_ERROR("embeddedice handshake timeout");
return ERROR_TARGET_TIMEOUT; return ERROR_TARGET_TIMEOUT;

View File

@ -814,4 +814,5 @@ struct target_type hla_target = {
.remove_breakpoint = cortex_m_remove_breakpoint, .remove_breakpoint = cortex_m_remove_breakpoint,
.add_watchpoint = cortex_m_add_watchpoint, .add_watchpoint = cortex_m_add_watchpoint,
.remove_watchpoint = cortex_m_remove_watchpoint, .remove_watchpoint = cortex_m_remove_watchpoint,
.profiling = cortex_m_profiling,
}; };

View File

@ -444,6 +444,8 @@ static uint32_t get_tapstatus(struct target *t)
static int enter_probemode(struct target *t) static int enter_probemode(struct target *t)
{ {
uint32_t tapstatus = 0; uint32_t tapstatus = 0;
int retries = 100;
tapstatus = get_tapstatus(t); tapstatus = get_tapstatus(t);
LOG_DEBUG("TS before PM enter = 0x%08" PRIx32, tapstatus); LOG_DEBUG("TS before PM enter = 0x%08" PRIx32, tapstatus);
if (tapstatus & TS_PM_BIT) { if (tapstatus & TS_PM_BIT) {
@ -456,15 +458,17 @@ static int enter_probemode(struct target *t)
scan.out[0] = 1; scan.out[0] = 1;
if (drscan(t, scan.out, scan.in, 1) != ERROR_OK) if (drscan(t, scan.out, scan.in, 1) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
while (retries--) {
tapstatus = get_tapstatus(t); tapstatus = get_tapstatus(t);
LOG_DEBUG("TS after PM enter = 0x%08" PRIx32, tapstatus); LOG_DEBUG("TS after PM enter = 0x%08" PRIx32, tapstatus);
if ((tapstatus & TS_PM_BIT) && (!(tapstatus & TS_EN_PM_BIT))) if ((tapstatus & TS_PM_BIT) && (!(tapstatus & TS_EN_PM_BIT)))
return ERROR_OK; return ERROR_OK;
else { }
LOG_ERROR("%s PM enter error, tapstatus = 0x%08" PRIx32 LOG_ERROR("%s PM enter error, tapstatus = 0x%08" PRIx32
, __func__, tapstatus); , __func__, tapstatus);
return ERROR_FAIL; return ERROR_FAIL;
}
} }
static int exit_probemode(struct target *t) static int exit_probemode(struct target *t)
@ -966,6 +970,7 @@ int lakemont_poll(struct target *t)
return target_call_event_callbacks(t, TARGET_EVENT_HALTED); return target_call_event_callbacks(t, TARGET_EVENT_HALTED);
} }
} }
return ERROR_OK; return ERROR_OK;
} }
@ -1111,15 +1116,137 @@ int lakemont_step(struct target *t, int current,
return retval; return retval;
} }
/* TODO - implement resetbreak fully through CLTAP registers */ static int lakemont_reset_break(struct target *t)
{
struct x86_32_common *x86_32 = target_to_x86_32(t);
struct jtag_tap *saved_tap = x86_32->curr_tap;
struct scan_field *fields = &scan.field;
int retval = ERROR_OK;
LOG_DEBUG("issuing port 0xcf9 reset");
/* prepare resetbreak setting the proper bits in CLTAPC_CPU_VPREQ */
x86_32->curr_tap = jtag_tap_by_position(1);
if (x86_32->curr_tap == NULL) {
x86_32->curr_tap = saved_tap;
LOG_ERROR("%s could not select quark_x10xx.cltap", __func__);
return ERROR_FAIL;
}
fields->in_value = NULL;
fields->num_bits = 8;
/* select CLTAPC_CPU_VPREQ instruction*/
scan.out[0] = 0x51;
fields->out_value = ((uint8_t *)scan.out);
jtag_add_ir_scan(x86_32->curr_tap, fields, TAP_IDLE);
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
x86_32->curr_tap = saved_tap;
LOG_ERROR("%s irscan failed to execute queue", __func__);
return retval;
}
/* set enable_preq_on_reset & enable_preq_on_reset2 bits*/
scan.out[0] = 0x06;
fields->out_value = ((uint8_t *)scan.out);
jtag_add_dr_scan(x86_32->curr_tap, 1, fields, TAP_IDLE);
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("%s drscan failed to execute queue", __func__);
x86_32->curr_tap = saved_tap;
return retval;
}
/* restore current tap */
x86_32->curr_tap = saved_tap;
return ERROR_OK;
}
/*
* If we ever get an adapter with support for PREQ# and PRDY#, we should
* update this function to add support for using those two signals.
*
* Meanwhile, we're assuming that we only support reset break.
*/
int lakemont_reset_assert(struct target *t) int lakemont_reset_assert(struct target *t)
{ {
LOG_DEBUG("-"); struct x86_32_common *x86_32 = target_to_x86_32(t);
/* write 0x6 to I/O port 0xcf9 to cause the reset */
uint8_t cf9_reset_val = 0x6;
int retval;
LOG_DEBUG(" ");
if (t->state != TARGET_HALTED) {
LOG_DEBUG("target must be halted first");
retval = lakemont_halt(t);
if (retval != ERROR_OK) {
LOG_ERROR("could not halt target");
return retval;
}
x86_32->forced_halt_for_reset = true;
}
if (t->reset_halt) {
retval = lakemont_reset_break(t);
if (retval != ERROR_OK)
return retval;
}
retval = x86_32_common_write_io(t, 0xcf9, BYTE, &cf9_reset_val);
if (retval != ERROR_OK) {
LOG_ERROR("could not write to port 0xcf9");
return retval;
}
if (!t->reset_halt && x86_32->forced_halt_for_reset) {
x86_32->forced_halt_for_reset = false;
retval = lakemont_resume(t, true, 0x00, false, true);
if (retval != ERROR_OK)
return retval;
}
/* remove breakpoints and watchpoints */
x86_32_common_reset_breakpoints_watchpoints(t);
return ERROR_OK; return ERROR_OK;
} }
int lakemont_reset_deassert(struct target *t) int lakemont_reset_deassert(struct target *t)
{ {
LOG_DEBUG("-"); int retval;
LOG_DEBUG(" ");
if (target_was_examined(t)) {
retval = lakemont_poll(t);
if (retval != ERROR_OK)
return retval;
}
if (t->reset_halt) {
/* entered PM after reset, update the state */
retval = lakemont_update_after_probemode_entry(t);
if (retval != ERROR_OK) {
LOG_ERROR("could not update state after probemode entry");
return retval;
}
if (t->state != TARGET_HALTED) {
LOG_WARNING("%s: ran after reset and before halt ...",
target_name(t));
if (target_was_examined(t)) {
retval = target_halt(t);
if (retval != ERROR_OK)
return retval;
} else {
t->state = TARGET_UNKNOWN;
}
}
}
return ERROR_OK; return ERROR_OK;
} }

View File

@ -36,6 +36,11 @@
#define EJTAG_INST_TCBCONTROLA 0x10 #define EJTAG_INST_TCBCONTROLA 0x10
#define EJTAG_INST_TCBCONTROLB 0x11 #define EJTAG_INST_TCBCONTROLB 0x11
#define EJTAG_INST_TCBDATA 0x12 #define EJTAG_INST_TCBDATA 0x12
#define EJTAG_INST_TCBCONTROLC 0x13
#define EJTAG_INST_PCSAMPLE 0x14
#define EJTAG_INST_TCBCONTROLD 0x15
#define EJTAG_INST_TCBCONTROLE 0x16
#define EJTAG_INST_FDC 0x17
#define EJTAG_INST_BYPASS 0xFF #define EJTAG_INST_BYPASS 0xFF
/* microchip PIC32MX specific instructions */ /* microchip PIC32MX specific instructions */

View File

@ -1248,8 +1248,7 @@ static int or1k_profiling(struct target *target, uint32_t *samples,
samples[sample_count++] = reg_value; samples[sample_count++] = reg_value;
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
if ((sample_count >= max_num_samples) || if ((sample_count >= max_num_samples) || timeval_compare(&now, &timeout) > 0) {
((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) {
LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count); LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
break; break;
} }

View File

@ -51,48 +51,47 @@
#include "lakemont.h" #include "lakemont.h"
#include "x86_32_common.h" #include "x86_32_common.h"
int quark_x10xx_target_create(struct target *t, Jim_Interp *interp) static int quark_x10xx_target_create(struct target *t, Jim_Interp *interp)
{ {
struct x86_32_common *x86_32 = calloc(1, sizeof(struct x86_32_common)); struct x86_32_common *x86_32 = calloc(1, sizeof(*x86_32));
if (x86_32 == NULL) {
LOG_ERROR("%s out of memory", __func__); if (!x86_32)
return ERROR_FAIL; return ERROR_FAIL;
}
x86_32_common_init_arch_info(t, x86_32); x86_32_common_init_arch_info(t, x86_32);
lakemont_init_arch_info(t, x86_32); lakemont_init_arch_info(t, x86_32);
x86_32->core_type = LMT1; x86_32->core_type = LMT1;
return ERROR_OK;
}
int quark_x10xx_init_target(struct command_context *cmd_ctx, struct target *t) return ERROR_OK;
{
return lakemont_init_target(cmd_ctx, t);
} }
struct target_type quark_x10xx_target = { struct target_type quark_x10xx_target = {
.name = "quark_x10xx", .name = "quark_x10xx",
/* Quark X1000 SoC */ /* Quark X1000 SoC */
.target_create = quark_x10xx_target_create, .target_create = quark_x10xx_target_create,
.init_target = quark_x10xx_init_target,
/* lakemont probemode specific code */ /* lakemont probemode specific code */
.poll = lakemont_poll,
.arch_state = lakemont_arch_state, .arch_state = lakemont_arch_state,
.halt = lakemont_halt,
.resume = lakemont_resume,
.step = lakemont_step,
.assert_reset = lakemont_reset_assert, .assert_reset = lakemont_reset_assert,
.deassert_reset = lakemont_reset_deassert, .deassert_reset = lakemont_reset_deassert,
.halt = lakemont_halt,
.init_target = lakemont_init_target,
.poll = lakemont_poll,
.resume = lakemont_resume,
.step = lakemont_step,
/* common x86 code */ /* common x86 code */
.add_breakpoint = x86_32_common_add_breakpoint,
.add_watchpoint = x86_32_common_add_watchpoint,
.commands = x86_32_command_handlers, .commands = x86_32_command_handlers,
.get_gdb_reg_list = x86_32_get_gdb_reg_list, .get_gdb_reg_list = x86_32_get_gdb_reg_list,
.mmu = x86_32_common_mmu,
.read_memory = x86_32_common_read_memory, .read_memory = x86_32_common_read_memory,
.write_memory = x86_32_common_write_memory, .read_phys_memory = x86_32_common_read_phys_mem,
.add_breakpoint = x86_32_common_add_breakpoint,
.remove_breakpoint = x86_32_common_remove_breakpoint, .remove_breakpoint = x86_32_common_remove_breakpoint,
.add_watchpoint = x86_32_common_add_watchpoint,
.remove_watchpoint = x86_32_common_remove_watchpoint, .remove_watchpoint = x86_32_common_remove_watchpoint,
.virt2phys = x86_32_common_virt2phys, .virt2phys = x86_32_common_virt2phys,
.read_phys_memory = x86_32_common_read_phys_mem, .write_memory = x86_32_common_write_memory,
.write_phys_memory = x86_32_common_write_phys_mem, .write_phys_memory = x86_32_common_write_phys_mem,
.mmu = x86_32_common_mmu,
}; };

View File

@ -1399,7 +1399,6 @@ int target_register_trace_callback(int (*callback)(struct target *target,
int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv) int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv)
{ {
struct target_timer_callback **callbacks_p = &target_timer_callbacks; struct target_timer_callback **callbacks_p = &target_timer_callbacks;
struct timeval now;
if (callback == NULL) if (callback == NULL)
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
@ -1416,14 +1415,8 @@ int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int
(*callbacks_p)->time_ms = time_ms; (*callbacks_p)->time_ms = time_ms;
(*callbacks_p)->removed = false; (*callbacks_p)->removed = false;
gettimeofday(&now, NULL); gettimeofday(&(*callbacks_p)->when, NULL);
(*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; timeval_add_time(&(*callbacks_p)->when, 0, time_ms * 1000);
time_ms -= (time_ms % 1000);
(*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000);
if ((*callbacks_p)->when.tv_usec > 1000000) {
(*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000;
(*callbacks_p)->when.tv_sec += 1;
}
(*callbacks_p)->priv = priv; (*callbacks_p)->priv = priv;
(*callbacks_p)->next = NULL; (*callbacks_p)->next = NULL;
@ -1558,14 +1551,8 @@ int target_call_trace_callbacks(struct target *target, size_t len, uint8_t *data
static int target_timer_callback_periodic_restart( static int target_timer_callback_periodic_restart(
struct target_timer_callback *cb, struct timeval *now) struct target_timer_callback *cb, struct timeval *now)
{ {
int time_ms = cb->time_ms; cb->when = *now;
cb->when.tv_usec = now->tv_usec + (time_ms % 1000) * 1000; timeval_add_time(&cb->when, 0, cb->time_ms * 1000L);
time_ms -= (time_ms % 1000);
cb->when.tv_sec = now->tv_sec + time_ms / 1000;
if (cb->when.tv_usec > 1000000) {
cb->when.tv_usec = cb->when.tv_usec - 1000000;
cb->when.tv_sec += 1;
}
return ERROR_OK; return ERROR_OK;
} }
@ -1609,9 +1596,7 @@ static int target_call_timer_callbacks_check_time(int checktime)
bool call_it = (*callback)->callback && bool call_it = (*callback)->callback &&
((!checktime && (*callback)->periodic) || ((!checktime && (*callback)->periodic) ||
now.tv_sec > (*callback)->when.tv_sec || timeval_compare(&now, &(*callback)->when) >= 0);
(now.tv_sec == (*callback)->when.tv_sec &&
now.tv_usec >= (*callback)->when.tv_usec));
if (call_it) if (call_it)
target_call_timer_callback(*callback, &now); target_call_timer_callback(*callback, &now);
@ -2030,8 +2015,7 @@ static int target_profiling_default(struct target *target, uint32_t *samples,
break; break;
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
if ((sample_count >= max_num_samples) || if ((sample_count >= max_num_samples) || timeval_compare(&now, &timeout) >= 0) {
((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) {
LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count); LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
break; break;
} }
@ -3131,6 +3115,10 @@ COMMAND_HANDLER(handle_md_command)
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count);
uint8_t *buffer = calloc(count, size); uint8_t *buffer = calloc(count, size);
if (buffer == NULL) {
LOG_ERROR("Failed to allocate md read buffer");
return ERROR_FAIL;
}
struct target *target = get_current_target(CMD_CTX); struct target *target = get_current_target(CMD_CTX);
int retval = fn(target, address, size, count, buffer); int retval = fn(target, address, size, count, buffer);
@ -3853,7 +3841,7 @@ typedef unsigned char UNIT[2]; /* unit of profiling */
/* Dump a gmon.out histogram file. */ /* Dump a gmon.out histogram file. */
static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filename, bool with_range, static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filename, bool with_range,
uint32_t start_address, uint32_t end_address, struct target *target) uint32_t start_address, uint32_t end_address, struct target *target, uint32_t duration_ms)
{ {
uint32_t i; uint32_t i;
FILE *f = fopen(filename, "w"); FILE *f = fopen(filename, "w");
@ -3921,7 +3909,8 @@ static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filena
writeLong(f, min, target); /* low_pc */ writeLong(f, min, target); /* low_pc */
writeLong(f, max, target); /* high_pc */ writeLong(f, max, target); /* high_pc */
writeLong(f, numBuckets, target); /* # of buckets */ writeLong(f, numBuckets, target); /* # of buckets */
writeLong(f, 100, target); /* KLUDGE! We lie, ca. 100Hz best case. */ float sample_rate = sampleNum / (duration_ms / 1000.0);
writeLong(f, sample_rate, target);
writeString(f, "seconds"); writeString(f, "seconds");
for (i = 0; i < (15-strlen("seconds")); i++) for (i = 0; i < (15-strlen("seconds")); i++)
writeData(f, &zero, 1); writeData(f, &zero, 1);
@ -3970,6 +3959,7 @@ COMMAND_HANDLER(handle_profile_command)
return ERROR_FAIL; return ERROR_FAIL;
} }
uint64_t timestart_ms = timeval_ms();
/** /**
* Some cores let us sample the PC without the * Some cores let us sample the PC without the
* annoying halt/resume step; for example, ARMv7 PCSR. * annoying halt/resume step; for example, ARMv7 PCSR.
@ -3981,6 +3971,7 @@ COMMAND_HANDLER(handle_profile_command)
free(samples); free(samples);
return retval; return retval;
} }
uint32_t duration_ms = timeval_ms() - timestart_ms;
assert(num_of_samples <= MAX_PROFILE_SAMPLE_NUM); assert(num_of_samples <= MAX_PROFILE_SAMPLE_NUM);
@ -4013,7 +4004,7 @@ COMMAND_HANDLER(handle_profile_command)
} }
write_gmon(samples, num_of_samples, CMD_ARGV[1], write_gmon(samples, num_of_samples, CMD_ARGV[1],
with_range, start_address, end_address, target); with_range, start_address, end_address, target, duration_ms);
command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]); command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]);
free(samples); free(samples);

View File

@ -209,15 +209,16 @@ static int read_phys_mem(struct target *t, uint32_t phys_address,
LOG_ERROR("%s invalid read size", __func__); LOG_ERROR("%s invalid read size", __func__);
break; break;
} }
if (retval != ERROR_OK)
break;
} }
/* restore CR0.PG bit if needed (regardless of retval) */ /* restore CR0.PG bit if needed (regardless of retval) */
if (pg_disabled) { if (pg_disabled) {
retval = x86_32->enable_paging(t); int retval2 = x86_32->enable_paging(t);
if (retval != ERROR_OK) { if (retval2 != ERROR_OK) {
LOG_ERROR("%s could not enable paging", __func__); LOG_ERROR("%s could not enable paging", __func__);
return retval; return retval2;
} }
pg_disabled = true;
} }
/* TODO: After reading memory from target, we must replace /* TODO: After reading memory from target, we must replace
* software breakpoints with the original instructions again. * software breakpoints with the original instructions again.
@ -364,6 +365,9 @@ static int read_mem(struct target *t, uint32_t size,
break; break;
} }
if (retval != ERROR_OK)
return retval;
/* read_hw_reg() will write to 4 bytes (uint32_t) /* read_hw_reg() will write to 4 bytes (uint32_t)
* Watch out, the buffer passed into read_mem() might be 1 or 2 bytes. * Watch out, the buffer passed into read_mem() might be 1 or 2 bytes.
*/ */
@ -436,6 +440,10 @@ static int write_mem(struct target *t, uint32_t size,
LOG_ERROR("%s invalid write mem size", __func__); LOG_ERROR("%s invalid write mem size", __func__);
return ERROR_FAIL; return ERROR_FAIL;
} }
if (retval != ERROR_OK)
return retval;
retval = x86_32->transaction_status(t); retval = x86_32->transaction_status(t);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("%s error on mem write", __func__); LOG_ERROR("%s error on mem write", __func__);
@ -606,7 +614,6 @@ int x86_32_common_read_memory(struct target *t, target_addr_t addr,
&& x86_32_common_read_phys_mem(t, physaddr, size, count, buf) != ERROR_OK) { && x86_32_common_read_phys_mem(t, physaddr, size, count, buf) != ERROR_OK) {
LOG_ERROR("%s failed to read memory from physical address " TARGET_ADDR_FMT, LOG_ERROR("%s failed to read memory from physical address " TARGET_ADDR_FMT,
__func__, physaddr); __func__, physaddr);
retval = ERROR_FAIL;
} }
/* restore PG bit if it was cleared prior (regardless of retval) */ /* restore PG bit if it was cleared prior (regardless of retval) */
retval = x86_32->enable_paging(t); retval = x86_32->enable_paging(t);
@ -662,7 +669,6 @@ int x86_32_common_write_memory(struct target *t, target_addr_t addr,
&& x86_32_common_write_phys_mem(t, physaddr, size, count, buf) != ERROR_OK) { && x86_32_common_write_phys_mem(t, physaddr, size, count, buf) != ERROR_OK) {
LOG_ERROR("%s failed to write memory to physical address " TARGET_ADDR_FMT, LOG_ERROR("%s failed to write memory to physical address " TARGET_ADDR_FMT,
__func__, physaddr); __func__, physaddr);
retval = ERROR_FAIL;
} }
/* restore PG bit if it was cleared prior (regardless of retval) */ /* restore PG bit if it was cleared prior (regardless of retval) */
retval = x86_32->enable_paging(t); retval = x86_32->enable_paging(t);
@ -733,15 +739,19 @@ int x86_32_common_read_io(struct target *t, uint32_t addr,
LOG_ERROR("%s invalid read io size", __func__); LOG_ERROR("%s invalid read io size", __func__);
return ERROR_FAIL; return ERROR_FAIL;
} }
/* restore CR0.PG bit if needed */ /* restore CR0.PG bit if needed */
if (pg_disabled) { if (pg_disabled) {
retval = x86_32->enable_paging(t); int retval2 = x86_32->enable_paging(t);
if (retval != ERROR_OK) { if (retval2 != ERROR_OK) {
LOG_ERROR("%s could not enable paging", __func__); LOG_ERROR("%s could not enable paging", __func__);
return retval2;
}
}
if (retval != ERROR_OK)
return retval; return retval;
}
pg_disabled = false;
}
uint32_t regval = 0; uint32_t regval = 0;
retval = x86_32->read_hw_reg(t, EAX, &regval, 0); retval = x86_32->read_hw_reg(t, EAX, &regval, 0);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
@ -818,15 +828,19 @@ int x86_32_common_write_io(struct target *t, uint32_t addr,
LOG_ERROR("%s invalid write io size", __func__); LOG_ERROR("%s invalid write io size", __func__);
return ERROR_FAIL; return ERROR_FAIL;
} }
/* restore CR0.PG bit if needed */ /* restore CR0.PG bit if needed */
if (pg_disabled) { if (pg_disabled) {
retval = x86_32->enable_paging(t); int retval2 = x86_32->enable_paging(t);
if (retval != ERROR_OK) { if (retval2 != ERROR_OK) {
LOG_ERROR("%s could not enable paging", __func__); LOG_ERROR("%s could not enable paging", __func__);
return retval2;
}
}
if (retval != ERROR_OK)
return retval; return retval;
}
pg_disabled = false;
}
retval = x86_32->transaction_status(t); retval = x86_32->transaction_status(t);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("%s error on io write", __func__); LOG_ERROR("%s error on io write", __func__);
@ -1141,7 +1155,6 @@ static int set_breakpoint(struct target *t, struct breakpoint *bp)
} }
} else { } else {
LOG_ERROR("%s core doesn't support SW breakpoints", __func__); LOG_ERROR("%s core doesn't support SW breakpoints", __func__);
error = ERROR_FAIL;
return ERROR_FAIL; return ERROR_FAIL;
} }
} }
@ -1260,6 +1273,38 @@ static int unset_watchpoint(struct target *t, struct watchpoint *wp)
return ERROR_OK; return ERROR_OK;
} }
/* after reset breakpoints and watchpoints in memory are not valid anymore and
* debug registers are cleared.
* we can't afford to remove sw breakpoints using the default methods as the
* memory doesn't have the same layout yet and an access might crash the target,
* so we just clear the openocd breakpoints structures.
*/
void x86_32_common_reset_breakpoints_watchpoints(struct target *t)
{
struct x86_32_common *x86_32 = target_to_x86_32(t);
struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list;
struct breakpoint *next_b;
struct watchpoint *next_w;
while (t->breakpoints) {
next_b = t->breakpoints->next;
free(t->breakpoints->orig_instr);
free(t->breakpoints);
t->breakpoints = next_b;
}
while (t->watchpoints) {
next_w = t->watchpoints->next;
free(t->watchpoints);
t->watchpoints = next_w;
}
for (int i = 0; i < x86_32->num_hw_bpoints; i++) {
debug_reg_list[i].used = 0;
debug_reg_list[i].bp_value = 0;
}
}
static int read_hw_reg_to_cache(struct target *t, int num) static int read_hw_reg_to_cache(struct target *t, int num)
{ {
uint32_t reg_value; uint32_t reg_value;

View File

@ -217,6 +217,7 @@ struct x86_32_common {
struct reg_cache *cache; struct reg_cache *cache;
struct jtag_tap *curr_tap; struct jtag_tap *curr_tap;
uint32_t stored_pc; uint32_t stored_pc;
int forced_halt_for_reset;
int flush; int flush;
/* pm_regs are for probemode save/restore state */ /* pm_regs are for probemode save/restore state */
@ -326,5 +327,6 @@ int x86_32_common_add_breakpoint(struct target *t, struct breakpoint *bp);
int x86_32_common_remove_breakpoint(struct target *t, struct breakpoint *bp); int x86_32_common_remove_breakpoint(struct target *t, struct breakpoint *bp);
int x86_32_common_add_watchpoint(struct target *t, struct watchpoint *wp); int x86_32_common_add_watchpoint(struct target *t, struct watchpoint *wp);
int x86_32_common_remove_watchpoint(struct target *t, struct watchpoint *wp); int x86_32_common_remove_watchpoint(struct target *t, struct watchpoint *wp);
void x86_32_common_reset_breakpoints_watchpoints(struct target *t);
#endif /* OPENOCD_TARGET_X86_32_COMMON_H */ #endif /* OPENOCD_TARGET_X86_32_COMMON_H */

View File

@ -404,8 +404,7 @@ static int xscale_read_tx(struct target *target, int consume)
} }
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
if ((now.tv_sec > timeout.tv_sec) || if (timeval_compare(&now, &timeout) > 0) {
((now.tv_sec == timeout.tv_sec) && (now.tv_usec > timeout.tv_usec))) {
LOG_ERROR("time out reading TX register"); LOG_ERROR("time out reading TX register");
return ERROR_TARGET_TIMEOUT; return ERROR_TARGET_TIMEOUT;
} }

View File

@ -0,0 +1,11 @@
#
# nordic module NRF52 (nRF52832/52840) attached to an adafruit ft232h module
# or any FT232H/FT2232H/FT4232H based board/module
#
source [find interface/ftdi/ft232h-module-swd.cfg]
#source [find interface/ftdi/minimodule-swd.cfg]
transport select swd
source [find target/nrf52.cfg]

View File

@ -1,5 +1,5 @@
# This is a ST NUCLEO L476RG board with a single STM32L476RGT6 chip. # Should work with all STM32L4 Nucleo Dev Boards.
# http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF261636 # http://www.st.com/en/evaluation-tools/stm32-mcu-nucleo.html
source [find interface/stlink.cfg] source [find interface/stlink.cfg]
@ -9,4 +9,3 @@ source [find target/stm32l4x.cfg]
# use hardware reset # use hardware reset
reset_config srst_only srst_nogate reset_config srst_only srst_nogate

View File

@ -6,12 +6,6 @@ if { [info exists JTAGSPI_IR] } {
set _JTAGSPI_IR $_USER1 set _JTAGSPI_IR $_USER1
} }
if { [info exists DR_LENGTH] } {
set _DR_LENGTH $DR_LENGTH
} else {
set _DR_LENGTH 1
}
if { [info exists TARGETNAME] } { if { [info exists TARGETNAME] } {
set _TARGETNAME $TARGETNAME set _TARGETNAME $TARGETNAME
} else { } else {
@ -25,7 +19,7 @@ if { [info exists FLASHNAME] } {
} }
target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap
flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR $_DR_LENGTH flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR
proc jtagspi_init {chain_id proxy_bit} { proc jtagspi_init {chain_id proxy_bit} {
# load proxy bitstream $proxy_bit and probe spi flash # load proxy bitstream $proxy_bit and probe spi flash

18
tcl/cpld/xilinx-xcf-p.cfg Normal file
View File

@ -0,0 +1,18 @@
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME xcf
}
# IDs acquired from Xilinx's DS123.pdf
# XCF08P <v>5057093
# XCF16P <v>5058093
# XCF32P <v>5059093
# The 4 top bits (28:31) are the device revision. Ignore it.
jtag newtap $_CHIPNAME flash -irlen 16 -ignore-version \
-expected-id 0x05057093 \
-expected-id 0x05058093 \
-expected-id 0x05059093
target create xcf.flash testee -chain-position $_CHIPNAME.flash
flash bank XCF_P xcf 0 0 0 0 xcf.flash

18
tcl/cpld/xilinx-xcf-s.cfg Normal file
View File

@ -0,0 +1,18 @@
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME xcf
}
# IDs acquired from Xilinx's DS123.pdf
# XCF01S <v>5044093
# XCF02S <v>5045093
# XCF04S <v>5046093
# The 4 top bits (28:31) are the device revision. Ignore it.
jtag newtap $_CHIPNAME flash -irlen 8 -ignore-version \
-expected-id 0x05044093 \
-expected-id 0x05045093 \
-expected-id 0x05046093
target create xcf.flash testee -chain-position $_CHIPNAME.flash
flash bank XCF_S xcf 0 0 0 0 xcf.flash

View File

@ -0,0 +1,18 @@
#
# Digilent JTAG-SMT2-NC
#
# http://store.digilentinc.com/jtag-smt2-nc-surface-mount-programming-module/
# https://reference.digilentinc.com/_media/jtag_smt2nc/jtag-smt2-nc_rm.pdf
#
# Based on reference sheet (above) and Xilinx KCU105 schematics
# https://www.xilinx.com/products/boards-and-kits/kcu105.html#documentation
#
# Note that the digilent_jtag_smt2 layout does not work and hangs while
# the ftdi_device_desc from digilent_hs2 is wrong.
interface ftdi
ftdi_device_desc "Digilent USB Device"
ftdi_vid_pid 0x0403 0x6014
ftdi_channel 0
ftdi_layout_init 0x00e8 0x60eb
reset_config none

View File

@ -0,0 +1,52 @@
#
# ADAFRUIT FTDI FT232H as a SWD direct connect interface
# Any FT232H based board may work
#
# http://www.ftdichip.com/Products/ICs/FT232H.htm
#
#
interface ftdi
ftdi_vid_pid 0x0403 0x6014
# data MSB..LSB direction (1:out) MSB..LSB
# 0000'0000'0011'0000 0000'0000'0011'1011
ftdi_layout_init 0x0030 0x003b
# 0xfff8 0xfffb
# Those signal are only required on some platforms or may required to be
# enabled explicitely (e.g. nrf5x chips).
ftdi_layout_signal nSRST -data 0x0010 -oe 0x0010
ftdi_layout_signal nTRST -data 0x0020 -oe 0x0020
# swd enable
ftdi_layout_signal SWD_EN -data 0
# tri-state (configure as input) TDO/TIO when reading
ftdi_layout_signal SWDIO_OE -data 0
transport select swd
# re-configure TDO as tri-state
#ftdi_layout_signal TDO -data 0x0002 -oe 0x0002
#ftdi_layout_signal TDI -data 0x0004
# Adafruit FT232H JTAG SWD
# Name Pin Name Func Func
# D0 J1-3 ADBUS0 TCK SWDCLK
# D1 J1-4 ADBUS1 TDO/DI SWDIO
# D2 J1-5 ADBUS2 TDI/DO SWDIO
# D3 J1-6 ADBUS3 TMS N/A
# D4 J1-7 ADBUS4 (GPIOL0) /nSRST optional module reset
# D5 J1-8 ADBUS5 (GPIOL1) /nTRST optional target reset
# D6 J1-9 ADBUS6 (GPIOL2)
# D7 J1-10 ADBUS7 (GPIOL3)
# C0 J2-1 ACBUS0 (GPIOH0)
# C1 J2-2 ACBUS1 (GPIOH1)
# C2 J2-3 ACBUS2 (GPIOH2)
# C3 J2-4 ACBUS3 (GPIOH3)
# C4 J2-5 ACBUS4 (GPIOH4)
# C5 J2-6 ACBUS5 (GPIOH5)
# C6 J2-7 ACBUS6 (GPIOH6)
# C7 J2-8 ACBUS7 (GPIOH7)
# C8 J2-9 ACBUS8
# C9 J2-10 ACBUS9

View File

@ -0,0 +1,54 @@
#
Supports SWD using the FT2232H or FT4232H minimodule.
# Each can support 2 SWD interfaces.
#
# FT2232H or FT4232H minimodule channel 0 (Channel A)
# Connector FTDI Target
# Pin Name
# --------- ------ ------
# CN2-11 VIO VDD_IO (Or connect to CN2-5 on the minimodule instead for a 3V3 interface)
# CN2-2 GND GND
# CN2-7 ADBUS0 (TCK) SWCLK
# CN2-9 ADBUS2 (TDI/TDO) SWDIO
# CN2-10 ADBUS1 (TDO/TDI) SWDIO
# CN2-14 ADBUS4 (GPIOL0) nRESET
#
# FT2232H minimodule channel 1 (Channel B)
# FTDI Target
# ---- ------
# CN2-11 - VDD_IO
# CN2-2 - GND
# CN3-26 - SWCLK
# CN3-25 - SWDIO
# CN3-24 - SWDIO
# CN3-21 - nRESET
#
# FT4232H minimodule channel 1 (Channel B)
# FTDI Target
# ---- ------
# CN2-11 - VDD_IO
# CN2-2 - GND
# CN2-18 - SWCLK
# CN2-17 - SWDIO
# CN2-20 - SWDIO
# CN2-22 - nRESET
#
interface ftdi
#Select your module type and channel
#ftdi_device_desc "FT2232H MiniModule"
ftdi_vid_pid 0x0403 0x6010
#ftdi_channel 1
#ftdi_device_desc "FT4232H MiniModule"
#ftdi_vid_pid 0x0403 0x6011
#ftdi_channel 1
ftdi_layout_init 0x0000 0x000b
ftdi_layout_signal nSRST -data 0x0010 -oe 0x0010
ftdi_layout_signal SWD_EN -data 0
ftdi_layout_signal SWDIO_OE -data 0
transport select swd

View File

@ -21,6 +21,10 @@ bcm2835gpio_speed_coeffs 113714 28
# Header pin numbers: 23 22 19 21 # Header pin numbers: 23 22 19 21
bcm2835gpio_jtag_nums 11 25 10 9 bcm2835gpio_jtag_nums 11 25 10 9
# Each of the SWD lines need a gpio number set: swclk swdio
# Header pin numbers: 23 22
bcm2835gpio_swd_nums 11 25
# If you define trst or srst, use appropriate reset_config # If you define trst or srst, use appropriate reset_config
# Header pin numbers: TRST - 26, SRST - 18 # Header pin numbers: TRST - 26, SRST - 18
@ -32,4 +36,3 @@ bcm2835gpio_jtag_nums 11 25 10 9
# or if you have both connected, # or if you have both connected,
# reset_config trst_and_srst srst_push_pull # reset_config trst_and_srst srst_push_pull

View File

@ -19,14 +19,11 @@ bcm2835gpio_speed_coeffs 146203 36
# Each of the JTAG lines need a gpio number set: tck tms tdi tdo # Each of the JTAG lines need a gpio number set: tck tms tdi tdo
# Header pin numbers: 23 22 19 21 # Header pin numbers: 23 22 19 21
# bcm2835gpio_jtag_nums 11 25 10 9 bcm2835gpio_jtag_nums 11 25 10 9
# or if you have both connected,
# reset_config trst_and_srst srst_push_pull
# Each of the SWD lines need a gpio number set: swclk swdio # Each of the SWD lines need a gpio number set: swclk swdio
# Header pin numbers: 22 18 # Header pin numbers: 23 22
bcm2835gpio_swd_nums 25 24 bcm2835gpio_swd_nums 11 25
# If you define trst or srst, use appropriate reset_config # If you define trst or srst, use appropriate reset_config
# Header pin numbers: TRST - 26, SRST - 18 # Header pin numbers: TRST - 26, SRST - 18
@ -34,9 +31,8 @@ bcm2835gpio_swd_nums 25 24
# bcm2835gpio_trst_num 7 # bcm2835gpio_trst_num 7
# reset_config trst_only # reset_config trst_only
bcm2835gpio_srst_num 18 # bcm2835gpio_srst_num 24
reset_config srst_only srst_push_pull # reset_config srst_only srst_push_pull
# or if you have both connected, # or if you have both connected,
# reset_config trst_and_srst srst_push_pull # reset_config trst_and_srst srst_push_pull

View File

@ -14,8 +14,18 @@ interface sysfsgpio
# Header pin numbers: 23 22 19 21 # Header pin numbers: 23 22 19 21
sysfsgpio_jtag_nums 11 25 10 9 sysfsgpio_jtag_nums 11 25 10 9
# At least one of srst or trst needs to be specified # Each of the SWD lines need a gpio number set: swclk swdio
# Header pin numbers: TRST - 26, SRST - 18 # Header pin numbers: 23 22
sysfsgpio_trst_num 7 sysfsgpio_swd_nums 11 25
# sysfsgpio_srst_num 24
# If you define trst or srst, use appropriate reset_config
# Header pin numbers: TRST - 26, SRST - 18
# sysfsgpio_trst_num 7
# reset_config trst_only
# sysfsgpio_srst_num 24
# reset_config srst_only srst_push_pull
# or if you have both connected,
# reset_config trst_and_srst srst_push_pull

37
tcl/target/imx7.cfg Normal file
View File

@ -0,0 +1,37 @@
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME imx7
}
# CoreSight Debug Access Port
if { [info exists DAP_TAPID] } {
set _DAP_TAPID $DAP_TAPID
} else {
set _DAP_TAPID 0x5ba00477
}
jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x0f \
-expected-id $_DAP_TAPID
#
# Cortex-A7 target
#
# GDB target: Cortex-A7, using DAP, configuring only one core
# Base addresses of cores:
# core 0 - 0x80070000
# core 1 - 0x80072000
set _TARGETNAME $_CHIPNAME.cpu_a7
target create $_TARGETNAME.0 cortex_a -chain-position $_CHIPNAME.dap \
-coreid 0 -dbgbase 0x80070000
target create $_TARGETNAME.1 cortex_a -chain-position $_CHIPNAME.dap \
-coreid 1 -dbgbase 0x80072000 -defer-examine
#
# Cortex-M4 target
#
set _TARGETNAME_2 $_CHIPNAME.cpu_m4
target create $_TARGETNAME_2 cortex_m -chain-position $_CHIPNAME.dap -ap-num 4 \
-defer-examine
targets $_TARGETNAME.0

View File

@ -1,5 +1,5 @@
# #
# Freescale Kinetis KE0x series devices # Freescale Kinetis KE0x and KEAx series devices
# #
source [find target/swj-dp.tcl] source [find target/swj-dp.tcl]

View File

@ -12,11 +12,11 @@ if { [info exists CHIPNAME] } {
} }
# Work-area is a space in RAM used for flash programming # Work-area is a space in RAM used for flash programming
# By default use 4kB # By default use 1KiB
if { [info exists WORKAREASIZE] } { if { [info exists WORKAREASIZE] } {
set _WORKAREASIZE $WORKAREASIZE set _WORKAREASIZE $WORKAREASIZE
} else { } else {
set _WORKAREASIZE 0x1000 set _WORKAREASIZE 0x400
} }
if { [info exists CPUTAPID] } { if { [info exists CPUTAPID] } {

12
tcl/target/stm8l152.cfg Normal file
View File

@ -0,0 +1,12 @@
#config script for STM8L152
set EEPROMSTART 0x1000
set EEPROMEND 0x13ff
proc stm8_reset_rop {} {
mwb 0x4800 0xaa
mwb 0x4800 0xaa
reset halt
}
source [find target/stm8l.cfg]

11
tcl/target/stm8s003.cfg Normal file
View File

@ -0,0 +1,11 @@
#config script for STM8S003
set FLASHEND 0x9FFF
set BLOCKSIZE 0x40
proc stm8_reset_rop {} {
mwb 0x4800 0x00
reset halt
}
source [find target/stm8s.cfg]

8
tcl/target/stm8s105.cfg Normal file
View File

@ -0,0 +1,8 @@
#config script for STM8S105
proc stm8_reset_rop {} {
mwb 0x4800 0x00
reset halt
}
source [find target/stm8s.cfg]

View File

@ -102,7 +102,7 @@ do_stage() {
for EXT in tar.gz tar.bz2 zip; do for EXT in tar.gz tar.bz2 zip; do
local FILE="${PACKAGE_RELEASE}.${EXT}" local FILE="${PACKAGE_RELEASE}.${EXT}"
# create archive signatures # create archive signatures
for HASH in md5 sha1; do for HASH in sha256; do
echo "sign: ${FILE}.${HASH}" echo "sign: ${FILE}.${HASH}"
${HASH}sum "${FILE}" > "archives/${FILE}.${HASH}" ${HASH}sum "${FILE}" > "archives/${FILE}.${HASH}"
done done

View File

@ -699,7 +699,7 @@ sub ctx_statement_block {
# An else is really a conditional as long as its not else if # An else is really a conditional as long as its not else if
if ($level == 0 && $coff_set == 0 && if ($level == 0 && $coff_set == 0 &&
(!defined($p) || $p =~ /(?:\s|\}|\+)/) && (!defined($p) || $p =~ /(?:\s|\}|\+)/) &&
$remainder =~ /^(else)(?:\s|{)/ && $remainder =~ /^(else)(?:\s|\{)/ &&
$remainder !~ /^else\s+if\b/) { $remainder !~ /^else\s+if\b/) {
$coff = $off + length($1) - 1; $coff = $off + length($1) - 1;
$coff_set = 1; $coff_set = 1;
@ -782,7 +782,7 @@ sub statement_block_size {
my ($stmt) = @_; my ($stmt) = @_;
$stmt =~ s/(^|\n)./$1/g; $stmt =~ s/(^|\n)./$1/g;
$stmt =~ s/^\s*{//; $stmt =~ s/^\s*\{//;
$stmt =~ s/}\s*$//; $stmt =~ s/}\s*$//;
$stmt =~ s/^\s*//; $stmt =~ s/^\s*//;
$stmt =~ s/\s*$//; $stmt =~ s/\s*$//;
@ -1136,7 +1136,7 @@ sub annotate_values {
print "ASSIGN($1)\n" if ($dbg_values > 1); print "ASSIGN($1)\n" if ($dbg_values > 1);
$type = 'N'; $type = 'N';
} elsif ($cur =~/^(;|{|})/) { } elsif ($cur =~/^(;|\{|})/) {
print "END($1)\n" if ($dbg_values > 1); print "END($1)\n" if ($dbg_values > 1);
$type = 'E'; $type = 'E';
$av_pend_colon = 'O'; $av_pend_colon = 'O';
@ -1783,7 +1783,7 @@ sub process {
} }
my $s = $stat; my $s = $stat;
$s =~ s/{.*$//s; $s =~ s/\{.*$//s;
# Ignore goto labels. # Ignore goto labels.
if ($s =~ /$Ident:\*$/s) { if ($s =~ /$Ident:\*$/s) {
@ -1879,7 +1879,7 @@ sub process {
#print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n"; #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n";
#print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n"; #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n";
if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) { if ($ctx !~ /\{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*\{/) {
ERROR("OPEN_BRACE", ERROR("OPEN_BRACE",
"that open brace { should be on the previous line\n" . "that open brace { should be on the previous line\n" .
"$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
@ -1920,7 +1920,7 @@ sub process {
my $continuation = 0; my $continuation = 0;
my $check = 0; my $check = 0;
$s =~ s/^.*\bdo\b//; $s =~ s/^.*\bdo\b//;
$s =~ s/^\s*{//; $s =~ s/^\s*\{//;
if ($s =~ s/^\s*\\//) { if ($s =~ s/^\s*\\//) {
$continuation = 1; $continuation = 1;
} }
@ -2024,7 +2024,7 @@ sub process {
} }
# check for initialisation to aggregates open brace on the next line # check for initialisation to aggregates open brace on the next line
if ($line =~ /^.\s*{/ && if ($line =~ /^.\s*\{/ &&
$prevline =~ /(?:^|[^=])=\s*$/) { $prevline =~ /(?:^|[^=])=\s*$/) {
ERROR("OPEN_BRACE", ERROR("OPEN_BRACE",
"that open brace { should be on the previous line\n" . $hereprev); "that open brace { should be on the previous line\n" . $hereprev);
@ -2231,7 +2231,7 @@ sub process {
} }
# open braces for enum, union and struct go on the same line. # open braces for enum, union and struct go on the same line.
if ($line =~ /^.\s*{/ && if ($line =~ /^.\s*\{/ &&
$prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) {
ERROR("OPEN_BRACE", ERROR("OPEN_BRACE",
"open brace '{' following $1 go on the same line\n" . $hereprev); "open brace '{' following $1 go on the same line\n" . $hereprev);
@ -2251,7 +2251,7 @@ sub process {
my ($where, $prefix) = ($-[1], $1); my ($where, $prefix) = ($-[1], $1);
if ($prefix !~ /$Type\s+$/ && if ($prefix !~ /$Type\s+$/ &&
($where != 0 || $prefix !~ /^.\s+$/) && ($where != 0 || $prefix !~ /^.\s+$/) &&
$prefix !~ /{\s+$/) { $prefix !~ /\{\s+$/) {
ERROR("BRACKET_SPACE", ERROR("BRACKET_SPACE",
"space prohibited before open square bracket '['\n" . $herecurr); "space prohibited before open square bracket '['\n" . $herecurr);
} }
@ -2493,7 +2493,7 @@ sub process {
## } ## }
#need space before brace following if, while, etc #need space before brace following if, while, etc
if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\){/) || if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) ||
$line =~ /do\{/) { $line =~ /do\{/) {
ERROR("SPACING", ERROR("SPACING",
"space required before the open brace '{'\n" . $herecurr); "space required before the open brace '{'\n" . $herecurr);
@ -2598,7 +2598,7 @@ sub process {
# Check for illegal assignment in if conditional -- and check for trailing # Check for illegal assignment in if conditional -- and check for trailing
# statements after the conditional. # statements after the conditional.
if ($line =~ /do\s*(?!{)/) { if ($line =~ /do\s*(?!\{)/) {
my ($stat_next) = ctx_statement_block($line_nr_next, my ($stat_next) = ctx_statement_block($line_nr_next,
$remain_next, $off_next); $remain_next, $off_next);
$stat_next =~ s/\n./\n /g; $stat_next =~ s/\n./\n /g;
@ -2630,7 +2630,7 @@ sub process {
substr($s, 0, length($c), ''); substr($s, 0, length($c), '');
$s =~ s/\n.*//g; $s =~ s/\n.*//g;
$s =~ s/$;//g; # Remove any comments $s =~ s/$;//g; # Remove any comments
if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && if (length($c) && $s !~ /^\s*\{?\s*\\*\s*$/ &&
$c !~ /}\s*while\s*/) $c !~ /}\s*while\s*/)
{ {
# Find out how long the conditional actually is. # Find out how long the conditional actually is.
@ -2669,7 +2669,7 @@ sub process {
if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) { if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) {
my $s = $1; my $s = $1;
$s =~ s/$;//g; # Remove any comments $s =~ s/$;//g; # Remove any comments
if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) { if ($s !~ /^\s*(?:\sif|(?:\{|)\s*\\?\s*$)/) {
ERROR("TRAILING_STATEMENTS", ERROR("TRAILING_STATEMENTS",
"trailing statements should be on next line\n" . $herecurr); "trailing statements should be on next line\n" . $herecurr);
} }
@ -2879,7 +2879,7 @@ sub process {
substr($block, 0, length($cond), ''); substr($block, 0, length($cond), '');
$seen++ if ($block =~ /^\s*{/); $seen++ if ($block =~ /^\s*\{/);
#print "cond<$cond> block<$block> allowed<$allowed>\n"; #print "cond<$cond> block<$block> allowed<$allowed>\n";
if (statement_lines($cond) > 1) { if (statement_lines($cond) > 1) {