Added SystemC version of HiFive FE310
This commit is contained in:
		
							
								
								
									
										158
									
								
								riscv.sc/gen_input/aon.rdl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								riscv.sc/gen_input/aon.rdl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,158 @@ | ||||
| regfile aon_regs { | ||||
| 	// Watchdog Timer Registers | ||||
| 	reg { | ||||
| 		name = "wdogcfg"; | ||||
| 		desc = "Watchdog Timer Config Register"; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} wdogcfg @0x00; | ||||
| 	reg { | ||||
| 		name ="wdogcount"; | ||||
| 		desc = "Watchdog Timer Count Registers"; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} wdogcount @0x08;  | ||||
| 	reg { | ||||
| 		name ="wdogs"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} wdogs @0x10;  | ||||
| 	reg { | ||||
| 		name ="wdogfeed"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} wdogfeed @0x18;  | ||||
| 	reg { | ||||
| 		name ="wdogkey"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} wdogkey @0x1C;  | ||||
| 	reg { | ||||
| 		name ="wdogcmp"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} wdogcmp @0x20; | ||||
| 	// Real-Time Clock Registers | ||||
| 	reg { | ||||
| 		name ="rtccfg"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} rtccfg @0x40; | ||||
| 	reg { | ||||
| 		name ="rtclo"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	}  rtclo @0x48; | ||||
|  	reg { | ||||
| 		name ="rtchi"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} rtchi @0x4C; | ||||
| 	reg { | ||||
| 		name ="rtcs"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	}  rtcs @0x50; | ||||
| 	reg { | ||||
| 		name ="rtccmp"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} rtccmp @0x60; | ||||
| 	// AON Clock Configuration Registers | ||||
| 	reg { | ||||
| 		name ="lfrosccfg"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} lfrosccfg @0x70; | ||||
| 	// Backup Registers | ||||
| 	reg { | ||||
| 		name ="lfrosccfg"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} backup[32] @0x80; | ||||
| 	// Power Management Unit | ||||
| 	reg { | ||||
| 		name ="pmuwakeupi"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="delay"; | ||||
| 		} delay[3:0]; | ||||
| 		field { | ||||
| 			name="vddpaden"; | ||||
| 		} vddpaden[5:5]; | ||||
| 		field { | ||||
| 			name="corerst"; | ||||
| 		} corerst[7:7]; | ||||
| 		field { | ||||
| 			name="hfclkrst"; | ||||
| 		} hfclkrst[8:8]; | ||||
| 	} pmuwakeupi[8] @0x0100; | ||||
| 	reg { | ||||
| 		name ="pmusleepi"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="delay"; | ||||
| 		} delay[3:0]; | ||||
| 		field { | ||||
| 			name="vddpaden"; | ||||
| 		} vddpaden[5:5]; | ||||
| 		field { | ||||
| 			name="corerst"; | ||||
| 		} corerst[7:7]; | ||||
| 		field { | ||||
| 			name="hfclkrst"; | ||||
| 		} hfclkrst[8:8]; | ||||
| 	} pmusleepi[8] @0x0120; | ||||
| 	reg { | ||||
| 		name ="pmuie"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} pmuie @0x0140; | ||||
| 	reg { | ||||
| 		name ="pmucause"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} pmucause @0x0144; | ||||
| 	reg { | ||||
| 		name ="pmusleep"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} pmusleep @0x0148; | ||||
| 	reg { | ||||
| 		name ="pmukey"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} pmukey @0x014C; | ||||
| }; | ||||
							
								
								
									
										27
									
								
								riscv.sc/gen_input/clint.rdl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								riscv.sc/gen_input/clint.rdl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| regfile clint_regs { | ||||
| 	reg { | ||||
| 		name = "msip"; | ||||
| 		desc = "Hart 0 software interrupt register"; | ||||
| 		field { | ||||
| 			name="msip"; | ||||
| 		} msip[0:0]; | ||||
| 	} msip @0; | ||||
| 	reg { | ||||
| 		name = "mtimecmp"; | ||||
| 		desc = "Hart 0 time comparator register"; | ||||
| 		regwidth=64; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 			fieldwidth=64; | ||||
| 		} data = 64'h7FFFFFFFFFFFFFFF; | ||||
| 	} mtimecmp @0x4000; | ||||
| 	reg { | ||||
| 		name = "mtime"; | ||||
| 		desc = "Timer register"; | ||||
| 		regwidth=64; | ||||
| 		field { | ||||
| 			fieldwidth=64; | ||||
| 			name="data"; | ||||
| 		} data[63:0]; | ||||
| 	} mtime @0xBFF8; | ||||
| }; | ||||
| @@ -2,10 +2,18 @@ | ||||
| `include "uart.rdl" | ||||
| `include "spi.rdl" | ||||
| `include "plic.rdl" | ||||
| `include "aon.rdl" | ||||
| `include "prci.rdl" | ||||
| `include "clint.rdl" | ||||
|  | ||||
| addrmap e300_plat_t { | ||||
|     plic_regs plic @0x0C000000; | ||||
|     gpio_regs gpio @0x10012000; | ||||
|     uart_regs uart @0x10013000; | ||||
|     spi_regs  spi  @0x10014000; | ||||
| 	lsb0; | ||||
| 	clint_regs clint @0x02000000; | ||||
|     plic_regs  plic  @0x0C000000; | ||||
|     aon_regs   aon   @0x10000000; | ||||
|     prci_regs  prci  @0x10008000; | ||||
|     gpio_regs  gpio  @0x10012000; | ||||
|     uart_regs  uart0 @0x10013000; | ||||
|     uart_regs  uart1 @0x10023000; | ||||
|     spi_regs   spi   @0x10014000;   | ||||
| } e300_plat; | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| regfile gpio_regs { | ||||
| 	lsb0; | ||||
| 	reg { | ||||
| 		name="value"; | ||||
| 		desc="pin value"; | ||||
|   | ||||
| @@ -2,36 +2,26 @@ regfile plic_regs { | ||||
| 	reg { | ||||
| 		name="priority"; | ||||
| 		desc="interrupt source priority"; | ||||
| 		field { | ||||
| 			name = "priority"; | ||||
| 		} priority[2:0]; | ||||
| 		field {} priority[2:0]; | ||||
| 	} priority[255] @0x004; | ||||
| 	reg { | ||||
| 		name="pending"; | ||||
| 		desc="pending irq"; | ||||
| 		field { | ||||
| 			name = "pending"; | ||||
| 		} pending[31:0]; | ||||
| 		field {} pending[31:0]; | ||||
| 	} pending @0x1000; | ||||
| 	reg { | ||||
| 		name="enabled"; | ||||
| 		desc="enabled interrupts"; | ||||
| 		field { | ||||
| 			name = "enabled"; | ||||
| 		} enabled[31:0]; | ||||
| 		field {} enabled[31:0]; | ||||
| 	} enabled @0x2000; | ||||
| 	reg { | ||||
| 		name="threshold"; | ||||
| 		desc="interrupt priority threshold"; | ||||
| 		field { | ||||
| 			name = "threshold"; | ||||
| 		} \threshold[2:0]; | ||||
| 		field {} \threshold[2:0]; | ||||
| 	} \threshold @0x200000; | ||||
| 	reg { | ||||
| 		name="claim/complete"; | ||||
| 		desc="interrupt handling completed"; | ||||
| 		field { | ||||
| 			name = "interrupt_claimed"; | ||||
| 		} interrupt_claimed[31:0]; | ||||
| 		field {} interrupt_claimed[31:0]; | ||||
| 	} claim_complete @0x200004; | ||||
| }; | ||||
							
								
								
									
										41
									
								
								riscv.sc/gen_input/prci.rdl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								riscv.sc/gen_input/prci.rdl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| regfile prci_regs { | ||||
| 	reg { | ||||
| 		name ="hfrosccfg"; | ||||
| 		desc = ""; | ||||
| 		field {} hfroscdiv[5:0]; | ||||
| 		field {} hfrosctrim[20:16]; | ||||
| 		field {} hfroscen[30:30]; | ||||
| 		field {} hfroscrdy[31:31]; | ||||
| 	} hfrosccfg @0x00; | ||||
| 	reg { | ||||
| 		name ="hfxosccfg"; | ||||
| 		desc = ""; | ||||
| 		field {} hfxoscrdy[31:31]; | ||||
| 		field {} hfxoscen[30:30]; | ||||
| 	} hfxosccfg @0x04; | ||||
|      reg { | ||||
|         name ="pllcfg"; | ||||
|         desc = ""; | ||||
|         field {} pllr[2:0]; | ||||
|         field {} pllf[9:4]; | ||||
|         field {} pllq[11:10]; | ||||
|         field {} pllsel[16:16]; | ||||
|         field {} pllrefsel[17:17]; | ||||
|         field {} pllbypass[18:18]; | ||||
|         field {} plllock[31:31]; | ||||
|     } pllcfg @0x08; | ||||
| 	reg { | ||||
| 		name ="plloutdiv"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} plloutdiv  @0x0c; | ||||
| 	reg { | ||||
| 		name ="coreclkcfg"; | ||||
| 		desc = ""; | ||||
| 		field { | ||||
| 			name="data"; | ||||
| 		} data[31:0]; | ||||
| 	} coreclkcfg @0x10; | ||||
| }; | ||||
| @@ -1,5 +1,4 @@ | ||||
| regfile spi_regs { | ||||
| 	lsb0; | ||||
| 	reg { | ||||
| 		name="sckdiv"; | ||||
| 		desc="Serial clock divisor"; | ||||
|   | ||||
| @@ -1,80 +1,45 @@ | ||||
| regfile uart_regs { | ||||
| 	lsb0; | ||||
| 	reg { | ||||
| 		name="txdata"; | ||||
| 		desc="Transmit data register"; | ||||
| 		field { | ||||
| 			name ="data"; | ||||
| 		} data[7:0]; | ||||
| 		field { | ||||
| 			name ="full"; | ||||
| 		} full[31:31]; | ||||
| 		field {} data[7:0]; | ||||
| 		field {} full[31:31]; | ||||
| 	} txdata @0x00; | ||||
| 	reg { | ||||
| 		name="rxdata"; | ||||
| 		desc="Receive data register"; | ||||
| 		field { | ||||
| 			name ="data"; | ||||
| 		} data[7:0]; | ||||
| 		field { | ||||
| 			name ="empty"; | ||||
| 		} empty[31:31]; | ||||
| 		field {} data[7:0]; | ||||
| 		field {} empty[31:31]; | ||||
| 	}rxdata @0x04; | ||||
| 	reg { | ||||
| 		name="txctrl"; | ||||
| 		desc="Transmit control register"; | ||||
| 		field { | ||||
| 			name ="txen"; | ||||
| 		} txen[1]; | ||||
| 		field { | ||||
| 			name ="nstop"; | ||||
| 		} nstop[1]; | ||||
| 		field { | ||||
| 			name ="reserved"; | ||||
| 		} reserved[14]; | ||||
| 		field { | ||||
| 			name ="txcnt"; | ||||
| 		} txcnt[3]; | ||||
| 		field {} txen[1]; | ||||
| 		field {} nstop[1]; | ||||
| 		field {} txcnt[18:16]; | ||||
| 	}txctrl @0x08; | ||||
| 	reg { | ||||
| 		name="rxctrl"; | ||||
| 		desc="Receive control register"; | ||||
| 		field { | ||||
| 			name ="rxen"; | ||||
| 		} rxen[1]; | ||||
| 		field { | ||||
| 			name ="reserved"; | ||||
| 		} reserved[15]; | ||||
| 		field { | ||||
| 			name ="rxcnt"; | ||||
| 		} rxcnt[3]; | ||||
| 		field {} rxen[1]; | ||||
| 		field {} rxcnt[18:16]; | ||||
| 	}rxctrl @0x0C; | ||||
| 	reg { | ||||
| 		name="ie"; | ||||
| 		desc="UART interrupt enable"; | ||||
| 		field{ | ||||
| 			name ="txwm"; | ||||
| 		} txwm[1]; | ||||
| 		field{ | ||||
| 			name ="rxwm"; | ||||
| 		} rxwm[1]; | ||||
| 		field{} txwm[1]; | ||||
| 		field{} rxwm[1]; | ||||
| 	}ie @0x10; | ||||
| 	reg { | ||||
| 		name="ip"; | ||||
| 		desc="UART Interrupt pending"; | ||||
| 		field{ | ||||
| 			name ="txwm"; | ||||
| 		} txwm[1]; | ||||
| 		field{ | ||||
| 			name ="rxwm"; | ||||
| 		} rxwm[1]; | ||||
| 		field{} txwm[1]; | ||||
| 		field{} rxwm[1]; | ||||
| 	} ip @0x14; | ||||
| 	reg { | ||||
| 		name="div"; | ||||
| 		desc="Baud rate divisor"; | ||||
| 		field{ | ||||
| 			name ="div"; | ||||
| 		} div[16]; | ||||
| 		field{} div[16]; | ||||
| 	} div @0x18; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -1,173 +0,0 @@ | ||||
| /******************************************************************************* | ||||
|  * Copyright (C) 2017, 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 API and implementation | ||||
|  ******************************************************************************/ | ||||
|  | ||||
| #ifndef _CLI_OPTIONS_H_ | ||||
| #define _CLI_OPTIONS_H_ | ||||
| #include <boost/program_options.hpp> | ||||
| #include <cstdio> | ||||
| #include <iostream> | ||||
| #include <util/logging.h> | ||||
|  | ||||
| namespace { | ||||
| const size_t ERROR_IN_COMMAND_LINE = 1; | ||||
| const size_t SUCCESS = 0; | ||||
| const size_t ERROR_UNHANDLED_EXCEPTION = 2; | ||||
|  | ||||
| inline void enable_log_level(int level) { | ||||
|     switch (level) { | ||||
|     case 0: | ||||
|         logging::Logger::reporting_level() = logging::FATAL; | ||||
|     /* no break */ | ||||
|     case 1: | ||||
|         logging::Logger::reporting_level() = logging::ERROR; | ||||
|     /* no break */ | ||||
|     case 2: | ||||
|         logging::Logger::reporting_level() = logging::WARNING; | ||||
|     /* no break */ | ||||
|     case 3: | ||||
|         logging::Logger::reporting_level() = logging::INFO; | ||||
|     /* no break */ | ||||
|     case 4: | ||||
|         logging::Logger::reporting_level() = logging::DEBUG; | ||||
|     /* no break */ | ||||
|     case 5: | ||||
|         logging::Logger::reporting_level() = logging::TRACE; | ||||
|         /* no break */ | ||||
|     } | ||||
| } | ||||
|  | ||||
| inline void configure_default_logger(boost::program_options::variables_map &vm) { | ||||
|     //	el::Configurations defaultConf; | ||||
|     //	defaultConf.setToDefault(); | ||||
|     //	defaultConf.set(el::Level::Error, el::ConfigurationType::Format, | ||||
|     //"%datetime{%H:%m:%s.%g} %level %msg"); | ||||
|     //	defaultConf.set(el::Level::Warning, el::ConfigurationType::Format, | ||||
|     //"%datetime{%H:%m:%s.%g} %level %msg"); | ||||
|     //	defaultConf.set(el::Level::Info, el::ConfigurationType::Format, | ||||
|     //"%datetime{%H:%m:%s.%g} %level %msg"); | ||||
|     //	defaultConf.set(el::Level::Debug, el::ConfigurationType::Format, | ||||
|     //"%datetime{%H:%m:%s.%g} %level %msg"); | ||||
|     //	defaultConf.set(el::Level::Trace, el::ConfigurationType::Format, | ||||
|     //"%datetime{%H:%m:%s.%g} %level %msg"); | ||||
|     if (vm.count("verbose")) enable_log_level(vm["verbose"].as<int>()); | ||||
|     if (vm.count("log-file")) logging::Output2FILE::stream() = fopen(vm["log-file"].as<std::string>().c_str(), "w"); | ||||
|     // default logger uses default configurations | ||||
|     //	el::Loggers::reconfigureLogger("default", defaultConf); | ||||
| } | ||||
|  | ||||
| inline void configure_debugger_logger() { | ||||
|     // configure the connection logger | ||||
|     //	el::Logger* gdbServerLogger = el::Loggers::getLogger(connection); | ||||
|     //	el::Configurations gdbServerConf; | ||||
|     //	gdbServerConf.setToDefault(); | ||||
|     //	gdbServerConf.set(el::Level::Error, el::ConfigurationType::Format, | ||||
|     //			"%datetime{%H:%m:%s.%g} %level [%logger] %msg"); | ||||
|     //	gdbServerConf.set(el::Level::Warning, el::ConfigurationType::Format, | ||||
|     //			"%datetime{%H:%m:%s.%g} %level [%logger] %msg"); | ||||
|     //	gdbServerConf.set(el::Level::Info, el::ConfigurationType::Format, | ||||
|     //			"%datetime{%H:%m:%s.%g} %level [%logger] %msg"); | ||||
|     //	gdbServerConf.set(el::Level::Debug, el::ConfigurationType::Format, | ||||
|     //			"%datetime{%H:%m:%s.%g} %level [%logger] %msg"); | ||||
|     //	gdbServerConf.set(el::Level::Trace, el::ConfigurationType::Format, | ||||
|     //			"%datetime{%H:%m:%s.%g} %level [%logger] %msg"); | ||||
|     //	enable_log_level(gdbServerConf, 5); | ||||
|     //	gdbServerLogger->configure(gdbServerConf); | ||||
| } | ||||
|  | ||||
| inline void configure_disass_logger(boost::program_options::variables_map &vm) { | ||||
|     //    el::Logger* disassLogger = el::Loggers::getLogger(disass); | ||||
|     //    el::Configurations disassConf; | ||||
|     //    if(vm.count(disass)){ | ||||
|     //        auto file_name=vm[disass].as<std::string>(); | ||||
|     //        disassConf.setToDefault(); | ||||
|     //        if (file_name.length() > 0) { | ||||
|     //            disassConf.set(el::Level::Global, el::ConfigurationType::ToFile, | ||||
|     //                    std::string("true")); | ||||
|     //            disassConf.set(el::Level::Global, | ||||
|     //                    el::ConfigurationType::ToStandardOutput, | ||||
|     //                    std::string("false")); | ||||
|     //            disassConf.set(el::Level::Global, el::ConfigurationType::Format, | ||||
|     //                    std::string("%msg")); | ||||
|     //            disassConf.set(el::Level::Global, | ||||
|     //            el::ConfigurationType::Filename, | ||||
|     //                    file_name); | ||||
|     //            std::ofstream str(file_name); // just to clear the file | ||||
|     //        } else { | ||||
|     //            disassConf.set(el::Level::Global, el::ConfigurationType::Format, | ||||
|     //                    "%datetime{%H:%m:%s.%g} [%logger] %msg"); | ||||
|     //        } | ||||
|     //    } else { | ||||
|     //        enable_log_level(disassConf, 0); | ||||
|     //    } | ||||
|     //	disassLogger->configure(disassConf); | ||||
| } | ||||
|  | ||||
| } // namespace | ||||
|  | ||||
| inline int parse_cli_options(boost::program_options::variables_map &vm, int argc, char *argv[]) { | ||||
|     namespace po = boost::program_options; | ||||
|     po::options_description desc("Options"); | ||||
|     desc.add_options()("help,h", "Print help message")("verbose,v", po::value<int>()->implicit_value(0), | ||||
|                                                        "Sets logging verbosity")("vmodule", po::value<std::string>(), | ||||
|                                                                                  "Defines the module(s) to be logged")( | ||||
|         "logging-flags", po::value<int>(), "Sets logging flag(s).")("log-file", po::value<std::string>(), | ||||
|                                                                     "Sets default log file.")( | ||||
|         "disass,d", po::value<std::string>()->implicit_value(""), | ||||
|         "Enables disassembly")("elf,l", po::value<std::vector<std::string>>(), "ELF file(s) to load")( | ||||
|         "gdb-port,g", po::value<unsigned>(), "enable gdb server and specify port to use")( | ||||
|         "input,i", po::value<std::string>(), "the elf file to load (instead of hex files)")( | ||||
|         "dump-ir", "dump the intermediate representation")("cycles,c", po::value<int64_t>()->default_value(-1), | ||||
|                                                            "number of cycles to run")( | ||||
|         "systemc,s", "Run as SystemC simulation")("time", po::value<int>(), "SystemC siimulation time in ms")( | ||||
|         "reset,r", po::value<std::string>(), "reset address")( | ||||
|         "trace", po::value<uint8_t>(), "enable tracing, or cmbintation of 1=signals and 2=TX text, 4=TX " | ||||
|                                        "compressed text, 6=TX in SQLite")("mem,m", po::value<std::string>(), | ||||
|                                                                           "the memory input file")("rv64", "run RV64"); | ||||
|     try { | ||||
|         po::store(po::parse_command_line(argc, argv, desc), vm); // can throw | ||||
|         // --help option | ||||
|         if (vm.count("help")) { | ||||
|             std::cout << "DBT-RISE-RiscV" << std::endl << desc << std::endl; | ||||
|             return SUCCESS; | ||||
|         } | ||||
|         po::notify(vm); // throws on error, so do after help in case | ||||
|     } catch (po::error &e) { | ||||
|         // there are problems | ||||
|         std::cerr << "ERROR: " << e.what() << std::endl << std::endl; | ||||
|         std::cerr << desc << std::endl; | ||||
|         return ERROR_IN_COMMAND_LINE; | ||||
|     } | ||||
|     return SUCCESS; | ||||
| } | ||||
| #endif /* _CLI_OPTIONS_H_ */ | ||||
							
								
								
									
										43
									
								
								riscv.sc/incl/sysc/SiFive/aon.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								riscv.sc/incl/sysc/SiFive/aon.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| /******************************************************************************* | ||||
|  * Copyright 2017 eyck@minres.com | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||||
|  * use this file except in compliance with the License.  You may obtain a copy | ||||
|  * of the License at | ||||
|  * | ||||
|  *   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the | ||||
|  * License for the specific language governing permissions and limitations under | ||||
|  * the License. | ||||
|  ******************************************************************************/ | ||||
|  | ||||
| #ifndef _AON_H_ | ||||
| #define _AON_H_ | ||||
|  | ||||
| #include <sysc/tlm_target.h> | ||||
|  | ||||
| namespace sysc { | ||||
|  | ||||
| class aon_regs; | ||||
|  | ||||
| class aon : public sc_core::sc_module, public tlm_target<> { | ||||
| public: | ||||
|     SC_HAS_PROCESS(aon); | ||||
|     sc_core::sc_in<sc_core::sc_time> clk_i; | ||||
|     sc_core::sc_in<bool> rst_i; | ||||
|     aon(sc_core::sc_module_name nm); | ||||
|     virtual ~aon() override; // need to keep it in source file because of fwd declaration of aon_regs | ||||
|  | ||||
| protected: | ||||
|     void clock_cb(); | ||||
|     void reset_cb(); | ||||
|     sc_core::sc_time clk; | ||||
|     std::unique_ptr<aon_regs> regs; | ||||
| }; | ||||
|  | ||||
| } /* namespace sysc */ | ||||
|  | ||||
| #endif /* _GPIO_H_ */ | ||||
							
								
								
									
										57
									
								
								riscv.sc/incl/sysc/SiFive/clint.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								riscv.sc/incl/sysc/SiFive/clint.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| /******************************************************************************* | ||||
|  * Copyright 2017 eyck@minres.com | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||||
|  * use this file except in compliance with the License.  You may obtain a copy | ||||
|  * of the License at | ||||
|  * | ||||
|  *   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the | ||||
|  * License for the specific language governing permissions and limitations under | ||||
|  * the License. | ||||
|  ******************************************************************************/ | ||||
|  | ||||
| #ifndef _CLINT_H_ | ||||
| #define _CLINT_H_ | ||||
|  | ||||
| #include <sysc/tlm_target.h> | ||||
|  | ||||
| namespace iss { | ||||
| namespace arch { | ||||
| template <typename BASE> struct riscv_hart_msu_vp; | ||||
| } | ||||
| } | ||||
|  | ||||
| namespace sysc { | ||||
|  | ||||
| class clint_regs; | ||||
| namespace SiFive { | ||||
| class core_complex; | ||||
| } | ||||
|  | ||||
| class clint : public sc_core::sc_module, public tlm_target<> { | ||||
| public: | ||||
|     SC_HAS_PROCESS(clint); | ||||
|     sc_core::sc_in<sc_core::sc_time> clk_i; | ||||
|     sc_core::sc_in<bool> rst_i; | ||||
|     sc_core::sc_out<bool> mtime_int_o; | ||||
|     sc_core::sc_out<bool> msip_int_o; | ||||
|     clint(sc_core::sc_module_name nm); | ||||
|     virtual ~clint() override; // need to keep it in source file because of fwd declaration of clint_regs | ||||
|  | ||||
| protected: | ||||
|     void clock_cb(); | ||||
|     void reset_cb(); | ||||
|     void update_mtime(); | ||||
|     sc_core::sc_time clk, last_updt; | ||||
|     unsigned cnt_fraction; | ||||
|     std::unique_ptr<clint_regs> regs; | ||||
|     sc_core::sc_event mtime_evt; | ||||
| }; | ||||
|  | ||||
| } /* namespace sysc */ | ||||
|  | ||||
| #endif /* _CLINT_H_ */ | ||||
| @@ -37,21 +37,89 @@ | ||||
| #ifndef _SYSC_SIFIVE_FE310_H_ | ||||
| #define _SYSC_SIFIVE_FE310_H_ | ||||
|  | ||||
| #include <iss/arch/riscv_hart_msu_vp.h> | ||||
| #include <iss/arch/rv32imac.h> | ||||
| #include <sysc/ext_attribute.h> | ||||
| #include <sysc/initiator_mixin.h> | ||||
| #include <sysc/traceable.h> | ||||
| #include <sysc/utilities.h> | ||||
| #include <tlm> | ||||
| #include <tlm_utils/tlm_quantumkeeper.h> | ||||
| #include <util/range_lut.h> | ||||
|  | ||||
| namespace iss { | ||||
| class vm_if; | ||||
| namespace arch { | ||||
| template <typename BASE> struct riscv_hart_msu_vp; | ||||
| } | ||||
| } | ||||
|  | ||||
| namespace sysc { | ||||
| namespace SiFive { | ||||
|  | ||||
| class core_complex : public iss::arch::riscv_hart_msu_vp<iss::arch::rv32imac>, public sc_core::sc_module { | ||||
| class tlm_dmi_ext : public tlm::tlm_dmi { | ||||
| public: | ||||
|     tlm::tlm_initiator_socket<32> initiator; | ||||
|     bool operator==(const tlm_dmi_ext &o) const { | ||||
|         return this->get_granted_access() == o.get_granted_access() && | ||||
|                this->get_start_address() == o.get_start_address() && this->get_end_address() == o.get_end_address(); | ||||
|     } | ||||
|  | ||||
|     bool operator!=(const tlm_dmi_ext &o) const { return !operator==(o); } | ||||
| }; | ||||
|  | ||||
| namespace SiFive { | ||||
| class core_wrapper; | ||||
|  | ||||
| class core_complex : public sc_core::sc_module, public sysc::traceable { | ||||
| public: | ||||
|     SC_HAS_PROCESS(core_complex); | ||||
|  | ||||
|     sysc::initiator_mixin<tlm::tlm_initiator_socket<32>> initiator; | ||||
|  | ||||
|     sc_core::sc_in<sc_core::sc_time> clk_i; | ||||
|  | ||||
|     sc_core::sc_in<bool> rst_i; | ||||
|  | ||||
|     sysc::ext_attribute<std::string> elf_file; | ||||
|  | ||||
|     sysc::ext_attribute<bool> enable_disass; | ||||
|  | ||||
|     sysc::ext_attribute<uint64_t> reset_address; | ||||
|  | ||||
|     sysc::ext_attribute<unsigned short> gdb_server_port; | ||||
|  | ||||
|     sysc::ext_attribute<bool> dump_ir; | ||||
|  | ||||
|     core_complex(sc_core::sc_module_name name); | ||||
|     virtual ~core_complex() = default; | ||||
|  | ||||
|     ~core_complex(); | ||||
|  | ||||
|     inline void sync() { | ||||
|         quantum_keeper.inc(curr_clk); | ||||
|         if (quantum_keeper.need_sync()) { | ||||
|             wait(quantum_keeper.get_local_time()); | ||||
|             quantum_keeper.reset(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool read_mem(uint64_t addr, unsigned length, uint8_t *const data); | ||||
|  | ||||
|     bool write_mem(uint64_t addr, unsigned length, const uint8_t *const data); | ||||
|  | ||||
|     bool read_mem_dbg(uint64_t addr, unsigned length, uint8_t *const data); | ||||
|  | ||||
|     bool write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *const data); | ||||
|  | ||||
|     void trace(sc_core::sc_trace_file *trf) override; | ||||
|  | ||||
| protected: | ||||
|     void before_end_of_elaboration(); | ||||
|     void start_of_simulation(); | ||||
|     void run(); | ||||
|     void clk_cb(); | ||||
|     util::range_lut<tlm_dmi_ext> read_lut, write_lut; | ||||
|     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; | ||||
| }; | ||||
|  | ||||
| } /* namespace SiFive */ | ||||
|   | ||||
							
								
								
									
										173
									
								
								riscv.sc/incl/sysc/SiFive/gen/aon_regs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								riscv.sc/incl/sysc/SiFive/gen/aon_regs.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,173 @@ | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Copyright (C) 2017, 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. | ||||
| // | ||||
| // Created on: Wed Oct 04 10:06:35 CEST 2017 | ||||
| //             *      aon_regs.h Author: <RDL Generator> | ||||
| // | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #ifndef _AON_REGS_H_ | ||||
| #define _AON_REGS_H_ | ||||
|  | ||||
| #include <sysc/register.h> | ||||
| #include <sysc/tlm_target.h> | ||||
| #include <sysc/utilities.h> | ||||
| #include <util/bit_field.h> | ||||
|  | ||||
| namespace sysc { | ||||
|  | ||||
| class aon_regs : public sc_core::sc_module, public sysc::resetable { | ||||
| public: | ||||
|     // storage declarations | ||||
|     uint32_t r_wdogcfg; | ||||
|  | ||||
|     uint32_t r_wdogcount; | ||||
|  | ||||
|     uint32_t r_wdogs; | ||||
|  | ||||
|     uint32_t r_wdogfeed; | ||||
|  | ||||
|     uint32_t r_wdogkey; | ||||
|  | ||||
|     uint32_t r_wdogcmp; | ||||
|  | ||||
|     uint32_t r_rtccfg; | ||||
|  | ||||
|     uint32_t r_rtclo; | ||||
|  | ||||
|     uint32_t r_rtchi; | ||||
|  | ||||
|     uint32_t r_rtcs; | ||||
|  | ||||
|     uint32_t r_rtccmp; | ||||
|  | ||||
|     uint32_t r_lfrosccfg; | ||||
|  | ||||
|     std::array<uint32_t, 32> r_backup; | ||||
|  | ||||
|     BEGIN_BF_DECL(pmuwakeupi_t, uint32_t); | ||||
|     BF_FIELD(delay, 0, 4); | ||||
|     BF_FIELD(vddpaden, 5, 1); | ||||
|     BF_FIELD(corerst, 7, 1); | ||||
|     BF_FIELD(hfclkrst, 8, 1); | ||||
|     END_BF_DECL(); | ||||
|     std::array<pmuwakeupi_t, 8> r_pmuwakeupi; | ||||
|  | ||||
|     BEGIN_BF_DECL(pmusleepi_t, uint32_t); | ||||
|     BF_FIELD(delay, 0, 4); | ||||
|     BF_FIELD(vddpaden, 5, 1); | ||||
|     BF_FIELD(corerst, 7, 1); | ||||
|     BF_FIELD(hfclkrst, 8, 1); | ||||
|     END_BF_DECL(); | ||||
|     std::array<pmusleepi_t, 8> r_pmusleepi; | ||||
|  | ||||
|     uint32_t r_pmuie; | ||||
|  | ||||
|     uint32_t r_pmucause; | ||||
|  | ||||
|     uint32_t r_pmusleep; | ||||
|  | ||||
|     uint32_t r_pmukey; | ||||
|  | ||||
|     // register declarations | ||||
|     sysc::sc_register<uint32_t> wdogcfg; | ||||
|     sysc::sc_register<uint32_t> wdogcount; | ||||
|     sysc::sc_register<uint32_t> wdogs; | ||||
|     sysc::sc_register<uint32_t> wdogfeed; | ||||
|     sysc::sc_register<uint32_t> wdogkey; | ||||
|     sysc::sc_register<uint32_t> wdogcmp; | ||||
|     sysc::sc_register<uint32_t> rtccfg; | ||||
|     sysc::sc_register<uint32_t> rtclo; | ||||
|     sysc::sc_register<uint32_t> rtchi; | ||||
|     sysc::sc_register<uint32_t> rtcs; | ||||
|     sysc::sc_register<uint32_t> rtccmp; | ||||
|     sysc::sc_register<uint32_t> lfrosccfg; | ||||
|     sysc::sc_register_indexed<uint32_t, 32> backup; | ||||
|     sysc::sc_register_indexed<pmuwakeupi_t, 8> pmuwakeupi; | ||||
|     sysc::sc_register_indexed<pmusleepi_t, 8> pmusleepi; | ||||
|     sysc::sc_register<uint32_t> pmuie; | ||||
|     sysc::sc_register<uint32_t> pmucause; | ||||
|     sysc::sc_register<uint32_t> pmusleep; | ||||
|     sysc::sc_register<uint32_t> pmukey; | ||||
|  | ||||
|     aon_regs(sc_core::sc_module_name nm); | ||||
|  | ||||
|     template <unsigned BUSWIDTH = 32> void registerResources(sysc::tlm_target<BUSWIDTH> &target); | ||||
| }; | ||||
| } | ||||
| ////////////////////////////////////////////////////////////////////////////// | ||||
| // member functions | ||||
| ////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| inline sysc::aon_regs::aon_regs(sc_core::sc_module_name nm) | ||||
| : sc_core::sc_module(nm) | ||||
| , NAMED(wdogcfg, r_wdogcfg, 0, *this) | ||||
| , NAMED(wdogcount, r_wdogcount, 0, *this) | ||||
| , NAMED(wdogs, r_wdogs, 0, *this) | ||||
| , NAMED(wdogfeed, r_wdogfeed, 0, *this) | ||||
| , NAMED(wdogkey, r_wdogkey, 0, *this) | ||||
| , NAMED(wdogcmp, r_wdogcmp, 0, *this) | ||||
| , NAMED(rtccfg, r_rtccfg, 0, *this) | ||||
| , NAMED(rtclo, r_rtclo, 0, *this) | ||||
| , NAMED(rtchi, r_rtchi, 0, *this) | ||||
| , NAMED(rtcs, r_rtcs, 0, *this) | ||||
| , NAMED(rtccmp, r_rtccmp, 0, *this) | ||||
| , NAMED(lfrosccfg, r_lfrosccfg, 0, *this) | ||||
| , NAMED(backup, r_backup, 0, *this) | ||||
| , NAMED(pmuwakeupi, r_pmuwakeupi, 0, *this) | ||||
| , NAMED(pmusleepi, r_pmusleepi, 0, *this) | ||||
| , NAMED(pmuie, r_pmuie, 0, *this) | ||||
| , NAMED(pmucause, r_pmucause, 0, *this) | ||||
| , NAMED(pmusleep, r_pmusleep, 0, *this) | ||||
| , NAMED(pmukey, r_pmukey, 0, *this) {} | ||||
|  | ||||
| template <unsigned BUSWIDTH> inline void sysc::aon_regs::registerResources(sysc::tlm_target<BUSWIDTH> &target) { | ||||
|     target.addResource(wdogcfg, 0x0UL); | ||||
|     target.addResource(wdogcount, 0x8UL); | ||||
|     target.addResource(wdogs, 0x10UL); | ||||
|     target.addResource(wdogfeed, 0x18UL); | ||||
|     target.addResource(wdogkey, 0x1cUL); | ||||
|     target.addResource(wdogcmp, 0x20UL); | ||||
|     target.addResource(rtccfg, 0x40UL); | ||||
|     target.addResource(rtclo, 0x48UL); | ||||
|     target.addResource(rtchi, 0x4cUL); | ||||
|     target.addResource(rtcs, 0x50UL); | ||||
|     target.addResource(rtccmp, 0x60UL); | ||||
|     target.addResource(lfrosccfg, 0x70UL); | ||||
|     target.addResource(backup, 0x80UL); | ||||
|     target.addResource(pmuwakeupi, 0x100UL); | ||||
|     target.addResource(pmusleepi, 0x120UL); | ||||
|     target.addResource(pmuie, 0x140UL); | ||||
|     target.addResource(pmucause, 0x144UL); | ||||
|     target.addResource(pmusleep, 0x148UL); | ||||
|     target.addResource(pmukey, 0x14cUL); | ||||
| } | ||||
|  | ||||
| #endif // _AON_REGS_H_ | ||||
							
								
								
									
										83
									
								
								riscv.sc/incl/sysc/SiFive/gen/clint_regs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								riscv.sc/incl/sysc/SiFive/gen/clint_regs.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Copyright (C) 2017, 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. | ||||
| // | ||||
| // Created on: Wed Oct 04 10:06:35 CEST 2017 | ||||
| //             *      clint_regs.h Author: <RDL Generator> | ||||
| // | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #ifndef _CLINT_REGS_H_ | ||||
| #define _CLINT_REGS_H_ | ||||
|  | ||||
| #include <sysc/register.h> | ||||
| #include <sysc/tlm_target.h> | ||||
| #include <sysc/utilities.h> | ||||
| #include <util/bit_field.h> | ||||
|  | ||||
| namespace sysc { | ||||
|  | ||||
| class clint_regs : public sc_core::sc_module, public sysc::resetable { | ||||
| public: | ||||
|     // storage declarations | ||||
|     BEGIN_BF_DECL(msip_t, uint32_t); | ||||
|     BF_FIELD(msip, 0, 1); | ||||
|     END_BF_DECL() r_msip; | ||||
|  | ||||
|     uint64_t r_mtimecmp; | ||||
|  | ||||
|     uint64_t r_mtime; | ||||
|  | ||||
|     // register declarations | ||||
|     sysc::sc_register<msip_t> msip; | ||||
|     sysc::sc_register<uint64_t> mtimecmp; | ||||
|     sysc::sc_register<uint64_t> mtime; | ||||
|  | ||||
|     clint_regs(sc_core::sc_module_name nm); | ||||
|  | ||||
|     template <unsigned BUSWIDTH = 32> void registerResources(sysc::tlm_target<BUSWIDTH> &target); | ||||
| }; | ||||
| } | ||||
| ////////////////////////////////////////////////////////////////////////////// | ||||
| // member functions | ||||
| ////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| inline sysc::clint_regs::clint_regs(sc_core::sc_module_name nm) | ||||
| : sc_core::sc_module(nm) | ||||
| , NAMED(msip, r_msip, 0, *this) | ||||
| , NAMED(mtimecmp, r_mtimecmp, 0, *this) | ||||
| , NAMED(mtime, r_mtime, 0, *this) {} | ||||
|  | ||||
| template <unsigned BUSWIDTH> inline void sysc::clint_regs::registerResources(sysc::tlm_target<BUSWIDTH> &target) { | ||||
|     target.addResource(msip, 0x0UL); | ||||
|     target.addResource(mtimecmp, 0x4000UL); | ||||
|     target.addResource(mtime, 0xbff8UL); | ||||
| } | ||||
|  | ||||
| #endif // _CLINT_REGS_H_ | ||||
| @@ -2,11 +2,15 @@ | ||||
| #define _E300_PLAT_MAP_H_ | ||||
| // need double braces, see | ||||
| // https://stackoverflow.com/questions/6893700/how-to-construct-stdarray-object-with-initializer-list#6894191 | ||||
| const std::array<sysc::target_memory_map_entry<32>, 4> e300_plat_map = {{ | ||||
|     {&i_plic, 0xc000000, 0x1000}, | ||||
|     {&i_gpio, 0x10012000, 0x1000}, | ||||
|     {&i_uart, 0x10013000, 0x1000}, | ||||
|     {&i_spi, 0x10014000, 0x1000}, | ||||
| const std::array<sysc::target_memory_map_entry<32>, 8> e300_plat_map = {{ | ||||
|     {&i_clint, 0x2000000, 0xc000}, | ||||
|     {&i_plic, 0xc000000, 0x200008}, | ||||
|     {&i_aon, 0x10000000, 0x150}, | ||||
|     {&i_prci, 0x10008000, 0x14}, | ||||
|     {&i_gpio, 0x10012000, 0x44}, | ||||
|     {&i_uart0, 0x10013000, 0x1c}, | ||||
|     {&i_uart1, 0x10023000, 0x1c}, | ||||
|     {&i_spi, 0x10014000, 0x78}, | ||||
| }}; | ||||
|  | ||||
| #endif /* _E300_PLAT_MAP_H_ */ | ||||
|   | ||||
| @@ -28,7 +28,7 @@ | ||||
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
| // POSSIBILITY OF SUCH DAMAGE. | ||||
| // | ||||
| // Created on: Wed Sep 20 11:47:24 CEST 2017 | ||||
| // Created on: Wed Oct 04 10:06:35 CEST 2017 | ||||
| //             *      gpio_regs.h Author: <RDL Generator> | ||||
| // | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -44,7 +44,7 @@ | ||||
| namespace sysc { | ||||
|  | ||||
| class gpio_regs : public sc_core::sc_module, public sysc::resetable { | ||||
| protected: | ||||
| public: | ||||
|     // storage declarations | ||||
|     uint32_t r_value; | ||||
|  | ||||
| @@ -99,7 +99,6 @@ protected: | ||||
|     sysc::sc_register<uint32_t> iof_sel; | ||||
|     sysc::sc_register<uint32_t> out_xor; | ||||
|  | ||||
| public: | ||||
|     gpio_regs(sc_core::sc_module_name nm); | ||||
|  | ||||
|     template <unsigned BUSWIDTH = 32> void registerResources(sysc::tlm_target<BUSWIDTH> &target); | ||||
|   | ||||
| @@ -28,7 +28,7 @@ | ||||
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
| // POSSIBILITY OF SUCH DAMAGE. | ||||
| // | ||||
| // Created on: Wed Sep 20 22:30:45 CEST 2017 | ||||
| // Created on: Wed Oct 04 10:06:35 CEST 2017 | ||||
| //             *      plic_regs.h Author: <RDL Generator> | ||||
| // | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -44,7 +44,7 @@ | ||||
| namespace sysc { | ||||
|  | ||||
| class plic_regs : public sc_core::sc_module, public sysc::resetable { | ||||
| protected: | ||||
| public: | ||||
|     // storage declarations | ||||
|     BEGIN_BF_DECL(priority_t, uint32_t); | ||||
|     BF_FIELD(priority, 0, 3); | ||||
| @@ -68,7 +68,6 @@ protected: | ||||
|     sysc::sc_register<threshold_t> threshold; | ||||
|     sysc::sc_register<uint32_t> claim_complete; | ||||
|  | ||||
| public: | ||||
|     plic_regs(sc_core::sc_module_name nm); | ||||
|  | ||||
|     template <unsigned BUSWIDTH = 32> void registerResources(sysc::tlm_target<BUSWIDTH> &target); | ||||
| @@ -90,8 +89,8 @@ template <unsigned BUSWIDTH> inline void sysc::plic_regs::registerResources(sysc | ||||
|     target.addResource(priority, 0x4UL); | ||||
|     target.addResource(pending, 0x1000UL); | ||||
|     target.addResource(enabled, 0x2000UL); | ||||
|     target.addResource(threshold, 0xc200000UL); | ||||
|     target.addResource(claim_complete, 0xc200004UL); | ||||
|     target.addResource(threshold, 0x200000UL); | ||||
|     target.addResource(claim_complete, 0x200004UL); | ||||
| } | ||||
|  | ||||
| #endif // _PLIC_REGS_H_ | ||||
|   | ||||
							
								
								
									
										107
									
								
								riscv.sc/incl/sysc/SiFive/gen/prci_regs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								riscv.sc/incl/sysc/SiFive/gen/prci_regs.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Copyright (C) 2017, 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. | ||||
| // | ||||
| // Created on: Wed Oct 04 10:06:35 CEST 2017 | ||||
| //             *      prci_regs.h Author: <RDL Generator> | ||||
| // | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #ifndef _PRCI_REGS_H_ | ||||
| #define _PRCI_REGS_H_ | ||||
|  | ||||
| #include <sysc/register.h> | ||||
| #include <sysc/tlm_target.h> | ||||
| #include <sysc/utilities.h> | ||||
| #include <util/bit_field.h> | ||||
|  | ||||
| namespace sysc { | ||||
|  | ||||
| class prci_regs : public sc_core::sc_module, public sysc::resetable { | ||||
| public: | ||||
|     // storage declarations | ||||
|     BEGIN_BF_DECL(hfrosccfg_t, uint32_t); | ||||
|     BF_FIELD(hfroscdiv, 0, 6); | ||||
|     BF_FIELD(hfrosctrim, 16, 5); | ||||
|     BF_FIELD(hfroscen, 30, 1); | ||||
|     BF_FIELD(hfroscrdy, 31, 1); | ||||
|     END_BF_DECL() r_hfrosccfg; | ||||
|  | ||||
|     BEGIN_BF_DECL(hfxosccfg_t, uint32_t); | ||||
|     BF_FIELD(hfxoscrdy, 31, 1); | ||||
|     BF_FIELD(hfxoscen, 30, 1); | ||||
|     END_BF_DECL() r_hfxosccfg; | ||||
|  | ||||
|     BEGIN_BF_DECL(pllcfg_t, uint32_t); | ||||
|     BF_FIELD(pllr, 0, 3); | ||||
|     BF_FIELD(pllf, 4, 6); | ||||
|     BF_FIELD(pllq, 10, 2); | ||||
|     BF_FIELD(pllsel, 16, 1); | ||||
|     BF_FIELD(pllrefsel, 17, 1); | ||||
|     BF_FIELD(pllbypass, 18, 1); | ||||
|     BF_FIELD(plllock, 31, 1); | ||||
|     END_BF_DECL() r_pllcfg; | ||||
|  | ||||
|     uint32_t r_plloutdiv; | ||||
|  | ||||
|     uint32_t r_coreclkcfg; | ||||
|  | ||||
|     // register declarations | ||||
|     sysc::sc_register<hfrosccfg_t> hfrosccfg; | ||||
|     sysc::sc_register<hfxosccfg_t> hfxosccfg; | ||||
|     sysc::sc_register<pllcfg_t> pllcfg; | ||||
|     sysc::sc_register<uint32_t> plloutdiv; | ||||
|     sysc::sc_register<uint32_t> coreclkcfg; | ||||
|  | ||||
|     prci_regs(sc_core::sc_module_name nm); | ||||
|  | ||||
|     template <unsigned BUSWIDTH = 32> void registerResources(sysc::tlm_target<BUSWIDTH> &target); | ||||
| }; | ||||
| } | ||||
| ////////////////////////////////////////////////////////////////////////////// | ||||
| // member functions | ||||
| ////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| inline sysc::prci_regs::prci_regs(sc_core::sc_module_name nm) | ||||
| : sc_core::sc_module(nm) | ||||
| , NAMED(hfrosccfg, r_hfrosccfg, 0, *this) | ||||
| , NAMED(hfxosccfg, r_hfxosccfg, 0, *this) | ||||
| , NAMED(pllcfg, r_pllcfg, 0, *this) | ||||
| , NAMED(plloutdiv, r_plloutdiv, 0, *this) | ||||
| , NAMED(coreclkcfg, r_coreclkcfg, 0, *this) {} | ||||
|  | ||||
| template <unsigned BUSWIDTH> inline void sysc::prci_regs::registerResources(sysc::tlm_target<BUSWIDTH> &target) { | ||||
|     target.addResource(hfrosccfg, 0x0UL); | ||||
|     target.addResource(hfxosccfg, 0x4UL); | ||||
|     target.addResource(pllcfg, 0x8UL); | ||||
|     target.addResource(plloutdiv, 0xcUL); | ||||
|     target.addResource(coreclkcfg, 0x10UL); | ||||
| } | ||||
|  | ||||
| #endif // _PRCI_REGS_H_ | ||||
| @@ -28,7 +28,7 @@ | ||||
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
| // POSSIBILITY OF SUCH DAMAGE. | ||||
| // | ||||
| // Created on: Wed Sep 20 22:30:45 CEST 2017 | ||||
| // Created on: Wed Oct 04 10:06:35 CEST 2017 | ||||
| //             *      spi_regs.h Author: <RDL Generator> | ||||
| // | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -44,7 +44,7 @@ | ||||
| namespace sysc { | ||||
|  | ||||
| class spi_regs : public sc_core::sc_module, public sysc::resetable { | ||||
| protected: | ||||
| public: | ||||
|     // storage declarations | ||||
|     BEGIN_BF_DECL(sckdiv_t, uint32_t); | ||||
|     BF_FIELD(div, 0, 12); | ||||
| @@ -141,7 +141,6 @@ protected: | ||||
|     sysc::sc_register<ie_t> ie; | ||||
|     sysc::sc_register<ip_t> ip; | ||||
|  | ||||
| public: | ||||
|     spi_regs(sc_core::sc_module_name nm); | ||||
|  | ||||
|     template <unsigned BUSWIDTH = 32> void registerResources(sysc::tlm_target<BUSWIDTH> &target); | ||||
|   | ||||
| @@ -28,7 +28,7 @@ | ||||
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
| // POSSIBILITY OF SUCH DAMAGE. | ||||
| // | ||||
| // Created on: Wed Sep 20 22:30:45 CEST 2017 | ||||
| // Created on: Wed Oct 04 10:06:35 CEST 2017 | ||||
| //             *      uart_regs.h Author: <RDL Generator> | ||||
| // | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -44,7 +44,7 @@ | ||||
| namespace sysc { | ||||
|  | ||||
| class uart_regs : public sc_core::sc_module, public sysc::resetable { | ||||
| protected: | ||||
| public: | ||||
|     // storage declarations | ||||
|     BEGIN_BF_DECL(txdata_t, uint32_t); | ||||
|     BF_FIELD(data, 0, 8); | ||||
| @@ -59,13 +59,11 @@ protected: | ||||
|     BEGIN_BF_DECL(txctrl_t, uint32_t); | ||||
|     BF_FIELD(txen, 0, 1); | ||||
|     BF_FIELD(nstop, 1, 1); | ||||
|     BF_FIELD(reserved, 2, 14); | ||||
|     BF_FIELD(txcnt, 16, 3); | ||||
|     END_BF_DECL() r_txctrl; | ||||
|  | ||||
|     BEGIN_BF_DECL(rxctrl_t, uint32_t); | ||||
|     BF_FIELD(rxen, 0, 1); | ||||
|     BF_FIELD(reserved, 1, 15); | ||||
|     BF_FIELD(rxcnt, 16, 3); | ||||
|     END_BF_DECL() r_rxctrl; | ||||
|  | ||||
| @@ -92,7 +90,6 @@ protected: | ||||
|     sysc::sc_register<ip_t> ip; | ||||
|     sysc::sc_register<div_t> div; | ||||
|  | ||||
| public: | ||||
|     uart_regs(sc_core::sc_module_name nm); | ||||
|  | ||||
|     template <unsigned BUSWIDTH = 32> void registerResources(sysc::tlm_target<BUSWIDTH> &target); | ||||
|   | ||||
| @@ -23,14 +23,19 @@ | ||||
| #ifndef SIMPLESYSTEM_H_ | ||||
| #define SIMPLESYSTEM_H_ | ||||
|  | ||||
| #include "aon.h" | ||||
| #include "clint.h" | ||||
| #include "gpio.h" | ||||
| #include "plic.h" | ||||
| #include "prci.h" | ||||
| #include "spi.h" | ||||
| #include "uart.h" | ||||
|  | ||||
| #include <array> | ||||
| #include <sysc/kernel/sc_module.h> | ||||
| #include <sysc/memory.h> | ||||
| #include <sysc/router.h> | ||||
| #include <sysc/utilities.h> | ||||
|  | ||||
| #include "core_complex.h" | ||||
|  | ||||
| @@ -40,14 +45,20 @@ class platform : public sc_core::sc_module { | ||||
| public: | ||||
|     SC_HAS_PROCESS(platform); | ||||
|  | ||||
|     SiFive::core_complex i_master; | ||||
|     SiFive::core_complex i_core_complex; | ||||
|     router<> i_router; | ||||
|     uart i_uart; | ||||
|     uart i_uart0, i_uart1; | ||||
|     spi i_spi; | ||||
|     gpio i_gpio; | ||||
|     plic i_plic; | ||||
|     aon i_aon; | ||||
|     prci i_prci; | ||||
|     clint i_clint; | ||||
|  | ||||
|     memory<512_MB, 32> i_mem_qspi; | ||||
|     memory<128_kB, 32> i_mem_ram; | ||||
|     sc_core::sc_signal<sc_core::sc_time> s_clk; | ||||
|     sc_core::sc_signal<bool> s_rst; | ||||
|     sc_core::sc_signal<bool> s_rst, s_mtime_int, s_msie_int; | ||||
|  | ||||
|     platform(sc_core::sc_module_name nm); | ||||
|  | ||||
|   | ||||
							
								
								
									
										45
									
								
								riscv.sc/incl/sysc/SiFive/prci.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								riscv.sc/incl/sysc/SiFive/prci.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| /******************************************************************************* | ||||
|  * Copyright 2017 eyck@minres.com | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||||
|  * use this file except in compliance with the License.  You may obtain a copy | ||||
|  * of the License at | ||||
|  * | ||||
|  *   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the | ||||
|  * License for the specific language governing permissions and limitations under | ||||
|  * the License. | ||||
|  ******************************************************************************/ | ||||
|  | ||||
| #ifndef _PRCI_H_ | ||||
| #define _PRCI_H_ | ||||
|  | ||||
| #include <sysc/tlm_target.h> | ||||
|  | ||||
| namespace sysc { | ||||
|  | ||||
| class prci_regs; | ||||
|  | ||||
| class prci : public sc_core::sc_module, public tlm_target<> { | ||||
| public: | ||||
|     SC_HAS_PROCESS(prci); | ||||
|     sc_core::sc_in<sc_core::sc_time> clk_i; | ||||
|     sc_core::sc_in<bool> rst_i; | ||||
|     prci(sc_core::sc_module_name nm); | ||||
|     virtual ~prci() override; // need to keep it in source file because of fwd declaration of prci_regs | ||||
|  | ||||
| protected: | ||||
|     void clock_cb(); | ||||
|     void reset_cb(); | ||||
|     void hfrosc_en_cb(); | ||||
|     sc_core::sc_time clk; | ||||
|     std::unique_ptr<prci_regs> regs; | ||||
|     sc_core::sc_event hfrosc_en_evt; | ||||
| }; | ||||
|  | ||||
| } /* namespace sysc */ | ||||
|  | ||||
| #endif /* _GPIO_H_ */ | ||||
| @@ -34,8 +34,10 @@ public: | ||||
| protected: | ||||
|     void clock_cb(); | ||||
|     void reset_cb(); | ||||
|     void transmit_data(); | ||||
|     sc_core::sc_time clk; | ||||
|     std::unique_ptr<uart_regs> regs; | ||||
|     std::vector<uint8_t> queue; | ||||
| }; | ||||
|  | ||||
| } /* namespace sysc */ | ||||
|   | ||||
| @@ -1,13 +1,9 @@ | ||||
| # library files | ||||
| FILE(GLOB RiscVSCHeaders *.h) | ||||
| FILE(GLOB RiscvSCSources sysc/*.cpp) | ||||
|  | ||||
| set(LIB_HEADERS ${RiscVSCHeaders} ) | ||||
| set(LIB_SOURCES | ||||
|     sysc/core_complex.cpp | ||||
|     sysc/gpio.cpp | ||||
|     sysc/plic.cpp | ||||
|     sysc/platform.cpp | ||||
|     sysc/spi.cpp | ||||
|     sysc/uart.cpp | ||||
| set(LIB_SOURCES ${RiscvSCSources} | ||||
| ) | ||||
|  | ||||
| set(APP_HEADERS ) | ||||
|   | ||||
| @@ -21,9 +21,12 @@ | ||||
|  */ | ||||
|  | ||||
| #include <boost/program_options.hpp> | ||||
| #include <iss/jit/MCJIThelper.h> | ||||
| #include <iss/log_categories.h> | ||||
| #include <sr_report/sr_report.h> | ||||
| #include <sstream> | ||||
| #include <sysc/SiFive/platform.h> | ||||
| #include <sysc/configurer.h> | ||||
| #include <sysc/report.h> | ||||
| #include <sysc/scv_tr_db.h> | ||||
| #include <sysc/tracer.h> | ||||
| @@ -39,19 +42,34 @@ const size_t ERROR_UNHANDLED_EXCEPTION = 2; | ||||
|  | ||||
| int sc_main(int argc, char *argv[]) { | ||||
|     //    sc_report_handler::set_handler(my_report_handler); | ||||
|     sysc::Logger::reporting_level() = log::DEBUG; | ||||
|     sysc::Logger<>::reporting_level() = log::ERROR; | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     // CLI argument parsing | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     po::options_description desc("Options"); | ||||
|     desc.add_options()("help,h", "Print help message")("debug,d", po::value<int>(), | ||||
|                                                        "set debug level")("trace,t", "trace SystemC signals"); | ||||
|     // clang-format off | ||||
|     desc.add_options() | ||||
|             ("help,h", "Print help message") | ||||
|             ("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity") | ||||
|             ("log-file", po::value<std::string>(), "Sets default log file.") | ||||
|             ("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly") | ||||
| //            ("elf,l", po::value<std::vector<std::string>>(), "ELF file(s) to load") | ||||
|             ("elf,l", po::value<std::string>(), "ELF file to load") | ||||
|             ("gdb-port,g", po::value<unsigned short>()->default_value(0), "enable gdb server and specify port to use") | ||||
|             ("dump-ir", "dump the intermediate representation") | ||||
|             ("cycles,c", po::value<int64_t>()->default_value(-1), "number of cycles to run") | ||||
|             ("quantum", po::value<unsigned>(), "SystemC quantum time in ns") | ||||
|             ("reset,r", po::value<std::string>(), "reset address") | ||||
|             ("trace,t", po::value<uint8_t>()->default_value(0), "enable tracing, or combintation of 1=signals and 2=TX text, 4=TX compressed text, 6=TX in SQLite") | ||||
|             ("rv64", "run RV64") | ||||
|             ("config-file,c", po::value<std::string>()->default_value(""), "configuration file"); | ||||
|     // clang-format on | ||||
|     po::variables_map vm; | ||||
|     try { | ||||
|         po::store(po::parse_command_line(argc, argv, desc), vm); // can throw | ||||
|         // --help option | ||||
|         if (vm.count("help")) { | ||||
|             std::cout << "JIT-ISS simulator for AVR" << std::endl << desc << std::endl; | ||||
|             std::cout << "DBT-RISE-RiscV simulator for RISC-V" << std::endl << desc << std::endl; | ||||
|             return SUCCESS; | ||||
|         } | ||||
|         po::notify(vm); // throws on error, so do after help in case | ||||
| @@ -61,21 +79,65 @@ int sc_main(int argc, char *argv[]) { | ||||
|         std::cerr << desc << std::endl; | ||||
|         return ERROR_IN_COMMAND_LINE; | ||||
|     } | ||||
|     if (vm.count("verbose")) { | ||||
|         auto l = logging::as_log_level(vm["verbose"].as<int>()); | ||||
|         LOGGER(DEFAULT)::reporting_level() = l; | ||||
|         LOGGER(connection)::reporting_level() = l; | ||||
|         LOGGER(SystemC)::reporting_level() = l; | ||||
|         sysc::Logger<>::reporting_level() = l; | ||||
|     } | ||||
|     if (vm.count("log-file")) { | ||||
|         // configure the connection logger | ||||
|         auto f = fopen(vm["log-file"].as<std::string>().c_str(), "w"); | ||||
|         LOG_OUTPUT(DEFAULT)::stream() = f; | ||||
|         LOG_OUTPUT(connection)::stream() = f; | ||||
|         LOG_OUTPUT(SystemC)::stream() = f; | ||||
|     } | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     // set up infrastructure | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     iss::init_jit(argc, argv); | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     // set up tracing & transaction recording | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     sysc::tracer trace("simple_system", sysc::tracer::TEXT, vm.count("trace")); | ||||
|     sysc::tracer trace("simple_system", static_cast<sysc::tracer::file_type>(vm["trace"].as<uint8_t>() >> 1), | ||||
|                        vm["trace"].as<uint8_t>() != 0); | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     // set up configuration | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     sysc::configurer cfg(vm["config-file"].as<std::string>()); | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     // instantiate top level | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     platform i_simple_system("i_simple_system"); | ||||
|     // sr_report_handler::add_sc_object_to_filter(&i_simple_system.i_master, | ||||
|     // sc_core::SC_WARNING, sc_core::SC_MEDIUM); | ||||
|  | ||||
|     // cfg.dump_hierarchy(); | ||||
|     if (vm.count("elf")) cfg.set_value("i_simple_system.i_core_complex.elf_file", vm["elf"].as<std::string>()); | ||||
|     if (vm.count("reset")) { | ||||
|         auto str = vm["reset"].as<std::string>(); | ||||
|         uint64_t start_address = str.find("0x") == 0 ? std::stoull(str.substr(2), 0, 16) : std::stoull(str, 0, 10); | ||||
|         cfg.set_value("i_simple_system.i_core_complex.reset_address", start_address); | ||||
|     } | ||||
|     if (vm.count("disass")) { | ||||
|         cfg.set_value("i_simple_system.i_core_complex.enable_disass", true); | ||||
|         LOGGER(disass)::reporting_level() = logging::INFO; | ||||
|         auto file_name = vm["disass"].as<std::string>(); | ||||
|         if (file_name.length() > 0) { | ||||
|             LOG_OUTPUT(disass)::stream() = fopen(file_name.c_str(), "w"); | ||||
|             LOGGER(disass)::print_time() = false; | ||||
|             LOGGER(disass)::print_severity() = false; | ||||
|         } | ||||
|     } | ||||
|     cfg.set_value("i_simple_system.i_core_complex.gdb_server_port", vm["gdb-port"].as<unsigned short>()); | ||||
|     cfg.set_value("i_simple_system.i_core_complex.dump_ir", vm.count("dump-ir") != 0); | ||||
|     if (vm.count("quantum")) { | ||||
|         tlm::tlm_global_quantum::instance().set(sc_core::sc_time(vm["quantum"].as<unsigned>(), sc_core::SC_NS)); | ||||
|     } | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     // run simulation | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     sc_start(sc_core::sc_time(100, sc_core::SC_NS)); | ||||
|     sc_start(); | ||||
|     if (!sc_end_of_simulation_invoked()) sc_stop(); | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
							
								
								
									
										48
									
								
								riscv.sc/src/sysc/aon.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								riscv.sc/src/sysc/aon.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Copyright 2017 eyck@minres.com | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||||
| // use this file except in compliance with the License.  You may obtain a copy | ||||
| // of the License at | ||||
| // | ||||
| //   http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the | ||||
| // License for the specific language governing permissions and limitations under | ||||
| // the License. | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #include "sysc/SiFive/aon.h" | ||||
| #include "sysc/SiFive/gen/aon_regs.h" | ||||
| #include "sysc/utilities.h" | ||||
|  | ||||
| namespace sysc { | ||||
|  | ||||
| aon::aon(sc_core::sc_module_name nm) | ||||
| : sc_core::sc_module(nm) | ||||
| , tlm_target<>(clk) | ||||
| , NAMED(clk_i) | ||||
| , NAMED(rst_i) | ||||
| , NAMEDD(aon_regs, regs) { | ||||
|     regs->registerResources(*this); | ||||
|     SC_METHOD(clock_cb); | ||||
|     sensitive << clk_i; | ||||
|     SC_METHOD(reset_cb); | ||||
|     sensitive << rst_i; | ||||
|     dont_initialize(); | ||||
| } | ||||
|  | ||||
| void aon::clock_cb() {} | ||||
|  | ||||
| aon::~aon() {} | ||||
|  | ||||
| void aon::reset_cb() { | ||||
|     if (rst_i.read()) | ||||
|         regs->reset_start(); | ||||
|     else | ||||
|         regs->reset_stop(); | ||||
| } | ||||
|  | ||||
| } /* namespace sysc */ | ||||
							
								
								
									
										95
									
								
								riscv.sc/src/sysc/clint.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								riscv.sc/src/sysc/clint.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Copyright 2017 eyck@minres.com | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||||
| // use this file except in compliance with the License.  You may obtain a copy | ||||
| // of the License at | ||||
| // | ||||
| //   http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the | ||||
| // License for the specific language governing permissions and limitations under | ||||
| // the License. | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #include "sysc/SiFive/clint.h" | ||||
| #include "sysc/SiFive/gen/clint_regs.h" | ||||
| #include "sysc/utilities.h" | ||||
|  | ||||
| namespace sysc { | ||||
|  | ||||
| const int lfclk_mutiplier = 1 << 12; | ||||
|  | ||||
| clint::clint(sc_core::sc_module_name nm) | ||||
| : sc_core::sc_module(nm) | ||||
| , tlm_target<>(clk) | ||||
| , NAMED(clk_i) | ||||
| , NAMED(rst_i) | ||||
| , NAMED(mtime_int_o) | ||||
| , NAMED(msip_int_o) | ||||
| , NAMEDD(clint_regs, regs) | ||||
| , cnt_fraction(0) { | ||||
|     regs->registerResources(*this); | ||||
|     SC_METHOD(clock_cb); | ||||
|     sensitive << clk_i; | ||||
|     SC_METHOD(reset_cb); | ||||
|     sensitive << rst_i; | ||||
|     dont_initialize(); | ||||
|     regs->mtimecmp.set_write_cb([this](sc_register<uint64_t> ®, uint64_t data) -> bool { | ||||
|         if (!regs->in_reset()) { | ||||
|             reg.put(data); | ||||
|             this->update_mtime(); | ||||
|         } | ||||
|         return true; | ||||
|     }); | ||||
|     regs->mtime.set_read_cb([this](const sc_register<uint64_t> ®, uint64_t &data) -> bool { | ||||
|         this->update_mtime(); | ||||
|         data = reg.get(); | ||||
|         return true; | ||||
|     }); | ||||
|     regs->mtime.set_write_cb([this](sc_register<uint64_t> ®, uint64_t data) -> bool { return false; }); | ||||
|     regs->msip.set_write_cb([this](sc_register<uint32_t> ®, uint32_t data) -> bool { | ||||
|         reg.put(data); | ||||
|         msip_int_o.write(regs->r_msip.msip); | ||||
|         return true; | ||||
|     }); | ||||
|     SC_METHOD(update_mtime); | ||||
|     sensitive << mtime_evt; | ||||
|     dont_initialize(); | ||||
| } | ||||
|  | ||||
| void clint::clock_cb() { | ||||
|     update_mtime(); | ||||
|     clk = clk_i.read(); | ||||
|     update_mtime(); | ||||
| } | ||||
|  | ||||
| clint::~clint() {} | ||||
|  | ||||
| void clint::reset_cb() { | ||||
|     if (rst_i.read()) { | ||||
|         regs->reset_start(); | ||||
|         msip_int_o.write(false); | ||||
|         mtime_int_o.write(false); | ||||
|         cnt_fraction = 0; | ||||
|     } else | ||||
|         regs->reset_stop(); | ||||
| } | ||||
|  | ||||
| void clint::update_mtime() { | ||||
|     auto diff = (sc_time_stamp() - last_updt) / clk; | ||||
|     auto diffi = (int)diff; | ||||
|     regs->r_mtime += (diffi + cnt_fraction) / lfclk_mutiplier; | ||||
|     cnt_fraction = (cnt_fraction + diffi) % lfclk_mutiplier; | ||||
|     mtime_evt.cancel(); | ||||
|     if (regs->r_mtimecmp > regs->r_mtime && clk > SC_ZERO_TIME) { | ||||
|         sc_core::sc_time next_trigger = (clk * lfclk_mutiplier) * (regs->r_mtimecmp - regs->mtime) - cnt_fraction * clk; | ||||
|         mtime_evt.notify(next_trigger); | ||||
|     } else | ||||
|         mtime_int_o.write(true); | ||||
|     last_updt = sc_time_stamp(); | ||||
| } | ||||
|  | ||||
| } /* namespace sysc */ | ||||
| @@ -34,16 +34,222 @@ | ||||
| // | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #include <iss/arch/riscv_hart_msu_vp.h> | ||||
| #include <iss/arch/rv32imac.h> | ||||
| #include <iss/iss.h> | ||||
| #include <iss/vm_types.h> | ||||
| #include <sysc/SiFive/core_complex.h> | ||||
| #include <sysc/report.h> | ||||
|  | ||||
| namespace sysc { | ||||
| namespace SiFive { | ||||
|  | ||||
| class core_wrapper : public iss::arch::riscv_hart_msu_vp<iss::arch::rv32imac> { | ||||
| public: | ||||
|     using core_type = iss::arch::rv32imac; | ||||
|     using base_type = iss::arch::riscv_hart_msu_vp<iss::arch::rv32imac>; | ||||
|     using phys_addr_t = typename iss::arch::traits<iss::arch::rv32imac>::phys_addr_t; | ||||
|     core_wrapper(core_complex *owner) | ||||
|     : owner(owner) {} | ||||
|  | ||||
|     void notify_phase(iss::arch_if::exec_phase phase); | ||||
|  | ||||
|     iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) { | ||||
|         if (addr.type & iss::DEBUG) | ||||
|             return owner->read_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err; | ||||
|         else | ||||
|             return owner->read_mem(addr.val, length, data) ? iss::Ok : iss::Err; | ||||
|     } | ||||
|  | ||||
|     iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data) { | ||||
|         if (addr.type & iss::DEBUG) | ||||
|             return owner->write_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err; | ||||
|         else | ||||
|             return owner->write_mem(addr.val, length, data) ? iss::Ok : iss::Err; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     core_complex *const owner; | ||||
| }; | ||||
|  | ||||
| void core_wrapper::notify_phase(exec_phase phase) { | ||||
|     core_type::notify_phase(phase); | ||||
|     if (phase == ISTART) owner->sync(); | ||||
| } | ||||
|  | ||||
| core_complex::core_complex(sc_core::sc_module_name name) | ||||
| : sc_core::sc_module(name) | ||||
| , NAMED(initiator) | ||||
| , NAMED(rst_i) { | ||||
|     // TODO Auto-generated constructor stub | ||||
| , NAMED(clk_i) | ||||
| , NAMED(rst_i) | ||||
| , NAMED(elf_file, this) | ||||
| , NAMED(enable_disass, true, this) | ||||
| , NAMED(reset_address, 0ULL, this) | ||||
| , NAMED(gdb_server_port, 0, this) | ||||
| , NAMED(dump_ir, false, this) | ||||
| , read_lut(tlm_dmi_ext()) | ||||
| , write_lut(tlm_dmi_ext()) { | ||||
|  | ||||
|     initiator.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void { | ||||
|         auto lut_entry = read_lut.getEntry(start); | ||||
|         if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) { | ||||
|             read_lut.removeEntry(lut_entry); | ||||
|         } | ||||
|         lut_entry = write_lut.getEntry(start); | ||||
|         if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) { | ||||
|             write_lut.removeEntry(lut_entry); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     SC_THREAD(run); | ||||
|     SC_METHOD(clk_cb); | ||||
|     sensitive << clk_i; | ||||
| } | ||||
|  | ||||
| core_complex::~core_complex() = default; | ||||
|  | ||||
| void core_complex::trace(sc_core::sc_trace_file *trf) {} | ||||
|  | ||||
| void core_complex::before_end_of_elaboration() { | ||||
|     cpu = std::make_unique<core_wrapper>(this); | ||||
|     vm = iss::create<iss::arch::rv32imac>(cpu.get(), gdb_server_port.value, dump_ir.value); | ||||
|     vm->setDisassEnabled(enable_disass.value); | ||||
| } | ||||
|  | ||||
| void core_complex::start_of_simulation() { | ||||
|     quantum_keeper.reset(); | ||||
|     if (elf_file.value.size() > 0) cpu->load_file(elf_file.value); | ||||
| } | ||||
|  | ||||
| void core_complex::clk_cb() { curr_clk = clk_i.read(); } | ||||
|  | ||||
| void core_complex::run() { | ||||
|     wait(sc_core::SC_ZERO_TIME); | ||||
|     cpu->reset(reset_address.value); | ||||
|     try { | ||||
|         vm->start(-1); | ||||
|     } catch (iss::simulation_stopped &e) { | ||||
|     } | ||||
|     sc_core::sc_stop(); | ||||
| } | ||||
|  | ||||
| bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data) { | ||||
|     auto lut_entry = read_lut.getEntry(addr); | ||||
|     if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && | ||||
|         addr + length <= lut_entry.get_end_address() + 1) { | ||||
|         auto offset = addr - lut_entry.get_start_address(); | ||||
|         std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data); | ||||
|         quantum_keeper.inc(lut_entry.get_read_latency()); | ||||
|         return true; | ||||
|     } else { | ||||
|         tlm::tlm_generic_payload gp; | ||||
|         gp.set_command(tlm::TLM_READ_COMMAND); | ||||
|         gp.set_address(addr); | ||||
|         gp.set_data_ptr(data); | ||||
|         gp.set_data_length(length); | ||||
|         gp.set_streaming_width(4); | ||||
|         auto delay{quantum_keeper.get_local_time()}; | ||||
|         initiator->b_transport(gp, delay); | ||||
|         LOG(TRACE) << "read_mem(0x" << std::hex << addr << ") : " << data; | ||||
|         if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) { | ||||
|             return false; | ||||
|         } | ||||
|         if (gp.is_dmi_allowed()) { | ||||
|             gp.set_command(tlm::TLM_READ_COMMAND); | ||||
|             gp.set_address(addr); | ||||
|             tlm_dmi_ext dmi_data; | ||||
|             if (initiator->get_direct_mem_ptr(gp, dmi_data)) { | ||||
|                 if (dmi_data.is_read_allowed()) | ||||
|                     read_lut.addEntry(dmi_data, dmi_data.get_start_address(), | ||||
|                                       dmi_data.get_end_address() - dmi_data.get_start_address() + 1); | ||||
|                 if (dmi_data.is_write_allowed()) | ||||
|                     write_lut.addEntry(dmi_data, dmi_data.get_start_address(), | ||||
|                                        dmi_data.get_end_address() - dmi_data.get_start_address() + 1); | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *const data) { | ||||
|     auto lut_entry = write_lut.getEntry(addr); | ||||
|     if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && | ||||
|         addr + length <= lut_entry.get_end_address() + 1) { | ||||
|         auto offset = addr - lut_entry.get_start_address(); | ||||
|         std::copy(data, data + length, lut_entry.get_dmi_ptr() + offset); | ||||
|         quantum_keeper.inc(lut_entry.get_read_latency()); | ||||
|         return true; | ||||
|     } else { | ||||
|         write_buf.resize(length); | ||||
|         std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity | ||||
|         tlm::tlm_generic_payload gp; | ||||
|         gp.set_command(tlm::TLM_WRITE_COMMAND); | ||||
|         gp.set_address(addr); | ||||
|         gp.set_data_ptr(write_buf.data()); | ||||
|         gp.set_data_length(length); | ||||
|         gp.set_streaming_width(4); | ||||
|         auto delay{quantum_keeper.get_local_time()}; | ||||
|         initiator->b_transport(gp, delay); | ||||
|         quantum_keeper.set(delay); | ||||
|         LOG(TRACE) << "write_mem(0x" << std::hex << addr << ") : " << data; | ||||
|         if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) { | ||||
|             return false; | ||||
|         } | ||||
|         if (gp.is_dmi_allowed()) { | ||||
|             gp.set_command(tlm::TLM_READ_COMMAND); | ||||
|             gp.set_address(addr); | ||||
|             tlm_dmi_ext dmi_data; | ||||
|             if (initiator->get_direct_mem_ptr(gp, dmi_data)) { | ||||
|                 if (dmi_data.is_read_allowed()) | ||||
|                     read_lut.addEntry(dmi_data, dmi_data.get_start_address(), | ||||
|                                       dmi_data.get_end_address() - dmi_data.get_start_address() + 1); | ||||
|                 if (dmi_data.is_write_allowed()) | ||||
|                     write_lut.addEntry(dmi_data, dmi_data.get_start_address(), | ||||
|                                        dmi_data.get_end_address() - dmi_data.get_start_address() + 1); | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool core_complex::read_mem_dbg(uint64_t addr, unsigned length, uint8_t *const data) { | ||||
|     auto lut_entry = read_lut.getEntry(addr); | ||||
|     if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && | ||||
|         addr + length <= lut_entry.get_end_address() + 1) { | ||||
|         auto offset = addr - lut_entry.get_start_address(); | ||||
|         std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data); | ||||
|         quantum_keeper.inc(lut_entry.get_read_latency()); | ||||
|         return true; | ||||
|     } else { | ||||
|         tlm::tlm_generic_payload gp; | ||||
|         gp.set_command(tlm::TLM_READ_COMMAND); | ||||
|         gp.set_address(addr); | ||||
|         gp.set_data_ptr(data); | ||||
|         gp.set_data_length(length); | ||||
|         gp.set_streaming_width(length); | ||||
|         return initiator->transport_dbg(gp) == length; | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *const data) { | ||||
|     auto lut_entry = write_lut.getEntry(addr); | ||||
|     if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && | ||||
|         addr + length <= lut_entry.get_end_address() + 1) { | ||||
|         auto offset = addr - lut_entry.get_start_address(); | ||||
|         std::copy(data, data + length, lut_entry.get_dmi_ptr() + offset); | ||||
|         quantum_keeper.inc(lut_entry.get_read_latency()); | ||||
|         return true; | ||||
|     } else { | ||||
|         write_buf.resize(length); | ||||
|         std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity | ||||
|         tlm::tlm_generic_payload gp; | ||||
|         gp.set_command(tlm::TLM_WRITE_COMMAND); | ||||
|         gp.set_address(addr); | ||||
|         gp.set_data_ptr(write_buf.data()); | ||||
|         gp.set_data_length(length); | ||||
|         gp.set_streaming_width(length); | ||||
|         return initiator->transport_dbg(gp) == length; | ||||
|     } | ||||
| } | ||||
|  | ||||
| } /* namespace SiFive */ | ||||
|   | ||||
| @@ -31,6 +31,7 @@ gpio::gpio(sc_core::sc_module_name nm) | ||||
|     sensitive << clk_i; | ||||
|     SC_METHOD(reset_cb); | ||||
|     sensitive << rst_i; | ||||
|     dont_initialize(); | ||||
| } | ||||
|  | ||||
| void gpio::clock_cb() {} | ||||
|   | ||||
| @@ -26,37 +26,60 @@ namespace sysc { | ||||
|  | ||||
| platform::platform(sc_core::sc_module_name nm) | ||||
| : sc_core::sc_module(nm) | ||||
| , NAMED(i_master) | ||||
| , NAMED(i_router, 4, 1) | ||||
| , NAMED(i_uart) | ||||
| , NAMED(i_core_complex) | ||||
| , NAMED(i_router, 10, 1) | ||||
| , NAMED(i_uart0) | ||||
| , NAMED(i_uart1) | ||||
| , NAMED(i_spi) | ||||
| , NAMED(i_gpio) | ||||
| , NAMED(i_plic) | ||||
| , NAMED(i_aon) | ||||
| , NAMED(i_prci) | ||||
| , NAMED(i_clint) | ||||
| , NAMED(i_mem_qspi) | ||||
| , NAMED(i_mem_ram) | ||||
| , NAMED(s_clk) | ||||
| , NAMED(s_rst) { | ||||
|     i_master.initiator(i_router.target[0]); | ||||
|     i_core_complex.initiator(i_router.target[0]); | ||||
|     size_t i = 0; | ||||
|     for (const auto &e : e300_plat_map) { | ||||
|         i_router.initiator.at(i)(e.target->socket); | ||||
|         i_router.add_target_range(i, e.start, e.size); | ||||
|         i++; | ||||
|     } | ||||
|     i_uart.clk_i(s_clk); | ||||
|     i_router.initiator.at(i)(i_mem_qspi.target); | ||||
|     i_router.add_target_range(i, 0x20000000, 512_MB); | ||||
|     i_router.initiator.at(++i)(i_mem_ram.target); | ||||
|     i_router.add_target_range(i, 0x80000000, 128_kB); | ||||
|  | ||||
|     i_uart0.clk_i(s_clk); | ||||
|     i_uart1.clk_i(s_clk); | ||||
|     i_spi.clk_i(s_clk); | ||||
|     i_gpio.clk_i(s_clk); | ||||
|     i_plic.clk_i(s_clk); | ||||
|     s_clk.write(10_ns); | ||||
|     i_aon.clk_i(s_clk); | ||||
|     i_prci.clk_i(s_clk); | ||||
|     i_clint.clk_i(s_clk); | ||||
|     i_core_complex.clk_i(s_clk); | ||||
|  | ||||
|     i_uart.rst_i(s_rst); | ||||
|     i_uart0.rst_i(s_rst); | ||||
|     i_uart1.rst_i(s_rst); | ||||
|     i_spi.rst_i(s_rst); | ||||
|     i_gpio.rst_i(s_rst); | ||||
|     i_plic.rst_i(s_rst); | ||||
|     i_master.rst_i(s_rst); | ||||
|     i_aon.rst_i(s_rst); | ||||
|     i_prci.rst_i(s_rst); | ||||
|     i_clint.rst_i(s_rst); | ||||
|     i_core_complex.rst_i(s_rst); | ||||
|  | ||||
|     i_clint.mtime_int_o(s_mtime_int); | ||||
|     i_clint.msip_int_o(s_msie_int); | ||||
|  | ||||
|     SC_THREAD(gen_reset); | ||||
| } | ||||
|  | ||||
| void platform::gen_reset() { | ||||
|     s_clk = 10_ns; | ||||
|     s_rst = true; | ||||
|     wait(10_ns); | ||||
|     s_rst = false; | ||||
|   | ||||
| @@ -31,6 +31,7 @@ plic::plic(sc_core::sc_module_name nm) | ||||
|     sensitive << clk_i; | ||||
|     SC_METHOD(reset_cb); | ||||
|     sensitive << rst_i; | ||||
|     dont_initialize(); | ||||
| } | ||||
|  | ||||
| plic::~plic() {} | ||||
|   | ||||
							
								
								
									
										71
									
								
								riscv.sc/src/sysc/prci.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								riscv.sc/src/sysc/prci.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Copyright 2017 eyck@minres.com | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||||
| // use this file except in compliance with the License.  You may obtain a copy | ||||
| // of the License at | ||||
| // | ||||
| //   http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the | ||||
| // License for the specific language governing permissions and limitations under | ||||
| // the License. | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #include "sysc/SiFive/prci.h" | ||||
| #include "sysc/SiFive/gen/prci_regs.h" | ||||
| #include "sysc/utilities.h" | ||||
|  | ||||
| namespace sysc { | ||||
|  | ||||
| prci::prci(sc_core::sc_module_name nm) | ||||
| : sc_core::sc_module(nm) | ||||
| , tlm_target<>(clk) | ||||
| , NAMED(clk_i) | ||||
| , NAMED(rst_i) | ||||
| , NAMEDD(prci_regs, regs) { | ||||
|     regs->registerResources(*this); | ||||
|     SC_METHOD(clock_cb); | ||||
|     sensitive << clk_i; | ||||
|     SC_METHOD(reset_cb); | ||||
|     sensitive << rst_i; | ||||
|     dont_initialize(); | ||||
|     SC_METHOD(hfrosc_en_cb); | ||||
|     sensitive << hfrosc_en_evt; | ||||
|     dont_initialize(); | ||||
|  | ||||
|     regs->hfrosccfg.set_write_cb([this](sysc::sc_register<uint32_t> ®, uint32_t data) -> bool { | ||||
|         reg.put(data); | ||||
|         if (this->regs->r_hfrosccfg & (1 << 30)) { // check rosc_en | ||||
|             this->hfrosc_en_evt.notify(1, sc_core::SC_US); | ||||
|         } | ||||
|         return true; | ||||
|     }); | ||||
|     regs->pllcfg.set_write_cb([this](sysc::sc_register<uint32_t> ®, uint32_t data) -> bool { | ||||
|         reg.put(data); | ||||
|         auto &pllcfg = this->regs->r_pllcfg; | ||||
|         if (pllcfg.pllbypass == 0 && pllcfg.pllq != 0) { // set pll_lock if pll is selected | ||||
|             pllcfg.plllock = 1; | ||||
|         } | ||||
|         return true; | ||||
|     }); | ||||
| } | ||||
|  | ||||
| void prci::clock_cb() {} | ||||
|  | ||||
| prci::~prci() {} | ||||
|  | ||||
| void prci::reset_cb() { | ||||
|     if (rst_i.read()) | ||||
|         regs->reset_start(); | ||||
|     else | ||||
|         regs->reset_stop(); | ||||
| } | ||||
|  | ||||
| void prci::hfrosc_en_cb() { | ||||
|     regs->r_hfrosccfg |= (1 << 31); // set rosc_rdy | ||||
| } | ||||
|  | ||||
| } /* namespace sysc */ | ||||
| @@ -31,6 +31,7 @@ spi::spi(sc_core::sc_module_name nm) | ||||
|     sensitive << clk_i; | ||||
|     SC_METHOD(reset_cb); | ||||
|     sensitive << rst_i; | ||||
|     dont_initialize(); | ||||
| } | ||||
|  | ||||
| spi::~spi() {} | ||||
|   | ||||
| @@ -16,6 +16,7 @@ | ||||
|  | ||||
| #include "sysc/SiFive/uart.h" | ||||
| #include "sysc/SiFive/gen/uart_regs.h" | ||||
| #include "sysc/report.h" | ||||
| #include "sysc/utilities.h" | ||||
|  | ||||
| namespace sysc { | ||||
| @@ -31,6 +32,14 @@ uart::uart(sc_core::sc_module_name nm) | ||||
|     sensitive << clk_i; | ||||
|     SC_METHOD(reset_cb); | ||||
|     sensitive << rst_i; | ||||
|     dont_initialize(); | ||||
|     regs->txdata.set_write_cb([this](sc_register<uint32_t> ®, uint32_t data) -> bool { | ||||
|         if (!this->regs->in_reset()) { | ||||
|             reg.put(data); | ||||
|             this->transmit_data(); | ||||
|         } | ||||
|         return true; | ||||
|     }); | ||||
| } | ||||
|  | ||||
| uart::~uart() {} | ||||
| @@ -44,4 +53,13 @@ void uart::reset_cb() { | ||||
|         regs->reset_stop(); | ||||
| } | ||||
|  | ||||
| void uart::transmit_data() { | ||||
|     if (queue.size() >> 0 && (regs->r_txdata.data == '\n' || regs->r_txdata.data == 0)) { | ||||
|         LOG(INFO) << this->name() << " transmit: '" << std::string(queue.begin(), queue.end()) << "'"; | ||||
|         queue.clear(); | ||||
|     } else { | ||||
|         queue.push_back(regs->r_txdata.data); | ||||
|     } | ||||
| } | ||||
|  | ||||
| } /* namespace sysc */ | ||||
|   | ||||
| @@ -1,81 +0,0 @@ | ||||
| /******************************************************************************* | ||||
|  * Copyright (C) 2017, 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 API and implementation | ||||
|  ******************************************************************************/ | ||||
|  | ||||
| #ifndef _CLI_OPTIONS_H_ | ||||
| #define _CLI_OPTIONS_H_ | ||||
| #include <boost/program_options.hpp> | ||||
| #include <cstdio> | ||||
| #include <iostream> | ||||
| #include <util/logging.h> | ||||
|  | ||||
| const size_t ERROR_IN_COMMAND_LINE = 1; | ||||
| const size_t SUCCESS = 0; | ||||
| const size_t ERROR_UNHANDLED_EXCEPTION = 2; | ||||
|  | ||||
| inline int parse_cli_options(boost::program_options::variables_map &vm, int argc, char *argv[]) { | ||||
|     namespace po = boost::program_options; | ||||
|     po::options_description desc("Options"); | ||||
|     desc.add_options()("help,h", "Print help message")("verbose,v", po::value<int>()->implicit_value(0), | ||||
|                                                        "Sets logging verbosity")("vmodule", po::value<std::string>(), | ||||
|                                                                                  "Defines the module(s) to be logged")( | ||||
|         "logging-flags", po::value<int>(), "Sets logging flag(s).")("log-file", po::value<std::string>(), | ||||
|                                                                     "Sets default log file.")( | ||||
|         "disass,d", po::value<std::string>()->implicit_value(""), | ||||
|         "Enables disassembly")("elf,l", po::value<std::vector<std::string>>(), "ELF file(s) to load")( | ||||
|         "gdb-port,g", po::value<unsigned>(), "enable gdb server and specify port to use")( | ||||
|         "input,i", po::value<std::string>(), "the elf file to load (instead of hex files)")( | ||||
|         "dump-ir", "dump the intermediate representation")("cycles,c", po::value<int64_t>()->default_value(-1), | ||||
|                                                            "number of cycles to run")( | ||||
|         "systemc,s", "Run as SystemC simulation")("time", po::value<int>(), "SystemC siimulation time in ms")( | ||||
|         "reset,r", po::value<std::string>(), "reset address")( | ||||
|         "trace", po::value<uint8_t>(), "enable tracing, or cmbintation of 1=signals and 2=TX text, 4=TX " | ||||
|                                        "compressed text, 6=TX in SQLite")("mem,m", po::value<std::string>(), | ||||
|                                                                           "the memory input file")("rv64", "run RV64"); | ||||
|     try { | ||||
|         po::store(po::parse_command_line(argc, argv, desc), vm); // can throw | ||||
|         // --help option | ||||
|         if (vm.count("help")) { | ||||
|             std::cout << "DBT-RISE-RiscV" << std::endl << desc << std::endl; | ||||
|             return SUCCESS; | ||||
|         } | ||||
|         po::notify(vm); // throws on error, so do after help in case | ||||
|     } catch (po::error &e) { | ||||
|         // there are problems | ||||
|         std::cerr << "ERROR: " << e.what() << std::endl << std::endl; | ||||
|         std::cerr << desc << std::endl; | ||||
|         return ERROR_IN_COMMAND_LINE; | ||||
|     } | ||||
|     return SUCCESS; | ||||
| } | ||||
| #endif /* _CLI_OPTIONS_H_ */ | ||||
| @@ -431,7 +431,7 @@ template <typename BASE> struct riscv_hart_msu_vp : public BASE { | ||||
|     riscv_hart_msu_vp(); | ||||
|     virtual ~riscv_hart_msu_vp() = default; | ||||
|  | ||||
|     virtual void load_file(std::string name, int type = -1); | ||||
|     void load_file(std::string name, int type = -1) override; | ||||
|  | ||||
|     virtual phys_addr_t v2p(const iss::addr_t &addr); | ||||
|  | ||||
| @@ -550,9 +550,12 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::load_file(std::string nam | ||||
|                 const auto fsize = pseg->get_file_size(); // 0x42c/0x0 | ||||
|                 const auto seg_data = pseg->get_data(); | ||||
|                 if (fsize > 0) { | ||||
|                     this->write( | ||||
|                         typed_addr_t<PHYSICAL>(iss::DEBUG_WRITE, traits<BASE>::MEM, pseg->get_virtual_address()), fsize, | ||||
|                         reinterpret_cast<const uint8_t *const>(seg_data)); | ||||
|                     auto res = this->write( | ||||
|                         typed_addr_t<PHYSICAL>(iss::DEBUG_WRITE, traits<BASE>::MEM, pseg->get_physical_address()), | ||||
|                         fsize, reinterpret_cast<const uint8_t *const>(seg_data)); | ||||
|                     if (res != iss::Ok) | ||||
|                         LOG(ERROR) << "problem writing " << fsize << "bytes to 0x" << std::hex | ||||
|                                    << pseg->get_physical_address(); | ||||
|                 } | ||||
|             } | ||||
|             for (const auto sec : reader.sections) { | ||||
| @@ -596,20 +599,9 @@ iss::status riscv_hart_msu_vp<BASE>::read(const iss::addr_t &addr, unsigned leng | ||||
|                 } | ||||
|             } | ||||
|             phys_addr_t paddr = (addr.type & iss::ADDRESS_TYPE) == iss::PHYSICAL ? addr : v2p(addr); | ||||
|             if ((paddr.val + length) > mem.size()) return iss::Err; | ||||
|             switch (paddr.val) { | ||||
|             case 0x0200BFF8: { // CLINT base, mtime reg | ||||
|                 uint64_t mtime = this->reg.icount >> 12 /*12*/; | ||||
|                 std::copy((uint8_t *)&mtime, ((uint8_t *)&mtime) + length, data); | ||||
|             } break; | ||||
|             case 0x10008000: { | ||||
|                 const mem_type::page_type &p = mem(paddr.val / mem.page_size); | ||||
|                 uint64_t offs = paddr.val & mem.page_addr_mask; | ||||
|                 std::copy(p.data() + offs, p.data() + offs + length, data); | ||||
|                 if (this->reg.icount > 30000) data[3] |= 0x80; | ||||
|             } break; | ||||
|             default: { return read_mem(paddr, length, data); } | ||||
|             } | ||||
|             auto res = read_mem(paddr, length, data); | ||||
|             if (res != iss::Ok) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault | ||||
|             return res; | ||||
|         } catch (trap_access &ta) { | ||||
|             this->reg.trap_state = (1 << 31) | ta.id; | ||||
|             return iss::Err; | ||||
| @@ -677,6 +669,33 @@ iss::status riscv_hart_msu_vp<BASE>::write(const iss::addr_t &addr, unsigned len | ||||
|     try { | ||||
|         switch (addr.space) { | ||||
|         case traits<BASE>::MEM: { | ||||
|             if ((addr.type & (iss::ACCESS_TYPE - iss::DEBUG)) == iss::FETCH && (addr.val & 0x1) == 1) { | ||||
|                 fault_data = addr.val; | ||||
|                 if ((addr.type & iss::DEBUG)) throw trap_access(0, addr.val); | ||||
|                 this->reg.trap_state = (1 << 31); // issue trap 0 | ||||
|                 return iss::Err; | ||||
|             } | ||||
|             try { | ||||
|                 if ((addr.val & ~PGMASK) != ((addr.val + length - 1) & ~PGMASK)) { // we may cross a page boundary | ||||
|                     vm_info vm = decode_vm_info<traits<BASE>::XLEN>(this->reg.machine_state, csr[satp]); | ||||
|                     if (vm.levels != 0) { // VM is active | ||||
|                         auto split_addr = (addr.val + length) & ~PGMASK; | ||||
|                         auto len1 = split_addr - addr.val; | ||||
|                         auto res = write(addr, len1, data); | ||||
|                         if (res == iss::Ok) | ||||
|                             res = write(iss::addr_t{addr.type, addr.space, split_addr}, length - len1, data + len1); | ||||
|                         return res; | ||||
|                     } | ||||
|                 } | ||||
|                 phys_addr_t paddr = (addr.type & iss::ADDRESS_TYPE) == iss::PHYSICAL ? addr : v2p(addr); | ||||
|                 auto res = write_mem(paddr, length, data); | ||||
|                 if (res != iss::Ok) this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (load access fault | ||||
|                 return res; | ||||
|             } catch (trap_access &ta) { | ||||
|                 this->reg.trap_state = (1 << 31) | ta.id; | ||||
|                 return iss::Err; | ||||
|             } | ||||
|  | ||||
|             phys_addr_t paddr = (addr.type & iss::ADDRESS_TYPE) == iss::PHYSICAL ? addr : v2p(addr); | ||||
|             if ((paddr.val + length) > mem.size()) return iss::Err; | ||||
|             switch (paddr.val) { | ||||
| @@ -691,22 +710,22 @@ iss::status riscv_hart_msu_vp<BASE>::write(const iss::addr_t &addr, unsigned len | ||||
|                 } | ||||
|                 return iss::Ok; | ||||
|             case 0x10008000: { // HFROSC base, hfrosccfg reg | ||||
|                 mem_type::page_type &p = mem(paddr.val / mem.page_size); | ||||
|                 size_t offs = paddr.val & mem.page_addr_mask; | ||||
|                 auto &p = mem(paddr.val / mem.page_size); | ||||
|                 auto offs = paddr.val & mem.page_addr_mask; | ||||
|                 std::copy(data, data + length, p.data() + offs); | ||||
|                 uint8_t &x = *(p.data() + offs + 3); | ||||
|                 auto &x = *(p.data() + offs + 3); | ||||
|                 if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1 | ||||
|                 return iss::Ok; | ||||
|             } | ||||
|             case 0x10008008: { // HFROSC base, pllcfg reg | ||||
|                 mem_type::page_type &p = mem(paddr.val / mem.page_size); | ||||
|                 size_t offs = paddr.val & mem.page_addr_mask; | ||||
|                 auto &p = mem(paddr.val / mem.page_size); | ||||
|                 auto offs = paddr.val & mem.page_addr_mask; | ||||
|                 std::copy(data, data + length, p.data() + offs); | ||||
|                 uint8_t &x = *(p.data() + offs + 3); | ||||
|                 auto &x = *(p.data() + offs + 3); | ||||
|                 x |= 0x80; // set pll lock upon writing | ||||
|                 return iss::Ok; | ||||
|             } break; | ||||
|             default: { return write_mem(paddr, length, data); } | ||||
|             default: {} | ||||
|             } | ||||
|         } break; | ||||
|         case traits<BASE>::CSR: { | ||||
| @@ -857,56 +876,102 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_satp(unsigne | ||||
| } | ||||
|  | ||||
| template <typename BASE> | ||||
| iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) { | ||||
|     const auto &p = mem(addr.val / mem.page_size); | ||||
|     auto offs = addr.val & mem.page_addr_mask; | ||||
|     std::copy(p.data() + offs, p.data() + offs + length, data); | ||||
|     return iss::Ok; | ||||
| iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { | ||||
|     if ((paddr.val + length) > mem.size()) return iss::Err; | ||||
|     switch (paddr.val) { | ||||
|     case 0x0200BFF8: { // CLINT base, mtime reg | ||||
|         uint64_t mtime = this->reg.icount >> 12 /*12*/; | ||||
|         std::copy((uint8_t *)&mtime, ((uint8_t *)&mtime) + length, data); | ||||
|     } break; | ||||
|     case 0x10008000: { | ||||
|         const mem_type::page_type &p = mem(paddr.val / mem.page_size); | ||||
|         uint64_t offs = paddr.val & mem.page_addr_mask; | ||||
|         std::copy(p.data() + offs, p.data() + offs + length, data); | ||||
|         if (this->reg.icount > 30000) data[3] |= 0x80; | ||||
|     } break; | ||||
|     default: { | ||||
|         const auto &p = mem(paddr.val / mem.page_size); | ||||
|         auto offs = paddr.val & mem.page_addr_mask; | ||||
|         std::copy(p.data() + offs, p.data() + offs + length, data); | ||||
|         return iss::Ok; | ||||
|     } | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename BASE> | ||||
| iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data) { | ||||
|     mem_type::page_type &p = mem(addr.val / mem.page_size); | ||||
|     std::copy(data, data + length, p.data() + (addr.val & mem.page_addr_mask)); | ||||
|     // tohost handling in case of riscv-test | ||||
|     if ((addr.type & iss::DEBUG) == 0) { | ||||
|         auto tohost_upper = | ||||
|             (traits<BASE>::XLEN == 32 && addr.val == (tohost + 4)) || (traits<BASE>::XLEN == 64 && addr.val == tohost); | ||||
|         auto tohost_lower = | ||||
|             (traits<BASE>::XLEN == 32 && addr.val == tohost) || (traits<BASE>::XLEN == 64 && addr.val == tohost); | ||||
|         if (tohost_lower || tohost_upper) { | ||||
|             uint64_t hostvar = *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)); | ||||
|             if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) { | ||||
|                 switch (hostvar >> 48) { | ||||
|                 case 0: | ||||
|                     if (hostvar != 0x1) | ||||
|                         LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar | ||||
|                                    << "), stopping simulation"; | ||||
|                     else | ||||
|                         LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar | ||||
|                                   << "), stopping simulation"; | ||||
|                     throw(iss::simulation_stopped(hostvar)); | ||||
|                 case 0x0101: { | ||||
|                     char c = static_cast<char>(hostvar & 0xff); | ||||
|                     if (c == '\n' || c == 0) { | ||||
|                         LOG(INFO) << "tohost send '" << uart_buf.str() << "'"; | ||||
|                         uart_buf.str(""); | ||||
|                     } else | ||||
|                         uart_buf << c; | ||||
|                     to_host_wr_cnt = 0; | ||||
|                 } break; | ||||
|                 default: | ||||
|                     break; | ||||
|                 } | ||||
|             } else if (tohost_lower) | ||||
|                 to_host_wr_cnt++; | ||||
|         } else if ((traits<BASE>::XLEN == 32 && addr.val == fromhost + 4) || | ||||
|                    (traits<BASE>::XLEN == 64 && addr.val == fromhost)) { | ||||
|             uint64_t fhostvar = *reinterpret_cast<uint64_t *>(p.data() + (fromhost & mem.page_addr_mask)); | ||||
|             *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar; | ||||
| iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) { | ||||
|     if ((paddr.val + length) > mem.size()) return iss::Err; | ||||
|     switch (paddr.val) { | ||||
|     case 0x10013000: // UART0 base, TXFIFO reg | ||||
|     case 0x10023000: // UART1 base, TXFIFO reg | ||||
|         uart_buf << (char)data[0]; | ||||
|         if (((char)data[0]) == '\n' || data[0] == 0) { | ||||
|             // LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send | ||||
|             // '"<<uart_buf.str()<<"'"; | ||||
|             std::cout << uart_buf.str(); | ||||
|             uart_buf.str(""); | ||||
|         } | ||||
|         return iss::Ok; | ||||
|     case 0x10008000: { // HFROSC base, hfrosccfg reg | ||||
|         mem_type::page_type &p = mem(paddr.val / mem.page_size); | ||||
|         size_t offs = paddr.val & mem.page_addr_mask; | ||||
|         std::copy(data, data + length, p.data() + offs); | ||||
|         uint8_t &x = *(p.data() + offs + 3); | ||||
|         if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1 | ||||
|         return iss::Ok; | ||||
|     } | ||||
|     case 0x10008008: { // HFROSC base, pllcfg reg | ||||
|         mem_type::page_type &p = mem(paddr.val / mem.page_size); | ||||
|         size_t offs = paddr.val & mem.page_addr_mask; | ||||
|         std::copy(data, data + length, p.data() + offs); | ||||
|         uint8_t &x = *(p.data() + offs + 3); | ||||
|         x |= 0x80; // set pll lock upon writing | ||||
|         return iss::Ok; | ||||
|     } break; | ||||
|     default: { | ||||
|         mem_type::page_type &p = mem(paddr.val / mem.page_size); | ||||
|         std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask)); | ||||
|         // tohost handling in case of riscv-test | ||||
|         if ((paddr.type & iss::DEBUG) == 0) { | ||||
|             auto tohost_upper = (traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4)) || | ||||
|                                 (traits<BASE>::XLEN == 64 && paddr.val == tohost); | ||||
|             auto tohost_lower = | ||||
|                 (traits<BASE>::XLEN == 32 && paddr.val == tohost) || (traits<BASE>::XLEN == 64 && paddr.val == tohost); | ||||
|             if (tohost_lower || tohost_upper) { | ||||
|                 uint64_t hostvar = *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)); | ||||
|                 if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) { | ||||
|                     switch (hostvar >> 48) { | ||||
|                     case 0: | ||||
|                         if (hostvar != 0x1) | ||||
|                             LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar | ||||
|                                        << "), stopping simulation"; | ||||
|                         else | ||||
|                             LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar | ||||
|                                       << "), stopping simulation"; | ||||
|                         throw(iss::simulation_stopped(hostvar)); | ||||
|                     case 0x0101: { | ||||
|                         char c = static_cast<char>(hostvar & 0xff); | ||||
|                         if (c == '\n' || c == 0) { | ||||
|                             LOG(INFO) << "tohost send '" << uart_buf.str() << "'"; | ||||
|                             uart_buf.str(""); | ||||
|                         } else | ||||
|                             uart_buf << c; | ||||
|                         to_host_wr_cnt = 0; | ||||
|                     } break; | ||||
|                     default: | ||||
|                         break; | ||||
|                     } | ||||
|                 } else if (tohost_lower) | ||||
|                     to_host_wr_cnt++; | ||||
|             } else if ((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) || | ||||
|                        (traits<BASE>::XLEN == 64 && paddr.val == fromhost)) { | ||||
|                 uint64_t fhostvar = *reinterpret_cast<uint64_t *>(p.data() + (fromhost & mem.page_addr_mask)); | ||||
|                 *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar; | ||||
|             } | ||||
|         } | ||||
|         return iss::Ok; | ||||
|     } | ||||
|     } | ||||
|     return iss::Ok; | ||||
| } | ||||
|  | ||||
| template <typename BASE> void riscv_hart_msu_vp<BASE>::check_interrupt() { | ||||
|   | ||||
| @@ -140,7 +140,7 @@ struct rv32imac : public arch_if { | ||||
|     using addr_t = typename traits<rv32imac>::addr_t; | ||||
|  | ||||
|     rv32imac(); | ||||
|     ~rv32imac(); | ||||
|     ~rv32imac() = default; | ||||
|  | ||||
|     void reset(uint64_t address = 0) override; | ||||
|  | ||||
| @@ -154,7 +154,7 @@ struct rv32imac : public arch_if { | ||||
|     /// deprecated | ||||
|     void update_flags(operations op, uint64_t opr1, uint64_t opr2) override{}; | ||||
|  | ||||
|     void notify_phase(exec_phase phase) { | ||||
|     void notify_phase(exec_phase phase) override { | ||||
|         if (phase == ISTART) { | ||||
|             ++reg.icount; | ||||
|             reg.PC = reg.NEXT_PC; | ||||
|   | ||||
| @@ -342,21 +342,8 @@ template <> | ||||
| std::unique_ptr<vm_if> create<arch::CORE_DEF_NAME>(arch::CORE_DEF_NAME *core, unsigned short port, bool dump) { | ||||
|     std::unique_ptr<CORE_DEF_NAME::vm_impl<arch::CORE_DEF_NAME>> ret = | ||||
|         std::make_unique<CORE_DEF_NAME::vm_impl<arch::CORE_DEF_NAME>>(*core, dump); | ||||
|     debugger::server<debugger::gdb_session>::run_server(ret.get(), port); | ||||
|     if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret.get(), port); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| template <> std::unique_ptr<vm_if> create<arch::CORE_DEF_NAME>(std::string inst_name, unsigned short port, bool dump) { | ||||
|     return create<arch::CORE_DEF_NAME>(new arch::riscv_hart_msu_vp<arch::CORE_DEF_NAME>(), port, | ||||
|                                        dump); /* FIXME: memory leak!!!!!!! */ | ||||
| } | ||||
|  | ||||
| template <> std::unique_ptr<vm_if> create<arch::CORE_DEF_NAME>(arch::CORE_DEF_NAME *core, bool dump) { | ||||
|     return std::make_unique<CORE_DEF_NAME::vm_impl<arch::CORE_DEF_NAME>>(*core, dump); /* FIXME: memory leak!!!!!!! */ | ||||
| } | ||||
|  | ||||
| template <> std::unique_ptr<vm_if> create<arch::CORE_DEF_NAME>(std::string inst_name, bool dump) { | ||||
|     return create<arch::CORE_DEF_NAME>(new arch::riscv_hart_msu_vp<arch::CORE_DEF_NAME>(), dump); | ||||
| } | ||||
|  | ||||
| } // namespace iss | ||||
|   | ||||
| @@ -4014,21 +4014,8 @@ template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(llvm::BasicBl | ||||
| template <> std::unique_ptr<vm_if> create<arch::rv32imac>(arch::rv32imac *core, unsigned short port, bool dump) { | ||||
|     std::unique_ptr<rv32imac::vm_impl<arch::rv32imac>> ret = | ||||
|         std::make_unique<rv32imac::vm_impl<arch::rv32imac>>(*core, dump); | ||||
|     debugger::server<debugger::gdb_session>::run_server(ret.get(), port); | ||||
|     if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret.get(), port); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| template <> std::unique_ptr<vm_if> create<arch::rv32imac>(std::string inst_name, unsigned short port, bool dump) { | ||||
|     return create<arch::rv32imac>(new arch::riscv_hart_msu_vp<arch::rv32imac>(), port, | ||||
|                                   dump); /* FIXME: memory leak!!!!!!! */ | ||||
| } | ||||
|  | ||||
| template <> std::unique_ptr<vm_if> create<arch::rv32imac>(arch::rv32imac *core, bool dump) { | ||||
|     return std::make_unique<rv32imac::vm_impl<arch::rv32imac>>(*core, dump); /* FIXME: memory leak!!!!!!! */ | ||||
| } | ||||
|  | ||||
| template <> std::unique_ptr<vm_if> create<arch::rv32imac>(std::string inst_name, bool dump) { | ||||
|     return create<arch::rv32imac>(new arch::riscv_hart_msu_vp<arch::rv32imac>(), dump); | ||||
| } | ||||
|  | ||||
| } // namespace iss | ||||
|   | ||||
| @@ -3101,21 +3101,8 @@ template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(llvm::BasicBl | ||||
|  | ||||
| template <> std::unique_ptr<vm_if> create<arch::rv64ia>(arch::rv64ia *core, unsigned short port, bool dump) { | ||||
|     std::unique_ptr<rv64ia::vm_impl<arch::rv64ia>> ret = std::make_unique<rv64ia::vm_impl<arch::rv64ia>>(*core, dump); | ||||
|     debugger::server<debugger::gdb_session>::run_server(ret.get(), port); | ||||
|     if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret.get(), port); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| template <> std::unique_ptr<vm_if> create<arch::rv64ia>(std::string inst_name, unsigned short port, bool dump) { | ||||
|     return create<arch::rv64ia>(new arch::riscv_hart_msu_vp<arch::rv64ia>(), port, | ||||
|                                 dump); /* FIXME: memory leak!!!!!!! */ | ||||
| } | ||||
|  | ||||
| template <> std::unique_ptr<vm_if> create<arch::rv64ia>(arch::rv64ia *core, bool dump) { | ||||
|     return std::make_unique<rv64ia::vm_impl<arch::rv64ia>>(*core, dump); /* FIXME: memory leak!!!!!!! */ | ||||
| } | ||||
|  | ||||
| template <> std::unique_ptr<vm_if> create<arch::rv64ia>(std::string inst_name, bool dump) { | ||||
|     return create<arch::rv64ia>(new arch::riscv_hart_msu_vp<arch::rv64ia>(), dump); | ||||
| } | ||||
|  | ||||
| } // namespace iss | ||||
|   | ||||
| @@ -54,8 +54,6 @@ using namespace iss::arch; | ||||
|  | ||||
| rv32imac::rv32imac() { reg.icount = 0; } | ||||
|  | ||||
| rv32imac::~rv32imac() {} | ||||
|  | ||||
| void rv32imac::reset(uint64_t address) { | ||||
|     for (size_t i = 0; i < traits<rv32imac>::NUM_REGS; ++i) | ||||
|         set_reg(i, std::vector<uint8_t>(sizeof(traits<rv32imac>::reg_t), 0)); | ||||
|   | ||||
| @@ -32,11 +32,12 @@ | ||||
| //       eyck@minres.com - initial API and implementation | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #include <cli_options.h> | ||||
| #include <iostream> | ||||
| #include <iss/iss.h> | ||||
|  | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #include <boost/program_options.hpp> | ||||
| #include <iss/arch/riscv_hart_msu_vp.h> | ||||
| #include <iss/arch/rv32imac.h> | ||||
| #include <iss/arch/rv64ia.h> | ||||
| #include <iss/jit/MCJIThelper.h> | ||||
| @@ -45,69 +46,97 @@ | ||||
| namespace po = boost::program_options; | ||||
|  | ||||
| int main(int argc, char *argv[]) { | ||||
|     /* | ||||
|      *  Define and parse the program options | ||||
|      */ | ||||
|     po::variables_map clim; | ||||
|     po::options_description desc("Options"); | ||||
|     // clang-format off | ||||
|     desc.add_options() | ||||
|         ("help,h", "Print help message") | ||||
|         ("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity") | ||||
|         ("log-file", po::value<std::string>(), "Sets default log file.") | ||||
|         ("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly") | ||||
|         ("elf,l", po::value<std::vector<std::string>>(), "ELF file(s) to load") | ||||
|         ("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use") | ||||
|         ("input,i", po::value<std::string>(), "the elf file to load (instead of hex files)") | ||||
|         ("dump-ir", "dump the intermediate representation") | ||||
|         ("cycles,c", po::value<int64_t>()->default_value(-1), "number of cycles to run") | ||||
|         ("systemc,s", "Run as SystemC simulation") | ||||
|         ("time", po::value<int>(), "SystemC siimulation time in ms") | ||||
|         ("reset,r", po::value<std::string>(), "reset address") | ||||
|         ("trace", po::value<uint8_t>(), "enable tracing, or cmbintation of 1=signals and 2=TX text, 4=TX compressed text, 6=TX in SQLite") | ||||
|         ("mem,m", po::value<std::string>(), "the memory input file") | ||||
|         ("rv64", "run RV64"); | ||||
|     // clang-format on | ||||
|     try { | ||||
|         /* | ||||
|          *  Define and parse the program options | ||||
|          */ | ||||
|         po::variables_map vm; | ||||
|         if (parse_cli_options(vm, argc, argv)) return ERROR_IN_COMMAND_LINE; | ||||
|         if (vm.count("verbose")) { | ||||
|             auto l = logging::as_log_level(vm["verbose"].as<int>()); | ||||
|             LOGGER(DEFAULT)::reporting_level() = l; | ||||
|             LOGGER(connection)::reporting_level() = l; | ||||
|         } | ||||
|         if (vm.count("log-file")) { | ||||
|             // configure the connection logger | ||||
|             auto f = fopen(vm["log-file"].as<std::string>().c_str(), "w"); | ||||
|             LOG_OUTPUT(DEFAULT)::stream() = f; | ||||
|             LOG_OUTPUT(connection)::stream() = f; | ||||
|         po::store(po::parse_command_line(argc, argv, desc), clim); // can throw | ||||
|         // --help option | ||||
|         if (clim.count("help")) { | ||||
|             std::cout << "DBT-RISE-RiscV simulator for RISC-V" << std::endl << desc << std::endl; | ||||
|             return 0; | ||||
|         } | ||||
|         po::notify(clim); // throws on error, so do after help in case | ||||
|     } catch (po::error &e) { | ||||
|         // there are problems | ||||
|         std::cerr << "ERROR: " << e.what() << std::endl << std::endl; | ||||
|         std::cerr << desc << std::endl; | ||||
|         return 1; | ||||
|     } | ||||
|     if (clim.count("verbose")) { | ||||
|         auto l = logging::as_log_level(clim["verbose"].as<int>()); | ||||
|         LOGGER(DEFAULT)::reporting_level() = l; | ||||
|         LOGGER(connection)::reporting_level() = l; | ||||
|     } | ||||
|     if (clim.count("log-file")) { | ||||
|         // configure the connection logger | ||||
|         auto f = fopen(clim["log-file"].as<std::string>().c_str(), "w"); | ||||
|         LOG_OUTPUT(DEFAULT)::stream() = f; | ||||
|         LOG_OUTPUT(connection)::stream() = f; | ||||
|     } | ||||
|  | ||||
|     try { | ||||
|         // application code comes here // | ||||
|         iss::init_jit(argc, argv); | ||||
|         bool dump = vm.count("dump-ir"); | ||||
|         bool dump = clim.count("dump-ir"); | ||||
|         // instantiate the simulator | ||||
|         std::unique_ptr<iss::vm_if> cpu{nullptr}; | ||||
|         if (vm.count("rv64") == 1) { | ||||
|             if (vm.count("gdb-port") == 1) | ||||
|                 cpu = iss::create<iss::arch::rv64ia>("rv64ia", vm["gdb-port"].as<unsigned>(), dump); | ||||
|             else | ||||
|                 cpu = iss::create<iss::arch::rv64ia>("rv64ia", dump); | ||||
|         std::unique_ptr<iss::vm_if> vm{nullptr}; | ||||
|         if (clim.count("rv64") == 1) { | ||||
|             auto cpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64ia>(); | ||||
|             vm = iss::create<iss::arch::rv64ia>(cpu, clim["gdb-port"].as<unsigned>(), dump); | ||||
|         } else { | ||||
|             if (vm.count("gdb-port") == 1) | ||||
|                 cpu = iss::create<iss::arch::rv32imac>("rv32ima", vm["gdb-port"].as<unsigned>(), dump); | ||||
|             else | ||||
|                 cpu = iss::create<iss::arch::rv32imac>("rv32ima", dump); | ||||
|             auto cpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv32imac>(); | ||||
|             vm = iss::create<iss::arch::rv32imac>(cpu, clim["gdb-port"].as<unsigned>(), dump); | ||||
|         } | ||||
|         if (vm.count("elf")) { | ||||
|             for (std::string input : vm["elf"].as<std::vector<std::string>>()) cpu->get_arch()->load_file(input); | ||||
|         } else if (vm.count("mem")) { | ||||
|             cpu->get_arch()->load_file(vm["mem"].as<std::string>(), iss::arch::traits<iss::arch::rv32imac>::MEM); | ||||
|         if (clim.count("elf")) { | ||||
|             for (std::string input : clim["elf"].as<std::vector<std::string>>()) vm->get_arch()->load_file(input); | ||||
|         } else if (clim.count("mem")) { | ||||
|             vm->get_arch()->load_file(clim["mem"].as<std::string>(), iss::arch::traits<iss::arch::rv32imac>::MEM); | ||||
|         } | ||||
|  | ||||
|         if (vm.count("disass")) { | ||||
|             cpu->setDisassEnabled(true); | ||||
|         if (clim.count("disass")) { | ||||
|             vm->setDisassEnabled(true); | ||||
|             LOGGER(disass)::reporting_level() = logging::INFO; | ||||
|             auto file_name = vm["disass"].as<std::string>(); | ||||
|             auto file_name = clim["disass"].as<std::string>(); | ||||
|             if (file_name.length() > 0) { | ||||
|                 LOG_OUTPUT(disass)::stream() = fopen(file_name.c_str(), "w"); | ||||
|                 LOGGER(disass)::print_time() = false; | ||||
|                 LOGGER(disass)::print_severity() = false; | ||||
|             } | ||||
|         } | ||||
|         if (vm.count("reset")) { | ||||
|             auto str = vm["reset"].as<std::string>(); | ||||
|             auto start_address = str.find("0x") == 0 ? std::stoull(str, 0, 16) : std::stoull(str, 0, 10); | ||||
|             cpu->reset(start_address); | ||||
|         if (clim.count("reset")) { | ||||
|             auto str = clim["reset"].as<std::string>(); | ||||
|             auto start_address = str.find("0x") == 0 ? std::stoull(str.substr(2), 0, 16) : std::stoull(str, 0, 10); | ||||
|             vm->reset(start_address); | ||||
|         } else { | ||||
|             cpu->reset(); | ||||
|             vm->reset(); | ||||
|         } | ||||
|         int64_t cycles = -1; | ||||
|         cycles = vm["cycles"].as<int64_t>(); | ||||
|         return cpu->start(cycles); | ||||
|         cycles = clim["cycles"].as<int64_t>(); | ||||
|         return vm->start(cycles); | ||||
|     } catch (std::exception &e) { | ||||
|         LOG(ERROR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit" | ||||
|                    << std::endl; | ||||
|         return ERROR_UNHANDLED_EXCEPTION; | ||||
|         return 2; | ||||
|     } | ||||
| } | ||||
|   | ||||
 Submodule sc-components updated: 3693b05536...35379b77b6
									
								
							
		Reference in New Issue
	
	Block a user