URL
https://opencores.org/ocsvn/s6soc/s6soc/trunk
Subversion Repositories s6soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/s6soc/trunk/sw/host
- from Rev 38 to Rev 45
- ↔ Reverse comparison
Rev 38 → Rev 45
/Makefile
39,20 → 39,22
## |
## |
all: |
PROGRAMS := wbregs readflash zipload buildsamples dumpuart |
PROGRAMS := wbregs readflash zipload dumpuart |
all: $(PROGRAMS) |
|
CXX := g++ |
OBJDIR := obj-pc |
# BUSSRCS:= deppbus.cpp regdefs.cpp |
BUSSRCS:= deppi.cpp regdefs.cpp llcomms.cpp ttybus.cpp |
SOURCES:= wbregs.cpp readflash.cpp zipload.cpp flashdrvr.cpp # flashload.cpp/ziprun.cpp |
BUSSRCS:= deppi.cpp regdefs.cpp llcomms.cpp ttybus.cpp byteswap.cpp |
CPUSRCS:= zipelf.cpp |
SOURCES:= wbregs.cpp readflash.cpp zipload.cpp flashdrvr.cpp |
ALLSRCS:= $(SOURCES) $(CPUSRCS) $(BUSSRCS) |
ADEPT := ../../../refs/digilent.adept.sdk_2.3.1 |
HEADERS:= deppbus.h devbus.h flashdrvr.h regdefs.h twoc.h |
OBJECTS:= $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(SOURCES))) |
OBJECTS:= $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(ALLSRCS))) |
BUSOBJS:= $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(BUSSRCS))) |
CFLAGS := -g -Wall -I$(ADEPT)/inc -I. |
LIBS := -L /usr/lib64/digilent/adept -ldmgr -ldepp |
LIBS := -L /usr/local/lib64/digilent/adept -ldmgr -ldepp -ldpcomm -ldftd2xx -ldabs |
|
%.o: $(OBJDIR)/ $(OBJDIR)/%.o |
$(OBJDIR)/%.o: %.cpp |
65,21 → 67,21
wbregs: $(OBJDIR)/wbregs.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
|
scope: $(OBJDIR)/scope.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
|
readflash: $(OBJDIR)/readflash.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
|
zipload: $(OBJDIR)/zipload.o $(OBJDIR)/flashdrvr.o $(BUSOBJS) |
zipload: $(OBJDIR)/zipload.o $(OBJDIR)/flashdrvr.o $(BUSOBJS) $(OBJDIR)/zipelf.o |
$(CXX) $(CFLAGS) $^ $(LIBS) -lelf -o $@ |
|
buildsamples: buildsamples.cpp |
$(CXX) $(CFLAGS) $^ -o $@ |
|
dumpuart: dumpuart.cpp |
$(CXX) $(CFLAGS) $^ -o $@ |
|
define build-depends |
@echo "Building dependency file(s)" |
@$(CXX) $(CFLAGS) -MM $(SOURCES) $(BUSSRCS) > $(OBJDIR)/xdepends.txt |
@$(CXX) $(CFLAGS) -MM $(ALLSRCS) > $(OBJDIR)/xdepends.txt |
@sed -e 's/^.*.o: /$(OBJDIR)\/&/' < $(OBJDIR)/xdepends.txt > $(OBJDIR)/depends.txt |
@rm $(OBJDIR)/xdepends.txt |
endef |
/deppi.cpp
52,14 → 52,67
#include "llcomms.h" |
#include "deppi.h" |
|
DEPPI::DEPPI(char *szSel) { |
if (!DmgrOpen(&m_dev, szSel)) { |
fprintf(stderr, "Open failed!\n"); |
FILE *dbgfp = stderr; |
|
DEPPI::DEPPI(const char *szSel) { |
if ((!szSel)||(szSel[0] == '\0')) { |
// Number of digilent devcies on a system |
int pcdvc; |
|
// Go fish and try to find the device |
DmgrEnumDevices(&pcdvc); |
|
if (pcdvc < 0) { |
depperr(); |
exit(EXIT_FAILURE); |
} |
|
// |
int found = 0; // Number of devices found mtg our criteria |
DVC dvcinfo; // A structure to receive device info |
int foundid=-1; // The id number of the device we found |
|
// |
for(int devid=0; devid < pcdvc; devid++) { |
DmgrGetDvc(devid, &dvcinfo); |
// fprintf(dbgfp, "DEVICE NAME: %s\n", dvcinfo.szName); |
if (strcmp(dvcinfo.szName, "CmodS6")==0) { |
found++; |
// fprintf(dbgfp, "Found a CMOD!\n"); |
foundid = devid; |
} |
} |
|
if (found == 0) { |
fprintf(stderr, "No CModS6 devices found\n"); |
exit(EXIT_FAILURE); |
} else if (found > 1) { |
fprintf(stderr, "More than one CModS6 device found. Please consider opening your\n"); |
fprintf(stderr, "device with a valid serial number instead.\n"); |
exit(EXIT_FAILURE); |
} |
|
DmgrGetDvc(foundid, &dvcinfo); |
if (!DmgrOpen(&m_dev, dvcinfo.szConn)) { |
fprintf(stderr, "Could not open device!\n"); |
depperr(); |
exit(EXIT_FAILURE); |
} |
|
// |
DmgrFreeDvcEnum(); |
} else if (!DmgrOpen(&m_dev, (char *)szSel)) { |
// We know the device serial number, so go open that particular |
// device |
fprintf(stderr, "Named device open (DmgrOpen) failed!\n"); |
depperr(); |
exit(EXIT_FAILURE); |
} |
|
if (!DeppEnable(m_dev)) { |
fprintf(stderr, "Could not enable DEPP interface\n"); |
fprintf(stderr, "Could not enable DEPP interface to (opened) device\n"); |
|
depperr(); |
exit(EXIT_FAILURE); |
} |
|
83,10 → 136,15
void DEPPI::depperr(void) { |
ERC erc = DmgrGetLastError(); |
if(erc != ercNoErc) { |
char scode[cchErcMax], msg[cchErcMsgMax]; |
DmgrSzFromErc(erc, scode, msg); |
fprintf(stderr, "ErrCode : %s\n", scode); |
fprintf(stderr, "ErrMessage: %s\n", msg); |
char scode[cchErcMax], smsg[cchErcMsgMax]; |
DmgrSzFromErc(erc, scode, smsg); |
fprintf(stderr, "ErrCode(%d): %s\n", erc, scode); |
fprintf(stderr, "ErrMessage: %s\n", smsg); |
|
if (erc == ercCapabilityConflict) { |
fprintf(stderr, "Do you have the hardware manager in Vivado open?\n"); |
fprintf(stderr, "That could cause this conflict.\n"); |
} |
close(); |
exit(EXIT_FAILURE); |
} |
94,8 → 152,9
|
void DEPPI::write(char *buf, int len) { |
bool good = true; |
const bool dbg = false; |
|
if (false) { |
if (dbg) { |
// Debug code--write one at a time |
fputs("WR: ", stdout); |
for(int i=0; i<len; i++) { |
115,10 → 174,11
int DEPPI::read(char *buf, int len, int timeout_ms) { |
int left = len, nr=0; |
struct timespec now, later; |
const bool dbg = false; |
|
clock_gettime(CLOCK_MONOTONIC, &now); |
|
// printf("USBI::read(%d) (FIFO is %d-%d)\n", len, m_rend, m_rbeg); |
if (dbg) fprintf(dbgfp, "USBI::read(%d) (FIFO is %d-%d)\n", len, m_rend, m_rbeg); |
nr = pop_fifo(buf, left); |
left -= nr; |
|
127,7 → 187,7
nr = pop_fifo(&buf[len-left], left); |
left -= nr; |
|
// printf("\tWHILE (nr = %d, LEFT = %d, len=%d)\n", nr, left, len); |
if (dbg) fprintf(dbgfp, "\tWHILE (nr = %d, LEFT = %d, len=%d)\n", nr, left, len); |
if (nr == 0) |
break; |
#define TIMEOUT |
151,7 → 211,7
#endif |
} |
|
// printf("READ %d characters (%d req, %d left)\n", len-left, len, left); |
if(dbg) fprintf(dbgfp, "READ %d characters (%d req, %d left)\n", len-left, len, left); |
return len-left; |
} |
|
159,7 → 219,10
int empty = RCV_BUFMASK - ((m_rbeg - m_rend)&(RCV_BUFMASK)); |
int len = clen; |
bool good = true; |
const bool dbg = false; |
|
|
if (dbg) fprintf(dbgfp, "DEPPI::raw_read(len=%d)\n", clen); |
if (len > empty) |
len = empty; |
if (len > 0) { |
177,7 → 240,7
} |
} else |
good = good && DeppGetRegRepeat(m_dev, 0, (unsigned char *)m_rxbuf, ln, false); |
// fprintf(stdout, "Pushing to FIFO\n"); |
if(dbg) fprintf(dbgfp, "DEPP: Pushing to FIFO\n"); |
push_fifo(m_rxbuf, ln); |
len -= ln; |
} |
187,31 → 250,39
} |
|
void DEPPI::flush_read(void) { |
while(poll(4)) { |
const bool dbg = false; |
|
if (dbg) fprintf(dbgfp, "DEPPI::FLUSH-READ()\n"); |
|
do { |
m_rbeg = m_rend = 0; |
} |
} while(poll(4)); |
|
if (dbg) fprintf(dbgfp, "DEPPI::FLUSH-READ() -- COMPLETE\n"); |
} |
|
void DEPPI::push_fifo(char *buf, int len) { |
char last = 0; |
char *sptr = buf; |
const bool dbg = false; |
|
// fprintf(stdout, "PUSH(%d)\n", len); |
if (dbg) fprintf(dbgfp, "DEPP::PUSH(%d)\n", len); |
|
if (m_rbeg != m_rend) |
last = m_rbuf[(m_rbeg-1)&RCV_BUFMASK]; |
if (dbg) fprintf(dbgfp, "DEPPI::PUSH() last=%d, rbeg=%d, rend=%d\n", last, m_rbeg, m_rend); |
for(int i=0; i<len; i++) { |
char v = *sptr++; |
if (((v & 0x80)||((unsigned char)v < 0x10))&&(v == last)) { |
// Skipp any stuff bytes |
// fprintf(stderr, "SKIPPING-1: %02x\n", v & 0x0ff); |
if (dbg) fprintf(dbgfp, "SKIPPING-1: %02x\n", v & 0x0ff); |
} else if ((unsigned char)v == 0x0ff) { |
// Skipp any not-yet-ready bytes |
// fprintf(stdout, "SKIPPING-2: %02x\n", 0x0ff); |
if (dbg) fprintf(dbgfp, "SKIPPING-2: %02x\n", 0x0ff); |
} else { |
m_rbuf[m_rbeg] = v; |
// fprintf(stdout, "PUSHING: %02x %c\n", v&0x0ff, |
// isprint(v)?v:'.'); |
if (dbg) fprintf(dbgfp, "PUSHING: 0x%02x \'%c\'\n", |
v&0x0ff, isprint(v)?v:'.'); |
m_rbeg = (m_rbeg+1)&(RCV_BUFMASK); |
} last = v; |
} |
221,9 → 292,10
int avail = (m_rbeg - m_rend)&(RCV_BUFMASK); |
int left = len; |
int nr = 0; |
const bool dbg = false; |
|
// printf("Attempting to pop %d items from FIFO (%d - %d)\n", |
// len, m_rend, m_rbeg); |
if (dbg) fprintf(dbgfp, "Attempting to pop %d items from FIFO (%d - %d)\n", |
len, m_rend, m_rbeg); |
while((avail > 0)&&(left > 0)) { |
int ln = RCV_BUFLEN-m_rend; |
if (ln > left) |
244,10 → 316,11
bool DEPPI::poll(unsigned ms) { |
int avail = (m_rbeg-m_rend)&(RCV_BUFMASK); |
bool r = true; |
const bool dbg = false; |
|
// printf("POLL\n"); |
if (dbg) fprintf(dbgfp, "POLL\n"); |
if ((avail < 2)&&((avail<1)||(m_rbuf[m_rend]&0x80)||(m_rbuf[m_rend]<0x10))) { |
// printf("POLL -- CALLS RAW READ\n"); |
if (dbg) fprintf(dbgfp, "POLL -- CALLS RAW READ\n"); |
raw_read(4,ms); |
avail = (m_rbeg-m_rend)&(RCV_BUFMASK); |
|
259,7 → 332,7
if (avail == ((m_rbeg-m_rend)&(RCV_BUFMASK))) |
break; // We didn't read anything more |
avail = (m_rbeg-m_rend)&(RCV_BUFMASK); |
// printf("POLL/LOOP -- %d available\n", avail); |
if (dbg) fprintf(dbgfp, "POLL/LOOP -- %d available\n", avail); |
} |
if (avail < 1) |
r = false; |
267,7 → 340,7
r = false; |
} else r = false; |
} |
// printf("POLL -- is %s\n", (r)?"true":"false"); |
if (dbg) fprintf(dbgfp, "POLL -- is %s\n", (r)?"true":"false"); |
|
return r; |
} |
/deppi.h
52,6 → 52,9
#define RCV_BUFLEN 512 |
#define RCV_BUFMASK (RCV_BUFLEN-1) |
|
// #define S6SN "SN:210282768825" |
#define S6SN "" |
|
#include "llcomms.h" |
|
class DEPPI : public LLCOMMSI { // DEPP Interface |
69,7 → 72,7
void depperr(void); |
|
public: |
DEPPI(char *szSel); |
DEPPI(const char *szSel); |
~DEPPI(void); |
|
virtual void close(void); |
/dumpuart.cpp
54,7 → 54,21
const char *fname = (argc>=3)?argv[2]:NULL; |
int ttyfd = -1, dumpfd = -1; |
|
if (argc < 2) { |
fprintf(stderr, "USAGE: dumpuart /dev/tty... \n"); |
exit(EXIT_FAILURE); |
} |
|
ttyfd = open(dev, O_RDONLY); |
if (ttyfd < 0) { |
fprintf(stderr, "Could not open device, %s\n", dev); |
exit(EXIT_FAILURE); |
} |
if (!isatty(ttyfd)) { |
fprintf(stderr, "Err: %s is not a terminal!\n", dev); |
exit(EXIT_FAILURE); |
} |
|
if (fname) |
dumpfd = open(fname, O_CREAT|O_TRUNC|O_WRONLY, 0644); |
|
/flashdrvr.cpp
11,7 → 11,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2016, Gisselquist Technology, LLC |
// Copyright (C) 2016-2017, 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 |
23,6 → 23,11
// 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 |
// |
30,9 → 35,9
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdint.h> |
#include <unistd.h> |
#include <strings.h> |
#include <ctype.h> |
43,6 → 48,7
#include "devbus.h" |
#include "regdefs.h" |
#include "flashdrvr.h" |
#include "byteswap.h" |
|
const bool HIGH_SPEED = false; |
|
74,11 → 80,11
} |
|
bool FLASHDRVR::erase_sector(const unsigned sector, const bool verify_erase) { |
DEVBUS::BUSW page[SZPAGE]; |
DEVBUS::BUSW page[SZPAGEW]; |
|
printf("Erasing sector: %08x\n", sector); |
if (m_debug) printf("Erasing sector: %08x\n", sector); |
m_fpga->writeio(R_QSPI_EREG, DISABLEWP); |
m_fpga->writeio(R_QSPI_EREG, ERASEFLAG + sector); |
m_fpga->writeio(R_QSPI_EREG, ERASEFLAG + (sector>>2)); |
|
// 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 |
88,19 → 94,21
if ((!HIGH_SPEED)||(!verify_erase)) { |
flwait(); |
|
printf("@%08x -> %08x\n", R_QSPI_EREG, |
if (m_debug) { |
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, |
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++) |
m_fpga->readi(sector+i*SZPAGEW, SZPAGEW, page); |
for(int i=0; i<SZPAGEW; i++) |
if (page[i] != 0xffffffff) |
return false; |
} |
109,41 → 117,54
return true; |
} |
|
bool FLASHDRVR::write_page(const unsigned addr, const unsigned len, |
const unsigned *data, const bool verify_write) { |
DEVBUS::BUSW buf[SZPAGE]; |
bool FLASHDRVR::page_program(const unsigned addr, const unsigned len, |
const char *data, const bool verify_write) { |
DEVBUS::BUSW buf[SZPAGEW], bswapd[SZPAGEW]; |
|
assert(len > 0); |
assert(len <= PGLEN); |
assert(len <= PGLENB); |
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); |
bool empty_page = true; |
for(unsigned i=0; i<len; i+=4) { |
DEVBUS::BUSW v; |
v = buildword((const unsigned char *)&data[i]); |
bswapd[(i>>2)] = v; |
if (v != 0xffffffff) |
empty_page = false; |
} |
|
// 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 (!empty_page) { |
// 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\r", addr, addr+len-1); |
m_fpga->writeio(R_QSPI_EREG, DISABLEWP); |
m_fpga->writei(addr, (len>>2), bswapd); |
fflush(stdout); |
|
// 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(unsigned i=0; i<len; i++) { |
if (buf[i] != data[i]) { |
printf("\nVERIFY FAILS[%d]: %08x\n", i, i+addr); |
m_fpga->readi(addr, len>>2, buf); |
for(unsigned i=0; i<(len>>2); i++) { |
if (buf[i] != bswapd[i]) { |
printf("\nVERIFY FAILS[%d]: %08x\n", i, (i<<2)+addr); |
printf("\t(Flash[%d]) %08x != %08x (Goal[%08x])\n", |
i, buf[i], data[i], i+addr); |
(i<<2), buf[i], bswapd[i], (i<<2)+addr); |
return false; |
} |
} // printf("\nVerify success\n"); |
151,47 → 172,38
} |
|
bool FLASHDRVR::write(const unsigned addr, const unsigned len, |
const unsigned *data, const bool verify) { |
const char *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 |
// 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); |
for(unsigned s=SECTOROF(addr); s<SECTOROF(addr+len+SECTORSZB-1); |
s+=SECTORSZB) { |
// Do we need to erase? |
bool need_erase = false; |
bool need_erase = false, need_program = false; |
unsigned newv = 0; // (s<addr)?addr:s; |
{ |
DEVBUS::BUSW *sbuf = new DEVBUS::BUSW[SECTORSZ]; |
const DEVBUS::BUSW *dp; |
char *sbuf = new char[SECTORSZB]; |
const char *dp; // pointer to our "desired" buffer |
unsigned base,ln; |
|
base = (addr>s)?addr:s; |
ln=((addr+len>s+SECTORSZ)?(s+SECTORSZ):(addr+len))-base; |
m_fpga->readi(base, ln, sbuf); |
ln=((addr+len>s+SECTORSZB)?(s+SECTORSZB):(addr+len))-base; |
m_fpga->readi(base, ln>>2, (uint32_t *)sbuf); |
byteswapbuf(ln>>2, (uint32_t *)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]); |
if (m_debug) { |
printf("\nNEED-ERASE @0x%08x ... %08x != %08x (Goal)\n", |
i+base-addr, sbuf[i], dp[i]); |
} |
need_erase = true; |
newv = i+base; |
newv = (i&-4)+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; |
} |
} else if ((sbuf[i] != dp[i])&&(newv == 0)) |
newv = (i&-4)+base; |
} |
} |
|
198,10 → 210,10
if (newv == 0) |
continue; // This sector already matches |
|
// Just erase anyway |
if (!need_erase) |
printf("NO ERASE NEEDED\n"); |
else { |
// Erase the sector if necessary |
if (!need_erase) { |
if (m_debug) printf("NO ERASE NEEDED\n"); |
} else { |
printf("ERASING SECTOR: %08x\n", s); |
if (!erase_sector(s, verify)) { |
printf("SECTOR ERASE FAILED!\n"); |
208,21 → 220,25
return false; |
} newv = (s<addr) ? addr : s; |
} |
for(unsigned p=newv; (p<s+SECTORSZ)&&(p<addr+len); p=PAGEOF(p+PGLEN)) { |
|
// Now walk through all of our pages in this sector and write |
// to them. |
for(unsigned p=newv; (p<s+SECTORSZB)&&(p<addr+len); p=PAGEOF(p+PGLENB)) { |
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)) { |
len = PAGEOF(start+PGLENB)-start; |
if (!page_program(start, len, &data[p-addr], verify)) { |
printf("WRITE-PAGE FAILED!\n"); |
return false; |
} |
} |
} if ((need_erase)||(need_program)) |
printf("Sector 0x%08x: DONE%15s\n", s, ""); |
} |
|
m_fpga->writeio(R_QSPI_EREG, 0); // Re-enable write protection |
m_fpga->writeio(R_QSPI_EREG, ENABLEWP); // Re-enable write protection |
|
return true; |
} |
/flashdrvr.h
4,7 → 4,8
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: Flash driver. Encapsulate writing to the flash device. |
// Purpose: Flash driver. Encapsulates writing, both erasing sectors and |
// the programming pages, to the flash device. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
11,7 → 12,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// Copyright (C) 2015-2017, 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 |
24,7 → 25,7
// 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 |
// 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. |
// |
44,15 → 45,16
class FLASHDRVR { |
private: |
DEVBUS *m_fpga; |
bool m_debug; |
|
void flwait(void); |
public: |
FLASHDRVR(DEVBUS *fpga) : m_fpga(fpga) {} |
FLASHDRVR(DEVBUS *fpga) : m_fpga(fpga), m_debug(false) {} |
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 page_program(const unsigned addr, const unsigned len, |
const char *data, const bool verify_write=true); |
bool write(const unsigned addr, const unsigned len, |
const unsigned *data, const bool verify=false); |
const char *data, const bool verify=false); |
}; |
|
#endif |
/llcomms.cpp
80,8 → 80,10
} |
|
void LLCOMMSI::close(void) { |
if(m_fdw>=0) ::close(m_fdw); |
if((m_fdr>=0)&&(m_fdr != m_fdw)) ::close(m_fdr); |
if(m_fdw>=0) |
::close(m_fdw); |
if((m_fdr>=0)&&(m_fdr != m_fdw)) |
::close(m_fdr); |
m_fdw = m_fdr = -1; |
} |
|
97,6 → 99,10
} 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) { |
/llcomms.h
55,6 → 55,10
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 { |
/readflash.cpp
72,7 → 72,7
FPGA::BUSW *buf = new FPGA::BUSW[BUFLN]; |
|
char szSel[64]; |
strcpy(szSel, "SN:210282768825"); |
strcpy(szSel, S6SN); |
m_fpga = FPGAOPEN(szSel); |
|
fprintf(stderr, "Before starting, nread = %ld\n", |
/regdefs.cpp
78,16 → 78,14
{ R_QSPI_IDREG, "QSPIID" }, |
{ R_QSPI_IDREG, "QSPII" }, |
// |
{ R_CLOCK, "CLOCK" }, |
{ R_CLOCK, "TIME" }, |
{ R_TIMER, "TIMER" }, |
{ R_STOPWATCH, "STOPWACH" }, |
{ R_STOPWATCH, "STOPWATCH" }, |
{ R_CKALARM, "CKALARM" }, |
{ R_CKALARM, "ALARM" }, |
// { R_DATE, "DATE" }, |
// Scopes are defined and come and go. Be aware, therefore, not all |
// of these scopes may be defined at the same time. |
// The real-time-clock registers have been removed |
// (they never fit in the core) |
// |
// The real-time-date register has been removed |
// (it never fit either) |
// |
// The wishbone scope |
// |
{ R_SCOPE, "SCOPE" }, |
{ R_SCOPE, "SCOP" }, |
{ R_SCOPED, "SCOPDATA" }, |
95,44 → 93,8
{ R_SCOPED, "SCOPED" }, |
{ R_SCOPED, "SCOPD" }, |
// |
// For working with the ICAPE interface ... if I can ever get a |
// testing environment suitable to prove that it works. |
// The ICAPE interface registers have been removed. |
// |
{ R_CFG_CRC, "FPGACRC" }, |
{ R_CFG_FAR_MAJ, "FPGAFARH" }, |
{ R_CFG_FAR_MIN, "FPGAFARL" }, |
{ R_CFG_FDRI, "FPGAFDRI" }, |
{ R_CFG_FDRO, "FPGAFDRO" }, |
{ R_CFG_CMD, "FPGACMD" }, |
{ R_CFG_CTL, "FPGACTL" }, |
{ R_CFG_MASK, "FPGAMASK" }, |
{ R_CFG_STAT, "FPGASTAT" }, |
{ R_CFG_LOUT, "FPGALOUT" }, |
{ R_CFG_COR1, "FPGACOR1" }, |
{ R_CFG_COR2, "FPGACOR2" }, |
{ R_CFG_PWRDN, "FPGAPWRDN" }, |
{ R_CFG_FLR, "FPGAFLR" }, |
{ R_CFG_IDCODE, "FPGAIDCODE" }, |
{ R_CFG_CWDT, "FPGACWDT" }, |
{ R_CFG_HCOPT, "FPGAHCOPT" }, |
{ R_CFG_CSBO, "FPGACSBO" }, |
{ R_CFG_GEN1, "FPGAGEN1" }, |
{ R_CFG_GEN2, "FPGAGEN2" }, |
{ R_CFG_GEN3, "FPGAGEN3" }, |
{ R_CFG_GEN4, "FPGAGEN4" }, |
{ R_CFG_GEN5, "FPGAGEN5" }, |
{ R_CFG_MODE, "FPGAMODE" }, |
{ R_CFG_GWE, "FPGAGWE" }, |
{ R_CFG_GTS, "FPGAGTS" }, |
{ R_CFG_MFWR, "FPGAMFWR" }, |
{ R_CFG_CCLK, "FPGACCLK" }, |
{ R_CFG_SEU, "FPGASEU" }, |
{ R_CFG_EXP, "FPGAEXP" }, |
{ R_CFG_RDBK, "FPGARDBK" }, |
{ R_CFG_BOOTSTS, "BOOTSTS" }, |
{ R_CFG_EYE, "FPGAEYE" }, |
{ R_CFG_CBC, "FPGACBC" }, |
// |
{ RAMBASE, "MEM" }, |
{ SPIFLASH, "FLASH" } |
}; |
/regdefs.h
4,7 → 4,8
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: |
// Purpose: This file defines C constants which can be used when |
// communicating with the FPGA device from the PC host. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
11,7 → 12,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// Copyright (C) 2015-2017, 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 |
38,78 → 39,41
#ifndef REGDEFS_H |
#define REGDEFS_H |
|
#define R_VERSION 0x00000108 |
#define R_ICONTROL 0x00000100 |
#define R_BUSERR 0x00000101 |
#define R_ITIMERA 0x00000102 |
#define R_ITIMERB 0x00000103 |
#define R_PWM 0x00000104 |
#define R_SPIO 0x00000105 |
#define R_GPIO 0x00000106 |
#define R_UART 0x00000107 |
#define R_ICONTROL 0x00000400 |
#define R_BUSERR 0x00000404 |
#define R_ITIMERA 0x00000408 |
#define R_ITIMERB 0x0000040c |
#define R_PWM 0x00000410 |
#define R_SPIO 0x00000414 |
#define R_GPIO 0x00000418 |
#define R_UART 0x0000041c |
#define R_VERSION 0x00000420 |
|
// WB Scope registers |
#define R_SCOPE 0x00000200 |
#define R_SCOPED 0x00000201 |
#define R_SCOPE 0x00000800 |
#define R_SCOPED 0x00000804 |
// |
// And because the flash driver needs these constants defined ... |
#define R_QSPI_EREG 0x0000030c |
#define R_QSPI_CREG 0x0000030d |
#define R_QSPI_SREG 0x0000030e |
#define R_QSPI_IDREG 0x0000030f |
#define R_QSPI_EREG 0x00000c00 |
#define R_QSPI_CREG 0x00000c04 |
#define R_QSPI_SREG 0x00000c08 |
#define R_QSPI_IDREG 0x00000c0c |
// |
// FPGA CONFIG/ICAP REGISTERS |
#define R_CFG_CRC 0x00000400 |
#define R_CFG_FAR_MAJ 0x00000401 |
#define R_CFG_FAR_MIN 0x00000402 |
#define R_CFG_FDRI 0x00000403 |
#define R_CFG_FDRO 0x00000404 |
#define R_CFG_CMD 0x00000405 |
#define R_CFG_CTL 0x00000406 |
#define R_CFG_MASK 0x00000407 |
#define R_CFG_STAT 0x00000408 |
#define R_CFG_LOUT 0x00000409 |
#define R_CFG_COR1 0x0000040a |
#define R_CFG_COR2 0x0000040b |
#define R_CFG_PWRDN 0x0000040c |
#define R_CFG_FLR 0x0000040d |
#define R_CFG_IDCODE 0x0000040e |
#define R_CFG_CWDT 0x0000040f |
#define R_CFG_HCOPT 0x00000410 |
#define R_CFG_CSBO 0x00000412 |
#define R_CFG_GEN1 0x00000413 |
#define R_CFG_GEN2 0x00000414 |
#define R_CFG_GEN3 0x00000415 |
#define R_CFG_GEN4 0x00000416 |
#define R_CFG_GEN5 0x00000417 |
#define R_CFG_MODE 0x00000418 |
#define R_CFG_GWE 0x00000419 |
#define R_CFG_GTS 0x0000041a |
#define R_CFG_MFWR 0x0000041b |
#define R_CFG_CCLK 0x0000041c |
#define R_CFG_SEU 0x0000041d |
#define R_CFG_EXP 0x0000041e |
#define R_CFG_RDBK 0x0000041f |
#define R_CFG_BOOTSTS 0x00000420 |
#define R_CFG_EYE 0x00000421 |
#define R_CFG_CBC 0x00000422 |
// RTC clock control |
#define R_CLOCK 0x00000800 |
#define R_TIMER 0x00000801 |
#define R_STOPWATCH 0x00000802 |
#define R_CKALARM 0x00000803 |
|
// RAM memory space |
#define RAMBASE 0x00002000 |
#define MEMWORDS (1<<12) |
#define RAMLEN MEMWORDS |
#define LGMEMSZ 14 |
#define RAMBASE (1<<LGMEMSZ) |
#define MEMWORDS (1<<(LGMEMSZ-1)) |
#define RAMLEN (1<<LGMEMSZ) |
|
// Flash memory space |
#define SPIFLASH 0x00400000 |
#define FLASHWORDS (1<<22) |
#define CONFIG_ADDRESS 0x00400000 // Main Xilinx configuration (ZipCPU) |
#define ALTCONFIG_ADDRESS 0x440000 // Alternate Xilinx configuration (Debug) |
#define RESET_ADDRESS 0x00480000 // ZipCPU Reset address |
#define LGFLASHSZ 24 // Log_2 of the number of bytes in flash |
#define SPIFLASH (1<<LGFLASHSZ) |
#define FLASHWORDS (1<<(LGFLASHSZ-2)) |
#define FLASHLEN (1<<LGFLASHSZ) |
#define CONFIG_ADDRESS SPIFLASH // Main Xilinx configuration (ZipCPU) |
#define ALTCONFIG_ADDRESS (SPIFLASH+0x100000) // Alt Xilinx config (Dbg) |
#define RESET_ADDRESS (SPIFLASH+0x200000) // ZipCPU Reset address |
|
// Interrupt control constants |
#define GIE 0x80000000 // Enable all interrupts |
121,19 → 85,24
// Flash control constants |
#define ERASEFLAG 0x80000000 |
#define DISABLEWP 0x10000000 |
#define ENABLEWP 0x00000000 |
|
// Sectors are defined as 64 kB (16 kW) |
#define SZPAGE 64 // 256 bytes |
#define PGLEN 64 // 256 bytes |
#define SZPAGEB 256 |
#define PGLENB 256 |
#define SZPAGEW 64 |
#define PGLENW 64 |
#define NPAGES 256 // 64 kB sectors / 256 bytes is ... |
#define SECTORSZ (NPAGES * SZPAGE) |
#define NSECTORS (FLASHWORDS/SECTORSZ) // 256 sectors |
#define SECTOROF(A) ((A) & (-1<<14)) // 64 kB ea |
#define PAGEOF(A) ((A) & (-1<<6)) |
#define SECTORSZB (NPAGES * SZPAGEB) // In bytes, not words!! |
#define SECTORSZW (NPAGES * SZPAGEW) // In words |
#define NSECTORS (FLASHLEN/SECTORSZB) // 256 sectors |
#define SECTOROF(A) ((A) & (-1<<16)) |
#define PAGEOF(A) ((A) & (-1<<8)) |
|
// Scop definition/sequences |
#define SCOPE_NO_RESET 0x80000000 |
#define SCOPE_TRIGGER (0x08000000|SCOPE_NO_RESET) |
#define SCOPE_MANUAL SCOPE_TRIGGER |
#define SCOPE_DISABLE (0x04000000) |
|
typedef struct { |
/ttybus.cpp
1,6 → 1,6
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: ttybus.cpp |
// Filename: ttybus.cpp |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
8,9 → 8,9
// with a serial port (through DEPP) 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 from an attached host computer. |
// 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 from an attached host computer. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
17,7 → 17,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// Copyright (C) 2015-2017, 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 |
30,7 → 30,7
// 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 |
// 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. |
// |
41,7 → 41,6
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#include <sys/socket.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
69,17 → 68,20
#define TTYC_INT '4' |
#define TTYC_ERR '5' |
|
const unsigned TTYBUS::MAXRDLEN = 1024; |
const unsigned TTYBUS::MAXRDLEN = 64; |
const unsigned TTYBUS::MAXWRLEN = 32; |
|
#define DBGPRINTF null |
// #define DBGPRINTF printf |
// #define DBGPRINTF filedump |
#ifndef DBGPRINTF |
#define DBGPRINTF null |
#else |
#warning "TTYBUS DEBUG IS TURNED ON" |
#endif |
|
void null(...) {} |
#include <stdarg.h> |
// #include <varargs.h> |
/* |
|
#include <stdarg.h> // replaces the (defunct) varargs.h include file |
void filedump(const char *fmt, ...) { |
static FILE *dbgfp = NULL; |
va_list args; |
90,8 → 92,13
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) |
192,7 → 199,16
|
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); |
202,83 → 218,90
ptr = encode_address(a); |
m_lastaddr = a; m_addr_set = true; |
|
for(int i=0; i<len; i++) { |
BUSW val = buf[i]; |
while(nw < len) { |
int ln = len-nw; |
if ((unsigned)ln > MAXWRLEN) |
ln = MAXWRLEN; |
|
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; |
DBGPRINTF("WRITEV-SUB(%08x%s,#%d,&buf[%d])\n", a+nw, (p)?"++":"", ln, nw); |
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 ); |
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); |
} 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; |
m_writetbl[m_wraddr++] = val; |
m_wraddr &= 0x0ff; |
if (m_wraddr == 0) { |
m_wrloaded = true; |
} |
} |
|
if (p == 1) m_lastaddr+=4; |
} |
// *ptr++ = charenc(0x2e); |
if (ln == len-nw) |
*ptr++ = '\n'; |
*ptr = '\0'; |
m_dev->write(m_buf, ptr-m_buf); |
DBGPRINTF(">> %s\n", m_buf); |
|
if (p == 1) m_lastaddr++; |
readidle(); |
|
nw += ln; |
ptr = m_buf; |
} |
// *ptr++ = charenc(0x2e); |
*ptr++ = '\n'; *ptr = '\0'; |
m_dev->write(m_buf, ptr-m_buf); |
DBGPRINTF("WR: LAST ADDRESS LEFT AT %08x\n", m_lastaddr); |
|
DBGPRINTF(">> %s\n", 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) { |
290,6 → 313,7
try { |
readv(a, 0, 1, &v); |
} catch(BUSERR b) { |
DBGPRINTF("BUSERR trying to read %08x\n", a); |
throw BUSERR(a); |
} |
|
304,12 → 328,13
} |
|
char *TTYBUS::encode_address(const TTYBUS::BUSW a) { |
TTYBUS::BUSW addr = a; |
TTYBUS::BUSW addr = a>>2; |
char *ptr = m_buf; |
|
// #warning DEBUG_APPROACH |
// encode(0, addr, ptr); |
// return ptr+6; |
// Double check that we are aligned |
if ((a&3)!=0) { |
throw BUSERR(a); |
} |
|
if ((m_addr_set)&&(a == m_lastaddr)) |
return ptr; |
316,7 → 341,7
|
if (m_addr_set) { |
// Encode a difference address |
int diffaddr = addr - m_lastaddr; |
int diffaddr = (a - m_lastaddr)>>2; |
ptr = m_buf; |
if ((diffaddr >= -32)&&(diffaddr < 32)) { |
*ptr++ = charenc(0x09); |
338,7 → 363,10
*ptr++ = charenc( diffaddr & 0x03f); |
} |
*ptr = '\0'; |
DBGPRINTF("DIF-ADDR: (%ld) \'%s\'\n", ptr-m_buf, m_buf); |
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); |
} |
|
{ |
388,15 → 416,17
char *TTYBUS::readcmd(const int inc, const int len, char *buf) { |
char *ptr = buf; |
|
DBGPRINTF("READCMD: LEN = %d\n", len); |
DBGPRINTF("READCMD: LEN = %d: ", len); |
assert(len < 520); |
assert(len > 0); |
|
if ((len < 8)||((len == 8)&&(inc))) { |
if (len <= 8) { |
*ptr++ = charenc(0x20 + (((len-1)&0x07)<<1) + (inc?1:0)); |
DBGPRINTF("%c\n", ptr[-1]); |
} else { |
*ptr++ = charenc(0x30 + (((len-8)>>5)&0x0e) + (inc?1:0)); |
*ptr++ = charenc( (len-8) & 0x03f); |
*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; |
403,7 → 433,7
} |
|
void TTYBUS::readv(const TTYBUS::BUSW a, const int inc, const int len, TTYBUS::BUSW *buf) { |
const int READAHEAD = MAXRDLEN/2, READBLOCK=MAXRDLEN/2; |
const int READAHEAD = 0, READBLOCK=(MAXRDLEN/2>512)?512:MAXRDLEN/2; |
int cmdrd = 0, nread = 0; |
// TTYBUS::BUSW addr = a; |
char *ptr = m_buf; |
429,23 → 459,28
*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; |
} while(nread<len) { |
} // DBGPRINTF("Reading %d words, to end the read\n", len-nread); |
while(nread<len) { |
buf[nread++] = readword(); |
} |
} catch(BUSERR b) { |
throw BUSERR(a+((inc)?nread:0)); |
DBGPRINTF("READV::BUSERR trying to read %08x\n", a+((inc)?nread:0)); |
throw BUSERR(a+((inc)?(nread<<2):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); |
|
if ((unsigned)m_lastaddr != (a+((inc)?(len<<2):0))) { |
DBGPRINTF("TTYBUS::READV(a=%08x,inc=%d,len=%4x,x) ERR: (Last) %08x != %08x + %08x (Expected)\n", a, inc, len<<2, m_lastaddr, a, (inc)?(len<<2):0); |
printf("TTYBUS::READV(a=%08x,inc=%d,len=%4x,x) ERR: (Last) %08x != %08x + %08x (Expected)\n", a, inc, len<<2, m_lastaddr, a, (inc)?(len<<2):0); |
sleep(1); |
assert((int)m_lastaddr == (a+(inc)?(len):0)); |
assert((int)m_lastaddr == (a+(inc)?(len<<2):0)); |
exit(-3); |
} |
|
DBGPRINTF("READV::COMPLETE\n"); |
} |
|
void TTYBUS::readi(const TTYBUS::BUSW a, const int len, TTYBUS::BUSW *buf) { |
469,6 → 504,7
do { |
nr = lclreadcode(&m_buf[0], 1); |
} while (nr < 1); |
DBGPRINTF("READWORD: -- lclreadcode, nr = %d, m_buf[0] = %c\n", nr, m_buf[0]); |
|
sixbits = chardec(m_buf[0]); |
|
483,6 → 519,7
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: |
489,6 → 526,7
m_interrupt_flag = true; |
break; |
case 5: |
DBGPRINTF("READWORD::BUSERR (unknown addr)\n"); |
m_bus_err = true; |
throw BUSERR(0); |
break; |
506,9 → 544,9
val = (val<<6) | (chardec(m_buf[5]) & 0x03f); |
|
m_addr_set = true; |
m_lastaddr = val; |
m_lastaddr = val<<2; |
|
DBGPRINTF("RCVD ADDR: 0x%08x\n", val); |
DBGPRINTF("RCVD ADDR: 0x%08x\n", val<<2); |
} else if (0x0c == (sixbits & 0x03c)) { // Set 32-bit address,compressed |
int nw = (sixbits & 0x03) + 2; |
do { |
532,8 → 570,8
} |
|
m_addr_set = true; |
m_lastaddr = val; |
DBGPRINTF("RCVD ADDR: 0x%08x (%d bytes)\n", val, nw+1); |
m_lastaddr = val<<2; |
DBGPRINTF("RCVD ADDR: 0x%08x (%d bytes)\n", val<<2, nw+1); |
} else |
found_start = true; |
} while(!found_start); |
544,8 → 582,8
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\n", val); |
m_lastaddr += (sixbits&1)?4:0; |
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 { |
556,15 → 594,17
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\n", idx, val); |
m_lastaddr += (sixbits&1)?4:0; |
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 |
rdaddr = (m_rdaddr - (((sixbits>>1)&0x07)+2)) & 0x03ff; |
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\n", rdaddr, val); |
m_lastaddr += (sixbits&1)?4:0; |
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); |
// DBGPRINTF("READ-WORD() -- RAW-READ, nr = %d\n", nr); |
do { |
nr += lclreadcode(&m_buf[nr], 6-nr); |
} while (nr < 6); |
577,10 → 617,10
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\n", |
m_lastaddr += (sixbits&1)?4:0; |
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_buf[4], m_buf[5], val, m_lastaddr); |
} else |
DBGPRINTF("READ-WORD() -- Unknown character, %02x\n", sixbits); |
|
587,6 → 627,146
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)?4:0; |
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)?4:0; |
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)?4:0; |
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)?4:0; |
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; |
/ttybus.h
17,7 → 17,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// Copyright (C) 2015-2017, 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 |
30,7 → 30,7
// 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 |
// 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. |
// |
91,6 → 91,7
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); |
109,8 → 110,8
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 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; }; |
/wbregs.cpp
105,7 → 105,7
nm = "no name"; |
|
char szSel[64]; |
strcpy(szSel, "SN:210282768825"); |
strcpy(szSel, S6SN); |
m_fpga = FPGAOPEN(szSel); |
|
if (argc < 2) { |
/zipload.cpp
18,7 → 18,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// Copyright (C) 2015-2017, 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 |
30,6 → 30,11
// 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 |
// |
37,7 → 42,6
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <sys/types.h> |
55,304 → 59,57
#include "deppi.h" |
#include "regdefs.h" |
#include "flashdrvr.h" |
#include "zipelf.h" |
|
bool iself(const char *fname) { |
FILE *fp; |
bool ret = true; |
|
if ((!fname)||(!fname[0])) |
return false; |
|
fp = fopen(fname, "rb"); |
|
if (!fp) return false; |
if (0x7f != fgetc(fp)) ret = false; |
if ('E' != fgetc(fp)) ret = false; |
if ('L' != fgetc(fp)) ret = false; |
if ('F' != fgetc(fp)) ret = false; |
fclose(fp); |
return ret; |
} |
|
long fgetwords(FILE *fp) { |
// Return the number of words in the current file, and return the |
// file as though it had never been adjusted |
long fpos, flen; |
fpos = ftell(fp); |
if (0 != fseek(fp, 0l, SEEK_END)) { |
fprintf(stderr, "ERR: Could not determine file size\n"); |
perror("O/S Err:"); |
exit(-2); |
} flen = ftell(fp); |
if (0 != fseek(fp, fpos, SEEK_SET)) { |
fprintf(stderr, "ERR: Could not seek on file\n"); |
perror("O/S Err:"); |
exit(-2); |
} flen /= sizeof(FPGA::BUSW); |
return flen; |
} |
|
FPGA *m_fpga; |
class SECTION { |
public: |
unsigned m_start, m_len; |
FPGA::BUSW m_data[1]; |
}; |
|
SECTION **singlesection(int nwords) { |
fprintf(stderr, "NWORDS = %d\n", nwords); |
size_t sz = (2*(sizeof(SECTION)+sizeof(SECTION *)) |
+(nwords-1)*(sizeof(FPGA::BUSW))); |
char *d = (char *)malloc(sz); |
SECTION **r = (SECTION **)d; |
memset(r, 0, sz); |
r[0] = (SECTION *)(&d[2*sizeof(SECTION *)]); |
r[0]->m_len = nwords; |
r[1] = (SECTION *)(&r[0]->m_data[r[0]->m_len]); |
r[0]->m_start = 0; |
r[1]->m_start = 0; |
r[1]->m_len = 0; |
|
return r; |
void usage(void) { |
printf("USAGE: zipload [-h] [<bit-file> [<alt-bit-file>]] <zip-program-file>\n"); |
printf("\n" |
"\t-h\tDisplay this usage statement\n" |
); |
} |
|
SECTION **rawsection(const char *fname) { |
SECTION **secpp, *secp; |
unsigned num_words; |
FILE *fp; |
int nr; |
void skip_bitfile_header(FILE *fp) { |
const unsigned SEARCHLN = 204, MATCHLN = 16; |
const unsigned char matchstr[MATCHLN] = { |
0xff, 0xff, 0xff, 0xff, |
0xff, 0xff, 0xff, 0xff, |
0xff, 0xff, 0xff, 0xff, |
// |
0xaa, 0x99, 0x55, 0x66 }; |
unsigned char buf[SEARCHLN]; |
|
fp = fopen(fname, "r"); |
if (fp == NULL) { |
fprintf(stderr, "Could not open: %s\n", fname); |
exit(-1); |
} |
rewind(fp); |
fread(buf, sizeof(char), SEARCHLN, fp); |
for(int start=0; start+MATCHLN<SEARCHLN; start++) { |
int mloc; |
|
if ((num_words=fgetwords(fp)) > FLASHWORDS-(RESET_ADDRESS-SPIFLASH)) { |
fprintf(stderr, "File overruns flash memory\n"); |
exit(-1); |
} |
secpp = singlesection(num_words); |
secp = secpp[0]; |
secp->m_start = RAMBASE; |
secp->m_len = num_words; |
nr= fread(secp->m_data, sizeof(FPGA::BUSW), num_words, fp); |
if (nr != (int)num_words) { |
fprintf(stderr, "Could not read entire file\n"); |
perror("O/S Err:"); |
exit(-2); |
} assert(secpp[1]->m_len == 0); |
|
return secpp; |
} |
|
unsigned byteswap(unsigned n) { |
unsigned r; |
|
r = (n&0x0ff); n>>= 8; |
r = (r<<8) | (n&0x0ff); n>>= 8; |
r = (r<<8) | (n&0x0ff); n>>= 8; |
r = (r<<8) | (n&0x0ff); n>>= 8; |
|
return r; |
} |
|
// #define CHEAP_AND_EASY |
#ifdef CHEAP_AND_EASY |
#else |
#include <libelf.h> |
#include <gelf.h> |
|
void elfread(const char *fname, unsigned &entry, SECTION **§ions) { |
Elf *e; |
int fd, i; |
size_t n; |
char *id; |
Elf_Kind ek; |
GElf_Ehdr ehdr; |
GElf_Phdr phdr; |
const bool dbg = false; |
|
if (elf_version(EV_CURRENT) == EV_NONE) { |
fprintf(stderr, "ELF library initialization err, %s\n", elf_errmsg(-1)); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} if ((fd = open(fname, O_RDONLY, 0)) < 0) { |
fprintf(stderr, "Could not open %s\n", fname); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} if ((e = elf_begin(fd, ELF_C_READ, NULL))==NULL) { |
fprintf(stderr, "Could not run elf_begin, %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
ek = elf_kind(e); |
if (ek == ELF_K_ELF) { |
; // This is the kind of file we should expect |
} else if (ek == ELF_K_AR) { |
fprintf(stderr, "Cannot run an archive!\n"); |
exit(EXIT_FAILURE); |
} else if (ek == ELF_K_NONE) { |
; |
} else { |
fprintf(stderr, "Unexpected ELF file kind!\n"); |
exit(EXIT_FAILURE); |
} |
|
if (gelf_getehdr(e, &ehdr) == NULL) { |
fprintf(stderr, "getehdr() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} if ((i=gelf_getclass(e)) == ELFCLASSNONE) { |
fprintf(stderr, "getclass() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} if ((id = elf_getident(e, NULL)) == NULL) { |
fprintf(stderr, "getident() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} if (i != ELFCLASS32) { |
fprintf(stderr, "This is a 64-bit ELF file, ZipCPU ELF files are all 32-bit\n"); |
exit(EXIT_FAILURE); |
} |
|
if (dbg) { |
printf(" %-20s 0x%jx\n", "e_type", (uintmax_t)ehdr.e_type); |
printf(" %-20s 0x%jx\n", "e_machine", (uintmax_t)ehdr.e_machine); |
printf(" %-20s 0x%jx\n", "e_version", (uintmax_t)ehdr.e_version); |
printf(" %-20s 0x%jx\n", "e_entry", (uintmax_t)ehdr.e_entry); |
printf(" %-20s 0x%jx\n", "e_phoff", (uintmax_t)ehdr.e_phoff); |
printf(" %-20s 0x%jx\n", "e_shoff", (uintmax_t)ehdr.e_shoff); |
printf(" %-20s 0x%jx\n", "e_flags", (uintmax_t)ehdr.e_flags); |
printf(" %-20s 0x%jx\n", "e_ehsize", (uintmax_t)ehdr.e_ehsize); |
printf(" %-20s 0x%jx\n", "e_phentsize", (uintmax_t)ehdr.e_phentsize); |
printf(" %-20s 0x%jx\n", "e_shentsize", (uintmax_t)ehdr.e_shentsize); |
printf("\n"); |
} |
|
|
// Check whether or not this is an ELF file for the ZipCPU ... |
if (ehdr.e_machine != 0x0dadd) { |
fprintf(stderr, "This is not a ZipCPU ELF file\n"); |
exit(EXIT_FAILURE); |
} |
|
// Get our entry address |
entry = ehdr.e_entry; |
|
|
// Now, let's go look at the program header |
if (elf_getphdrnum(e, &n) != 0) { |
fprintf(stderr, "elf_getphdrnum() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
unsigned total_octets = 0, current_offset=0, current_section=0; |
for(i=0; i<(int)n; i++) { |
total_octets += sizeof(SECTION *)+sizeof(SECTION); |
|
if (gelf_getphdr(e, i, &phdr) != &phdr) { |
fprintf(stderr, "getphdr() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
// Search backwards, since the starting bytes just aren't that |
// interesting. |
for(mloc = MATCHLN-1; mloc >= 0; mloc--) |
if (buf[start+mloc] != matchstr[mloc]) |
break; |
if (mloc < 0) { |
fseek(fp, start, SEEK_SET); |
return; |
} |
|
if (dbg) { |
printf(" %-20s 0x%x\n", "p_type", phdr.p_type); |
printf(" %-20s 0x%jx\n", "p_offset", phdr.p_offset); |
printf(" %-20s 0x%jx\n", "p_vaddr", phdr.p_vaddr); |
printf(" %-20s 0x%jx\n", "p_paddr", phdr.p_paddr); |
printf(" %-20s 0x%jx\n", "p_filesz", phdr.p_filesz); |
printf(" %-20s 0x%jx\n", "p_memsz", phdr.p_memsz); |
printf(" %-20s 0x%x [", "p_flags", phdr.p_flags); |
|
if (phdr.p_flags & PF_X) printf(" Execute"); |
if (phdr.p_flags & PF_R) printf(" Read"); |
if (phdr.p_flags & PF_W) printf(" Write"); |
printf("]\n"); |
printf(" %-20s 0x%jx\n", "p_align", phdr.p_align); |
} |
|
total_octets += phdr.p_memsz; |
} |
|
char *d = (char *)malloc(total_octets + sizeof(SECTION)+sizeof(SECTION *)); |
memset(d, 0, total_octets); |
|
SECTION **r = sections = (SECTION **)d; |
current_offset = (n+1)*sizeof(SECTION *); |
current_section = 0; |
|
for(i=0; i<(int)n; i++) { |
r[i] = (SECTION *)(&d[current_offset]); |
|
if (gelf_getphdr(e, i, &phdr) != &phdr) { |
fprintf(stderr, "getphdr() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
if (dbg) { |
printf(" %-20s 0x%jx\n", "p_offset", phdr.p_offset); |
printf(" %-20s 0x%jx\n", "p_vaddr", phdr.p_vaddr); |
printf(" %-20s 0x%jx\n", "p_paddr", phdr.p_paddr); |
printf(" %-20s 0x%jx\n", "p_filesz", phdr.p_filesz); |
printf(" %-20s 0x%jx\n", "p_memsz", phdr.p_memsz); |
printf(" %-20s 0x%x [", "p_flags", phdr.p_flags); |
|
if (phdr.p_flags & PF_X) printf(" Execute"); |
if (phdr.p_flags & PF_R) printf(" Read"); |
if (phdr.p_flags & PF_W) printf(" Write"); |
printf("]\n"); |
|
printf(" %-20s 0x%jx\n", "p_align", phdr.p_align); |
} |
|
current_section++; |
|
r[i]->m_start = phdr.p_paddr; |
r[i]->m_len = phdr.p_filesz/ sizeof(FPGA::BUSW); |
|
current_offset += phdr.p_memsz + sizeof(SECTION); |
|
// Now, let's read in our section ... |
if (lseek(fd, phdr.p_offset, SEEK_SET) < 0) { |
fprintf(stderr, "Could not seek to file position %08lx\n", phdr.p_offset); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} if (phdr.p_filesz > phdr.p_memsz) |
phdr.p_filesz = 0; |
if (read(fd, r[i]->m_data, phdr.p_filesz) != (int)phdr.p_filesz) { |
fprintf(stderr, "Didnt read entire section\n"); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} |
|
// Next, we need to byte swap it from big to little endian |
for(unsigned j=0; j<r[i]->m_len; j++) |
r[i]->m_data[j] = byteswap(r[i]->m_data[j]); |
|
if (dbg) for(unsigned j=0; j<r[i]->m_len; j++) |
fprintf(stderr, "ADR[%04x] = %08x\n", r[i]->m_start+j, |
r[i]->m_data[j]); |
} |
|
r[i] = (SECTION *)(&d[current_offset]); |
r[current_section]->m_start = 0; |
r[current_section]->m_len = 0; |
|
elf_end(e); |
close(fd); |
fprintf(stderr, "Could not find bin-file header within bit file\n"); |
fclose(fp); |
exit(EXIT_FAILURE); |
} |
#endif |
|
void usage(void) { |
printf("USAGE: ziprun [-h] [<bit-file> [<alt-bit-file>]] <zip-program-file>\n"); |
printf("\n" |
"\t-h\tDisplay this usage statement\n"); |
} |
|
int main(int argc, char **argv) { |
int skp=0; |
bool permit_raw_files = false, debug_only = false; |
unsigned entry = RAMBASE; |
int skp=0, argn; |
bool debug_only = false, verbose = false; |
bool ignore_missing_memory = false; |
unsigned entry = 0; |
FLASHDRVR *flash = NULL; |
const char *bitfile = NULL, *altbitfile = NULL; |
const char *bitfile = NULL, *altbitfile = NULL, *execfile = NULL; |
size_t bitsz; |
FILE *fp; |
|
if (argc < 2) { |
usage(); |
360,7 → 117,7
} |
|
skp=1; |
for(int argn=0; argn<argc-skp; argn++) { |
for(argn=0; argn<argc-skp; argn++) { |
if (argv[argn+skp][0] == '-') { |
switch(argv[argn+skp][1]) { |
case 'd': |
370,8 → 127,8
usage(); |
exit(EXIT_SUCCESS); |
break; |
case 'r': |
permit_raw_files = true; |
case 'v': |
verbose = true; |
break; |
default: |
fprintf(stderr, "Unknown option, -%c\n\n", |
380,112 → 137,158
exit(EXIT_FAILURE); |
break; |
} skp++; argn--; |
} else { // Check for bit files |
int sl = strlen(argv[argn+skp]); |
if ((sl>4)&&(strcmp(&argv[argn+skp][sl-4],".bit")==0)) { |
if (bitfile == NULL) |
bitfile = argv[argn+skp]; |
else if (altbitfile == NULL) |
altbitfile = argv[argn+skp]; |
else { |
fprintf(stderr, "Err: Too many bit files listed\n"); |
exit(EXIT_FAILURE); |
} skp++; argn--; |
} else |
argv[argn] = argv[argn+skp]; |
} else { |
// Anything here must be either the program to load, |
// or a bit file to load |
argv[argn] = argv[argn+skp]; |
} |
} argc -= skp; |
|
|
for(argn=0; argn<argc; argn++) { |
if (iself(argv[argn])) { |
if (execfile) { |
printf("Too many executable files given, %s and %s\n", execfile, argv[argn]); |
usage(); |
exit(EXIT_FAILURE); |
} execfile = argv[argn]; |
} else { // if (isbitfile(argv[argn])) |
if (!bitfile) |
bitfile = argv[argn]; |
else if (!altbitfile) |
altbitfile = argv[argn]; |
else { |
printf("Unknown file name or too many files, %s\n", argv[argn]); |
usage(); |
exit(EXIT_FAILURE); |
} |
} |
} |
|
if (verbose) { |
if (bitfile) printf(" BITFILE: %s\n", bitfile); |
if (altbitfile) printf("ABITFILE: %s\n", altbitfile); |
if (execfile) printf("EXECTFILE: %s\n", execfile); |
} |
|
if ((execfile == NULL)&&(bitfile == NULL)) { |
printf("No executable or bit file(s) given!\n\n"); |
usage(); |
exit(EXIT_FAILURE); |
} |
|
if ((bitfile == NULL)&&(altbitfile != NULL)) { |
printf("Cannot program an alternate bitfile without a main bitfile\n\n"); |
usage(); |
exit(EXIT_FAILURE); |
} |
|
if ((bitfile)&&(access(bitfile,R_OK)!=0)) { |
// If there's no code file, or the code file cannot be opened |
fprintf(stderr, "Cannot open bitfile, %s\n", bitfile); |
exit(EXIT_FAILURE); |
} if ((altbitfile)&&(access(altbitfile,R_OK)!=0)) { |
fprintf(stderr, "Cannot open alternate bitfile, %s\n", |
altbitfile); |
} |
|
if ((altbitfile)&&(access(altbitfile,R_OK)!=0)) { |
// If there's no code file, or the code file cannot be opened |
fprintf(stderr, "Cannot open alternate bitfile, %s\n", altbitfile); |
exit(EXIT_FAILURE); |
} if(((!bitfile)&&(argc<=0)) || ((argc>0)&&(access(argv[0],R_OK)!=0))) { |
} if ((execfile)&&(access(execfile,R_OK)!=0)) { |
// If there's no code file, or the code file cannot be opened |
if (argc>0) |
fprintf(stderr, "Cannot open executable, %s\n", argv[0]); |
else |
usage(); |
fprintf(stderr, "Cannot open executable, %s\n\n", execfile); |
usage(); |
exit(EXIT_FAILURE); |
} else if (!iself(execfile)) { |
printf("%s is not an executable file\n\n", execfile); |
usage(); |
exit(EXIT_FAILURE); |
} |
|
const char *codef = (argc>0)?argv[0]:NULL; |
DEVBUS::BUSW *fbuf = new DEVBUS::BUSW[FLASHWORDS]; |
char *fbuf = new char[FLASHLEN]; |
|
// Set the flash buffer to all ones |
memset(fbuf, -1, FLASHWORDS*sizeof(fbuf[0])); |
memset(fbuf, -1, FLASHLEN); |
|
if (debug_only) { |
m_fpga = NULL; |
} else { |
char szSel[64]; |
strcpy(szSel, "SN:210282768825"); |
strcpy(szSel, S6SN); |
m_fpga = new FPGA(new DEPPI(szSel)); |
} |
|
// Make certain we can talk to the FPGA |
try { |
unsigned v = m_fpga->readio(R_VERSION); |
if (v < 0x20170000) { |
fprintf(stderr, "Could not communicate with board (invalid version)\n"); |
exit(EXIT_FAILURE); |
} |
} catch(BUSERR b) { |
fprintf(stderr, "Could not communicate with board (BUSERR when reading VERSION)\n"); |
exit(EXIT_FAILURE); |
} |
|
flash = (debug_only)?NULL : new FLASHDRVR(m_fpga); |
|
// First, see if we need to load a bit file |
if (bitfile) { |
int len; |
FILE *fp = fopen(bitfile, "rb"); |
|
fseek(fp, 0x5dl, SEEK_SET); |
len = fread(&fbuf[CONFIG_ADDRESS-SPIFLASH], |
fp = fopen(bitfile, "r"); |
if (strcmp(&argv[argn][strlen(argv[argn])-4],".bit")==0) |
skip_bitfile_header(fp); |
bitsz = fread(&fbuf[CONFIG_ADDRESS-SPIFLASH], |
sizeof(fbuf[0]), |
FLASHWORDS-(CONFIG_ADDRESS-SPIFLASH), fp); |
assert(len + CONFIG_ADDRESS < ALTCONFIG_ADDRESS); |
FLASHLEN - (CONFIG_ADDRESS-SPIFLASH), fp); |
fclose(fp); |
|
for(int i=0; i<4; i++) { |
// printf("0x%08x\n", fbuf[i]); |
assert(fbuf[i] == 0x0ffffffff); |
} // printf("0x%08x\n", fbuf[4]); |
assert(fbuf[4] == 0x0665599aa); |
|
printf("Loading: %s\n", bitfile); |
if ((flash)&&(!flash->write(CONFIG_ADDRESS, len, &fbuf[CONFIG_ADDRESS-SPIFLASH], true))) { |
fprintf(stderr, "Could not write primary bitfile\n"); |
exit(EXIT_FAILURE); |
try { |
printf("Loading: %s\n", bitfile); |
flash->write(CONFIG_ADDRESS, bitsz, fbuf, true); |
} catch(BUSERR b) { |
fprintf(stderr, "BUS-ERR @0x%08x\n", b.addr); |
exit(-1); |
} |
} if (altbitfile) { |
int len; |
FILE *fp = fopen(altbitfile, "rb"); |
} |
|
// The alternate configuration follows the first configuration |
len = fread(&fbuf[ALTCONFIG_ADDRESS-SPIFLASH], |
// Then see if we were given an alternate bit file |
if (altbitfile) { |
size_t altsz; |
assert(CONFIG_ADDRESS + bitsz < ALTCONFIG_ADDRESS); |
|
fp = fopen(altbitfile, "r"); |
if (strcmp(&argv[argn][strlen(argv[argn])-4],".bit")==0) |
skip_bitfile_header(fp); |
altsz = fread(&fbuf[ALTCONFIG_ADDRESS-SPIFLASH], |
sizeof(fbuf[0]), |
FLASHWORDS-(ALTCONFIG_ADDRESS-SPIFLASH), fp); |
assert(len + ALTCONFIG_ADDRESS < RESET_ADDRESS); |
FLASHLEN-(ALTCONFIG_ADDRESS-SPIFLASH), fp); |
assert(ALTCONFIG_ADDRESS+altsz < RESET_ADDRESS); |
fclose(fp); |
printf("Loading: %s\n", altbitfile); |
|
if ((flash)&&(!flash->write(ALTCONFIG_ADDRESS, len, &fbuf[ALTCONFIG_ADDRESS-SPIFLASH], true))) { |
fprintf(stderr, "Could not write alternate bitfile\n"); |
exit(EXIT_FAILURE); |
try { |
printf("Loading: %s\n", altbitfile); |
flash->write(ALTCONFIG_ADDRESS, altsz, fbuf, true); |
} catch(BUSERR b) { |
fprintf(stderr, "BUS-ERR @0x%08x\n", b.addr); |
exit(-1); |
} |
} else { |
assert(CONFIG_ADDRESS+bitsz < RESET_ADDRESS); |
} |
|
if (codef) try { |
SECTION **secpp = NULL, *secp; |
if (execfile) try { |
ELFSECTION **secpp = NULL, *secp; |
|
if(iself(codef)) { |
if(iself(execfile)) { |
// zip-readelf will help with both of these ... |
elfread(codef, entry, secpp); |
elfread(execfile, entry, secpp); |
assert(entry == RESET_ADDRESS); |
} else if (permit_raw_files) { |
secpp = rawsection(codef); |
entry = RESET_ADDRESS; |
} else { |
fprintf(stderr, "ERR: %s is not in ELF format\n", codef); |
fprintf(stderr, "ERR: %s is not in ELF format\n", execfile); |
exit(EXIT_FAILURE); |
} |
|
printf("Loading: %s\n", codef); |
printf("Loading: %s\n", execfile); |
// assert(secpp[1]->m_len = 0); |
for(int i=0; secpp[i]->m_len; i++) { |
bool valid = false; |
492,16 → 295,13
secp= secpp[i]; |
if ((secp->m_start >= RESET_ADDRESS) |
&&(secp->m_start+secp->m_len |
<= SPIFLASH+FLASHWORDS)) |
<= SPIFLASH+FLASHLEN)) |
valid = true; |
if ((secp->m_start >= RAMBASE) |
&&(secp->m_start+secp->m_len |
<= RAMBASE+MEMWORDS)) |
valid = true; |
if (!valid) { |
fprintf(stderr, "No such memory on board: 0x%08x - %08x\n", |
secp->m_start, secp->m_start+secp->m_len); |
exit(EXIT_FAILURE); |
if (!ignore_missing_memory) |
exit(EXIT_FAILURE); |
} |
} |
|
508,28 → 308,34
unsigned startaddr = RESET_ADDRESS, codelen = 0; |
for(int i=0; secpp[i]->m_len; i++) { |
secp = secpp[i]; |
if ((secp->m_start >= RAMBASE) |
&&(secp->m_start+secp->m_len |
<= RAMBASE+MEMWORDS)) { |
for(int i=0; (unsigned)i<secp->m_len; i++) { |
if (secp->m_data[i] != 0) { |
fprintf(stderr, "ERR: Cannot set RAM upon bootup!\n"); |
fprintf(stderr, "(The bootloaders just not that smart ... yet)\n"); |
fprintf(stderr, "Attempting to set %08x - %08x\n", secp->m_start, secp->m_start+secp->m_len-1); |
fprintf(stderr, "%08x cannot be set to %08x\n", secp->m_start+i, secp->m_data[i]); |
exit(EXIT_FAILURE); |
} |
} |
} else { |
if (secp->m_start < startaddr) { |
codelen += (startaddr-secp->m_start); |
startaddr = secp->m_start; |
} if (secp->m_start+secp->m_len > startaddr+codelen) { |
codelen = secp->m_start+secp->m_len-startaddr; |
} memcpy(&fbuf[secp->m_start-SPIFLASH], |
secp->m_data, |
secp->m_len*sizeof(FPGA::BUSW)); |
|
unsigned start, idx, ln; |
|
start = secp->m_start; |
idx = 0; |
ln = secp->m_len; |
if (secp->m_start < SPIFLASH) { |
start = SPIFLASH; |
idx = SPIFLASH-secp->m_start; |
if (idx > secp->m_len) |
continue; |
ln = secp->m_len-idx; |
} if (start + ln > SPIFLASH+FLASHLEN) { |
if (start > SPIFLASH+FLASHLEN) |
continue; |
ln = SPIFLASH+FLASHLEN-start; |
} |
|
// We only ever write to the flash |
if (start < startaddr) { |
// Keep track of the first address in |
// flash, as well as the last address |
// that we will write |
codelen += (startaddr-secp->m_start); |
startaddr = secp->m_start; |
} if (start+ln > startaddr+codelen) { |
codelen = secp->m_start+secp->m_len-startaddr; |
} memcpy(&fbuf[start-SPIFLASH], &secp->m_data[idx], ln); |
} |
if ((flash)&&(!flash->write(startaddr, codelen, &fbuf[startaddr-SPIFLASH], true))) { |
fprintf(stderr, "ERR: Could not write program to flash\n"); |
540,13 → 346,8
if (m_fpga) m_fpga->readio(R_VERSION); // Check for bus errors |
|
// Now ... how shall we start this CPU? |
printf("The CPU should be fully loaded, you may now start\n"); |
printf("it. To start the CPU, either toggle power or type\n"); |
printf("%% wbregs fpgagen1 0 \n"); |
printf("%% wbregs fpgagen2 0x0300 \n"); |
printf("%% wbregs fpgacmd 14 \n"); |
} catch(BUSERR a) { |
fprintf(stderr, "XULA-BUS error: %08x\n", a.addr); |
fprintf(stderr, "S6-BUS error: %08x\n", a.addr); |
exit(-2); |
} |
|