Skip to content
Permalink

Comparing changes

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

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: whitequark/glasgow
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 671eb9520f86
Choose a base ref
...
head repository: whitequark/glasgow
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 19fdbdec71bd
Choose a head ref
  • 8 commits
  • 14 files changed
  • 2 contributors

Commits on Mar 8, 2019

  1. Copy the full SHA
    f7e0ee0 View commit details
  2. applet.interface.i2c_master: use argparse subparsers.

    Instead of mutually exclusive groups.
    whitequark committed Mar 8, 2019
    Copy the full SHA
    9030521 View commit details
  3. applet.memory.25x: remove default for ADDRESS and LENGTH arguments.

    These need to be specified explicitly anyway in virtually all cases.
    whitequark committed Mar 8, 2019
    Copy the full SHA
    2698dfd View commit details
  4. applet.memory.24x: use argparse subparsers.

    Instead of mutually exclusive groups.
    
    Also, handle errors.
    whitequark committed Mar 8, 2019
    Copy the full SHA
    f6279ac View commit details
  5. Copy the full SHA
    a5cbd1a View commit details
  6. Copy the full SHA
    b209775 View commit details
  7. Copy the full SHA
    0f25724 View commit details
  8. Copy the full SHA
    19fdbde View commit details
53 changes: 19 additions & 34 deletions hardware/boards/glasgow/io_banks.sch
Original file line number Diff line number Diff line change
@@ -669,26 +669,16 @@ Wire Wire Line
Connection ~ 10000 1650
Wire Wire Line
10000 1650 10000 1850
Text Label 9200 1050 0 50 ~ 0
Text Label 9150 1050 0 50 ~ 0
U1
Text Label 9200 1250 0 50 ~ 0
Text Label 9150 1250 0 50 ~ 0
U2
Text Label 9200 1450 0 50 ~ 0
Text Label 9150 1450 0 50 ~ 0
U3
Text Label 9200 1650 0 50 ~ 0
Text Label 9150 1650 0 50 ~ 0
U4
Text Label 9200 1850 0 50 ~ 0
Text Label 9150 1850 0 50 ~ 0
U5
Wire Wire Line
9200 1850 9300 1850
Wire Wire Line
9350 1650 9300 1650
Wire Wire Line
9200 1450 9300 1450
Wire Wire Line
9350 1250 9300 1250
Wire Wire Line
9200 1050 9300 1050
Text Label 5350 4350 2 50 ~ 0
U1
Text Label 5350 4050 2 50 ~ 0
@@ -1282,21 +1272,6 @@ Wire Wire Line
5250 5150 5350 5150
Wire Bus Line
5500 5800 5850 5800
Connection ~ 9300 1050
Wire Wire Line
9300 1050 9350 1050
Connection ~ 9300 1250
Wire Wire Line
9300 1250 9200 1250
Connection ~ 9300 1450
Wire Wire Line
9300 1450 9350 1450
Connection ~ 9300 1650
Wire Wire Line
9300 1650 9200 1650
Connection ~ 9300 1850
Wire Wire Line
9300 1850 9350 1850
Wire Bus Line
2050 5800 2400 5800
Text Label 5250 5650 0 50 ~ 0
@@ -1511,6 +1486,20 @@ Text Notes 10450 1500 0 50 ~ 0
116µA Vf = 2.51V
Wire Notes Line
10350 1050 10400 1050
Text Notes 10450 1700 0 50 ~ 0
76µA Vf = 2.54V
Text Notes 10450 1900 0 50 ~ 0
174µA Vf = 2.48V
Wire Wire Line
9150 1850 9300 1850
Wire Wire Line
9150 1650 9300 1650
Wire Wire Line
9150 1450 9300 1450
Wire Wire Line
9150 1250 9300 1250
Wire Wire Line
9150 1050 9300 1050
Wire Bus Line
5850 4950 5850 5800
Wire Bus Line
@@ -1529,8 +1518,4 @@ Wire Bus Line
2050 3850 2050 5800
Wire Bus Line
9050 3200 9050 5800
Text Notes 10450 1700 0 50 ~ 0
76µA Vf = 2.54V
Text Notes 10450 1900 0 50 ~ 0
174µA Vf = 2.48V
$EndSCHEMATC
41 changes: 22 additions & 19 deletions software/glasgow/applet/interface/i2c_master/__init__.py
Original file line number Diff line number Diff line change
@@ -285,40 +285,43 @@ async def run(self, device, args):

