├── .gitignore ├── LICENSE ├── README.md ├── src ├── CpuTrace.cc ├── CpuTrace.h ├── FstProcess.cc ├── FstProcess.h ├── Logger.cc ├── Logger.h ├── Makefile ├── MemTrace.cc ├── MemTrace.h ├── RegFileTrace.cc ├── RegFileTrace.h ├── TcpServer.cc ├── TcpServer.h ├── fst │ ├── CMakeLists.txt │ ├── Makefile │ ├── Makefile.am │ ├── Makefile.in │ ├── README.md │ ├── block_format.txt │ ├── config.h │ ├── fastlz.c │ ├── fastlz.h │ ├── fst_win_unistd.h │ ├── fstapi.c │ ├── fstapi.h │ ├── lz4.c │ └── lz4.h ├── fst_code.cc ├── gdb_conf.cmd ├── gdbstub.cc ├── gdbstub.h ├── gdbstub │ ├── .gitignore │ ├── LICENSE.txt │ ├── Makefile │ ├── README.md │ ├── arch_x86 │ │ ├── gdbstub_int.nasm │ │ ├── gdbstub_sys.c │ │ └── gdbstub_sys.h │ ├── demo │ │ ├── demo.c │ │ └── demo.gdbinit │ ├── gdbstub.c │ ├── gdbstub.h │ ├── gdbstub.ld.in │ └── tests │ │ ├── smoketest.gdbinit │ │ └── smoketest.sh ├── gdbstub_sys.cc ├── gdbstub_sys.h └── main.cc ├── test_data ├── configParams.txt ├── openocd.log ├── progmem.bin ├── progmem.elf ├── sw_semihosting │ ├── .gitignore │ ├── Makefile │ ├── lib.c │ ├── lib.h │ ├── main.c │ ├── printf.c │ ├── printf.h │ ├── printf_config.h │ ├── reg.h │ ├── riscv.h │ ├── sections.lds │ ├── semihosting.c │ ├── semihosting.h │ ├── start.S │ ├── top_defines.h │ └── trap.c ├── top.fst ├── top.fst.hier └── waves.gtkw └── various.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | .*.sw* 4 | *.log 5 | gdbwave 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Tom Verbeure 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GDBWave 2 | 3 | GDB server to debug CPU simulation waveform traces. 4 | 5 | See [GDBWave - A Post-Simulation Waveform-Based RISC-V GDB Debugging Server](https://tomverbeure.github.io/2022/02/20/GDBWave-Post-Simulation-RISCV-SW-Debugging.html). 6 | 7 | # Usage 8 | 9 | **Start gdbwave** 10 | 11 | ```sh 12 | cd ./src 13 | make run 14 | ``` 15 | 16 | This does the following: 17 | 18 | * Read in an FST file. 19 | * Extract all the instruction addresses with associated simulation timestamp. 20 | * Extract all CPU writes to the CPU register file 21 | * Extract all CPU writes to external memory 22 | * Start a GDB server 23 | * Makes GDB believe that it's dealing with an active or simulated CPU 24 | 25 | -------------------------------------------------------------------------------- /src/CpuTrace.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | #include "CpuTrace.h" 9 | #include "Logger.h" 10 | 11 | extern bool verbose; 12 | 13 | CpuTrace::CpuTrace(FstProcess & fstProc, FstSignal clk, FstSignal pcValid, FstSignal pc) : 14 | fstProc(fstProc), 15 | clk(clk), 16 | pcValid(pcValid), 17 | pc(pc) 18 | { 19 | init(); 20 | } 21 | 22 | static void pcChangedCB(uint64_t time, FstSignal *signal, const unsigned char *value, void *userInfo) 23 | { 24 | CpuTrace *cpuTrace = (CpuTrace *)userInfo; 25 | 26 | if (strstr((char *)value, "x") || strstr((char *)value, "z")){ 27 | return; 28 | } 29 | 30 | uint64_t valueInt = stol(string((const char *)value), nullptr, 2); 31 | 32 | #if 0 33 | LOG_DEBUG("%ld, %ud, %s, %s, %ld", time, signal->handle, signal->name.c_str(), value, valueInt); 34 | #endif 35 | 36 | if (signal->handle == cpuTrace->pcValid.handle){ 37 | cpuTrace->curPcValidVal = valueInt; 38 | return; 39 | } 40 | 41 | if (signal->handle == cpuTrace->pc.handle){ 42 | cpuTrace->curPcVal = valueInt; 43 | return; 44 | } 45 | 46 | // All signals changes on the rising edge of the clock. Everything is stable at the falling edge... 47 | if (signal->handle == cpuTrace->clk.handle && valueInt == 0){ 48 | if (cpuTrace->curPcValidVal){ 49 | 50 | if (verbose) LOG_INFO("instr retire: %ld, %08lx", time, cpuTrace->curPcVal); 51 | 52 | PcValue pc = { time, cpuTrace->curPcVal }; 53 | cpuTrace->pcTrace.push_back(pc); 54 | } 55 | } 56 | } 57 | 58 | void CpuTrace::init() 59 | { 60 | vector sigs; 61 | 62 | sigs.push_back(&clk); 63 | sigs.push_back(&pcValid); 64 | sigs.push_back(&pc); 65 | 66 | bool allSigsFound = fstProc.assignHandles(sigs); 67 | if (!allSigsFound){ 68 | fstProc.reportSignalsNotFound(sigs); 69 | exit(-1); 70 | } 71 | 72 | #if 0 73 | for(auto sig: sigs){ 74 | LOG_DEBUG(sig->name + "," + std::to_string(sig->handle); 75 | } 76 | #endif 77 | 78 | curPcValidVal = 0; 79 | curPcVal = 0; 80 | 81 | fstProc.getValueChanges(sigs, pcChangedCB, (void *)this); 82 | 83 | LOG_INFO("Nr CPU instructions: %ld", pcTrace.size()); 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/CpuTrace.h: -------------------------------------------------------------------------------- 1 | #ifndef CPU_TRACE_H 2 | #define CPU_TRACE_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | struct PcValue 9 | { 10 | uint64_t time; 11 | uint64_t pc; 12 | }; 13 | 14 | class CpuTrace 15 | { 16 | public: 17 | CpuTrace(FstProcess & fstProc, FstSignal clk, FstSignal pcValid, FstSignal pc); 18 | void init(); 19 | 20 | // Object to manage access to FST file 21 | FstProcess & fstProc; 22 | 23 | // Handles to signals inside the FST file 24 | FstSignal clk; 25 | FstSignal pcValid; 26 | FstSignal pc; 27 | 28 | // Helper signals for the FST callbacks to extract the PC values 29 | uint64_t curPcValidVal; 30 | uint64_t curPcVal; 31 | 32 | // All PC values in the FST trace 33 | vector pcTrace; 34 | 35 | vector::iterator pcTraceIt; 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/FstProcess.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "FstProcess.h" 6 | #include "Logger.h" 7 | 8 | FstProcess::FstProcess(string fstFileName) : 9 | fstFileName(fstFileName) 10 | { 11 | fstCtx = fstReaderOpen(fstFileName.c_str()); 12 | if (fstCtx == NULL) { 13 | stringstream ss; 14 | ss << "Could not open file '" << fstFileName << "'"; 15 | throw runtime_error(ss.str()); 16 | } 17 | } 18 | 19 | FstProcess::~FstProcess() 20 | { 21 | fstReaderClose(fstCtx); 22 | } 23 | 24 | string FstProcess::infoStr(void) 25 | { 26 | stringstream ss; 27 | 28 | const char * curFlatScope = fstReaderGetCurrentFlatScope(fstCtx); 29 | int curScopeLen = fstReaderGetCurrentScopeLen(fstCtx); 30 | int doubleEndianMatchState = fstReaderGetDoubleEndianMatchState(fstCtx); 31 | uint64_t dumpActivityChangeTime = fstReaderGetDumpActivityChangeTime(fstCtx, 0); 32 | unsigned char dumpActivityChangeValue = fstReaderGetDumpActivityChangeValue(fstCtx, 0); 33 | int fileType = fstReaderGetFileType(fstCtx); 34 | int fseekFailed = fstReaderGetFseekFailed(fstCtx); 35 | uint64_t memoryUsedByWriter = fstReaderGetMemoryUsedByWriter(fstCtx); 36 | uint32_t numDumpActivityChanges = fstReaderGetNumberDumpActivityChanges(fstCtx); 37 | 38 | // void * curScopeUserInfo = fstReaderGetCurrentScopeUserInfo(fstCtx); 39 | // fstHandle maxHandle = fstReaderGetMaxHandle(fstCtx); 40 | // char * fstReaderGetValueFromHandleAtTime(fstCtx, uint64_t tim, fstHandle facidx, char *buf); 41 | // int facProcessMask = fstReaderGetFacProcessMask(fstCtx, fstHandle facidx); 42 | 43 | ss << "============================================================" << endl; 44 | ss << "aliasCount: " << aliasCount() << endl; 45 | ss << "curFlatScope: " << curFlatScope << endl; 46 | ss << "curScopeLen: " << curScopeLen << endl; 47 | ss << "date: " << date() << endl; 48 | ss << "doubleEndianMatchState: " << doubleEndianMatchState << endl; 49 | ss << "dumpActivityChangeTime: " << dumpActivityChangeTime << endl; 50 | ss << "dumpActivityChangeValue: " << (int)dumpActivityChangeValue << endl; 51 | ss << "fileType: " << fileType << " (" << fileTypeStrings[fileType] << ")" << endl; 52 | ss << "fseekFailed: " << fseekFailed << endl; 53 | ss << "memoryUsedByWriter:" << memoryUsedByWriter << endl; 54 | ss << "numDumpActivityChanges: " << numDumpActivityChanges << endl; 55 | ss << "scopeCount: " << scopeCount() << endl; 56 | ss << "startTime: " << startTime() << endl; 57 | ss << "endTime: " << endTime() << endl; 58 | ss << "timeZero: " << timezero() << endl; 59 | ss << "timescale:" << timescale() << endl; 60 | ss << "valueChangeSectionCount: " << valueChangeSectionCount() << endl; 61 | ss << "varCount: " << varCount() << endl; 62 | ss << "Version string: " << version() << endl; 63 | ss << "============================================================" << endl; 64 | 65 | // FIXME: move... 66 | if (numDumpActivityChanges > 0){ 67 | LOG_ERROR("Blackout regions are not supported."); 68 | exit(-2); 69 | } 70 | 71 | return ss.str(); 72 | } 73 | 74 | // For a given list of signals, look for and assign the fstHandle 75 | // Return true if all signals are found. 76 | bool FstProcess::assignHandles(vector &signals) 77 | { 78 | struct fstHier *hier; 79 | string curScopeName; 80 | 81 | bool sigNotFound; 82 | 83 | fstReaderIterateHierRewind(fstCtx); 84 | while((hier = fstReaderIterateHier(fstCtx))){ 85 | 86 | switch(hier->htyp){ 87 | case FST_HT_SCOPE: { 88 | curScopeName = fstReaderPushScope(fstCtx, hier->u.scope.name, NULL); 89 | LOG_DEBUG("curScopeName: %s", curScopeName.c_str()); 90 | break; 91 | } 92 | 93 | case FST_HT_UPSCOPE: { 94 | curScopeName = fstReaderPopScope(fstCtx); 95 | LOG_DEBUG("curScopeName: %s", curScopeName.c_str()); 96 | break; 97 | } 98 | 99 | case FST_HT_VAR: { 100 | string curName = hier->u.var.name; 101 | LOG_DEBUG("curName: %s", curName.c_str()); 102 | 103 | sigNotFound = false; 104 | for(auto sig: signals){ 105 | if (sig->hasHandle) 106 | continue; 107 | sigNotFound = true; 108 | 109 | if (sig->scopeName == curScopeName && sig->name == curName){ 110 | sig->hasHandle = true; 111 | sig->handle = hier->u.var.handle; 112 | } 113 | } 114 | break; 115 | } 116 | } 117 | 118 | } 119 | 120 | return !sigNotFound; 121 | } 122 | 123 | void FstProcess::reportSignalsNotFound(vector &signals) 124 | { 125 | LOG_WARNING("Not all signals found..."); 126 | 127 | for(auto sig: signals){ 128 | if (!sig->hasHandle){ 129 | LOG_WARNING("Signal not found: %s.%s\n", sig->scopeName.c_str(), sig->name.c_str()); 130 | } 131 | } 132 | } 133 | 134 | void FstProcess::fst_callback2(void *user_callback_data_pointer, uint64_t time, fstHandle sigHandle, const unsigned char *value, uint32_t len) 135 | { 136 | throw runtime_error("callback2 not supported."); 137 | } 138 | 139 | void FstProcess::fst_callback(void *user_callback_data_pointer, uint64_t time, fstHandle sigHandle, const unsigned char *value) 140 | { 141 | struct FstCallbackInfo *cbInfo = (struct FstCallbackInfo *)user_callback_data_pointer; 142 | map::iterator it = cbInfo->handle2Signal.find(sigHandle); 143 | 144 | cbInfo->valueChangedCB(time, it->second, value, cbInfo->userInfo); 145 | } 146 | 147 | void FstProcess::getValueChanges( 148 | vector signals, 149 | void (*valueChangedCB)(uint64_t time, FstSignal *signal, const unsigned char *value, void *userInfo), 150 | void *userInfo) 151 | { 152 | struct FstCallbackInfo cbInfo; 153 | cbInfo.valueChangedCB = valueChangedCB; 154 | cbInfo.userInfo = userInfo; 155 | 156 | fstReaderClrFacProcessMaskAll(fstCtx); 157 | 158 | for(auto sig: signals){ 159 | fstReaderSetFacProcessMask(fstCtx, sig->handle); 160 | cbInfo.handle2Signal.insert({sig->handle, sig}); 161 | } 162 | 163 | fstReaderIterBlocks2(fstCtx, FstProcess::fst_callback, FstProcess::fst_callback2, (void *)&cbInfo, NULL); 164 | } 165 | 166 | -------------------------------------------------------------------------------- /src/FstProcess.h: -------------------------------------------------------------------------------- 1 | #ifndef FST_PROCESS_H 2 | #define FST_PROCESS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | using namespace std; 13 | 14 | class FstSignal 15 | { 16 | public: 17 | FstSignal() : hasHandle(false) {} 18 | FstSignal(string scopeName, string name) : scopeName(scopeName), name(name), hasHandle(false) {} 19 | FstSignal(string fullName) : scopeName(getScope(fullName)), name(getLocalName(fullName)), hasHandle(false) {} 20 | 21 | string scopeName; 22 | string name; 23 | bool hasHandle; 24 | fstHandle handle; 25 | 26 | static string getScope(string full_path){ 27 | int last_dot = full_path.find_last_of('.'); 28 | return full_path.substr(0, last_dot); 29 | } 30 | static string getLocalName(string full_path){ 31 | int last_dot = full_path.find_last_of('.'); 32 | return full_path.substr(last_dot+1); 33 | } 34 | }; 35 | 36 | class FstProcess 37 | { 38 | public: 39 | FstProcess(string fstFileName); 40 | ~FstProcess(); 41 | 42 | string version(void) { return fstReaderGetVersionString(fstCtx); }; 43 | string date(void) { 44 | string d = fstReaderGetDateString(fstCtx); 45 | d = regex_replace(d, regex("^\\s+"), string("")); 46 | d = regex_replace(d, regex("\\s+$"), string("")); 47 | return d; 48 | } 49 | 50 | uint64_t aliasCount(void) { return fstReaderGetAliasCount(fstCtx); }; 51 | uint64_t startTime(void) { return fstReaderGetStartTime(fstCtx); }; 52 | uint64_t endTime(void) { return fstReaderGetEndTime(fstCtx); }; 53 | int64_t timezero(void) { return fstReaderGetTimezero(fstCtx); }; 54 | uint64_t scopeCount(void) { return fstReaderGetScopeCount(fstCtx); }; 55 | int timescale(void) { return (int)fstReaderGetTimescale(fstCtx); }; 56 | uint64_t varCount(void) { return fstReaderGetVarCount(fstCtx); }; 57 | uint64_t valueChangeSectionCount(void) { return fstReaderGetValueChangeSectionCount(fstCtx); }; 58 | 59 | string infoStr(void); 60 | 61 | bool assignHandles(vector &signals); 62 | void reportSignalsNotFound(vector &signals); 63 | void getValueChanges(vector signals, void (*valueChangedCB)(uint64_t time, FstSignal *signal, const unsigned char *value, void *userInfo), void *userInfo); 64 | 65 | struct FstCallbackInfo { 66 | map handle2Signal; 67 | void (*valueChangedCB)(uint64_t time, FstSignal *signal, const unsigned char *value, void *userInfo); 68 | void *userInfo; 69 | }; 70 | 71 | static void fst_callback2(void *user_callback_data_pointer, uint64_t time, fstHandle txidx, const unsigned char *value, uint32_t len); 72 | static void fst_callback(void *user_callback_data_pointer, uint64_t time, fstHandle txidx, const unsigned char *value); 73 | 74 | //private: 75 | string fstFileName; 76 | void * fstCtx; 77 | 78 | public: 79 | const vector fileTypeStrings = { 80 | "VERILOG", 81 | "VHDL", 82 | "VERILOG_VHDL" 83 | }; 84 | 85 | const vector scopeTypeStrings = { 86 | "VCD_MODULE", 87 | "VCD_TASK", 88 | "VCD_FUNCTION", 89 | "VCD_BEGIN", 90 | "VCD_FORK", 91 | "VCD_GENERATE", 92 | "VCD_STRUCT", 93 | "VCD_UNION", 94 | "VCD_CLASS", 95 | "VCD_INTERFACE", 96 | "VCD_PACKAGE", 97 | "VCD_PROGRAM", 98 | 99 | "VHDL_ARCHITECTURE", 100 | "VHDL_PROCEDURE", 101 | "VHDL_FUNCTION", 102 | "VHDL_RECORD", 103 | "VHDL_PROCESS", 104 | "VHDL_BLOCK", 105 | "VHDL_FOR_GENERATE", 106 | "VHDL_IF_GENERATE", 107 | "VHDL_GENERATE", 108 | "VHDL_PACKAGE" 109 | }; 110 | 111 | const vector varTypeStrings = { 112 | "VCD_EVENT", 113 | "VCD_INTEGER", 114 | "VCD_PARAMETER", 115 | "VCD_REAL", 116 | "VCD_REAL_PARAMETER", 117 | "VCD_REG", 118 | "VCD_SUPPLY0", 119 | "VCD_SUPPLY1", 120 | "VCD_TIME", 121 | "VCD_TRI", 122 | "VCD_TRIAND", 123 | "VCD_TRIOR", 124 | "VCD_TRIREG", 125 | "VCD_TRI0", 126 | "VCD_TRI1", 127 | "VCD_WAND", 128 | "VCD_WIRE", 129 | "VCD_WOR", 130 | "VCD_PORT", 131 | "VCD_SPARRAY", 132 | "VCD_REALTIME", 133 | 134 | "GEN_STRING", 135 | 136 | "SV_BIT", 137 | "SV_LOGIC", 138 | "SV_INT", 139 | "SV_SHORTINT", 140 | "SV_LONGINT", 141 | "SV_BYTE", 142 | "SV_ENUM", 143 | "SV_SHORTREAL" 144 | }; 145 | 146 | const vector varDirStrings = { 147 | "IMPLICIT", 148 | "INPUT", 149 | "OUTPUT", 150 | "INOUT", 151 | "BUFFER", 152 | "LINKAGE" 153 | }; 154 | 155 | const vector hierTypeStrings = { 156 | "SCOPE", 157 | "UPSCOPE", 158 | "VAR", 159 | "ATTRBEGIN", 160 | "ATTREND", 161 | 162 | "TREEBEGIN", 163 | "TREEEND", 164 | }; 165 | 166 | }; 167 | 168 | #endif 169 | 170 | -------------------------------------------------------------------------------- /src/Logger.cc: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/Logger.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGGER_H 2 | #define LOGGER_H 3 | 4 | // Singleton pattern described here: https://stackoverflow.com/questions/1008019/c-singleton-design-pattern 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class Logger 11 | { 12 | public: 13 | static Logger& log(void) 14 | { 15 | static Logger instance; 16 | return instance; 17 | }; 18 | 19 | private: 20 | Logger() : debugLevel(ERROR) {}; 21 | 22 | public: 23 | Logger(Logger const &) = delete; 24 | void operator=(Logger const &) = delete; 25 | 26 | enum DebugLevel { 27 | NONE = -1, 28 | ERROR = 0, 29 | WARNING = 1, 30 | INFO = 2, 31 | DEBUG = 3 32 | }; 33 | 34 | private: 35 | DebugLevel debugLevel; 36 | std::string logFileName; 37 | std::ofstream logFile; 38 | 39 | public: 40 | void setDebugLevel(DebugLevel l){ 41 | debugLevel = l; 42 | }; 43 | void setLogFile(std::string fn){ 44 | logFileName = fn; 45 | logFile.open(fn); 46 | } 47 | void out(DebugLevel l, std::string s, bool prefix = true, bool ret = true) { 48 | if (l <= debugLevel){ 49 | std::string p_str = ""; 50 | if (prefix){ 51 | switch(l){ 52 | case ERROR: p_str = "ERROR : "; break; 53 | case WARNING: p_str = "WARNING: "; break; 54 | case INFO: p_str = "INFO : "; break; 55 | case DEBUG: p_str = "DEBUG : "; break; 56 | default: break; 57 | } 58 | } 59 | 60 | std::cerr << p_str << s; 61 | if (ret) std::cerr << std::endl; 62 | 63 | if (logFile){ 64 | logFile << p_str << s; 65 | if (ret) logFile << std::endl; 66 | } 67 | } 68 | } 69 | void error(std::string s){ 70 | out(DebugLevel::ERROR, s); 71 | } 72 | void warning(std::string s){ 73 | out(DebugLevel::WARNING, s); 74 | } 75 | void info(std::string s){ 76 | out(DebugLevel::INFO, s); 77 | } 78 | void debug(std::string s){ 79 | out(DebugLevel::DEBUG, s); 80 | } 81 | 82 | }; 83 | 84 | #define LOG_ERROR(...) { \ 85 | char s[4096]; \ 86 | snprintf(s, sizeof(s), __VA_ARGS__); \ 87 | Logger::log().error(s); \ 88 | } 89 | 90 | #define LOG_WARNING(...) { \ 91 | char s[4096]; \ 92 | snprintf(s, sizeof(s), __VA_ARGS__); \ 93 | Logger::log().warning(s); \ 94 | } 95 | 96 | #define LOG_INFO(...) { \ 97 | char s[4096]; \ 98 | snprintf(s, sizeof(s), __VA_ARGS__); \ 99 | Logger::log().info(s); \ 100 | } 101 | 102 | #define LOG_DEBUG(...) { \ 103 | char s[4096]; \ 104 | snprintf(s, sizeof(s), __VA_ARGS__); \ 105 | Logger::log().debug(s); \ 106 | } 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | INC_FILES = FstProcess.h CpuTrace.h RegFileTrace.h MemTrace.h TcpServer.h Logger.h 4 | OBJ_FILES = main.o FstProcess.o CpuTrace.o RegFileTrace.o MemTrace.o TcpServer.o Logger.o gdbstub.o gdbstub_sys.o 5 | LIB_FILES = -lfstapi -lz 6 | 7 | UNAME_S = $(shell uname -s) 8 | ifeq ($(UNAME_S),Linux) 9 | RISCV_TOOLCHAIN = /opt/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin/ 10 | endif 11 | ifeq ($(UNAME_S),Darwin) 12 | RISCV_TOOLCHAIN = /opt/riscv64-unknown-elf-gcc-10.1.0-2020.08.2-x86_64-apple-darwin/bin 13 | endif 14 | 15 | RISCV_PREFIX = riscv64-unknown-elf- 16 | 17 | RISCV_GDB = $(RISCV_TOOLCHAIN)/$(RISCV_PREFIX)gdb 18 | 19 | CXXFLAGS += --std=c++14 -I. -Wall -pedantic -g -O0 -Wno-format-zero-length 20 | LDFLAGS += -L./fst -Wall -g 21 | 22 | TEST_FST = ../test_data/top.fst 23 | TEST_PARAMS = ../test_data/configParams.txt 24 | 25 | all: gdbwave 26 | 27 | run: gdbwave 28 | ./gdbwave -w $(TEST_FST) -c $(TEST_PARAMS) 29 | 30 | gdbwave: fst/libfstapi.a $(OBJ_FILES) $(INC_FILES) 31 | $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(OBJ_FILES) $(LIB_FILES) 32 | 33 | fst/libfstapi.a: 34 | cd fst && make 35 | 36 | $(OBJ_FILES): $(INC_FILES) 37 | 38 | gdb: 39 | $(RISCV_GDB) ../test_data/progmem.elf -x ./gdb_conf.cmd 40 | 41 | wave: 42 | gtkwave ../test_data/top.fst ../test_data/waves.gtkw 43 | 44 | clean: 45 | \rm -fr gdbwave *.o 46 | cd fst && make clean 47 | -------------------------------------------------------------------------------- /src/MemTrace.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | #include "MemTrace.h" 11 | #include "Logger.h" 12 | 13 | extern bool verbose; 14 | 15 | MemTrace::MemTrace(FstProcess & fstProc, string memInitFileName, int memInitStartAddr, 16 | FstSignal clk, 17 | FstSignal memCmdValid, FstSignal memCmdReady, FstSignal memCmdAddr, FstSignal memCmdSize, FstSignal memCmdWr, FstSignal memCmdWrData, 18 | FstSignal memRspValid, FstSignal memRspData) : 19 | fstProc(fstProc), 20 | memInitFileName(memInitFileName), 21 | memInitStartAddr(memInitStartAddr), 22 | clk(clk), 23 | memCmdValid(memCmdValid), 24 | memCmdReady(memCmdReady), 25 | memCmdAddr(memCmdAddr), 26 | memCmdSize(memCmdSize), 27 | memCmdWr(memCmdWr), 28 | memCmdWrData(memCmdWrData), 29 | memRspValid(memRspValid), 30 | memRspData(memRspData) 31 | { 32 | init(); 33 | } 34 | 35 | static void memChangedCB(uint64_t time, FstSignal *signal, const unsigned char *value, void *userInfo) 36 | { 37 | MemTrace *memTrace = (MemTrace *)userInfo; 38 | memTrace->processSignalChanged(time, signal, value); 39 | } 40 | 41 | void MemTrace::processSignalChanged(uint64_t time, FstSignal *signal, const unsigned char *value) 42 | { 43 | if (strstr((char *)value, "x") || strstr((char *)value, "z")){ 44 | return; 45 | } 46 | 47 | uint64_t valueInt = stol(string((const char *)value), nullptr, 2); 48 | 49 | #if 0 50 | LOG_DEBUG("%ld, %ud, %s, %s, %ld", time, signal->handle, signal->name.c_str(), value, valueInt); 51 | #endif 52 | 53 | if (signal->handle == memCmdValid.handle){ 54 | curMemCmdValid = valueInt; 55 | return; 56 | } 57 | 58 | if (signal->handle == memCmdReady.handle){ 59 | curMemCmdReady = valueInt; 60 | return; 61 | } 62 | 63 | if (signal->handle == memCmdAddr.handle){ 64 | curMemCmdAddr = valueInt; 65 | return; 66 | } 67 | 68 | if (signal->handle == memCmdSize.handle){ 69 | curMemCmdSize = valueInt; 70 | return; 71 | } 72 | 73 | if (signal->handle == memCmdWr.handle){ 74 | curMemCmdWr = valueInt; 75 | return; 76 | } 77 | 78 | if (signal->handle == memCmdWrData.handle){ 79 | curMemCmdWrData = valueInt; 80 | return; 81 | } 82 | 83 | if (signal->handle == memRspValid.handle){ 84 | curMemRspValid = valueInt; 85 | return; 86 | } 87 | 88 | if (signal->handle == memRspData.handle){ 89 | curMemRspData = valueInt; 90 | return; 91 | } 92 | 93 | // All signals changes on the rising edge of the clock. Everything is stable at the falling edge... 94 | if (signal->handle == clk.handle && valueInt == 0){ 95 | if (curMemCmdValid && curMemCmdReady){ 96 | // For now, only handle memory writes. 97 | if (curMemCmdWr){ 98 | int byteEna = 0; 99 | switch(curMemCmdSize){ 100 | case 0: byteEna = 1 << (curMemCmdAddr & 3); break; 101 | case 1: byteEna = 3 << (curMemCmdAddr & 3); break; 102 | default: byteEna = 15; break; 103 | } 104 | 105 | for(int byteNr=0; byteNr<4;++byteNr){ 106 | if (byteEna & (1<> (byteNr * 8)) & 255; 108 | uint64_t addr = (curMemCmdAddr & ~3) | byteNr; 109 | 110 | if (verbose) LOG_INFO("MemWr: 0x%08lx <- 0x%02lx (@%ld)", addr, byteVal, time); 111 | 112 | MemAccess ma = { time, curMemCmdWr, addr, byteVal }; 113 | memTrace.push_back(ma); 114 | } 115 | } 116 | } 117 | } 118 | } 119 | } 120 | 121 | void MemTrace::init() 122 | { 123 | if (!memInitFileName.empty()){ 124 | LOG_INFO("Loading mem init file: %s", memInitFileName.c_str()); 125 | ifstream initFile(memInitFileName, ios::in | ios::binary); 126 | if (initFile.fail()){ 127 | LOG_ERROR("Error opening mem init file: %s (%s)", memInitFileName.c_str(), strerror(errno)); 128 | exit(1); 129 | } 130 | memInitContents = vector((std::istreambuf_iterator(initFile)), std::istreambuf_iterator()); 131 | } 132 | 133 | vector sigs; 134 | 135 | sigs.push_back(&clk); 136 | sigs.push_back(&memCmdValid); 137 | sigs.push_back(&memCmdReady); 138 | sigs.push_back(&memCmdAddr); 139 | sigs.push_back(&memCmdSize); 140 | sigs.push_back(&memCmdWr); 141 | sigs.push_back(&memCmdWrData); 142 | sigs.push_back(&memRspValid); 143 | sigs.push_back(&memRspData); 144 | 145 | bool allSigsFound = fstProc.assignHandles(sigs); 146 | if (!allSigsFound){ 147 | fstProc.reportSignalsNotFound(sigs); 148 | exit(-1); 149 | } 150 | 151 | curMemCmdValid = false; 152 | curMemCmdReady = false; 153 | curMemCmdAddr = 0; 154 | curMemCmdSize = 0; 155 | curMemCmdWr = false; 156 | curMemCmdWrData = 0; 157 | curMemRspValid = false; 158 | curMemRspData = 0; 159 | 160 | fstProc.getValueChanges(sigs, memChangedCB, (void *)this); 161 | 162 | LOG_INFO("Nr mem write transactions: %ld", memTrace.size()); 163 | } 164 | 165 | 166 | bool MemTrace::getValue(uint64_t time, uint64_t addr, char *value) 167 | { 168 | bool valueValid = false; 169 | uint64_t val = 0; 170 | 171 | if (addr >= memInitStartAddr && addr < (memInitStartAddr + memInitContents.size())){ 172 | valueValid = true; 173 | val = memInitContents[addr - memInitStartAddr]; 174 | } 175 | 176 | for(auto m: memTrace){ 177 | if (m.time > time) 178 | break; 179 | 180 | if (m.wr && m.addr == addr){ 181 | valueValid = true; 182 | val = m.value; 183 | } 184 | } 185 | 186 | *value = val; 187 | 188 | return valueValid; 189 | } 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /src/MemTrace.h: -------------------------------------------------------------------------------- 1 | #ifndef MEM_TRACE_H 2 | #define MEM_TRACE_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | struct MemAccess 10 | { 11 | uint64_t time; 12 | bool wr; 13 | uint64_t addr; 14 | uint64_t value; 15 | }; 16 | 17 | class MemTrace 18 | { 19 | public: 20 | MemTrace(FstProcess & fstProc, string memInitFileName, int memInitStartAddr, 21 | FstSignal clk, 22 | FstSignal memCmdValid, FstSignal memCmdReady, FstSignal memCmdAddr, FstSignal memCmdSize, FstSignal memCmdWr, FstSignal memCmdWrData, 23 | FstSignal memRspValid, FstSignal memRspData); 24 | 25 | void init(); 26 | 27 | //void findNextMemAccess(uint64_t startTime, uint64_t pc_value); 28 | 29 | // Object to manage access to FST file 30 | FstProcess & fstProc; 31 | 32 | // Memory initialization values at bootup 33 | string memInitFileName; 34 | unsigned int memInitStartAddr; 35 | std::vector memInitContents; 36 | 37 | // Handles to signals inside the FST file 38 | FstSignal clk; 39 | FstSignal memCmdValid; 40 | FstSignal memCmdReady; 41 | FstSignal memCmdAddr; 42 | FstSignal memCmdSize; 43 | FstSignal memCmdWr; 44 | FstSignal memCmdWrData; 45 | FstSignal memRspValid; 46 | FstSignal memRspData; 47 | 48 | // Helper signals for the FST callbacks to extract the PC values 49 | bool curMemCmdValid; 50 | bool curMemCmdReady; 51 | uint64_t curMemCmdAddr; 52 | uint64_t curMemCmdSize; 53 | bool curMemCmdWr; 54 | uint64_t curMemCmdWrData; 55 | bool curMemRspValid; 56 | uint64_t curMemRspData; 57 | 58 | // All PC values in the FST trace 59 | vector memTrace; 60 | 61 | vector::iterator memTraceIt; 62 | 63 | void processSignalChanged(uint64_t time, FstSignal *signal, const unsigned char *value); 64 | 65 | bool getValue(uint64_t time, uint64_t addr, char *value); 66 | }; 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/RegFileTrace.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | #include "RegFileTrace.h" 10 | #include "Logger.h" 11 | 12 | extern bool verbose; 13 | 14 | RegFileTrace::RegFileTrace(FstProcess & fstProc, FstSignal clk, FstSignal memWr, FstSignal memAddr, FstSignal memWrData) : 15 | fstProc(fstProc), 16 | clk(clk), 17 | memWr(memWr), 18 | memAddr(memAddr), 19 | memWrData(memWrData) 20 | { 21 | init(); 22 | } 23 | 24 | static void memChangedCB(uint64_t time, FstSignal *signal, const unsigned char *value, void *userInfo) 25 | { 26 | RegFileTrace *regFileTrace = (RegFileTrace *)userInfo; 27 | 28 | if (strstr((char *)value, "x") || strstr((char *)value, "z")){ 29 | return; 30 | } 31 | 32 | uint64_t valueInt = stol(string((const char *)value), nullptr, 2); 33 | 34 | #if 0 35 | LOG_DEBUG("%ld, %ud, %s, %s, %ld", time, signal->handle, signal->name.c_str(), value, valueInt); 36 | #endif 37 | 38 | if (signal->handle == regFileTrace->memWr.handle){ 39 | regFileTrace->curMemWr = valueInt; 40 | return; 41 | } 42 | 43 | if (signal->handle == regFileTrace->memAddr.handle){ 44 | regFileTrace->curMemAddr = valueInt; 45 | return; 46 | } 47 | 48 | if (signal->handle == regFileTrace->memWrData.handle){ 49 | regFileTrace->curMemWrData = valueInt; 50 | return; 51 | } 52 | 53 | // All signals changes on the rising edge of the clock. Everything is stable at the falling edge... 54 | if (signal->handle == regFileTrace->clk.handle && valueInt == 0){ 55 | if (regFileTrace->curMemWr){ 56 | if (verbose) LOG_INFO("RegWr: 0x%08lx <- 0x%08lx (@%ld)", regFileTrace->curMemAddr, regFileTrace->curMemWrData, time); 57 | 58 | RegFileAccess mem = { time, regFileTrace->curMemWr, regFileTrace->curMemAddr, regFileTrace->curMemWrData }; 59 | regFileTrace->regFileTrace.push_back(mem); 60 | } 61 | } 62 | } 63 | 64 | void RegFileTrace::init() 65 | { 66 | vector sigs; 67 | 68 | sigs.push_back(&clk); 69 | sigs.push_back(&memWr); 70 | sigs.push_back(&memAddr); 71 | sigs.push_back(&memWrData); 72 | 73 | bool allSigsFound = fstProc.assignHandles(sigs); 74 | if (!allSigsFound){ 75 | fstProc.reportSignalsNotFound(sigs); 76 | exit(-1); 77 | } 78 | 79 | curMemWr = false; 80 | curMemAddr = 0; 81 | curMemWrData = 0; 82 | 83 | fstProc.getValueChanges(sigs, memChangedCB, (void *)this); 84 | 85 | LOG_INFO("Nr regfile write transactions: %ld", regFileTrace.size()); 86 | } 87 | 88 | 89 | bool RegFileTrace::getValue(uint64_t time, uint64_t addr, uint64_t *value) 90 | { 91 | bool valueValid = false; 92 | uint64_t val; 93 | 94 | for(auto m: regFileTrace){ 95 | if (m.time > time) 96 | break; 97 | 98 | if (m.wr && m.addr == addr){ 99 | valueValid = true; 100 | val = m.value; 101 | } 102 | } 103 | 104 | if (valueValid){ 105 | *value = val; 106 | } 107 | 108 | return valueValid; 109 | } 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/RegFileTrace.h: -------------------------------------------------------------------------------- 1 | #ifndef REG_FILE_TRACE_H 2 | #define REG_FILE_TRACE_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | struct RegFileAccess 9 | { 10 | uint64_t time; 11 | bool wr; 12 | uint64_t addr; 13 | uint64_t value; 14 | }; 15 | 16 | class RegFileTrace 17 | { 18 | public: 19 | RegFileTrace(FstProcess & fstProc, FstSignal clk, FstSignal memWr, FstSignal memAddr, FstSignal memWrData); 20 | void init(); 21 | 22 | // Object to manage access to FST file 23 | FstProcess & fstProc; 24 | 25 | // Handles to signals inside the FST file 26 | FstSignal clk; 27 | FstSignal memWr; 28 | FstSignal memAddr; 29 | FstSignal memWrData; 30 | 31 | // Helper signals for the FST callbacks to extract the PC values 32 | bool curMemWr; 33 | uint64_t curMemAddr; 34 | uint64_t curMemWrData; 35 | 36 | // All PC values in the FST trace 37 | vector regFileTrace; 38 | 39 | vector::iterator regFileTraceIt; 40 | 41 | bool getValue(uint64_t time, uint64_t addr, uint64_t *value); 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/TcpServer.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "TcpServer.h" 11 | #include "Logger.h" 12 | 13 | using namespace std; 14 | 15 | TcpServer::TcpServer(int port) : port(port) 16 | { 17 | open(port); 18 | } 19 | 20 | TcpServer::~TcpServer() 21 | { 22 | close(socket_fd); 23 | close(server_fd); 24 | } 25 | 26 | void TcpServer::open(int port) 27 | { 28 | // Based on testbench from Hazard3 project: 29 | // https://github.com/Wren6991/Hazard3/blob/c1f17b0b23d7e1a52241663bfb53568c89440f2d/test/sim/openocd/tb.cpp#L98 30 | 31 | int server_fd; 32 | struct sockaddr_in sock_addr; 33 | socklen_t sock_addr_len = sizeof(sock_addr); 34 | 35 | server_fd = ::socket(AF_INET, SOCK_STREAM, 0); 36 | if (server_fd == 0) { 37 | perror("socket failed"); 38 | throw runtime_error("Socket creation failed."); 39 | } 40 | 41 | #if !defined(__APPLE__) 42 | // Both SO_REUSEADDR and SO_REUSEPORT are required to allow the TCP server to restart again immediately 43 | // after closing it, but one way or the other, that doesn't work on macOS... 44 | int sock_opt = 1; 45 | int setsockopt_rc = ::setsockopt( 46 | server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, // fails on macOS 47 | &sock_opt, sizeof(sock_opt) 48 | ); 49 | 50 | if (setsockopt_rc) { 51 | cerr << setsockopt_rc << endl; 52 | perror("setsockopt failed"); 53 | throw runtime_error("setsockopt failed."); 54 | } 55 | #endif 56 | 57 | sock_addr.sin_family = AF_INET; 58 | sock_addr.sin_addr.s_addr = INADDR_ANY; 59 | sock_addr.sin_port = htons(this->port); 60 | if (::bind(server_fd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) < 0) { 61 | perror("bind failed"); 62 | throw runtime_error("bind failed."); 63 | } 64 | 65 | LOG_INFO("Waiting for connection on port %d...", this->port); 66 | if (::listen(server_fd, 3) < 0) { 67 | perror("listen failed"); 68 | throw runtime_error("listen failed."); 69 | } 70 | 71 | socket_fd = ::accept(server_fd, (struct sockaddr *)&sock_addr, &sock_addr_len); 72 | if (socket_fd < 0) { 73 | perror("accept failed"); 74 | throw runtime_error("accept failed."); 75 | } 76 | 77 | LOG_INFO("Connected!"); 78 | } 79 | 80 | ssize_t TcpServer::xmit(const void *buf, size_t len) 81 | { 82 | #if !defined(__APPLE__) 83 | ssize_t ret = ::send(socket_fd, buf, len, MSG_NOSIGNAL); 84 | #else 85 | ssize_t ret = ::send(socket_fd, buf, len, 0); 86 | #endif 87 | return ret; 88 | } 89 | 90 | ssize_t TcpServer::recv(void *buf, size_t buf_size) 91 | { 92 | ssize_t ret = ::read(socket_fd, buf, buf_size); 93 | return ret; 94 | } 95 | 96 | #if 0 97 | void tcpTest() 98 | { 99 | TcpServer tcpServer(3333); 100 | 101 | unsigned char rxbuf[256]; 102 | int ret; 103 | 104 | while( (ret = tcpServer.recv(rxbuf, 256)) > 0){ 105 | cout << "ret:" << ret << endl; 106 | if (ret > 0){ 107 | tcpServer.xmit("hhh", 3); 108 | tcpServer.xmit(rxbuf, ret); 109 | } 110 | } 111 | 112 | if (ret == 0){ 113 | cout << "Connection closed..." << endl; 114 | } 115 | else{ 116 | cout << "Connection error: " << ret << endl; 117 | } 118 | } 119 | #endif 120 | 121 | -------------------------------------------------------------------------------- /src/TcpServer.h: -------------------------------------------------------------------------------- 1 | #ifndef TCP_SERVER_H 2 | #define TCP_SERVER_H 3 | 4 | #include 5 | 6 | class TcpServer 7 | { 8 | public: 9 | TcpServer(int port); 10 | ~TcpServer(); 11 | 12 | void open(int port); 13 | ssize_t xmit(const void *buf, size_t len); 14 | ssize_t recv(void *buf, size_t buf_size); 15 | 16 | private: 17 | int server_fd; 18 | int socket_fd; 19 | int port; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/fst/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0) 2 | 3 | project (fstlib) 4 | 5 | ######################################################################################################################## 6 | # Easiest way to get ZLib on windows is using vcpkg, to load vcpkg: 7 | # cmake -DCMAKE_TOOLCHAIN_FILE=[path to vcpkg]/scripts/buildsystems/vcpkg.cmake 8 | if(CMAKE_TOOLCHAIN_FILE) 9 | message(STATUS "Using VCPKG from ${CMAKE_TOOLCHAIN_FILE}") 10 | endif() 11 | ######################################################################################################################## 12 | find_package(ZLIB REQUIRED) 13 | 14 | add_library(fstapi fstapi.c fstapi.h fst_win_unistd.h) 15 | target_link_libraries(fstapi PRIVATE ZLIB::ZLIB) 16 | # hack to avoid creating dummy config.h 17 | target_compile_definitions(fstapi PRIVATE -DFST_CONFIG_INCLUDE="fstapi.h") 18 | 19 | if(MSVC) 20 | # define __MINGW32__ to minimize changes to upstream 21 | target_compile_definitions(fstapi PRIVATE __MINGW32__ _CRT_SECURE_NO_WARNINGS FST_DO_MISALIGNED_OPS) 22 | target_compile_options(fstapi PRIVATE /wd4244 /wd4267 /wd4146 /wd4996) 23 | endif() 24 | -------------------------------------------------------------------------------- /src/fst/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CFLAGS += -I. -g 3 | OBJ_FILES = fastlz.o lz4.o fstapi.o 4 | AR_FILE = libfstapi.a 5 | 6 | $(AR_FILE): $(OBJ_FILES) 7 | ar rcs $(AR_FILE) $(OBJ_FILES) 8 | 9 | clean: 10 | rm -fr *.o *.a 11 | -------------------------------------------------------------------------------- /src/fst/Makefile.am: -------------------------------------------------------------------------------- 1 | ## -*- makefile -*- 2 | ## 3 | 4 | AM_CFLAGS= $(LIBZ_CFLAGS) $(LIBJUDY_CFLAGS) 5 | 6 | noinst_LIBRARIES= libfst.a 7 | 8 | libfst_a_SOURCES= fastlz.c fastlz.h lz4.c lz4.h fstapi.c fstapi.h fst_win_unistd.h 9 | 10 | EXTRA_DIST= block_format.txt CMakeLists.txt 11 | -------------------------------------------------------------------------------- /src/fst/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile.in generated by automake 1.13.4 from Makefile.am. 2 | # @configure_input@ 3 | 4 | # Copyright (C) 1994-2013 Free Software Foundation, Inc. 5 | 6 | # This Makefile.in is free software; the Free Software Foundation 7 | # gives unlimited permission to copy and/or distribute it, 8 | # with or without modifications, as long as this notice is preserved. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 12 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 13 | # PARTICULAR PURPOSE. 14 | 15 | @SET_MAKE@ 16 | 17 | VPATH = @srcdir@ 18 | am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 19 | am__make_running_with_option = \ 20 | case $${target_option-} in \ 21 | ?) ;; \ 22 | *) echo "am__make_running_with_option: internal error: invalid" \ 23 | "target option '$${target_option-}' specified" >&2; \ 24 | exit 1;; \ 25 | esac; \ 26 | has_opt=no; \ 27 | sane_makeflags=$$MAKEFLAGS; \ 28 | if $(am__is_gnu_make); then \ 29 | sane_makeflags=$$MFLAGS; \ 30 | else \ 31 | case $$MAKEFLAGS in \ 32 | *\\[\ \ ]*) \ 33 | bs=\\; \ 34 | sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ 35 | | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ 36 | esac; \ 37 | fi; \ 38 | skip_next=no; \ 39 | strip_trailopt () \ 40 | { \ 41 | flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ 42 | }; \ 43 | for flg in $$sane_makeflags; do \ 44 | test $$skip_next = yes && { skip_next=no; continue; }; \ 45 | case $$flg in \ 46 | *=*|--*) continue;; \ 47 | -*I) strip_trailopt 'I'; skip_next=yes;; \ 48 | -*I?*) strip_trailopt 'I';; \ 49 | -*O) strip_trailopt 'O'; skip_next=yes;; \ 50 | -*O?*) strip_trailopt 'O';; \ 51 | -*l) strip_trailopt 'l'; skip_next=yes;; \ 52 | -*l?*) strip_trailopt 'l';; \ 53 | -[dEDm]) skip_next=yes;; \ 54 | -[JT]) skip_next=yes;; \ 55 | esac; \ 56 | case $$flg in \ 57 | *$$target_option*) has_opt=yes; break;; \ 58 | esac; \ 59 | done; \ 60 | test $$has_opt = yes 61 | am__make_dryrun = (target_option=n; $(am__make_running_with_option)) 62 | am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) 63 | pkgdatadir = $(datadir)/@PACKAGE@ 64 | pkgincludedir = $(includedir)/@PACKAGE@ 65 | pkglibdir = $(libdir)/@PACKAGE@ 66 | pkglibexecdir = $(libexecdir)/@PACKAGE@ 67 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd 68 | install_sh_DATA = $(install_sh) -c -m 644 69 | install_sh_PROGRAM = $(install_sh) -c 70 | install_sh_SCRIPT = $(install_sh) -c 71 | INSTALL_HEADER = $(INSTALL_DATA) 72 | transform = $(program_transform_name) 73 | NORMAL_INSTALL = : 74 | PRE_INSTALL = : 75 | POST_INSTALL = : 76 | NORMAL_UNINSTALL = : 77 | PRE_UNINSTALL = : 78 | POST_UNINSTALL = : 79 | subdir = src/helpers/fst 80 | DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ 81 | $(top_srcdir)/depcomp 82 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 83 | am__aclocal_m4_deps = $(top_srcdir)/configure.ac 84 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ 85 | $(ACLOCAL_M4) 86 | mkinstalldirs = $(install_sh) -d 87 | CONFIG_HEADER = $(top_builddir)/config.h 88 | CONFIG_CLEAN_FILES = 89 | CONFIG_CLEAN_VPATH_FILES = 90 | LIBRARIES = $(noinst_LIBRARIES) 91 | AR = ar 92 | ARFLAGS = cru 93 | AM_V_AR = $(am__v_AR_@AM_V@) 94 | am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) 95 | am__v_AR_0 = @echo " AR " $@; 96 | am__v_AR_1 = 97 | libfst_a_AR = $(AR) $(ARFLAGS) 98 | libfst_a_LIBADD = 99 | am_libfst_a_OBJECTS = fastlz.$(OBJEXT) lz4.$(OBJEXT) fstapi.$(OBJEXT) 100 | libfst_a_OBJECTS = $(am_libfst_a_OBJECTS) 101 | AM_V_P = $(am__v_P_@AM_V@) 102 | am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) 103 | am__v_P_0 = false 104 | am__v_P_1 = : 105 | AM_V_GEN = $(am__v_GEN_@AM_V@) 106 | am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) 107 | am__v_GEN_0 = @echo " GEN " $@; 108 | am__v_GEN_1 = 109 | AM_V_at = $(am__v_at_@AM_V@) 110 | am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) 111 | am__v_at_0 = @ 112 | am__v_at_1 = 113 | DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) 114 | depcomp = $(SHELL) $(top_srcdir)/depcomp 115 | am__depfiles_maybe = depfiles 116 | am__mv = mv -f 117 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ 118 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) 119 | AM_V_CC = $(am__v_CC_@AM_V@) 120 | am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) 121 | am__v_CC_0 = @echo " CC " $@; 122 | am__v_CC_1 = 123 | CCLD = $(CC) 124 | LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ 125 | AM_V_CCLD = $(am__v_CCLD_@AM_V@) 126 | am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) 127 | am__v_CCLD_0 = @echo " CCLD " $@; 128 | am__v_CCLD_1 = 129 | SOURCES = $(libfst_a_SOURCES) 130 | DIST_SOURCES = $(libfst_a_SOURCES) 131 | am__can_run_installinfo = \ 132 | case $$AM_UPDATE_INFO_DIR in \ 133 | n|no|NO) false;; \ 134 | *) (install-info --version) >/dev/null 2>&1;; \ 135 | esac 136 | am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) 137 | # Read a list of newline-separated strings from the standard input, 138 | # and print each of them once, without duplicates. Input order is 139 | # *not* preserved. 140 | am__uniquify_input = $(AWK) '\ 141 | BEGIN { nonempty = 0; } \ 142 | { items[$$0] = 1; nonempty = 1; } \ 143 | END { if (nonempty) { for (i in items) print i; }; } \ 144 | ' 145 | # Make sure the list of sources is unique. This is necessary because, 146 | # e.g., the same source file might be shared among _SOURCES variables 147 | # for different programs/libraries. 148 | am__define_uniq_tagged_files = \ 149 | list='$(am__tagged_files)'; \ 150 | unique=`for i in $$list; do \ 151 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 152 | done | $(am__uniquify_input)` 153 | ETAGS = etags 154 | CTAGS = ctags 155 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 156 | ACLOCAL = @ACLOCAL@ 157 | AET2_CFLAGS = @AET2_CFLAGS@ 158 | AET2_LDADD = @AET2_LDADD@ 159 | ALLOCA = @ALLOCA@ 160 | AMTAR = @AMTAR@ 161 | AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ 162 | AUTOCONF = @AUTOCONF@ 163 | AUTOHEADER = @AUTOHEADER@ 164 | AUTOMAKE = @AUTOMAKE@ 165 | AWK = @AWK@ 166 | CC = @CC@ 167 | CCDEPMODE = @CCDEPMODE@ 168 | CFLAGS = @CFLAGS@ 169 | COCOA_GTK_CFLAGS = @COCOA_GTK_CFLAGS@ 170 | COCOA_GTK_LDADD = @COCOA_GTK_LDADD@ 171 | COCOA_GTK_LDFLAGS = @COCOA_GTK_LDFLAGS@ 172 | CPP = @CPP@ 173 | CPPFLAGS = @CPPFLAGS@ 174 | CXX = @CXX@ 175 | CXXDEPMODE = @CXXDEPMODE@ 176 | CXXFLAGS = @CXXFLAGS@ 177 | CYGPATH_W = @CYGPATH_W@ 178 | DEFS = @DEFS@ 179 | DEPDIR = @DEPDIR@ 180 | ECHO_C = @ECHO_C@ 181 | ECHO_N = @ECHO_N@ 182 | ECHO_T = @ECHO_T@ 183 | EGREP = @EGREP@ 184 | EXEEXT = @EXEEXT@ 185 | EXTDEBUG = @EXTDEBUG@ 186 | EXTDEBUG2 = @EXTDEBUG2@ 187 | EXTDEBUG3 = @EXTDEBUG3@ 188 | EXTDEBUG4 = @EXTDEBUG4@ 189 | EXTLOAD_CFLAGS = @EXTLOAD_CFLAGS@ 190 | FASTTREE_CFLAGS = @FASTTREE_CFLAGS@ 191 | FSDB_CFLAGS = @FSDB_CFLAGS@ 192 | FSDB_LDADD = @FSDB_LDADD@ 193 | GCONF_CFLAGS = @GCONF_CFLAGS@ 194 | GCONF_LIBS = @GCONF_LIBS@ 195 | GEDITTEST = @GEDITTEST@ 196 | GEDIT_CFLAGS = @GEDIT_CFLAGS@ 197 | GIO_CFLAGS = @GIO_CFLAGS@ 198 | GIO_LIBS = @GIO_LIBS@ 199 | GLIB_COMPILE_SCHEMAS = @GLIB_COMPILE_SCHEMAS@ 200 | GPERF = @GPERF@ 201 | GREP = @GREP@ 202 | GSETTINGS_CFLAGS = @GSETTINGS_CFLAGS@ 203 | GSETTINGS_DISABLE_SCHEMAS_COMPILE = @GSETTINGS_DISABLE_SCHEMAS_COMPILE@ 204 | GTK_CFLAGS = @GTK_CFLAGS@ 205 | GTK_CONFIG = @GTK_CONFIG@ 206 | GTK_LIBS = @GTK_LIBS@ 207 | GTK_MAC_CFLAGS = @GTK_MAC_CFLAGS@ 208 | GTK_MAC_LIBS = @GTK_MAC_LIBS@ 209 | GTK_UNIX_PRINT_CFLAGS = @GTK_UNIX_PRINT_CFLAGS@ 210 | GTK_UNIX_PRINT_LIBS = @GTK_UNIX_PRINT_LIBS@ 211 | INSTALL = @INSTALL@ 212 | INSTALL_DATA = @INSTALL_DATA@ 213 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 214 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ 215 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ 216 | LDFLAGS = @LDFLAGS@ 217 | LEX = @LEX@ 218 | LEXLIB = @LEXLIB@ 219 | LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ 220 | LIBBZ2_CFLAGS = @LIBBZ2_CFLAGS@ 221 | LIBBZ2_DIR = @LIBBZ2_DIR@ 222 | LIBBZ2_LDADD = @LIBBZ2_LDADD@ 223 | LIBJUDY_CFLAGS = @LIBJUDY_CFLAGS@ 224 | LIBJUDY_LDADD = @LIBJUDY_LDADD@ 225 | LIBOBJS = @LIBOBJS@ 226 | LIBS = @LIBS@ 227 | LIBXZ_CFLAGS = @LIBXZ_CFLAGS@ 228 | LIBXZ_LDADD = @LIBXZ_LDADD@ 229 | LIBZ_CFLAGS = @LIBZ_CFLAGS@ 230 | LIBZ_DIR = @LIBZ_DIR@ 231 | LIBZ_LDADD = @LIBZ_LDADD@ 232 | LTLIBOBJS = @LTLIBOBJS@ 233 | MAINT = @MAINT@ 234 | MAKEINFO = @MAKEINFO@ 235 | MINGW_LDADD = @MINGW_LDADD@ 236 | MKDIR_P = @MKDIR_P@ 237 | OBJEXT = @OBJEXT@ 238 | PACKAGE = @PACKAGE@ 239 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ 240 | PACKAGE_NAME = @PACKAGE_NAME@ 241 | PACKAGE_STRING = @PACKAGE_STRING@ 242 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ 243 | PACKAGE_URL = @PACKAGE_URL@ 244 | PACKAGE_VERSION = @PACKAGE_VERSION@ 245 | PATH_SEPARATOR = @PATH_SEPARATOR@ 246 | PKG_CONFIG = @PKG_CONFIG@ 247 | PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ 248 | PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ 249 | POW_LIB = @POW_LIB@ 250 | RANLIB = @RANLIB@ 251 | RPC_CFLAGS = @RPC_CFLAGS@ 252 | RPC_LDADD = @RPC_LDADD@ 253 | SET_MAKE = @SET_MAKE@ 254 | SHELL = @SHELL@ 255 | STRIP = @STRIP@ 256 | STRUCT_PACK = @STRUCT_PACK@ 257 | TCL_DEFADD = @TCL_DEFADD@ 258 | TCL_INCLUDE_SPEC = @TCL_INCLUDE_SPEC@ 259 | TCL_LDADD = @TCL_LDADD@ 260 | TCL_LIB_SPEC = @TCL_LIB_SPEC@ 261 | TCL_MAJOR_VERSION = @TCL_MAJOR_VERSION@ 262 | TCL_MINOR_VERSION = @TCL_MINOR_VERSION@ 263 | TIRPC_CFLAGS = @TIRPC_CFLAGS@ 264 | TIRPC_LIBS = @TIRPC_LIBS@ 265 | TK_INCLUDE_SPEC = @TK_INCLUDE_SPEC@ 266 | TK_LDADD = @TK_LDADD@ 267 | TK_LIB_SPEC = @TK_LIB_SPEC@ 268 | UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ 269 | UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ 270 | VERSION = @VERSION@ 271 | XDGDATADIR = @XDGDATADIR@ 272 | abs_builddir = @abs_builddir@ 273 | abs_srcdir = @abs_srcdir@ 274 | abs_top_builddir = @abs_top_builddir@ 275 | abs_top_srcdir = @abs_top_srcdir@ 276 | ac_ct_CC = @ac_ct_CC@ 277 | ac_ct_CXX = @ac_ct_CXX@ 278 | am__include = @am__include@ 279 | am__leading_dot = @am__leading_dot@ 280 | am__quote = @am__quote@ 281 | am__tar = @am__tar@ 282 | am__untar = @am__untar@ 283 | bindir = @bindir@ 284 | build_alias = @build_alias@ 285 | builddir = @builddir@ 286 | datadir = @datadir@ 287 | datarootdir = @datarootdir@ 288 | docdir = @docdir@ 289 | dvidir = @dvidir@ 290 | exec_prefix = @exec_prefix@ 291 | gsettingsschemadir = @gsettingsschemadir@ 292 | host_alias = @host_alias@ 293 | htmldir = @htmldir@ 294 | includedir = @includedir@ 295 | infodir = @infodir@ 296 | install_sh = @install_sh@ 297 | libdir = @libdir@ 298 | libexecdir = @libexecdir@ 299 | localedir = @localedir@ 300 | localstatedir = @localstatedir@ 301 | mandir = @mandir@ 302 | mkdir_p = @mkdir_p@ 303 | oldincludedir = @oldincludedir@ 304 | pdfdir = @pdfdir@ 305 | prefix = @prefix@ 306 | program_transform_name = @program_transform_name@ 307 | psdir = @psdir@ 308 | sbindir = @sbindir@ 309 | sharedstatedir = @sharedstatedir@ 310 | srcdir = @srcdir@ 311 | sysconfdir = @sysconfdir@ 312 | target_alias = @target_alias@ 313 | top_build_prefix = @top_build_prefix@ 314 | top_builddir = @top_builddir@ 315 | top_srcdir = @top_srcdir@ 316 | AM_CFLAGS = $(LIBZ_CFLAGS) $(LIBJUDY_CFLAGS) 317 | noinst_LIBRARIES = libfst.a 318 | libfst_a_SOURCES = fastlz.c fastlz.h lz4.c lz4.h fstapi.c fstapi.h fst_win_unistd.h 319 | EXTRA_DIST = block_format.txt CMakeLists.txt 320 | all: all-am 321 | 322 | .SUFFIXES: 323 | .SUFFIXES: .c .o .obj 324 | $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) 325 | @for dep in $?; do \ 326 | case '$(am__configure_deps)' in \ 327 | *$$dep*) \ 328 | ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ 329 | && { if test -f $@; then exit 0; else break; fi; }; \ 330 | exit 1;; \ 331 | esac; \ 332 | done; \ 333 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/helpers/fst/Makefile'; \ 334 | $(am__cd) $(top_srcdir) && \ 335 | $(AUTOMAKE) --foreign src/helpers/fst/Makefile 336 | .PRECIOUS: Makefile 337 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 338 | @case '$?' in \ 339 | *config.status*) \ 340 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ 341 | *) \ 342 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ 343 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ 344 | esac; 345 | 346 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) 347 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 348 | 349 | $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 350 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 351 | $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) 352 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 353 | $(am__aclocal_m4_deps): 354 | 355 | clean-noinstLIBRARIES: 356 | -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) 357 | 358 | libfst.a: $(libfst_a_OBJECTS) $(libfst_a_DEPENDENCIES) $(EXTRA_libfst_a_DEPENDENCIES) 359 | $(AM_V_at)-rm -f libfst.a 360 | $(AM_V_AR)$(libfst_a_AR) libfst.a $(libfst_a_OBJECTS) $(libfst_a_LIBADD) 361 | $(AM_V_at)$(RANLIB) libfst.a 362 | 363 | mostlyclean-compile: 364 | -rm -f *.$(OBJEXT) 365 | 366 | distclean-compile: 367 | -rm -f *.tab.c 368 | 369 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fastlz.Po@am__quote@ 370 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fstapi.Po@am__quote@ 371 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lz4.Po@am__quote@ 372 | 373 | .c.o: 374 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< 375 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po 376 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ 377 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 378 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< 379 | 380 | .c.obj: 381 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` 382 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po 383 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ 384 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 385 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` 386 | 387 | ID: $(am__tagged_files) 388 | $(am__define_uniq_tagged_files); mkid -fID $$unique 389 | tags: tags-am 390 | TAGS: tags 391 | 392 | tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) 393 | set x; \ 394 | here=`pwd`; \ 395 | $(am__define_uniq_tagged_files); \ 396 | shift; \ 397 | if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ 398 | test -n "$$unique" || unique=$$empty_fix; \ 399 | if test $$# -gt 0; then \ 400 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ 401 | "$$@" $$unique; \ 402 | else \ 403 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ 404 | $$unique; \ 405 | fi; \ 406 | fi 407 | ctags: ctags-am 408 | 409 | CTAGS: ctags 410 | ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) 411 | $(am__define_uniq_tagged_files); \ 412 | test -z "$(CTAGS_ARGS)$$unique" \ 413 | || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ 414 | $$unique 415 | 416 | GTAGS: 417 | here=`$(am__cd) $(top_builddir) && pwd` \ 418 | && $(am__cd) $(top_srcdir) \ 419 | && gtags -i $(GTAGS_ARGS) "$$here" 420 | cscopelist: cscopelist-am 421 | 422 | cscopelist-am: $(am__tagged_files) 423 | list='$(am__tagged_files)'; \ 424 | case "$(srcdir)" in \ 425 | [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ 426 | *) sdir=$(subdir)/$(srcdir) ;; \ 427 | esac; \ 428 | for i in $$list; do \ 429 | if test -f "$$i"; then \ 430 | echo "$(subdir)/$$i"; \ 431 | else \ 432 | echo "$$sdir/$$i"; \ 433 | fi; \ 434 | done >> $(top_builddir)/cscope.files 435 | 436 | distclean-tags: 437 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags 438 | 439 | distdir: $(DISTFILES) 440 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 441 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 442 | list='$(DISTFILES)'; \ 443 | dist_files=`for file in $$list; do echo $$file; done | \ 444 | sed -e "s|^$$srcdirstrip/||;t" \ 445 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ 446 | case $$dist_files in \ 447 | */*) $(MKDIR_P) `echo "$$dist_files" | \ 448 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ 449 | sort -u` ;; \ 450 | esac; \ 451 | for file in $$dist_files; do \ 452 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ 453 | if test -d $$d/$$file; then \ 454 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ 455 | if test -d "$(distdir)/$$file"; then \ 456 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 457 | fi; \ 458 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ 459 | cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ 460 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 461 | fi; \ 462 | cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ 463 | else \ 464 | test -f "$(distdir)/$$file" \ 465 | || cp -p $$d/$$file "$(distdir)/$$file" \ 466 | || exit 1; \ 467 | fi; \ 468 | done 469 | check-am: all-am 470 | check: check-am 471 | all-am: Makefile $(LIBRARIES) 472 | installdirs: 473 | install: install-am 474 | install-exec: install-exec-am 475 | install-data: install-data-am 476 | uninstall: uninstall-am 477 | 478 | install-am: all-am 479 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am 480 | 481 | installcheck: installcheck-am 482 | install-strip: 483 | if test -z '$(STRIP)'; then \ 484 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 485 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 486 | install; \ 487 | else \ 488 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 489 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 490 | "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ 491 | fi 492 | mostlyclean-generic: 493 | 494 | clean-generic: 495 | 496 | distclean-generic: 497 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) 498 | -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) 499 | 500 | maintainer-clean-generic: 501 | @echo "This command is intended for maintainers to use" 502 | @echo "it deletes files that may require special tools to rebuild." 503 | clean: clean-am 504 | 505 | clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am 506 | 507 | distclean: distclean-am 508 | -rm -rf ./$(DEPDIR) 509 | -rm -f Makefile 510 | distclean-am: clean-am distclean-compile distclean-generic \ 511 | distclean-tags 512 | 513 | dvi: dvi-am 514 | 515 | dvi-am: 516 | 517 | html: html-am 518 | 519 | html-am: 520 | 521 | info: info-am 522 | 523 | info-am: 524 | 525 | install-data-am: 526 | 527 | install-dvi: install-dvi-am 528 | 529 | install-dvi-am: 530 | 531 | install-exec-am: 532 | 533 | install-html: install-html-am 534 | 535 | install-html-am: 536 | 537 | install-info: install-info-am 538 | 539 | install-info-am: 540 | 541 | install-man: 542 | 543 | install-pdf: install-pdf-am 544 | 545 | install-pdf-am: 546 | 547 | install-ps: install-ps-am 548 | 549 | install-ps-am: 550 | 551 | installcheck-am: 552 | 553 | maintainer-clean: maintainer-clean-am 554 | -rm -rf ./$(DEPDIR) 555 | -rm -f Makefile 556 | maintainer-clean-am: distclean-am maintainer-clean-generic 557 | 558 | mostlyclean: mostlyclean-am 559 | 560 | mostlyclean-am: mostlyclean-compile mostlyclean-generic 561 | 562 | pdf: pdf-am 563 | 564 | pdf-am: 565 | 566 | ps: ps-am 567 | 568 | ps-am: 569 | 570 | uninstall-am: 571 | 572 | .MAKE: install-am install-strip 573 | 574 | .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ 575 | clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \ 576 | distclean-compile distclean-generic distclean-tags distdir dvi \ 577 | dvi-am html html-am info info-am install install-am \ 578 | install-data install-data-am install-dvi install-dvi-am \ 579 | install-exec install-exec-am install-html install-html-am \ 580 | install-info install-info-am install-man install-pdf \ 581 | install-pdf-am install-ps install-ps-am install-strip \ 582 | installcheck installcheck-am installdirs maintainer-clean \ 583 | maintainer-clean-generic mostlyclean mostlyclean-compile \ 584 | mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ 585 | uninstall-am 586 | 587 | 588 | # Tell versions [3.59,3.63) of GNU make to not export all variables. 589 | # Otherwise a system limit (for SysV at least) may be exceeded. 590 | .NOEXPORT: 591 | -------------------------------------------------------------------------------- /src/fst/README.md: -------------------------------------------------------------------------------- 1 | 2 | Code copied from GTKWave `./gtkwave3/src/helpers/fst` directory. 3 | (C) Tony Bybell 4 | 5 | -------------------------------------------------------------------------------- /src/fst/block_format.txt: -------------------------------------------------------------------------------- 1 | See fstapi.h for the values for the FST_BL_XXX enums. 2 | 3 | =========================================================================== 4 | 5 | compressed wrapper (typically over whole file) 6 | 7 | uint8_t FST_BL_ZWRAPPER 8 | uint64_t section length 9 | uint64_t length of uncompressed data 10 | [zlib compressed data] 11 | 12 | =========================================================================== 13 | 14 | header block 15 | 16 | uint8_t FST_BL_HDR 17 | uint64_t section length 18 | uint64_t start time 19 | uint64_t end time 20 | double endian test for "e" 21 | uint64_t memory used by writer 22 | uint64_t scope creation count 23 | uint64_t var creation count 24 | uint64_t max var idcode 25 | uint64_t vc section count 26 | int8_t timescale exponent 27 | [128 bytes] version 28 | [128 bytes] date 29 | 30 | =========================================================================== 31 | 32 | geometry block 33 | 34 | uint8_t FST_BL_GEOM 35 | uint64_t section length 36 | uint64_t length of uncompressed geometry data 37 | uint64_t maxhandle 38 | [compressed data] 39 | 40 | (length of compressed data is section length - 24) 41 | 42 | =========================================================================== 43 | 44 | hierarchy block 45 | 46 | uint8_t FST_BL_HIER 47 | uint64_t section length 48 | uint64_t length of uncompressed hier data 49 | [zlib compressed data] 50 | 51 | or 52 | 53 | uint8_t FST_BL_HIER_LZ4 54 | uint64_t section length 55 | uint64_t length of uncompressed hier data 56 | [lz4 compressed data] 57 | 58 | uint8_t FST_BL_HIER_LZ4DUO 59 | uint64_t section length 60 | uint64_t length of uncompressed hier data 61 | varint length of hier data compressed once with lz4 62 | [lz4 double compressed data] 63 | 64 | 65 | =========================================================================== 66 | 67 | dumpon/off block 68 | 69 | uint8_t FST_BL_BLACKOUT 70 | uint64_t section length 71 | varint num blackouts (section below is repeated this # times) 72 | [ 73 | uint8_t on/off (nonzero = on) 74 | varint delta time 75 | ] 76 | 77 | =========================================================================== 78 | 79 | 1..n value change blocks: 80 | 81 | // header 82 | 83 | uint8_t FST_BL_VCDATA (or FST_BL_VCDATA_DYN_ALIAS) 84 | uint64_t section length 85 | uint64_t begin time of section 86 | uint64_t end time of section 87 | uint64_t amount of buffer memory required in reader for full vc traversal 88 | varint maxvalpos (length of uncompressed data) 89 | varint length of compressed data 90 | varint maxhandle associated with this checkpoint data 91 | [compressed data] 92 | 93 | --- 94 | 95 | // value changes 96 | 97 | varint maxhandle associated with the value change data 98 | uint8_t pack type ('F' is fastlz, '4' is lz4, 99 | others ['Z'/'!'] are zlib) 100 | 101 | varint chain 0 compressed data length (0 = uncompressed) 102 | [compressed data] 103 | ... 104 | varint chain n compressed data length (0 = uncompressed) 105 | [compressed data] 106 | 107 | --- 108 | 109 | // index: chain pointer table (from 0..maxhandle-1) 110 | 111 | varint if &1 == 1, this is <<1 literal delta 112 | if &1 == 0, this is <<1 RLE count of zeros 113 | if == 0, next varint is handle of prev chain to use, 114 | bit only if FST_BL_VCDATA_DYN_ALIAS or 115 | later VCDATA format 116 | 117 | --- 118 | 119 | uint64_t index length (subtract from here to get index position) 120 | 121 | --- 122 | 123 | [compressed data for time section] 124 | uint64_t uncompressed data length in bytes 125 | uint64_t compressed data length in bytes 126 | uint64_t number of time items 127 | 128 | // end of section 129 | 130 | =========================================================================== 131 | -------------------------------------------------------------------------------- /src/fst/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | 5 | #endif 6 | 7 | -------------------------------------------------------------------------------- /src/fst/fastlz.c: -------------------------------------------------------------------------------- 1 | /* 2 | FastLZ - lightning-fast lossless compression library 3 | 4 | Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) 5 | Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) 6 | Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | SPDX-License-Identifier: MIT 27 | */ 28 | 29 | #include "fastlz.h" 30 | 31 | #if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) 32 | 33 | /* 34 | * Always check for bound when decompressing. 35 | * Generally it is best to leave it defined. 36 | */ 37 | #define FASTLZ_SAFE 38 | 39 | 40 | /* 41 | * Give hints to the compiler for branch prediction optimization. 42 | */ 43 | #if defined(__GNUC__) && (__GNUC__ > 2) 44 | #define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) 45 | #define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) 46 | #else 47 | #define FASTLZ_EXPECT_CONDITIONAL(c) (c) 48 | #define FASTLZ_UNEXPECT_CONDITIONAL(c) (c) 49 | #endif 50 | 51 | /* 52 | * Use inlined functions for supported systems. 53 | */ 54 | #if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C) 55 | #define FASTLZ_INLINE inline 56 | #elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) 57 | #define FASTLZ_INLINE __inline 58 | #else 59 | #define FASTLZ_INLINE 60 | #endif 61 | 62 | /* 63 | * Prevent accessing more than 8-bit at once, except on x86 architectures. 64 | */ 65 | #if !defined(FASTLZ_STRICT_ALIGN) 66 | #define FASTLZ_STRICT_ALIGN 67 | #if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */ 68 | #undef FASTLZ_STRICT_ALIGN 69 | #elif defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__amd64) /* GNU C */ 70 | #undef FASTLZ_STRICT_ALIGN 71 | #elif defined(_M_IX86) /* Intel, MSVC */ 72 | #undef FASTLZ_STRICT_ALIGN 73 | #elif defined(__386) 74 | #undef FASTLZ_STRICT_ALIGN 75 | #elif defined(_X86_) /* MinGW */ 76 | #undef FASTLZ_STRICT_ALIGN 77 | #elif defined(__I86__) /* Digital Mars */ 78 | #undef FASTLZ_STRICT_ALIGN 79 | #endif 80 | #endif 81 | 82 | /* prototypes */ 83 | int fastlz_compress(const void* input, int length, void* output); 84 | int fastlz_compress_level(int level, const void* input, int length, void* output); 85 | int fastlz_decompress(const void* input, int length, void* output, int maxout); 86 | 87 | #define MAX_COPY 32 88 | #define MAX_LEN 264 /* 256 + 8 */ 89 | #define MAX_DISTANCE 8192 90 | 91 | #if !defined(FASTLZ_STRICT_ALIGN) 92 | #define FASTLZ_READU16(p) *((const flzuint16*)(p)) 93 | #else 94 | #define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8) 95 | #endif 96 | 97 | #define HASH_LOG 13 98 | #define HASH_SIZE (1<< HASH_LOG) 99 | #define HASH_MASK (HASH_SIZE-1) 100 | #define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; } 101 | 102 | #undef FASTLZ_LEVEL 103 | #define FASTLZ_LEVEL 1 104 | 105 | #undef FASTLZ_COMPRESSOR 106 | #undef FASTLZ_DECOMPRESSOR 107 | #define FASTLZ_COMPRESSOR fastlz1_compress 108 | #define FASTLZ_DECOMPRESSOR fastlz1_decompress 109 | static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); 110 | static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); 111 | #include "fastlz.c" 112 | 113 | #undef FASTLZ_LEVEL 114 | #define FASTLZ_LEVEL 2 115 | 116 | #undef MAX_DISTANCE 117 | #define MAX_DISTANCE 8191 118 | #define MAX_FARDISTANCE (65535+MAX_DISTANCE-1) 119 | 120 | #undef FASTLZ_COMPRESSOR 121 | #undef FASTLZ_DECOMPRESSOR 122 | #define FASTLZ_COMPRESSOR fastlz2_compress 123 | #define FASTLZ_DECOMPRESSOR fastlz2_decompress 124 | static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); 125 | static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); 126 | #include "fastlz.c" 127 | 128 | int fastlz_compress(const void* input, int length, void* output) 129 | { 130 | /* for short block, choose fastlz1 */ 131 | if(length < 65536) 132 | return fastlz1_compress(input, length, output); 133 | 134 | /* else... */ 135 | return fastlz2_compress(input, length, output); 136 | } 137 | 138 | int fastlz_decompress(const void* input, int length, void* output, int maxout) 139 | { 140 | /* magic identifier for compression level */ 141 | int level = ((*(const flzuint8*)input) >> 5) + 1; 142 | 143 | if(level == 1) 144 | return fastlz1_decompress(input, length, output, maxout); 145 | if(level == 2) 146 | return fastlz2_decompress(input, length, output, maxout); 147 | 148 | /* unknown level, trigger error */ 149 | return 0; 150 | } 151 | 152 | int fastlz_compress_level(int level, const void* input, int length, void* output) 153 | { 154 | if(level == 1) 155 | return fastlz1_compress(input, length, output); 156 | if(level == 2) 157 | return fastlz2_compress(input, length, output); 158 | 159 | return 0; 160 | } 161 | 162 | #else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ 163 | 164 | static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output) 165 | { 166 | const flzuint8* ip = (const flzuint8*) input; 167 | const flzuint8* ip_bound = ip + length - 2; 168 | const flzuint8* ip_limit = ip + length - 12; 169 | flzuint8* op = (flzuint8*) output; 170 | 171 | const flzuint8* htab[HASH_SIZE]; 172 | const flzuint8** hslot; 173 | flzuint32 hval; 174 | 175 | flzuint32 copy; 176 | 177 | /* sanity check */ 178 | if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) 179 | { 180 | if(length) 181 | { 182 | /* create literal copy only */ 183 | *op++ = length-1; 184 | ip_bound++; 185 | while(ip <= ip_bound) 186 | *op++ = *ip++; 187 | return length+1; 188 | } 189 | else 190 | return 0; 191 | } 192 | 193 | /* initializes hash table */ 194 | for (hslot = htab; hslot < htab + HASH_SIZE; hslot++) 195 | *hslot = ip; 196 | 197 | /* we start with literal copy */ 198 | copy = 2; 199 | *op++ = MAX_COPY-1; 200 | *op++ = *ip++; 201 | *op++ = *ip++; 202 | 203 | /* main loop */ 204 | while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) 205 | { 206 | const flzuint8* ref; 207 | flzuint32 distance; 208 | 209 | /* minimum match length */ 210 | flzuint32 len = 3; 211 | 212 | /* comparison starting-point */ 213 | const flzuint8* anchor = ip; 214 | 215 | /* check for a run */ 216 | #if FASTLZ_LEVEL==2 217 | if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) 218 | { 219 | distance = 1; 220 | /* ip += 3; */ /* scan-build, never used */ 221 | ref = anchor - 1 + 3; 222 | goto match; 223 | } 224 | #endif 225 | 226 | /* find potential match */ 227 | HASH_FUNCTION(hval,ip); 228 | hslot = htab + hval; 229 | ref = htab[hval]; 230 | 231 | /* calculate distance to the match */ 232 | distance = anchor - ref; 233 | 234 | /* update hash table */ 235 | *hslot = anchor; 236 | 237 | /* is this a match? check the first 3 bytes */ 238 | if(distance==0 || 239 | #if FASTLZ_LEVEL==1 240 | (distance >= MAX_DISTANCE) || 241 | #else 242 | (distance >= MAX_FARDISTANCE) || 243 | #endif 244 | *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++) 245 | goto literal; 246 | 247 | #if FASTLZ_LEVEL==2 248 | /* far, needs at least 5-byte match */ 249 | if(distance >= MAX_DISTANCE) 250 | { 251 | if(*ip++ != *ref++ || *ip++!= *ref++) 252 | goto literal; 253 | len += 2; 254 | } 255 | 256 | match: 257 | #endif 258 | 259 | /* last matched byte */ 260 | ip = anchor + len; 261 | 262 | /* distance is biased */ 263 | distance--; 264 | 265 | if(!distance) 266 | { 267 | /* zero distance means a run */ 268 | flzuint8 x = ip[-1]; 269 | while(ip < ip_bound) 270 | if(*ref++ != x) break; else ip++; 271 | } 272 | else 273 | for(;;) 274 | { 275 | /* safe because the outer check against ip limit */ 276 | if(*ref++ != *ip++) break; 277 | if(*ref++ != *ip++) break; 278 | if(*ref++ != *ip++) break; 279 | if(*ref++ != *ip++) break; 280 | if(*ref++ != *ip++) break; 281 | if(*ref++ != *ip++) break; 282 | if(*ref++ != *ip++) break; 283 | if(*ref++ != *ip++) break; 284 | while(ip < ip_bound) 285 | if(*ref++ != *ip++) break; 286 | break; 287 | } 288 | 289 | /* if we have copied something, adjust the copy count */ 290 | if(copy) 291 | /* copy is biased, '0' means 1 byte copy */ 292 | *(op-copy-1) = copy-1; 293 | else 294 | /* back, to overwrite the copy count */ 295 | op--; 296 | 297 | /* reset literal counter */ 298 | copy = 0; 299 | 300 | /* length is biased, '1' means a match of 3 bytes */ 301 | ip -= 3; 302 | len = ip - anchor; 303 | 304 | /* encode the match */ 305 | #if FASTLZ_LEVEL==2 306 | if(distance < MAX_DISTANCE) 307 | { 308 | if(len < 7) 309 | { 310 | *op++ = (len << 5) + (distance >> 8); 311 | *op++ = (distance & 255); 312 | } 313 | else 314 | { 315 | *op++ = (7 << 5) + (distance >> 8); 316 | for(len-=7; len >= 255; len-= 255) 317 | *op++ = 255; 318 | *op++ = len; 319 | *op++ = (distance & 255); 320 | } 321 | } 322 | else 323 | { 324 | /* far away, but not yet in the another galaxy... */ 325 | if(len < 7) 326 | { 327 | distance -= MAX_DISTANCE; 328 | *op++ = (len << 5) + 31; 329 | *op++ = 255; 330 | *op++ = distance >> 8; 331 | *op++ = distance & 255; 332 | } 333 | else 334 | { 335 | distance -= MAX_DISTANCE; 336 | *op++ = (7 << 5) + 31; 337 | for(len-=7; len >= 255; len-= 255) 338 | *op++ = 255; 339 | *op++ = len; 340 | *op++ = 255; 341 | *op++ = distance >> 8; 342 | *op++ = distance & 255; 343 | } 344 | } 345 | #else 346 | 347 | if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2)) 348 | while(len > MAX_LEN-2) 349 | { 350 | *op++ = (7 << 5) + (distance >> 8); 351 | *op++ = MAX_LEN - 2 - 7 -2; 352 | *op++ = (distance & 255); 353 | len -= MAX_LEN-2; 354 | } 355 | 356 | if(len < 7) 357 | { 358 | *op++ = (len << 5) + (distance >> 8); 359 | *op++ = (distance & 255); 360 | } 361 | else 362 | { 363 | *op++ = (7 << 5) + (distance >> 8); 364 | *op++ = len - 7; 365 | *op++ = (distance & 255); 366 | } 367 | #endif 368 | 369 | /* update the hash at match boundary */ 370 | HASH_FUNCTION(hval,ip); 371 | htab[hval] = ip++; 372 | HASH_FUNCTION(hval,ip); 373 | htab[hval] = ip++; 374 | 375 | /* assuming literal copy */ 376 | *op++ = MAX_COPY-1; 377 | 378 | continue; 379 | 380 | literal: 381 | *op++ = *anchor++; 382 | ip = anchor; 383 | copy++; 384 | if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) 385 | { 386 | copy = 0; 387 | *op++ = MAX_COPY-1; 388 | } 389 | } 390 | 391 | /* left-over as literal copy */ 392 | ip_bound++; 393 | while(ip <= ip_bound) 394 | { 395 | *op++ = *ip++; 396 | copy++; 397 | if(copy == MAX_COPY) 398 | { 399 | copy = 0; 400 | *op++ = MAX_COPY-1; 401 | } 402 | } 403 | 404 | /* if we have copied something, adjust the copy length */ 405 | if(copy) 406 | *(op-copy-1) = copy-1; 407 | else 408 | op--; 409 | 410 | #if FASTLZ_LEVEL==2 411 | /* marker for fastlz2 */ 412 | *(flzuint8*)output |= (1 << 5); 413 | #endif 414 | 415 | return op - (flzuint8*)output; 416 | } 417 | 418 | static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout) 419 | { 420 | const flzuint8* ip = (const flzuint8*) input; 421 | const flzuint8* ip_limit = ip + length; 422 | flzuint8* op = (flzuint8*) output; 423 | flzuint8* op_limit = op + maxout; 424 | flzuint32 ctrl = (*ip++) & 31; 425 | int loop = 1; 426 | 427 | do 428 | { 429 | const flzuint8* ref = op; 430 | flzuint32 len = ctrl >> 5; 431 | flzuint32 ofs = (ctrl & 31) << 8; 432 | 433 | if(ctrl >= 32) 434 | { 435 | #if FASTLZ_LEVEL==2 436 | flzuint8 code; 437 | #endif 438 | len--; 439 | ref -= ofs; 440 | if (len == 7-1) 441 | #if FASTLZ_LEVEL==1 442 | len += *ip++; 443 | ref -= *ip++; 444 | #else 445 | do 446 | { 447 | code = *ip++; 448 | len += code; 449 | } while (code==255); 450 | code = *ip++; 451 | ref -= code; 452 | 453 | /* match from 16-bit distance */ 454 | if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) 455 | if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) 456 | { 457 | ofs = (*ip++) << 8; 458 | ofs += *ip++; 459 | ref = op - ofs - MAX_DISTANCE; 460 | } 461 | #endif 462 | 463 | #ifdef FASTLZ_SAFE 464 | if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) 465 | return 0; 466 | 467 | if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output)) 468 | return 0; 469 | #endif 470 | 471 | if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) 472 | ctrl = *ip++; 473 | else 474 | loop = 0; 475 | 476 | if(ref == op) 477 | { 478 | /* optimize copy for a run */ 479 | flzuint8 b = ref[-1]; 480 | *op++ = b; 481 | *op++ = b; 482 | *op++ = b; 483 | for(; len; --len) 484 | *op++ = b; 485 | } 486 | else 487 | { 488 | #if !defined(FASTLZ_STRICT_ALIGN) 489 | const flzuint16* p; 490 | flzuint16* q; 491 | #endif 492 | /* copy from reference */ 493 | ref--; 494 | *op++ = *ref++; 495 | *op++ = *ref++; 496 | *op++ = *ref++; 497 | 498 | #if !defined(FASTLZ_STRICT_ALIGN) 499 | /* copy a byte, so that now it's word aligned */ 500 | if(len & 1) 501 | { 502 | *op++ = *ref++; 503 | len--; 504 | } 505 | 506 | /* copy 16-bit at once */ 507 | q = (flzuint16*) op; 508 | op += len; 509 | p = (const flzuint16*) ref; 510 | for(len>>=1; len > 4; len-=4) 511 | { 512 | *q++ = *p++; 513 | *q++ = *p++; 514 | *q++ = *p++; 515 | *q++ = *p++; 516 | } 517 | for(; len; --len) 518 | *q++ = *p++; 519 | #else 520 | for(; len; --len) 521 | *op++ = *ref++; 522 | #endif 523 | } 524 | } 525 | else 526 | { 527 | ctrl++; 528 | #ifdef FASTLZ_SAFE 529 | if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) 530 | return 0; 531 | if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) 532 | return 0; 533 | #endif 534 | 535 | *op++ = *ip++; 536 | for(--ctrl; ctrl; ctrl--) 537 | *op++ = *ip++; 538 | 539 | loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit); 540 | if(loop) 541 | ctrl = *ip++; 542 | } 543 | } 544 | while(FASTLZ_EXPECT_CONDITIONAL(loop)); 545 | 546 | return op - (flzuint8*)output; 547 | } 548 | 549 | #endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ 550 | -------------------------------------------------------------------------------- /src/fst/fastlz.h: -------------------------------------------------------------------------------- 1 | /* 2 | FastLZ - lightning-fast lossless compression library 3 | 4 | Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) 5 | Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) 6 | Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | SPDX-License-Identifier: MIT 27 | */ 28 | 29 | #ifndef FASTLZ_H 30 | #define FASTLZ_H 31 | 32 | #include 33 | 34 | #define flzuint8 uint8_t 35 | #define flzuint16 uint16_t 36 | #define flzuint32 uint32_t 37 | 38 | 39 | #define FASTLZ_VERSION 0x000100 40 | 41 | #define FASTLZ_VERSION_MAJOR 0 42 | #define FASTLZ_VERSION_MINOR 0 43 | #define FASTLZ_VERSION_REVISION 0 44 | 45 | #define FASTLZ_VERSION_STRING "0.1.0" 46 | 47 | #if defined (__cplusplus) 48 | extern "C" { 49 | #endif 50 | 51 | /** 52 | Compress a block of data in the input buffer and returns the size of 53 | compressed block. The size of input buffer is specified by length. The 54 | minimum input buffer size is 16. 55 | 56 | The output buffer must be at least 5% larger than the input buffer 57 | and can not be smaller than 66 bytes. 58 | 59 | If the input is not compressible, the return value might be larger than 60 | length (input buffer size). 61 | 62 | The input buffer and the output buffer can not overlap. 63 | */ 64 | 65 | int fastlz_compress(const void* input, int length, void* output); 66 | 67 | /** 68 | Decompress a block of compressed data and returns the size of the 69 | decompressed block. If error occurs, e.g. the compressed data is 70 | corrupted or the output buffer is not large enough, then 0 (zero) 71 | will be returned instead. 72 | 73 | The input buffer and the output buffer can not overlap. 74 | 75 | Decompression is memory safe and guaranteed not to write the output buffer 76 | more than what is specified in maxout. 77 | */ 78 | 79 | int fastlz_decompress(const void* input, int length, void* output, int maxout); 80 | 81 | /** 82 | Compress a block of data in the input buffer and returns the size of 83 | compressed block. The size of input buffer is specified by length. The 84 | minimum input buffer size is 16. 85 | 86 | The output buffer must be at least 5% larger than the input buffer 87 | and can not be smaller than 66 bytes. 88 | 89 | If the input is not compressible, the return value might be larger than 90 | length (input buffer size). 91 | 92 | The input buffer and the output buffer can not overlap. 93 | 94 | Compression level can be specified in parameter level. At the moment, 95 | only level 1 and level 2 are supported. 96 | Level 1 is the fastest compression and generally useful for short data. 97 | Level 2 is slightly slower but it gives better compression ratio. 98 | 99 | Note that the compressed data, regardless of the level, can always be 100 | decompressed using the function fastlz_decompress above. 101 | */ 102 | 103 | int fastlz_compress_level(int level, const void* input, int length, void* output); 104 | 105 | #if defined (__cplusplus) 106 | } 107 | #endif 108 | 109 | #endif /* FASTLZ_H */ 110 | -------------------------------------------------------------------------------- /src/fst/fst_win_unistd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2018 Tony Bybell. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | * 22 | * SPDX-License-Identifier: MIT 23 | */ 24 | 25 | #ifndef WIN_UNISTD_H 26 | #define WIN_UNISTD_H 27 | 28 | #include 29 | #ifdef _WIN64 30 | #include 31 | #else 32 | #include 33 | #endif 34 | 35 | #include 36 | 37 | #define ftruncate _chsize_s 38 | #define unlink _unlink 39 | #define fileno _fileno 40 | #define lseek _lseeki64 41 | 42 | #ifdef _WIN64 43 | #define ssize_t __int64 44 | #define SSIZE_MAX 9223372036854775807i64 45 | #else 46 | #define ssize_t long 47 | #define SSIZE_MAX 2147483647L 48 | #endif 49 | 50 | #include "stdint.h" 51 | 52 | #endif //WIN_UNISTD_H 53 | -------------------------------------------------------------------------------- /src/fst/fstapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2018 Tony Bybell. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | * 22 | * SPDX-License-Identifier: MIT 23 | */ 24 | 25 | #ifndef FST_API_H 26 | #define FST_API_H 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #if defined(_MSC_VER) 39 | #include "fst_win_unistd.h" 40 | #else 41 | #include 42 | #endif 43 | #include 44 | 45 | #define FST_RDLOAD "FSTLOAD | " 46 | 47 | typedef uint32_t fstHandle; 48 | typedef uint32_t fstEnumHandle; 49 | 50 | enum fstWriterPackType { 51 | FST_WR_PT_ZLIB = 0, 52 | FST_WR_PT_FASTLZ = 1, 53 | FST_WR_PT_LZ4 = 2 54 | }; 55 | 56 | enum fstFileType { 57 | FST_FT_MIN = 0, 58 | 59 | FST_FT_VERILOG = 0, 60 | FST_FT_VHDL = 1, 61 | FST_FT_VERILOG_VHDL = 2, 62 | 63 | FST_FT_MAX = 2 64 | }; 65 | 66 | enum fstBlockType { 67 | FST_BL_HDR = 0, 68 | FST_BL_VCDATA = 1, 69 | FST_BL_BLACKOUT = 2, 70 | FST_BL_GEOM = 3, 71 | FST_BL_HIER = 4, 72 | FST_BL_VCDATA_DYN_ALIAS = 5, 73 | FST_BL_HIER_LZ4 = 6, 74 | FST_BL_HIER_LZ4DUO = 7, 75 | FST_BL_VCDATA_DYN_ALIAS2 = 8, 76 | 77 | FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */ 78 | FST_BL_SKIP = 255 /* used while block is being written */ 79 | }; 80 | 81 | enum fstScopeType { 82 | FST_ST_MIN = 0, 83 | 84 | FST_ST_VCD_MODULE = 0, 85 | FST_ST_VCD_TASK = 1, 86 | FST_ST_VCD_FUNCTION = 2, 87 | FST_ST_VCD_BEGIN = 3, 88 | FST_ST_VCD_FORK = 4, 89 | FST_ST_VCD_GENERATE = 5, 90 | FST_ST_VCD_STRUCT = 6, 91 | FST_ST_VCD_UNION = 7, 92 | FST_ST_VCD_CLASS = 8, 93 | FST_ST_VCD_INTERFACE = 9, 94 | FST_ST_VCD_PACKAGE = 10, 95 | FST_ST_VCD_PROGRAM = 11, 96 | 97 | FST_ST_VHDL_ARCHITECTURE = 12, 98 | FST_ST_VHDL_PROCEDURE = 13, 99 | FST_ST_VHDL_FUNCTION = 14, 100 | FST_ST_VHDL_RECORD = 15, 101 | FST_ST_VHDL_PROCESS = 16, 102 | FST_ST_VHDL_BLOCK = 17, 103 | FST_ST_VHDL_FOR_GENERATE = 18, 104 | FST_ST_VHDL_IF_GENERATE = 19, 105 | FST_ST_VHDL_GENERATE = 20, 106 | FST_ST_VHDL_PACKAGE = 21, 107 | 108 | FST_ST_MAX = 21, 109 | 110 | FST_ST_GEN_ATTRBEGIN = 252, 111 | FST_ST_GEN_ATTREND = 253, 112 | 113 | FST_ST_VCD_SCOPE = 254, 114 | FST_ST_VCD_UPSCOPE = 255 115 | }; 116 | 117 | enum fstVarType { 118 | FST_VT_MIN = 0, /* start of vartypes */ 119 | 120 | FST_VT_VCD_EVENT = 0, 121 | FST_VT_VCD_INTEGER = 1, 122 | FST_VT_VCD_PARAMETER = 2, 123 | FST_VT_VCD_REAL = 3, 124 | FST_VT_VCD_REAL_PARAMETER = 4, 125 | FST_VT_VCD_REG = 5, 126 | FST_VT_VCD_SUPPLY0 = 6, 127 | FST_VT_VCD_SUPPLY1 = 7, 128 | FST_VT_VCD_TIME = 8, 129 | FST_VT_VCD_TRI = 9, 130 | FST_VT_VCD_TRIAND = 10, 131 | FST_VT_VCD_TRIOR = 11, 132 | FST_VT_VCD_TRIREG = 12, 133 | FST_VT_VCD_TRI0 = 13, 134 | FST_VT_VCD_TRI1 = 14, 135 | FST_VT_VCD_WAND = 15, 136 | FST_VT_VCD_WIRE = 16, 137 | FST_VT_VCD_WOR = 17, 138 | FST_VT_VCD_PORT = 18, 139 | FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */ 140 | FST_VT_VCD_REALTIME = 20, 141 | 142 | FST_VT_GEN_STRING = 21, /* generic string type (max len is defined dynamically via fstWriterEmitVariableLengthValueChange) */ 143 | 144 | FST_VT_SV_BIT = 22, 145 | FST_VT_SV_LOGIC = 23, 146 | FST_VT_SV_INT = 24, /* declare as size = 32 */ 147 | FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */ 148 | FST_VT_SV_LONGINT = 26, /* declare as size = 64 */ 149 | FST_VT_SV_BYTE = 27, /* declare as size = 8 */ 150 | FST_VT_SV_ENUM = 28, /* declare as appropriate type range */ 151 | FST_VT_SV_SHORTREAL = 29, /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted as double, not a float) */ 152 | 153 | FST_VT_MAX = 29 /* end of vartypes */ 154 | }; 155 | 156 | enum fstVarDir { 157 | FST_VD_MIN = 0, 158 | 159 | FST_VD_IMPLICIT = 0, 160 | FST_VD_INPUT = 1, 161 | FST_VD_OUTPUT = 2, 162 | FST_VD_INOUT = 3, 163 | FST_VD_BUFFER = 4, 164 | FST_VD_LINKAGE = 5, 165 | 166 | FST_VD_MAX = 5 167 | }; 168 | 169 | enum fstHierType { 170 | FST_HT_MIN = 0, 171 | 172 | FST_HT_SCOPE = 0, 173 | FST_HT_UPSCOPE = 1, 174 | FST_HT_VAR = 2, 175 | FST_HT_ATTRBEGIN = 3, 176 | FST_HT_ATTREND = 4, 177 | 178 | /* FST_HT_TREEBEGIN and FST_HT_TREEEND are not yet used by FST but are currently used when fstHier bridges other formats */ 179 | FST_HT_TREEBEGIN = 5, 180 | FST_HT_TREEEND = 6, 181 | 182 | FST_HT_MAX = 6 183 | }; 184 | 185 | enum fstAttrType { 186 | FST_AT_MIN = 0, 187 | 188 | FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */ 189 | FST_AT_ARRAY = 1, 190 | FST_AT_ENUM = 2, 191 | FST_AT_PACK = 3, 192 | 193 | FST_AT_MAX = 3 194 | }; 195 | 196 | enum fstMiscType { 197 | FST_MT_MIN = 0, 198 | 199 | FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */ 200 | FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */ 201 | FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */ 202 | FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */ 203 | FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */ 204 | FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */ 205 | FST_MT_VALUELIST = 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */ 206 | FST_MT_ENUMTABLE = 7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */ 207 | FST_MT_UNKNOWN = 8, 208 | 209 | FST_MT_MAX = 8 210 | }; 211 | 212 | enum fstArrayType { 213 | FST_AR_MIN = 0, 214 | 215 | FST_AR_NONE = 0, 216 | FST_AR_UNPACKED = 1, 217 | FST_AR_PACKED = 2, 218 | FST_AR_SPARSE = 3, 219 | 220 | FST_AR_MAX = 3 221 | }; 222 | 223 | enum fstEnumValueType { 224 | FST_EV_SV_INTEGER = 0, 225 | FST_EV_SV_BIT = 1, 226 | FST_EV_SV_LOGIC = 2, 227 | FST_EV_SV_INT = 3, 228 | FST_EV_SV_SHORTINT = 4, 229 | FST_EV_SV_LONGINT = 5, 230 | FST_EV_SV_BYTE = 6, 231 | FST_EV_SV_UNSIGNED_INTEGER = 7, 232 | FST_EV_SV_UNSIGNED_BIT = 8, 233 | FST_EV_SV_UNSIGNED_LOGIC = 9, 234 | FST_EV_SV_UNSIGNED_INT = 10, 235 | FST_EV_SV_UNSIGNED_SHORTINT = 11, 236 | FST_EV_SV_UNSIGNED_LONGINT = 12, 237 | FST_EV_SV_UNSIGNED_BYTE = 13, 238 | 239 | FST_EV_REG = 14, 240 | FST_EV_TIME = 15, 241 | 242 | FST_EV_MAX = 15 243 | }; 244 | 245 | enum fstPackType { 246 | FST_PT_NONE = 0, 247 | FST_PT_UNPACKED = 1, 248 | FST_PT_PACKED = 2, 249 | FST_PT_TAGGED_PACKED = 3, 250 | 251 | FST_PT_MAX = 3 252 | }; 253 | 254 | enum fstSupplementalVarType { 255 | FST_SVT_MIN = 0, 256 | 257 | FST_SVT_NONE = 0, 258 | 259 | FST_SVT_VHDL_SIGNAL = 1, 260 | FST_SVT_VHDL_VARIABLE = 2, 261 | FST_SVT_VHDL_CONSTANT = 3, 262 | FST_SVT_VHDL_FILE = 4, 263 | FST_SVT_VHDL_MEMORY = 5, 264 | 265 | FST_SVT_MAX = 5 266 | }; 267 | 268 | enum fstSupplementalDataType { 269 | FST_SDT_MIN = 0, 270 | 271 | FST_SDT_NONE = 0, 272 | 273 | FST_SDT_VHDL_BOOLEAN = 1, 274 | FST_SDT_VHDL_BIT = 2, 275 | FST_SDT_VHDL_BIT_VECTOR = 3, 276 | FST_SDT_VHDL_STD_ULOGIC = 4, 277 | FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5, 278 | FST_SDT_VHDL_STD_LOGIC = 6, 279 | FST_SDT_VHDL_STD_LOGIC_VECTOR = 7, 280 | FST_SDT_VHDL_UNSIGNED = 8, 281 | FST_SDT_VHDL_SIGNED = 9, 282 | FST_SDT_VHDL_INTEGER = 10, 283 | FST_SDT_VHDL_REAL = 11, 284 | FST_SDT_VHDL_NATURAL = 12, 285 | FST_SDT_VHDL_POSITIVE = 13, 286 | FST_SDT_VHDL_TIME = 14, 287 | FST_SDT_VHDL_CHARACTER = 15, 288 | FST_SDT_VHDL_STRING = 16, 289 | 290 | FST_SDT_MAX = 16, 291 | 292 | FST_SDT_SVT_SHIFT_COUNT = 10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left after shifting FST_SDT_SVT_SHIFT_COUNT */ 293 | FST_SDT_ABS_MAX = ((1<<(FST_SDT_SVT_SHIFT_COUNT))-1) 294 | }; 295 | 296 | 297 | struct fstHier 298 | { 299 | unsigned char htyp; 300 | 301 | union { 302 | /* if htyp == FST_HT_SCOPE */ 303 | struct fstHierScope { 304 | unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */ 305 | const char *name; 306 | const char *component; 307 | uint32_t name_length; /* strlen(u.scope.name) */ 308 | uint32_t component_length; /* strlen(u.scope.component) */ 309 | } scope; 310 | 311 | /* if htyp == FST_HT_VAR */ 312 | struct fstHierVar { 313 | unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */ 314 | unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */ 315 | unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */ 316 | unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */ 317 | unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */ 318 | const char *name; 319 | uint32_t length; 320 | fstHandle handle; 321 | uint32_t name_length; /* strlen(u.var.name) */ 322 | unsigned is_alias : 1; 323 | } var; 324 | 325 | /* if htyp == FST_HT_ATTRBEGIN */ 326 | struct fstHierAttr { 327 | unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */ 328 | unsigned char subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */ 329 | const char *name; 330 | uint64_t arg; /* number of array elements, struct members, or some other payload (possibly ignored) */ 331 | uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer (FST_AT_MISC + FST_MT_SOURCESTEM) */ 332 | uint32_t name_length; /* strlen(u.attr.name) */ 333 | } attr; 334 | } u; 335 | }; 336 | 337 | 338 | struct fstETab 339 | { 340 | char *name; 341 | uint32_t elem_count; 342 | char **literal_arr; 343 | char **val_arr; 344 | }; 345 | 346 | 347 | /* 348 | * writer functions 349 | */ 350 | void fstWriterClose(void *ctx); 351 | void * fstWriterCreate(const char *nam, int use_compressed_hier); 352 | fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, const char **literal_arr, const char **val_arr); 353 | /* used for Verilog/SV */ 354 | fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd, 355 | uint32_t len, const char *nam, fstHandle aliasHandle); 356 | /* future expansion for VHDL and other languages. The variable type, data type, etc map onto 357 | the current Verilog/SV one. The "type" string is optional for a more verbose or custom description */ 358 | fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd, 359 | uint32_t len, const char *nam, fstHandle aliasHandle, 360 | const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt); 361 | void fstWriterEmitDumpActive(void *ctx, int enable); 362 | void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle); 363 | void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val); 364 | void fstWriterEmitValueChange32(void *ctx, fstHandle handle, 365 | uint32_t bits, uint32_t val); 366 | void fstWriterEmitValueChange64(void *ctx, fstHandle handle, 367 | uint32_t bits, uint64_t val); 368 | void fstWriterEmitValueChangeVec32(void *ctx, fstHandle handle, 369 | uint32_t bits, const uint32_t *val); 370 | void fstWriterEmitValueChangeVec64(void *ctx, fstHandle handle, 371 | uint32_t bits, const uint64_t *val); 372 | void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len); 373 | void fstWriterEmitTimeChange(void *ctx, uint64_t tim); 374 | void fstWriterFlushContext(void *ctx); 375 | int fstWriterGetDumpSizeLimitReached(void *ctx); 376 | int fstWriterGetFseekFailed(void *ctx); 377 | void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype, 378 | const char *attrname, uint64_t arg); 379 | void fstWriterSetAttrEnd(void *ctx); 380 | void fstWriterSetComment(void *ctx, const char *comm); 381 | void fstWriterSetDate(void *ctx, const char *dat); 382 | void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes); 383 | void fstWriterSetEnvVar(void *ctx, const char *envvar); 384 | void fstWriterSetFileType(void *ctx, enum fstFileType filetype); 385 | void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ); 386 | void fstWriterSetParallelMode(void *ctx, int enable); 387 | void fstWriterSetRepackOnClose(void *ctx, int enable); /* type = 0 (none), 1 (libz) */ 388 | void fstWriterSetScope(void *ctx, enum fstScopeType scopetype, 389 | const char *scopename, const char *scopecomp); 390 | void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath); 391 | void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath); 392 | void fstWriterSetTimescale(void *ctx, int ts); 393 | void fstWriterSetTimescaleFromString(void *ctx, const char *s); 394 | void fstWriterSetTimezero(void *ctx, int64_t tim); 395 | void fstWriterSetUpscope(void *ctx); 396 | void fstWriterSetValueList(void *ctx, const char *vl); 397 | void fstWriterSetVersion(void *ctx, const char *vers); 398 | 399 | 400 | /* 401 | * reader functions 402 | */ 403 | void fstReaderClose(void *ctx); 404 | void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx); 405 | void fstReaderClrFacProcessMaskAll(void *ctx); 406 | uint64_t fstReaderGetAliasCount(void *ctx); 407 | const char * fstReaderGetCurrentFlatScope(void *ctx); 408 | void * fstReaderGetCurrentScopeUserInfo(void *ctx); 409 | int fstReaderGetCurrentScopeLen(void *ctx); 410 | const char * fstReaderGetDateString(void *ctx); 411 | int fstReaderGetDoubleEndianMatchState(void *ctx); 412 | uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx); 413 | unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx); 414 | uint64_t fstReaderGetEndTime(void *ctx); 415 | int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx); 416 | int fstReaderGetFileType(void *ctx); 417 | int fstReaderGetFseekFailed(void *ctx); 418 | fstHandle fstReaderGetMaxHandle(void *ctx); 419 | uint64_t fstReaderGetMemoryUsedByWriter(void *ctx); 420 | uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx); 421 | uint64_t fstReaderGetScopeCount(void *ctx); 422 | uint64_t fstReaderGetStartTime(void *ctx); 423 | signed char fstReaderGetTimescale(void *ctx); 424 | int64_t fstReaderGetTimezero(void *ctx); 425 | uint64_t fstReaderGetValueChangeSectionCount(void *ctx); 426 | char * fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf); 427 | uint64_t fstReaderGetVarCount(void *ctx); 428 | const char * fstReaderGetVersionString(void *ctx); 429 | struct fstHier *fstReaderIterateHier(void *ctx); 430 | int fstReaderIterateHierRewind(void *ctx); 431 | int fstReaderIterBlocks(void *ctx, 432 | void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value), 433 | void *user_callback_data_pointer, FILE *vcdhandle); 434 | int fstReaderIterBlocks2(void *ctx, 435 | void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value), 436 | void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len), 437 | void *user_callback_data_pointer, FILE *vcdhandle); 438 | void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable); 439 | void * fstReaderOpen(const char *nam); 440 | void * fstReaderOpenForUtilitiesOnly(void); 441 | const char * fstReaderPopScope(void *ctx); 442 | int fstReaderProcessHier(void *ctx, FILE *vcdhandle); 443 | const char * fstReaderPushScope(void *ctx, const char *nam, void *user_info); 444 | void fstReaderResetScope(void *ctx); 445 | void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx); 446 | void fstReaderSetFacProcessMaskAll(void *ctx); 447 | void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time); 448 | void fstReaderSetUnlimitedTimeRange(void *ctx); 449 | void fstReaderSetVcdExtensions(void *ctx, int enable); 450 | 451 | 452 | /* 453 | * utility functions 454 | */ 455 | int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */ 456 | int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len); 457 | int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len); 458 | struct fstETab *fstUtilityExtractEnumTableFromString(const char *s); 459 | void fstUtilityFreeEnumTable(struct fstETab *etab); /* must use to free fstETab properly */ 460 | 461 | 462 | #ifdef __cplusplus 463 | } 464 | #endif 465 | 466 | #endif 467 | -------------------------------------------------------------------------------- /src/fst/lz4.h: -------------------------------------------------------------------------------- 1 | /* 2 | LZ4 - Fast LZ compression algorithm 3 | Header File 4 | Copyright (C) 2011-2015, Yann Collet. 5 | 6 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are 10 | met: 11 | 12 | * Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | * Redistributions in binary form must reproduce the above 15 | copyright notice, this list of conditions and the following disclaimer 16 | in the documentation and/or other materials provided with the 17 | distribution. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | SPDX-License-Identifier: BSD-2-Clause 32 | 33 | You can contact the author at : 34 | - LZ4 source repository : https://github.com/Cyan4973/lz4 35 | - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c 36 | */ 37 | #pragma once 38 | 39 | #if defined (__cplusplus) 40 | extern "C" { 41 | #endif 42 | 43 | /* 44 | * lz4.h provides block compression functions, and gives full buffer control to programmer. 45 | * If you need to generate inter-operable compressed data (respecting LZ4 frame specification), 46 | * and can let the library handle its own memory, please use lz4frame.h instead. 47 | */ 48 | 49 | /************************************** 50 | * Version 51 | **************************************/ 52 | #define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ 53 | #define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ 54 | #define LZ4_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */ 55 | #define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) 56 | int LZ4_versionNumber (void); 57 | 58 | /************************************** 59 | * Tuning parameter 60 | **************************************/ 61 | /* 62 | * LZ4_MEMORY_USAGE : 63 | * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) 64 | * Increasing memory usage improves compression ratio 65 | * Reduced memory usage can improve speed, due to cache effect 66 | * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache 67 | */ 68 | #define LZ4_MEMORY_USAGE 14 69 | 70 | 71 | /************************************** 72 | * Simple Functions 73 | **************************************/ 74 | 75 | int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); 76 | int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); 77 | 78 | /* 79 | LZ4_compress_default() : 80 | Compresses 'sourceSize' bytes from buffer 'source' 81 | into already allocated 'dest' buffer of size 'maxDestSize'. 82 | Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). 83 | It also runs faster, so it's a recommended setting. 84 | If the function cannot compress 'source' into a more limited 'dest' budget, 85 | compression stops *immediately*, and the function result is zero. 86 | As a consequence, 'dest' content is not valid. 87 | This function never writes outside 'dest' buffer, nor read outside 'source' buffer. 88 | sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE 89 | maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) 90 | return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) 91 | or 0 if compression fails 92 | 93 | LZ4_decompress_safe() : 94 | compressedSize : is the precise full size of the compressed block. 95 | maxDecompressedSize : is the size of destination buffer, which must be already allocated. 96 | return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) 97 | If destination buffer is not large enough, decoding will stop and output an error code (<0). 98 | If the source stream is detected malformed, the function will stop decoding and return a negative result. 99 | This function is protected against buffer overflow exploits, including malicious data packets. 100 | It never writes outside output buffer, nor reads outside input buffer. 101 | */ 102 | 103 | 104 | /************************************** 105 | * Advanced Functions 106 | **************************************/ 107 | #define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ 108 | #define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) 109 | 110 | /* 111 | LZ4_compressBound() : 112 | Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) 113 | This function is primarily useful for memory allocation purposes (destination buffer size). 114 | Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). 115 | Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize) 116 | inputSize : max supported value is LZ4_MAX_INPUT_SIZE 117 | return : maximum output size in a "worst case" scenario 118 | or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) 119 | */ 120 | int LZ4_compressBound(int inputSize); 121 | 122 | /* 123 | LZ4_compress_fast() : 124 | Same as LZ4_compress_default(), but allows to select an "acceleration" factor. 125 | The larger the acceleration value, the faster the algorithm, but also the lesser the compression. 126 | It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. 127 | An acceleration value of "1" is the same as regular LZ4_compress_default() 128 | Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. 129 | */ 130 | int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration); 131 | 132 | 133 | /* 134 | LZ4_compress_fast_extState() : 135 | Same compression function, just using an externally allocated memory space to store compression state. 136 | Use LZ4_sizeofState() to know how much memory must be allocated, 137 | and allocate it on 8-bytes boundaries (using malloc() typically). 138 | Then, provide it as 'void* state' to compression function. 139 | */ 140 | int LZ4_sizeofState(void); 141 | int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration); 142 | 143 | 144 | /* 145 | LZ4_compress_destSize() : 146 | Reverse the logic, by compressing as much data as possible from 'source' buffer 147 | into already allocated buffer 'dest' of size 'targetDestSize'. 148 | This function either compresses the entire 'source' content into 'dest' if it's large enough, 149 | or fill 'dest' buffer completely with as much data as possible from 'source'. 150 | *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'. 151 | New value is necessarily <= old value. 152 | return : Nb bytes written into 'dest' (necessarily <= targetDestSize) 153 | or 0 if compression fails 154 | */ 155 | int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize); 156 | 157 | 158 | /* 159 | LZ4_decompress_fast() : 160 | originalSize : is the original and therefore uncompressed size 161 | return : the number of bytes read from the source buffer (in other words, the compressed size) 162 | If the source stream is detected malformed, the function will stop decoding and return a negative result. 163 | Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. 164 | note : This function fully respect memory boundaries for properly formed compressed data. 165 | It is a bit faster than LZ4_decompress_safe(). 166 | However, it does not provide any protection against intentionally modified data stream (malicious input). 167 | Use this function in trusted environment only (data to decode comes from a trusted source). 168 | */ 169 | int LZ4_decompress_fast (const char* source, char* dest, int originalSize); 170 | 171 | /* 172 | LZ4_decompress_safe_partial() : 173 | This function decompress a compressed block of size 'compressedSize' at position 'source' 174 | into destination buffer 'dest' of size 'maxDecompressedSize'. 175 | The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, 176 | reducing decompression time. 177 | return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) 178 | Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. 179 | Always control how many bytes were decoded. 180 | If the source stream is detected malformed, the function will stop decoding and return a negative result. 181 | This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets 182 | */ 183 | int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize); 184 | 185 | 186 | /*********************************************** 187 | * Streaming Compression Functions 188 | ***********************************************/ 189 | #define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) 190 | #define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long)) 191 | /* 192 | * LZ4_stream_t 193 | * information structure to track an LZ4 stream. 194 | * important : init this structure content before first use ! 195 | * note : only allocated directly the structure if you are statically linking LZ4 196 | * If you are using liblz4 as a DLL, please use below construction methods instead. 197 | */ 198 | typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t; 199 | 200 | /* 201 | * LZ4_resetStream 202 | * Use this function to init an allocated LZ4_stream_t structure 203 | */ 204 | void LZ4_resetStream (LZ4_stream_t* streamPtr); 205 | 206 | /* 207 | * LZ4_createStream will allocate and initialize an LZ4_stream_t structure 208 | * LZ4_freeStream releases its memory. 209 | * In the context of a DLL (liblz4), please use these methods rather than the static struct. 210 | * They are more future proof, in case of a change of LZ4_stream_t size. 211 | */ 212 | LZ4_stream_t* LZ4_createStream(void); 213 | int LZ4_freeStream (LZ4_stream_t* streamPtr); 214 | 215 | /* 216 | * LZ4_loadDict 217 | * Use this function to load a static dictionary into LZ4_stream. 218 | * Any previous data will be forgotten, only 'dictionary' will remain in memory. 219 | * Loading a size of 0 is allowed. 220 | * Return : dictionary size, in bytes (necessarily <= 64 KB) 221 | */ 222 | int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); 223 | 224 | /* 225 | * LZ4_compress_fast_continue 226 | * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio. 227 | * Important : Previous data blocks are assumed to still be present and unmodified ! 228 | * 'dst' buffer must be already allocated. 229 | * If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. 230 | * If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero. 231 | */ 232 | int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration); 233 | 234 | /* 235 | * LZ4_saveDict 236 | * If previously compressed data block is not guaranteed to remain available at its memory location 237 | * save it into a safer place (char* safeBuffer) 238 | * Note : you don't need to call LZ4_loadDict() afterwards, 239 | * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue() 240 | * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error 241 | */ 242 | int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize); 243 | 244 | 245 | /************************************************ 246 | * Streaming Decompression Functions 247 | ************************************************/ 248 | 249 | #define LZ4_STREAMDECODESIZE_U64 4 250 | #define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) 251 | typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t; 252 | /* 253 | * LZ4_streamDecode_t 254 | * information structure to track an LZ4 stream. 255 | * init this structure content using LZ4_setStreamDecode or memset() before first use ! 256 | * 257 | * In the context of a DLL (liblz4) please prefer usage of construction methods below. 258 | * They are more future proof, in case of a change of LZ4_streamDecode_t size in the future. 259 | * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure 260 | * LZ4_freeStreamDecode releases its memory. 261 | */ 262 | LZ4_streamDecode_t* LZ4_createStreamDecode(void); 263 | int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); 264 | 265 | /* 266 | * LZ4_setStreamDecode 267 | * Use this function to instruct where to find the dictionary. 268 | * Setting a size of 0 is allowed (same effect as reset). 269 | * Return : 1 if OK, 0 if error 270 | */ 271 | int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); 272 | 273 | /* 274 | *_continue() : 275 | These decoding functions allow decompression of multiple blocks in "streaming" mode. 276 | Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) 277 | In the case of a ring buffers, decoding buffer must be either : 278 | - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) 279 | In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). 280 | - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. 281 | maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block. 282 | In which case, encoding and decoding buffers do not need to be synchronized, 283 | and encoding ring buffer can have any size, including small ones ( < 64 KB). 284 | - _At least_ 64 KB + 8 bytes + maxBlockSize. 285 | In which case, encoding and decoding buffers do not need to be synchronized, 286 | and encoding ring buffer can have any size, including larger than decoding buffer. 287 | Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, 288 | and indicate where it is saved using LZ4_setStreamDecode() 289 | */ 290 | int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize); 291 | int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); 292 | 293 | 294 | /* 295 | Advanced decoding functions : 296 | *_usingDict() : 297 | These decoding functions work the same as 298 | a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue() 299 | They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure. 300 | */ 301 | int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize); 302 | int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize); 303 | 304 | 305 | 306 | /************************************** 307 | * Obsolete Functions 308 | **************************************/ 309 | /* Deprecate Warnings */ 310 | /* Should these warnings messages be a problem, 311 | it is generally possible to disable them, 312 | with -Wno-deprecated-declarations for gcc 313 | or _CRT_SECURE_NO_WARNINGS in Visual for example. 314 | You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */ 315 | #ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK 316 | # define LZ4_DEPRECATE_WARNING_DEFBLOCK 317 | # define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) 318 | # if (LZ4_GCC_VERSION >= 405) || defined(__clang__) 319 | # define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) 320 | # elif (LZ4_GCC_VERSION >= 301) 321 | # define LZ4_DEPRECATED(message) __attribute__((deprecated)) 322 | # elif defined(_MSC_VER) 323 | # define LZ4_DEPRECATED(message) __declspec(deprecated(message)) 324 | # else 325 | # pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler") 326 | # define LZ4_DEPRECATED(message) 327 | # endif 328 | #endif /* LZ4_DEPRECATE_WARNING_DEFBLOCK */ 329 | 330 | /* Obsolete compression functions */ 331 | /* These functions are planned to start generate warnings by r131 approximately */ 332 | int LZ4_compress (const char* source, char* dest, int sourceSize); 333 | int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize); 334 | int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); 335 | int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); 336 | int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); 337 | int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); 338 | 339 | /* Obsolete decompression functions */ 340 | /* These function names are completely deprecated and must no longer be used. 341 | They are only provided here for compatibility with older programs. 342 | - LZ4_uncompress is the same as LZ4_decompress_fast 343 | - LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe 344 | These function prototypes are now disabled; uncomment them only if you really need them. 345 | It is highly recommended to stop using these prototypes and migrate to maintained ones */ 346 | /* int LZ4_uncompress (const char* source, char* dest, int outputSize); */ 347 | /* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */ 348 | 349 | /* Obsolete streaming functions; use new streaming interface whenever possible */ 350 | LZ4_DEPRECATED("use LZ4_createStream() instead") void* LZ4_create (char* inputBuffer); 351 | LZ4_DEPRECATED("use LZ4_createStream() instead") int LZ4_sizeofStreamState(void); 352 | LZ4_DEPRECATED("use LZ4_resetStream() instead") int LZ4_resetStreamState(void* state, char* inputBuffer); 353 | LZ4_DEPRECATED("use LZ4_saveDict() instead") char* LZ4_slideInputBuffer (void* state); 354 | 355 | /* Obsolete streaming decoding functions */ 356 | LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize); 357 | LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize); 358 | 359 | 360 | #if defined (__cplusplus) 361 | } 362 | #endif 363 | -------------------------------------------------------------------------------- /src/fst_code.cc: -------------------------------------------------------------------------------- 1 | 2 | 3 | // Just some example code that I don't need anymore, but that I also don't want to delete just yet... 4 | 5 | { 6 | void *fstCtx; 7 | fstCtx = fstProc.fstCtx; 8 | 9 | int numHierVars = 0; 10 | 11 | int hierCntr = 0; 12 | struct fstHier *hier; 13 | string cur_scope_name; 14 | while((hier = fstReaderIterateHier(fstCtx))){ 15 | cout << "hierType(" << fstProc.hierTypeStrings[hier->htyp] << "), hierCntr(" << hierCntr << ")" << endl; 16 | 17 | switch(hier->htyp){ 18 | case FST_HT_SCOPE: { 19 | cout << " scope.typ(" << (int)hier->u.scope.typ << "," << fstProc.scopeTypeStrings[hier->u.scope.typ] << ")" << endl; 20 | cout << " scope.name(" << hier->u.scope.name << ")" << endl; 21 | cout << " scope.component(" << hier->u.scope.component << ")" << endl; 22 | 23 | const char *scope_full_name = fstReaderPushScope(fstCtx, hier->u.scope.name, NULL); 24 | int scope_full_name_len = fstReaderGetCurrentScopeLen(fstCtx); 25 | cout << " scope_full_name(" << scope_full_name << ")" << endl; 26 | cout << " scope_full_name_len(" << scope_full_name_len << ")" << endl; 27 | 28 | cur_scope_name = scope_full_name; 29 | 30 | break; 31 | } 32 | 33 | case FST_HT_UPSCOPE: { 34 | const char *scope_full_name = fstReaderPopScope(fstCtx); 35 | int scope_full_name_len = fstReaderGetCurrentScopeLen(fstCtx); 36 | cout << " scope_full_name(" << scope_full_name << ")" << endl; 37 | cout << " scope_full_name_len(" << scope_full_name_len << ")" << endl; 38 | 39 | cur_scope_name = scope_full_name; 40 | 41 | break; 42 | } 43 | 44 | case FST_HT_VAR: { 45 | cout << " var.name(" << hier->u.var.name << ")" << endl; 46 | cout << " var.scope(" << cur_scope_name << ")" << endl; 47 | cout << " var.typ(" << (int)hier->u.var.typ << "," << fstProc.varTypeStrings[hier->u.var.typ] << ")" << endl; 48 | cout << " var.direction(" << (int)hier->u.var.direction << "," << fstProc.varDirStrings[hier->u.var.direction] << ")" << endl; 49 | cout << " var.length(" << hier->u.var.length << ")" << endl; 50 | cout << " var.is_alias(" << hier->u.var.is_alias << ")" << endl; 51 | cout << " var.handle(" << hier->u.var.handle << ")" << endl; 52 | cout << " numHierVars(" << numHierVars << ")" << endl; 53 | 54 | if (clk_scope == cur_scope_name && clk_name == hier->u.var.name){ 55 | cout << "CLK MATCH!!!" << endl; 56 | clk_handle = hier->u.var.handle; 57 | } 58 | 59 | if (retired_pc_scope == cur_scope_name && retired_pc_name == hier->u.var.name){ 60 | cout << "PC MATCH!!!" << endl; 61 | retired_pc_handle = hier->u.var.handle; 62 | } 63 | 64 | if (retired_pc_valid_scope == cur_scope_name && retired_pc_valid_name == hier->u.var.name){ 65 | cout << "PC_VALID MATCH!!!" << endl; 66 | retired_pc_valid_handle = hier->u.var.handle; 67 | } 68 | 69 | ++numHierVars; 70 | break; 71 | } 72 | } 73 | 74 | ++hierCntr; 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/gdb_conf.cmd: -------------------------------------------------------------------------------- 1 | set logging on 2 | set logging overwrite on 3 | dir ../test_data/sw_semihosting 4 | set verbose on 5 | set trace-commands on 6 | set remotelogfile gdb_rsp.log 7 | set pagination off 8 | target extended-remote localhost:3333 9 | br main 10 | #c 11 | #br 35 12 | #c 13 | 14 | -------------------------------------------------------------------------------- /src/gdbstub.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2019 Matt Borgerson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef _GDBSTUB_H_ 24 | #define _GDBSTUB_H_ 25 | 26 | /* Enable debug statements (printf) */ 27 | #ifndef GDBSTUB_DEBUG 28 | #define GDBSTUB_DEBUG 0 29 | #endif 30 | 31 | /* Include platform specific definitions */ 32 | #include "gdbstub_sys.h" 33 | 34 | /***************************************************************************** 35 | * Macros 36 | ****************************************************************************/ 37 | 38 | #if GDBSTUB_DEBUG 39 | #define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) 40 | #else 41 | #define DEBUG_PRINT(...) 42 | #endif 43 | 44 | #ifndef EOF 45 | #define EOF (-1) 46 | #endif 47 | 48 | #ifndef NULL 49 | #define NULL ((void*)0) 50 | #endif 51 | 52 | #ifndef ASSERT 53 | #if GDBSTUB_DEBUG 54 | #define ASSERT(x) { \ 55 | if (!(x)) { \ 56 | fprintf(stderr, "ASSERTION FAILED\n"); \ 57 | fprintf(stderr, " Assertion: %s\n", #x); \ 58 | fprintf(stderr, " Location: %s @ %s:%d\n", __func__, \ 59 | __FILE__, __LINE__); \ 60 | exit(1); \ 61 | } \ 62 | } 63 | #else 64 | #define ASSERT(x) \ 65 | do {} while (0) 66 | #endif 67 | #endif 68 | 69 | /***************************************************************************** 70 | * Prototypes 71 | ****************************************************************************/ 72 | 73 | int dbg_main(struct dbg_state *state); 74 | 75 | /* System functions, supported by all stubs */ 76 | int dbg_sys_getc(void); 77 | int dbg_sys_putchar(int ch); 78 | int dbg_sys_mem_readb(address addr, char *val); 79 | int dbg_sys_mem_writeb(address addr, char val); 80 | int dbg_sys_continue(); 81 | int dbg_sys_step(); 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /src/gdbstub/.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | *.elf 3 | *.ld 4 | *.o 5 | -------------------------------------------------------------------------------- /src/gdbstub/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2019 Matt Borgerson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/gdbstub/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016-2019 Matt Borgerson 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | 23 | ARCH := arch_x86 24 | 25 | # Include a simple demo that can be debugged 26 | INCLUDE_DEMO = 1 27 | 28 | CC = gcc 29 | CFLAGS = -Werror -ansi -Os -g -ffunction-sections -fno-stack-protector -I$(ARCH) -I$(PWD) 30 | LD = ld 31 | LDFLAGS = --script=gdbstub.ld --gc-sections 32 | NASM = nasm 33 | NASM_FLAGS = -felf 34 | OBJCOPY = objcopy 35 | OBJCOPYFLAGS = --output-target=binary 36 | TARGET = gdbstub.bin 37 | BASE_ADDRESS = 0x500000 38 | OBJECTS = gdbstub.o \ 39 | $(ARCH)/gdbstub_sys.o 40 | 41 | ifeq ($(ARCH),arch_x86) 42 | CFLAGS += -m32 43 | LDFLAGS += -m elf_i386 44 | OBJECTS += $(ARCH)/gdbstub_int.o 45 | else 46 | $(error Please specify a supported architecture) 47 | endif 48 | 49 | ifeq ($(INCLUDE_DEMO),1) 50 | OBJECTS += demo/demo.o 51 | endif 52 | 53 | all: $(TARGET) 54 | .PRECIOUS: %.elf 55 | 56 | %.bin: %.elf 57 | $(OBJCOPY) $(OBJCOPYFLAGS) $^ $@ 58 | 59 | %.elf: $(OBJECTS) gdbstub.ld 60 | $(LD) $(LDFLAGS) -o $@ $(OBJECTS) 61 | 62 | gdbstub.ld: gdbstub.ld.in Makefile 63 | $(CC) -o $@ -x c -P -E \ 64 | -DBASE_ADDRESS=$(BASE_ADDRESS) \ 65 | -DINCLUDE_DEMO=$(INCLUDE_DEMO) \ 66 | $< 67 | 68 | %.o: %.c 69 | $(CC) $(CFLAGS) -o $@ -c $< 70 | 71 | %.o: %.nasm 72 | $(NASM) -o $@ $(NASM_FLAGS) $< 73 | 74 | .PHONY: clean 75 | clean: 76 | rm -f \ 77 | $(TARGET) \ 78 | $(TARGET:.bin=.elf) \ 79 | $(OBJECTS) \ 80 | gdbstub.ld 81 | -------------------------------------------------------------------------------- /src/gdbstub/README.md: -------------------------------------------------------------------------------- 1 | gdbstub 2 | ======= 3 | This is a simple GDB stub that can be easily dropped in to your project to allow 4 | you to debug a target platform using GDB (or another application which supports 5 | remote GDB targets). It has no library dependencies (such as libc) and requires 6 | just standard tools to build. 7 | 8 | Protocol 9 | -------- 10 | Communication between the stub and the debugger takes place via the [GDB 11 | Remote Serial Protocol](https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html). 12 | 13 | Porting 14 | ------- 15 | This was developed for x86 systems, but it's fairly modular. With a little 16 | effort, it can be easily ported to other platforms. You will need to modify 17 | `gdbstub_sys.h` and `gdbstub_sys.c` to fit your platform's needs accordingly. 18 | 19 | Building 20 | -------- 21 | Running `make` produces ELF binary `gdbstub.elf` with an entry point 22 | (`dbg_start`) that will simply hook the current IDT (to support debug 23 | interrupts) and break. 24 | 25 | Additionally, a simple flat binary `gdbstub.bin` is created from the ELF binary. 26 | The intent for this flat binary is to be trivially loaded and jumped to. 27 | 28 | Demo 29 | ---- 30 | In `demo/demo.c` there is a simple function that's used for demonstration and 31 | testing. To test the GDB stub out, you can launch an instance of the full-system 32 | emulator [QEMU](https://www.qemu.org/) as follows: 33 | 34 | qemu-system-i386 -serial tcp:127.0.0.1:1234,server -display none -kernel gdbstub.elf 35 | 36 | This will launch QEMU, create a virtual machine with a virtual serial port that 37 | can be connected to through local TCP port 1234, then load and run the stub 38 | executable inside the virtual machine. 39 | 40 | You can then launch your local GDB client with the `demo.gdbinit` script to get 41 | your GDB client to connect to the virtual serial port and begin debugging the 42 | demo application: 43 | 44 | gdb --command=demo/demo.gdbinit 45 | 46 | For example, step a couple of times and print out the value of `x`: 47 | 48 | (gdb) s 2 49 | (gdb) p/x x 50 | $1 = 0xdeadbeef 51 | 52 | License 53 | ------- 54 | This software is published under the terms of the MIT License. See `LICENSE.txt` 55 | for full license. 56 | 57 | Matt Borgerson, 2016-2019 58 | -------------------------------------------------------------------------------- /src/gdbstub/arch_x86/gdbstub_int.nasm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright (c) 2016-2019 Matt Borgerson 3 | ; 4 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 5 | ; of this software and associated documentation files (the "Software"), to deal 6 | ; in the Software without restriction, including without limitation the rights 7 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | ; copies of the Software, and to permit persons to whom the Software is 9 | ; furnished to do so, subject to the following conditions: 10 | ; 11 | ; The above copyright notice and this permission notice shall be included in 12 | ; all copies or substantial portions of the Software. 13 | ; 14 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | ; SOFTWARE. 21 | ; 22 | 23 | bits 32 24 | 25 | %define NUM_HANDLERS 32 26 | 27 | section .data 28 | global dbg_int_handlers 29 | 30 | ; Generate table of handlers 31 | dbg_int_handlers: 32 | %macro handler_addr 1 33 | dd dbg_int_handler_%1 34 | %endmacro 35 | %assign i 0 36 | %rep NUM_HANDLERS 37 | handler_addr i 38 | %assign i i+1 39 | %endrep 40 | 41 | section .text 42 | extern dbg_int_handler 43 | 44 | %macro int 1 45 | dbg_int_handler_%1: 46 | push 0 ; Dummy Error code 47 | push %1 ; Interrupt Vector 48 | jmp dbg_int_handler_common 49 | %endmacro 50 | 51 | %macro inte 1 52 | dbg_int_handler_%1: 53 | ; Error code already on stack 54 | push %1 ; Interrupt Vector 55 | jmp dbg_int_handler_common 56 | %endmacro 57 | 58 | ; Generate Interrupt Handlers 59 | %assign i 0 60 | %rep NUM_HANDLERS 61 | %if (i == 8) || ((i >= 10) && (i <= 14)) || (i == 17) 62 | inte i 63 | %else 64 | int i 65 | %endif 66 | %assign i i+1 67 | %endrep 68 | 69 | ; Common Interrupt Handler 70 | dbg_int_handler_common: 71 | pushad 72 | push ds 73 | push es 74 | push fs 75 | push gs 76 | push ss 77 | mov ebp, esp 78 | 79 | ; Stack: 80 | ; - EFLAGS 81 | ; - CS 82 | ; - EIP 83 | ; - ERROR CODE 84 | ; - VECTOR 85 | ; - EAX 86 | ; - ECX 87 | ; - EDX 88 | ; - EBX 89 | ; - ESP 90 | ; - EBP 91 | ; - ESI 92 | ; - EDI 93 | ; - DS 94 | ; - ES 95 | ; - FS 96 | ; - GS 97 | ; - SS 98 | 99 | push ebp 100 | call dbg_int_handler 101 | 102 | mov esp, ebp 103 | pop ss 104 | pop gs 105 | pop fs 106 | pop es 107 | pop ds 108 | popad 109 | add esp, 8 ; Pop error & vector 110 | iret 111 | -------------------------------------------------------------------------------- /src/gdbstub/arch_x86/gdbstub_sys.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2019 Matt Borgerson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include "gdbstub.h" 24 | 25 | #ifdef __STRICT_ANSI__ 26 | #define asm __asm__ 27 | #endif 28 | 29 | #define SERIAL_COM1 0x3f8 30 | #define SERIAL_COM2 0x2f8 31 | #define SERIAL_PORT SERIAL_COM1 32 | 33 | #define NUM_IDT_ENTRIES 32 34 | 35 | /***************************************************************************** 36 | * BSS Data 37 | ****************************************************************************/ 38 | 39 | static struct dbg_idt_gate dbg_idt_gates[NUM_IDT_ENTRIES]; 40 | static struct dbg_state dbg_state; 41 | 42 | /***************************************************************************** 43 | * Misc. Functions 44 | ****************************************************************************/ 45 | 46 | void *dbg_sys_memset(void *ptr, int data, size_t len) 47 | { 48 | char *p = ptr; 49 | 50 | while (len--) { 51 | *p++ = (char)data; 52 | } 53 | 54 | return ptr; 55 | } 56 | 57 | /* 58 | * Get current code segment (CS register). 59 | */ 60 | uint32_t dbg_get_cs(void) 61 | { 62 | uint32_t cs; 63 | 64 | asm volatile ( 65 | "push %%cs;" 66 | "pop %%eax;" 67 | /* Outputs */ : "=a" (cs) 68 | /* Inputs */ : /* None */ 69 | /* Clobbers */ : /* None */ 70 | ); 71 | 72 | return cs; 73 | } 74 | 75 | /***************************************************************************** 76 | * Interrupt Management Functions 77 | ****************************************************************************/ 78 | 79 | /* 80 | * Initialize idt_gates with the interrupt handlers. 81 | */ 82 | int dbg_init_gates(void) 83 | { 84 | size_t i; 85 | uint16_t cs; 86 | 87 | cs = dbg_get_cs(); 88 | for (i = 0; i < NUM_IDT_ENTRIES; i++) { 89 | dbg_idt_gates[i].flags = 0x8E00; 90 | dbg_idt_gates[i].segment = cs; 91 | dbg_idt_gates[i].offset_low = 92 | ((uint32_t)dbg_int_handlers[i] ) & 0xffff; 93 | dbg_idt_gates[i].offset_high = 94 | ((uint32_t)dbg_int_handlers[i] >> 16) & 0xffff; 95 | } 96 | 97 | return 0; 98 | } 99 | 100 | /* 101 | * Load a new IDT. 102 | */ 103 | int dbg_load_idt(struct dbg_idtr *idtr) 104 | { 105 | asm volatile ( 106 | "lidt %0" 107 | /* Outputs */ : /* None */ 108 | /* Inputs */ : "m" (*idtr) 109 | /* Clobbers */ : /* None */ 110 | ); 111 | 112 | return 0; 113 | } 114 | 115 | /* 116 | * Get current IDT. 117 | */ 118 | int dbg_store_idt(struct dbg_idtr *idtr) 119 | { 120 | asm volatile ( 121 | "sidt %0" 122 | /* Outputs */ : "=m" (*idtr) 123 | /* Inputs */ : /* None */ 124 | /* Clobbers */ : /* None */ 125 | ); 126 | 127 | return 0; 128 | } 129 | 130 | /* 131 | * Hook a vector of the current IDT. 132 | */ 133 | int dbg_hook_idt(uint8_t vector, const void *function) 134 | { 135 | struct dbg_idtr idtr; 136 | struct dbg_idt_gate *gates; 137 | 138 | dbg_store_idt(&idtr); 139 | gates = (struct dbg_idt_gate *)idtr.offset; 140 | gates[vector].flags = 0x8E00; 141 | gates[vector].segment = dbg_get_cs(); 142 | gates[vector].offset_low = (((uint32_t)function) ) & 0xffff; 143 | gates[vector].offset_high = (((uint32_t)function) >> 16) & 0xffff; 144 | 145 | return 0; 146 | } 147 | 148 | /* 149 | * Initialize IDT gates and load the new IDT. 150 | */ 151 | int dbg_init_idt(void) 152 | { 153 | struct dbg_idtr idtr; 154 | 155 | dbg_init_gates(); 156 | idtr.len = sizeof(dbg_idt_gates)-1; 157 | idtr.offset = (uint32_t)dbg_idt_gates; 158 | dbg_load_idt(&idtr); 159 | 160 | return 0; 161 | } 162 | 163 | /* 164 | * Common interrupt handler routine. 165 | */ 166 | void dbg_int_handler(struct dbg_interrupt_state *istate) 167 | { 168 | dbg_interrupt(istate); 169 | } 170 | 171 | /* 172 | * Debug interrupt handler. 173 | */ 174 | void dbg_interrupt(struct dbg_interrupt_state *istate) 175 | { 176 | dbg_sys_memset(&dbg_state.registers, 0, sizeof(dbg_state.registers)); 177 | 178 | /* Translate vector to signal */ 179 | switch (istate->vector) { 180 | case 1: dbg_state.signum = 5; break; 181 | case 3: dbg_state.signum = 5; break; 182 | default: dbg_state.signum = 7; 183 | } 184 | 185 | /* Load Registers */ 186 | dbg_state.registers[DBG_CPU_I386_REG_EAX] = istate->eax; 187 | dbg_state.registers[DBG_CPU_I386_REG_ECX] = istate->ecx; 188 | dbg_state.registers[DBG_CPU_I386_REG_EDX] = istate->edx; 189 | dbg_state.registers[DBG_CPU_I386_REG_EBX] = istate->ebx; 190 | dbg_state.registers[DBG_CPU_I386_REG_ESP] = istate->esp; 191 | dbg_state.registers[DBG_CPU_I386_REG_EBP] = istate->ebp; 192 | dbg_state.registers[DBG_CPU_I386_REG_ESI] = istate->esi; 193 | dbg_state.registers[DBG_CPU_I386_REG_EDI] = istate->edi; 194 | dbg_state.registers[DBG_CPU_I386_REG_PC] = istate->eip; 195 | dbg_state.registers[DBG_CPU_I386_REG_CS] = istate->cs; 196 | dbg_state.registers[DBG_CPU_I386_REG_PS] = istate->eflags; 197 | dbg_state.registers[DBG_CPU_I386_REG_SS] = istate->ss; 198 | dbg_state.registers[DBG_CPU_I386_REG_DS] = istate->ds; 199 | dbg_state.registers[DBG_CPU_I386_REG_ES] = istate->es; 200 | dbg_state.registers[DBG_CPU_I386_REG_FS] = istate->fs; 201 | dbg_state.registers[DBG_CPU_I386_REG_GS] = istate->gs; 202 | 203 | dbg_main(&dbg_state); 204 | 205 | /* Restore Registers */ 206 | istate->eax = dbg_state.registers[DBG_CPU_I386_REG_EAX]; 207 | istate->ecx = dbg_state.registers[DBG_CPU_I386_REG_ECX]; 208 | istate->edx = dbg_state.registers[DBG_CPU_I386_REG_EDX]; 209 | istate->ebx = dbg_state.registers[DBG_CPU_I386_REG_EBX]; 210 | istate->esp = dbg_state.registers[DBG_CPU_I386_REG_ESP]; 211 | istate->ebp = dbg_state.registers[DBG_CPU_I386_REG_EBP]; 212 | istate->esi = dbg_state.registers[DBG_CPU_I386_REG_ESI]; 213 | istate->edi = dbg_state.registers[DBG_CPU_I386_REG_EDI]; 214 | istate->eip = dbg_state.registers[DBG_CPU_I386_REG_PC]; 215 | istate->cs = dbg_state.registers[DBG_CPU_I386_REG_CS]; 216 | istate->eflags = dbg_state.registers[DBG_CPU_I386_REG_PS]; 217 | istate->ss = dbg_state.registers[DBG_CPU_I386_REG_SS]; 218 | istate->ds = dbg_state.registers[DBG_CPU_I386_REG_DS]; 219 | istate->es = dbg_state.registers[DBG_CPU_I386_REG_ES]; 220 | istate->fs = dbg_state.registers[DBG_CPU_I386_REG_FS]; 221 | istate->gs = dbg_state.registers[DBG_CPU_I386_REG_GS]; 222 | } 223 | 224 | /***************************************************************************** 225 | * I/O Functions 226 | ****************************************************************************/ 227 | 228 | /* 229 | * Write to I/O port. 230 | */ 231 | void dbg_io_write_8(uint16_t port, uint8_t val) 232 | { 233 | asm volatile ( 234 | "outb %%al, %%dx;" 235 | /* Outputs */ : /* None */ 236 | /* Inputs */ : "a" (val), "d" (port) 237 | /* Clobbers */ : /* None */ 238 | ); 239 | } 240 | 241 | /* 242 | * Read from I/O port. 243 | */ 244 | uint8_t dbg_io_read_8(uint16_t port) 245 | { 246 | uint8_t val; 247 | 248 | asm volatile ( 249 | "inb %%dx, %%al;" 250 | /* Outputs */ : "=a" (val) 251 | /* Inputs */ : "d" (port) 252 | /* Clobbers */ : /* None */ 253 | ); 254 | 255 | return val; 256 | } 257 | 258 | /***************************************************************************** 259 | * NS16550 Serial Port (IO) 260 | ****************************************************************************/ 261 | 262 | #define SERIAL_THR 0 263 | #define SERIAL_RBR 0 264 | #define SERIAL_LSR 5 265 | 266 | int dbg_serial_getc(void) 267 | { 268 | /* Wait for data */ 269 | while ((dbg_io_read_8(SERIAL_PORT + SERIAL_LSR) & 1) == 0); 270 | return dbg_io_read_8(SERIAL_PORT + SERIAL_RBR); 271 | } 272 | 273 | int dbg_serial_putchar(int ch) 274 | { 275 | /* Wait for THRE (bit 5) to be high */ 276 | while ((dbg_io_read_8(SERIAL_PORT + SERIAL_LSR) & (1<<5)) == 0); 277 | dbg_io_write_8(SERIAL_PORT + SERIAL_THR, ch); 278 | return ch; 279 | } 280 | 281 | /***************************************************************************** 282 | * Debugging System Functions 283 | ****************************************************************************/ 284 | 285 | /* 286 | * Write one character to the debugging stream. 287 | */ 288 | int dbg_sys_putchar(int ch) 289 | { 290 | return dbg_serial_putchar(ch); 291 | } 292 | 293 | /* 294 | * Read one character from the debugging stream. 295 | */ 296 | int dbg_sys_getc(void) 297 | { 298 | return dbg_serial_getc() & 0xff; 299 | } 300 | 301 | /* 302 | * Read one byte from memory. 303 | */ 304 | int dbg_sys_mem_readb(address addr, char *val) 305 | { 306 | *val = *(volatile char *)addr; 307 | return 0; 308 | } 309 | 310 | /* 311 | * Write one byte to memory. 312 | */ 313 | int dbg_sys_mem_writeb(address addr, char val) 314 | { 315 | *(volatile char *)addr = val; 316 | return 0; 317 | } 318 | 319 | /* 320 | * Continue program execution. 321 | */ 322 | int dbg_sys_continue(void) 323 | { 324 | dbg_state.registers[DBG_CPU_I386_REG_PS] &= ~(1<<8); 325 | return 0; 326 | } 327 | 328 | /* 329 | * Single step the next instruction. 330 | */ 331 | int dbg_sys_step(void) 332 | { 333 | dbg_state.registers[DBG_CPU_I386_REG_PS] |= 1<<8; 334 | return 0; 335 | } 336 | 337 | /* 338 | * Debugger init function. 339 | * 340 | * Hooks the IDT to enable debugging. 341 | */ 342 | void dbg_start(void) 343 | { 344 | /* Hook current IDT. */ 345 | dbg_hook_idt(1, dbg_int_handlers[1]); 346 | dbg_hook_idt(3, dbg_int_handlers[3]); 347 | 348 | /* Interrupt to start debugging. */ 349 | asm volatile ("int3"); 350 | } 351 | -------------------------------------------------------------------------------- /src/gdbstub/arch_x86/gdbstub_sys.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2019 Matt Borgerson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef _GDBSTUB_SYS_H_ 24 | #define _GDBSTUB_SYS_H_ 25 | 26 | /* Define the size_t type */ 27 | #define DBG_DEFINE_SIZET 1 28 | 29 | /* Define required standard integer types (e.g. uint16_t) */ 30 | #define DBG_DEFINE_STDINT 1 31 | 32 | /***************************************************************************** 33 | * Types 34 | ****************************************************************************/ 35 | 36 | #if DBG_DEFINE_STDINT 37 | typedef unsigned char uint8_t; 38 | typedef unsigned short uint16_t; 39 | typedef unsigned long uint32_t; 40 | #endif 41 | 42 | #if DBG_DEFINE_SIZET 43 | typedef unsigned int size_t; 44 | #endif 45 | 46 | typedef unsigned int address; 47 | typedef unsigned int reg; 48 | 49 | #pragma pack(1) 50 | struct dbg_interrupt_state { 51 | uint32_t ss; 52 | uint32_t gs; 53 | uint32_t fs; 54 | uint32_t es; 55 | uint32_t ds; 56 | uint32_t edi; 57 | uint32_t esi; 58 | uint32_t ebp; 59 | uint32_t esp; 60 | uint32_t ebx; 61 | uint32_t edx; 62 | uint32_t ecx; 63 | uint32_t eax; 64 | uint32_t vector; 65 | uint32_t error_code; 66 | uint32_t eip; 67 | uint32_t cs; 68 | uint32_t eflags; 69 | }; 70 | #pragma pack() 71 | 72 | #pragma pack(1) 73 | struct dbg_idtr 74 | { 75 | uint16_t len; 76 | uint32_t offset; 77 | }; 78 | #pragma pack() 79 | 80 | #pragma pack(1) 81 | struct dbg_idt_gate 82 | { 83 | uint16_t offset_low; 84 | uint16_t segment; 85 | uint16_t flags; 86 | uint16_t offset_high; 87 | }; 88 | #pragma pack() 89 | 90 | enum DBG_REGISTER { 91 | DBG_CPU_I386_REG_EAX = 0, 92 | DBG_CPU_I386_REG_ECX = 1, 93 | DBG_CPU_I386_REG_EDX = 2, 94 | DBG_CPU_I386_REG_EBX = 3, 95 | DBG_CPU_I386_REG_ESP = 4, 96 | DBG_CPU_I386_REG_EBP = 5, 97 | DBG_CPU_I386_REG_ESI = 6, 98 | DBG_CPU_I386_REG_EDI = 7, 99 | DBG_CPU_I386_REG_PC = 8, 100 | DBG_CPU_I386_REG_PS = 9, 101 | DBG_CPU_I386_REG_CS = 10, 102 | DBG_CPU_I386_REG_SS = 11, 103 | DBG_CPU_I386_REG_DS = 12, 104 | DBG_CPU_I386_REG_ES = 13, 105 | DBG_CPU_I386_REG_FS = 14, 106 | DBG_CPU_I386_REG_GS = 15, 107 | DBG_CPU_I386_NUM_REGISTERS = 16 108 | }; 109 | 110 | struct dbg_state { 111 | int signum; 112 | reg registers[DBG_CPU_I386_NUM_REGISTERS]; 113 | }; 114 | 115 | /***************************************************************************** 116 | * Const Data 117 | ****************************************************************************/ 118 | 119 | extern void const * const dbg_int_handlers[]; 120 | 121 | /***************************************************************************** 122 | * Prototypes 123 | ****************************************************************************/ 124 | 125 | int dbg_hook_idt(uint8_t vector, const void *function); 126 | int dbg_init_gates(void); 127 | int dbg_init_idt(void); 128 | int dbg_load_idt(struct dbg_idtr *idtr); 129 | int dbg_store_idt(struct dbg_idtr *idtr); 130 | uint32_t dbg_get_cs(void); 131 | void dbg_int_handler(struct dbg_interrupt_state *istate); 132 | void dbg_interrupt(struct dbg_interrupt_state *istate); 133 | void dbg_start(void); 134 | void dbg_io_write_8(uint16_t port, uint8_t val); 135 | uint8_t dbg_io_read_8(uint16_t port); 136 | void *dbg_sys_memset(void *ptr, int data, size_t len); 137 | 138 | #endif 139 | -------------------------------------------------------------------------------- /src/gdbstub/demo/demo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2019 Matt Borgerson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include "gdbstub.h" 24 | 25 | static void simple_loop(void) 26 | { 27 | volatile int x; 28 | int i; 29 | 30 | x = 0xdeadbeef; 31 | for (i = 0; 1; i++) { 32 | x ^= (1 << (i % 32)); 33 | } 34 | } 35 | 36 | /* This will be called at startup. */ 37 | void _start(void) 38 | { 39 | /* Enable debugging hooks and break */ 40 | dbg_start(); 41 | 42 | /* Example code to debug through... */ 43 | simple_loop(); 44 | } 45 | -------------------------------------------------------------------------------- /src/gdbstub/demo/demo.gdbinit: -------------------------------------------------------------------------------- 1 | # To observe RSP packets, enable the following line: 2 | # set debug remote 1 3 | 4 | symbol-file gdbstub.elf 5 | target remote 127.0.0.1:1234 6 | b simple_loop 7 | layout split 8 | c 9 | -------------------------------------------------------------------------------- /src/gdbstub/gdbstub.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2019 Matt Borgerson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef _GDBSTUB_H_ 24 | #define _GDBSTUB_H_ 25 | 26 | /* Enable debug statements (printf) */ 27 | #ifndef DEBUG 28 | #define DEBUG 0 29 | #endif 30 | 31 | /* Include platform specific definitions */ 32 | #include "gdbstub_sys.h" 33 | 34 | /***************************************************************************** 35 | * Macros 36 | ****************************************************************************/ 37 | 38 | #if DEBUG 39 | #define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) 40 | #else 41 | #define DEBUG_PRINT(...) 42 | #endif 43 | 44 | #ifndef EOF 45 | #define EOF (-1) 46 | #endif 47 | 48 | #ifndef NULL 49 | #define NULL ((void*)0) 50 | #endif 51 | 52 | #ifndef ASSERT 53 | #if DEBUG 54 | #define ASSERT(x) { \ 55 | if (!(x)) { \ 56 | fprintf(stderr, "ASSERTION FAILED\n"); \ 57 | fprintf(stderr, " Assertion: %s\n", #x); \ 58 | fprintf(stderr, " Location: %s @ %s:%d\n", __func__, \ 59 | __FILE__, __LINE__); \ 60 | exit(1); \ 61 | } \ 62 | } 63 | #else 64 | #define ASSERT(x) \ 65 | do {} while (0) 66 | #endif 67 | #endif 68 | 69 | /***************************************************************************** 70 | * Prototypes 71 | ****************************************************************************/ 72 | 73 | int dbg_main(struct dbg_state *state); 74 | 75 | /* System functions, supported by all stubs */ 76 | int dbg_sys_getc(void); 77 | int dbg_sys_putchar(int ch); 78 | int dbg_sys_mem_readb(address addr, char *val); 79 | int dbg_sys_mem_writeb(address addr, char val); 80 | int dbg_sys_continue(); 81 | int dbg_sys_step(); 82 | 83 | #endif -------------------------------------------------------------------------------- /src/gdbstub/gdbstub.ld.in: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2019 Matt Borgerson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #if INCLUDE_DEMO 24 | #define ENTRYPOINT _start 25 | #else 26 | #define ENTRYPOINT dbg_start 27 | #endif 28 | 29 | #define MULTIBOOT_MAGIC 0x1badb002 30 | #define MULTIBOOT_FLAGS 0x10000 31 | #define MULTIBOOT_CSUM (0 - (MULTIBOOT_MAGIC + MULTIBOOT_FLAGS)) 32 | 33 | ENTRY(ENTRYPOINT) 34 | 35 | MEMORY 36 | { 37 | RAM (WX) : ORIGIN = BASE_ADDRESS, LENGTH = 0x10000 38 | } 39 | 40 | SECTIONS 41 | { 42 | .text : { 43 | *(.text.dbg_start) 44 | 45 | #if INCLUDE_DEMO 46 | . = ALIGN(16); 47 | /* Include a multiboot header to boot in QEMU */ 48 | multiboot_hdr = .; 49 | LONG(MULTIBOOT_MAGIC) 50 | LONG(MULTIBOOT_FLAGS) 51 | LONG(MULTIBOOT_CSUM) 52 | LONG(multiboot_hdr) 53 | LONG(BASE_ADDRESS) 54 | LONG(_load_end_addr) 55 | LONG(_bss_end_addr) 56 | LONG(ENTRYPOINT) 57 | #endif 58 | 59 | *(.text) 60 | *(.rodata) 61 | } > RAM 62 | 63 | .data : { 64 | *(.data) 65 | *(.bss) 66 | _load_end_addr = .; 67 | _bss_end_addr = .; 68 | } > RAM 69 | 70 | /DISCARD/ : { 71 | *(.comment) 72 | *(.note.GNU-stack) 73 | *(.eh_frame) 74 | *(.rela.eh_frame) 75 | *(.shstrtab) 76 | *(.symtab) 77 | *(.strtab) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/gdbstub/tests/smoketest.gdbinit: -------------------------------------------------------------------------------- 1 | set pagination off 2 | symbol-file gdbstub.elf 3 | target remote 127.0.0.1:1234 4 | b simple_loop 5 | c 6 | 7 | # Step twice and check value of `x` variable 8 | s 2 9 | if x == 0xdeadbeef 10 | printf "PASS\n" 11 | quit 0 12 | else 13 | printf "FAIL\n" 14 | quit 1 15 | end 16 | -------------------------------------------------------------------------------- /src/gdbstub/tests/smoketest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Launching QEMU" 3 | qemu-system-i386 \ 4 | -serial tcp:127.0.0.1:1234,server \ 5 | -display none \ 6 | -kernel gdbstub.bin & 7 | sleep 1 8 | 9 | echo "Running GDB" 10 | gdb --command tests/smoketest.gdbinit 11 | RESULT=$? 12 | 13 | echo "Terminating QEMU" 14 | killall qemu-system-i386 15 | 16 | exit $RESULT 17 | -------------------------------------------------------------------------------- /src/gdbstub_sys.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "TcpServer.h" 6 | #include "Logger.h" 7 | 8 | #include "gdbstub.h" 9 | #include "gdbstub_sys.h" 10 | 11 | static TcpServer *tcpServer; 12 | static CpuTrace *cpuTrace; 13 | static RegFileTrace *regFileTrace; 14 | static MemTrace *memTrace; 15 | 16 | static struct dbg_state dbg_state; 17 | 18 | static map breakpoints; 19 | 20 | void dbg_sys_init(TcpServer &tS, CpuTrace &cT, RegFileTrace &rT, MemTrace &mT) 21 | { 22 | tcpServer = &tS; 23 | cpuTrace = &cT; 24 | regFileTrace = &rT; 25 | memTrace = &mT; 26 | 27 | cpuTrace->pcTraceIt = cpuTrace->pcTrace.begin(); 28 | 29 | for(int i=0;i<32;++i){ 30 | dbg_state.registers[i] = 0xdeadbeef; 31 | } 32 | 33 | dbg_sys_update_state(); 34 | 35 | int ret; 36 | do{ 37 | ret = dbg_main(&dbg_state); 38 | } while(ret == 0); 39 | 40 | LOG_ERROR("GDB client disconnected."); 41 | } 42 | 43 | void dbg_sys_update_state() 44 | { 45 | for(int i=0;i<32;++i){ 46 | uint64_t value; 47 | if (regFileTrace->getValue(cpuTrace->pcTraceIt->time, i, &value)){ 48 | dbg_state.registers[i] = (uint32_t)value; 49 | } 50 | } 51 | 52 | dbg_state.registers[DBG_CPU_RISCV_PC] = cpuTrace->pcTraceIt->pc; 53 | } 54 | 55 | 56 | #define RXBUF_SIZE 256 57 | static unsigned char rxbuf[RXBUF_SIZE]; 58 | static int rxbuf_cur_idx = 0; 59 | static int rxbuf_len = 0; 60 | 61 | int dbg_sys_getc(void) 62 | { 63 | if (rxbuf_cur_idx != rxbuf_len){ 64 | return rxbuf[rxbuf_cur_idx++]; 65 | } 66 | 67 | ssize_t ret = tcpServer->recv((void *)rxbuf, RXBUF_SIZE); 68 | if (ret > 0){ 69 | rxbuf_cur_idx = 0; 70 | rxbuf_len = ret; 71 | return rxbuf[rxbuf_cur_idx++]; 72 | } 73 | else{ 74 | return EOF; 75 | } 76 | } 77 | 78 | #define TXBUF_SIZE 256 79 | static unsigned char txbuf[TXBUF_SIZE]; 80 | 81 | int dbg_sys_putchar(int ch) 82 | { 83 | txbuf[0] = ch; 84 | size_t ret = tcpServer->xmit((void *)txbuf, 1); 85 | if (ret > 0){ 86 | return ch; 87 | } 88 | else{ 89 | return EOF; 90 | } 91 | } 92 | 93 | int dbg_sys_mem_readb(address addr, char *val) 94 | { 95 | memTrace->getValue(cpuTrace->pcTraceIt->time, addr, val); 96 | return 0; 97 | } 98 | 99 | int dbg_sys_mem_writeb(address addr, char val) 100 | { 101 | return 0; 102 | } 103 | 104 | void print_pc(CpuTrace * cpuTrace) 105 | { 106 | auto t = cpuTrace->pcTraceIt->time; 107 | auto pc = cpuTrace->pcTraceIt->pc; 108 | 109 | LOG_INFO("PC: 0x%08lx @ %ld (%ld/%ld)", pc, t, std::distance(cpuTrace->pcTrace.begin(), cpuTrace->pcTraceIt), cpuTrace->pcTrace.size()-1); 110 | } 111 | 112 | // End of trace conditions are treated differently for step and continue, because 113 | // of the way GDB behaves. 114 | // 115 | // When you do 'continue' and you issue a SIGTRAP at the end of the trace, GDB 116 | // will expect a breakpoint, treat it as a breakpoint even if the SIGTRAP happens 117 | // at an address that was not defined as a breakpoint. 118 | // Because of this, you can keep on issuing 'continue' indefinitely once you're 119 | // at the last instruction of the trace. 120 | // This is great, because GDB will assume that the program is still running and you can 121 | // still print variables and such. 122 | // 123 | // It's different for 'step' (the low level RSP assembler version). Once you've reached 124 | // the last instruction of a trace and you issue a high level step, GDB will issue low level 125 | // RSP step instructions until the addres is reached of the next high level command. 126 | // If the PC does not increase (and it can't, because we're at the end of the trace) and you 127 | // return from the step with a SIGTRAP, then GDB gets in an endless loop of issuing steps. 128 | // If, on the other hand, you issue a SIGABRT or something like that, GDB gets very confused 129 | // and stops sending commands to GDBWave, no matter what coommands you give GDB. 130 | // The current solution is to send a "W" reply, which means "program has terminated". 131 | // This has the big negative that you can't do anything like 'print' etc anymore, but 132 | // at least, you can restart the program without losing breakpoints etc. 133 | 134 | int dbg_sys_continue(void) 135 | { 136 | while(cpuTrace->pcTraceIt != cpuTrace->pcTrace.end()){ 137 | address curAddr = cpuTrace->pcTraceIt->pc; 138 | 139 | print_pc(cpuTrace); 140 | 141 | auto breakpointIt = breakpoints.find(curAddr); 142 | if (breakpointIt != breakpoints.end()){ 143 | LOG_INFO("Hit breakpoint %ld at PC = 0x%08lx", std::distance(breakpoints.begin(), breakpointIt), cpuTrace->pcTraceIt->pc); 144 | break; 145 | } 146 | 147 | ++cpuTrace->pcTraceIt; 148 | } 149 | 150 | if (cpuTrace->pcTraceIt == cpuTrace->pcTrace.end()){ 151 | LOG_INFO("Reached end of trace!"); 152 | cpuTrace->pcTraceIt = cpuTrace->pcTrace.end() -1; 153 | } 154 | 155 | print_pc(cpuTrace); 156 | 157 | dbg_state.signum = 0x05; // SIGTRAP 158 | dbg_sys_update_state(); 159 | 160 | return 0; 161 | } 162 | 163 | int dbg_sys_step(void) 164 | { 165 | if (cpuTrace->pcTraceIt != cpuTrace->pcTrace.end()){ 166 | ++cpuTrace->pcTraceIt; 167 | } 168 | 169 | if (cpuTrace->pcTraceIt == cpuTrace->pcTrace.end()){ 170 | LOG_INFO("Reached end of trace!"); 171 | cpuTrace->pcTraceIt = cpuTrace->pcTrace.end()-1; 172 | 173 | // -1 will ultimately result in a terminate message. 174 | return -1; 175 | } 176 | else{ 177 | dbg_state.signum = 0x05; // SIGTRAP 178 | } 179 | 180 | print_pc(cpuTrace); 181 | 182 | dbg_sys_update_state(); 183 | 184 | return 0; 185 | } 186 | 187 | int dbg_sys_restart(void) 188 | { 189 | cpuTrace->pcTraceIt = cpuTrace->pcTrace.begin(); 190 | return 0; 191 | } 192 | 193 | 194 | 195 | int dbg_sys_add_breakpoint(address addr) 196 | { 197 | auto breakpointIt = breakpoints.find(addr); 198 | 199 | if (breakpointIt == breakpoints.end()){ 200 | breakpoints[addr] = true; 201 | LOG_INFO(">>>>>>>>> Breakpoint added: 0x%08x. Nr of breakpoints: %ld", addr, breakpoints.size()); 202 | } 203 | 204 | return 0; 205 | } 206 | 207 | int dbg_sys_delete_breakpoint(address addr) 208 | { 209 | auto breakpointIt = breakpoints.find(addr); 210 | 211 | if (breakpointIt != breakpoints.end()){ 212 | breakpoints.erase(breakpointIt); 213 | LOG_INFO("<<<<<<<<< Breakpoint deleted: 0x%08x. Nr of breakpoints: %ld", addr, breakpoints.size()); 214 | } 215 | 216 | return 0; 217 | } 218 | 219 | -------------------------------------------------------------------------------- /src/gdbstub_sys.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2019 Matt Borgerson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef _GDBSTUB_SYS_H_ 24 | #define _GDBSTUB_SYS_H_ 25 | 26 | #include 27 | #include 28 | 29 | #include "TcpServer.h" 30 | #include "CpuTrace.h" 31 | #include "RegFileTrace.h" 32 | #include "MemTrace.h" 33 | 34 | /***************************************************************************** 35 | * Types 36 | ****************************************************************************/ 37 | 38 | typedef unsigned int address; 39 | typedef unsigned int reg; 40 | 41 | #pragma pack(1) 42 | struct dbg_interrupt_state { 43 | uint32_t ss; 44 | uint32_t gs; 45 | uint32_t fs; 46 | uint32_t es; 47 | uint32_t ds; 48 | uint32_t edi; 49 | uint32_t esi; 50 | uint32_t ebp; 51 | uint32_t esp; 52 | uint32_t ebx; 53 | uint32_t edx; 54 | uint32_t ecx; 55 | uint32_t eax; 56 | uint32_t vector; 57 | uint32_t error_code; 58 | uint32_t eip; 59 | uint32_t cs; 60 | uint32_t eflags; 61 | }; 62 | #pragma pack() 63 | 64 | #pragma pack(1) 65 | struct dbg_idtr 66 | { 67 | uint16_t len; 68 | uint32_t offset; 69 | }; 70 | #pragma pack() 71 | 72 | #pragma pack(1) 73 | struct dbg_idt_gate 74 | { 75 | uint16_t offset_low; 76 | uint16_t segment; 77 | uint16_t flags; 78 | uint16_t offset_high; 79 | }; 80 | #pragma pack() 81 | 82 | enum DBG_REGISTER { 83 | DBG_CPU_RISCV_REG_0 = 0, 84 | DBG_CPU_RISCV_REG_1 = 1, 85 | DBG_CPU_RISCV_REG_2 = 2, 86 | DBG_CPU_RISCV_REG_3 = 3, 87 | DBG_CPU_RISCV_REG_4 = 4, 88 | DBG_CPU_RISCV_REG_5 = 5, 89 | DBG_CPU_RISCV_REG_6 = 6, 90 | DBG_CPU_RISCV_REG_7 = 7, 91 | DBG_CPU_RISCV_REG_8 = 8, 92 | DBG_CPU_RISCV_REG_9 = 9, 93 | DBG_CPU_RISCV_REG_10 = 10, 94 | DBG_CPU_RISCV_REG_11 = 11, 95 | DBG_CPU_RISCV_REG_12 = 12, 96 | DBG_CPU_RISCV_REG_13 = 13, 97 | DBG_CPU_RISCV_REG_14 = 14, 98 | DBG_CPU_RISCV_REG_15 = 15, 99 | DBG_CPU_RISCV_REG_16 = 16, 100 | DBG_CPU_RISCV_REG_17 = 17, 101 | DBG_CPU_RISCV_REG_18 = 18, 102 | DBG_CPU_RISCV_REG_19 = 19, 103 | DBG_CPU_RISCV_REG_20 = 20, 104 | DBG_CPU_RISCV_REG_21 = 21, 105 | DBG_CPU_RISCV_REG_22 = 22, 106 | DBG_CPU_RISCV_REG_23 = 23, 107 | DBG_CPU_RISCV_REG_24 = 24, 108 | DBG_CPU_RISCV_REG_25 = 25, 109 | DBG_CPU_RISCV_REG_26 = 26, 110 | DBG_CPU_RISCV_REG_27 = 27, 111 | DBG_CPU_RISCV_REG_28 = 28, 112 | DBG_CPU_RISCV_REG_29 = 29, 113 | DBG_CPU_RISCV_REG_30 = 30, 114 | DBG_CPU_RISCV_REG_31 = 31, 115 | DBG_CPU_RISCV_PC = 32, 116 | DBG_CPU_RISCV_NUM_REGISTERS = 33 117 | }; 118 | 119 | struct dbg_state { 120 | int signum; 121 | reg registers[DBG_CPU_RISCV_NUM_REGISTERS]; 122 | }; 123 | 124 | /***************************************************************************** 125 | * Const Data 126 | ****************************************************************************/ 127 | 128 | extern void const * const dbg_int_handlers[]; 129 | 130 | /***************************************************************************** 131 | * Prototypes 132 | ****************************************************************************/ 133 | 134 | void dbg_sys_init(TcpServer &tS, CpuTrace &cT, RegFileTrace &rT, MemTrace &mT); 135 | void dbg_sys_update_state(); 136 | 137 | int dbg_hook_idt(uint8_t vector, const void *function); 138 | int dbg_init_gates(void); 139 | int dbg_init_idt(void); 140 | int dbg_load_idt(struct dbg_idtr *idtr); 141 | int dbg_store_idt(struct dbg_idtr *idtr); 142 | uint32_t dbg_get_cs(void); 143 | void dbg_int_handler(struct dbg_interrupt_state *istate); 144 | void dbg_interrupt(struct dbg_interrupt_state *istate); 145 | void dbg_start(void); 146 | void dbg_io_write_8(uint16_t port, uint8_t val); 147 | uint8_t dbg_io_read_8(uint16_t port); 148 | void *dbg_sys_memset(void *ptr, int data, size_t len); 149 | int dbg_sys_restart(void); 150 | int dbg_sys_add_breakpoint(address); 151 | int dbg_sys_delete_breakpoint(address); 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /src/main.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "Logger.h" 11 | #include "CpuTrace.h" 12 | #include "MemTrace.h" 13 | #include "RegFileTrace.h" 14 | #include "FstProcess.h" 15 | #include "TcpServer.h" 16 | #include "gdbstub.h" 17 | 18 | #define DEVELOP 1 19 | 20 | using namespace std; 21 | 22 | bool verbose = false; 23 | 24 | struct ConfigParams { 25 | string fstFileName; 26 | string cpuClkSignal; 27 | string retiredPcSignal; 28 | string retiredPcValidSignal; 29 | 30 | string regFileWriteValidSignal; 31 | string regFileWriteAddrSignal; 32 | string regFileWriteDataSignal; 33 | 34 | string memCmdValidSignal; 35 | string memCmdReadySignal; 36 | string memCmdAddrSignal; 37 | string memCmdSizeSignal; 38 | string memCmdWrSignal; 39 | string memCmdWrDataSignal; 40 | string memRspValidSignal; 41 | string memRspRdDataSignal; 42 | 43 | string memInitFileName; 44 | int memInitStartAddr; 45 | }; 46 | 47 | string get_scope(string full_path) 48 | { 49 | int last_dot = full_path.find_last_of('.'); 50 | 51 | return full_path.substr(0, last_dot); 52 | } 53 | 54 | string get_local_name(string full_path) 55 | { 56 | int last_dot = full_path.find_last_of('.'); 57 | 58 | return full_path.substr(last_dot+1); 59 | } 60 | 61 | // trim from start (in place) 62 | static inline void ltrim(std::string &s) { 63 | s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { 64 | return !std::isspace(ch); 65 | })); 66 | } 67 | 68 | // trim from end (in place) 69 | static inline void rtrim(std::string &s) { 70 | s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { 71 | return !std::isspace(ch); 72 | }).base(), s.end()); 73 | } 74 | 75 | // trim from both ends (in place) 76 | static inline void trim(std::string &s) { 77 | ltrim(s); 78 | rtrim(s); 79 | } 80 | 81 | void help() 82 | { 83 | LOG_INFO("Usage: gdbwave "); 84 | LOG_INFO(" -w "); 85 | LOG_INFO(" -c "); 86 | LOG_INFO(" -p "); 87 | LOG_INFO(" -v verbose"); 88 | LOG_INFO(""); 89 | LOG_INFO("Example: ./gdbwave -w ./test_data/top.fst -c ./test_data/configParams.txt"); 90 | LOG_INFO(""); 91 | } 92 | 93 | void parseConfig(ifstream & configFile, ConfigParams &c) 94 | { 95 | string line; 96 | LOG_INFO("Reading configuration parameters..."); 97 | 98 | while(getline(configFile, line)){ 99 | trim(line); 100 | if (line[0] == '#' || line.empty()) 101 | continue; 102 | auto delimiterPos = line.find("="); 103 | auto name = line.substr(0, delimiterPos); 104 | auto value = line.substr(delimiterPos+1); 105 | 106 | trim(name); 107 | trim(value); 108 | 109 | if (name == "cpuClk") 110 | c.cpuClkSignal = value; 111 | else if (name == "retiredPc") 112 | c.retiredPcSignal = value; 113 | else if (name == "retiredPcValid") 114 | c.retiredPcValidSignal = value; 115 | else if (name == "regFileWriteValid") 116 | c.regFileWriteValidSignal = value; 117 | else if (name == "regFileWriteAddr") 118 | c.regFileWriteAddrSignal = value; 119 | else if (name == "regFileWriteData") 120 | c.regFileWriteDataSignal = value; 121 | 122 | else if (name == "memCmdValid") 123 | c.memCmdValidSignal = value; 124 | else if (name == "memCmdReady") 125 | c.memCmdReadySignal = value; 126 | else if (name == "memCmdAddr") 127 | c.memCmdAddrSignal = value; 128 | else if (name == "memCmdSize") 129 | c.memCmdSizeSignal = value; 130 | else if (name == "memCmdWr") 131 | c.memCmdWrSignal = value; 132 | else if (name == "memCmdWrData") 133 | c.memCmdWrDataSignal = value; 134 | else if (name == "memRspValid") 135 | c.memRspValidSignal = value; 136 | else if (name == "memRspRdData") 137 | c.memRspRdDataSignal = value; 138 | 139 | else if (name == "memInitFile") 140 | c.memInitFileName = value; 141 | else if (name == "memInitStartAddr") 142 | c.memInitStartAddr = stoi(value); 143 | 144 | else{ 145 | LOG_ERROR("Unknown configuration parameter: %s", name.c_str()); 146 | exit(1); 147 | } 148 | 149 | LOG_INFO("%s:%s", name.c_str(), value.c_str()); 150 | } 151 | } 152 | 153 | int main(int argc, char **argv) 154 | { 155 | int c; 156 | Logger::log().setDebugLevel(Logger::INFO); 157 | Logger::log().setLogFile("./gdbwave.log"); 158 | 159 | ConfigParams configParams; 160 | int portNr = 3333; 161 | 162 | string fstFileName; 163 | string configParamsFileName; 164 | 165 | while((c = getopt(argc, argv, "hw:c:p:v")) != -1){ 166 | switch(c){ 167 | case 'h': 168 | help(); 169 | exit(0); 170 | break; 171 | case 'w': 172 | fstFileName = optarg; 173 | break; 174 | case 'c': 175 | configParamsFileName = optarg; 176 | break; 177 | case 'p': 178 | portNr = stoi(optarg); 179 | break; 180 | case 'v': 181 | verbose = true; 182 | break; 183 | case '?': 184 | return 1; 185 | } 186 | } 187 | 188 | #if DEVELOP==1 189 | if (fstFileName.empty()){ 190 | fstFileName = "../test_data/top.fst"; 191 | } 192 | if (configParamsFileName.empty()){ 193 | configParamsFileName = "../test_data/configParams.txt"; 194 | } 195 | #else 196 | if (fstFileName.empty()){ 197 | LOG_ERROR("FST waveform file not specified!"); 198 | return 1; 199 | } 200 | 201 | if (configParamsFileName.empty()){ 202 | LOG_ERROR(stderr, "Configuration parameter file not specified!"); 203 | return 1; 204 | } 205 | #endif 206 | 207 | ifstream configFile(configParamsFileName, ios::in); 208 | parseConfig(configFile, configParams); 209 | 210 | if (configParams.cpuClkSignal.empty()){ 211 | LOG_ERROR("CPU clock signal not specified!"); 212 | return 1; 213 | } 214 | 215 | if (configParams.retiredPcSignal.empty()){ 216 | LOG_ERROR("CPU program counter signal not specified!"); 217 | return 1; 218 | } 219 | 220 | if (configParams.retiredPcValidSignal.empty()){ 221 | LOG_ERROR("CPU program counter valid signal not specified!"); 222 | return 1; 223 | } 224 | 225 | FstProcess fstProc(fstFileName); 226 | LOG_INFO("%s", fstProc.infoStr().c_str()); 227 | 228 | FstSignal clkSig(configParams.cpuClkSignal); 229 | 230 | FstSignal retiredPcSig (configParams.retiredPcSignal); 231 | FstSignal retiredPcValidSig(configParams.retiredPcValidSignal); 232 | 233 | FstSignal regFileWriteValidSig(configParams.regFileWriteValidSignal); 234 | FstSignal regFileWriteAddrSig (configParams.regFileWriteAddrSignal); 235 | FstSignal regFileWriteDataSig (configParams.regFileWriteDataSignal); 236 | 237 | FstSignal memCmdValidSig (configParams.memCmdValidSignal); 238 | FstSignal memCmdReadySig (configParams.memCmdReadySignal); 239 | FstSignal memCmdAddrSig (configParams.memCmdAddrSignal); 240 | FstSignal memCmdSizeSig (configParams.memCmdSizeSignal); 241 | FstSignal memCmdWrSig (configParams.memCmdWrSignal); 242 | FstSignal memCmdWrDataSig (configParams.memCmdWrDataSignal); 243 | FstSignal memRspValidSig (configParams.memRspValidSignal); 244 | FstSignal memRspDataSig (configParams.memRspRdDataSignal); 245 | 246 | CpuTrace cpuTrace(fstProc, clkSig, retiredPcValidSig, retiredPcSig); 247 | RegFileTrace regFileTrace(fstProc, clkSig, regFileWriteValidSig, regFileWriteAddrSig, regFileWriteDataSig); 248 | MemTrace memTrace(fstProc, 249 | configParams.memInitFileName, configParams.memInitStartAddr, 250 | clkSig, 251 | memCmdValidSig, memCmdReadySig, memCmdAddrSig, memCmdSizeSig, memCmdWrSig, memCmdWrDataSig, 252 | memRspValidSig, memRspDataSig); 253 | 254 | TcpServer tcpServer(portNr); 255 | dbg_sys_init(tcpServer, cpuTrace, regFileTrace, memTrace); 256 | 257 | return 0; 258 | } 259 | -------------------------------------------------------------------------------- /test_data/configParams.txt: -------------------------------------------------------------------------------- 1 | cpuClk = TOP.top.u_vex.cpu.clk 2 | 3 | retiredPc = TOP.top.u_vex.cpu.lastStagePc 4 | retiredPcValid = TOP.top.u_vex.cpu.lastStageIsValid 5 | 6 | regFileWriteValid = TOP.top.u_vex.cpu.lastStageRegFileWrite_valid 7 | regFileWriteAddr = TOP.top.u_vex.cpu.lastStageRegFileWrite_payload_address 8 | regFileWriteData = TOP.top.u_vex.cpu.lastStageRegFileWrite_payload_data 9 | 10 | memCmdValid = TOP.top.dBus_cmd_valid 11 | memCmdReady = TOP.top.dBus_cmd_ready 12 | memCmdAddr = TOP.top.dBus_cmd_payload_address 13 | memCmdSize = TOP.top.dBus_cmd_payload_size 14 | memCmdWr = TOP.top.dBus_cmd_payload_wr 15 | memCmdWrData = TOP.top.dBus_cmd_payload_data 16 | memRspValid = TOP.top.dBus_rsp_ready 17 | memRspRdData = TOP.top.dBus_rsp_data 18 | 19 | memInitFile = ../test_data/progmem.bin 20 | memInitStartAddr = 0 21 | -------------------------------------------------------------------------------- /test_data/progmem.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomverbeure/gdbwave/fd59fbb80c731e62634d07647c089ec2f7a84d7d/test_data/progmem.bin -------------------------------------------------------------------------------- /test_data/progmem.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomverbeure/gdbwave/fd59fbb80c731e62634d07647c089ec2f7a84d7d/test_data/progmem.elf -------------------------------------------------------------------------------- /test_data/sw_semihosting/.gitignore: -------------------------------------------------------------------------------- 1 | progmem*.* 2 | *.o 3 | coefs.h 4 | openocd.log 5 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/Makefile: -------------------------------------------------------------------------------- 1 | 2 | # When you change the memory size below, make sure to also change it in: 3 | # 4 | # ./sw/sections.lds 5 | # ./sw/start.S 6 | # ./rtl/top.v 7 | 8 | MEM_WORDS = 1024 9 | MEM_BYTES = 4096 10 | 11 | MARCH = rv32ic 12 | CPU_FREQ_MHZ = 50 13 | CC_OPT = -Os 14 | 15 | OBJ_FILES = start.o main.o lib.o trap.o semihosting.o printf.o 16 | 17 | #OPENOCD_DIR ?= ~/tools/openocd_riscv 18 | #OPENOCD ?= $(OPENOCD_DIR)/src/openocd 19 | 20 | OPENOCD_DIR ?= /opt/openocd_vex 21 | OPENOCD ?= $(OPENOCD_DIR)/bin/openocd 22 | 23 | # Downloaded from https://github.com/sifive/freedom-tools/releases 24 | UNAME_S = $(shell uname -s) 25 | ifeq ($(UNAME_S),Linux) 26 | TOOLS_PREFIX = /opt/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin 27 | endif 28 | ifeq ($(UNAME_S),Darwin) 29 | TOOLS_PREFIX = /opt/riscv64-unknown-elf-gcc-10.1.0-2020.08.2-x86_64-apple-darwin/bin 30 | endif 31 | 32 | TARGET = $(TOOLS_PREFIX)/riscv64-unknown-elf 33 | 34 | DEFINES = -DCPU_FREQ=$(CPU_FREQ_MHZ)000000 35 | DEFINES += -DPRINTF_INCLUDE_CONFIG_H 36 | 37 | AS = $(TARGET)-as 38 | ASFLAGS = -march=$(MARCH) -mabi=ilp32 39 | LD = $(TARGET)-gcc 40 | LDFLAGS = -march=$(MARCH) -g -ggdb -mabi=ilp32 -Wl,-Tsections.lds,-Map,progmem.map -ffreestanding -nostartfiles -Wl,--no-relax -Wl,--start-group,--end-group 41 | CC = $(TARGET)-gcc 42 | CFLAGS = -march=$(MARCH) -g -ggdb -mno-div -mabi=ilp32 -ffunction-sections -fdata-sections -Wall -Wextra -pedantic $(DEFINES) $(CC_OPT) 43 | OBJCOPY = $(TARGET)-objcopy 44 | OBJDUMP = $(TARGET)-objdump 45 | READELF = $(TARGET)-readelf 46 | 47 | CREATE_MIF = ../misc/create_mif.rb 48 | 49 | .PHONY: all clean 50 | 51 | all: progmem.dis progmem.bin 52 | 53 | progmem.dis: progmem.elf 54 | $(OBJDUMP) -s -D $< > $@ 55 | 56 | progmem.bin: progmem.elf 57 | $(OBJCOPY) -O binary $< $@ 58 | 59 | progmem.elf: $(OBJ_FILES) top_defines.h sections.lds Makefile 60 | $(LD) $(LDFLAGS) -o $@ $(OBJ_FILES) -lm 61 | 62 | $(OBJ_FILES): top_defines.h riscv.h semihosting.h reg.h printf.h printf_config.h lib.h 63 | 64 | clean: 65 | \rm -fr *.o *.hex *.elf *.dis *.bin *.coe *.map *.mif *.mem *.funcs *.globs 66 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/lib.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "reg.h" 5 | #include "top_defines.h" 6 | #include "lib.h" 7 | 8 | static inline uint32_t internal_rdcycle(void) { 9 | uint32_t cycle; 10 | asm volatile ("rdcycle %0" : "=r"(cycle)); 11 | return cycle; 12 | } 13 | 14 | static inline uint32_t internal_rdcycleh(void) { 15 | uint32_t cycle; 16 | asm volatile ("rdcycleh %0" : "=r"(cycle)); 17 | return cycle; 18 | } 19 | 20 | uint64_t rdcycle64(void) { 21 | 22 | uint32_t msw; 23 | uint32_t lsw; 24 | 25 | do{ 26 | msw = internal_rdcycleh(); 27 | lsw = internal_rdcycle(); 28 | } while(msw != internal_rdcycleh()); 29 | 30 | return ((uint64_t)msw << 32) | lsw; 31 | } 32 | 33 | void wait_cycles(uint32_t cycles) 34 | { 35 | uint64_t start; 36 | 37 | start = rdcycle64(); 38 | while ((rdcycle64() - start) <= (uint64_t)cycles) {} 39 | } 40 | 41 | 42 | void wait_ms(uint32_t ms) 43 | { 44 | wait_cycles((uint32_t)CPU_FREQ / 1000UL * ms); 45 | } 46 | 47 | void wait_us(uint32_t us) 48 | { 49 | wait_cycles((uint32_t)CPU_FREQ / 1000000UL * us); 50 | } 51 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef LIB_H 2 | #define LIB_H 3 | 4 | uint64_t rdcycle64(void); 5 | void wait_cycles(uint32_t cycles); 6 | void wait_ms(uint32_t ms); 7 | void wait_us(uint32_t us); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "riscv.h" 6 | #include "reg.h" 7 | #include "top_defines.h" 8 | #include "lib.h" 9 | #include "semihosting.h" 10 | #include "printf.h" 11 | 12 | void wait_led_cycle(int ms) 13 | { 14 | if (REG_RD_FIELD(STATUS, SIMULATION) == 1){ 15 | // Wait for a much shorter time when simulation... 16 | wait_cycles(100); 17 | } 18 | else{ 19 | wait_ms(ms); 20 | } 21 | } 22 | 23 | int global_cntr = 0; 24 | 25 | int main() 26 | { 27 | REG_WR(LED_CONFIG, 0x07); 28 | wait_led_cycle(1000); 29 | REG_WR(LED_CONFIG, 0x00); 30 | 31 | printf("Hello World!\n"); 32 | 33 | while(1){ 34 | int wait_time = REG_RD_FIELD(STATUS, BUTTON) ? 200 : 100; 35 | sh_writec('.'); 36 | REG_WR(LED_CONFIG, 0x01); 37 | wait_led_cycle(wait_time); 38 | 39 | REG_WR(LED_CONFIG, 0x02); 40 | wait_led_cycle(wait_time); 41 | 42 | REG_WR(LED_CONFIG, 0x04); 43 | wait_led_cycle(wait_time); 44 | 45 | int c = getchar(); 46 | printf("char: %d", c); 47 | 48 | global_cntr++; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/printf.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // \author (c) Marco Paland (info@paland.com) 3 | // 2014-2019, PALANDesign Hannover, Germany 4 | // 5 | // \license The MIT License (MIT) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | // \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on 26 | // embedded systems with a very limited resources. 27 | // Use this instead of bloated standard/newlib printf. 28 | // These routines are thread safe and reentrant. 29 | // 30 | /////////////////////////////////////////////////////////////////////////////// 31 | 32 | #ifndef _PRINTF_H_ 33 | #define _PRINTF_H_ 34 | 35 | #include 36 | #include 37 | 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | 44 | /** 45 | * Output a character to a custom device like UART, used by the printf() function 46 | * This function is declared here only. You have to write your custom implementation somewhere 47 | * \param character Character to output 48 | */ 49 | void _putchar(char character); 50 | 51 | 52 | /** 53 | * Tiny printf implementation 54 | * You have to implement _putchar if you use printf() 55 | * To avoid conflicts with the regular printf() API it is overridden by macro defines 56 | * and internal underscore-appended functions like printf_() are used 57 | * \param format A string that specifies the format of the output 58 | * \return The number of characters that are written into the array, not counting the terminating null character 59 | */ 60 | #define printf printf_ 61 | int printf_(const char* format, ...); 62 | 63 | 64 | /** 65 | * Tiny sprintf implementation 66 | * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! 67 | * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! 68 | * \param format A string that specifies the format of the output 69 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character 70 | */ 71 | #define sprintf sprintf_ 72 | int sprintf_(char* buffer, const char* format, ...); 73 | 74 | 75 | /** 76 | * Tiny snprintf/vsnprintf implementation 77 | * \param buffer A pointer to the buffer where to store the formatted string 78 | * \param count The maximum number of characters to store in the buffer, including a terminating null character 79 | * \param format A string that specifies the format of the output 80 | * \param va A value identifying a variable arguments list 81 | * \return The number of characters that COULD have been written into the buffer, not counting the terminating 82 | * null character. A value equal or larger than count indicates truncation. Only when the returned value 83 | * is non-negative and less than count, the string has been completely written. 84 | */ 85 | #define snprintf snprintf_ 86 | #define vsnprintf vsnprintf_ 87 | int snprintf_(char* buffer, size_t count, const char* format, ...); 88 | int vsnprintf_(char* buffer, size_t count, const char* format, va_list va); 89 | 90 | 91 | /** 92 | * Tiny vprintf implementation 93 | * \param format A string that specifies the format of the output 94 | * \param va A value identifying a variable arguments list 95 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character 96 | */ 97 | #define vprintf vprintf_ 98 | int vprintf_(const char* format, va_list va); 99 | 100 | 101 | /** 102 | * printf with output function 103 | * You may use this as dynamic alternative to printf() with its fixed _putchar() output 104 | * \param out An output function which takes one character and an argument pointer 105 | * \param arg An argument pointer for user data passed to output function 106 | * \param format A string that specifies the format of the output 107 | * \return The number of characters that are sent to the output function, not counting the terminating null character 108 | */ 109 | int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); 110 | 111 | 112 | #ifdef __cplusplus 113 | } 114 | #endif 115 | 116 | 117 | #endif // _PRINTF_H_ 118 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/printf_config.h: -------------------------------------------------------------------------------- 1 | 2 | #define PRINTF_DISABLE_SUPPORT_FLOAT 3 | #define PRINTF_DISABLE_SUPPORT_EXPONENTIAL 4 | #define PRINTF_DISABLE_SUPPORT_LONG_LONG 5 | #define PRINTF_DISABLE_SUPPORT_PTRDIFF_T 6 | 7 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/reg.h: -------------------------------------------------------------------------------- 1 | #ifndef REG_H 2 | #define REG_H 3 | 4 | #define REG_WR(reg_name, wr_data) (*((volatile uint32_t *)(0x80000000 | reg_name##_ADDR)) = (wr_data)) 5 | #define REG_RD(reg_name) (*((volatile uint32_t *)(0x80000000 | reg_name##_ADDR))) 6 | 7 | #define FIELD_MASK(reg_name, field_name) ( ((1<<(reg_name##_##field_name##_FIELD_LENGTH))-1) << (reg_name##_##field_name##_FIELD_START)) 8 | 9 | #define REG_WR_FIELD(reg_name, field_name, wr_data) (*((volatile uint32_t *)(0x80000000 | reg_name##_ADDR)) = \ 10 | ((REG_RD(reg_name) \ 11 | & ~FIELD_MASK(reg_name, field_name)) \ 12 | | (((wr_data)<<(reg_name##_##field_name##_FIELD_START)) & FIELD_MASK(reg_name, field_name)))) 13 | 14 | #define REG_RD_FIELD(reg_name, field_name) ((REG_RD(reg_name) & FIELD_MASK(reg_name, field_name)) >> (reg_name##_##field_name##_FIELD_START)) 15 | 16 | #define MEM_WR(mem_name, wr_addr, wr_data) (*( (volatile uint32_t *)(0x80000000 | mem_name##_ADDR) + (wr_addr)) = (wr_data)) 17 | 18 | #define MEM_RD(mem_name, rd_addr) (*((volatile uint32_t *)((0x80000000 | mem_name##_ADDR) + ((rd_addr) << 2)))) 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/riscv.h: -------------------------------------------------------------------------------- 1 | #ifndef RISCV_H 2 | #define RISCV_H 3 | 4 | //exceptions 5 | #define CAUSE_ILLEGAL_INSTRUCTION 2 6 | #define CAUSE_MACHINE_TIMER 7 7 | #define CAUSE_SCALL 9 8 | 9 | //interrupts 10 | #define CAUSE_MACHINE_EXTERNAL 11 11 | 12 | 13 | #define MEDELEG_INSTRUCTION_PAGE_FAULT (1 << 12) 14 | #define MEDELEG_LOAD_PAGE_FAULT (1 << 13) 15 | #define MEDELEG_STORE_PAGE_FAULT (1 << 15) 16 | #define MEDELEG_USER_ENVIRONNEMENT_CALL (1 << 8) 17 | #define MIDELEG_SUPERVISOR_SOFTWARE (1 << 1) 18 | #define MIDELEG_SUPERVISOR_TIMER (1 << 5) 19 | #define MIDELEG_SUPERVISOR_EXTERNAL (1 << 9) 20 | 21 | #define MIP_STIP (1 << 5) 22 | #define MIE_MTIE (1 << CAUSE_MACHINE_TIMER) 23 | #define MIE_MEIE (1UL << CAUSE_MACHINE_EXTERNAL) 24 | 25 | #define MSTATUS_UIE 0x00000001UL 26 | #define MSTATUS_SIE 0x00000002UL 27 | #define MSTATUS_HIE 0x00000004UL 28 | #define MSTATUS_MIE 0x00000008UL 29 | #define MSTATUS_UPIE 0x00000010UL 30 | #define MSTATUS_SPIE 0x00000020UL 31 | #define MSTATUS_HPIE 0x00000040UL 32 | #define MSTATUS_MPIE 0x00000080UL 33 | #define MSTATUS_SPP 0x00000100UL 34 | #define MSTATUS_HPP 0x00000600UL 35 | #define MSTATUS_MPP 0x00001800UL 36 | #define MSTATUS_FS 0x00006000UL 37 | #define MSTATUS_XS 0x00018000UL 38 | #define MSTATUS_MPRV 0x00020000UL 39 | #define MSTATUS_SUM 0x00040000UL 40 | #define MSTATUS_MXR 0x00080000UL 41 | #define MSTATUS_TVM 0x00100000UL 42 | #define MSTATUS_TW 0x00200000UL 43 | #define MSTATUS_TSR 0x00400000UL 44 | #define MSTATUS32_SD 0x80000000UL 45 | #define MSTATUS_UXL 0x0000000300000000U 46 | #define MSTATUS_SXL 0x0000000C00000000U 47 | #define MSTATUS64_SD 0x8000000000000000U 48 | 49 | #define SSTATUS_UIE 0x00000001UL 50 | #define SSTATUS_SIE 0x00000002UL 51 | #define SSTATUS_UPIE 0x00000010UL 52 | #define SSTATUS_SPIE 0x00000020UL 53 | #define SSTATUS_SPP 0x00000100UL 54 | #define SSTATUS_FS 0x00006000UL 55 | #define SSTATUS_XS 0x00018000UL 56 | #define SSTATUS_SUM 0x00040000UL 57 | #define SSTATUS_MXR 0x00080000UL 58 | #define SSTATUS32_SD 0x80000000UL 59 | #define SSTATUS_UXL 0x0000000300000000U 60 | #define SSTATUS64_SD 0x8000000000000000U 61 | 62 | 63 | #define PMP_R 0x01 64 | #define PMP_W 0x02 65 | #define PMP_X 0x04 66 | #define PMP_A 0x18 67 | #define PMP_L 0x80 68 | #define PMP_SHIFT 2 69 | 70 | #define PMP_TOR 0x08 71 | #define PMP_NA4 0x10 72 | #define PMP_NAPOT 0x18 73 | 74 | #define MSCRATCH 0x340 75 | #define MCAUSE 0x342 76 | #define MEPC 0x341 77 | #define MEPC 0x341 78 | #define MTVAL 0x343 79 | 80 | #define RDCYCLE 0xC00 81 | #define RDTIME 0xC01 82 | #define RDINSTRET 0xC02 83 | #define RDCYCLEH 0xC80 84 | #define RDTIMEH 0xC81 85 | #define RDINSTRETH 0xC82 86 | 87 | 88 | #define csr_swap(csr, val) \ 89 | __extension__ ({ \ 90 | uint32_t __v = (uint32_t)(val); \ 91 | __asm__ __volatile__ ("csrrw %0, " #csr ", %1" \ 92 | : "=r" (__v) : "rK" (__v)); \ 93 | __v; \ 94 | }) 95 | 96 | #define csr_read(csr) \ 97 | __extension__ ({ \ 98 | uint32_t __v; \ 99 | __asm__ __volatile__ ("csrr %0, " #csr \ 100 | : "=r" (__v)); \ 101 | __v; \ 102 | }) 103 | 104 | #define csr_write(csr, val) \ 105 | { \ 106 | uint32_t __v = (uint32_t)(val); \ 107 | __asm__ __volatile__ ("csrw " #csr ", %0" \ 108 | : : "rK" (__v)); \ 109 | } 110 | 111 | #define csr_read_set(csr, val) \ 112 | __extension__ ({ \ 113 | uint32_t __v = (uint32_t)(val); \ 114 | __asm__ __volatile__ ("csrrs %0, " #csr ", %1" \ 115 | : "=r" (__v) : "rK" (__v)); \ 116 | __v; \ 117 | }) 118 | 119 | #define csr_set(csr, val) \ 120 | { \ 121 | uint32_t __v = (uint32_t)(val); \ 122 | __asm__ __volatile__ ("csrs " #csr ", %0" \ 123 | : : "rK" (__v)); \ 124 | } 125 | 126 | #define csr_read_clear(csr, val) \ 127 | __extension__ ({ \ 128 | uint32_t __v = (uint32_t)(val); \ 129 | __asm__ __volatile__ ("csrrc %0, " #csr ", %1" \ 130 | : "=r" (__v) : "rK" (__v)); \ 131 | __v; \ 132 | }) 133 | 134 | #define csr_clear(csr, val) \ 135 | { \ 136 | uint32_t __v = (uint32_t)(val); \ 137 | __asm__ __volatile__ ("csrc " #csr ", %0" \ 138 | : : "rK" (__v)); \ 139 | } 140 | 141 | 142 | 143 | #endif 144 | 145 | 146 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/sections.lds: -------------------------------------------------------------------------------- 1 | 2 | MEMORY 3 | { 4 | ram (ax) : ORIGIN = 0x00000000, LENGTH = 4K 5 | } 6 | 7 | SECTIONS 8 | { 9 | .text : 10 | { 11 | start.o(.text*) 12 | *(.text*) 13 | } > ram 14 | 15 | .rodata ALIGN(4) : 16 | { 17 | *(.rodata*) 18 | *(.srodata*) 19 | } > ram 20 | 21 | .data ALIGN (8) : 22 | { 23 | *(.data*) 24 | *(.sdata*) 25 | } > ram 26 | 27 | .bss ALIGN(8) (NOLOAD) : 28 | { 29 | *(.bss*) 30 | *(.sbss*) 31 | *(COMMON) 32 | } > ram 33 | 34 | _end = .; 35 | } 36 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/semihosting.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "printf.h" 5 | #include "semihosting.h" 6 | 7 | #define SEMIHOSTING_SYS_OPEN 0x01 8 | #define SEMIHOSTING_SYS_CLOSE 0x02 9 | #define SEMIHOSTING_SYS_WRITEC 0x03 10 | #define SEMIHOSTING_SYS_WRITE0 0x04 11 | #define SEMIHOSTING_SYS_WRITE 0x05 12 | #define SEMIHOSTING_SYS_READ 0x06 13 | #define SEMIHOSTING_SYS_READC 0x07 14 | #define SEMIHOSTING_SYS_ISERROR 0x08 15 | #define SEMIHOSTING_SYS_ISTTY 0x09 16 | #define SEMIHOSTING_SYS_SEEK 0x0A 17 | #define SEMIHOSTING_SYS_FLEN 0x0C 18 | #define SEMIHOSTING_SYS_TMPNAM 0x0D 19 | #define SEMIHOSTING_SYS_REMOVE 0x0E 20 | #define SEMIHOSTING_SYS_RENAME 0x0F 21 | #define SEMIHOSTING_SYS_CLOCK 0x10 22 | #define SEMIHOSTING_SYS_TIME 0x11 23 | #define SEMIHOSTING_SYS_SYSTEM 0x12 24 | #define SEMIHOSTING_SYS_ERRNO 0x13 25 | #define SEMIHOSTING_SYS_GET_CMDLINE 0x15 26 | #define SEMIHOSTING_SYS_HEAPINFO 0x16 27 | #define SEMIHOSTING_EnterSVC 0x17 28 | #define SEMIHOSTING_ReportException 0x18 29 | #define SEMIHOSTING_SYS_ELAPSED 0x30 30 | #define SEMIHOSTING_SYS_TICKFREQ 0x31 31 | 32 | #define OS_INTEGER_TRACE_TMP_ARRAY_SIZE 128 33 | 34 | #define RISCV_SEMIHOSTING_CALL_NUMBER 7 35 | 36 | 37 | static inline int __attribute__ ((always_inline)) call_host(int reason, void* arg) { 38 | #if 1 39 | register int value asm ("a0") = reason; 40 | register void* ptr asm ("a1") = arg; 41 | asm volatile ( 42 | // Workaround for RISC-V lack of multiple EBREAKs. 43 | " .option push \n" 44 | " .option norvc \n" 45 | // Force 16-byte alignment to make sure that the 3 instruction fall 46 | // within the same virtual page. If you the instruction straddle a page boundary 47 | // the debugger fetching the instructions could lead to a page fault. 48 | " .align 4 \n" 49 | " slli x0, x0, 0x1f \n" 50 | " ebreak \n" 51 | " srai x0, x0, %[swi] \n" 52 | " .option pop \n" 53 | 54 | : "=r" (value) /* Outputs */ 55 | : "0" (value), "r" (ptr), [swi] "i" (RISCV_SEMIHOSTING_CALL_NUMBER) /* Inputs */ 56 | : "memory" /* Clobbers */ 57 | ); 58 | return value; 59 | #else 60 | return 0; 61 | #endif 62 | } 63 | 64 | void sh_write0(const char* buf) 65 | { 66 | // send string 67 | call_host(SEMIHOSTING_SYS_WRITE0, (void*) buf); 68 | } 69 | 70 | void sh_writec(char c) 71 | { 72 | // send string 73 | call_host(SEMIHOSTING_SYS_WRITEC, (void*)&c); 74 | } 75 | 76 | char sh_readc(void) 77 | { 78 | return call_host(SEMIHOSTING_SYS_READC, (void*)NULL); 79 | } 80 | 81 | void _putchar(char character) 82 | { 83 | sh_writec(character); 84 | } 85 | 86 | int printf_(const char* format, ...) 87 | { 88 | char buffer[128]; 89 | 90 | va_list va; 91 | va_start(va, format); 92 | const int ret = vsnprintf(buffer, sizeof(buffer)-1, format, va); 93 | va_end(va); 94 | 95 | sh_write0(buffer); 96 | return ret; 97 | } 98 | 99 | int putchar(int c) 100 | { 101 | sh_writec((char)c); 102 | return c; 103 | } 104 | 105 | int getchar(void) 106 | { 107 | return (int)sh_readc(); 108 | } 109 | 110 | #if 0 111 | int fopen(const char *pathname, const char *mode) 112 | { 113 | } 114 | #endif 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/semihosting.h: -------------------------------------------------------------------------------- 1 | #ifndef SEMIHOSTING_H 2 | #define SEMIHOSTING_H 3 | 4 | //int32_t trace_write(const char* buf, uint32_t nbyte); 5 | 6 | void sh_write0(const char* buf); 7 | void sh_writec(char c); 8 | char sh_readc(void); 9 | 10 | int getchar(void); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/start.S: -------------------------------------------------------------------------------- 1 | .section .text 2 | .global _start 3 | .global main 4 | 5 | .org 0x00000000 6 | _start: 7 | j _start_continue 8 | 9 | .org 0x00000020 10 | _trap: 11 | addi sp, sp, -32*4 12 | 13 | sw x1, 1*4(sp) 14 | sw x2, 2*4(sp) 15 | sw x3, 3*4(sp) 16 | sw x4, 4*4(sp) 17 | sw x5, 5*4(sp) 18 | sw x6, 6*4(sp) 19 | sw x7, 7*4(sp) 20 | sw x8, 8*4(sp) 21 | sw x9, 9*4(sp) 22 | sw x10, 10*4(sp) 23 | sw x11, 11*4(sp) 24 | sw x12, 12*4(sp) 25 | sw x13, 13*4(sp) 26 | sw x14, 14*4(sp) 27 | sw x15, 15*4(sp) 28 | sw x16, 16*4(sp) 29 | sw x17, 17*4(sp) 30 | sw x18, 18*4(sp) 31 | sw x19, 19*4(sp) 32 | sw x20, 20*4(sp) 33 | sw x21, 21*4(sp) 34 | sw x22, 22*4(sp) 35 | sw x23, 23*4(sp) 36 | sw x24, 24*4(sp) 37 | sw x25, 25*4(sp) 38 | sw x26, 26*4(sp) 39 | sw x27, 27*4(sp) 40 | sw x28, 28*4(sp) 41 | sw x29, 29*4(sp) 42 | sw x30, 30*4(sp) 43 | sw x31, 31*4(sp) 44 | 45 | call trap 46 | 47 | /* Restore full register state */ 48 | lw x1, 1*4(sp) 49 | lw x2, 2*4(sp) 50 | lw x3, 3*4(sp) 51 | lw x4, 4*4(sp) 52 | lw x5, 5*4(sp) 53 | lw x6, 6*4(sp) 54 | lw x7, 7*4(sp) 55 | lw x8, 8*4(sp) 56 | lw x9, 9*4(sp) 57 | lw x10, 10*4(sp) 58 | lw x11, 11*4(sp) 59 | lw x12, 12*4(sp) 60 | lw x13, 13*4(sp) 61 | lw x14, 14*4(sp) 62 | lw x15, 15*4(sp) 63 | lw x16, 16*4(sp) 64 | lw x17, 17*4(sp) 65 | lw x18, 18*4(sp) 66 | lw x19, 19*4(sp) 67 | lw x20, 20*4(sp) 68 | lw x21, 21*4(sp) 69 | lw x22, 22*4(sp) 70 | lw x23, 23*4(sp) 71 | lw x24, 24*4(sp) 72 | lw x25, 25*4(sp) 73 | lw x26, 26*4(sp) 74 | lw x27, 27*4(sp) 75 | lw x28, 28*4(sp) 76 | lw x29, 29*4(sp) 77 | lw x30, 30*4(sp) 78 | lw x31, 31*4(sp) 79 | 80 | addi sp, sp, 32*4 81 | 82 | mret 83 | 84 | _start_continue: 85 | /* set stack pointer */ 86 | li sp,4096 87 | 88 | /* jump to main C code */ 89 | jal ra,main 90 | 91 | /* trap */ 92 | ebreak 93 | 94 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/top_defines.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TOP_DEFINES_H 3 | #define TOP_DEFINES_H 4 | 5 | //============================================================ 6 | // LED 7 | //============================================================ 8 | 9 | #define LED_CONFIG_ADDR 0x00000000 10 | 11 | #define LED_CONFIG_VALUE_FIELD_START 0 12 | #define LED_CONFIG_VALUE_FIELD_LENGTH 3 13 | 14 | //============================================================ 15 | // STATUS 16 | //============================================================ 17 | 18 | #define STATUS_ADDR 0x00000004 19 | 20 | #define STATUS_BUTTON_FIELD_START 0 21 | #define STATUS_BUTTON_FIELD_LENGTH 1 22 | 23 | #define STATUS_SIMULATION_FIELD_START 1 24 | #define STATUS_SIMULATION_FIELD_LENGTH 1 25 | 26 | #endif 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /test_data/sw_semihosting/trap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "riscv.h" 6 | #include "reg.h" 7 | #include "top_defines.h" 8 | #include "lib.h" 9 | 10 | int exception_addr; 11 | int exception_instr; 12 | int exception_cause; 13 | 14 | #define EBREAK_OPCODE 0x00100073 15 | #define EBREAK_MCAUSE 0x00000003 16 | 17 | // This should not be called by anything unless something goes very bad... 18 | void trap() 19 | { 20 | static int trap_induced_ebreak = 0; 21 | 22 | int mepc = csr_read(mepc); // Address of trap 23 | int mtval = csr_read(mtval); // Instruction value of trap 24 | int mcause = csr_read(mcause); // Reason for the trap 25 | 26 | // Grab trap exception status registers and store them in some global 27 | // variables for each access by debugger. 28 | if (!trap_induced_ebreak){ 29 | exception_addr = mepc; 30 | exception_instr = mtval; 31 | exception_cause = mcause; 32 | 33 | if (mcause == EBREAK_MCAUSE && mtval == EBREAK_OPCODE){ 34 | // This trap was triggered by an EBREAK instruction that 35 | // was NOT the one futher below in this trap handler. 36 | 37 | // There 2 common reasons for an EBREAK instruction: 38 | // 39 | // * the EBREAK was created by GDB to serve as a soft breakpoint. 40 | // The CPU will halt, because it will always halt on EBREAK when openocd has been 41 | // connected to the CPU. However, in such a case, this code should never have 42 | // been reached. 43 | // 44 | // * the EBREAK was part of the semihosting call. (See semihosting.c) 45 | // When a debugger is connected, this will once again result in a CPU halt, 46 | // OpenOCD will service the semihosting call, and, just like for a soft breakpoing, 47 | // OpenOCD will set the PC to whichever value is necessary. 48 | // The instruction below will, again, not be executed. 49 | // 50 | // HOWEVER, if the semihosting function is called when no debugger was ever attached, 51 | // then this trap will be called. The best course of action, then, is 52 | // to simply return from the trap and let the semihosting function continue to 53 | // prevent the CPU from hanging in the trap handler. This way, you can test the 54 | // firmware that runs on the VexRiscv without debugger attached, but with semihosting 55 | // calls active. 56 | csr_write(mepc, mepc+4); 57 | return; 58 | } 59 | } 60 | 61 | // Insert an EBREAK instruction so that the CPU will halt, and a connected debugger 62 | // will report the halt to the user. 63 | // However, only do this once, because when a debugger isn't connected, you get 64 | // an endless cascade of EBREAKs which will ultimately crash the stack. 65 | if (!trap_induced_ebreak){ 66 | trap_induced_ebreak = 1; 67 | asm volatile ( 68 | "ebreak\n" 69 | ); 70 | } 71 | 72 | // Add endless loop so that we stay in the trap function after the first EBREAK, or when 73 | // the VexRiscv has been configured without EBREAK instruction support. 74 | while(1) 75 | ; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /test_data/top.fst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomverbeure/gdbwave/fd59fbb80c731e62634d07647c089ec2f7a84d7d/test_data/top.fst -------------------------------------------------------------------------------- /test_data/top.fst.hier: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomverbeure/gdbwave/fd59fbb80c731e62634d07647c089ec2f7a84d7d/test_data/top.fst.hier -------------------------------------------------------------------------------- /test_data/waves.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Sun Dec 26 07:14:44 2021 4 | [*] 5 | [dumpfile] "/home/tom/projects/gdbwave/test_data/top.fst" 6 | [dumpfile_mtime] "Mon Nov 29 06:35:46 2021" 7 | [dumpfile_size] 2135906 8 | [savefile] "/home/tom/projects/gdbwave/test_data/waves.gtkw" 9 | [timestart] 0 10 | [size] 2096 1374 11 | [pos] 91 49 12 | *-31.907537 1023000 662247742 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [markername] Abreakpoint 14 | [treeopen] TOP. 15 | [treeopen] TOP.top.u_vex. 16 | [sst_width] 495 17 | [signals_width] 464 18 | [sst_expanded] 1 19 | [sst_vpaned_height] 414 20 | @28 21 | TOP.top.u_vex.cpu.clk 22 | @200 23 | - 24 | @28 25 | TOP.top.led0 26 | TOP.top.led1 27 | TOP.top.led2 28 | @200 29 | - 30 | @28 31 | TOP.top.iBus_cmd_valid 32 | TOP.top.iBus_cmd_ready 33 | @22 34 | TOP.top.iBus_cmd_payload_pc[31:0] 35 | @8022 36 | TOP.top.iBus_cmd_payload_pc[31:0] 37 | @20000 38 | - 39 | - 40 | @28 41 | TOP.top.iBus_rsp_valid 42 | @22 43 | TOP.top.iBus_rsp_payload_inst[31:0] 44 | @200 45 | - 46 | @28 47 | TOP.top.u_vex.cpu.lastStageIsValid 48 | @22 49 | TOP.top.u_vex.cpu.lastStagePc[31:0] 50 | @200 51 | - 52 | @22 53 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[0][31:0] 54 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[1][31:0] 55 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[2][31:0] 56 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[3][31:0] 57 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[4][31:0] 58 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[5][31:0] 59 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[6][31:0] 60 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[7][31:0] 61 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[8][31:0] 62 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[9][31:0] 63 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[10][31:0] 64 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[11][31:0] 65 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[12][31:0] 66 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[13][31:0] 67 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[14][31:0] 68 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[15][31:0] 69 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[16][31:0] 70 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[17][31:0] 71 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[18][31:0] 72 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[19][31:0] 73 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[20][31:0] 74 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[21][31:0] 75 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[22][31:0] 76 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[23][31:0] 77 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[24][31:0] 78 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[25][31:0] 79 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[26][31:0] 80 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[27][31:0] 81 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[28][31:0] 82 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[29][31:0] 83 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[30][31:0] 84 | TOP.top.u_vex.cpu.RegFilePlugin_regFile[31][31:0] 85 | @200 86 | - 87 | @28 88 | TOP.top.u_vex.cpu.lastStageRegFileWrite_valid 89 | @22 90 | TOP.top.u_vex.cpu.lastStageRegFileWrite_payload_address[4:0] 91 | TOP.top.u_vex.cpu.lastStageRegFileWrite_payload_data[31:0] 92 | @201 93 | - 94 | @22 95 | TOP.top.dBus_cmd_payload_address[31:0] 96 | TOP.top.dBus_cmd_payload_data[31:0] 97 | @28 98 | TOP.top.dBus_cmd_payload_size[1:0] 99 | TOP.top.dBus_cmd_payload_wr 100 | TOP.top.dBus_cmd_ready 101 | TOP.top.dBus_cmd_valid 102 | @22 103 | TOP.top.dBus_rsp_data[31:0] 104 | @28 105 | TOP.top.dBus_rsp_error 106 | TOP.top.dBus_rsp_ready 107 | @22 108 | TOP.top.dBus_wdata[31:0] 109 | [pattern_trace] 1 110 | [pattern_trace] 0 111 | -------------------------------------------------------------------------------- /various.md: -------------------------------------------------------------------------------- 1 | 2 | Just a bunch of notes that I took along the way... 3 | 4 | # FST 5 | 6 | * Info about FST: 7 | 8 | * [fstminer.c](https://github.com/gtkwave/gtkwave/blob/master/gtkwave3-gtk3/src/helpers/fstminer.c) 9 | * [fst.c](https://github.com/gtkwave/gtkwave/blob/master/gtkwave3-gtk3/src/fst.c) 10 | 11 | # FST questions 12 | 13 | * No support for vector with LSB that is not 0? 14 | 15 | * What does "fac" stand for? 16 | 17 | facility? 18 | 19 | `num_facs = fstReaderGetVarCount(ctx);` 20 | 21 | * what is `doubleEndianMatchState`? 22 | 23 | * what is `valudChangeSectionCount`? 24 | 25 | How do I use it? 26 | 27 | * what is a dumpActivityChange? 28 | 29 | Does it have to do with times where values are not recorded? 30 | 31 | * `fstReaderIterateHier` goes through the whole signal hierarchy? 32 | 33 | Why is GTKWave going through the whole hierarchy for each signal? 34 | 35 | * What is an alias? 36 | 37 | Signals in a design that have identical values. Signals that are aliases have the same 38 | fstHandle. 39 | 40 | For example, for the following design, `io_occupancy`, `full`, `when_Stream_l1017`, and 41 | `IBusSimplePlugin_rspJoin_rspBuffer_c_io_occupancy` are all aliases. 42 | 43 | ```verilog 44 | module StreamFifoLowLatency ( 45 | ... 46 | output [0:0] io_occupancy, 47 | ... 48 | ); 49 | 50 | ... 51 | assign ptrMatch = 1'b1; 52 | assign io_occupancy = (risingOccupancy && ptrMatch); 53 | ... 54 | assign full = (ptrMatch && risingOccupancy); 55 | assign empty = (ptrMatch && (! risingOccupancy)); 56 | assign when_Stream_l1017 = (! empty); 57 | endmodule 58 | 59 | ... 60 | 61 | StreamFifoLowLatency IBusSimplePlugin_rspJoin_rspBuffer_c ( 62 | ... 63 | .io_occupancy (IBusSimplePlugin_rspJoin_rspBuffer_c_io_occupancy ), //o 64 | ... 65 | ); 66 | 67 | ``` 68 | 69 | * GTKWave code scans for '[' in the signal names, but signal names only have this 70 | when the signal is an array of values. IOW: the signal name does not contain an individual bit selector. 71 | 72 | 73 | * `fstReaderSetFacProcessMask`, `fstReaderClrFacProcessMask` 74 | 75 | What do they do? 76 | 77 | `fstReaderClrFacProcessMask(fstCtx, fstHandle);` : remove signal from those that are returned by fstReaderIterBlocks2? 78 | 79 | ``` 80 | void fstReaderSetFacProcessMaskAll(void *ctx); 81 | void fstReaderClrFacProcessMaskAll(void *ctx); 82 | 83 | void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx); 84 | void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx); 85 | int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx); 86 | ``` 87 | 88 | 89 | 90 | * difference between `value_change_callback` and `value_change_callback_varlen` ? 91 | 92 | I never see a callback with a len that is not 0? 93 | 94 | 95 | * Probing VexRiscv PC: 96 | 97 | > Here is how the verilator testbench track the commited state of the CPU : 98 | > https://github.com/SpinalHDL/VexRiscv/blob/master/src/test/cpp/regression/main.cpp#L1778 99 | > https://github.com/SpinalHDL/VexRiscv/blob/master/src/test/cpp/regression/main.cpp#L1793 100 | > https://github.com/SpinalHDL/VexRiscv/blob/master/src/test/cpp/regression/main.cpp#L1803 101 | > lastStagexxxxx is the way ^^ 102 | > It was made for that purpose 103 | 104 | * Hazard3 OpenOCD remote_bitbang server 105 | 106 | https://github.com/Wren6991/Hazard3/blob/c1f17b0b23d7e1a52241663bfb53568c89440f2d/test/sim/openocd/tb.cpp#L91g 107 | 108 | * GDB packets: https://sourceware.org/gdb/current/onlinedocs/gdb/Packets.html#Packets 109 | 110 | * RISC-V GDB register description: 111 | 112 | * https://github.com/bminor/binutils-gdb/blob/master/gdb/features/riscv/32bit-cpu.xml 113 | * (derived) https://github.com/bminor/binutils-gdb/blob/master/gdb/features/riscv/32bit-cpu.c 114 | 115 | 116 | * gdbstub 117 | 118 | ``` 119 | demo.c:_start 120 | demo.c:dbg_start() 121 | arch_x86/gdbstub_sys: dbg_start(void) 122 | - setup interrupt handlers to dbg_int_handlers(1 and 3) 123 | - issue interrupt to start debugging 124 | arch_x86/gdbstub_int.nasm:dbg_int_handlers: 125 | -> dbg_int_handler_common: 126 | - save registers 127 | - call dbg_int_handler() 128 | 129 | arch_x86/gdbstub_sys.c: void dbg_int_handler(struct dbg_interrupt_state *istate) 130 | arch_x86/gdbstub_sys.c: void dbg_interrupt(struct dbg_interrupt_state *istate) 131 | - memset dbg_state.registers 132 | - set correct signum 133 | - copy istate to dbg_state.registers 134 | - dbg_main(dbg_state) 135 | gdbstub.cc: int dbg_main(struct dbg_state *state) 136 | dbg_send_signal_packet(pkt_buf.., state->signum) 137 | This sends a "S AA" response (See E.3 Stop Reply Packets), where AA is the 138 | signum. 139 | wihle(1){ 140 | receive packet from client 141 | process packet 142 | } 143 | - restore istate from dbg_state.registers 144 | 145 | 146 | ``` 147 | 148 | * [`radare2`](https://github.com/radareorg/radare2) reverse engineering tool 149 | 150 | * See also: https://rada.re/n/radare2.html 151 | 152 | **TODO/Limitations** 153 | 154 | * Improved error messages for config file 155 | * Fix 'next' issue 156 | * Link with GTKWave 157 | * Support superscalar CPUs 158 | * Load ELF files directly 159 | * Support complex memory maps 160 | * Decode register file and memory reads 161 | * Support for RISC-V instruction tracing decompression 162 | 163 | --------------------------------------------------------------------------------