1582 lines
46 KiB
Common Lisp
1582 lines
46 KiB
Common Lisp
;;;-*- Mode: Lisp; Package: cl-user -*-
|
|
|
|
(in-package :cl-user)
|
|
|
|
(defparameter *compactimage* '(
|
|
|
|
#"
|
|
// Compact image"#
|
|
|
|
#+avr-nano
|
|
#"
|
|
/*
|
|
movepointer - corrects pointers to an object that has moved from 'from' to 'to'
|
|
*/
|
|
void movepointer (object *from, object *to) {
|
|
for (int i=0; i<WORKSPACESIZE; i++) {
|
|
object *obj = &Workspace[i];
|
|
unsigned int type = (obj->type) & ~MARKBIT;
|
|
if (marked(obj) && (type >= STRING || type==ZZERO || (type == SYMBOL && longsymbolp(obj)))) {
|
|
if (car(obj) == (object *)((uintptr_t)from | MARKBIT))
|
|
car(obj) = (object *)((uintptr_t)to | MARKBIT);
|
|
if (cdr(obj) == from) cdr(obj) = to;
|
|
}
|
|
}
|
|
// Fix strings and long symbols
|
|
for (int i=0; i<WORKSPACESIZE; i++) {
|
|
object *obj = &Workspace[i];
|
|
if (marked(obj)) {
|
|
unsigned int type = (obj->type) & ~MARKBIT;
|
|
if (type == STRING || (type == SYMBOL && longsymbolp(obj))) {
|
|
obj = cdr(obj);
|
|
while (obj != NULL) {
|
|
if (cdr(obj) == to) cdr(obj) = from;
|
|
obj = (object *)((uintptr_t)(car(obj)) & ~MARKBIT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}"#
|
|
|
|
#-avr-nano
|
|
#"
|
|
/*
|
|
movepointer - Corrects pointers to an object that has been moved from 'from' to 'to'.
|
|
Only need to scan addresses below 'from' as there are no accessible objects above that.
|
|
*/
|
|
void movepointer (object *from, object *to) {
|
|
uintptr_t limit = ((uintptr_t)(from) - (uintptr_t)(Workspace))/sizeof(uintptr_t);
|
|
for (uintptr_t i=0; i<limit; i++) {
|
|
object *obj = &Workspace[i];
|
|
unsigned int type = (obj->type) & ~MARKBIT;
|
|
if (marked(obj) && (type >= ARRAY || type==ZZERO || (type == SYMBOL && longsymbolp(obj)))) {
|
|
if (car(obj) == (object *)((uintptr_t)from | MARKBIT))
|
|
car(obj) = (object *)((uintptr_t)to | MARKBIT);
|
|
if (cdr(obj) == from) cdr(obj) = to;
|
|
}
|
|
}
|
|
// Fix strings and long symbols
|
|
for (uintptr_t i=0; i<limit; i++) {
|
|
object *obj = &Workspace[i];
|
|
if (marked(obj)) {
|
|
unsigned int type = (obj->type) & ~MARKBIT;
|
|
if (type == STRING || (type == SYMBOL && longsymbolp(obj))) {
|
|
obj = cdr(obj);
|
|
while (obj != NULL) {
|
|
if (cdr(obj) == to) cdr(obj) = from;
|
|
obj = (object *)((uintptr_t)(car(obj)) & ~MARKBIT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}"#
|
|
|
|
#"
|
|
/*
|
|
compactimage - Marks all accessible objects. Moves the last marked object down to the first free space gap, correcting
|
|
pointers by calling movepointer(). Then repeats until there are no more gaps.
|
|
*/
|
|
uintptr_t compactimage (object **arg) {
|
|
markobject(tee);
|
|
markobject(GlobalEnv);
|
|
markobject(GCStack);
|
|
object *firstfree = Workspace;
|
|
while (marked(firstfree)) firstfree++;
|
|
object *obj = &Workspace[WORKSPACESIZE-1];
|
|
while (firstfree < obj) {
|
|
if (marked(obj)) {
|
|
car(firstfree) = car(obj);
|
|
cdr(firstfree) = cdr(obj);
|
|
unmark(obj);
|
|
movepointer(obj, firstfree);
|
|
if (GlobalEnv == obj) GlobalEnv = firstfree;
|
|
if (GCStack == obj) GCStack = firstfree;
|
|
if (*arg == obj) *arg = firstfree;
|
|
while (marked(firstfree)) firstfree++;
|
|
}
|
|
obj--;
|
|
}
|
|
sweep();
|
|
return firstfree - Workspace;
|
|
}"#))
|
|
|
|
(defparameter *make-filename* '(
|
|
|
|
#-(or esp arm)
|
|
#"
|
|
// Make SD card filename
|
|
|
|
char *MakeFilename (object *arg, char *buffer) {
|
|
int max = BUFFERSIZE-1;
|
|
int i = 0;
|
|
do {
|
|
char c = nthchar(arg, i);
|
|
if (c == '\0') break;
|
|
buffer[i++] = c;
|
|
} while (i<max);
|
|
buffer[i] = '\0';
|
|
return buffer;
|
|
}"#
|
|
|
|
#+(or esp arm)
|
|
#"
|
|
// Make SD card filename
|
|
|
|
char *MakeFilename (object *arg, char *buffer) {
|
|
int max = BUFFERSIZE-1;
|
|
buffer[0]='/';
|
|
int i = 1;
|
|
do {
|
|
char c = nthchar(arg, i-1);
|
|
if (c == '\0') break;
|
|
buffer[i++] = c;
|
|
} while (i<max);
|
|
buffer[i] = '\0';
|
|
return buffer;
|
|
}"#))
|
|
|
|
#+(or avr avr-nano)
|
|
(defparameter *saveimage* #"
|
|
// Save-image and load-image
|
|
|
|
#if defined(sdcardsupport)
|
|
|
|
/*
|
|
SDBegin - a standard call on all platforms to initialise the SD Card interface.
|
|
*/
|
|
void SDBegin() {
|
|
SD.begin(SDCARD_SS_PIN);
|
|
}
|
|
|
|
void SDWriteInt (File file, int data) {
|
|
file.write(data & 0xFF); file.write(data>>8 & 0xFF);
|
|
}
|
|
|
|
int SDReadInt (File file) {
|
|
uint8_t b0 = file.read(); uint8_t b1 = file.read();
|
|
return b0 | b1<<8;
|
|
}
|
|
#elif defined(FLASHWRITESIZE)
|
|
#if defined (CPU_AVR64DD28)
|
|
// save-image area is the 6144 bytes (12 x 512-byte pages) from 0xE600 to 0xFE00
|
|
// Leave 512 bytes at the top for DxCore
|
|
const uint32_t BaseAddress = 0xE600;
|
|
uint8_t FlashCheck() {
|
|
return Flash.checkWritable();
|
|
}
|
|
|
|
void FlashWriteInt (uint32_t *addr, int data) {
|
|
if (((*addr) & 0x1FF) == 0) Flash.erasePage(BaseAddress + ((*addr) & 0xFE00));
|
|
Flash.writeWord(BaseAddress + *addr, data);
|
|
(*addr)++; (*addr)++;
|
|
}
|
|
|
|
void FlashEndWrite (uint32_t *addr) {
|
|
(void) addr;
|
|
}
|
|
|
|
uint8_t FlashReadByte (uint32_t *addr) {
|
|
return Flash.readByte(BaseAddress + (*addr)++);
|
|
}
|
|
|
|
int FlashReadInt (uint32_t *addr) {
|
|
int data = Flash.readWord(BaseAddress + *addr);
|
|
(*addr)++; (*addr)++;
|
|
return data;
|
|
}
|
|
#endif
|
|
#else
|
|
void EEPROMWriteInt (unsigned int *addr, int data) {
|
|
EEPROM.write((*addr)++, data & 0xFF); EEPROM.write((*addr)++, data>>8 & 0xFF);
|
|
}
|
|
|
|
int EEPROMReadInt (unsigned int *addr) {
|
|
uint8_t b0 = EEPROM.read((*addr)++); uint8_t b1 = EEPROM.read((*addr)++);
|
|
return b0 | b1<<8;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
saveimage - saves an image of the workspace to the persistent storage selected for the platform.
|
|
*/
|
|
unsigned int saveimage (object *arg) {
|
|
#if defined(sdcardsupport)
|
|
unsigned int imagesize = compactimage(&arg);
|
|
SDBegin();
|
|
File file;
|
|
if (stringp(arg)) {
|
|
char buffer[BUFFERSIZE];
|
|
file = SD.open(MakeFilename(arg, buffer), O_RDWR | O_CREAT | O_TRUNC);
|
|
if (!file) error2(PSTR("problem saving to SD card or invalid filename"));
|
|
arg = NULL;
|
|
} else if (arg == NULL || listp(arg)) {
|
|
file = SD.open("/ULISP.IMG", O_RDWR | O_CREAT | O_TRUNC);
|
|
if (!file) error2(PSTR("problem saving to SD card"));
|
|
}
|
|
else error(invalidarg, arg);
|
|
SDWriteInt(file, (uintptr_t)arg);
|
|
SDWriteInt(file, imagesize);
|
|
SDWriteInt(file, (uintptr_t)GlobalEnv);
|
|
SDWriteInt(file, (uintptr_t)GCStack);
|
|
#if defined(CODESIZE)
|
|
for (int i=0; i<CODESIZE; i++) file.write(MyCode[i]);
|
|
#endif
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
SDWriteInt(file, (uintptr_t)car(obj));
|
|
SDWriteInt(file, (uintptr_t)cdr(obj));
|
|
}
|
|
file.close();
|
|
return imagesize;
|
|
#elif defined(FLASHWRITESIZE)
|
|
unsigned int imagesize = compactimage(&arg);
|
|
if (!(arg == NULL || listp(arg))) error(invalidarg, arg);
|
|
if (FlashCheck()) error2(PSTR("flash write not supported"));
|
|
// Save to Flash
|
|
#if defined(CODESIZE)
|
|
int bytesneeded = 10 + CODESIZE + imagesize*4;
|
|
#else
|
|
int bytesneeded = 10 + imagesize*4;
|
|
#endif
|
|
if (bytesneeded > FLASHWRITESIZE) error(PSTR("image too large"), number(imagesize));
|
|
uint32_t addr = 0;
|
|
FlashWriteInt(&addr, (uintptr_t)arg);
|
|
FlashWriteInt(&addr, imagesize);
|
|
FlashWriteInt(&addr, (uintptr_t)GlobalEnv);
|
|
FlashWriteInt(&addr, (uintptr_t)GCStack);
|
|
#if defined(CODESIZE)
|
|
for (int i=0; i<CODESIZE/2; i++) FlashWriteInt(&addr, MyCode[i*2] | MyCode[i*2+1]<<8);
|
|
#endif
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
FlashWriteInt(&addr, (uintptr_t)car(obj));
|
|
FlashWriteInt(&addr, (uintptr_t)cdr(obj));
|
|
}
|
|
FlashEndWrite(&addr);
|
|
return imagesize;
|
|
#elif defined(EEPROMSIZE)
|
|
unsigned int imagesize = compactimage(&arg);
|
|
if (!(arg == NULL || listp(arg))) error(invalidarg, arg);
|
|
int bytesneeded = imagesize*4 + 10;
|
|
if (bytesneeded > EEPROMSIZE) error(PSTR("image too large"), number(imagesize));
|
|
unsigned int addr = 0;
|
|
EEPROMWriteInt(&addr, (unsigned int)arg);
|
|
EEPROMWriteInt(&addr, imagesize);
|
|
EEPROMWriteInt(&addr, (unsigned int)GlobalEnv);
|
|
EEPROMWriteInt(&addr, (unsigned int)GCStack);
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
EEPROMWriteInt(&addr, (uintptr_t)car(obj));
|
|
EEPROMWriteInt(&addr, (uintptr_t)cdr(obj));
|
|
}
|
|
return imagesize;
|
|
#else
|
|
(void) arg;
|
|
error2(PSTR("not available"));
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
loadimage - loads an image of the workspace from the persistent storage selected for the platform.
|
|
*/
|
|
unsigned int loadimage (object *arg) {
|
|
#if defined(sdcardsupport)
|
|
SDBegin();
|
|
File file;
|
|
if (stringp(arg)) {
|
|
char buffer[BUFFERSIZE];
|
|
file = SD.open(MakeFilename(arg, buffer));
|
|
if (!file) error2(PSTR("problem loading from SD card or invalid filename"));
|
|
}
|
|
else if (arg == NULL) {
|
|
file = SD.open("/ULISP.IMG");
|
|
if (!file) error2(PSTR("problem loading from SD card"));
|
|
}
|
|
else error(invalidarg, arg);
|
|
SDReadInt(file);
|
|
unsigned int imagesize = SDReadInt(file);
|
|
GlobalEnv = (object *)SDReadInt(file);
|
|
GCStack = (object *)SDReadInt(file);
|
|
#if defined(CODESIZE)
|
|
for (int i=0; i<CODESIZE; i++) MyCode[i] = file.read();
|
|
#endif
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)SDReadInt(file);
|
|
cdr(obj) = (object *)SDReadInt(file);
|
|
}
|
|
file.close();
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#elif defined(FLASHWRITESIZE)
|
|
(void) arg;
|
|
if (FlashCheck()) error2(PSTR("flash write not supported"));
|
|
uint32_t addr = 0;
|
|
FlashReadInt(&addr); // Skip eval address
|
|
unsigned int imagesize = FlashReadInt(&addr);
|
|
if (imagesize == 0 || imagesize == 0xFFFF) error2(PSTR("no saved image"));
|
|
GlobalEnv = (object *)FlashReadInt(&addr);
|
|
GCStack = (object *)FlashReadInt(&addr);
|
|
#if defined(CODESIZE)
|
|
for (int i=0; i<CODESIZE; i++) MyCode[i] = FlashReadByte(&addr);
|
|
#endif
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)FlashReadInt(&addr);
|
|
cdr(obj) = (object *)FlashReadInt(&addr);
|
|
}
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#elif defined(EEPROMSIZE)
|
|
(void) arg;
|
|
unsigned int addr = 2; // Skip eval address
|
|
unsigned int imagesize = EEPROMReadInt(&addr);
|
|
if (imagesize == 0 || imagesize == 0xFFFF) error2(PSTR("no saved image"));
|
|
GlobalEnv = (object *)EEPROMReadInt(&addr);
|
|
GCStack = (object *)EEPROMReadInt(&addr);
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)EEPROMReadInt(&addr);
|
|
cdr(obj) = (object *)EEPROMReadInt(&addr);
|
|
}
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#else
|
|
(void) arg;
|
|
error2(PSTR("not available"));
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
autorunimage - loads and runs an image of the workspace from the persistent storage selected for the platform.
|
|
*/
|
|
void autorunimage () {
|
|
#if defined(sdcardsupport)
|
|
SDBegin();
|
|
File file = SD.open("ULISP.IMG");
|
|
if (!file) error2(PSTR("problem autorunning from SD card"));
|
|
object *autorun = (object *)SDReadInt(file);
|
|
file.close();
|
|
if (autorun != NULL) {
|
|
loadimage(NULL);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#elif defined(FLASHWRITESIZE)
|
|
uint32_t addr = 0;
|
|
object *autorun = (object *)FlashReadInt(&addr);
|
|
if (autorun != NULL && (unsigned int)autorun != 0xFFFF) {
|
|
loadimage(nil);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#elif defined(EEPROMSIZE)
|
|
unsigned int addr = 0;
|
|
object *autorun = (object *)EEPROMReadInt(&addr);
|
|
if (autorun != NULL && (unsigned int)autorun != 0xFFFF) {
|
|
loadimage(nil);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#else
|
|
error2(PSTR("not available"));
|
|
#endif
|
|
}"#)
|
|
|
|
#+arm
|
|
(defparameter *saveimage* #"
|
|
// Save-image and load-image
|
|
|
|
#if defined(sdcardsupport)
|
|
|
|
/*
|
|
SDBegin - a standard call on all platforms to initialise the SD Card interface.
|
|
*/
|
|
void SDBegin() {
|
|
#if defined(ARDUINO_ADAFRUIT_FEATHER_RP2040_ADALOGGER)
|
|
SD.begin(SDCARD_SS_PIN, SPI1);
|
|
#else
|
|
SD.begin(SDCARD_SS_PIN);
|
|
#endif
|
|
}
|
|
|
|
void SDWrite32 (File file, int data) {
|
|
file.write(data & 0xFF); file.write(data>>8 & 0xFF);
|
|
file.write(data>>16 & 0xFF); file.write(data>>24 & 0xFF);
|
|
}
|
|
|
|
int SDRead32 (File file) {
|
|
uintptr_t b0 = file.read(); uintptr_t b1 = file.read();
|
|
uintptr_t b2 = file.read(); uintptr_t b3 = file.read();
|
|
return b0 | b1<<8 | b2<<16 | b3<<24;
|
|
}
|
|
#elif defined(LITTLEFS)
|
|
void FSWrite32 (File file, uint32_t data) {
|
|
union { uint32_t data2; uint8_t u8[4]; };
|
|
data2 = data;
|
|
if (file.write(u8, 4) != 4) error2(PSTR("not enough room"));
|
|
}
|
|
|
|
uint32_t FSRead32 (File file) {
|
|
union { uint32_t data; uint8_t u8[4]; };
|
|
file.read(u8, 4);
|
|
return data;
|
|
}
|
|
#elif defined(DATAFLASH)
|
|
// Winbond DataFlash support for Adafruit M4 Express boards
|
|
#define PAGEPROG 0x02
|
|
#define READSTATUS 0x05
|
|
#define READDATA 0x03
|
|
#define WRITEENABLE 0x06
|
|
#define BLOCK64K 0xD8
|
|
#define READID 0x90
|
|
|
|
// Arduino pins used for dataflash
|
|
#if defined(ARDUINO_ITSYBITSY_M0) || defined(ARDUINO_SAMD_FEATHER_M0_EXPRESS)
|
|
const int sck = 38, ssel = 39, mosi = 37, miso = 36;
|
|
#elif defined(EXTERNAL_FLASH_USE_QSPI)
|
|
const int sck = PIN_QSPI_SCK, ssel = PIN_QSPI_CS, mosi = PIN_QSPI_IO0, miso = PIN_QSPI_IO1;
|
|
#endif
|
|
|
|
void FlashBusy () {
|
|
digitalWrite(ssel, 0);
|
|
FlashWrite(READSTATUS);
|
|
while ((FlashReadByte() & 1) != 0);
|
|
digitalWrite(ssel, 1);
|
|
}
|
|
|
|
inline void FlashWrite (uint8_t data) {
|
|
shiftOut(mosi, sck, MSBFIRST, data);
|
|
}
|
|
|
|
inline uint8_t FlashReadByte () {
|
|
return shiftIn(miso, sck, MSBFIRST);
|
|
}
|
|
|
|
void FlashWriteByte (uint32_t *addr, uint8_t data) {
|
|
// New page
|
|
if (((*addr) & 0xFF) == 0) {
|
|
digitalWrite(ssel, 1);
|
|
FlashBusy();
|
|
FlashWriteEnable();
|
|
digitalWrite(ssel, 0);
|
|
FlashWrite(PAGEPROG);
|
|
FlashWrite((*addr)>>16);
|
|
FlashWrite((*addr)>>8);
|
|
FlashWrite(0);
|
|
}
|
|
FlashWrite(data);
|
|
(*addr)++;
|
|
}
|
|
|
|
void FlashWriteEnable () {
|
|
digitalWrite(ssel, 0);
|
|
FlashWrite(WRITEENABLE);
|
|
digitalWrite(ssel, 1);
|
|
}
|
|
|
|
bool FlashCheck () {
|
|
uint8_t devID;
|
|
digitalWrite(ssel, HIGH); pinMode(ssel, OUTPUT);
|
|
pinMode(sck, OUTPUT);
|
|
pinMode(mosi, OUTPUT);
|
|
pinMode(miso, INPUT);
|
|
digitalWrite(sck, LOW); digitalWrite(mosi, HIGH);
|
|
digitalWrite(ssel, LOW);
|
|
FlashWrite(READID);
|
|
for (uint8_t i=0; i<4; i++) FlashReadByte();
|
|
devID = FlashReadByte();
|
|
digitalWrite(ssel, HIGH);
|
|
return (devID >= 0x14 && devID <= 0x17); // true = found correct device
|
|
}
|
|
|
|
void FlashBeginWrite (uint32_t *addr, uint32_t bytes) {
|
|
*addr = 0;
|
|
uint8_t blocks = (bytes+65535)/65536;
|
|
// Erase 64K
|
|
for (uint8_t b=0; b<blocks; b++) {
|
|
FlashWriteEnable();
|
|
digitalWrite(ssel, 0);
|
|
FlashWrite(BLOCK64K);
|
|
FlashWrite(b); FlashWrite(0); FlashWrite(0);
|
|
digitalWrite(ssel, 1);
|
|
FlashBusy();
|
|
}
|
|
}
|
|
|
|
void FlashWrite32 (uint32_t *addr, uint32_t data) {
|
|
FlashWriteByte(addr, data & 0xFF); FlashWriteByte(addr, data>>8 & 0xFF);
|
|
FlashWriteByte(addr, data>>16 & 0xFF); FlashWriteByte(addr, data>>24 & 0xFF);
|
|
}
|
|
|
|
inline void FlashEndWrite (uint32_t *addr) {
|
|
(void) addr;
|
|
digitalWrite(ssel, 1);
|
|
FlashBusy();
|
|
}
|
|
|
|
void FlashBeginRead (uint32_t *addr) {
|
|
*addr = 0;
|
|
FlashBusy();
|
|
digitalWrite(ssel, 0);
|
|
FlashWrite(READDATA);
|
|
FlashWrite(0); FlashWrite(0); FlashWrite(0);
|
|
}
|
|
|
|
uint32_t FlashRead32 (uint32_t *addr) {
|
|
(void) addr;
|
|
uint8_t b0 = FlashReadByte(); uint8_t b1 = FlashReadByte();
|
|
uint8_t b2 = FlashReadByte(); uint8_t b3 = FlashReadByte();
|
|
return b0 | b1<<8 | b2<<16 | b3<<24;
|
|
}
|
|
|
|
inline void FlashEndRead(uint32_t *addr) {
|
|
(void) addr;
|
|
digitalWrite(ssel, 1);
|
|
}
|
|
|
|
#elif defined(CPUFLASH)
|
|
// For ATSAMD21
|
|
__attribute__((__aligned__(256))) static const uint8_t flash_store[FLASHSIZE] = { };
|
|
|
|
void row_erase (const volatile void *addr) {
|
|
NVMCTRL->ADDR.reg = ((uint32_t)addr) / 2;
|
|
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER;
|
|
while (!NVMCTRL->INTFLAG.bit.READY);
|
|
}
|
|
|
|
void page_clear () {
|
|
// Execute "PBC" Page Buffer Clear
|
|
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC;
|
|
while (NVMCTRL->INTFLAG.bit.READY == 0);
|
|
}
|
|
|
|
void page_write () {
|
|
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP;
|
|
while (NVMCTRL->INTFLAG.bit.READY == 0);
|
|
}
|
|
|
|
bool FlashCheck() {
|
|
return true;
|
|
}
|
|
|
|
void FlashBeginWrite(uint32_t *addr, uint32_t bytes) {
|
|
(void) bytes;
|
|
*addr = (uint32_t)flash_store;
|
|
// Disable automatic page write
|
|
NVMCTRL->CTRLB.bit.MANW = 1;
|
|
}
|
|
|
|
void FlashWrite32 (uint32_t *addr, uint32_t data) {
|
|
if (((*addr) & 0xFF) == 0) row_erase((const volatile void *)(*addr));
|
|
if (((*addr) & 0x3F) == 0) page_clear();
|
|
*(volatile uint32_t *)(*addr) = data;
|
|
(*addr) = (*addr) + 4;
|
|
if (((*addr) & 0x3F) == 0) page_write();
|
|
}
|
|
|
|
void FlashEndWrite (uint32_t *addr) {
|
|
if (((*addr) & 0x3F) != 0) page_write();
|
|
}
|
|
|
|
void FlashBeginRead(uint32_t *addr) {
|
|
*addr = (uint32_t)flash_store;
|
|
}
|
|
|
|
uint32_t FlashRead32 (uint32_t *addr) {
|
|
uint32_t data = *(volatile const uint32_t *)(*addr);
|
|
(*addr) = (*addr) + 4;
|
|
return data;
|
|
}
|
|
|
|
void FlashEndRead (uint32_t *addr) {
|
|
(void) addr;
|
|
}
|
|
#elif defined(EEPROMFLASH)
|
|
|
|
bool FlashCheck() {
|
|
return (EEPROM.length() == FLASHSIZE);
|
|
}
|
|
|
|
void FlashBeginWrite(uint32_t *addr, uint32_t bytes) {
|
|
(void) bytes;
|
|
*addr = 0;
|
|
}
|
|
|
|
void FlashWrite32 (uint32_t *addr, uint32_t data) {
|
|
EEPROM.put(*addr, data);
|
|
(*addr) = (*addr) + 4;
|
|
}
|
|
|
|
void FlashEndWrite (uint32_t *addr) {
|
|
(void) addr;
|
|
}
|
|
|
|
void FlashBeginRead(uint32_t *addr) {
|
|
*addr = 0;
|
|
}
|
|
|
|
uint32_t FlashRead32 (uint32_t *addr) {
|
|
uint32_t data;
|
|
EEPROM.get(*addr, data);
|
|
(*addr) = (*addr) + 4;
|
|
return data;
|
|
}
|
|
|
|
void FlashEndRead (uint32_t *addr) {
|
|
(void) addr;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
saveimage - saves an image of the workspace to the persistent storage selected for the platform.
|
|
*/
|
|
int saveimage (object *arg) {
|
|
#if defined(sdcardsupport)
|
|
unsigned int imagesize = compactimage(&arg);
|
|
SDBegin();
|
|
File file;
|
|
if (stringp(arg)) {
|
|
char buffer[BUFFERSIZE];
|
|
file = SD.open(MakeFilename(arg, buffer), O_RDWR | O_CREAT | O_TRUNC);
|
|
if (!file) error2(PSTR("problem saving to SD card or invalid filename"));
|
|
arg = NULL;
|
|
} else if (arg == NULL || listp(arg)) {
|
|
file = SD.open("/ULISP.IMG", O_RDWR | O_CREAT | O_TRUNC);
|
|
if (!file) error2(PSTR("problem saving to SD card"));
|
|
} else error(invalidarg, arg);
|
|
SDWrite32(file, (uintptr_t)arg);
|
|
SDWrite32(file, imagesize);
|
|
SDWrite32(file, (uintptr_t)GlobalEnv);
|
|
SDWrite32(file, (uintptr_t)GCStack);
|
|
for (int i=0; i<CODESIZE; i++) file.write(MyCode[i]);
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
SDWrite32(file, (uintptr_t)car(obj));
|
|
SDWrite32(file, (uintptr_t)cdr(obj));
|
|
}
|
|
file.close();
|
|
return imagesize;
|
|
#elif defined(LITTLEFS)
|
|
unsigned int imagesize = compactimage(&arg);
|
|
LittleFS.begin(LITTLEFS);
|
|
File file;
|
|
if (stringp(arg)) {
|
|
char buffer[BUFFERSIZE];
|
|
file = LittleFS.open(MakeFilename(arg, buffer), FS_FILE_WRITE);
|
|
if (!file) error2("problem saving to LittleFS or invalid filename");
|
|
arg = NULL;
|
|
} else if (arg == NULL || listp(arg)) {
|
|
file = LittleFS.open("/ULISP.IMG", FS_FILE_WRITE);
|
|
if (!file) error2(PSTR("problem saving to LittleFS"));
|
|
} else error(invalidarg, arg);
|
|
FSWrite32(file, (uintptr_t)arg);
|
|
FSWrite32(file, imagesize);
|
|
FSWrite32(file, (uintptr_t)GlobalEnv);
|
|
FSWrite32(file, (uintptr_t)GCStack);
|
|
if (file.write(MyCode, CODESIZE) != CODESIZE) error2(PSTR("not enough room"));
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
FSWrite32(file, (uintptr_t)car(obj));
|
|
FSWrite32(file, (uintptr_t)cdr(obj));
|
|
}
|
|
file.close();
|
|
return imagesize;
|
|
#elif defined(DATAFLASH) || defined(CPUFLASH) || defined(EEPROMFLASH)
|
|
unsigned int imagesize = compactimage(&arg);
|
|
if (!(arg == NULL || listp(arg))) error(invalidarg, arg);
|
|
if (!FlashCheck()) error2(PSTR("flash not available"));
|
|
// Save to flash
|
|
uint32_t bytesneeded = 16 + CODESIZE + imagesize*8;
|
|
if (bytesneeded > FLASHSIZE) error(PSTR("image too large"), number(imagesize));
|
|
uint32_t addr;
|
|
FlashBeginWrite(&addr, bytesneeded);
|
|
FlashWrite32(&addr, (uintptr_t)arg);
|
|
FlashWrite32(&addr, imagesize);
|
|
FlashWrite32(&addr, (uintptr_t)GlobalEnv);
|
|
FlashWrite32(&addr, (uintptr_t)GCStack);
|
|
for (int i=0; i<CODESIZE; i=i+4) {
|
|
union { uint32_t u32; uint8_t u8[4]; };
|
|
u8[0] = MyCode[i]; u8[1] = MyCode[i+1]; u8[2] = MyCode[i+2]; u8[3] = MyCode[i+3];
|
|
FlashWrite32(&addr, u32);
|
|
}
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
FlashWrite32(&addr, (uintptr_t)car(obj));
|
|
FlashWrite32(&addr, (uintptr_t)cdr(obj));
|
|
}
|
|
FlashEndWrite(&addr);
|
|
return imagesize;
|
|
#else
|
|
(void) arg;
|
|
error2(PSTR("not available"));
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
loadimage - loads an image of the workspace from the persistent storage selected for the platform.
|
|
*/
|
|
int loadimage (object *arg) {
|
|
#if defined(sdcardsupport)
|
|
SDBegin();
|
|
File file;
|
|
if (stringp(arg)) {
|
|
char buffer[BUFFERSIZE];
|
|
file = SD.open(MakeFilename(arg, buffer));
|
|
if (!file) error2(PSTR("problem loading from SD card or invalid filename"));
|
|
} else if (arg == NULL) {
|
|
file = SD.open("/ULISP.IMG");
|
|
if (!file) error2(PSTR("problem loading from SD card"));
|
|
} else error(invalidarg, arg);
|
|
SDRead32(file);
|
|
unsigned int imagesize = SDRead32(file);
|
|
GlobalEnv = (object *)SDRead32(file);
|
|
GCStack = (object *)SDRead32(file);
|
|
for (int i=0; i<CODESIZE; i++) MyCode[i] = file.read();
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)SDRead32(file);
|
|
cdr(obj) = (object *)SDRead32(file);
|
|
}
|
|
file.close();
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#elif defined(LITTLEFS)
|
|
LittleFS.begin(LITTLEFS);
|
|
File file;
|
|
if (stringp(arg)) {
|
|
char buffer[BUFFERSIZE];
|
|
file = LittleFS.open(MakeFilename(arg, buffer), FS_FILE_READ);
|
|
if (!file) error2("problem loading from LittleFS or invalid filename");
|
|
}
|
|
else if (arg == NULL) {
|
|
file = LittleFS.open("/ULISP.IMG", FS_FILE_READ);
|
|
if (!file) error2(PSTR("problem loading from LittleFS"));
|
|
}
|
|
else error(invalidarg, arg);
|
|
FSRead32(file);
|
|
unsigned int imagesize = FSRead32(file);
|
|
GlobalEnv = (object *)FSRead32(file);
|
|
GCStack = (object *)FSRead32(file);
|
|
file.read(MyCode, CODESIZE);
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)FSRead32(file);
|
|
cdr(obj) = (object *)FSRead32(file);
|
|
}
|
|
file.close();
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#elif defined(DATAFLASH) || defined(CPUFLASH) || defined(EEPROMFLASH)
|
|
(void) arg;
|
|
if (!FlashCheck()) error2(PSTR("flash not available"));
|
|
uint32_t addr;
|
|
FlashBeginRead(&addr);
|
|
FlashRead32(&addr); // Skip eval address
|
|
uint32_t imagesize = FlashRead32(&addr);
|
|
if (imagesize == 0 || imagesize == 0xFFFFFFFF) error2(PSTR("no saved image"));
|
|
GlobalEnv = (object *)FlashRead32(&addr);
|
|
GCStack = (object *)FlashRead32(&addr);
|
|
for (int i=0; i<CODESIZE; i=i+4) {
|
|
union { uint32_t u32; uint8_t u8[4]; };
|
|
u32 = FlashRead32(&addr);
|
|
MyCode[i] = u8[0]; MyCode[i+1] = u8[1]; MyCode[i+2] = u8[2]; MyCode[i+3] = u8[3];
|
|
}
|
|
for (uint32_t i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)FlashRead32(&addr);
|
|
cdr(obj) = (object *)FlashRead32(&addr);
|
|
}
|
|
FlashEndRead(&addr);
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#else
|
|
(void) arg;
|
|
error2(PSTR("not available"));
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
autorunimage - loads and runs an image of the workspace from the persistent storage selected for the platform.
|
|
*/
|
|
void autorunimage () {
|
|
#if defined(sdcardsupport)
|
|
SDBegin();
|
|
File file = SD.open("/ULISP.IMG");
|
|
if (!file) error2(PSTR("problem autorunning from SD card"));
|
|
object *autorun = (object *)SDRead32(file);
|
|
file.close();
|
|
if (autorun != NULL) {
|
|
loadimage(NULL);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#elif defined(LITTLEFS)
|
|
LittleFS.begin(LITTLEFS);
|
|
File file = LittleFS.open("/ULISP.IMG", FS_FILE_READ);
|
|
if (!file) error2(PSTR("problem autorunning from LittleFS"));
|
|
object *autorun = (object *)FSRead32(file);
|
|
file.close();
|
|
if (autorun != NULL) {
|
|
loadimage(NULL);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#elif defined(DATAFLASH) || defined(CPUFLASH) || defined(EEPROMFLASH)
|
|
if (!FlashCheck()) error2(PSTR("flash not available"));
|
|
uint32_t addr;
|
|
FlashBeginRead(&addr);
|
|
object *autorun = (object *)FlashRead32(&addr);
|
|
FlashEndRead(&addr);
|
|
if (autorun != NULL && (unsigned int)autorun != 0xFFFFFFFF) {
|
|
loadimage(nil);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#else
|
|
error2(PSTR("autorun not available"));
|
|
#endif
|
|
}"#)
|
|
|
|
#+esp
|
|
(defparameter *saveimage* #"
|
|
// Save-image and load-image
|
|
|
|
#if defined(sdcardsupport)
|
|
|
|
/*
|
|
SDBegin - a standard call on all platforms to initialise the SD Card interface.
|
|
*/
|
|
void SDBegin() {
|
|
SD.begin();
|
|
}
|
|
|
|
void SDWriteInt (File file, int data) {
|
|
file.write(data & 0xFF); file.write(data>>8 & 0xFF);
|
|
file.write(data>>16 & 0xFF); file.write(data>>24 & 0xFF);
|
|
}
|
|
|
|
int SDReadInt (File file) {
|
|
uintptr_t b0 = file.read(); uintptr_t b1 = file.read();
|
|
uintptr_t b2 = file.read(); uintptr_t b3 = file.read();
|
|
return b0 | b1<<8 | b2<<16 | b3<<24;
|
|
}
|
|
#elif defined(LITTLEFS)
|
|
void FSWrite32 (File file, uint32_t data) {
|
|
union { uint32_t data2; uint8_t u8[4]; };
|
|
data2 = data;
|
|
if (file.write(u8, 4) != 4) error2(PSTR("not enough room"));
|
|
}
|
|
|
|
uint32_t FSRead32 (File file) {
|
|
union { uint32_t data; uint8_t u8[4]; };
|
|
file.read(u8, 4);
|
|
return data;
|
|
}
|
|
#else
|
|
void EpromWriteInt(int *addr, uintptr_t data) {
|
|
EEPROM.write((*addr)++, data & 0xFF); EEPROM.write((*addr)++, data>>8 & 0xFF);
|
|
EEPROM.write((*addr)++, data>>16 & 0xFF); EEPROM.write((*addr)++, data>>24 & 0xFF);
|
|
}
|
|
|
|
int EpromReadInt (int *addr) {
|
|
uint8_t b0 = EEPROM.read((*addr)++); uint8_t b1 = EEPROM.read((*addr)++);
|
|
uint8_t b2 = EEPROM.read((*addr)++); uint8_t b3 = EEPROM.read((*addr)++);
|
|
return b0 | b1<<8 | b2<<16 | b3<<24;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
saveimage - saves an image of the workspace to the persistent storage selected for the platform.
|
|
*/
|
|
unsigned int saveimage (object *arg) {
|
|
#if defined(sdcardsupport)
|
|
unsigned int imagesize = compactimage(&arg);
|
|
SDBegin();
|
|
File file;
|
|
if (stringp(arg)) {
|
|
char buffer[BUFFERSIZE];
|
|
file = SD.open(MakeFilename(arg, buffer), FILE_WRITE);
|
|
if (!file) error2(PSTR("problem saving to SD card or invalid filename"));
|
|
arg = NULL;
|
|
} else if (arg == NULL || listp(arg)) {
|
|
file = SD.open("/ULISP.IMG", FILE_WRITE);
|
|
if (!file) error2(PSTR("problem saving to SD card"));
|
|
} else error(invalidarg, arg);
|
|
SDWriteInt(file, (uintptr_t)arg);
|
|
SDWriteInt(file, imagesize);
|
|
SDWriteInt(file, (uintptr_t)GlobalEnv);
|
|
SDWriteInt(file, (uintptr_t)GCStack);
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
SDWriteInt(file, (uintptr_t)car(obj));
|
|
SDWriteInt(file, (uintptr_t)cdr(obj));
|
|
}
|
|
file.close();
|
|
return imagesize;
|
|
#elif defined(LITTLEFS)
|
|
unsigned int imagesize = compactimage(&arg);
|
|
if (!LittleFS.begin(true)) error2(PSTR("problem mounting LittleFS"));
|
|
int bytesneeded = imagesize*8 + 36; int bytesavailable = LittleFS.totalBytes();
|
|
if (bytesneeded > bytesavailable) error("image too large by", number(bytesneeded - bytesavailable));
|
|
File file;
|
|
if (stringp(arg)) {
|
|
char buffer[BUFFERSIZE];
|
|
file = LittleFS.open(MakeFilename(arg, buffer), "w");
|
|
if (!file) error2(PSTR("problem saving to LittleFS or invalid filename"));
|
|
arg = NULL;
|
|
} else if (arg == NULL || listp(arg)) {
|
|
file = LittleFS.open("/ULISP.IMG", "w");
|
|
if (!file) error2(PSTR("problem saving to LittleFS"));
|
|
} else error(invalidarg, arg);
|
|
FSWrite32(file, (uintptr_t)arg);
|
|
FSWrite32(file, imagesize);
|
|
FSWrite32(file, (uintptr_t)GlobalEnv);
|
|
FSWrite32(file, (uintptr_t)GCStack);
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
FSWrite32(file, (uintptr_t)car(obj));
|
|
FSWrite32(file, (uintptr_t)cdr(obj));
|
|
}
|
|
file.close();
|
|
return imagesize;
|
|
#elif defined(EEPROMSIZE)
|
|
unsigned int imagesize = compactimage(&arg);
|
|
if (!(arg == NULL || listp(arg))) error(PSTR("illegal argument"), arg);
|
|
int bytesneeded = imagesize*8 + 36;
|
|
if (bytesneeded > EEPROMSIZE) error("image too large by", number(bytesneeded - EEPROMSIZE));
|
|
EEPROM.begin(EEPROMSIZE);
|
|
int addr = 0;
|
|
EpromWriteInt(&addr, (uintptr_t)arg);
|
|
EpromWriteInt(&addr, imagesize);
|
|
EpromWriteInt(&addr, (uintptr_t)GlobalEnv);
|
|
EpromWriteInt(&addr, (uintptr_t)GCStack);
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
EpromWriteInt(&addr, (uintptr_t)car(obj));
|
|
EpromWriteInt(&addr, (uintptr_t)cdr(obj));
|
|
}
|
|
EEPROM.commit();
|
|
return imagesize;
|
|
#else
|
|
(void) arg;
|
|
error2(PSTR("not available"));
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
loadimage - loads an image of the workspace from the persistent storage selected for the platform.
|
|
*/
|
|
unsigned int loadimage (object *arg) {
|
|
#if defined(sdcardsupport)
|
|
SDBegin();
|
|
File file;
|
|
if (stringp(arg)) {
|
|
char buffer[BUFFERSIZE];
|
|
file = SD.open(MakeFilename(arg, buffer));
|
|
if (!file) error2(PSTR("problem loading from SD card or invalid filename"));
|
|
} else if (arg == NULL) {
|
|
file = SD.open("/ULISP.IMG");
|
|
if (!file) error2(PSTR("problem loading from SD card"));
|
|
} else error(invalidarg, arg);
|
|
SDReadInt(file);
|
|
unsigned int imagesize = SDReadInt(file);
|
|
GlobalEnv = (object *)SDReadInt(file);
|
|
GCStack = (object *)SDReadInt(file);
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)SDReadInt(file);
|
|
cdr(obj) = (object *)SDReadInt(file);
|
|
}
|
|
file.close();
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#elif defined(LITTLEFS)
|
|
if (!LittleFS.begin()) error2(PSTR("problem mounting LittleFS"));
|
|
File file;
|
|
if (stringp(arg)) {
|
|
char buffer[BUFFERSIZE];
|
|
file = LittleFS.open(MakeFilename(arg, buffer), "r");
|
|
if (!file) error2(PSTR("problem loading from LittleFS or invalid filename"));
|
|
}
|
|
else if (arg == NULL) {
|
|
file = LittleFS.open("/ULISP.IMG", "r");
|
|
if (!file) error2(PSTR("problem loading from LittleFS"));
|
|
}
|
|
else error(invalidarg, arg);
|
|
FSRead32(file);
|
|
unsigned int imagesize = FSRead32(file);
|
|
GlobalEnv = (object *)FSRead32(file);
|
|
GCStack = (object *)FSRead32(file);
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)FSRead32(file);
|
|
cdr(obj) = (object *)FSRead32(file);
|
|
}
|
|
file.close();
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#elif defined(EEPROMSIZE)
|
|
(void) arg;
|
|
EEPROM.begin(EEPROMSIZE);
|
|
int addr = 0;
|
|
EpromReadInt(&addr); // Skip eval address
|
|
unsigned int imagesize = EpromReadInt(&addr);
|
|
if (imagesize == 0 || imagesize == 0xFFFFFFFF) error2(PSTR("no saved image"));
|
|
GlobalEnv = (object *)EpromReadInt(&addr);
|
|
GCStack = (object *)EpromReadInt(&addr);
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)EpromReadInt(&addr);
|
|
cdr(obj) = (object *)EpromReadInt(&addr);
|
|
}
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#else
|
|
(void) arg;
|
|
error2(PSTR("not available"));
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
autorunimage - loads and runs an image of the workspace from the persistent storage selected for the platform.
|
|
*/
|
|
void autorunimage () {
|
|
#if defined(sdcardsupport)
|
|
SDBegin();
|
|
File file = SD.open("/ULISP.IMG");
|
|
if (!file) error2(PSTR("problem autorunning from SD card"));
|
|
object *autorun = (object *)SDReadInt(file);
|
|
file.close();
|
|
if (autorun != NULL) {
|
|
loadimage(NULL);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#elif defined(LITTLEFS)
|
|
if (!LittleFS.begin()) error2(PSTR("problem mounting LittleFS"));
|
|
File file = LittleFS.open("/ULISP.IMG", "r");
|
|
if (!file) error2(PSTR("problem autorunning from LittleFS"));
|
|
object *autorun = (object *)FSRead32(file);
|
|
file.close();
|
|
if (autorun != NULL) {
|
|
loadimage(NULL);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#elif defined(EEPROMSIZE)
|
|
EEPROM.begin(EEPROMSIZE);
|
|
int addr = 0;
|
|
object *autorun = (object *)EpromReadInt(&addr);
|
|
if (autorun != NULL && (unsigned int)autorun != 0xFFFF) {
|
|
loadimage(NULL);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#else
|
|
error2(PSTR("autorun not available"));
|
|
#endif
|
|
}"#)
|
|
|
|
#+riscv
|
|
(defparameter *saveimage* #"
|
|
// Save-image and load-image
|
|
|
|
#if defined(sdcardsupport)
|
|
|
|
/*
|
|
SDBegin - a standard call on all platforms to initialise the SD Card interface.
|
|
*/
|
|
void SDBegin() {
|
|
if (!SD.begin(SS)) error2("problem initialising SD card");
|
|
}
|
|
|
|
typedef union {
|
|
uintptr_t sdpointer;
|
|
uint8_t sdbyte[8];
|
|
} sdbuffer_t;
|
|
|
|
void SDWriteInt (File file, uintptr_t data) {
|
|
sdbuffer_t sdbuf;
|
|
sdbuf.sdpointer = data;
|
|
for (int i=0; i<8; i++) file.write(sdbuf.sdbyte[i]);
|
|
}
|
|
|
|
uintptr_t SDReadInt (File file) {
|
|
sdbuffer_t sdbuf;
|
|
for (int i=0; i<8; i++) sdbuf.sdbyte[i] = file.read();
|
|
return sdbuf.sdpointer;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
saveimage - saves an image of the workspace to the persistent storage selected for the platform.
|
|
*/
|
|
int saveimage (object *arg) {
|
|
#if defined(sdcardsupport)
|
|
uintptr_t imagesize = compactimage(&arg);
|
|
SDBegin();
|
|
File file;
|
|
if (stringp(arg)) {
|
|
char buffer[BUFFERSIZE];
|
|
file = SD.open(MakeFilename(arg, buffer), FILE_WRITE);
|
|
if (!file) error2(PSTR("problem saving to SD card or invalid filename"));
|
|
arg = NULL;
|
|
} else if (arg == NULL || listp(arg)) {
|
|
file = SD.open("ULISP.IMG", O_RDWR | O_CREAT | O_TRUNC);
|
|
if (!file) error2(PSTR("problem saving to SD card"));
|
|
} else error(invalidarg, arg);
|
|
SDWriteInt(file, (uintptr_t)arg);
|
|
SDWriteInt(file, (uintptr_t)imagesize);
|
|
SDWriteInt(file, (uintptr_t)GlobalEnv);
|
|
SDWriteInt(file, (uintptr_t)GCStack);
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
SDWriteInt(file, (uintptr_t)SymbolTop);
|
|
int SymbolUsed = SymbolTop - SymbolTable;
|
|
for (int i=0; i<SymbolUsed; i++) file.write(SymbolTable[i]);
|
|
#endif
|
|
for (int i=0; i<CODESIZE; i++) file.write(MyCode[i]);
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
SDWriteInt(file, (uintptr_t)car(obj));
|
|
SDWriteInt(file, (uintptr_t)cdr(obj));
|
|
}
|
|
file.close();
|
|
return imagesize;
|
|
#else
|
|
(void) arg;
|
|
error2(PSTR("not available"));
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
loadimage - loads an image of the workspace from the persistent storage selected for the platform.
|
|
*/
|
|
int loadimage (object *arg) {
|
|
#if defined(sdcardsupport)
|
|
SDBegin();
|
|
File file;
|
|
if (stringp(arg)) {
|
|
char buffer[BUFFERSIZE];
|
|
file = SD.open(MakeFilename(arg, buffer));
|
|
if (!file) error2(PSTR("problem loading from SD card or invalid filename"));
|
|
} else if (arg == NULL) {
|
|
file = SD.open("ULISP.IMG");
|
|
if (!file) error2(PSTR("problem loading from SD card"));
|
|
} else error(invalidarg, arg);
|
|
SDReadInt(file);
|
|
uintptr_t imagesize = SDReadInt(file);
|
|
GlobalEnv = (object *)SDReadInt(file);
|
|
GCStack = (object *)SDReadInt(file);
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
SymbolTop = (char *)SDReadInt(file);
|
|
int SymbolUsed = SymbolTop - SymbolTable;
|
|
for (int i=0; i<SymbolUsed; i++) SymbolTable[i] = file.read();
|
|
#endif
|
|
for (int i=0; i<CODESIZE; i++) MyCode[i] = file.read();
|
|
for (int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)SDReadInt(file);
|
|
cdr(obj) = (object *)SDReadInt(file);
|
|
}
|
|
file.close();
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#else
|
|
(void) arg;
|
|
error2(PSTR("not available"));
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
autorunimage - loads and runs an image of the workspace from the persistent storage selected for the platform.
|
|
*/
|
|
void autorunimage () {
|
|
#if defined(sdcardsupport)
|
|
SDBegin();
|
|
File file = SD.open("ULISP.IMG");
|
|
if (!file) error2(PSTR("problem autorunning from SD card"));
|
|
object *autorun = (object *)SDReadInt(file);
|
|
file.close();
|
|
if (autorun != NULL) {
|
|
loadimage(NULL);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#else
|
|
error2(PSTR("autorun not available"));
|
|
#endif
|
|
}"#)
|
|
|
|
#+stm32
|
|
(defparameter *saveimage* #"
|
|
// Save-image and load-image
|
|
const unsigned int Eeprom = 0x801D800;
|
|
|
|
#if defined(sdcardsupport)
|
|
void SDWriteInt (File file, int data) {
|
|
file.write(data & 0xFF); file.write(data>>8 & 0xFF);
|
|
file.write(data>>16 & 0xFF); file.write(data>>24 & 0xFF);
|
|
}
|
|
#else
|
|
void FlashSetup () {
|
|
FLASH_Unlock();
|
|
uint16_t Status;
|
|
for (int page = Eeprom; page < 0x8020000; page = page + 0x400) {
|
|
Status = FLASH_ErasePage(page);
|
|
if (Status != FLASH_COMPLETE) error2(PSTR("flash erase failed"));
|
|
}
|
|
}
|
|
|
|
void FlashWrite16 (unsigned int *addr, uint16_t data) {
|
|
uint16_t Status = FLASH_ProgramHalfWord((*addr) + Eeprom, data);
|
|
if (Status != FLASH_COMPLETE) error2(PSTR("flash write failed"));
|
|
(*addr) = (*addr) + 2;
|
|
}
|
|
|
|
void FlashWriteInt (unsigned int *addr, int data) {
|
|
FlashWrite16(addr, data & 0xFFFF); FlashWrite16(addr, data>>16 & 0xFFFF);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
saveimage - saves an image of the workspace to the persistent storage selected for the platform.
|
|
*/
|
|
int saveimage (object *arg) {
|
|
unsigned int imagesize = compactimage(&arg);
|
|
#if defined(sdcardsupport)
|
|
File file;
|
|
if (stringp(arg)) {
|
|
file = SD.open(MakeFilename(arg), O_RDWR | O_CREAT | O_TRUNC);
|
|
arg = NULL;
|
|
} else if (arg == NULL || listp(arg)) file = SD.open("ULISP.IMG", O_RDWR | O_CREAT | O_TRUNC);
|
|
else error3(SAVEIMAGE, PSTR("illegal argument"));
|
|
if (!file) error(PSTR("Problem saving to SD card"));
|
|
SDWriteInt(file, (uintptr_t)arg);
|
|
SDWriteInt(file, imagesize);
|
|
SDWriteInt(file, (uintptr_t)GlobalEnv);
|
|
SDWriteInt(file, (uintptr_t)GCStack);
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
SDWriteInt(file, (uintptr_t)SymbolTop);
|
|
for (int i=0; i<SYMBOLTABLESIZE; i++) file.write(SymbolTable[i]);
|
|
#endif
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
SDWriteInt(file, (uintptr_t)car(obj));
|
|
SDWriteInt(file, (uintptr_t)cdr(obj));
|
|
}
|
|
file.close();
|
|
return imagesize;
|
|
#else
|
|
FlashSetup();
|
|
// Save to EEPROM
|
|
int bytesneeded = imagesize*8 + SYMBOLTABLESIZE + 20;
|
|
if (bytesneeded > EEPROMSIZE) {
|
|
pfstring(PSTR("Error: image too large: "), pserial);
|
|
pint(imagesize, pserial); pln(pserial);
|
|
GCStack = NULL;
|
|
longjmp(exception, 1);
|
|
}
|
|
unsigned int addr = 0;
|
|
FlashWriteInt(&addr, (uintptr_t)arg);
|
|
FlashWriteInt(&addr, imagesize);
|
|
FlashWriteInt(&addr, (uintptr_t)GlobalEnv);
|
|
FlashWriteInt(&addr, (uintptr_t)GCStack);
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
FlashWriteInt(&addr, (uintptr_t)SymbolTop);
|
|
for (int i=0; i<SYMBOLTABLESIZE; i=i+2) FlashWrite16(&addr, SymbolTable[i] | SymbolTable[i+1]<<8);
|
|
#endif
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
FlashWriteInt(&addr, (uintptr_t)car(obj));
|
|
FlashWriteInt(&addr, (uintptr_t)cdr(obj));
|
|
}
|
|
return imagesize;
|
|
}
|
|
#endif
|
|
|
|
#if defined(sdcardsupport)
|
|
int SDReadInt (File file) {
|
|
uintptr_t b0 = file.read(); uintptr_t b1 = file.read();
|
|
uintptr_t b2 = file.read(); uintptr_t b3 = file.read();
|
|
return b0 | b1<<8 | b2<<16 | b3<<24;
|
|
}
|
|
#else
|
|
uint16_t FlashRead16 (unsigned int *addr) {
|
|
uint16_t data = (*(__IO uint16*)((*addr) + Eeprom));
|
|
(*addr) = (*addr) + 2;
|
|
return data;
|
|
}
|
|
|
|
int FlashReadInt (unsigned int *addr) {
|
|
uint16_t b0 = FlashRead16(addr);
|
|
uint16_t b1 = FlashRead16(addr);
|
|
return b0 | b1<<16;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
loadimage - loads an image of the workspace from the persistent storage selected for the platform.
|
|
*/
|
|
int loadimage (object *arg) {
|
|
#if defined(sdcardsupport)
|
|
File file;
|
|
if (stringp(arg)) file = SD.open(MakeFilename(arg));
|
|
else if (arg == NULL) file = SD.open("/ULISP.IMG");
|
|
else error3(LOADIMAGE, PSTR("illegal argument"));
|
|
if (!file) error(PSTR("Problem loading from SD card"));
|
|
SDReadInt(file);
|
|
unsigned int imagesize = SDReadInt(file);
|
|
GlobalEnv = (object *)SDReadInt(file);
|
|
GCStack = (object *)SDReadInt(file);
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
SymbolTop = (char *)SDReadInt(file);
|
|
for (int i=0; i<SYMBOLTABLESIZE; i++) SymbolTable[i] = file.read();
|
|
#endif
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)SDReadInt(file);
|
|
cdr(obj) = (object *)SDReadInt(file);
|
|
}
|
|
file.close();
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#else
|
|
unsigned int addr = 0;
|
|
FlashReadInt(&addr); // Skip eval address
|
|
unsigned int imagesize = FlashReadInt(&addr);
|
|
if (imagesize == 0 || imagesize == 0xFFFFFFFF) error2(PSTR("no saved image"));
|
|
GlobalEnv = (object *)FlashReadInt(&addr);
|
|
GCStack = (object *)FlashReadInt(&addr);
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
SymbolTop = (char *)FlashReadInt(&addr);
|
|
for (int i=0; i<SYMBOLTABLESIZE; i=i+2) {
|
|
uint16_t bytes = FlashRead16(&addr);
|
|
SymbolTable[i] = bytes & 0xFF;
|
|
SymbolTable[i+1] = bytes>>8 & 0xFF;
|
|
}
|
|
#endif
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)FlashReadInt(&addr);
|
|
cdr(obj) = (object *)FlashReadInt(&addr);
|
|
}
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
autorunimage - loads and runs an image of the workspace from the persistent storage selected for the platform.
|
|
*/
|
|
void autorunimage () {
|
|
#if defined(sdcardsupport)
|
|
File file = SD.open("ULISP.IMG");
|
|
if (!file) error(PSTR("Error: Problem autorunning from SD card"));
|
|
object *autorun = (object *)SDReadInt(file);
|
|
file.close();
|
|
if (autorun != NULL) {
|
|
loadimage(NULL);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#else
|
|
unsigned int addr = 0;
|
|
object *autorun = (object *)FlashReadInt(&addr);
|
|
if (autorun != NULL && (unsigned int)autorun != 0xFFFFFFFF) {
|
|
loadimage(nil);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#endif
|
|
}"#)
|
|
|
|
#+msp430
|
|
(defparameter *saveimage* #"
|
|
// Save-image and load-image
|
|
|
|
#if defined(sdcardsupport)
|
|
void SDWriteInt (File file, int data) {
|
|
file.write(data & 0xFF); file.write(data>>8 & 0xFF);
|
|
}
|
|
#elif defined(__MSP430F5529__)
|
|
#include "MspFlash.h"
|
|
const int segmentsize = 0x200; // 512
|
|
unsigned char image[13*segmentsize] PERSIST; // We need 12*512 in the middle of this
|
|
#define FLASH SEGPTR(image)
|
|
#elif defined(__MSP430FR5969__) || defined(__MSP430FR5994__) || defined(__MSP430FR6989__)
|
|
struct image_struct {
|
|
object *eval;
|
|
unsigned int datasize;
|
|
object *globalenv;
|
|
object *gcstack;
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
char *symboltop;
|
|
char table[SYMBOLTABLESIZE];
|
|
#endif
|
|
object data[IMAGEDATASIZE];
|
|
};
|
|
|
|
struct image_struct image PERSIST;
|
|
#endif
|
|
|
|
/*
|
|
saveimage - saves an image of the workspace to the persistent storage selected for the platform.
|
|
*/
|
|
int saveimage (object *arg) {
|
|
unsigned int imagesize = compactimage(&arg);
|
|
#if defined(sdcardsupport)
|
|
File file;
|
|
if (stringp(arg)) {
|
|
file = SD.open(MakeFilename(arg), O_RDWR | O_CREAT | O_TRUNC);
|
|
arg = NULL;
|
|
} else if (arg == NULL || listp(arg)) file = SD.open("/ULISP.IMG", O_RDWR | O_CREAT | O_TRUNC);
|
|
else error3(SAVEIMAGE, PSTR("illegal argument"));
|
|
if (!file) error(PSTR("Problem saving to SD card"));
|
|
SDWriteInt(file, (uintptr_t)arg);
|
|
SDWriteInt(file, imagesize);
|
|
SDWriteInt(file, (uintptr_t)GlobalEnv);
|
|
SDWriteInt(file, (uintptr_t)GCStack);
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
SDWriteInt(file, (uintptr_t)SymbolTop);
|
|
for (int i=0; i<SYMBOLTABLESIZE; i++) file.write(SymbolTable[i]);
|
|
#endif
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
SDWriteInt(file, (uintptr_t)car(obj));
|
|
SDWriteInt(file, (uintptr_t)cdr(obj));
|
|
}
|
|
file.close();
|
|
return imagesize;
|
|
#elif defined(__MSP430F5529__)
|
|
if (!(arg == NULL || listp(arg))) error3(SAVEIMAGE, PSTR(" illegal argument"));
|
|
int bytesneeded = imagesize*4 + SYMBOLTABLESIZE + 10;
|
|
if (imagesize > IMAGEDATASIZE) {
|
|
pfstring(PSTR("Error: image too large: "), pserial);
|
|
pint(imagesize, pserial); pln(pserial);
|
|
GCStack = NULL;
|
|
longjmp(exception, 1);
|
|
}
|
|
// Erase flash
|
|
for (int i=0; i<12; i++) Flash.erase(FLASH + i*segmentsize);
|
|
unsigned char *workstart = FLASH+8;
|
|
Flash.write(FLASH, (unsigned char*)&imagesize, 2);
|
|
Flash.write(FLASH+2, (unsigned char*)&arg, 2);
|
|
Flash.write(FLASH+4, (unsigned char*)&GlobalEnv, 2);
|
|
Flash.write(FLASH+6, (unsigned char*)&GCStack, 2);
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
Flash.write(FLASH+8, (unsigned char*)&SymbolTop, 2);
|
|
Flash.write(FLASH+10, (unsigned char*)SymbolTable, SYMBOLTABLESIZE);
|
|
workstart = FLASH + SYMBOLTABLESIZE + 10;
|
|
#endif
|
|
Flash.write(workstart, (unsigned char*)Workspace, imagesize*4);
|
|
return imagesize;
|
|
#elif defined(__MSP430FR5969__) || defined(__MSP430FR5994__) || defined(__MSP430FR6989__)
|
|
if (!(arg == NULL || listp(arg))) error3(SAVEIMAGE, PSTR(" illegal argument"));
|
|
int bytesneeded = imagesize*4 + SYMBOLTABLESIZE + 10;
|
|
if (imagesize > IMAGEDATASIZE) {
|
|
pfstring(PSTR("Error: image too large: "), pserial);
|
|
pint(imagesize, pserial); pln(pserial);
|
|
GCStack = NULL;
|
|
longjmp(exception, 1);
|
|
}
|
|
image.datasize = imagesize;
|
|
image.eval = arg;
|
|
image.globalenv = GlobalEnv;
|
|
image.gcstack = GCStack;
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
image.symboltop = SymbolTop;
|
|
for (int i=0; i<SYMBOLTABLESIZE; i++) image.table[i] = SymbolTable[i];
|
|
#endif
|
|
for (unsigned int i=0; i<imagesize; i++) image.data[i] = Workspace[i];
|
|
return imagesize;
|
|
#endif
|
|
}
|
|
|
|
#if defined(sdcardsupport)
|
|
int SDReadInt (File file) {
|
|
uintptr_t b0 = file.read(); uintptr_t b1 = file.read();
|
|
return b0 | b1<<8;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
loadimage - loads an image of the workspace from the persistent storage selected for the platform.
|
|
*/
|
|
int loadimage (object *arg) {
|
|
#if defined(sdcardsupport)
|
|
File file;
|
|
if (stringp(arg)) file = SD.open(MakeFilename(arg));
|
|
else if (arg == NULL) file = SD.open("/ULISP.IMG");
|
|
else error3(LOADIMAGE, PSTR("illegal argument"));
|
|
if (!file) error(PSTR("Problem loading from SD card"));
|
|
SDReadInt(file);
|
|
unsigned int imagesize = SDReadInt(file);
|
|
GlobalEnv = (object *)SDReadInt(file);
|
|
GCStack = (object *)SDReadInt(file);
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
SymbolTop = (char *)SDReadInt(file);
|
|
for (int i=0; i<SYMBOLTABLESIZE; i++) SymbolTable[i] = file.read();
|
|
#endif
|
|
for (unsigned int i=0; i<imagesize; i++) {
|
|
object *obj = &Workspace[i];
|
|
car(obj) = (object *)SDReadInt(file);
|
|
cdr(obj) = (object *)SDReadInt(file);
|
|
}
|
|
file.close();
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#elif defined(__MSP430F5529__)
|
|
unsigned int imagesize;
|
|
unsigned char *workstart = FLASH+8;
|
|
Flash.read(FLASH, (unsigned char*)&imagesize, 2);
|
|
Flash.read(FLASH+4, (unsigned char*)&GlobalEnv, 2);
|
|
Flash.read(FLASH+6, (unsigned char*)&GCStack, 2);
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
Flash.read(FLASH+8, (unsigned char*)&SymbolTop, 2);
|
|
Flash.read(FLASH+10, (unsigned char*)SymbolTable, SYMBOLTABLESIZE);
|
|
workstart = FLASH + SYMBOLTABLESIZE + 10;
|
|
#endif
|
|
Flash.read(workstart, (unsigned char*)Workspace, imagesize*4);
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#elif defined(__MSP430FR5969__) || defined(__MSP430FR5994__) || defined(__MSP430FR6989__)
|
|
unsigned int imagesize;
|
|
imagesize = image.datasize;
|
|
GlobalEnv = image.globalenv;
|
|
GCStack = image.gcstack;
|
|
#if SYMBOLTABLESIZE > BUFFERSIZE
|
|
SymbolTop = image.symboltop;
|
|
for (int i=0; i<SYMBOLTABLESIZE; i++) SymbolTable[i] = image.table[i];
|
|
#endif
|
|
for (unsigned int i=0; i<imagesize; i++) Workspace[i] = image.data[i];
|
|
gc(NULL, NULL);
|
|
return imagesize;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
autorunimage - loads and runs an image of the workspace from the persistent storage selected for the platform.
|
|
*/
|
|
void autorunimage () {
|
|
#if defined(sdcardsupport)
|
|
File file = SD.open("ULISP.IMG");
|
|
if (!file) error(PSTR("Problem autorunning from SD card"));
|
|
object *autorun = (object *)SDReadInt(file);
|
|
file.close();
|
|
if (autorun != NULL) {
|
|
loadimage(NULL);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#elif defined(__MSP430F5529__)
|
|
object *autorun;
|
|
Flash.read(FLASH+2, (unsigned char*)&autorun, 2);
|
|
if (autorun != NULL && (unsigned int)autorun != 0xFFFF) {
|
|
loadimage(nil);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#elif defined(__MSP430FR5969__) || defined(__MSP430FR5994__) || defined(__MSP430FR6989__)
|
|
object *autorun = image.eval;
|
|
if (autorun != NULL && (unsigned int)autorun != 0xFFFF) {
|
|
loadimage(nil);
|
|
apply(autorun, NULL, NULL);
|
|
}
|
|
#endif
|
|
}"#)
|
|
|