def __init__(self): ScopeTemplate.__init__(self) self._is_connected = False self.params.init() self._cwusb = NAEUSB() self.ser = self._cwusb self.scopetype = self self.dev = self self.xmega = XMEGAPDI(self._cwusb) self.avr = AVRISP(self._cwusb) self.usart = USART(self._cwusb) self.serialstm32f = STM32FSerial(cwserial=self.usart) self.serialstm32f.scope = self self.io = GPIOSettings(self._cwusb) self.adc = ADCSettings(self._cwusb) self.glitch = GlitchSettings(self._cwusb) self._timeout = 2 self._lasttrace = None self.getParams().addChildren([ {'name':"CW-Lite XMEGA Programmer", 'tip':"Open XMEGA Programmer (ChipWhisperer-Lite Only)", 'type':"menu", "action":lambda _:self.getCwliteXMEGA().show()}, {'name':"CW-Lite AVR Programmer", 'tip':"Open AVR Programmer (ChipWhisperer-Lite Only)", 'type':"menu", "action":lambda _:self.getCwliteAVR().show()}, {'name':'Serial STM32F Programmer', 'tip':"Open STM32F Programmer (Serial/ChipWhisperer)", 'type':"menu", "action":lambda _:self.getSerialSTM32F().show()} ]) self.disable_newattr()
def get_cw_type(sn=None): """ Gets the scope type of the connected ChipWhisperer If multiple connected, sn must be specified """ from chipwhisperer.hardware.naeusb.naeusb import NAEUSB from chipwhisperer.capture import scopes possible_ids = [0xace0, 0xace2, 0xace3] cwusb = NAEUSB() possible_sn = cwusb.get_possible_devices(idProduct=possible_ids) name = "" if len(possible_sn) == 0: raise OSError("USB Device not found. Did you connect it first?") if (len(possible_sn) > 1): if sn is None: serial_numbers = [] for d in possible_sn: serial_numbers.append("sn = {} ({})".format(str(d['sn']), str(d['product']))) raise Warning("Multiple chipwhisperers connected, but device and/or serial number not specified.\nDevices:\n{}".format(serial_numbers)) else: for d in possible_sn: if d['sn'] == sn: name = d['product'] else: name = possible_sn[0]['product'] #print(name) if (name == "ChipWhisperer Lite") or (name == "ChipWhisperer CW1200"): return scopes.OpenADC elif name == "ChipWhisperer Nano": return scopes.CWNano
def __init__(self): self._cwusb = NAEUSB() # Connect required modules up here self.fpga = FPGA(self._cwusb) self.xmega = XMEGAPDI(self._cwusb) self.avr = AVRISP(self._cwusb) self.usart = USART(self._cwusb) self.getParams().addChildren([{ 'name': "CW-Lite XMEGA Programmer", 'tip': "Open XMEGA Programmer (ChipWhisperer-Lite Only)", 'type': "menu", "action": lambda _: self.getCwliteXMEGA().show() }, { 'name': "CW-Lite AVR Programmer", 'tip': "Open AVR Programmer (ChipWhisperer-Lite Only)", 'type': "menu", "action": lambda _: self.getCwliteAVR().show() }])
def __init__(self): self._cwusb = NAEUSB() # Connect required modules up here self.fpga = FPGA(self._cwusb) self.xmega = XMEGAPDI(self._cwusb) self.avr = AVRISP(self._cwusb) self.usart = USART(self._cwusb) self.serialstm32f = STM32FSerial(cwserial=self.usart, cwapi=None)
def __init__(self, target, scope, defines_files=None, bs='', force_bitfile=False): """ Args: target: SimpleSerial target scope: CW scope naeusb: NewAE USB interface platform (string): CW305 or CW610 (PhyWhisperer) defines_files (list of 2 strings): path to defines_trace.v and defines_pw.v """ super().__init__() self._trace_port_width = 4 self._base_target_clock = 7.384e6 self._base_baud = 38400 self._usb_clock = 96e6 self._uart_clock = self._usb_clock * 2 self.expected_verilog_defines = 107 self.swo_mode = False self.board_rev = 4 self._scope = scope # Detect whether we exist on CW305 or CW610 based on the target we're given: if target._name == 'Simple Serial': self.platform = 'CW610' self._ss = target self._naeusb = NAEUSB() self._naeusb.con(idProduct=[0xC610]) # we're using the CW NAEUSB, which has no knowledge of PW firmware, so let's manually # check the FW version here: fw_latest = [1, 1] if self._naeusb.readFwVersion()[0] < fw_latest[0]: logging.warning( 'Your PhyWhisperer firmware is outdated - latest is %d.%d' % (fw_latest[0], fw_latest[1]) + '. Suggested to update firmware, as you may experience errors.' ) self._fpga = FPGA(self._naeusb) if not self._fpga.isFPGAProgrammed() or force_bitfile: if not bs: bs = pkg_resources.resource_filename( 'chipwhisperer', 'hardware/firmware/tracewhisperer_top.bit') self._fpga.FPGAProgram(open(bs, 'rb'), exceptOnDoneFailure=False) else: self.platform = 'CW305' self._ss = cw.target(scope) self._naeusb = target._naeusb self.slurp_defines(defines_files) self._set_defaults()
def __init__(self): TargetTemplate.__init__(self) self._naeusb = NAEUSB() self.pll = PLLCDCE906(self._naeusb, ref_freq=12.0E6) self.fpga = FPGA(self._naeusb) self.hw = None self.oa = None self._woffset = 0x400 self._woffset_sam3U = 0x000 self._clksleeptime = 1 self._clkusbautooff = True self.last_key = bytearray([0] * 16)
def __init__(self): TargetTemplate.__init__(self) self._naeusb = NAEUSB() self.pll = PLLCDCE906(self._naeusb, ref_freq = 12.0E6, parent=self) self.fpga = FPGA(self._naeusb) self.hw = None # self._fpgabs = QSettings().value("cw305-bitstream", '') self.oa = None self._woffset = 0x400 self.params.addChildren([ {'name':'PLL Settings', 'key':'pll', 'type':'group', 'children':[ {'name':'Enabled', 'key':'pllenabled', 'type':'bool', 'default':False, 'set':self.pll.pll_enable_set, 'get':self.pll.pll_enable_get, 'psync':False}, {'name':'CLK-SMA (X6)', 'key':'pll0', 'type':'group', 'children':[ {'name':'CLK-SMA Enabled', 'key':'pll0enabled', 'type':'bool', 'default':False, 'set':partial(self.pll.pll_outenable_set, outnum=0), 'get':partial(self.pll.pll_outenable_get, outnum=0), 'psync':False}, {'name':'CLK-SMA Source', 'key':'pll0source', 'type':'list', 'values':['PLL0', 'PLL1', 'PLL2'], 'default':'PLL0', 'set':partial(self.pll.pll_outsource_set, outnum=0), 'get':partial(self.pll.pll_outsource_get, outnum=0), 'psync':False}, {'name':'CLK-SMA Slew Rate', 'key':'pll0slew', 'type':'list', 'values':['+3nS', '+2nS', '+1nS', '+0nS'], 'default':'+0nS', 'set':partial(self.pll.pll_outslew_set, outnum=0), 'get':partial(self.pll.pll_outslew_get, outnum=0), 'psync':False}, {'name':'PLL0 Frequency', 'key':'pll0freq', 'type':'float', 'limits':(0.625E6, 167E6), 'default':0, 'step':1E6, 'siPrefix':True, 'suffix':'Hz', 'set':partial(self.pll.pll_outfreq_set, outnum=0), 'get':partial(self.pll.pll_outfreq_get, outnum=0), 'psync':False}, ]}, {'name':'CLK-N13 (FGPA Pin N13)', 'key':'pll1', 'type':'group', 'children':[ {'name':'CLK-N13 Enabled', 'key':'pll1enabled', 'type':'bool', 'default':False, 'set':partial(self.pll.pll_outenable_set, outnum=1), 'get':partial(self.pll.pll_outenable_get, outnum=1), 'psync':False}, {'name':'CLK-N13 Source', 'key':'pll1source', 'type':'list', 'values':['PLL1'], 'value':'PLL1'}, {'name':'CLK-N13 Slew Rate', 'key':'pll1slew', 'type':'list', 'values':['+3nS', '+2nS', '+1nS', '+0nS'], 'default':'+0nS', 'set':partial(self.pll.pll_outslew_set, outnum=1), 'get':partial(self.pll.pll_outslew_get, outnum=1), 'psync':False}, {'name':'PLL1 Frequency', 'key':'pll1freq', 'type':'float', 'limits':(0.625E6, 167E6), 'default':0, 'step':1E6, 'siPrefix':True, 'suffix':'Hz', 'set':partial(self.pll.pll_outfreq_set, outnum=1), 'get':partial(self.pll.pll_outfreq_get, outnum=1), 'psync':False}, ]}, {'name':'CLK-E12 (FGPA Pin E12)', 'key':'pll2', 'type':'group', 'children':[ {'name':'CLK-E12 Enabled', 'key':'pll2enabled', 'type':'bool', 'default':False, 'set':partial(self.pll.pll_outenable_set, outnum=2), 'get':partial(self.pll.pll_outenable_get, outnum=2), 'psync':False}, {'name':'CLK-E12 Source', 'key':'pll2source', 'type':'list', 'values':['PLL2'], 'value':'PLL2'}, {'name':'CLK-E12 Slew Rate', 'key':'pll2slew', 'type':'list', 'values':['+0nS', '+1nS', '+2nS', '+3nS'], 'default':'+0nS', 'set':partial(self.pll.pll_outslew_set, outnum=2), 'get':partial(self.pll.pll_outslew_get, outnum=2), 'psync':False}, {'name':'PLL2 Frequency', 'key':'pll2freq', 'type':'float', 'limits':(0.625E6, 167E6), 'default':0, 'step':1E6, 'siPrefix':True, 'suffix':'Hz', 'set':partial(self.pll.pll_outfreq_set, outnum=2), 'get':partial(self.pll.pll_outfreq_get, outnum=2), 'psync':False}, ]}, {'name':'Save as Default (stored in EEPROM)', 'type':'action', 'action':lambda _ : self.pll.pll_writedefaults()}, ]}, {'name':'Disable CLKUSB For Capture', 'key':'clkusbautooff', 'type':'bool', 'value':True}, {'name':'Time CLKUSB Disabled for', 'key':'clksleeptime', 'type':'int', 'range':(1, 50000), 'value':50, 'suffix':'mS'}, {'name':'CLKUSB Manual Setting', 'key':'clkusboff', 'type':'bool', 'value':True, 'action':self.usb_clk_setenabled_action}, {'name':'Send Trigger', 'type':'action', 'action':self.usb_trigger_toggle}, {'name':'VCC-INT', 'key':'vccint', 'type':'float', 'default':1.00, 'range':(0.6, 1.10), 'suffix':' V', 'decimals':3, 'set':self.vccint_set, 'get':self.vccint_get, 'step':0.01}, {'name':'FPGA Bitstream', 'type':'group', 'children':[ {'name':'Bitstream File', 'key':'fpgabsfile', 'type':'file', 'value':"", "filter":'*.bit'}, {'name':'Program FPGA', 'type':'action', 'action':self.gui_programfpga}, ]}, ])
class CWLiteUSB(Parameterized): _name = "ChipWisperer-Lite USB" def __init__(self): self._cwusb = NAEUSB() # Connect required modules up here self.fpga = FPGA(self._cwusb) self.xmega = XMEGAPDI(self._cwusb) self.avr = AVRISP(self._cwusb) self.usart = USART(self._cwusb) self.getParams().addChildren([{ 'name': "CW-Lite XMEGA Programmer", 'tip': "Open XMEGA Programmer (ChipWhisperer-Lite Only)", 'type': "menu", "action": lambda _: self.getCwliteXMEGA().show() }, { 'name': "CW-Lite AVR Programmer", 'tip': "Open AVR Programmer (ChipWhisperer-Lite Only)", 'type': "menu", "action": lambda _: self.getCwliteAVR().show() }]) def con(self, idProduct): return self._cwusb.con(idProduct=idProduct) # def __del__(self): # print "here" def dis(self): if self.params is not None: self.getParams().delete() self.params = None # gc.collect() # print sys.getrefcount(self) # print gc.get_referrers(self) def usbdev(self): return self._cwusb def getCwliteXMEGA(self): if not hasattr(self, 'cwliteXMEGA'): self.cwliteXMEGA = XMEGAProgrammerDialog() self.cwliteXMEGA.setUSBInterface(self.xmega) return self.cwliteXMEGA def getCwliteAVR(self): if not hasattr(self, 'cwliteAVR'): self.cwliteAVR = AVRProgrammerDialog() self.cwliteAVR.setUSBInterface(self.avr) return self.cwliteAVR
class CWLiteUSB(Parameterized): _name = "ChipWisperer-Lite USB" def __init__(self): self._cwusb = NAEUSB() # Connect required modules up here self.fpga = FPGA(self._cwusb) self.xmega = XMEGAPDI(self._cwusb) self.avr = AVRISP(self._cwusb) self.usart = USART(self._cwusb) self.getParams().addChildren([ {'name':"CW-Lite XMEGA Programmer", 'tip':"Open XMEGA Programmer (ChipWhisperer-Lite Only)", 'type':"menu", "action":lambda _:self.getCwliteXMEGA().show()}, {'name':"CW-Lite AVR Programmer", 'tip':"Open AVR Programmer (ChipWhisperer-Lite Only)", 'type':"menu", "action":lambda _:self.getCwliteAVR().show()} ]) def con(self): self._cwusb.con() # def __del__(self): # print "here" def dis(self): self.getParams().delete() self.params = None # gc.collect() # print sys.getrefcount(self) # print gc.get_referrers(self) def usbdev(self): return self._cwusb def getCwliteXMEGA(self): if not hasattr(self, 'cwliteXMEGA'): self.cwliteXMEGA = XMEGAProgrammerDialog() self.cwliteXMEGA.setUSBInterface(self.xmega) return self.cwliteXMEGA def getCwliteAVR(self): if not hasattr(self, 'cwliteAVR'): self.cwliteAVR = AVRProgrammerDialog() self.cwliteAVR.setUSBInterface(self.avr) return self.cwliteAVR
def __init__(self): TargetTemplate.__init__(self) self._naeusb = NAEUSB() self.pll = PLLCDCE906(self._naeusb, ref_freq=12.0E6) self.fpga = FPGA(self._naeusb) self.hw = None self.oa = None self._woffset_sam3U = 0x000 self.default_verilog_defines = 'cw305_defines.v' self.default_verilog_defines_full_path = '../../hardware/victims/cw305_artixtarget/fpga/common/' + self.default_verilog_defines self.registers = 12 # number of registers we expect to find self.bytecount_size = 7 # pBYTECNT_SIZE in Verilog self._clksleeptime = 1 self._clkusbautooff = True self.last_key = bytearray([0] * 16) self.target_name = 'AES'
def __init__(self): self._cwusb = NAEUSB() # Connect required modules up here self.fpga = FPGA(self._cwusb) self.xmega = XMEGAPDI(self._cwusb) self.avr = AVRISP(self._cwusb) self.usart = USART(self._cwusb) self.getParams().addChildren([ {'name':"CW-Lite XMEGA Programmer", 'tip':"Open XMEGA Programmer (ChipWhisperer-Lite Only)", 'type':"menu", "action":lambda _:self.getCwliteXMEGA().show()}, {'name':"CW-Lite AVR Programmer", 'tip':"Open AVR Programmer (ChipWhisperer-Lite Only)", 'type':"menu", "action":lambda _:self.getCwliteAVR().show()} ])
def __init__(self): ScopeTemplate.__init__(self) self._is_connected = False self._cwusb = NAEUSB() self.ser = self._cwusb self.scopetype = self self.dev = self self.xmega = XMEGAPDI(self._cwusb) self.avr = AVRISP(self._cwusb) self.usart = USART(self._cwusb) self.serialstm32f = STM32FSerial(cwserial=self.usart) self.serialstm32f.scope = self self.io = GPIOSettings(self._cwusb) self.adc = ADCSettings(self._cwusb) self.glitch = GlitchSettings(self._cwusb) self._timeout = 2 self._lasttrace = None self.disable_newattr()
def __init__(self): self._cwusb = NAEUSB() # Connect required modules up here self.fpga = FPGA(self._cwusb) self.xmega = XMEGAPDI(self._cwusb) self.avr = AVRISP(self._cwusb) self.usart = USART(self._cwusb) self.serialstm32f = STM32FSerial(cwserial=self.usart, cwapi=CWCoreAPI.getInstance()) self.getParams().addChildren([{ 'name': "CW-Lite XMEGA Programmer", 'tip': "Open XMEGA Programmer (ChipWhisperer-Lite Only)", 'type': "menu", "action": lambda _: self.getCwliteXMEGA().show() }, { 'name': "CW-Lite AVR Programmer", 'tip': "Open AVR Programmer (ChipWhisperer-Lite Only)", 'type': "menu", "action": lambda _: self.getCwliteAVR().show() }, { 'name': 'Serial STM32F Programmer', 'tip': "Open STM32F Programmer (Serial/ChipWhisperer)", 'type': "menu", "action": lambda _: self.getSerialSTM32F().show() }])
def __init__(self, *args, **kwargs): # maybe later can hijack cw305 stuff, but for now don't pass import chipwhisperer as cw self._naeusb = NAEUSB() self.pll = PLLCDCE906(self._naeusb, ref_freq=12.0E6) self.fpga = FPGA(self._naeusb) self.hw = None self.oa = None self._woffset_sam3U = 0x000 self.default_verilog_defines = 'cw305_defines.v' self.default_verilog_defines_full_path = os.path.dirname( cw.__file__ ) + '/../../hardware/victims/cw305_artixtarget/fpga/common/' + self.default_verilog_defines self.registers = 12 # number of registers we expect to find self.bytecount_size = 7 # pBYTECNT_SIZE in Verilog self._clksleeptime = 1 self._clkusbautooff = True self.last_key = bytearray([0] * 16) self.target_name = 'AES'
class CWLiteUSB(object): _name = "ChipWisperer-Lite USB" def __init__(self): self._cwusb = NAEUSB() # Connect required modules up here self.fpga = FPGA(self._cwusb) self.xmega = XMEGAPDI(self._cwusb) self.avr = AVRISP(self._cwusb) self.usart = USART(self._cwusb) self.serialstm32f = STM32FSerial(cwserial=self.usart, cwapi=None) def get_possible_devices(self, idProduct): return self._cwusb.get_possible_devices(idProduct=idProduct) def con(self, *args, **kwargs): return self._cwusb.con(*args, **kwargs) def dis(self): pass def usbdev(self): return self._cwusb
def __init__(self, parentParam=None): TargetTemplate.__init__(self, parentParam) self._naeusb = NAEUSB() self.pll = PLLCDCE906(self._naeusb, ref_freq = 12.0E6, parent=self) self.fpga = FPGA(self._naeusb) self.hw = None # self._fpgabs = QSettings().value("cw305-bitstream", '') self.oa = None self._woffset = 0x400 self.params.addChildren([ {'name':'PLL Settings', 'key':'pll', 'type':'group', 'children':[ {'name':'Enabled', 'key':'pllenabled', 'type':'bool', 'default':False, 'set':self.pll.pll_enable_set, 'get':self.pll.pll_enable_get, 'psync':False}, {'name':'CLK-SMA (X6)', 'key':'pll0', 'type':'group', 'children':[ {'name':'CLK-SMA Enabled', 'key':'pll0enabled', 'type':'bool', 'default':False, 'set':partial(self.pll.pll_outenable_set, outnum=0), 'get':partial(self.pll.pll_outenable_get, outnum=0), 'psync':False}, {'name':'CLK-SMA Source', 'key':'pll0source', 'type':'list', 'values':['PLL0', 'PLL1', 'PLL2'], 'default':'PLL0', 'set':partial(self.pll.pll_outsource_set, outnum=0), 'get':partial(self.pll.pll_outsource_get, outnum=0), 'psync':False}, {'name':'CLK-SMA Slew Rate', 'key':'pll0slew', 'type':'list', 'values':['+3nS', '+2nS', '+1nS', '+0nS'], 'default':'+0nS', 'set':partial(self.pll.pll_outslew_set, outnum=0), 'get':partial(self.pll.pll_outslew_get, outnum=0), 'psync':False}, {'name':'PLL0 Frequency', 'key':'pll0freq', 'type':'float', 'limits':(0.625E6, 167E6), 'default':0, 'step':1E6, 'siPrefix':True, 'suffix':'Hz', 'set':partial(self.pll.pll_outfreq_set, outnum=0), 'get':partial(self.pll.pll_outfreq_get, outnum=0), 'psync':False}, ]}, {'name':'CLK-N13 (FGPA Pin N13)', 'key':'pll1', 'type':'group', 'children':[ {'name':'CLK-N13 Enabled', 'key':'pll1enabled', 'type':'bool', 'default':False, 'set':partial(self.pll.pll_outenable_set, outnum=1), 'get':partial(self.pll.pll_outenable_get, outnum=1), 'psync':False}, {'name':'CLK-N13 Source', 'key':'pll1source', 'type':'list', 'values':['PLL1'], 'value':'PLL1'}, {'name':'CLK-N13 Slew Rate', 'key':'pll1slew', 'type':'list', 'values':['+3nS', '+2nS', '+1nS', '+0nS'], 'default':'+0nS', 'set':partial(self.pll.pll_outslew_set, outnum=1), 'get':partial(self.pll.pll_outslew_get, outnum=1), 'psync':False}, {'name':'PLL1 Frequency', 'key':'pll1freq', 'type':'float', 'limits':(0.625E6, 167E6), 'default':0, 'step':1E6, 'siPrefix':True, 'suffix':'Hz', 'set':partial(self.pll.pll_outfreq_set, outnum=1), 'get':partial(self.pll.pll_outfreq_get, outnum=1), 'psync':False}, ]}, {'name':'CLK-E12 (FGPA Pin E12)', 'key':'pll2', 'type':'group', 'children':[ {'name':'CLK-E12 Enabled', 'key':'pll2enabled', 'type':'bool', 'default':False, 'set':partial(self.pll.pll_outenable_set, outnum=2), 'get':partial(self.pll.pll_outenable_get, outnum=2), 'psync':False}, {'name':'CLK-E12 Source', 'key':'pll2source', 'type':'list', 'values':['PLL2'], 'value':'PLL2'}, {'name':'CLK-E12 Slew Rate', 'key':'pll2slew', 'type':'list', 'values':['+0nS', '+1nS', '+2nS', '+3nS'], 'default':'+0nS', 'set':partial(self.pll.pll_outslew_set, outnum=2), 'get':partial(self.pll.pll_outslew_get, outnum=2), 'psync':False}, {'name':'PLL2 Frequency', 'key':'pll2freq', 'type':'float', 'limits':(0.625E6, 167E6), 'default':0, 'step':1E6, 'siPrefix':True, 'suffix':'Hz', 'set':partial(self.pll.pll_outfreq_set, outnum=2), 'get':partial(self.pll.pll_outfreq_get, outnum=2), 'psync':False}, ]}, {'name':'Save as Default (stored in EEPROM)', 'type':'action', 'action':lambda _ : self.pll.pll_writedefaults()}, ]}, {'name':'Disable CLKUSB For Capture', 'key':'clkusbautooff', 'type':'bool', 'value':True}, {'name':'Time CLKUSB Disabled for', 'key':'clksleeptime', 'type':'int', 'range':(1, 50000), 'value':50, 'suffix':'mS'}, {'name':'CLKUSB Manual Setting', 'key':'clkusboff', 'type':'bool', 'value':True, 'action':self.usb_clk_setenabled_action}, {'name':'Send Trigger', 'type':'action', 'action':self.usb_trigger_toggle}, {'name':'VCC-INT', 'key':'vccint', 'type':'float', 'default':1.00, 'range':(0.6, 1.10), 'suffix':' V', 'decimals':3, 'set':self.vccint_set, 'get':self.vccint_get}, {'name':'FPGA Bitstream', 'type':'group', 'children':[ {'name':'Bitstream File', 'key':'fpgabsfile', 'type':'file', 'value':"", "filter":'*.bit'}, {'name':'Program FPGA', 'type':'action', 'action':self.gui_programfpga}, ]}, ])
class CW305(TargetTemplate): """CW305 target object. This class contains the public API for the CW305 hardware. To connect to the CW305, the easiest method is:: import chipwhisperer as cw scope = cw.scope() # scope can also be None here, unlike with the default SimpleSerial target = cw.target(scope, targets.CW305, bsfile=<valid FPGA bitstream file>) As of CW5.3, you can also specify the following:: # can also be '35t' target = cw.target(scope, fpga_id='100t') To automatically program with the example AES bitstream If you're using the reference designs, typical configuration requires you to set the FPGA VCC-INT voltage and enable and set the clock via the PLL. You'll probably also want to disable the USB clock during encryption to reduce noise:: target.vccint_set(1.0) #set VCC-INT to 1V target.pll.pll_enable_set(True) #Enable PLL chip target.pll.pll_outenable_set(False, 0) # Disable unused PLL0 target.pll.pll_outenable_set(True, 1) # Enable PLL target.pll.pll_outenable_set(False, 2) # Disable unused PLL2 # optional, but reduces power trace noise target.clkusbautooff = True target.clksleeptime = 1 # 1ms typically good for sleep Don't forget to clock the ChipWhisperer ADC off the FPGA instead of the internal clock:: scope.clock.adc_src = "extclk_x4" scope.clock.reset_adc() # make sure the DCM is locked Note that connecting to the CW305 includes programming the CW305 FPGA, if it isn't already. For more help about CW305 settings, try help() on this CW305 submodule: * target.pll """ _name = "ChipWhisperer CW305 (Artix-7)" BATCHRUN_START = 0x1 BATCHRUN_RANDOM_KEY = 0x2 BATCHRUN_RANDOM_PT = 0x4 def __init__(self): TargetTemplate.__init__(self) self._naeusb = NAEUSB() self.pll = PLLCDCE906(self._naeusb, ref_freq=12.0E6) self.fpga = FPGA(self._naeusb) self.hw = None self.oa = None self._woffset_sam3U = 0x000 self.default_verilog_defines = 'cw305_defines.v' self.default_verilog_defines_full_path = '../../hardware/victims/cw305_artixtarget/fpga/common/' + self.default_verilog_defines self.registers = 12 # number of registers we expect to find self.bytecount_size = 7 # pBYTECNT_SIZE in Verilog self._clksleeptime = 1 self._clkusbautooff = True self.last_key = bytearray([0] * 16) self.target_name = 'AES' def _getNAEUSB(self): return self._naeusb def slurp_defines(self, defines_files=None): """ Parse Verilog defines file so we can access register and bit definitions by name and avoid 'magic numbers'. Args: defines_files (list): list of Verilog define files to parse """ self.verilog_define_matches = 0 if type(defines_files) != list: logging.error( 'defines_files must be provided as a list (even it it contains a single element)' ) for i, defines_file in enumerate(defines_files): if type(defines_file) == io.BytesIO: defines = io.TextIOWrapper(defines_file) else: if not os.path.isfile(defines_file): logging.error( 'Cannot find %s. Please specify the location of %s on your filesystem.' % (defines_files, self.default_verilog_defines)) defines = open(defines_file, 'r') define_regex_base = re.compile(r'`define') define_regex_reg = re.compile(r'`define\s+?REG_') define_regex_radix = re.compile( r'`define\s+?(\w+).+?\'([bdh])([0-9a-fA-F]+)') define_regex_noradix = re.compile(r'`define\s+?(\w+?)\s+?(\d+?)') block_offset = 0 for define in defines: if define_regex_base.search(define): reg = define_regex_reg.search(define) match = define_regex_radix.search(define) if match: self.verilog_define_matches += 1 if match.group(2) == 'b': radix = 2 elif match.group(2) == 'h': radix = 16 else: radix = 10 setattr(self, match.group(1), int(match.group(3), radix) + block_offset) else: match = define_regex_noradix.search(define) if match: self.verilog_define_matches += 1 setattr(self, match.group(1), int(match.group(2), 10) + block_offset) else: logging.warning("Couldn't parse line: %s", define) defines.close() # make sure everything is cool: if self.verilog_define_matches != self.registers: logging.warning( "Trouble parsing Verilog defines files (%s): didn't find the right number of defines; expected %d, got %d.\n" % (defines_file, self.registers, self.verilog_define_matches) + "Ensure that the Verilog defines files above are the same that were used to build the bitfile." ) def get_fpga_buildtime(self): """Returns date and time when FPGA bitfile was generated. """ raw = self.fpga_read(self.REG_BUILDTIME, 4) # definitions: Xilinx XAPP1232 day = raw[3] >> 3 month = ((raw[3] & 0x7) << 1) + (raw[2] >> 7) year = ((raw[2] >> 1) & 0x3f) + 2000 hour = ((raw[2] & 0x1) << 4) + (raw[1] >> 4) minute = ((raw[1] & 0xf) << 2) + (raw[0] >> 6) return "FPGA build time: {}/{}/{}, {}:{}".format( month, day, year, hour, minute) def fpga_write(self, addr, data): """Write to an address on the FPGA Args: addr (int): Address to write to data (list): Data to write to addr """ addr = addr << self.bytecount_size return self._naeusb.cmdWriteMem(addr, data) def fpga_read(self, addr, readlen): """Read from an address on the FPGA Args: addr (int): Address to read from readlen (int): Length of data to read Returns: Requested data as a list """ addr = addr << self.bytecount_size data = self._naeusb.cmdReadMem(addr, readlen) return data def usb_clk_setenabled(self, status): """ Turn on or off the Data Clock to the FPGA """ if status: self._naeusb.sendCtrl(CW305_USB.REQ_SYSCFG, CW305_USB.SYSCFG_CLKON) else: self._naeusb.sendCtrl(CW305_USB.REQ_SYSCFG, CW305_USB.SYSCFG_CLKOFF) def usb_trigger_toggle(self, _=None): """ Toggle the trigger line high then low """ self._naeusb.sendCtrl(CW305_USB.REQ_SYSCFG, CW305_USB.SYSCFG_TOGGLE) def vccint_set(self, vccint=1.0): """ Set the VCC-INT for the FPGA """ # print "vccint = " + str(vccint) if (vccint < 0.6) or (vccint > 1.15): raise ValueError("VCC-Int out of range 0.6V-1.1V") # Convert to mV vccint = int(vccint * 1000) vccsetting = [vccint & 0xff, (vccint >> 8) & 0xff, 0] # calculate checksum vccsetting[2] = vccsetting[0] ^ vccsetting[1] ^ CW305_USB.VCCINT_XORKEY self._naeusb.sendCtrl(CW305_USB.REQ_VCCINT, 0, vccsetting) resp = self._naeusb.readCtrl(CW305_USB.REQ_VCCINT, dlen=3) if resp[0] != 2: raise IOError("VCC-INT Write Error, response = %d" % resp[0]) def vccint_get(self): """ Get the last set value for VCC-INT """ resp = self._naeusb.readCtrl(CW305_USB.REQ_VCCINT, dlen=3) return float(resp[1] | (resp[2] << 8)) / 1000.0 def _con(self, scope=None, bsfile=None, force=False, fpga_id=None, defines_files=None, slurp=True): """Connect to CW305 board, and download bitstream. If the target has already been programmed it skips reprogramming unless forced. Args: scope (ScopeTemplate): An instance of a scope object. bsfile (path): The path to the bitstream file to program the FPGA with. force (bool): Whether or not to force reprogramming. fpga_id (string): '100t', '35t', or None. If bsfile is None and fpga_id specified, program with AES firmware for fpga_id defines_files (list, optional): path to cw305_defines.v slurp (bool, optional): Whether or not to slurp the Verilog defines. """ from datetime import datetime self._naeusb.con(idProduct=[0xC305]) if not fpga_id is None: if fpga_id not in ('100t', '35t'): raise ValueError(f"Invalid fpga {fpga_id}") self._fpga_id = fpga_id if self.fpga.isFPGAProgrammed() == False or force: if bsfile is None: if not fpga_id is None: from chipwhisperer.hardware.firmware.cw305 import getsome if self.target_name == 'AES': bsdata = getsome(f"AES_{fpga_id}.bit") elif self.target_name == 'Cryptech ecdsa256-v1 pmul': bsdata = getsome(f"ECDSA256v1_pmul_{fpga_id}.bit") starttime = datetime.now() status = self.fpga.FPGAProgram(bsdata, exceptOnDoneFailure=False) stoptime = datetime.now() if status: logging.info('FPGA Config OK, time: %s' % str(stoptime - starttime)) else: logging.warning( 'FPGA Done pin failed to go high, check bitstream is for target device.' ) else: print("No FPGA Bitstream file specified.") elif not os.path.isfile(bsfile): print(("FPGA Bitstream not configured or '%s' not a file." % str(bsfile))) else: starttime = datetime.now() status = self.fpga.FPGAProgram(open(bsfile, "rb"), exceptOnDoneFailure=False) stoptime = datetime.now() if status: logging.info('FPGA Config OK, time: %s' % str(stoptime - starttime)) else: logging.warning( 'FPGA Done pin failed to go high, check bitstream is for target device.' ) self.usb_clk_setenabled(True) self.pll.cdce906init() if defines_files is None: if fpga_id is None: verilog_defines = [self.default_verilog_defines_full_path] else: from chipwhisperer.hardware.firmware.cw305 import getsome verilog_defines = [getsome(self.default_verilog_defines)] else: verilog_defines = defines_files if slurp: self.slurp_defines(verilog_defines) def _dis(self): if self._naeusb: self._naeusb.close() def checkEncryptionKey(self, key): """Validate encryption key""" return key def loadEncryptionKey(self, key): """Write encryption key to FPGA""" self.key = key key = key[::-1] self.fpga_write(self.REG_CRYPT_KEY, key) def loadInput(self, inputtext): """Write input to FPGA""" self.input = inputtext text = inputtext[::-1] self.fpga_write(self.REG_CRYPT_TEXTIN, text) def is_done(self): """Check if FPGA is done""" result = self.fpga_read(self.REG_CRYPT_GO, 1)[0] if result == 0x01: return False else: self.fpga_write(self.REG_USER_LED, [0]) return True isDone = camel_case_deprecated(is_done) def readOutput(self): """"Read output from FPGA""" data = self.fpga_read(self.REG_CRYPT_CIPHEROUT, 16) data = data[::-1] #self.newInputData.emit(util.list2hexstr(data)) return data @property def latest_fw(self): cw_type = self._getCWType() if cw_type == "cwlite": from chipwhisperer.hardware.firmware.cwlite import fwver elif cw_type == "cw1200": from chipwhisperer.hardware.firmware.cw1200 import fwver ret = OrderedDict() return {"major": fwver[0], "minor": fwver[1]} @property def fw_version(self): a = self._naeusb.readFwVersion() return {"major": a[0], "minor": a[1], "debug": a[2]} @property def clkusbautooff(self): """ If set, the USB clock is automatically disabled on capture. The USB clock is re-enabled after self.clksleeptime milliseconds. Reads/Writes to the FPGA will not be possible until after the USB clock is reenabled, meaning :code:`usb_trigger_toggle()` must be used to trigger the FPGA to perform an encryption. :Getter: Gets whether to turn off the USB clock on capture :Setter: Sets whether to turn off the USB clock on capture """ return self._clkusbautooff @clkusbautooff.setter def clkusbautooff(self, state): self._clkusbautooff = state @property def clksleeptime(self): """ Time (in milliseconds) that the USB clock is disabled for upon capture, if self.clkusbautooff is set. """ return self._clksleeptime @clksleeptime.setter def clksleeptime(self, value): self._clksleeptime = value def go(self): """Disable USB clock (if requested), perform encryption, re-enable clock""" if self.clkusbautooff: self.usb_clk_setenabled(False) self.fpga_write(self.REG_USER_LED, [0x01]) time.sleep(0.001) self.usb_trigger_toggle() # it's also possible to 'go' via register write but that won't take if # the USB clock was turned off: #self.fpga_write(self.REG_CRYPT_GO, [1]) if self.clkusbautooff: time.sleep(self.clksleeptime / 1000.0) self.usb_clk_setenabled(True) def simpleserial_read(self, cmd, pay_len, end='\n', timeout=250, ack=True): """Read data from target Mimics simpleserial protocol of serial based targets Args: cmd (str): Command to ues. Only accepts 'r' for now. pay_len: Unused end: Unused timeout: Unused ack: Unused Returns: Value from Crypto output register .. versionadded:: 5.1 Added simpleserial_read to CW305 """ if cmd == "r": return self.readOutput() else: raise ValueError("Unknown command {}".format(cmd)) def simpleserial_write(self, cmd, data, end=None): """Write data to target. Mimics simpleserial protocol of serial based targets. Args: cmd (str): Command to use. Target supports 'p' (write plaintext), and 'k' (write key). data (bytearray): Data to write to target end: Unused Raises: ValueError: Unknown command .. versionadded:: 5.1 Added simpleserial_write to CW305 """ if cmd == 'p': self.loadInput(data) self.go() elif cmd == 'k': self.loadEncryptionKey(data) else: raise ValueError("Unknown command {}".format(cmd)) def set_key(self, key, ack=False, timeout=250): """Checks if key is different from the last one sent. If so, send it. Args: key (bytearray): key to send ack: Unused timeout: Unused .. versionadded:: 5.1 Added set_key to CW305 """ if self.last_key != key: self.last_key = key self.simpleserial_write('k', key) def batchRun(self, batchsize=1024, random_key=True, random_pt=True, seed=None): """ Run multiple encryptions on random data Args: batchsize (int): The number of encryption to run (default 1024). random_key (bool): True if the key is random (default False). random_pt (bool): True if the plaintext are random (default True). seed (int): random int32 for the PRG. """ if seed is None: seed = random.randint(0, 2**32) data = [] data.extend( packuint32(1 | (random_key << 1) | (random_pt << 2) | (batchsize << 16))) data.extend(packuint32(seed)) self.sam3u_write(0, data) # generate the inputs if random_key: key = [[0 for x in range(16)] for y in range(batchsize)] else: key = None if random_pt: pt = [[0 for x in range(16)] for y in range(batchsize)] else: pt = None for b in range(batchsize): if random_key: for j in range(16): key[b][15 - j] = seed >> 24 seed += ((seed * seed) & 0xffffffff) | 0x5 seed &= 0xffffffff if random_pt: for j in range(16): pt[b][15 - j] = seed >> 24 seed += ((seed * seed) & 0xffffffff) | 0x5 seed &= 0xffffffff return key, pt def sam3u_write(self, addr, data): """Write to an address on the FPGA Args: addr (int): Address to write to data (list): Data to write to addr Raises: IOError: User attempted to write to a read-only location """ if addr < self._woffset_sam3U: raise IOError("Write to read-only location: 0x%04x" % addr) if len(data) > (256 + addr): raise IOError("Write will overflow at location: 0x%04x" % (256)) return self._naeusb.cmdWriteSam3U(addr, data) @fw_ver_required(0, 30) def spi_mode(self, enable=True, timeout=200, bsfile=None): """Enter programming mode for the onboard SPI chip Reprograms the FPGA with the appropriate bitstream and returns an object with which to program the CW305 SPI chip (see documentation on the returned object for more info) Args: enable (bool): Enable the SPI interface before returning it. Defaults to True timeout (int): USB timeout in ms. Defaults to 200. bsfile (string): If not None, program with a bitstream pointed to by bsfile. If None, program with SPI passthrough bitstream for the chip specified during connection (or cw.target()) Returns: A FPGASPI object which can be used to erase/program/verify/read the SPI chip on the CW305. """ from datetime import datetime if self._fpga_id is None and bsfile is None: logging.warning( "CW305 requires passthrough bitstream to program SPI chip, but file/chip not specified" ) else: bsdata = None if self._fpga_id: from chipwhisperer.hardware.firmware.cw305 import getsome bsdata = getsome(f"SPI_flash_{self._fpga_id}.bit") else: bsdata = open(bsfile, "rb") starttime = datetime.now() status = self.fpga.FPGAProgram(bsdata, exceptOnDoneFailure=False) stoptime = datetime.now() if status: logging.info('FPGA Config OK, time: %s' % str(stoptime - starttime)) else: logging.warning( 'FPGA Done pin failed to go high, check bitstream is for target device.' ) spi = FPGASPI(self._naeusb, timeout) spi.enable_interface(enable) return spi @fw_ver_required(0, 40) def gpio_mode(self, timeout=200): """Allow arbitrary GPIO access on SAM3U Allows low-level IO access to SAM3U GPIO, and also SPI transfers. (see documentation on the returned object for more info) Args: timeout (int): USB timeout in ms. Defaults to 200. Returns: A FPGAIO object which can be used to access IO on the CW305. """ io = FPGAIO(self._naeusb, timeout) return io
class CWLiteUSB(Parameterized): _name = "ChipWisperer-Lite USB" def __init__(self): self._cwusb = NAEUSB() # Connect required modules up here self.fpga = FPGA(self._cwusb) self.xmega = XMEGAPDI(self._cwusb) self.avr = AVRISP(self._cwusb) self.usart = USART(self._cwusb) self.serialstm32f = STM32FSerial(cwserial=self.usart, cwapi=CWCoreAPI.getInstance()) self.getParams().addChildren([{ 'name': "CW-Lite XMEGA Programmer", 'tip': "Open XMEGA Programmer (ChipWhisperer-Lite Only)", 'type': "menu", "action": lambda _: self.getCwliteXMEGA().show() }, { 'name': "CW-Lite AVR Programmer", 'tip': "Open AVR Programmer (ChipWhisperer-Lite Only)", 'type': "menu", "action": lambda _: self.getCwliteAVR().show() }, { 'name': 'Serial STM32F Programmer', 'tip': "Open STM32F Programmer (Serial/ChipWhisperer)", 'type': "menu", "action": lambda _: self.getSerialSTM32F().show() }]) def get_possible_devices(self, idProduct): return self._cwusb.get_possible_devices(idProduct=idProduct) def con(self, *args, **kwargs): return self._cwusb.con(*args, **kwargs) # def __del__(self): # print "here" def dis(self): if self.params is not None: self.getParams().delete() self.params = None # gc.collect() # print sys.getrefcount(self) # print gc.get_referrers(self) def usbdev(self): return self._cwusb def getCwliteXMEGA(self): if not hasattr(self, 'cwliteXMEGA'): self.cwliteXMEGA = XMEGAProgrammerDialog() return self.cwliteXMEGA def getCwliteAVR(self): if not hasattr(self, 'cwliteAVR'): self.cwliteAVR = AVRProgrammerDialog() return self.cwliteAVR def getSerialSTM32F(self): if not hasattr(self, 'serialSTM32F'): self.serialSTM32F = STM32FProgrammerDialog() return self.serialSTM32F
class CWNano(ScopeTemplate, Plugin, util.DisableNewAttr): """CWNano scope object. This class contains the public API for the CWNano hardware. It includes specific settings for each of these devices. To connect to one of these devices, the easiest method is This code will automatically detect an attached ChipWhisperer device and connect to it. For more help about scope settings, try help() on each of the ChipWhisperer scope submodules: scope.adc scope.io scope.glitch """ _name = "ChipWhisperer Nano" REQ_ARM = 0x29 REQ_SAMPLES = 0x2A def __init__(self): ScopeTemplate.__init__(self) self._is_connected = False self.params.init() self._cwusb = NAEUSB() self.ser = self._cwusb self.scopetype = self self.dev = self self.xmega = XMEGAPDI(self._cwusb) self.avr = AVRISP(self._cwusb) self.usart = USART(self._cwusb) self.serialstm32f = STM32FSerial(cwserial=self.usart) self.serialstm32f.scope = self self.io = GPIOSettings(self._cwusb) self.adc = ADCSettings(self._cwusb) self.glitch = GlitchSettings(self._cwusb) self._timeout = 2 self._lasttrace = None self.getParams().addChildren([ {'name':"CW-Lite XMEGA Programmer", 'tip':"Open XMEGA Programmer (ChipWhisperer-Lite Only)", 'type':"menu", "action":lambda _:self.getCwliteXMEGA().show()}, {'name':"CW-Lite AVR Programmer", 'tip':"Open AVR Programmer (ChipWhisperer-Lite Only)", 'type':"menu", "action":lambda _:self.getCwliteAVR().show()}, {'name':'Serial STM32F Programmer', 'tip':"Open STM32F Programmer (Serial/ChipWhisperer)", 'type':"menu", "action":lambda _:self.getSerialSTM32F().show()} ]) self.disable_newattr() def getCurrentScope(self): return self def _con(self): self._cwusb.con(idProduct=[0xACE0]) self.disable_newattr() self._is_connected = True return True def _dis(self): self.enable_newattr() self._is_connected = False return True def arm(self): """Arm the ADC, the trigger will be GPIO4 rising edge (fixed trigger).""" if self.connectStatus.value() is False: raise Warning("Scope \"" + self.getName() + "\" is not connected. Connect it first...") self._cwusb.sendCtrl(self.REQ_ARM, 1) def capture(self): """Raises IOError if unknown failure, returns 'True' if timeout, 'False' if no timeout""" starttime = datetime.datetime.now() while self._cwusb.readCtrl(self.REQ_ARM, dlen=1)[0] == 0: # Wait for a moment before re-running the loop time.sleep(0.05) diff = datetime.datetime.now() - starttime # If we've timed out, don't wait any longer for a trigger if (diff.total_seconds() > self._timeout): logging.warning('Timeout in cwnano capture()') return True self._lasttrace = self._cwusb.cmdReadMem(0, self.adc.samples) self._lasttrace = np.array(self._lasttrace) / 256.0 - 0.5 self.newDataReceived(0, self._lasttrace, 0, self.adc.clk_freq) return False def getLastTrace(self): """Return the last trace captured with this scope. """ return self._lasttrace def _dict_repr(self): dict = OrderedDict() dict['io'] = self.io._dict_repr() dict['adc'] = self.adc._dict_repr() dict['glitch'] = self.glitch._dict_repr() return dict def __repr__(self): # Add some extra information about ChipWhisperer type here if self._is_connected: ret = "ChipWhisperer Nano Device\n" return ret + dict_to_str(self._dict_repr()) else: ret = "ChipWhisperer Nano device (disconnected)" return ret def __str__(self): return self.__repr__() def get_possible_devices(self, idProduct): return self._cwusb.get_possible_devices(idProduct=idProduct) def usbdev(self): return self._cwusb def getCwliteXMEGA(self): if not hasattr(self, 'cwliteXMEGA'): self.enable_newattr() self.cwliteXMEGA = XMEGAProgrammerDialog() self.disable_newattr() return self.cwliteXMEGA def getCwliteAVR(self): if not hasattr(self, 'cwliteAVR'): self.enable_newattr() self.cwliteAVR = AVRProgrammerDialog() self.disable_newattr() return self.cwliteAVR def getSerialSTM32F(self): if not hasattr(self, 'serialSTM32F'): self.enable_newattr() self.serialSTM32F = STM32FProgrammerDialog() self.disable_newattr() return self.serialSTM32F
class CW305(TargetTemplate): """CW305 target object. This class contains the public API for the CW305 hardware. To connect to the CW305, the easiest method is:: import chipwhisperer as cw scope = cw.scope() # scope can also be None here, unlike with the default SimpleSerial target = cw.target(scope, targets.CW305, bsfile=<valid FPGA bitstream file>) As of CW5.3, you can also specify the following:: # can also be '35t' target = cw.target(scope, fpga_id='100t') To automatically program with the example AES bitstream If you're using the reference designs, typical configuration requires you to set the FPGA VCC-INT voltage and enable and set the clock via the PLL. You'll probably also want to disable the USB clock during encryption to reduce noise:: target.vccint_set(1.0) #set VCC-INT to 1V target.pll.pll_enable_set(True) #Enable PLL chip target.pll.pll_outenable_set(False, 0) # Disable unused PLL0 target.pll.pll_outenable_set(True, 1) # Enable PLL target.pll.pll_outenable_set(False, 2) # Disable unused PLL2 # optional, but reduces power trace noise target.clkusbautooff = True target.clksleeptime = 1 # 1ms typically good for sleep Don't forget to clock the ChipWhisperer ADC off the FPGA instead of the internal clock:: scope.clock.adc_src = "extclk_x4" scope.clock.reset_adc() # make sure the DCM is locked Note that connecting to the CW305 includes programming the CW305 FPGA, if it isn't already. For more help about CW305 settings, try help() on this CW305 submodule: * target.pll """ _name = "ChipWhisperer CW305 (Artix-7)" BATCHRUN_START = 0x1 BATCHRUN_RANDOM_KEY = 0x2 BATCHRUN_RANDOM_PT = 0x4 def __init__(self): TargetTemplate.__init__(self) self._naeusb = NAEUSB() self.pll = PLLCDCE906(self._naeusb, ref_freq=12.0E6) self.fpga = FPGA(self._naeusb) self.hw = None self.oa = None self._woffset = 0x400 self._woffset_sam3U = 0x000 self._clksleeptime = 1 self._clkusbautooff = True self.last_key = bytearray([0] * 16) def _getNAEUSB(self): return self._naeusb def fpga_write(self, addr, data): """Write to an address on the FPGA Args: addr (int): Address to write to data (list): Data to write to addr Raises: IOError: User attempted to write to a read-only location """ if addr < self._woffset: raise IOError("Write to read-only location: 0x%04x" % addr) return self._naeusb.cmdWriteMem(addr, data) def fpga_read(self, addr, readlen): """Read from an address on the FPGA Args: addr (int): Address to read from readlen (int): Length of data to read Returns: Requested data as a list """ if addr > self._woffset: logging.info( 'Read from write address, confirm this is not an error') data = self._naeusb.cmdReadMem(addr, readlen) return data def usb_clk_setenabled(self, status): """ Turn on or off the Data Clock to the FPGA """ if status: self._naeusb.sendCtrl(CW305_USB.REQ_SYSCFG, CW305_USB.SYSCFG_CLKON) else: self._naeusb.sendCtrl(CW305_USB.REQ_SYSCFG, CW305_USB.SYSCFG_CLKOFF) def usb_trigger_toggle(self, _=None): """ Toggle the trigger line high then low """ self._naeusb.sendCtrl(CW305_USB.REQ_SYSCFG, CW305_USB.SYSCFG_TOGGLE) def vccint_set(self, vccint=1.0): """ Set the VCC-INT for the FPGA """ # print "vccint = " + str(vccint) if (vccint < 0.6) or (vccint > 1.15): raise ValueError("VCC-Int out of range 0.6V-1.1V") # Convert to mV vccint = int(vccint * 1000) vccsetting = [vccint & 0xff, (vccint >> 8) & 0xff, 0] # calculate checksum vccsetting[2] = vccsetting[0] ^ vccsetting[1] ^ CW305_USB.VCCINT_XORKEY self._naeusb.sendCtrl(CW305_USB.REQ_VCCINT, 0, vccsetting) resp = self._naeusb.readCtrl(CW305_USB.REQ_VCCINT, dlen=3) if resp[0] != 2: raise IOError("VCC-INT Write Error, response = %d" % resp[0]) def vccint_get(self): """ Get the last set value for VCC-INT """ resp = self._naeusb.readCtrl(CW305_USB.REQ_VCCINT, dlen=3) return float(resp[1] | (resp[2] << 8)) / 1000.0 def _con(self, scope=None, bsfile=None, force=False, fpga_id=None): """Connect to CW305 board, and download bitstream. If the target has already been programmed it skips reprogramming unless forced. Args: scope (ScopeTemplate): An instance of a scope object. bsfile (path): The path to the bitstream file to program the FPGA with. force (bool): Whether or not to force reprogramming. fpga_id (string): '100t', '35t', or None. If bsfile is None and fpga_id specified, program with AES firmware for fpga_id """ from datetime import datetime self._naeusb.con(idProduct=[0xC305]) if not fpga_id is None: if fpga_id not in ('100t', '35t'): raise ValueError(f"Invalid fpga {fpga_id}") self._fpga_id = fpga_id if self.fpga.isFPGAProgrammed() == False or force: if bsfile is None: if not fpga_id is None: from chipwhisperer.hardware.firmware.cw305 import getsome bsdata = getsome(f"AES_{fpga_id}.bit") starttime = datetime.now() status = self.fpga.FPGAProgram(bsdata, exceptOnDoneFailure=False) stoptime = datetime.now() if status: logging.info('FPGA Config OK, time: %s' % str(stoptime - starttime)) else: logging.warning( 'FPGA Done pin failed to go high, check bitstream is for target device.' ) else: print("No FPGA Bitstream file specified.") elif not os.path.isfile(bsfile): print(("FPGA Bitstream not configured or '%s' not a file." % str(bsfile))) else: starttime = datetime.now() status = self.fpga.FPGAProgram(open(bsfile, "rb"), exceptOnDoneFailure=False) stoptime = datetime.now() if status: logging.info('FPGA Config OK, time: %s' % str(stoptime - starttime)) else: logging.warning( 'FPGA Done pin failed to go high, check bitstream is for target device.' ) self.usb_clk_setenabled(True) self.fpga_write(0x100 + self._woffset, [0]) self.pll.cdce906init() def _dis(self): if self._naeusb: self._naeusb.close() def checkEncryptionKey(self, key): """Validate encryption key""" return key def loadEncryptionKey(self, key): """Write encryption key to FPGA""" self.key = key key = key[::-1] self.fpga_write(0x100 + self._woffset, key) def loadInput(self, inputtext): """Write input to FPGA""" self.input = inputtext text = inputtext[::-1] self.fpga_write(0x200 + self._woffset, text) def is_done(self): """Check if FPGA is done""" result = self.fpga_read(0x50, 1)[0] if result == 0x00: return False else: # Clear trigger self.fpga_write(0x40 + self._woffset, [0]) # LED Off self.fpga_write(0x10 + self._woffset, [0]) return True isDone = camel_case_deprecated(is_done) def readOutput(self): """"Read output from FPGA""" data = self.fpga_read(0x200, 16) data = data[::-1] #self.newInputData.emit(util.list2hexstr(data)) return data @property def latest_fw(self): cw_type = self._getCWType() if cw_type == "cwlite": from chipwhisperer.hardware.firmware.cwlite import fwver elif cw_type == "cw1200": from chipwhisperer.hardware.firmware.cw1200 import fwver ret = OrderedDict() return {"major": fwver[0], "minor": fwver[1]} @property def fw_version(self): a = self._naeusb.readFwVersion() return {"major": a[0], "minor": a[1], "debug": a[2]} @property def clkusbautooff(self): """ If set, the USB clock is automatically disabled on capture. The USB clock is re-enabled after self.clksleeptime milliseconds. Reads/Writes to the FPGA will not be possible until after the USB clock is reenabled, meaning :code:`usb_trigger_toggle()` must be used to trigger the FPGA to perform an encryption. :Getter: Gets whether to turn off the USB clock on capture :Setter: Sets whether to turn off the USB clock on capture """ return self._clkusbautooff @clkusbautooff.setter def clkusbautooff(self, state): self._clkusbautooff = state @property def clksleeptime(self): """ Time (in milliseconds) that the USB clock is disabled for upon capture, if self.clkusbautooff is set. """ return self._clksleeptime @clksleeptime.setter def clksleeptime(self, value): self._clksleeptime = value def go(self): """Disable USB clock (if requested), perform encryption, re-enable clock""" if self.clkusbautooff: self.usb_clk_setenabled(False) #LED On self.fpga_write(0x10 + self._woffset, [0x01]) time.sleep(0.001) self.usb_trigger_toggle() # self.FPGAWrite(0x100, [1]) # self.FPGAWrite(0x100, [0]) if self.clkusbautooff: time.sleep(self.clksleeptime / 1000.0) self.usb_clk_setenabled(True) def simpleserial_read(self, cmd, pay_len, end='\n', timeout=250, ack=True): """Read data from target Mimics simpleserial protocol of serial based targets Args: cmd (str): Command to ues. Only accepts 'r' for now. pay_len: Unused end: Unused timeout: Unused ack: Unused Returns: Value from Crypto output register .. versionadded:: 5.1 Added simpleserial_read to CW305 """ if cmd == "r": return self.readOutput() else: raise ValueError("Unknown command {}".format(cmd)) def simpleserial_write(self, cmd, data, end=None): """Write data to target. Mimics simpleserial protocol of serial based targets. Args: cmd (str): Command to use. Target supports 'p' (write plaintext), and 'k' (write key). data (bytearray): Data to write to target end: Unused Raises: ValueError: Unknown command .. versionadded:: 5.1 Added simpleserial_write to CW305 """ if cmd == 'p': self.loadInput(data) self.go() elif cmd == 'k': self.loadEncryptionKey(data) else: raise ValueError("Unknown command {}".format(cmd)) def set_key(self, key, ack=False, timeout=250): """Checks if key is different from the last one sent. If so, send it. Args: key (bytearray): key to send ack: Unused timeout: Unused .. versionadded:: 5.1 Added set_key to CW305 """ if self.last_key != key: self.last_key = key self.simpleserial_write('k', key) def batchRun(self, batchsize=1024, random_key=True, random_pt=True, seed=None): """ Run multiple encryptions on random data Args: batchsize (int): The number of encryption to run (default 1024). random_key (bool): True if the key is random (default False). random_pt (bool): True if the plaintext are random (default True). seed (int): random int32 for the PRG. """ if seed is None: seed = random.randint(0, 2**32) data = [] data.extend( packuint32(1 | (random_key << 1) | (random_pt << 2) | (batchsize << 16))) data.extend(packuint32(seed)) self.sam3u_write(0, data) # generate the inputs if random_key: key = [[0 for x in range(16)] for y in range(batchsize)] else: key = None if random_pt: pt = [[0 for x in range(16)] for y in range(batchsize)] else: pt = None for b in range(batchsize): if random_key: for j in range(16): key[b][15 - j] = seed >> 24 seed += ((seed * seed) & 0xffffffff) | 0x5 seed &= 0xffffffff if random_pt: for j in range(16): pt[b][15 - j] = seed >> 24 seed += ((seed * seed) & 0xffffffff) | 0x5 seed &= 0xffffffff return key, pt def sam3u_write(self, addr, data): """Write to an address on the FPGA Args: addr (int): Address to write to data (list): Data to write to addr Raises: IOError: User attempted to write to a read-only location """ if addr < self._woffset_sam3U: raise IOError("Write to read-only location: 0x%04x" % addr) if len(data) > (256 + addr): raise IOError("Write will overflow at location: 0x%04x" % (256)) return self._naeusb.cmdWriteSam3U(addr, data) @fw_ver_required(0, 30) def spi_mode(self, enable=True, timeout=200, bsfile=None): """Enter programming mode for the onboard SPI chip Reprograms the FPGA with the appropriate bitstream and returns an object with which to program the CW305 SPI chip (see documentation on the returned object for more info) Args: enable (bool): Enable the SPI interface before returning it. Defaults to True timeout (int): USB timeout in ms. Defaults to 200. bsfile (string): If not None, program with a bitstream pointed to by bsfile. If None, program with SPI passthrough bitstream for the chip specified during connection (or cw.target()) Returns: A FPGASPI object which can be used to erase/program/verify/read the SPI chip on the CW305. """ from datetime import datetime if self._fpga_id is None and bsfile is None: logging.warning( "CW305 requires passthrough bitstream to program SPI chip, but file/chip not specified" ) else: bsdata = None if self._fpga_id: from chipwhisperer.hardware.firmware.cw305 import getsome bsdata = getsome(f"SPI_flash_{self._fpga_id}.bit") else: bsdata = open(bsfile, "rb") starttime = datetime.now() status = self.fpga.FPGAProgram(bsdata, exceptOnDoneFailure=False) stoptime = datetime.now() if status: logging.info('FPGA Config OK, time: %s' % str(stoptime - starttime)) else: logging.warning( 'FPGA Done pin failed to go high, check bitstream is for target device.' ) spi = FPGASPI(self._naeusb, timeout) spi.enable_interface(enable) return spi
class TraceWhisperer(): """ Trace interface object. This class contains the public API for the Arm Coresight trace sniffing hardware, which may exist on either the CW305 or the CW610 (PhyWhisperer) platform. To connect, the easiest method is:: (a) CW305 (DesignStart) case: import chipwhisperer as cw from chipwhisperer.capture.trace.TraceWhisperer import TraceWhisperer scope = cw.scope() target = cw.target(scope, targets.CW305, bsfile=<valid FPGA bitstream file>) trace = TraceWhisperer(target, scope) (b) CW610 (PhyWhisperer) case: import chipwhisperer as cw from chipwhisperer.capture.trace.TraceWhisperer import TraceWhisperer scope = cw.scope() target = cw.target(scope) trace = TraceWhisperer(target) """ _name = "TraceWhisperer" # must be in sync with firmware: regs = { 'DWT_CTRL': '00', 'DWT_COMP0': '01', 'DWT_COMP1': '02', 'ETM_CR': '03', 'ETM_TESSEICR': '04', 'ETM_TEEVR': '05', 'ETM_TECR1': '06', 'ETM_TRACEIDR': '07', 'TPI_ACPR': '08', 'TPI_SPPR': '09', 'TPI_FFCR': '0a', 'TPI_CSPSR': '0b', 'ITM_TCR': '0c' } rule_length = [0] * 8 longsync = [255, 255, 255, 127] shortsync = [255, 127] def __init__(self, target, scope, defines_files=None, bs='', force_bitfile=False): """ Args: target: SimpleSerial target scope: CW scope naeusb: NewAE USB interface platform (string): CW305 or CW610 (PhyWhisperer) defines_files (list of 2 strings): path to defines_trace.v and defines_pw.v """ super().__init__() self._trace_port_width = 4 self._base_target_clock = 7.384e6 self._base_baud = 38400 self._usb_clock = 96e6 self._uart_clock = self._usb_clock * 2 self.expected_verilog_defines = 107 self.swo_mode = False self.board_rev = 4 self._scope = scope # Detect whether we exist on CW305 or CW610 based on the target we're given: if target._name == 'Simple Serial': self.platform = 'CW610' self._ss = target self._naeusb = NAEUSB() self._naeusb.con(idProduct=[0xC610]) # we're using the CW NAEUSB, which has no knowledge of PW firmware, so let's manually # check the FW version here: fw_latest = [1, 1] if self._naeusb.readFwVersion()[0] < fw_latest[0]: logging.warning( 'Your PhyWhisperer firmware is outdated - latest is %d.%d' % (fw_latest[0], fw_latest[1]) + '. Suggested to update firmware, as you may experience errors.' ) self._fpga = FPGA(self._naeusb) if not self._fpga.isFPGAProgrammed() or force_bitfile: if not bs: bs = pkg_resources.resource_filename( 'chipwhisperer', 'hardware/firmware/tracewhisperer_top.bit') self._fpga.FPGAProgram(open(bs, 'rb'), exceptOnDoneFailure=False) else: self.platform = 'CW305' self._ss = cw.target(scope) self._naeusb = target._naeusb self.slurp_defines(defines_files) self._set_defaults() def _set_defaults(self): """ Set some registers which for various reasons don't reset to what we want them to. """ self.fpga_write(self.REG_CAPTURE_WHILE_TRIG, [1]) # TODO- temporary for development: self.fpga_write(self.REG_REVERSE_TRACEDATA, [0]) #self.set_reg('TPI_ACPR', '00000000') def reset_fpga(self): """ Reset FPGA registers to defaults, use liberally to clear incorrect states. On the CW305, this resets the full FPGA, including the Arm core. """ self.fpga_write(self.REG_RESET_REG, [1]) self.fpga_write(self.REG_RESET_REG, [0]) self._set_defaults() def slurp_defines(self, defines_files=None): """ Parse Verilog defines file so we can access register and bit definitions by name and avoid 'magic numbers'. """ self.verilog_define_matches = 0 if not defines_files: defines_files = [ pkg_resources.resource_filename( 'chipwhisperer', 'capture/trace/defines/defines_trace.v'), pkg_resources.resource_filename( 'chipwhisperer', 'capture/trace/defines/defines_pw.v') ] for i, defines_file in enumerate(defines_files): defines = open(defines_file, 'r') define_regex_base = re.compile(r'`define') define_regex_reg = re.compile(r'`define\s+?REG_') define_regex_radix = re.compile( r'`define\s+?(\w+).+?\'([bdh])([0-9a-fA-F]+)') define_regex_noradix = re.compile(r'`define\s+?(\w+?)\s+?(\d+?)') for define in defines: if define_regex_base.search(define): reg = define_regex_reg.search(define) match = define_regex_radix.search(define) if reg: if i == 0: block_offset = self.TRACE_REG_SELECT << 6 else: block_offset = self.MAIN_REG_SELECT << 6 else: block_offset = 0 if match: self.verilog_define_matches += 1 if match.group(2) == 'b': radix = 2 elif match.group(2) == 'h': radix = 16 else: radix = 10 setattr(self, match.group(1), int(match.group(3), radix) + block_offset) else: match = define_regex_noradix.search(define) if match: self.verilog_define_matches += 1 setattr(self, match.group(1), int(match.group(2), 10) + block_offset) else: logging.warning("Couldn't parse line: %s", define) defines.close() # make sure everything is cool: assert self.verilog_define_matches == self.expected_verilog_defines, "Trouble parsing Verilog defines file (%s): didn't find the right number of defines; expected %d, got %d" % ( defines_file, self.expected_verilog_defines, self.verilog_define_matches) def set_trace_mode(self, mode, swo_div=8, acpr=0): """Set trace or SWO mode. SWO mode is only available on CW610 platform. For SWO mode, we also adjust the target clock to match the SWO parameters. Args: mode (string): 'trace' or 'swo' swo_div (int): number of 96 MHz clock cycles per SWO bit (SWO mode only) acpr (int): value for TPI.ACPR register (SWO mode only) """ if mode == 'trace': self.swo_mode = False self.set_reg('TPI_SPPR', '00000000') self.fpga_write(self.REG_SWO_ENABLE, [0]) elif mode == 'swo': if self.platform == 'CW305': raise ValueError('CW305 does not support SWO mode') self.swo_mode = True self.set_reg('TPI_SPPR', '00000002') self.set_reg('TPI_ACPR', '%08x' % acpr) self.fpga_write( self.REG_SWO_BITRATE_DIV, [swo_div - 1] ) # not a typo: hardware requires -1; doing this is easier than fixing the hardware self.fpga_write(self.REG_SWO_ENABLE, [1]) # Next we set the target clock and update CW baud rate accordingly: new_target_clock = int(self._uart_clock / (swo_div * (acpr + 1))) self._scope.clock.clkgen_freq = new_target_clock self._ss.baud = int(self._base_baud * (new_target_clock / self._base_target_clock)) self.swo_target_clock_ratio = self._usb_clock / new_target_clock logging.info( "Ensure target is in SWD mode, e.g. using jtag_to_swd().") else: logging.error('Invalid mode %s: specify "trace" or "swo"', mode) def set_capture_mode(self, mode, counts=0): """Determine the duration of the trace capture. Args: mode (string): 'while_trig' or 'count_cycles' or 'count_writes' counts (int): number of cycles (mode == 'count_cycles') or writes (mode == 'count_writes') to capture for (0 = capture until full) """ if mode == 'while_trig': self.fpga_write(self.REG_CAPTURE_WHILE_TRIG, [1]) elif mode == 'count_cycles': self.fpga_write(self.REG_CAPTURE_WHILE_TRIG, [0]) self.fpga_write(self.REG_COUNT_WRITES, [0]) self.fpga_write(self.REG_CAPTURE_LEN, int.to_bytes(counts, length=4, byteorder='little')) elif mode == 'count_writes': self.fpga_write(self.REG_CAPTURE_WHILE_TRIG, [0]) self.fpga_write(self.REG_COUNT_WRITES, [1]) self.fpga_write(self.REG_CAPTURE_LEN, int.to_bytes(counts, length=4, byteorder='little')) else: logging.error('Invalid mode %s') def set_board_rev(self, rev): """For development only - the rev3 board has different pin assignments. The board revision must be set correctly both here and in the FPGA. This convenience function ensures both are set properly. Args: rev (int): 3 or 4 """ assert rev in [3, 4] self.board_rev = rev self.fpga_write(self.REG_BOARD_REV, [rev]) def jtag_to_swd(self): """Switch to SWD mode by driving the JTAG-to-SWD sequence on TMS/TCK. (reference: https://developer.arm.com/documentation/ka001179/1-0/) Args: none """ if self.board_rev == 3: self.tms_bit = 0 self.tck_bit = 2 elif self.board_rev == 4: self.tms_bit = 0 self.tck_bit = 1 self.fpga_write(self.REG_USERIO_PWDRIVEN, [(1 << self.tms_bit) + (1 << self.tck_bit)]) self.fpga_write(self.REG_USERIO_DATA, [1 << self.tms_bit]) self._line_reset() self._send_tms_byte(0x9e) self._send_tms_byte(0xe7) self._line_reset() self.fpga_write(self.REG_USERIO_DATA, [1 << self.tms_bit]) self.fpga_write(self.REG_USERIO_PWDRIVEN, [0]) def _send_tms_byte(self, data): """Bit-bang 8 bits of data on TMS/TCK (LSB first). Args: data (int): 8 bits data to send. """ for i in range(8): bit = (data & 2**i) >> i self.fpga_write(self.REG_USERIO_DATA, [bit << self.tms_bit]) self.fpga_write(self.REG_USERIO_DATA, [(1 << self.tck_bit) + (bit << self.tms_bit)]) def _line_reset(self, num_bytes=8): """Bit-bang a line reset on TMS/TCK. Args: none """ for i in range(num_bytes): self._send_tms_byte(0xff) def check_clocks(self): """Check that PLLs are locked. Args: none """ locks = self.fpga_read(self.REG_MMCM_LOCKED, 1)[0] assert (locks & 2) == 2, 'Trigger/UART clock not locked!' if not self.swo_mode and self.platform == 'CW610': assert (locks & 1) == 1, 'Trace clock not locked!' def simpleserial_write(self, cmd, data, printresult=False): """Convenience function to send a simpleserial command to the simpleserial target, and optionally fetch and print the result. """ self._ss.simpleserial_write(cmd, data) if printresult: time.sleep(0.6) # ECC is slow! print(self._ss.read().split('\n')[0]) def set_reg(self, reg, data, printresult=False): """Set a Cortex debug register Args: reg (string): Register to write. See self.regs for available registers. data (string): 8-character hex string, value to write to specified register (e.g. '1000F004') """ if reg in self.regs: data = self.regs[reg] + data self._ss.simpleserial_write('s', util.hexStrToByteArray(data)) time.sleep(0.1) if printresult: print(self._ss.read().split('\n')[0]) else: logging.error('Register %s does not exist.', reg) def get_reg(self, reg): """Reads a Cortex debug register Args: reg (string): Register to read. See self.regs for available registers. """ if reg in self.regs: data = self.regs[reg] + '00000000' self._ss.simpleserial_write('g', util.hexStrToByteArray(data)) time.sleep(0.1) return self._ss.read().split('\n')[0][1:] else: logging.error('Register %s does not exist.', reg) def set_pattern_match(self, index, pattern, mask=[0xff] * 8): """Sets pattern match and mask parameters Args: index: match index [0-7] pattern: list of 8-bit integers, pattern match value mask: list of 8-bit integers, pattern mask value """ self.fpga_write(self.REG_TRACE_PATTERN0 + index, pattern) self.fpga_write(self.REG_TRACE_MASK0 + index, mask) # count trailing zeros in the mask, as these determine how much time elapses from # the start of receiving a trace packet, until the match is determined -- so that the # recorded timestamp can be rolled back to when the trace packet began trailing_zeros = 0 for m in mask[::-1]: if not m: trailing_zeros += 1 self.rule_length[index] = 8 - trailing_zeros def arm_trace(self): """Arms trace sniffer for capture; also checks sync status. """ self.fpga_write(self.REG_ARM, [1]) self.synced() def synced(self): """Checks that trace trigger module is synchronized. """ assert self.fpga_read(self.REG_SYNCHRONIZED, 1)[0] == 1, 'Not synchronized!' def resync(self): """Force trace sniffer to resynchronize (using sync frames that are continously emitted on the parallel trace port). Failure could be from absence of a trace clock, or mis-sampling of trace data due to setup/hold violations (clock edge too close to data edge). """ self.fpga_write(self.REG_TRACE_RESET_SYNC, [1]) self.synced() def is_done(self): """Calls SimpleSerial target's is_done(). """ return self._ss.is_done() def fpga_write(self, addr, data): """Write to an FPGA register. Args: addr (int): Address to write to data (list): Data to write to addr """ # on CW305, change word address to byte address (CW610 uses addressing differently) if self.platform == 'CW305': addr = addr << 7 return self._naeusb.cmdWriteMem(addr, data) def fpga_read(self, addr, readlen=4): """Read from an FPGA register. Args: addr (int): Address to read from readlen (int): Length of data to read Returns: Requested data as a list """ # on CW305, change word address to byte address (CW610 uses addressing differently) if self.platform == 'CW305': addr = addr << 7 data = self._naeusb.cmdReadMem(addr, readlen) return data def check_fifo_errors(self, underflow=0, overflow=0): """Check whether an underflow or overflow occured on the capture FIFO. Args: underflow (int, optional): expected status, 0 or 1 overflow (int, optional): expected status, 0 or 1 """ status = self.fpga_read(self.REG_SNIFF_FIFO_STAT, 1)[0] fifo_underflow = (status & 2) >> 1 fifo_overflow = (status & 16) >> 4 assert fifo_underflow == underflow assert fifo_overflow == overflow def fifo_empty(self): """Returns True if the capture FIFO is empty, False otherwise. """ if self.fpga_read(self.REG_SNIFF_FIFO_STAT, 1)[0] & 1: return True else: return False def get_fpga_buildtime(self): """Returns date and time when FPGA bitfile was generated. """ raw = self.fpga_read(addr=self.REG_BUILDTIME, readlen=4) # definitions: Xilinx XAPP1232 day = raw[3] >> 3 month = ((raw[3] & 0x7) << 1) + (raw[2] >> 7) year = ((raw[2] >> 1) & 0x3f) + 2000 hour = ((raw[2] & 0x1) << 4) + (raw[1] >> 4) minute = ((raw[1] & 0xf) << 2) + (raw[0] >> 6) return "FPGA build time: {}/{}/{}, {}:{}".format( month, day, year, hour, minute) def get_fw_buildtime(self): """Returns date and time when target FW was compiled. """ self._ss.simpleserial_write('i', b'') time.sleep(0.1) return self._ss.read().split('\n')[0] def get_target_name(self): """Returns project-specific 'name' embedded in target bitfile """ nameb = self.fpga_read(self.REG_NAME, 8) names = '' for i in nameb: names += hex(i)[2:] return bytearray.fromhex(names).decode() def test_itm(self, port=1): """Print test string via ITM using specified port number. Args: port (int): ITM port number to use. """ self._ss.simpleserial_write('t', bytearray([port])) time.sleep(0.1) print(self._ss.read().split('\n')[0]) def read_capture_data(self): """Read captured trace data. Returns: List of captured entries. Each list element is itself a 3-element list, containing the 3 bytes that make up a capture entry. Can be parsed by get_rule_match_times() or get_raw_trace_packets(). See defines_trace.v for definition of the FIFO data fields. """ data = [] starttime = time.time() # first check for FIFO to not be empty: assert self.fifo_empty() == False, 'FIFO is empty' # then check that no underflows or overflows occurred during capture: self.check_fifo_errors() while not self.fifo_empty(): data.append(self.fpga_read(self.REG_SNIFF_FIFO_RD, 4)[1:4]) if len(data): # maybe we only got empty reads if data[-1][2] & 2**self.FE_FIFO_STAT_UNDERFLOW: logging.warning("Capture FIFO underflowed!") return data def print_raw_data(self, rawdata): """Prints collected raw data in hexadecimal. Raw data includes data type, timestamp, and payload. See defines_trace.v for bitfield definitions. """ for e in rawdata: entry = 0 entry += (e[2] & 0x3) << 16 entry += e[1] << 8 entry += e[0] print('%05x' % entry) def get_rule_match_times(self, rawdata, rawtimes=False, verbose=False): """Split raw capture data into data events and times, stat events and times. Args: rawdata: raw capture data, list of lists, e.g. obtained from read_capture_data() rawtimes: True: return reported times (obtained at the *end* of the pattern match) False: roll back times to the *start* of the pattern match verbose: print timestamped rules Returns: list of [time, rule index] tuples """ times = [] timecounter = 0 lasttime = 0 lastadjust = 0 for raw in rawdata: command = raw[2] & 0x3 if command == self.FE_FIFO_CMD_DATA: timecounter += raw[0] data = raw[1] rule = int(math.log2(data)) if rawtimes: adjust = 0 else: adjust = self.rule_length[rule] * self._cycles_per_byte() timecounter = timecounter - adjust + lastadjust delta = timecounter - lasttime lasttime = timecounter lastadjust = adjust if verbose: print("%8d rule # %d, delta = %d" % (timecounter, rule, delta)) times.append([timecounter, rule]) elif command == self.FE_FIFO_CMD_TIME: timecounter += raw[0] + (raw[1] << 8) elif command == self.FE_FIFO_CMD_STAT: raise ValueError( "Unexpected STAT command, not supported by this method; maybe try get_raw_trace_packets() instead?" ) elif command == self.FE_FIFO_CMD_STRM: pass return times def _cycles_per_byte(self): """Returns number of clock cycles needed to send one byte of trace data over the trace or SWO port. """ if self.swo_mode: return 8 else: return 8 / self._trace_port_width def get_raw_trace_packets(self, rawdata, removesyncs=True, verbose=False): """Split raw capture data into pseudo-frames, optionally suppressing sync frames (and using those sync frames as marker which is separating pseudo-frames). It's the best we can do without actually parsing the trace packets, which is best left to other tools! Args: rawdata: raw capture data, list of lists, e.g. obtained from read_capture_data() verbose: print timestamped packets Returns: list of pseudo-frames """ pseudoframes = [] pseudoframe = [] timecounter = 0 lasttime = 0 for raw in rawdata: command = raw[2] & 0x3 if command == self.FE_FIFO_CMD_STAT: timecounter += raw[0] data = raw[1] if not len(pseudoframe): starttime = timecounter pseudoframe.append(data) if removesyncs: if pseudoframe[-len(self.longsync):] == self.longsync: pseudoframe = pseudoframe[:-len(self.longsync)] sync_removed = True #print('Removed long') elif pseudoframe[-len(self.shortsync):] == self.shortsync: pseudoframe = pseudoframe[:-len(self.shortsync)] sync_removed = True #print('Removed short') else: sync_removed = False else: sync_removed = False if sync_removed and len(pseudoframe): pseudoframes.append([starttime, pseudoframe]) if verbose: print("Pseudoframe: ", end='') for b in pseudoframe: print('%02x ' % b, end='') print() pseudoframe = [] delta = timecounter - lasttime lasttime = timecounter elif command == self.FE_FIFO_CMD_TIME: timecounter += raw[0] + (raw[1] << 8) elif command == self.FE_FIFO_CMD_DATA: raise ValueError( "Unexpected DATA command, not supported by this method; maybe try get_rule_match_times() instead?" ) elif command == self.FE_FIFO_CMD_STRM: pass if not removesyncs: pseudoframes.append([starttime, pseudoframe]) return pseudoframes def use_soft_trigger(self): """ Use target-generated trigger to initiate trace capture. """ self.fpga_write(self.REG_SOFT_TRIG_ENABLE, [1]) self.fpga_write(self.REG_SOFT_TRIG_PASSTHRU, [1]) self.fpga_write(self.REG_PATTERN_TRIG_ENABLE, [0]) def use_trace_trigger(self, rule=0): """ Use matching trace data to initiate trace capture. Args: rule (int): rule number to use """ self.fpga_write(self.REG_SOFT_TRIG_ENABLE, [0]) self.fpga_write(self.REG_SOFT_TRIG_PASSTHRU, [0]) self.fpga_write(self.REG_PATTERN_TRIG_ENABLE, [2**rule]) self.fpga_write(self.REG_TRIGGER_ENABLE, [1]) # these can be customized but let's start you off with simple default values: self.fpga_write(self.REG_NUM_TRIGGERS, [1]) self.fpga_write(self.REG_TRIGGER_WIDTH, [16]) def set_isync_matches(self, addr0=0, addr1=0, match=None): """ Set exact PC address matching rules. Args: addr0 (int): Matching address 0 (DWT_COMP0) addr1 (int): Matching address 0 (DWT_COMP1) match: None: disable PC address match packets 0: enable addr0 matching only 1: enable addr1 matching only "both": enable both addr0 and addr1 matching """ self.set_reg('DWT_COMP0', '%08x' % addr0) self.set_reg('DWT_COMP1', '%08x' % addr1) if match == None: self.set_reg('ETM_TEEVR', '00000000') elif match == 0: self.set_reg('ETM_TEEVR', '00000020') elif match == 1: self.set_reg('ETM_TEEVR', '00000021') elif match == 'both': self.set_reg('ETM_TEEVR', '000150a0') def set_periodic_pc_sampling(self, enable=1, cyctap=0, postinit=1, postreset=0): """ Set periodic PC sampling parameters. Enabling PC sampling through this method will start PC sampling *after* the target triggers, thereby ensuring that the resulting trace data can be parsed without trouble. Alternatively, you can set the DWT_CTRL register directly. Args: enable (int): enable or disable periodic PC sampling cyctap (int): DWT_CTRL.CYCTAP bit postinit (int): DWT_CTRL.POSTINIT bits postreset (int): DWT_CTRL.POSTRESET bits """ self.simpleserial_write('c', bytearray( [enable, cyctap, postinit, postreset]), printresult=False) def write_raw_capture(self, raw, filename='raw.bin', presyncs=8): """Writes raw trace data to a file (which can be read by orbuculum). Prepends a number of sync frames to facilitate parsing. Args: raw (array): raw trace data as obtained from get_raw_trace_packets() filename (string): output file presyncs (int): number of long syncronization frames which are prepended to the collected trace data. """ binout = open(filename, "wb") for i in range(presyncs): binout.write(bytes(self.longsync)) for frame in raw: binout.write(bytes(frame[1])) binout.close()
class CWNano(ScopeTemplate, util.DisableNewAttr): """CWNano scope object. This class contains the public API for the CWNano hardware. It includes specific settings for each of these devices. To connect to one of these devices, the easiest method is:: import chipwhisperer as cw scope = cw.scope(type=scopes.CWNano) Some sane default settings can be set using:: scope.default_setup() For more help about scope settings, try help() on each of the ChipWhisperer scope submodules (scope.adc, scope.io, scope.glitch): * :attr:`scope.adc <.CWNano.adc>` * :attr:`scope.io <.CWNano.io>` * :attr:`scope.glitch <.CWNano.glitch>` * :meth:`scope.default_setup <.CWNano.default_setup>` * :meth:`scope.con <.CWNano.con>` * :meth:`scope.dis <.CWNano.dis>` * :meth:`scope.get_last_trace <.CWNano.get_last_trace>` * :meth:`scope.arm <.CWNano.arm>` * :meth:`scope.capture <.CWNano.capture>` """ _name = "ChipWhisperer Nano" REQ_ARM = 0x29 REQ_SAMPLES = 0x2A def __init__(self): ScopeTemplate.__init__(self) self._is_connected = False self._cwusb = NAEUSB() self.ser = self._cwusb self.scopetype = self self.dev = self self.xmega = XMEGAPDI(self._cwusb) self.avr = AVRISP(self._cwusb) self.usart = USART(self._cwusb) self.serialstm32f = STM32FSerial(cwserial=self.usart) self.serialstm32f.scope = self self.io = GPIOSettings(self._cwusb) self.adc = ADCSettings(self._cwusb) self.glitch = GlitchSettings(self._cwusb) self._timeout = 2 self._lasttrace = None self.disable_newattr() def default_setup(self): """ Sets up sane capture defaults for this scope * 7.5MHz ADC clock * 7.5MHz output clock * 5000 capture samples * tio1 = serial rx * tio2 = serial tx * glitch module off .. versionadded:: 5.1 Added default setup for CWNano """ self.adc.clk_freq = 7.5E6 self.io.clkout = 7.5E6 self.adc.samples = 5000 self.io.tio1 = "serial_rx" self.io.tio2 = "serial_tx" self.glitch.repeat = 0 def getCurrentScope(self): return self def _getNAEUSB(self): return self._cwusb @property def sn(self): return self._cwusb.snum @property def latest_fw(self): from chipwhisperer.hardware.firmware.cwnano import fwver return {"major": fwver[0], "minor": fwver[1]} @property def fw_version(self): a = self._cwusb.readFwVersion() return {"major": a[0], "minor": a[1], "debug": a[2]} def _con(self, sn=None): try: possible_sn = self._cwusb.get_possible_devices(idProduct=[0xACE0]) serial_numbers = [] if len(possible_sn) > 1: if sn is None: for d in possible_sn: serial_numbers.append("sn = {} ({})".format(str(d['sn']), str(d['product']))) raise Warning("Multiple ChipWhisperers detected. Please specify device from the following list using cw.scope(sn=<SN>): \n{}".format(serial_numbers)) else: sn = None found_id = self._cwusb.con(idProduct=[0xACE0], serial_number=sn) except (IOError, ValueError): raise Warning("Could not connect to cwnano. It may have been disconnected, is in an error state, or is being used by another tool.") self.disable_newattr() self._is_connected = True return True def _dis(self): self.enable_newattr() self.usbdev().close() self._is_connected = False return True def arm(self): """Arm the ADC, the trigger will be GPIO4 rising edge (fixed trigger).""" with DelayedKeyboardInterrupt(): if self.connectStatus is False: raise Warning("Scope \"" + self.getName() + "\" is not connected. Connect it first...") self._cwusb.sendCtrl(self.REQ_ARM, 1) def capture(self): """Raises IOError if unknown failure, returns 'True' if timeout, 'False' if no timeout""" with DelayedKeyboardInterrupt(): starttime = datetime.datetime.now() while self._cwusb.readCtrl(self.REQ_ARM, dlen=1)[0] == 0: # Wait for a moment before re-running the loop time.sleep(0.001) diff = datetime.datetime.now() - starttime # If we've timed out, don't wait any longer for a trigger if (diff.total_seconds() > self._timeout): logging.warning('Timeout in cwnano capture()') return True self._lasttrace = self._cwusb.cmdReadMem(0, self.adc.samples) # can just keep rerunning this until it works I think i = 0 while len(self._lasttrace) < self.adc.samples: logging.debug("couldn't read ADC data from Nano, retrying...") self._lasttrace = self._cwusb.cmdReadMem(0, self.adc.samples) i+= 1 if i > 20: logging.warning("Couldn't read trace data back from Nano") return True self._lasttrace = np.array(self._lasttrace) / 256.0 - 0.5 #self.newDataReceived(0, self._lasttrace, 0, self.adc.clk_freq) return False def get_last_trace(self): """Return the last trace captured with this scope. """ return self._lasttrace getLastTrace = camel_case_deprecated(get_last_trace) def _dict_repr(self): dict = OrderedDict() dict['fw_version'] = self.fw_version dict['io'] = self.io._dict_repr() dict['adc'] = self.adc._dict_repr() dict['glitch'] = self.glitch._dict_repr() return dict def __repr__(self): # Add some extra information about ChipWhisperer type here if self._is_connected: ret = "ChipWhisperer Nano Device\n" return ret + dict_to_str(self._dict_repr()) else: ret = "ChipWhisperer Nano device (disconnected)" return ret def __str__(self): return self.__repr__() def get_possible_devices(self, idProduct): return self._cwusb.get_possible_devices(idProduct=idProduct) def usbdev(self): return self._cwusb
class CW305(TargetTemplate): _name = "ChipWhisperer CW305 (Artix-7)" def __init__(self, parentParam=None): TargetTemplate.__init__(self, parentParam) self._naeusb = NAEUSB() self.pll = PLLCDCE906(self._naeusb, ref_freq = 12.0E6, parent=self) self.fpga = FPGA(self._naeusb) self.hw = None # self._fpgabs = QSettings().value("cw305-bitstream", '') self.oa = None self._woffset = 0x400 self.params.addChildren([ {'name':'PLL Settings', 'key':'pll', 'type':'group', 'children':[ {'name':'Enabled', 'key':'pllenabled', 'type':'bool', 'default':False, 'set':self.pll.pll_enable_set, 'get':self.pll.pll_enable_get, 'psync':False}, {'name':'CLK-SMA (X6)', 'key':'pll0', 'type':'group', 'children':[ {'name':'CLK-SMA Enabled', 'key':'pll0enabled', 'type':'bool', 'default':False, 'set':partial(self.pll.pll_outenable_set, outnum=0), 'get':partial(self.pll.pll_outenable_get, outnum=0), 'psync':False}, {'name':'CLK-SMA Source', 'key':'pll0source', 'type':'list', 'values':['PLL0', 'PLL1', 'PLL2'], 'default':'PLL0', 'set':partial(self.pll.pll_outsource_set, outnum=0), 'get':partial(self.pll.pll_outsource_get, outnum=0), 'psync':False}, {'name':'CLK-SMA Slew Rate', 'key':'pll0slew', 'type':'list', 'values':['+3nS', '+2nS', '+1nS', '+0nS'], 'default':'+0nS', 'set':partial(self.pll.pll_outslew_set, outnum=0), 'get':partial(self.pll.pll_outslew_get, outnum=0), 'psync':False}, {'name':'PLL0 Frequency', 'key':'pll0freq', 'type':'float', 'limits':(0.625E6, 167E6), 'default':0, 'step':1E6, 'siPrefix':True, 'suffix':'Hz', 'set':partial(self.pll.pll_outfreq_set, outnum=0), 'get':partial(self.pll.pll_outfreq_get, outnum=0), 'psync':False}, ]}, {'name':'CLK-N13 (FGPA Pin N13)', 'key':'pll1', 'type':'group', 'children':[ {'name':'CLK-N13 Enabled', 'key':'pll1enabled', 'type':'bool', 'default':False, 'set':partial(self.pll.pll_outenable_set, outnum=1), 'get':partial(self.pll.pll_outenable_get, outnum=1), 'psync':False}, {'name':'CLK-N13 Source', 'key':'pll1source', 'type':'list', 'values':['PLL1'], 'value':'PLL1'}, {'name':'CLK-N13 Slew Rate', 'key':'pll1slew', 'type':'list', 'values':['+3nS', '+2nS', '+1nS', '+0nS'], 'default':'+0nS', 'set':partial(self.pll.pll_outslew_set, outnum=1), 'get':partial(self.pll.pll_outslew_get, outnum=1), 'psync':False}, {'name':'PLL1 Frequency', 'key':'pll1freq', 'type':'float', 'limits':(0.625E6, 167E6), 'default':0, 'step':1E6, 'siPrefix':True, 'suffix':'Hz', 'set':partial(self.pll.pll_outfreq_set, outnum=1), 'get':partial(self.pll.pll_outfreq_get, outnum=1), 'psync':False}, ]}, {'name':'CLK-E12 (FGPA Pin E12)', 'key':'pll2', 'type':'group', 'children':[ {'name':'CLK-E12 Enabled', 'key':'pll2enabled', 'type':'bool', 'default':False, 'set':partial(self.pll.pll_outenable_set, outnum=2), 'get':partial(self.pll.pll_outenable_get, outnum=2), 'psync':False}, {'name':'CLK-E12 Source', 'key':'pll2source', 'type':'list', 'values':['PLL2'], 'value':'PLL2'}, {'name':'CLK-E12 Slew Rate', 'key':'pll2slew', 'type':'list', 'values':['+0nS', '+1nS', '+2nS', '+3nS'], 'default':'+0nS', 'set':partial(self.pll.pll_outslew_set, outnum=2), 'get':partial(self.pll.pll_outslew_get, outnum=2), 'psync':False}, {'name':'PLL2 Frequency', 'key':'pll2freq', 'type':'float', 'limits':(0.625E6, 167E6), 'default':0, 'step':1E6, 'siPrefix':True, 'suffix':'Hz', 'set':partial(self.pll.pll_outfreq_set, outnum=2), 'get':partial(self.pll.pll_outfreq_get, outnum=2), 'psync':False}, ]}, {'name':'Save as Default (stored in EEPROM)', 'type':'action', 'action':lambda _ : self.pll.pll_writedefaults()}, ]}, {'name':'Disable CLKUSB For Capture', 'key':'clkusbautooff', 'type':'bool', 'value':True}, {'name':'Time CLKUSB Disabled for', 'key':'clksleeptime', 'type':'int', 'range':(1, 50000), 'value':50, 'suffix':'mS'}, {'name':'CLKUSB Manual Setting', 'key':'clkusboff', 'type':'bool', 'value':True, 'action':self.usb_clk_setenabled_action}, {'name':'Send Trigger', 'type':'action', 'action':self.usb_trigger_toggle}, {'name':'VCC-INT', 'key':'vccint', 'type':'float', 'default':1.00, 'range':(0.6, 1.10), 'suffix':' V', 'decimals':3, 'set':self.vccint_set, 'get':self.vccint_get}, {'name':'FPGA Bitstream', 'type':'group', 'children':[ {'name':'Bitstream File', 'key':'fpgabsfile', 'type':'file', 'value':"", "filter":'*.bit'}, {'name':'Program FPGA', 'type':'action', 'action':self.gui_programfpga}, ]}, ]) def fpga_write(self, addr, data): """ Write to specified address """ if addr < self._woffset: raise IOError("Write to read-only location: 0x%04x"%addr) return self._naeusb.cmdWriteMem(addr, data) def fpga_read(self, addr, readlen): """ Read from address """ if addr > self._woffset: print "NOTE: Read from write address, confirm this is not an error" data = self._naeusb.cmdReadMem(addr, readlen) return data def usb_clk_setenabled_action(self, p): self.usb_clk_setenabled(p.getValue()) def usb_clk_setenabled(self, status): """ Turn on or off the Data Clock to the FPGA """ if status: self._naeusb.sendCtrl(CW305_USB.REQ_SYSCFG, CW305_USB.SYSCFG_CLKON) else: self._naeusb.sendCtrl(CW305_USB.REQ_SYSCFG, CW305_USB.SYSCFG_CLKOFF) def usb_trigger_toggle(self, _=None): """ Toggle the trigger line high then low """ self._naeusb.sendCtrl(CW305_USB.REQ_SYSCFG, CW305_USB.SYSCFG_TOGGLE) @setupSetParam("VCC-INT") def vccint_set(self, vccint=1.0): """ Set the VCC-INT for the FPGA """ # print "vccint = " + str(vccint) if (vccint < 0.6) or (vccint > 1.15): raise ValueError("VCC-Int out of range 0.6V-1.1V") # Convert to mV vccint = int(vccint * 1000) vccsetting = [vccint & 0xff, (vccint >> 8) & 0xff, 0] # calculate checksum vccsetting[2] = vccsetting[0] ^ vccsetting[1] ^ CW305_USB.VCCINT_XORKEY self._naeusb.sendCtrl(CW305_USB.REQ_VCCINT, 0, vccsetting) resp = self._naeusb.readCtrl(CW305_USB.REQ_VCCINT, dlen=3) if resp[0] != 2: raise IOError("VCC-INT Write Error, response = %d" % resp[0]) def vccint_get(self): """ Get the last set value for VCC-INT """ resp = self._naeusb.readCtrl(CW305_USB.REQ_VCCINT, dlen=3) return float(resp[1] | (resp[2] << 8)) / 1000.0 def gui_programfpga(self, _=None): bsfile = self.params.getChild(['FPGA Bitstream',"fpgabsfile"]).getValue() if not os.path.isfile(bsfile): raise Warning("FPGA Bitstream not configured or %s not a file." % str(bsfile)) starttime = datetime.now() self.fpga.FPGAProgram(open(bsfile, "rb")) stoptime = datetime.now() print "FPGA Config time: %s" % str(stoptime - starttime) def con(self, scope = None, bsfile=None, force = False): """Connect to CW305 board, download bitstream""" self._naeusb.con(idProduct=0xC305) if self.fpga.isFPGAProgrammed() == False or force: bsfile = self.params.getChild(['FPGA Bitstream',"fpgabsfile"]).getValue() if not os.path.isfile(bsfile): print("FPGA Bitstream not configured or %s not a file." % str(bsfile)) else: from datetime import datetime starttime = datetime.now() self.fpga.FPGAProgram(open(bsfile, "rb")) stoptime = datetime.now() print "FPGA Config time: %s" % str(stoptime - starttime) self.usb_clk_setenabled(True) self.fpga_write(0x100+self._woffset, [0]) self.params.refreshAllParameters() self.pll.cdce906init() self.connectStatus.setValue(True) def checkEncryptionKey(self, key): """Validate encryption key""" return key def loadEncryptionKey(self, key): """Write encryption key to FPGA""" self.key = key key = key[::-1] self.fpga_write(0x100+self._woffset, key) def loadInput(self, inputtext): """Write input to FPGA""" self.input = inputtext text = inputtext[::-1] self.fpga_write(0x200+self._woffset, text) def isDone(self): """Check if FPGA is done""" result = self.fpga_read(0x50, 1)[0] if result == 0x00: return False else: # Clear trigger self.fpga_write(0x40+self._woffset, [0]) # LED Off self.fpga_write(0x10+self._woffset, [0]) return True def readOutput(self): """"Read output from FPGA""" data = self.fpga_read(0x200, 16) data = data[::-1] return data def go(self): """Disable USB clock (if requested), perform encryption, re-enable clock""" if self.findParam('clkusbautooff').getValue(): self.usb_clk_setenabled(False) #LED On self.fpga_write(0x10+self._woffset, [0x01]) time.sleep(0.01) self.usb_trigger_toggle() # self.FPGAWrite(0x100, [1]) # self.FPGAWrite(0x100, [0]) if self.findParam('clkusbautooff').getValue(): time.sleep(self.findParam('clksleeptime').getValue() / 1000.0) self.usb_clk_setenabled(True)
class CW310(CW305): def __init__(self, *args, **kwargs): # maybe later can hijack cw305 stuff, but for now don't pass import chipwhisperer as cw self._naeusb = NAEUSB() self.pll = PLLCDCE906(self._naeusb, ref_freq=12.0E6) self.fpga = FPGA(self._naeusb) self.hw = None self.oa = None self._woffset_sam3U = 0x000 self.default_verilog_defines = 'cw305_defines.v' self.default_verilog_defines_full_path = os.path.dirname( cw.__file__ ) + '/../../hardware/victims/cw305_artixtarget/fpga/common/' + self.default_verilog_defines self.registers = 12 # number of registers we expect to find self.bytecount_size = 7 # pBYTECNT_SIZE in Verilog self._clksleeptime = 1 self._clkusbautooff = True self.last_key = bytearray([0] * 16) self.target_name = 'AES' def _con(self, scope=None, bsfile=None, force=False, fpga_id=None, defines_files=None, slurp=True): # add more stuff later self._naeusb.con(idProduct=[0xC310]) # self.pll.cdce906init() if defines_files is None: if fpga_id is None: verilog_defines = [self.default_verilog_defines_full_path] else: from chipwhisperer.hardware.firmware.cw305 import getsome verilog_defines = [getsome(self.default_verilog_defines)] else: verilog_defines = defines_files if slurp: self.slurp_defines(verilog_defines) if bsfile: status = self.fpga.FPGAProgram(open(bsfile, "rb")) def usb_set_voltage(self, pdo_num, voltage): if pdo_num not in [2, 3]: raise ValueError("pdo_num must be 2 or 3, {}".format(pdo_num)) if (voltage > 20 or voltage < 5): raise ValueError( "Voltage must be between 5 and 20, {}".format(voltage)) self._naeusb.sendCtrl(0x40, 0, [0x28, 0x89 + (pdo_num - 2) * (0x04)]) snk_pdo = self._naeusb.readCtrl(0x41, 0, 4) voltage *= 20 voltage = int(voltage) snk_pdo[1] &= ~0xFC snk_pdo[2] &= ~0x0F print(snk_pdo) snk_pdo[1] |= ((voltage << 2) & 0xFC) snk_pdo[2] |= ((voltage >> 6) & 0x0F) print(voltage) print(snk_pdo) self._naeusb.sendCtrl(0x41, 0, snk_pdo) def usb_set_current(self, pdo_num, current): if pdo_num not in [2, 3]: raise ValueError("pdo_num must be 2 or 3, {}".format(pdo_num)) if (current > 5 or current < 0.5): raise ValueError( "Voltage must be between 0.5 and 20, {}".format(voltage)) snk_pdo = self._naeusb.readCtrl(0x41, 0, 4) current *= 100 current = int(current) snk_pdo[0] &= ~0xFF snk_pdo[1] &= ~0x03 print(snk_pdo) snk_pdo[0] |= (current & 0xFF) snk_pdo[1] |= ((current >> 8) & 0x03) print(current) print(snk_pdo) self._naeusb.sendCtrl(0x41, 0, snk_pdo) def usb_negotiate_pdo(self): #soft reset self._naeusb.sendCtrl(0x40, 0, [0x28, 0x51]) self._naeusb.sendCtrl(0x41, 0, [0x0D]) #send reset on pdo bus self._naeusb.sendCtrl(0x40, 0, [0x28, 0x1A]) self._naeusb.sendCtrl(0x41, 0, [0x26]) def _dis(self): if self._naeusb: self._naeusb.close()
class CW305(TargetTemplate): _name = "ChipWhisperer CW305 (Artix-7)" def __init__(self): TargetTemplate.__init__(self) self._naeusb = NAEUSB() self.pll = PLLCDCE906(self._naeusb, ref_freq=12.0E6, parent=self) self.fpga = FPGA(self._naeusb) self.hw = None # self._fpgabs = QSettings().value("cw305-bitstream", '') self.oa = None self._woffset = 0x400 self.params.addChildren([ { 'name': 'PLL Settings', 'key': 'pll', 'type': 'group', 'children': [ { 'name': 'Enabled', 'key': 'pllenabled', 'type': 'bool', 'default': False, 'set': self.pll.pll_enable_set, 'get': self.pll.pll_enable_get, 'psync': False }, { 'name': 'CLK-SMA (X6)', 'key': 'pll0', 'type': 'group', 'children': [ { 'name': 'CLK-SMA Enabled', 'key': 'pll0enabled', 'type': 'bool', 'default': False, 'set': partial(self.pll.pll_outenable_set, outnum=0), 'get': partial(self.pll.pll_outenable_get, outnum=0), 'psync': False }, { 'name': 'CLK-SMA Source', 'key': 'pll0source', 'type': 'list', 'values': ['PLL0', 'PLL1', 'PLL2'], 'default': 'PLL0', 'set': partial(self.pll.pll_outsource_set, outnum=0), 'get': partial(self.pll.pll_outsource_get, outnum=0), 'psync': False }, { 'name': 'CLK-SMA Slew Rate', 'key': 'pll0slew', 'type': 'list', 'values': ['+3nS', '+2nS', '+1nS', '+0nS'], 'default': '+0nS', 'set': partial(self.pll.pll_outslew_set, outnum=0), 'get': partial(self.pll.pll_outslew_get, outnum=0), 'psync': False }, { 'name': 'PLL0 Frequency', 'key': 'pll0freq', 'type': 'float', 'limits': (0.625E6, 167E6), 'default': 0, 'step': 1E6, 'siPrefix': True, 'suffix': 'Hz', 'set': partial(self.pll.pll_outfreq_set, outnum=0), 'get': partial(self.pll.pll_outfreq_get, outnum=0), 'psync': False }, ] }, { 'name': 'CLK-N13 (FGPA Pin N13)', 'key': 'pll1', 'type': 'group', 'children': [ { 'name': 'CLK-N13 Enabled', 'key': 'pll1enabled', 'type': 'bool', 'default': False, 'set': partial(self.pll.pll_outenable_set, outnum=1), 'get': partial(self.pll.pll_outenable_get, outnum=1), 'psync': False }, { 'name': 'CLK-N13 Source', 'key': 'pll1source', 'type': 'list', 'values': ['PLL1'], 'value': 'PLL1' }, { 'name': 'CLK-N13 Slew Rate', 'key': 'pll1slew', 'type': 'list', 'values': ['+3nS', '+2nS', '+1nS', '+0nS'], 'default': '+0nS', 'set': partial(self.pll.pll_outslew_set, outnum=1), 'get': partial(self.pll.pll_outslew_get, outnum=1), 'psync': False }, { 'name': 'PLL1 Frequency', 'key': 'pll1freq', 'type': 'float', 'limits': (0.625E6, 167E6), 'default': 0, 'step': 1E6, 'siPrefix': True, 'suffix': 'Hz', 'set': partial(self.pll.pll_outfreq_set, outnum=1), 'get': partial(self.pll.pll_outfreq_get, outnum=1), 'psync': False }, ] }, { 'name': 'CLK-E12 (FGPA Pin E12)', 'key': 'pll2', 'type': 'group', 'children': [ { 'name': 'CLK-E12 Enabled', 'key': 'pll2enabled', 'type': 'bool', 'default': False, 'set': partial(self.pll.pll_outenable_set, outnum=2), 'get': partial(self.pll.pll_outenable_get, outnum=2), 'psync': False }, { 'name': 'CLK-E12 Source', 'key': 'pll2source', 'type': 'list', 'values': ['PLL2'], 'value': 'PLL2' }, { 'name': 'CLK-E12 Slew Rate', 'key': 'pll2slew', 'type': 'list', 'values': ['+0nS', '+1nS', '+2nS', '+3nS'], 'default': '+0nS', 'set': partial(self.pll.pll_outslew_set, outnum=2), 'get': partial(self.pll.pll_outslew_get, outnum=2), 'psync': False }, { 'name': 'PLL2 Frequency', 'key': 'pll2freq', 'type': 'float', 'limits': (0.625E6, 167E6), 'default': 0, 'step': 1E6, 'siPrefix': True, 'suffix': 'Hz', 'set': partial(self.pll.pll_outfreq_set, outnum=2), 'get': partial(self.pll.pll_outfreq_get, outnum=2), 'psync': False }, ] }, { 'name': 'Save as Default (stored in EEPROM)', 'type': 'action', 'action': lambda _: self.pll.pll_writedefaults() }, ] }, { 'name': 'Disable CLKUSB For Capture', 'key': 'clkusbautooff', 'type': 'bool', 'value': True }, { 'name': 'Time CLKUSB Disabled for', 'key': 'clksleeptime', 'type': 'int', 'range': (1, 50000), 'value': 50, 'suffix': 'mS' }, { 'name': 'CLKUSB Manual Setting', 'key': 'clkusboff', 'type': 'bool', 'value': True, 'action': self.usb_clk_setenabled_action }, { 'name': 'Send Trigger', 'type': 'action', 'action': self.usb_trigger_toggle }, { 'name': 'VCC-INT', 'key': 'vccint', 'type': 'float', 'default': 1.00, 'range': (0.6, 1.10), 'suffix': ' V', 'decimals': 3, 'set': self.vccint_set, 'get': self.vccint_get }, { 'name': 'FPGA Bitstream', 'type': 'group', 'children': [ { 'name': 'Bitstream File', 'key': 'fpgabsfile', 'type': 'file', 'value': "", "filter": '*.bit' }, { 'name': 'Program FPGA', 'type': 'action', 'action': self.gui_programfpga }, ] }, ]) def fpga_write(self, addr, data): """ Write to specified address """ if addr < self._woffset: raise IOError("Write to read-only location: 0x%04x" % addr) return self._naeusb.cmdWriteMem(addr, data) def fpga_read(self, addr, readlen): """ Read from address """ if addr > self._woffset: logging.info( 'Read from write address, confirm this is not an error') data = self._naeusb.cmdReadMem(addr, readlen) return data def usb_clk_setenabled_action(self, p): self.usb_clk_setenabled(p.getValue()) def usb_clk_setenabled(self, status): """ Turn on or off the Data Clock to the FPGA """ if status: self._naeusb.sendCtrl(CW305_USB.REQ_SYSCFG, CW305_USB.SYSCFG_CLKON) else: self._naeusb.sendCtrl(CW305_USB.REQ_SYSCFG, CW305_USB.SYSCFG_CLKOFF) def usb_trigger_toggle(self, _=None): """ Toggle the trigger line high then low """ self._naeusb.sendCtrl(CW305_USB.REQ_SYSCFG, CW305_USB.SYSCFG_TOGGLE) @setupSetParam("VCC-INT") def vccint_set(self, vccint=1.0): """ Set the VCC-INT for the FPGA """ # print "vccint = " + str(vccint) if (vccint < 0.6) or (vccint > 1.15): raise ValueError("VCC-Int out of range 0.6V-1.1V") # Convert to mV vccint = int(vccint * 1000) vccsetting = [vccint & 0xff, (vccint >> 8) & 0xff, 0] # calculate checksum vccsetting[2] = vccsetting[0] ^ vccsetting[1] ^ CW305_USB.VCCINT_XORKEY self._naeusb.sendCtrl(CW305_USB.REQ_VCCINT, 0, vccsetting) resp = self._naeusb.readCtrl(CW305_USB.REQ_VCCINT, dlen=3) if resp[0] != 2: raise IOError("VCC-INT Write Error, response = %d" % resp[0]) def vccint_get(self): """ Get the last set value for VCC-INT """ resp = self._naeusb.readCtrl(CW305_USB.REQ_VCCINT, dlen=3) return float(resp[1] | (resp[2] << 8)) / 1000.0 def gui_programfpga(self, _=None): bsfile = self.params.getChild(['FPGA Bitstream', "fpgabsfile"]).getValue() if not os.path.isfile(bsfile): raise Warning("FPGA Bitstream not configured or %s not a file." % str(bsfile)) starttime = datetime.now() result = self.fpga.FPGAProgram(open(bsfile, "rb"), exceptOnDoneFailure=False) stoptime = datetime.now() if result: logging.info('FPGA Config OK, time: %s' % str(stoptime - starttime)) else: logging.warning( 'FPGA Config failed: DONE pin did not go high. Check bitstream is for target device.' ) def _con(self, scope=None, bsfile=None, force=False): """Connect to CW305 board, download bitstream""" self._naeusb.con(idProduct=[0xC305]) if self.fpga.isFPGAProgrammed() == False or force: if bsfile is None: bsfile = self.params.getChild(['FPGA Bitstream', "fpgabsfile"]).getValue() if not os.path.isfile(bsfile): print("FPGA Bitstream not configured or '%s' not a file." % str(bsfile)) else: from datetime import datetime starttime = datetime.now() status = self.fpga.FPGAProgram(open(bsfile, "rb"), exceptOnDoneFailure=False) stoptime = datetime.now() if status: logging.info('FPGA Config OK, time: %s' % str(stoptime - starttime)) else: logging.warning( 'FPGA Done pin failed to go high, check bitstream is for target device.' ) self.usb_clk_setenabled(True) self.fpga_write(0x100 + self._woffset, [0]) self.params.refreshAllParameters() self.pll.cdce906init() def _dis(self): if self._naeusb: self._naeusb.close() def checkEncryptionKey(self, key): """Validate encryption key""" return key def loadEncryptionKey(self, key): """Write encryption key to FPGA""" self.key = key key = key[::-1] self.fpga_write(0x100 + self._woffset, key) def loadInput(self, inputtext): """Write input to FPGA""" self.input = inputtext text = inputtext[::-1] self.fpga_write(0x200 + self._woffset, text) def isDone(self): """Check if FPGA is done""" result = self.fpga_read(0x50, 1)[0] if result == 0x00: return False else: # Clear trigger self.fpga_write(0x40 + self._woffset, [0]) # LED Off self.fpga_write(0x10 + self._woffset, [0]) return True def readOutput(self): """"Read output from FPGA""" data = self.fpga_read(0x200, 16) data = data[::-1] self.newInputData.emit(util.list2hexstr(data)) return data def go(self): """Disable USB clock (if requested), perform encryption, re-enable clock""" if self.findParam('clkusbautooff').getValue(): self.usb_clk_setenabled(False) #LED On self.fpga_write(0x10 + self._woffset, [0x01]) time.sleep(0.01) self.usb_trigger_toggle() # self.FPGAWrite(0x100, [1]) # self.FPGAWrite(0x100, [0]) if self.findParam('clkusbautooff').getValue(): time.sleep(self.findParam('clksleeptime').getValue() / 1000.0) self.usb_clk_setenabled(True)