Compare commits
	
		
			1 Commits
		
	
	
		
			9c456ba8f2
			...
			a35974c9f5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a35974c9f5 | 
| @@ -67,7 +67,15 @@ set_target_properties(${PROJECT_NAME} PROPERTIES | |||||||
| if(SystemC_FOUND) | if(SystemC_FOUND) | ||||||
| 	add_library(${PROJECT_NAME}_sc src/sysc/core_complex.cpp) | 	add_library(${PROJECT_NAME}_sc src/sysc/core_complex.cpp) | ||||||
| 	target_compile_definitions(${PROJECT_NAME}_sc PUBLIC WITH_SYSTEMC) | 	target_compile_definitions(${PROJECT_NAME}_sc PUBLIC WITH_SYSTEMC) | ||||||
|     target_compile_definitions(${PROJECT_NAME}_sc PRIVATE CORE_${CORE_NAME}) |     if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_b.h) | ||||||
|  |         target_compile_definitions(${PROJECT_NAME}_sc PRIVATE CORE_TGC_B) | ||||||
|  |     endif() | ||||||
|  | 	if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_c.h) | ||||||
|  |         target_compile_definitions(${PROJECT_NAME}_sc PRIVATE CORE_TGC_C) | ||||||
|  |     endif() | ||||||
|  |     if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_d.h) | ||||||
|  |         target_compile_definitions(${PROJECT_NAME}_sc PRIVATE CORE_TGC_D) | ||||||
|  |     endif() | ||||||
| 	target_include_directories(${PROJECT_NAME}_sc PUBLIC ../incl ${SystemC_INCLUDE_DIRS} ${CCI_INCLUDE_DIRS}) | 	target_include_directories(${PROJECT_NAME}_sc PUBLIC ../incl ${SystemC_INCLUDE_DIRS} ${CCI_INCLUDE_DIRS}) | ||||||
| 	 | 	 | ||||||
| 	if(SCV_FOUND)    | 	if(SCV_FOUND)    | ||||||
| @@ -110,17 +118,3 @@ install(TARGETS dbt-core-tgc tgc-sim | |||||||
|   PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} COMPONENT devel   # headers for mac (note the different component -> different package) |   PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} COMPONENT devel   # headers for mac (note the different component -> different package) | ||||||
|   INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}             # headers |   INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}             # headers | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # |  | ||||||
| # SYSTEM PACKAGING (RPM, TGZ, ...) |  | ||||||
| # _____________________________________________________________________________ |  | ||||||
|  |  | ||||||
| #include(CPackConfig) |  | ||||||
|  |  | ||||||
| # |  | ||||||
| # CMAKE PACKAGING (for other CMake projects to use this one easily) |  | ||||||
| # _____________________________________________________________________________ |  | ||||||
|  |  | ||||||
| #include(PackageConfigurator) |  | ||||||
							
								
								
									
										235
									
								
								incl/iss/arch/riscv_hart_common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								incl/iss/arch/riscv_hart_common.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,235 @@ | |||||||
