Browse Source

Add OpenULINK firmware

Build requires SDCC, the Small Device C Compiler.
tags/v0.5.0-rc1
Martin Schmölzer 12 years ago
committed by Øyvind Harboe
parent
commit
3c3f3c4247
19 changed files with 3297 additions and 0 deletions
  1. +90
    -0
      src/jtag/drivers/OpenULINK/Makefile
  2. +34
    -0
      src/jtag/drivers/OpenULINK/README
  3. +26
    -0
      src/jtag/drivers/OpenULINK/include/common.h
  4. +34
    -0
      src/jtag/drivers/OpenULINK/include/delay.h
  5. +125
    -0
      src/jtag/drivers/OpenULINK/include/io.h
  6. +46
    -0
      src/jtag/drivers/OpenULINK/include/jtag.h
  7. +26
    -0
      src/jtag/drivers/OpenULINK/include/main.h
  8. +187
    -0
      src/jtag/drivers/OpenULINK/include/msgtypes.h
  9. +33
    -0
      src/jtag/drivers/OpenULINK/include/protocol.h
  10. +742
    -0
      src/jtag/drivers/OpenULINK/include/reg_ezusb.h
  11. +41
    -0
      src/jtag/drivers/OpenULINK/include/shorttypes.h
  12. +267
    -0
      src/jtag/drivers/OpenULINK/include/usb.h
  13. +83
    -0
      src/jtag/drivers/OpenULINK/src/USBJmpTb.a51
  14. +51
    -0
      src/jtag/drivers/OpenULINK/src/delay.c
  15. +414
    -0
      src/jtag/drivers/OpenULINK/src/jtag.c
  16. +92
    -0
      src/jtag/drivers/OpenULINK/src/main.c
  17. +212
    -0
      src/jtag/drivers/OpenULINK/src/protocol.c
  18. +543
    -0
      src/jtag/drivers/OpenULINK/src/usb.c
  19. +251
    -0
      src/jtag/drivers/OpenULINK/ulink_firmware.hex

+ 90
- 0
src/jtag/drivers/OpenULINK/Makefile View File

@@ -0,0 +1,90 @@
############################################################################
# Copyright (C) 2011 by Martin Schmoelzer #
# <martin.schmoelzer@student.tuwien.ac.at> #
# #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the #
# Free Software Foundation, Inc., #
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
############################################################################

# Define the name of our tools. Some distributions (e. g. Fedora) prefix
# the SDCC executables, change this accordingly!
PREFIX =

# Small Device C Compiler: http://sdcc.sourceforge.net/
CC = $(PREFIX)-sdcc

# 8051 assembler, part of the SDCC software package.
AS = $(PREFIX)-sdas8051

# SDCC produces quite messy Intel HEX files. This tool is be used to re-format
# those files. It is not required for the firmware download functionality in
# the OpenOCD driver, but the resulting file is smaller.
PACKIHX = $(PREFIX)-packihx

# GNU binutils size. Used to print the size of the IHX file generated by SDCC.
SIZE = size

# Source and header directories.
SRC_DIR = src
INCLUDE_DIR = include

CODE_SIZE = 0x1B00

# Starting address of __xdata variables. Since the OpenULINK firmware does not
# use any of the isochronous interrupts, we can use the isochronous buffer space
# as XDATA memory.
XRAM_LOC = 0x2000
XRAM_SIZE = 0x0800

CFLAGS = --std-sdcc99 --opt-code-size --model-small
LDFLAGS = --code-loc 0x0000 --code-size $(CODE_SIZE) --xram-loc $(XRAM_LOC) \
--xram-size $(XRAM_SIZE) --iram-size 256 --model-small

# list of base object files
OBJECTS = main.rel usb.rel protocol.rel jtag.rel delay.rel USBJmpTb.rel
HEADERS = $(INCLUDE_DIR)/main.h \
$(INCLUDE_DIR)/usb.h \
$(INCLUDE_DIR)/protocol.h \
$(INCLUDE_DIR)/jtag.h \
$(INCLUDE_DIR)/delay.h \
$(INCLUDE_DIR)/reg_ezusb.h \
$(INCLUDE_DIR)/io.h \
$(INCLUDE_DIR)/msgtypes.h \
$(INCLUDE_DIR)/shorttypes.h

# Disable all built-in rules.
.SUFFIXES:

# Targets which are executed even when identically named file is present.
.PHONY: all, clean

all: ulink_firmware.ihx
$(SIZE) ulink_firmware.ihx

ulink_firmware.ihx: $(OBJECTS)
$(CC) -mmcs51 $(LDFLAGS) -o $@ $^

# Rebuild every C module (there are only 5 of them) if any header changes.
%.rel: $(SRC_DIR)/%.c $(HEADERS)
$(CC) -c $(CFLAGS) -mmcs51 -I$(INCLUDE_DIR) -o $@ $<

%.rel: $(SRC_DIR)/%.a51
$(AS) -lsgo $@ $<

clean:
rm -f *.asm *.lst *.rel *.rst *.sym *.ihx *.lnk *.map *.mem

hex: ulink_firmware.ihx
$(PACKIHX) ulink_firmware.ihx > ulink_firmware.hex

+ 34
- 0
src/jtag/drivers/OpenULINK/README View File

@@ -0,0 +1,34 @@
This is the OpenULINK firmware for the Keil ULINK JTAG adapter.

The main components of the Keil ULINK adapter are:
- Cypress EZ-USB microcontroller: enhanced 8051 CPU + USB core (1.1 Full-Speed)
- SRAM memory chip
- Level shifters to support different JTAG signal voltage levels
- Pin headers for various JTAG pin assignments

This firmware can only be run on the ORIGINAL Keil ULINK adapter, not on the
newer ULINK2, ULINK-ME or ULINK-PRO, as these adapters are based on different
hardware.

To compile the firmware, the SDCC compiler package is required. Most Linux
distributions include SDCC in their official package repositories. The SDCC
source code can be found at http://sdcc.sourceforge.net/
Simply type "make hex" in the OpenULINK directory to compile the firmware.
"make clean" will remove all generated files except the Intel HEX file required
for downloading the firmware to the ULINK adapter.

Note that the EZ-USB microcontroller does not have on-chip flash, nor does the
Keil ULINK include on-board memory to store the firmware program of the EZ-USB.
Instead, upon initial connection of the ULINK adapter to the host PC via USB,
the EZ-USB core has enough intelligence to act as a stand-alone USB device,
responding to USB control requests and allowing firmware download via a special
VENDOR-type control request. Then, the EZ-USB microcontroller simulates a
disconnect and re-connect to the USB bus. It may take up to two seconds for the
host to recognize the newly connected device before OpenOCD can proceed to
execute JTAG commands. This delay is only visible when OpenOCD first uses a
blank (unconfigured) ULINK device.

Once the user disconnects the ULINK adapter, all its memory contents are lost
and the firmware download process has to be executed again. This also maintains
compatibility with the original Keil uVision IDE, which will happily download
its own firmware image to a blank ULINK adapter.

+ 26
- 0
src/jtag/drivers/OpenULINK/include/common.h View File

@@ -0,0 +1,26 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#ifndef __COMMON_H
#define __COMMON_H

#define DIV_ROUND_UP(m, n) (((m) + (n) - 1) / (n))

#endif

+ 34
- 0
src/jtag/drivers/OpenULINK/include/delay.h View File

@@ -0,0 +1,34 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#ifndef __DELAY_H
#define __DELAY_H

#include "shorttypes.h"

#define NOP {__asm nop __endasm;}

void delay_5us(void);
void delay_1ms(void);

void delay_us(u16 delay);
void delay_ms(u16 delay);

#endif

+ 125
- 0
src/jtag/drivers/OpenULINK/include/io.h View File

@@ -0,0 +1,125 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#ifndef __IO_H
#define __IO_H

#include "reg_ezusb.h"

/***************************************************************************
* JTAG Signals: *
***************************************************************************
* TMS ....... Test Mode Select *
* TCK ....... Test Clock *
* TDI ....... Test Data Input (from device point of view, not JTAG *
* adapter point of view!) *
* TDO ....... Test Data Output (from device point of view, not JTAG *
* adapter point of view!) *
* TRST ...... Test Reset: Used to reset the TAP Finite State Machine *
* into the Test Logic Reset state *
* RTCK ...... Return Test Clock *
* OCDSE ..... Enable/Disable OCDS interface (Infineon specific) - shared *
* with /JEN *
* TRAP ...... Trap Condition (Infineon specific) - shared with TSTAT *
* BRKIN ..... Hardware Break-In (Infineon specific) *
* BRKOUT .... Hardware Break-Out (Infineon specific) *
* /JEN ...... JTAG-Enable (STMicroelectronics specific) - shared *
* with OCDSE *
* TSTAT ..... JTAG ISP Status (STMicroelectronics specific) - shared *
* with TRAP *
* RESET ..... Chip Reset (STMicroelectronics specific) *
* /TERR ..... JTAG ISP Error (STMicroelectronics specific) - shared *
* with BRKOUT *
***************************************************************************/

/* PORT A */
#define PIN_U_OE OUTA0
// PA1 Not Connected
#define PIN_OE OUTA2
// PA3 Not Connected
#define PIN_RUN_LED OUTA4
#define PIN_TDO PINA5
#define PIN_BRKOUT PINA6
#define PIN_COM_LED OUTA7


/* PORT B */
#define PIN_TDI OUTB0
#define PIN_TMS OUTB1
#define PIN_TCK OUTB2
#define PIN_TRST OUTB3
#define PIN_BRKIN OUTB4
#define PIN_RESET OUTB5
#define PIN_OCDSE OUTB6
#define PIN_TRAP PINB7

/* JTAG Signals with direction 'OUT' on port B */
#define MASK_PORTB_DIRECTION_OUT (PIN_TDI | PIN_TMS | PIN_TCK | PIN_TRST | PIN_BRKIN | PIN_RESET | PIN_OCDSE)

/* PORT C */
#define PIN_RXD0 PINC0
#define PIN_TXD0 OUTC1
#define PIN_RESET_2 PINC2
// PC3 Not Connected
// PC4 Not Connected
#define PIN_RTCK PINC5
#define PIN_WR OUTC6
// PC7 Not Connected

/* LED Macros */
#define SET_RUN_LED() OUTA &= ~PIN_RUN_LED
#define CLEAR_RUN_LED() OUTA |= PIN_RUN_LED

#define SET_COM_LED() OUTA &= ~PIN_COM_LED
#define CLEAR_COM_LED() OUTA |= PIN_COM_LED

/* JTAG Pin Macros */
#define GET_TMS() (PINSB & PIN_TMS)
#define GET_TCK() (PINSB & PIN_TCK)

#define GET_TDO() (PINSA & PIN_TDO)
#define GET_BRKOUT() (PINSA & PIN_BRKOUT)
#define GET_TRAP() (PINSB & PIN_TRAP)
#define GET_RTCK() (PINSC & PIN_RTCK)

#define SET_TMS_HIGH() OUTB |= PIN_TMS
#define SET_TMS_LOW() OUTB &= ~PIN_TMS

#define SET_TCK_HIGH() OUTB |= PIN_TCK
#define SET_TCK_LOW() OUTB &= ~PIN_TCK

#define SET_TDI_HIGH() OUTB |= PIN_TDI
#define SET_TDI_LOW() OUTB &= ~PIN_TDI

/* TRST and RESET are low-active and inverted by hardware. SET_HIGH de-asserts
* the signal (enabling reset), SET_LOW asserts the signal (disabling reset) */
#define SET_TRST_HIGH() OUTB |= PIN_TRST
#define SET_TRST_LOW() OUTB &= ~PIN_TRST

#define SET_RESET_HIGH() OUTB |= PIN_RESET
#define SET_RESET_LOW() OUTB &= ~PIN_RESET

#define SET_OCDSE_HIGH() OUTB |= PIN_OCDSE
#define SET_OCDSE_LOW() OUTB &= ~PIN_OCDSE

#define SET_BRKIN_HIGH() OUTB |= PIN_BRKIN
#define SET_BRKIN_LOW() OUTB &= ~PIN_BRKIN

#endif

+ 46
- 0
src/jtag/drivers/OpenULINK/include/jtag.h View File

@@ -0,0 +1,46 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#ifndef __JTAG_H
#define __JTAG_H

#include "shorttypes.h"

#define NOP {__asm nop __endasm;}

void jtag_scan_in(u8 out_offset, u8 in_offset);
void jtag_scan_out(u8 out_offset);
void jtag_scan_io(u8 out_offset, u8 in_offset);

void jtag_slow_scan_in(u8 scan_size_bytes, u8 tdo_index, u8 scan_options);
void jtag_slow_scan_out(u8 scan_size_bytes, u8 tdi_index, u8 scan_options);
void jtag_slow_scan_io(u8 scan_size_bytes, u8 tdi_index, u8 tdo_index,
u8 scan_options);

void jtag_clock_tck(u16 count);
void jtag_clock_tms(u8 count, u8 sequence);
void jtag_slow_clock_tms(u8 count, u8 sequence);

u16 jtag_get_signals(void);
void jtag_set_signals(u8 low, u8 high);

void jtag_configure_tck_delay(u8 scan, u8 tck, u8 tms);

#endif

+ 26
- 0
src/jtag/drivers/OpenULINK/include/main.h View File

@@ -0,0 +1,26 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#ifndef __MAIN_H
#define __MAIN_H

void io_init(void);

#endif

+ 187
- 0
src/jtag/drivers/OpenULINK/include/msgtypes.h View File

@@ -0,0 +1,187 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

