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

Subversion Repositories xulalx25soc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /xulalx25soc/trunk
    from Rev 28 to Rev 29
    Reverse comparison

Rev 28 → Rev 29

/sw/flashdrvr.h
0,0 → 1,53
////////////////////////////////////////////////////////////////////////////////
//
// Filename: flashdrvr.h
//
// Project: XuLA2-LX25 System on a Chip
//
// Purpose: Flash driver. Encapsulate writing to the flash device.
//
// Creator: Dan Gisselquist
// Gisselquist Tecnology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
#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/regdefs.h
57,6 → 57,12
#define R_CKALARM 0x00000113
#define R_CKSPEED 0x00000114
 
// And because the flash driver needs these constants defined ...
#define R_QSPI_EREG 0x0000010c
#define R_QSPI_CREG 0x0000010d
#define R_QSPI_SREG 0x0000010e
#define R_QSPI_IDREG 0x0000010f
 
// GPS registers
// 0x00000114
// 0x00000115
126,6 → 132,7
#define FLASHWORDS (1<<18)
// SDRAM memory space
#define SDRAMBASE 0x00800000
#define SDRAMWORDS (1<<25)
// Zip CPU Control and Debug registers
#define R_ZIPCTRL 0x01000000
#define R_ZIPDATA 0x01000001
134,6 → 141,9
// Interrupt control constants
#define GIE 0x80000000 // Enable all interrupts
#define SCOPEN 0x80080008 // Enable WBSCOPE interrupts
#define ISPIF_EN 0x80040004 // Enable SPI Flash interrupts
#define ISPIF_DIS 0x00040000 // Disable SPI Flash interrupts
#define ISPIF_CLR 0x00000004 // Clear pending SPI Flash interrupt
 
// Flash control constants
#define ERASEFLAG 0x80000000
144,8 → 154,8
#define NPAGES 32
#define SECTORSZ (NPAGES * SZPAGE)
#define NSECTORS 256
#define SECTOROF(A) (A & (-1<<10))
#define PAGEOF(A) (A & (-1<<6))
#define SECTOROF(A) ((A) & (-1<<10))
#define PAGEOF(A) ((A) & (-1<<6))
 
#define RAMLEN 0x02000
 
/sw/ziprun.cpp
45,6 → 45,9
//
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <strings.h>
#include <ctype.h>
55,28 → 58,342
#include "usbi.h"
#include "port.h"
#include "regdefs.h"
#include "flashdrvr.h"
 
bool iself(const char *fname) {
FILE *fp;
bool ret = true;
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;
}
 
SECTION **rawsection(const char *fname) {
SECTION **secpp, *secp;
unsigned num_words;
FILE *fp;
int nr;
 
fp = fopen(fname, "r");
if (fp == NULL) {
fprintf(stderr, "Could not open: %s\n", fname);
exit(-1);
}
 
if ((num_words=fgetwords(fp)) > MEMWORDS) {
fprintf(stderr, "File overruns Block RAM\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 **&sections) {
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);
}
 
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);
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_vaddr;
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[current_section]->m_start = 0;
r[current_section]->m_len = 0;
 
elf_end(e);
close(fd);
}
#endif
 
void usage(void) {
printf("USAGE: ziprun [-hmprux] <zip-program-file>\n");
printf("\n"
"\t-h\tDisplay this usage statement\n"
"\t-m\tClear unused memory locations. Note this only applies to SDRAM\n"
"\t\t(if used) and block ram, not flash.\n"
"\t-p [PORT]\tConnect to the XuLA device across a network access\n"
"\t\tconnection using port PORT, rather than attempting a USB\n"
"\t\tconnection. If PORT is not given, %s:%d will be\n"
"\t\tassumed as a default.\n"
"\t-u\tAccess the XuLA board via the USB connector [DEFAULT]\n"
"\t-x\tClear all of the ZipCPU registers to a known initial state\n\n",
FPGAHOST,FPGAPORT);
}
 
