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 |