/**
* @file Definition of the commands supported by the OpenULINK firmware.
*
* Basically, two types of commands can be distinguished:
* - Commands with fixed payload size
* - Commands with variable payload size
*
* SCAN commands (in all variations) carry payloads of variable size, all
* other commands carry payloads of fixed size.
*
* In the case of SCAN commands, the payload size (n) is calculated by
* dividing the scan_size_bits variable by 8, rounding up the result.
*
* Offset zero always contains the command ID.
*
****************************************************************************
* CMD_SCAN_IN, CMD_SLOW_SCAN_IN: *
* *
* OUT: *
* offset 1: scan_size_bytes *
* offset 2: bits_last_byte *
* offset 3: tms_count_start + tms_count_end *
* offset 4: tms_sequence_start *
* offset 5: tms_sequence_end *
* *
* IN: *
* offset 0..n: TDO data *
****************************************************************************
* CMD_SCAN_OUT, CMD_SLOW_SCAN_OUT: *
* *
* OUT: *
* offset 1: scan_size_bytes *
* offset 2: bits_last_byte *
* offset 3: tms_count_start + tms_count_end *
* offset 4: tms_sequence_start *
* offset 5: tms_sequence_end *
* offset 6..x: TDI data *
****************************************************************************
* CMD_SCAN_IO, CMD_SLOW_SCAN_IO: *
* *
* OUT: *
* offset 1: scan_size_bytes *
* offset 2: bits_last_byte *
* offset 3: tms_count_start + tms_count_end *
* offset 4: tms_sequence_start *
* offset 5: tms_sequence_end *
* offset 6..x: TDI data *
* *
* IN: *
* offset 0..n: TDO data *
****************************************************************************
* CMD_CLOCK_TMS, CMD_SLOW_CLOCK_TMS: *
* *
* OUT: *
* offset 1: tms_count *
* offset 2: tms_sequence *
****************************************************************************
* CMD_CLOCK_TCK: *
* *
* OUT: *
* offset 1: low byte of tck_count *
* offset 2: high byte of tck_count *
****************************************************************************
* CMD_CLOCK_SLEEP_US: *
* *
* OUT: *
* offset 1: low byte of sleep_us *
* offset 2: high byte of sleep_us *
****************************************************************************
* CMD_CLOCK_SLEEP_MS: *
* *
* OUT: *
* offset 1: low byte of sleep_ms *
* offset 2: high byte of sleep_ms *
****************************************************************************
* CMD_GET_SIGNALS: *
* *
* IN: *
* offset 0: current state of input signals *
* offset 1: current state of output signals *
****************************************************************************
* CMD_SET_SIGNALS: *
* *
* OUT: *
* offset 1: signals that should be de-asserted *
* offset 2: signals that should be asserted *
****************************************************************************
* CMD_CONFIGURE_TCK_FREQ: *
* *
* OUT: *
* offset 1: delay value for scan functions *
* offset 2: delay value for clock_tck function *
* offset 3: delay value for clock_tms function *
****************************************************************************
* CMD_SET_LEDS: *
* *
* OUT: *
* offset 1: LED states: *
* Bit 0: turn COM LED on *
* Bit 1: turn RUN LED on *
* Bit 2: turn COM LED off *
* Bit 3: turn RUN LED off *
* Bits 7..4: Reserved *
****************************************************************************
* CMD_TEST: *
* *
* OUT: *
* offset 1: unused dummy value *
****************************************************************************
*/

#ifndef __MSGTYPES_H
#define __MSGTYPES_H

/*
* Command IDs:
*
* Bits 7..6: Reserved, should always be zero
* Bits 5..0: Command ID. There are 62 usable IDs. Of this 63 available IDs,
* the IDs 0x00..0x1F are commands with variable payload size,
* the IDs 0x20..0x3F are commands with fixed payload size.
*/

#define CMD_ID_MASK 0x3F

/* Commands with variable payload size */
#define CMD_SCAN_IN 0x00
#define CMD_SLOW_SCAN_IN 0x01
#define CMD_SCAN_OUT 0x02
#define CMD_SLOW_SCAN_OUT 0x03
#define CMD_SCAN_IO 0x04
#define CMD_SLOW_SCAN_IO 0x05

/* Commands with fixed payload size */
#define CMD_CLOCK_TMS 0x20
#define CMD_SLOW_CLOCK_TMS 0x21
#define CMD_CLOCK_TCK 0x22
#define CMD_SLEEP_US 0x23
#define CMD_SLEEP_MS 0x24
#define CMD_GET_SIGNALS 0x25
#define CMD_SET_SIGNALS 0x26
#define CMD_CONFIGURE_TCK_FREQ 0x27
#define CMD_SET_LEDS 0x28
#define CMD_TEST 0x29

/* JTAG signal definition for jtag_get_signals() -- Input signals! */
#define SIGNAL_TDO (1<<0)
#define SIGNAL_BRKOUT (1<<1)
#define SIGNAL_TRAP (1<<2)
#define SIGNAL_RTCK (1<<3)

/* JTAG signal definition for jtag_get_signals() -- Output signals! */
#define SIGNAL_TDI (1<<0)
#define SIGNAL_TMS (1<<1)
#define SIGNAL_TCK (1<<2)
#define SIGNAL_TRST (1<<3)
#define SIGNAL_BRKIN (1<<4)
#define SIGNAL_RESET (1<<5)
#define SIGNAL_OCDSE (1<<6)

/* LED definitions for CMD_SET_LEDS and CMD_CLEAR_LEDS commands */
#define COM_LED_ON (1<<0)
#define RUN_LED_ON (1<<1)
#define COM_LED_OFF (1<<2)
#define RUN_LED_OFF (1<<3)

#endif

+ 33
- 0
src/jtag/drivers/OpenULINK/include/protocol.h View File

@@ -0,0 +1,33 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#ifndef __PROTOCOL_H
#define __PROTOCOL_H

#include "shorttypes.h"
#include "common.h"
#include <stdbool.h>

void execute_set_led_command(void);

bool execute_command(void);
void command_loop(void);

#endif

+ 742
- 0
src/jtag/drivers/OpenULINK/include/reg_ezusb.h View File

@@ -0,0 +1,742 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#ifndef REG_EZUSB_H
#define REG_EZUSB_H

/**
* @file All information in this file was taken from the EZ-USB Technical
* Reference Manual, Cypress Semiconductor, 3901 North First Street
* San Jose, CA 95134 (www.cypress.com).
*
* The EZ-USB Technical Reference Manual is called "EZ-USB TRM" hereafter.
*
* The following bit name definitions differ from those in the EZ-USB TRM:
* - All lowercase characters in the EZ-USB TRM bit names have been converted
* to capitals (e. g. "WakeSRC" converted to "WAKESRC").
* - CPUCS: 8051RES is named "RES8051".
* - ISOCTL: Two MBZ ("Must Be Zero") bits are named "MBZ0" and "MBZ1".
* - I2CS: STOP and START bits are preceded by "I2C_"
* - INxCS, OUTxCS: the busy and stall bits are named "EPBSY" and "EPSTALL".
* - TOGCTL: EZ-USB TRM bit names are preceded by "TOG_".
*/

/* Compiler-specific definitions of SBIT, SFR, SFRX, ... macros */
#include <mcs51/compiler.h>

/* Bit vectors */
#define bmBit0 0x01
#define bmBit1 0x02
#define bmBit2 0x04
#define bmBit3 0x08
#define bmBit4 0x10
#define bmBit5 0x20
#define bmBit6 0x40
#define bmBit7 0x80

/***************************************************************************/
/************************ Special Function Registers ***********************/
/***************************************************************************/

/* See EZ-USB TRM, pp. A-9 - A-10 */

SFR(SP, 0x81);
SFR(DPL0, 0x82);
SFR(DPH0, 0x83);
SFR(DPL1, 0x84);
SFR(DPL2, 0x85);

SFR(DPS, 0x86);
#define SEL bmBit0
// Bit 1 read-only, always reads '0'
// Bit 2 read-only, always reads '0'
// Bit 3 read-only, always reads '0'
// Bit 4 read-only, always reads '0'
// Bit 5 read-only, always reads '0'
// Bit 6 read-only, always reads '0'
// Bit 7 read-only, always reads '0'

SFR(PCON, 0x87);
#define IDLE bmBit0
#define STOP bmBit1
#define GF0 bmBit2
#define GF1 bmBit3
// Bit 4 read-only, always reads '1'
// Bit 5 read-only, always reads '1'
// Bit 6 unused
#define SMOD0 bmBit7

SFR(TCON, 0x88);
SBIT(IT0, 0x88, 0);
SBIT(IE0, 0x88, 1);
SBIT(IT1, 0x88, 2);
SBIT(IE1, 0x88, 3);
SBIT(TR0, 0x88, 4);
SBIT(TF0, 0x88, 5);
SBIT(TR1, 0x88, 6);
SBIT(TF1, 0x88, 7);

SFR(TMOD, 0x89);
/* Some bits in this register share the same name in the EZ-USB TRM. Therefore,
* we add a '0'/'1' to distinguish them */
#define M00 bmBit0
#define M01 bmBit1
#define CT0 bmBit2
#define GATE0 bmBit3
#define M10 bmBit4
#define M11 bmBit5
#define CT1 bmBit6
#define GATE1 bmBit7

SFR(TL0, 0x8A);
SFR(TL1, 0x8B);
SFR(TH0, 0x8C);
SFR(TH1, 0x8D);

SFR(CKCON, 0x8E);
#define MD0 bmBit0
#define MD1 bmBit1
#define MD2 bmBit2
#define T0M bmBit3
#define T1M bmBit4
#define T2M bmBit5
// Bit 6 unused
// Bit 7 unused

SFR(SPC_FNC, 0x8D);
#define bmWRS bmBit0
// Bit 1 read-only, always reads '0'
// Bit 2 read-only, always reads '0'
// Bit 3 read-only, always reads '0'
// Bit 4 read-only, always reads '0'
// Bit 5 read-only, always reads '0'
// Bit 6 read-only, always reads '0'
// Bit 7 read-only, always reads '0'

SFR(EXIF, 0x91);
// Bit 0 read-only, always reads '0'
// Bit 1 read-only, always reads '0'
// Bit 2 read-only, always reads '0'
// Bit 3 read-only, always reads '1'
#define USBINT bmBit4
#define I2CINT bmBit5
#define IE4 bmBit6
#define IE5 bmBit7

/* Definition of the _XPAGE register, according to SDCC Compiler User Guide,
* Version 3.0.1, Chapter 4, p. 61. Also see EZ-USB TRM, p. 2-4. */
SFR(MPAGE, 0x92);
SFR(_XPAGE, 0x92);

SFR(SCON0, 0x98);
SBIT(RI_0, 0x98, 0);
SBIT(TI_0, 0x98, 1);
SBIT(RB8_0, 0x98, 2);
SBIT(TB8_0, 0x98, 3);
SBIT(REN_0, 0x98, 4);
SBIT(SM2_0, 0x98, 5);
SBIT(SM1_0, 0x98, 6);
SBIT(SM0_0, 0x98, 7);

SFR(SBUF0, 0x99);

SFR(IE, 0xA8);
SBIT(EX0, 0xA8, 0);
SBIT(ET0, 0xA8, 1);
SBIT(EX1, 0xA8, 2);
SBIT(ET1, 0xA8, 3);
SBIT(ES0, 0xA8, 4);
SBIT(ET2, 0xA8, 5);
SBIT(ES1, 0xA8, 6);
SBIT(EA, 0xA8, 7);

SFR(IP, 0xB8);
SBIT(PX0, 0xB8, 0);
SBIT(PT0, 0xB8, 1);
SBIT(PX1, 0xB8, 2);
SBIT(PT1, 0xB8, 3);
SBIT(PS0, 0xB8, 4);
SBIT(PT2, 0xB8, 5);
SBIT(PS1, 0xB8, 6);
// Bit 7 read-only, always reads '1'

SFR(SCON1, 0xC0);
SBIT(RI_1, 0xC0, 0);
SBIT(TI_1, 0xC0, 1);
SBIT(RB8_1, 0xC0, 2);
SBIT(TB8_1, 0xC0, 3);
SBIT(REN_1, 0xC0, 4);
SBIT(SM2_1, 0xC0, 5);
SBIT(SM1_1, 0xC0, 6);
SBIT(SM0_1, 0xC0, 7);

SFR(SBUF1, 0xC1);

SFR(T2CON, 0xC8);
SBIT(CPRL2, 0xC8, 0);
SBIT(CT2, 0xC8, 1);
SBIT(TR2, 0xC8, 2);
SBIT(EXEN2, 0xC8, 3);
SBIT(TCLK, 0xC8, 4);
SBIT(RCLK, 0xC8, 5);
SBIT(EXF2, 0xC8, 6);
SBIT(TF2, 0xC8, 7);

SFR(RCAP2L, 0xCA);
SFR(RCAP2H, 0xCB);
SFR(TL2, 0xCC);
SFR(TH2, 0xCD);

SFR(PSW, 0xD0);
SBIT(P, 0xD0, 0);
SBIT(F1, 0xD0, 1);
SBIT(OV, 0xD0, 2);
SBIT(RS0, 0xD0, 3);
SBIT(RS1, 0xD0, 4);
SBIT(F0, 0xD0, 5);
SBIT(AC, 0xD0, 6);
SBIT(CY, 0xD0, 7);

SFR(EICON, 0xD8);
// Bit 0 read-only, always reads '0'
// Bit 1 read-only, always reads '0'
// Bit 2 read-only, always reads '0'
SBIT(INT6, 0xD8, 3);
SBIT(RESI, 0xD8, 4);
SBIT(ERESI, 0xD8, 5);
// Bit 6 read-only, always reads '1'
SBIT(SMOD1, 0xD8, 7);

