OpenCores
URL https://opencores.org/ocsvn/openarty/openarty/trunk

Subversion Repositories openarty

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openarty/trunk
    from Rev 3 to Rev 4
    Reverse comparison

Rev 3 → Rev 4

/sw/startupex.sh
0,0 → 1,35
#!/bin/bash
 
WBREGS=./wbregs
RED=0x00ff0000
GREEN=0x0000ff00
WHITE=0x000f0f0f
BLACK=0x00000000
DIMGREEN=0x00001f00
 
$WBREGS led 0x0f
 
$WBREGS clrled0 $RED
$WBREGS clrled1 $RED
$WBREGS clrled2 $RED
$WBREGS clrled3 $RED
 
sleep 1
$WBREGS clrled0 $GREEN
sleep 1
$WBREGS clrled1 $GREEN
$WBREGS clrled0 $DIMGREEN
sleep 1
$WBREGS clrled2 $GREEN
$WBREGS clrled1 $DIMGREEN
sleep 1
$WBREGS clrled3 $GREEN
$WBREGS clrled2 $DIMGREEN
sleep 1
$WBREGS clrled0 $WHITE
$WBREGS clrled1 $BLACK
$WBREGS clrled2 $BLACK
$WBREGS clrled3 $WHITE
$WBREGS led 0x00
 
 
/sw/host/portbus.cpp
0,0 → 1,665
//
//
// Filename: portbus.cpp
//
// Project: UART to WISHBONE FPGA library
//
// 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
// Gisselquist Tecnology, LLC
//
// Copyright: 2015
//
//
#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 "portbus.h"
 
char PORTBUS::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, "SIXBITVAL isn\'t!!!! sixbitval = %08x\n", sixbitval);
assert((sixbitval & (~0x03f))==0);
return 0;
}
 
unsigned PORTBUS::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 PORTBUS::lclread(char *buf, int len) {
int nr;
nr = m_dev->read(buf, len);
 
if (false) {
// if (nr > 0)
// printf("READ %d bytes (%5x:%5x), req %d, raw %d\n", nr, m_rdfirst, m_rdlast, rq, rnr);
for(int i=0; i<nr; i++) {
if ('\n' == buf[i])
printf("\n\\n< ");
else if (buf[i] == '\0')
printf("\nBRK\n");
else if ('\r' == buf[i])
printf("\\r");
else putchar(buf[i]);
} fflush(stdout);
} return nr;
}
 
