# define D(x)
#endif
-/////////// Circular buffer
-
-template <typename T>
-unsigned int circular_buffer_t<T>::size() const
-{
- if (end >= start)
- return end - start;
- else
- return end + capacity - start;
-}
-
-template <typename T>
-void circular_buffer_t<T>::consume(unsigned int bytes)
-{
- start = (start + bytes) % capacity;
-}
-
-template <typename T>
-unsigned int circular_buffer_t<T>::contiguous_empty_size() const
-{
- if (end >= start)
- if (start == 0)
- return capacity - end - 1;
- else
- return capacity - end;
- else
- return start - end - 1;
-}
-
-template <typename T>
-unsigned int circular_buffer_t<T>::contiguous_data_size() const
-{
- if (end >= start)
- return end - start;
- else
- return capacity - start;
-}
-
-template <typename T>
-void circular_buffer_t<T>::data_added(unsigned int bytes)
-{
- end += bytes;
- assert(end <= capacity);
- if (end == capacity)
- end = 0;
-}
-
-template <typename T>
-void circular_buffer_t<T>::reset()
-{
- start = 0;
- end = 0;
-}
-
-template <typename T>
-void circular_buffer_t<T>::append(const T *src, unsigned int count)
-{
- unsigned int copy = std::min(count, contiguous_empty_size());
- memcpy(contiguous_empty(), src, copy * sizeof(T));
- data_added(copy);
- count -= copy;
- if (count > 0) {
- assert(count < contiguous_empty_size());
- memcpy(contiguous_empty(), src+copy, count * sizeof(T));
- data_added(count);
- }
-}
-
-template <typename T>
-void circular_buffer_t<T>::append(T value)
-{
- append(&value, 1);
-}
-
/////////// remote_bitbang_t
remote_bitbang_t::remote_bitbang_t(uint16_t port, jtag_dtm_t *tap) :
tap(tap),
socket_fd(0),
- client_fd(0),
- recv_buf(64 * 1024),
- send_buf(64 * 1024)
+ client_fd(0)
{
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd == -1) {
}
}
-void remote_bitbang_t::read()
-{
- // Reading from a non-blocking socket still blocks if there is no data
- // available.
-
- size_t count = recv_buf.contiguous_empty_size();
- ssize_t bytes = ::read(client_fd, recv_buf.contiguous_empty(), count);
- if (bytes == -1) {
- if (errno == EAGAIN) {
- // We'll try again the next call.
- } else {
- fprintf(stderr, "failed to read on socket: %s (%d)\n", strerror(errno), errno);
- abort();
- }
- } else if (bytes == 0) {
- // The remote disconnected.
- client_fd = 0;
- recv_buf.reset();
- send_buf.reset();
- } else {
- recv_buf.data_added(bytes);
- D(fprintf(stderr, "receive buffer: "));
- for (unsigned i = 0; i < recv_buf.size(); i++) {
- D(fprintf(stderr, "%c", recv_buf[i]));
- }
- D(fprintf(stderr, "\n"));
- }
-}
-
-void remote_bitbang_t::write()
-{
- if (send_buf.empty())
- return;
-
- while (!send_buf.empty()) {
- unsigned int count = send_buf.contiguous_data_size();
- assert(count > 0);
- ssize_t bytes = ::write(client_fd, send_buf.contiguous_data(), count);
- if (bytes == -1) {
- fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
- abort();
- } else if (bytes == 0) {
- // Client can't take any more data right now.
- break;
- } else {
- D(fprintf(stderr, "wrote %zd bytes: ", bytes));
- for (int i = 0; i < bytes; i++) {
- D(fprintf(stderr, "%c", send_buf[i]));
- }
- D(fprintf(stderr, "\n"));
- send_buf.consume(bytes);
- }
- }
-}
-
void remote_bitbang_t::tick()
{
if (client_fd > 0) {
- this->read();
- process_input();
- this->write();
+ execute_commands();
} else {
this->accept();
}
}
-void remote_bitbang_t::process_input()
+void remote_bitbang_t::execute_commands()
{
- // TODO: get rid of the circular buffers, and just read/write here with
- // simple local buffers.
- // Each message is a single character, so there's never any need to keep a
- // partially transmitted message around.
+ const unsigned buf_size = 64 * 1024;
+ char recv_buf[buf_size];
+ char send_buf[buf_size];
+ unsigned total_received = 0;
+ ssize_t bytes = read(client_fd, recv_buf, buf_size);
+ while (bytes > 0) {
+ total_received += bytes;
+ unsigned send_offset = 0;
+ for (unsigned i = 0; i < bytes; i++) {
+ uint8_t command = recv_buf[i];
+
+ switch (command) {
+ case 'B': fprintf(stderr, "*BLINK*\n"); break;
+ case 'b': fprintf(stderr, "_______\n"); break;
+ case 'r': tap->reset(); break;
+ case '0': tap->set_pins(0, 0, 0); break;
+ case '1': tap->set_pins(0, 0, 1); break;
+ case '2': tap->set_pins(0, 1, 0); break;
+ case '3': tap->set_pins(0, 1, 1); break;
+ case '4': tap->set_pins(1, 0, 0); break;
+ case '5': tap->set_pins(1, 0, 1); break;
+ case '6': tap->set_pins(1, 1, 0); break;
+ case '7': tap->set_pins(1, 1, 1); break;
+ case 'R': send_buf[send_offset++] = tap->tdo() ? '1' : '0'; break;
+ default:
+ fprintf(stderr, "remote_bitbang got unsupported command '%c'\n",
+ command);
+ }
+ }
+ unsigned sent = 0;
+ while (sent < send_offset) {
+ bytes = write(client_fd, send_buf + sent, send_offset);
+ if (bytes == -1) {
+ fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
+ abort();
+ }
+ sent += bytes;
+ }
- for (unsigned i = 0; i < recv_buf.size(); i++) {
- uint8_t command = recv_buf[i];
+ if (total_received > buf_size) {
+ // Don't go forever, because that could starve the main simulation.
+ break;
+ }
+ bytes = read(client_fd, recv_buf, buf_size);
+ }
- switch (command) {
- case 'B': fprintf(stderr, "*BLINK*\n"); break;
- case 'b': fprintf(stderr, "_______\n"); break;
- case 'r': tap->reset(); break;
- case '0': tap->set_pins(0, 0, 0); break;
- case '1': tap->set_pins(0, 0, 1); break;
- case '2': tap->set_pins(0, 1, 0); break;
- case '3': tap->set_pins(0, 1, 1); break;
- case '4': tap->set_pins(1, 0, 0); break;
- case '5': tap->set_pins(1, 0, 1); break;
- case '6': tap->set_pins(1, 1, 0); break;
- case '7': tap->set_pins(1, 1, 1); break;
- case 'R': send_buf.append(tap->tdo() ? '1' : '0'); break;
- default:
- fprintf(stderr, "remote_bitbang got unsupported command '%c'\n", command);
+ if (bytes == -1) {
+ if (errno == EAGAIN) {
+ // We'll try again the next call.
+ } else {
+ fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n",
+ strerror(errno), errno);
+ abort();
}
+ } else if (bytes == 0) {
+ // The remote disconnected.
+ close(client_fd);
+ client_fd = 0;
}
- recv_buf.reset();
}
#include "jtag_dtm.h"
-template <typename T>
-class circular_buffer_t
-{
-public:
- // The buffer can store capacity-1 data elements.
- circular_buffer_t(unsigned int capacity) : data(new T[capacity]),
- start(0), end(0), capacity(capacity) {}
- circular_buffer_t() : start(0), end(0), capacity(0) {}
- ~circular_buffer_t() { delete[] data; }
-
- T *data;
- unsigned int start; // Data start, inclusive.
- unsigned int end; // Data end, exclusive.
- unsigned int capacity; // Size of the buffer.
- unsigned int size() const;
- bool empty() const { return start == end; }
- bool full() const { return ((end+1) % capacity) == start; }
- T entry(unsigned index) { return data[(start + index) % capacity]; }
-
- // Return size and address of the block of RAM where more data can be copied
- // to be added to the buffer.
- unsigned int contiguous_empty_size() const;
- T *contiguous_empty() { return data + end; }
- void data_added(unsigned int bytes);
-
- unsigned int contiguous_data_size() const;
- T *contiguous_data() { return data + start; }
- // Tell the buffer that some bytes were consumed from the start of the
- // buffer.
- void consume(unsigned int bytes);
-
- void reset();
-
- T operator[](unsigned int i) const { return data[(start + i) % capacity]; }
-
- void append(const T *src, unsigned int count);
- void append(T value);
-};
-
class remote_bitbang_t
{
public:
int socket_fd;
int client_fd;
- circular_buffer_t<uint8_t> recv_buf;
- circular_buffer_t<uint8_t> send_buf;
// Check for a client connecting, and accept if there is one.
void accept();
- // Read as much into recv_buf as possible.
- void read();
- // Write as much of send_buf as possible.
- void write();
-
- // Process the input buffer.
- void process_input();
+ // Execute any commands the client has for us.
+ void execute_commands();
};
#endif