SFR(ACC, 0xE0);

SFR(EIE, 0xE8);
SBIT(EUSB, 0xE8, 0);
SBIT(EI2C, 0xE8, 1);
SBIT(EX4, 0xE8, 2);
SBIT(EX5, 0xE8, 3);
SBIT(EWDI, 0xE8, 4);
// Bit 5 read-only, always reads '1'
// Bit 6 read-only, always reads '1'
// Bit 7 read-only, always reads '1'

SFR(B, 0xF0);

SFR(EIP, 0xF8);
SBIT(PUSB, 0xF8, 0);
SBIT(PI2C, 0xF8, 1);
SBIT(PX4, 0xF8, 2);
SBIT(PX5, 0xF8, 3);
SBIT(PX6, 0xF8, 4);
// Bit 5 read-only, always reads '1'
// Bit 6 read-only, always reads '1'
// Bit 7 read-only, always reads '1'

/***************************************************************************/
/***************************** XDATA Registers *****************************/
/***************************************************************************/

/************************ Endpoint 0-7 Data Buffers ************************/
SFRX(OUT7BUF[64], 0x7B40);
SFRX(IN7BUF[64], 0x7B80);
SFRX(OUT6BUF[64], 0x7BC0);
SFRX(IN6BUF[64], 0x7C00);
SFRX(OUT5BUF[64], 0x7C40);
SFRX(IN5BUF[64], 0x7C80);
SFRX(OUT4BUF[64], 0x7CC0);
SFRX(IN4BUF[64], 0x7D00);
SFRX(OUT3BUF[64], 0x7D40);
SFRX(IN3BUF[64], 0x7D80);
SFRX(OUT2BUF[64], 0x7DC0);
SFRX(IN2BUF[64], 0x7E00);
SFRX(OUT1BUF[64], 0x7E40);
SFRX(IN1BUF[64], 0x7E80);
SFRX(OUT0BUF[64], 0x7EC0);
SFRX(IN0BUF[64], 0x7F00);
// 0x7F40 - 0x7F5F reserved

/**************************** Isochronous Data *****************************/
SFRX(OUT8DATA, 0x7F60);
SFRX(OUT9DATA, 0x7F61);
SFRX(OUT10DATA, 0x7F62);
SFRX(OUT11DATA, 0x7F63);
SFRX(OUT12DATA, 0x7F64);
SFRX(OUT13DATA, 0x7F65);
SFRX(OUT14DATA, 0x7F66);
SFRX(OUT15DATA, 0x7F67);

SFRX(IN8DATA, 0x7F68);
SFRX(IN9DATA, 0x7F69);
SFRX(IN10DATA, 0x7F6A);
SFRX(IN11DATA, 0x7F6B);
SFRX(IN12DATA, 0x7F6C);
SFRX(IN13DATA, 0x7F6D);
SFRX(IN14DATA, 0x7F6E);
SFRX(IN15DATA, 0x7F6F);

/************************* Isochronous Byte Counts *************************/
SFRX(OUT8BCH, 0x7F70);
SFRX(OUT8BCL, 0x7F71);
SFRX(OUT9BCH, 0x7F72);
SFRX(OUT9BCL, 0x7F73);
SFRX(OUT10BCH, 0x7F74);
SFRX(OUT10BCL, 0x7F75);
SFRX(OUT11BCH, 0x7F76);
SFRX(OUT11BCL, 0x7F77);
SFRX(OUT12BCH, 0x7F78);
SFRX(OUT12BCL, 0x7F79);
SFRX(OUT13BCH, 0x7F7A);
SFRX(OUT13BCL, 0x7F7B);
SFRX(OUT14BCH, 0x7F7C);
SFRX(OUT14BCL, 0x7F7D);
SFRX(OUT15BCH, 0x7F7E);
SFRX(OUT16BCL, 0x7F7F);

/****************************** CPU Registers ******************************/
SFRX(CPUCS, 0x7F92);
#define RES8051 bmBit0
#define CLK24OE bmBit1
// Bit 2 read-only, always reads '0'
// Bit 3 read-only, always reads '0'
// Bits 4...7: Chip Revision

SFRX(PORTACFG, 0x7F93);
#define T0OUT bmBit0
#define T1OUT bmBit1
#define OE bmBit2
#define CS bmBit3
#define FWR bmBit4
#define FRD bmBit5
#define RXD0OUT bmBit6
#define RXD1OUT bmBit7

SFRX(PORTBCFG, 0x7F94);
#define T2 bmBit0
#define T2EX bmBit1
#define RXD1 bmBit2
#define TXD1 bmBit3
#define INT4 bmBit4
#define INT5 bmBit5
#define INT6 bmBit6
#define T2OUT bmBit7

SFRX(PORTCCFG, 0x7F95);
#define RXD0 bmBit0
#define TXD0 bmBit1
#define INT0 bmBit2
#define INT1 bmBit3
#define T0 bmBit4
#define T1 bmBit5
#define WR bmBit6
#define RD bmBit7

/*********************** Input-Output Port Registers ***********************/
SFRX(OUTA, 0x7F96);
#define OUTA0 bmBit0
#define OUTA1 bmBit1
#define OUTA2 bmBit2
#define OUTA3 bmBit3
#define OUTA4 bmBit4
#define OUTA5 bmBit5
#define OUTA6 bmBit6
#define OUTA7 bmBit7

SFRX(OUTB, 0x7F97);
#define OUTB0 bmBit0
#define OUTB1 bmBit1
#define OUTB2 bmBit2
#define OUTB3 bmBit3
#define OUTB4 bmBit4
#define OUTB5 bmBit5
#define OUTB6 bmBit6
#define OUTB7 bmBit7

SFRX(OUTC, 0x7F98);
#define OUTC0 bmBit0
#define OUTC1 bmBit1
#define OUTC2 bmBit2
#define OUTC3 bmBit3
#define OUTC4 bmBit4
#define OUTC5 bmBit5
#define OUTC6 bmBit6
#define OUTC7 bmBit7

SFRX(PINSA, 0x7F99);
#define PINA0 bmBit0
#define PINA1 bmBit1
#define PINA2 bmBit2
#define PINA3 bmBit3
#define PINA4 bmBit4
#define PINA5 bmBit5
#define PINA6 bmBit6
#define PINA7 bmBit7

SFRX(PINSB, 0x7F9A);
#define PINB0 bmBit0
#define PINB1 bmBit1
#define PINB2 bmBit2
#define PINB3 bmBit3
#define PINB4 bmBit4
#define PINB5 bmBit5
#define PINB6 bmBit6
#define PINB7 bmBit7

SFRX(PINSC, 0x7F9B);
#define PINC0 bmBit0
#define PINC1 bmBit1
#define PINC2 bmBit2
#define PINC3 bmBit3
#define PINC4 bmBit4
#define PINC5 bmBit5
#define PINC6 bmBit6
#define PINC7 bmBit7

SFRX(OEA, 0x7F9C);
#define OEA0 bmBit0
#define OEA1 bmBit1
#define OEA2 bmBit2
#define OEA3 bmBit3
#define OEA4 bmBit4
#define OEA5 bmBit5
#define OEA6 bmBit6
#define OEA7 bmBit7

SFRX(OEB, 0x7F9D);
#define OEB0 bmBit0
#define OEB1 bmBit1
#define OEB2 bmBit2
#define OEB3 bmBit3
#define OEB4 bmBit4
#define OEB5 bmBit5
#define OEB6 bmBit6
#define OEB7 bmBit7

SFRX(OEC, 0x7F9E);
#define OEC0 bmBit0
#define OEC1 bmBit1
#define OEC2 bmBit2
#define OEC3 bmBit3
#define OEC4 bmBit4
#define OEC5 bmBit5
#define OEC6 bmBit6
#define OEC7 bmBit7

// 0x7F9F reserved

/****************** Isochronous Control/Status Registers *******************/
SFRX(ISOERR, 0x7FA0);
#define ISO8ERR bmBit0
#define ISO9ERR bmBit1
#define ISO10ERR bmBit2
#define ISO11ERR bmBit3
#define ISO12ERR bmBit4
#define ISO13ERR bmBit5
#define ISO14ERR bmBit6
#define ISO15ERR bmBit7

SFRX(ISOCTL, 0x7FA1);
#define ISODISAB bmBit0
#define MBZ0 bmBit1
#define MBZ1 bmBit2
#define PPSTAT bmBit3
// Bit 4 unused
// Bit 5 unused
// Bit 6 unused
// Bit 7 unused

SFRX(ZBCOUT, 0x7FA2);
#define EP8 bmBit0
#define EP9 bmBit1
#define EP10 bmBit2
#define EP11 bmBit3
#define EP12 bmBit4
#define EP13 bmBit5
#define EP14 bmBit6
#define EP15 bmBit7

// 0x7FA3 reserved
// 0x7FA4 reserved

/****************************** I2C Registers ******************************/
SFRX(I2CS, 0x7FA5);
#define DONE bmBit0
#define ACK bmBit1
#define BERR bmBit2
#define ID0 bmBit3
#define ID1 bmBit4
#define LASTRD bmBit5
#define I2C_STOP bmBit6
#define I2C_START bmBit7

SFRX(I2DAT, 0x7FA6);
// 0x7FA7 reserved

/******************************* Interrupts ********************************/
SFRX(IVEC, 0x7FA8);
// Bit 0 read-only, always reads '0'
// Bit 1 read-only, always reads '0'
#define IV0 bmBit2
#define IV1 bmBit3
#define IV2 bmBit4
#define IV3 bmBit5
#define IV4 bmBit6
// Bit 7 read-only, always reads '0'

SFRX(IN07IRQ, 0x7FA9);
#define IN0IR bmBit0
#define IN1IR bmBit1
#define IN2IR bmBit2
#define IN3IR bmBit3
#define IN4IR bmBit4
#define IN5IR bmBit5
#define IN6IR bmBit6
#define IN7IR bmBit7

SFRX(OUT07IRQ, 0x7FAA);
#define OUT0IR bmBit0
#define OUT1IR bmBit1
#define OUT2IR bmBit2
#define OUT3IR bmBit3
#define OUT4IR bmBit4
#define OUT5IR bmBit5
#define OUT6IR bmBit6
#define OUT7IR bmBit7

SFRX(USBIRQ, 0x7FAB);
#define SUDAVIR bmBit0
#define SOFIR bmBit1
#define SUTOKIR bmBit2
#define SUSPIR bmBit3
#define URESIR bmBit4
// Bit 5 unused
// Bit 6 unused
// Bit 7 unused

SFRX(IN07IEN, 0x7FAC);
#define IN0IEN bmBit0
#define IN1IEN bmBit1
#define IN2IEN bmBit2
#define IN3IEN bmBit3
#define IN4IEN bmBit4
#define IN5IEN bmBit5
#define IN6IEN bmBit6
#define IN7IEN bmBit7

SFRX(OUT07IEN, 0x7FAD);
#define OUT0IEN bmBit0
#define OUT1IEN bmBit1
#define OUT2IEN bmBit2
#define OUT3IEN bmBit3
#define OUT4IEN bmBit4
#define OUT5IEN bmBit5
#define OUT6IEN bmBit6
#define OUT7IEN bmBit7

SFRX(USBIEN, 0x7FAE);
#define SUDAVIE bmBit0
#define SOFIE bmBit1
#define SUTOKIE bmBit2
#define SUSPIE bmBit3
#define URESIE bmBit4
// Bit 5 unused
// Bit 6 unused
// Bit 7 unused

SFRX(USBBAV, 0x7FAF);
#define AVEN bmBit0
#define BPEN bmBit1
#define BPPULSE bmBit2
#define BREAK bmBit3
// Bit 4 unused
// Bit 5 unused
// Bit 6 unused
// Bit 7 unused

// 0x7FB0 reserved
// 0x7FB1 reserved
SFRX(BPADDRH, 0x7FB2);
SFRX(BPADDRL, 0x7FB3);

/****************************** Endpoints 0-7 ******************************/
SFRX(EP0CS, 0x7FB4);
#define EP0STALL bmBit0
#define HSNAK bmBit1
#define IN0BSY bmBit2
#define OUT0BSY bmBit3
// Bit 4 unused
// Bit 5 unused
// Bit 6 unused
// Bit 7 unused

SFRX(IN0BC, 0x7FB5);
SFRX(IN1CS, 0x7FB6);
SFRX(IN1BC, 0x7FB7);
SFRX(IN2CS, 0x7FB8);
SFRX(IN2BC, 0x7FB9);
SFRX(IN3CS, 0x7FBA);
SFRX(IN3BC, 0x7FBB);
SFRX(IN4CS, 0x7FBC);
SFRX(IN4BC, 0x7FBD);
SFRX(IN5CS, 0x7FBE);
SFRX(IN5BC, 0x7FBF);
SFRX(IN6CS, 0x7FC0);
SFRX(IN6BC, 0x7FC1);
SFRX(IN7CS, 0x7FC2);
SFRX(IN7BC, 0x7FC3);
// 0x7FC4 reserved
SFRX(OUT0BC, 0x7FC5);
SFRX(OUT1CS, 0x7FC6);
SFRX(OUT1BC, 0x7FC7);
SFRX(OUT2CS, 0x7FC8);
SFRX(OUT2BC, 0x7FC9);
SFRX(OUT3CS, 0x7FCA);
SFRX(OUT3BC, 0x7FCB);
SFRX(OUT4CS, 0x7FCC);
SFRX(OUT4BC, 0x7FCD);
SFRX(OUT5CS, 0x7FCE);
SFRX(OUT5BC, 0x7FCF);
SFRX(OUT6CS, 0x7FD0);
SFRX(OUT6BC, 0x7FD1);
SFRX(OUT7CS, 0x7FD2);
SFRX(OUT7BC, 0x7FD3);