int PORTBUS::lclreadcode(char *buf, int len) {
char *sp, *dp;
int nr, ret;
 
nr = lclread(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 PORTBUS::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 PORTBUS::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 PORTBUS::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 PORTBUS::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 PORTBUS::writeio(const BUSW a, const BUSW v) {
if (a == m_lastaddr) {
encode(1, v, &m_buf[0]);
m_buf[6] = '\n';
m_buf[7] = '\0';
m_dev->write(m_buf, 7);
} else if (a == (m_lastaddr + 1)) {
if ((v >= 0)&&(v <= 255)) {
encode(3, v<<24, &m_buf[0]);
m_buf[2] = '\n';
m_buf[3] = '\0';
m_dev->write(m_buf, 3);
} else {
encode(2, v, &m_buf[0]);
m_buf[6] = '\n';
m_buf[7] = '\0';
m_dev->write(m_buf, 7);
}
} else { // Gotta do this the hard way
// printf("WRITEIO--HARD(%08x, %08x)\n", a, v);
encode(0, a, &m_buf[0]);
encode(0, v, &m_buf[6]);
m_buf[12] = '\n';
m_buf[13] = '\0';
m_dev->write(m_buf, 12);
}
 
m_lastaddr = a; m_addr_set = true;
}
 
void PORTBUS::writev(const BUSW a, const int p, const int len, const BUSW *buf) {
int ci;
 
// Allocate a buffer of six bytes per word, one for addr, plus six more
bufalloc((len+2)*6);
 
// Encode the address
encode(0, a, &m_buf[0]); ci = 6; m_lastaddr = a; m_addr_set = true;
// Now all but the last of the data
for(int i=0; i<len-1; i++) {
encode(p, buf[i], &m_buf[ci]);
// printf("WRITE(%08x, %08x)\n", m_lastaddr, buf[i]);
ci += 6;
 
if (p == 2)
m_lastaddr++;
} encode(0, buf[len-1], &m_buf[ci]); ci += 6;
// printf("WRITE(%08x, %08x)\n", m_lastaddr, buf[len-1]);
m_buf[ci++] = '\n';
m_buf[ci++] = '\0';
m_dev->write(m_buf, ci-1);
}
 
void PORTBUS::writez(const BUSW a, const int len, const BUSW *buf) {
writev(a, 1, len, buf);
}
 
void PORTBUS::writei(const BUSW a, const int len, const BUSW *buf) {
writev(a, 2, len, buf);
}
 
PORTBUS::BUSW PORTBUS::readio(const PORTBUS::BUSW a) {
m_bus_err = false;
// printf("READIO(0x%08x, last = %08x)\n", a, m_lastaddr);
if ((m_lastaddr == a)&&(m_addr_set)) {
m_buf[0] = charenc(0x05<<2);
m_buf[1] = '\n';
m_buf[2] = '\0';
m_dev->write(m_buf, 2);
} else if (((m_lastaddr+1) == a)&&(m_addr_set)) {
m_buf[0] = charenc((0x05<<2)+1);
m_buf[1] = '\n';
m_buf[2] = '\0';
m_dev->write(m_buf, 2);
} else if ((m_lastaddr+255 >= a)&&(m_lastaddr-256 <= a)&&(m_addr_set)) {
int offset;
 
// m_lastaddr + offset = a
// offset = a - m_lastaddr
offset = (a - m_lastaddr) & 0x1ff;
m_buf[0] = charenc((3<<3)|((offset>>6)&0x07));
m_buf[1] = charenc(offset & 0x03f);
m_buf[2] = '\n';
m_buf[3] = '\0';
m_dev->write(m_buf, 3);
} else { // Do this the hard way
encode(4, a, m_buf);
m_buf[ 6] = '\n';
m_buf[ 7] = '\0';
m_dev->write(m_buf, 7);
}
 
// Read I/O is never a vector read, so we skip that here
BUSW v;
 
try {
v = readword();
} catch(BUSERR b) {
throw BUSERR(a);
}
 
if ((m_lastaddr != a)&&(m_addr_set)) {
printf("LAST-ADDR MIS-MATCH: (RCVD) %08x != %08x (XPECTED)\n", m_lastaddr, a);
m_addr_set = false;
 
exit(-3);
} else {
m_lastaddr = a; m_addr_set = true;
}
 
return v;
}
 
void PORTBUS::readv(const PORTBUS::BUSW a, const int inc, const int len, PORTBUS::BUSW *buf) {
int nxtln = len;
PORTBUS::BUSW addr = a;
char *ptr;
 
if (len <= 0)
return;
 
// printf("READV(%08x,+%d,%d,&buf)\n", a, inc, len);
 
// bufalloc(6+10);
 
// printf("READV[0x%08x]->0x%08x\n", a, a+inc*len);
if (true) { // ((m_lastaddr != addr)||(!m_addr_set)) {
encode(4, addr, m_buf);
ptr = &m_buf[6];
nxtln = len - 1;
if (nxtln <= 0) {
*ptr++ = '\n';
*ptr++ = '\0';
m_dev->write(m_buf, 7);
buf[0] = readword();
return;
}
 
addr += inc;
} else {
// We still need to issue a read command, but this time from
// this address. Otherwise we'll bomb the vector read by
// incrementing before reading.
m_buf[0] = charenc(0x05<<2);
ptr = &m_buf[1];
if (nxtln <= 0) {
*ptr++ = '\n';
*ptr++ = '\0';
m_dev->write(m_buf, 7);
buf[0] = readword();
return;
}
}
 
// printf(" ... READV(%08x,+%d,%d,&buf)\n", addr, inc, nxtln);
 
nxtln &= 0x03ff;
*ptr++ = charenc(0x20+((inc)?0x10:0)+((nxtln>>6)&0x0f));
*ptr++ = charenc(nxtln & 0x03f);
*ptr++ = '\n'; *ptr = '\0';
m_dev->write(m_buf, (ptr-m_buf));
 
for(int i=0; i<len; i++) {
buf[i] = readword();
if (m_bus_err) {
throw BUSERR(a+((inc)?i:0));
printf("BUS ERROR!\n");
 
for(int i=0; i<50; i++)
lclread(m_buf, 50);
exit(-3);
break;
}
// printf("READ[i=%4x, a+i=%08x] = %08x\n", i, a+i, buf[i]);
}
 
if (m_lastaddr != (a+((inc)?(len-1):0))) {
printf("(Last) %08x != %08x + %08x (Expected)\n", m_lastaddr, a, (inc)?(len-1):0);
assert(m_lastaddr == (a+(inc)?(len-1):0));
exit(-3);
}
}
 
void PORTBUS::readi(const PORTBUS::BUSW a, const int len, PORTBUS::BUSW *buf) {
int MAXLN = 1023;
int ln = len;
PORTBUS::BUSW *bptr = buf;
PORTBUS::BUSW addr = a;
 
while(ln > MAXLN) {
readv(addr, 1, MAXLN, bptr); printf("#"); fflush(stdout);
bptr += MAXLN;
ln -= MAXLN;
addr += MAXLN;
} if (ln > 0)
readv(addr, 1, ln, bptr);
}
 
void PORTBUS::readz(const PORTBUS::BUSW a, const int len, PORTBUS::BUSW *buf) {
int MAXLN = 1023;
int ln = len;
PORTBUS::BUSW *bptr = buf;
 
while(ln > MAXLN) {
readv(a, 0, MAXLN, bptr);
bptr += MAXLN;
ln -= MAXLN;
} if (ln > 0)
readv(a, 0, ln, bptr);
}
 
PORTBUS::BUSW PORTBUS::readword(void) {
PORTBUS::BUSW val = 0;
int nr;
unsigned sixbits;
 
 
// printf("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 (m_buf[0] == 'I')
m_interrupt_flag = true;
else if (m_buf[0] == 'E') {
m_bus_err = true;
throw BUSERR(0);
} else if (m_buf[0] == 'R') {
m_bus_err = true;
throw BUSERR(0);
} else if (m_buf[0] == 'B') { // Bus is still busy
; // printf("BUSY\n");
} else if (m_buf[0] == 'Q') { // Transaction abandoned
; // printf("BUSY\n");
//
// We could fail our transaction here, but ...
// what if the 'Q' was in the 'Q' from before our
// read command? Reading it doesn't mean there's
// anything wrong, just that time has passed.
//
// m_bus_err = true;
// printf("\nTRANSACTION FAILURE!\n");
// exit(-3);
// return 0;
} else if (sixbits&(~0x03f))
// Ignore new lines, unprintables, and characters
// not a part of our code
;
else if (0 == (sixbits & 0x38)) {
// A 'W' ... adjust our known address ... NOT
// We adjust our address automatically at the end
// of the write command, not based upon what write
// response gets read from the port--those are just
// bonus.
//
// if (sixbits == 0x04)
// m_addr_set = false;
// else if (sixbits & 0x04)
// m_lastaddr += (-1<<2)|(sixbits&0x03);
// else m_lastaddr += (sixbits & 0x03);
} else if (0x20 == sixbits) { // Legacy 'W')
; // m_addr_set = false;
} else if (0x0c == (sixbits & 0x03e)) {
found_start = true;
} else if (0x01c == (sixbits & 0x03e)) {
found_start = true;
} else if (0x20 & sixbits) {
found_start = true;
} else if (0x1f == sixbits) { // Legacy 'V')
printf("Found a legacy read word\n");
exit(-1);
} else if (0x14 == (sixbits & 0x3c)) {
found_start = true;
}
} while(!found_start);
 
if (m_buf[0] == 'V') {
//
// LEGACY READ
//
// Read the flag and the data word, but not the newline
nr = 0;
do {
nr += lclread(&m_buf[1+nr], 10-nr);
} while(nr < 10);
m_buf[1+10] = '\0';
if (m_buf[6] != ':')
m_decode_err = true;
val = 0;
for(int i=0; i<4; i++)
val = (val << 4) | decodehex(m_buf[2+i]);
for(int i=0; i<4; i++)
val = (val << 4) | decodehex(m_buf[7+i]);
m_buf[11] = '\0';
// printf("DEC: %11s --> %08x\n", m_buf, val);
if (m_buf[1] == 'x') {
// The address of this read follows, suck in the newline as well
nr = 0;
do {
nr += lclread(&m_buf[11+nr], 4+8+2-nr);
} while(nr < 4+8+1);
m_buf[11+4+8+1] = '\0';
if (m_buf[17] != ':')
m_decode_err = true;
m_lastaddr = 0;
for(int i=0; i<4; i++)
m_lastaddr = (m_lastaddr << 4) | decodehex(m_buf[13+i]);
for(int i=0; i<4; i++)
m_lastaddr = (m_lastaddr << 4) | decodehex(m_buf[18+i]);
m_addr_set = true;
// printf("READ-ADDR = %08x\n", m_lastaddr);
} else {
// Read the end of line, so thus ready for another
lclread(&m_buf[11], 1);
m_buf[12] = '\n'; m_buf[13] = '\0';
if (m_buf[1] == '+')
m_lastaddr += 1;
}
} else if (0x14 == (sixbits & 0x3c)) { // 'N'
// Passes, for a read of zero
m_lastaddr = 0; m_addr_set = true;
do {
nr += lclreadcode(&m_buf[nr], 6-nr);
} while (nr < 6);
val = decodestr(m_buf);
} else if (0x0c == (sixbits & 0x3e)) { // Vx {1,Addr}, Data
do {
nr += lclreadcode(&m_buf[nr], 12-nr);
} while (nr < 12);
m_lastaddr = decodestr(m_buf);
m_lastaddr |= 0x80000000;
val = decodestr(&m_buf[6]);
printf("Vx: Read a %08x from %08x\n", val, m_lastaddr);
// Can't test--don't have negative addresses in my design
} else if (0x1c == (sixbits & 0x3e)) { // Vx {0,Addr}, Data
do {
nr += lclreadcode(&m_buf[nr], 12-nr);
} while (nr < 12);
m_lastaddr = decodestr(m_buf);
val = decodestr(&m_buf[6]);
// S0006000D%
// Vx Addr = 6, Data = Da(a) = 6'hD,6'h24
// Data = 001101 100100
// Data = 011 0110 0100
// Data = 0x364 = 878
// = DFFF = 57343
// printf("Vx(%c%c%c%c%c%c,%c%c%c%c%c%c): Read a %08x from %08x\n",
// m_buf[0], m_buf[1], m_buf[2], m_buf[3], m_buf[4], m_buf[5],
// m_buf[6], m_buf[7], m_buf[8], m_buf[9], m_buf[10], m_buf[11],
// val, m_lastaddr);
// PASSES!
} else if (0x20 == (sixbits & 0x30)) { // V+ {2-bit offset}, Data
do {
nr += lclreadcode(&m_buf[nr], 6-nr);
} while (nr < 6);
if (0x04 == (sixbits & 0x0c)) {
m_lastaddr--;
} else if (0x08 == (sixbits & 0x0c)) {
; // m_lastaddr = m_lastaddr
} else if (0x0c == (sixbits & 0x0c)) {
m_lastaddr++;
}
val = decodestr(&m_buf[0]);
// printf("V++(%c%c%c%c%c%c,%02x): Read a %08x from %08x\n",
// m_buf[0], m_buf[1], m_buf[2], m_buf[3], m_buf[4], m_buf[5],
// sixbits,
// val, m_lastaddr);
// Passes!
} else if (0x30 == (sixbits & 0x30)) { // V+ {6-bit offset}, Data
do {
nr += lclreadcode(&m_buf[nr], 7-nr);
} while(nr < 7);
if (sixbits&0x08) { // Sign extension necessary
m_lastaddr += (-1<<8)+((sixbits<<4)&0xf0)
+((chardec(m_buf[1])&0x3c)>>2);
} else {
m_lastaddr += ((sixbits<<4)&0x0f0)
+((chardec(m_buf[1])&0x3c)>>2);
}
val = decodestr(&m_buf[1]);
// printf("V+8(%c%c%c%c%c%c%c,%02x): Read a %08x from %08x\n",
// m_buf[0], m_buf[1], m_buf[2], m_buf[3], m_buf[4], m_buf[5], m_buf[6],
// sixbits,
// val, m_lastaddr);
// PASSES!
} else {
fprintf(stderr, "CANT DECODE %c, SIXBITS = %02x!!!!\n",
m_buf[0], sixbits);
exit(-1);
}
 
 
// printf("RDWORD %s\n", m_buf);
return val;
}
 
#ifdef LEGACY_READWORD
PORTBUS::BUSW PORTBUS::legacy_readword(void) {
PORTBUS::BUSW val = 0;
int nr;
 
// printf("READ-WORD()\n");
 
do {
// Blocking read (for now)
do {
nr = lclread(&m_buf[0], 1);
} while (nr < 1);
 
if (m_buf[0] == 'I')
m_interrupt_flag = true;
else if (m_buf[0] == 'E') {
m_bus_err = true;
throw BUSERR(0);
return 0;
} else if (m_buf[0] == 'Q') // Bus is still busy
; // printf("BUSY\n");
else if (m_buf[0] == '\n') // Ignore new lines
;
else if (m_buf[0] == '\r') // Ignore carriage returns
;
} while(m_buf[0] != 'V');
 
// Read the flag and the data word, but not the newline
nr = 0;
do {
nr += lclread(&m_buf[1+nr], 10-nr);
} while(nr < 10);
m_buf[1+10] = '\0';
if (m_buf[6] != ':')
m_decode_err = true;
val = 0;
for(int i=0; i<4; i++)
val = (val << 4) | decodehex(m_buf[2+i]);
for(int i=0; i<4; i++)
val = (val << 4) | decodehex(m_buf[7+i]);
m_buf[11] = '\0';
// printf("DEC: %11s --> %08x\n", m_buf, val);
 
if (m_buf[1] == 'x') {
// The address of this read follows, suck in the newline as well
nr = 0;
do {
nr += lclread(&m_buf[11+nr], 4+8+2-nr);
} while(nr < 4+8+1);
 
m_buf[11+4+8+1] = '\0';
 
if (m_buf[17] != ':')
m_decode_err = true;
m_lastaddr = 0;
for(int i=0; i<4; i++)
m_lastaddr = (m_lastaddr << 4) | decodehex(m_buf[13+i]);
for(int i=0; i<4; i++)
m_lastaddr = (m_lastaddr << 4) | decodehex(m_buf[18+i]);
m_addr_set = true;
// printf("READ-ADDR = %08x\n", m_lastaddr);
} else {
// Read the end of line, so thus ready for another
lclread(&m_buf[11], 1);
m_buf[12] = '\n'; m_buf[13] = '\0';
 
if (m_buf[1] == '+')
m_lastaddr += 1;
}
 
// printf("RDWORD %s\n", m_buf);
return val;
}
#endif
 
void PORTBUS::usleep(unsigned ms) {
if (m_dev->poll(ms)) {
int nr;
nr = lclread(m_buf, 16);
if (nr == 0) {
// Connection closed, let it drop
printf("Connection closed!!\n");
m_dev->close();
exit(-1);
} for(int i=0; i<nr; i++) {
if (m_buf[i] == 'I') {
m_interrupt_flag = true;
// printf("!!!!!!!!!!!!!!!!! ----- INTERRUPT!\n");
}
// else if (m_buf[nr] == 'Q')
// else if (m_buf[nr] == 'W')
// else if (m_buf[nr] == '\n')
}
}
}
 
void PORTBUS::wait(void) {
int nr;
if (m_interrupt_flag)
printf("INTERRUPTED PRIOR TO WAIT()\n");
do {
// nr = lclread(m_buf, 1);
// if ((nr > 0)&&(isprint(m_buf[0]))&&(!isspace(m_buf[0])))
// printf("RCVD: \'%c\'\n", m_buf[0]);
usleep(200);
} while(!m_interrupt_flag);
// m_interrupt_flag = true;
}
 
/sw/host/ttybus.h
0,0 → 1,105
//
//
// Filename: ttybus.h
//
// Project: UART to WISHBONE FPGA library
//
// 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
// Gisselquist Tecnology, LLC
//
// Copyright: 2015
//
//
#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) const;
unsigned chardec(const char b) const;
void encode(const int fbits, const BUSW v, char *buf) const;
unsigned decodestr(const char *buf) const;
int decodehex(const char hx) const;
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);
void readidle(void);
 
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
/sw/host/wbprogram.cpp
0,0 → 1,112
//
//
// Filename: wbprogram.cpp
//
// Project: FPGA library development (Basys3 development board)
//
// Purpose: Program the memory with a given '.bin' file.
//
// 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"
#include "flashdrvr.h"
 
