Commit 4b8f28ee authored by Wesley W. Terpstra's avatar Wesley W. Terpstra

Import phase from our repository

parents
SUBDIRS = src
aclocal
autoheader
automake -a -c
autoconf
AC_PREREQ(2.67)
AC_INIT([phase], [0.1], [w.terpstra@gsi.de])
AC_CONFIG_AUX_DIR(tools)
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
AC_CONFIG_SRCDIR(src/common/component.h)
AC_CONFIG_HEADER(src/common/config.h)
AM_MAINTAINER_MODE
AC_LANG(C++)
AC_PROG_CXX
AC_PROG_RANLIB
AC_CHECK_HEADERS([stdint.h])
AC_TYPE_UINT64_T
AC_TYPE_UINT32_T
AC_TYPE_UINT16_T
AC_TYPE_UINT8_T
AC_ARG_WITH([libftdi],
[AS_HELP_STRING([--with-libftdi],
[use libftdi for FTDI-based cables])],
[], [with_libftdi=check])
AS_IF([test "x$with_libftdi" != xno], [
save_LIBS=$LIBS
save_CPPFLAGS=$CPPFLAGS
AS_IF([test "x$with_libftdi" != xyes -a "x$with_libftdi" != xcheck], [
FTDILIBS="-L$with_libftdi -lftdi"
FTDICFLAGS="-I$with_libftdi"
],[
AC_PATH_TOOL(LIBFTDI_CONFIG, libftdi-config, no)
AS_IF([test "$LIBFTDI_CONFIG" != "no"],[
FTDILIBS=`$LIBFTDI_CONFIG --libs`
FTDICFLAGS=`$LIBFTDI_CONFIG --cflags`
],)
])
LIBS="$FTDILIBS $LIBS"
CPPFLAGS="$CPPFLAGS $FTDICFLAGS"
AC_CHECK_FUNC([ftdi_usb_open], [
AC_DEFINE(HAVE_LIBFTDI, 1, [Define if you have libftdi])
HAVELIBFTDI=yes
],[
AC_MSG_WARN([*** libftdi not detected. No support for FTDI-based USB JTAG cables via libftdi.])
LIBS=$save_LIBS
CPPFLAGS=$save_CPPFLAGS
])
],)
AS_IF([test "x$HAVELIBFTDI" = "xyes"],[
AM_CONDITIONAL(HAVE_LIBFTDI, true)
],[
AM_CONDITIONAL(HAVE_LIBFTDI, false)
])
AC_CONFIG_FILES([Makefile src/Makefile src/common/Makefile src/pinouts/Makefile src/components/Makefile])
AC_OUTPUT
SUBDIRS = common pinouts components
AM_CXXFLAGS = -Wall -Werror -I..
noinst_LIBRARIES = libcommon.a
libcommon_a_SOURCES = \
pinout.cpp \
component.cpp \
slaveport.cpp \
masterport.cpp
#ifndef BITS_H
#define BITS_H
#include <vector>
#include <cstring> // size_t, uintptr_t, ptrdiff_t
#include "integer.h"
/* !!! TODO: add allocator support */
class Bits {
protected:
typedef uintptr_t rep;
public:
struct Cell {
public:
operator bool () const;
Cell& operator = (bool x);
Cell& operator = (const Cell& x);
void flip();
bool operator == (const Cell& x) const;
bool operator != (const Cell& x) const;
bool operator < (const Cell& x) const;
bool operator > (const Cell& x) const;
bool operator <= (const Cell& x) const;
bool operator >= (const Cell& x) const;
protected:
Cell(rep* ptr, rep mask);
rep* ptr;
rep mask;
friend class Bits;
friend class Iterator;
friend class ConstIterator;
};
struct IteratorBase : public std::iterator<std::random_access_iterator_tag, bool> {
public:
bool operator == (const IteratorBase& i) const;
bool operator != (const IteratorBase& i) const;
bool operator < (const IteratorBase& i) const;
bool operator > (const IteratorBase& i) const;
bool operator <= (const IteratorBase& i) const;
bool operator >= (const IteratorBase& i) const;
protected:
IteratorBase(rep* p, rep m);
rep* ptr;
rep mask;
void inc();
void dec();
void add(difference_type i);
};
struct Iterator : public IteratorBase {
public:
typedef Cell reference;
typedef Cell* pointer;
typedef Iterator iterator;
Iterator();
reference operator * () const;
iterator& operator ++ ();
iterator& operator -- ();
iterator operator ++ (int);
iterator operator -- (int);
iterator& operator += (difference_type i);
iterator& operator -= (difference_type i);
iterator operator + (difference_type i) const;
iterator operator - (difference_type i) const;
reference operator [] (difference_type i) const;
protected:
Iterator(rep* ptr, rep mask);
friend class Bits;
};
struct ConstIterator : public IteratorBase {
public:
typedef bool reference;
typedef bool const_reference;
typedef const bool* pointer;
typedef ConstIterator const_iterator;
ConstIterator();
ConstIterator(const Iterator& i);
const_reference operator * () const;
const_iterator& operator ++ ();
const_iterator& operator -- ();
const_iterator operator ++ (int);
const_iterator operator -- (int);
const_iterator& operator += (difference_type i);
const_iterator& operator -= (difference_type i);
const_iterator operator + (difference_type i) const;
const_iterator operator - (difference_type i) const;
const_reference operator [] (difference_type i) const;
protected:
ConstIterator(rep* ptr, rep mask);
friend class Bits;
};
typedef bool value_type;
typedef size_t size_type;
typedef Iterator::difference_type diference_type;
typedef Cell reference;
typedef bool const_reference;
typedef Cell* pointer;
typedef const bool* const_pointer;
typedef Iterator iterator;
typedef ConstIterator const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
Bits(const Bits& x);
~Bits();
// Empty bits
Bits();
// Named constructors
explicit Bits(uint8_t x);
explicit Bits(uint16_t x);
explicit Bits(uint32_t x);
explicit Bits(uint64_t x);
// Reverse conversion
operator uint8_t () const;
operator uint16_t () const;
operator uint32_t () const;
operator uint64_t () const;
// Given length
explicit Bits(size_type n, const bool& value);
//template <typename InputIterator>
//void assign(InputIterator first, InputIterator last);
//void assign(size_type n, const bool& value);
void swap(Bits& x);
static void swap(Bits& x, Bits& y);
Bits& operator = (const Bits& x);
bool empty() const;
size_type size() const;
size_type capacity() const;
//void resize(size_type n, const bool& value = false);
reference operator [] (size_type i);
const_reference operator [] (size_type i) const;
reference at(size_type i);
const_reference at(size_type i) const;
iterator begin();
iterator end ();
const_iterator begin() const;
const_iterator end () const;
reverse_iterator rbegin();
reverse_iterator rend ();
const_reverse_iterator rbegin() const;
const_reverse_iterator rend () const;
reference front();
reference back ();
const_reference front() const;
const_reference back () const;
bool operator == (const Bits& x) const;
bool operator != (const Bits& x) const;
bool operator < (const Bits& x) const; // When one prefixs the other, the shorter is "smaller"
bool operator > (const Bits& x) const;
bool operator <= (const Bits& x) const;
bool operator >= (const Bits& x) const;
// insert, erase, push_back, pop_back, clear -- all change the size and are not supported
protected:
static size_type rep_cells(size_type bits);
rep* alloc(size_type cells);
rep* ptr() const;
static size_type shift_cap(size_type shift, size_type size);
union Un {
rep local;
rep* buffer;
};
size_type length;
mutable Un un;
};
//Bits::IteratorBase::difference_type operator - (const Bits::IteratorBase& x, const Bits::IteratorBase& y);
Bits::Iterator operator + (Bits::Iterator::difference_type i, const Bits::Iterator& x);
Bits::ConstIterator operator + (Bits::ConstIterator::difference_type i, const Bits::ConstIterator& x);
/* Implementation is all inlined for speed */
#include "bits.tcc"
#endif
This diff is collapsed.
#ifndef COMMAND_H
#define COMMAND_H
#include "integer.h"
class Command {
public:
enum Instruction { WRITE, READ, WAIT };
Command(); // WRITE
Command(Instruction c, uint64_t nanoseconds = 0);
Instruction instruction() const;
uint64_t delay() const; // if WAIT, returns delay length
private:
uint64_t value;
static const uint64_t write = UINT64_C(0xffffffffffffffff);
static const uint64_t read = UINT64_C(0xfffffffffffffffe);
static const uint64_t max_wait = UINT64_C(0xfffffffffffffffd);
};
inline Command::Command() : value(write) { }
inline Command::Command(Command::Instruction c, uint64_t nanoseconds) {
switch (c) {
case WRITE:
value = write;
break;
case READ:
value = read;
break;
case WAIT:
if (nanoseconds > max_wait)
value = max_wait;
else
value = nanoseconds;
break;
}
}
inline Command::Instruction Command::instruction() const {
if (value == write) return WRITE;
if (value == read) return READ;
return WAIT;
}
inline uint64_t Command::delay() const {
if (value < max_wait) return value;
return 0;
}
#endif
#include "component.h"
Component::~Component() {
}
void Component::init() {
}
// !!! To be implemented:
MasterPort& addMasterPort(const std::string& name, const Pinout& pinout) {
throw -1;
}
SlavePort& addSlavePort (const std::string& name, const Pinout& pinout) {
throw -1;
}
#ifndef COMPONENT_H
#define COMPONENT_H
#include <string>
#include "recvqueue.h"
#include "sendqueue.h"
#include "slaveport.h"
#include "masterport.h"
#include "protocolviolation.h"
/* A component represents a protocol node.
*
* It has masters, which send commands (read/write/wait) to it.
* It has slaves which to which it sends the translated commands.
*
* After issuing a read command, a component's slave will invoke the
* recv method. The component then maps that data to the master's recv.
*
* A component may provide multiple master ports; for example, JTAG
* provides an IR and DR port. Similarly, it may need multiple slave ports.
* Derived components specify their ports via add{Master/Slave}Port.
*
* The situation is somewhat complicated by buffering.
* Many components combine multiple commands into commands sent to slaves.
* For example, a bit FIFO might need to combine 8 write commands into 1.
* Thus, the send and recv methods operate on queues.
*
* Components can safely read/write to slave devices while processing a
* queue without worrying about cross-component ordering. The scheduler
* code manages the queues behind the scenes to ensure maximal queueing
* without violating the execution order.
*/
class Component {
public:
/* Necessary for a virtual base class: */
virtual ~Component();
/* The name of this component */
virtual std::string name() const = 0;
/* Initialize (and reset) the component hardware and state machine.
* Since the component's ports are not connected until after construction,
* we cannot do hardware initialization until after chain configuration.
*/
virtual void init();
/* Process received bits read from slave devices.
* The entire recv queue MUST be processed before returning.
* If there is a problem, throw ProtocolViolation
*/
virtual void recv(RecvQueue::const_iterator i, RecvQueue::const_iterator end) = 0;
/* Process bits sent from a master device.
* Normally, the entire send queue SHOULD be processed.
* However, if the results of a read are needed before part of the
* queue can be further processed, a short read is permitted.
* Returned is the position in the stalled command queue.
* If there is a problem, throw ProtocolViolation
*/
virtual SendQueue::const_iterator send(SendQueue::const_iterator i, SendQueue::const_iterator end) = 0;
/* Define new ports */
MasterPort& addMasterPort(const std::string& name, const Pinout& pinout);
SlavePort& addSlavePort (const std::string& name, const Pinout& pinout);
};
#endif
#ifndef INTEGER_H
#define INTEGER_H
#include "config.h"
#ifdef HAVE_STDINT_H
// stdint.h provides it
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
#include <stdint.h>
#else
// For windows/other-broken-OS, the config.h defines them
#endif
#endif
#include "masterport.h"
// !!! To be implemented
const Component* MasterPort::destination_component() const {
return 0;
}
const SlavePort* MasterPort::destination_port() const {
return 0;
}
void MasterPort::recv(const Bits& bits) {
}
bool MasterPort::compatible(const SlavePort& masterport) const {
return false;
}
#ifndef MASTER_PORT_H
#define MASTER_PORT_H
#include "pinout.h"
#include "bits.h"
#include "integer.h"
#include "command.h"
class Component;
class SlavePort;
class Scheduler;
/* A SlavePort is used by a component to send commands to its slaves.
* The particular component connected to this port
*/
class MasterPort {
public:
MasterPort(const std::string& name, const Pinout& pinout);
// Information about this port
const std::string& name() const;
const Pinout& pinout() const;
// The target of the port
const Component* destination_component() const; // DO NOT send/recv to it!!!
const SlavePort* destination_port() const;
void recv(const Bits& bits);
// Is a slave compatible with this port?
bool compatible(const SlavePort& slaveport) const;
bool operator == (const MasterPort& other) const {
return this == &other;
}
protected:
std::string name_;
Pinout pinout_;
Scheduler* scheduler_;
int device_;
int port_;
friend class Scheduler;
};
inline const std::string& MasterPort::name() const {
return name_;
}
inline const Pinout& MasterPort::pinout() const {
return pinout_;
}
#endif
#include <sstream>
#include <assert.h>
#include "pinout.h"
template <class T>
inline std::string to_string (const T& t)
{
std::stringstream ss;
ss << t;
return ss.str();
}
Pinout::Pinout(int pins) : pins_(pins) {
for (int i = 0; i < pins; ++i) {
std::string name = "PIN" + to_string(i);
pins_[i].name = name;
pins_[i].direction = INOUT;
table_[name] = i;
}
}
int Pinout::pins() const {
return pins_.size();
}
int Pinout::getPin(const std::string& name) const {
Table::const_iterator i = table_.find(name);
if (i == table_.end()) return -1;
return i->second;
}
const std::string& Pinout::name(int pin) const {
assert (pin >= 0 && (Pins::size_type)pin < pins_.size());
return pins_[pin].name;
}
Pinout::Direction Pinout::direction(int pin) const {
assert (pin >= 0 && (Pins::size_type)pin < pins_.size());
return pins_[pin].direction;
}
void Pinout::setPin(int pin, const std::string& name, Pinout::Direction dir) {
assert(pin >= 0 && (Pins::size_type)pin < pins_.size() && table_.find(name) == table_.end());
std::string oldname = pins_[pin].name;
pins_[pin].name = name;
pins_[pin].direction = dir;
table_.erase(oldname);
table_[name] = pin;
}
#ifndef PINOUT_H
#define PINOUT_H
#include <string>
#include <map>
#include <vector>
class Pinout {
public:
Pinout(int pins = -1);
int pins() const; // -1 = undefined (unlimited)
enum Direction { IN, OUT, INOUT };
void setPin(int pin, const std::string& name, Direction dir);
int getPin(const std::string& name) const; // -1 = undefined
Direction direction(int pin) const;
const std::string& name(int pin) const;
protected:
struct Pin {
std::string name;
Direction direction;
};
typedef std::vector<Pin> Pins;
typedef std::map<std::string, int> Table;
Pins pins_;
Table table_;
};
#endif
#ifndef PROTOCOL_VIOLATION_H
#define PROTOCOL_VIOLATION_H
#include <string>
class Component;
struct ProtocolViolation {
Component* object;
std::string reason;
ProtocolViolation(Component* o, const std::string& r)
: object(o), reason(r) { }
};
#endif
#ifndef REV_QUEUE_H
#define RECV_QUEUE_H
#include <vector>
#include "bits.h"
class SlavePort;
struct RecvRequest {
const SlavePort& slave;
Bits bits;
};
typedef std::vector<RecvRequest> RecvQueue;
#endif
#ifndef SEND_QUEUE_H
#define SEND_QUEUE_H
#include <vector>
#include "bits.h"
#include "command.h"
class MasterPort;
struct SendRequest {
const MasterPort& master;
Command command;
Bits bits;
};
typedef std::vector<SendRequest> SendQueue;
#endif
#include "slaveport.h"
#include "masterport.h"
// !!! To be implemented
const Component* SlavePort::source_component() const {
return 0;
}
const MasterPort* SlavePort::source_port() const {
return 0;
}
void SlavePort::send(Command c, const Bits& bits) {
}
bool SlavePort::compatible(const MasterPort& masterport) const {
return masterport.compatible(*this);
}
#ifndef SLAVE_PORT_H
#define SLAVE_PORT_H
#include "pinout.h"
#include "bits.h"
#include "integer.h"
#include "command.h"
class Component;
class MasterPort;
class Scheduler;
/* A SlavePort is used by a component to send commands to its slaves.
* The particular component connected to this port
*/
class SlavePort {
public:
SlavePort(const std::string& name, const Pinout& pinout);
// Information about this port
const std::string& name() const;
const Pinout& pinout() const;
// The target of the port
const Component* source_component() const; // DO NOT send/recv to it!!!
const MasterPort* source_port() const;
void write(const Bits& bits);
void read(int number_of_bits);
void read(); // uses default pinout width
void wait_ns(uint64_t); // No-op on 0
void wait_us(uint64_t);
void wait_ms(uint64_t);
void wait_s(uint64_t);
void send(Command c, const Bits& bits);
// Is a master compatible with this port?
bool compatible(const MasterPort& masterport) const;
bool operator == (const SlavePort& other) const {
return this == &other;
}
protected:
std::string name_;
Pinout pinout_;
Scheduler* scheduler_;
int device_;
int port_;
friend class Scheduler;
};
inline const std::string& SlavePort::name() const {
return name_;
}
inline const Pinout& SlavePort::pinout() const {
return pinout_;
}
inline void SlavePort::write(const Bits& bits) {
send(Command(Command::WRITE), bits);
}
inline void SlavePort::read(int number_of_bits) {
send(Command(Command::READ), Bits(number_of_bits, false));
}
inline void SlavePort::read() {
read(pinout_.pins());
}
inline void SlavePort::wait_ns(uint64_t ns) {
send(Command(Command::WAIT, ns), Bits());
}
inline void SlavePort::wait_us(uint64_t us) {
wait_ns(us*UINT64_C(1000));
}
inline void SlavePort::wait_ms(uint64_t ms) {
wait_ns(ms*UINT64_C(1000000));
}
inline void SlavePort::wait_s(uint64_t s) {
wait_ns(s*UINT64_C(1000000000));
}
#endif
AM_CXXFLAGS = -Wall -Werror -I..
noinst_LIBRARIES = libcomponents.a
libcomponents_a_SOURCES = \
jtag-bitbang/jtag-bitbang.cpp \
jtag-chain/jtag-chain.cpp \
register-buffer/register-buffer.cpp \
ftdi/ftdi-byte-mode.cpp
etherbone
ip:port is memory map
memory map
creates registers on a per-address basis
persistent register
don't repeat writes to a register
=> put on most IRs before the jtag chain
=> put also before the USER0 register
jtag chain
determine IR length
count devices
scan idcodes
demux into distinct JTAGs
jtag register map
creates registers on a per-id basis
sld hub
writes to two registers USER0+USER1
provides for each 'instance id' an IR and DR
smart outputs
record output pins writes to feed back into reads
usb-blaster
pack into USB frames
jtag state machine
create tck/tdo/tms signals
ltdi driver
...
LM32 jtag
uart
csr
memory
LM32 debug ROM
...
current node pointed at:
nothing before it can run until it is drained
=> when executing, might as well drain entire queue
...
inqueue fills up while prior nodes run
all prior nodes are blocked
fully drain queue to output queue ... except if get stuck by a 'read'
move data from output queue as long as
nothing before it
(update next filled pointer on each move)
...
everything before the pointer has an empty inqueue
everything after the pointer has an empty outqueue
...
flush all cached writes out
push read data all the way to sources using same algorithm, but inverted
...
#ifndef ALTERA_SLD_HUB_H
#define ALTERA_SLD_HUB_H
#include "component.h"
class AlteraSldHub : public Component {
public:
AlteraSldHub(int width);
std::string name() const;
void init();
void recv(RecvQueue::const_iterator i, RecvQueue::const_iterator end);
SendQueue::const_iterator send(SendQueue::const_iterator i, SendQueue::const_iterator end);
protected:
MasterPort& IR;
MasterPort& DR;
SlavePort& USER0;
SlavePort& USER1;
};
#endif
#include "ftdi-byte-mode.h"
#include "pinouts/pinouts.h"
FTDI_ByteMode::FTDI_ByteMode(struct usb_device* dev, int rate)
: master(addMasterPort("Master", byte_pinout)),
slave(addSlavePort("End-of-Chain", eoc_pinout)),
baudrate(rate)
{
if (ftdi_init(&ftdi) != 0)
throw ProtocolViolation(0, "Not enough memory to init ftdi");
if (ftdi_usb_open_dev(&ftdi, dev) != 0)
throw ProtocolViolation(this, std::string("init: ftdi_usb_open_dev: ") + ftdi_get_error_string(&ftdi));
}
FTDI_ByteMode::~FTDI_ByteMode() {
ftdi_usb_close(&ftdi);
ftdi_deinit(&ftdi);
}
std::string FTDI_ByteMode::name() const {
return "FTDI_ByteMode";
}
void FTDI_ByteMode::init() {
if (ftdi_set_line_property2(&ftdi, BITS_8, STOP_BIT_1, NONE, BREAK_OFF) != 0) // 8N1
throw ProtocolViolation(this, std::string("init: ftdi_set_line_property2: ") + ftdi_get_error_string(&ftdi));
if (ftdi_disable_bitbang(&ftdi) != 0) // byte mode
throw ProtocolViolation(this, std::string("init: ftdi_disable_bitbang: ") + ftdi_get_error_string(&ftdi));
if (ftdi_set_baudrate(&ftdi, baudrate) != 0)
throw ProtocolViolation(this, std::string("init: ftdi_set_baudrate: ") + ftdi_get_error_string(&ftdi));
}
void FTDI_ByteMode::recv(RecvQueue::const_iterator i, RecvQueue::const_iterator end) {
unsigned char buf[64];
int got;
while ((got = ftdi_read_data(&ftdi, buf, sizeof(buf))) > 0) {
// Push each bytes to the reader
for (int i = 0; i < got; ++i)
master.recv(Bits(buf[i]));
}
if (got < 0)
throw ProtocolViolation(this, std::string("recv: ftdi_read_data: ") + ftdi_get_error_string(&ftdi));
}
SendQueue::const_iterator FTDI_ByteMode::send(SendQueue::const_iterator i, SendQueue::const_iterator end) {
unsigned char buf[64];
int fill, sent, got;
while (i != end) {
// Fill the buffer
for (fill = 0; i != end; ++i) {
buf[fill] = i->bits;
if (++fill == sizeof(buf)) break;
}
// Push the buffer out to FTDI
got = sent = 0;
while (sent != fill && (got = ftdi_write_data(&ftdi, buf+sent, fill-sent)) >= 0)
sent += got;
if (got < 0)
throw ProtocolViolation(this, std::string("send: ftdi_write_data: ") + ftdi_get_error_string(&ftdi));
}
return i;
}
#ifndef FTDI_BYTE_MODE_H
#define FTDI_BYTE_MODE_H
// ftdi includes stdint indirectly and screws up the defines
#include "integer.h"
#include <ftdi.h>
#include "component.h"
class FTDI_ByteMode : public Component {
public:
FTDI_ByteMode(struct usb_device* dev, int baudrate);
~FTDI_ByteMode();
std::string name() const;
void init();
void recv(RecvQueue::const_iterator i, RecvQueue::const_iterator end);
SendQueue::const_iterator send(SendQueue::const_iterator i, SendQueue::const_iterator end);
protected:
MasterPort& master;
SlavePort& slave; // tells us when to read
int baudrate;
struct ftdi_context ftdi;
};
#endif
#include "pinouts/pinouts.h"
#include "jtag-bitbang.h"
JTAG_BitBang::JTAG_BitBang(uint64_t delay_ns)
: IR(addMasterPort("IR", Pinout())), // We don't have a fixed width for the
DR(addMasterPort("DR", Pinout())), // IR/DR registers. It must be probed.
JTAG(addSlavePort("JTAG", JTAG_pinout)),
TCK(JTAG_pinout.getPin("TCK")),
TMS(JTAG_pinout.getPin("TMS")),
TDI(JTAG_pinout.getPin("TDI")),
TDO(JTAG_pinout.getPin("TDO")),
delay(delay_ns),
queue() { }
std::string JTAG_BitBang::name() const {
return "JTAG_BitBang";
}
void JTAG_BitBang::clock(int tms, int tdo) {
Bits b(JTAG_pinout.pins(), false);
b[TCK] = true;
b[TDO] = tdo;
b[TMS] = tms;
JTAG.write(b);
JTAG.wait_ns(delay);
b[TCK] = false;
JTAG.write(b);
JTAG.wait_ns(delay);
}
void JTAG_BitBang::init() {
// 5 times send TMS=1 -> brings us to reset state
for (int i = 0; i < 5; ++i) clock(1, 0);
// idle state
clock(0, 0);
}
SendQueue::const_iterator JTAG_BitBang::send(SendQueue::const_iterator i, SendQueue::const_iterator end) {
for (; i != end; ++i) {
if (i->command.instruction() == Command::WAIT) {
JTAG.wait_ns(i->command.delay());
} else {
// Confirm that there is a write after any read
bool read = i->command.instruction() == Command::READ;
if (read) {
SendQueue::const_iterator next = i;
++next;
if (next == end || next->command.instruction() != Command::WRITE)
throw ProtocolViolation(this, "READ not followed by WRITE");
if (i->bits.size() != next->bits.size())
throw ProtocolViolation(this, "READ followed by unequal WRITE");
// skip past the read
i = next;
// record the master of this read so we can route the result
queue.push(Read(i->master == IR, i->bits.size()));
}
// Move to shift DR/IR state from idle state
if (i->master == DR) {
clock(1, 0); // select DR scan
clock(0, 0); // capture DR
clock(0, 0); // shift DR state
} else { // else i->master == IR
clock(1, 0); // select DR scan
clock(1, 0); // select IR scan
clock(0, 0); // capture IR
clock(0, 0); // shift IR state
}
// Shift in the bits
for (Bits::size_type j = 0; j < i->bits.size(); ++j) {
// sample TDI if doing a read
if (read) JTAG.read();
// shift in new value
clock(j == i->bits.size()-1, i->bits[j]);
}
// now in exit-IR/DR state
clock(1, 0); // update IR/DR
clock(0, 0); // run-test / idle
// ^^^ this last step CAN be optimized away (Altera does it for example)
// However, some devices might expect a completed update clock tick
}
}
return i;
}
void JTAG_BitBang::recv(RecvQueue::const_iterator i, RecvQueue::const_iterator end) {
while (i != end) {
if (queue.empty())
throw ProtocolViolation(this, "More received data than expected");
Bits result(queue.front().bits, false);
for (int j = 0; j < queue.front().bits; ++j) {
if (i == end)
throw ProtocolViolation(this, "Register bounary not preserved");
result[j] = i->bits[TDI];
++i;
}
if (queue.front().ir)
IR.recv(result);
else
DR.recv(result);
queue.pop();
}
}
#ifndef JTAG_BITBANG_H
#define JTAG_BITBANG_H
#include <queue>
#include "component.h"
class JTAG_BitBang : public Component {
public:
JTAG_BitBang(uint64_t delay_ns = 0);
std::string name() const;
void init();
void recv(RecvQueue::const_iterator i, RecvQueue::const_iterator end);
SendQueue::const_iterator send(SendQueue::const_iterator i, SendQueue::const_iterator end);
protected:
void clock(int tms, int tdo);
MasterPort& IR;
MasterPort& DR;
SlavePort& JTAG;
int TCK, TMS, TDI, TDO; // jtag pins
uint64_t delay; // clock delay
struct Read {
bool ir;
int bits;
Read(bool i, int j) : ir(i), bits(j) { }
};
typedef std::queue<Read> Queue;
Queue queue;
};
#endif
#ifndef JTAG_CHAIN_H
#define JTAG_CHAIN_H
#include "component.h"
class JTAG_Chain : public Component {
public:
JTAG_Chain();
// Scan the chain (assumed to be reset)
// Then set all devices into bypass mode
void init();
// Report detected device IDCODEs
std::vector<uint32_t> detected();
// Configure the chain
protected:
};
#endif
#include "register-buffer.h"
RegisterBuffer::RegisterBuffer(const Pinout& po, bool rw, bool rr)
: master(addMasterPort("Master", po)),
slave(addSlavePort("Slave", po)),
reduce_write(rw),
reduce_read(rr),
valid(false),
value(po.pins(), false) { }
void RegisterBuffer::init () {
valid = false;
}
void RegisterBuffer::recv(RecvQueue::const_iterator i, RecvQueue::const_iterator end) {
while (!cache_replay.empty()) {
Bits& next = cache_replay.front();
if (next.size() == 0) {
// Not a cached value
if (i == end) {
break;
} else {
cache_replay.pop();
master.recv(i->bits);
++i;
}
} else {
// Replay cache
master.recv(next);
cache_replay.pop();
}
}
if (i != end)
throw ProtocolViolation(this, "queue exhausted before data fully read");
}
SendQueue::const_iterator RegisterBuffer::send(SendQueue::const_iterator i, SendQueue::const_iterator end) {
for (; i != end; ++i) {
switch (i->command.instruction()) {
case Command::WAIT:
slave.wait_ns(i->command.delay());
break;
case Command::WRITE:
if (reduce_write && valid && i->bits == value) {
// eliminate this write
} else {
valid = true;
value = i->bits;
slave.send(i->command, i->bits);
}
break;
case Command::READ:
if (reduce_read && valid && i->bits.size() == value.size()) {
// eliminate read
cache_replay.push(value);
} else {
cache_replay.push(Bits());
slave.send(i->command, i->bits);
}
break;
}
}
return i;
}
#ifndef REGISTER_BUFFER_H
#define REGISTER_BUFFER_H
#include "component.h"
#include <queue>
class RegisterBuffer : public Component {
public:
RegisterBuffer(const Pinout& po, bool reduce_write = true, bool reduce_read = true);
std::string name() const;
void init();
void recv(RecvQueue::const_iterator i, RecvQueue::const_iterator end);
SendQueue::const_iterator send(SendQueue::const_iterator i, SendQueue::const_iterator end);
protected:
MasterPort& master;
SlavePort& slave;
bool reduce_write, reduce_read;
bool valid;
Bits value;
std::queue<Bits> cache_replay;
};
#endif
AM_CXXFLAGS = -Wall -Werror -I..
noinst_LIBRARIES = libpinout.a
libpinout_a_SOURCES = \
jtag.cpp \
byte.cpp \
eoc.cpp
#include "pinouts.h"
static Pinout byte_pinout_make() {
Pinout o(8);
o.setPin(0, "D0", Pinout::INOUT);
o.setPin(0, "D1", Pinout::INOUT);
o.setPin(0, "D2", Pinout::INOUT);
o.setPin(0, "D3", Pinout::INOUT);
o.setPin(0, "D4", Pinout::INOUT);
o.setPin(0, "D5", Pinout::INOUT);
o.setPin(0, "D6", Pinout::INOUT);
o.setPin(0, "D7", Pinout::INOUT);
return o;
}
const Pinout byte_pinout(byte_pinout_make());
#include "pinouts.h"
const Pinout eoc_pinout;
#include "pinouts.h"
static Pinout JTAG_pinout_make() {
Pinout o(4);
o.setPin(0, "TCK", Pinout::OUT);
o.setPin(1, "TMS", Pinout::OUT);
o.setPin(2, "TDO", Pinout::OUT);
o.setPin(3, "TDI", Pinout::IN);
return o;
}
const Pinout JTAG_pinout(JTAG_pinout_make());
#ifndef PINOUTS_H
#define PINOUTS_H
#include "common/pinout.h"
extern const Pinout eoc_pinout; // <nil>
extern const Pinout JTAG_pinout; // TCK, TMS, TDO, TDI
extern const Pinout byte_pinout; // D0...D7
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment