Skip to content

Commit

Permalink
Reformat hs3program
Browse files Browse the repository at this point in the history
  • Loading branch information
moni-gomspace committed May 27, 2024
1 parent d5131b2 commit 80ff66e
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 251 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
*.pdf
*.egg-info
build
.vscode
.vscode
venv
*.elf
83 changes: 50 additions & 33 deletions digilent_hs3/hs3program/avr32.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,17 @@ def _WaitFlashReady(self):
fsrReg = self._GetRegister(self.FSR)
# If LOCKE bit in FSR set
if (fsrReg & FSR_LOCKE_MASK) >> FSR_LOCKE_OFFSET:
raise Exception(
"Programming of at least one locked lock region has happend since the last read of FSR")
raise RuntimeError(
"Programming of at least one locked lock region has happend since the last read of FSR"
)
# If PROGE bit in FSR set
if (fsrReg & FSR_PROGE_MASK) >> FSR_PROGE_OFFSET:
raise Exception(
"An invalid command and/or bad keywords were written in the Flash Command Register")
raise RuntimeError("An invalid command and/or bad keywords were written in the Flash Command Register")
# Read FRDY bit in FSR
if (fsrReg & FSR_FRDY_MASK) >> FSR_FRDY_OFFSET:
return # FLASH ready for next operation
raise Exception("Timeout while waiting for flash controller to be ready")

raise RuntimeError("Timeout while waiting for flash controller to be ready")

def _ClearPageBuffer(self):
command = WRITE_PROTECT_KEY | CMD_CLEAR_PAGE_BUFFER
Expand All @@ -94,6 +94,7 @@ def _ClearPageBuffer(self):
def DeviceSize(self) -> int:
if not self._device_size:
self._GetInternalFlashSize()
assert self._device_size is not None
return self._device_size

@property
Expand All @@ -104,6 +105,7 @@ def FlashBase(self) -> int:
def PageSize(self) -> int:
if not self._page_size:
self._GetInternalFlashSize()
assert self._page_size is not None
return self._page_size

def _GetInternalFlashSize(self):
Expand Down Expand Up @@ -146,23 +148,22 @@ def _GetInternalFlashSize(self):
elif fsz == 14:
size = 2048 * 1024
else:
raise Exception("Unknown flash size")
raise RuntimeError("Unknown flash size")
self._device_size = size

def UnlockRegion(self, offset, size):
if (offset >= USER_PAGE_OFFSET) and (offset < USER_PAGE_OFFSET + self.PageSize):
return # the user page doesn't need unlocking
if (offset >= self.DeviceSize) or (offset+size > self.DeviceSize):
raise Exception(
"Region to be unlock lies outside flash address space")
lastpagetounlock = (offset+size) // self.PageSize
if (offset >= self.DeviceSize) or (offset + size > self.DeviceSize):
raise RuntimeError("Region to be unlock lies outside flash address space")
lastpagetounlock = (offset + size) // self.PageSize
# compute start offset of page to write to
page = offset & ~(self.PageSize - 1)
pagenr = offset // self.PageSize
while pagenr <= lastpagetounlock:
command = WRITE_PROTECT_KEY | CMD_UNLOCK_REGION
# include the correct page number in the command
command |= ((pagenr << FCMD_PAGEN_OFFSET) & FCMD_PAGEN_MASK)
command |= (pagenr << FCMD_PAGEN_OFFSET) & FCMD_PAGEN_MASK
# Unlocking page: pagenr
self._WaitFlashReady()
self._WriteCommand(command) # execute unlock page command
Expand Down Expand Up @@ -190,13 +191,13 @@ def EraseRegionSequence(self, offset, size):
if (offset >= USER_PAGE_OFFSET) and (offset < USER_PAGE_OFFSET + self.PageSize):
self.EraseUserPage()

lastpagetoerase = (offset+size) // self.PageSize
lastpagetoerase = (offset + size) // self.PageSize
# compute start offset of page to write to
page = offset & ~(self.PageSize - 1)
pagenr = offset // self.PageSize
while (pagenr <= lastpagetoerase):
while pagenr <= lastpagetoerase:
Command = WRITE_PROTECT_KEY | CMD_ERASE_PAGE
Command |= ((pagenr << FCMD_PAGEN_OFFSET) & FCMD_PAGEN_MASK)
Command |= (pagenr << FCMD_PAGEN_OFFSET) & FCMD_PAGEN_MASK
# include the correct page number in the command
self._WaitFlashReady()
self._WriteCommand(Command) # execute page erase command
Expand All @@ -208,24 +209,30 @@ def EraseRegionSequence(self, offset, size):