DEVBUS *m_fpga;
void closeup(int v) {
m_fpga->kill();
exit(0);
}
 
int main(int argc, char **argv) {
FILE *fp;
const int BUFLN = (1<<20); // 4MB Flash
DEVBUS::BUSW *buf = new DEVBUS::BUSW[BUFLN], v, addr = QSPIFLASH;
FLASHDRVR *flash;
int argn = 1;
 
if ((argc > argn)&&(NULL != strstr(argv[argn],"tty")))
m_fpga = new FPGA(new TTYCOMMS(argv[argn++]));
else if ((argc > argn)&&(NULL != strchr(argv[argn],':'))) {
char *ptr = strchr(argv[argn],':');
*ptr++ = '\n';
m_fpga = new FPGA(new NETCOMMS(argv[argn++], atoi(ptr)));
} else {
FPGAOPEN(m_fpga);
}
 
// Start with testing the version:
try {
printf("VERSION: %08x\n", m_fpga->readio(R_VERSION));
} catch(BUSERR b) {
printf("VERSION: (Bus-Err)\n");
exit(-1);
}
 
// SPI flash testing
// Enable the faster (vector) reads
bool vector_read = true;
unsigned sz;
bool esectors[NSECTORS];
 
argn = 1;
if (argc <= argn) {
printf("BAD USAGE: program [@<Address>] file.bin\n");
exit(-1);
} else if (argv[argn][0] == '@') {
addr = strtoul(&argv[argn][1], NULL, 0);
if ((addr < QSPIFLASH)||(addr > QSPIFLASH*2)) {
printf("BAD ADDRESS: 0x%08x (from %s)\n", addr, argv[argn]);
exit(-1);
} argn++;
}
 
if (argc<= argn) {
printf("BAD USAGE: no file argument\n");
exit(-1);
} else if (0 != access(argv[argn], R_OK)) {
printf("Cannot access %s\n", argv[argn]);
exit(-1);
}
 
flash = new FLASHDRVR(m_fpga);
 
fp = fopen(argv[argn], "r");
sz = fread(buf, sizeof(buf[0]), BUFLN, fp);
fclose(fp);
 
try {
flash->write(addr, sz, buf, false);
} catch(BUSERR b) {
fprintf(stderr, "BUS-ERR @0x%08x\n", b.addr);
exit(-1);
}
 
try {
// Turn on the write protect flag
m_fpga->writeio(R_QSPI_EREG, 0);
} catch(BUSERR b) {
fprintf(stderr, "BUS-ERR, trying to read QSPI port\n");
exit(-1);
}
 
if (m_fpga->poll())
printf("FPGA was interrupted\n");
delete m_fpga;
}
 
 
/sw/host/flashdrvr.h
0,0 → 1,34
//
//
// Filename: flashdrvr.h
//
// Project: FPGA library development (Basys3 development board)
//
// Purpose: Flash driver. Encapsulate writing to the flash device.
//
// Creator: Dan Gisselquist
// Gisselquist Tecnology, LLC
//
// Copyright: 2015
//
//
#ifndef FLASHDRVR_H
#define FLASHDRVR_H
 
#include "regdefs.h"
 
class FLASHDRVR {
private:
DEVBUS *m_fpga;
 
void flwait(void);
public:
FLASHDRVR(DEVBUS *fpga) : m_fpga(fpga) {}
bool erase_sector(const unsigned sector, const bool verify_erase=true);
bool write_page(const unsigned addr, const unsigned len,
const unsigned *data, const bool verify_write=true);
bool write(const unsigned addr, const unsigned len,
const unsigned *data, const bool verify=false);
};
 
#endif
/sw/host/wbsettime.cpp
0,0 → 1,147
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbsettime
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: To set the on-board clock of an FPGA using the rtclight or
// rtcclock FPGA protocols.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, 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.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// 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);
}
if (m_fpga->poll())
printf("FPGA was interrupted\n");
delete m_fpga;
}
 
/sw/host/portbus.h
0,0 → 1,92
//
//
// Filename: portbus.h
//
// Project: UART to WISHBONE FPGA library
//
// 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
// Gisselquist Tecnology, LLC
//
// Copyright: 2015
//
//
#ifndef PORTBUS_H
#define PORTBUS_H
 
#include <unistd.h>
#include "llcomms.h"
#include "devbus.h"
 
typedef unsigned int uint32;
 
#define RDBUFLN 2048
 
class PORTBUS : public DEVBUS {
public:
unsigned long m_total_nread;
private:
LLCOMMSI *m_dev;
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;
 
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_rdfirst = m_rdlast = 0;
m_rdbuf = new char[RDBUFLN];
m_total_nread = 0l;
}
 
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);
public:
PORTBUS(void) { init(); }
PORTBUS(LLCOMMSI *comms) : m_dev(comms) { init(); }
~PORTBUS(void) { m_dev->close();
if (m_buf) delete[] m_buf; m_buf = NULL; }
 
void kill(void) { m_dev->close(); }
void open(const char *dev);
void open(const char *host, const int port);
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
/sw/host/llcomms.cpp
0,0 → 1,134
//
//
// Filename: llcomms.cpp
//
// Project: UART to WISHBONE FPGA library
//
// 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
// Gisselquist Tecnology, LLC
//
// Copyright: 2015
//
//
#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;
}
 
int LLCOMMSI::available(void) {
return poll(0)?1:0;
}
 
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;
}
 
/sw/host/scopecls.cpp
0,0 → 1,131
////////////////////////////////////////////////////////////////////////////////
//
// Filename: scopecls.cpp
//
// Project: XuLA2-LX25 SoC based upon the ZipCPU
//
// Purpose: After rebuilding the same code over and over again for every
// "scope" I tried to interact with, I thought it would be simpler
// to try to make a more generic interface, that other things could plug
// into. This is that more generic interface.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, 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.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// 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 "devbus.h"
#include "scopecls.h"
 
bool SCOPE::ready() {
unsigned v;
v = m_fpga->readio(m_addr);
if (m_scoplen == 0) {
m_scoplen = (1<<((v>>20)&0x01f));
} v = (v>>28)&6;
return (v==6);
}
 
void SCOPE::decode_control(void) {
unsigned v;
 
v = m_fpga->readio(m_addr);
printf("\t31. RESET:\t%s\n", (v&0x80000000)?"Ongoing":"Complete");
printf("\t30. STOPPED:\t%s\n", (v&0x40000000)?"Yes":"No");
printf("\t29. TRIGGERED:\t%s\n", (v&0x20000000)?"Yes":"No");
printf("\t28. PRIMED:\t%s\n", (v&0x10000000)?"Yes":"No");
printf("\t27. MANUAL:\t%s\n", (v&0x08000000)?"Yes":"No");
printf("\t26. DISABLED:\t%s\n", (v&0x04000000)?"Yes":"No");
printf("\t25. ZERO:\t%s\n", (v&0x02000000)?"Yes":"No");
printf("\tSCOPLEN:\t%08x (%d)\n", m_scoplen, m_scoplen);
printf("\tHOLDOFF:\t%08x\n", (v&0x0fffff));
printf("\tTRIGLOC:\t%d\n", m_scoplen-(v&0x0fffff));
}
 
int SCOPE::scoplen(void) {
if (m_scoplen == 0) {
int lgln = (m_fpga->readio(m_addr)>>20)&0x01f;
m_scoplen = (1<<lgln);
} return m_scoplen;
}
 
void SCOPE::read(void) {
DEVBUS::BUSW addrv = 0;
 
scoplen();
if (m_scoplen <= 4) {
printf("Not a scope?\n");
}
 
DEVBUS::BUSW *buf;
 
buf = new DEVBUS::BUSW[m_scoplen];
 
if (m_vector_read) {
m_fpga->readz(m_addr+1, m_scoplen, buf);
} else {
for(unsigned int i=0; i<m_scoplen; i++)
buf[i] = m_fpga->readio(m_addr+1);
}
 
if(m_compressed) {
for(int i=0; i<(int)m_scoplen; i++) {
if ((buf[i]>>31)&1) {
addrv += (buf[i]&0x7fffffff);
printf(" ** (+0x%08x = %8d)\n",
(buf[i]&0x07fffffff),
(buf[i]&0x07fffffff));
continue;
}
printf("%10d %08x: ", addrv++, buf[i]);
decode(buf[i]);
printf("\n");
}
} else {
for(int i=0; i<(int)m_scoplen; i++) {
if ((i>0)&&(buf[i] == buf[i-1])&&(i<(int)(m_scoplen-1))) {
if ((i>2)&&(buf[i] != buf[i-2]))
printf(" **** ****\n");
continue;
} printf("%9d %08x: ", i, buf[i]);
decode(buf[i]);
printf("\n");
}
}
 
delete[] buf;
}
 
