From: drath Date: Wed, 22 Nov 2006 13:03:10 +0000 (+0000) Subject: - added a PLD (programmable logic device) subsystem for FPGA, CPLD etc. configuration X-Git-Tag: v0.1.0~1140 X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=commitdiff_plain;h=e9297b40b994f071474210e7d9e224d50e25fcaf - added a PLD (programmable logic device) subsystem for FPGA, CPLD etc. configuration - added support for loading .bit files into Xilinx Virtex-II devices - added support for the Gateworks GW16012 JTAG dongle - merged CFI fixes from XScale branch - a few minor fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@116 b42882b7-edfa-0310-969c-e2dbd0fdcd60 --- diff --git a/src/Makefile.am b/src/Makefile.am index 208041f109..467149797f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,11 +4,11 @@ openocd_SOURCES = openocd.c # set the include path found by configure INCLUDES = -I$(top_srcdir)/src/helper \ -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/target -I$(top_srcdir)/src/xsvf -I$(top_srcdir)/src/server \ - -I$(top_srcdir)/src/flash $(all_includes) + -I$(top_srcdir)/src/flash -I$(top_srcdir)/src/pld $(all_includes) # the library search path. openocd_LDFLAGS = $(all_libraries) -SUBDIRS = helper jtag xsvf target server flash +SUBDIRS = helper jtag xsvf target server flash pld if IS_MINGW MINGWLDADD = -lwsock32 @@ -43,4 +43,5 @@ openocd_LDADD = $(top_builddir)/src/xsvf/libxsvf.a \ $(top_builddir)/src/helper/libhelper.a \ $(top_builddir)/src/server/libserver.a $(top_builddir)/src/helper/libhelper.a \ $(top_builddir)/src/flash/libflash.a $(top_builddir)/src/target/libtarget.a \ + $(top_builddir)/src/pld/libpld.a \ $(FTDI2232LIB) $(FTD2XXLIB) $(MINGWLDADD) diff --git a/src/flash/cfi.c b/src/flash/cfi.c index bb548c22d1..e91fcc7ed2 100644 --- a/src/flash/cfi.c +++ b/src/flash/cfi.c @@ -208,8 +208,12 @@ u8 cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout) } DEBUG("status: 0x%x", status); - - if (status != 0x80) + + if ((status & 0x80) != 0x80) + { + ERROR("timeout while waiting for WSM to become ready"); + } + else if (status != 0x80) { ERROR("status register: 0x%x", status); if (status & 0x2) @@ -352,6 +356,8 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char ** ERROR("no target '%i' configured", args[5]); exit(-1); } + + cfi_info->write_algorithm = NULL; /* bank wasn't probed yet */ cfi_info->qry[0] = -1; @@ -434,6 +440,9 @@ int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last) u8 command[8]; int i; + /* if the device supports neither legacy lock/unlock (bit 3) nor + * instant individual block locking (bit 5). + */ if (!(pri_ext->feature_support & 0x28)) return ERROR_FLASH_OPERATION_FAILED; @@ -456,7 +465,8 @@ int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last) bank->sectors[i].is_protected = 0; } - cfi_intel_wait_status_busy(bank, 100); + /* Clear lock bits operation may take up to 1.4s */ + cfi_intel_wait_status_busy(bank, 1400); } /* if the device doesn't support individual block lock bits set/clear, @@ -544,27 +554,40 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 cfi_flash_bank_t *cfi_info = bank->driver_priv; cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext; target_t *target = cfi_info->target; - reg_param_t reg_params[5]; + reg_param_t reg_params[7]; armv4_5_algorithm_t armv4_5_info; working_area_t *source; u32 buffer_size = 32768; u8 write_command[CFI_MAX_BUS_WIDTH]; + u8 busy_pattern[CFI_MAX_BUS_WIDTH]; + u8 error_pattern[CFI_MAX_BUS_WIDTH]; int i; int retval; + /* algorithm register usage: + * r0: source address (in RAM) + * r1: target address (in Flash) + * r2: count + * r3: flash write command + * r4: status byte (returned to host) + * r5: busy test pattern + * r6: error test pattern + */ + u32 word_32_code[] = { 0xe4904004, /* loop: ldr r4, [r0], #4 */ 0xe5813000, /* str r3, [r1] */ 0xe5814000, /* str r4, [r1] */ - 0xe5914000, /* busy ldr r4, [r1] */ - 0xe3140080, /* tst r4, #0x80 */ - 0x0afffffc, /* beq busy */ - 0xe314007f, /* tst r4, #0x7f */ + 0xe5914000, /* busy: ldr r4, [r1] */ + 0xe0047005, /* and r7, r4, r5 */ + 0xe1570005, /* cmp r7, r5 */ + 0x1afffffb, /* bne busy */ + 0xe1140006, /* tst r4, r6 */ 0x1a000003, /* bne done */ 0xe2522001, /* subs r2, r2, #1 */ 0x0a000001, /* beq done */ 0xe2811004, /* add r1, r1 #4 */ - 0xeafffff3, /* b loop */ + 0xeafffff2, /* b loop */ 0xeafffffe, /* done: b -2 */ }; @@ -573,14 +596,15 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 0xe1c130b0, /* strh r3, [r1] */ 0xe1c140b0, /* strh r4, [r1] */ 0xe1d140b0, /* busy ldrh r4, [r1] */ - 0xe3140080, /* tst r4, #0x80 */ - 0x0afffffc, /* beq busy */ - 0xe314007f, /* tst r4, #0x7f */ + 0xe0047005, /* and r7, r4, r5 */ + 0xe1570005, /* cmp r7, r5 */ + 0x1afffffb, /* bne busy */ + 0xe1140006, /* tst r4, r6 */ 0x1a000003, /* bne done */ 0xe2522001, /* subs r2, r2, #1 */ 0x0a000001, /* beq done */ 0xe2811002, /* add r1, r1 #2 */ - 0xeafffff3, /* b loop */ + 0xeafffff2, /* b loop */ 0xeafffffe, /* done: b -2 */ }; @@ -589,14 +613,15 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 0xe5c13000, /* strb r3, [r1] */ 0xe5c14000, /* strb r4, [r1] */ 0xe5d14000, /* busy ldrb r4, [r1] */ - 0xe3140080, /* tst r4, #0x80 */ - 0x0afffffc, /* beq busy */ - 0xe314007f, /* tst r4, #0x7f */ + 0xe0047005, /* and r7, r4, r5 */ + 0xe1570005, /* cmp r7, r5 */ + 0x1afffffb, /* bne busy */ + 0xe1140006, /* tst r4, r6 */ 0x1a000003, /* bne done */ 0xe2522001, /* subs r2, r2, #1 */ 0x0a000001, /* beq done */ 0xe2811001, /* add r1, r1 #1 */ - 0xeafffff3, /* b loop */ + 0xeafffff2, /* b loop */ 0xeafffffe, /* done: b -2 */ }; @@ -609,7 +634,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 /* flash write code */ if (!cfi_info->write_algorithm) { - if (target_alloc_working_area(target, 4 * 13, &cfi_info->write_algorithm) != ERROR_OK) + if (target_alloc_working_area(target, 4 * 14, &cfi_info->write_algorithm) != ERROR_OK) { WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -618,15 +643,15 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 /* write algorithm code to working area */ if (bank->bus_width == 1) { - target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_8_code); + target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_8_code); } else if (bank->bus_width == 2) { - target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_16_code); + target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_16_code); } else if (bank->bus_width == 4) { - target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_32_code); + target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_32_code); } else { @@ -653,6 +678,12 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_IN); + init_reg_param(®_params[5], "r5", 32, PARAM_OUT); + init_reg_param(®_params[6], "r6", 32, PARAM_OUT); + + cfi_command(bank, 0x40, write_command); + cfi_command(bank, 0x80, busy_pattern); + cfi_command(bank, 0x7f, error_pattern); while (count > 0) { @@ -663,16 +694,17 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); - cfi_command(bank, 0x40, write_command); buf_set_u32(reg_params[3].value, 0, 32, buf_get_u32(write_command, 0, 32)); + buf_set_u32(reg_params[5].value, 0, 32, buf_get_u32(busy_pattern, 0, 32)); + buf_set_u32(reg_params[6].value, 0, 32, buf_get_u32(error_pattern, 0, 32)); - if ((retval = target->type->run_algorithm(target, 0, NULL, 5, reg_params, cfi_info->write_algorithm->address, cfi_info->write_algorithm->address + (12 * 4), 10000, &armv4_5_info)) != ERROR_OK) + if ((retval = target->type->run_algorithm(target, 0, NULL, 7, reg_params, cfi_info->write_algorithm->address, cfi_info->write_algorithm->address + (13 * 4), 10000, &armv4_5_info)) != ERROR_OK) { cfi_intel_clear_status_register(bank); return ERROR_FLASH_OPERATION_FAILED; } - if (buf_get_u32(reg_params[4].value, 0, 32) != 0x80) + if (buf_get_u32(reg_params[4].value, 0, 32) & target_buffer_get_u32(target, error_pattern)) { /* read status register (outputs debug inforation) */ cfi_intel_wait_status_busy(bank, 100); @@ -692,7 +724,9 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); - + destroy_reg_param(®_params[5]); + destroy_reg_param(®_params[6]); + return ERROR_OK; } @@ -932,9 +966,9 @@ int cfi_probe(struct flash_bank_s *bank) cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a); cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c); - DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, cfi_info->max_buf_write_size); + DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size)); - if (1 << cfi_info->dev_size != bank->size) + if (((1 << cfi_info->dev_size) * bank->bus_width / bank->chip_width) != bank->size) { WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size); } @@ -963,7 +997,7 @@ int cfi_probe(struct flash_bank_s *bank) for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) { bank->sectors[sector].offset = offset; - bank->sectors[sector].size = (cfi_info->erase_region_info[i] >> 16) * 256; + bank->sectors[sector].size = ((cfi_info->erase_region_info[i] >> 16) * 256) * bank->bus_width / bank->chip_width; offset += bank->sectors[sector].size; bank->sectors[sector].is_erased = -1; bank->sectors[sector].is_protected = -1; @@ -1112,7 +1146,7 @@ int cfi_intel_protect_check(struct flash_bank_s *bank) cfi_flash_bank_t *cfi_info = bank->driver_priv; cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext; target_t *target = cfi_info->target; - u8 command[8]; + u8 command[CFI_MAX_BUS_WIDTH]; int i; /* check if block lock bits are supported on this device */ diff --git a/src/helper/binarybuffer.c b/src/helper/binarybuffer.c index 6afd6e593c..7d41dc73a4 100644 --- a/src/helper/binarybuffer.c +++ b/src/helper/binarybuffer.c @@ -143,8 +143,8 @@ int buf_cmp_mask(u8 *buf1, u8 *buf2, u8 *mask, int size) /* mask out bits that don't really belong to the buffer if size isn't a multiple of 8 bits */ if ((size % 8) && (i == num_bytes -1 )) { - if (((buf1[i] & ((1 << (size % 8)) - 1)) & ((1 << (size % 8)) - 1)) != - ((buf2[i] & ((1 << (size % 8)) - 1)) & ((1 << (size % 8)) - 1))) + if ((buf1[i] & ((1 << (size % 8)) - 1) & mask[i]) != + (buf2[i] & ((1 << (size % 8)) - 1) & mask[i])) return 1; } else diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am index c63c734a7f..d4812a468a 100644 --- a/src/jtag/Makefile.am +++ b/src/jtag/Makefile.am @@ -55,6 +55,12 @@ else AT91RM9200FILES = endif -libjtag_a_SOURCES = jtag.c $(BITBANGFILES) $(PARPORTFILES) $(FT2232FILES) $(AMTJTAGACCELFILES) $(EP93XXFILES) $(AT91RM9200FILES) +if GW16012 +GW16012FILES = gw16012.c +else +GW16012FILES = +endif + +libjtag_a_SOURCES = jtag.c $(BITBANGFILES) $(PARPORTFILES) $(FT2232FILES) $(AMTJTAGACCELFILES) $(EP93XXFILES) $(AT91RM9200FILES) $(GW16012FILES) noinst_HEADERS = bitbang.h jtag.h diff --git a/src/jtag/ft2232.c b/src/jtag/ft2232.c index 67167c78b1..096111bc8e 100644 --- a/src/jtag/ft2232.c +++ b/src/jtag/ft2232.c @@ -52,13 +52,13 @@ /* enable this to debug io latency */ -#if 0 +#if 1 #define _DEBUG_USB_IO_ #endif /* enable this to debug communication */ -#if 0 +#if 1 #define _DEBUG_USB_COMMS_ #endif @@ -470,7 +470,7 @@ void ft2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size int cur_byte = 0; int last_bit; - if ((!ir_scan && (cur_state != TAP_SD)) || (ir_scan && (cur_state != TAP_SI))) + if (!((!ir_scan && (cur_state == TAP_SD)) || (ir_scan && (cur_state == TAP_SI)))) { /* command "Clock Data to TMS/CS Pin (no Read)" */ BUFFER_ADD = 0x4b; @@ -491,8 +491,9 @@ void ft2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size } /* add command for complete bytes */ - if (num_bytes > 1) + while (num_bytes > 1) { + int thisrun_bytes; if (type == SCAN_IO) { /* Clock Data Bytes In and Out LSB First */ @@ -511,24 +512,206 @@ void ft2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size BUFFER_ADD = 0x28; //DEBUG("added TDI bytes (i %i)", num_bytes); } - BUFFER_ADD = (num_bytes-2) & 0xff; - BUFFER_ADD = ((num_bytes-2) >> 8) & 0xff; + thisrun_bytes = (num_bytes > 65537) ? 65536 : (num_bytes - 1); + num_bytes -= thisrun_bytes; + BUFFER_ADD = (thisrun_bytes - 1) & 0xff; + BUFFER_ADD = ((thisrun_bytes - 1) >> 8) & 0xff; + if (type != SCAN_IN) + { + /* add complete bytes */ + while(thisrun_bytes-- > 0) + { + BUFFER_ADD = buffer[cur_byte]; + cur_byte++; + bits_left -= 8; + } + } + else /* (type == SCAN_IN) */ + { + bits_left -= 8 * (thisrun_bytes); + } } + + /* the most signifcant bit is scanned during TAP movement */ if (type != SCAN_IN) + last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1; + else + last_bit = 0; + + /* process remaining bits but the last one */ + if (bits_left > 1) { - /* add complete bytes */ - while(num_bytes-- > 1) + if (type == SCAN_IO) + { + /* Clock Data Bits In and Out LSB First */ + BUFFER_ADD = 0x3b; + //DEBUG("added TDI bits (io) %i", bits_left - 1); + } + else if (type == SCAN_OUT) { + /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ + BUFFER_ADD = 0x1b; + //DEBUG("added TDI bits (o)"); + } + else if (type == SCAN_IN) + { + /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ + BUFFER_ADD = 0x2a; + //DEBUG("added TDI bits (i %i)", bits_left - 1); + } + BUFFER_ADD = bits_left - 2; + if (type != SCAN_IN) BUFFER_ADD = buffer[cur_byte]; - cur_byte++; - bits_left -= 8; + } + + if ((ir_scan && (end_state == TAP_SI)) || + (!ir_scan && (end_state == TAP_SD))) + { + if (type == SCAN_IO) + { + /* Clock Data Bits In and Out LSB First */ + BUFFER_ADD = 0x3b; + //DEBUG("added TDI bits (io) %i", bits_left - 1); } + else if (type == SCAN_OUT) + { + /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ + BUFFER_ADD = 0x1b; + //DEBUG("added TDI bits (o)"); + } + else if (type == SCAN_IN) + { + /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ + BUFFER_ADD = 0x2a; + //DEBUG("added TDI bits (i %i)", bits_left - 1); + } + BUFFER_ADD = 0x0; + BUFFER_ADD = last_bit; } - if (type == SCAN_IN) + else + { + /* move from Shift-IR/DR to end state */ + if (type != SCAN_OUT) + { + /* Clock Data to TMS/CS Pin with Read */ + BUFFER_ADD = 0x6b; + //DEBUG("added TMS scan (read)"); + } + else + { + /* Clock Data to TMS/CS Pin (no Read) */ + BUFFER_ADD = 0x4b; + //DEBUG("added TMS scan (no read)"); + } + BUFFER_ADD = 0x6; + BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7); + cur_state = end_state; + } +} + +int ft2232_large_scan(scan_command_t *cmd, enum scan_type type, u8 *buffer, int scan_size) +{ + int num_bytes = (scan_size + 7) / 8; + int bits_left = scan_size; + int cur_byte = 0; + int last_bit; + u8 *receive_buffer = malloc(CEIL(scan_size, 8)); + u8 *receive_pointer = receive_buffer; + u32 bytes_written; + u32 bytes_read; + int retval; + int thisrun_read = 0; + + if (cmd->ir_scan) { - bits_left -= 8 * (num_bytes - 1); + ERROR("BUG: large IR scans are not supported"); + exit(-1); } + if (cur_state != TAP_SD) + { + /* command "Clock Data to TMS/CS Pin (no Read)" */ + BUFFER_ADD = 0x4b; + /* scan 7 bit */ + BUFFER_ADD = 0x6; + /* TMS data bits */ + BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD); + cur_state = TAP_SD; + } + + if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) + { + ERROR("couldn't write MPSSE commands to FT2232"); + exit(-1); + } + DEBUG("ft2232_buffer_size: %i, bytes_written: %i", ft2232_buffer_size, bytes_written); + ft2232_buffer_size = 0; + + /* add command for complete bytes */ + while (num_bytes > 1) + { + int thisrun_bytes; + + if (type == SCAN_IO) + { + /* Clock Data Bytes In and Out LSB First */ + BUFFER_ADD = 0x39; + //DEBUG("added TDI bytes (io %i)", num_bytes); + } + else if (type == SCAN_OUT) + { + /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */ + BUFFER_ADD = 0x19; + //DEBUG("added TDI bytes (o)"); + } + else if (type == SCAN_IN) + { + /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */ + BUFFER_ADD = 0x28; + //DEBUG("added TDI bytes (i %i)", num_bytes); + } + thisrun_bytes = (num_bytes > 65537) ? 65536 : (num_bytes - 1); + thisrun_read = thisrun_bytes; + num_bytes -= thisrun_bytes; + BUFFER_ADD = (thisrun_bytes - 1) & 0xff; + BUFFER_ADD = ((thisrun_bytes - 1) >> 8) & 0xff; + if (type != SCAN_IN) + { + /* add complete bytes */ + while(thisrun_bytes-- > 0) + { + BUFFER_ADD = buffer[cur_byte]; + cur_byte++; + bits_left -= 8; + } + } + else /* (type == SCAN_IN) */ + { + bits_left -= 8 * (thisrun_bytes); + } + + if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) + { + ERROR("couldn't write MPSSE commands to FT2232"); + exit(-1); + } + DEBUG("ft2232_buffer_size: %i, bytes_written: %i", ft2232_buffer_size, bytes_written); + ft2232_buffer_size = 0; + + if (type != SCAN_OUT) + { + if ((retval = ft2232_read(receive_pointer, thisrun_read, &bytes_read)) != ERROR_OK) + { + ERROR("couldn't read from FT2232"); + exit(-1); + } + DEBUG("thisrun_read: %i, bytes_read: %i", thisrun_read, bytes_read); + receive_pointer += bytes_read; + } + } + + thisrun_read = 0; + /* the most signifcant bit is scanned during TAP movement */ if (type != SCAN_IN) last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1; @@ -559,30 +742,83 @@ void ft2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size BUFFER_ADD = bits_left - 2; if (type != SCAN_IN) BUFFER_ADD = buffer[cur_byte]; + + if (type != SCAN_OUT) + thisrun_read += 2; } - /* move from Shift-IR/DR to end state */ - if (type != SCAN_OUT) + if (end_state == TAP_SD) { - /* Clock Data to TMS/CS Pin with Read */ - BUFFER_ADD = 0x6b; - //DEBUG("added TMS scan (read)"); + if (type == SCAN_IO) + { + /* Clock Data Bits In and Out LSB First */ + BUFFER_ADD = 0x3b; + //DEBUG("added TDI bits (io) %i", bits_left - 1); + } + else if (type == SCAN_OUT) + { + /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ + BUFFER_ADD = 0x1b; + //DEBUG("added TDI bits (o)"); + } + else if (type == SCAN_IN) + { + /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ + BUFFER_ADD = 0x2a; + //DEBUG("added TDI bits (i %i)", bits_left - 1); + } + BUFFER_ADD = 0x0; + BUFFER_ADD = last_bit; } else { - /* Clock Data to TMS/CS Pin (no Read) */ - BUFFER_ADD = 0x4b; - //DEBUG("added TMS scan (no read)"); + /* move from Shift-IR/DR to end state */ + if (type != SCAN_OUT) + { + /* Clock Data to TMS/CS Pin with Read */ + BUFFER_ADD = 0x6b; + //DEBUG("added TMS scan (read)"); + } + else + { + /* Clock Data to TMS/CS Pin (no Read) */ + BUFFER_ADD = 0x4b; + //DEBUG("added TMS scan (no read)"); + } + BUFFER_ADD = 0x6; + BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7); + cur_state = end_state; } - BUFFER_ADD = 0x6; - BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7); - cur_state = end_state; - + + if (type != SCAN_OUT) + thisrun_read += 1; + + if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) + { + ERROR("couldn't write MPSSE commands to FT2232"); + exit(-1); + } + DEBUG("ft2232_buffer_size: %i, bytes_written: %i", ft2232_buffer_size, bytes_written); + ft2232_buffer_size = 0; + + if (type != SCAN_OUT) + { + if ((retval = ft2232_read(receive_pointer, thisrun_read, &bytes_read)) != ERROR_OK) + { + ERROR("couldn't read from FT2232"); + exit(-1); + } + DEBUG("thisrun_read: %i, bytes_read: %i", thisrun_read, bytes_read); + receive_pointer += bytes_read; + } + + return ERROR_OK; } int ft2232_predict_scan_out(int scan_size, enum scan_type type) { int predicted_size = 3; + int num_bytes = (scan_size - 1) / 8; if (cur_state != TAP_SD) predicted_size += 3; @@ -590,14 +826,14 @@ int ft2232_predict_scan_out(int scan_size, enum scan_type type) if (type == SCAN_IN) /* only from device to host */ { /* complete bytes */ - predicted_size += (CEIL(scan_size, 8) > 1) ? 3 : 0; + predicted_size += (CEIL(num_bytes, 65536)) * 3; /* remaining bits - 1 (up to 7) */ predicted_size += ((scan_size - 1) % 8) ? 2 : 0; } else /* host to device, or bidirectional */ { /* complete bytes */ - predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) + 3 - 1) : 0; + predicted_size += num_bytes + (CEIL(num_bytes, 65536)) * 3; /* remaining bits -1 (up to 7) */ predicted_size += ((scan_size - 1) % 8) ? 3 : 0; } @@ -910,9 +1146,26 @@ int ft2232_execute_queue() scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); predicted_size = ft2232_predict_scan_out(scan_size, type); - if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) + if ((predicted_size + 1) > FT2232_BUFFER_SIZE) + { + DEBUG("oversized ft2232 scan (predicted_size > FT2232_BUFFER_SIZE)"); + /* unsent commands before this */ + if (first_unsent != cmd) + ft2232_send_and_recv(first_unsent, cmd); + + /* current command */ + if (cmd->cmd.scan->end_state != -1) + ft2232_end_state(cmd->cmd.scan->end_state); + ft2232_large_scan(cmd->cmd.scan, type, buffer, scan_size); + require_send = 0; + first_unsent = cmd->next; + if (buffer) + free(buffer); + break; + } + else if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) { - DEBUG("ftd2xx buffer size reached, sending queued commands (first_unsent: %x, cmd: %x)", first_unsent, cmd); + DEBUG("ft2232 buffer size reached, sending queued commands (first_unsent: %x, cmd: %x)", first_unsent, cmd); ft2232_send_and_recv(first_unsent, cmd); require_send = 0; first_unsent = cmd; diff --git a/src/jtag/gw16012.c b/src/jtag/gw16012.c new file mode 100644 index 0000000000..6210a52c48 --- /dev/null +++ b/src/jtag/gw16012.c @@ -0,0 +1,507 @@ +/*************************************************************************** + * Copyright (C) 2006 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "replacements.h" + +#include "jtag.h" + +/* system includes */ + +/* system includes */ +// -ino: 060521-1036 +#ifdef __FreeBSD__ + +#include +#include +#include +#define ioperm(startport,length,enable)\ + i386_set_ioperm((startport), (length), (enable)) + +#else + +#ifndef _WIN32 +#include +#else +#include "errno.h" +#endif /* _WIN32 */ + +#endif /* __FreeBSD__ */ + +#include +#include + +#include +#include + +#if PARPORT_USE_PPDEV == 1 +#ifdef __FreeBSD__ +#include +#include +#define PPRSTATUS PPIGSTATUS +#define PPWDATA PPISDATA +#else +#include +#include +#endif +#include +#include +#endif + +#if PARPORT_USE_GIVEIO == 1 +#if IS_CYGWIN == 1 +#include +#include +#undef ERROR +#endif +#endif + +#include "log.h" + +/* configuration */ +unsigned long gw16012_port; + +/* interface variables + */ +static u8 gw16012_msb = 0x0; +static u8 gw16012_control_value = 0x0; + +#if PARPORT_USE_PPDEV == 1 +static int device_handle; +#endif + +int gw16012_execute_queue(void); +int gw16012_register_commands(struct command_context_s *cmd_ctx); +int gw16012_speed(int speed); +int gw16012_init(void); +int gw16012_quit(void); + +int gw16012_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +jtag_interface_t gw16012_interface = +{ + .name = "gw16012", + + .execute_queue = gw16012_execute_queue, + + .support_pathmove = 0, + + .speed = gw16012_speed, + .register_commands = gw16012_register_commands, + .init = gw16012_init, + .quit = gw16012_quit, +}; + +int gw16012_register_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, NULL, "parport_port", gw16012_handle_parport_port_command, + COMMAND_CONFIG, NULL); + + return ERROR_OK; +} + +void gw16012_data(u8 value) +{ + value = (value & 0x7f) | gw16012_msb; + gw16012_msb ^= 0x80; /* toggle MSB */ + + #if PARPORT_USE_PPDEV == 1 + ioctl(device_handle, PPWDATA, &value); + #else + #ifdef __FreeBSD__ + outb(gw16012_port, value); + #else + outb(value, gw16012_port); + #endif + #endif +} + +void gw16012_control(u8 value) +{ + if (value != gw16012_control_value) + { + gw16012_control_value = value; + + #if PARPORT_USE_PPDEV == 1 + ioctl(device_handle, PPWCONTROL, &gw16012_control_value); + #else + #ifdef __FreeBSD__ + outb(gw16012_port + 2, gw16012_control_value); + #else + outb(gw16012_control_value, gw16012_port + 2); + #endif + #endif + } +} + +void gw16012_input(u8 *value) +{ + #if PARPORT_USE_PPDEV == 1 + ioctl(device_handle, PPRSTATUS, value); + #else + *value = inb(gw16012_port + 1); + #endif +} + +/* (1) assert or (0) deassert reset lines */ +void gw16012_reset(int trst, int srst) +{ + DEBUG("trst: %i, srst: %i", trst, srst); + + if (trst == 0) + gw16012_control(0x0d); + else if (trst == 1) + gw16012_control(0x0c); + + if (srst == 0) + gw16012_control(0x0a); + else if (srst == 1) + gw16012_control(0x0b); +} + +int gw16012_speed(int speed) +{ + + return ERROR_OK; +} + +void gw16012_end_state(state) +{ + if (tap_move_map[state] != -1) + end_state = state; + else + { + ERROR("BUG: %i is not a valid end state", state); + exit(-1); + } +} + +void gw16012_state_move(void) +{ + int i=0, tms=0; + u8 tms_scan = TAP_MOVE(cur_state, end_state); + + gw16012_control(0x0); /* single-bit mode */ + + for (i = 0; i < 7; i++) + { + tms = (tms_scan >> i) & 1; + gw16012_data(tms << 1); /* output next TMS bit */ + } + + cur_state = end_state; +} + +void gw16012_runtest(int num_cycles) +{ + enum tap_state saved_end_state = end_state; + int i; + + /* only do a state_move when we're not already in RTI */ + if (cur_state != TAP_RTI) + { + gw16012_end_state(TAP_RTI); + gw16012_state_move(); + } + + for (i = 0; i < num_cycles; i++) + { + gw16012_control(0x0); /* single-bit mode */ + gw16012_data(0x0); /* TMS cycle with TMS low */ + } + + gw16012_end_state(saved_end_state); + if (cur_state != end_state) + gw16012_state_move(); +} + +void gw16012_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size) +{ + int bits_left = scan_size; + int bit_count = 0; + enum tap_state saved_end_state = end_state; + u8 scan_out, scan_in; + + if (ir_scan) + gw16012_end_state(TAP_SI); + else + gw16012_end_state(TAP_SD); + + gw16012_state_move(); + gw16012_end_state(saved_end_state); + + while (type == SCAN_OUT && ((bits_left - 1) > 7)) + { + gw16012_control(0x2); /* seven-bit mode */ + scan_out = buf_get_u32(buffer, bit_count, 7); + gw16012_data(scan_out); + bit_count += 7; + bits_left -= 7; + } + + gw16012_control(0x0); /* single-bit mode */ + while (bits_left-- > 0) + { + u8 tms = 0; + if (bits_left == 0) /* last bit */ + { + if ((ir_scan && (end_state == TAP_SI)) + || (!ir_scan && (end_state == TAP_SD))) + { + tms = 0; + } + else + { + tms = 2; + } + } + + scan_out = buf_get_u32(buffer, bit_count, 1); + gw16012_data(scan_out | tms); + if (type != SCAN_OUT) + { + gw16012_input(&scan_in); + buf_set_u32(buffer, bit_count, 1, ((scan_in & 0x08) >> 3)); + } + bit_count++; + } + + if (!((ir_scan && (end_state == TAP_SI)) || + (!ir_scan && (end_state == TAP_SD)))) + { + gw16012_data(0x0); + if (ir_scan) + cur_state = TAP_PI; + else + cur_state = TAP_PD; + + if (cur_state != end_state) + gw16012_state_move(); + } +} + +int gw16012_execute_queue(void) +{ + jtag_command_t *cmd = jtag_command_queue; /* currently processed command */ + int scan_size; + enum scan_type type; + u8 *buffer; + + while (cmd) + { + switch (cmd->type) + { + case JTAG_END_STATE: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("end_state: %i", cmd->cmd.end_state->end_state); +#endif + if (cmd->cmd.end_state->end_state != -1) + gw16012_end_state(cmd->cmd.end_state->end_state); + break; + case JTAG_RESET: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); +#endif + if (cmd->cmd.reset->trst == 1) + { + cur_state = TAP_TLR; + } + gw16012_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + case JTAG_RUNTEST: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); +#endif + if (cmd->cmd.runtest->end_state != -1) + gw16012_end_state(cmd->cmd.runtest->end_state); + gw16012_runtest(cmd->cmd.runtest->num_cycles); + break; + case JTAG_STATEMOVE: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("statemove end in %i", cmd->cmd.statemove->end_state); +#endif + if (cmd->cmd.statemove->end_state != -1) + gw16012_end_state(cmd->cmd.statemove->end_state); + gw16012_state_move(); + break; + case JTAG_SCAN: + if (cmd->cmd.scan->end_state != -1) + gw16012_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); +#ifdef _DEBUG_JTAG_IO_ + DEBUG("%s scan (%i) %i bit end in %i", (cmd->cmd.scan->ir_scan) ? "ir" : "dr", + type, scan_size, cmd->cmd.scan->end_state); +#endif + gw16012_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + return ERROR_JTAG_QUEUE_FAILED; + if (buffer) + free(buffer); + break; + case JTAG_SLEEP: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("sleep", cmd->cmd.sleep->us); +#endif + jtag_sleep(cmd->cmd.sleep->us); + break; + default: + ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); + } + cmd = cmd->next; + } + + return ERROR_OK; +} + +#if PARPORT_USE_GIVEIO == 1 +int gw16012_get_giveio_access() +{ + HANDLE h; + OSVERSIONINFO version; + + version.dwOSVersionInfoSize = sizeof version; + if (!GetVersionEx( &version )) { + errno = EINVAL; + return -1; + } + if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) + return 0; + + h = CreateFile( "\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if (h == INVALID_HANDLE_VALUE) { + errno = ENODEV; + return -1; + } + + CloseHandle( h ); + + return 0; +} +#endif + +int gw16012_init(void) +{ +#if PARPORT_USE_PPDEV == 1 + char buffer[256]; + int i = 0; + u8 control_port; +#endif + u8 status_port; + +#if PARPORT_USE_PPDEV == 1 + if (device_handle>0) + { + ERROR("device is already opened"); + return ERROR_JTAG_INIT_FAILED; + } + +#ifdef __FreeBSD__ + DEBUG("opening /dev/ppi%d...", gw16012_port); + + snprintf(buffer, 256, "/dev/ppi%d", gw16012_port); + device_handle = open(buffer, O_WRONLY); +#else + DEBUG("opening /dev/parport%d...", gw16012_port); + + snprintf(buffer, 256, "/dev/parport%d", gw16012_port); + device_handle = open(buffer, O_WRONLY); +#endif + if (device_handle<0) + { + ERROR("cannot open device. check it exists and that user read and write rights are set"); + return ERROR_JTAG_INIT_FAILED; + } + + DEBUG("...open"); + +#ifndef __FreeBSD__ + i=ioctl(device_handle, PPCLAIM); + if (i<0) + { + ERROR("cannot claim device"); + return ERROR_JTAG_INIT_FAILED; + } + + i = PARPORT_MODE_COMPAT; + i= ioctl(device_handle, PPSETMODE, & i); + if (i<0) + { + ERROR(" cannot set compatible mode to device"); + return ERROR_JTAG_INIT_FAILED; + } + + i = IEEE1284_MODE_COMPAT; + i = ioctl(device_handle, PPNEGOT, & i); + if (i<0) + { + ERROR("cannot set compatible 1284 mode to device"); + return ERROR_JTAG_INIT_FAILED; + } +#endif +#else + if (gw16012_port == 0) + { + gw16012_port = 0x378; + WARNING("No gw16012 port specified, using default '0x378' (LPT1)"); + } + + DEBUG("requesting privileges for parallel port 0x%x...", gw16012_port); +#if PARPORT_USE_GIVEIO == 1 + if (gw16012_get_giveio_access() != 0) +#else /* PARPORT_USE_GIVEIO */ + if (ioperm(gw16012_port, 3, 1) != 0) +#endif /* PARPORT_USE_GIVEIO */ + { + ERROR("missing privileges for direct i/o"); + return ERROR_JTAG_INIT_FAILED; + } + DEBUG("...privileges granted"); +#endif /* PARPORT_USE_PPDEV */ + + gw16012_input(&status_port); + gw16012_msb = (status_port & 0x80) ^ 0x80; + + gw16012_speed(jtag_speed); + gw16012_reset(0, 0); + + return ERROR_OK; +} + +int gw16012_quit(void) +{ + + return ERROR_OK; +} + +int gw16012_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 0) + return ERROR_OK; + + /* only if the port wasn't overwritten by cmdline */ + if (gw16012_port == 0) + gw16012_port = strtoul(args[0], NULL, 0); + + return ERROR_OK; +} diff --git a/src/jtag/jtag.c b/src/jtag/jtag.c index 4ba227c09b..259a327dd8 100644 --- a/src/jtag/jtag.c +++ b/src/jtag/jtag.c @@ -144,6 +144,10 @@ jtag_event_callback_t *jtag_event_callbacks; extern jtag_interface_t at91rm9200_interface; #endif +#if BUILD_GW16012 == 1 + extern jtag_interface_t gw16012_interface; +#endif + jtag_interface_t *jtag_interfaces[] = { #if BUILD_PARPORT == 1 &parport_interface, @@ -162,6 +166,9 @@ jtag_interface_t *jtag_interfaces[] = { #endif #if BUILD_AT91RM9200 == 1 &at91rm9200_interface, +#endif +#if BUILD_GW16012 == 1 + &gw16012_interface, #endif NULL, }; @@ -959,7 +966,7 @@ int jtag_build_buffer(scan_command_t *cmd, u8 **buffer) if (cmd->fields[i].out_value) { #ifdef _DEBUG_JTAG_IO_ - char* char_buf = buf_to_str(cmd->fields[i].out_value, cmd->fields[i].num_bits, 16); + char* char_buf = buf_to_str(cmd->fields[i].out_value, (cmd->fields[i].num_bits > 64) ? 64 : cmd->fields[i].num_bits, 16); #endif buf_set_buf(cmd->fields[i].out_value, 0, *buffer, bit_count, cmd->fields[i].num_bits); #ifdef _DEBUG_JTAG_IO_ @@ -993,7 +1000,7 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd) #ifdef _DEBUG_JTAG_IO_ char *char_buf; - char_buf = buf_to_str(captured, num_bits, 16); + char_buf = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16); DEBUG("fields[%i].in_value: 0x%s", i, char_buf); free(char_buf); #endif @@ -1031,9 +1038,9 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd) if ((cmd->fields[i].in_check_mask && buf_cmp_mask(captured, cmd->fields[i].in_check_value, cmd->fields[i].in_check_mask, num_bits)) || (!cmd->fields[i].in_check_mask && buf_cmp(captured, cmd->fields[i].in_check_mask, num_bits))) { - char *captured_char = buf_to_str(captured, num_bits, 16); - char *in_check_value_char = buf_to_str(cmd->fields[i].in_check_value, num_bits, 16); - char *in_check_mask_char = buf_to_str(cmd->fields[i].in_check_mask, num_bits, 16); + char *captured_char = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16); + char *in_check_value_char = buf_to_str(cmd->fields[i].in_check_value, (num_bits > 64) ? 64 : num_bits, 16); + char *in_check_mask_char = buf_to_str(cmd->fields[i].in_check_mask, (num_bits > 64) ? 64 : num_bits, 16); /* TODO: error reporting */ WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s check_mask: 0x%s", captured_char, in_check_value_char, in_check_mask_char); retval = ERROR_JTAG_QUEUE_FAILED; diff --git a/src/openocd.c b/src/openocd.c index 4df416e8f2..3abc609e14 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -18,7 +18,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#define OPENOCD_VERSION "Open On-Chip Debugger (2006-10-12 18:00 CEST)" +#define OPENOCD_VERSION "Open On-Chip Debugger (2006-11-22 14:00 CEST)" #ifdef HAVE_CONFIG_H #include "config.h" @@ -32,6 +32,7 @@ #include "xsvf.h" #include "target.h" #include "flash.h" +#include "pld.h" #include "command.h" #include "server.h" @@ -74,6 +75,7 @@ int main(int argc, char *argv[]) xsvf_register_commands(cmd_ctx); target_register_commands(cmd_ctx); flash_register_commands(cmd_ctx); + pld_register_commands(cmd_ctx); if (log_init(cmd_ctx) != ERROR_OK) return EXIT_FAILURE; @@ -107,6 +109,10 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; DEBUG("flash init complete"); + if (pld_init(cmd_ctx) != ERROR_OK) + return EXIT_FAILURE; + DEBUG("pld init complete"); + /* initialize tcp server */ server_init(); diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am new file mode 100644 index 0000000000..e3386257d4 --- /dev/null +++ b/src/pld/Makefile.am @@ -0,0 +1,5 @@ +INCLUDES = -I$(top_srcdir)/src/server -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag $(all_includes) +METASOURCES = AUTO +noinst_LIBRARIES = libpld.a +noinst_HEADERS = pld.h xilinx_bit.h virtex2.h +libpld_a_SOURCES = pld.c xilinx_bit.c virtex2.c diff --git a/src/pld/pld.c b/src/pld/pld.c new file mode 100644 index 0000000000..a20f9d9443 --- /dev/null +++ b/src/pld/pld.c @@ -0,0 +1,218 @@ +/*************************************************************************** + * Copyright (C) 2006 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pld.h" + +#include "jtag.h" +#include "command.h" +#include "log.h" +#include "time_support.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* pld drivers + */ +extern pld_driver_t virtex2_pld; + +pld_driver_t *pld_drivers[] = +{ + &virtex2_pld, + NULL, +}; + +pld_device_t *pld_devices; +static command_t *pld_cmd; + +int handle_pld_devices_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_pld_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_pld_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int pld_init(struct command_context_s *cmd_ctx) +{ + if (pld_devices) + { + register_command(cmd_ctx, pld_cmd, "devices", handle_pld_devices_command, COMMAND_EXEC, + "list configured pld devices"); + register_command(cmd_ctx, pld_cmd, "load", handle_pld_load_command, COMMAND_EXEC, + "load configuration into programmable logic device"); + } + + return ERROR_OK; +} + +pld_device_t *get_pld_device_by_num(int num) +{ + pld_device_t *p; + int i = 0; + + for (p = pld_devices; p; p = p->next) + { + if (i++ == num) + { + return p; + } + } + + return NULL; +} + +/* pld device [driver_options ...] + */ +int handle_pld_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int i; + int found = 0; + + if (argc < 1) + { + WARNING("incomplete 'pld bank' configuration"); + return ERROR_OK; + } + + for (i = 0; pld_drivers[i]; i++) + { + if (strcmp(args[0], pld_drivers[i]->name) == 0) + { + pld_device_t *p, *c; + + /* register pld specific commands */ + if (pld_drivers[i]->register_commands(cmd_ctx) != ERROR_OK) + { + ERROR("couldn't register '%s' commands", args[0]); + exit(-1); + } + + c = malloc(sizeof(pld_device_t)); + c->driver = pld_drivers[i]; + c->next = NULL; + + if (pld_drivers[i]->pld_device_command(cmd_ctx, cmd, args, argc, c) != ERROR_OK) + { + ERROR("'%s' driver rejected pld device", args[0]); + free(c); + return ERROR_OK; + } + + /* put pld device in linked list */ + if (pld_devices) + { + /* find last pld device */ + for (p = pld_devices; p && p->next; p = p->next); + if (p) + p->next = c; + } + else + { + pld_devices = c; + } + + found = 1; + } + } + + /* no matching pld driver found */ + if (!found) + { + ERROR("pld driver '%s' not found", args[0]); + exit(-1); + } + + return ERROR_OK; +} + +int handle_pld_devices_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + pld_device_t *p; + int i = 0; + + if (!pld_devices) + { + command_print(cmd_ctx, "no pld devices configured"); + return ERROR_OK; + } + + for (p = pld_devices; p; p = p->next) + { + command_print(cmd_ctx, "#%i: %s", i++, p->driver->name); + } + + return ERROR_OK; +} + +int handle_pld_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + struct timeval start, end, duration; + pld_device_t *p; + + gettimeofday(&start, NULL); + + if (argc < 2) + { + command_print(cmd_ctx, "usage: pld load "); + return ERROR_OK; + } + + p = get_pld_device_by_num(strtoul(args[0], NULL, 0)); + if (!p) + { + command_print(cmd_ctx, "pld device '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + if ((retval = p->driver->load(p, args[1])) != ERROR_OK) + { + command_print(cmd_ctx, "failed loading file %s to pld device %i", + args[1], strtoul(args[0], NULL, 0)); + switch (retval) + { + } + } + else + { + gettimeofday(&end, NULL); + timeval_subtract(&duration, &end, &start); + + command_print(cmd_ctx, "loaded file %s to pld device %i in %is %ius", + args[1], strtoul(args[0], NULL, 0), duration.tv_sec, duration.tv_usec); + } + + return ERROR_OK; +} + +int pld_register_commands(struct command_context_s *cmd_ctx) +{ + pld_cmd = register_command(cmd_ctx, NULL, "pld", NULL, COMMAND_ANY, "programmable logic device commands"); + + register_command(cmd_ctx, pld_cmd, "device", handle_pld_device_command, COMMAND_CONFIG, NULL); + + return ERROR_OK; +} diff --git a/src/pld/pld.h b/src/pld/pld.h new file mode 100644 index 0000000000..e4cfc07157 --- /dev/null +++ b/src/pld/pld.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2006 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * 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 PLD_H +#define PLD_H + +#include "command.h" + +struct pld_device_s; + +typedef struct pld_driver_s +{ + char *name; + int (*register_commands)(struct command_context_s *cmd_ctx); + int (*pld_device_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct pld_device_s *pld_device); + int (*load)(struct pld_device_s *pld_device, char *filename); +} pld_driver_t; + +typedef struct pld_device_s +{ + pld_driver_t *driver; + void *driver_priv; + struct pld_device_s *next; +} pld_device_t; + +extern int pld_register_commands(struct command_context_s *cmd_ctx); +extern int pld_init(struct command_context_s *cmd_ctx); +extern pld_device_t *get_pld_device_by_num(int num); + +#define ERROR_PLD_DEVICE_INVALID (-1000) +#define ERROR_PLD_FILE_LOAD_FAILED (-1001) + +#endif /* PLD_H */ diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c new file mode 100644 index 0000000000..8624367fab --- /dev/null +++ b/src/pld/virtex2.c @@ -0,0 +1,264 @@ +/*************************************************************************** + * Copyright (C) 2006 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "virtex2.h" + +#include "pld.h" +#include "xilinx_bit.h" +#include "command.h" +#include "log.h" +#include "jtag.h" + +#include + +int virtex2_register_commands(struct command_context_s *cmd_ctx); +int virtex2_pld_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct pld_device_s *pld_device); +int virtex2_load(struct pld_device_s *pld_device, char *filename); + +pld_driver_t virtex2_pld = +{ + .name = "virtex2", + .register_commands = virtex2_register_commands, + .pld_device_command = virtex2_pld_device_command, + .load = virtex2_load, +}; + +int virtex2_set_instr(int chain_pos, u32 new_instr) +{ + jtag_device_t *device = jtag_get_device(chain_pos); + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = chain_pos; + field.num_bits = device->ir_length; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_instr); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_ir_scan(1, &field, TAP_RTI); + + free(field.out_value); + } + + return ERROR_OK; +} + +int virtex2_send_32(struct pld_device_s *pld_device, int num_words, u32 *words) +{ + virtex2_pld_device_t *virtex2_info = pld_device->driver_priv; + scan_field_t scan_field; + u8 *values; + int i; + + values = malloc(num_words * 4); + + scan_field.device = virtex2_info->chain_pos; + scan_field.num_bits = num_words * 32; + scan_field.out_value = values; + scan_field.out_mask = NULL; + scan_field.in_value = NULL; + scan_field.in_check_value = NULL; + scan_field.in_check_mask = NULL; + scan_field.in_handler = NULL; + scan_field.in_handler_priv = NULL; + + for (i = 0; i < num_words; i++) + buf_set_u32(values + 4 * i, 0, 32, flip_u32(*words++, 32)); + + virtex2_set_instr(virtex2_info->chain_pos, 0x5); /* CFG_IN */ + + jtag_add_dr_scan(1, &scan_field, TAP_PD); + + free(values); + + return ERROR_OK; +} + +int virtex2_jtag_buf_to_u32(u8 *in_buf, void *priv) +{ + u32 *dest = priv; + *dest = flip_u32(le_to_h_u32(in_buf), 32); + return ERROR_OK; +} + +int virtex2_receive_32(struct pld_device_s *pld_device, int num_words, u32 *words) +{ + virtex2_pld_device_t *virtex2_info = pld_device->driver_priv; + scan_field_t scan_field; + + scan_field.device = virtex2_info->chain_pos; + scan_field.num_bits = 32; + scan_field.out_value = NULL; + scan_field.out_mask = NULL; + scan_field.in_value = NULL; + scan_field.in_check_value = NULL; + scan_field.in_check_mask = NULL; + scan_field.in_handler = virtex2_jtag_buf_to_u32; + + virtex2_set_instr(virtex2_info->chain_pos, 0x4); /* CFG_OUT */ + + while (num_words--) + { + scan_field.in_handler_priv = words++; + jtag_add_dr_scan(1, &scan_field, TAP_PD); + } + + return ERROR_OK; +} + +int virtex2_read_stat(struct pld_device_s *pld_device, u32 *status) +{ + u32 data[5]; + + jtag_add_statemove(TAP_TLR); + + data[0] = 0xaa995566; /* synch word */ + data[1] = 0x2800E001; /* Type 1, read, address 7, 1 word */ + data[2] = 0x20000000; /* NOOP (Type 1, read, address 0, 0 words */ + data[3] = 0x20000000; /* NOOP */ + data[4] = 0x20000000; /* NOOP */ + virtex2_send_32(pld_device, 5, data); + + virtex2_receive_32(pld_device, 1, status); + + jtag_execute_queue(); + + DEBUG("status: 0x%8.8x", *status); + + return ERROR_OK; +} + +int virtex2_load(struct pld_device_s *pld_device, char *filename) +{ + virtex2_pld_device_t *virtex2_info = pld_device->driver_priv; + xilinx_bit_file_t bit_file; + int retval; + int i; + + scan_field_t field; + + field.device = virtex2_info->chain_pos; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + if ((retval = xilinx_read_bit_file(&bit_file, filename)) != ERROR_OK) + return retval; + + jtag_add_end_state(TAP_RTI); + virtex2_set_instr(virtex2_info->chain_pos, 0xb); /* JPROG_B */ + jtag_execute_queue(); + jtag_add_sleep(1000); + + virtex2_set_instr(virtex2_info->chain_pos, 0x5); /* CFG_IN */ + jtag_execute_queue(); + + for (i = 0; i < bit_file.length; i++) + bit_file.data[i] = flip_u32(bit_file.data[i], 8); + + field.num_bits = bit_file.length * 8; + field.out_value = bit_file.data; + + jtag_add_dr_scan(1, &field, TAP_PD); + jtag_execute_queue(); + + jtag_add_statemove(TAP_TLR); + + jtag_add_end_state(TAP_RTI); + virtex2_set_instr(virtex2_info->chain_pos, 0xc); /* JSTART */ + jtag_add_runtest(13, TAP_RTI); + virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */ + virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */ + virtex2_set_instr(virtex2_info->chain_pos, 0xc); /* JSTART */ + jtag_add_runtest(13, TAP_RTI); + virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */ + jtag_execute_queue(); + + return ERROR_OK; +} + +int virtex2_handle_read_stat_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + pld_device_t *device; + virtex2_pld_device_t *virtex2_info; + u32 status; + + if (argc < 1) + { + command_print(cmd_ctx, "usage: virtex2 read_stat "); + return ERROR_OK; + } + + device = get_pld_device_by_num(strtoul(args[0], NULL, 0)); + if (!device) + { + command_print(cmd_ctx, "pld device '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + virtex2_info = device->driver_priv; + + virtex2_read_stat(device, &status); + + command_print(cmd_ctx, "virtex2 status register: 0x%8.8x", status); + + return ERROR_OK; +} + +int virtex2_register_commands(struct command_context_s *cmd_ctx) +{ + command_t *virtex2_cmd = register_command(cmd_ctx, NULL, "virtex2", NULL, COMMAND_ANY, "virtex2 specific commands"); + + register_command(cmd_ctx, virtex2_cmd, "read_stat", virtex2_handle_read_stat_command, COMMAND_EXEC, + "read Virtex-II status register"); + + return ERROR_OK; +} + +int virtex2_pld_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct pld_device_s *pld_device) +{ + virtex2_pld_device_t *virtex2_info; + + if (argc < 2) + { + WARNING("incomplete pld device 'virtex2' configuration"); + return ERROR_PLD_DEVICE_INVALID; + } + + virtex2_info = malloc(sizeof(virtex2_pld_device_t)); + pld_device->driver_priv = virtex2_info; + + virtex2_info->chain_pos = strtoul(args[1], NULL, 0); + + return ERROR_OK; +} diff --git a/src/pld/virtex2.h b/src/pld/virtex2.h new file mode 100644 index 0000000000..1b5865dd84 --- /dev/null +++ b/src/pld/virtex2.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * Copyright (C) 2006 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * 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 VIRTEX2_H +#define VIRTEX2_H + +#include "pld.h" +#include "xilinx_bit.h" + +typedef struct virtex2_pld_device_s +{ + int chain_pos; +} virtex2_pld_device_t; + +#endif /* VIRTEX2_H */ diff --git a/src/pld/xilinx_bit.c b/src/pld/xilinx_bit.c new file mode 100644 index 0000000000..7bf72b2ee9 --- /dev/null +++ b/src/pld/xilinx_bit.c @@ -0,0 +1,146 @@ +/*************************************************************************** + * Copyright (C) 2006 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xilinx_bit.h" + +#include "pld.h" +#include "log.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +int read_section(FILE *input_file, int length_size, char section, u32 *buffer_length, u8 **buffer) +{ + u8 length_buffer[4]; + u32 length; + char section_char; + int read_count; + + if ((length_size != 2) && (length_size != 4)) + { + ERROR("BUG: length_size neither 2 nor 4"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if ((read_count = fread(§ion_char, 1, 1, input_file)) != 1) + { + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (section_char != section) + { + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if ((read_count = fread(length_buffer, 1, length_size, input_file)) != length_size) + { + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (length_size == 4) + length = be_to_h_u32(length_buffer); + + if (length_size == 2) + length = be_to_h_u16(length_buffer); + + if (buffer_length) + *buffer_length = length; + + *buffer = malloc(length); + + if ((read_count = fread(*buffer, 1, length, input_file)) != length) + { + return ERROR_PLD_FILE_LOAD_FAILED; + } + + return ERROR_OK; +} + +int xilinx_read_bit_file(xilinx_bit_file_t *bit_file, char *filename) +{ + FILE *input_file; + struct stat input_stat; + int read_count; + + if (!filename || !bit_file) + return ERROR_INVALID_ARGUMENTS; + + if (stat(filename, &input_stat) == -1) + { + ERROR("couldn't stat() %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (S_ISDIR(input_stat.st_mode)) + { + ERROR("%s is a directory", filename); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (input_stat.st_size == 0){ + ERROR("Empty file %s", filename); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (!(input_file = fopen(filename, "rb"))) + { + ERROR("couldn't open %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if ((read_count = fread(bit_file->unknown_header, 1, 13, input_file)) != 13) + { + ERROR("couldn't read unknown_header from file '%s'", filename); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (read_section(input_file, 2, 'a', NULL, &bit_file->source_file) != ERROR_OK) + return ERROR_PLD_FILE_LOAD_FAILED; + + if (read_section(input_file, 2, 'b', NULL, &bit_file->part_name) != ERROR_OK) + return ERROR_PLD_FILE_LOAD_FAILED; + + if (read_section(input_file, 2, 'c', NULL, &bit_file->date) != ERROR_OK) + return ERROR_PLD_FILE_LOAD_FAILED; + + if (read_section(input_file, 2, 'd', NULL, &bit_file->time) != ERROR_OK) + return ERROR_PLD_FILE_LOAD_FAILED; + + if (read_section(input_file, 4, 'e', &bit_file->length, &bit_file->data) != ERROR_OK) + return ERROR_PLD_FILE_LOAD_FAILED; + + DEBUG("bit_file: %s %s %s,%s %i", bit_file->source_file, bit_file->part_name, + bit_file->date, bit_file->time, bit_file->length); + + fclose(input_file); + + return ERROR_OK; +} diff --git a/src/pld/xilinx_bit.h b/src/pld/xilinx_bit.h new file mode 100644 index 0000000000..505957ab8a --- /dev/null +++ b/src/pld/xilinx_bit.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2006 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * 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 XILINX_BIT_H +#define XILINX_BIT_H + +#include "types.h" + +typedef struct xilinx_bit_file_s +{ + u8 unknown_header[13]; + u8 *source_file; + u8 *part_name; + u8 *date; + u8 *time; + u32 length; + u8 *data; +} xilinx_bit_file_t; + +int xilinx_read_bit_file(xilinx_bit_file_t *bit_file, char *filename); + +#endif /* XILINX_BIT_H */ diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 00fb2f0785..3eab03354b 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -285,7 +285,7 @@ reg_cache_t* armv4_5_build_reg_cache(target_t *target, armv4_5_common_t *armv4_5 int num_regs = 37; reg_cache_t *cache = malloc(sizeof(reg_cache_t)); reg_t *reg_list = malloc(sizeof(reg_t) * num_regs); - armv4_5_core_reg_t *arch_info = malloc(sizeof(reg_t) * num_regs); + armv4_5_core_reg_t *arch_info = malloc(sizeof(armv4_5_core_reg_t) * num_regs); int i; cache->name = "arm v4/5 registers"; @@ -630,7 +630,7 @@ int armv4_5_run_algorithm(struct target_s *target, int num_mem_params, mem_param for (i = 0; i <= 16; i++) { - DEBUG("restoring register %s with value 0x%8.8x", ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).name, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).value, 0, 32)); + DEBUG("restoring register %s with value 0x%8.8x", ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).name, context[i]); buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).value, 0, 32, context[i]); ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).valid = 1; ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).dirty = 1;