diff --git a/src/test/csrc/emu.cpp b/src/test/csrc/emu.cpp index 292bd82627442eace5bf859f2d1ee34ab3462100..396bc4757f5a4a39849d6362d726c430edc257d7 100644 --- a/src/test/csrc/emu.cpp +++ b/src/test/csrc/emu.cpp @@ -430,7 +430,7 @@ void Emulator::snapshot_save(const char *filename) { } void Emulator::snapshot_load(const char *filename) { - VerilatedRestore stream; + VerilatedRestoreMem stream; stream.open(filename); stream >> *dut_ptr; diff --git a/src/test/csrc/ram.cpp b/src/test/csrc/ram.cpp index b3026fc941e39f85e26c6f61cf0fa0ccdfc2899f..40cb3e26ec6a04d0982365f1008d05c70ef51d10 100644 --- a/src/test/csrc/ram.cpp +++ b/src/test/csrc/ram.cpp @@ -4,7 +4,7 @@ #include "common.h" #include "ram.h" -#define RAMSIZE (64 * 1024 * 1024 * 1024UL) +#define RAMSIZE (256 * 1024 * 1024UL) #ifdef WITH_DRAMSIM3 #include "cosimulation.h" @@ -104,9 +104,9 @@ void addpageSv39() { #endif // Return whether the file is a gz file -int isGzFile(const char *img) { - assert(img != NULL && strlen(img) >= 4); - return !strcmp(img + (strlen(img) - 3), ".gz"); +int isGzFile(const char *filename) { + assert(filename != NULL && strlen(filename) >= 4); + return !strcmp(filename + (strlen(filename) - 3), ".gz"); } // Read binary from .gz file diff --git a/src/test/csrc/snapshot.cpp b/src/test/csrc/snapshot.cpp index 15aafafbfbfeaae769cd445a8f75330d4823c289..e4bbdcb708635be4414d098aa174fcfd63780b21 100644 --- a/src/test/csrc/snapshot.cpp +++ b/src/test/csrc/snapshot.cpp @@ -1,6 +1,88 @@ #include "snapshot.h" +#include #ifdef VM_SAVABLE + +int compressToFile(uint8_t *buf, const char *filename, long size) { + gzFile gzfp = gzopen(filename, "wb"); + assert(gzfp != NULL); + + assert(gzwrite(gzfp, buf, size) > 0); + + gzclose(gzfp); + return 0; + + // gzFile compressed_mem = gzopen(filename, "wb"); + + // if(compressed_mem == NULL) { + // printf("Can't open compressed binary file '%s'", filename); + // return -1; + // } + + // uint64_t curr_size = 0; + // const uint32_t chunk_size = 16384; + // long *temp_page = new long[chunk_size]; + // long *pmem_current = (long*)ptr; + + // while (curr_size < buf_size) { + // uint32_t bytes_write = gzwrite(compressed_mem, temp_page, chunk_size); + // if (bytes_write == 0) { break; } + // for (uint32_t x = 0; x < bytes_write / sizeof(long) + 1; x++) { + // if (*(temp_page + x) != 0) { + // pmem_current = (long*)((uint8_t*)ptr + curr_size + x * sizeof(long)); + // *pmem_current = *(temp_page + x); + // } + // } + // curr_size += bytes_write; + // } + // printf("Write %lu bytes from gz stream in total\n", curr_size); + + // delete [] temp_page; + + // if(gzclose(compressed_mem)) { + // printf("Error closing '%s'\n", filename); + // return -1; + // } + // return curr_size; +} + +// Read binary from .gz file +int readFromGz(void* ptr, const char *file_name, long buf_size) { + gzFile compressed_mem = gzopen(file_name, "rb"); + + if(compressed_mem == NULL) { + printf("Can't open compressed binary file '%s'", file_name); + return -1; + } + + uint64_t curr_size = 0; + const uint32_t chunk_size = 16384; + long *temp_page = new long[chunk_size]; + long *pmem_current = (long*)ptr; + + while (curr_size < buf_size) { + uint32_t bytes_read = gzread(compressed_mem, temp_page, chunk_size); + if (bytes_read == 0) { break; } + // assert(bytes_read % sizeof(long) == 0); + for (uint32_t x = 0; x < bytes_read / sizeof(long) + 1; x++) { + if (*(temp_page + x) != 0) { + pmem_current = (long*)((uint8_t*)ptr + curr_size + x * sizeof(long)); + *pmem_current = *(temp_page + x); + } + } + curr_size += bytes_read; + } + printf("Read %lu bytes from gz stream in total\n", curr_size); + + delete [] temp_page; + + if(gzclose(compressed_mem)) { + printf("Error closing '%s'\n", file_name); + return -1; + } + return curr_size; +} + void VerilatedSaveMem::flush() { long flush_size = m_cp - m_bufp; assert(buf_size - size > flush_size); @@ -13,11 +95,86 @@ void VerilatedSaveMem::save() { if (size == 0) return; trailer(); flush(); - FILE *fp = fopen(m_filename.c_str(), "w"); - assert(fp != NULL); - fwrite(buf, size, 1, fp); - fclose(fp); + if(size <= (512 * 1024 * 1024UL)){ + FILE *fp = fopen(m_filename.c_str(), "w"); + assert(fp != NULL); + fwrite(buf, size, 1, fp); + fclose(fp); + } else { + compressToFile(buf, (m_filename + ".gz").c_str(), size); + } size = 0; printf("save snapshot to %s...\n", m_filename.c_str()); } + +void VerilatedRestoreMem::fill() { + m_assertOne.check(); + if (VL_UNLIKELY(!isOpen())) return; + // Move remaining characters down to start of buffer. (No memcpy, overlaps allowed) + vluint8_t* rp = m_bufp; + for (vluint8_t* sp = m_cp; sp < m_endp; *rp++ = *sp++) {} // Overlaps + m_endp = m_bufp + (m_endp - m_cp); + m_cp = m_bufp; // Reset buffer + // Read into buffer starting at m_endp + while (true) { + ssize_t remaining = (m_bufp + bufferSize() - m_endp); + if (remaining == 0) break; + errno = 0; + ssize_t got = unbuf_read(m_endp, remaining); + if (got > 0) { + m_endp += got; + } else if (VL_UNCOVERABLE(got < 0)) { + if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) { + // LCOV_EXCL_START + // write failed, presume error (perhaps out of disk space) + std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno); + VL_FATAL_MT("", 0, "", msg.c_str()); + close(); + break; + // LCOV_EXCL_STOP + } + } else { // got==0, EOF + // Fill buffer from here to end with NULLs so reader's don't + // need to check eof each character. + while (m_endp < m_bufp + bufferSize()) *m_endp++ = '\0'; + break; + } + } +} + +void VerilatedRestoreMem::open(const char* filename) { + m_assertOne.check(); + if (isOpen()) return; + VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n", filenamep);); + + if (VL_UNCOVERABLE(filename[0] == '|')) { + assert(0); // LCOV_EXCL_LINE // Not supported yet. + } else { + size = readFromGz(buf, filename, buf_size); + } + m_isOpen = true; + m_filename = filename; + m_cp = m_bufp; + m_endp = m_bufp; + header(); +} + +void VerilatedRestoreMem::close() { + if (!isOpen()) return; + trailer(); + flush(); + m_isOpen = false; +} + +int VerilatedRestoreMem::unbuf_read(uint8_t* dest, long rsize) { + if(buf_ptr + rsize > size) { + rsize = size - buf_ptr; + } + for(int i = 0; i < rsize; i++) { + dest[i] = buf[buf_ptr + i]; + } + buf_ptr += rsize; + + return rsize; +} #endif diff --git a/src/test/csrc/snapshot.h b/src/test/csrc/snapshot.h index 5bebdceda71a0f9f15a5d954277acbaa44a4ce10..5e039ab650de4c7bddde12d914e9c06ccec897f0 100644 --- a/src/test/csrc/snapshot.h +++ b/src/test/csrc/snapshot.h @@ -32,6 +32,29 @@ public: void flush(); void save(); }; + +class VerilatedRestoreMem : public VerilatedDeserialize { + const static long buf_size = (1024 * 1024 * 1024UL); + uint8_t *buf; + long size, buf_ptr; + // gzFile compressed_mem; + +public: + VerilatedRestoreMem() { + buf = new uint8_t[buf_size]; + size = 0; + } + ~VerilatedRestoreMem() { close(); delete buf; } + + void open(const char* filenamep) VL_MT_UNSAFE_ONE; + void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); } + + int unbuf_read(uint8_t* dest, long rsize); + + void close(); + void flush() {} + void fill(); +}; #endif #endif