Browse Source

jtag: JTAG implementation for X6500 (over ft232r)

Mostly cloned from my LPC1343CodeBase driver
Luke Dashjr 13 years ago
parent
commit
2907899b28
3 changed files with 180 additions and 1 deletions
  1. 1 1
      Makefile.am
  2. 144 0
      jtag.c
  3. 35 0
      jtag.h

+ 1 - 1
Makefile.am

@@ -115,7 +115,7 @@ dist_bitstreams_DATA = bitstreams/*
 endif
 
 if HAS_X6500
-bfgminer_SOURCES += driver-x6500.c ft232r.c
+bfgminer_SOURCES += driver-x6500.c ft232r.c ft232r.h jtag.c jtag.h
 bitstreamsdir = $(bindir)/bitstreams
 dist_bitstreams_DATA = bitstreams/*
 endif

+ 144 - 0
jtag.c

@@ -0,0 +1,144 @@
+/*
+ * Copyright 2012 Luke Dashjr
+ *
+ * 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 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+// NOTE: This code is based on code Luke-Jr wrote originally for LPC1343CodeBase
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ft232r.h"
+#include "jtag.h"
+
+// NOTE: The order of tms and tdi here are inverted from LPC1343CodeBase
+bool jtag_clock(struct jtag_port *jp, bool tms, bool tdi, bool *tdo)
+{
+	unsigned char buf[4];
+	memset(buf, (tms ? (1 << jp->tms) : 0)
+	          | (tdi ? (1 << jp->tdi) : 0), sizeof(buf));
+	buf[1] |= jp->tck;
+	if (ft232r_write_all(jp->ftdi, buf, sizeof(buf)) != sizeof(buf))
+		return false;
+	if (ft232r_read_all(jp->ftdi, buf, sizeof(buf)) != sizeof(buf))
+		return false;
+	if (tdo)
+		*tdo = buf[3] & jp->tdo;
+	return true;
+}
+
+static bool jtag_rw_bit(struct jtag_port *jp, void *buf, uint8_t mask, bool tms, bool do_read)
+{
+	uint8_t *byte = buf;
+	bool tdo;
+	if (!jtag_clock(jp, tms, byte[0] & mask, do_read ? &tdo : NULL))
+		return false;
+	if (do_read) {
+		if (tdo)
+			byte[0] |= mask;
+		else
+			byte[0] &= ~mask;
+	}
+	return true;
+}
+
+// Expects to start at the Capture step, to handle 0-length gracefully
+bool _jtag_llrw(struct jtag_port *jp, void *buf, size_t bitlength, bool do_read, int stage)
+{
+	uint8_t *data = buf;
+	int i, j;
+	div_t d;
+	
+	if (!bitlength)
+		return jtag_clock(jp, true, false, NULL);
+
+	if (stage & 1)
+		if (!jtag_clock(jp, false, false, NULL))
+			return false;
+
+	d = div(bitlength - 1, 8);
+
+	for (i = 0; i < d.quot; ++i) {
+		for (j = 0x80; j; j /= 2) {
+			if (!jtag_rw_bit(jp, &data[i], 0x80, false, do_read))
+				return false;
+		}
+	}
+	for (j = 0; j < d.rem; ++j)
+		if (!jtag_rw_bit(jp, &data[i], 0x80 >> j, false, do_read))
+			return false;
+	if (stage & 2) {
+		if (!jtag_rw_bit(jp, &data[i], 0x80 >> j, true, do_read))
+			return false;
+		if (!jtag_clock(jp, true, false, NULL))  // Update
+			return false;
+	}
+	else
+		if (!jtag_rw_bit(jp, &data[i], 0x80 >> j, false, do_read))
+			return false;
+	return true;
+}
+
+bool jtag_reset(struct jtag_port *jp)
+{
+	for (int i = 0; i < 5; ++i)
+		if (!jtag_clock(jp, true, false, NULL))
+			return false;
+	return jtag_clock(jp, false, false, NULL);
+}
+
+// Returns -1 for failure, -2 for unknown, or zero and higher for number of devices
+ssize_t jtag_detect(struct jtag_port *jp)
+{
+	// TODO: detect more than 1 device
+	int i;
+	bool tdo;
+	
+	if (!(1
+	 && jtag_write(jp, JTAG_REG_IR, "\xff", 8)
+	 && jtag_clock(jp, true , false, NULL)  // Select DR
+	 && jtag_clock(jp, false, false, NULL)  // Capture DR
+	 && jtag_clock(jp, false, false, NULL)  // Shift DR
+	))
+		return false;
+	for (i = 0; i < 4; ++i)
+		if (!jtag_clock(jp, false, false, NULL))
+			return false;
+	if (!jtag_clock(jp, false, false, &tdo))
+		return false;
+	if (tdo)
+		return -1;
+	for (i = 0; i < 4; ++i)
+	{
+		if (!jtag_clock(jp, false, true, &tdo))
+			return -1;
+		if (tdo)
+			break;
+	}
+	if (!jtag_reset(jp))
+		return -1;
+	return i < 2 ? i : -2;
+}
+
+bool _jtag_rw(struct jtag_port *jp, enum jtagreg r, void *buf, size_t bitlength, bool do_read, int stage)
+{
+	if (!jtag_clock(jp, true, false, NULL))  // Select DR
+		return false;
+	if (r == JTAG_REG_IR)
+		if (!jtag_clock(jp, true, false, NULL))  // Select IR
+			return false;
+	if (!jtag_clock(jp, false, false, NULL))  // Capture
+		return false;
+	return _jtag_llrw(jp, buf, bitlength, do_read, stage);  // Exit1
+}
+
+bool jtag_run(struct jtag_port *jp)
+{
+	return jtag_clock(jp, false, false, NULL);
+}

+ 35 - 0
jtag.h

@@ -0,0 +1,35 @@
+#ifndef BFGMINER_JTAG_H
+#define BFGMINER_JTAG_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+
+struct jtag_port {
+	struct ft232r_device_handle *ftdi;
+	uint8_t tck;
+	uint8_t tms;
+	uint8_t tdi;
+	uint8_t tdo;
+};
+
+enum jtagreg {
+	JTAG_REG_DR,
+	JTAG_REG_IR,
+};
+
+extern bool jtag_clock(struct jtag_port *, bool tms, bool tdi, bool *tdo);
+extern bool _jtag_llrw(struct jtag_port *, void *buf, size_t bitlength, bool do_read, int stage);
+extern bool jtag_reset(struct jtag_port *);
+extern ssize_t jtag_detect(struct jtag_port *);
+extern bool _jtag_rw(struct jtag_port *, enum jtagreg r, void *buf, size_t bitlength, bool do_read, int stage);
+#define jtag_read(jp, r, data, bitlen)  _jtag_rw(jp, r, data, bitlen, true, 0xff)
+#define jtag_sread(jp, r, data, bitlen)  _jtag_rw(jp, r, data, bitlen, true, 1)
+#define jtag_sread_more(jp, data, bitlen, finish)  _jtag_llrw(jp, data, bitlen, true, (finish) ? 2 : 0)
+// Cast is used to accept const data - while it ignores the compiler attribute, it still won't modify the data
+#define jtag_write(jp, r, data, bitlen)  _jtag_rw(jp, r, (void*)data, bitlen, false, 0xff)
+#define jtag_swrite(jp, r, data, bitlen)  _jtag_rw(jp, r, (void*)data, bitlen, false, 1)
+#define jtag_swrite_more(jp, data, bitlen, finish)  _jtag_llrw(jp, (void*)data, bitlen, false, (finish) ? 2 : 0)
+extern bool jtag_run(struct jtag_port *);
+
+#endif