/sw/host/llcomms.h
0,0 → 1,52
////////////////////////////////////////////////////////////////////////////////
//
//
// Filename: llcomms.cpp
//
// Project: UART to WISHBONE FPGA library
//
// 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
// Gisselquist Tecnology, LLC
//
// Copyright: 2015
//
//
#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);
 
// Tests whether or not bytes are available to be read, returns a
// count of the bytes that may be immediately read
virtual int available(void); // { return 0; };
};
 
class TTYCOMMS : public LLCOMMSI {
public:
TTYCOMMS(const char *dev);
};
 
class NETCOMMS : public LLCOMMSI {
public:
NETCOMMS(const char *dev, const int port);
};
 
#endif
/sw/host/eqspiscope.cpp
0,0 → 1,132
////////////////////////////////////////////////////////////////////////////////
//
// Filename: eqspiscope.cpp
//
// Project: XuLA2-LX25 SoC based upon the ZipCPU
//
// Purpose:
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, 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.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// 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"
#include "scopecls.h"
 
#define WBSCOPE R_QSCOPE
#define WBSCOPEDATA R_QSCOPED
 
FPGA *m_fpga;
void closeup(int v) {
m_fpga->kill();
exit(0);
}
 
class EQSPISCOPE : public SCOPE {
public:
EQSPISCOPE(FPGA *fpga, unsigned addr, bool vecread)
: SCOPE(fpga, addr, false, false) {};
~EQSPISCOPE(void) {}
virtual void decode(DEVBUS::BUSW val) const {
int cyc, cstb, dstb, ack, back, accepted, valid, word,
out, cs, sck, mod, odat, idat;
 
cyc = (val>>31)&1;
cstb = (val>>30)&1;
dstb = (val>>29)&1;
ack = (val>>28)&1;
back = (val>>27)&1;
accepted = (val>>26)&1;
valid = (val>>25)&1;
word = (val>>18)&0x07f;
out = (val>>12)&0x03f;
cs = (val>>11)&1;
sck = (val>>10)&1;
mod = (val>> 8)&3;
odat = (val>> 4)&15;
idat = (val )&15;
 
printf("%s%s%s%s%s%s%s %02x %02x %s%s %d %x-> ->%x",
(cyc)?"C ":" ",
(cstb)?"C":" ",
(dstb)?"D":" ",
(ack)?"AK":" ",
(back)?"+":" ",
(accepted)?"ACC":" ",
(valid)?"V":" ",
word<<1, out<<2,
(cs)?" ":"CS",
(sck)?"CK":" ",
(mod), odat, idat);
}
};
 
int main(int argc, char **argv) {
int skp=0, port = FPGAPORT;
bool use_usb = false;
 
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;
 
FPGAOPEN(m_fpga);
 
signal(SIGSTOP, closeup);
signal(SIGHUP, closeup);
 
EQSPISCOPE *scope = new EQSPISCOPE(m_fpga, WBSCOPE, false);
if (!scope->ready()) {
printf("Scope is not yet ready:\n");
scope->decode_control();
} else
scope->read();
delete m_fpga;
}
 
/sw/host/regdefs.cpp
0,0 → 1,244
////////////////////////////////////////////////////////////////////////////////
//
// Filename: regdefs.h
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, 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.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// 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_VERSION, "VERSION" },
{ R_ICONTROL, "ICONTROL" },
{ R_ICONTROL, "INT" },
{ R_ICONTROL, "PIC" },
{ R_BUSERR, "BUSERR" },
{ R_BUSERR, "BUS" },
{ R_PWCOUNT, "PWRCOUNT" },
{ R_BTNSW, "BTNSW" },
{ R_BTNSW, "BTNS" },
{ R_BTNSW, "BTN" },
{ R_BTNSW, "SW" },
{ R_BTNSW, "SWITCHES" },
{ R_BTNSW, "SWITCH" },
{ R_LEDS, "LEDS" },
{ R_LEDS, "LED" },
{ R_UART_SETUP, "UARTSETUP" },
{ R_UART_SETUP, "UART" },
{ R_UART_SETUP, "AUXSETUP" },
{ R_UART_SETUP, "AUX" },
{ R_GPS_SETUP, "GPSSETUP" },
{ R_GPS_SETUP, "GPSUART" },
{ R_CLR0, "CLRLED0" },
{ R_CLR1, "CLRLED1" },
{ R_CLR2, "CLRLED2" },
{ R_CLR3, "CLRLED3" },
{ R_CLR0, "CLR0" },
{ R_CLR1, "CLR1" },
{ R_CLR2, "CLR2" },
{ R_CLR3, "CLR3" },
{ R_DATE, "DATE" },
{ R_GPIO, "GPIO" },
{ R_UARTRX, "AUXRX" },
{ R_UARTRX, "RX" },
{ R_UARTTX, "AUXTX" },
{ R_UARTTX, "TX" },
//
{ R_GPSRX, "GPSRX" },
{ R_GPSTX, "GPSTX" },
// Scope registers--these scopes may or may not be present depending
// upon your current configuration.
{ R_QSCOPE, "SCOPE" },
{ R_QSCOPE, "SCOP" },
{ R_QSCOPED, "SCOPDATA" },
{ R_QSCOPED, "SCDATA" },
{ R_QSCOPED, "SCOPED" },
{ R_QSCOPED, "SCOPD" },
{ R_GPSCOPE, "GPSSCOPE" },
{ R_GPSCOPE, "GPSSCOP" },
{ R_GPSCOPED, "GPSSCDATA" },
{ R_GPSCOPED, "GPSSCD" },
{ R_GPSCOPED, "GPSDATA" },
{ R_ENSCOPE, "ENSCOPE" },
{ R_ENSCOPE, "ENSCOP" },
{ R_ENSCOPED, "ENSCOPED" },
{ R_ENSCOPED, "ENSCOPD" },
{ R_RAMSCOPE, "RAMSCOPE" },
{ R_RAMSCOPE, "RAMSCOP" },
{ R_RAMSCOPED, "RAMSCOPD" },
// RTC registers
{ R_CLOCK, "CLOCK" },
{ R_CLOCK, "TIME" },
{ R_TIMER, "TIMER" },
{ R_STOPWATCH, "STOPWACH" },
{ R_STOPWATCH, "STOPWATCH" },
{ R_CKALARM, "CKALARM" },
{ R_CKALARM, "ALARM" },
// SDCard registers
{ R_SDCARD_CTRL, "SDCARD" },
{ R_SDCARD_DATA, "SDDATA" },
{ R_SDCARD_FIFOA, "SDFIF0" },
{ R_SDCARD_FIFOA, "SDFIFO" },
{ R_SDCARD_FIFOA, "SDFIFA" },
{ R_SDCARD_FIFOA, "SDFIFO0" },
{ R_SDCARD_FIFOA, "SDFIFOA" },
{ R_SDCARD_FIFOB, "SDFIF1" },
{ R_SDCARD_FIFOB, "SDFIFB" },
{ R_SDCARD_FIFOB, "SDFIFO1" },
{ R_SDCARD_FIFOB, "SDFIFOB" },
// GPS control loop control
{ R_GPS_ALPHA, "ALPHA" },
{ R_GPS_BETA, "BETA" },
{ R_GPS_GAMMA, "GAMMA" },
{ R_GPS_STEP, "GPSSTEP" },
// Network packet interface (not built yet)
// OLED Control
{ R_OLED_CMD, "OLED" },
{ R_OLED_CDATA, "OLEDCA" },
{ R_OLED_CDATB, "OLEDCB" },
{ R_OLED_DATA, "ODATA" },
// Unused section
// GPS Testbench
{ R_GPSTB_FREQ, "GPSFREQ" },
{ R_GPSTB_JUMP, "GPSJUMP" },
{ R_GPSTB_ERRHI, "ERRHI" },
{ R_GPSTB_ERRLO, "ERRLO" },
{ R_GPSTB_COUNTHI, "CNTHI" },
{ R_GPSTB_COUNTLO, "CNTLO" },
{ R_GPSTB_STEPHI, "STEPHI" },
{ R_GPSTB_STEPLO, "STEPLO" },
//
// Ethernet MDIO registers
{ R_MDIO_BMCR, "BMCR" },
{ R_MDIO_BMSR, "BMSR" },
{ R_MDIO_PHYIDR1, "PHYIDR1" },
{ R_MDIO_PHYIDR2, "PHYIDR2" },
{ R_MDIO_ANAR, "ANAR" },
{ R_MDIO_ANLPAR, "ANLPAR" },
{ R_MDIO_ANER, "ANER" },
{ R_MDIO_ANNPTR, "ANNPTR" },
{ R_MDIO_PHYSTS, "PHYSTS" },
{ R_MDIO_FCSCR, "FCSCR" },
{ R_MDIO_RECR, "RECR" },
{ R_MDIO_PCSR, "PCSR" },
{ R_MDIO_RBR, "RBR" },
{ R_MDIO_LEDCR, "LEDCR" },
{ R_MDIO_PHYCR, "PHYCR" },
{ R_MDIO_BTSCR, "BTSCR" },
{ R_MDIO_CDCTRL, "CDCTRL" },
{ R_MDIO_EDCR, "EDCR" },
//
// Flash configuration register names
{ R_QSPI_EREG, "QSPIEREG" },
{ R_QSPI_EREG, "QSPIE" },
{ R_QSPI_STAT, "QSPIS" },
{ R_QSPI_NVCONF,"QSPINVCONF" },
{ R_QSPI_NVCONF,"QSPINV" },
{ R_QSPI_VCONF, "QSPIVCONF" },
{ R_QSPI_VCONF, "QSPIV" },
{ R_QSPI_EVCONF,"QSPIEVCONF" },
{ R_QSPI_EVCONF,"QSPIEV" },
{ R_QSPI_LOCK, "QSPILOCK" },
{ R_QSPI_FLAG, "QSPIFLAG" },
{ R_QSPI_ID, "QSPIID" },
{ R_QSPI_IDA, "QSPIIDA" },
{ R_QSPI_IDB, "QSPIIDB" },
{ R_QSPI_IDC, "QSPIIDC" },
{ R_QSPI_IDD, "QSPIIDD" },
{ R_QSPI_OTPWP, "QSPIOTPWP" },
{ R_QSPI_OTP, "QSPIOTP" },
//
{ R_CFG_CRC, "FPGACRC" },
{ R_CFG_FAR, "FPGAFAR" },
{ R_CFG_FDRI, "FPGAFDRI" },
{ R_CFG_FDRO, "FPGAFDRO" },
{ R_CFG_CMD, "FPGACMD" },
{ R_CFG_CTL0, "FPGACTL0" },
{ R_CFG_MASK, "FPGAMASK" },
{ R_CFG_STAT, "FPGASTAT" },
{ R_CFG_LOUT, "FPGALOUT" },
{ R_CFG_COR0, "FPGACOR0" },
{ R_CFG_MFWR, "FPGAMFWR" },
{ R_CFG_CBC, "FPGACBC" },
{ R_CFG_IDCODE, "FPGAIDCODE" },
{ R_CFG_AXSS, "FPGAAXSS" },
{ R_CFG_COR0, "FPGACOR1" },
{ R_CFG_WBSTAR, "WBSTAR" },
{ R_CFG_TIMER, "CFGTIMER" },
{ R_CFG_BOOTSTS,"BOOTSTS" },
{ R_CFG_CTL1, "FPGACTL1" },
{ R_CFG_BSPI, "FPGABSPI" },
//
{ R_ZIPCTRL, "ZIPCTRL" },
{ R_ZIPCTRL, "ZIPC" },
{ R_ZIPCTRL, "CPU" },
{ R_ZIPCTRL, "CPUC" },
{ R_ZIPDATA, "ZIPDATA" },
{ R_ZIPDATA, "ZIPD" },
{ R_ZIPDATA, "CPUD" },
{ EQSPIFLASH, "FLASH" },
{ MEMBASE, "BLKRAM" },
{ MEMBASE, "MEM" },
{ RAMBASE, "DDR3SDRAM" },
{ RAMBASE, "SDRAM" },
{ RAMBASE, "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;
}
 