/* The INxSTALL, OUTxSTALL, INxBSY and OUTxBSY bits are the same for all
* INxCS/OUTxCS registers. For better readability, we define them only once */
#define EPSTALL bmBit0
#define EPBSY bmBit1

/************************** Global USB Registers ***************************/
SFRX(SUDPTRH, 0x7FD4);
SFRX(SUDPTRL, 0x7FD5);

SFRX(USBCS, 0x7FD6);
#define SIGRSUME bmBit0
#define RENUM bmBit1
#define DISCOE bmBit2
#define DISCON bmBit3
// Bit 4 unused
// Bit 5 unused
// Bit 6 unused
#define WAKESRC bmBit7

SFRX(TOGCTL, 0x7FD7);
#define TOG_EP0 bmBit0
#define TOG_EP1 bmBit1
#define TOG_EP2 bmBit2
// Bit 3 is read-only, always reads '0'
#define TOG_IO bmBit4
#define TOG_R bmBit5
#define TOG_S bmBit6
#define TOG_Q bmBit7

SFRX(USBFRAMEL, 0x7FD8);
SFRX(USBFRAMEH, 0x7FD9);
// 0x7FDA reserved
SFRX(FNADDR, 0x7FDB);
// 0x7FDC reserved

SFRX(USBPAIR, 0x7FDD);
#define PR2IN bmBit0
#define PR4IN bmBit1
#define PR6IN bmBit2
#define PR2OUT bmBit3
#define PR4OUT bmBit4
#define PR6OUT bmBit5
// Bit 6 unused
#define ISOSEND0 bmBit7

SFRX(IN07VAL, 0x7FDE);
// Bit 0 is read-only, always reads '1'
#define IN1VAL bmBit1
#define IN2VAL bmBit2
#define IN3VAL bmBit3
#define IN4VAL bmBit4
#define IN5VAL bmBit5
#define IN6VAL bmBit6
#define IN7VAL bmBit7

SFRX(OUT07VAL, 0x7FDF);
// Bit 0 is read-only, always reads '1'
#define OUT1VAL bmBit1
#define OUT2VAL bmBit2
#define OUT3VAL bmBit3
#define OUT4VAL bmBit4
#define OUT5VAL bmBit5
#define OUT6VAL bmBit6
#define OUT7VAL bmBit7

SFRX(INISOVAL, 0x7FE0);
#define IN8VAL bmBit0
#define IN9VAL bmBit1
#define IN10VAL bmBit2
#define IN11VAL bmBit3
#define IN12VAL bmBit4
#define IN13VAL bmBit5
#define IN14VAL bmBit6
#define IN15VAL bmBit7

SFRX(OUTISOVAL, 0x7FE1);
#define OUT8VAL bmBit0
#define OUT9VAL bmBit1
#define OUT10VAL bmBit2
#define OUT11VAL bmBit3
#define OUT12VAL bmBit4
#define OUT13VAL bmBit5
#define OUT14VAL bmBit6
#define OUT15VAL bmBit7

SFRX(FASTXFR, 0x7FE2);
#define WMOD0 bmBit0
#define WMOD1 bmBit1
#define WPOL bmBit2
#define RMOD0 bmBit3
#define RMOD1 bmBit4
#define RPOL bmBit5
#define FBLK bmBit6
#define FISO bmBit7

SFRX(AUTOPTRH, 0x7FE3);
SFRX(AUTOPTRL, 0x7FE4);
SFRX(AUTODATA, 0x7FE5);
// 0x7FE6 reserved
// 0x7FE7 reserved

/******************************* Setup Data ********************************/
SFRX(SETUPDAT[8], 0x7FE8);

/************************* Isochronous FIFO sizes **************************/
SFRX(OUT8ADDR, 0x7FF0);
SFRX(OUT9ADDR, 0x7FF1);
SFRX(OUT10ADDR, 0x7FF2);
SFRX(OUT11ADDR, 0x7FF3);
SFRX(OUT12ADDR, 0x7FF4);
SFRX(OUT13ADDR, 0x7FF5);
SFRX(OUT14ADDR, 0x7FF6);
SFRX(OUT15ADDR, 0x7FF7);

SFRX(IN8ADDR, 0x7FF8);
SFRX(IN9ADDR, 0x7FF9);
SFRX(IN10ADDR, 0x7FFA);
SFRX(IN11ADDR, 0x7FFB);
SFRX(IN12ADDR, 0x7FFC);
SFRX(IN13ADDR, 0x7FFD);
SFRX(IN14ADDR, 0x7FFE);
SFRX(IN15ADDR, 0x7FFF);

#endif

+ 41
- 0
src/jtag/drivers/OpenULINK/include/shorttypes.h View File

@@ -0,0 +1,41 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#ifndef __SHORTTYPES_H
#define __SHORTTYPES_H

#include <stdint.h>

/**
* @file Integer type definitions for shorter code (easier to stay within 80
* character maximum line length).
*/

/* Signed integers */
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;

/* Unsigned integers */
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;

#endif

+ 267
- 0
src/jtag/drivers/OpenULINK/include/usb.h View File

@@ -0,0 +1,267 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#ifndef __USB_H
#define __USB_H

#include "shorttypes.h"
#include "reg_ezusb.h"

#include <stdbool.h>

#define NULL (void*)0;

/* High and Low byte of a word (u16) */
#define HI8(word) (u8)(((u16)word >> 8) & 0xff)
#define LO8(word) (u8)((u16)word & 0xff)

/* Convenience functions */
#define STALL_EP0() EP0CS |= EP0STALL
#define CLEAR_IRQ() EXIF &= ~USBINT

/*********** USB descriptors. See section 9.5 of the USB 1.1 spec **********/

/* USB Descriptor Types. See USB 1.1 spec, page 187, table 9-5 */
#define DESCRIPTOR_TYPE_DEVICE 0x01
#define DESCRIPTOR_TYPE_CONFIGURATION 0x02
#define DESCRIPTOR_TYPE_STRING 0x03
#define DESCRIPTOR_TYPE_INTERFACE 0x04
#define DESCRIPTOR_TYPE_ENDPOINT 0x05

#define STR_DESCR(len,...) { len*2+2, DESCRIPTOR_TYPE_STRING, { __VA_ARGS__ } }

/** USB Device Descriptor. See USB 1.1 spec, pp. 196 - 198 */
typedef struct {
u8 bLength; ///< Size of this descriptor in bytes.
u8 bDescriptorType; ///< DEVICE Descriptor Type.
u16 bcdUSB; ///< USB specification release number (BCD).
u8 bDeviceClass; ///< Class code.
u8 bDeviceSubClass; ///< Subclass code.
u8 bDeviceProtocol; ///< Protocol code.
u8 bMaxPacketSize0; ///< Maximum packet size for EP0 (8, 16, 32, 64).
u16 idVendor; ///< USB Vendor ID.
u16 idProduct; ///< USB Product ID.
u16 bcdDevice; ///< Device Release Number (BCD).
u8 iManufacturer; ///< Index of manufacturer string descriptor.
u8 iProduct; ///< Index of product string descriptor.
u8 iSerialNumber; ///< Index of string descriptor containing serial #.
u8 bNumConfigurations; ///< Number of possible configurations.
} usb_device_descriptor_t;

/** USB Configuration Descriptor. See USB 1.1 spec, pp. 199 - 200 */
typedef struct {
u8 bLength; ///< Size of this descriptor in bytes.
u8 bDescriptorType; ///< CONFIGURATION descriptor type.
u16 wTotalLength; ///< Combined total length of all descriptors.
u8 bNumInterfaces; ///< Number of interfaces in this configuration.
u8 bConfigurationValue; ///< Value used to select this configuration.
u8 iConfiguration; ///< Index of configuration string descriptor.
u8 bmAttributes; ///< Configuration characteristics.
u8 MaxPower; ///< Maximum power consumption in 2 mA units.
} usb_config_descriptor_t;

/** USB Interface Descriptor. See USB 1.1 spec, pp. 201 - 203 */
typedef struct {
u8 bLength; ///< Size of this descriptor in bytes.
u8 bDescriptorType; ///< INTERFACE descriptor type.
u8 bInterfaceNumber; ///< Interface number.
u8 bAlternateSetting; ///< Value used to select alternate setting.
u8 bNumEndpoints; ///< Number of endpoints used by this interface.
u8 bInterfaceClass; ///< Class code.
u8 bInterfaceSubclass; ///< Subclass code.
u8 bInterfaceProtocol; ///< Protocol code.
u8 iInterface; ///< Index of interface string descriptor.
} usb_interface_descriptor_t;

/** USB Endpoint Descriptor. See USB 1.1 spec, pp. 203 - 204 */
typedef struct {
u8 bLength; ///< Size of this descriptor in bytes.
u8 bDescriptorType; ///< ENDPOINT descriptor type.
u8 bEndpointAddress; ///< Endpoint Address: USB 1.1 spec, table 9-10.
u8 bmAttributes; ///< Endpoint Attributes: USB 1.1 spec, table 9-10.
u16 wMaxPacketSize; ///< Maximum packet size for this endpoint.
u8 bInterval; ///< Polling interval (in ms) for this endpoint.
} usb_endpoint_descriptor_t;

/** USB Language Descriptor. See USB 1.1 spec, pp. 204 - 205 */
typedef struct {
u8 bLength; ///< Size of this descriptor in bytes.
u8 bDescriptorType; ///< STRING descriptor type.
u16 wLANGID[]; ///< LANGID codes.
} usb_language_descriptor_t;

/** USB String Descriptor. See USB 1.1 spec, pp. 204 - 205 */
typedef struct {
u8 bLength; ///< Size of this descriptor in bytes.
u8 bDescriptorType; ///< STRING descriptor type.
u16 bString[]; ///< UNICODE encoded string.
} usb_string_descriptor_t;

/********************** USB Control Endpoint 0 related *********************/

/** USB Control Setup Data. See USB 1.1 spec, pp. 183 - 185 */
typedef struct {
u8 bmRequestType; ///< Characteristics of a request.
u8 bRequest; ///< Specific request.
u16 wValue; ///< Field that varies according to request.
u16 wIndex; ///< Field that varies according to request.
u16 wLength; ///< Number of bytes to transfer in data stage.
} setup_data_t;

/* External declarations for variables that need to be accessed outside of
* the USB module */
extern volatile bool EP2_out;
extern volatile bool EP2_in;
extern volatile __xdata __at 0x7FE8 setup_data_t setup_data;

/*
* USB Request Types (bmRequestType): See USB 1.1 spec, page 183, table 9-2
*
* Bit 7: Data transfer direction
* 0 = Host-to-device
* 1 = Device-to-host
* Bit 6...5: Type
* 0 = Standard
* 1 = Class
* 2 = Vendor
* 3 = Reserved
* Bit 4...0: Recipient
* 0 = Device
* 1 = Interface
* 2 = Endpoint
* 3 = Other
* 4...31 = Reserved
*/

#define USB_DIR_OUT 0x00
#define USB_DIR_IN 0x80

#define USB_REQ_TYPE_STANDARD (0x00 << 5)
#define USB_REQ_TYPE_CLASS (0x01 << 5)
#define USB_REQ_TYPE_VENDOR (0x02 << 5)
#define USB_REQ_TYPE_RESERVED (0x03 << 5)

#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03

/* bmRequestType for USB Standard Requests */

/* Clear Interface Request */
#define CF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
#define CF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
#define CF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT)

/* Get Configuration Request */
#define GC_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)

/* Get Descriptor Request */
#define GD_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)

/* Get Interface Request */
#define GI_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)

/* Get Status Request: See USB 1.1 spec, page 190 */
#define GS_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
#define GS_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
#define GS_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT)

/* Set Address Request is handled by EZ-USB core */

/* Set Configuration Request */
#define SC_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)

/* Set Descriptor Request */
#define SD_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)

/* Set Feature Request */
#define SF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
#define SF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
#define SF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT)

/* Set Interface Request */
#define SI_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)

/* Synch Frame Request */
#define SY_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT)

/* USB Requests (bRequest): See USB 1.1 spec, table 9-4 on page 187 */
#define GET_STATUS 0
#define CLEAR_FEATURE 1
// Value '2' is reserved for future use
#define SET_FEATURE 3
// Value '4' is reserved for future use
#define SET_ADDRESS 5
#define GET_DESCRIPTOR 6
#define SET_DESCRIPTOR 7
#define GET_CONFIGURATION 8
#define SET_CONFIGURATION 9
#define GET_INTERFACE 10
#define SET_INTERFACE 11
#define SYNCH_FRAME 12

/* Standard Feature Selectors: See USB 1.1 spec, table 9-6 on page 188 */
#define DEVICE_REMOTE_WAKEUP 1
#define ENDPOINT_HALT 0

/************************** EZ-USB specific stuff **************************/

/** USB Interrupts. See AN2131-TRM, page 9-4 for details */
typedef enum {
SUDAV_ISR = 13,
SOF_ISR,
SUTOK_ISR,
SUSPEND_ISR,
USBRESET_ISR,
IBN_ISR,
EP0IN_ISR,
EP0OUT_ISR,
EP1IN_ISR,
EP1OUT_ISR,
EP2IN_ISR,
EP2OUT_ISR,
EP3IN_ISR,
EP3OUT_ISR,
EP4IN_ISR,
EP4OUT_ISR,
EP5IN_ISR,
EP5OUT_ISR,
EP6IN_ISR,
EP6OUT_ISR,
EP7IN_ISR,
EP7OUT_ISR
} USB_ISR;