int main(int argc, char **argv) {
FILE *fp;
int nr, pos=0;
const int BUFLN = 128;
FPGA::BUSW *buf = new FPGA::BUSW[BUFLN];
int skp=0, port = FPGAPORT;
bool use_usb = true;
int skp=0, port = FPGAPORT;
bool use_usb = true, permit_raw_files = false;
unsigned entry = RAMBASE;
bool clear_registers = false, clear_memory = false;
FLASHDRVR *flash = NULL;
 
if (argc < 2) {
usage();
exit(EXIT_SUCCESS);
}
 
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') {
switch(argv[argn+skp][1]) {
case 'h':
usage();
exit(EXIT_SUCCESS);
case 'm':
clear_memory = true;
fprintf(stderr, "Clear memory feature not yet implemented\n");
exit(EXIT_FAILURE);
break;
case 'p':
use_usb = false;
if (isdigit(argv[argn+skp][2]))
port = atoi(&argv[argn+skp][2]);
}
skp++; argn--;
break;
case 'r':
permit_raw_files = true;
break;
case 'u':
use_usb = true;
break;
case 'x':
clear_registers = true;
break;
} skp++; argn--;
} else
argv[argn] = argv[argn+skp];
} argc -= skp;
92,120 → 409,143
"\tziprun loads the object file into memory, resets the CPU, and leaves it\n"
"\tin a halted state ready to start running the object file.\n");
exit(-1);
}
} const char *codef = argv[0];
 
printf("Halting the CPU\n");
m_fpga->usleep(5);
m_fpga->writeio(R_ZIPCTRL, CPU_RESET|CPU_HALT);
 
fp = fopen(argv[0], "r");
if (fp == NULL) {
fprintf(stderr, "Could not open: %s\n", argv[0]);
exit(-1);
}
 
try {
pos = RAMBASE;
while((nr=fread(buf, sizeof(FPGA::BUSW), BUFLN, fp))>0) {
// printf("Writing %4d values, pos = %08x\n", nr, pos);
m_fpga->writei(pos, nr, buf);
// printf("\tWritten\n");
pos += nr;
} printf("Successfully wrote %04x (%6d) words into memory\n",
pos-RAMBASE, pos-RAMBASE);
m_fpga->readio(R_ZIPCTRL);
SECTION **secpp = NULL, *secp;
 
// Do we want to zero out all other RAM addresses?
#define ZERO_RAM
#ifdef ZERO_RAM
unsigned int MAXRAM=2*RAMBASE;
for(int i=0; i<BUFLN; i++)
buf[i] = 0;
printf("***********************\n");
while(pos < (int)MAXRAM-BUFLN-1) {
m_fpga->writei(pos, BUFLN, buf);
m_fpga->readio(R_ZIPCTRL);
pos += BUFLN;
} m_fpga->writei(pos, MAXRAM-pos-1, buf);
pos += MAXRAM-pos-1;
if(iself(codef)) {
#ifndef CHEAP_AND_EASY
// zip-readelf will help with both of these ...
elfread(codef, entry, secpp);
 
m_fpga->usleep(500);
printf("Zerod rest of RAM - to %06x\n", pos);
fprintf(stderr, "Secpp = %08lx\n", (unsigned long)secpp);
for(int i=0; secpp[i]->m_len; i++) {
secp = secpp[i];
fprintf(stderr, "Sec[%2d] - %08x - %08x\n",
i, secp->m_start,
secp->m_start+secp->m_len);
}
#else
char tmpbuf[TMP_MAX], cmdbuf[256];
int unused_fd;
 
strcpy(tmpbuf, "/var/tmp/ziprunXXXX");
 
// Make a temporary file
unused_fd = mkostemp(tmpbuf, O_CREAT|O_TRUNC|O_RDWR);
// Close it immediately, since we won't be writing to it
// ourselves
close(unused_fd);
 
// Now we write to it, as part of calling objcopy
//
sprintf(cmdbuf, "zip-objcopy -S -O binary --reverse-bytes=4 %s %s", codef, tmpbuf);
 
if (system(cmdbuf) != 0) {
unlink(tmpbuf);
fprintf(stderr, "ZIPRUN: Could not comprehend ELF binary\n");
exit(-2);
}
 
secpp = rawsection(tmpbuf);
unlink(tmpbuf);
entry = RAMBASE;
#endif
} catch(BUSERR a) {
fprintf(stderr, "BUS Err at address 0x%08x\n", a.addr);
fprintf(stderr, "... is your program too long for this memory?\n");
m_fpga->writeio(R_ZIPCTRL, CPU_RESET|CPU_HALT|CPU_CLRCACHE);
exit(-2);
}
try {
m_fpga->readio(R_ZIPCTRL);
} catch(BUSERR a) {
fprintf(stderr, "Bus-Err? (%08x)\n", a.addr);
}
} else if (permit_raw_files) {
secpp = rawsection(codef);
entry = RAMBASE;
}
 