/sw/host/scopecls.h
0,0 → 1,67
////////////////////////////////////////////////////////////////////////////////
//
// Filename: scopecls.h
//
// Project: XuLA2-LX25 SoC based upon the ZipCPU
//
// Purpose: After rebuilding the same code over and over again for every
// "scope" I tried to interact with, I thought it would be simpler
// to try to make a more generic interface, that other things could plug
// into. This is that more generic interface.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, 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.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#ifndef SCOPECLS_H
#define SCOPECLS_H
 
#include "devbus.h"
 
class SCOPE {
DEVBUS *m_fpga;
DEVBUS::BUSW m_addr;
bool m_compressed, m_vector_read;
unsigned m_scoplen;
 
public:
SCOPE(DEVBUS *fpga, unsigned addr,
bool compressed=false, bool vecread=true)
: m_fpga(fpga), m_addr(addr),
m_compressed(compressed), m_vector_read(vecread),
m_scoplen(0) {}
~SCOPE(void) {}
 
bool ready();
void decode_control(void);
virtual void decode(DEVBUS::BUSW v) const {};
int scoplen(void);
void read(void);
};
 
#endif // SCOPECLS_H
/sw/host/netuart.cpp
0,0 → 1,338
#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"
 
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, int ttyfd, int confd, int timeout) {
struct pollfd p[2];
int pv, nfds;
 
p[0].fd = ttyfd;
p[0].events = POLLIN | POLLERR;
if (confd >= 0) {
p[1].fd = confd;
p[1].events = POLLIN | POLLRDHUP | POLLERR;
nfds = 2;
} else nfds = 1;
 
if ((pv=poll(p, nfds, timeout)) < 0) {
perror("Poll Failed! O/S Err:");
exit(-1);
}
if (p[0].revents & POLLIN) {
int nr = read(ttyfd, lb.m_buf, 256);
if (nr > 0) {
// printf("%d read from TTY\n", nr);
if (confd >= 0) {
int nw;
nw = write(confd, lb.m_buf, nr);
if(nw != nr) {
// This fails when the other end resets
// the connection. Thus, we'll just
// kindly close the connection and skip
// the assert that once was at the end.
fprintf(stderr, "ERR: Could not write return string to buffer\n");
perror("O/S Err:");
close(confd);
confd = -1;
lb.m_connected = false;
nfds = 1;
// assert(nw == 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;
}
}
} else if (p[0].revents)
printf("UNKNOWN TTY EVENT: %d\n", p[0].revents);
 
if((nfds>1)&&(p[1].revents & POLLIN)) {
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;
// printf("Disconnect\n");
close(confd);
} else if (nr > 0) {
// printf("%d read from SKT\n", nr);
int nw = 0, ttlw=0;
 
errno = 0;
do {
nw = write(ttyfd, &lb.m_buf[ttlw], nr-ttlw);
 
if ((nw < 0)&&(errno == EAGAIN)) {
nw = 0;
usleep(10);
} else if (nw < 0) {
fprintf(stderr, "ERR: %4d\n", errno);
perror("O/S Err: ");
assert(nw > 0);
break;
}
// if (nw != nr-ttlw)
// printf("Only wrote %d\n", nw);
ttlw += nw;
} while(ttlw < 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 >= sizeof(lb.m_oline)-1)) {
if (lb.m_olen >= 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);
}
 
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
#ifndef LOW_SPEED
int skt = setup_listener(FPGAPORT);
#else
int skt = setup_listener(FPGAPORT+1);
#endif
int tty;
bool done = false;
 
signal(SIGSTOP, sigstop);
signal(SIGBUS, sigbus);
signal(SIGSEGV, sigsegv);
signal(SIGPIPE, SIG_IGN);
signal(SIGINT, sigint);
signal(SIGHUP, sighup);
 
if ((argc > 1)&&(NULL != strstr(argv[1], "/ttyUSB"))) {
// printf("Opening %s\n", argv[1]);
tty = open(argv[1], O_RDWR | O_NONBLOCK);
} else if (argc == 1) {
const char *deftty = "/dev/ttyUSB2";
// printf("Opening %s\n", deftty);
tty = open(deftty, O_RDWR | O_NONBLOCK);
} else {
printf("Unknown argument: %s\n", argv[1]);
exit(-2);
}
 
if (tty < 0) {
printf("Could not open tty\n");
perror("O/S Err:");
exit(-1);
} else if (isatty(tty)) {
struct termios tb;
 
printf("Setting up TTY\n");
if (tcgetattr(tty, &tb) < 0) {
printf("Could not get TTY attributes\n");
perror("O/S Err:");
exit(-2);
}
#ifndef LOW_SPEED
// Set 8 bits, 4MBaud, no parity, 1 stop bit
// const char set_highspeed[] = "00000600000PG00006";
// Set 7 bits, 4MBaud, no parity, 1 stop bit
if (false) {
const char set_highspeed[] = "0000060G000P";
const char read_qspic[] = "G0000D";
const char newline[] = "\n";
::write(tty, newline, sizeof(newline));
::write(tty, read_qspic, sizeof(read_qspic));
::write(tty, set_highspeed, sizeof(set_highspeed));
::write(tty, newline, sizeof(newline));
printf("< "); fflush(stdout);
::write(STDOUT_FILENO, read_qspic, sizeof(read_qspic));
::write(STDOUT_FILENO, set_highspeed, sizeof(set_highspeed));
::write(STDOUT_FILENO, newline, sizeof(newline));
printf("\n"); usleep(400);
tcdrain(tty);
}
#endif
 
cfmakeraw(&tb); // Sets no parity, 8 bits, one stop bit
tb.c_cflag &= (~(CRTSCTS)); // Sets no parity, 8 bit
tb.c_cflag &= (~(CSTOPB)); // One stop bit
#ifndef LOW_SPEED
// Switch to 7 bit
tb.c_cflag &= ~(CSIZE);
tb.c_cflag |= CS7;
// And 4 MBaud
cfsetispeed(&tb, B4000000);
cfsetospeed(&tb, B4000000);
#else
// Set the speed to 115200 baud
cfsetispeed(&tb, B115200);
cfsetospeed(&tb, B115200);
#endif
if (tcsetattr(tty, TCSANOW, &tb) < 0) {
printf("Could not set any TTY attributes\n");
perror("O/S Err:");
}
tcflow(tty, TCOON);
}
 
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, tty, -1, 0))
;
 
// Now, process that connection until it's gone
while(lb.m_connected) {
check_incoming(lb, tty, con, -1);
}
}
 
printf("Closing our socket\n");
close(skt);
}
 