@classmethod
def add_interact_arguments(cls, parser):
parser.add_argument(
"--scan-device-id", action="store_true", default=False,
help="read device ID from devices responding to scan")

g_operation = parser.add_mutually_exclusive_group(required=True)
g_operation.add_argument(
"--scan-read", action="store_true", default=False,
help="scan all possible I2C read addresses")
g_operation.add_argument(
"--scan-write", action="store_true", default=False,
help="scan all possible I2C write addresses")
g_operation.add_argument(
"--repl", action="store_true", default=False,
help="drop into Python shell; use `i2c_iface` to communicate")
p_operation = parser.add_subparsers(dest="operation", metavar="OPERATION", required=True)

def add_scan_id_argument(parser):
parser.add_argument(
"--device-id", action="store_true", default=False,
help="read device ID from devices responding to scan")

p_scan_read = p_operation.add_parser(
"scan-read", help="scan all possible I2C read addresses")
add_scan_id_argument(p_scan_read)

p_scan_write = p_operation.add_parser(
"scan-write", help="scan all possible I2C write addresses")
add_scan_id_argument(p_scan_write)

p_repl = p_operation.add_parser(
"repl", help="drop into Python shell; use `i2c_iface` to communicate")

async def interact(self, device, args, i2c_iface):
if args.scan_read or args.scan_write:
if args.operation in ("scan-read", "scan-write"):
# Don't scan reserved I2C addresses.
for addr in range(0b0001_000, 0b1111_000):
responded = False
if args.scan_read:
if args.operation == "scan-read":
# We need to read at least one byte in order to transmit a NAK bit
# so that the addressed device releases SDA.
if await i2c_iface.read(addr, 1, stop=True) is not None:
self.logger.info("scan found read address %s",
"{:#09b}".format(addr))
responded = True
if args.scan_write:
if args.operation == "scan-write":
if await i2c_iface.write(addr, [], stop=True) is True:
self.logger.info("scan found write address %s",
"{:#09b}".format(addr))
responded = True

if responded and args.scan_device_id:
if responded and args.device_id:
device_id = await i2c_iface.device_id(addr)
if device_id is None:
self.logger.warning("device %s did not acknowledge Device ID", bin(addr))
@@ -327,7 +330,7 @@ async def interact(self, device, args, i2c_iface):
self.logger.info("device %s ID: manufacturer %s, part %s, revision %s",
bin(addr), bin(manufacturer), bin(part_ident), bin(revision))

if args.repl:
if args.operation == "repl":
await AsyncInteractiveConsole(locals={"i2c_iface":i2c_iface}).interact()

# -------------------------------------------------------------------------------------------------
20 changes: 15 additions & 5 deletions software/glasgow/applet/interface/jtag_probe/__init__.py
Original file line number Diff line number Diff line change
@@ -533,12 +533,22 @@ def segment_irs(self, ir_value, count=None):

irs = []
ir_offset = 0
ir_starts = ir_value.search(bitarray("10"))
for ir_start0, ir_start1 in zip(ir_starts, ir_starts[1:] + [len(ir_value)]):
ir_length = ir_start1 - ir_start0
self._log_h("found ir[%d]", ir_length)
if count == 1:
# 1 TAP case; the entire IR belongs to the only TAP we have.
ir_length = len(ir_value)
self._log_h("found ir[%d] (1-tap)", ir_length)
irs.append((ir_offset, ir_length))
ir_offset += ir_length
else:
# >1 TAP case; there is no way to segment IR without knowledge of specific devices
# involved, but an IR always starts with 10, and we can use this to try and guess
# the IR segmentation. Our segmentation is pessimistic, i.e. it always detects either
# as many IRs as TAPs, or more IRs than TAPs.
ir_starts = ir_value.search(bitarray("10"))
for ir_start0, ir_start1 in zip(ir_starts, ir_starts[1:] + [len(ir_value)]):
ir_length = ir_start1 - ir_start0
self._log_h("found ir[%d] (n-tap)", ir_length)
irs.append((ir_offset, ir_length))
ir_offset += ir_length