// Clear any buffers
printf("Clearing the cache\n");
m_fpga->writeio(R_ZIPCTRL, CPU_RESET|CPU_HALT|CPU_CLRCACHE);
// assert(secpp[1]->m_len = 0);
for(int i=0; secpp[i]->m_len; i++) {
bool valid = false;
secp= secpp[i];
if ((secp->m_start >= RAMBASE)&&(secp->m_start+secp->m_len <= RAMBASE+MEMWORDS))
valid = true;
else if ((secp->m_start >= SDRAMBASE)&&(secp->m_start+secp->m_len <= SDRAMBASE+SDRAMWORDS))
valid = true;
else if ((secp->m_start >= SPIFLASH)&&(secp->m_start+secp->m_len <= SPIFLASH+FLASHWORDS))
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(-2);
}
}
 
printf("Clearing all registers to zero, PC regs to MEMBASE\n");
// Clear all registers to zero
for(int i=0; i<32; i++) {
try {
m_fpga->writeio(R_ZIPCTRL, CPU_HALT|i);
m_fpga->readio(R_ZIPCTRL);
} catch(BUSERR a) {
fprintf(stderr, "Bus-ERR while trying to set CPUCTRL to %x\n", CPU_HALT|i);
if (clear_memory) 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)) {
FPGA::BUSW zbuf[128], a;
memset(zbuf, 0, 128*sizeof(FPGA::BUSW));
for(a=RAMBASE; a<RAMBASE+MEMWORDS; a+=128)
m_fpga->writei(a, 128, zbuf);
break;
}
}
try {
if ((i&0x0f)==0x0f)
m_fpga->writeio(R_ZIPDATA, RAMBASE);
else
m_fpga->writeio(R_ZIPDATA, 0);
// printf("REG[%2x] <= %08x\n", i, ((i&0x0f)==0x0f)?RAMBASE:0);
// m_fpga->readio(R_ZIPDATA);
// printf("\t= %08x\n", m_fpga->readio(R_ZIPDATA));
} catch(BUSERR a) {
fprintf(stderr, "Bus-ERR while trying to clear reg %x\n", i);
 
if (clear_memory) for(int i=0; secpp[i]->m_len; i++) {
secp = secpp[i];
if ((secp->m_start >= SDRAMBASE)
&&(secp->m_start+secp->m_len
<= SDRAMBASE+SDRAMWORDS)) {
FPGA::BUSW zbuf[128], a;
memset(zbuf, 0, 128*sizeof(FPGA::BUSW));
for(a=SDRAMBASE; a<SDRAMBASE+SDRAMWORDS; a+=128)
m_fpga->writei(a, 128, zbuf);
break;
}
}
}
for(int i=0; secpp[i]->m_len; i++) {
bool inflash=false;
 
printf("Clearing all peripherals\n");
for(int i=32; i<32+16; i++) {
try {
if (i==33)
continue; // Don't start the watchdog
if (i==34)
continue; // Don't start the flash cache
if (i==39)
continue; // Jiffies don't clear, don't set the intrupt
m_fpga->writeio(R_ZIPCTRL, CPU_HALT|i);
m_fpga->writeio(R_ZIPDATA, 0);
} catch (BUSERR a) {
fprintf(stderr, "Bus-ERR while trying to clear peripheral %d\n", i);
secp = secpp[i];
if ((secp->m_start >= SPIFLASH)
&&(secp->m_start+secp->m_len
<= SPIFLASH+FLASHWORDS))
inflash = true;
if (inflash) {
if (!flash)
flash = new FLASHDRVR(m_fpga);
flash->write(secp->m_start, secp->m_len, secp->m_data, true);
} else
m_fpga->writei(secp->m_start, secp->m_len, secp->m_data);
}
}
m_fpga->readio(R_ZIPCTRL);
 
printf("Starting CPU\n");
try {
m_fpga->writeio(R_ZIPCTRL, CPU_HALT|CPU_sCC); // Start in interrupt mode
// Clear any buffers
printf("Clearing the cache\n");
m_fpga->writeio(R_ZIPCTRL, CPU_RESET|CPU_HALT|CPU_CLRCACHE);
 
if (clear_registers) {
printf("Clearing all registers to zero\n");
// Clear all registers to zero
for(int i=0; i<32; i++) {
m_fpga->writeio(R_ZIPCTRL, CPU_HALT|i);
m_fpga->writeio(R_ZIPDATA, 0);
}
}
 
// Start in interrupt mode
m_fpga->writeio(R_ZIPCTRL, CPU_HALT|CPU_sCC);
m_fpga->writeio(R_ZIPDATA, 0x000);
printf("SCC <= 0x%08x\n", m_fpga->readio(R_ZIPDATA));
} catch (BUSERR a) {
fprintf(stderr, "Bus Err while trying to set CC register\n");
}
 
try {
// Set our entry point into our code
m_fpga->writeio(R_ZIPCTRL, CPU_HALT|CPU_sPC);
printf("CPU <= 0x%08x\n", m_fpga->readio(R_ZIPCTRL));
m_fpga->writeio(R_ZIPDATA, RAMBASE); // Start at the base of RAM
printf("SPC <= 0x%08x\n", m_fpga->readio(R_ZIPDATA));
} catch (BUSERR a) {
fprintf(stderr, "Bus Err while trying to set PC register\n");
m_fpga->writeio(R_ZIPDATA, entry);
} catch(BUSERR a) {
fprintf(stderr, "XULA-BUS error\n");
m_fpga->writeio(R_ZIPCTRL, CPU_RESET|CPU_HALT|CPU_CLRCACHE);
exit(-2);
}
printf("PC set to start at %08x\n", m_fpga->readio(R_ZIPDATA));
// m_fpga->writeio(R_ZIPCTRL, CPU_GO); // Release the CPU to start
 
delete m_fpga;
}
/sw/flashdrvr.cpp
0,0 → 1,217
////////////////////////////////////////////////////////////////////////////////
//
// Filename: flashdrvr.cpp
//
// Project: XuLA2-LX25 System on a Chip
//
// Purpose: Flash driver. Encapsulate writing to the flash device.
//
// Creator: Dan Gisselquist
// Gisselquist Tecnology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 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.
//
// 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 "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 v, 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 v, 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.
if ((!HIGH_SPEED)||(!verify_write)) {
flwait();
} if (verify_write) {
// 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;
}
}
} 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
 