/*************************** Function Prototypes ***************************/

__xdata u8* usb_get_endpoint_cs_reg(u8 ep);
void usb_reset_data_toggle(u8 ep);

bool usb_handle_get_status(void);
bool usb_handle_clear_feature(void);
bool usb_handle_set_feature(void);
bool usb_handle_get_descriptor(void);
void usb_handle_set_interface(void);

void usb_handle_setup_data(void);
void usb_init(void);

#endif

+ 83
- 0
src/jtag/drivers/OpenULINK/src/USBJmpTb.a51 View File

@@ -0,0 +1,83 @@
;--------------------------------------------------------------------------;
; Copyright (C) 2011 by Martin Schmoelzer ;
; <martin.schmoelzer@student.tuwien.ac.at> ;
; ;
; This program is free software; you can redistribute it and/or modify ;
; it under the terms of the GNU General Public License as published by ;
; the Free Software Foundation; either version 2 of the License, or ;
; (at your option) any later version. ;
; ;
; This program is distributed in the hope that it will be useful, ;
; but WITHOUT ANY WARRANTY; without even the implied warranty of ;
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;
; GNU General Public License for more details. ;
; ;
; You should have received a copy of the GNU General Public License ;
; along with this program; if not, write to the ;
; Free Software Foundation, Inc., ;
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ;
;--------------------------------------------------------------------------;

.module JUMPTABLE
.globl USB_AutoVector
.globl USB_Jump_Table

;--------------------------------------------------------------------------;
; Interrupt Vectors ;
;--------------------------------------------------------------------------;
.area USB_JV (ABS,OVR) ; Absolute, Overlay
.org 0x43 ; USB interrupt (INT2) jumps here
USB_AutoVector = #. + 2
ljmp USB_jump_table

;--------------------------------------------------------------------------;
; USB Jump Table ;
;--------------------------------------------------------------------------;
.area USB_JT (ABS) ; Absolute placement
.org 0x1B00 ; Place jump table at 0x1B00

USB_jump_table: ; autovector jump table
ljmp _sudav_isr ; Setup Data Available
.db 0
ljmp _sof_isr ; Start of Frame
.db 0
ljmp _sutok_isr ; Setup Data Loading
.db 0
ljmp _suspend_isr ; Global Suspend
.db 0
ljmp _usbreset_isr ; USB Reset
.db 0
ljmp _ibn_isr ; IN Bulk NAK interrupt
.db 0
ljmp _ep0in_isr ; Endpoint 0 IN
.db 0
ljmp _ep0out_isr ; Endpoint 0 OUT
.db 0
ljmp _ep1in_isr ; Endpoint 1 IN
.db 0
ljmp _ep1out_isr ; Endpoint 1 OUT
.db 0
ljmp _ep2in_isr ; Endpoint 2 IN
.db 0
ljmp _ep2out_isr ; Endpoint 2 OUT
.db 0
ljmp _ep3in_isr ; Endpoint 3 IN
.db 0
ljmp _ep3out_isr ; Endpoint 3 OUT
.db 0
ljmp _ep4in_isr ; Endpoint 4 IN
.db 0
ljmp _ep4out_isr ; Endpoint 4 OUT
.db 0
ljmp _ep5in_isr ; Endpoint 5 IN
.db 0
ljmp _ep5out_isr ; Endpoint 5 OUT
.db 0
ljmp _ep6in_isr ; Endpoint 6 IN
.db 0
ljmp _ep6out_isr ; Endpoint 6 OUT
.db 0
ljmp _ep7in_isr ; Endpoint 7 IN
.db 0
ljmp _ep7out_isr ; Endpoint 7 OUT
.db 0

+ 51
- 0
src/jtag/drivers/OpenULINK/src/delay.c View File

@@ -0,0 +1,51 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#include "delay.h"

void delay_5us(void)
{
NOP;
}

void delay_1ms(void) {
u16 i;

for (i = 0; i < 598; i++);
}

void delay_us(u16 delay)
{
u16 i;
u16 maxcount = (delay / 5);

for (i = 0; i < maxcount; i++) {
delay_5us();
}
}

void delay_ms(u16 delay)
{
u16 i;

for (i = 0; i < delay; i++) {
delay_1ms();
}
}

+ 414
- 0
src/jtag/drivers/OpenULINK/src/jtag.c View File

@@ -0,0 +1,414 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#include "jtag.h"

#include "io.h"
#include "msgtypes.h"
#include "common.h"

#include <stdbool.h>

/** Delay value for SCAN operations with less than maximum TCK frequency */
u8 delay_scan = 0;

/** Delay value for CLOCK_TCK operations */
u8 delay_tck = 0;

/** Delay value for CLOCK_TMS operations with less than maximum frequency */
u8 delay_tms = 0;

/**
* Perform JTAG SCAN-IN operation at maximum TCK frequency.
*
* Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and
* stored in the EP2 IN buffer.
*
* @param out_offset offset in OUT2BUF where payload data starts
*/
void jtag_scan_in(u8 out_offset, u8 in_offset)
{
u8 scan_size_bytes, bits_last_byte;
u8 tms_count_start, tms_count_end;
u8 tms_sequence_start, tms_sequence_end;
u8 tdo_data, i, j;

u8 outb_buffer;

/* Get parameters from OUT2BUF */
scan_size_bytes = OUT2BUF[out_offset];
bits_last_byte = OUT2BUF[out_offset + 1];
tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
tms_sequence_start = OUT2BUF[out_offset + 3];
tms_sequence_end = OUT2BUF[out_offset + 4];

if (tms_count_start > 0) {
jtag_clock_tms(tms_count_start, tms_sequence_start);
}

outb_buffer = OUTB & ~(PIN_TDI | PIN_TCK | PIN_TMS);

/* Shift all bytes except the last byte */
for (i = 0; i < scan_size_bytes - 1; i++) {
tdo_data = 0;

for (j = 0; j < 8; j++) {
OUTB = outb_buffer; /* TCK changes here */
OUTB = (outb_buffer | PIN_TCK);
tdo_data = tdo_data >> 1;

if (GET_TDO()) {
tdo_data |= 0x80;
}
}

/* Copy TDO data to IN2BUF */
IN2BUF[i + in_offset] = tdo_data;
}

tdo_data = 0;

/* Shift the last byte */
for (j = 0; j < bits_last_byte; j++) {
/* Assert TMS signal if requested and this is the last bit */
if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
outb_buffer |= PIN_TMS;
tms_count_end--;
tms_sequence_end = tms_sequence_end >> 1;
}

OUTB = outb_buffer; /* TCK change here */
OUTB = (outb_buffer | PIN_TCK);
tdo_data = tdo_data >> 1;

if (GET_TDO()) {
tdo_data |= 0x80;
}
}
tdo_data = tdo_data >> (8 - bits_last_byte);

/* Copy TDO data to IN2BUF */
IN2BUF[i + in_offset] = tdo_data;

/* Move to correct end state */
if (tms_count_end > 0) {
jtag_clock_tms(tms_count_end, tms_sequence_end);
}
}

/**
* Perform JTAG SCAN-OUT operation at maximum TCK frequency.
*
* Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
* data is not sampled.
* The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state.
*
* @param out_offset offset in OUT2BUF where payload data starts
*/
void jtag_scan_out(u8 out_offset)
{
u8 scan_size_bytes, bits_last_byte;
u8 tms_count_start, tms_count_end;
u8 tms_sequence_start, tms_sequence_end;
u8 tdi_data, i, j;

u8 outb_buffer;

/* Get parameters from OUT2BUF */
scan_size_bytes = OUT2BUF[out_offset];
bits_last_byte = OUT2BUF[out_offset + 1];
tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
tms_sequence_start = OUT2BUF[out_offset + 3];
tms_sequence_end = OUT2BUF[out_offset + 4];
if (tms_count_start > 0) {
jtag_clock_tms(tms_count_start, tms_sequence_start);
}

outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS);

/* Shift all bytes except the last byte */
for (i = 0; i < scan_size_bytes - 1; i++) {
tdi_data = OUT2BUF[i + out_offset + 5];

for (j = 0; j < 8; j++) {
if (tdi_data & 0x01) {
outb_buffer |= PIN_TDI;
}
else {
outb_buffer &= ~PIN_TDI;
}

OUTB = outb_buffer; /* TDI and TCK change here */
tdi_data = tdi_data >> 1;
OUTB = (outb_buffer | PIN_TCK);
}
}

tdi_data = OUT2BUF[i + out_offset + 5];

/* Shift the last byte */
for (j = 0; j < bits_last_byte; j++) {
if (tdi_data & 0x01) {
outb_buffer |= PIN_TDI;
}
else {
outb_buffer &= ~PIN_TDI;
}

/* Assert TMS signal if requested and this is the last bit */
if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
outb_buffer |= PIN_TMS;
tms_count_end--;
tms_sequence_end = tms_sequence_end >> 1;
}

OUTB = outb_buffer; /* TDI and TCK change here */
tdi_data = tdi_data >> 1;
OUTB = (outb_buffer | PIN_TCK);
}

/* Move to correct end state */
if (tms_count_end > 0) {
jtag_clock_tms(tms_count_end, tms_sequence_end);
}
}

/**
* Perform bidirectional JTAG SCAN operation at maximum TCK frequency.
*
* Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
* data is sampled and stored in the EP2 IN buffer.
* The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state.
*
* @param out_offset offset in OUT2BUF where payload data starts
*/
void jtag_scan_io(u8 out_offset, u8 in_offset)
{
u8 scan_size_bytes, bits_last_byte;
u8 tms_count_start, tms_count_end;
u8 tms_sequence_start, tms_sequence_end;
u8 tdi_data, tdo_data, i, j;

u8 outb_buffer;

/* Get parameters from OUT2BUF */
scan_size_bytes = OUT2BUF[out_offset];
bits_last_byte = OUT2BUF[out_offset + 1];
tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
tms_sequence_start = OUT2BUF[out_offset + 3];
tms_sequence_end = OUT2BUF[out_offset + 4];
if (tms_count_start > 0) {
jtag_clock_tms(tms_count_start, tms_sequence_start);
}

outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS);

/* Shift all bytes except the last byte */
for (i = 0; i < scan_size_bytes - 1; i++) {
tdi_data = OUT2BUF[i + out_offset + 5];
tdo_data = 0;

for (j = 0; j < 8; j++) {
if (tdi_data & 0x01) {
outb_buffer |= PIN_TDI;
}
else {
outb_buffer &= ~PIN_TDI;
}

OUTB = outb_buffer; /* TDI and TCK change here */
tdi_data = tdi_data >> 1;
OUTB = (outb_buffer | PIN_TCK);
tdo_data = tdo_data >> 1;

if (GET_TDO()) {
tdo_data |= 0x80;
}
}

/* Copy TDO data to IN2BUF */
IN2BUF[i + in_offset] = tdo_data;
}

tdi_data = OUT2BUF[i + out_offset + 5];
tdo_data = 0;

/* Shift the last byte */
for (j = 0; j < bits_last_byte; j++) {
if (tdi_data & 0x01) {
outb_buffer |= PIN_TDI;
}
else {
outb_buffer &= ~PIN_TDI;
}

/* Assert TMS signal if requested and this is the last bit */
if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
outb_buffer |= PIN_TMS;
tms_count_end--;
tms_sequence_end = tms_sequence_end >> 1;
}

OUTB = outb_buffer; /* TDI and TCK change here */
tdi_data = tdi_data >> 1;
OUTB = (outb_buffer | PIN_TCK);
tdo_data = tdo_data >> 1;

if (GET_TDO()) {
tdo_data |= 0x80;
}
}
tdo_data = tdo_data >> (8 - bits_last_byte);

/* Copy TDO data to IN2BUF */
IN2BUF[i + in_offset] = tdo_data;
/* Move to correct end state */
if (tms_count_end > 0) {
jtag_clock_tms(tms_count_end, tms_sequence_end);
}
}

/**
* Generate TCK clock cycles.
*
* @param count number of TCK clock cyclces to generate.
*/
void jtag_clock_tck(u16 count)
{
u16 i;
u8 j;

for ( i = 0; i < count; i++ ) {
SET_TCK_LOW();
for(j = 0; j < delay_tck; j++);

SET_TCK_HIGH();
for(j = 0; j < delay_tck; j++);
}
}

/**
* Perform TAP-FSM state transitions at maximum TCK frequency.
*
* @param count the number of state transitions to perform.
* @param sequence the TMS pin levels for each state transition, starting with
* the least-significant bit.
*/
void jtag_clock_tms(u8 count, u8 sequence)
{
volatile u8 outb_buffer;
u8 i;

outb_buffer = OUTB & ~(PIN_TCK);

for ( i = 0; i < count; i++ ) {
/* Set TMS pin according to sequence parameter */
if ( sequence & 0x1 ) {
outb_buffer |= PIN_TMS;
}
else {
outb_buffer &= ~PIN_TMS;
}

OUTB = outb_buffer;
sequence = sequence >> 1;
OUTB = outb_buffer | PIN_TCK;
}
}

/**
* Perform TAP-FSM state transitions at less than maximum TCK frequency.
*
* @param count the number of state transitions to perform.
* @param sequence the TMS pin levels for each state transition, starting with
* the least-significant bit.
*/
void jtag_slow_clock_tms(u8 count, u8 sequence)
{

}