/sw/host/dumpflash.cpp
0,0 → 1,110
////////////////////////////////////////////////////////////////////////////////
//
// Filename: dumpflash.cpp
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// 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-2016, 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.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// 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 EQSPIFLASH
#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 = true;
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("eqspidump.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;
}
 
 
/sw/host/regdefs.h
0,0 → 1,228
////////////////////////////////////////////////////////////////////////////////
//
// Filename: regdefs.h
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, 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.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// 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_VERSION 0x00000100
#define R_ICONTROL 0x00000101
#define R_BUSERR 0x00000102
#define R_PWCOUNT 0x00000103
#define R_BTNSW 0x00000104
#define R_LEDS 0x00000105
#define R_UART_SETUP 0x00000106
#define R_GPS_SETUP 0x00000107
#define R_CLR0 0x00000108
#define R_CLR1 0x00000109
#define R_CLR2 0x0000010a
#define R_CLR3 0x0000010b
#define R_DATE 0x0000010c
#define R_GPIO 0x0000010d
#define R_UARTRX 0x0000010e
#define R_UARTTX 0x0000010f
#define R_GPSRX 0x00000110
#define R_GPSTX 0x00000111
// WB Scope registers
#define R_QSCOPE 0x00000120 // Quad SPI scope ctrl
#define R_QSCOPED 0x00000121 // and data
#define R_GPSCOPE 0x00000122 // GPS configuration scope control
#define R_GPSCOPED 0x00000123 // and data, uses Mouse scope addrs
#define R_ENSCOPE 0x00000124 // Next generation UART-WISHBONE
#define R_ENSCOPED 0x00000125 // conversion scope
#define R_RAMSCOPE 0x00000126 // DDR3 SDRAM Scope
#define R_RAMSCOPED 0x00000127 //
// RTC Clock Registers
#define R_CLOCK 0x00000128
#define R_TIMER 0x00000129
#define R_STOPWATCH 0x0000012a
#define R_CKALARM 0x0000012b
// SD Card Control
#define R_SDCARD_CTRL 0x0000012c
#define R_SDCARD_DATA 0x0000012d
#define R_SDCARD_FIFOA 0x0000012e
#define R_SDCARD_FIFOB 0x0000012f
// GPS Loop control, 0x0130
#define R_GPS_ALPHA 0x00000130
#define R_GPS_BETA 0x00000131
#define R_GPS_GAMMA 0x00000132
#define R_GPS_STEP 0x00000133
// Network packet interface, 0x0134
// OLED
#define R_OLED_CMD 0x00000138
#define R_OLED_CDATA 0x00000139
#define R_OLED_CDATB 0x0000013a
#define R_OLED_DATA 0x0000013b
// Unused: 0x13c-0x13f
// GPS Testbench: 0x140-0x147
#define R_GPSTB_FREQ 0x00000140
#define R_GPSTB_JUMP 0x00000141
#define R_GPSTB_ERRHI 0x00000142
#define R_GPSTB_ERRLO 0x00000143
#define R_GPSTB_COUNTHI 0x00000144
#define R_GPSTB_COUNTLO 0x00000145
#define R_GPSTB_STEPHI 0x00000146
#define R_GPSTB_STEPLO 0x00000147
// Unused: 0x148-0x19f
// Ethernet configuration (MDIO) port: 0x1a0-0x1bf
#define R_MDIO_BMCR 0x000001a0
#define R_MDIO_BMSR 0x000001a1
#define R_MDIO_PHYIDR1 0x000001a2
#define R_MDIO_PHYIDR2 0x000001a3
#define R_MDIO_ANAR 0x000001a4
#define R_MDIO_ANLPAR 0x000001a5
// #define R_MDIO_ANLPARNP 0x000001a5
#define R_MDIO_ANER 0x000001a6
#define R_MDIO_ANNPTR 0x000001a7
#define R_MDIO_PHYSTS 0x000001b0
#define R_MDIO_FCSCR 0x000001b4
#define R_MDIO_RECR 0x000001b5
#define R_MDIO_PCSR 0x000001b6
#define R_MDIO_RBR 0x000001b7
#define R_MDIO_LEDCR 0x000001b8
#define R_MDIO_PHYCR 0x000001b9
#define R_MDIO_BTSCR 0x000001ba
#define R_MDIO_CDCTRL 0x000001bb
#define R_MDIO_EDCR 0x000001bd
// Flash: 0x1c0-0x1df
#define R_QSPI_EREG 0x000001c0
#define R_QSPI_STAT 0x000001c1
#define R_QSPI_NVCONF 0x000001c2
#define R_QSPI_VCONF 0x000001c3
#define R_QSPI_EVCONF 0x000001c4
#define R_QSPI_LOCK 0x000001c5
#define R_QSPI_FLAG 0x000001c6
// #define R_QSPI_ASYNC 0x000001c7
#define R_QSPI_ID 0x000001c8
#define R_QSPI_IDA 0x000001c9
#define R_QSPI_IDB 0x000001ca
#define R_QSPI_IDC 0x000001cb
#define R_QSPI_IDD 0x000001cc
//
#define R_QSPI_OTPWP 0x000001cf
#define R_QSPI_OTP 0x000001d0
 
// FPGA CONFIG REGISTERS: 0x1e0-0x1ff
#define R_CFG_CRC 0x000001e0
#define R_CFG_FAR 0x000001e1
#define R_CFG_FDRI 0x000001e2
#define R_CFG_FDRO 0x000001e3
#define R_CFG_CMD 0x000001e4
#define R_CFG_CTL0 0x000001e5
#define R_CFG_MASK 0x000001e6
#define R_CFG_STAT 0x000001e7
#define R_CFG_LOUT 0x000001e8
#define R_CFG_COR0 0x000001e9
#define R_CFG_MFWR 0x000001ea
#define R_CFG_CBC 0x000001eb
#define R_CFG_IDCODE 0x000001ec
#define R_CFG_AXSS 0x000001ed
#define R_CFG_COR1 0x000001ee
#define R_CFG_WBSTAR 0x000001f0
#define R_CFG_TIMER 0x000001f1
#define R_CFG_BOOTSTS 0x000001f6
#define R_CFG_CTL1 0x000001f8
#define R_CFG_BSPI 0x000001ff
// Block RAM memory space
#define MEMBASE 0x00008000
#define MEMWORDS 0x00008000
// Flash memory space
#define EQSPIFLASH 0x00400000
#define FLASHWORDS (1<<22)
// DDR3 SDRAM memory space
#define RAMBASE 0x04000000
#define RAMWORDS (1<<26)
// Zip CPU Control and Debug registers
#define R_ZIPCTRL 0x01000000
#define R_ZIPDATA 0x01000001
 
// Interrupt control constants
#define GIE 0x80000000 // Enable all interrupts
#define ISPIF_EN 0x82000200 // Enable all, enable QSPI, clear QSPI
#define ISPIF_DIS 0x02000200 // Disable all, disable QSPI
#define ISPIF_CLR 0x00000200 // Clear QSPI interrupt
#define SCOPEN 0x84000400 // Enable WBSCOPE interrupts
 
// Flash control constants
#define ERASEFLAG 0x80000000
#define DISABLEWP 0x10000000
 
#define SZPAGE 64
#define PGLEN 64
#define NPAGES 256
#define SECTORSZ (NPAGES * SZPAGE)
#define NSECTORS 64
#define SECTOROF(A) ((A) & (-1<<14))
#define PAGEOF(A) ((A) & (-1<<6))
 
#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)
 
#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
/sw/host/wbregs.cpp
0,0 → 1,139
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbregs.cpp
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// 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-2016, 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.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// 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);
}
 
void usage(void) {
printf("USAGE: wbregs address [value]\n"
"\n"
"\tWBREGS stands for Wishbone registers. It is designed to allow a\n"
"\tuser to peek and poke at registers within a given FPGA design, so\n"
"\tlong as those registers have addresses on the wishbone bus. The\n"
"\taddress may reference peripherals or memory, depending upon how the\n"
"\tbus is configured.\n"
"\n"
"\tAddress is either a 32-bit value with the syntax of strtoul, or a\n"
"\tregister name. Register names can be found in regdefs.cpp\n"
"\n"
"\tIf a value is given, that value will be written to the indicated\n"
"\taddress, otherwise the result from reading the address will be \n"
"\twritten to the screen.\n");
}
 
int main(int argc, char **argv) {
int skp=0, port = FPGAPORT;
bool use_usb = true, use_decimal = false;
 
skp=1;
for(int argn=0; argn<argc-skp; argn++) {
if (argv[argn+skp][0] == '-') {
if (argv[argn+skp][1] == 'd') {
use_decimal = true;
} else {
usage();
exit(EXIT_SUCCESS);
}
skp++; argn--;
} else
argv[argn] = argv[argn+skp];
} argc -= skp;
 
FPGAOPEN(m_fpga);
 
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;
if (use_decimal)
printf("%d\n", v);
else
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;
}
 
/sw/host/port.h
0,0 → 1,52
////////////////////////////////////////////////////////////////////////////////
//
// Filename: port.h
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, 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.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#ifndef PORT_H
#define PORT_H
 
// #define FPGAHOST "lazarus"
#define FPGAHOST "localhost"
#define FPGATTY "/dev/ttyUSB1"
#define FPGAPORT 6502
 
#ifndef FORCE_UART
#define FPGAOPEN(V) V= new FPGA(new NETCOMMS(FPGAHOST, FPGAPORT))
#else
#define FPGAOPEN(V) V= new FPGA(new TTYCOMMS(FPGATTY))
#endif
 
#endif
/sw/host/ttybus.cpp
0,0 → 1,805
//
//
// Filename: ttybus.cpp
//
// Project: UART to WISHBONE FPGA library
//
// 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
// Gisselquist Tecnology, LLC
//
// Copyright: 2015
//
//
#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 printf
#define DBGPRINTF filedump
#ifndef DBGPRINTF
#define DBGPRINTF null
#endif
 
