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 **§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); |
} |
|
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 |