|  | /******************************************************************************* | ||||||
|  |  * Copyright (C) 2017, 2018, 2021 MINRES Technologies GmbH | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer in the documentation | ||||||
|  |  *    and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * 3. Neither the name of the copyright holder nor the names of its contributors | ||||||
|  |  *    may be used to endorse or promote products derived from this software | ||||||
|  |  *    without specific prior written permission. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||||
|  |  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||||||
|  |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||||
|  |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||||
|  |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||||
|  |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||||
|  |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||||
|  |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||||
|  |  * POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  * | ||||||
|  |  * Contributors: | ||||||
|  |  *       eyck@minres.com - initial implementation | ||||||
|  |  ******************************************************************************/ | ||||||
|  |  | ||||||
|  | #ifndef _RISCV_HART_COMMON | ||||||
|  | #define _RISCV_HART_COMMON | ||||||
|  |  | ||||||
|  | #include "iss/arch_if.h" | ||||||
|  | #include <cstdint> | ||||||
|  |  | ||||||
|  | namespace iss { | ||||||
|  | namespace arch { | ||||||
|  |  | ||||||
|  | enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 }; | ||||||
|  |  | ||||||
|  | enum riscv_csr { | ||||||
|  |     /* user-level CSR */ | ||||||
|  |     // User Trap Setup | ||||||
|  |     ustatus = 0x000, | ||||||
|  |     uie = 0x004, | ||||||
|  |     utvec = 0x005, | ||||||
|  |     // User Trap Handling | ||||||
|  |     uscratch = 0x040, | ||||||
|  |     uepc = 0x041, | ||||||
|  |     ucause = 0x042, | ||||||
|  |     utval = 0x043, | ||||||
|  |     uip = 0x044, | ||||||
|  |     // User Floating-Point CSRs | ||||||
|  |     fflags = 0x001, | ||||||
|  |     frm = 0x002, | ||||||
|  |     fcsr = 0x003, | ||||||
|  |     // User Counter/Timers | ||||||
|  |     cycle = 0xC00, | ||||||
|  |     time = 0xC01, | ||||||
|  |     instret = 0xC02, | ||||||
|  |     hpmcounter3 = 0xC03, | ||||||
|  |     hpmcounter4 = 0xC04, | ||||||
|  |     /*...*/ | ||||||
|  |     hpmcounter31 = 0xC1F, | ||||||
|  |     cycleh = 0xC80, | ||||||
|  |     timeh = 0xC81, | ||||||
|  |     instreth = 0xC82, | ||||||
|  |     hpmcounter3h = 0xC83, | ||||||
|  |     hpmcounter4h = 0xC84, | ||||||
|  |     /*...*/ | ||||||
|  |     hpmcounter31h = 0xC9F, | ||||||
|  |     /* supervisor-level CSR */ | ||||||
|  |     // Supervisor Trap Setup | ||||||
|  |     sstatus = 0x100, | ||||||
|  |     sedeleg = 0x102, | ||||||
|  |     sideleg = 0x103, | ||||||
|  |     sie = 0x104, | ||||||
|  |     stvec = 0x105, | ||||||
|  |     scounteren = 0x106, | ||||||
|  |     // Supervisor Trap Handling | ||||||
|  |     sscratch = 0x140, | ||||||
|  |     sepc = 0x141, | ||||||
|  |     scause = 0x142, | ||||||
|  |     stval = 0x143, | ||||||
|  |     sip = 0x144, | ||||||
|  |     // Supervisor Protection and Translation | ||||||
|  |     satp = 0x180, | ||||||
|  |     /* machine-level CSR */ | ||||||
|  |     // Machine Information Registers | ||||||
|  |     mvendorid = 0xF11, | ||||||
|  |     marchid = 0xF12, | ||||||
|  |     mimpid = 0xF13, | ||||||
|  |     mhartid = 0xF14, | ||||||
|  |     // Machine Trap Setup | ||||||
|  |     mstatus = 0x300, | ||||||
|  |     misa = 0x301, | ||||||
|  |     medeleg = 0x302, | ||||||
|  |     mideleg = 0x303, | ||||||
|  |     mie = 0x304, | ||||||
|  |     mtvec = 0x305, | ||||||
|  |     mcounteren = 0x306, | ||||||
|  |     // Machine Trap Handling | ||||||
|  |     mscratch = 0x340, | ||||||
|  |     mepc = 0x341, | ||||||
|  |     mcause = 0x342, | ||||||
|  |     mtval = 0x343, | ||||||
|  |     mip = 0x344, | ||||||
|  |     // Physical Memory Protection | ||||||
|  |     pmpcfg0 = 0x3A0, | ||||||
|  |     pmpcfg1 = 0x3A1, | ||||||
|  |     pmpcfg2 = 0x3A2, | ||||||
|  |     pmpcfg3 = 0x3A3, | ||||||
|  |     pmpaddr0 = 0x3B0, | ||||||
|  |     pmpaddr1 = 0x3B1, | ||||||
|  |     pmpaddr2 = 0x3B2, | ||||||
|  |     pmpaddr3 = 0x3B3, | ||||||
|  |     pmpaddr4 = 0x3B4, | ||||||
|  |     pmpaddr5 = 0x3B5, | ||||||
|  |     pmpaddr6 = 0x3B6, | ||||||
|  |     pmpaddr7 = 0x3B7, | ||||||
|  |     pmpaddr8 = 0x3B8, | ||||||
|  |     pmpaddr9 = 0x3B9, | ||||||
|  |     pmpaddr10 = 0x3BA, | ||||||
|  |     pmpaddr11 = 0x3BB, | ||||||
|  |     pmpaddr12 = 0x3BC, | ||||||
|  |     pmpaddr13 = 0x3BD, | ||||||
|  |     pmpaddr14 = 0x3BE, | ||||||
|  |     pmpaddr15 = 0x3BF, | ||||||
|  |     // Machine Counter/Timers | ||||||
|  |     mcycle = 0xB00, | ||||||
|  |     minstret = 0xB02, | ||||||
|  |     mhpmcounter3 = 0xB03, | ||||||
|  |     mhpmcounter4 = 0xB04, | ||||||
|  |     /*...*/ | ||||||
|  |     mhpmcounter31 = 0xB1F, | ||||||
|  |     mcycleh = 0xB80, | ||||||
|  |     minstreth = 0xB82, | ||||||
|  |     mhpmcounter3h = 0xB83, | ||||||
|  |     mhpmcounter4h = 0xB84, | ||||||
|  |     /*...*/ | ||||||
|  |     mhpmcounter31h = 0xB9F, | ||||||
|  |     // Machine Counter Setup | ||||||
|  |     mhpmevent3 = 0x323, | ||||||
|  |     mhpmevent4 = 0x324, | ||||||
|  |     /*...*/ | ||||||
|  |     mhpmevent31 = 0x33F, | ||||||
|  |     // Debug/Trace Registers (shared with Debug Mode) | ||||||
|  |     tselect = 0x7A0, | ||||||
|  |     tdata1 = 0x7A1, | ||||||
|  |     tdata2 = 0x7A2, | ||||||
|  |     tdata3 = 0x7A3, | ||||||
|  |     // Debug Mode Registers | ||||||
|  |     dcsr = 0x7B0, | ||||||
|  |     dpc = 0x7B1, | ||||||
|  |     dscratch = 0x7B2 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | enum { | ||||||
|  |     PGSHIFT = 12, | ||||||
|  |     PTE_PPN_SHIFT = 10, | ||||||
|  |     // page table entry (PTE) fields | ||||||
|  |     PTE_V = 0x001,   // Valid | ||||||
|  |     PTE_R = 0x002,   // Read | ||||||
|  |     PTE_W = 0x004,   // Write | ||||||
|  |     PTE_X = 0x008,   // Execute | ||||||
|  |     PTE_U = 0x010,   // User | ||||||
|  |     PTE_G = 0x020,   // Global | ||||||
|  |     PTE_A = 0x040,   // Accessed | ||||||
|  |     PTE_D = 0x080,   // Dirty | ||||||
|  |     PTE_SOFT = 0x300 // Reserved for Software | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename T> inline bool PTE_TABLE(T PTE) { return (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V); } | ||||||
|  |  | ||||||
|  | enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3 }; | ||||||
|  |  | ||||||
|  | enum { | ||||||
|  |     ISA_A = 1, | ||||||
|  |     ISA_B = 1 << 1, | ||||||
|  |     ISA_C = 1 << 2, | ||||||
|  |     ISA_D = 1 << 3, | ||||||
|  |     ISA_E = 1 << 4, | ||||||
|  |     ISA_F = 1 << 5, | ||||||
|  |     ISA_G = 1 << 6, | ||||||
|  |     ISA_I = 1 << 8, | ||||||
|  |     ISA_M = 1 << 12, | ||||||
|  |     ISA_N = 1 << 13, | ||||||
|  |     ISA_Q = 1 << 16, | ||||||
|  |     ISA_S = 1 << 18, | ||||||
|  |     ISA_U = 1 << 20 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct vm_info { | ||||||
|  |     int levels; | ||||||
|  |     int idxbits; | ||||||
|  |     int ptesize; | ||||||
|  |     uint64_t ptbase; | ||||||
|  |     bool is_active() { return levels; } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class trap_load_access_fault : public trap_access { | ||||||
|  | public: | ||||||
|  |     trap_load_access_fault(uint64_t badaddr) | ||||||
|  |     : trap_access(5 << 16, badaddr) {} | ||||||
|  | }; | ||||||
|  | class illegal_instruction_fault : public trap_access { | ||||||
|  | public: | ||||||
|  |     illegal_instruction_fault(uint64_t badaddr) | ||||||
|  |     : trap_access(2 << 16, badaddr) {} | ||||||
|  | }; | ||||||
|  | class trap_instruction_page_fault : public trap_access { | ||||||
|  | public: | ||||||
|  |     trap_instruction_page_fault(uint64_t badaddr) | ||||||
|  |     : trap_access(12 << 16, badaddr) {} | ||||||
|  | }; | ||||||
|  | class trap_load_page_fault : public trap_access { | ||||||
|  | public: | ||||||
|  |     trap_load_page_fault(uint64_t badaddr) | ||||||
|  |     : trap_access(13 << 16, badaddr) {} | ||||||
|  | }; | ||||||
|  | class trap_store_page_fault : public trap_access { | ||||||
|  | public: | ||||||
|  |     trap_store_page_fault(uint64_t badaddr) | ||||||
|  |     : trap_access(15 << 16, badaddr) {} | ||||||
|  | }; | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| /******************************************************************************* | /******************************************************************************* | ||||||
|  * Copyright (C) 2017, 2018, MINRES Technologies GmbH |  * Copyright (C) 2021, MINRES Technologies GmbH | ||||||
|  * All rights reserved. |  * All rights reserved. | ||||||
|  * |  * | ||||||
|  * Redistribution and use in source and binary forms, with or without |  * Redistribution and use in source and binary forms, with or without | ||||||
| @@ -32,11 +32,11 @@ | |||||||
|  *       eyck@minres.com - initial implementation |  *       eyck@minres.com - initial implementation | ||||||
|  ******************************************************************************/ |  ******************************************************************************/ | ||||||
|  |  | ||||||
| #ifndef _RISCV_CORE_H_ | #ifndef _RISCV_HART_M_P_H | ||||||
| #define _RISCV_CORE_H_ | #define _RISCV_HART_M_P_H | ||||||
|  |  | ||||||
|  | #include "riscv_hart_common.h" | ||||||
| #include "iss/arch/traits.h" | #include "iss/arch/traits.h" | ||||||
| #include "iss/arch_if.h" |  | ||||||
| #include "iss/instrumentation_if.h" | #include "iss/instrumentation_if.h" | ||||||
| #include "iss/log_categories.h" | #include "iss/log_categories.h" | ||||||
| #include "iss/vm_if.h" | #include "iss/vm_if.h" | ||||||
| @@ -66,116 +66,10 @@ | |||||||
| namespace iss { | namespace iss { | ||||||
| namespace arch { | namespace arch { | ||||||
|  |  | ||||||
| enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 }; | template <typename BASE> class riscv_hart_m_p : public BASE { | ||||||
|  | protected: | ||||||
| enum riscv_csr { |     const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; | ||||||
|     /* user-level CSR */ |     const std::array<const char *, 16> trap_str = {{"" | ||||||
|     // User Trap Setup |  | ||||||
|     ustatus = 0x000, |  | ||||||
|     uie = 0x004, |  | ||||||
|     utvec = 0x005, |  | ||||||
|     // User Trap Handling |  | ||||||
|     uscratch = 0x040, |  | ||||||
|     uepc = 0x041, |  | ||||||
|     ucause = 0x042, |  | ||||||
|     utval = 0x043, |  | ||||||
|     uip = 0x044, |  | ||||||
|     // User Floating-Point CSRs |  | ||||||
|     fflags = 0x001, |  | ||||||
|     frm = 0x002, |  | ||||||
|     fcsr = 0x003, |  | ||||||
|     // User Counter/Timers |  | ||||||
|     cycle = 0xC00, |  | ||||||
|     time = 0xC01, |  | ||||||
|     instret = 0xC02, |  | ||||||
|     hpmcounter3 = 0xC03, |  | ||||||
|     hpmcounter4 = 0xC04, |  | ||||||
|     /*...*/ |  | ||||||
|     hpmcounter31 = 0xC1F, |  | ||||||
|     cycleh = 0xC80, |  | ||||||
|     timeh = 0xC81, |  | ||||||
|     instreth = 0xC82, |  | ||||||
|     hpmcounter3h = 0xC83, |  | ||||||
|     hpmcounter4h = 0xC84, |  | ||||||
|     /*...*/ |  | ||||||
|     hpmcounter31h = 0xC9F, |  | ||||||
|     /* supervisor-level CSR */ |  | ||||||
|     // Supervisor Trap Setup |  | ||||||
|     sstatus = 0x100, |  | ||||||
|     sedeleg = 0x102, |  | ||||||
|     sideleg = 0x103, |  | ||||||
|     sie = 0x104, |  | ||||||
|     stvec = 0x105, |  | ||||||
|     scounteren = 0x106, |  | ||||||
|     // Supervisor Trap Handling |  | ||||||
|     sscratch = 0x140, |  | ||||||
|     sepc = 0x141, |  | ||||||
|     scause = 0x142, |  | ||||||
|     stval = 0x143, |  | ||||||
|     sip = 0x144, |  | ||||||
|     // Supervisor Protection and Translation |  | ||||||
|     satp = 0x180, |  | ||||||
|     /* machine-level CSR */ |  | ||||||
|     // Machine Information Registers |  | ||||||
|     mvendorid = 0xF11, |  | ||||||
|     marchid = 0xF12, |  | ||||||
|     mimpid = 0xF13, |  | ||||||
|     mhartid = 0xF14, |  | ||||||
|     // Machine Trap Setup |  | ||||||
|     mstatus = 0x300, |  | ||||||
|     misa = 0x301, |  | ||||||
|     medeleg = 0x302, |  | ||||||
|     mideleg = 0x303, |  | ||||||
|     mie = 0x304, |  | ||||||
|     mtvec = 0x305, |  | ||||||
|     mcounteren = 0x306, |  | ||||||
|     // Machine Trap Handling |  | ||||||
|     mscratch = 0x340, |  | ||||||
|     mepc = 0x341, |  | ||||||
|     mcause = 0x342, |  | ||||||
|     mtval = 0x343, |  | ||||||
|     mip = 0x344, |  | ||||||
|     // Machine Protection and Translation |  | ||||||
|     pmpcfg0 = 0x3A0, |  | ||||||
|     pmpcfg1 = 0x3A1, |  | ||||||
|     pmpcfg2 = 0x3A2, |  | ||||||
|     pmpcfg3 = 0x3A3, |  | ||||||
|     pmpaddr0 = 0x3B0, |  | ||||||
|     pmpaddr1 = 0x3B1, |  | ||||||
|     /*...*/ |  | ||||||
|     pmpaddr15 = 0x3BF, |  | ||||||
|     // Machine Counter/Timers |  | ||||||
|     mcycle = 0xB00, |  | ||||||
|     minstret = 0xB02, |  | ||||||
|     mhpmcounter3 = 0xB03, |  | ||||||
|     mhpmcounter4 = 0xB04, |  | ||||||
|     /*...*/ |  | ||||||
|     mhpmcounter31 = 0xB1F, |  | ||||||
|     mcycleh = 0xB80, |  | ||||||
|     minstreth = 0xB82, |  | ||||||
|     mhpmcounter3h = 0xB83, |  | ||||||
|     mhpmcounter4h = 0xB84, |  | ||||||
|     /*...*/ |  | ||||||
|     mhpmcounter31h = 0xB9F, |  | ||||||
|     // Machine Counter Setup |  | ||||||
|     mhpmevent3 = 0x323, |  | ||||||
|     mhpmevent4 = 0x324, |  | ||||||
|     /*...*/ |  | ||||||
|     mhpmevent31 = 0x33F, |  | ||||||
|     // Debug/Trace Registers (shared with Debug Mode) |  | ||||||
|     tselect = 0x7A0, |  | ||||||
|     tdata1 = 0x7A1, |  | ||||||
|     tdata2 = 0x7A2, |  | ||||||
|     tdata3 = 0x7A3, |  | ||||||
|     // Debug Mode Registers |  | ||||||
|     dcsr = 0x7B0, |  | ||||||
|     dpc = 0x7B1, |  | ||||||
|     dscratch = 0x7B2 |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| namespace { |  | ||||||
|  |  | ||||||
| std::array<const char *, 16> trap_str = {{"" |  | ||||||
|                                               "Instruction address misaligned", // 0 |                                               "Instruction address misaligned", // 0 | ||||||
|                                               "Instruction access fault",       // 1 |                                               "Instruction access fault",       // 1 | ||||||
|                                               "Illegal instruction",            // 2 |                                               "Illegal instruction",            // 2 | ||||||
| @@ -192,59 +86,10 @@ std::array<const char *, 16> trap_str = {{"" | |||||||
|                                               "Load page fault",                // d |                                               "Load page fault",                // d | ||||||
|                                               "Reserved",                       // e |                                               "Reserved",                       // e | ||||||
|                                               "Store/AMO page fault"}}; |                                               "Store/AMO page fault"}}; | ||||||
| std::array<const char *, 12> irq_str = { |     const std::array<const char *, 12> irq_str = { | ||||||
|         {"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt", |         {"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt", | ||||||
|          "User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt", |          "User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt", | ||||||
|          "User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; |          "User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; | ||||||
|  |  | ||||||
| enum { |  | ||||||
|     PGSHIFT = 12, |  | ||||||
|     PTE_PPN_SHIFT = 10, |  | ||||||
|     // page table entry (PTE) fields |  | ||||||
|     PTE_V = 0x001,   // Valid |  | ||||||
|     PTE_R = 0x002,   // Read |  | ||||||
|     PTE_W = 0x004,   // Write |  | ||||||
|     PTE_X = 0x008,   // Execute |  | ||||||
|     PTE_U = 0x010,   // User |  | ||||||
|     PTE_G = 0x020,   // Global |  | ||||||
|     PTE_A = 0x040,   // Accessed |  | ||||||
|     PTE_D = 0x080,   // Dirty |  | ||||||
|     PTE_SOFT = 0x300 // Reserved for Software |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| template <typename T> inline bool PTE_TABLE(T PTE) { return (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V); } |  | ||||||
|  |  | ||||||
| enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3 }; |  | ||||||
|  |  | ||||||
| enum { |  | ||||||
|     ISA_A = 1, |  | ||||||
|     ISA_B = 1 << 1, |  | ||||||
|     ISA_C = 1 << 2, |  | ||||||
|     ISA_D = 1 << 3, |  | ||||||
|     ISA_E = 1 << 4, |  | ||||||
|     ISA_F = 1 << 5, |  | ||||||
|     ISA_G = 1 << 6, |  | ||||||
|     ISA_I = 1 << 8, |  | ||||||
|     ISA_M = 1 << 12, |  | ||||||
|     ISA_N = 1 << 13, |  | ||||||
|     ISA_Q = 1 << 16, |  | ||||||
|     ISA_S = 1 << 18, |  | ||||||
|     ISA_U = 1 << 20 |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| class trap_load_access_fault : public trap_access { |  | ||||||
| public: |  | ||||||
|     trap_load_access_fault(uint64_t badaddr) |  | ||||||
|     : trap_access(5 << 16, badaddr) {} |  | ||||||
| }; |  | ||||||
| class illegal_instruction_fault : public trap_access { |  | ||||||
| public: |  | ||||||
|     illegal_instruction_fault(uint64_t badaddr) |  | ||||||
|     : trap_access(2 << 16, badaddr) {} |  | ||||||
| }; |  | ||||||
| } // namespace |  | ||||||
|  |  | ||||||
| template <typename BASE> class riscv_hart_m_p : public BASE { |  | ||||||
| public: | public: | ||||||
|     using super = BASE; |     using super = BASE; | ||||||
|     using this_class = riscv_hart_m_p<BASE>; |     using this_class = riscv_hart_m_p<BASE>; | ||||||
| @@ -313,6 +158,7 @@ public: | |||||||
|             return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011  // only machine mode is supported |             return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011  // only machine mode is supported | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |     using hart_state_type = hart_state<reg_t>; | ||||||
|  |  | ||||||
|     constexpr reg_t get_irq_mask() { |     constexpr reg_t get_irq_mask() { | ||||||
|         return 0b101110111011; // only machine mode is supported |         return 0b101110111011; // only machine mode is supported | ||||||
| @@ -387,7 +233,7 @@ protected: | |||||||
|     virtual iss::status read_csr(unsigned addr, reg_t &val); |     virtual iss::status read_csr(unsigned addr, reg_t &val); | ||||||
|     virtual iss::status write_csr(unsigned addr, reg_t val); |     virtual iss::status write_csr(unsigned addr, reg_t val); | ||||||
|  |  | ||||||
|     hart_state<reg_t> state; |     hart_state_type state; | ||||||
|     uint64_t cycle_offset; |     uint64_t cycle_offset; | ||||||
|     reg_t fault_data; |     reg_t fault_data; | ||||||
|     uint64_t tohost = tohost_dflt; |     uint64_t tohost = tohost_dflt; | ||||||
| @@ -729,7 +575,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned ad | |||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_status(unsigned addr, reg_t &val) { | template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_status(unsigned addr, reg_t &val) { | ||||||
|     val = state.mstatus & hart_state<reg_t>::get_mask(); |     val = state.mstatus & hart_state_type::get_mask(); | ||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -876,7 +722,7 @@ iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length, | |||||||
|  |  | ||||||
| template <typename BASE> inline void riscv_hart_m_p<BASE>::reset(uint64_t address) { | template <typename BASE> inline void riscv_hart_m_p<BASE>::reset(uint64_t address) { | ||||||
|     BASE::reset(address); |     BASE::reset(address); | ||||||
|     state.mstatus = hart_state<reg_t>::mstatus_reset_val; |     state.mstatus = hart_state_type::mstatus_reset_val; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() { | template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() { | ||||||
| @@ -958,4 +804,4 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::leave_trap(uint64_t flag | |||||||
| } // namespace arch | } // namespace arch | ||||||
| } // namespace iss | } // namespace iss | ||||||
|  |  | ||||||
| #endif /* _RISCV_CORE_H_ */ | #endif /* _RISCV_HART_M_P_H */ | ||||||
|   | |||||||
							
								
								
									
										1199
									
								
								incl/iss/arch/riscv_hart_msu_vp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1199
									
								
								incl/iss/arch/riscv_hart_msu_vp.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,5 +1,5 @@ | |||||||
| /******************************************************************************* | /******************************************************************************* | ||||||
|  * Copyright (C) 2017, 2018, MINRES Technologies GmbH |  * Copyright (C) 2021 MINRES Technologies GmbH | ||||||
|  * All rights reserved. |  * All rights reserved. | ||||||
|  * |  * | ||||||
|  * Redistribution and use in source and binary forms, with or without |  * Redistribution and use in source and binary forms, with or without | ||||||
| @@ -32,11 +32,11 @@ | |||||||
|  *       eyck@minres.com - initial implementation |  *       eyck@minres.com - initial implementation | ||||||
|  ******************************************************************************/ |  ******************************************************************************/ | ||||||
|  |  | ||||||
| #ifndef _RISCV_CORE_H_ | #ifndef _RISCV_HART_MU_P_H | ||||||
| #define _RISCV_CORE_H_ | #define _RISCV_HART_MU_P_H | ||||||
|  |  | ||||||
|  | #include "riscv_hart_common.h" | ||||||
| #include "iss/arch/traits.h" | #include "iss/arch/traits.h" | ||||||
| #include "iss/arch_if.h" |  | ||||||
| #include "iss/instrumentation_if.h" | #include "iss/instrumentation_if.h" | ||||||
| #include "iss/log_categories.h" | #include "iss/log_categories.h" | ||||||
| #include "iss/vm_if.h" | #include "iss/vm_if.h" | ||||||
| @@ -66,116 +66,10 @@ | |||||||
| namespace iss { | namespace iss { | ||||||
| namespace arch { | namespace arch { | ||||||
|  |  | ||||||
| enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 }; | template <typename BASE, bool PMP=false> class riscv_hart_mu_p : public BASE { | ||||||
|  | protected: | ||||||
| enum riscv_csr { |     const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; | ||||||
|     /* user-level CSR */ |     const std::array<const char *, 16> trap_str = {{"" | ||||||
|     // User Trap Setup |  | ||||||
|     ustatus = 0x000, |  | ||||||
|     uie = 0x004, |  | ||||||
|     utvec = 0x005, |  | ||||||
|     // User Trap Handling |  | ||||||
|     uscratch = 0x040, |  | ||||||
|     uepc = 0x041, |  | ||||||
|     ucause = 0x042, |  | ||||||
|     utval = 0x043, |  | ||||||
|     uip = 0x044, |  | ||||||
|     // User Floating-Point CSRs |  | ||||||
|     fflags = 0x001, |  | ||||||
|     frm = 0x002, |  | ||||||
|     fcsr = 0x003, |  | ||||||
|     // User Counter/Timers |  | ||||||
|     cycle = 0xC00, |  | ||||||
|     time = 0xC01, |  | ||||||
|     instret = 0xC02, |  | ||||||
|     hpmcounter3 = 0xC03, |  | ||||||
|     hpmcounter4 = 0xC04, |  | ||||||
|     /*...*/ |  | ||||||
|     hpmcounter31 = 0xC1F, |  | ||||||
|     cycleh = 0xC80, |  | ||||||
|     timeh = 0xC81, |  | ||||||
|     instreth = 0xC82, |  | ||||||
|     hpmcounter3h = 0xC83, |  | ||||||
|     hpmcounter4h = 0xC84, |  | ||||||
|     /*...*/ |  | ||||||
|     hpmcounter31h = 0xC9F, |  | ||||||
|     /* supervisor-level CSR */ |  | ||||||
|     // Supervisor Trap Setup |  | ||||||
|     sstatus = 0x100, |  | ||||||
|     sedeleg = 0x102, |  | ||||||
|     sideleg = 0x103, |  | ||||||
|     sie = 0x104, |  | ||||||
|     stvec = 0x105, |  | ||||||
|     scounteren = 0x106, |  | ||||||
|     // Supervisor Trap Handling |  | ||||||
|     sscratch = 0x140, |  | ||||||
|     sepc = 0x141, |  | ||||||
|     scause = 0x142, |  | ||||||
|     stval = 0x143, |  | ||||||
|     sip = 0x144, |  | ||||||
|     // Supervisor Protection and Translation |  | ||||||
|     satp = 0x180, |  | ||||||
|     /* machine-level CSR */ |  | ||||||
|     // Machine Information Registers |  | ||||||
|     mvendorid = 0xF11, |  | ||||||
|     marchid = 0xF12, |  | ||||||
|     mimpid = 0xF13, |  | ||||||
|     mhartid = 0xF14, |  | ||||||
|     // Machine Trap Setup |  | ||||||
|     mstatus = 0x300, |  | ||||||
|     misa = 0x301, |  | ||||||
|     medeleg = 0x302, |  | ||||||
|     mideleg = 0x303, |  | ||||||
|     mie = 0x304, |  | ||||||
|     mtvec = 0x305, |  | ||||||
|     mcounteren = 0x306, |  | ||||||
|     // Machine Trap Handling |  | ||||||
|     mscratch = 0x340, |  | ||||||
|     mepc = 0x341, |  | ||||||
|     mcause = 0x342, |  | ||||||
|     mtval = 0x343, |  | ||||||
|     mip = 0x344, |  | ||||||
|     // Machine Protection and Translation |  | ||||||
|     pmpcfg0 = 0x3A0, |  | ||||||
|     pmpcfg1 = 0x3A1, |  | ||||||
|     pmpcfg2 = 0x3A2, |  | ||||||
|     pmpcfg3 = 0x3A3, |  | ||||||
|     pmpaddr0 = 0x3B0, |  | ||||||
|     pmpaddr1 = 0x3B1, |  | ||||||
|     /*...*/ |  | ||||||
|     pmpaddr15 = 0x3BF, |  | ||||||
|     // Machine Counter/Timers |  | ||||||
|     mcycle = 0xB00, |  | ||||||
|     minstret = 0xB02, |  | ||||||
|     mhpmcounter3 = 0xB03, |  | ||||||
|     mhpmcounter4 = 0xB04, |  | ||||||
|     /*...*/ |  | ||||||
|     mhpmcounter31 = 0xB1F, |  | ||||||
|     mcycleh = 0xB80, |  | ||||||
|     minstreth = 0xB82, |  | ||||||
|     mhpmcounter3h = 0xB83, |  | ||||||
|     mhpmcounter4h = 0xB84, |  | ||||||
|     /*...*/ |  | ||||||
|     mhpmcounter31h = 0xB9F, |  | ||||||
|     // Machine Counter Setup |  | ||||||
|     mhpmevent3 = 0x323, |  | ||||||
|     mhpmevent4 = 0x324, |  | ||||||
|     /*...*/ |  | ||||||
|     mhpmevent31 = 0x33F, |  | ||||||
|     // Debug/Trace Registers (shared with Debug Mode) |  | ||||||
|     tselect = 0x7A0, |  | ||||||
|     tdata1 = 0x7A1, |  | ||||||
|     tdata2 = 0x7A2, |  | ||||||
|     tdata3 = 0x7A3, |  | ||||||
|     // Debug Mode Registers |  | ||||||
|     dcsr = 0x7B0, |  | ||||||
|     dpc = 0x7B1, |  | ||||||
|     dscratch = 0x7B2 |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| namespace { |  | ||||||
|  |  | ||||||
| std::array<const char *, 16> trap_str = {{"" |  | ||||||
|                                               "Instruction address misaligned", // 0 |                                               "Instruction address misaligned", // 0 | ||||||
|                                               "Instruction access fault",       // 1 |                                               "Instruction access fault",       // 1 | ||||||
|                                               "Illegal instruction",            // 2 |                                               "Illegal instruction",            // 2 | ||||||
| @@ -192,62 +86,13 @@ std::array<const char *, 16> trap_str = {{"" | |||||||
|                                               "Load page fault",                // d |                                               "Load page fault",                // d | ||||||
|                                               "Reserved",                       // e |                                               "Reserved",                       // e | ||||||
|                                               "Store/AMO page fault"}}; |                                               "Store/AMO page fault"}}; | ||||||
| std::array<const char *, 12> irq_str = { |     const std::array<const char *, 12> irq_str = { | ||||||
|         {"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt", |         {"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt", | ||||||
|          "User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt", |          "User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt", | ||||||
|          "User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; |          "User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; | ||||||
|  |  | ||||||
| enum { |  | ||||||
|     PGSHIFT = 12, |  | ||||||
|     PTE_PPN_SHIFT = 10, |  | ||||||
|     // page table entry (PTE) fields |  | ||||||
|     PTE_V = 0x001,   // Valid |  | ||||||
|     PTE_R = 0x002,   // Read |  | ||||||
|     PTE_W = 0x004,   // Write |  | ||||||
|     PTE_X = 0x008,   // Execute |  | ||||||
|     PTE_U = 0x010,   // User |  | ||||||
|     PTE_G = 0x020,   // Global |  | ||||||
|     PTE_A = 0x040,   // Accessed |  | ||||||
|     PTE_D = 0x080,   // Dirty |  | ||||||
|     PTE_SOFT = 0x300 // Reserved for Software |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| template <typename T> inline bool PTE_TABLE(T PTE) { return (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V); } |  | ||||||
|  |  | ||||||
| enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3 }; |  | ||||||
|  |  | ||||||
| enum { |  | ||||||
|     ISA_A = 1, |  | ||||||
|     ISA_B = 1 << 1, |  | ||||||
|     ISA_C = 1 << 2, |  | ||||||
|     ISA_D = 1 << 3, |  | ||||||
|     ISA_E = 1 << 4, |  | ||||||
|     ISA_F = 1 << 5, |  | ||||||
|     ISA_G = 1 << 6, |  | ||||||
|     ISA_I = 1 << 8, |  | ||||||
|     ISA_M = 1 << 12, |  | ||||||
|     ISA_N = 1 << 13, |  | ||||||
|     ISA_Q = 1 << 16, |  | ||||||
|     ISA_S = 1 << 18, |  | ||||||
|     ISA_U = 1 << 20 |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| class trap_load_access_fault : public trap_access { |  | ||||||
| public: |  | ||||||
|     trap_load_access_fault(uint64_t badaddr) |  | ||||||
|     : trap_access(5 << 16, badaddr) {} |  | ||||||
| }; |  | ||||||
| class illegal_instruction_fault : public trap_access { |  | ||||||
| public: |  | ||||||
|     illegal_instruction_fault(uint64_t badaddr) |  | ||||||
|     : trap_access(2 << 16, badaddr) {} |  | ||||||
| }; |  | ||||||
| } // namespace |  | ||||||
|  |  | ||||||
| template <typename BASE> class riscv_hart_mu_p : public BASE { |  | ||||||
| public: | public: | ||||||
|     using super = BASE; |     using super = BASE; | ||||||
|     using this_class = riscv_hart_mu_p<BASE>; |     using this_class = riscv_hart_mu_p<BASE, PMP>; | ||||||
|     using phys_addr_t = typename super::phys_addr_t; |     using phys_addr_t = typename super::phys_addr_t; | ||||||
|     using reg_t = typename super::reg_t; |     using reg_t = typename super::reg_t; | ||||||
|     using addr_t = typename super::addr_t; |     using addr_t = typename super::addr_t; | ||||||
| @@ -301,21 +146,35 @@ public: | |||||||
|  |  | ||||||
|         static const reg_t mstatus_reset_val = 0; |         static const reg_t mstatus_reset_val = 0; | ||||||
|  |  | ||||||
|         void write_mstatus(T val) { |         void write_mstatus(T val, unsigned priv_lvl) { | ||||||
|             auto mask = get_mask(); |             auto mask = get_mask(priv_lvl); | ||||||
|             auto new_val = (mstatus.backing.val & ~mask) | (val & mask); |             auto new_val = (mstatus.backing.val & ~mask) | (val & mask); | ||||||
|             mstatus = new_val; |             mstatus = new_val; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         T satp; |         T satp; | ||||||
|  |  | ||||||
|         static constexpr uint32_t get_mask() { |         static constexpr uint32_t get_mask(unsigned priv_lvl) { | ||||||
|             return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011  // only machine mode is supported | #if __cplusplus < 201402L | ||||||
|  |             return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL; | ||||||
|  | #else | ||||||
|  |             switch (priv_lvl) { | ||||||
|  |             case PRIV_U: return 0x80000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001 | ||||||
|  |             default:     return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011 | ||||||
|  |             } | ||||||
|  | #endif | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |     using hart_state_type = hart_state<reg_t>; | ||||||
|  |  | ||||||
|     constexpr reg_t get_irq_mask() { |     constexpr reg_t get_irq_mask(size_t mode) { | ||||||
|         return 0b101110111011; // only machine mode is supported |         std::array<const reg_t, 4> m = {{ | ||||||
|  |             0b000100010001, // U mode | ||||||
|  |             0b001100110011, // S mode | ||||||
|  |             0, | ||||||
|  |             0b101110111011 // M mode | ||||||
|  |         }}; | ||||||
|  |         return m[mode]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     riscv_hart_mu_p(); |     riscv_hart_mu_p(); | ||||||
| @@ -338,8 +197,8 @@ public: | |||||||
| 	void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; }; | 	void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; }; | ||||||
|  |  | ||||||
|     void disass_output(uint64_t pc, const std::string instr) override { |     void disass_output(uint64_t pc, const std::string instr) override { | ||||||
|         CLOG(INFO, disass) << fmt::format("0x{:016x}    {:40} [s:0x{:x};c:{}]", |         CLOG(INFO, disass) << fmt::format("0x{:016x}    {:40} [p:{};s:0x{:x};c:{}]", | ||||||
|                 pc, instr, (reg_t)state.mstatus, this->reg.icount); |                 pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; } |     iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; } | ||||||
| @@ -359,7 +218,7 @@ public: | |||||||
| protected: | protected: | ||||||
|     struct riscv_instrumentation_if : public iss::instrumentation_if { |     struct riscv_instrumentation_if : public iss::instrumentation_if { | ||||||
|  |  | ||||||
|         riscv_instrumentation_if(riscv_hart_mu_p<BASE> &arch) |         riscv_instrumentation_if(riscv_hart_mu_p<BASE, PMP> &arch) | ||||||
|         : arch(arch) {} |         : arch(arch) {} | ||||||
|         /** |         /** | ||||||
|          * get the name of this architecture |          * get the name of this architecture | ||||||
| @@ -374,7 +233,7 @@ protected: | |||||||
|  |  | ||||||
|         virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; }; |         virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; }; | ||||||
|  |  | ||||||
|         riscv_hart_mu_p<BASE> &arch; |         riscv_hart_mu_p<BASE, PMP> &arch; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     friend struct riscv_instrumentation_if; |     friend struct riscv_instrumentation_if; | ||||||
| @@ -387,7 +246,7 @@ protected: | |||||||
|     virtual iss::status read_csr(unsigned addr, reg_t &val); |     virtual iss::status read_csr(unsigned addr, reg_t &val); | ||||||
|     virtual iss::status write_csr(unsigned addr, reg_t val); |     virtual iss::status write_csr(unsigned addr, reg_t val); | ||||||
|  |  | ||||||
|     hart_state<reg_t> state; |     hart_state_type state; | ||||||
|     uint64_t cycle_offset; |     uint64_t cycle_offset; | ||||||
|     reg_t fault_data; |     reg_t fault_data; | ||||||
|     uint64_t tohost = tohost_dflt; |     uint64_t tohost = tohost_dflt; | ||||||
| @@ -427,8 +286,8 @@ protected: | |||||||
|     void check_interrupt(); |     void check_interrupt(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename BASE> | template <typename BASE, bool PMP> | ||||||
| riscv_hart_mu_p<BASE>::riscv_hart_mu_p() | riscv_hart_mu_p<BASE, PMP>::riscv_hart_mu_p() | ||||||
| : state() | : state() | ||||||
| , cycle_offset(0) | , cycle_offset(0) | ||||||
| , instr_if(*this) { | , instr_if(*this) { | ||||||
| @@ -437,33 +296,39 @@ riscv_hart_mu_p<BASE>::riscv_hart_mu_p() | |||||||
|     for (unsigned addr = mcycle; addr <= hpmcounter31; ++addr) csr_wr_cb[addr] = nullptr; |     for (unsigned addr = mcycle; addr <= hpmcounter31; ++addr) csr_wr_cb[addr] = nullptr; | ||||||
|     for (unsigned addr = mcycleh; addr <= hpmcounter31h; ++addr) csr_wr_cb[addr] = nullptr; |     for (unsigned addr = mcycleh; addr <= hpmcounter31h; ++addr) csr_wr_cb[addr] = nullptr; | ||||||
|     // special handling |     // special handling | ||||||
|     csr_rd_cb[time] = &riscv_hart_mu_p<BASE>::read_time; |     csr_rd_cb[time] = &this_class::read_time; | ||||||
|     csr_wr_cb[time] = nullptr; |     csr_wr_cb[time] = nullptr; | ||||||
|     csr_rd_cb[timeh] = &riscv_hart_mu_p<BASE>::read_time; |     csr_rd_cb[timeh] = &this_class::read_time; | ||||||
|     csr_wr_cb[timeh] = nullptr; |     csr_wr_cb[timeh] = nullptr; | ||||||
|     csr_rd_cb[mcycle] = &riscv_hart_mu_p<BASE>::read_cycle; |     csr_rd_cb[mcycle] = &this_class::read_cycle; | ||||||
|     csr_rd_cb[mcycleh] = &riscv_hart_mu_p<BASE>::read_cycle; |     csr_rd_cb[mcycleh] = &this_class::read_cycle; | ||||||
|     csr_rd_cb[minstret] = &riscv_hart_mu_p<BASE>::read_cycle; |     csr_rd_cb[minstret] = &this_class::read_cycle; | ||||||
|     csr_rd_cb[minstreth] = &riscv_hart_mu_p<BASE>::read_cycle; |     csr_rd_cb[minstreth] = &this_class::read_cycle; | ||||||
|     csr_rd_cb[mstatus] = &riscv_hart_mu_p<BASE>::read_status; |     csr_rd_cb[mstatus] = &this_class::read_status; | ||||||
|     csr_wr_cb[mstatus] = &riscv_hart_mu_p<BASE>::write_status; |     csr_wr_cb[mstatus] = &this_class::write_status; | ||||||
|     csr_rd_cb[mip] = &riscv_hart_mu_p<BASE>::read_ip; |     csr_rd_cb[ustatus] = &this_class::read_status; | ||||||
|     csr_wr_cb[mip] = &riscv_hart_mu_p<BASE>::write_ip; |     csr_wr_cb[ustatus] = &this_class::write_status; | ||||||
|     csr_rd_cb[mie] = &riscv_hart_mu_p<BASE>::read_ie; |     csr_rd_cb[mip] = &this_class::read_ip; | ||||||
|     csr_wr_cb[mie] = &riscv_hart_mu_p<BASE>::write_ie; |     csr_wr_cb[mip] = &this_class::write_ip; | ||||||
|     csr_rd_cb[mhartid] = &riscv_hart_mu_p<BASE>::read_hartid; |     csr_rd_cb[uip] = &this_class::read_ip; | ||||||
|  |     csr_wr_cb[uip] = &this_class::write_ip; | ||||||
|  |     csr_rd_cb[mie] = &this_class::read_ie; | ||||||
|  |     csr_wr_cb[mie] = &this_class::write_ie; | ||||||
|  |     csr_rd_cb[uie] = &this_class::read_ie; | ||||||
|  |     csr_wr_cb[uie] = &this_class::write_ie; | ||||||
|  |     csr_rd_cb[mhartid] = &this_class::read_hartid; | ||||||
|     // common regs |     // common regs | ||||||
|     const std::array<unsigned, 6> addrs{{mepc, mtvec, mscratch, mcause, mtval, mscratch}}; |     const std::array<unsigned, 6> addrs{{mepc, mtvec, mscratch, mcause, mtval, mscratch}}; | ||||||
|     for(auto addr: addrs) { |     for(auto addr: addrs) { | ||||||
|         csr_rd_cb[addr] = &riscv_hart_mu_p<BASE>::read_reg; |         csr_rd_cb[addr] = &this_class::read_reg; | ||||||
|         csr_wr_cb[addr] = &riscv_hart_mu_p<BASE>::write_reg; |         csr_wr_cb[addr] = &this_class::write_reg; | ||||||
|     } |     } | ||||||
|     // read-only registers |     // read-only registers | ||||||
|     csr_rd_cb[misa] = &riscv_hart_mu_p<BASE>::read_reg; |     csr_rd_cb[misa] = &this_class::read_reg; | ||||||
|     csr_wr_cb[misa] = nullptr; |     csr_wr_cb[misa] = nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> std::pair<uint64_t, bool> riscv_hart_mu_p<BASE>::load_file(std::string name, int type) { | template <typename BASE, bool PMP> std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, PMP>::load_file(std::string name, int type) { | ||||||
|     FILE *fp = fopen(name.c_str(), "r"); |     FILE *fp = fopen(name.c_str(), "r"); | ||||||
|     if (fp) { |     if (fp) { | ||||||
|         std::array<char, 5> buf; |         std::array<char, 5> buf; | ||||||
| @@ -507,8 +372,8 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_mu_p<BASE>::load_f | |||||||
|     throw std::runtime_error("memory load file not found"); |     throw std::runtime_error("memory load file not found"); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> | template <typename BASE, bool PMP> | ||||||
| iss::status riscv_hart_mu_p<BASE>::read(const address_type type, const access_type access, const uint32_t space, | iss::status riscv_hart_mu_p<BASE, PMP>::read(const address_type type, const access_type access, const uint32_t space, | ||||||
|         const uint64_t addr, const unsigned length, uint8_t *const data) { |         const uint64_t addr, const unsigned length, uint8_t *const data) { | ||||||
| #ifndef NDEBUG | #ifndef NDEBUG | ||||||
|     if (access && iss::access_type::DEBUG) { |     if (access && iss::access_type::DEBUG) { | ||||||
| @@ -565,8 +430,8 @@ iss::status riscv_hart_mu_p<BASE>::read(const address_type type, const access_ty | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> | template <typename BASE, bool PMP> | ||||||
| iss::status riscv_hart_mu_p<BASE>::write(const address_type type, const access_type access, const uint32_t space, | iss::status riscv_hart_mu_p<BASE, PMP>::write(const address_type type, const access_type access, const uint32_t space, | ||||||
|         const uint64_t addr, const unsigned length, const uint8_t *const data) { |         const uint64_t addr, const unsigned length, const uint8_t *const data) { | ||||||
| #ifndef NDEBUG | #ifndef NDEBUG | ||||||
|     const char *prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; |     const char *prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; | ||||||
| @@ -672,7 +537,7 @@ iss::status riscv_hart_mu_p<BASE>::write(const address_type type, const access_t | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::read_csr(unsigned addr, reg_t &val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_csr(unsigned addr, reg_t &val) { | ||||||
|     if (addr >= csr.size()) return iss::Err; |     if (addr >= csr.size()) return iss::Err; | ||||||
|     auto req_priv_lvl = (addr >> 8) & 0x3; |     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||||
|     if (this->reg.PRIV < req_priv_lvl) // not having required privileges |     if (this->reg.PRIV < req_priv_lvl) // not having required privileges | ||||||
| @@ -683,7 +548,7 @@ template <typename BASE> iss::status riscv_hart_mu_p<BASE>::read_csr(unsigned ad | |||||||
|     return (this->*(it->second))(addr, val); |     return (this->*(it->second))(addr, val); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::write_csr(unsigned addr, reg_t val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_csr(unsigned addr, reg_t val) { | ||||||
|     if (addr >= csr.size()) return iss::Err; |     if (addr >= csr.size()) return iss::Err; | ||||||
|     auto req_priv_lvl = (addr >> 8) & 0x3; |     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||||
|     if (this->reg.PRIV < req_priv_lvl) // not having required privileges |     if (this->reg.PRIV < req_priv_lvl) // not having required privileges | ||||||
| @@ -696,17 +561,17 @@ template <typename BASE> iss::status riscv_hart_mu_p<BASE>::write_csr(unsigned a | |||||||
|     return (this->*(it->second))(addr, val); |     return (this->*(it->second))(addr, val); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::read_reg(unsigned addr, reg_t &val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_reg(unsigned addr, reg_t &val) { | ||||||
|     val = csr[addr]; |     val = csr[addr]; | ||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::write_reg(unsigned addr, reg_t val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_reg(unsigned addr, reg_t val) { | ||||||
|     csr[addr] = val; |     csr[addr] = val; | ||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::read_cycle(unsigned addr, reg_t &val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_cycle(unsigned addr, reg_t &val) { | ||||||
|     auto cycle_val = this->reg.icount + cycle_offset; |     auto cycle_val = this->reg.icount + cycle_offset; | ||||||
|     if (addr == mcycle) { |     if (addr == mcycle) { | ||||||
|         val = static_cast<reg_t>(cycle_val); |         val = static_cast<reg_t>(cycle_val); | ||||||
| @@ -717,7 +582,7 @@ template <typename BASE> iss::status riscv_hart_mu_p<BASE>::read_cycle(unsigned | |||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::read_time(unsigned addr, reg_t &val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_time(unsigned addr, reg_t &val) { | ||||||
|     uint64_t time_val = (this->reg.icount + cycle_offset) / (100000000 / 32768 - 1); //-> ~3052; |     uint64_t time_val = (this->reg.icount + cycle_offset) / (100000000 / 32768 - 1); //-> ~3052; | ||||||
|     if (addr == time) { |     if (addr == time) { | ||||||
|         val = static_cast<reg_t>(time_val); |         val = static_cast<reg_t>(time_val); | ||||||
| @@ -728,51 +593,55 @@ template <typename BASE> iss::status riscv_hart_mu_p<BASE>::read_time(unsigned a | |||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::read_status(unsigned addr, reg_t &val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_status(unsigned addr, reg_t &val) { | ||||||
|     val = state.mstatus & hart_state<reg_t>::get_mask(); |     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||||
|  |     val = state.mstatus & hart_state_type::get_mask(req_priv_lvl); | ||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::write_status(unsigned addr, reg_t val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_status(unsigned addr, reg_t val) { | ||||||
|     state.write_mstatus(val); |     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||||
|  |     state.write_mstatus(val, req_priv_lvl); | ||||||
|     check_interrupt(); |     check_interrupt(); | ||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::read_ie(unsigned addr, reg_t &val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_ie(unsigned addr, reg_t &val) { | ||||||
|     val = csr[mie]; |     val = csr[mie]; | ||||||
|     val &= csr[mideleg]; |     val &= csr[mideleg]; | ||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::read_hartid(unsigned addr, reg_t &val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_hartid(unsigned addr, reg_t &val) { | ||||||
|     val = mhartid_reg; |     val = mhartid_reg; | ||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::write_ie(unsigned addr, reg_t val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_ie(unsigned addr, reg_t val) { | ||||||
|     auto mask = get_irq_mask(); |     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||||
|  |     auto mask = get_irq_mask(req_priv_lvl); | ||||||
|     csr[mie] = (csr[mie] & ~mask) | (val & mask); |     csr[mie] = (csr[mie] & ~mask) | (val & mask); | ||||||
|     check_interrupt(); |     check_interrupt(); | ||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::read_ip(unsigned addr, reg_t &val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_ip(unsigned addr, reg_t &val) { | ||||||
|     val = csr[mip]; |     val = csr[mip]; | ||||||
|     val &= csr[mideleg]; |     val &= csr[mideleg]; | ||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::write_ip(unsigned addr, reg_t val) { | template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_ip(unsigned addr, reg_t val) { | ||||||
|     auto mask = get_irq_mask(); |     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||||
|  |     auto mask = get_irq_mask(req_priv_lvl); | ||||||
|     mask &= ~(1 << 7); // MTIP is read only |     mask &= ~(1 << 7); // MTIP is read only | ||||||
|     csr[mip] = (csr[mip] & ~mask) | (val & mask); |     csr[mip] = (csr[mip] & ~mask) | (val & mask); | ||||||
|     check_interrupt(); |     check_interrupt(); | ||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> | template <typename BASE, bool PMP> | ||||||
| iss::status riscv_hart_mu_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { | iss::status riscv_hart_mu_p<BASE, PMP>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { | ||||||
|     if ((paddr.val + length) > mem.size()) return iss::Err; |     if ((paddr.val + length) > mem.size()) return iss::Err; | ||||||
|     if(mem_read_cb) return mem_read_cb(paddr, length, data); |     if(mem_read_cb) return mem_read_cb(paddr, length, data); | ||||||
|     switch (paddr.val) { |     switch (paddr.val) { | ||||||
| @@ -797,8 +666,8 @@ iss::status riscv_hart_mu_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, | |||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> | template <typename BASE, bool PMP> | ||||||
| iss::status riscv_hart_mu_p<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) { | iss::status riscv_hart_mu_p<BASE, PMP>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) { | ||||||
|     if ((paddr.val + length) > mem.size()) return iss::Err; |     if ((paddr.val + length) > mem.size()) return iss::Err; | ||||||
|     if(mem_write_cb) return mem_write_cb(paddr, length, data); |     if(mem_write_cb) return mem_write_cb(paddr, length, data); | ||||||
|     switch (paddr.val) { |     switch (paddr.val) { | ||||||
| @@ -874,12 +743,12 @@ iss::status riscv_hart_mu_p<BASE>::write_mem(phys_addr_t paddr, unsigned length, | |||||||
|     return iss::Ok; |     return iss::Ok; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> inline void riscv_hart_mu_p<BASE>::reset(uint64_t address) { | template <typename BASE, bool PMP> inline void riscv_hart_mu_p<BASE, PMP>::reset(uint64_t address) { | ||||||
|     BASE::reset(address); |     BASE::reset(address); | ||||||
|     state.mstatus = hart_state<reg_t>::mstatus_reset_val; |     state.mstatus = hart_state_type::mstatus_reset_val; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> void riscv_hart_mu_p<BASE>::check_interrupt() { | template <typename BASE, bool PMP> void riscv_hart_mu_p<BASE, PMP>::check_interrupt() { | ||||||
|     auto ideleg = csr[mideleg]; |     auto ideleg = csr[mideleg]; | ||||||
|     // Multiple simultaneous interrupts and traps at the same privilege level are |     // Multiple simultaneous interrupts and traps at the same privilege level are | ||||||
|     // handled in the following decreasing priority order: |     // handled in the following decreasing priority order: | ||||||
| @@ -901,23 +770,36 @@ template <typename BASE> void riscv_hart_mu_p<BASE>::check_interrupt() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> uint64_t riscv_hart_mu_p<BASE>::enter_trap(uint64_t flags, uint64_t addr) { | template <typename BASE, bool PMP> uint64_t riscv_hart_mu_p<BASE, PMP>::enter_trap(uint64_t flags, uint64_t addr) { | ||||||
|     // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] |     // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] | ||||||
|     // calculate and write mcause val |     // calculate and write mcause val | ||||||
|     auto trap_id = bit_sub<0, 16>(flags); |     auto trap_id = bit_sub<0, 16>(flags); | ||||||
|     auto cause = bit_sub<16, 15>(flags); |     auto cause = bit_sub<16, 15>(flags); | ||||||
|     if (trap_id == 0 && cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause |     if (trap_id == 0 && cause == 11) cause = 0x8 + this->reg.PRIV; // adjust environment call cause | ||||||
|     // calculate effective privilege level |     // calculate effective privilege level | ||||||
|  |     auto new_priv = PRIV_M; | ||||||
|     if (trap_id == 0) { // exception |     if (trap_id == 0) { // exception | ||||||
|  |         if (this->reg.PRIV != PRIV_M && ((csr[medeleg] >> cause) & 0x1) != 0) | ||||||
|  |             new_priv = PRIV_U; | ||||||
|         // store ret addr in xepc register |         // store ret addr in xepc register | ||||||
|         csr[mepc] = static_cast<reg_t>(addr); // store actual address instruction of exception |         csr[uepc | (new_priv << 8)] = static_cast<reg_t>(addr); // store actual address instruction of exception | ||||||
|         csr[mtval] = fault_data; |         /* | ||||||
|  |          * write mtval if new_priv=M_MODE, spec says: | ||||||
|  |          * When a hardware breakpoint is triggered, or an instruction-fetch, load, | ||||||
|  |          * or store address-misaligned, | ||||||
|  |          * access, or page-fault exception occurs, mtval is written with the | ||||||
|  |          * faulting effective address. | ||||||
|  |          */ | ||||||
|  |         csr[utval | (new_priv << 8)] = fault_data; | ||||||
|         fault_data = 0; |         fault_data = 0; | ||||||
|     } else { |     } else { | ||||||
|         csr[mepc] = this->reg.NEXT_PC; // store next address if interrupt |         if (this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0) | ||||||
|  |             new_priv = PRIV_U; | ||||||
|  |         csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt | ||||||
|         this->reg.pending_trap = 0; |         this->reg.pending_trap = 0; | ||||||
|     } |     } | ||||||
|     csr[mcause] = (trap_id << 31) + cause; |     size_t adr = ucause | (new_priv << 8); | ||||||
|  |     csr[adr] = (trap_id << 31) + cause; | ||||||
|     // update mstatus |     // update mstatus | ||||||
|     // xPP field of mstatus is written with the active privilege mode at the time |     // xPP field of mstatus is written with the active privilege mode at the time | ||||||
|     // of the trap; the x PIE field of mstatus |     // of the trap; the x PIE field of mstatus | ||||||
| @@ -925,37 +807,64 @@ template <typename BASE> uint64_t riscv_hart_mu_p<BASE>::enter_trap(uint64_t fla | |||||||
|     // the trap; and the x IE field of mstatus |     // the trap; and the x IE field of mstatus | ||||||
|     // is cleared |     // is cleared | ||||||
|     // store the actual privilege level in yPP and store interrupt enable flags |     // store the actual privilege level in yPP and store interrupt enable flags | ||||||
|     state.mstatus.MPP = PRIV_M; |     switch (new_priv) { | ||||||
|  |     case PRIV_M: | ||||||
|  |         state.mstatus.MPP = this->reg.PRIV; | ||||||
|     	state.mstatus.MPIE = state.mstatus.MIE; |     	state.mstatus.MPIE = state.mstatus.MIE; | ||||||
|     	state.mstatus.MIE = false; |     	state.mstatus.MIE = false; | ||||||
|  |         break; | ||||||
|  |     case PRIV_U: | ||||||
|  |         state.mstatus.UPIE = state.mstatus.UIE; | ||||||
|  |         state.mstatus.UIE = false; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // get trap vector |     // get trap vector | ||||||
|     auto ivec = csr[mtvec]; |     auto ivec = csr[utvec | (new_priv << 8)]; | ||||||
|     // calculate addr// set NEXT_PC to trap addressess to jump to based on MODE |     // calculate addr// set NEXT_PC to trap addressess to jump to based on MODE | ||||||
|     // bits in mtvec |     // bits in mtvec | ||||||
|     this->reg.NEXT_PC = ivec & ~0x1UL; |     this->reg.NEXT_PC = ivec & ~0x1UL; | ||||||
|     if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause; |     if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause; | ||||||
|     // reset trap state |     // reset trap state | ||||||
|     this->reg.PRIV = PRIV_M; |     this->reg.PRIV = new_priv; | ||||||
|     this->reg.trap_state = 0; |     this->reg.trap_state = 0; | ||||||
|     std::array<char, 32> buffer; |     std::array<char, 32> buffer; | ||||||
|     sprintf(buffer.data(), "0x%016lx", addr); |     sprintf(buffer.data(), "0x%016lx", addr); | ||||||
|     if((flags&0xffffffff) != 0xffffffff) |     if((flags&0xffffffff) != 0xffffffff) | ||||||
|     CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" |     CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" | ||||||
|                        << (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" << cause << ")" |                        << (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" << cause << ")" | ||||||
|                        << " at address " << buffer.data() << " occurred"; |                        << " at address " << buffer.data() << " occurred, changing privilege level from " | ||||||
|  |                        << lvl[this->reg.PRIV] << " to " << lvl[new_priv]; | ||||||
|     return this->reg.NEXT_PC; |     return this->reg.NEXT_PC; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename BASE> uint64_t riscv_hart_mu_p<BASE>::leave_trap(uint64_t flags) { | template <typename BASE, bool PMP> uint64_t riscv_hart_mu_p<BASE, PMP>::leave_trap(uint64_t flags) { | ||||||
|  |     auto inst_priv = (flags & 0x3)? 3:0; | ||||||
|  |     auto status = state.mstatus; | ||||||
|  |  | ||||||
|  |     // pop the relevant lower-privilege interrupt enable and privilege mode stack | ||||||
|  |     // clear respective yIE | ||||||
|  |     switch (inst_priv) { | ||||||
|  |     case PRIV_M: | ||||||
|  |         this->reg.PRIV = state.mstatus.MPP; | ||||||
|  |         state.mstatus.MPP = 0; // clear mpp to U mode | ||||||
|         state.mstatus.MIE = state.mstatus.MPIE; |         state.mstatus.MIE = state.mstatus.MPIE; | ||||||
|  |         break; | ||||||
|  |     case PRIV_U: | ||||||
|  |         this->reg.PRIV = 0; | ||||||
|  |         state.mstatus.UIE = state.mstatus.UPIE; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|     // sets the pc to the value stored in the x epc register. |     // sets the pc to the value stored in the x epc register. | ||||||
|     this->reg.NEXT_PC = csr[mepc]; |     this->reg.NEXT_PC = csr[uepc | inst_priv << 8]; | ||||||
|     CLOG(INFO, disass) << "Executing xRET"; |     CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[this->reg.PRIV] << " to " | ||||||
|  |                        << lvl[this->reg.PRIV]; | ||||||
|     return this->reg.NEXT_PC; |     return this->reg.NEXT_PC; | ||||||
| } | } | ||||||
|  |  | ||||||
| } // namespace arch | } // namespace arch | ||||||
| } // namespace iss | } // namespace iss | ||||||
|  |  | ||||||
| #endif /* _RISCV_CORE_H_ */ | #endif /* _RISCV_HART_MU_P_H */ | ||||||
|   | |||||||
| @@ -48,16 +48,6 @@ class scv_tr_stream; | |||||||
| struct _scv_tr_generator_default_data; | struct _scv_tr_generator_default_data; | ||||||
| template <class T_begin, class T_end> class scv_tr_generator; | template <class T_begin, class T_end> class scv_tr_generator; | ||||||
|  |  | ||||||
| namespace iss { |  | ||||||
| class vm_if; |  | ||||||
| namespace arch { |  | ||||||
| template <typename BASE> class riscv_hart_m_p; |  | ||||||
| } |  | ||||||
| namespace debugger { |  | ||||||
| class target_adapter_if; |  | ||||||
| } |  | ||||||
| } // namespace iss |  | ||||||
|  |  | ||||||
| namespace sysc { | namespace sysc { | ||||||
|  |  | ||||||
| class tlm_dmi_ext : public tlm::tlm_dmi { | class tlm_dmi_ext : public tlm::tlm_dmi { | ||||||
| @@ -97,6 +87,8 @@ public: | |||||||
|  |  | ||||||
|     cci::cci_param<uint64_t> reset_address{"reset_address", 0ULL}; |     cci::cci_param<uint64_t> reset_address{"reset_address", 0ULL}; | ||||||
|  |  | ||||||
|  |     cci::cci_param<std::string> core_type{"core_type", "tgc_c"}; | ||||||
|  |  | ||||||
|     cci::cci_param<std::string> backend{"backend", "interp"}; |     cci::cci_param<std::string> backend{"backend", "interp"}; | ||||||
|  |  | ||||||
|     cci::cci_param<unsigned short> gdb_server_port{"gdb_server_port", 0}; |     cci::cci_param<unsigned short> gdb_server_port{"gdb_server_port", 0}; | ||||||
| @@ -145,9 +137,7 @@ protected: | |||||||
|     tlm_utils::tlm_quantumkeeper quantum_keeper; |     tlm_utils::tlm_quantumkeeper quantum_keeper; | ||||||
|     std::vector<uint8_t> write_buf; |     std::vector<uint8_t> write_buf; | ||||||
|     std::unique_ptr<core_wrapper> cpu; |     std::unique_ptr<core_wrapper> cpu; | ||||||
|     std::unique_ptr<iss::vm_if> vm; |  | ||||||
|     sc_core::sc_time curr_clk; |     sc_core::sc_time curr_clk; | ||||||
|     iss::debugger::target_adapter_if *tgt_adapter; |  | ||||||
| #ifdef WITH_SCV | #ifdef WITH_SCV | ||||||
|     //! transaction recording database |     //! transaction recording database | ||||||
|     scv_tr_db *m_db; |     scv_tr_db *m_db; | ||||||
|   | |||||||
| @@ -31,17 +31,20 @@ | |||||||
|  *******************************************************************************/ |  *******************************************************************************/ | ||||||
|  |  | ||||||
| #include "sysc/core_complex.h" | #include "sysc/core_complex.h" | ||||||
|  | #ifdef CORE_TGC_B | ||||||
|  | #include "iss/arch/riscv_hart_m_p.h" | ||||||
|  | #include "iss/arch/tgc_b.h" | ||||||
|  | using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>; | ||||||
|  | #endif | ||||||
| #ifdef CORE_TGC_C | #ifdef CORE_TGC_C | ||||||
| #include "iss/arch/riscv_hart_m_p.h" | #include "iss/arch/riscv_hart_m_p.h" | ||||||
| #include "iss/arch/tgc_c.h" | #include "iss/arch/tgc_c.h" | ||||||
| using core_type = iss::arch::tgc_c; | using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>; | ||||||
| using plat_type = iss::arch::riscv_hart_m_p<core_type>; |  | ||||||
| #endif | #endif | ||||||
| #ifdef CORE_TGC_D | #ifdef CORE_TGC_D | ||||||
| #include "iss/arch/riscv_hart_mu_p.h" | #include "iss/arch/riscv_hart_mu_p.h" | ||||||
| #include "iss/arch/tgc_d.h" | #include "iss/arch/tgc_d.h" | ||||||
| using core_type = iss::arch::tgc_d; | using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d>; | ||||||
| using plat_type = iss::arch::riscv_hart_mu_p<core_type>; |  | ||||||
| #endif | #endif | ||||||
| #include "iss/debugger/encoderdecoder.h" | #include "iss/debugger/encoderdecoder.h" | ||||||
| #include "iss/debugger/gdb_session.h" | #include "iss/debugger/gdb_session.h" | ||||||
| @@ -53,6 +56,10 @@ using plat_type = iss::arch::riscv_hart_mu_p<core_type>; | |||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <sstream> | #include <sstream> | ||||||
|  |  | ||||||
|  | #define STR(X) #X | ||||||
|  | #define CREATE_CORE(CN) \ | ||||||
|  | else if (type == STR(CN)) { std::tie(cpu, vm) = create_core<CN ## _plat_type>(backend, gdb_port, hart_id); } | ||||||
|  |  | ||||||
| #ifdef WITH_SCV | #ifdef WITH_SCV | ||||||
| #include <array> | #include <array> | ||||||
| #include <scv.h> | #include <scv.h> | ||||||
| @@ -67,41 +74,17 @@ using namespace sc_core; | |||||||
|  |  | ||||||
| namespace { | namespace { | ||||||
| iss::debugger::encoder_decoder encdec; | iss::debugger::encoder_decoder encdec; | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| namespace { |  | ||||||
|  |  | ||||||
| std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; | std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; | ||||||
|  |  | ||||||
| std::array<const char*, 16> trap_str = { { |  | ||||||
| 		"Instruction address misaligned", |  | ||||||
| 		"Instruction access fault", |  | ||||||
| 		"Illegal instruction", |  | ||||||
| 		"Breakpoint", |  | ||||||
| 		"Load address misaligned", |  | ||||||
| 		"Load access fault", |  | ||||||
| 		"Store/AMO address misaligned", |  | ||||||
| 		"Store/AMO access fault", |  | ||||||
| 		"Environment call from U-mode", |  | ||||||
| 		"Environment call from S-mode", |  | ||||||
| 		"Reserved", |  | ||||||
| 		"Environment call from M-mode", |  | ||||||
| 		"Instruction page fault", |  | ||||||
| 		"Load page fault", |  | ||||||
| 		"Reserved", |  | ||||||
| 		"Store/AMO page fault" |  | ||||||
| } }; |  | ||||||
| std::array<const char*, 12> irq_str = { { |  | ||||||
| 		"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt", |  | ||||||
| 		"User timer interrupt",    "Supervisor timer interrupt",    "Reserved", "Machine timer interrupt", |  | ||||||
| 		"User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt" } }; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| class core_wrapper : public plat_type { | template<typename PLAT> | ||||||
|  | class core_wrapper_t : public PLAT { | ||||||
| public: | public: | ||||||
|     using phys_addr_t = typename arch::traits<core_type>::phys_addr_t; |     using reg_t       = typename arch::traits<typename PLAT::super>::reg_t; | ||||||
|     core_wrapper(core_complex *owner) |     using phys_addr_t = typename arch::traits<typename PLAT::super>::phys_addr_t; | ||||||
|  |     using heart_state_t = typename PLAT::hart_state_type; | ||||||
|  |     core_wrapper_t(core_complex *owner) | ||||||
|     : owner(owner) { } |     : owner(owner) { } | ||||||
|  |  | ||||||
|     uint32_t get_mode() { return this->reg.PRIV; } |     uint32_t get_mode() { return this->reg.PRIV; } | ||||||
| @@ -110,10 +93,10 @@ public: | |||||||
|  |  | ||||||
|     inline bool get_interrupt_execution() { return this->interrupt_sim; } |     inline bool get_interrupt_execution() { return this->interrupt_sim; } | ||||||
|  |  | ||||||
|     plat_type::hart_state<plat_type::reg_t> &get_state() { return this->state; } |     heart_state_t &get_state() { return this->state; } | ||||||
|  |  | ||||||
|     void notify_phase(exec_phase p) override { |     void notify_phase(iss::arch_if::exec_phase p) override { | ||||||
|         if (p == ISTART) owner->sync(this->reg.icount + cycle_offset); |         if (p == iss::arch_if::ISTART) owner->sync(this->reg.icount); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     sync_type needed_sync() const override { return PRE_SYNC; } |     sync_type needed_sync() const override { return PRE_SYNC; } | ||||||
| @@ -122,7 +105,7 @@ public: | |||||||
|         if (INFO <= Log<Output2FILE<disass>>::reporting_level() && Output2FILE<disass>::stream()) { |         if (INFO <= Log<Output2FILE<disass>>::reporting_level() && Output2FILE<disass>::stream()) { | ||||||
|             std::stringstream s; |             std::stringstream s; | ||||||
|             s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0') |             s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0') | ||||||
|               << std::setw(sizeof(reg_t) * 2) << (reg_t)state.mstatus << std::dec << ";c:" << this->reg.icount << "]"; |               << std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:" << this->reg.icount << "]"; | ||||||
|             Log<Output2FILE<disass>>().get(INFO, "disass") |             Log<Output2FILE<disass>>().get(INFO, "disass") | ||||||
|                 << "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40) |                 << "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40) | ||||||
|                 << std::setfill(' ') << std::left << instr << s.str(); |                 << std::setfill(' ') << std::left << instr << s.str(); | ||||||
| @@ -165,7 +148,7 @@ public: | |||||||
|             } |             } | ||||||
|             return ret?Ok:Err; |             return ret?Ok:Err; | ||||||
|         } else { |         } else { | ||||||
|             return plat_type::read_csr(addr, val); |             return PLAT::read_csr(addr, val); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -174,11 +157,11 @@ public: | |||||||
|         do { |         do { | ||||||
|             wait(wfi_evt); |             wait(wfi_evt); | ||||||
|         } while (this->reg.pending_trap == 0); |         } while (this->reg.pending_trap == 0); | ||||||
|         plat_type::wait_until(flags); |         PLAT::wait_until(flags); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void local_irq(short id, bool value) { |     void local_irq(short id, bool value) { | ||||||
|         plat_type::reg_t mask = 0; |         reg_t mask = 0; | ||||||
|         switch (id) { |         switch (id) { | ||||||
|         case 16: // SW |         case 16: // SW | ||||||
|             mask = 1 << 3; |             mask = 1 << 3; | ||||||
| @@ -238,11 +221,82 @@ int cmd_sysc(int argc, char *argv[], debugger::out_func of, debugger::data_func | |||||||
|     return Err; |     return Err; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | using cpu_ptr = std::unique_ptr<iss::arch_if>; | ||||||
|  | using vm_ptr= std::unique_ptr<iss::vm_if>; | ||||||
|  |  | ||||||
|  | class core_wrapper { | ||||||
|  | public: | ||||||
|  |     core_wrapper(core_complex *owner) : owner(owner) { } | ||||||
|  |  | ||||||
|  |     void reset(uint64_t addr){vm->reset(addr);} | ||||||
|  |     inline void start(){vm->start();} | ||||||
|  |     inline std::pair<uint64_t, bool> load_file(std::string const& name){ return cpu->load_file(name);}; | ||||||
|  |  | ||||||
|  |     std::function<unsigned(void)> get_mode; | ||||||
|  |     std::function<uint64_t(void)> get_state; | ||||||
|  |     std::function<bool(void)> get_interrupt_execution; | ||||||
|  |     std::function<void(bool)> set_interrupt_execution; | ||||||
|  |     std::function<void(short, bool)> local_irq; | ||||||
|  |  | ||||||
|  |     template<typename PLAT> | ||||||
|  |     std::tuple<cpu_ptr, vm_ptr> create_core(std::string const& backend, unsigned gdb_port, uint32_t hart_id){ | ||||||
|  |         auto* lcpu = new core_wrapper_t<PLAT>(owner); | ||||||
|  |         lcpu->set_mhartid(hart_id); | ||||||
|  |         get_mode = [lcpu]() { return lcpu->get_mode(); }; | ||||||
|  |         get_state = [lcpu]() { return lcpu->get_state().mstatus.backing.val; }; | ||||||
|  |         get_interrupt_execution = [lcpu]() { return lcpu->get_interrupt_execution(); }; | ||||||
|  |         set_interrupt_execution = [lcpu](bool b) { return lcpu->set_interrupt_execution(b); }; | ||||||
|  |         local_irq = [lcpu](short s, bool b) { return lcpu->local_irq(s, b); }; | ||||||
|  |         if(backend == "interp") | ||||||
|  |             return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(lcpu, gdb_port)}}; | ||||||
|  | #ifdef WITH_LLVM | ||||||
|  |         if(backend == "llvm") | ||||||
|  |             return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}}; | ||||||
|  | #endif | ||||||
|  | #ifdef WITH_TCC | ||||||
|  |         if(backend == "tcc") | ||||||
|  |     s        return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}}; | ||||||
|  | #endif | ||||||
|  |         return {nullptr, nullptr}; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id){ | ||||||
|  |        if (type == "") { | ||||||
|  |            LOG(ERROR) << "Illegal argument value for core type: " << type << std::endl; | ||||||
|  |        } | ||||||
|  | #ifdef CORE_TGC_B | ||||||
|  |        CREATE_CORE(tgc_c) | ||||||
|  | #endif | ||||||
|  | #ifdef CORE_TGC_C | ||||||
|  |        CREATE_CORE(tgc_c) | ||||||
|  | #endif | ||||||
|  | #ifdef CORE_TGC_D | ||||||
|  |        CREATE_CORE(tgc_d) | ||||||
|  | #endif | ||||||
|  |         else { | ||||||
|  |             LOG(ERROR) << "Illegal argument value for core type: " << type << std::endl; | ||||||
|  |         } | ||||||
|  |         auto *srv = debugger::server<debugger::gdb_session>::get(); | ||||||
|  |         if (srv) tgt_adapter = srv->get_target(); | ||||||
|  |         if (tgt_adapter) | ||||||
|  |             tgt_adapter->add_custom_command( | ||||||
|  |                 {"sysc", [this](int argc, char *argv[], debugger::out_func of, | ||||||
|  |                                 debugger::data_func df) -> int { return cmd_sysc(argc, argv, of, df, tgt_adapter); }, | ||||||
|  |                  "SystemC sub-commands: break <time>, print_time"}); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     core_complex * const owner; | ||||||
|  |     vm_ptr vm{nullptr}; | ||||||
|  |     cpu_ptr cpu{nullptr}; | ||||||
|  |     iss::debugger::target_adapter_if *tgt_adapter{nullptr}; | ||||||
|  | }; | ||||||
|  |  | ||||||
| core_complex::core_complex(sc_module_name name) | core_complex::core_complex(sc_module_name name) | ||||||
| : sc_module(name) | : sc_module(name) | ||||||
| , read_lut(tlm_dmi_ext()) | , read_lut(tlm_dmi_ext()) | ||||||
| , write_lut(tlm_dmi_ext()) | , write_lut(tlm_dmi_ext()) | ||||||
| , tgt_adapter(nullptr) |  | ||||||
| #ifdef WITH_SCV | #ifdef WITH_SCV | ||||||
| , m_db(scv_tr_db::get_default_db()) | , m_db(scv_tr_db::get_default_db()) | ||||||
| , stream_handle(nullptr) | , stream_handle(nullptr) | ||||||
| @@ -279,40 +333,16 @@ core_complex::~core_complex() = default; | |||||||
|  |  | ||||||
| void core_complex::trace(sc_trace_file *trf) const {} | void core_complex::trace(sc_trace_file *trf) const {} | ||||||
|  |  | ||||||
| using vm_ptr= std::unique_ptr<iss::vm_if>; |  | ||||||
| vm_ptr create_cpu(core_wrapper* cpu, std::string const& backend, unsigned gdb_port){ |  | ||||||
|     if(backend == "interp") |  | ||||||
|         return vm_ptr{iss::interp::create<core_type>(cpu, gdb_port)}; |  | ||||||
| #ifdef WITH_LLVM |  | ||||||
|     if(backend == "llvm") |  | ||||||
|         return vm_ptr{iss::llvm::create(lcpu, gdb_port)}; |  | ||||||
| #endif |  | ||||||
| #ifdef WITH_TCC |  | ||||||
|     if(backend == "tcc") |  | ||||||
|         return vm_ptr{iss::tcc::create<core_type>(cpu, gdb_port)}; |  | ||||||
| #endif |  | ||||||
|     return {nullptr}; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void core_complex::before_end_of_elaboration() { | void core_complex::before_end_of_elaboration() { | ||||||
|     SCCDEBUG(SCMOD)<<"instantiating iss::arch::tgf with "<<backend.get_value()<<" backend"; |     SCCDEBUG(SCMOD)<<"instantiating iss::arch::tgf with "<<backend.get_value()<<" backend"; | ||||||
|     cpu = scc::make_unique<core_wrapper>(this); |     cpu = scc::make_unique<core_wrapper>(this); | ||||||
|     cpu->set_mhartid(mhartid.get_value()); |     cpu->create_cpu(core_type.get_value(), backend.get_value(), gdb_server_port.get_value(), mhartid.get_value()); | ||||||
|  |     sc_assert(cpu->vm!=nullptr); | ||||||
|     vm = create_cpu(cpu.get(), backend.get_value(), gdb_server_port.get_value()); |  | ||||||
|     sc_assert(vm!=nullptr); |  | ||||||
| #ifdef WITH_SCV | #ifdef WITH_SCV | ||||||
|     vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr); |     cpu->vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr); | ||||||
| #else | #else | ||||||
|     vm->setDisassEnabled(enable_disass.get_value()); |     vm->setDisassEnabled(enable_disass.get_value()); | ||||||
| #endif | #endif | ||||||
|     auto *srv = debugger::server<debugger::gdb_session>::get(); |  | ||||||
|     if (srv) tgt_adapter = srv->get_target(); |  | ||||||
|     if (tgt_adapter) |  | ||||||
|         tgt_adapter->add_custom_command( |  | ||||||
|             {"sysc", [this](int argc, char *argv[], debugger::out_func of, |  | ||||||
|                             debugger::data_func df) -> int { return cmd_sysc(argc, argv, of, df, tgt_adapter); }, |  | ||||||
|              "SystemC sub-commands: break <time>, print_time"}); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void core_complex::start_of_simulation() { | void core_complex::start_of_simulation() { | ||||||
| @@ -344,7 +374,7 @@ void core_complex::disass_output(uint64_t pc, const std::string instr_str) { | |||||||
|     tr_handle.record_attribute("PC", pc); |     tr_handle.record_attribute("PC", pc); | ||||||
|     tr_handle.record_attribute("INSTR", instr_str); |     tr_handle.record_attribute("INSTR", instr_str); | ||||||
|     tr_handle.record_attribute("MODE", lvl[cpu->get_mode()]); |     tr_handle.record_attribute("MODE", lvl[cpu->get_mode()]); | ||||||
|     tr_handle.record_attribute("MSTATUS", cpu->get_state().mstatus.backing.val); |     tr_handle.record_attribute("MSTATUS", cpu->get_state()); | ||||||
|     tr_handle.record_attribute("LTIME_START", quantum_keeper.get_current_time().value() / 1000); |     tr_handle.record_attribute("LTIME_START", quantum_keeper.get_current_time().value() / 1000); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| @@ -375,7 +405,7 @@ void core_complex::run() { | |||||||
|             wait(clk_i.value_changed_event()); |             wait(clk_i.value_changed_event()); | ||||||
|         } |         } | ||||||
|         cpu->set_interrupt_execution(false); |         cpu->set_interrupt_execution(false); | ||||||
|         vm->start(); |         cpu->start(); | ||||||
|     } while (cpu->get_interrupt_execution()); |     } while (cpu->get_interrupt_execution()); | ||||||
|     sc_stop(); |     sc_stop(); | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user