def SetGPFuseByte(self, index, value):
if index > 3 or index < 0:
raise Exception("Invalid fuse byte")

command = WRITE_PROTECT_KEY | CMD_PROGRAM_GP_FUSE_BYTE | (index << FCMD_PAGEN_OFFSET) | ((value & 0xFF) << (FCMD_PAGEN_OFFSET+3))
raise RuntimeError("Invalid fuse byte")

command = (
WRITE_PROTECT_KEY
| CMD_PROGRAM_GP_FUSE_BYTE
| (index << FCMD_PAGEN_OFFSET)
| ((value & 0xFF) << (FCMD_PAGEN_OFFSET + 3))
)

self._WaitFlashReady()
self._WriteCommand(command)
self._WaitFlashReady()

def WriteFuses(self, fuses: int):
def WriteFuses(self, fuses: int) -> None:
"""Assumes fuses are 32 bits"""
for i in range(4):
self.SetGPFuseByte(i, (fuses >> (8*i)) & 0xFF)
self.SetGPFuseByte(i, (fuses >> (8 * i)) & 0xFF)

def _ProgramPage(self, address: int, cmd: int, offset: int, data: bytes):
def _ProgramPage(self, address: int, cmd: int, offset: int, data: bytes) -> None:
bufferPacket = data
if (offset > 0) or (offset+len(data) < self.PageSize):
bufferPacket = self._ReadBlockWords(address, self.PageSize // 4)
bufferPacket[offset:offset+len(data)] = data
if (offset > 0) or (offset + len(data) < self.PageSize):
bufferPacketArray = bytearray(self._ReadBlockWords(address, self.PageSize // 4))
bufferPacketArray[offset : offset + len(data)] = data
bufferPacket = bufferPacketArray

self._ClearPageBuffer()
self._WriteBlockWords(address, bufferPacket)
Expand All @@ -235,16 +242,22 @@ def _ProgramPage(self, address: int, cmd: int, offset: int, data: bytes):
self._WriteCommand(command)
self._WaitFlashReady()

def ProgramUserPage(self, page_offset: int, DataBuffer: bytes):
def ProgramUserPage(self, page_offset: int, DataBuffer: bytes) -> None:
self._ProgramPage(self.FlashBase + USER_PAGE_OFFSET, CMD_WRITE_USER_PAGE, page_offset, DataBuffer)

def ProgramSequence(self, address: int, data_buffer: bytes, progress_callback: typing.Callable[[int, int], None]):
if (address >= self.FlashBase + USER_PAGE_OFFSET) and (self.FlashBase + address < USER_PAGE_OFFSET + self.PageSize):
def ProgramSequence(
self, address: int, data_buffer: bytes, progress_callback: typing.Callable[[int, int], None]
) -> None:
if (address >= self.FlashBase + USER_PAGE_OFFSET) and (
self.FlashBase + address < USER_PAGE_OFFSET + self.PageSize
):
self.ProgramUserPage(address - (self.FlashBase + USER_PAGE_OFFSET), data_buffer)
return

if (address >= self.FlashBase + self.DeviceSize) or (address+len(data_buffer) > self.FlashBase + self.DeviceSize):
raise Exception("Region to be programmed lies outside flash address space")
if (address >= self.FlashBase + self.DeviceSize) or (
address + len(data_buffer) > self.FlashBase + self.DeviceSize
):
raise RuntimeError("Region to be programmed lies outside flash address space")

page_number = (address - self.FlashBase) // self.PageSize
first_page = page_number
Expand All @@ -259,10 +272,14 @@ def ProgramSequence(self, address: int, data_buffer: bytes, progress_callback: t
# Write bytes
command = CMD_WRITE_PAGE
command |= page_number << FCMD_PAGEN_OFFSET
self._ProgramPage(page_number * self.PageSize + self.FlashBase, command, address % self.PageSize, data_buffer[index:index + bytes_in_page])
self._ProgramPage(
page_number * self.PageSize + self.FlashBase,
command,
address % self.PageSize,
data_buffer[index : index + bytes_in_page],
)

if progress_callback:
progress_callback(page_number - first_page, last_page - first_page)
progress_callback(page_number - first_page, last_page - first_page)

address = 0
page_number += 1
Expand All @@ -276,4 +293,4 @@ def ReadMemory(self, address: int, size: int) -> bytes:
data_offset = address - aligned_address

data = self._ReadBlockWords(aligned_address, (aligned_end - aligned_address) // 4)
return data[data_offset:data_offset+size]
return data[data_offset : data_offset + size]
81 changes: 56 additions & 25 deletions digilent_hs3/hs3program/avr32_prog.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,46 @@
#!/bin/env python3
#!/usr/bin/env python3
# Copyright (C) 2012-2022 Jeppe Johansen <jeppe@j-software.dk>
import argparse
import logging
import sys
import time
from elftools.elf.elffile import ELFFile

from hs3program.avr32 import AVR32, FLASH_BASE
from elftools.elf.elffile import ELFFile
from hs3program.avr32 import AVR32
from hs3program.ftdi_jtag_adapter import FTDIJtagAdapter
from hs3program.jtag_adapter import JtagAdapter

ADAPTERS = {
"busblaster_v25": lambda frequency: FTDIJtagAdapter(0x0403, 0x6010, 0x0000, 0x0010, frequency=frequency, nSRST=(0x0200, 0x0800), nTRST=(0x0100, 0x0400)),
"digilent_hs3": lambda frequency: FTDIJtagAdapter(0x0403, 0x6014, 0x0080, 0x0080, frequency=frequency, nSRST=(0x2000, 0x1000)),
"openmoko_dbv3": lambda frequency: FTDIJtagAdapter(0x1457, 0x5118, 0x0000, 0x0010, frequency=frequency, nSRST=(0x0800, 0x0400), nTRST=(0x0200, 0x0100)),
"busblaster_v25": lambda frequency: FTDIJtagAdapter(
0x0403, 0x6010, 0x0000, 0x0010, frequency=frequency, nSRST=(0x0200, 0x0800), nTRST=(0x0100, 0x0400)
),
"digilent_hs3": lambda frequency: FTDIJtagAdapter(
0x0403, 0x6014, 0x0080, 0x0080, frequency=frequency, nSRST=(0x2000, 0x1000)
),
"openmoko_dbv3": lambda frequency: FTDIJtagAdapter(
0x1457, 0x5118, 0x0000, 0x0010, frequency=frequency, nSRST=(0x0800, 0x0400), nTRST=(0x0200, 0x0100)
),
}


def get_adapter(config, frequency) -> JtagAdapter:
if config in ADAPTERS:
return ADAPTERS[config](frequency)
raise Exception("Unknown adapter: " + config)


def program_segment(dev: AVR32, address: int, mem_size: int, data: bytes, do_erase: bool, verify: bool):
def program_segment(dev: AVR32, address: int, mem_size: int, data: bytes, do_erase: bool, verify: bool) -> None:
assert not do_erase, "No segment erase support yet"
assert mem_size == len(data), "Data should be as long as memory segment"

def progress(current, total):
if sys.stdout.isatty():
sys.stdout.write("\r [%d%%] Wrote page %d out of %d" % (int(100*(current+1)/total), current + 1, total))
sys.stdout.write(
"\r [%d%%] Wrote page %d out of %d" % (int(100 * (current + 1) / total), current + 1, total)
)
sys.stdout.flush()
else:
print(" [%d%%] Wrote page %d out of %d" % (int(100*(current+1)/total), current + 1, total))
print(" [%d%%] Wrote page %d out of %d" % (int(100 * (current + 1) / total), current + 1, total))

try:
dev.ProgramSequence(address, data, progress)
Expand All @@ -42,7 +51,7 @@ def progress(current, total):
sys.stdout.flush()
else:
print(" Verifying...")

readback = dev.ReadMemory(address, len(data))

error_offset = -1
Expand All @@ -51,7 +60,10 @@ def progress(current, total):
error_offset = i
break
if error_offset >= 0:
raise Exception("Verification failed. Difference in read data at address: %d. Expected %02x, but read %02x." % (address+error_offset, data[error_offset], readback[error_offset]))
raise RuntimeError(
"Verification failed. Difference in read data at address: %d. Expected %02x, but read %02x."
% (address + error_offset, data[error_offset], readback[error_offset])
)
finally:
if sys.stdout.isatty():
sys.stdout.write("\n")
Expand All @@ -64,9 +76,9 @@ def program(programmer, flash=None, no_verify=False, chip_erase=True, detect=Fal
adapter.SetSignal("TCK", False)

# Do the AVR32 reset sequence
adapter.SRST('0')
adapter.SRST("0")
time.sleep(0.1)
adapter.SRST('z')
adapter.SRST("z")

if detect:
adapter.DetectDevices()
Expand All @@ -82,7 +94,7 @@ def program(programmer, flash=None, no_verify=False, chip_erase=True, detect=Fal
if dump:
print("Dumping flash contents")
with open(dump, "wb") as f:
f.write(dev._ReadBlockWords(dev.FlashBase, dev.DeviceSize // 4))
f.write(dev._ReadBlockWords(dev.FlashBase, dev.DeviceSize // 4)) # pylint: disable=protected-access

if chip_erase:
print("Performing chip erase")
Expand All @@ -98,8 +110,12 @@ def program(programmer, flash=None, no_verify=False, chip_erase=True, detect=Fal
elf = ELFFile(file)

for seg in elf.iter_segments("PT_LOAD"):
print(" Writing segment. Address: %8x Size: %x" % (seg.header["p_paddr"], seg.header["p_memsz"]))
program_segment(dev, seg.header["p_paddr"], seg.header["p_memsz"], seg.data(), not chip_erase, not no_verify)
print(
" Writing segment. Address: %8x Size: %x" % (seg.header["p_paddr"], seg.header["p_memsz"])
)
program_segment(
dev, seg.header["p_paddr"], seg.header["p_memsz"], seg.data(), not chip_erase, not no_verify
)

if fuses:
print("Writing fuses")
Expand All @@ -109,9 +125,9 @@ def program(programmer, flash=None, no_verify=False, chip_erase=True, detect=Fal
print("Resetting...")
adapter.SetSignal("TCK", True)

adapter.SRST('0')
adapter.SRST("0")
time.sleep(0.1)
adapter.SRST('z')
adapter.SRST("z")

adapter.SetSignal("TCK", False)
finally:
Expand All @@ -120,29 +136,44 @@ def program(programmer, flash=None, no_verify=False, chip_erase=True, detect=Fal

def main():
parser = argparse.ArgumentParser()
parser.add_argument("--programmer", "-p", default="digilent_hs3", type=str, choices=ADAPTERS.keys(), help="Which JTAG adapter to use")
parser.add_argument(
"--programmer",
"-p",
default="digilent_hs3",
type=str,
choices=ADAPTERS.keys(),
help="Which JTAG adapter to use",
)
parser.add_argument("--chip_erase", "-E", action="store_true", help="Perform full chip erase.")
parser.add_argument("--reset", "-R", action="store_true", help="Perform chip reset after programming.")
parser.add_argument("--dump", "-D", metavar="filename", default=None, type=str, help="Read the current FLASH contents (if not protected) out into a binary file.")
parser.add_argument(
"--dump",
"-D",
metavar="filename",
default=None,
type=str,
help="Read the current FLASH contents (if not protected) out into a binary file.",
)
parser.add_argument("--detect", "-d", action="store_true", help="Do detection of devices on JTAG bus")
parser.add_argument("--flash", "-f", default=None, type=str, help="Path to ELF file to be programmed")
parser.add_argument("--no-verify", "-V", action="store_true", help="Skip verifying flash")
parser.add_argument("--fuses", "-GP", default=None, type=str, help="Program fuses")
parser.add_argument("--verbose", "-v",action="store_true", help="Verbose log output")
parser.add_argument("--verbose", "-v", action="store_true", help="Verbose log output")
args = parser.parse_args()

level = logging.DEBUG if args.verbose else logging.INFO
del args.verbose

logging.basicConfig(
filename='log_file_name.log',
filename="hs3program.log",
level=level,
format= '[%(asctime)s] %(name)s %(levelname)s - %(message)s',
datefmt='%H:%M:%S'
format="[%(asctime)s] %(name)s %(levelname)s - %(message)s",
datefmt="%H:%M:%S",
)
logging.root.setLevel(level)

program(**vars(args))


if __name__ == "__main__":
main()
main()
Loading

0 comments on commit 80ff66e

Please sign in to comment.