Compare commits
	
		
			7 Commits
		
	
	
		
			58fb815f32
			...
			37db31fb4b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 37db31fb4b | |||
| e2da306eee | |||
| 41051f8f34 | |||
| 2a7449fa1e | |||
|   | a6c48ceaac | ||
| 1e30b68507 | |||
|   | ed793471bb | 
| @@ -1,4 +1,4 @@ | |||||||
| cmake_minimum_required(VERSION 3.12) | cmake_minimum_required(VERSION 3.18) | ||||||
| list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) | ||||||
|  |  | ||||||
| # ############################################################################## | # ############################################################################## | ||||||
|   | |||||||
| @@ -373,7 +373,7 @@ volatile std::array<bool, 2> dummy = { | |||||||
| 		    auto vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false); | 		    auto vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false); | ||||||
| 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | ||||||
|             if(init_data){ |             if(init_data){ | ||||||
|                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t)>*>(init_data); |                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*)>*>(init_data); | ||||||
|                 cpu->set_semihosting_callback(*cb); |                 cpu->set_semihosting_callback(*cb); | ||||||
|             } |             } | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{vm}}; |             return {cpu_ptr{cpu}, vm_ptr{vm}}; | ||||||
| @@ -383,7 +383,7 @@ volatile std::array<bool, 2> dummy = { | |||||||
| 		    auto vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false); | 		    auto vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false); | ||||||
| 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | ||||||
|             if(init_data){ |             if(init_data){ | ||||||
|                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t)>*>(init_data); |                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*)>*>(init_data); | ||||||
|                 cpu->set_semihosting_callback(*cb); |                 cpu->set_semihosting_callback(*cb); | ||||||
|             } |             } | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{vm}}; |             return {cpu_ptr{cpu}, vm_ptr{vm}}; | ||||||
|   | |||||||
| @@ -293,7 +293,7 @@ public: | |||||||
|  |  | ||||||
|     void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); } |     void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); } | ||||||
|  |  | ||||||
|     void set_semihosting_callback(std::function<void(arch_if*, reg_t, reg_t)>& cb) { semihosting_cb = cb; }; |     void set_semihosting_callback(semihosting_cb_t<reg_t> cb) { semihosting_cb = cb; }; | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|     struct riscv_instrumentation_if : public iss::instrumentation_if { |     struct riscv_instrumentation_if : public iss::instrumentation_if { | ||||||
| @@ -354,7 +354,7 @@ protected: | |||||||
|     bool tohost_lower_written = false; |     bool tohost_lower_written = false; | ||||||
|     riscv_instrumentation_if instr_if; |     riscv_instrumentation_if instr_if; | ||||||
|  |  | ||||||
|     std::function<void(arch_if*, reg_t, reg_t)> semihosting_cb; |     semihosting_cb_t<reg_t> semihosting_cb; | ||||||
|  |  | ||||||
|     using mem_type = util::sparse_array<uint8_t, 1ULL << 32>; |     using mem_type = util::sparse_array<uint8_t, 1ULL << 32>; | ||||||
|     using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>; |     using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>; | ||||||
| @@ -1125,9 +1125,6 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le | |||||||
|                         } |                         } | ||||||
|                         this->reg.trap_state = std::numeric_limits<uint32_t>::max(); |                         this->reg.trap_state = std::numeric_limits<uint32_t>::max(); | ||||||
|                         this->interrupt_sim = hostvar; |                         this->interrupt_sim = hostvar; | ||||||
| #ifndef WITH_TCC |  | ||||||
|                         // throw(iss::simulation_stopped(hostvar)); |  | ||||||
| #endif |  | ||||||
|                         break; |                         break; | ||||||
|                     case 0x0101: { |                     case 0x0101: { | ||||||
|                         char c = static_cast<char>(hostvar & 0xff); |                         char c = static_cast<char>(hostvar & 0xff); | ||||||
| @@ -1272,7 +1269,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e | |||||||
| #endif | #endif | ||||||
|                     CLOG(INFO, disass) << "Semihosting call at address " << buffer.data() << " occurred "; |                     CLOG(INFO, disass) << "Semihosting call at address " << buffer.data() << " occurred "; | ||||||
|  |  | ||||||
|                     semihosting_callback(this, this->reg.X10 /*a0*/, this->reg.X11 /*a1*/); |                     semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/); | ||||||
|                     return this->reg.NEXT_PC; |                     return this->reg.NEXT_PC; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -319,7 +319,7 @@ public: | |||||||
|  |  | ||||||
|     void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); } |     void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); } | ||||||
|  |  | ||||||
|     void set_semihosting_callback(std::function<void(arch_if*, reg_t, reg_t)>& cb) { semihosting_cb = cb; }; |     void set_semihosting_callback(semihosting_cb_t<reg_t> cb) { semihosting_cb = cb; }; | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|     struct riscv_instrumentation_if : public iss::instrumentation_if { |     struct riscv_instrumentation_if : public iss::instrumentation_if { | ||||||
| @@ -380,7 +380,7 @@ protected: | |||||||
|     bool tohost_lower_written = false; |     bool tohost_lower_written = false; | ||||||
|     riscv_instrumentation_if instr_if; |     riscv_instrumentation_if instr_if; | ||||||
|  |  | ||||||
|     std::function<void(arch_if*, reg_t, reg_t)> semihosting_cb; |     semihosting_cb_t<reg_t>  semihosting_cb; | ||||||
|  |  | ||||||
|     using mem_type = util::sparse_array<uint8_t, 1ULL << 32>; |     using mem_type = util::sparse_array<uint8_t, 1ULL << 32>; | ||||||
|     using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>; |     using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>; | ||||||
| @@ -1507,7 +1507,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>:: | |||||||
| #endif | #endif | ||||||
|                     CLOG(INFO, disass) << "Semihosting call at address " << buffer.data() << " occurred "; |                     CLOG(INFO, disass) << "Semihosting call at address " << buffer.data() << " occurred "; | ||||||
|  |  | ||||||
|                     semihosting_callback(this, this->reg.X10 /*a0*/, this->reg.X11 /*a1*/); |                     semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/); | ||||||
|                     return this->reg.NEXT_PC; |                     return this->reg.NEXT_PC; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -1,16 +1,61 @@ | |||||||
| #include "semihosting.h" | #include "semihosting.h" | ||||||
| #include <cstdint> | #include <cstdint> | ||||||
|  | #include <map> | ||||||
| #include <iss/vm_types.h> | #include <iss/vm_types.h> | ||||||
| #include <stdexcept> | #include <stdexcept> | ||||||
|  | #include <chrono> | ||||||
| // explanation of syscalls can be found at https://github.com/SpinalHDL/openocd_riscv/blob/riscv_spinal/src/target/semihosting_common.h | // explanation of syscalls can be found at https://github.com/SpinalHDL/openocd_riscv/blob/riscv_spinal/src/target/semihosting_common.h | ||||||
| template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T call_number, T parameter) { |  | ||||||
|     switch(static_cast<semihosting_syscalls>(call_number)) { | const char *SYS_OPEN_MODES_STRS[] = { "r", "rb", "r+", "r+b", "w", "wb", "w+", "w+b", "a", "ab", "a+", "a+b" }; | ||||||
|  |  | ||||||
|  | template <typename T> T sh_read_field(iss::arch_if* arch_if_ptr, T addr, int len=4) { | ||||||
|  |     uint8_t bytes[4]; | ||||||
|  |     auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, addr, 4, &bytes[0]); | ||||||
|  |     //auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character); | ||||||
|  |  | ||||||
|  |     if(res != iss::Ok){ | ||||||
|  |         return 0; //TODO THROW ERROR | ||||||
|  |     } else return static_cast<T>(bytes[0]) | (static_cast<T>(bytes[1]) << 8) | (static_cast<T>(bytes[2]) << 16) | (static_cast<T>(bytes[3]) << 24); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename T> std::string sh_read_string(iss::arch_if* arch_if_ptr, T addr, T str_len){ | ||||||
|  |     std::vector<uint8_t> buffer(str_len); | ||||||
|  |     for (int i = 0; i < str_len; i++ ) { | ||||||
|  |         buffer[i] = sh_read_field(arch_if_ptr, addr + i, 1); | ||||||
|  |     } | ||||||
|  |     std::string str(buffer.begin(), buffer.end()); | ||||||
|  |     return str; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template <typename T> void semihosting_callback<T>::operator()(iss::arch_if* arch_if_ptr, T* call_number, T* parameter) { | ||||||
|  |     static std::map<T, FILE *> openFiles; | ||||||
|  |     static T file_count = 3; | ||||||
|  |     static T semihostingErrno; | ||||||
|  |  | ||||||
|  |     switch(static_cast<semihosting_syscalls>(*call_number)) { | ||||||
|     case semihosting_syscalls::SYS_CLOCK: { |     case semihosting_syscalls::SYS_CLOCK: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         auto end = std::chrono::high_resolution_clock::now(); // end measurement  | ||||||
|  |         auto elapsed = end - timeVar; | ||||||
|  |         auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); | ||||||
|  |         *call_number = millis; //TODO get time now | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_CLOSE: { |     case semihosting_syscalls::SYS_CLOSE: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         T file_handle = *parameter; | ||||||
|  |         if (openFiles.size() <= file_handle && file_handle < 0) { | ||||||
|  |             semihostingErrno = EBADF; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         auto file = openFiles[file_handle]; | ||||||
|  |         openFiles.erase(file_handle); | ||||||
|  |         if (!(file == stdin || file == stdout || file == stderr)) { | ||||||
|  |             int i = fclose(file); | ||||||
|  |             *call_number = i; | ||||||
|  |         } else { | ||||||
|  |             *call_number = -1; | ||||||
|  |             semihostingErrno = EINTR; | ||||||
|  |         } | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_ELAPSED: { |     case semihosting_syscalls::SYS_ELAPSED: { | ||||||
| @@ -18,7 +63,7 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal | |||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_ERRNO: { |     case semihosting_syscalls::SYS_ERRNO: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         *call_number = semihostingErrno; | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_EXIT: { |     case semihosting_syscalls::SYS_EXIT: { | ||||||
| @@ -31,7 +76,15 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal | |||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_FLEN: { |     case semihosting_syscalls::SYS_FLEN: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         T file_handle = *parameter; | ||||||
|  |         auto file = openFiles[file_handle]; | ||||||
|  |  | ||||||
|  |         size_t currentPos = ftell(file); | ||||||
|  |         if (currentPos < 0) throw std::runtime_error("SYS_FLEN negative value"); | ||||||
|  |         fseek(file, 0, SEEK_END); | ||||||
|  |         size_t length = ftell(file); | ||||||
|  |         fseek(file, currentPos, SEEK_SET); | ||||||
|  |         *call_number = (T)length; | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_GET_CMDLINE: { |     case semihosting_syscalls::SYS_GET_CMDLINE: { | ||||||
| @@ -43,39 +96,127 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal | |||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_ISERROR: { |     case semihosting_syscalls::SYS_ISERROR: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         T value = *parameter; | ||||||
|  |         *call_number = (value != 0); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_ISTTY: { |     case semihosting_syscalls::SYS_ISTTY: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         T file_handle = *parameter;        | ||||||
|  |         *call_number = (file_handle == 0 || file_handle == 1 || file_handle == 2); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_OPEN: { |     case semihosting_syscalls::SYS_OPEN: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         T path_str_addr = sh_read_field<T>(arch_if_ptr, *parameter); | ||||||
|  |         T mode = sh_read_field<T>(arch_if_ptr, 4+(*parameter)); | ||||||
|  |         T path_len = sh_read_field<T>(arch_if_ptr, 8+(*parameter)); | ||||||
|  |  | ||||||
|  |         std::string path_str = sh_read_string<T>(arch_if_ptr, path_str_addr, path_len); | ||||||
|  |  | ||||||
|  |         //TODO LOG INFO | ||||||
|  |  | ||||||
|  |         if (mode >= 12) { | ||||||
|  |             //TODO throw ERROR | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         FILE *file = nullptr; | ||||||
|  |         if(path_str == ":tt") { | ||||||
|  |             if (mode < 4) | ||||||
|  |                 file = stdin; | ||||||
|  |             else if (mode < 8)  | ||||||
|  |                 file = stdout; | ||||||
|  |             else  | ||||||
|  |                 file = stderr; | ||||||
|  |         } else { | ||||||
|  |             file = fopen(path_str.c_str(), SYS_OPEN_MODES_STRS[mode]); | ||||||
|  |             if (file == nullptr) { | ||||||
|  |                 //TODO throw error | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         T file_handle = file_count++; | ||||||
|  |         openFiles[file_handle] = file; | ||||||
|  |         *call_number = file_handle; | ||||||
|         break; |         break; | ||||||
|  |  | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_READ: { |     case semihosting_syscalls::SYS_READ: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         T file_handle = sh_read_field<T>(arch_if_ptr, (*parameter)+4); | ||||||
|  |         T addr = sh_read_field<T>(arch_if_ptr, *parameter); | ||||||
|  |         T count = sh_read_field<T>(arch_if_ptr, (*parameter)+8); | ||||||
|  |  | ||||||
|  |         auto file = openFiles[file_handle]; | ||||||
|  |  | ||||||
|  |         std::vector<uint8_t> buffer(count); | ||||||
|  |         size_t num_read = 0; | ||||||
|  |         if (file == stdin) | ||||||
|  |         { | ||||||
|  |             // when reading from stdin: mimic behaviour from read syscall | ||||||
|  |             // and return on newline. | ||||||
|  |             while (num_read < count) | ||||||
|  |             { | ||||||
|  |                 char c = fgetc(file); | ||||||
|  |                 buffer[num_read] = c; | ||||||
|  |                 num_read++; | ||||||
|  |                 if (c == '\n') | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             num_read = fread(buffer.data(), 1, count, file); | ||||||
|  |         } | ||||||
|  |         buffer.resize(num_read); | ||||||
|  |         for(int i  = 0; i<num_read; i++) { | ||||||
|  |             auto res = arch_if_ptr->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, addr+i, 1, &buffer[i]); | ||||||
|  |             if(res != iss::Ok) | ||||||
|  |                 return; | ||||||
|  |         } | ||||||
|  |         *call_number = count - num_read; | ||||||
|         break; |         break; | ||||||
|  |  | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_READC: { |     case semihosting_syscalls::SYS_READC: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         uint8_t character = getchar(); | ||||||
|  |         //character = getchar(); | ||||||
|  |         /*if(character != iss::Ok) | ||||||
|  |             std::cout << "Not OK"; | ||||||
|  |             return;*/ | ||||||
|  |         *call_number = character; | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_REMOVE: { |     case semihosting_syscalls::SYS_REMOVE: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         T path_str_addr = sh_read_field<T>(arch_if_ptr, *parameter); | ||||||
|  |         T path_len = sh_read_field<T>(arch_if_ptr, (*parameter)+4); | ||||||
|  |         std::string path_str = sh_read_string<T>(arch_if_ptr, path_str_addr, path_len); | ||||||
|  |  | ||||||
|  |         if(remove(path_str.c_str())<0) *call_number = -1; | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_RENAME: { |     case semihosting_syscalls::SYS_RENAME: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         T path_str_addr_old = sh_read_field<T>(arch_if_ptr, *parameter); | ||||||
|  |         T path_len_old = sh_read_field<T>(arch_if_ptr, (*parameter)+4); | ||||||
|  |         T path_str_addr_new = sh_read_field<T>(arch_if_ptr, (*parameter)+8); | ||||||
|  |         T path_len_new = sh_read_field<T>(arch_if_ptr, (*parameter)+12); | ||||||
|  |  | ||||||
|  |         std::string path_str_old = sh_read_string<T>(arch_if_ptr, path_str_addr_old, path_len_old); | ||||||
|  |         std::string path_str_new = sh_read_string<T>(arch_if_ptr, path_str_addr_new, path_len_new);  | ||||||
|  |         rename(path_str_old.c_str(), path_str_new.c_str());        | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_SEEK: { |     case semihosting_syscalls::SYS_SEEK: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         T file_handle = sh_read_field<T>(arch_if_ptr, *parameter); | ||||||
|  |         T pos = sh_read_field<T>(arch_if_ptr, (*parameter)+1); | ||||||
|  |         auto file = openFiles[file_handle]; | ||||||
|  |  | ||||||
|  |         int retval = fseek(file, pos, SEEK_SET); | ||||||
|  |         if(retval<0) throw std::runtime_error("SYS_SEEK negative return value"); | ||||||
|  |  | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_SYSTEM: { |     case semihosting_syscalls::SYS_SYSTEM: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         T cmd_addr = sh_read_field<T>(arch_if_ptr, *parameter); | ||||||
|  |         T cmd_len = sh_read_field<T>(arch_if_ptr, (*parameter)+1);  | ||||||
|  |         std::string cmd = sh_read_string<T>(arch_if_ptr, cmd_addr, cmd_len); | ||||||
|  |         system(cmd.c_str()); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_TICKFREQ: { |     case semihosting_syscalls::SYS_TICKFREQ: { | ||||||
| @@ -83,20 +224,43 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal | |||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_TIME: { |     case semihosting_syscalls::SYS_TIME: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         //returns time in seconds scince 01.01.1970 00:00 | ||||||
|  |         *call_number = time(NULL); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_TMPNAM: { |     case semihosting_syscalls::SYS_TMPNAM: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         T buffer_addr = sh_read_field<T>(arch_if_ptr, *parameter); | ||||||
|  |         T identifier = sh_read_field<T>(arch_if_ptr, (*parameter)+1); | ||||||
|  |         T buffer_len = sh_read_field<T>(arch_if_ptr, (*parameter)+2); | ||||||
|  |  | ||||||
|  |         if (identifier > 255) { | ||||||
|  |             *call_number = -1; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         std::stringstream ss; | ||||||
|  |         ss << "tmp/file-" << std::setfill('0') << std::setw(3) << identifier; | ||||||
|  |         std::string filename = ss.str(); | ||||||
|  |  | ||||||
|  |         for(int i = 0; i < buffer_len; i++) { | ||||||
|  |             uint8_t character = filename[i]; | ||||||
|  |             auto res = arch_if_ptr->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, (*parameter)+i, 1, &character); | ||||||
|  |             if(res != iss::Ok) return; | ||||||
|  |         } | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_WRITE: { |     case semihosting_syscalls::SYS_WRITE: { | ||||||
|         throw std::runtime_error("Semihosting Call not Implemented"); |         T file_handle = sh_read_field<T>(arch_if_ptr, (*parameter)+4); | ||||||
|  |         T addr = sh_read_field<T>(arch_if_ptr, *parameter); | ||||||
|  |         T count = sh_read_field<T>(arch_if_ptr, (*parameter)+8); | ||||||
|  |  | ||||||
|  |         auto file = openFiles[file_handle]; | ||||||
|  |         std::string str = sh_read_string<T>(arch_if_ptr, addr, count); | ||||||
|  |         fwrite(&str[0], 1, count, file); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_WRITEC: { |     case semihosting_syscalls::SYS_WRITEC: { | ||||||
|         uint8_t character; |         uint8_t character; | ||||||
|         auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, parameter, 1, &character); |         auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character); | ||||||
|         if(res != iss::Ok) |         if(res != iss::Ok) | ||||||
|             return; |             return; | ||||||
|         putchar(character); |         putchar(character); | ||||||
| @@ -105,13 +269,13 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal | |||||||
|     case semihosting_syscalls::SYS_WRITE0: { |     case semihosting_syscalls::SYS_WRITE0: { | ||||||
|         uint8_t character; |         uint8_t character; | ||||||
|         while(1) { |         while(1) { | ||||||
|             auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, parameter, 1, &character); |             auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character); | ||||||
|             if(res != iss::Ok) |             if(res != iss::Ok) | ||||||
|                 return; |                 return; | ||||||
|             if(character == 0) |             if(character == 0) | ||||||
|                 break; |                 break; | ||||||
|             putchar(character); |             putchar(character); | ||||||
|             parameter++; |             (*parameter)++; | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
| @@ -128,5 +292,5 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal | |||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| template void semihosting_callback<uint32_t>(iss::arch_if* arch_if_ptr, uint32_t call_number, uint32_t parameter); | template class semihosting_callback<uint32_t>; | ||||||
| template void semihosting_callback<uint64_t>(iss::arch_if* arch_if_ptr, uint64_t call_number, uint64_t parameter); | template class semihosting_callback<uint64_t>; | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
| #ifndef _SEMIHOSTING_H_ | #ifndef _SEMIHOSTING_H_ | ||||||
| #define _SEMIHOSTING_H_ | #define _SEMIHOSTING_H_ | ||||||
| #include <iss/arch_if.h> | #include <iss/arch_if.h> | ||||||
|  | #include <functional> | ||||||
|  | #include <chrono> | ||||||
| /* | /* | ||||||
|  * According to: |  * According to: | ||||||
|  * "Semihosting for AArch32 and AArch64, Release 2.0" |  * "Semihosting for AArch32 and AArch64, Release 2.0" | ||||||
| @@ -48,6 +50,11 @@ enum class semihosting_syscalls { | |||||||
|     USER_CMD_0x1FF = 0x1FF, |     USER_CMD_0x1FF = 0x1FF, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T call_number, T parameter); | template <typename T> struct semihosting_callback{ | ||||||
|  |     std::chrono::high_resolution_clock::time_point timeVar; | ||||||
|  |     semihosting_callback(): timeVar(std::chrono::high_resolution_clock::now()) {} | ||||||
|  |     void operator()(iss::arch_if* arch_if_ptr, T* call_number, T* parameter); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename T> using semihosting_cb_t = std::function<void(iss::arch_if*, T*, T*)>; | ||||||
| #endif | #endif | ||||||
| @@ -119,7 +119,8 @@ int main(int argc, char* argv[]) { | |||||||
|         // instantiate the simulator |         // instantiate the simulator | ||||||
|         iss::vm_ptr vm{nullptr}; |         iss::vm_ptr vm{nullptr}; | ||||||
|         iss::cpu_ptr cpu{nullptr}; |         iss::cpu_ptr cpu{nullptr}; | ||||||
|         std::function<void(iss::arch_if*, uint32_t, uint32_t)> semihosting_cb = &semihosting_callback<uint32_t>; |         semihosting_callback<uint32_t> cb{};  | ||||||
|  |         semihosting_cb_t<uint32_t> semihosting_cb = [&cb](iss::arch_if* i, uint32_t* a0, uint32_t* a1) {cb(i,a0,a1);}; | ||||||
|         std::string isa_opt(clim["isa"].as<std::string>()); |         std::string isa_opt(clim["isa"].as<std::string>()); | ||||||
|         if(isa_opt.size() == 0 || isa_opt == "?") { |         if(isa_opt.size() == 0 || isa_opt == "?") { | ||||||
|             auto list = f.get_names(); |             auto list = f.get_names(); | ||||||
|   | |||||||
| @@ -4795,7 +4795,7 @@ volatile std::array<bool, 2> dummy = { | |||||||
| 		    auto vm = new asmjit::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | 		    auto vm = new asmjit::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | ||||||
| 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | ||||||
|             if(init_data){ |             if(init_data){ | ||||||
|                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data); |                 auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::tgc5c>::reg_t>*>(init_data); | ||||||
|                 cpu->set_semihosting_callback(*cb); |                 cpu->set_semihosting_callback(*cb); | ||||||
|             } |             } | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{vm}}; |             return {cpu_ptr{cpu}, vm_ptr{vm}}; | ||||||
| @@ -4805,7 +4805,7 @@ volatile std::array<bool, 2> dummy = { | |||||||
| 		    auto vm = new asmjit::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | 		    auto vm = new asmjit::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | ||||||
| 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | ||||||
|             if(init_data){ |             if(init_data){ | ||||||
|                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data); |                 auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::tgc5c>::reg_t>*>(init_data); | ||||||
|                 cpu->set_semihosting_callback(*cb); |                 cpu->set_semihosting_callback(*cb); | ||||||
|             } |             } | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{vm}}; |             return {cpu_ptr{cpu}, vm_ptr{vm}}; | ||||||
|   | |||||||
| @@ -2700,7 +2700,7 @@ volatile std::array<bool, 2> dummy = { | |||||||
| 		    auto vm = new interp::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | 		    auto vm = new interp::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | ||||||
| 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | ||||||
|             if(init_data){ |             if(init_data){ | ||||||
|                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data); |                 auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::tgc5c>::reg_t>*>(init_data); | ||||||
|                 cpu->set_semihosting_callback(*cb); |                 cpu->set_semihosting_callback(*cb); | ||||||
|             } |             } | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{vm}}; |             return {cpu_ptr{cpu}, vm_ptr{vm}}; | ||||||
| @@ -2710,7 +2710,7 @@ volatile std::array<bool, 2> dummy = { | |||||||
| 		    auto vm = new interp::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | 		    auto vm = new interp::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | ||||||
| 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | ||||||
|             if(init_data){ |             if(init_data){ | ||||||
|                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data); |                 auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::tgc5c>::reg_t>*>(init_data); | ||||||
|                 cpu->set_semihosting_callback(*cb); |                 cpu->set_semihosting_callback(*cb); | ||||||
|             } |             } | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{vm}}; |             return {cpu_ptr{cpu}, vm_ptr{vm}}; | ||||||
|   | |||||||
| @@ -4722,7 +4722,7 @@ volatile std::array<bool, 2> dummy = { | |||||||
| 		    auto vm = new llvm::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | 		    auto vm = new llvm::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | ||||||
| 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | ||||||
|             if(init_data){ |             if(init_data){ | ||||||
|                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data); |                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t*, arch::traits<arch::tgc5c>::reg_t*)>*>(init_data); | ||||||
|                 cpu->set_semihosting_callback(*cb); |                 cpu->set_semihosting_callback(*cb); | ||||||
|             } |             } | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{vm}}; |             return {cpu_ptr{cpu}, vm_ptr{vm}}; | ||||||
| @@ -4732,7 +4732,7 @@ volatile std::array<bool, 2> dummy = { | |||||||
| 		    auto vm = new llvm::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | 		    auto vm = new llvm::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | ||||||
| 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | ||||||
|             if(init_data){ |             if(init_data){ | ||||||
|                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data); |                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t*, arch::traits<arch::tgc5c>::reg_t*)>*>(init_data); | ||||||
|                 cpu->set_semihosting_callback(*cb); |                 cpu->set_semihosting_callback(*cb); | ||||||
|             } |             } | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{vm}}; |             return {cpu_ptr{cpu}, vm_ptr{vm}}; | ||||||
|   | |||||||
| @@ -3653,7 +3653,7 @@ volatile std::array<bool, 2> dummy = { | |||||||
| 		    auto vm = new tcc::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | 		    auto vm = new tcc::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | ||||||
| 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | ||||||
|             if(init_data){ |             if(init_data){ | ||||||
|                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data); |                 auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::tgc5c>::reg_t>*>(init_data); | ||||||
|                 cpu->set_semihosting_callback(*cb); |                 cpu->set_semihosting_callback(*cb); | ||||||
|             } |             } | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{vm}}; |             return {cpu_ptr{cpu}, vm_ptr{vm}}; | ||||||
| @@ -3663,7 +3663,7 @@ volatile std::array<bool, 2> dummy = { | |||||||
| 		    auto vm = new tcc::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | 		    auto vm = new tcc::tgc5c::vm_impl<arch::tgc5c>(*cpu, false); | ||||||
| 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | 		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); | ||||||
|             if(init_data){ |             if(init_data){ | ||||||
|                 auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data); |                 auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::tgc5c>::reg_t>*>(init_data); | ||||||
|                 cpu->set_semihosting_callback(*cb); |                 cpu->set_semihosting_callback(*cb); | ||||||
|             } |             } | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{vm}}; |             return {cpu_ptr{cpu}, vm_ptr{vm}}; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user