/**
* Get current JTAG signal states.
*
* @return a 16-bit integer where the most-significant byte contains the state
* of the JTAG input signals and the least-significant byte cotains the state
* of the JTAG output signals.
*/
u16 jtag_get_signals(void)
{
u8 input_signal_state, output_signal_state;

input_signal_state = 0;
output_signal_state = 0;

/* Get states of input pins */
if (GET_TDO()) {
input_signal_state |= SIGNAL_TDO;
}
if (GET_BRKOUT()) {
input_signal_state |= SIGNAL_BRKOUT;
}
if (GET_TRAP()) {
input_signal_state |= SIGNAL_TRAP;
}
if (GET_RTCK()) {
/* Using RTCK this way would be extremely slow,
* implemented only for the sake of completeness */
input_signal_state |= SIGNAL_RTCK;
}

/* Get states of output pins */
output_signal_state = PINSB & MASK_PORTB_DIRECTION_OUT;

return ((u16)input_signal_state << 8) | ((u16)output_signal_state);
}

/**
* Set state of JTAG output signals.
*
* @param low signals which should be de-asserted.
* @param high signals which should be asserted.
*/
void jtag_set_signals(u8 low, u8 high)
{
OUTB &= ~(low & MASK_PORTB_DIRECTION_OUT);
OUTB |= (high & MASK_PORTB_DIRECTION_OUT);
}

/**
* Configure TCK delay parameters.
*
* @param scan number of delay cycles in shift operations.
* @param tck number of delay cycles in clock_tck operations.
* @param tms number of delay cycles in clock_tms operations.
*/
void jtag_configure_tck_delay(u8 scan, u8 tck, u8 tms)
{
delay_scan = scan;
delay_tck = tck;
delay_tms = tms;
}

+ 92
- 0
src/jtag/drivers/OpenULINK/src/main.c View File

@@ -0,0 +1,92 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#include "main.h"

#include "shorttypes.h"
#include "io.h"
#include "usb.h"
#include "protocol.h"

extern void sudav_isr(void) __interrupt SUDAV_ISR;
extern void sof_isr(void) __interrupt;
extern void sutok_isr(void) __interrupt;
extern void suspend_isr(void) __interrupt;
extern void usbreset_isr(void) __interrupt;
extern void ibn_isr(void) __interrupt;
extern void ep0in_isr(void) __interrupt;
extern void ep0out_isr(void) __interrupt;
extern void ep1in_isr(void) __interrupt;
extern void ep1out_isr(void) __interrupt;
extern void ep2in_isr(void) __interrupt;
extern void ep2out_isr(void) __interrupt;
extern void ep3in_isr(void) __interrupt;
extern void ep3out_isr(void) __interrupt;
extern void ep4in_isr(void) __interrupt;
extern void ep4out_isr(void) __interrupt;
extern void ep5in_isr(void) __interrupt;
extern void ep5out_isr(void) __interrupt;
extern void ep6in_isr(void) __interrupt;
extern void ep6out_isr(void) __interrupt;
extern void ep7in_isr(void) __interrupt;
extern void ep7out_isr(void) __interrupt;

void io_init(void)
{
/* PORTxCFG register bits select alternate functions (1 == alternate function,
* 0 == standard I/O)
* OEx register bits turn on/off output buffer (1 == output, 0 == input)
* OUTx register bits determine pin state of output
* PINx register bits reflect pin state (high == 1, low == 0) */

/* PORT A */
PORTACFG = PIN_OE;
OEA = PIN_U_OE | PIN_OE | PIN_RUN_LED | PIN_COM_LED;
OUTA = PIN_RUN_LED | PIN_COM_LED;

/* PORT B */
PORTBCFG = 0x00;
OEB = PIN_TDI | PIN_TMS | PIN_TCK | PIN_TRST | PIN_BRKIN | PIN_RESET
| PIN_OCDSE;

/* TRST and RESET signals are low-active but inverted by hardware, so we clear
* these signals here! */
OUTB = 0x00;

/* PORT C */
PORTCCFG = PIN_WR;
OEC = PIN_TXD0 | PIN_WR;
OUTC = 0x00;
}

int main(void)
{
io_init();
usb_init();

/* Enable Interrupts */
EA = 1;

/* Begin executing command(s). This function never returns. */
command_loop();

/* Never reached, but SDCC complains about missing return statement */
return 0;
}

+ 212
- 0
src/jtag/drivers/OpenULINK/src/protocol.c View File

@@ -0,0 +1,212 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#include "protocol.h"
#include "jtag.h"
#include "delay.h"
#include "usb.h"
#include "io.h"
#include "msgtypes.h"

#include "reg_ezusb.h"

/**
* @file Implementation of the OpenULINK communication protocol.
*
* The OpenULINK protocol uses one OUT and one IN endpoint. These two endpoints
* are configured to use the maximum packet size for full-speed transfers,
* 64 bytes. Commands always start with a command ID (see msgtypes.h for
* command ID definitions) and contain zero or more payload data bytes in both
* transfer directions (IN and OUT). The payload
*
* Almost all commands contain a fixed number of payload data bytes. The number
* of payload data bytes for the IN and OUT direction does not need to be the
* same.
*
* Multiple commands may be sent in one EP2 Bulk-OUT packet. Because the
* OpenULINK firmware does not perform bounds checking for EP2 Bulk-IN packets,
* the host MUST ensure that the commands sent in the OUT packet require a
* maximum of 64 bytes of IN data.
*/

/** Index in EP2 Bulk-OUT data buffer that contains the current command ID */
volatile u8 cmd_id_index;

/** Number of data bytes already in EP2 Bulk-IN buffer */
volatile u8 payload_index_in;

/**
* Execute a SET_LEDS command.
*/
void execute_set_led_command(void)
{
u8 led_state = OUT2BUF[cmd_id_index + 1];

if (led_state & RUN_LED_ON) {
SET_RUN_LED();
}

if (led_state & COM_LED_ON) {
SET_COM_LED();
}

if (led_state & RUN_LED_OFF) {
CLEAR_RUN_LED();
}

if (led_state & COM_LED_OFF) {
CLEAR_COM_LED();
}
}

/**
* Executes one command and updates global command indexes.
*
* @param index the index of the Bulk EP2-OUT data buffer at which the
* command ID is stored.
* @return true if this command was the last command.
* @return false if there are more commands within the current contents of the
* Bulk EP2-OUT data buffer.
*/
bool execute_command(void)
{
u8 usb_out_bytecount, usb_in_bytecount;
u16 signal_state;
u16 count;

/* Most commands do not transfer IN data. To save code space, we write 0 to
* usb_in_bytecount here, then modify it in the switch statement below where
* neccessary */
usb_in_bytecount = 0;

switch (OUT2BUF[cmd_id_index] /* Command ID */) {
case CMD_SCAN_IN:
usb_out_bytecount = 5;
usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
jtag_scan_in(cmd_id_index + 1, payload_index_in);
break;
case CMD_SCAN_OUT:
usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5;
jtag_scan_out(cmd_id_index + 1);
break;
case CMD_SCAN_IO:
usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
usb_out_bytecount = usb_in_bytecount + 5;
jtag_scan_io(cmd_id_index + 1, payload_index_in);
break;
case CMD_CLOCK_TMS:
usb_out_bytecount = 2;
jtag_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
break;
case CMD_CLOCK_TCK:
usb_out_bytecount = 2;
count = (u16)OUT2BUF[cmd_id_index + 1];
count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
jtag_clock_tck(count);
break;
case CMD_SLEEP_US:
usb_out_bytecount = 2;
count = (u16)OUT2BUF[cmd_id_index + 1];
count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
delay_us(count);
break;
case CMD_SLEEP_MS:
usb_out_bytecount = 2;
count = (u16)OUT2BUF[cmd_id_index + 1];
count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
delay_ms(count);
break;
case CMD_GET_SIGNALS:
usb_out_bytecount = 0;
usb_in_bytecount = 2;
signal_state = jtag_get_signals();
IN2BUF[payload_index_in] = (signal_state >> 8) & 0x00FF;
IN2BUF[payload_index_in + 1] = signal_state & 0x00FF;
break;
case CMD_SET_SIGNALS:
usb_out_bytecount = 2;
jtag_set_signals(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
break;
case CMD_SET_LEDS:
usb_out_bytecount = 1;
execute_set_led_command();
break;
case CMD_TEST:
usb_out_bytecount = 1;
/* Do nothing... This command is only used to test if the device is ready
* to accept new commands */
break;
default:
/* Should never be reached */
usb_out_bytecount = 0;
break;
}

/* Update EP2 Bulk-IN data byte count */
payload_index_in += usb_in_bytecount;

/* Determine if this was the last command */
if ((cmd_id_index + usb_out_bytecount + 1) >= OUT2BC) {
return true;
}
else {
/* Not the last command, update cmd_id_index */
cmd_id_index += (usb_out_bytecount + 1);
return false;
}
}

/**
* Forever wait for commands and execute them as they arrive.
*/
void command_loop(void)
{
bool last_command;

while (1) {
cmd_id_index = 0;
payload_index_in = 0;

/* Wait until host sends EP2 Bulk-OUT packet */
while (!EP2_out);
EP2_out = 0;

/* Turn on COM LED to indicate command execution */
SET_COM_LED();

/* Execute the commands */
last_command = false;
while (last_command == false) {
last_command = execute_command();
}

CLEAR_COM_LED();
/* Send back EP2 Bulk-IN packet if required */
if (payload_index_in > 0) {
IN2BC = payload_index_in;
while (!EP2_in);
EP2_in = 0;
}

/* Re-arm EP2-OUT after command execution */
OUT2BC = 0;
}
}

+ 543
- 0
src/jtag/drivers/OpenULINK/src/usb.c View File

@@ -0,0 +1,543 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

/**
* @file Defines USB descriptors, interrupt routines and helper functions.
* To minimize code size, we make the following assumptions:
* - The OpenULINK has exactly one configuration
* - and exactly one alternate setting
*
* Therefore, we do not have to support the Set Configuration USB request.
*/

#include "usb.h"
#include "delay.h"
#include "io.h"

/* Also update external declarations in "include/usb.h" if making changes to
* these variables! */
volatile bool EP2_out = 0;
volatile bool EP2_in = 0;

volatile __xdata __at 0x7FE8 setup_data_t setup_data;

/* Define number of endpoints (except Control Endpoint 0) in a central place.
* Be sure to include the neccessary endpoint descriptors! */
#define NUM_ENDPOINTS 2

/*
* Normally, we would initialize the descriptor structures in C99 style:
*
* __code usb_device_descriptor_t device_descriptor = {
* .bLength = foo,
* .bDescriptorType = bar,
* .bcdUSB = 0xABCD,
* ...
* };
*
* But SDCC currently does not support this, so we have to do it the
* old-fashioned way...
*/

__code usb_device_descriptor_t device_descriptor = {
/* .bLength = */ sizeof(usb_device_descriptor_t),
/* .bDescriptorType = */ DESCRIPTOR_TYPE_DEVICE,
/* .bcdUSB = */ 0x0110, /* BCD: 01.00 (Version 1.0 USB spec) */
/* .bDeviceClass = */ 0xFF, /* 0xFF = vendor-specific */
/* .bDeviceSubClass = */ 0xFF,
/* .bDeviceProtocol = */ 0xFF,
/* .bMaxPacketSize0 = */ 64,
/* .idVendor = */ 0xC251,
/* .idProduct = */ 0x2710,
/* .bcdDevice = */ 0x0100,
/* .iManufacturer = */ 1,
/* .iProduct = */ 2,
/* .iSerialNumber = */ 3,
/* .bNumConfigurations = */ 1
};

/* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */

__code usb_config_descriptor_t config_descriptor = {
/* .bLength = */ sizeof(usb_config_descriptor_t),
/* .bDescriptorType = */ DESCRIPTOR_TYPE_CONFIGURATION,
/* .wTotalLength = */ sizeof(usb_config_descriptor_t) +
sizeof(usb_interface_descriptor_t) +
NUM_ENDPOINTS * sizeof(usb_endpoint_descriptor_t),
/* .bNumInterfaces = */ 1,
/* .bConfigurationValue = */ 1,
/* .iConfiguration = */ 4, /* String describing this configuration */
/* .bmAttributes = */ 0x80, /* Only MSB set according to USB spec */
/* .MaxPower = */ 50 /* 100 mA */
};

__code usb_interface_descriptor_t interface_descriptor00 = {
/* .bLength = */ sizeof(usb_interface_descriptor_t),
/* .bDescriptorType = */ DESCRIPTOR_TYPE_INTERFACE,
/* .bInterfaceNumber = */ 0,
/* .bAlternateSetting = */ 0,
/* .bNumEndpoints = */ NUM_ENDPOINTS,
/* .bInterfaceClass = */ 0xFF,
/* .bInterfaceSubclass = */ 0xFF,
/* .bInterfaceProtocol = */ 0xFF,
/* .iInterface = */ 0
};

__code usb_endpoint_descriptor_t Bulk_EP2_IN_Endpoint_Descriptor = {
/* .bLength = */ sizeof(usb_endpoint_descriptor_t),
/* .bDescriptorType = */ 0x05,
/* .bEndpointAddress = */ 2 | USB_DIR_IN,
/* .bmAttributes = */ 0x02,
/* .wMaxPacketSize = */ 64,
/* .bInterval = */ 0
};

__code usb_endpoint_descriptor_t Bulk_EP2_OUT_Endpoint_Descriptor = {
/* .bLength = */ sizeof(usb_endpoint_descriptor_t),
/* .bDescriptorType = */ 0x05,
/* .bEndpointAddress = */ 2 | USB_DIR_OUT,
/* .bmAttributes = */ 0x02,
/* .wMaxPacketSize = */ 64,
/* .bInterval = */ 0
};

__code usb_language_descriptor_t language_descriptor = {
/* .bLength = */ 4,
/* .bDescriptorType = */ DESCRIPTOR_TYPE_STRING,
/* .wLANGID = */ {0x0409 /* US English */}
};

__code usb_string_descriptor_t strManufacturer = STR_DESCR(9,'O','p','e','n','U','L','I','N','K');
__code usb_string_descriptor_t strProduct = STR_DESCR(9,'O','p','e','n','U','L','I','N','K');
__code usb_string_descriptor_t strSerialNumber = STR_DESCR(6, '0','0','0','0','0','1');
__code usb_string_descriptor_t strConfigDescr = STR_DESCR(12, 'J','T','A','G',' ','A','d','a','p','t','e','r');

/* Table containing pointers to string descriptors */
__code usb_string_descriptor_t* __code en_string_descriptors[4] = {
&strManufacturer,
&strProduct,
&strSerialNumber,
&strConfigDescr
};

void sudav_isr(void) __interrupt SUDAV_ISR
{
CLEAR_IRQ();

usb_handle_setup_data();

USBIRQ = SUDAVIR;
EP0CS |= HSNAK;
}

void sof_isr(void) __interrupt SOF_ISR { }
void sutok_isr(void) __interrupt SUTOK_ISR { }
void suspend_isr(void) __interrupt SUSPEND_ISR { }
void usbreset_isr(void) __interrupt USBRESET_ISR { }
void ibn_isr(void) __interrupt IBN_ISR { }

void ep0in_isr(void) __interrupt EP0IN_ISR { }
void ep0out_isr(void) __interrupt EP0OUT_ISR { }
void ep1in_isr(void) __interrupt EP1IN_ISR { }
void ep1out_isr(void) __interrupt EP1OUT_ISR { }

/**
* EP2 IN: called after the transfer from uC->Host has finished: we sent data
*/
void ep2in_isr(void) __interrupt EP2IN_ISR {
EP2_in = 1;

CLEAR_IRQ();
IN07IRQ = IN2IR; // Clear OUT2 IRQ
}

/**
* EP2 OUT: called after the transfer from Host->uC has finished: we got data
*/
void ep2out_isr(void) __interrupt EP2OUT_ISR {
EP2_out = 1;

CLEAR_IRQ();
OUT07IRQ = OUT2IR; // Clear OUT2 IRQ
}

void ep3in_isr(void) __interrupt EP3IN_ISR { }
void ep3out_isr(void) __interrupt EP3OUT_ISR { }
void ep4in_isr(void) __interrupt EP4IN_ISR { }
void ep4out_isr(void) __interrupt EP4OUT_ISR { }
void ep5in_isr(void) __interrupt EP5IN_ISR { }
void ep5out_isr(void) __interrupt EP5OUT_ISR { }
void ep6in_isr(void) __interrupt EP6IN_ISR { }
void ep6out_isr(void) __interrupt EP6OUT_ISR { }
void ep7in_isr(void) __interrupt EP7IN_ISR { }
void ep7out_isr(void) __interrupt EP7OUT_ISR { }

/**
* Return the control/status register for an endpoint
*
* @param ep endpoint address
* @return on success: pointer to Control & Status register for endpoint
* specified in \a ep
* @return on failure: NULL
*/
__xdata u8* usb_get_endpoint_cs_reg(u8 ep)
{
/* Mask direction bit */
u8 ep_num = ep & 0x7F;

switch (ep_num) {
case 0:
return &EP0CS;
break;
case 1:
return ep & 0x80 ? &IN1CS : &OUT1CS;
break;
case 2:
return ep & 0x80 ? &IN2CS : &OUT2CS;
break;
case 3:
return ep & 0x80 ? &IN3CS : &OUT3CS;
break;
case 4:
return ep & 0x80 ? &IN4CS : &OUT4CS;
break;
case 5:
return ep & 0x80 ? &IN5CS : &OUT5CS;
break;
case 6:
return ep & 0x80 ? &IN6CS : &OUT6CS;
break;
case 7:
return ep & 0x80 ? &IN7CS : &OUT7CS;
break;
}

return NULL;
}

void usb_reset_data_toggle(u8 ep)
{
/* TOGCTL register:
+----+-----+-----+------+-----+-------+-------+-------+
| Q | S | R | IO | 0 | EP2 | EP1 | EP0 |
+----+-----+-----+------+-----+-------+-------+-------+

To reset data toggle bits, we have to write the endpoint direction (IN/OUT)
to the IO bit and the endpoint number to the EP2..EP0 bits. Then, in a
separate write cycle, the R bit needs to be set.
*/
u8 togctl_value = (ep & 0x80 >> 3) | (ep & 0x7);

/* First step: Write EP number and direction bit */
TOGCTL = togctl_value;

/* Second step: Set R bit */
togctl_value |= TOG_R;
TOGCTL = togctl_value;
}

/**
* Handle GET_STATUS request.
*
* @return on success: true
* @return on failure: false
*/
bool usb_handle_get_status(void)
{
u8 *ep_cs;

switch (setup_data.bmRequestType) {
case GS_DEVICE:
/* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup.
* Byte 1: reserved, reset to zero */
IN0BUF[0] = 0;
IN0BUF[1] = 0;

/* Send response */
IN0BC = 2;
break;
case GS_INTERFACE:
/* Always return two zero bytes according to USB 1.1 spec, p. 191 */
IN0BUF[0] = 0;
IN0BUF[1] = 0;

/* Send response */
IN0BC = 2;
break;
case GS_ENDPOINT:
/* Get stall bit for endpoint specified in low byte of wIndex */
ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex & 0xff);

if (*ep_cs & EPSTALL) {
IN0BUF[0] = 0x01;
}
else {
IN0BUF[0] = 0x00;
}

/* Second byte sent has to be always zero */
IN0BUF[1] = 0;

/* Send response */
IN0BC = 2;
break;
default:
return false;
break;
}

return true;
}

