;;;-*- 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; itype) & ~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; itype) & ~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; itype) & ~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; itype) & ~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>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 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 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>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>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 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>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 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 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 BUFFERSIZE SDWriteInt(file, (uintptr_t)SymbolTop); int SymbolUsed = SymbolTop - SymbolTable; for (int i=0; i BUFFERSIZE SymbolTop = (char *)SDReadInt(file); int SymbolUsed = SymbolTop - SymbolTable; for (int i=0; i>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 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 BUFFERSIZE SymbolTop = (char *)SDReadInt(file); for (int i=0; i BUFFERSIZE SymbolTop = (char *)FlashReadInt(&addr); for (int i=0; i>8 & 0xFF; } #endif for (unsigned int i=0; i>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 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 BUFFERSIZE SymbolTop = (char *)SDReadInt(file); for (int i=0; i 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