void null(...) {}
#include <stdarg.h> // replaces the (defunct) varargs.h include file
void filedump(const char *fmt, ...) {
static FILE *dbgfp = NULL;
va_list args;
 
if (!dbgfp)
dbgfp = fopen("debug.txt", "w");
va_start(args, fmt);
vfprintf(dbgfp, fmt, args);
va_end(args);
fflush(dbgfp);
 
// If you want the debug output to go to stderr as well, you can
// uncomment the next couple of lines
// va_start(args, fmt);
// vfprintf(stderr, fmt, args);
// va_end(args);
}
 
char TTYBUS::charenc(const int sixbitval) const {
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) const {
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) const {
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) const {
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) const {
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;
int nw = 0;
 
// We'll never be called with more than MAXWRLEN words to write at once.
// This is a configurable option length, set at the top of this file.
// (currently set at 32, but subject to change ...) This is important,
// as the return channel *must* be capable of holding at least this many
// acknowledgments in its buffer.
//
// assert(len <= MAXWRLEN);
 
// 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;
 
while(nw < len) {
int ln = len-nw;
if ((unsigned)ln > MAXWRLEN)
ln = MAXWRLEN;
 
for(int i=0; i<ln; i++) {
BUSW val = buf[nw+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);
if (ln == len-nw)
*ptr++ = '\n';
*ptr = '\0';
m_dev->write(m_buf, ptr-m_buf);
DBGPRINTF(">> %s\n", m_buf);
 
readidle();
 
nw += ln;
ptr = m_buf;
}
DBGPRINTF("WR: LAST ADDRESS LEFT AT %08x\n", m_lastaddr);
 
// Need to clear the incoming queue ... if there's anything there.
// We could do a ...
// readacks(len);
// to clear a known number of acks (up to half the length of our buffer
// which we can let just sit for speed ...), or we could do a ...
// readtilidle(void);
// Then, upon startup we could also start with a readtilidle(); command.
// This would help to clear out the problems between programs, where
// one program doesn't finish reading, and the next gets a confusing
// message.
readidle();
}
 
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);
*/
writev(a, 0, len, buf);
}
 
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);
*/
writev(a, 1, len, buf);
}
 
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.
DBGPRINTF("READIO(0x%08x)\n", a);
try {
readv(a, 0, 1, &v);
} catch(BUSERR b) {
DBGPRINTF("BUSERR trying to read %08x\n", a);
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\' encodes last_addr(0x%08x) %c %d(0x%08x)\n",
ptr-m_buf, m_buf,
m_lastaddr, (diffaddr<0)?'-':'+',
diffaddr, diffaddr&0x0ffffffff);
}
 
{
// 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: ", len);
assert(len < 520);
assert(len > 0);
 
if (len <= 8) {
*ptr++ = charenc(0x20 + (((len-1)&0x07)<<1) + (inc?1:0));
DBGPRINTF("%c\n", ptr[-1]);
} else {
*ptr++ = charenc(0x30 + (((len-9)>>5)&0x0e) + (inc?1:0));
*ptr++ = charenc( (len-9) & 0x03f);
DBGPRINTF("%c%c\n", ptr[-2], ptr[-1]);
}
 
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>512)?512: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));
 
// DBGPRINTF("Reading %d words\n", (cmdrd-nread));
while(nread<(cmdrd-READAHEAD)) {
buf[nread++] = readword();
} ptr = m_buf;
} // DBGPRINTF("Reading %d words, to end the read\n", len-nread);
while(nread<len) {
buf[nread++] = readword();
}
} catch(BUSERR b) {
DBGPRINTF("READV::BUSERR trying to read %08x\n", a+((inc)?nread:0));
throw BUSERR(a+((inc)?nread:0));
}
 
if ((unsigned)m_lastaddr != (a+((inc)?(len):0))) {
DBGPRINTF("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);
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);
}
 
DBGPRINTF("READV::COMPLETE\n");
}
 
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);
DBGPRINTF("READWORD: -- lclreadcode, nr = %d, m_buf[0] = %c\n", m_buf[0]);
 
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;
DBGPRINTF("READWORD::BUSRESET (unknown addr)\n");
throw BUSERR(0);
break;
case 4:
m_interrupt_flag = true;
break;
case 5:
DBGPRINTF("READWORD::BUSERR (unknown addr)\n");
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;
 
DBGPRINTF("READ-WORD() -- sixbits = %02x\n", sixbits);
if (0x06 == (sixbits & 0x03e)) { // Tbl read, last value
rdaddr = (m_rdaddr-1)&0x03ff;
val = m_readtbl[rdaddr];
m_lastaddr += (sixbits&1);
DBGPRINTF("READ-WORD() -- repeat last value, %08x, A= %08x\n", val, m_lastaddr);
} 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);
DBGPRINTF("READ-WORD() -- long table value[%3d], %08x, A=%08x\n", idx, val, m_lastaddr);
} else if (0x20 == (sixbits & 0x030)) { // Tbl read, 2-9 into past
int idx;
idx = (((sixbits>>1)&0x07)+2);
rdaddr = (m_rdaddr - idx) & 0x03ff;
val = m_readtbl[rdaddr];
m_lastaddr += (sixbits&1);
DBGPRINTF("READ-WORD() -- short table value[%3d], %08x, A=%08x\n", idx, val, m_lastaddr);
} else if (0x38 == (sixbits & 0x038)) { // Raw read
// DBGPRINTF("READ-WORD() -- RAW-READ, nr = %d\n", nr);
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);
DBGPRINTF("READ-WORD() -- RAW-READ %02x:%02x:%02x:%02x:%02x:%02x -- %08x, A=%08x\n",
m_buf[0], m_buf[1], m_buf[2], m_buf[3],
m_buf[4], m_buf[5], val, m_lastaddr);
} else
DBGPRINTF("READ-WORD() -- Unknown character, %02x\n", sixbits);
 
return val;
}
 
void TTYBUS::readidle(void) {
TTYBUS::BUSW val = 0;
int nr;
unsigned sixbits;
bool found_start = false;
 
DBGPRINTF("READ-IDLE()\n");
 
while((!found_start)&&(m_dev->available())
&&((nr=lclreadcode(&m_buf[0], 1))>0)) {
nr = lclreadcode(&m_buf[0], 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:
// Write acknowledgement, ignore it here
// This is one of the big reasons why we are
// doing this.
break;
case 3:
m_bus_err = true;
DBGPRINTF("READ-IDLE() - BUSERR\n");
throw BUSERR(0);
break;
case 4:
m_interrupt_flag = true;
break;
case 5:
m_bus_err = true;
DBGPRINTF("READ-IDLE() - BUS RESET\n");
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);
 
/* Ignore the address, as we are in readidle();
m_addr_set = true;
m_lastaddr = val;
*/
 
DBGPRINTF("RCVD IDLE-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);
}
 
/* Ignore address, we are in readidle();
m_addr_set = true;
m_lastaddr = val;
*/
DBGPRINTF("RCVD IDLE-ADDR: 0x%08x (%d bytes)\n", val, nw+1);
} else
found_start = true;
}
 
if (found_start) {
// We're in readidle(). We don't expect to find any data.
// But ... we did. So, just read it off and ignore it.
int rdaddr;
 
DBGPRINTF("READ-IDLE() PANIC! -- sixbits = %02x\n", sixbits);
if (0x06 == (sixbits & 0x03e)) { // Tbl read, last value
rdaddr = (m_rdaddr-1)&0x03ff;
val = m_readtbl[rdaddr];
m_lastaddr += (sixbits&1);
DBGPRINTF("READ-IDLE() -- repeat last value, %08x\n", val);
} 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);
DBGPRINTF("READ-IDLE() -- long table value[%3d], %08x\n", idx, val);
} 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);
DBGPRINTF("READ-IDLE() -- short table value[%3d], %08x\n", rdaddr, val);
} 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);
DBGPRINTF("READ-IDLE() -- RAW-READ %02x:%02x:%02x:%02x:%02x:%02x -- %08x\n",
m_buf[0], m_buf[1], m_buf[2], m_buf[3],
m_buf[4], m_buf[5], val);
} else
DBGPRINTF("READ-IDLE() -- Unknown character, %02x\n", sixbits);
 
}
}
 
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
 
/sw/host/flashdrvr.cpp
0,0 → 1,216
//
//
// Filename: flashdrvr.cpp
//
// Project: FPGA library development (Basys3 development board)
//
// Purpose: Flash driver. Encapsulate writing to the flash device.
//
// 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 "regdefs.h"
#include "flashdrvr.h"
 
const bool HIGH_SPEED = false;
 
void FLASHDRVR::flwait(void) {
DEVBUS::BUSW v;
 
v = m_fpga->readio(R_QSPI_EREG);
if ((v&ERASEFLAG)==0)
return;
m_fpga->writeio(R_ICONTROL, ISPIF_DIS);
m_fpga->clear();
m_fpga->writeio(R_ICONTROL, ISPIF_EN);
 
do {
// Start by checking that we are still erasing. The interrupt
// may have been generated while we were setting things up and
// disabling things, so this just double checks for us. If
// the interrupt was tripped, we're done. If not, we can now
// wait for an interrupt.
v = m_fpga->readio(R_QSPI_EREG);
if (v&ERASEFLAG) {
m_fpga->usleep(400);
if (m_fpga->poll()) {
m_fpga->clear();
m_fpga->writeio(R_ICONTROL, ISPIF_EN);
}
}
} while(v & ERASEFLAG);
}
 
