URL
https://opencores.org/ocsvn/xulalx25soc/xulalx25soc/trunk
Subversion Repositories xulalx25soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/xulalx25soc
- from Rev 4 to Rev 5
- ↔ Reverse comparison
Rev 4 → Rev 5
/trunk/sw/ttybus.h
0,0 → 1,124
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: ttybus.h |
// |
// Project: XuLA2 board |
// |
// Purpose: This is the C++ program on the command side that will interact |
// with a UART on an FPGA, to command the WISHBONE on that same |
// FPGA to ... whatever we wish to command it to do. |
// |
// This code does not run on an FPGA, is not a test bench, neither |
// is it a simulator. It is a portion of a command program |
// for commanding an FPGA. |
// |
// This particular implementation is a complete rewrite of the |
// last implementation, adding compression into the interface that |
// wasn't there before. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#ifndef TTYBUS_H |
#define TTYBUS_H |
|
#include "llcomms.h" |
#include "devbus.h" |
|
#define RDBUFLN 2048 |
|
class TTYBUS : public DEVBUS { |
public: |
unsigned long m_total_nread; |
private: |
LLCOMMSI *m_dev; |
static const unsigned MAXRDLEN, MAXWRLEN; |
|
bool m_interrupt_flag, m_decode_err, m_addr_set, m_bus_err; |
unsigned int m_lastaddr; |
|
int m_buflen, m_rdfirst, m_rdlast; |
char *m_buf, *m_rdbuf; |
|
bool m_wrloaded; |
int m_rdaddr, m_wraddr; |
BUSW m_readtbl[1024], m_writetbl[512]; |
|
void init(void) { |
m_interrupt_flag = false; |
m_buflen = 0; m_buf = NULL; |
m_addr_set = false; |
bufalloc(64); |
m_bus_err = false; |
m_decode_err = false; |
m_wrloaded = false; |
|
m_rdfirst = m_rdlast = 0; |
m_rdbuf = new char[RDBUFLN]; |
|
m_rdaddr = m_wraddr = 0; |
} |
|
char charenc(const int sixbitval); |
unsigned chardec(const char b); |
void encode(const int fbits, const BUSW v, char *buf); |
unsigned decodestr(const char *buf); |
int decodehex(const char hx); |
void bufalloc(int len); |
BUSW readword(void); // Reads a word value from the bus |
void readv(const BUSW a, const int inc, const int len, BUSW *buf); |
void writev(const BUSW a, const int p, const int len, const BUSW *buf); |
|
int lclread(char *buf, int len); |
int lclreadcode(char *buf, int len); |
char *encode_address(const BUSW a); |
char *readcmd(const int inc, const int len, char *buf); |
public: |
TTYBUS(LLCOMMSI *comms) : m_dev(comms) { init(); } |
virtual ~TTYBUS(void) { |
m_dev->close(); |
if (m_buf) delete[] m_buf; m_buf = NULL; |
delete m_rdbuf; m_rdbuf = NULL; |
delete m_dev; |
} |
|
void kill(void) { m_dev->close(); } |
void close(void) { m_dev->close(); } |
void writeio(const BUSW a, const BUSW v); |
BUSW readio(const BUSW a); |
void readi(const BUSW a, const int len, BUSW *buf); |
void readz(const BUSW a, const int len, BUSW *buf); |
void writei(const BUSW a, const int len, const BUSW *buf); |
void writez(const BUSW a, const int len, const BUSW *buf); |
bool poll(void) { return m_interrupt_flag; }; |
void usleep(unsigned msec); // Sleep until interrupt |
void wait(void); // Sleep until interrupt |
bool bus_err(void) const { return m_bus_err; }; |
void reset_err(void) { m_bus_err = false; } |
void clear(void) { m_interrupt_flag = false; } |
}; |
|
#endif |
/trunk/sw/netusb.cpp
0,0 → 1,275
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: netusb.cpp |
// |
// Project: XuLA2 board |
// |
// Purpose: Forwards a XuLA2 board USB connection over a TCP socket, so |
// a non-local computer can control the board. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <fcntl.h> |
#include <termios.h> |
#include <sys/socket.h> |
#include <arpa/inet.h> |
#include <string.h> |
#include <poll.h> |
#include <signal.h> |
#include <ctype.h> |
#include <assert.h> |
#include <errno.h> |
|
#include "port.h" |
#include "usbi.h" |
|
void sigstop(int v) { |
fprintf(stderr, "SIGSTOP!!\n"); |
exit(0); |
} |
void sighup(int v) { |
fprintf(stderr, "SIGHUP!!\n"); |
exit(0); |
} |
void sigint(int v) { |
fprintf(stderr, "SIGINT!!\n"); |
exit(0); |
} |
void sigsegv(int v) { |
fprintf(stderr, "SIGSEGV!!\n"); |
exit(0); |
} |
void sigbus(int v) { |
fprintf(stderr, "SIGBUS!!\n"); |
exit(0); |
} |
void sigpipe(int v) { |
fprintf(stderr, "SIGPIPE!!\n"); |
exit(0); |
} |
|
int setup_listener(const int port) { |
int skt; |
struct sockaddr_in my_addr; |
|
printf("Listening on port %d\n", port); |
|
skt = socket(AF_INET, SOCK_STREAM, 0); |
if (skt < 0) { |
perror("Could not allocate socket: "); |
exit(-1); |
} |
|
// Set the reuse address option |
{ |
int optv = 1, er; |
er = setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, &optv, sizeof(optv)); |
if (er != 0) { |
perror("SockOpt Err:"); |
exit(-1); |
} |
} |
|
memset(&my_addr, 0, sizeof(struct sockaddr_in)); // clear structure |
my_addr.sin_family = AF_INET; |
my_addr.sin_addr.s_addr = htonl(INADDR_ANY); |
my_addr.sin_port = htons(port); |
|
if (bind(skt, (struct sockaddr *)&my_addr, sizeof(my_addr))!=0) { |
perror("BIND FAILED:"); |
exit(-1); |
} |
|
if (listen(skt, 1) != 0) { |
perror("Listen failed:"); |
exit(-1); |
} |
|
return skt; |
} |
|
class LINBUFS { |
public: |
char m_iline[512], m_oline[512]; |
char m_buf[256]; |
int m_ilen, m_olen; |
bool m_connected; |
|
LINBUFS(void) { |
m_ilen = 0; m_olen = 0; m_connected = false; |
} |
}; |
|
bool check_incoming(LINBUFS &lb, USBI *usbp, int confd, int timeout) { |
struct pollfd p[2]; |
int pv, nfds; |
|
if (confd >= 0) { |
// Only do this if we currently have a network connection |
p[0].fd = confd; |
p[0].events = POLLIN | POLLRDHUP | POLLERR; |
nfds = 1; |
|
if ((pv=poll(p, nfds, timeout)) < 0) { |
perror("Poll Failed! O/S Err:"); |
exit(-1); |
} |
if (p[0].revents & POLLIN) { |
/* |
else if (p[0].revents) |
printf("UNKNOWN TTY EVENT: %d\n", p[0].revents); |
*/ |
int nr = read(confd, lb.m_buf, 256); |
if (nr == 0) { |
lb.m_connected = false; |
if (lb.m_olen > 0) { |
lb.m_oline[lb.m_olen] = '\0'; |
printf("< %s\n", lb.m_oline); |
} lb.m_olen = 0; |
close(confd); |
} else if (nr > 0) { |
usbp->write(lb.m_buf, nr); |
} for(int i=0; i<nr; i++) { |
lb.m_oline[lb.m_olen++] = lb.m_buf[i]; |
assert(lb.m_buf[i] != '\0'); |
if ((lb.m_oline[lb.m_olen-1]=='\n')||(lb.m_oline[lb.m_olen-1]=='\r')||(lb.m_olen >= (int)sizeof(lb.m_oline)-1)) { |
if (lb.m_olen >= (int)sizeof(lb.m_oline)-1) |
lb.m_oline[lb.m_olen] = '\0'; |
else |
lb.m_oline[lb.m_olen-1] = '\0'; |
if (lb.m_olen > 1) |
printf("< %s\n", lb.m_oline); |
lb.m_olen = 0; |
} |
} |
} else if ((nfds>1)&&(p[1].revents)) { |
printf("UNKNOWN SKT EVENT: %d\n", p[1].revents); |
} |
} |
|
if (usbp->poll(2)) { |
int nr, nrn; |
|
nr = nrn = usbp->read(lb.m_buf,1,2); |
while((nrn>0)&&(nr<255)&&((lb.m_buf[0]&0x80)==0)&&(lb.m_buf[0]>0x10)) { |
nrn = usbp->read(&lb.m_buf[nr],1,2); |
nr += nrn; |
} if ((nr > 0)&&(confd >= 0)) { |
// Return our result if we have a network |
// connection |
write(confd, lb.m_buf, nr); |
} for(int i=0; i<nr; i++) { |
lb.m_iline[lb.m_ilen++] = lb.m_buf[i]; |
if ((lb.m_iline[lb.m_ilen-1]=='\n')||(lb.m_iline[lb.m_ilen-1]=='\r')||(lb.m_ilen>=sizeof(lb.m_iline)-1)) { |
if (lb.m_ilen >= sizeof(lb.m_iline)-1) |
lb.m_iline[lb.m_ilen] = '\0'; |
else |
lb.m_iline[lb.m_ilen-1] = '\0'; |
if (lb.m_ilen > 1) |
printf("%c %s\n", |
(confd>=0)?'>':'#', lb.m_iline); |
lb.m_ilen = 0; |
} |
} |
} |
|
return (pv > 0); |
} |
|
int myaccept(int skt, int timeout) { |
int con = -1; |
struct pollfd p[1]; |
int pv; |
|
p[0].fd = skt; |
p[0].events = POLLIN | POLLERR; |
if ((pv=poll(p, 1, timeout)) < 0) { |
perror("Poll Failed! O/S Err:"); |
exit(-1); |
} if (p[0].revents & POLLIN) { |
con = accept(skt, 0, 0); |
if (con < 0) { |
perror("Accept failed! O/S Err:"); |
exit(-1); |
} |
} return con; |
} |
|
int main(int argc, char **argv) { |
// First, accept a network connection |
int skt = setup_listener(FPGAPORT); |
USBI *usbp; |
bool done = false; |
|
signal(SIGSTOP, sigstop); |
signal(SIGBUS, sigbus); |
signal(SIGSEGV, sigsegv); |
signal(SIGPIPE, SIG_IGN); |
signal(SIGINT, sigint); |
signal(SIGHUP, sighup); |
|
usbp = new USBI(); |
|
LINBUFS lb; |
while(!done) { |
int con; |
|
// Accept a connection before going on |
// Let's call poll(), so we can still read any |
// tty messages even when not accepted |
con = myaccept(skt, 50); |
if (con >= 0) { |
lb.m_connected = true; |
|
/* |
// Set our new socket as non-blocking |
int flags = fcntl(fd, F_GETFL, 0); |
flags |= O_NONBLOCK; |
fcntl(fd, F_SETFL, flags); |
*/ |
|
// printf("Received a new connection\n"); |
} |
|
// Flush any buffer within the TTY |
while(check_incoming(lb, usbp, -1, 0)) |
; |
|
// Now, process that connection until it's gone |
while(lb.m_connected) { |
check_incoming(lb, usbp, con, -1); |
} |
} |
|
printf("Closing our socket\n"); |
close(skt); |
} |
|
/trunk/sw/usbi.cpp
0,0 → 1,415
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: |
// |
// Project: XuLA2 board |
// |
// Purpose: Creates a USB port, similar to a serial port, out of the |
// XuLA2 JTAG interface S/W. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <string.h> |
#include <ctype.h> |
// #include <usb.h> |
|
#include <libusb.h> |
|
#include "llcomms.h" |
#include "usbi.h" |
|
// Walk us through the JTAG Chain: |
// 5-1's to go to test/reset |
// 0 to go to Run-Test/Idle |
// 1 to go to select-dr-scan |
// 1 to go to select-ir-scan |
// 0 to go to capture-ir |
// 0 to go to shift-ir |
// (6-bit code 0x02 through TDI to IR, while sending 0-bits to TMS) |
// 1 to leave shift IR and go to exit1-ir |
// 1 to go to update-ir |
// 1 to go to select-dr-scan |
// 0 to go to capture-dr |
// 0 to go to shift-dr |
#define RESET_JTAG_LEN 12 |
static const char RESET_TO_USER_DR[RESET_JTAG_LEN] = { |
JTAG_CMD, |
21, // clocks |
0,0,0, // Also clocks, higher order bits |
PUT_TMS_MASK | PUT_TDI_MASK, // flags |
(char)(0x0df), // TMS: Five ones, then one zero, and two ones -- low bits first |
0x00, // TDI: irrelevant here |
(char)0x80, // TMS: two zeros, then six zeros |
0x08, // TDI: user command #1, bit reversed |
0x03, // TMS: three ones, then two zeros |
0x00 // TDI byte -- irrelevant here |
// |
// 0xc0, // TDI byte -- user command #2 |
// 0x40, // TDI: user command #1 |
// 0x0c, // TDI byte -- user command #2, bit reversed |
}; |
|
// |
// TMS: |
#define TX_DR_LEN 12 |
static const char TX_DR_BITS[TX_DR_LEN] = { |
JTAG_CMD, |
48, // clocks |
0,0,0, // Also clocks, higher order bits |
PUT_TDI_MASK, // flags |
(char)0x0ff, 0, 0, 0, 0, 0 // Six data bytes |
// module_id = 255 |
// 32'h(payload.length) |
// payload |
// module_id + payload.len + num_result_bits, length=32 + payload ??? |
}; |
|
// |
// TMS: |
// |
#define REQ_RX_LEN 6 |
static const char REQ_RX_BITS[REQ_RX_LEN] = { |
JTAG_CMD, |
(const char)((USB_PKTLEN-REQ_RX_LEN)*8), // bits-requested |
0,0,0, // Also clocks, higher order bits |
GET_TDO_MASK|TDI_VAL_MASK, // flags:TDI is kept low here, so no TDI flag |
// No data given, since there's no info to send or receive |
// Leave the result in shift-DR mode |
}; |
|
/* |
#define RETURN_TO_RESET_LEN 7 |
static const char RETURN_TO_RESET[RETURN_TO_RESET_LEN] = { |
JTAG_CMD, |
5, // clocks |
0,0,0, // Also clocks, higher order bits |
PUT_TMS_MASK, // flags |
(char)0x0ff, // Five ones |
}; |
*/ |
|
USBI::USBI(void) { |
int config; |
|
m_total_nread = 0; |
|
if (0 != libusb_init(&m_usb_context)) { |
fprintf(stderr, "Error initializing the USB library\n"); |
perror("O/S Err:"); |
exit(-1); |
} |
|
m_xula_usb_device = libusb_open_device_with_vid_pid(m_usb_context, |
VENDOR_ID, PRODUCT_ID); |
if (!m_xula_usb_device) { |
fprintf(stderr, "Could not open XuLA device\n"); |
perror("O/S Err:"); |
|
libusb_exit(m_usb_context); |
exit(-1); |
} |
|
if (0 != libusb_get_configuration(m_xula_usb_device, &config)) { |
fprintf(stderr, "Could not get configuration\n"); |
perror("O/S Err:"); |
|
libusb_close(m_xula_usb_device); |
libusb_exit(m_usb_context); |
exit(-1); |
} |
|
if (0 != libusb_claim_interface(m_xula_usb_device, XESS_INTERFACE)) { |
fprintf(stderr, "Could not claim interface\n"); |
perror("O/S Err:"); |
|
libusb_close(m_xula_usb_device); |
libusb_exit(m_usb_context); |
exit(-1); |
} |
|
unsigned char abuf[RESET_JTAG_LEN]; |
int actual_length = RESET_JTAG_LEN, r; |
|
memcpy(abuf, RESET_TO_USER_DR, RESET_JTAG_LEN); |
r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_OUT, |
abuf, RESET_JTAG_LEN, &actual_length, 4); |
if ((r!=0)||(actual_length != RESET_JTAG_LEN)) { |
// Try clearing the queue twice, then doing this |
do { |
r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_IN, |
(unsigned char *)m_rxbuf, USB_PKTLEN, &actual_length, 20); |
} while((r==0)&&(actual_length > 0)); |
|
r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_OUT, |
abuf, RESET_JTAG_LEN, &actual_length, 4); |
if ((r != 0)||(actual_length != RESET_JTAG_LEN)) { |
printf("Some error took place requesting RESET_TO_USER_DR\n"); |
printf("r = %d, actual_length = %d (vs %d requested)\n", |
r, actual_length, RESET_JTAG_LEN); |
perror("O/S Err"); |
exit(-2); |
} |
} |
|
// Initialize our read FIFO |
m_rbeg = m_rend = 0; |
|
flush_read(); |
} |
|
void USBI::close(void) { |
// Release our interface |
if (0 != libusb_release_interface(m_xula_usb_device, XESS_INTERFACE)) { |
fprintf(stderr, "Could not release interface\n"); |
perror("O/S Err:"); |
|
libusb_close(m_xula_usb_device); |
libusb_exit(m_usb_context); |
exit(-1); |
} |
|
// And then close our device with |
libusb_close(m_xula_usb_device); |
|
// And just before exiting, we free our USB context |
libusb_exit(m_usb_context); |
} |
|
void USBI::write(char *buf, int len) { |
int r, actual_length; |
|
if (len >= USB_PKTLEN) { |
const int nv = USB_PKTLEN/2-1; |
for(int pos=0; pos<len; pos+=nv) |
write(&buf[pos], (len-pos>nv)?(nv):len-pos); |
} else { |
memset(m_txbuf, 0, len+6); |
m_txbuf[0] = JTAG_CMD; |
m_txbuf[1] = len * 8; |
m_txbuf[2] = 0; |
m_txbuf[3] = 0; |
m_txbuf[4] = 0; |
m_txbuf[5] = PUT_TDI_MASK | GET_TDO_MASK; |
|
for(int i=0; i<len; i++) |
m_txbuf[6+i] = buf[i]; |
r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_OUT, |
(unsigned char*)m_txbuf, len+6, &actual_length, 0); |
if ((r!=0)||(actual_length != len+6)) { |
printf("WRITE::(buf, %d) -- ERR\n", len+6); |
printf("r = %d, actual_length = %d (!= %d requested)\n", r, |
actual_length, len+6); |
|
if (r == -7) { |
r = libusb_bulk_transfer(m_xula_usb_device, |
XESS_ENDPOINT_OUT, |
(unsigned char*)m_txbuf, len+6, |
&actual_length, 2); |
if ((r!=0)||(actual_length != len+6)) { |
printf("WRITE::(buf, %d) -- ERR\n", len+6); |
printf("r = %d, actual_length = %d (!= %d requested)\n", r, |
actual_length, len+6); |
perror("O/S Err"); |
|
exit(-2); |
} |
} else { |
perror("O/S Err"); |
exit(-2); |
} |
} |
|
// Try to read back however many bytes we can |
r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_IN, |
(unsigned char*)m_rxbuf, USB_PKTLEN, &actual_length, 20); |
if ((r==0)&&(actual_length > 0)) { |
push_fifo(m_rxbuf, actual_length); |
} else { |
printf("Some error took place in receiving\n"); |
perror("O/S Err"); |
} |
} |
} |
|
int USBI::read(char *buf, int len) { |
return read(buf, len, 4); |
} |
|
int USBI::read(char *buf, int len, int timeout_ms) { |
int left = len, nr=0; |
|
// printf("USBI::read(%d) (FIFO is %d-%d)\n", len, m_rend, m_rbeg); |
nr = pop_fifo(buf, left); |
left -= nr; |
|
while(left > 0) { |
raw_read(left, timeout_ms); |
nr = pop_fifo(buf, left); |
left -= nr; |
|
// printf("\tWHILE (nr = %d, LEFT = %d, len=%d)\n", nr, left, len); |
if (nr == 0) |
break; |
} |
|
// printf("READ %d characters (%d req, %d left)\n", len-left, len, left); |
return len-left; |
} |
|
void USBI::raw_read(const int clen, int timeout_ms) { |
int avail = (m_rbeg - m_rend)&(RCV_BUFMASK), actual_length; |
int len = clen; |
if (len > RCV_BUFMASK-avail) |
len = RCV_BUFMASK-avail; |
if (len > 26) |
len = 26; |
|
// printf("USBI::RAW-READ(%d, was %d)\n", len, clen); |
memcpy(m_txbuf, REQ_RX_BITS, REQ_RX_LEN); |
|
int r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_OUT, |
(unsigned char *)m_txbuf, REQ_RX_LEN, &actual_length, |
timeout_ms); |
if ((r==0)&&(actual_length == REQ_RX_LEN)) { |
} else if (r == -7) { |
// Nothing to read in the timeout provided |
// We'll have to request this data again ... later |
return; |
} else { |
printf("READ(WRITE,READ-REQ) -- ERR\n"); |
printf("r = %d, actual_length = %d (!= %d requested)\n", r, |
actual_length, len+6); |
perror("O/S Err"); |
exit(-2); |
} |
|
// Try to read back however many bytes we can |
r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_IN, |
(unsigned char *)m_rxbuf, USB_PKTLEN, &actual_length, 0); |
if ((r==0)&&(actual_length > 0)) { |
/* |
printf("RAW-READ() -> %d Read\n", actual_length); |
for(int i=0; i<actual_length; i++) |
printf("%02x ", m_rxbuf[i] & 0x0ff); |
printf("\n"); |
*/ |
push_fifo(m_rxbuf, actual_length); |
} else if (r == -7) { |
// Nothing to read in the timeout provided |
// Return, adding nothing to our FIFO |
} else { |
printf("Some error took place in receiving\n"); |
perror("O/S Err"); |
} |
|
// fprintf(stderr, "\tUSBI::RAW-READ() -- COMPLETE (%d avail)\n", |
// (m_rbeg-m_rend)&(RCV_BUFMASK)); |
} |
|
void USBI::flush_read(void) { |
while(poll(4)) { |
m_rbeg = m_rend = 0; |
} |
} |
|
void USBI::push_fifo(char *buf, int len) { |
char last = 0; |
char *sptr = buf; |
|
// printf("Pushing %d items onto FIFO (%d - %d)\n", len, m_rend, m_rbeg); |
if (m_rbeg != m_rend) |
last = m_rbuf[m_rend]; |
for(int i=0; i<len; i++) { |
char v = *sptr++; |
if (((v & 0x80)||((unsigned char)v < 0x10))&&(v == last)) { |
// printf("\tSkipping: %02x\n", v & 0x0ff); |
} else if ((unsigned char)v == 0x0ff) { |
} else { |
m_rbuf[m_rbeg] = v; |
m_rbeg = (m_rbeg+1)&(RCV_BUFMASK); |
// printf("\tPushing: %02x\n", v & 0x0ff); |
} last = v; |
} |
} |
|
int USBI::pop_fifo(char *buf, int len) { |
int avail = (m_rbeg - m_rend)&(RCV_BUFMASK); |
int left = len; |
int nr = 0; |
|
// printf("Attempting to pop %d items from FIFO (%d - %d)\n", |
// len, m_rend, m_rbeg); |
while((avail > 0)&&(left > 0)) { |
int ln = RCV_BUFLEN-m_rend; |
if (ln > left) |
ln = left; |
if (ln > avail) |
ln = avail; |
memcpy(&buf[len-left], &m_rbuf[m_rend], ln); |
left -= ln; |
avail -= ln; |
m_rend = (m_rend + ln)&(RCV_BUFMASK); |
nr += ln; |
} |
|
/* |
if (nr > 0) |
printf("\tPopped %d items, buf[0] = %02x (%d - %d)\n", |
nr, buf[0], m_rend, m_rbeg); |
else |
printf("\tPopped nothing, %d - %d\n", m_rend, m_rbeg); |
*/ |
return nr; |
} |
|
bool USBI::poll(unsigned ms) { |
int avail = (m_rbeg-m_rend)&(RCV_BUFMASK); |
bool r = true; |
|
// printf("POLL request\n"); |
|
if ((avail < 2)&&((avail<1)||(m_rbuf[m_rend]&0x80)||(m_rbuf[m_rend]<0x10))) { |
raw_read(4,ms); |
avail = (m_rbeg-m_rend)&(RCV_BUFMASK); |
// printf("%d availabe\n", avail); |
|
char v = (m_rbuf[(m_rbeg-1)&(RCV_BUFMASK)]); |
while(((v&0x80)==0)&&((unsigned)v>=0x10)&&(avail < RCV_BUFMASK-32)) { |
raw_read(26,ms); |
avail = (m_rbeg-m_rend)&(RCV_BUFMASK); |
} |
if (avail < 1) |
r = false; |
else if ((avail==1)&&((m_rbuf[m_rend]&0x80)||(m_rbuf[m_rend]<0x10))) |
r = false; |
} |
|
// printf("USBI::poll() -> %s (%d avail)\n", (r)?"true":"false", avail); |
return r; |
} |
/trunk/sw/wbsettime.cpp
0,0 → 1,147
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbsettime.cpp |
// |
// Project: XuLA2 board |
// |
// Purpose: To give a user access, via a command line program, to set the |
// real time clock within the FPGA. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <strings.h> |
#include <ctype.h> |
#include <string.h> |
#include <signal.h> |
#include <assert.h> |
#include <time.h> |
|
#include "port.h" |
#include "llcomms.h" |
#include "regdefs.h" |
|
DEVBUS *m_fpga; |
void closeup(int v) { |
m_fpga->kill(); |
exit(0); |
} |
|
int main(int argc, char **argv) { |
DEVBUS::BUSW v; |
|
bool set_time = true, read_hack = false; |
|
FPGAOPEN(m_fpga); |
|
signal(SIGSTOP, closeup); |
signal(SIGHUP, closeup); |
|
|
time_t now, then; |
|
// We first wait for a second change, because we don't know how |
// much time this will take. |
DEVBUS::BUSW clockword = 0l, dateword = 0l; |
clockword = m_fpga->readio(R_CLOCK); |
|
now = time(NULL); |
while(time(NULL) == now) |
; |
|
if (set_time) { |
// Now, we have one second to set the time |
struct tm *tmp; |
int sleepv = 0; |
|
then = now+1; |
tmp = localtime(&then); |
clockword &= ~0x03fffff; |
|
if (tmp->tm_sec != 0) { |
// printf("THEN SECONDS = %d, ADDING %d\n", |
// tmp->tm_sec, 60-tmp->tm_sec); |
if (tmp->tm_sec < 58) |
sleepv = 59 - tmp->tm_sec; |
then += 60 - tmp->tm_sec; |
tmp = localtime(&then); |
// printf("Sleeping %d seconds (THEN->SEC = %d)\n", sleepv, tmp->tm_sec); |
} |
|
// printf("ORIGINAL : %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec); |
// Seconds |
clockword |= (((tmp->tm_sec)%10)&0x0f); |
clockword |= (((tmp->tm_sec)/10)&0x0f)<< 4; |
// Minutes |
clockword |= (((tmp->tm_min)%10)&0x0f)<< 8; |
clockword |= (((tmp->tm_min)/10)&0x0f)<<12; |
// Hours |
clockword |= (((tmp->tm_hour)%10)&0x0f)<<16; |
clockword |= (((tmp->tm_hour)/10)&0x0f)<<20; |
|
// Years |
dateword = 0x00000000; |
dateword |= (((tmp->tm_year+1900)/1000)&0x0f)<<28; |
dateword |=((((tmp->tm_year+1900)/100 )%10)&0x0f)<<24; |
dateword |=((((tmp->tm_year+1900)/10 )%10)&0x0f)<<20; |
dateword |=((((tmp->tm_year+1900) )%10)&0x0f)<<16; |
dateword |= (((tmp->tm_mon +1)/10)&0x0f)<<12; |
dateword |= (((tmp->tm_mon +1)%10)&0x0f)<< 8; |
dateword |= (((tmp->tm_mday )/10)&0x0f)<< 4; |
dateword |= (((tmp->tm_mday )%10)&0x0f); |
if (sleepv > 0) |
sleep(sleepv); |
|
while(time(NULL) < then) |
; |
m_fpga->writeio(R_CLOCK, clockword); |
|
printf("Time set to %06x\n", clockword & 0x03fffff); |
#ifdef R_DATE // If we have the date capability |
m_fpga->writeio(R_DATE, dateword); |
printf("Date set to %08x\n", dateword); |
printf("(Now reads %08x)\n", m_fpga->readio(R_DATE)); |
#endif // R_DATE |
|
now = then; |
} if (read_hack) { |
then = time(NULL) + 5; |
while(time(NULL) < then) |
; |
clockword = m_fpga->readio(R_CLOCK); |
printf("Hack : %08x\n", m_fpga->readio(R_TIMEHACK)); |
printf(" SUBS: %08x:%08x\n", m_fpga->readio(R_HACKHI), m_fpga->readio(R_HACKLO)); |
|
} |
|
if (m_fpga->poll()) |
printf("FPGA was interrupted\n"); |
delete m_fpga; |
} |
|
/trunk/sw/llcomms.cpp
0,0 → 1,148
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: llcomms.cpp |
// |
// Project: XuLA2 board |
// |
// Purpose: This is the C++ program on the command side that will interact |
// with a UART on an FPGA, both sending and receiving characters. |
// Any bus interaction will call routines from this lower level |
// library to accomplish the actual connection to and |
// transmission to/from the board. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#include <sys/socket.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <fcntl.h> |
#include <termios.h> |
#include <netinet/in.h> |
#include <netdb.h> |
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <errno.h> |
#include <arpa/inet.h> |
#include <assert.h> |
#include <strings.h> |
#include <poll.h> |
#include <ctype.h> |
|
#include "llcomms.h" |
|
LLCOMMSI::LLCOMMSI(void) { |
m_fdw = -1; |
m_fdr = -1; |
m_total_nread = 0l; |
m_total_nwrit = 0l; |
} |
|
void LLCOMMSI::write(char *buf, int len) { |
int nw; |
nw = ::write(m_fdw, buf, len); |
m_total_nwrit += nw; |
assert(nw == len); |
} |
|
int LLCOMMSI::read(char *buf, int len) { |
int nr; |
nr = ::read(m_fdr, buf, len); |
m_total_nread += nr; |
return nr; |
} |
|
void LLCOMMSI::close(void) { |
if(m_fdw>=0) ::close(m_fdw); |
if((m_fdr>=0)&&(m_fdr != m_fdw)) ::close(m_fdr); |
m_fdw = m_fdr = -1; |
} |
|
bool LLCOMMSI::poll(unsigned ms) { |
struct pollfd fds; |
|
fds.fd = m_fdr; |
fds.events = POLLIN; |
::poll(&fds, 1, ms); |
|
if (fds.revents & POLLIN) { |
return true; |
} else return false; |
} |
|
TTYCOMMS::TTYCOMMS(const char *dev) { |
m_fdr = ::open(dev, O_RDWR | O_NONBLOCK); |
if (m_fdr < 0) { |
printf("\n Error : Could not open %s\n", dev); |
perror("O/S Err:"); |
exit(-1); |
} |
|
if (isatty(m_fdr)) { |
struct termios tb; |
tcgetattr(m_fdr, &tb); |
cfmakeraw(&tb); |
// tb.c_iflag &= (~(IXON|IXOFF)); |
tb.c_cflag &= (~(CRTSCTS)); |
tcsetattr(m_fdr, TCSANOW, &tb); |
tcflow(m_fdr, TCOON); |
} |
|
m_fdw = m_fdr; |
} |
|
NETCOMMS::NETCOMMS(const char *host, const int port) { |
struct sockaddr_in serv_addr; |
struct hostent *hp; |
|
if ((m_fdr = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
printf("\n Error : Could not create socket \n"); |
exit(-1); |
} |
|
memset(&serv_addr, '0', sizeof(serv_addr)); |
|
hp = gethostbyname(host); |
if (hp == NULL) { |
printf("Could not get host entity for %s\n", host); |
perror("O/S Err:"); |
exit(-1); |
} |
bcopy(hp->h_addr, &serv_addr.sin_addr.s_addr, hp->h_length); |
|
serv_addr.sin_family = AF_INET; |
serv_addr.sin_port = htons(port); |
|
if (connect(m_fdr,(struct sockaddr *)&serv_addr, sizeof(serv_addr))< 0){ |
perror("Connect Failed Err"); |
exit(-1); |
} |
|
m_fdw = m_fdr; |
} |
|
/trunk/sw/usbi.h
0,0 → 1,53
#ifndef USBI_H |
#define USBI_H |
|
#include <libusb.h> |
|
#define VENDOR_ID 0x04d8 |
#define PRODUCT_ID 0x0ff8c |
#define XESS_INTERFACE 0 |
#define XESS_ENDPOINT_OUT 0x01 |
#define XESS_ENDPOINT_IN 0x81 |
#define XESS_ENDPOINT_IN 0x81 |
// |
#define JTAG_CMD 0x4f |
#define GET_TDO_MASK 0x01 |
#define PUT_TMS_MASK 0x02 |
#define TMS_VAL_MASK 0x04 |
#define PUT_TDI_MASK 0x08 |
#define TDI_VAL_MASK 0x10 |
// |
// #define USER1_INSTR 0x02 // a SIX bit two |
#define USB_PKTLEN 32 |
#define RCV_BUFLEN 512 |
#define RCV_BUFMASK (RCV_BUFLEN-1) |
|
#include "llcomms.h" |
|
class USBI : public LLCOMMSI { // USB Interface |
private: |
char m_rbuf[RCV_BUFLEN]; |
char m_txbuf[2*USB_PKTLEN], m_rxbuf[2*USB_PKTLEN]; |
int m_rbeg, m_rend; |
|
libusb_context *m_usb_context; |
libusb_device **m_usb_dev_list; |
libusb_device_handle *m_xula_usb_device; |
|
virtual int pop_fifo(char *buf, int len); |
virtual void push_fifo(char *buf, int len); |
virtual void raw_read(int len, int timeout_ms); |
virtual void flush_read(void); |
|
public: |
USBI(void); |
|
virtual void close(void); |
virtual int read(char *buf, int len); |
virtual int read(char *buf, int len, int timeout_ms); |
virtual void write(char *buf, int len); |
virtual bool poll(unsigned ms); |
}; |
|
#endif // USBI_H |
|
/trunk/sw/ramscope.cpp
0,0 → 1,188
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: ramscope.cpp |
// |
// Project: XuLA2 board |
// |
// Purpose: To read out, and decompose, the results of the wishbone scope |
// as applied to the ICAPE2 interaction. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <strings.h> |
#include <ctype.h> |
#include <string.h> |
#include <signal.h> |
#include <assert.h> |
|
#include "usbi.h" |
#include "port.h" |
#include "llcomms.h" |
#include "regdefs.h" |
|
#define WBSCOPE R_RAMSCOPE |
#define WBSCOPEDATA R_RAMSCOPED |
|
FPGA *m_fpga; |
void closeup(int v) { |
m_fpga->kill(); |
exit(0); |
} |
|
unsigned brev(const unsigned v) { |
unsigned int r, a; |
a = v; |
r = 0; |
for(int i=0; i<8; i++) { |
r <<= 1; |
r |= (a&1); |
a >>= 1; |
} return r; |
} |
|
unsigned wrev(const unsigned v) { |
unsigned r = brev(v&0x0ff); |
r |= brev((v>>8)&0x0ff)<<8; |
return r; |
} |
|
int main(int argc, char **argv) { |
bool skipping = false; |
unsigned v, lgln, scoplen; |
DEVBUS::BUSW *buf; |
|
FPGAOPEN(m_fpga); |
|
signal(SIGSTOP, closeup); |
signal(SIGHUP, closeup); |
|
printf("Attempting to read address %08x\n", WBSCOPE); |
v = m_fpga->readio(WBSCOPE); |
if (0x60000000 != (v & 0x60000000)) { |
printf("Scope is not yet ready:\n"); |
printf("\tRESET:\t\t%s\n", (v&0x80000000)?"Ongoing":"Complete"); |
printf("\tSTOPPED:\t%s\n", (v&0x40000000)?"Yes":"No"); |
printf("\tTRIGGERED:\t%s\n", (v&0x20000000)?"Yes":"No"); |
printf("\tPRIMED:\t\t%s\n", (v&0x10000000)?"Yes":"No"); |
printf("\tMANUAL:\t\t%s\n", (v&0x08000000)?"Yes":"No"); |
printf("\tDISABLED:\t%s\n", (v&0x04000000)?"Yes":"No"); |
printf("\tZERO:\t\t%s\n", (v&0x02000000)?"Yes":"No"); |
exit(0); |
} else printf("SCOPD = %08x\n", v); |
|
lgln = (v>>20) & 0x1f; |
scoplen = (1<<lgln); |
|
buf = new DEVBUS::BUSW[scoplen]; |
|
if (false) { |
printf("Attempting vector read\n"); |
m_fpga->readz(WBSCOPEDATA, scoplen, buf); |
|
printf("Vector read complete\n"); |
} else { |
for(unsigned int i=0; i<scoplen; i++) |
buf[i] = m_fpga->readio(WBSCOPEDATA); |
} |
|
for(unsigned int i=0; i<scoplen; i++) { |
int cmd; |
|
if ((i>0)&&(buf[i] == buf[i-1])&& |
(i<scoplen-1)&&(buf[i] == buf[i+1])) { |
if (!skipping) |
printf(" ****\n"); |
skipping = true; |
continue; |
} skipping = false; |
printf("%6d %08x:", i, buf[i]); |
printf("S(%x) ", (buf[i]>>27)&0x0f); |
if (buf[i] & 0x40000000) |
printf("W "); else printf("R "); |
printf("WB(%s%s%s%s%s", |
(buf[i]&0x80000000)?"CYC":" ", |
(buf[i]&0x40000000)?"STB":" ", |
(buf[i]&0x20000000)?"WE":" ", |
(buf[i]&0x10000000)?"ACK":" ", |
(buf[i]&0x08000000)?"STL":" "); |
// |
if ((buf[i]&0xc8000000)==0xc0000000) |
printf("*"); |
else |
printf(" "); |
printf(")-SD[%d%d%d%d,%d]", |
(buf[i]&0x04000000)?1:0, |
(buf[i]&0x02000000)?1:0, |
(buf[i]&0x01000000)?1:0, |
(buf[i]&0x00800000)?1:0, |
(buf[i]&0x00600000)>>21); |
cmd = (buf[i] >> 23)&0x0f; |
if (buf[i]&0x00100000) |
printf("<- "); |
else |
printf("-> "); |
printf("%s", (buf[i]&0x00080000)?"P":" "); // Pending |
printf("@%3x,", (buf[i]>>8)&0x07ff); |
/* |
printf(",%s%s%s%s%s", |
(buf[i]&0x080)?"R":"-", |
(buf[i]&0x040)?"P":".", |
(buf[i]&0x020)?"P":".", |
(buf[i]&0x010)?"P":".", |
(buf[i]&0x008)?"P":"."); |
printf("/%x%x%x", |
(buf[i]>>2)&0x01, |
(buf[i]>>1)&0x01, |
(buf[i]&0x01)); |
*/ |
printf("/%02x ", buf[i] & 0x0ff); |
|
if (cmd & 0x8) |
printf("(inactive)"); |
switch(cmd) { |
case 0x01: printf("Refresh"); break; |
case 0x02: printf("Precharge"); break; |
case 0x03: printf("Activate"); break; |
case 0x04: printf("Write"); break; |
case 0x05: printf("Read"); break; |
case 0x07: printf("NoOp"); break; |
default: break; |
} |
|
printf("\n"); |
} |
|
if (m_fpga->poll()) { |
printf("FPGA was interrupted\n"); |
m_fpga->clear(); |
m_fpga->writeio(R_ICONTROL, SCOPEN); |
} |
delete m_fpga; |
} |
|
/trunk/sw/llcomms.h
0,0 → 1,67
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: llcomms.h |
// |
// Project: XuLA2 board |
// |
// Purpose: This is the C++ program on the command side that will interact |
// with a UART on an FPGA, both sending and receiving characters. |
// Any bus interaction will call routines from this lower level |
// library to accomplish the actual connection to and |
// transmission to/from the board. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#ifndef LLCOMMS_H |
#define LLCOMMS_H |
|
class LLCOMMSI { |
protected: |
int m_fdw, m_fdr; |
LLCOMMSI(void); |
public: |
unsigned long m_total_nread, m_total_nwrit; |
|
virtual ~LLCOMMSI(void) { close(); } |
virtual void kill(void) { this->close(); }; |
virtual void close(void); |
virtual void write(char *buf, int len); |
virtual int read(char *buf, int len); |
virtual bool poll(unsigned ms); |
}; |
|
class TTYCOMMS : public LLCOMMSI { |
public: |
TTYCOMMS(const char *dev); |
}; |
|
class NETCOMMS : public LLCOMMSI { |
public: |
NETCOMMS(const char *dev, const int port); |
}; |
|
#endif |
/trunk/sw/regdefs.cpp
0,0 → 1,183
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: regdefs.cpp |
// |
// Project: XuLA2 board |
// |
// Purpose: To give human readable names to the various registers available |
// internal to the processor on the wishbone bus. This file is |
// primarily used for name to number translation within wbregs.cpp. |
// All names for a given register are equivalent, save only that the |
// register will always be identified by its first name in any output. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <strings.h> |
#include <ctype.h> |
#include "regdefs.h" |
|
const REGNAME raw_bregs[] = { |
// { R_RESET, "RESET" }, |
// { R_STATUS, "STATUS" }, |
// { R_CONTROL, "CONTROL" }, |
{ R_VERSION, "VERSION" }, |
{ R_ICONTROL, "ICONTROL" }, |
{ R_ICONTROL, "INT" }, |
{ R_ICONTROL, "PIC" }, |
{ R_ICONTROL, "INTC" }, |
{ R_BUSERR, "BUSERR" }, |
{ R_BUSERR, "BUS" }, |
{ R_DATE, "DATE" }, |
{ R_GPIO, "GPIO" }, |
{ R_UART_CTRL, "UARTCTRL" }, |
{ R_UART_CTRL, "UART" }, |
{ R_PWM_INTERVAL,"PWMI" }, |
{ R_PWM_DATA, "PWMDATA" }, |
{ R_PWM_DATA, "PWM" }, |
{ R_UART_RX, "UART-RX" }, |
{ R_UART_RX, "RX" }, |
{ R_UART_TX, "UART-TX" }, |
{ R_UART_TX, "TX" }, |
// |
{ R_SPIF_EREG, "SPIFEREG" }, |
{ R_SPIF_EREG, "SPIFE" }, |
{ R_SPIF_CREG, "SPIFCONF" }, |
{ R_SPIF_CREG, "SPIFC" }, |
{ R_SPIF_SREG, "SPIFSTAT" }, |
{ R_SPIF_SREG, "SPIFS" }, |
{ R_SPIF_IDREG, "SPIFID" }, |
{ R_SPIF_IDREG, "SPIFI" }, |
// |
{ R_CLOCK, "CLOCK" }, |
{ R_CLOCK, "TIME" }, |
{ R_TIMER, "TIMER" }, |
{ R_STOPWATCH, "STOPWACH" }, |
{ R_STOPWATCH, "STOPWATCH" }, |
{ R_CKALARM, "CKALARM" }, |
{ R_CKALARM, "ALARM" }, |
{ R_CKSPEED, "CKSPEED" }, |
{ R_TIMEHACK, "TIMEHACK" }, |
{ R_TIMEHACK, "HACK" }, |
{ R_HACKHI, "HACKHI" }, |
{ R_HACKLO, "HACKLO" }, |
{ R_TIMEHACK, "HACK" }, |
// Scopes are defined and come and go. Be aware, therefore, not all |
// of these scopes may be defined at the same time. |
{ R_QSCOPE, "SCOPE" }, |
{ R_QSCOPE, "SCOP" }, |
{ R_QSCOPED, "SCOPDATA" }, |
{ R_QSCOPED, "SCDATA" }, |
{ R_CFGSCOPE, "CFGSCOPE" }, |
{ R_CFGSCOPE, "CFGSCOP" }, |
{ R_CFGSCOPED, "CFGSCOPD" }, |
{ R_CPUSCOPE, "CPUSCOPE" }, |
{ R_CPUSCOPE, "CPUSCOP" }, |
{ R_CPUSCOPED, "CPUSCOPD" }, |
{ R_RAMSCOPE, "MEMSCOPE" }, |
{ R_RAMSCOPE, "MEMSCOP" }, |
{ R_RAMSCOPED, "MEMSCOPD" }, |
{ R_RAMSCOPE, "RAMSCOPE" }, |
{ R_RAMSCOPE, "RAMSCOP" }, |
{ R_RAMSCOPED, "RAMSCOPD" }, |
// |
// For working with the ICAPE interface ... if I can ever get a |
// testing environment suitable to prove that it works. |
// |
{ R_CFG_CRC, "FPGACRC" }, |
{ R_CFG_FAR_MAJ, "FPGAFARH" }, |
{ R_CFG_FAR_MIN, "FPGAFARL" }, |
{ R_CFG_FDRI, "FPGAFDRI" }, |
{ R_CFG_FDRO, "FPGAFDRO" }, |
{ R_CFG_CMD, "FPGACMD" }, |
{ R_CFG_CTL, "FPGACTL" }, |
{ R_CFG_MASK, "FPGAMASK" }, |
{ R_CFG_STAT, "FPGASTAT" }, |
{ R_CFG_LOUT, "FPGALOUT" }, |
{ R_CFG_COR1, "FPGACOR1" }, |
{ R_CFG_COR2, "FPGACOR2" }, |
{ R_CFG_PWRDN, "FPGAPWRDN" }, |
{ R_CFG_FLR, "FPGAFLR" }, |
{ R_CFG_IDCODE, "FPGAIDCODE" }, |
{ R_CFG_CWDT, "FPGACWDT" }, |
{ R_CFG_HCOPT, "FPGAHCOPT" }, |
{ R_CFG_CSBO, "FPGACSBO" }, |
{ R_CFG_GEN1, "FPGAGEN1" }, |
{ R_CFG_GEN2, "FPGAGEN2" }, |
{ R_CFG_GEN3, "FPGAGEN3" }, |
{ R_CFG_GEN4, "FPGAGEN4" }, |
{ R_CFG_GEN5, "FPGAGEN5" }, |
{ R_CFG_MODE, "FPGAMODE" }, |
{ R_CFG_GWE, "FPGAGWE" }, |
{ R_CFG_GTS, "FPGAGTS" }, |
{ R_CFG_MFWR, "FPGAMFWR" }, |
{ R_CFG_CCLK, "FPGACCLK" }, |
{ R_CFG_SEU, "FPGASEU" }, |
{ R_CFG_EXP, "FPGAEXP" }, |
{ R_CFG_RDBK, "FPGARDBK" }, |
{ R_CFG_BOOTSTS, "BOOTSTS" }, |
{ R_CFG_EYE, "FPGAEYE" }, |
{ R_CFG_CBC, "FPGACBC" }, |
// |
// |
{ R_ZIPCTRL, "ZIPCTRL" }, |
{ R_ZIPCTRL, "ZIPC" }, |
{ R_ZIPCTRL, "CPU" }, |
{ R_ZIPCTRL, "CPUC" }, |
{ R_ZIPDATA, "ZIPDATA" }, |
{ R_ZIPDATA, "ZIPD" }, |
{ R_ZIPDATA, "CPUD" }, |
// |
{ RAMBASE, "MEM" }, |
{ SPIFLASH, "FLASH" }, |
{ SDRAMBASE, "SDRAM" }, |
{ SDRAMBASE, "RAM" } |
}; |
|
#define RAW_NREGS (sizeof(raw_bregs)/sizeof(bregs[0])) |
|
const REGNAME *bregs = raw_bregs; |
const int NREGS = RAW_NREGS; |
|
unsigned addrdecode(const char *v) { |
if (isalpha(v[0])) { |
for(int i=0; i<NREGS; i++) |
if (strcasecmp(v, bregs[i].m_name)==0) |
return bregs[i].m_addr; |
fprintf(stderr, "Unknown register: %s\n", v); |
exit(-2); |
} else |
return strtoul(v, NULL, 0); |
} |
|
const char *addrname(const unsigned v) { |
for(int i=0; i<NREGS; i++) |
if (bregs[i].m_addr == v) |
return bregs[i].m_name; |
return NULL; |
} |
|
/trunk/sw/zipdbg.cpp
0,0 → 1,500
/////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: zipdbg.cpp |
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core |
// |
// Purpose: |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
// |
/////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
/////////////////////////////////////////////////////////////////////////////// |
// |
// |
#include <stdlib.h> |
#include <signal.h> |
#include <time.h> |
#include <unistd.h> |
|
#include <ctype.h> |
#include <ncurses.h> |
|
#include "zopcodes.h" |
#include "zparser.h" |
#include "devbus.h" |
#include "regdefs.h" |
|
#include "usbi.h" |
#include "port.h" |
|
#define CMD_REG 0 |
#define CMD_DATA 1 |
#define CMD_HALT (1<<10) |
#define CMD_STALL (1<<9) |
#define CMD_STEP (1<<8) |
#define CMD_INT (1<<7) |
#define CMD_RESET (1<<6) |
|
#define KEY_ESCAPE 27 |
#define KEY_RETURN 10 |
#define CTRL(X) ((X)&0x01f) |
|
#define MAXERR 1000 // 1k cycles |
|
bool gbl_err = false; |
|
// No particular "parameters" need definition or redefinition here. |
class ZIPPY : public DEVBUS { |
typedef DEVBUS::BUSW BUSW; |
DEVBUS *m_fpga; |
int m_cursor; |
public: |
ZIPPY(DEVBUS *fpga) : m_fpga(fpga), m_cursor(0) {} |
|
void kill(void) { m_fpga->kill(); } |
void close(void) { m_fpga->close(); } |
void writeio(const BUSW a, const BUSW v) { m_fpga->writeio(a, v); } |
BUSW readio(const BUSW a) { return m_fpga->readio(a); } |
void readi(const BUSW a, const int len, BUSW *buf) { |
return m_fpga->readi(a, len, buf); } |
void readz(const BUSW a, const int len, BUSW *buf) { |
return m_fpga->readz(a, len, buf); } |
void writei(const BUSW a, const int len, const BUSW *buf) { |
return m_fpga->writei(a, len, buf); } |
void writez(const BUSW a, const int len, const BUSW *buf) { |
return m_fpga->writez(a, len, buf); } |
bool poll(void) { return m_fpga->poll(); } |
void usleep(unsigned ms) { m_fpga->usleep(ms); } |
void wait(void) { m_fpga->wait(); } |
bool bus_err(void) const { return m_fpga->bus_err(); } |
void reset_err(void) { m_fpga->reset_err(); } |
void clear(void) { m_fpga->clear(); } |
|
void reset(void) { writeio(R_ZIPCTRL, CPU_RESET|CPU_HALT); } |
void step(void) { writeio(R_ZIPCTRL, CPU_STEP); } |
void go(void) { writeio(R_ZIPCTRL, CPU_GO); } |
void halt(void) { writeio(R_ZIPCTRL, CPU_HALT); } |
bool stalled(void) { return ((readio(R_ZIPCTRL)&CPU_STALL)==0); } |
|
void showval(int y, int x, const char *lbl, unsigned int v, bool c) { |
if (c) |
mvprintw(y,x, ">%s> 0x%08x<", lbl, v); |
else |
mvprintw(y,x, " %s: 0x%08x ", lbl, v); |
} |
|
void dispreg(int y, int x, const char *n, unsigned int v, bool c) { |
// 4,4,8,1 = 17 of 20, +2 = 18 |
if (c) |
mvprintw(y, x, ">%s> 0x%08x<", n, v); |
else |
mvprintw(y, x, " %s: 0x%08x ", n, v); |
} |
|
void showins(int y, const char *lbl, |
const int gie, const unsigned int pc) { |
char line[80]; |
unsigned int v; |
|
mvprintw(y, 0, "%s: 0x%08x", lbl, pc); |
|
if (gie) attroff(A_BOLD); |
else attron(A_BOLD); |
|
line[0] = '\0'; |
try { |
v= readio(pc); |
zipi_to_string(v, line); |
printw(" 0x%08x", v); |
printw(" %-24s", &line[1]); |
} catch(BUSERR b) { |
printw(" 0x%08x %-24s", b.addr, "(Bus Error)"); |
} |
attroff(A_BOLD); |
} |
|
unsigned int cmd_read(unsigned int a) { |
int errcount = 0; |
|
if (gbl_err) |
return 0; |
|
writeio(R_ZIPCTRL, CMD_HALT|(a&0x3f)); |
while(((readio(R_ZIPCTRL) & CPU_STALL) == 0)&&(errcount < MAXERR)) |
errcount++; |
if (errcount < MAXERR) |
return readio(R_ZIPDATA); |
else { |
gbl_err = true; |
return 0; |
} |
} |
|
void cmd_write(unsigned int a, int v) { |
if (gbl_err) |
return; |
|
int errcount = 0; |
writeio(R_ZIPCTRL, CMD_HALT|(a&0x3f)); |
while(((readio(R_ZIPCTRL) & CPU_STALL) == 0)&&(errcount < MAXERR)) |
errcount++; |
if (errcount < MAXERR) |
writeio(R_ZIPDATA, (unsigned int)v); |
else |
gbl_err = true; |
} |
|
void read_state(void) { |
int ln= 0; |
bool gie; |
|
if (m_cursor < 0) |
m_cursor = 0; |
else if (m_cursor >= 44) |
m_cursor = 43; |
|
mvprintw(ln,0, "Peripherals"); |
mvprintw(ln,40,"%-40s", "CPU State: "); |
{ |
unsigned int v = readio(R_ZIPCTRL); |
mvprintw(ln,51, ""); |
if (v & 0x010000) |
printw("EXT-INT "); |
if ((v & 0x003000) == 0x03000) |
printw("Halted "); |
else if (v & 0x001000) |
printw("Sleeping "); |
else if (v & 0x002000) |
printw("Supervisor Mod "); |
if (v & 0x008000) |
printw("Break-Enabled "); |
if (v & 0x000080) |
printw("PIC Enabled "); |
} ln++; |
showval(ln, 0, "PIC ", cmd_read(32+ 0), (m_cursor==0)); |
showval(ln,20, "WDT ", cmd_read(32+ 1), (m_cursor==1)); |
showval(ln,40, "WBUS", cmd_read(32+ 2), (m_cursor==2)); |
showval(ln,60, "PIC2", cmd_read(32+ 3), (m_cursor==3)); |
ln++; |
showval(ln, 0, "TMRA", cmd_read(32+ 4), (m_cursor==4)); |
showval(ln,20, "TMRB", cmd_read(32+ 5), (m_cursor==5)); |
showval(ln,40, "TMRC", cmd_read(32+ 6), (m_cursor==6)); |
showval(ln,60, "JIF ", cmd_read(32+ 7), (m_cursor==7)); |
|
ln++; |
showval(ln, 0, "UTSK", cmd_read(32+12), (m_cursor==8)); |
showval(ln,20, "UMST", cmd_read(32+13), (m_cursor==9)); |
showval(ln,40, "UPST", cmd_read(32+14), (m_cursor==10)); |
showval(ln,60, "UICT", cmd_read(32+15), (m_cursor==11)); |
|
ln++; |
ln++; |
unsigned int cc = cmd_read(14); |
gie = (cc & 0x020); |
if (gie) |
attroff(A_BOLD); |
else |
attron(A_BOLD); |
mvprintw(ln, 0, "Supervisor Registers"); |
ln++; |
|
dispreg(ln, 0, "sR0 ", cmd_read(0), (m_cursor==12)); |
dispreg(ln,20, "sR1 ", cmd_read(1), (m_cursor==13)); |
dispreg(ln,40, "sR2 ", cmd_read(2), (m_cursor==14)); |
dispreg(ln,60, "sR3 ", cmd_read(3), (m_cursor==15)); ln++; |
|
dispreg(ln, 0, "sR4 ", cmd_read(4), (m_cursor==16)); |
dispreg(ln,20, "sR5 ", cmd_read(5), (m_cursor==17)); |
dispreg(ln,40, "sR6 ", cmd_read(6), (m_cursor==18)); |
dispreg(ln,60, "sR7 ", cmd_read(7), (m_cursor==19)); ln++; |
|
dispreg(ln, 0, "sR8 ", cmd_read( 8), (m_cursor==20)); |
dispreg(ln,20, "sR9 ", cmd_read( 9), (m_cursor==21)); |
dispreg(ln,40, "sR10", cmd_read(10), (m_cursor==22)); |
dispreg(ln,60, "sR11", cmd_read(11), (m_cursor==23)); ln++; |
|
dispreg(ln, 0, "sR12", cmd_read(12), (m_cursor==24)); |
dispreg(ln,20, "sSP ", cmd_read(13), (m_cursor==25)); |
|
mvprintw(ln,40, "%csCC :%s%s%s%s%s%s%s%s", |
(m_cursor==26)?'>':' ', |
(cc & 0x100)?"TP":" ", |
(cc & 0x040)?"ST":" ", |
(cc & 0x020)?"IE":" ", |
(cc & 0x010)?"SL":" ", |
(cc&8)?"V":" ", |
(cc&4)?"N":" ", |
(cc&2)?"C":" ", |
(cc&1)?"Z":" "); |
dispreg(ln,60, "sPC ", cmd_read(15), (m_cursor==27)); |
ln++; |
|
if (gie) |
attron(A_BOLD); |
else |
attroff(A_BOLD); |
mvprintw(ln, 0, "User Registers"); ln++; |
dispreg(ln, 0, "uR0 ", cmd_read(16), (m_cursor==28)); |
dispreg(ln,20, "uR1 ", cmd_read(17), (m_cursor==29)); |
dispreg(ln,40, "uR2 ", cmd_read(18), (m_cursor==30)); |
dispreg(ln,60, "uR3 ", cmd_read(19), (m_cursor==31)); ln++; |
|
dispreg(ln, 0, "uR4 ", cmd_read(20), (m_cursor==32)); |
dispreg(ln,20, "uR5 ", cmd_read(21), (m_cursor==33)); |
dispreg(ln,40, "uR6 ", cmd_read(22), (m_cursor==34)); |
dispreg(ln,60, "uR7 ", cmd_read(23), (m_cursor==35)); ln++; |
|
dispreg(ln, 0, "uR8 ", cmd_read(24), (m_cursor==36)); |
dispreg(ln,20, "uR9 ", cmd_read(25), (m_cursor==37)); |
dispreg(ln,40, "uR10", cmd_read(26), (m_cursor==38)); |
dispreg(ln,60, "uR11", cmd_read(27), (m_cursor==39)); ln++; |
|
dispreg(ln, 0, "uR12", cmd_read(28), (m_cursor==40)); |
dispreg(ln,20, "uSP ", cmd_read(29), (m_cursor==41)); |
cc = cmd_read(30); |
mvprintw(ln,40, "%cuCC :%s%s%s%s%s%s%s%s", |
(m_cursor == 42)?'>':' ', |
(cc&0x100)?"TP":" ", |
(cc&0x040)?"ST":" ", |
(cc&0x020)?"IE":" ", |
(cc&0x010)?"SL":" ", |
(cc&8)?"V":" ", |
(cc&4)?"N":" ", |
(cc&2)?"C":" ", |
(cc&1)?"Z":" "); |
dispreg(ln,60, "uPC ", cmd_read(31), (m_cursor==43)); |
|
attroff(A_BOLD); |
ln+=2; |
|
ln+=3; |
BUSW pc = cmd_read((gie)?31:15); |
showins(ln, "I ", gie, pc+2); ln++; |
showins(ln, "Dc", gie, pc+1); ln++; |
showins(ln, "Op", gie, pc ); ln++; |
showins(ln, "Al", gie, pc-1); ln++; |
} |
|
void cursor_up(void) { |
if (m_cursor > 3) |
m_cursor -= 4; |
} void cursor_down(void) { |
if (m_cursor < 40) |
m_cursor += 4; |
} void cursor_left(void) { |
if (m_cursor > 0) |
m_cursor--; |
else m_cursor = 43; |
} void cursor_right(void) { |
if (m_cursor < 43) |
m_cursor++; |
else m_cursor = 0; |
} |
|
int cursor(void) { return m_cursor; } |
}; |
|
FPGA *m_fpga; |
|
void get_value(ZIPPY *zip) { |
int wy, wx, ra; |
int c = zip->cursor(); |
|
wx = (c & 0x03) * 20 + 9 + 1; |
wy = (c >> 2); |
if (wy >= 3+4) |
wy++; |
if (wy > 3) |
wy += 2; |
wy++; |
|
if (c >= 12) |
ra = c - 12; |
else |
ra = c + 32; |
|
bool done = false; |
char str[16]; |
int pos = 0; str[pos] = '\0'; |
while(!done) { |
int chv = getch(); |
switch(chv) { |
case KEY_ESCAPE: |
pos = 0; str[pos] = '\0'; done = true; |
break; |
case KEY_RETURN: case KEY_ENTER: case KEY_UP: case KEY_DOWN: |
done = true; |
break; |
case KEY_LEFT: case KEY_BACKSPACE: |
if (pos > 0) pos--; |
break; |
case KEY_CLEAR: |
pos = 0; |
break; |
case '0': case ' ': str[pos++] = '0'; break; |
case '1': str[pos++] = '1'; break; |
case '2': str[pos++] = '2'; break; |
case '3': str[pos++] = '3'; break; |
case '4': str[pos++] = '4'; break; |
case '5': str[pos++] = '5'; break; |
case '6': str[pos++] = '6'; break; |
case '7': str[pos++] = '7'; break; |
case '8': str[pos++] = '8'; break; |
case '9': str[pos++] = '9'; break; |
case 'A': case 'a': str[pos++] = 'A'; break; |
case 'B': case 'b': str[pos++] = 'B'; break; |
case 'C': case 'c': str[pos++] = 'C'; break; |
case 'D': case 'd': str[pos++] = 'D'; break; |
case 'E': case 'e': str[pos++] = 'E'; break; |
case 'F': case 'f': str[pos++] = 'F'; break; |
} |
|
if (pos > 8) |
pos = 8; |
str[pos] = '\0'; |
|
attron(A_NORMAL | A_UNDERLINE); |
mvprintw(wy, wx, "%-8s", str); |
if (pos > 0) { |
attron(A_NORMAL | A_UNDERLINE | A_BLINK); |
mvprintw(wy, wx+pos-1, "%c", str[pos-1]); |
} |
attrset(A_NORMAL); |
} |
|
if (pos > 0) { |
int v; |
v = strtoul(str, NULL, 16); |
zip->cmd_write(ra, v); |
} |
} |
|
void on_sigint(int v) { |
endwin(); |
|
fprintf(stderr, "Interrupted!\n"); |
exit(-2); |
} |
|
int main(int argc, char **argv) { |
// FPGAOPEN(m_fpga); |
ZIPPY *zip; // |
|
int skp=0, port = FPGAPORT; |
bool use_usb = true; |
|
skp=1; |
for(int argn=0; argn<argc-skp; argn++) { |
if (argv[argn+skp][0] == '-') { |
if (argv[argn+skp][1] == 'u') |
use_usb = true; |
else if (argv[argn+skp][1] == 'p') { |
use_usb = false; |
if (isdigit(argv[argn+skp][2])) |
port = atoi(&argv[argn+skp][2]); |
} |
skp++; argn--; |
} else |
argv[argn] = argv[argn+skp]; |
} argc -= skp; |
|
if (use_usb) |
m_fpga = new FPGA(new USBI()); |
else |
m_fpga = new FPGA(new NETCOMMS(FPGAHOST, port)); |
zip = new ZIPPY(m_fpga); |
|
|
initscr(); |
raw(); |
noecho(); |
keypad(stdscr, true); |
|
signal(SIGINT, on_sigint); |
|
int chv; |
bool done = false; |
|
zip->halt(); |
for(int i=0; (i<5)&&(zip->stalled()); i++) |
; |
if (!zip->stalled()) |
zip->read_state(); |
while((!done)&&(!gbl_err)) { |
chv = getch(); |
switch(chv) { |
case 'g': case 'G': |
m_fpga->writeio(R_ZIPCTRL, CPU_GO); |
// We just released the CPU, so we're now done. |
done = true; |
break; |
case 'l': case 'L': case CTRL('L'): |
redrawwin(stdscr); |
break; |
case 'q': case 'Q': case CTRL('C'): |
case KEY_CANCEL: case KEY_CLOSE: case KEY_EXIT: |
case KEY_ESCAPE: |
done = true; |
break; |
case 'r': case 'R': |
zip->reset(); |
erase(); |
break; |
case 's': case 'S': |
zip->step(); |
zip->read_state(); |
break; |
case KEY_IC: case KEY_ENTER: |
get_value(zip); |
break; |
case KEY_UP: |
zip->cursor_up(); |
break; |
case KEY_DOWN: |
zip->cursor_down(); |
break; |
case KEY_LEFT: |
zip->cursor_left(); |
break; |
case KEY_RIGHT: |
zip->cursor_right(); |
break; |
case ERR: case KEY_CLEAR: |
default: |
; |
} |
|
if ((!done)&&(!gbl_err)) { |
if (zip->stalled()) |
erase(); |
} |
} |
|
endwin(); |
|
if (gbl_err) { |
printf("Killed on error: could not access bus!\n"); |
exit(-2); |
} |
} |
|
/trunk/sw/cpuscope.cpp
0,0 → 1,170
// |
// |
// Filename: cpuscope.cpp |
// |
// Project: FPGA library development (Basys-3 development board) |
// |
// Purpose: To read out, and decompose, the results of the wishbone scope |
// as applied to the ICAPE2 interaction. |
// |
// Creator: Dan Gisselquist |
// Gisselquist Tecnology, LLC |
// |
// Copyright: 2015 |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <strings.h> |
#include <ctype.h> |
#include <string.h> |
#include <signal.h> |
#include <assert.h> |
|
#include "usbi.h" |
#include "port.h" |
#include "llcomms.h" |
#include "regdefs.h" |
|
#define WBSCOPE R_CPUSCOPE |
#define WBSCOPEDATA R_CPUSCOPED |
|
#include "zopcodes.h" |
|
FPGA *m_fpga; |
void closeup(int v) { |
m_fpga->kill(); |
exit(0); |
} |
|
unsigned brev(const unsigned v) { |
unsigned int r, a; |
a = v; |
r = 0; |
for(int i=0; i<8; i++) { |
r <<= 1; |
r |= (a&1); |
a >>= 1; |
} return r; |
} |
|
unsigned wrev(const unsigned v) { |
unsigned r = brev(v&0x0ff); |
r |= brev((v>>8)&0x0ff)<<8; |
return r; |
} |
|
int main(int argc, char **argv) { |
FPGAOPEN(m_fpga); |
|
signal(SIGSTOP, closeup); |
signal(SIGHUP, closeup); |
|
unsigned v, lgln, scoplen; |
printf("Attempting to read address %08x\n", WBSCOPE); |
v = m_fpga->readio(WBSCOPE); |
if (0x60000000 != (v & 0x60000000)) { |
printf("Scope is not yet ready:\n"); |
printf("\tRESET:\t\t%s\n", (v&0x80000000)?"Ongoing":"Complete"); |
printf("\tSTOPPED:\t%s\n", (v&0x40000000)?"Yes":"No"); |
printf("\tTRIGGERED:\t%s\n", (v&0x20000000)?"Yes":"No"); |
printf("\tPRIMED:\t\t%s\n", (v&0x10000000)?"Yes":"No"); |
printf("\tMANUAL:\t\t%s\n", (v&0x08000000)?"Yes":"No"); |
printf("\tDISABLED:\t%s\n", (v&0x04000000)?"Yes":"No"); |
printf("\tZERO:\t\t%s\n", (v&0x02000000)?"Yes":"No"); |
exit(0); |
} else printf("SCOPD = %08x\n", v); |
|
lgln = (v>>20) & 0x1f; |
scoplen = (1<<lgln); |
|
DEVBUS::BUSW *buf; |
buf = new DEVBUS::BUSW[scoplen]; |
|
if (false) { |
printf("Attempting vector read\n"); |
m_fpga->readz(WBSCOPEDATA, scoplen, buf); |
|
printf("Vector read complete\n"); |
} else { |
for(unsigned int i=0; i<scoplen; i++) |
buf[i] = m_fpga->readio(WBSCOPEDATA); |
} |
|
for(unsigned int i=0; i<scoplen; i++) { |
char sbuf[64]; |
|
if ((i>0)&&(buf[i] == buf[i-1])&& |
(i<scoplen-1)&&(buf[i] == buf[i+1])) |
continue; |
printf("%6d %08x:", i, buf[i]); |
|
unsigned addr = (buf[i]>>24)&0x0ff; |
zipi_to_string(m_fpga->readio(0x02000+addr),sbuf); |
printf(" %2x %-24s", (buf[i]>>24)&0x0ff, sbuf); |
printf(" %s%s%s%s%s %s%s%s", |
((buf[i]>>23)&1)?"P":" ", |
((buf[i]>>22)&1)?"D":" ", |
((buf[i]>>21)&1)?"O":" ", |
((buf[i]>>20)&1)?"A":" ", |
((buf[i]>>19)&1)?"M":" ", |
((buf[i]>>18)&1)?"o":" ", |
((buf[i]>>17)&1)?"a":" ", |
((buf[i]>>16)&1)?"m":" "); |
printf(" A=%02x ", (buf[i]>>8)&0x0ff); |
printf(" %s%02x ", |
(((buf[i]>>16)&3)!=0)?"W->":"(w)", |
(buf[i]&0x0ff)); |
/* |
printf("%s", ((buf[i]>>31)&1)?"OpV":" "); |
printf("%s", ((buf[i]>>30)&1)?"opA":" "); |
printf("%s", ((buf[i]>>29)&1)?"AlV":" "); |
printf("%s", ((buf[i]>>28)&1)?"AlW":" "); |
printf("%s", ((buf[i]>>27)&1)?"opM":" "); |
printf("%s", ((buf[i]>>26)&1)?"MmV":" "); |
if (true) { |
int op = (buf[i]>>22)&0x0f; |
switch(op) { |
case 0: printf("CMP "); break; |
case 1: printf("TST "); break; |
case 2: printf("MOV "); break; |
case 3: printf("LDI "); break; |
case 4: printf("AUX "); break; |
case 5: printf("ROL "); break; |
case 6: printf("LOD "); break; |
case 7: printf("STO "); break; |
case 8: printf("SUB "); break; |
case 9: printf("AND "); break; |
case 10: printf("ADD "); break; |
case 11: printf(" OR "); break; |
case 12: printf("XOR "); break; |
case 13: printf("LSL "); break; |
case 14: printf("ASR "); break; |
case 15: printf("LSR "); break; |
default: printf("ILL "); break; |
} |
} else |
printf("%x", (buf[i]>>22)&0x0f); |
printf(" %s", ((buf[i]>>21)&1)?"W":" "); |
if ((buf[i]>>21)&1) |
printf("[%X]", ((buf[i]>>17)&0x0f)); |
else |
printf("(%x)", ((buf[i]>>17)&0x0f)); |
printf("D[%X]", ((buf[i]>>13)&0x0f)); |
printf(" r_opA=..%02x", (buf[i]>>7)&0x3f); |
printf(" opA=..%02x", (buf[i]>>1)&0x3f); |
printf(" ALU=..%d", buf[i]&1); |
*/ |
|
printf("\n"); |
} |
|
if (m_fpga->poll()) { |
printf("FPGA was interrupted\n"); |
m_fpga->clear(); |
m_fpga->writeio(R_ICONTROL, SCOPEN); |
} |
delete m_fpga; |
} |
|
/trunk/sw/dumpflash.cpp
0,0 → 1,107
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: dumpflash.cpp |
// |
// Project: XuLA2 board |
// |
// Purpose: Read/Empty the entire contents of the flash memory to a file. |
// The flash is unchanged by this process. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <strings.h> |
#include <ctype.h> |
#include <string.h> |
#include <signal.h> |
#include <assert.h> |
|
#include "port.h" |
#include "regdefs.h" |
|
FPGA *m_fpga; |
void closeup(int v) { |
m_fpga->kill(); |
exit(0); |
} |
|
// #define DUMPMEM RAMBASE |
// #define DUMPWORDS MEMWORDS |
|
#define DUMPMEM SPIFLASH |
#define DUMPWORDS FLASHWORDS // 1MB Flash |
|
int main(int argc, char **argv) { |
FILE *fp; |
const int BUFLN = MEMWORDS; // 1MB Flash |
FPGA::BUSW *buf = new FPGA::BUSW[BUFLN]; |
|
FPGAOPEN(m_fpga); |
fprintf(stderr, "Before starting, nread = %ld\n", |
m_fpga->m_total_nread); |
|
// Start with testing the version: |
printf("VERSION: %08x\n", m_fpga->readio(R_VERSION)); |
|
// SPI flash testing |
// Enable the faster (vector) reads |
bool vector_read = false; |
unsigned sz; |
|
if (vector_read) { |
m_fpga->readi(DUMPMEM, BUFLN, buf); |
} else { |
for(int i=0; i<BUFLN; i++) { |
buf[i] = m_fpga->readio(DUMPMEM+i); |
// if (0 == (i&0x0ff)) |
printf("i = %02x / %04x, addr = i + %04x = %08x\n", i, BUFLN, DUMPMEM, i+DUMPMEM); |
} |
} |
printf("\nREAD-COMPLETE\n"); |
|
// Now, let's find the end |
sz = BUFLN-1; |
while((sz>0)&&(buf[sz] == 0xffffffff)) |
sz--; |
sz+=1; |
printf("The size of the buffer is 0x%06x or %d words\n", sz, sz); |
|
fp = fopen("spiftest.bin","w"); |
fwrite(buf, sizeof(buf[0]), sz, fp); |
fclose(fp); |
|
printf("The read was accomplished in %ld bytes over the UART\n", |
m_fpga->m_total_nread); |
|
if (m_fpga->poll()) |
printf("FPGA was interrupted\n"); |
delete m_fpga; |
} |
|
|
/trunk/sw/regdefs.h
0,0 → 1,197
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: regdefs.h |
// |
// Project: XuLA2 board |
// |
// Purpose: |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#ifndef REGDEFS_H |
#define REGDEFS_H |
|
// #define R_RESET 0x00000100 |
// #define R_STATUS 0x00000101 |
// #define R_CONTROL 0x00000101 |
#define R_VERSION 0x00000102 |
#define R_ICONTROL 0x00000103 |
#define R_BUSERR 0x00000104 |
#define R_DATE 0x00000105 |
#define R_GPIO 0x00000106 |
#define R_UART_CTRL 0x00000107 |
#define R_PWM_INTERVAL 0x00000108 |
#define R_PWM_DATA 0x00000109 |
#define R_UART_RX 0x0000010a |
#define R_UART_TX 0x0000010b |
#define R_SPIF_EREG 0x0000010c |
#define R_SPIF_CREG 0x0000010d |
#define R_SPIF_SREG 0x0000010e |
#define R_SPIF_IDREG 0x0000010f |
#define R_CLOCK 0x00000110 |
#define R_TIMER 0x00000111 |
#define R_STOPWATCH 0x00000112 |
#define R_CKALARM 0x00000113 |
#define R_CKSPEED 0x00000114 |
#define R_TIMEHACK 0x00000115 |
#define R_HACKHI 0x00000116 |
#define R_HACKLO 0x00000117 |
|
// GPS registers |
// 0x00000114 |
// 0x00000115 |
// 0x00000116 |
// 0x00000117 |
|
// WB Scope registers wb_addr[31:3]==30'h23, i.e. 46, 8c, 118 |
#define R_QSCOPE 0x00000118 // Quad SPI scope ctrl |
#define R_QSCOPED 0x00000119 // and data |
#define R_CFGSCOPE 0x0000011a // Configuration/ICAPE scope control |
#define R_CFGSCOPED 0x0000011b // and data |
#define R_RAMSCOPE 0x0000011c // SDRAM scope control |
#define R_RAMSCOPED 0x0000011d // and data |
#define R_CPUSCOPE 0x0000011e // SDRAM scope control |
#define R_CPUSCOPED 0x0000011f // and data |
// |
// SD Card |
// 0x00000120 |
// 0x00000121 |
// 0x00000122 |
// 0x00000123 |
// |
// Unused/open |
// #define SOMETHING 0x00000124 -- 0x013f (28 spaces) |
// |
// FPGA CONFIG/ICAP REGISTERS |
#define R_CFG_CRC 0x00000140 |
#define R_CFG_FAR_MAJ 0x00000141 |
#define R_CFG_FAR_MIN 0x00000142 |
#define R_CFG_FDRI 0x00000143 |
#define R_CFG_FDRO 0x00000144 |
#define R_CFG_CMD 0x00000145 |
#define R_CFG_CTL 0x00000146 |
#define R_CFG_MASK 0x00000147 |
#define R_CFG_STAT 0x00000148 |
#define R_CFG_LOUT 0x00000149 |
#define R_CFG_COR1 0x0000014a |
#define R_CFG_COR2 0x0000014b |
#define R_CFG_PWRDN 0x0000014c |
#define R_CFG_FLR 0x0000014d |
#define R_CFG_IDCODE 0x0000014e |
#define R_CFG_CWDT 0x0000014f |
#define R_CFG_HCOPT 0x00000150 |
#define R_CFG_CSBO 0x00000152 |
#define R_CFG_GEN1 0x00000153 |
#define R_CFG_GEN2 0x00000154 |
#define R_CFG_GEN3 0x00000155 |
#define R_CFG_GEN4 0x00000156 |
#define R_CFG_GEN5 0x00000157 |
#define R_CFG_MODE 0x00000158 |
#define R_CFG_GWE 0x00000159 |
#define R_CFG_GTS 0x0000015a |
#define R_CFG_MFWR 0x0000015b |
#define R_CFG_CCLK 0x0000015c |
#define R_CFG_SEU 0x0000015d |
#define R_CFG_EXP 0x0000015e |
#define R_CFG_RDBK 0x0000015f |
#define R_CFG_BOOTSTS 0x00000160 |
#define R_CFG_EYE 0x00000161 |
#define R_CFG_CBC 0x00000162 |
|
// RAM memory space |
#define RAMBASE 0x00002000 |
#define MEMWORDS (1<<13) |
// Flash memory space |
#define SPIFLASH 0x00040000 |
#define FLASHWORDS (1<<18) |
// SDRAM memory space |
#define SDRAMBASE 0x00800000 |
// Zip CPU Control and Debug registers |
#define R_ZIPCTRL 0x01000000 |
#define R_ZIPDATA 0x01100001 |
|
|
// Interrupt control constants |
#define GIE 0x80000000 // Enable all interrupts |
#define ISPIF_EN 0x80040004 // Enable all, enable SPI, clear SPI |
#define ISPIF_DIS 0x00040000 // Disable all, disable SPI |
#define ISPIF_CLR 0x00000004 // Clear SPI interrupt |
#define SCOPEN 0x80080008 // Enable WBSCOPE interrupts |
|
// Flash control constants |
#define ERASEFLAG 0x80000000 |
#define DISABLEWP 0x10000000 |
|
#define SZPAGE 64 |
#define PGLEN 64 |
#define NPAGES 32 |
#define SECTORSZ (NPAGES * SZPAGE) |
#define NSECTORS 256 |
#define SECTOROF(A) (A & (-1<<10)) |
#define PAGEOF(A) (A & (-1<<6)) |
|
#define RAMLEN 0x02000 |
|
// ZIP Control sequences |
#define CPU_GO 0x0000 |
#define CPU_RESET 0x0040 |
#define CPU_INT 0x0080 |
#define CPU_STEP 0x0100 |
#define CPU_STALL 0x0200 |
#define CPU_HALT 0x0400 |
#define CPU_CLRCACHE 0x0800 |
#define CPU_sR0 (0x0000|CPU_HALT) |
#define CPU_sSP (0x000d|CPU_HALT) |
#define CPU_sCC (0x000e|CPU_HALT) |
#define CPU_sPC (0x000f|CPU_HALT) |
#define CPU_uR0 (0x0010|CPU_HALT) |
#define CPU_uSP (0x001d|CPU_HALT) |
#define CPU_uCC (0x001e|CPU_HALT) |
#define CPU_uPC (0x001f|CPU_HALT) |
|
// Scop definition/sequences |
#define SCOPE_NO_RESET 0x80000000 |
#define SCOPE_TRIGGER (0x08000000|SCOPE_NO_RESET) |
#define SCOPE_DISABLE (0x04000000) |
|
typedef struct { |
unsigned m_addr; |
const char *m_name; |
} REGNAME; |
|
extern const REGNAME *bregs; |
extern const int NREGS; |
// #define NREGS (sizeof(bregs)/sizeof(bregs[0])) |
|
extern unsigned addrdecode(const char *v); |
extern const char *addrname(const unsigned v); |
|
#include "ttybus.h" |
// #include "portbus.h" |
|
typedef TTYBUS FPGA; |
|
#endif |
/trunk/sw/usbtst.cpp
0,0 → 1,244
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <string.h> |
#include <ctype.h> |
// #include <usb.h> |
|
#include <libusb.h> |
|
// /sys/bus/usb/devices/1-4/ is our device, as currently plugged in |
// |
// It supports |
// 1 configuration |
// 1 interface |
// and has a product string of... |
// "XuLA - XESS Micro Logic Array" |
// |
#define VENDOR_ID 0x04d8 |
#define PRODUCT_ID 0x0ff8c |
#define XESS_ENDPOINT_OUT 0x01 |
#define XESS_ENDPOINT_IN 0x81 |
// |
#define JTAG_CMD 0x4f |
#define GET_TDO_MASK 0x01 |
#define PUT_TMS_MASK 0x02 |
#define TMS_VAL_MASK 0x04 |
#define PUT_TDI_MASK 0x08 |
#define TDI_VAL_MASK 0x10 |
// |
#define USER1_INSTR 0x02 // a SIX bit two |
|
|
bool gbl_transfer_received = false; |
|
// libusbtransfer_cb_fn callback; |
extern "C" { |
void my_callback(libusb_transfer *tfr) { |
gbl_transfer_received = true; |
|
printf("Callback received!\n"); |
} |
} |
|
// All messages must be 32 bytes or less |
// |
|
|
// Walk us through the JTAG Chain: |
// 5-1's to go to test/reset |
// 0 to go to Run-Test/Idle |
// 1 to go to select-dr-scan |
// 1 to go to select-ir-scan |
// 0 to go to capture-ir |
// 0 to go to shift-ir |
// (6-bit code 0x02 through TDI to IR, while sending 0-bits to TMS) |
// 1 to leave shift IR and go to exit1-ir |
// 1 to go to update-ir |
// 1 to go to select-dr-scan |
// 0 to go to capture-dr |
// 0 to go to shift-dr |
#define RESET_JTAG_LEN 12 |
const char RESET_TO_USER_DR[RESET_JTAG_LEN] = { |
JTAG_CMD, |
21, // clocks |
0,0,0, // Also clocks, higher order bits |
PUT_TMS_MASK | PUT_TDI_MASK, // flags |
(char)(0x0df), // TMS: Five ones, then one zero, and two ones -- low bits first |
0x00, // TDI: irrelevant here |
(char)(0x80), // TMS: two zeros, then six zeros |
0x08, // TDI: user command #1, bit reversed |
0x03, // TMS: three ones, then two zeros |
0x00 // TDI byte -- irrelevant here |
// |
// 0xc0, // TDI byte -- user command #2 |
// 0x40, // TDI: user command #1 |
// 0x0c, // TDI byte -- user command #2, bit reversed |
}; |
|
// |
// TMS: |
/* |
#define TX_DR_LEN 12 |
const char TX_DR_BITS[TX_DR_LEN] = { |
JTAG_CMD, |
48, // clocks |
0,0,0, // Also clocks, higher order bits |
PUT_TDI_MASK, // flags |
(char)0x0ff, 0, 0, 0, 0, 0 // Six data bytes |
// module_id = 255 |
// 32'h(payload.length) |
// payload |
// module_id + payload.len + num_result_bits, length=32 + payload ??? |
}; |
*/ |
|
// |
// TMS: |
// |
#define REQ_RX_LEN 6 |
const char REQ_RX_BITS[REQ_RX_LEN] = { |
JTAG_CMD, |
(char)((32-6)*8), // bits-requested |
0,0,0, // Also clocks, higher order bits |
GET_TDO_MASK|TDI_VAL_MASK, // flags:TDI is kept low here, so no TDI flag |
// No data given, since there's no info to send or receive |
// Leave the result in shift-DR mode |
}; |
|
#define RETURN_TO_RESET_LEN 7 |
const char RETURN_TO_RESET[RETURN_TO_RESET_LEN] = { |
JTAG_CMD, |
5, // clocks |
0,0,0, // Also clocks, higher order bits |
PUT_TMS_MASK, // flags |
(char)(0x0ff), // Five ones |
}; |
|
int dec(int v) { |
int br = 0; |
|
/* |
br = (br<<1)|(v&1); v>>=1; |
br = (br<<1)|(v&1); v>>=1; |
br = (br<<1)|(v&1); v>>=1; |
br = (br<<1)|(v&1); v>>=1; |
|
br = (br<<1)|(v&1); v>>=1; |
br = (br<<1)|(v&1); v>>=1; |
br = (br<<1)|(v&1); v>>=1; |
br = (br<<1)|(v&1); v>>=1; |
*/ |
br = v&0x07f; |
|
if (br == ' ') |
return br; |
else if (isgraph(br)) |
return br; |
else |
return '.'; |
} |
|
// |
// If max packet length is 32, why do you waste 4 bytes on num_clocks? |
// Why is the bit counter always from 8 to zero? |
// |
|
int main(int argc, char **argv) { |
libusb_context *usb_context; |
libusb_device_handle *xula_usb_device; |
int config; |
|
if (0 != libusb_init(&usb_context)) { |
fprintf(stderr, "Error initializing the USB library\n"); |
perror("O/S Err:"); |
exit(-1); |
} |
|
xula_usb_device = libusb_open_device_with_vid_pid(usb_context, |
VENDOR_ID, PRODUCT_ID); |
if (!xula_usb_device) { |
fprintf(stderr, "Could not open XuLA device\n"); |
perror("O/S Err:"); |
|
libusb_exit(usb_context); |
exit(-1); |
} |
|
if (0 != libusb_get_configuration(xula_usb_device, &config)) { |
fprintf(stderr, "Could not get configuration\n"); |
perror("O/S Err:"); |
|
libusb_close(xula_usb_device); |
libusb_exit(usb_context); |
exit(-1); |
} |
|
printf("Current configuration is %d\n", config); |
int interface = 0; |
|
if (0 != libusb_claim_interface(xula_usb_device, interface)) { |
fprintf(stderr, "Could not claim interface\n"); |
perror("O/S Err:"); |
|
libusb_close(xula_usb_device); |
libusb_exit(usb_context); |
exit(-1); |
} |
|
unsigned char *abuf = new unsigned char[32]; |
int actual_length = 32; |
memcpy(abuf, RESET_TO_USER_DR, RESET_JTAG_LEN); |
int r = libusb_bulk_transfer(xula_usb_device, XESS_ENDPOINT_OUT, |
abuf, RESET_JTAG_LEN, &actual_length, 20); |
if ((r==0)&&(actual_length == RESET_JTAG_LEN)) { |
printf("Successfully sent RESET_TO_USER_DR!\n"); |
} else { |
printf("Some error took place requesting RESET_TO_USER_DR\n"); |
perror("O/S Err"); |
} |
|
memset(abuf, 0, 32); |
memcpy(abuf, REQ_RX_BITS, REQ_RX_LEN); |
r = libusb_bulk_transfer(xula_usb_device, XESS_ENDPOINT_OUT, |
abuf, REQ_RX_LEN, &actual_length, 20); |
if ((r==0)&&(actual_length == REQ_RX_LEN)) { |
printf("Successfully sent request for TDO bits!\n"); |
} else { |
printf("Some error took place in requesting TDO bits\n"); |
printf("r = %d, actual_length = %d (!= %d)\n", r, |
actual_length, REQ_RX_LEN); |
perror("O/S Err"); |
} |
|
r = libusb_bulk_transfer(xula_usb_device, XESS_ENDPOINT_IN, |
abuf, 32, &actual_length, 20); |
if ((r==0)&&(actual_length > 0)) { |
printf("Successfully read %d bytes from port!\n", actual_length); |
for(int i=0; i<(actual_length); i+=4) |
printf("%2d: %02x %02x %02x %02x -- %c%c%c%c\n", i, |
abuf[i+0], abuf[i+1], abuf[i+2], abuf[i+3], |
dec(abuf[i+0]),dec(abuf[i+1]), dec(abuf[i+2]), dec(abuf[i+3])); |
} else { |
printf("Some error took place in receiving\n"); |
perror("O/S Err"); |
} |
|
|
// Release our interface |
if (0 != libusb_release_interface(xula_usb_device, interface)) { |
fprintf(stderr, "Could not release interface\n"); |
perror("O/S Err:"); |
|
libusb_close(xula_usb_device); |
libusb_exit(usb_context); |
exit(-1); |
} |
|
// And then close our device with |
libusb_close(xula_usb_device); |
|
// And just before exiting, we free our USB context |
libusb_exit(usb_context); |
} |
|
/trunk/sw/ziprun.cpp
0,0 → 1,210
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: ziprun.cpp |
// |
// Project: XuLA2 board |
// |
// Purpose: To load a program for the ZipCPU into memory. |
// |
// Steps: |
// 1. Halt and reset the CPU |
// 2. Load memory |
// 3. Clear the cache |
// 4. Clear any registers |
// 5. Set the PC to point to the FPGA local memory |
// THIS DOES NOT START THE PROGRAM!! The CPU is left in the halt state. |
// To actually start the program, execute a ./wbregs cpu 0. (Actually, |
// any value between 0x0 and 0x1f will work, the difference being what |
// register you will be able to inspect while the CPU is running.) |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <strings.h> |
#include <ctype.h> |
#include <string.h> |
#include <signal.h> |
#include <assert.h> |
|
#include "usbi.h" |
#include "port.h" |
#include "regdefs.h" |
|
FPGA *m_fpga; |
|
int main(int argc, char **argv) { |
FILE *fp; |
int nr, pos=0; |
const int BUFLN = 128; |
FPGA::BUSW *buf = new FPGA::BUSW[BUFLN]; |
int skp=0, port = FPGAPORT; |
bool use_usb = true; |
|
skp=1; |
for(int argn=0; argn<argc-skp; argn++) { |
if (argv[argn+skp][0] == '-') { |
if (argv[argn+skp][1] == 'u') |
use_usb = true; |
else if (argv[argn+skp][1] == 'p') { |
use_usb = false; |
if (isdigit(argv[argn+skp][2])) |
port = atoi(&argv[argn+skp][2]); |
} |
skp++; argn--; |
} else |
argv[argn] = argv[argn+skp]; |
} argc -= skp; |
|
if (use_usb) |
m_fpga = new FPGA(new USBI()); |
else |
m_fpga = new FPGA(new NETCOMMS(FPGAHOST, port)); |
|
if ((argc<=0)||(access(argv[0],R_OK)!=0)) { |
printf("Usage: ziprun obj-file\n"); |
printf("\n" |
"\tziprun loads the object file into memory, resets the CPU, and leaves it\n" |
"\tin a halted state ready to start running the object file.\n"); |
exit(-1); |
} |
|
// FPGAOPEN(m_fpga); |
|
printf("Halting the CPU\n"); |
m_fpga->writeio(R_ZIPCTRL, CPU_RESET|CPU_HALT); |
|
fp = fopen(argv[0], "r"); |
if (fp == NULL) { |
fprintf(stderr, "Could not open: %s\n", argv[0]); |
exit(-1); |
} |
|
try { |
pos = RAMBASE; |
while((nr=fread(buf, sizeof(FPGA::BUSW), BUFLN, fp))>0) { |
// printf("Writing %4d values, pos = %08x\n", nr, pos); |
m_fpga->writei(pos, nr, buf); |
// printf("\tWritten\n"); |
pos += nr; |
} printf("Successfully wrote %04x (%6d) words into memory\n", |
pos-RAMBASE, pos-RAMBASE); |
m_fpga->readio(R_ZIPCTRL); |
|
// Do we want to zero out all other RAM addresses? |
#define ZERO_RAM |
#ifdef ZERO_RAM |
unsigned int MAXRAM=2*RAMBASE; |
for(int i=0; i<BUFLN; i++) |
buf[i] = 0; |
printf("***********************\n"); |
while(pos < (int)MAXRAM-BUFLN-1) { |
m_fpga->writei(pos, BUFLN, buf); |
m_fpga->readio(R_ZIPCTRL); |
pos += BUFLN; |
} m_fpga->writei(pos, MAXRAM-pos-1, buf); |
pos += MAXRAM-pos-1; |
|
m_fpga->usleep(500); |
printf("Zerod rest of RAM - to %06x\n", pos); |
#endif |
} catch(BUSERR a) { |
fprintf(stderr, "BUS Err at address 0x%08x\n", a.addr); |
fprintf(stderr, "... is your program too long for this memory?\n"); |
m_fpga->writeio(R_ZIPCTRL, CPU_RESET|CPU_HALT|CPU_CLRCACHE); |
exit(-2); |
} |
try { |
m_fpga->readio(R_ZIPCTRL); |
} catch(BUSERR a) { |
fprintf(stderr, "Bus-Err? (%08x)\n", a.addr); |
} |
|
// Clear any buffers |
printf("Clearing the cache\n"); |
m_fpga->writeio(R_ZIPCTRL, CPU_RESET|CPU_HALT|CPU_CLRCACHE); |
|
// printf("Clearing all registers to zero, PC regs to MEMBASE\n"); |
// Clear all registers to zero |
for(int i=0; i<32; i++) { |
unsigned int v; |
try { |
m_fpga->writeio(R_ZIPCTRL, CPU_HALT|i); |
m_fpga->readio(R_ZIPCTRL); |
} catch(BUSERR a) { |
fprintf(stderr, "Bus-ERR while trying to set CPUCTRL to %x\n", CPU_HALT|i); |
} |
try { |
if ((i&0x0f)==0x0f) |
m_fpga->writeio(R_ZIPDATA, RAMBASE); |
else |
m_fpga->writeio(R_ZIPDATA, 0); |
// printf("REG[%2x] <= %08x\n", i, ((i&0x0f)==0x0f)?RAMBASE:0); |
// m_fpga->readio(R_ZIPDATA); |
// printf("\t= %08x\n", m_fpga->readio(R_ZIPDATA)); |
} catch(BUSERR a) { |
fprintf(stderr, "Bus-ERR while trying to clear reg %x\n", i); |
} |
} for(int i=32; i<32+16; i++) { |
try { |
if (i==33) |
continue; // Don't start the watchdog |
if (i==34) |
continue; // Don't start the flash cache |
if (i==39) |
continue; // Jiffies don't clear, don't set the intrupt |
m_fpga->writeio(R_ZIPCTRL, CPU_HALT|i); |
m_fpga->writeio(R_ZIPDATA, 0); |
} catch (BUSERR a) { |
fprintf(stderr, "Bus-ERR while trying to clear peripheral %d\n", i); |
} |
} |
|
printf("Starting CPU\n"); |
try { |
m_fpga->writeio(R_ZIPCTRL, CPU_HALT|CPU_sCC); // Start in interrupt mode |
m_fpga->writeio(R_ZIPDATA, 0x000); |
printf("SCC <= 0x%08x\n", m_fpga->readio(R_ZIPDATA)); |
} catch (BUSERR a) { |
fprintf(stderr, "Bus Err while trying to set CC register\n"); |
} |
|
try { |
m_fpga->writeio(R_ZIPCTRL, CPU_HALT|CPU_sPC); |
printf("CPU <= 0x%08x\n", m_fpga->readio(R_ZIPCTRL)); |
m_fpga->writeio(R_ZIPDATA, RAMBASE); // Start at the base of RAM |
printf("SPC <= 0x%08x\n", m_fpga->readio(R_ZIPDATA)); |
} catch (BUSERR a) { |
fprintf(stderr, "Bus Err while trying to set PC register\n"); |
} |
printf("PC set to start at %08x\n", m_fpga->readio(R_ZIPDATA)); |
// m_fpga->writeio(R_ZIPCTRL, CPU_GO); // Release the CPU to start |
|
delete m_fpga; |
} |
|
/trunk/sw/wbregs.cpp
0,0 → 1,122
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbregs.cpp |
// |
// Project: XuLA2 board |
// |
// Purpose: To give a user access, via a command line program, to read |
// and write wishbone registers one at a time. Thus this program |
// implements readio() and writeio() but nothing more. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <strings.h> |
#include <ctype.h> |
#include <string.h> |
#include <signal.h> |
#include <assert.h> |
|
#include "llcomms.h" |
#include "usbi.h" |
#include "port.h" |
#include "regdefs.h" |
|
FPGA *m_fpga; |
void closeup(int v) { |
m_fpga->kill(); |
exit(0); |
} |
|
int main(int argc, char **argv) { |
int skp=0, port = FPGAPORT; |
bool use_usb = true; |
|
skp=1; |
for(int argn=0; argn<argc-skp; argn++) { |
if (argv[argn+skp][0] == '-') { |
if (argv[argn+skp][1] == 'u') |
use_usb = true; |
else if (argv[argn+skp][1] == 'p') { |
use_usb = false; |
if (isdigit(argv[argn+skp][2])) |
port = atoi(&argv[argn+skp][2]); |
} |
skp++; argn--; |
} else |
argv[argn] = argv[argn+skp]; |
} argc -= skp; |
|
if (use_usb) |
m_fpga = new FPGA(new USBI()); |
else |
m_fpga = new FPGA(new NETCOMMS(FPGAHOST, port)); |
|
signal(SIGSTOP, closeup); |
signal(SIGHUP, closeup); |
|
if ((argc < 1)||(argc > 2)) { |
// usage(); |
printf("USAGE: wbregs address [value]\n"); |
exit(-1); |
} |
|
const char *nm; |
unsigned address = addrdecode(argv[0]), value; |
nm = addrname(address); |
if (nm == NULL) |
nm = "no name"; |
|
if (argc < 2) { |
FPGA::BUSW v; |
try { |
unsigned char a, b, c, d; |
v = m_fpga->readio(address); |
a = (v>>24)&0x0ff; |
b = (v>>16)&0x0ff; |
c = (v>> 8)&0x0ff; |
d = (v )&0x0ff; |
printf("%08x (%8s) : [%c%c%c%c] %08x\n", address, nm, |
isgraph(a)?a:'.', isgraph(b)?b:'.', |
isgraph(c)?c:'.', isgraph(d)?d:'.', v); |
} catch(BUSERR b) { |
printf("%08x (%8s) : BUS-ERROR\n", address, nm); |
} |
} else { |
value = strtoul(argv[1], NULL, 0); |
m_fpga->writeio(address, value); |
printf("%08x (%8s)-> %08x\n", address, nm, value); |
} |
|
if (m_fpga->poll()) |
printf("FPGA was interrupted\n"); |
delete m_fpga; |
} |
|
/trunk/sw/cfgscope.cpp
0,0 → 1,124
// |
// |
// Filename: cfgscope.cpp |
// |
// Project: FPGA library development (Basys-3 development board) |
// |
// Purpose: To read out, and decompose, the results of the wishbone scope |
// as applied to the ICAPE2 interaction. |
// |
// Creator: Dan Gisselquist |
// Gisselquist Tecnology, LLC |
// |
// Copyright: 2015 |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <strings.h> |
#include <ctype.h> |
#include <string.h> |
#include <signal.h> |
#include <assert.h> |
|
#include "port.h" |
#include "llcomms.h" |
#include "regdefs.h" |
|
#define WBSCOPE R_CFGSCOPE |
#define WBSCOPEDATA R_CFGSCOPED |
|
FPGA *m_fpga; |
void closeup(int v) { |
m_fpga->kill(); |
exit(0); |
} |
|
unsigned brev(const unsigned v) { |
unsigned int r, a; |
a = v; |
r = 0; |
for(int i=0; i<8; i++) { |
r <<= 1; |
r |= (a&1); |
a >>= 1; |
} return r; |
} |
|
unsigned wrev(const unsigned v) { |
unsigned r = brev(v&0x0ff); |
r |= brev((v>>8)&0x0ff)<<8; |
return r; |
} |
|
int main(int argc, char **argv) { |
FPGAOPEN(m_fpga); |
|
signal(SIGSTOP, closeup); |
signal(SIGHUP, closeup); |
|
unsigned v, lgln, scoplen; |
printf("Attempting to read address %08x\n", WBSCOPE); |
v = m_fpga->readio(WBSCOPE); |
if (0x60000000 != (v & 0x60000000)) { |
printf("Scope is not yet ready:\n"); |
printf("\tRESET:\t\t%s\n", (v&0x80000000)?"Ongoing":"Complete"); |
printf("\tSTOPPED:\t%s\n", (v&0x40000000)?"Yes":"No"); |
printf("\tTRIGGERED:\t%s\n", (v&0x20000000)?"Yes":"No"); |
printf("\tPRIMED:\t\t%s\n", (v&0x10000000)?"Yes":"No"); |
printf("\tMANUAL:\t\t%s\n", (v&0x08000000)?"Yes":"No"); |
printf("\tDISABLED:\t%s\n", (v&0x04000000)?"Yes":"No"); |
printf("\tZERO:\t\t%s\n", (v&0x02000000)?"Yes":"No"); |
exit(0); |
} else printf("SCOPD = %08x\n", v); |
|
lgln = (v>>20) & 0x1f; |
scoplen = (1<<lgln); |
|
DEVBUS::BUSW *buf; |
buf = new DEVBUS::BUSW[scoplen]; |
|
if (false) { |
printf("Attempting vector read\n"); |
m_fpga->readz(WBSCOPEDATA, scoplen, buf); |
|
printf("Vector read complete\n"); |
} else { |
for(unsigned int i=0; i<scoplen; i++) |
buf[i] = m_fpga->readio(WBSCOPEDATA); |
} |
|
for(unsigned int i=0; i<scoplen; i++) { |
if ((i>0)&&(buf[i] == buf[i-1])&& |
(i<scoplen-1)&&(buf[i] == buf[i+1])) |
continue; |
printf("%6d %08x:", i, buf[i]); |
printf("S(%x) ", (buf[i]>>27)&0x0f); |
if (buf[i] & 0x40000000) |
printf("W "); else printf("R "); |
printf("WB(%s%s%s%s%s)-%s%s%s%s%s", |
(buf[i]&0x2000000)?"CYC":" ", |
(buf[i]&0x1000000)?"STB":" ", |
(buf[i]&0x0800000)?"WE":" ", |
(buf[i]&0x0400000)?"ACK":" ", |
(buf[i]&0x0200000)?"STL":" ", |
(buf[i]&0x0100000)?"EDG":" ", |
(buf[i]&0x0080000)?"CLK":" ", |
(buf[i]&0x0040000)?" ":"CEn", |
(buf[i]&0x0020000)?"BSY":" ", |
(buf[i]&0x0010000)?" ":"WE"); |
if (buf[i]&0x10000) |
printf("->"); // Read |
else printf("<-"); |
printf(" %04x\n", wrev(buf[i] & 0x0ffff)); |
} |
|
if (m_fpga->poll()) { |
printf("FPGA was interrupted\n"); |
m_fpga->clear(); |
m_fpga->writeio(R_ICONTROL, SCOPEN); |
} |
delete m_fpga; |
} |
|
/trunk/sw/port.h
0,0 → 1,55
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: port.h |
// |
// Project: XuLA2 board |
// |
// Purpose: Defines the communication parameters necessary for communicating |
// with the device. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#ifndef PORT_H |
#define PORT_H |
|
// #include "usbi.h" |
|
// There are two ways to connect: via a serial port, and via a TCP socket |
// connected to a serial port. This way, we can connect the device on one |
// computer, test it, and when/if it doesn't work we can replace the device |
// with the test-bench. Across the network, no one will know any better that |
// anything had changed. |
#define FPGAHOST "lazarus" // A random hostname,back from the grave |
#define FPGATTY "/dev/ttyUSB1" |
#define FPGAPORT 7239 // Just some random port number .... |
|
#ifdef USBI_H |
#define FPGAOPEN(V) V= new FPGA(new USBI()) |
#else |
#define FPGAOPEN(V) V= new FPGA(new NETCOMMS(FPGAHOST, FPGAPORT)) |
#endif |
|
#endif |
/trunk/sw/ttybus.cpp
0,0 → 1,595
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: ttybus.cpp |
// |
// Project: XuLA2 board |
// |
// Purpose: This is the C++ program on the command side that will interact |
// with a UART on an FPGA, to command the WISHBONE on that same |
// FPGA to ... whatever we wish to command it to do. |
// |
// This code does not run on an FPGA, is not a test bench, neither |
// is it a simulator. It is a portion of a command program |
// for commanding an FPGA. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#include <sys/socket.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <fcntl.h> |
#include <termios.h> |
#include <netinet/in.h> |
#include <netdb.h> |
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <errno.h> |
#include <arpa/inet.h> |
#include <assert.h> |
#include <strings.h> |
#include <poll.h> |
#include <ctype.h> |
|
#include "ttybus.h" |
|
#define TTYC_IDLE '0' |
#define TTYC_BUSY '1' |
#define TTYC_WRITE '2' |
#define TTYC_RESET '3' |
#define TTYC_INT '4' |
#define TTYC_ERR '5' |
|
const unsigned TTYBUS::MAXRDLEN = 1024; |
const unsigned TTYBUS::MAXWRLEN = 32; |
|
#define DBGPRINTF null |
// #define DBGPRINTF printf |
void null(...) {} |
|
char TTYBUS::charenc(const int sixbitval) { |
if (sixbitval < 10) |
return '0' + sixbitval; |
else if (sixbitval < 10+26) |
return 'A' - 10 + sixbitval; |
else if (sixbitval < 10+26+26) |
return 'a' - 10 - 26 + sixbitval; |
else if (sixbitval == 0x3e) |
return '@'; |
else if (sixbitval == 0x3f) |
return '%'; |
|
fprintf(stderr, "INTERNAL ERR: SIXBITVAL isn\'t!!!! sixbitval = %08x\n", sixbitval); |
assert((sixbitval & (~0x03f))==0); |
return 0; |
} |
|
unsigned TTYBUS::chardec(const char b) { |
if ((b >= '0')&&(b <= '9')) |
return b-'0'; |
else if ((b >= 'A')&&(b <= 'Z')) |
return b-'A'+10; |
else if ((b >= 'a')&&(b <= 'z')) |
return b-'a'+36; |
else if (b == '@') |
return 0x03e; |
else if (b == '%') |
return 0x03f; |
else |
return 0x0100; // ERR -- invalid code |
} |
|
int TTYBUS::lclreadcode(char *buf, int len) { |
char *sp, *dp; |
int nr, ret; |
|
nr = m_dev->read(buf, len); |
m_total_nread += nr; |
ret = nr; sp = buf; dp = buf; |
for(int i=0; i<nr; i++) { |
if (chardec(*sp)&(~0x3f)) { |
ret--; // Skip this value, not a valid codeword |
sp++; |
} else { |
*sp++ = *dp++; |
} |
} return ret; |
} |
|
void TTYBUS::bufalloc(int len) { |
if ((m_buf)&&(m_buflen >= len)) |
return; |
if (m_buf) |
delete[] m_buf; |
m_buflen = (len&(-0x3f))+0x40; |
m_buf = new char[m_buflen]; |
} |
|
void TTYBUS::encode(const int hb, const BUSW val, char *buf) { |
buf[0] = charenc( (hb<<2)|((val>>30)&0x03) ); |
buf[1] = charenc( (val>>24)&0x3f); |
buf[2] = charenc( (val>>18)&0x3f); |
buf[3] = charenc( (val>>12)&0x3f); |
buf[4] = charenc( (val>> 6)&0x3f); |
buf[5] = charenc( (val )&0x3f); |
} |
|
unsigned TTYBUS::decodestr(const char *buf) { |
unsigned r; |
|
r = chardec(buf[0]) & 0x03; |
r = (r<<6) | (chardec(buf[1]) & 0x03f); |
r = (r<<6) | (chardec(buf[2]) & 0x03f); |
r = (r<<6) | (chardec(buf[3]) & 0x03f); |
r = (r<<6) | (chardec(buf[4]) & 0x03f); |
r = (r<<6) | (chardec(buf[5]) & 0x03f); |
|
return r; |
} |
|
int TTYBUS::decodehex(const char hx) { |
if ((hx >= '0')&&(hx <= '9')) |
return hx-'0'; |
else if ((hx >= 'A')&&(hx <= 'Z')) |
return hx-'A'+10; |
else if ((hx >= 'a')&&(hx <= 'z')) |
return hx-'a'+10; |
else |
return 0; |
} |
|
void TTYBUS::writeio(const BUSW a, const BUSW v) { |
|
writev(a, 0, 1, &v); |
m_lastaddr = a; m_addr_set = true; |
} |
|
void TTYBUS::writev(const BUSW a, const int p, const int len, const BUSW *buf) { |
char *ptr; |
|
// Allocate a buffer of six bytes per word, one for addr, plus |
// six more |
bufalloc((len+2)*6); |
|
DBGPRINTF("WRITEV(%08x,%d,#%d,0x%08x ...)\n", a, p, len, buf[0]); |
// Encode the address |
ptr = encode_address(a); |
m_lastaddr = a; m_addr_set = true; |
|
for(int i=0; i<len; i++) { |
BUSW val = buf[i]; |
|
int caddr = 0; |
// Let's try compression |
for(int i=1; i<256; i++) { |
unsigned tstaddr; |
tstaddr = (m_wraddr - i) & 0x0ff; |
if ((!m_wrloaded)&&(tstaddr > (unsigned)m_wraddr)) |
break; |
if (m_writetbl[tstaddr] == val) { |
caddr = ( m_wraddr- tstaddr ) & 0x0ff; |
break; |
} |
} |
|
if (caddr != 0) |
DBGPRINTF("WR[%08x] = %08x (= TBL[%4x] <= %4x)\n", m_lastaddr, val, caddr, m_wraddr); |
else |
DBGPRINTF("WR[%08x] = %08x\n", m_lastaddr, val); |
|
if (caddr != 0) { |
*ptr++ = charenc( (((caddr>>6)&0x03)<<1) + (p?1:0) + 0x010); |
*ptr++ = charenc( caddr &0x3f ); |
|
} else { |
// For testing, let's start just doing this the hard way |
*ptr++ = charenc( (((val>>30)&0x03)<<1) + (p?1:0) + 0x018); |
*ptr++ = charenc( (val>>24)&0x3f); |
*ptr++ = charenc( (val>>18)&0x3f); |
*ptr++ = charenc( (val>>12)&0x3f); |
*ptr++ = charenc( (val>> 6)&0x3f); |
*ptr++ = charenc( (val )&0x3f); |
|
m_writetbl[m_wraddr++] = val; |
m_wraddr &= 0x0ff; |
if (m_wraddr == 0) { |
m_wrloaded = true; |
} |
} |
|
if (p == 1) m_lastaddr++; |
} |
// *ptr++ = charenc(0x2e); |
*ptr++ = '\n'; *ptr = '\0'; |
m_dev->write(m_buf, ptr-m_buf); |
|
DBGPRINTF(">> %s\n", m_buf); |
DBGPRINTF("WR: LAST ADDRESS LEFT AT %08x\n", m_lastaddr); |
} |
|
void TTYBUS::writez(const BUSW a, const int len, const BUSW *buf) { |
int ln = len; |
const TTYBUS::BUSW *bptr = buf; |
TTYBUS::BUSW addr = a; |
|
while((unsigned)ln > MAXWRLEN) { |
writev(addr, 0, MAXWRLEN, bptr); |
bptr += MAXWRLEN; |
ln -= MAXWRLEN; |
// addr += MAXWRLEN; |
} if ((unsigned)ln > 0) |
writev(addr, 0, ln, bptr); |
} |
|
void TTYBUS::writei(const BUSW a, const int len, const BUSW *buf) { |
int ln = len; |
const TTYBUS::BUSW *bptr = buf; |
TTYBUS::BUSW addr = a; |
|
while((unsigned)ln > MAXWRLEN) { |
writev(addr, 1, MAXWRLEN, bptr); |
bptr += MAXWRLEN; |
ln -= MAXWRLEN; |
addr += MAXWRLEN; |
} if ((unsigned)ln > 0) |
writev(addr, 1, ln, bptr); |
} |
|
TTYBUS::BUSW TTYBUS::readio(const TTYBUS::BUSW a) { |
BUSW v; |
|
// I/O reads are now the same as vector reads, but with a vector length |
// of one. |
try { |
readv(a, 0, 1, &v); |
} catch(BUSERR b) { |
throw BUSERR(a); |
} |
|
if (m_lastaddr != a) { |
DBGPRINTF("LAST-ADDR MIS-MATCH: (RCVD) %08x != %08x (XPECTED)\n", m_lastaddr, a); |
m_addr_set = false; |
|
exit(-3); |
} |
|
return v; |
} |
|
char *TTYBUS::encode_address(const TTYBUS::BUSW a) { |
TTYBUS::BUSW addr = a; |
char *ptr = m_buf; |
|
if ((m_addr_set)&&(a == m_lastaddr)) |
return ptr; |
|
if (m_addr_set) { |
// Encode a difference address |
int diffaddr = addr - m_lastaddr; |
ptr = m_buf; |
if ((diffaddr >= -32)&&(diffaddr < 32)) { |
*ptr++ = charenc(0x09); |
*ptr++ = charenc(diffaddr & 0x03f); |
} else if ((diffaddr >= -2048)&&(diffaddr < 2048)) { |
*ptr++ = charenc(0x0b); |
*ptr++ = charenc((diffaddr>>6) & 0x03f); |
*ptr++ = charenc( diffaddr & 0x03f); |
} else if ((diffaddr >= -(1<<17))&&(diffaddr < (1<<17))) { |
*ptr++ = charenc(0x0d); |
*ptr++ = charenc((diffaddr>>12) & 0x03f); |
*ptr++ = charenc((diffaddr>> 6) & 0x03f); |
*ptr++ = charenc( diffaddr & 0x03f); |
} else if ((diffaddr >= -(1<<23))&&(diffaddr < (1<<23))) { |
*ptr++ = charenc(0x0d); |
*ptr++ = charenc((diffaddr>>18) & 0x03f); |
*ptr++ = charenc((diffaddr>>12) & 0x03f); |
*ptr++ = charenc((diffaddr>> 6) & 0x03f); |
*ptr++ = charenc( diffaddr & 0x03f); |
} |
*ptr = '\0'; |
// DBGPRINTF("DIF-ADDR: (%ld) \'%s\'\n", ptr-m_buf, m_buf); |
} |
|
{ |
// Encode an absolute (low memory) address |
// Prefer absolute address encoding over differential encoding, |
// when both encodings encode the same address, and when both |
// encode the address in the same number of words |
if ((addr <= 0x03f)&&((ptr == m_buf)||(ptr >= &m_buf[2]))) { |
ptr = m_buf; |
*ptr++ = charenc(0x08); |
*ptr++ = charenc(addr); |
} else if((addr <= 0x0fff)&&((ptr == m_buf)||(ptr >= &m_buf[3]))) { |
// DBGPRINTF("Setting ADDR.3 to %08x\n", addr); |
ptr = m_buf; |
*ptr++ = charenc(0x0a); |
*ptr++ = charenc((addr>> 6) & 0x03f); |
*ptr++ = charenc( addr & 0x03f); |
} else if((addr <= 0x03ffff)&&((ptr == m_buf)||(ptr >= &m_buf[4]))) { |
// DBGPRINTF("Setting ADDR.4 to %08x\n", addr); |
ptr = m_buf; |
*ptr++ = charenc(0x0c); |
*ptr++ = charenc((addr>>12) & 0x03f); |
*ptr++ = charenc((addr>> 6) & 0x03f); |
*ptr++ = charenc( addr & 0x03f); |
} else if((addr <= 0x0ffffff)&&((ptr == m_buf)||(ptr >= &m_buf[5]))) { |
// DBGPRINTF("Setting ADDR.5 to %08x\n", addr); |
ptr = m_buf; |
*ptr++ = charenc(0x0e); |
*ptr++ = charenc((addr>>18) & 0x03f); |
*ptr++ = charenc((addr>>12) & 0x03f); |
*ptr++ = charenc((addr>> 6) & 0x03f); |
*ptr++ = charenc( addr & 0x03f); |
} else if (ptr == m_buf) { // Send our address prior to any read |
ptr = m_buf; |
encode(0, addr, ptr); |
ptr+=6; |
} |
} |
|
*ptr = '\0'; |
// DBGPRINTF("ADDR-CMD: (%ld) \'%s\'\n", ptr-m_buf, m_buf); |
m_rdaddr = 0; |
|
return ptr; |
} |
|
char *TTYBUS::readcmd(const int inc, const int len, char *buf) { |
char *ptr = buf; |
|
// DBGPRINTF("READCMD: LEN = %d\n", len); |
assert(len < 520); |
assert(len > 0); |
|
if ((len < 8)||((len == 8)&&(inc))) { |
*ptr++ = charenc(0x20 + (((len-1)&0x07)<<1) + (inc?1:0)); |
} else { |
*ptr++ = charenc(0x30 + (((len-8)>>5)&0x0e) + (inc?1:0)); |
*ptr++ = charenc( (len-8) & 0x03f); |
} |
|
return ptr; |
} |
|
void TTYBUS::readv(const TTYBUS::BUSW a, const int inc, const int len, TTYBUS::BUSW *buf) { |
const int READAHEAD = MAXRDLEN/2, READBLOCK=MAXRDLEN/2; |
int cmdrd = 0, nread = 0; |
// TTYBUS::BUSW addr = a; |
char *ptr = m_buf; |
|
if (len <= 0) |
return; |
// DBGPRINTF("READV(%08x,%d,#%4d)\n", a, inc, len); |
|
ptr = encode_address(a); |
try { |
while(cmdrd < len) { |
// ptr = m_buf; |
do { |
int nrd = len-cmdrd; |
if (nrd > READBLOCK) |
nrd = READBLOCK; |
if (cmdrd-nread + nrd>READAHEAD+READBLOCK) |
nrd = READAHEAD+READBLOCK-(cmdrd-nread); |
ptr = readcmd(inc, nrd, ptr); |
cmdrd += nrd; |
} while((cmdrd-nread < READAHEAD+READBLOCK)&&(cmdrd< len)); |
|
*ptr++ = '\n'; *ptr = '\0'; |
m_dev->write(m_buf, (ptr-m_buf)); |
|
while(nread<(cmdrd-READAHEAD)) { |
buf[nread++] = readword(); |
} ptr = m_buf; |
} while(nread<len) { |
buf[nread++] = readword(); |
} |
} catch(BUSERR b) { |
throw BUSERR(a+((inc)?nread:0)); |
} |
|
if ((unsigned)m_lastaddr != (a+((inc)?(len):0))) { |
printf("TTYBUS::READV(a=%08x,inc=%d,len=%4x,x) ERR: (Last) %08x != %08x + %08x (Expected)\n", a, inc, len, m_lastaddr, a, (inc)?(len):0); |
sleep(1); |
assert((int)m_lastaddr == (a+(inc)?(len):0)); |
exit(-3); |
} |
} |
|
void TTYBUS::readi(const TTYBUS::BUSW a, const int len, TTYBUS::BUSW *buf) { |
readv(a, 1, len, buf); |
} |
|
void TTYBUS::readz(const TTYBUS::BUSW a, const int len, TTYBUS::BUSW *buf) { |
readv(a, 0, len, buf); |
} |
|
TTYBUS::BUSW TTYBUS::readword(void) { |
TTYBUS::BUSW val = 0; |
int nr; |
unsigned sixbits; |
|
// DBGPRINTF("READ-WORD()\n"); |
|
bool found_start = false; |
do { |
// Blocking read (for now) |
do { |
nr = lclreadcode(&m_buf[0], 1); |
} while (nr < 1); |
|
sixbits = chardec(m_buf[0]); |
|
if (sixbits&(~0x03f)) { |
// Ignore new lines, unprintables, and characters |
// not a part of our code |
; |
} else if (sixbits < 6) { |
switch(sixbits) { |
case 0: break; // Idle -- ignore |
case 1: break; // Idle, but the bus is busy |
case 2: break; // Write acknowledgement, ignore it here |
case 3: |
m_bus_err = true; |
throw BUSERR(0); |
break; |
case 4: |
m_interrupt_flag = true; |
break; |
case 5: |
m_bus_err = true; |
throw BUSERR(0); |
break; |
} |
} else if (0x08 == (sixbits & 0x3c)) { // Set 32-bit address |
do { |
nr += lclreadcode(&m_buf[nr], 6-nr); |
} while (nr < 6); |
|
val = chardec(m_buf[0]) & 0x03; |
val = (val<<6) | (chardec(m_buf[1]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[2]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[3]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[4]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[5]) & 0x03f); |
|
m_addr_set = true; |
m_lastaddr = val; |
|
// DBGPRINTF("RCVD ADDR: 0x%08x\n", val); |
} else if (0x0c == (sixbits & 0x03c)) { // Set 32-bit address,compressed |
int nw = (sixbits & 0x03) + 2; |
do { |
nr += lclreadcode(&m_buf[nr], nw-nr); |
} while (nr < nw); |
|
if (nw == 2) { |
val = chardec(m_buf[1]); |
} else if (nw == 3) { |
val = chardec(m_buf[1]); |
val = (val<<6) | (chardec(m_buf[2]) & 0x03f); |
} else if (nw == 4) { |
val = chardec(m_buf[1]); |
val = (val<<6) | (chardec(m_buf[2]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[3]) & 0x03f); |
} else { // if (nw == 5) |
val = chardec(m_buf[1]); |
val = (val<<6) | (chardec(m_buf[2]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[3]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[4]) & 0x03f); |
} |
|
m_addr_set = true; |
m_lastaddr = val; |
// DBGPRINTF("RCVD ADDR: 0x%08x (%d bytes)\n", val, nw+1); |
} else |
found_start = true; |
} while(!found_start); |
|
int rdaddr; |
|
if (0x06 == (sixbits & 0x03e)) { // Tbl read, last value |
rdaddr = (m_rdaddr-1)&0x03ff; |
val = m_readtbl[rdaddr]; |
m_lastaddr += (sixbits&1); |
} else if (0x10 == (sixbits & 0x030)) { // Tbl read, up to 521 into past |
int idx; |
do { |
nr += lclreadcode(&m_buf[nr], 2-nr); |
} while (nr < 2); |
|
idx = (chardec(m_buf[0])>>1) & 0x07; |
idx = ((idx<<6) | (chardec(m_buf[1]) & 0x03f)) + 2 + 8; |
rdaddr = (m_rdaddr-idx)&0x03ff; |
val = m_readtbl[rdaddr]; |
m_lastaddr += (sixbits&1); |
} else if (0x20 == (sixbits & 0x030)) { // Tbl read, 2-9 into past |
rdaddr = (m_rdaddr - (((sixbits>>1)&0x07)+2)) & 0x03ff; |
val = m_readtbl[rdaddr]; |
m_lastaddr += (sixbits&1); |
} else if (0x38 == (sixbits & 0x038)) { // Raw read |
do { |
nr += lclreadcode(&m_buf[nr], 6-nr); |
} while (nr < 6); |
|
val = (chardec(m_buf[0])>>1) & 0x03; |
val = (val<<6) | (chardec(m_buf[1]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[2]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[3]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[4]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[5]) & 0x03f); |
|
m_readtbl[m_rdaddr++] = val; m_rdaddr &= 0x03ff; |
m_lastaddr += (sixbits&1); |
} |
|
return val; |
} |
|
void TTYBUS::usleep(unsigned ms) { |
if (m_dev->poll(ms)) { |
int nr; |
nr = m_dev->read(m_buf, 16); |
if (nr == 0) { |
// Connection closed, let it drop |
DBGPRINTF("Connection closed!!\n"); |
m_dev->close(); |
exit(-1); |
} for(int i=0; i<nr; i++) { |
if (m_buf[i] == TTYC_INT) { |
m_interrupt_flag = true; |
// DBGPRINTF("!!!!!!!!!!!!!!!!! ----- INTERRUPT!\n"); |
} else if (m_buf[i] == TTYC_IDLE) { |
// DBGPRINTF("Interface is now idle\n"); |
} else if (m_buf[i] == TTYC_WRITE) { |
} else if (m_buf[i] == TTYC_RESET) { |
// DBGPRINTF("Bus was RESET!\n"); |
} else if (m_buf[i] == TTYC_ERR) { |
DBGPRINTF("Bus error\n"); |
} else if (m_buf[i] == TTYC_BUSY) { |
// DBGPRINTF("Interface is ... busy ??\n"); |
} |
// else if (m_buf[nr] == 'Q') |
// else if (m_buf[nr] == 'W') |
// else if (m_buf[nr] == '\n') |
} |
} |
} |
|
void TTYBUS::wait(void) { |
if (m_interrupt_flag) |
DBGPRINTF("INTERRUPTED PRIOR TO WAIT()\n"); |
do { |
usleep(200); |
} while(!m_interrupt_flag); |
} |
|
// TTYBUS: 3503421 ~= 3.3 MB, stopwatch = 1:18.5 seconds, vs 53.8 secs |
// If you issue two 512 word reads at once, time drops to 41.6 secs. |
// PORTBUS: 6408320 ~= 6.1 MB, ... 26% improvement, 53 seconds real time |
|
/trunk/sw/txtest.cpp
0,0 → 1,256
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <string.h> |
#include <ctype.h> |
// #include <usb.h> |
|
#include <libusb.h> |
|
// /sys/bus/usb/devices/1-4/ is our device, as currently plugged in |
// |
// It supports |
// 1 configuration |
// 1 interface |
// and has a product string of... |
// "XuLA - XESS Micro Logic Array" |
// |
#define VENDOR_ID 0x04d8 |
#define PRODUCT_ID 0x0ff8c |
#define XESS_ENDPOINT_OUT 0x01 |
#define XESS_ENDPOINT_IN 0x81 |
// |
#define JTAG_CMD 0x4f |
#define GET_TDO_MASK 0x01 |
#define PUT_TMS_MASK 0x02 |
#define TMS_VAL_MASK 0x04 |
#define PUT_TDI_MASK 0x08 |
#define TDI_VAL_MASK 0x10 |
// |
#define USER1_INSTR 0x02 // a SIX bit two |
|
|
bool gbl_transfer_received = false; |
|
// libusbtransfer_cb_fn callback; |
extern "C" { |
void my_callback(libusb_transfer *tfr) { |
gbl_transfer_received = true; |
|
printf("Callback received!\n"); |
} |
} |
|
// All messages must be 32 bytes or less |
// |
|
|
// Walk us through the JTAG Chain: |
// 5-1's to go to test/reset |
// 0 to go to Run-Test/Idle |
// 1 to go to select-dr-scan |
// 1 to go to select-ir-scan |
// 0 to go to capture-ir |
// 0 to go to shift-ir |
// (6-bit code 0x02 through TDI to IR, while sending 0-bits to TMS) |
// 1 to leave shift IR and go to exit1-ir |
// 1 to go to update-ir |
// 1 to go to select-dr-scan |
// 0 to go to capture-dr |
// 0 to go to shift-dr |
#define RESET_JTAG_LEN 12 |
const char RESET_TO_USER_DR[RESET_JTAG_LEN] = { |
JTAG_CMD, |
21, // clocks |
0,0,0, // Also clocks, higher order bits |
PUT_TMS_MASK | PUT_TDI_MASK, // flags |
(char)(0x0df), // TMS: Five ones, then one zero, and two ones -- low bits first |
0x00, // TDI: irrelevant here |
(char)(0x80), // TMS: two zeros, then six zeros |
0x08, // TDI: user command #1, bit reversed |
0x03, // TMS: three ones, then two zeros |
0x00 // TDI byte -- irrelevant here |
// |
// 0xc0, // TDI byte -- user command #2 |
// 0x40, // TDI: user command #1 |
// 0x0c, // TDI byte -- user command #2, bit reversed |
}; |
|
// |
// TMS: |
/* |
#define TX_DR_LEN 12 |
const char TX_DR_BITS[TX_DR_LEN] = { |
JTAG_CMD, |
48, // clocks |
0,0,0, // Also clocks, higher order bits |
PUT_TDI_MASK, // flags |
(char)0x0ff, 0, 0, 0, 0, 0 // Six data bytes |
// module_id = 255 |
// 32'h(payload.length) |
// payload |
// module_id + payload.len + num_result_bits, length=32 + payload ??? |
}; |
*/ |
|
// |
// TMS: |
// |
#define REQ_RX_LEN 6 |
const char REQ_RX_BITS[REQ_RX_LEN] = { |
JTAG_CMD, |
(char)((32-6)*8), // bits-requested |
0,0,0, // Also clocks, higher order bits |
GET_TDO_MASK|TDI_VAL_MASK, // flags:TDI is kept low here, so no TDI flag |
// No data given, since there's no info to send or receive |
// Leave the result in shift-DR mode |
}; |
|
#define RETURN_TO_RESET_LEN 7 |
const char RETURN_TO_RESET[RETURN_TO_RESET_LEN] = { |
JTAG_CMD, |
5, // clocks |
0,0,0, // Also clocks, higher order bits |
PUT_TMS_MASK, // flags |
(char)(0x0ff), // Five ones |
}; |
|
int dec(int v) { |
int br = 0; |
|
/* |
br = (br<<1)|(v&1); v>>=1; |
br = (br<<1)|(v&1); v>>=1; |
br = (br<<1)|(v&1); v>>=1; |
br = (br<<1)|(v&1); v>>=1; |
|
br = (br<<1)|(v&1); v>>=1; |
br = (br<<1)|(v&1); v>>=1; |
br = (br<<1)|(v&1); v>>=1; |
br = (br<<1)|(v&1); v>>=1; |
*/ |
br = v&0x07f; |
|
if (br == ' ') |
return br; |
else if (isgraph(br)) |
return br; |
else |
return '.'; |
} |
|
// |
// If max packet length is 32, why do you waste 4 bytes on num_clocks? |
// Why is the bit counter always from 8 to zero? |
// |
|
int main(int argc, char **argv) { |
libusb_context *usb_context; |
libusb_device_handle *xula_usb_device; |
int config; |
|
if (0 != libusb_init(&usb_context)) { |
fprintf(stderr, "Error initializing the USB library\n"); |
perror("O/S Err:"); |
exit(-1); |
} |
|
xula_usb_device = libusb_open_device_with_vid_pid(usb_context, |
VENDOR_ID, PRODUCT_ID); |
if (!xula_usb_device) { |
fprintf(stderr, "Could not open XuLA device\n"); |
perror("O/S Err:"); |
|
libusb_exit(usb_context); |
exit(-1); |
} |
|
if (0 != libusb_get_configuration(xula_usb_device, &config)) { |
fprintf(stderr, "Could not get configuration\n"); |
perror("O/S Err:"); |
|
libusb_close(xula_usb_device); |
libusb_exit(usb_context); |
exit(-1); |
} |
|
printf("Current configuration is %d\n", config); |
int interface = 0; |
|
if (0 != libusb_claim_interface(xula_usb_device, interface)) { |
fprintf(stderr, "Could not claim interface\n"); |
perror("O/S Err:"); |
|
libusb_close(xula_usb_device); |
libusb_exit(usb_context); |
exit(-1); |
} |
|
unsigned char *abuf = new unsigned char[32]; |
int actual_length = 32; |
memcpy(abuf, RESET_TO_USER_DR, RESET_JTAG_LEN); |
int r = libusb_bulk_transfer(xula_usb_device, XESS_ENDPOINT_OUT, |
abuf, RESET_JTAG_LEN, &actual_length, 20); |
if ((r==0)&&(actual_length == RESET_JTAG_LEN)) { |
printf("Successfully sent RESET_TO_USER_DR!\n"); |
} else { |
printf("Some error took place requesting RESET_TO_USER_DR\n"); |
perror("O/S Err"); |
} |
|
const char hello_world[] = "Hello, World!\n"; |
abuf[0] = JTAG_CMD; |
abuf[1] = strlen(hello_world) * 8 + 8; |
abuf[2] = abuf[3] = abuf[4] = 0; |
abuf[5] = PUT_TDI_MASK | GET_TDO_MASK; |
strcpy((char *)&abuf[6], hello_world); |
// abuf[6] = 0xff; |
// abuf[7] = 0xff; |
// abuf[8] = 0x00; |
// abuf[9] = 0xff; |
// abuf[10] = 0x01; |
// abuf[11] = 0x02; |
// abuf[12] = 0x04; |
// abuf[13] = 0x08; |
r = libusb_bulk_transfer(xula_usb_device, XESS_ENDPOINT_OUT, |
abuf, strlen(hello_world)+6+1, &actual_length, 20); |
if ((r==0)&&(actual_length == strlen(hello_world)+6+1)) { |
printf("Successfully sent request for TDO bits!\n"); |
} else { |
printf("Some error took place in requesting TDO bits\n"); |
printf("r = %d, actual_length = %d (!= %d)\n", r, |
actual_length, (int)strlen(hello_world)+6); |
perror("O/S Err"); |
} |
|
r = libusb_bulk_transfer(xula_usb_device, XESS_ENDPOINT_IN, |
abuf, strlen(hello_world)+1, &actual_length, 20); |
if ((r==0)&&(actual_length > 0)) { |
printf("Successfully read %d bytes from port!\n", actual_length); |
for(int i=0; i<(actual_length); i+=4) |
printf("%2d: %02x %02x %02x %02x -- %c%c%c%c\n", i, |
abuf[i+0], abuf[i+1], abuf[i+2], abuf[i+3], |
dec(abuf[i+0]),dec(abuf[i+1]), dec(abuf[i+2]), dec(abuf[i+3])); |
} else { |
printf("Some error took place in receiving\n"); |
perror("O/S Err"); |
} |
|
|
// Release our interface |
if (0 != libusb_release_interface(xula_usb_device, interface)) { |
fprintf(stderr, "Could not release interface\n"); |
perror("O/S Err:"); |
|
libusb_close(xula_usb_device); |
libusb_exit(usb_context); |
exit(-1); |
} |
|
// And then close our device with |
libusb_close(xula_usb_device); |
|
// And just before exiting, we free our USB context |
libusb_exit(usb_context); |
} |
|
/trunk/sw/dumpsdram.cpp
0,0 → 1,139
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: dumpsdram.cpp |
// |
// Project: XuLA2 board |
// |
// Purpose: Read local memory, dump into a file. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <strings.h> |
#include <ctype.h> |
#include <string.h> |
#include <signal.h> |
#include <assert.h> |
|
#include "usbi.h" |
#include "port.h" |
#include "regdefs.h" |
|
FPGA *m_fpga; |
|
int main(int argc, char **argv) { |
FILE *fp, *fpin; |
unsigned pos=0; |
const int BUFLN = 127; |
FPGA::BUSW *buf = new FPGA::BUSW[BUFLN], |
*cmp = new FPGA::BUSW[BUFLN]; |
|
if (argc<=2) { |
printf("Usage: dumpsdram srcfile outfile\n"); |
exit(-1); |
} |
|
FPGAOPEN(m_fpga); |
|
fpin = fopen(argv[1], "rb"); |
if (fpin == NULL) { |
fprintf(stderr, "Could not open %s\n", argv[1]); |
exit(-1); |
} |
|
try { |
int nr; |
pos = SDRAMBASE; |
do { |
nr = BUFLN; |
if (nr + pos > SDRAMBASE*2) |
nr = SDRAMBASE*2 - pos; |
nr = fread(buf, sizeof(FPGA::BUSW), nr, fpin); |
if (nr <= 0) |
break; |
m_fpga->writei(pos, nr, buf); |
pos += nr; |
} while((nr > 0)&&(pos < 2*SDRAMBASE)); |
|
printf("SUCCESS::fully wrote full file to memory (pos = %08x)\n", pos); |
} catch(BUSERR a) { |
fprintf(stderr, "BUS Err while writing at address 0x%08x\n", a.addr); |
fprintf(stderr, "... is your program too long for this memory?\n"); |
exit(-2); |
} |
|
rewind(fpin); |
|
fp = fopen(argv[2], "wb"); |
if (fp == NULL) { |
fprintf(stderr, "Could not open: %s\n", argv[2]); |
exit(-1); |
} |
|
try { |
pos = SDRAMBASE; |
const unsigned int MAXRAM = SDRAMBASE*2; |
do { |
int nw, nr; |
if (MAXRAM-pos > BUFLN) |
nr = BUFLN; |
else |
nr = MAXRAM-pos; |
m_fpga->readi(pos, nr, buf); |
pos += nr; |
nw = fwrite(buf, sizeof(FPGA::BUSW), nr, fp); |
if (nw < nr) { |
printf("Only wrote %d of %d words!\n", nw, nr); |
exit(-2); |
} printf("nr = %d, pos = %08x (%08x / %08x)\n", nr, |
pos, SDRAMBASE, MAXRAM); |
|
{int cr; |
cr = fread(cmp, sizeof(FPGA::BUSW), nr, fpin); |
for(int i=0; i<cr; i++) |
if (cmp[i] != buf[i]) |
fprintf(stderr, "MISMATCH: MEM[%08x] = %08x != %08x\n", |
pos-nr+i, buf[i], cmp[i]); |
if (cr != nr) { |
printf("Only read %d words from our input file\n", cr); |
break; |
} |
} |
} while(pos < MAXRAM); |
printf("Successfully read&copied %04x (%6d) words from memory\n", |
pos-SDRAMBASE, pos-SDRAMBASE); |
} catch(BUSERR a) { |
fprintf(stderr, "BUS Err at address 0x%08x\n", a.addr); |
fprintf(stderr, "... is your program too long for this memory?\n"); |
exit(-2); |
} |
|
delete m_fpga; |
} |
|
/trunk/sw/Makefile
0,0 → 1,129
################################################################################ |
## |
## Filename: Makefile |
## |
## Project: XuLA2 board |
## |
## Purpose: |
## |
## |
## Creator: Dan Gisselquist, Ph.D. |
## Gisselquist Technology, LLC |
## |
################################################################################ |
## |
## Copyright (C) 2015, Gisselquist Technology, LLC |
## |
## This program is free software (firmware): 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. |
## |
## This program is distributed in the hope that it will be useful, but WITHOUT |
## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
## for more details. |
## |
## License: GPL, v3, as defined and found on www.gnu.org, |
## http:##www.gnu.org/licenses/gpl.html |
## |
## |
################################################################################ |
## |
## |
.PHONY: all |
PROGRAMS := $(OBJDIR) usbtst wbregs netusb wbsettime dumpflash \ |
dumpsdram ziprun ramscope |
all: $(PROGRAMS) |
CXX := g++ |
LIBUSBINC := -I/usr/include/libusb-1.0/ |
LIBUSBDIR := -L/usr/lib/x86_64-linux-gnu |
OBJDIR := obj-pc |
ZIPD := /home/dan/work/rnd/zipcpu/trunk/sw/zasm |
BUSSRCS := ttybus.cpp llcomms.cpp regdefs.cpp usbi.cpp |
SOURCES := ziprun.cpp zipdbg.cpp dumpsdram.cpp wbregs.cpp netusb.cpp $(BUSSRCS) |
HEADERS := llcomms.h ttybus.h devbus.h regdefs.h usbi.h |
OBJECTS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(SOURCES))) |
BUSOBJS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(BUSSRCS))) |
CFLAGS := -g -Wall $(LIBUSBINC) -I. -I../../fpgalib/sw |
LIBS := -lusb-1.0 |
|
all: $(PROGRAMS) |
|
%.o: $(OBJDIR)/ $(OBJDIR)/%.o |
$(OBJDIR)/%.o: %.cpp |
$(CXX) $(CFLAGS) -c $< -o $@ |
$(OBJDIR)/zipdbg.o: zipdbg.cpp |
$(CXX) $(CFLAGS) -I$(ZIPD) -c $< -o $@ |
$(OBJDIR)/cpuscope.o: cpuscope.cpp |
$(CXX) $(CFLAGS) -I$(ZIPD) -c $< -o $@ |
|
.PHONY: clean |
clean: |
rm -rf $(OBJDIR)/ $(PROGRAMS) |
|
|
# wbprogram: $(OBJDIR)/wbprogram.o $(OBJDIR)/flashdrvr.o $(BUSOBJS) |
# $(CXX) -g $^ -o $@ |
netusb: $(OBJDIR)/netusb.o $(OBJDIR)/usbi.o $(OBJDIR)/llcomms.o |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
wbsettime: $(OBJDIR)/wbsettime.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
wbregs: $(OBJDIR)/wbregs.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
dumpflash: $(OBJDIR)/dumpflash.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
cfgscope: $(OBJDIR)/cfgscope.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
ramscope: $(OBJDIR)/ramscope.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
dumpsdram: $(OBJDIR)/dumpsdram.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
ziprun: $(OBJDIR)/ziprun.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
ZIPOBJS_RAW := twoc.o zparser.o zopcodes.o |
ZIPOBJS := $(addprefix $(ZIPD)/$(OBJDIR)/,$(ZIPOBJS_RAW)) |
zipdbg: $(OBJDIR)/zipdbg.o $(BUSOBJS) $(ZIPOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -lncurses -o $@ |
cpuscope: $(OBJDIR)/cpuscope.o $(BUSOBJS) $(ZIPOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
|
nothing: |
@echo |
|
# ziprun: $(OBJDIR)/ziprun.o $(BUSOBJS) |
# $(CXX) -g $^ -o $@ |
# zipdbg: zipdbg.cpp $(ZIPD)/zparser.cpp $(ZIPD)/zopcodes.cpp $(ZIPD)/twoc.cpp $(BUSOBJS) |
# $(CXX) -g -I../bench/cpp -I $(ZIPD)/ $^ -lncurses -o $@ |
|
usbtst: usbtst.cpp |
$(CXX) $(CFLAGS) usbtst.cpp $(LIBS) -o usbtst |
txtest: txtest.cpp |
$(CXX) $(CFLAGS) txtest.cpp $(LIBS) -o txtest |
|
|
define build-depends |
@echo "Building dependency file(s)" |
@$(CXX) $(CPPFLAGS) -MM -I$(ZIPD) $(SOURCES) > $(OBJDIR)/xdepends.txt |
@sed -e 's/^.*.o: /$(OBJDIR)\/&/' < $(OBJDIR)/xdepends.txt > $(OBJDIR)/depends.txt |
@rm $(OBJDIR)/xdepends.txt |
endef |
|
tags: $(SOURCES) $(HEADERS) |
@echo "Generating tags" |
@ctags $(SOURCES) $(HEADERS) |
|
.PHONY: depends |
depends: tags |
$(build-depends) |
|
$(OBJDIR)/depends.txt: $(OBJDIR)/ $(SOURCES) $(HEADERS) |
$(build-depends) |
|
$(OBJDIR)/: |
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi" |
|
# obj-pc/usbi.o: usbi.cpp |
# $(CXX) $(LIBUSBINC) -I../../fpgalib/sw -c usbi.cpp -o $@ |
|
-include $(OBJDIR)/depends.txt |
/trunk/sw/devbus.h
0,0 → 1,106
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: devbus.h |
// |
// Project: XuLA2 board |
// |
// Purpose: The purpose of this file is to document an interface which |
// any device with a bus, whether it be implemented over a UART, |
// an ethernet, or a PCI express bus, must implement. This describes |
// only an interface, and not how that interface is to be accomplished. |
// |
// The neat part of this interface is that, if programs are designed to |
// work with it, than the implementation details may be changed later |
// and any program that once worked with the interface should be able |
// to continue to do so. (i.e., switch from a UART controlled bus to a |
// PCI express controlled bus, with minimal change to the software of |
// interest.) |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): 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. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#ifndef DEVBUS_H |
#define DEVBUS_H |
|
#include <stdio.h> |
#include <unistd.h> |
|
typedef unsigned int uint32; |
|
class BUSERR { |
public: |
uint32 addr; |
BUSERR(const uint32 a) : addr(a) {}; |
}; |
|
class DEVBUS { |
public: |
typedef uint32 BUSW; |
|
virtual void kill(void) = 0; |
virtual void close(void) = 0; |
|
// Write a single value to a single address |
virtual void writeio(const BUSW a, const BUSW v) = 0; |
|
// Read a single value to a single address |
virtual BUSW readio(const BUSW a) = 0; |
|
// Read a series of values from values from a block of memory |
virtual void readi(const BUSW a, const int len, BUSW *buf) = 0; |
|
// Read a series of values from the same address in memory |
virtual void readz(const BUSW a, const int len, BUSW *buf) = 0; |
|
virtual void writei(const BUSW a, const int len, const BUSW *buf) = 0; |
virtual void writez(const BUSW a, const int len, const BUSW *buf) = 0; |
|
// Query whether or not an interrupt has taken place |
virtual bool poll(void) = 0; |
|
// Sleep until interrupt, but sleep no longer than msec milliseconds |
virtual void usleep(unsigned msec) = 0; |
|
// Sleep until an interrupt, no matter how long it takes for that |
// interrupt to take place |
virtual void wait(void) = 0; |
|
// Query whether or not a bus error has taken place. This is somewhat |
// of a misnomer, as my current bus error detection code exits any |
// interface, but ... it is what it is. |
virtual bool bus_err(void) const = 0; |
|
// Clear any bus error condition. |
virtual void reset_err(void) = 0; |
|
// Clear any interrupt condition that has already been noticed by |
// the interface, does not check for further interrupt |
virtual void clear(void) = 0; |
|
virtual ~DEVBUS(void) { }; |
}; |
|
#endif |