4k-rom-tester.py

4k-rom-tester.py (3705 bytes)

import os
import time
import board
import digitalio
import struct

# 4k ram tester
def make_dios(*args):
    return [digitalio.DigitalInOut(a) for a in args]


address_pins = make_dios(*(getattr(board, f"GP{i}") for i in range(11, 11+12)))
for a in address_pins:
    a.switch_to_output()

data_pins = make_dios(*(getattr(board, f"GP{i}") for i in range(8)))

not_write_enable = digitalio.DigitalInOut(board.GP10)
not_write_enable.switch_to_output(True)

not_output_enable = digitalio.DigitalInOut(board.GP8)
not_output_enable.switch_to_output(True)

not_chip_enable = digitalio.DigitalInOut(board.GP9)
not_chip_enable.switch_to_output(True)

random_data = os.urandom(16)

def set_pins(value, pins):
    for p in pins:
        p.switch_to_output(value & 1)
        value >>= 1

def get_pins(pins):
    value = 0
    for i, p in enumerate(pins):
        value |= p.value << i
    return value

def read_out(*args):
    for p in data_pins:
        p.switch_to_input(digitalio.Pull.UP)

    not_chip_enable.value = False

    if not args: args = (0x800,)
    for addr in range(*args):
        set_pins(addr, address_pins) # There's no way the 150ns setup is violated at CP speeds!
        not_output_enable.value = False
        yield get_pins(data_pins)
        not_output_enable.value = True

    not_chip_enable.value = True

def _write(data, start_addr=0):
    for p in data_pins:
        p.switch_to_output(False)

    not_output_enable.value = True

    print(end=f"{start_addr:04x}")
    for offset, byte in enumerate(data):
        addr = start_addr + offset
        set_pins(addr, address_pins)
        set_pins(byte, data_pins)
        not_chip_enable.value = False
        assert get_pins(data_pins) == byte
        not_write_enable.value = False
        not_write_enable.value = True
        not_chip_enable.value = True
        print(end='.')

    not_chip_enable.value = True

def write(data, start_addr=0):
    _write(data, start_addr)
    print()

def verify(data, start_addr = 0):
    for p in data_pins:
        p.switch_to_input(digitalio.Pull.UP)

    not_output_enable.value = False
    not_chip_enable.value = False

    result = True

    for offset, byte in enumerate(data):
        addr = start_addr + offset
        set_pins(addr, address_pins)

        readback = get_pins(data_pins)
        if readback != byte:
            print(f"0x{addr:04x} {byte:02x} {readback:02x}")
            result = False

    if not result:
        raise ValueError("Verify failed")

    print("Verified")


def write_verify(data, start_addr = 0):
    _write(data, start_addr)
    verify(data, start_addr)

## Uncomment if you want to pre-erase the eeprom (not needed)
#write_verify(b"\xff" * 2048)

def readn(start, count=1):
    return bytes(read_out(start, start+count))

