Compare commits
	
		
			1 Commits
		
	
	
		
			9c456ba8f2
			...
			a35974c9f5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a35974c9f5 | 
| @@ -67,7 +67,15 @@ set_target_properties(${PROJECT_NAME} PROPERTIES | ||||
| if(SystemC_FOUND) | ||||
| 	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 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}) | ||||
| 	 | ||||
| 	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) | ||||
|   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. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
| @@ -32,11 +32,11 @@ | ||||
|  *       eyck@minres.com - initial implementation | ||||
|  ******************************************************************************/ | ||||
|  | ||||
| #ifndef _RISCV_CORE_H_ | ||||
| #define _RISCV_CORE_H_ | ||||
| #ifndef _RISCV_HART_M_P_H | ||||
| #define _RISCV_HART_M_P_H | ||||
|  | ||||
| #include "riscv_hart_common.h" | ||||
| #include "iss/arch/traits.h" | ||||
| #include "iss/arch_if.h" | ||||
| #include "iss/instrumentation_if.h" | ||||
| #include "iss/log_categories.h" | ||||
| #include "iss/vm_if.h" | ||||
| @@ -66,185 +66,30 @@ | ||||
| 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, | ||||
|     // 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 access fault",       // 1 | ||||
|                                           "Illegal instruction",            // 2 | ||||
|                                           "Breakpoint",                     // 3 | ||||
|                                           "Load address misaligned",        // 4 | ||||
|                                           "Load access fault",              // 5 | ||||
|                                           "Store/AMO address misaligned",   // 6 | ||||
|                                           "Store/AMO access fault",         // 7 | ||||
|                                           "Environment call from U-mode",   // 8 | ||||
|                                           "Environment call from S-mode",   // 9 | ||||
|                                           "Reserved",                       // a | ||||
|                                           "Environment call from M-mode",   // b | ||||
|                                           "Instruction page fault",         // c | ||||
|                                           "Load page fault",                // d | ||||
|                                           "Reserved",                       // e | ||||
|                                           "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"}}; | ||||
|  | ||||
| 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 { | ||||
| protected: | ||||
|     const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; | ||||
|     const std::array<const char *, 16> trap_str = {{"" | ||||
|                                               "Instruction address misaligned", // 0 | ||||
|                                               "Instruction access fault",       // 1 | ||||
|                                               "Illegal instruction",            // 2 | ||||
|                                               "Breakpoint",                     // 3 | ||||
|                                               "Load address misaligned",        // 4 | ||||
|                                               "Load access fault",              // 5 | ||||
|                                               "Store/AMO address misaligned",   // 6 | ||||
|                                               "Store/AMO access fault",         // 7 | ||||
|                                               "Environment call from U-mode",   // 8 | ||||
|                                               "Environment call from S-mode",   // 9 | ||||
|                                               "Reserved",                       // a | ||||
|                                               "Environment call from M-mode",   // b | ||||
|                                               "Instruction page fault",         // c | ||||
|                                               "Load page fault",                // d | ||||
|                                               "Reserved",                       // e | ||||
|                                               "Store/AMO page fault"}}; | ||||
|     const 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"}}; | ||||
| public: | ||||
|     using super = 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 | ||||
|         } | ||||
|     }; | ||||
|     using hart_state_type = hart_state<reg_t>; | ||||
|  | ||||
|     constexpr reg_t get_irq_mask() { | ||||
|         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 write_csr(unsigned addr, reg_t val); | ||||
|  | ||||
|     hart_state<reg_t> state; | ||||
|     hart_state_type state; | ||||
|     uint64_t cycle_offset; | ||||
|     reg_t fault_data; | ||||
|     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) { | ||||
|     val = state.mstatus & hart_state<reg_t>::get_mask(); | ||||
|     val = state.mstatus & hart_state_type::get_mask(); | ||||
|     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) { | ||||
|     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() { | ||||
| @@ -958,4 +804,4 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::leave_trap(uint64_t flag | ||||
| } // namespace arch | ||||
| } // 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. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
| @@ -32,11 +32,11 @@ | ||||
|  *       eyck@minres.com - initial implementation | ||||
|  ******************************************************************************/ | ||||
|  | ||||
| #ifndef _RISCV_CORE_H_ | ||||
| #define _RISCV_CORE_H_ | ||||
| #ifndef _RISCV_HART_MU_P_H | ||||
| #define _RISCV_HART_MU_P_H | ||||
|  | ||||
| #include "riscv_hart_common.h" | ||||
| #include "iss/arch/traits.h" | ||||
| #include "iss/arch_if.h" | ||||
| #include "iss/instrumentation_if.h" | ||||
| #include "iss/log_categories.h" | ||||
| #include "iss/vm_if.h" | ||||
| @@ -66,188 +66,33 @@ | ||||
| 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, | ||||
|     // 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 access fault",       // 1 | ||||
|                                           "Illegal instruction",            // 2 | ||||
|                                           "Breakpoint",                     // 3 | ||||
|                                           "Load address misaligned",        // 4 | ||||
|                                           "Load access fault",              // 5 | ||||
|                                           "Store/AMO address misaligned",   // 6 | ||||
|                                           "Store/AMO access fault",         // 7 | ||||
|                                           "Environment call from U-mode",   // 8 | ||||
|                                           "Environment call from S-mode",   // 9 | ||||
|                                           "Reserved",                       // a | ||||
|                                           "Environment call from M-mode",   // b | ||||
|                                           "Instruction page fault",         // c | ||||
|                                           "Load page fault",                // d | ||||
|                                           "Reserved",                       // e | ||||
|                                           "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"}}; | ||||
|  | ||||
| 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 { | ||||
| template <typename BASE, bool PMP=false> class riscv_hart_mu_p : public BASE { | ||||
| protected: | ||||
|     const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; | ||||
|     const std::array<const char *, 16> trap_str = {{"" | ||||
|                                               "Instruction address misaligned", // 0 | ||||
|                                               "Instruction access fault",       // 1 | ||||
|                                               "Illegal instruction",            // 2 | ||||
|                                               "Breakpoint",                     // 3 | ||||
|                                               "Load address misaligned",        // 4 | ||||
|                                               "Load access fault",              // 5 | ||||
|                                               "Store/AMO address misaligned",   // 6 | ||||
|                                               "Store/AMO access fault",         // 7 | ||||
|                                               "Environment call from U-mode",   // 8 | ||||
|                                               "Environment call from S-mode",   // 9 | ||||
|                                               "Reserved",                       // a | ||||
|                                               "Environment call from M-mode",   // b | ||||
|                                               "Instruction page fault",         // c | ||||
|                                               "Load page fault",                // d | ||||
|                                               "Reserved",                       // e | ||||
|                                               "Store/AMO page fault"}}; | ||||
|     const 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"}}; | ||||
| public: | ||||
|     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 reg_t = typename super::reg_t; | ||||
|     using addr_t = typename super::addr_t; | ||||
| @@ -301,21 +146,35 @@ public: | ||||
|  | ||||
|         static const reg_t mstatus_reset_val = 0; | ||||
|  | ||||
|         void write_mstatus(T val) { | ||||
|             auto mask = get_mask(); | ||||
|         void write_mstatus(T val, unsigned priv_lvl) { | ||||
|             auto mask = get_mask(priv_lvl); | ||||
|             auto new_val = (mstatus.backing.val & ~mask) | (val & mask); | ||||
|             mstatus = new_val; | ||||
|         } | ||||
|  | ||||
|         T satp; | ||||
|  | ||||
|         static constexpr uint32_t get_mask() { | ||||
|             return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011  // only machine mode is supported | ||||
|         static constexpr uint32_t get_mask(unsigned priv_lvl) { | ||||
| #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() { | ||||
|         return 0b101110111011; // only machine mode is supported | ||||
|     constexpr reg_t get_irq_mask(size_t mode) { | ||||
|         std::array<const reg_t, 4> m = {{ | ||||
|             0b000100010001, // U mode | ||||
|             0b001100110011, // S mode | ||||
|             0, | ||||
|             0b101110111011 // M mode | ||||
|         }}; | ||||
|         return m[mode]; | ||||
|     } | ||||
|  | ||||
|     riscv_hart_mu_p(); | ||||
| @@ -338,8 +197,8 @@ public: | ||||
| 	void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; }; | ||||
|  | ||||
|     void disass_output(uint64_t pc, const std::string instr) override { | ||||
|         CLOG(INFO, disass) << fmt::format("0x{:016x}    {:40} [s:0x{:x};c:{}]", | ||||
|                 pc, instr, (reg_t)state.mstatus, this->reg.icount); | ||||
|         CLOG(INFO, disass) << fmt::format("0x{:016x}    {:40} [p:{};s:0x{:x};c:{}]", | ||||
|                 pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount); | ||||
|     }; | ||||
|  | ||||
|     iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; } | ||||
| @@ -359,7 +218,7 @@ public: | ||||
| protected: | ||||
|     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) {} | ||||
|         /** | ||||
|          * get the name of this architecture | ||||
| @@ -374,7 +233,7 @@ protected: | ||||
|  | ||||
|         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; | ||||
| @@ -387,7 +246,7 @@ protected: | ||||
|     virtual iss::status read_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; | ||||
|     reg_t fault_data; | ||||
|     uint64_t tohost = tohost_dflt; | ||||
| @@ -427,8 +286,8 @@ protected: | ||||
|     void check_interrupt(); | ||||
| }; | ||||
|  | ||||
| template <typename BASE> | ||||
| riscv_hart_mu_p<BASE>::riscv_hart_mu_p() | ||||
| template <typename BASE, bool PMP> | ||||
| riscv_hart_mu_p<BASE, PMP>::riscv_hart_mu_p() | ||||
| : state() | ||||
| , cycle_offset(0) | ||||
| , 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 = mcycleh; addr <= hpmcounter31h; ++addr) csr_wr_cb[addr] = nullptr; | ||||
|     // 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_rd_cb[timeh] = &riscv_hart_mu_p<BASE>::read_time; | ||||
|     csr_rd_cb[timeh] = &this_class::read_time; | ||||
|     csr_wr_cb[timeh] = nullptr; | ||||
|     csr_rd_cb[mcycle] = &riscv_hart_mu_p<BASE>::read_cycle; | ||||
|     csr_rd_cb[mcycleh] = &riscv_hart_mu_p<BASE>::read_cycle; | ||||
|     csr_rd_cb[minstret] = &riscv_hart_mu_p<BASE>::read_cycle; | ||||
|     csr_rd_cb[minstreth] = &riscv_hart_mu_p<BASE>::read_cycle; | ||||
|     csr_rd_cb[mstatus] = &riscv_hart_mu_p<BASE>::read_status; | ||||
|     csr_wr_cb[mstatus] = &riscv_hart_mu_p<BASE>::write_status; | ||||
|     csr_rd_cb[mip] = &riscv_hart_mu_p<BASE>::read_ip; | ||||
|     csr_wr_cb[mip] = &riscv_hart_mu_p<BASE>::write_ip; | ||||
|     csr_rd_cb[mie] = &riscv_hart_mu_p<BASE>::read_ie; | ||||
|     csr_wr_cb[mie] = &riscv_hart_mu_p<BASE>::write_ie; | ||||
|     csr_rd_cb[mhartid] = &riscv_hart_mu_p<BASE>::read_hartid; | ||||
|     csr_rd_cb[mcycle] = &this_class::read_cycle; | ||||
|     csr_rd_cb[mcycleh] = &this_class::read_cycle; | ||||
|     csr_rd_cb[minstret] = &this_class::read_cycle; | ||||
|     csr_rd_cb[minstreth] = &this_class::read_cycle; | ||||
|     csr_rd_cb[mstatus] = &this_class::read_status; | ||||
|     csr_wr_cb[mstatus] = &this_class::write_status; | ||||
|     csr_rd_cb[ustatus] = &this_class::read_status; | ||||
|     csr_wr_cb[ustatus] = &this_class::write_status; | ||||
|     csr_rd_cb[mip] = &this_class::read_ip; | ||||
|     csr_wr_cb[mip] = &this_class::write_ip; | ||||
|     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 | ||||
|     const std::array<unsigned, 6> addrs{{mepc, mtvec, mscratch, mcause, mtval, mscratch}}; | ||||
|     for(auto addr: addrs) { | ||||
|         csr_rd_cb[addr] = &riscv_hart_mu_p<BASE>::read_reg; | ||||
|         csr_wr_cb[addr] = &riscv_hart_mu_p<BASE>::write_reg; | ||||
|         csr_rd_cb[addr] = &this_class::read_reg; | ||||
|         csr_wr_cb[addr] = &this_class::write_reg; | ||||
|     } | ||||
|     // 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; | ||||
| } | ||||
|  | ||||
| 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"); | ||||
|     if (fp) { | ||||
|         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"); | ||||
| } | ||||
|  | ||||
| template <typename BASE> | ||||
| iss::status riscv_hart_mu_p<BASE>::read(const address_type type, const access_type access, const uint32_t space, | ||||
| template <typename BASE, bool PMP> | ||||
| 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) { | ||||
| #ifndef NDEBUG | ||||
|     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> | ||||
| iss::status riscv_hart_mu_p<BASE>::write(const address_type type, const access_type access, const uint32_t space, | ||||
| template <typename BASE, bool PMP> | ||||
| 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) { | ||||
| #ifndef NDEBUG | ||||
|     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; | ||||
|     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||
|     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); | ||||
| } | ||||
|  | ||||
| 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; | ||||
|     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||
|     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); | ||||
| } | ||||
|  | ||||
| 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]; | ||||
|     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; | ||||
|     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; | ||||
|     if (addr == mcycle) { | ||||
|         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; | ||||
| } | ||||
|  | ||||
| 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; | ||||
|     if (addr == time) { | ||||
|         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; | ||||
| } | ||||
|  | ||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::read_status(unsigned addr, reg_t &val) { | ||||
|     val = state.mstatus & hart_state<reg_t>::get_mask(); | ||||
| template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_status(unsigned addr, reg_t &val) { | ||||
|     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||
|     val = state.mstatus & hart_state_type::get_mask(req_priv_lvl); | ||||
|     return iss::Ok; | ||||
| } | ||||
|  | ||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::write_status(unsigned addr, reg_t val) { | ||||
|     state.write_mstatus(val); | ||||
| template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_status(unsigned addr, reg_t val) { | ||||
|     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||
|     state.write_mstatus(val, req_priv_lvl); | ||||
|     check_interrupt(); | ||||
|     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[mideleg]; | ||||
|     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; | ||||
|     return iss::Ok; | ||||
| } | ||||
|  | ||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::write_ie(unsigned addr, reg_t val) { | ||||
|     auto mask = get_irq_mask(); | ||||
| template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_ie(unsigned addr, reg_t val) { | ||||
|     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||
|     auto mask = get_irq_mask(req_priv_lvl); | ||||
|     csr[mie] = (csr[mie] & ~mask) | (val & mask); | ||||
|     check_interrupt(); | ||||
|     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[mideleg]; | ||||
|     return iss::Ok; | ||||
| } | ||||
|  | ||||
| template <typename BASE> iss::status riscv_hart_mu_p<BASE>::write_ip(unsigned addr, reg_t val) { | ||||
|     auto mask = get_irq_mask(); | ||||
| template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_ip(unsigned addr, reg_t val) { | ||||
|     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||
|     auto mask = get_irq_mask(req_priv_lvl); | ||||
|     mask &= ~(1 << 7); // MTIP is read only | ||||
|     csr[mip] = (csr[mip] & ~mask) | (val & mask); | ||||
|     check_interrupt(); | ||||
|     return iss::Ok; | ||||
| } | ||||
|  | ||||
| template <typename BASE> | ||||
| iss::status riscv_hart_mu_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { | ||||
| template <typename BASE, bool PMP> | ||||
| 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(mem_read_cb) return mem_read_cb(paddr, length, data); | ||||
|     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; | ||||
| } | ||||
|  | ||||
| template <typename BASE> | ||||
| iss::status riscv_hart_mu_p<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) { | ||||
| template <typename BASE, bool PMP> | ||||
| 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(mem_write_cb) return mem_write_cb(paddr, length, data); | ||||
|     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; | ||||
| } | ||||
|  | ||||
| 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); | ||||
|     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]; | ||||
|     // Multiple simultaneous interrupts and traps at the same privilege level are | ||||
|     // 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] | ||||
|     // calculate and write mcause val | ||||
|     auto trap_id = bit_sub<0, 16>(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 | ||||
|     auto new_priv = PRIV_M; | ||||
|     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 | ||||
|         csr[mepc] = static_cast<reg_t>(addr); // store actual address instruction of exception | ||||
|         csr[mtval] = fault_data; | ||||
|         csr[uepc | (new_priv << 8)] = static_cast<reg_t>(addr); // store actual address instruction of exception | ||||
|         /* | ||||
|          * 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; | ||||
|     } 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; | ||||
|     } | ||||
|     csr[mcause] = (trap_id << 31) + cause; | ||||
|     size_t adr = ucause | (new_priv << 8); | ||||
|     csr[adr] = (trap_id << 31) + cause; | ||||
|     // update mstatus | ||||
|     // xPP field of mstatus is written with the active privilege mode at the time | ||||
|     // 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 | ||||
|     // is cleared | ||||
|     // store the actual privilege level in yPP and store interrupt enable flags | ||||
|     state.mstatus.MPP = PRIV_M; | ||||
|     state.mstatus.MPIE = state.mstatus.MIE; | ||||
|     state.mstatus.MIE = false; | ||||
|     switch (new_priv) { | ||||
|     case PRIV_M: | ||||
|         state.mstatus.MPP = this->reg.PRIV; | ||||
|     	state.mstatus.MPIE = state.mstatus.MIE; | ||||
|     	state.mstatus.MIE = false; | ||||
|         break; | ||||
|     case PRIV_U: | ||||
|         state.mstatus.UPIE = state.mstatus.UIE; | ||||
|         state.mstatus.UIE = false; | ||||
|         break; | ||||
|     default: | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     // 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 | ||||
|     // bits in mtvec | ||||
|     this->reg.NEXT_PC = ivec & ~0x1UL; | ||||
|     if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause; | ||||
|     // reset trap state | ||||
|     this->reg.PRIV = PRIV_M; | ||||
|     this->reg.PRIV = new_priv; | ||||
|     this->reg.trap_state = 0; | ||||
|     std::array<char, 32> buffer; | ||||
|     sprintf(buffer.data(), "0x%016lx", addr); | ||||
|     if((flags&0xffffffff) != 0xffffffff) | ||||
|     CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with 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; | ||||
| } | ||||
|  | ||||
| template <typename BASE> uint64_t riscv_hart_mu_p<BASE>::leave_trap(uint64_t flags) { | ||||
|     state.mstatus.MIE = state.mstatus.MPIE; | ||||
| 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; | ||||
|         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. | ||||
|     this->reg.NEXT_PC = csr[mepc]; | ||||
|     CLOG(INFO, disass) << "Executing xRET"; | ||||
|     this->reg.NEXT_PC = csr[uepc | inst_priv << 8]; | ||||
|     CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[this->reg.PRIV] << " to " | ||||
|                        << lvl[this->reg.PRIV]; | ||||
|     return this->reg.NEXT_PC; | ||||
| } | ||||
|  | ||||
| } // namespace arch | ||||
| } // 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; | ||||
| 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 { | ||||
|  | ||||
| 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<std::string> core_type{"core_type", "tgc_c"}; | ||||
|  | ||||
|     cci::cci_param<std::string> backend{"backend", "interp"}; | ||||
|  | ||||
|     cci::cci_param<unsigned short> gdb_server_port{"gdb_server_port", 0}; | ||||
| @@ -145,9 +137,7 @@ protected: | ||||
|     tlm_utils::tlm_quantumkeeper quantum_keeper; | ||||
|     std::vector<uint8_t> write_buf; | ||||
|     std::unique_ptr<core_wrapper> cpu; | ||||
|     std::unique_ptr<iss::vm_if> vm; | ||||
|     sc_core::sc_time curr_clk; | ||||
|     iss::debugger::target_adapter_if *tgt_adapter; | ||||
| #ifdef WITH_SCV | ||||
|     //! transaction recording database | ||||
|     scv_tr_db *m_db; | ||||
|   | ||||
| @@ -31,17 +31,20 @@ | ||||
|  *******************************************************************************/ | ||||
|  | ||||
| #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 | ||||
| #include "iss/arch/riscv_hart_m_p.h" | ||||
| #include "iss/arch/tgc_c.h" | ||||
| using core_type = iss::arch::tgc_c; | ||||
| using plat_type = iss::arch::riscv_hart_m_p<core_type>; | ||||
| using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>; | ||||
| #endif | ||||
| #ifdef CORE_TGC_D | ||||
| #include "iss/arch/riscv_hart_mu_p.h" | ||||
| #include "iss/arch/tgc_d.h" | ||||
| using core_type = iss::arch::tgc_d; | ||||
| using plat_type = iss::arch::riscv_hart_mu_p<core_type>; | ||||
| using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d>; | ||||
| #endif | ||||
| #include "iss/debugger/encoderdecoder.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 <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 | ||||
| #include <array> | ||||
| #include <scv.h> | ||||
| @@ -67,41 +74,17 @@ using namespace sc_core; | ||||
|  | ||||
| namespace { | ||||
| iss::debugger::encoder_decoder encdec; | ||||
| } | ||||
|  | ||||
|  | ||||
| namespace { | ||||
|  | ||||
| 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: | ||||
|     using phys_addr_t = typename arch::traits<core_type>::phys_addr_t; | ||||
|     core_wrapper(core_complex *owner) | ||||
|     using reg_t       = typename arch::traits<typename PLAT::super>::reg_t; | ||||
|     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) { } | ||||
|  | ||||
|     uint32_t get_mode() { return this->reg.PRIV; } | ||||
| @@ -110,10 +93,10 @@ public: | ||||
|  | ||||
|     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 { | ||||
|         if (p == ISTART) owner->sync(this->reg.icount + cycle_offset); | ||||
|     void notify_phase(iss::arch_if::exec_phase p) override { | ||||
|         if (p == iss::arch_if::ISTART) owner->sync(this->reg.icount); | ||||
|     } | ||||
|  | ||||
|     sync_type needed_sync() const override { return PRE_SYNC; } | ||||
| @@ -122,7 +105,7 @@ public: | ||||
|         if (INFO <= Log<Output2FILE<disass>>::reporting_level() && Output2FILE<disass>::stream()) { | ||||
|             std::stringstream s; | ||||
|             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") | ||||
|                 << "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40) | ||||
|                 << std::setfill(' ') << std::left << instr << s.str(); | ||||
| @@ -165,7 +148,7 @@ public: | ||||
|             } | ||||
|             return ret?Ok:Err; | ||||
|         } else { | ||||
|             return plat_type::read_csr(addr, val); | ||||
|             return PLAT::read_csr(addr, val); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -174,11 +157,11 @@ public: | ||||
|         do { | ||||
|             wait(wfi_evt); | ||||
|         } while (this->reg.pending_trap == 0); | ||||
|         plat_type::wait_until(flags); | ||||
|         PLAT::wait_until(flags); | ||||
|     } | ||||
|  | ||||
|     void local_irq(short id, bool value) { | ||||
|         plat_type::reg_t mask = 0; | ||||
|         reg_t mask = 0; | ||||
|         switch (id) { | ||||
|         case 16: // SW | ||||
|             mask = 1 << 3; | ||||
| @@ -238,11 +221,82 @@ int cmd_sysc(int argc, char *argv[], debugger::out_func of, debugger::data_func | ||||
|     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) | ||||
| : sc_module(name) | ||||
| , read_lut(tlm_dmi_ext()) | ||||
| , write_lut(tlm_dmi_ext()) | ||||
| , tgt_adapter(nullptr) | ||||
| #ifdef WITH_SCV | ||||
| , m_db(scv_tr_db::get_default_db()) | ||||
| , stream_handle(nullptr) | ||||
| @@ -279,40 +333,16 @@ core_complex::~core_complex() = default; | ||||
|  | ||||
| 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() { | ||||
|     SCCDEBUG(SCMOD)<<"instantiating iss::arch::tgf with "<<backend.get_value()<<" backend"; | ||||
|     cpu = scc::make_unique<core_wrapper>(this); | ||||
|     cpu->set_mhartid(mhartid.get_value()); | ||||
|  | ||||
|     vm = create_cpu(cpu.get(), backend.get_value(), gdb_server_port.get_value()); | ||||
|     sc_assert(vm!=nullptr); | ||||
|     cpu->create_cpu(core_type.get_value(), backend.get_value(), gdb_server_port.get_value(), mhartid.get_value()); | ||||
|     sc_assert(cpu->vm!=nullptr); | ||||
| #ifdef WITH_SCV | ||||
|     vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr); | ||||
|     cpu->vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr); | ||||
| #else | ||||
|     vm->setDisassEnabled(enable_disass.get_value()); | ||||
| #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() { | ||||
| @@ -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("INSTR", instr_str); | ||||
|     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); | ||||
| #endif | ||||
| } | ||||
| @@ -375,7 +405,7 @@ void core_complex::run() { | ||||
|             wait(clk_i.value_changed_event()); | ||||
|         } | ||||
|         cpu->set_interrupt_execution(false); | ||||
|         vm->start(); | ||||
|         cpu->start(); | ||||
|     } while (cpu->get_interrupt_execution()); | ||||
|     sc_stop(); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user