// 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);
// 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)&&(!erase_sector(s, verify))) {
printf("SECTOR ERASE FAILED!\n");
return false;
} else if (!need_erase)
printf("NO ERASE NEEDED\n");
else {
printf("ERASING SECTOR %08x\n", s);
newv = (s<addr) ? addr : s;
}
for(unsigned p=newv; (p<s+SECTORSZ)&&(p<addr+len); p=PAGEOF(p+PGLEN))
if (!write_page(p, (p+PGLEN<addr+len)
?((PAGEOF(p)!=PAGEOF(p+PGLEN-1))?(PAGEOF(p+PGLEN-1)-p):PGLEN)
:(addr+len-p), &data[p-addr]), verify) {
printf("WRITE-PAGE FAILED!\n");
return false;
}
}
 
m_fpga->writeio(R_QSPI_EREG, 0); // Re-enable write protection
}
 
/sw/Makefile
41,8 → 41,9
OBJDIR := obj-pc
ZIPD := /home/dan/work/rnd/zipcpu/trunk/sw/zasm
BUSSRCS := ttybus.cpp llcomms.cpp regdefs.cpp usbi.cpp
SOURCES := ziprun.cpp zipdbg.cpp dumpsdram.cpp wbregs.cpp netusb.cpp $(BUSSRCS)
HEADERS := llcomms.h ttybus.h devbus.h regdefs.h usbi.h
SOURCES := ziprun.cpp zipdbg.cpp dumpsdram.cpp wbregs.cpp netusb.cpp \
flashdrvr.cpp $(BUSSRCS)
HEADERS := llcomms.h ttybus.h devbus.h regdefs.h usbi.h flashdrvr.h
OBJECTS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(SOURCES)))
BUSOBJS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(BUSSRCS)))
CFLAGS := -g -Wall $(LIBUSBINC) -I. -I../../fpgalib/sw
79,8 → 80,8
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@
dumpsdram: $(OBJDIR)/dumpsdram.o $(BUSOBJS)
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@
ziprun: $(OBJDIR)/ziprun.o $(BUSOBJS)
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@
ziprun: $(OBJDIR)/ziprun.o $(OBJDIR)/flashdrvr.o $(BUSOBJS)
$(CXX) $(CFLAGS) $^ $(LIBS) -lelf -o $@
zipstate: $(OBJDIR)/zipstate.o $(BUSOBJS)
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@
ZIPOBJS_RAW := twoc.o zparser.o zopcodes.o

powered by: WebSVN 2.1.0

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