/**
* Handle CLEAR_FEATURE request.
*
* @return on success: true
* @return on failure: false
*/
bool usb_handle_clear_feature(void)
{
__xdata u8 *ep_cs;

switch (setup_data.bmRequestType) {
case CF_DEVICE:
/* Clear remote wakeup not supported: stall EP0 */
STALL_EP0();
break;
case CF_ENDPOINT:
if (setup_data.wValue == 0) {
/* Unstall the endpoint specified in wIndex */
ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex);
if (!ep_cs) {
return false;
}
*ep_cs &= ~EPSTALL;
}
else {
/* Unsupported feature, stall EP0 */
STALL_EP0();
}
break;
default:
/* Vendor commands... */
}

return true;
}

/**
* Handle SET_FEATURE request.
*
* @return on success: true
* @return on failure: false
*/
bool usb_handle_set_feature(void)
{
__xdata u8 *ep_cs;

switch (setup_data.bmRequestType) {
case SF_DEVICE:
if (setup_data.wValue == 2) {
return true;
}
break;
case SF_ENDPOINT:
if (setup_data.wValue == 0) {
/* Stall the endpoint specified in wIndex */
ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex);
if (!ep_cs) {
return false;
}
*ep_cs |= EPSTALL;
}
else {
/* Unsupported endpoint feature */
return false;
}
break;
default:
/* Vendor commands... */
break;
}

return true;
}

/**
* Handle GET_DESCRIPTOR request.
*
* @return on success: true
* @return on failure: false
*/
bool usb_handle_get_descriptor(void)
{
__xdata u8 descriptor_type;
__xdata u8 descriptor_index;

descriptor_type = (setup_data.wValue & 0xff00) >> 8;
descriptor_index = setup_data.wValue & 0x00ff;

switch (descriptor_type) {
case DESCRIPTOR_TYPE_DEVICE:
SUDPTRH = HI8(&device_descriptor);
SUDPTRL = LO8(&device_descriptor);
break;
case DESCRIPTOR_TYPE_CONFIGURATION:
SUDPTRH = HI8(&config_descriptor);
SUDPTRL = LO8(&config_descriptor);
break;
case DESCRIPTOR_TYPE_STRING:
if (setup_data.wIndex == 0) {
/* Supply language descriptor */
SUDPTRH = HI8(&language_descriptor);
SUDPTRL = LO8(&language_descriptor);
}
else if (setup_data.wIndex == 0x0409 /* US English */) {
/* Supply string descriptor */
SUDPTRH = HI8(en_string_descriptors[descriptor_index - 1]);
SUDPTRL = LO8(en_string_descriptors[descriptor_index - 1]);
}
else {
return false;
}
break;
default:
/* Unsupported descriptor type */
return false;
break;
}

return true;
}

/**
* Handle SET_INTERFACE request.
*/
void usb_handle_set_interface(void)
{
/* Reset Data Toggle */
usb_reset_data_toggle(USB_DIR_IN | 2);
usb_reset_data_toggle(USB_DIR_OUT | 2);

/* Unstall & clear busy flag of all valid IN endpoints */
IN2CS = 0 | EPBSY;
/* Unstall all valid OUT endpoints, reset bytecounts */
OUT2CS = 0;
OUT2BC = 0;
}

/**
* Handle the arrival of a USB Control Setup Packet.
*/
void usb_handle_setup_data(void)
{
switch (setup_data.bRequest) {
case GET_STATUS:
if (!usb_handle_get_status()) {
STALL_EP0();
}
break;
case CLEAR_FEATURE:
if (!usb_handle_clear_feature()) {
STALL_EP0();
}
break;
case 2: case 4:
/* Reserved values */
STALL_EP0();
break;
case SET_FEATURE:
if (!usb_handle_set_feature()) {
STALL_EP0();
}
break;
case SET_ADDRESS:
/* Handled by USB core */
break;
case SET_DESCRIPTOR:
/* Set Descriptor not supported. */
STALL_EP0();
break;
case GET_DESCRIPTOR:
if (!usb_handle_get_descriptor()) {
STALL_EP0();
}
break;
case GET_CONFIGURATION:
/* OpenULINK has only one configuration, return its index */
IN0BUF[0] = config_descriptor.bConfigurationValue;
IN0BC = 1;
break;
case SET_CONFIGURATION:
/* OpenULINK has only one configuration -> nothing to do */
break;
case GET_INTERFACE:
/* OpenULINK only has one interface, return its number */
IN0BUF[0] = interface_descriptor00.bInterfaceNumber;
IN0BC = 1;
break;
case SET_INTERFACE:
usb_handle_set_interface();
break;
case SYNCH_FRAME:
/* Isochronous endpoints not used -> nothing to do */
break;
default:
/* Any other requests: do nothing */
break;
}
}

/**
* USB initialization. Configures USB interrupts, endpoints and performs
* ReNumeration.
*/
void usb_init(void) {
/* Mark endpoint 2 IN & OUT as valid */
IN07VAL = IN2VAL;
OUT07VAL = OUT2VAL;

/* Make sure no isochronous endpoints are marked valid */
INISOVAL = 0;
OUTISOVAL = 0;

/* Disable isochronous endpoints. This makes the isochronous data buffers
* available as 8051 XDATA memory at address 0x2000 - 0x27FF */
ISOCTL = ISODISAB;

/* Enable USB Autovectoring */
USBBAV |= AVEN;
/* Enable SUDAV interrupt */
USBIEN |= SUDAVIE;

/* Enable EP2 OUT & IN interrupts */
OUT07IEN = OUT2IEN;
IN07IEN = IN2IEN;

/* Enable USB interrupt (EIE register) */
EUSB = 1;

/* Perform ReNumeration */
USBCS = DISCON | RENUM;
delay_ms(200);
USBCS = DISCOE | RENUM;
}

+ 251
- 0
src/jtag/drivers/OpenULINK/ulink_firmware.hex View File