bool FLASHDRVR::erase_sector(const unsigned sector, const bool verify_erase) {
DEVBUS::BUSW page[SZPAGE];
 
printf("Erasing sector: %08x\n", sector);
m_fpga->writeio(R_QSPI_EREG, DISABLEWP);
m_fpga->writeio(R_QSPI_EREG, ERASEFLAG + sector);
 
// If we're in high speed mode and we want to verify the erase, then
// we can skip waiting for the erase to complete by issueing a read
// command immediately. As soon as the erase completes the read will
// begin sending commands back. This allows us to recover the lost
// time between the interrupt and the next command being received.
if ((!HIGH_SPEED)||(!verify_erase)) {
flwait();
 
printf("@%08x -> %08x\n", R_QSPI_EREG,
m_fpga->readio(R_QSPI_EREG));
printf("@%08x -> %08x\n", R_QSPI_SREG,
m_fpga->readio(R_QSPI_SREG));
printf("@%08x -> %08x\n", sector,
m_fpga->readio(sector));
}
 
// Now, let's verify that we erased the sector properly
if (verify_erase) {
for(int i=0; i<NPAGES; i++) {
m_fpga->readi(sector+i*SZPAGE, SZPAGE, page);
for(int i=0; i<SZPAGE; i++)
if (page[i] != 0xffffffff)
return false;
}
}
 
return true;
}
 
bool FLASHDRVR::write_page(const unsigned addr, const unsigned len,
const unsigned *data, const bool verify_write) {
DEVBUS::BUSW buf[SZPAGE];
 
assert(len > 0);
assert(len <= PGLEN);
assert(PAGEOF(addr)==PAGEOF(addr+len-1));
 
if (len <= 0)
return true;
 
// Write the page
m_fpga->writeio(R_ICONTROL, ISPIF_DIS);
m_fpga->clear();
m_fpga->writeio(R_ICONTROL, ISPIF_EN);
printf("Writing page: 0x%08x - 0x%08x\n", addr, addr+len-1);
m_fpga->writeio(R_QSPI_EREG, DISABLEWP);
m_fpga->writei(addr, len, data);
 
// If we're in high speed mode and we want to verify the write, then
// we can skip waiting for the write to complete by issueing a read
// command immediately. As soon as the write completes the read will
// begin sending commands back. This allows us to recover the lost
// time between the interrupt and the next command being received.
flwait();
// if ((!HIGH_SPEED)||(!verify_write)) { }
if (verify_write) {
// printf("Attempting to verify page\n");
// NOW VERIFY THE PAGE
m_fpga->readi(addr, len, buf);
for(int i=0; i<len; i++) {
if (buf[i] != data[i]) {
printf("\nVERIFY FAILS[%d]: %08x\n", i, i+addr);
printf("\t(Flash[%d]) %08x != %08x (Goal[%08x])\n",
i, buf[i], data[i], i+addr);
return false;
}
} // printf("\nVerify success\n");
} return true;
}
 
bool FLASHDRVR::write(const unsigned addr, const unsigned len,
const unsigned *data, const bool verify) {
// Work through this one sector at a time.
// If this buffer is equal to the sector value(s), go on
// If not, erase the sector
 
/*
fprintf(stderr, "FLASH->write(%08x, %d, ..., %s)\n", addr, len,
(verify)?"Verify":"");
*/
// m_fpga->writeio(R_QSPI_CREG, 2);
// m_fpga->readio(R_VERSION); // Read something innocuous
 
// Just to make sure the driver knows that these values are ...
// m_fpga->readio(R_QSPI_CREG);
// m_fpga->readio(R_QSPI_SREG);
// Because the status register may invoke protections here, we
// void them.
// m_fpga->writeio(R_QSPI_SREG, 0);
// m_fpga->readio(R_VERSION); // Read something innocuous
 
for(unsigned s=SECTOROF(addr); s<SECTOROF(addr+len+SECTORSZ-1); s+=SECTORSZ) {
// printf("IN LOOP, s=%08x\n", s);
// Do we need to erase?
bool need_erase = false;
unsigned newv = 0; // (s<addr)?addr:s;
{
DEVBUS::BUSW *sbuf = new DEVBUS::BUSW[SECTORSZ];
const DEVBUS::BUSW *dp;
unsigned base,ln;
base = (addr>s)?addr:s;
ln=((addr+len>s+SECTORSZ)?(s+SECTORSZ):(addr+len))-base;
m_fpga->readi(base, ln, sbuf);
 
dp = &data[base-addr];
for(unsigned i=0; i<ln; i++) {
if ((sbuf[i]&dp[i]) != dp[i]) {
printf("\nNEED-ERASE @0x%08x ... %08x != %08x (Goal)\n",
i+base-addr, sbuf[i], dp[i]);
need_erase = true;
newv = i+base;
break;
} else if ((sbuf[i] != dp[i])&&(newv == 0)) {
// if (newv == 0)
// printf("MEM[%08x] = %08x (!= %08x (Goal))\n",
// i+base, sbuf[i], dp[i]);
newv = i+base;
}
}
}
 
if (newv == 0)
continue; // This sector already matches
 
// Just erase anyway
if (!need_erase)
printf("NO ERASE NEEDED\n");
else {
printf("ERASING SECTOR: %08x\n", s);
if (!erase_sector(s, verify)) {
printf("SECTOR ERASE FAILED!\n");
return false;
} newv = (s<addr) ? addr : s;
}
for(unsigned p=newv; (p<s+SECTORSZ)&&(p<addr+len); p=PAGEOF(p+PGLEN)) {
unsigned start = p, len = addr+len-start;
 
// BUT! if we cross page boundaries, we need to clip
// our results to the page boundary
if (PAGEOF(start+len-1)!=PAGEOF(start))
len = PAGEOF(start+PGLEN)-start;
if (!write_page(start, len, &data[p-addr], verify)) {
printf("WRITE-PAGE FAILED!\n");
return false;
}
}
}
 
m_fpga->writeio(R_QSPI_EREG, 0); // Re-enable write protection
 
return true;
}
 
/sw/host/Makefile
0,0 → 1,109
################################################################################
##
## Filename: Makefile
##
## Project: OpenArty, an entirely open SoC based upon the Arty platform
##
## Purpose:
## Targets:
##
## Creator: Dan Gisselquist, Ph.D.
## Gisselquist Technology, LLC
##
################################################################################
##
## Copyright (C) 2015-2016, 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.
##
## You should have received a copy of the GNU General Public License along
## with this program. (It's in the $(ROOT)/doc directory, run make with no
## target there if the PDF file isn't present.) If not, see
## <http://www.gnu.org/licenses/> for a copy.
##
## License: GPL, v3, as defined and found on www.gnu.org,
## http://www.gnu.org/licenses/gpl.html
##
##
################################################################################
##
##
.PHONY: all
PROGRAMS := wbregs netuart wbsettime dumpflash # wbprogram
all: $(PROGRAMS)
CXX := g++
OBJDIR := obj-pc
# ZIPD := /home/dan/work/rnd/zipcpu/trunk/sw/zasm
BUSOBJS := $(OBJDIR)/ttybus.o $(OBJDIR)/llcomms.o $(OBJDIR)/regdefs.o
# BUSOBJS := $(OBJDIR)/portbus.o $(OBJDIR)/llcomms.o $(OBJDIR)/regdefs.o
SOURCES := wbregs.cpp wbprogram.cpp netuart.cpp wbsettime.cpp \
ttybus.cpp llcomms.cpp
# ziprun.cpp
# dumpmem.cpp nmea.cpp display.cpp
HEADERS := llcomms.h ttybus.h devbus.h
OBJECTS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(SOURCES)))
 
%.o: $(OBJDIR)/%.o
$(OBJDIR)/%.o: %.cpp
$(CXX) -g -c $< -o $@
 
$(OBJDIR)/hsnetuart.o: netuart.cpp
$(CXX) -g -c -DHIGH_SPEED $< -o $@
 
.PHONY: clean
clean:
rm -rf $(OBJDIR)/*.o $(PROGRAMS)
 
# dumpflash: $(OBJDIR)/dumpflash.o $(BUSOBJS)
# $(CXX) -g $^ -o $@
# wbprogram: $(OBJDIR)/wbprogram.o $(OBJDIR)/flashdrvr.o $(BUSOBJS)
# $(CXX) -g $^ -o $@
netuart: $(OBJDIR)/netuart.o
$(CXX) -g $^ -o $@
hsnetuart: $(OBJDIR)/hsnetuart.o
$(CXX) -g $^ -o $@
wbsettime: $(OBJDIR)/wbsettime.o $(BUSOBJS)
$(CXX) -g $^ -o $@
wbregs: $(OBJDIR)/wbregs.o $(BUSOBJS)
$(CXX) -g $^ -o $@
dumpflash: $(OBJDIR)/dumpflash.o $(BUSOBJS)
$(CXX) -g $^ -o $@
eqspiscope: $(OBJDIR)/eqspiscope.o $(OBJDIR)/scopecls.o $(BUSOBJS)
$(CXX) -g $^ -o $@
# ziprun: $(OBJDIR)/ziprun.o $(OBJDIR)/flashdrvr.o $(BUSOBJS)
# $(CXX) -g $^ -lelf -o $@
# zipdbg: zipdbg.cpp $(ZIPD)/zparser.cpp $(ZIPD)/zopcodes.cpp $(ZIPD)/twoc.cpp $(BUSOBJS)
# $(CXX) -g -I../bench/cpp -I $(ZIPD)/ $^ -lncurses -o $@
# zipstate: zipstate.cpp $(BUSOBJS)
# $(CXX) -g $^ -o $@
 
define build-depends
@echo "Building dependency file(s)"
@$(CXX) $(CPPFLAGS) -MM $(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"
 
-include $(OBJDIR)/depends.txt
/sw/host/devbus.h
0,0 → 1,80
//
//
// Filename: devbus.h
//
// Project: UART to WISHBONE FPGA library
//
// Purpose: The purpose of this file is to document an interface which
// any devic 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.
//
// Creator: Dan Gisselquist
// Gisselquist Tecnology, LLC
//
// Copyright: 2015
//
//
#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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.