From c9b74898f30ba1218e2e683151fb082d3bc35fd5 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 6 Apr 2012 23:23:11 +0200 Subject: Move chip algorithms to submodule Signed-off-by: Michael Buesch --- libtoprammer/chips/_74hc4094.py | 150 +++++++++++ libtoprammer/chips/__init__.py | 15 ++ libtoprammer/chips/at27c256r.py | 82 ++++++ libtoprammer/chips/at89c2051dip20.py | 230 +++++++++++++++++ libtoprammer/chips/atmega32dip40.py | 47 ++++ libtoprammer/chips/atmega88dip28.py | 47 ++++ libtoprammer/chips/atmega8dip28.py | 79 ++++++ libtoprammer/chips/atmega_common.py | 465 +++++++++++++++++++++++++++++++++++ libtoprammer/chips/attiny13dip8.py | 358 +++++++++++++++++++++++++++ libtoprammer/chips/attiny26dip20.py | 48 ++++ libtoprammer/chips/generic_sram.py | 122 +++++++++ libtoprammer/chips/hm62256dip28.py | 45 ++++ libtoprammer/chips/m24cxxdip8.py | 260 ++++++++++++++++++++ libtoprammer/chips/m2764a.py | 173 +++++++++++++ libtoprammer/chips/m8cissp.py | 457 ++++++++++++++++++++++++++++++++++ libtoprammer/chips/unitest.py | 171 +++++++++++++ libtoprammer/chips/w29ee011dip32.py | 254 +++++++++++++++++++ 17 files changed, 3003 insertions(+) create mode 100644 libtoprammer/chips/_74hc4094.py create mode 100644 libtoprammer/chips/__init__.py create mode 100644 libtoprammer/chips/at27c256r.py create mode 100644 libtoprammer/chips/at89c2051dip20.py create mode 100644 libtoprammer/chips/atmega32dip40.py create mode 100644 libtoprammer/chips/atmega88dip28.py create mode 100644 libtoprammer/chips/atmega8dip28.py create mode 100644 libtoprammer/chips/atmega_common.py create mode 100644 libtoprammer/chips/attiny13dip8.py create mode 100644 libtoprammer/chips/attiny26dip20.py create mode 100644 libtoprammer/chips/generic_sram.py create mode 100644 libtoprammer/chips/hm62256dip28.py create mode 100644 libtoprammer/chips/m24cxxdip8.py create mode 100644 libtoprammer/chips/m2764a.py create mode 100644 libtoprammer/chips/m8cissp.py create mode 100644 libtoprammer/chips/unitest.py create mode 100644 libtoprammer/chips/w29ee011dip32.py (limited to 'libtoprammer/chips') diff --git a/libtoprammer/chips/_74hc4094.py b/libtoprammer/chips/_74hc4094.py new file mode 100644 index 0000000..e04d63e --- /dev/null +++ b/libtoprammer/chips/_74hc4094.py @@ -0,0 +1,150 @@ +""" +# TOP2049 Open Source programming suite +# +# 74HC4094 unit-tester +# +# Copyright (c) 2011 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from unitest import * + +class Chip_74hc4094(Chip_Unitest): + def __init__(self): + Chip_Unitest.__init__(self, chipPackage="DIP16", + chipPinVCC=16, + chipPinGND=8, + VCCVoltage=5) + + def __initChip(self): + self.zifPin_STR = self.generator.getZifPinForPackagePin(1) + self.zifPin_D = self.generator.getZifPinForPackagePin(2) + self.zifPin_CP = self.generator.getZifPinForPackagePin(3) + self.zifPin_OE = self.generator.getZifPinForPackagePin(15) + self.zifPin_QS1 = self.generator.getZifPinForPackagePin(9) + self.zifPin_QS2 = self.generator.getZifPinForPackagePin(10) + self.zifPins_QP = [] + for packagePin in (4, 5, 6, 7, 14, 13, 12, 11): + self.zifPins_QP.append( + self.generator.getZifPinForPackagePin(packagePin)) + + self.reset() + + outen = 0 + for zifPin in (self.zifPin_STR, self.zifPin_D, + self.zifPin_CP, self.zifPin_OE): + outen |= (1 << (zifPin - 1)) + self.setOutputEnableMask(outen) + + self.applyGND(True) + self.applyVCC(True) + + def test(self): + testPatterns = (0xFF, 0x00, 0xAA, 0x55, 0xF0, 0x0F, + 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00) + + self.progressMeterInit("Logic test", len(testPatterns)) + self.__initChip() + + # Initialize the register to all-zero + self.setOutputs(self.__makeOutMask(STR=0, D=0, CP=0, OE=0)) + for i in range(0, 9): + self.setOutputs(self.__makeOutMask(STR=0, D=0, CP=1, OE=0)) + self.setOutputs(self.__makeOutMask(STR=0, D=0, CP=0, OE=0)) + self.setOutputs(self.__makeOutMask(STR=1, D=0, CP=0, OE=0)) + self.setOutputs(self.__makeOutMask(STR=0, D=0, CP=0, OE=1)) + + QP = self.__readQP() + if QP != 0x00: + self.throwError("Failed to clear the shiftregister. Got 0x%02X" % QP) + + prevContents = 0x00 + prev_QS1 = False + count = 0 + for testPattern in testPatterns: + self.progressMeter(count) + self.setOutputs(self.__makeOutMask(STR=0, D=0, CP=0, OE=0)) + for bitNr in range(7, -1, -1): # MSB first + self.setOutputs(self.__makeOutMask(STR=0, + D=(testPattern & (1 << bitNr)), + CP=0, OE=0)) + self.setOutputs(self.__makeOutMask(STR=0, D=0, CP=1, OE=0)) + (QS1, QS2) = self.__readQS() + word = (prevContents << 8) | testPattern + expect_QS1 = bool(word & (1 << (bitNr + 7))) + expect_QS2 = prev_QS1 + prev_QS1 = expect_QS1 + if QS1 != expect_QS1 or QS2 != expect_QS2: + self.throwError("Got invalid QS serial output for " + "test pattern 0x%02X bit %d. Got %d/%d, but " + "expected %d/%d" %\ + (testPattern, bitNr, QS1, QS2, + expect_QS1, expect_QS2)) + self.setOutputs(self.__makeOutMask(STR=0, D=0, CP=0, OE=0)) + self.setOutputs(self.__makeOutMask(STR=1, D=0, CP=0, OE=0)) + self.setOutputs(self.__makeOutMask(STR=0, D=0, CP=0, OE=1)) + + QP = self.__readQP() + if QP != testPattern: + self.throwError("Failed on test pattern 0x%02X. Got 0x%02X" %\ + (testPattern, QP)) + + prevContents = testPattern + count += 1 + self.progressMeterFinish() + + def __makeOutMask(self, STR, D, CP, OE): + mask = 0 + if STR: + mask |= (1 << (self.zifPin_STR - 1)) + if D: + mask |= (1 << (self.zifPin_D - 1)) + if CP: + mask |= (1 << (self.zifPin_CP - 1)) + if OE: + mask |= (1 << (self.zifPin_OE - 1)) + return mask + + def __readQP(self): + QPValue = 0 + count = 0 + inputs = self.getInputs() + for zifPin in self.zifPins_QP: + if inputs & (1 << (zifPin - 1)): + QPValue |= (1 << count) + count += 1 + return QPValue + + def __readQS(self): + QS1 = False + QS2 = False + inputs = self.getInputs() + if inputs & (1 << (self.zifPin_QS1 - 1)): + QS1 = True + if inputs & (1 << (self.zifPin_QS2 - 1)): + QS2 = True + return (QS1, QS2) + +ChipDescription( + Chip_74hc4094, + chipID = "74hc4094dip16", + bitfile = "unitest", + runtimeID = (0x0008, 0x01), + chipType = ChipDescription.TYPE_LOGIC, + description = "74HC(T)4094 shift-register", + chipVendors = ("Philips", "Other"), +) diff --git a/libtoprammer/chips/__init__.py b/libtoprammer/chips/__init__.py new file mode 100644 index 0000000..32ee95d --- /dev/null +++ b/libtoprammer/chips/__init__.py @@ -0,0 +1,15 @@ +# Import all chip modules in alphabetical order +from _74hc4094 import * +from at27c256r import * +from at89c2051dip20 import * +from atmega32dip40 import * +from atmega8dip28 import * +from atmega88dip28 import * +from attiny13dip8 import * +from attiny26dip20 import * +from hm62256dip28 import * +from m24cxxdip8 import * +from m2764a import * +from m8cissp import * +from unitest import * +from w29ee011dip32 import * diff --git a/libtoprammer/chips/at27c256r.py b/libtoprammer/chips/at27c256r.py new file mode 100644 index 0000000..9dff427 --- /dev/null +++ b/libtoprammer/chips/at27c256r.py @@ -0,0 +1,82 @@ +""" +# TOP2049 Open Source programming suite +# +# Atmel AT27C256R EPROM +# +# Copyright (c) 2012 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from libtoprammer.chip import * + + +class Chip_at27c256r(Chip): + def __init__(self): + Chip.__init__(self, + chipPackage = "DIP28", + chipPinVCC = 28, + chipPinsVPP = 1, + chipPinGND = 14) + self.sizeBytes = 32 * 1024 + self.generic = GenericAlgorithms(self) + self.addrSetter = AddrSetter(self, 0x10, 0x11) + + def readEEPROM(self): + self.__turnOn() + return self.generic.simpleReadEPROM( + sizeBytes = self.sizeBytes, + readData8Func = self.__dataRead, + addrSetter = self.addrSetter, + initFunc = lambda: self.__setFlags(oe=0, ce=0), + exitFunc = lambda: self.__setFlags(oe=1, ce=1) + ) + +# def writeEEPROM(self): +# pass#TODO + + def __turnOn(self): + self.__setFlags() + self.generic.simpleVoltageSetup() + + def __setDataPins(self, value): + self.top.cmdFPGAWrite(0x12, value) + + def __setFlags(self, data_en=0, prog_en=0, ce=1, oe=1): + value = 0 + if data_en: + value |= (1 << 0) + if prog_en: + value |= (1 << 1) + if ce: + value |= (1 << 2) + if oe: + value |= (1 << 3) + self.top.cmdFPGAWrite(0x13, value) + + def __progPulse(self): + self.top.cmdFPGAWrite(0x14, 0) + + def __dataRead(self): + self.top.cmdFPGARead(0x10) + +ChipDescription(Chip_at27c256r, + bitfile = "at27c256r", + runtimeID = (0x000C, 0x01), + chipType = ChipDescription.TYPE_EPROM, + chipVendors = "Atmel", + description = "AT27C256R", + packages = ( ("DIP28", ""), ) +) diff --git a/libtoprammer/chips/at89c2051dip20.py b/libtoprammer/chips/at89c2051dip20.py new file mode 100644 index 0000000..c23a89d --- /dev/null +++ b/libtoprammer/chips/at89c2051dip20.py @@ -0,0 +1,230 @@ +""" +# TOP2049 Open Source programming suite +# +# Atmel AT89C2051 DIP20 Support +# +# Copyright (c) 2010 Guido +# Copyright (c) 2010 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from libtoprammer.chip import * + + +class Chip_AT89C2051dip20(Chip): + STAT_BUSY = 0x01 # Programmer is running a command + STAT_ERR = 0x02 # Error during write + + def __init__(self): + Chip.__init__(self, + chipPackage = "DIP20", + chipPinVCC = 20, + chipPinsVPP = 1, + chipPinGND = 10) + + def __initChip(self): + self.applyVCC(False) + self.applyVPP(False) + self.applyGND(True) + self.top.cmdSetVCCVoltage(5) + self.top.cmdSetVPPVoltage(5) + + def readSignature(self): + self.__initChip() + self.applyGND(True) + self.applyVCC(True) + self.top.cmdSetVPPVoltage(5) + self.__loadCommand(5) # VPP on + self.__loadCommand(1) # set P3.2 + self.__setP3x(P33=0, P34=0, P35=0, IA=0) + data = "" + self.top.cmdFPGARead(0x10) + self.__setP3x(P33=0, P34=0, P35=0, IA=1) + self.__setP3x(P33=0, P34=0, P35=0, IA=0) + self.top.cmdFPGARead(0x10) + self.__setP3x(P33=0, P34=0, P35=0, IA=1) + self.__setP3x(P33=0, P34=0, P35=0, IA=0) + self.top.cmdFPGARead(0x10) + data += self.top.cmdReadBufferReg() + self.__setP3x(P33=0, P34=1, P35=0, IA=0) + self.__loadCommand(6) # VPP off + signature = "" + signature += data[0] + signature += data[1] + self.top.printInfo("Signature: %X, %X" % (byte2int(signature[0]), byte2int(signature[1]))) + return signature + + def erase(self): + self.__initChip() + self.applyGND(True) + self.applyVCC(True) + self.__loadCommand(1) # set P3.2 + self.top.cmdSetVPPVoltage(5) + self.applyVPP(True) + self.__loadCommand(5) # VPP on + self.__setP3x(P33=1, P34=0, P35=0, IA=0) + self.top.cmdSetVPPVoltage(12) + self.__runCommandSync(4) + self.applyVPP(False) + self.top.cmdSetVPPVoltage(5) + self.__setP3x(P33=0, P34=1, P35=0, IA=0) + self.__loadCommand(5) # VPP off + self.top.flushCommands() + self.top.printInfo("at89c2051dip20: Erasing flash, verifying ...") + ok = self.__verifyErase() + if ok == 0: + self.top.printInfo("at89c2051dip20: Erase done.") + else: + self.top.printInfo("at89c2051dip20: Erase failed!") + + def readProgmem(self): + self.__initChip() + self.applyGND(True) + self.applyVCC(True) + self.__loadCommand(1) # set P3.2 + self.top.cmdSetVPPVoltage(5) + self.applyVPP(True) + self.__loadCommand(5) # VPP on + self.__setP3x(P33=0, P34=0, P35=1, IA=0) + image = "" + byteCount = 0 + self.progressMeterInit("Reading Flash", 0x800) + for addr in range(0, 0x800): + self.progressMeter(addr) + self.top.cmdFPGARead(0x10) + self.__setP3x(P33=0, P34=0, P35=1, IA=1) + self.__setP3x(P33=0, P34=0, P35=1, IA=0) + byteCount += 1 + if byteCount == self.top.getBufferRegSize(): + image += self.top.cmdReadBufferReg(byteCount) + byteCount = 0 + image += self.top.cmdReadBufferReg(byteCount) + self.applyVPP(False) + self.__setP3x(P33=0, P34=1, P35=0, IA=0) + self.__loadCommand(5) # VPP off + self.top.flushCommands() + self.progressMeterFinish() + + return image + + def writeProgmem(self, image): + if len(image) > 0x800: + self.throwError("Invalid EPROM image size %d (expected <=%d)" %\ + (len(image), 0x800)) + self.__initChip() + self.applyGND(True) + self.applyVCC(True) + self.__loadCommand(1) # set P3.2 + self.top.cmdSetVPPVoltage(5) + self.applyVPP(True) + self.__loadCommand(5) # VPP on + self.__setP3x(P33=0, P34=1, P35=1, IA=0) + self.top.cmdSetVPPVoltage(12) + self.progressMeterInit("Writing Flash", len(image)) + for addr in range(0, len(image)): + self.progressMeter(addr) + data = byte2int(image[addr]) + if data != 0xFF: + self.__loadData(data) + self.__loadCommand(3) + ok = self.__progWait() + if (ok & self.STAT_ERR) != 0: + self.throwError("Write byte failed.") + self.__setP3x(P33=0, P34=1, P35=1, IA=1) + self.__setP3x(P33=0, P34=1, P35=1, IA=0) + self.applyVPP(False) + self.top.cmdSetVPPVoltage(5) + self.__setP3x(P33=0, P34=1, P35=0, IA=0) + self.__loadCommand(5) # VPP off + self.top.flushCommands() + self.progressMeterFinish() + ok = self.__verifyProgmem(image) + if ok == 0: + self.top.printInfo("at89c2051dip20: Write flash done.") + else: + self.top.printInfo("at89c2051dip20: Write flash failed!") + + def __verifyErase(self): + ok = 0 + image = self.readProgmem() + for addr in range(0, 0x800): + if byte2int(image[addr]) != 0xFF: + ok = 1 + return ok + + def __verifyProgmem(self,image): + data = self.readProgmem() + ok = 0 + for addr in range(0, 0x800): + if byte2int(image[addr]) != byte2int(data[addr]): + ok = 1 + return ok + + def __loadData(self, data): + self.top.cmdFPGAWrite(0x10, data) + + def __loadCommand(self, command): + self.top.cmdFPGAWrite(0x12, command & 0xFF) + + def __runCommandSync(self, command): + self.__loadCommand(command) + self.__busyWait() + + def __setP3x(self, P33, P34, P35, IA): + data = 0 + if P33: + data |= 1 + if P34: + data |= 2 + if P35: + data |= 4 + if IA: + data |= 8 + self.top.cmdFPGAWrite(0x16, data) + + def __getStatusFlags(self): + self.top.cmdFPGARead(0x12) + stat = self.top.cmdReadBufferReg() + return byte2int(stat[0]) + + def __busy(self): + return bool(self.__getStatusFlags() & self.STAT_BUSY) + + def __busyWait(self): + for i in range(0, 26): + if not self.__busy(): + return + self.top.hostDelay(0.001) + self.throwError("Timeout in busywait.") + + def __progWait(self): + for i in range(0,4): + self.top.cmdFPGARead(0x12) + stat = self.top.cmdReadBufferReg() + if (byte2int(stat[0]) & self.STAT_BUSY) == 0: + return byte2int(stat[0]) + self.top.hostDelay(0.001) + self.throwError("Timeout in busywait.") + +ChipDescription( + Chip_AT89C2051dip20, + bitfile = "at89c2051dip20", + runtimeID = (0x0005, 0x01), + chipVendors = "Atmel", + description = "AT89C2051", + maintainer = None, + packages = ( ("DIP20", ""), ) +) diff --git a/libtoprammer/chips/atmega32dip40.py b/libtoprammer/chips/atmega32dip40.py new file mode 100644 index 0000000..486cec3 --- /dev/null +++ b/libtoprammer/chips/atmega32dip40.py @@ -0,0 +1,47 @@ +""" +# TOP2049 Open Source programming suite +# +# Atmel Mega32 DIP40 support +# +# Copyright (c) 2009-2010 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from atmega_common import * + + +class Chip_ATMega32DIP40(Chip_ATMega_common): + def __init__(self): + Chip_ATMega_common.__init__(self, + chipPackage = "DIP40", + chipPinVCC = 10, + chipPinsVPP = 9, + chipPinGND = 11, + signature = "\x1E\x95\x02", + flashPageSize = 64, + flashPages = 256, + eepromPageSize = 4, + eepromPages = 256) + +ChipDescription( + Chip_ATMega32DIP40, + bitfile = "atmega32dip40", + runtimeID = (0x0004, 0x01), + chipVendors = "Atmel", + description = "AtMega32", + packages = ( ("DIP40", ""), ), + comment = "Insert upside down into ZIF socket" +) diff --git a/libtoprammer/chips/atmega88dip28.py b/libtoprammer/chips/atmega88dip28.py new file mode 100644 index 0000000..de1fc2b --- /dev/null +++ b/libtoprammer/chips/atmega88dip28.py @@ -0,0 +1,47 @@ +""" +# TOP2049 Open Source programming suite +# +# Atmel Mega88 DIP28 support +# +# Copyright (c) 2009-2010 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from atmega_common import * + + +class Chip_ATMega88DIP28(Chip_ATMega_common): + def __init__(self): + Chip_ATMega_common.__init__(self, + chipPackage = "DIP28", + chipPinVCC = 7, + chipPinsVPP = 1, + chipPinGND = 8, + signature = "\x1E\x93\x0A", + flashPageSize = 32, + flashPages = 128, + eepromPageSize = 4, + eepromPages = 128) + +ChipDescription( + Chip_ATMega88DIP28, + bitfile = "atmega8dip28", + chipID = "atmega88dip28", + runtimeID = (0x0003, 0x01), + chipVendors = "Atmel", + description = "AtMega88", + packages = ( ("DIP28", ""), ), +) diff --git a/libtoprammer/chips/atmega8dip28.py b/libtoprammer/chips/atmega8dip28.py new file mode 100644 index 0000000..6b680bb --- /dev/null +++ b/libtoprammer/chips/atmega8dip28.py @@ -0,0 +1,79 @@ +""" +# TOP2049 Open Source programming suite +# +# Atmel Mega8 DIP28 support +# +# Copyright (c) 2009-2010 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from atmega_common import * + + +class Chip_ATMega8DIP28(Chip_ATMega_common): + def __init__(self): + Chip_ATMega_common.__init__(self, + chipPackage = "DIP28", + chipPinVCC = 7, + chipPinsVPP = 1, + chipPinGND = 8, + signature = "\x1E\x93\x07", + flashPageSize = 32, + flashPages = 128, + eepromPageSize = 4, + eepromPages = 128) + +fuseDesc = ( + BitDescription(0, "CKSEL0"), + BitDescription(1, "CKSEL1"), + BitDescription(2, "CKSEL2"), + BitDescription(3, "CKSEL3"), + BitDescription(4, "SUT0"), + BitDescription(5, "SUT1"), + BitDescription(6, "BODEN"), + BitDescription(7, "BODLEVEL"), + BitDescription(8, "BOOTRST"), + BitDescription(9, "BOOTSZ0"), + BitDescription(10, "BOOTSZ1"), + BitDescription(11, "EESAVE"), + BitDescription(12, "CKOPT"), + BitDescription(13, "SPIEN"), + BitDescription(14, "WDTON"), + BitDescription(15, "RSTDISBL"), +) + +lockbitDesc = ( + BitDescription(0, "LB1"), + BitDescription(1, "LB2"), + BitDescription(2, "BLB01"), + BitDescription(3, "BLB02"), + BitDescription(4, "BLB11"), + BitDescription(5, "BLB12"), + BitDescription(6, "Unused"), + BitDescription(7, "Unused"), + BitDescription(8, "Unused"), +) + +ChipDescription( + Chip_ATMega8DIP28, + bitfile = "atmega8dip28", + runtimeID = (0x0003, 0x01), + chipVendors = "Atmel", + description = "AtMega8", + fuseDesc = fuseDesc, + lockbitDesc = lockbitDesc, + packages = ( ("DIP28", ""), ) +) diff --git a/libtoprammer/chips/atmega_common.py b/libtoprammer/chips/atmega_common.py new file mode 100644 index 0000000..1609528 --- /dev/null +++ b/libtoprammer/chips/atmega_common.py @@ -0,0 +1,465 @@ +""" +# TOP2049 Open Source programming suite +# +# Implements the Atmel Mega MCU parallel HV programming algorithm +# +# Copyright (c) 2009-2010 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from libtoprammer.chip import * + + +class Chip_ATMega_common(Chip): + # The Atmel Mega programming commands + CMD_CHIPERASE = 0x80 # Chip Erase + CMD_WRITEFUSE = 0x40 # Write Fuse Bits + CMD_WRITELOCK = 0x20 # Write Lock Bits + CMD_WRITEFLASH = 0x10 # Write Flash + CMD_WRITEEEPROM = 0x11 # Write EEPROM + CMD_READSIG = 0x08 # Read Signature bytes and Calibration byte + CMD_READFUSELOCK = 0x04 # Read Fuse and Lock bits + CMD_READFLASH = 0x02 # Read Flash + CMD_READEEPROM = 0x03 # Read EEPROM + + def __init__(self, + chipPackage, chipPinVCC, chipPinsVPP, chipPinGND, + signature, + flashPageSize, flashPages, + eepromPageSize, eepromPages + ): + Chip.__init__(self, + chipPackage = chipPackage, + chipPinVCC = chipPinVCC, + chipPinsVPP = chipPinsVPP, + chipPinGND = chipPinGND) + self.signature = signature + self.flashPageSize = flashPageSize # Flash page size, in words + self.flashPages = flashPages # Nr of flash pages + self.eepromPageSize = eepromPageSize # EEPROM page size, in bytes + self.eepromPages = eepromPages # Nr of EEPROM pages + + def readSignature(self): + self.__enterPM() + + (signature, calibration) = self.__readSigAndCalib() + + return signature + + def erase(self): + self.__enterPM() + + self.progressMeterInit("Erasing chip", 0) + self.__loadCommand(self.CMD_CHIPERASE) + self.__pulseWR() + self.__waitForRDY() + self.progressMeterFinish() + + def readProgmem(self): + self.__enterPM() + + self.progressMeterInit("Reading Flash", self.flashPages) + image = "" + for page in range(0, self.flashPages): + self.progressMeter(page) + readWords = 0 + for word in range(0, self.flashPageSize): + self.__loadCommand(self.CMD_READFLASH) + self.__loadAddr((page * self.flashPageSize) + word) + self.__readWordToStatusReg() + readWords += 1 + if readWords >= 32: + image += self.top.cmdReadBufferReg() + readWords = 0 + if readWords: + data = self.top.cmdReadBufferReg() + image += data[0:readWords*2] + self.progressMeterFinish() + return image + + def writeProgmem(self, image): + flashBytes = self.flashPageSize * 2 * self.flashPages + if len(image) != flashBytes: + self.throwError("Invalid program memory image size %d (expected %d)" %\ + (len(image), flashBytes)) + self.__enterPM() + + self.progressMeterInit("Writing Flash", self.flashPages) + for page in range(0, self.flashPages): + self.progressMeter(page) + for word in range(0, self.flashPageSize): + self.__loadCommand(self.CMD_WRITEFLASH) + addr = (page * self.flashPageSize) + word + self.__loadAddr(addr) + addr *= 2 + data = image[addr : addr + 2] + self.__loadData(byte2int(data[0]) | (byte2int(data[1]) << 8)) + self.__setBS1(1) + self.__pulsePAGEL() + self.__setBS1(0) + self.__pulseWR() + self.__waitForRDY() + self.progressMeterFinish() + + def readEEPROM(self): + self.__enterPM() + + assert(self.eepromPageSize <= self.top.getBufferRegSize()) + self.progressMeterInit("Reading EEPROM", self.eepromPages) + image = "" + for page in range(0, self.eepromPages): + self.progressMeter(page) + for byte in range(0, self.eepromPageSize): + self.__loadCommand(self.CMD_READEEPROM) + self.__loadAddr((page * self.eepromPageSize) + byte) + self.__readLowByteToStatusReg() + data = self.top.cmdReadBufferReg() + image += data[0:self.eepromPageSize] + self.progressMeterFinish() + return image + + def writeEEPROM(self, image): + eepromBytes = self.eepromPageSize * self.eepromPages + if len(image) != eepromBytes: + self.throwError("Invalid EEPROM image size %d (expected %d)" %\ + (len(image), eepromBytes)) + self.__enterPM() + + self.progressMeterInit("Writing EEPROM", self.eepromPages) + for page in range(0, self.eepromPages): + self.progressMeter(page) + for byte in range(0, self.eepromPageSize): + self.__loadCommand(self.CMD_WRITEEEPROM) + addr = (page * self.eepromPageSize) + byte + self.__loadAddr(addr) + data = image[addr] + self.__loadDataLow(byte2int(data[0])) + self.__pulsePAGEL() + self.__setBS1(0) + self.__pulseWR() + self.__waitForRDY() + self.progressMeterFinish() + + def readFuse(self): + self.__enterPM() + + self.progressMeterInit("Reading Fuse bits", 0) + (fuse, lock) = self.__readFuseAndLockBits() + self.progressMeterFinish() + return fuse + + def writeFuse(self, image): + if len(image) != 2: + self.throwError("Invalid Fuses image size %d (expected %d)" %\ + (len(image), 2)) + self.__enterPM() + + self.progressMeterInit("Writing Fuse bits", 0) + self.__loadCommand(self.CMD_WRITEFUSE) + self.__setBS2(0) + self.__loadDataLow(byte2int(image[0])) + self.__pulseWR() + self.__waitForRDY() + self.__loadCommand(self.CMD_WRITEFUSE) + self.__loadDataLow(byte2int(image[1])) + self.__setBS1(1) + self.__pulseWR() + self.__waitForRDY() + self.progressMeterFinish() + + def readLockbits(self): + self.__enterPM() + + self.progressMeterInit("Reading lock bits", 0) + (fuses, lockbits) = self.__readFuseAndLockBits() + self.progressMeterFinish() + + return lockbits + + def writeLockbits(self, image): + if len(image) != 1: + self.throwError("Invalid lock-bits image size %d (expected %d)" %\ + (len(image), 1)) + self.__enterPM() + + self.progressMeterInit("Writing lock bits", 0) + self.__loadCommand(self.CMD_WRITELOCK) + self.__loadDataLow(byte2int(image[0])) + self.__pulseWR() + self.__waitForRDY() + self.progressMeterFinish() + + def __readSigAndCalib(self): + """Reads the signature and calibration bytes and returns them. + This function expects a DUT present and pins initialized.""" + signature = "" + calibration = "" + for addr in range(0, 3): + self.__loadCommand(self.CMD_READSIG) + self.__loadAddr(addr) + self.__readWordToStatusReg() + data = self.top.cmdReadBufferReg() + if addr == 0: + calibration += data[1] + signature += data[0] + return (signature, calibration) + + def __readFuseAndLockBits(self): + """Reads the Fuse and Lock bits and returns them. + This function expects a DUT present and pins initialized.""" + self.__loadCommand(self.CMD_READFUSELOCK) + self.__setBS2(0) + self.__readWordToStatusReg() + self.__setBS2(1) + self.__readWordToStatusReg() + self.__setBS2(0) + data = self.top.cmdReadBufferReg() + fuses = data[0] + data[3] + lock = data[1] + return (fuses, lock) + + def __enterPM(self): + "Enter HV programming mode." + self.applyVPP(False) + self.applyVCC(False) + self.applyGND(True) + self.top.cmdSetVPPVoltage(0) + self.top.cmdSetVPPVoltage(12) + self.top.cmdSetVCCVoltage(5) + + self.__setVoltageControl(VPP_en=1, VPP=0, VCC_en=1, VCC=0) + self.__setXA0(0) + self.__setXA1(0) + self.__setBS1(0) + self.__setPAGEL(0) + self.__setWR(0) + self.top.hostDelay(0.1) + + self.applyVCC(True) + self.__setVoltageControl(VPP_en=1, VPP=0, VCC_en=1, VCC=1) + self.top.hostDelay(0.1) + + self.__setOE(0) + self.__setWR(1) + self.__setXTAL1(0) + self.__setXA0(0) + self.__setXA1(0) + self.__setBS1(0) + self.__setBS2(0) + self.__setPAGEL(0) + self.__pulseXTAL1(10) + self.top.flushCommands() + + self.__setVoltageControl(VPP_en=0, VPP=0, VCC_en=1, VCC=1) + self.applyVPP(True) + + self.__setOE(1) + + (signature, calibration) = self.__readSigAndCalib() + if signature != self.signature: + msg = "Unexpected device signature. " +\ + "Want %02X%02X%02X, but got %02X%02X%02X" % \ + (byte2int(self.signature[0]), byte2int(self.signature[1]), + byte2int(self.signature[2]), + byte2int(signature[0]), byte2int(signature[1]), + byte2int(signature[2])) + if self.top.getForceLevel() >= 1: + self.printWarning(msg) + else: + self.throwError(msg) + + def __readWordToStatusReg(self): + """Read a data word from the DUT into the status register.""" + self.__setBS1(0) + self.__setOE(0) + self.top.cmdFPGARead(0x10) + self.__setBS1(1) + self.top.cmdFPGARead(0x10) + self.__setOE(1) + + def __readLowByteToStatusReg(self): + """Read the low data byte from the DUT into the status register.""" + self.__setBS1(0) + self.__setOE(0) + self.top.cmdFPGARead(0x10) + self.__setOE(1) + + def __readHighByteToStatusReg(self): + """Read the high data byte from the DUT into the status register.""" + self.__setBS1(1) + self.__setOE(0) + self.top.cmdFPGARead(0x10) + self.__setOE(1) + + def __loadData(self, data): + """Load a data word.""" + self.__loadDataLow(data) + self.__loadDataHigh(data >> 8) + + def __loadDataLow(self, dataLow): + """Load the low data byte.""" + self.__setBS1(0) + self.__setXA0(1) + self.__setXA1(0) + self.top.cmdFPGAWrite(0x10, dataLow & 0xFF) + self.__pulseXTAL1() + + def __loadDataHigh(self, dataHigh): + """Load the high data byte.""" + self.__setBS1(1) + self.__setXA0(1) + self.__setXA1(0) + self.top.cmdFPGAWrite(0x10, dataHigh & 0xFF) + self.__pulseXTAL1() + + def __loadAddr(self, addr): + """Load an address word.""" + self.__loadAddrLow(addr) + self.__loadAddrHigh(addr >> 8) + + def __loadAddrLow(self, addrLow): + """Load the low address byte.""" + self.__setBS1(0) + self.__setXA0(0) + self.__setXA1(0) + self.top.cmdFPGAWrite(0x10, addrLow & 0xFF) + self.__pulseXTAL1() + + def __loadAddrHigh(self, addrHigh): + """Load the high address byte.""" + self.__setBS1(1) + self.__setXA0(0) + self.__setXA1(0) + self.top.cmdFPGAWrite(0x10, addrHigh & 0xFF) + self.__pulseXTAL1() + + def __loadCommand(self, command): + """Load a command into the device.""" +# self.top.queueCommand("\x34") + self.__setBS1(0) +# self.top.queueCommand("\x34") + self.__setXA0(0) + self.__setXA1(1) + self.top.cmdFPGAWrite(0x10, command) + self.__pulseXTAL1() + + def __waitForRDY(self): + """Wait for the RDY pin to go high.""" + self.top.hostDelay(0.01) + for i in range(0, 50): + if self.__getRDY(): + return + self.top.hostDelay(0.01) + self.throwError("Timeout waiting for READY signal from chip.") + + def __getRDY(self): + """Read the state of the RDY/BSY pin.""" + return bool(self.__getStatus() & 0x01) + + def __getStatus(self): + """Read the programmer status register""" + self.top.cmdFPGARead(0x12) + stat = self.top.cmdReadBufferReg() + return byte2int(stat[0]) + + def __setOE(self, high): + """Set the OE pin of the DUT""" + value = 0x02 + if high: + value |= 0x80 + self.top.cmdFPGAWrite(0x12, value) + + def __setWR(self, high): + """Set the WR pin of the DUT""" + value = 0x03 + if high: + value |= 0x80 + self.top.cmdFPGAWrite(0x12, value) + + def __pulseWR(self, count=1): + """Do a negative pulse on the WR pin of the DUT""" + while count > 0: + self.__setWR(0) + self.__setWR(1) + count -= 1 + + def __setBS1(self, high): + """Set the BS1 pin of the DUT""" + value = 0x04 + if high: + value |= 0x80 + self.top.cmdFPGAWrite(0x12, value) + + def __setXA0(self, high): + """Set the XA0 pin of the DUT""" + value = 0x05 + if high: + value |= 0x80 + self.top.cmdFPGAWrite(0x12, value) + + def __setXA1(self, high): + """Set the XA1 pin of the DUT""" + value = 0x06 + if high: + value |= 0x80 + self.top.cmdFPGAWrite(0x12, value) + + def __setXTAL1(self, high): + """Set the XTAL1 pin of the DUT""" + value = 0x07 + if high: + value |= 0x80 + self.top.cmdFPGAWrite(0x12, value) + + def __pulseXTAL1(self, count=1): + """Do a positive pulse on the XTAL1 pin of the DUT""" + while count > 0: + self.__setXTAL1(1) + self.__setXTAL1(0) + count -= 1 + + def __setPAGEL(self, high): + """Set the PAGEL pin of the DUT""" + value = 0x09 + if high: + value |= 0x80 + self.top.cmdFPGAWrite(0x12, value) + + def __pulsePAGEL(self, count=1): + """Do a positive pulse on the PAGEL pin of the DUT""" + while count > 0: + self.__setPAGEL(1) + self.__setPAGEL(0) + count -= 1 + + def __setBS2(self, high): + """Set the BS2 pin of the DUT""" + value = 0x0A + if high: + value |= 0x80 + self.top.cmdFPGAWrite(0x12, value) + + def __setVoltageControl(self, VPP_en, VPP, VCC_en, VCC): + value = 0 + if VPP_en: + value |= 0x01 + if VPP: + value |= 0x02 + if VCC_en: + value |= 0x04 + if VCC: + value |= 0x08 + self.top.cmdFPGAWrite(0x11, value) diff --git a/libtoprammer/chips/attiny13dip8.py b/libtoprammer/chips/attiny13dip8.py new file mode 100644 index 0000000..bacd3b7 --- /dev/null +++ b/libtoprammer/chips/attiny13dip8.py @@ -0,0 +1,358 @@ +""" +# TOP2049 Open Source programming suite +# +# Atmel Tiny13 DIP8 +# +# Copyright (c) 2010 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from libtoprammer.chip import * + + +class Chip_AtTiny13dip8(Chip): + PROGCMD_SENDINSTR = 1 # Send an instruction to the chip + + STAT_BUSY = 0x01 # Programmer is running a command + STAT_SDO = 0x02 # Raw SDO pin state + + def __init__(self): + Chip.__init__(self, + chipPackage = "DIP8", + chipPinVCC = 8, + chipPinsVPP = 1, + chipPinGND = 4) + self.signature = "\x1E\x90\x07" + self.flashPageSize = 16 + self.flashPages = 32 + self.eepromPageSize = 4 + self.eepromPages = 16 + + def readSignature(self): + self.__enterPM() + self.progressMeterInit("Reading signature", 0) + signature = self.__readSignature() + self.progressMeterFinish() + return signature + + def erase(self): + self.__enterPM() + self.progressMeterInit("Erasing chip", 0) + self.__sendInstr(SDI=0x80, SII=0x4C) + self.__sendInstr(SDI=0x00, SII=0x64) + self.__sendInstr(SDI=0x00, SII=0x6C) + self.__waitHighSDO() + self.__sendNOP() + self.progressMeterFinish() + + def readProgmem(self): + nrWords = self.flashPages * self.flashPageSize + image = "" + self.__enterPM() + self.progressMeterInit("Reading flash", nrWords) + self.__sendReadFlashInstr() + currentHigh = -1 + bufferedBytes = 0 + for word in range(0, nrWords): + self.progressMeter(word) + low = word & 0xFF + high = (word >> 8) & 0xFF + self.__sendInstr(SDI=low, SII=0x0C) + if high != currentHigh: + self.__sendInstr(SDI=high, SII=0x1C) + currentHigh = high + self.__sendInstr(SDI=0x00, SII=0x68) + self.__sendInstr(SDI=0x00, SII=0x6C) + self.__readSDOBufferHigh() + bufferedBytes += 1 + self.__sendInstr(SDI=0x00, SII=0x78) + self.__sendInstr(SDI=0x00, SII=0x7C) + self.__readSDOBufferHigh() + bufferedBytes += 1 + if bufferedBytes == self.top.getBufferRegSize(): + image += self.top.cmdReadBufferReg(bufferedBytes) + bufferedBytes = 0 + image += self.top.cmdReadBufferReg(bufferedBytes) + self.progressMeterFinish() + return image + + def writeProgmem(self, image): + nrWords = self.flashPages * self.flashPageSize + if len(image) > nrWords * 2 or len(image) % 2 != 0: + self.throwError("Invalid flash image size %d (expected <=%d and word aligned)" %\ + (len(image), nrWords * 2)) + self.__enterPM() + self.progressMeterInit("Writing flash", len(image) // 2) + self.__sendWriteFlashInstr() + currentHigh = -1 + for word in range(0, len(image) // 2): + self.progressMeter(word) + low = word & 0xFF + high = (word >> 8) & 0xFF + self.__sendInstr(SDI=low, SII=0x0C) + self.__sendInstr(SDI=byte2int(image[word * 2 + 0]), SII=0x2C) + self.__sendInstr(SDI=byte2int(image[word * 2 + 1]), SII=0x3C) + self.__sendInstr(SDI=0x00, SII=0x7D) + self.__sendInstr(SDI=0x00, SII=0x7C) + if ((word + 1) % self.flashPageSize == 0) or word == len(image) // 2 - 1: + if currentHigh != high: + self.__sendInstr(SDI=high, SII=0x1C) + currentHigh = high + self.__sendInstr(SDI=0x00, SII=0x64) + self.__sendInstr(SDI=0x00, SII=0x6C) + self.__waitHighSDO() + self.__sendNOP() + self.progressMeterFinish() + + def readEEPROM(self): + nrBytes = self.eepromPages * self.eepromPageSize + image = "" + self.__enterPM() + self.progressMeterInit("Reading EEPROM", nrBytes) + self.__sendReadEEPROMInstr() + currentPage = -1 + bufferedBytes = 0 + for i in range(0, nrBytes): + self.progressMeter(i) + low = i & 0xFF + high = (i >> 8) & 0xFF + self.__sendInstr(SDI=low, SII=0x0C) + if currentPage != high: + self.__sendInstr(SDI=high, SII=0x1C) + currentPage = high + self.__sendInstr(SDI=0x00, SII=0x68) + self.__sendInstr(SDI=0x00, SII=0x6C) + self.__readSDOBufferHigh() + bufferedBytes += 1 + if bufferedBytes == self.top.getBufferRegSize(): + image += self.top.cmdReadBufferReg(bufferedBytes) + bufferedBytes = 0 + image += self.top.cmdReadBufferReg(bufferedBytes) + self.progressMeterFinish() + return image + + def writeEEPROM(self, image): + nrBytes = self.eepromPages * self.eepromPageSize + if len(image) > nrBytes: + self.throwError("Invalid EEPROM image size %d (expected <=%d)" %\ + (len(image), nrBytes)) + self.__enterPM() + self.progressMeterInit("Writing EEPROM", len(image)) + self.__sendWriteEEPROMInstr() + for i in range(0, len(image)): + self.progressMeter(i) + self.__sendInstr(SDI=i, SII=0x0C) + self.__sendInstr(SDI=byte2int(image[i]), SII=0x2C) + self.__sendInstr(SDI=0x00, SII=0x6D) + self.__sendInstr(SDI=0x00, SII=0x6C) + if ((i + 1) % self.eepromPageSize == 0) or i == len(image) - 1: + self.__sendInstr(SDI=0x00, SII=0x64) + self.__sendInstr(SDI=0x00, SII=0x6C) + self.__waitHighSDO() + self.__sendNOP() + self.progressMeterFinish() + + def readFuse(self): + fuses = [] + self.__enterPM() + self.progressMeterInit("Reading fuses", 0) + self.__sendInstr(SDI=0x04, SII=0x4C) + self.__sendInstr(SDI=0x00, SII=0x68) + self.__sendInstr(SDI=0x00, SII=0x6C) + self.__readSDOBufferHigh() + fuses.append(self.top.cmdReadBufferReg(1)) + self.__sendInstr(SDI=0x04, SII=0x4C) + self.__sendInstr(SDI=0x00, SII=0x7A) + self.__sendInstr(SDI=0x00, SII=0x7E) + self.__readSDOBufferHigh() + fuses.append(int2byte(self.top.cmdReadBufferReg8() | 0xE0)) + self.progressMeterFinish() + return b"".join(fuses) + + def writeFuse(self, image): + if len(image) != 2: + self.throwError("Invalid Fuses image size %d (expected %d)" %\ + (len(image), 2)) + self.__enterPM() + self.progressMeterInit("Writing fuses", 0) + self.__sendInstr(SDI=0x40, SII=0x4C) + self.__sendInstr(SDI=byte2int(image[0]), SII=0x2C) + self.__sendInstr(SDI=0x00, SII=0x64) + self.__sendInstr(SDI=0x00, SII=0x6C) + self.__waitHighSDO() + self.__sendInstr(SDI=0x40, SII=0x4C) + self.__sendInstr(SDI=(byte2int(image[1]) & 0x1F), SII=0x2C) + self.__sendInstr(SDI=0x00, SII=0x74) + self.__sendInstr(SDI=0x00, SII=0x7C) + self.__waitHighSDO() + self.progressMeterFinish() + + def readLockbits(self): + self.__enterPM() + self.progressMeterInit("Reading lockbits", 0) + self.__sendInstr(SDI=0x04, SII=0x4C) + self.__sendInstr(SDI=0x00, SII=0x78) + self.__sendInstr(SDI=0x00, SII=0x7C) + self.__readSDOBufferHigh() + lockbits = int2byte(self.top.cmdReadBufferReg8() | 0xFC) + self.progressMeterFinish() + return lockbits + + def writeLockbits(self, image): + if len(image) != 1: + self.throwError("Invalid Lockbits image size %d (expected %d)" %\ + (len(image), 1)) + self.__enterPM() + self.progressMeterInit("Writing lockbits", 0) + self.__sendInstr(SDI=0x20, SII=0x4C) + self.__sendInstr(SDI=(byte2int(image[0]) & 3), SII=0x2C) + self.__sendInstr(SDI=0x00, SII=0x64) + self.__sendInstr(SDI=0x00, SII=0x6C) + self.__waitHighSDO() + self.progressMeterFinish() + + def __readSignature(self): + self.__sendInstr(SDI=0x08, SII=0x4C) + for i in range(0, 3): + self.__sendInstr(SDI=i, SII=0x0C) + self.__sendInstr(SDI=0x00, SII=0x68) + self.__sendInstr(SDI=0x00, SII=0x6C) + self.__readSDOBufferHigh() + return self.top.cmdReadBufferReg()[0:3] + + def __enterPM(self): + "Enter HV programming mode." + self.applyVCC(False) + self.applyVPP(False) + self.applyGND(False) + self.top.cmdSetVCCVoltage(5) + self.top.cmdSetVPPVoltage(0) + self.top.cmdSetVPPVoltage(12) + self.applyGND(True) + self.applyVCC(True) + + self.__setPins(SCI=0, SDO_en=0, RST_en=1, RST=0) + for i in range(0, 6): + self.__setPins(SCI=0, SDO_en=0, RST_en=1, RST=0) + self.__setPins(SCI=1, SDO_en=0, RST_en=1, RST=0) + self.__setPins(SCI=0, SDO_en=1, SDO=0, RST_en=1, RST=0) + self.top.hostDelay(0.001) + self.__setPins(SDO_en=1, SDO=0, RST_en=0) + self.applyVPP(True) + self.top.hostDelay(0.001) + self.__setPins(SDO_en=0) + self.top.hostDelay(0.01) + + signature = self.__readSignature() + if signature != self.signature: + msg = "Unexpected device signature. " +\ + "Want %02X%02X%02X, but got %02X%02X%02X" % \ + (byte2int(self.signature[0]), byte2int(self.signature[1]), + byte2int(self.signature[2]), + byte2int(signature[0]), byte2int(signature[1]), + byte2int(signature[2])) + if self.top.getForceLevel() >= 1: + self.printWarning(msg) + else: + self.throwError(msg) + + def __sendReadEEPROMInstr(self): + self.__sendInstr(SDI=0x03, SII=0x4C) + + def __sendWriteEEPROMInstr(self): + self.__sendInstr(SDI=0x11, SII=0x4C) + + def __sendReadFlashInstr(self): + self.__sendInstr(SDI=0x02, SII=0x4C) + + def __sendWriteFlashInstr(self): + self.__sendInstr(SDI=0x10, SII=0x4C) + + def __sendNOP(self): + self.__sendInstr(SDI=0x00, SII=0x4C) + + def __sendInstr(self, SDI, SII): + self.__setSDI(SDI) + self.__setSII(SII) + self.__loadCommand(self.PROGCMD_SENDINSTR) + # We do not poll the busy flag, because that would result + # in a significant slowdown. We delay long enough for the + # command to finish execution, instead. + self.top.hostDelay(0.001) + + def __setSDI(self, sdi): + self.top.cmdFPGAWrite(0x13, sdi & 0xFF) + + def __setSII(self, sii): + self.top.cmdFPGAWrite(0x14, sii & 0xFF) + + def __loadCommand(self, command): + self.top.cmdFPGAWrite(0x12, command & 0xFF) + + def __runCommandSync(self, command): + self.__loadCommand(command) + self.__busyWait() + + def __setPins(self, SCI=0, SDO_en=0, SDO=0, RST_en=0, RST=0): + data = 0 + if SCI: + data |= 1 + if SDO_en: + data |= 2 + if SDO: + data |= 4 + if RST_en: + data |= 8 + if RST: + data |= 16 + self.top.cmdFPGAWrite(0x15, data) + + def __getStatusFlags(self): + self.top.cmdFPGARead(0x12) + stat = self.top.cmdReadBufferReg() + return byte2int(stat[0]) + + def __readSDOBufferHigh(self): + self.top.cmdFPGARead(0x10) + + def __rawSDOState(self): + return bool(self.__getStatusFlags() & self.STAT_SDO) + + def __busy(self): + return bool(self.__getStatusFlags() & self.STAT_BUSY) + + def __busyWait(self): + for i in range(0, 100): + if not self.__busy(): + return + self.top.hostDelay(0.01) + self.throwError("Timeout in busywait.") + + def __waitHighSDO(self): + for i in range(0, 100): + if self.__rawSDOState(): + return + self.top.hostDelay(0.01) + self.throwError("Timeout waiting for SDO.") + +ChipDescription( + Chip_AtTiny13dip8, + bitfile = "attiny13dip8", + runtimeID = (0x0001, 0x01), + chipVendors = "Atmel", + description = "AtTiny13", + packages = ( ("DIP8", ""), ), +) diff --git a/libtoprammer/chips/attiny26dip20.py b/libtoprammer/chips/attiny26dip20.py new file mode 100644 index 0000000..0faaa63 --- /dev/null +++ b/libtoprammer/chips/attiny26dip20.py @@ -0,0 +1,48 @@ +""" +# TOP2049 Open Source programming suite +# +# Atmel Tiny26 DIP20 support +# +# Copyright (c) 2009-2010 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from atmega_common import * + + +class Chip_ATTiny26DIP20(Chip_ATMega_common): + def __init__(self): + Chip_ATMega_common.__init__(self, + chipPackage = "DIP20", + chipPinVCC = 5, + chipPinsVPP = 10, + chipPinGND = 6, + signature = "\x1E\x91\x09", + flashPageSize = 16, + flashPages = 64, + eepromPageSize = 4, + eepromPages = 32) + +ChipDescription( + Chip_ATTiny26DIP20, + bitfile = "attiny26dip20", + runtimeID = (0x0002, 0x01), + chipVendors = "Atmel", + description = "AtTiny26", + packages = ( ("DIP20", ""), ), + comment = "Special ZIF position", + broken = True +) diff --git a/libtoprammer/chips/generic_sram.py b/libtoprammer/chips/generic_sram.py new file mode 100644 index 0000000..29ba860 --- /dev/null +++ b/libtoprammer/chips/generic_sram.py @@ -0,0 +1,122 @@ +""" +# TOP2049 Open Source programming suite +# +# Generic SRAM chip +# +# Copyright (c) 2011 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from libtoprammer.chip import * + + +class Chip_genericSRAM(Chip): + def __init__(self, chipPackage, chipPinVCC, chipPinGND, + VCCVoltage, + nrAddressBits, nrDataBits): + Chip.__init__(self, + chipPackage = chipPackage, + chipPinVCC = chipPinVCC, + chipPinGND = chipPinGND) + self.VCCVoltage = VCCVoltage + self.nrAddressBits = nrAddressBits + self.nrAddressBytes = int(math.ceil((float(self.nrAddressBits) - 0.1) / 8)) + self.nrDataBits = nrDataBits + assert(nrDataBits == 8) + + def erase(self): + self.writeRAM(int2byte(0) * self.__sizeBytes()) + + def test(self): + generic = GenericAlgorithms(self) + generic.simpleTest(self.readRAM, self.writeRAM, + self.__sizeBytes()) + + def readRAM(self): + image = [] + + self.progressMeterInit("Reading SRAM", self.__sizeBytes()) + self.__turnOnChip() + self.__setControlPins(CE=0, OE=0, WE=1) + nrBytes = 0 + for addr in range(0, self.__sizeBytes()): + self.progressMeter(addr) + self.__setAddress(addr) + self.__readData() + nrBytes += 1 + if nrBytes == self.top.getBufferRegSize(): + image.append(self.top.cmdReadBufferReg(nrBytes)) + nrBytes = 0 + image.append(self.top.cmdReadBufferReg(nrBytes)) + self.__setControlPins(CE=1, OE=1, WE=1) + self.progressMeterFinish() + + return b"".join(image) + + def writeRAM(self, image): + if len(image) > self.__sizeBytes(): + self.throwError("Invalid memory image size %d (expected max %d)" %\ + (len(image), self.__sizeBytes())) + + self.progressMeterInit("Writing SRAM", self.__sizeBytes()) + self.__turnOnChip() + self.__setControlPins(CE=0, OE=1, WE=1) + for addr in range(0, len(image)): + self.progressMeter(addr) + self.__setAddress(addr) + self.__writeData(image[addr]) + self.__setControlPins(CE=0, OE=1, WE=0) + self.top.cmdDelay(0.00000007) # Delay at least 70 nsec + self.__setControlPins(CE=0, OE=1, WE=1) + self.__setControlPins(CE=1, OE=1, WE=1) + self.progressMeterFinish() + + def __sizeBytes(self): + return (1 << self.nrAddressBits) + + def __turnOnChip(self): + self.__setControlPins(CE=1, OE=1, WE=1) + self.top.cmdSetVCCVoltage(self.VCCVoltage) + self.applyGND(True) + self.applyVCC(True) + self.lastAddress = None + + def __setControlPins(self, CE=1, OE=1, WE=1): + value = 0 + if CE: + value |= 1 + if OE: + value |= 2 + if WE: + value |= 4 + self.top.cmdFPGAWrite(0x11, value) + + def __writeData(self, data): + data = byte2int(data) + self.top.cmdFPGAWrite(0x10, data) + + def __readData(self): + self.top.cmdFPGARead(0x10) + + def __setAddress(self, addr): + for i in range(0, self.nrAddressBytes): + shift = 8 * i + mask = 0xFF << shift + if self.lastAddress is None or\ + (self.lastAddress & mask) != (addr & mask): + self.top.cmdFPGAWrite(0x12 + i, + (addr & mask) >> shift) + self.lastAddress = addr diff --git a/libtoprammer/chips/hm62256dip28.py b/libtoprammer/chips/hm62256dip28.py new file mode 100644 index 0000000..708c5a9 --- /dev/null +++ b/libtoprammer/chips/hm62256dip28.py @@ -0,0 +1,45 @@ +""" +# TOP2049 Open Source programming suite +# +# HM62256 DIP28 SRAM support +# +# Copyright (c) 2011 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from generic_sram import * + + +class Chip_HM62256DIP28(Chip_genericSRAM): + def __init__(self): + Chip_genericSRAM.__init__(self, + chipPackage = "DIP28", + chipPinVCC = 28, + chipPinGND = 14, + VCCVoltage = 5, + nrAddressBits = 15, + nrDataBits = 8, + ) + +ChipDescription( + Chip_HM62256DIP28, + bitfile = "hm62256dip28", + runtimeID = (0x000A, 0x01), + chipType = ChipDescription.TYPE_SRAM, + chipVendors = "S@Tech", + description = "HM62256 SRAM", + packages = ( ("DIP28", ""), ) +) diff --git a/libtoprammer/chips/m24cxxdip8.py b/libtoprammer/chips/m24cxxdip8.py new file mode 100644 index 0000000..8d3f156 --- /dev/null +++ b/libtoprammer/chips/m24cxxdip8.py @@ -0,0 +1,260 @@ +""" +# TOP2049 Open Source programming suite +# +# M24C16 I2C based serial EEPROM +# +# Copyright (c) 2011 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from libtoprammer.chip import * + + +class Chip_m24cXXdip8_common(Chip): + CMD_DEVSEL_READ = 0 + CMD_DEVSEL_WRITE = 1 + CMD_SETADDR = 2 + CMD_DATA_READ = 3 + CMD_DATA_READ_STOP = 4 + CMD_DATA_WRITE = 5 + CMD_DATA_WRITE_STOP = 6 + + def __init__(self, eepromSize): + Chip.__init__(self, + chipPackage = "DIP8", + chipPinVCC = 8, + chipPinGND = 4) + self.eepromSize = eepromSize # in bytes + + def __chipTurnOn(self): + self.top.cmdSetVCCVoltage(5) + self.top.cmdSetVPPVoltage(5) + self.applyVCC(True) + self.applyVPP(False) + self.applyGND(True) + self.top.cmdEnableZifPullups(True) + + self.currentAddrExt = None + + def erase(self): + self.writeEEPROM("\xFF" * self.eepromSize) + + def readEEPROM(self): + self.__chipTurnOn() + + image = "" + count = 0 + prevAddr = None + self.progressMeterInit("Reading EEPROM", self.eepromSize) + for addr in range(0, self.eepromSize): + self.progressMeter(addr) + if prevAddr is None or (prevAddr & 0xFF00) != (addr & 0xFF00): + self.__setAddress(addr, writeMode=False) + self.__runCommand(self.CMD_DEVSEL_WRITE) + self.__runCommand(self.CMD_SETADDR) + self.__runCommand(self.CMD_DEVSEL_READ) + self.__runCommand(self.CMD_DATA_READ_STOP) + prevAddr = addr + else: + self.__runCommand(self.CMD_DEVSEL_READ) + self.__runCommand(self.CMD_DATA_READ_STOP) + self.__readData() + count += 1 + if count == self.top.getBufferRegSize(): + image += self.top.cmdReadBufferReg(count) + count = 0 + image += self.top.cmdReadBufferReg(count) + self.progressMeterFinish() + + return image + + def writeEEPROM(self, image): + if len(image) > self.eepromSize: + self.throwError("Invalid EEPROM image size %d (expected <=%d)" %\ + (len(image), self.eepromSize)) + self.__chipTurnOn() + + self.progressMeterInit("Writing EEPROM", len(image)) + prevAddr = None + for addr in range(0, len(image)): + self.progressMeter(addr) + self.__setData(byte2int(image[addr])) + if prevAddr is None or (prevAddr & 0xFFF0) != (addr & 0xFFF0): + self.__setAddress(addr, writeMode=True) + self.__runCommand(self.CMD_DEVSEL_WRITE, busyWait=True) + self.__runCommand(self.CMD_SETADDR, busyWait=True) + self.__runCommand(self.CMD_DATA_WRITE, busyWait=True) + prevAddr = addr + else: + if (addr & 0xF) == 0xF: + self.__runCommand(self.CMD_DATA_WRITE_STOP, busyWait=True) + else: + self.__runCommand(self.CMD_DATA_WRITE, busyWait=True) + self.progressMeterFinish() + + def __readData(self): + self.top.cmdFPGARead(0x10) + + def __setData(self, dataByte): + self.top.cmdFPGAWrite(0x12, dataByte & 0xFF) + + def __setAddress(self, address, writeMode): + # Address base + self.top.cmdFPGAWrite(0x11, address & 0xFF) + # Address extension + sizeMask = self.eepromSize - 1 + assert(sizeMask & ~0x7FF == 0) + addrExt = address & 0x700 & sizeMask + if self.currentAddrExt != addrExt: + self.currentAddrExt = addrExt + if sizeMask & 0x0100: + E0 = addrExt & 0x0100 + E0_en = 0 + else: + E0 = 0 + E0_en = 1 + if sizeMask & 0x0200: + E1 = addrExt & 0x0200 + E1_en = 0 + else: + E1 = 0 + E1_en = 1 + if sizeMask & 0x0400: + E2 = addrExt & 0x0400 + E2_en = 0 + else: + E2 = 0 + E2_en = 1 + if writeMode: + WC = 0 + else: + WC = 1 + self.__setControlPins(E0=E0, E0_en=E0_en, + E1=E1, E1_en=E1_en, + E2=E2, E2_en=E2_en, + WC=WC) + + def __runCommand(self, command, busyWait=False): + self.top.cmdFPGAWrite(0x10, command & 0xFF) + if busyWait: + self.__busyWait() + else: + # We do not read busy flags, but wait long enough for + # the operation to finish. This is safe for eeprom read. + self.top.cmdDelay(0.00009) + + def __isBusy(self): + (busy0, busy1) = self.__getStatusFlags() + return busy0 != busy1 + + def __busyWait(self): + for i in range(0, 100): + if not self.__isBusy(): + return + self.top.hostDelay(0.001) + self.throwError("Timeout in busywait.") + + def __getStatusFlags(self): + self.top.cmdFPGARead(0x11) + stat = self.top.cmdReadBufferReg8() + busy0 = bool(stat & 0x01) + busy1 = bool(stat & 0x02) + return (busy0, busy1) + + def __setControlPins(self, E0, E0_en, E1, E1_en, E2, E2_en, WC): + value = 0 + if E0: + value |= (1 << 0) + if E0_en: + value |= (1 << 1) + if E1: + value |= (1 << 2) + if E1_en: + value |= (1 << 3) + if E2: + value |= (1 << 4) + if E2_en: + value |= (1 << 5) + if WC: + value |= (1 << 6) + self.top.cmdFPGAWrite(0x13, value) + +class Chip_m24c01dip8(Chip_m24cXXdip8_common): + def __init__(self): + Chip_m24cXXdip8_common.__init__(self, eepromSize = 1024 * 1 // 8) + +class Chip_m24c02dip8(Chip_m24cXXdip8_common): + def __init__(self): + Chip_m24cXXdip8_common.__init__(self, eepromSize = 1024 * 2 // 8) + +class Chip_m24c04dip8(Chip_m24cXXdip8_common): + def __init__(self): + Chip_m24cXXdip8_common.__init__(self, eepromSize = 1024 * 4 // 8) + +class Chip_m24c08dip8(Chip_m24cXXdip8_common): + def __init__(self): + Chip_m24cXXdip8_common.__init__(self, eepromSize = 1024 * 8 // 8) + +class Chip_m24c16dip8(Chip_m24cXXdip8_common): + def __init__(self): + Chip_m24cXXdip8_common.__init__(self, eepromSize = 1024 * 16 // 8) + +class ChipDescription_m24cXX(ChipDescription): + def __init__(self, chipImplClass, chipID, description): + ChipDescription.__init__(self, + chipImplClass = chipImplClass, + bitfile = "m24c16dip8", + chipID = chipID, + runtimeID = (0x000B, 0x01), + chipType = ChipDescription.TYPE_EEPROM, + chipVendors = "ST", + description = description, + packages = ( + ("DIP8", ""), + ("SO8", "With 1:1 adapter"), + ("TSSOP8", "With 1:1 adapter"), + ), + ) + +ChipDescription_m24cXX( + Chip_m24c01dip8, + chipID = "m24c01dip8", + description = "M24C01 I2C EEPROM", +) + +ChipDescription_m24cXX( + Chip_m24c02dip8, + chipID = "m24c02dip8", + description = "M24C02 I2C EEPROM", +) + +ChipDescription_m24cXX( + Chip_m24c04dip8, + chipID = "m24c04dip8", + description = "M24C04 I2C EEPROM", +) + +ChipDescription_m24cXX( + Chip_m24c08dip8, + chipID = "m24c08dip8", + description = "M24C08 I2C EEPROM", +) + +ChipDescription_m24cXX( + Chip_m24c16dip8, + chipID = "m24c16dip8", + description = "M24C16 I2C EEPROM", +) diff --git a/libtoprammer/chips/m2764a.py b/libtoprammer/chips/m2764a.py new file mode 100644 index 0000000..7eecbb9 --- /dev/null +++ b/libtoprammer/chips/m2764a.py @@ -0,0 +1,173 @@ +""" +# TOP2049 Open Source programming suite +# +# M2764A EPROM programmer +# +# Copyright (c) 2010 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from libtoprammer.chip import * + + +class Chip_M2764A(Chip): + PROGCMD_PPULSE = 1 # Perform a P-pulse + + STAT_BUSY = 0x01 # Programmer is running a command + + def __init__(self): + Chip.__init__(self, + chipPackage = "DIP28", + chipPinVCC = 28, + chipPinsVPP = 1, + chipPinGND = 14) + + def __initChip(self): + self.applyVCC(False) + self.applyVPP(False) + self.applyGND(False) + self.top.cmdSetVCCVoltage(5) + self.top.cmdSetVPPVoltage(0) + self.top.cmdSetVPPVoltage(5) + + def readEEPROM(self): + self.__initChip() + self.top.cmdSetVCCVoltage(5) + self.top.cmdSetVPPVoltage(5) + self.applyVCC(True) + self.applyVPP(True) + self.applyGND(True) + + image = "" + self.progressMeterInit("Reading EPROM", 0x2000) + self.__setEG(E=1, G=1) + byteCount = 0 + for addr in range(0, 0x2000): + self.progressMeter(addr) + self.__readDataToStatusReg(addr) + byteCount += 1 + if byteCount == self.top.getBufferRegSize(): + image += self.top.cmdReadBufferReg(byteCount) + byteCount = 0 + image += self.top.cmdReadBufferReg(byteCount) + self.__setEG(E=1, G=1) + self.progressMeterFinish() + + return image + + def writeEEPROM(self, image): + if len(image) > 0x2000: + self.throwError("Invalid EPROM image size %d (expected <=%d)" %\ + (len(image), 0x2000)) + + self.__initChip() + self.top.cmdSetVCCVoltage(5) + self.top.cmdSetVPPVoltage(12) + self.applyVCC(True) + self.applyVPP(True) + self.applyGND(True) + + self.progressMeterInit("Writing EPROM", len(image)) + self.__setEG(E=1, G=1) + for addr in range(0, len(image)): + self.progressMeter(addr) + data = byte2int(image[addr]) + if data != 0xFF: + self.__writeData(addr, data) + self.__setEG(E=1, G=1) + self.progressMeterFinish() + + def __readDataToStatusReg(self, addr): + self.__loadAddr(addr) + self.__setEG(E=0, G=0) + self.top.cmdFPGARead(0x10) + + def __writeData(self, addr, data): + self.__setEG(E=0, G=1) + self.__loadAddr(addr) + self.__loadData(data) + self.__loadPPulseLen(1) + self.__runCommandSync(self.PROGCMD_PPULSE) + for i in range(0, 25): + self.__readDataToStatusReg(addr) + stat = self.top.cmdReadBufferReg() + r = byte2int(stat[0]) + if r == data: + break + self.__setEG(E=0, G=1) + self.__runCommandSync(self.PROGCMD_PPULSE) + else: + self.throwError("Failed to program 0x%04X (got 0x%02X, expected 0x%02X)" %\ + (addr, r, data)) + self.__setEG(E=0, G=1) + self.__loadPPulseLen(3 * (i + 1)) + self.__runCommandSync(self.PROGCMD_PPULSE) + + def __loadData(self, data): + self.top.cmdFPGAWrite(0x10, data) + + def __loadCommand(self, command): + self.top.cmdFPGAWrite(0x12, command & 0xFF) + + def __runCommandSync(self, command): + self.__loadCommand(command) + self.__busyWait() + + def __loadAddrLow(self, addrLow): + self.top.cmdFPGAWrite(0x13, addrLow & 0xFF) + + def __loadAddrHigh(self, addrHigh): + self.top.cmdFPGAWrite(0x14, addrHigh & 0xFF) + + def __loadAddr(self, addr): + self.__loadAddrLow(addr) + self.__loadAddrHigh(addr >> 8) + + def __loadPPulseLen(self, msec): + self.top.cmdFPGAWrite(0x15, msec) + + def __setEG(self, E, G): + data = 0 + if E: + data |= 1 + if G: + data |= 2 + self.top.cmdFPGAWrite(0x16, data) + + def __getStatusFlags(self): + self.top.cmdFPGARead(0x12) + stat = self.top.cmdReadBufferReg() + return byte2int(stat[0]) + + def __busy(self): + return bool(self.__getStatusFlags() & self.STAT_BUSY) + + def __busyWait(self): + for i in range(0, 100): + if not self.__busy(): + return + self.top.hostDelay(0.01) + self.throwError("Timeout in busywait.") + +ChipDescription( + Chip_M2764A, + bitfile = "m2764a", + runtimeID = (0x0006, 0x01), + chipType = ChipDescription.TYPE_EPROM, + description = "M2764A EPROM", + maintainer = None, + packages = ( ("DIP28", ""), ), +) diff --git a/libtoprammer/chips/m8cissp.py b/libtoprammer/chips/m8cissp.py new file mode 100644 index 0000000..975a5ea --- /dev/null +++ b/libtoprammer/chips/m8cissp.py @@ -0,0 +1,457 @@ +""" +# TOP2049 Open Source programming suite +# +# Cypress M8C In System Serial Programmer +# +# Copyright (c) 2010-2011 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from libtoprammer.chip import * +import time + + +class Chip_M8C_ISSP(Chip): + ISSPCMD_POR = 1 # Perform a power-on-reset + ISSPCMD_PWROFF = 2 # Turn power off + ISSPCMD_EXEC = 3 # Do an "execute" transfer + + STAT_BUSY0 = 0x01 + STAT_BUSY1 = 0x02 + STAT_ISSPSTATE = 0x1C + STAT_ISSPSTATE_SHIFT = 2 + STAT_SDATA = 0x20 + + STRVEC_INIT1 = ( + "1100101010000000000111", + "0000000000000000000000", + "0000000000000000000000", + "0000000000000000000000", + "0000000000000000000000", + "0000000000000000000000", + "1101111011100010000111", + "1101111101000000000111", + "1101111011100000000111", + "1101111011100010000111", + "1101111111000000100111", + "1101110001000000100111", + "1101110000000000011111", + "1101111011100000000111", + "1001111100000111010111", + "1001111100100000011111", + "1001111101101000000111", + "1001111110000000000111", + "1001111111001010110111", + "1001111110100000001111", + "1001111111100000001111", + "1001111111110000000111", + "1101111011100010000111", + "1101110001000000000111", + "1101111111000000000111", + "1101110000000000000111", + "1101111011100000000111", + "1101111010000000011111", + "1101111010100000000111", + "1101111011000000000111", + "1101111100000000000111", + "1101111100100110000111", + ) + + STRVEC_INIT2 = ( + "1001111101000000000111", + "1101111000000000110111", + "1101111100000000000111", + "1101111111100010010111", + ) + + STRVEC_IDSETUP = ( + "1101111011100010000111", + "1101110000000000010111", + "1101111011100010000111", + "1101111101000000000111", + "1101111011100000000111", + "1101111011100010000111", + "1101111111000000100111", + "1101110001000000100111", + "1101110000000000011111", + "1101111011100000000111", + "1001111100000111010111", + "1001111100100000011111", + "1001111101101000000111", + "1001111110000000000111", + "1001111111001010110111", + "1001111110100000001111", + "1001111111100000001111", + "1001111111110000000111", + "1101111011100010000111", + "1101110001000000000111", + "1101111111000000000111", + "1101110000000000000111", + "1101111011100000000111", + "1101111010000000011111", + "1101111010100000000111", + "1101111011000000000111", + "1101111100000000000111", + "1101111100100110000111", + "1001111101000000000111", + "1101111000000000110111", + "1101111100000000000111", + "1101111111100010010111", + ) + + STRVEC_READBYTE = ( + "101aaaaaaaaZDDDDDDDDZ1", + ) + + STRVEC_WRITEBYTE = ( + "100aaaaaaaadddddddd111", + ) + + STRVEC_ERASEALL = ( + "1001111110000010101111", + "1001111111001010110111", + "1101111011100010000111", + "1101111101000000000111", + "1101111011100000000111", + "1101111011100010000111", + "1101111111000000100111", + "1101110001000000100111", + "1101110000000000011111", + "1101111011100000000111", + "1001111100000111010111", + "1001111100100000011111", + "1001111101101000000111", + "1001111110000000000111", + "1001111111001010110111", + "1001111110100000001111", + "1001111111100000001111", + "1001111111110000000111", + "1101111011100010000111", + "1101110001000000000111", + "1101111111000000000111", + "1101110000000000000111", + "1101111011100000000111", + "1101111010000000011111", + "1101111010100000000111", + "1101111011000000000111", + "1101111100000000000111", + "1101111100100110000111", + "1101111000000000101111", + "1101111100000000000111", + "1101111111100010010111", + ) + + STRVEC_SETBLKNUM = ( + "10011111010dddddddd111", + ) + + STRVEC_READBLK = ( + "1101111011100010000111", + "1101111101000000000111", + "1101111011100000000111", + "1101111011100010000111", + "1101111111000000100111", + "1101110001000000100111", + "1101110000000000011111", + "1101111011100000000111", + "1001111100000111010111", + "1001111100100000011111", + "1001111101101000000111", + "1001111110000000000111", + "1001111111001010110111", + "1001111110100000001111", + "1001111111100000001111", + "1001111111110000000111", + "1101111011100010000111", + "1101110001000000000111", + "1101111111000000000111", + "1101110000000000000111", + "1101111011100000000111", + "1101111010000000011111", + "1101111010100000000111", + "1101111011000000000111", + "1101111100000000000111", + "1101111100100110000111", + "1101111000000000001111", + "1101111100000000000111", + "1101111111100010010111", + ) + + STRVEC_WRITEBLK = ( + "1001111110001010100111", + "1001111111001010110111", + "1101111011100010000111", + "1101111101000000000111", + "1101111011100000000111", + "1101111011100010000111", + "1101111111000000100111", + "1101110001000000100111", + "1101110000000000011111", + "1101111011100000000111", + "1001111100000111010111", + "1001111100100000011111", + "1001111101101000000111", + "1001111110000000000111", + "1001111111001010110111", + "1001111110100000001111", + "1001111111100000001111", + "1001111111110000000111", + "1101111011100010000111", + "1101110001000000000111", + "1101111111000000000111", + "1101110000000000000111", + "1101111011100000000111", + "1101111010000000011111", + "1101111010100000000111", + "1101111011000000000111", + "1101111100000000000111", + "1101111100100110000111", + "1101111000000000010111", + "1101111100000000000111", + "1101111111100010010111", + ) + + STRVEC_READCHKSUM = ( + "10111111001ZDDDDDDDDZ1", + "10111111000ZDDDDDDDDZ1", + ) + + STRVEC_READID = ( + "10111111000ZDDDDDDDDZ1", + "10111111001ZDDDDDDDDZ1", + ) + + def __init__(self): + Chip.__init__(self) +# self.progmemSize = 1024 * 16 + self.progmemSize = 256#XXX + + def readSignature(self): + self.progressMeterInit("Reading chip ID", 0) + self.__powerOnReset() + gotID = self.__readID() + self.progressMeterFinish() + + return int2byte(gotID & 0xFF) + int2byte((gotID >> 8) & 0xFF) + + def erase(self): + self.progressMeterInit("Erasing chip", 0) + self.__powerOnReset() + self.__bitbangStringVectors(self.STRVEC_ERASEALL) + self.__runCommandSync(self.ISSPCMD_EXEC) + self.progressMeterFinish() + + def writeProgmem(self, image): + if len(image) > self.progmemSize or len(image) % 64 != 0: + self.throwError("Invalid program memory image size %d " + "(expected <=%d and multiple of 64)" %\ + (len(image), self.progmemSize)) + + self.progressMeterInit("Writing program memory", len(image)) + self.__powerOnReset() + for blknum in range(0, len(image) // 64): + for i in range(0, 64): + self.progressMeter(blknum * 64 + i) + self.__writeByte(i, byte2int(image[blknum * 64 + i])) + vec = self.__stringVectorReplace(self.STRVEC_SETBLKNUM[0], "d", blknum) + self.__bitbangStringVector(vec) + self.__bitbangStringVectors(self.STRVEC_WRITEBLK) + self.__runCommandSync(self.ISSPCMD_EXEC) + self.progressMeterFinish() + + def readProgmem(self): + self.progressMeterInit("Reading program memory", self.progmemSize) + self.__powerOnReset() + assert(self.progmemSize % 64 == 0) + image = [] + for blknum in range(0, self.progmemSize // 64): + vec = self.__stringVectorReplace(self.STRVEC_SETBLKNUM[0], "d", blknum) + self.__bitbangStringVector(vec) + self.__bitbangStringVectors(self.STRVEC_READBLK) + self.__runCommandSync(self.ISSPCMD_EXEC) + for i in range(0, 64): + self.progressMeter(blknum * 64 + i) + image.append(int2byte(self.__readByte(i))) + #FIXME return_code + self.progressMeterFinish() + return b"".join(image) + + def __powerDown(self): + "Turn the power to the device off" + self.printDebug("Powering device down...") + self.__runCommandSync(self.ISSPCMD_PWROFF) + self.top.hostDelay(5) + + def __powerOnReset(self): + "Perform a complete power-on-reset and initialization" + self.top.vcc.setLayoutMask(0) + self.top.vpp.setLayoutMask(0) + self.top.gnd.setLayoutMask(0) + self.top.cmdSetVCCVoltage(5) + self.top.cmdSetVPPVoltage(5) + + self.printDebug("Initializing supply power...") + self.top.gnd.setLayoutPins( (20,) ) + self.top.vcc.setLayoutPins( (21,) ) + +#FIXME when to do exec? + self.__powerDown() + self.printDebug("Performing a power-on-reset...") + self.__uploadStringVector(self.STRVEC_INIT1[0]) + self.__runCommandSync(self.ISSPCMD_POR) + self.printDebug("Sending vector 1...") + self.__bitbangStringVectors(self.STRVEC_INIT1[1:]) +#XXX self.__runCommandSync(self.ISSPCMD_EXEC) + self.printDebug("Sending vector 2...") + self.__bitbangStringVectors(self.STRVEC_INIT2) + self.__runCommandSync(self.ISSPCMD_EXEC) + + def __readID(self): + "Read the silicon ID" + self.__bitbangStringVectors(self.STRVEC_IDSETUP) + self.__runCommandSync(self.ISSPCMD_EXEC) + + low = (self.__bitbangStringVector(self.STRVEC_READID[0]) >> 2) & 0xFF + high = (self.__bitbangStringVector(self.STRVEC_READID[1]) >> 2) & 0xFF + + return low | (high << 8) + + def __readByte(self, address): + vec = self.__stringVectorReplace(self.STRVEC_READBYTE[0], "a", address) + inputData = self.__bitbangStringVector(vec) + return (inputData >> 2) & 0xFF + + def __writeByte(self, address, byte): + vec = self.__stringVectorReplace(self.STRVEC_WRITEBYTE[0], "a", address) + vec = self.__stringVectorReplace(vec, "d", byte) + self.__bitbangStringVector(vec) + + def __loadCommand(self, command): + self.top.cmdFPGAWrite(0x11, command & 0xFF) + + def __runCommandSync(self, command): + self.printDebug("Running synchronous command %d" % command) + self.__loadCommand(command) + self.__busyWait() + + def __setBitbang(self, SDATA, SDATA_in, SCLK, SCLK_z): + value = 0 + if SDATA: + value |= 0x01 + if SDATA_in: + value |= 0x02 + if SCLK: + value |= 0x04 + if SCLK_z: + value |= 0x08 + self.top.cmdFPGAWrite(0x10, value) + + def __getStatusFlags(self): + self.top.cmdFPGARead(0x10) + stat = self.top.cmdReadBufferReg8() + isspState = (stat & self.STAT_ISSPSTATE) >> self.STAT_ISSPSTATE_SHIFT + sdata = bool(stat & self.STAT_SDATA) + isBusy = bool(stat & self.STAT_BUSY0) != bool(stat & self.STAT_BUSY1) + self.printDebug("isspState = 0x%02X, isBusy = %d, busyFlags = 0x%01X, sdata = %d" %\ + (isspState, isBusy, (stat & (self.STAT_BUSY0 | self.STAT_BUSY1)), sdata)) + return (isBusy, sdata, isspState) + + def __busy(self): + (isBusy, sdata, isspState) = self.__getStatusFlags() + return isBusy + + def __getSDATA(self): + (isBusy, sdata, isspState) = self.__getStatusFlags() + return int(sdata) + + def __busyWait(self): + for i in range(0, 200): + if not self.__busy(): + return + self.top.hostDelay(0.01) + self.throwError("Timeout in busywait. Chip not responding?") + + def __stringVectorToBinary(self, vector): + binary = 0 + inputMask = 0 + assert(len(vector) == 22) + bit = len(vector) - 1 + for b in vector: + if b == "1": + binary |= (1 << bit) + elif b == "0": + pass + elif b == "H" or b == "L" or b == "Z" or b == "D": + inputMask |= (1 << bit) + else: + assert(0) + bit -= 1 + return (binary, inputMask) + + def __stringVectorReplace(self, strVec, replace, data): + ret = "" + for i in range(len(strVec) - 1, -1, -1): + b = strVec[i] + if b == replace: + if (data & 1): + ret = "1" + ret + else: + ret = "0" + ret + data >>= 1 + else: + ret = b + ret + return ret + + def __bitbangStringVector(self, strVec): + vectorSize = len(strVec) + (vector, inputMask) = self.__stringVectorToBinary(strVec) + inputData = 0 + self.__setBitbang(SDATA=0, SDATA_in=1, SCLK=0, SCLK_z=0) + for i in range(vectorSize - 1, -1, -1): + if inputMask & (1 << i): + self.__setBitbang(SDATA=0, SDATA_in=1, SCLK=1, SCLK_z=0) + self.__setBitbang(SDATA=0, SDATA_in=1, SCLK=0, SCLK_z=0) + self.top.cmdDelay(0.000001) + sdata = self.__getSDATA() + inputData |= (sdata << i) + else: + self.__setBitbang(SDATA=(vector & (1 << i)), SDATA_in=0, + SCLK=1, SCLK_z=0) + self.__setBitbang(SDATA=0, SDATA_in=0, SCLK=0, SCLK_z=0) + self.top.cmdDelay(0.000001) + return inputData + + def __bitbangStringVectors(self, strVecList): + for strVec in strVecList: + self.__bitbangStringVector(strVec) + + def __uploadStringVector(self, strVec): + (vector, inputMask) = self.__stringVectorToBinary(strVec) + assert(inputMask == 0) + self.top.cmdFPGAWrite(0x12, vector & 0xFF) + self.top.cmdFPGAWrite(0x13, (vector >> 8) & 0xFF) + self.top.cmdFPGAWrite(0x14, (vector >> 8) & 0xFF) + +ChipDescription( + Chip_M8C_ISSP, + bitfile = "m8c-issp", + runtimeID = (0x0007, 0x01), + chipVendors = "Cypress", + description = "M8C In System Serial Programmer", + packages = ( ("M8C ISSP header", "Special adapter"), ), + comment = "Special adapter required", + broken = True +) diff --git a/libtoprammer/chips/unitest.py b/libtoprammer/chips/unitest.py new file mode 100644 index 0000000..9f4cf87 --- /dev/null +++ b/libtoprammer/chips/unitest.py @@ -0,0 +1,171 @@ +""" +# TOP2049 Open Source programming suite +# +# Universal device tester +# +# Copyright (c) 2010 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from libtoprammer.chip import * + + +class Chip_Unitest(Chip): + def __init__(self, chipPackage=None, chipPinVCC=None, chipPinsVPP=None, chipPinGND=None, + VCCVoltage=None, VPPVoltage=None): + Chip.__init__(self, chipPackage=chipPackage, chipPinVCC=chipPinVCC, + chipPinsVPP=chipPinsVPP, chipPinGND=chipPinGND) + self.autogenVCCVoltage = VCCVoltage + self.autogenVPPVoltage = VPPVoltage + + def shutdownChip(self): + self.printDebug("Shutdown chip") + self.reset() + + def reset(self): + self.top.vcc.setLayoutPins( [] ) + self.vccMask = 0 + self.top.vpp.setLayoutPins( [] ) + self.vppMask = 0 + self.top.gnd.setLayoutPins( [] ) + self.gndMask = 0 + self.top.cmdSetVCCVoltage(self.top.vcc.minVoltage()) + self.top.cmdSetVPPVoltage(self.top.vpp.minVoltage()) + self.oscMask = 0 + self.setOutputEnableMask(0) + self.setOutputs(0) + self.setOscMask(0) + self.top.flushCommands() + + def setVCC(self, voltage, layout): + self.vccMask = self.top.vcc.ID2mask(layout) + self.__updateOutEn() + self.top.cmdSetVCCVoltage(voltage) + self.top.vcc.setLayoutID(layout) + self.top.flushCommands() + + def setVPP(self, voltage, layouts): + self.vppMask = 0 + for layout in layouts: + self.vppMask |= self.top.vpp.ID2mask(layout) + self.__updateOutEn() + self.top.cmdSetVPPVoltage(voltage) + self.top.vpp.setLayoutMask(0) # Reset + for layout in layouts: + self.top.vpp.setLayoutID(layout) + self.top.flushCommands() + + def setGND(self, layout): + self.gndMask = self.top.gnd.ID2mask(layout) + self.__updateOutEn() + self.top.gnd.setLayoutID(layout) + self.top.flushCommands() + + # Overloaded layout generator interface. + def applyVCC(self, turnOn): + layoutID = 0 + if turnOn: + (layoutID, layoutMask) = self.generator.getVCCLayout() + self.setVCC(self.autogenVCCVoltage, layoutID) + + # Overloaded layout generator interface. + def applyVPP(self, turnOn, packagePinsToTurnOn=[]): + assert(not packagePinsToTurnOn) # Not supported, yet. + layouts = [] + if turnOn: + layouts = map(lambda (layoutID, layoutMask): layoutID, + self.generator.getVPPLayouts()) + self.setVPP(self.autogenVPPVoltage, layouts) + + # Overloaded layout generator interface. + def applyGND(self, turnOn): + layoutID = 0 + if turnOn: + (layoutID, layoutMask) = self.generator.getGNDLayout() + self.setGND(layoutID) + + def __updateOutEn(self): + mask = self.desiredOutEnMask + mask &= ~self.gndMask + mask &= ~self.vccMask + mask &= ~self.vppMask + mask |= self.oscMask + self.top.cmdFPGAWrite(0x50, mask & 0xFF) + self.top.cmdFPGAWrite(0x51, (mask >> 8) & 0xFF) + self.top.cmdFPGAWrite(0x52, (mask >> 16) & 0xFF) + self.top.cmdFPGAWrite(0x53, (mask >> 24) & 0xFF) + self.top.cmdFPGAWrite(0x54, (mask >> 32) & 0xFF) + self.top.cmdFPGAWrite(0x55, (mask >> 40) & 0xFF) + self.top.flushCommands() + + def setOutputEnableMask(self, mask): + self.desiredOutEnMask = mask + self.__updateOutEn() + + def __updateOut(self): + mask = self.desiredOutMask + mask &= ~self.oscMask + self.top.cmdFPGAWrite(0x70, mask & 0xFF) + self.top.cmdFPGAWrite(0x71, (mask >> 8) & 0xFF) + self.top.cmdFPGAWrite(0x72, (mask >> 16) & 0xFF) + self.top.cmdFPGAWrite(0x73, (mask >> 24) & 0xFF) + self.top.cmdFPGAWrite(0x74, (mask >> 32) & 0xFF) + self.top.cmdFPGAWrite(0x75, (mask >> 40) & 0xFF) + self.top.flushCommands() + + def setOutputs(self, mask): + self.desiredOutMask = mask + self.__updateOut() + + def getInputs(self): + self.top.cmdFPGARead(0x30) + self.top.cmdFPGARead(0x31) + self.top.cmdFPGARead(0x32) + self.top.cmdFPGARead(0x33) + self.top.cmdFPGARead(0x34) + self.top.cmdFPGARead(0x35) + inputs = self.top.cmdReadBufferReg48() + return inputs + + def getOscFreq(self): + return self.top.getOscillatorHz() + + def setOscDivider(self, div): + self.top.cmdFPGAWrite(0x12, div & 0xFF) + self.top.cmdFPGAWrite(0x13, (div >> 8) & 0xFF) + self.top.cmdFPGAWrite(0x14, (div >> 16) & 0xFF) + self.top.cmdFPGAWrite(0x15, (div >> 24) & 0xFF) + self.top.flushCommands() + + def setOscMask(self, mask): + self.oscMask = mask + self.top.cmdFPGAWrite(0x30, mask & 0xFF) + self.top.cmdFPGAWrite(0x31, (mask >> 8) & 0xFF) + self.top.cmdFPGAWrite(0x32, (mask >> 16) & 0xFF) + self.top.cmdFPGAWrite(0x33, (mask >> 24) & 0xFF) + self.top.cmdFPGAWrite(0x34, (mask >> 32) & 0xFF) + self.top.cmdFPGAWrite(0x35, (mask >> 40) & 0xFF) + self.__updateOutEn() + self.__updateOut() + self.top.flushCommands() + +ChipDescription( + Chip_Unitest, + bitfile = "unitest", + runtimeID = (0x0008, 0x01), + chipType = ChipDescription.TYPE_INTERNAL, + description = "Universal device tester", +) diff --git a/libtoprammer/chips/w29ee011dip32.py b/libtoprammer/chips/w29ee011dip32.py new file mode 100644 index 0000000..0948c0f --- /dev/null +++ b/libtoprammer/chips/w29ee011dip32.py @@ -0,0 +1,254 @@ +""" +# TOP2049 Open Source programming suite +# +# Winbond W29EE011 DIP32 +# Winbond W29EE011 PLCC32 (inside 1:1 PLCC32->DIP32 adapter) +# +# Copyright (c) 2010 Michael Buesch +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from libtoprammer.chip import * + + +class Chip_w29ee011dip32(Chip): + PROGCMD_WRITEBUF = 1 # Write buffer to chip + + STAT_BUSY = 0x01 # Programmer is running a command + + def __init__(self): + Chip.__init__(self, + chipPackage = "DIP32", + chipPinVCC = 32, + chipPinsVPP = None, + chipPinGND = 16) + + def erase(self): + self.applyVCC(True) + self.applyVPP(True) + self.applyGND(True) + + commands = ( + (0x5555, 0xAA), + (0x2AAA, 0x55), + (0x5555, 0x80), + (0x5555, 0xAA), + (0x2AAA, 0x55), + (0x5555, 0x10), + ) + + self.progressMeterInit("Erasing chip", 0) + self.__setCEOE(CE=0, OE=1) + + self.__resetBufferPointers() + self.__swDataProtect(False) + self.__runCommandSync(self.PROGCMD_WRITEBUF) + self.top.hostDelay(0.05) + self.__resetBufferPointers() + for command in commands: + self.__appendJEDEC(command[0], command[1]) + self.__runCommandSync(self.PROGCMD_WRITEBUF) + self.top.hostDelay(0.05) + + self.__setCEOE(CE=1, OE=1) + self.progressMeterFinish() + + def readEEPROM(self): + self.applyVCC(True) + self.applyVPP(True) + self.applyGND(True) + + self.progressMeterInit("Reading EEPROM", 0x20000) + self.__setCEOE(CE=0, OE=0) + image = self.__readRange(0, 0x20000, progress=True) + self.__setCEOE(CE=1, OE=1) + self.progressMeterFinish() + + return image + + def __readRange(self, baseAddress, size, progress=False): + image = "" + byteCount = 0 + prevAddr = baseAddress + self.__loadReadAddrLo(baseAddress) + self.__loadReadAddrMed(baseAddress >> 8) + self.__loadReadAddrHi(baseAddress >> 16) + for offset in range(0, size): + addr = baseAddress + offset + if progress: + self.progressMeter(addr) + if (addr & 0xFF) != (prevAddr & 0xFF): + self.__loadReadAddrLo(addr) + if (addr & 0xFF00) != (prevAddr & 0xFF00): + self.__loadReadAddrMed(addr >> 8) + if (addr & 0xFF0000) != (prevAddr & 0xFF0000): + self.__loadReadAddrHi(addr >> 16) + prevAddr = addr + self.top.cmdFPGARead(0x10) + byteCount += 1 + if byteCount == self.top.getBufferRegSize(): + image += self.top.cmdReadBufferReg(byteCount) + byteCount = 0 + image += self.top.cmdReadBufferReg(byteCount) + return image + + def writeEEPROM(self, image): + if len(image) > 0x20000: + self.throwError("Invalid EPROM image size %d (expected <=%d)" %\ + (len(image), 0x20000)) + + self.applyVCC(True) + self.applyVPP(True) + self.applyGND(True) + + self.progressMeterInit("Writing EEPROM", len(image)) + self.__setCEOE(CE=0, OE=1) + for addr in range(0, len(image), 128): + self.progressMeter(addr) + pagelen = min(128, len(image) - addr) + page = image[addr:addr+pagelen] + self.__writePage(addr, page) + self.__setCEOE(CE=1, OE=1) + self.progressMeterFinish() + + def __swDataProtect(self, enable): + if enable: + jedecCommands = ( + (0x5555, 0xAA), + (0x2AAA, 0x55), + (0x5555, 0xA0), + ) + else: + jedecCommands = ( + (0x5555, 0xAA), + (0x2AAA, 0x55), + (0x5555, 0x80), + (0x5555, 0xAA), + (0x2AAA, 0x55), + (0x5555, 0x20), + ) + for command in jedecCommands: + self.__appendJEDEC(command[0], command[1]) + + def __writePage(self, pageAddress, pageData): + for t in range(0, 15): + self.__resetBufferPointers() + self.__swDataProtect(True) + assert(len(pageData) <= 128) + for byte in pageData: + self.__writeBufAppend(byte2int(byte)) + self.__loadWriteAddr(pageAddress) + self.__runCommandSync(self.PROGCMD_WRITEBUF) + self.top.hostDelay(0.01) + # Verify + self.__setCEOE(CE=0, OE=0) + verifyImage = self.__readRange(pageAddress, len(pageData)) + self.__setCEOE(CE=0, OE=1) + if verifyImage == pageData: + break + self.top.hostDelay(0.1) + else: + self.throwError("Verify error on page write at address 0x%05X" % pageAddress) + + def __writeBufAppend(self, byte): + # This also auto-increments the write buffer pointer + self.top.cmdFPGAWrite(0x10, byte & 0xFF) + + def __resetBufferPointers(self): + self.top.cmdFPGAWrite(0x13, 0) + + def __loadCommand(self, command): + self.top.cmdFPGAWrite(0x12, command & 0xFF) + + def __runCommandSync(self, command): + self.__loadCommand(command) + self.__busyWait() + + def __loadWriteAddr(self, addr): + self.__loadWriteAddrLo(addr) + self.__loadWriteAddrMed(addr >> 8) + self.__loadWriteAddrHi(addr >> 16) + + def __loadWriteAddrLo(self, addrLo): + self.top.cmdFPGAWrite(0x14, addrLo & 0xFF) + + def __loadWriteAddrMed(self, addrMed): + self.top.cmdFPGAWrite(0x15, addrMed & 0xFF) + + def __loadWriteAddrHi(self, addrHi): + self.top.cmdFPGAWrite(0x16, addrHi & 0xFF) + + def __loadReadAddrLo(self, addrLo): + self.top.cmdFPGAWrite(0x17, addrLo & 0xFF) + + def __loadReadAddrMed(self, addrMed): + self.top.cmdFPGAWrite(0x18, addrMed & 0xFF) + + def __loadReadAddrHi(self, addrHi): + self.top.cmdFPGAWrite(0x19, addrHi & 0xFF) + + def __setCEOE(self, CE, OE): + data = 0 + if CE: + data |= 0x01 + if OE: + data |= 0x02 + self.top.cmdFPGAWrite(0x1A, data) + + def __appendJEDEC(self, addr, data): + self.__loadJEDECAddrLo(addr) + self.__loadJEDECAddrMed(addr >> 8) + self.__loadJEDECAddrHi(addr >> 16) + self.__loadJEDECData(data) + + def __loadJEDECAddrLo(self, addrLo): + self.top.cmdFPGAWrite(0x1B, addrLo & 0xFF) + + def __loadJEDECAddrMed(self, addrMed): + self.top.cmdFPGAWrite(0x1C, addrMed & 0xFF) + + def __loadJEDECAddrHi(self, addrHi): + self.top.cmdFPGAWrite(0x1D, addrHi & 0xFF) + + def __loadJEDECData(self, data): + # This also auto-increments the JEDEC buffer pointer + self.top.cmdFPGAWrite(0x1E, data & 0xFF) + + def __getStatusFlags(self): + self.top.cmdFPGARead(0x12) + stat = self.top.cmdReadBufferReg() + return byte2int(stat[0]) + + def __busy(self): + return bool(self.__getStatusFlags() & self.STAT_BUSY) + + def __busyWait(self): + for i in range(0, 100): + if not self.__busy(): + return + self.top.hostDelay(0.01) + self.throwError("Timeout in busywait.") + +ChipDescription( + Chip_w29ee011dip32, + bitfile = "w29ee011dip32", + runtimeID = (0x0009, 0x01), + chipType = ChipDescription.TYPE_EEPROM, + chipVendors = "Winbond", + description = "W29EE011 EEPROM", + packages = ( ("DIP32", ""), ("PLCC32", "Use 1:1 PLCC32->DIP32 adapter"), ), + broken = True, +) -- cgit v1.2.3