@@ -0,0 +1,251 @@
:040000000200733255
:01000B0032C2
:0100130032BA
:01001B0032B2
:0100230032AA
:01002B0032A2
:01003300329A
:01003B003292
:01004300328A
:01004B003282
:01005300327A
:01005B003272
:01006300326A
:03006B0002011F70
:0300D90002006EB4
:05006E0012011080FEEC
:1000DC00907F937404F0907F9C7495F0907F96744D
:1000EC0090F0907F94E4F0907F9D747FF0907F97D8
:1000FC00E4F0907F957440F0907F9E7442F0907F76
:10010C0098E4F0221200DC1204FCD2AF1207C89063
:03011C00000022BE
:0400CC00C200C201AB
:10011F00C021C0E0C0F0C082C083C002C003C004D1
:10012F00C005C006C007C000C001C0D075D00053C5
:10013F0091EF120455907FAB7401F0907FB4E044BF
:10014F0002F0D0D0D001D000D007D006D005D00417
:10015F00D003D002D083D082D0F0D0E0D021323281
:10016F003232323232323232C0E0C082C083D201F8
:10017F005391EF907FA97404F0D083D082D0E032F6
:10018F00C0E0C082C083D2005391EF907FAA740465
:10019F00F0D083D082D0E032323232323232323249
:1001AF003232AA82747F5AFB7407B50300500302E0
:1001BF000269EB2B2B9001C8730201E00201E402EC
:1001CF0001F702020A02021D02023002024302027A
:1001DF0056907FB422EA30E7067BB67C7F80047BA3
:1001EF00C67C7F8B828C8322EA30E7067BB87C7FCC
:1001FF0080047BC87C7F8B828C8322EA30E7067B6E
:10020F00BA7C7F80047BCA7C7F8B828C8322EA300E
:10021F00E7067BBC7C7F80047BCC7C7F8B828C83CE
:10022F0022EA30E7067BBE7C7F80047BCE7C7F8B0F
:10023F00828C8322EA30E7067BC07C7F80047BD0F0
:10024F007C7F8B828C8322EA30E7067AC27B7F80A9
:10025F00047AD27B7F8A828B832290000022AA822B
:10026F0074105AFB74075A4203907FD7EBF0742037
:10027F004BF022907FE8E0FABA8002800ABA81023E
:10028F008016BA825D8022907F00E4F0907F01F0AB
:10029F00907FB57402F0804C907F00E4F0907F0166
:1002AF00F0907FB57402F0803B907FECE0FAA3E012
:1002BF008A821201B1AA82AB837C008A828B838CE3
:1002CF00F0120D90FA30E008907F007401F0800575
:1002DF00907F00E4F0907F01E4F0907FB57402F01E
:1002EF008002C322D322907FE8E0FA6005BA02466B
:1002FF00800A907FB4E0FA4401F0803A907FEAE000
:10030F00FAA3E0FB4A7027907FECE0FAA3E08A8221
:10031F001201B1AA82AB83EA4B7002C3228A828B8D
:10032F0083E0FC5304FE8A828B83ECF08008907F7D
:10033F00B4E0FA4401F0D322907FE8E0FA6005BA06
:10034F0002468010907FEAE0FAA3E0FBBA0239BBC5
:10035F000036D322907FEAE0FAA3E0FB4A702790A1
:10036F007FECE0FAA3E08A821201B1AA82AB83EAA2
:10037F004B7002C3228A828B83E0FC4304018A8282
:10038F008B83ECF08002C322D322907FEAE0A3E0BC
:10039F00FA907FEAE0FBA3E07C00BA0102800CBA7E
:1003AF000202801DBA0302802E807B7AB07C0D90F2
:1003BF007FD4ECF07AB07C0D7C00907FD5EAF08092
:1003CF00677AC27C0D907FD4ECF07AC27C0D7C00F2
:1003DF00907FD5EAF08051907FECE0FAA3E0FC4AE1
:1003EF0070167AE27C0D907FD4ECF07AE27C0D7C73
:1003FF0000907FD5EAF08030907FECE0FAA3E0FC2C
:10040F00BA0921BC041E1BEB2BFA900E3693CAA31C
:10041F0093FB8A048B05907FD4EDF07B00907FD502
:10042F00EAF08004C322C322D32275828212026DA6
:10043F0075820212026D907FB87402F0907FC8E44B
:10044F00F0907FC9F022907FE9E0FA740CB50200BA
:10045F00500122EA2A2A9004697302049002049E32
:10046F000204AC0204B40204AC0204C10204CA02C6
:10047F0004C20204D70204E70204E80204F80204EB
:10048F00FB120282500122907FB4E04401F022124D
:10049F0002F5500122907FB4E04401F022907FB426
:1004AF00E04401F0221203474042907FB4E0440140
:1004BF00F02222907FB4E04401F022120399402CE5
:1004CF00907FB4E04401F022900DC7E493907F0039
:1004DF00F0907FB57401F02222900DCDE493907FC0
:1004EF0000F0907FB57401F02212043922907FDE64
:1004FF007404F0907FDF7404F0907FE0E4F0907F5D
:10050F00E1F0907FA17401F0907FAFE04401F09093
:10051F007FAEE04401F0907FAD7404F0907FAC7437
:10052F0004F0D2E8907FD6740AF09000C8120D3D07
:07053F00907FD67406F02244
:100DB00012011001FFFFFF4051C210270001010284
:100DC000030109022000010104803209040000022D
:100DD000FFFFFF00070582024000000705020240F6
:100DE00000000403090414034F00700065006E0046
:100DF00055004C0049004E004B0014034F0070009A
:100E000065006E0055004C0049004E004B000E037B
:100E10003000300030003000300031001A034A004A
:100E20005400410047002000410064006100700050
:0E0E3000740065007200E60DFA0D0E0E1C0E29
:10054600E5080424C0F582E4347DF583E0FA30E161
:1005560008907F96E0FB54EFF0EA30E008907F9633
:10056600E0FB547FF0EA30E308907F96E0FB44100E
:10057600F0EA30E208907F96E0FA4480F0227A00B2
:10058600E50824C0F582E4347DF583E0FB603EBBDC
:100596000202805FBB040302061CBB200302064363
:1005A600BB2203020673BB23030206ACBB24030271
:1005B60006E5BB250302071DBB260302074CBB2825
:1005C6000302077BBB290302078A02078E7B05E528
:1005D600080424C0F582E4347DF583E0FAE50804D6
:1005E600F58285090DC002C003120805D003D002AA
:1005F600020790E5080424C0F582E4347DF583E023
:100606002405FBE50804F582C002C003120951D097
:1006160003D002020790E5080424C0F582E4347D85
:10062600F583E0FA2405FBE50804F582850917C081
:1006360002C003120A83D003D0020207907B02E5B0
:10064600080424C0F582E4347DF583E0FC740225B9
:100656000824C0F582E4347DF583E0F5228C82C05F
:1006660002C003120C5BD003D0020207907B02E5A6
:10067600080424C0F582E4347DF583E0FC7D007433
:1006860002250824C0F582E4347DF583E0FFE442C8
:1006960004EF42058C828D83C002C003120C20D069
:1006A60003D0020207907B02E5080424C0F582E429
:1006B600347DF583E0FC7D007402250824C0F582B4
:1006C600E4347DF583E0FFE44204EF42058C828D3D
:1006D60083C002C003120D0AD003D0020207907B2A
:1006E60002E5080424C0F582E4347DF583E0FC7D50
:1006F600007402250824C0F582E4347DF583E0FF0A
:10070600E44204EF42058C828D83C002C003120DC1
:100716003DD003D00280737B007A02C002C0031270
:100726000C95AC82AD83D003D00285098275837E99
:100736008D06EEF0E509042400F582E4347EF583A7
:100746007D00ECF080447B02E5080424C0F582E4D9
:10075600347DF583E0FC7402250824C0F582E43478
:100766007DF583E0F5228C82C002C003120CD8D03E
:1007760003D00280157B01C002C003120546D003D8
:10078600D00280067B0180027B00EA2509F509AAD2
:10079600087C008B057E00ED2AFAEE3CFC0ABA00C6
:1007A600010C907FC9E0FD7E00C3EA9DEC64808E5B
:1007B600F063F08095F04002D322EB042508F5089B
:1007C600C32275080075090010000280FB907F9611
:1007D600E0FA547FF0C202200207120584920280DA
:1007E600F6907F96E0FA4480F0E509600B907FB9B9
:0F07F600E509F010010280FB907FC9E4F080C399
:0900D000750A00750B00750C00A7
:10080500E582FA24C0F582E4347DF583E0F50EEA4D
:100815000424C0F582E4347DF583E0F50F74022AE3
:10082500FD24C0F582E4347DF583E0C4540FFE5306
:10083500060FED24C0F582E4347DF583E0FD740FE9
:100845005DF51074032A24C0F582E4347DF583E058
:10085500FF74042A24C0F582E4347DF583E0F511A4
:10086500EE60078F228E82120C5B907F97E0FE531D
:1008750006F87F0074044EF87900AD0E7B001DBDAF
:10088500FF011B89027C00C3EA9DEC64808BF06349
:10089500F08095F050357A007B00BB080050199028
:1008A5007F97EEF0E8F0EAC313FA907F99E0FC3009
:1008B500E5034302800B80E2E50D292400F582E47F
:1008C500347EF583EAF009890780AF89077A00ABA2
:1008D50010751200E512B50F00503EAD0F78001DE2
:1008E500BDFF0118A9127C00E9B50511ECB5000D95
:1008F500EB600A4306021BE511C313F511907F97C0
:10090500EEF074044EF0EAC313FA907F99E0FC30E0
:10091500E503430280051280BBAC0F7D007408C35C
:100925009CFCE49DFD8CF005F0EA8002C313D5F034
:10093500FBFAE50D2F2400F582E4347EF583EAF019
:10094500EB60088511228B82020C5B22E582FA247A
:10095500C0F582E4347DF583E0F513EA0424C0F59F
:1009650082E4347DF583E0F51474022AFD24C0F594
:1009750082E4347DF583E0C4540FFE53060FED2465
:10098500C0F582E4347DF583E0FD740F5DF51574E3
:10099500032A24C0F582E4347DF583E0FF74042A3C
:1009A50024C0F582E4347DF583E0F516EE600B8F07
:1009B500228E82C002120C5BD002907F97E0FE531C
:1009C50006F97F00A9137D0019B9FF011D8F037872
:1009D50000C3EB99E864808DF063F08095F05038A2
:1009E500EA2F240524C0F582E4347DF583E0FB7D00
:1009F50000BD0800501FEB30E0054306018003539E
:100A050006FE907F97EEF0EBC313FB907F9774047F
:100A15004EF00D80DC0F80ACEA2F240524C0F58252
:100A2500E4347DF583E0FBAA157D00EDB514005097
:100A350041EB30E00543060180035306FEAF147811
:100A4500001FBFFF01188D017C00E9B50711ECB54A
:100A5500000DEA600A4306021AE516C313F516905F
:100A65007F97EEF0EBC313FB907F9774044EF00D68
:100A750080B9EA60088516228A82020C5B22E5822B
:100A8500F51824C0F582E4347DF583E0F519E51801
:100A95000424C0F582E4347DF583E0F51A7402255B
:100AA50018FD24C0F582E4347DF583E0C4540FFEBF
:100AB50053060FED24C0F582E4347DF583E0FD7423
:100AC5000F5DF51B7403251824C0F582E4347DF50C
:100AD50083E0FF7404251824C0F582E4347DF58392
:100AE500E0F51CEE60078F228E82120C5B907F97DB
:100AF500E0FE5306F97F007900AD197B001DBDFFAF
:100B0500011B89007A00C3E89DEA64808BF063F0DD
:100B15008095F0505EE51829240524C0F582E4345B
:100B25007DF583E0F51D7B007D00BD08005031E5B6
:100B35001D30E00543060180035306FE907F97EEC6
:100B4500F0E51DC313F51D907F9774044EF0EBC3BC
:100B550013FB907F99E0F830E5034303800D80CACD
:100B6500E517292400F582E4347EF583EBF0098945
:100B75000780868907E51829240524C0F582E43411
:100B85007DF583E0F51D7B00AD1B751E00E51EB5EB
:100B95001A005054E51D30E0054306018003530655
:100BA500FEA91A7C0019B9FF011CA81E7A00E8B538
:100BB5000111EAB5040DED600A4306021DE51CC3EB
:100BC50013F51C907F97EEF0E51DC313F51D907F7F
:100BD5009774044EF0EBC313FB907F99E0FA30E570
:100BE50003430380051E80A5AC1A7A007408C39CD4
:100BF500FCE49AFA8CF005F0EB8002C313D5F0FB08
:100C0500FBE5172F2400F582E4347EF583EBF0ED48
:100C15006008851C228D82020C5B22AA82AB837C34
:100C2500007D00C3EC9AED9B502B907F97E054FB21
:100C3500F07E00EEB50B0050030E80F7907F97E035
:100C45004404F07E00EEB50B0050030E80F70CBC9B
:100C550000D10D80CE22AA82907F97E0FB74FB5BCA
:100C6500F5237B00EBB502005024E52230E0054377
:100C7500230280035323FD907F97E523F0E522C3EC
:100C850013F522907F9774044523F00B80D622221A
:100C95007A00907F99E0FB30E5027A01907F99E038
:100CA500FB30E603430202907F9AE0FB30E7034303
:100CB5000204907F9BE0FB30E503430208907F9A96
:100CC500E0FB53037F8A04E4FAFDEB4AF582ED4C21
:100CD500F58322E582547FF4FA907F97E05AF07409
:100CE5007F5522FA907F97E04AF02285820A852275
:100CF5000B85230C2200227A567B021ABAFF011BB0
:100D0500EA4B70F722752205752300120D67AA823A
:100D1500AB837C007D00C3EC9AED9B501AC002C0EA
:100D250003C004C005120CFAD005D004D003D002CC
:100D35000CBC00E20D80DF22AA82AB837C007D0023
:100D4500C3EC9AED9B501AC002C003C004C0051243
:100D55000CFCD005D004D003D0020CBC00E20D8001
:020D6500DF228B
:03004300021B009D
:101B000002011F0002016E0002016F00020170005D
:101B100002017100020172000201730002017400EF
:101B200002017500020176000201770002018F00B8
:101B30000201A7000201A8000201A9000201AA00F7
:101B40000201AB000201AC000201AD000201AE00D7
:081B50000201AF000201B00028
:100D67007A10E4FBFCE58225E0F582E58333F58321
:100D7700EB33FBEC33FCEB9522F5F0EC95234006C7
:090D8700FCABF0438201DADD222D
:0600A200E478FFF6D8FD32
:100080007900E94400601B7A00900E3E780075927A
:1000900020E493F2A308B800020592D9F4DAF275CD
:0200A00092FFCD
:1000A8007800E84400600A7900759220E4F309D8E2
:1000B800FC7800E84400600C7900902000E4F0A38C
:0400C800D8FCD9FA8D
:0D007300758123120DACE582600302006E62
:100D900020F71430F6148883A88220F507E6A8838C
:100DA00075830022E280F7E49322E022758200221C
:00000001FF

Loading…
Cancel
Save