if count is not None and len(irs) != count:
self._log_h("ir count does not match idcode count")
103 changes: 81 additions & 22 deletions software/glasgow/applet/memory/_24x/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import argparse

from ...interface.i2c_master import I2CMasterApplet
from ... import *
@@ -68,34 +69,58 @@ async def write(self, addr, data):
class Memory24xApplet(I2CMasterApplet, name="memory-24x"):
logger = logging.getLogger(__name__)
help = "read and write 24-series I²C EEPROM memories"
default_page_size = 8
description = """
Read and write memories compatible with 24-series EEPROM memory, such as Microchip 24C02C,
Atmel 24C256, or hundreds of other memories that typically have "24X" where X is a letter
in their part number.
If one address byte is used and an address higher than 255 is specified, either directly
or implicitly through operation size, the high address bits are logically ORed with
the I2C address.
the I²C address. In this case the pins used on smaller devices for low address bits are
internally not connected.
# Page size
The memory performs writes by first latching incoming data into a page buffer, and committing
the page buffer after a stop condition. If more data is provided than the page buffer size,
or if page boundary is crossed when the address is autoincremneted, a wraparound occurs; this
generally results in wrong memory contents after the write operation is complete. The purpose
of having a page buffer is to batch updates, since a write of any length between 1 and page
size takes the same amount of time.
Using the correct page size is vitally important for writes. A smaller page size can always
be used with a memory that actually has a larger page size, but not vice versa. Using a page
size larger than 1 is necessary to get good performance.
The default page size in this applet is {page_size}, because no memories with page smaller
than {page_size} bytes have been observed in the wild so far, and this results in decent
performance with all memories. However, it is possible that a memory could have a smaller
page size. In that case it is necessary to specify a `--page-size 1` option explicitly.
Conversely, specifying a larger page size, when applicable, will significantly improve write
performance.
# Pinout
The pinout of a typical 24-series IC is as follows:
* 8-pin: A0=1 A1=2 A2=3 SDA=5 SCL=6 WP=7 VCC=8 GND=4
"""
""".format(page_size=default_page_size)

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

parser.add_argument(
"-A", "--i2c-address", type=int, metavar="I2C-ADDR", default=0b1010000,
help="I2C address of the memory; typically 0b1010(A2)(A1)(A0) "
help="I²C address of the memory; typically 0b1010(A2)(A1)(A0) "
"(default: 0b1010000)")
parser.add_argument(
"-W", "--address-width", type=int, choices=[1, 2], required=True,
help="number of address bytes to use (one of: 1 2)")
parser.add_argument(
"-P", "--page-size", type=int, metavar="PAGE-SIZE", default=8,
help="page buffer size; writes will be split into PAGE-SIZE byte chunks")
"-P", "--page-size", type=int, metavar="PAGE-SIZE", default=cls.default_page_size,
help="page buffer size; writes will be split into PAGE-SIZE byte long aligned chunks")

async def run(self, device, args):
i2c_iface = await super().run(device, args)
@@ -104,23 +129,57 @@ async def run(self, device, args):

@classmethod
def add_interact_arguments(cls, parser):
parser.add_argument(
"-a", "--address", type=int, metavar="ADDR", default=0,
help="first memory address of the read or write operation")
g_operation = parser.add_mutually_exclusive_group(required=True)
g_operation.add_argument(
"-r", "--read", type=int, metavar="SIZE",
help="read SIZE bytes starting at ADDR")
def hex(arg): return bytes.fromhex(arg)
g_operation.add_argument(
"-w", "--write", type=hex, metavar="DATA",
help="write hex bytes DATA starting at ADDR")
def address(arg):
return int(arg, 0)
def length(arg):
return int(arg, 0)
def hex_bytes(arg):
return bytes.fromhex(arg)

p_operation = parser.add_subparsers(dest="operation", metavar="OPERATION", required=True)

p_read = p_operation.add_parser(
"read", help="read memory")
p_read.add_argument(
"address", metavar="ADDRESS", type=address,
help="read memory starting at address ADDRESS, with wraparound")
p_read.add_argument(
"length", metavar="LENGTH", type=length,
help="read LENGTH bytes from memory")
p_read.add_argument(
"-f", "--file", metavar="FILENAME", type=argparse.FileType("wb"),
help="write memory contents to FILENAME")

p_write = p_operation.add_parser(
"write", help="write memory")
p_write.add_argument(
"address", metavar="ADDRESS", type=address,
help="write memory starting at address ADDRESS")
g_data = p_write.add_mutually_exclusive_group(required=True)
g_data.add_argument(
"-d", "--data", metavar="DATA", type=hex_bytes,
help="write memory with DATA as hex bytes")
g_data.add_argument(
"-f", "--file", metavar="FILENAME", type=argparse.FileType("rb"),
help="write memory with contents of FILENAME")

async def interact(self, device, args, m24x_iface):
if args.read is not None:
result = await m24x_iface.read(args.address, args.read)
if result is not None:
print(result.hex())
if args.operation == "read":
data = await m24x_iface.read(args.address, args.length)
if data is None:
raise GlasgowAppletError("memory did not acknowledge read")

if args.file:
args.file.write(data)
else:
print(data.hex())

if args.operation == "write":
if args.data is not None:
data = args.data
if args.file is not None:
data = args.file.read()

elif args.write is not None:
await m24x_iface.write(args.address, args.write)
success = await m24x_iface.write(args.address, data)
if not success:
raise GlasgowAppletError("memory did not acknowledge write")
6 changes: 3 additions & 3 deletions software/glasgow/applet/memory/_25x/__init__.py
Original file line number Diff line number Diff line change
@@ -270,10 +270,10 @@ def bits(arg):

def add_read_arguments(parser):
parser.add_argument(
"address", metavar="ADDRESS", type=address, default=0,
"address", metavar="ADDRESS", type=address,
help="read memory starting at address ADDRESS, with wraparound")
parser.add_argument(
"length", metavar="LENGTH", type=length, default=0,
"length", metavar="LENGTH", type=length,
help="read LENGTH bytes from memory")
parser.add_argument(
"-f", "--file", metavar="FILENAME", type=argparse.FileType("wb"),
@@ -289,7 +289,7 @@ def add_read_arguments(parser):

def add_program_arguments(parser):
parser.add_argument(
"address", metavar="ADDRESS", type=address, default=0,
"address", metavar="ADDRESS", type=address,
help="program memory starting at address ADDRESS")
g_data = parser.add_mutually_exclusive_group(required=True)
g_data.add_argument(
2 changes: 1 addition & 1 deletion software/glasgow/arch/arc/core.py
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@
AUX_AUX_USER_SP_addr = 0x0d
AUX_INT_VECTOR_BASE_addr = 0x25

AUX_STATUS32 = Bitfield("AUX_STATUS32", 4, [
AUX_STATUS32 = Bitfield("AUX_STATUS32", 32, [
("H", 1),
("E1", 1),
("E2", 1),
6 changes: 3 additions & 3 deletions software/glasgow/arch/arc/jtag.py
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@

# DR values

DR_STATUS = Bitfield("DR_STATUS", 1, [
DR_STATUS = Bitfield("DR_STATUS", 4, [
("ST", 1),
("FL", 1),
("RD", 1),
@@ -44,10 +44,10 @@
DR_TXN_COMMAND_READ_CORE = bitarray("1010", endian="little")
DR_TXN_COMMAND_READ_AUX = bitarray("0110", endian="little")

DR_ADDRESS = Bitfield("DR_ADDRESS", 4, [
DR_ADDRESS = Bitfield("DR_ADDRESS", 32, [
("Address", 32),
])

DR_DATA = Bitfield("DR_DATA", 4, [
DR_DATA = Bitfield("DR_DATA", 32, [
("Data", 32),
])
Loading