def print_ihex(address, rectype, data):
    data = list(data)
    data_str = "".join(f"{b:02x}" for b in data)
    data_len = len(data)
    assert data_len < 256
    assert 0 <= rectype < 256
    assert 0 <= address < 65536

    checksum = (-(data_len + sum(data) + rectype + address + address // 256)) & 0xff

    print(f":{data_len:02x}{address:04x}{rectype:02x}{data_str}{checksum:02x}")

if __name__ == '__main__':
    command = input("[P]rogram, [V]erify or [R]eadout? ").lower() 
    if command == "p":
        write(random_data, 0)
    if command in ("p", "v"):
        verify(random_data, 0)
    else:
        stride = 32
        end = 4096
        if end % stride != 0:
            raise ValueError("{stride=} incompatible with {end=}")

        for start_address in range(0, 2048, stride):
            print_ihex(start_address, 0, read_out(start_address, start_address + stride))
        print_ihex(0, 1, [])

cp-2k-ram-flasher.py

cp-2k-ram-flasher.py (4793 bytes)

import time
import board
import digitalio
import struct

def make_dios(*args):
    return [digitalio.DigitalInOut(a) for a in args]


address_pins = make_dios(
    board.GP19,
    board.GP20,
    board.GP21,
    board.GP22,
    board.GP26,
    board.GP27,
    board.GP28,
    board.GP4,
    board.GP5,
    board.GP6,
    board.GP9,
)

for a in address_pins:
    a.switch_to_output()

data_pins = make_dios(
    board.GP18,
    board.GP17,
    board.GP16,
    board.GP15,
    board.GP14,
    board.GP13,
    board.GP12,
    board.GP11,
)

not_write_enable = digitalio.DigitalInOut(board.GP7)
not_write_enable.switch_to_output(True)

not_output_enable = digitalio.DigitalInOut(board.GP8)
not_output_enable.switch_to_output(True)

not_chip_enable = digitalio.DigitalInOut(board.GP10)
not_chip_enable.switch_to_output(True)

def a2b_hex(data):
    if len(data) % 2 != 0:
        raise ValueError("Odd-length string")
    return bytes(int(data[i:i+2], 16) for i in range(0, len(data), 2))

def print_ihex(address, rectype, data):
    data = list(data)
    data_str = "".join(f"{b:02x}" for b in data)
    data_len = len(data)
    assert data_len < 256
    assert 0 <= rectype < 256
    assert 0 <= address < 65536

    checksum = (-(data_len + sum(data) + rectype + address + address // 256)) & 0xff

    print(f":{data_len:02x}{address:04x}{rectype:02x}{data_str}{checksum:02x}")

def ihex(f):
    lineno = 0
    while True:
        lineno += 1
        line = f.readline()
        if not line:
            break
        line = line.strip()
        if not line.startswith(':'): continue
        line_bin = a2b_hex(line[1:])
        if sum(line_bin) % 256 != 0:
            raise ValueError(f"Bad checksum on line {lineno}")
        data_len = struct.unpack('>BHB', line_bin[:4])[0]
        data_len, address, rectype, data, checksum = struct.unpack(f'>BHB{data_len}sB', line_bin)

        yield (address, rectype, data)

def set_pins(value, pins):
    for p in pins:
        p.switch_to_output(value & 1)
        value >>= 1

def get_pins(pins):
    value = 0
    for i, p in enumerate(pins):
        value |= p.value << i
    return value

def strobe(pin):
    pin.value = False
    pin.value = True

def read_out(*args):
    for p in data_pins:
        p.switch_to_input(digitalio.Pull.UP)

    not_output_enable.value = False
    not_chip_enable.value = False

    if not args: args = (0x800,)
    for addr in range(*args):
        set_pins(addr, address_pins) # There's no way the 150ns setup is violated at CP speeds!
        yield get_pins(data_pins)

def _write(data, start_addr=0):
    for p in data_pins:
        p.switch_to_output(False)

    not_output_enable.value = True
    not_chip_enable.value = False

    print(end=f"{start_addr:04x}")
    for offset, byte in enumerate(data):
        addr = start_addr + offset
        set_pins(addr, address_pins)
        set_pins(byte, data_pins)
        assert get_pins(data_pins) == byte
        not_write_enable.value = False
        not_write_enable.value = True
        print(end='.')

def write(data, start_addr=0):
    _write(data, start_addr)
    print()

def verify(data, start_addr = 0):
    for p in data_pins:
        p.switch_to_input(digitalio.Pull.UP)

    not_output_enable.value = False
    not_chip_enable.value = False

    result = True

    for offset, byte in enumerate(data):
        addr = start_addr + offset
        set_pins(addr, address_pins)

        readback = get_pins(data_pins)
        if readback != byte:
            print(f"0x{addr:04x} {byte:02x} {readback:02x}")
            result = False

    if not result:
        raise ValueError("Verify failed")

    print("Verified")


def write_verify(data, start_addr = 0):
    _write(data, start_addr)
    verify(data, start_addr)

## Uncomment if you want to pre-erase the eeprom (not needed)
#write_verify(b"\xff" * 2048)

command = input("[P]rogram, [V]erify or [R]eadout? ").lower() 
if command == "p":
    with open("xrxpl.hex") as f:
        for address, rectype, data in ihex(f):
            if rectype == 0:
                write_verify(data, address)
            elif rectype == 1:
                break
            else:
                print(address, rectype, data)
if command in ("p", "v"):
    with open("xrxpl.hex") as f:
        for address, rectype, data in ihex(f):
            if rectype == 0:
                verify(data, address)
            elif rectype == 1:
                break
            else:
                print(address, rectype, data)
else:
    stride = 32
    end = 2048
    if end % stride != 0:
        raise ValueError("{stride=} incompatible with {end=}")

    for start_address in range(0, 2048, stride):
        print_ihex(start_address, 0, read_out(start_address, start_address + stride))
    print_ihex(0, 1, [])