mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-05 06:32:37 +00:00
feat: add verilator sim env
This commit is contained in:
9 files changed
+3664
No files matched your search
@@ -0,0 +1,129 @@
|
||||
#include <csignal>
|
||||
#include "rang.hpp"
|
||||
#include "Emulator.h"
|
||||
|
||||
static int signal_received = 0;
|
||||
|
||||
void sig_handler(int signo)
|
||||
{
|
||||
if (signal_received != 0)
|
||||
{
|
||||
std::cout << "SIGINT received, forcely shutting down." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
std::cout << "\nSIGINT received, gracefully shutting down... Type Ctrl+C again to stop forcely." << std::endl;
|
||||
signal_received = signo;
|
||||
}
|
||||
|
||||
void env_init()
|
||||
{
|
||||
std::cout << rang::fg::magenta << "Emulator compiled at " << __DATE__ << ", " << __TIME__ << rang::fg::reset << std::endl;
|
||||
if (signal(SIGINT, sig_handler) == SIG_ERR)
|
||||
{
|
||||
std::cout << "can't catch SIGINT" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void flash_init(const char *img);
|
||||
|
||||
Emulator::Emulator(cxxopts::ParseResult &res)
|
||||
{
|
||||
args.dumpWave = res["dump-wave"].as<bool>();
|
||||
args.dumpBegin = res["log-begin"].as<unsigned long>();
|
||||
auto tmp = res["log-end"].as<unsigned long>();
|
||||
if (tmp > 0)
|
||||
args.dumpEnd = tmp;
|
||||
|
||||
tmp = res["sim-time"].as<unsigned long>();
|
||||
if (tmp > 0)
|
||||
args.simTime = tmp;
|
||||
|
||||
args.image = res["image"].as<std::string>();
|
||||
|
||||
startTime = chrono::system_clock::now();
|
||||
if (args.image == "")
|
||||
{
|
||||
std::cout << rang::fg::red << "Image file unspecified. Use -i to provide the image of flash" << rang::fg::reset << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::cout << rang::fg::green << "Initializing flash with " << args.image << " ..." << rang::fg::reset << std::endl;
|
||||
flash_init(args.image.c_str());
|
||||
|
||||
dutPtr = new VysyxSoCFull;
|
||||
reset();
|
||||
|
||||
if (args.dumpWave)
|
||||
{
|
||||
#ifdef DUMP_WAVE_FST
|
||||
wavePtr = new VerilatedFstC;
|
||||
#endif
|
||||
Verilated::traceEverOn(true);
|
||||
std::cout << rang::fg::yellow << "`dump-wave` enabled, waves will be written to \"soc.wave\"." << rang::fg::reset << std::endl;
|
||||
dutPtr->trace(wavePtr, 1);
|
||||
wavePtr->open("soc.wave");
|
||||
wavePtr->dump(0);
|
||||
}
|
||||
}
|
||||
|
||||
Emulator::~Emulator()
|
||||
{
|
||||
if (wavePtr)
|
||||
{
|
||||
wavePtr->close();
|
||||
delete wavePtr;
|
||||
}
|
||||
}
|
||||
|
||||
void Emulator::reset()
|
||||
{
|
||||
std::cout << rang::fg::yellow << "Initializing and resetting DUT ..." << rang::fg::reset << std::endl;
|
||||
dutPtr->reset = 1;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
dutPtr->clock = 0;
|
||||
dutPtr->eval();
|
||||
dutPtr->clock = 1;
|
||||
dutPtr->eval();
|
||||
}
|
||||
dutPtr->clock = 0;
|
||||
dutPtr->reset = 0;
|
||||
dutPtr->eval();
|
||||
}
|
||||
|
||||
void Emulator::step()
|
||||
{
|
||||
dutPtr->clock = 1;
|
||||
dutPtr->eval();
|
||||
++cycle;
|
||||
if (args.dumpWave && args.dumpBegin <= cycle && cycle <= args.dumpEnd)
|
||||
{
|
||||
wavePtr->dump((vluint64_t)cycle);
|
||||
}
|
||||
dutPtr->clock = 0;
|
||||
dutPtr->eval();
|
||||
}
|
||||
|
||||
void Emulator::state()
|
||||
{
|
||||
auto elapsed = chrono::duration_cast<chrono::seconds>(chrono::system_clock::now() - startTime);
|
||||
std::cout << rang::fg::yellow << "Simulation " << cycle << " cycles in " << elapsed.count() << "s" << rang::fg::reset << std::endl;
|
||||
}
|
||||
|
||||
bool Emulator::getArriveTime()
|
||||
{
|
||||
auto elapsed = chrono::duration_cast<chrono::seconds>(chrono::system_clock::now() - startTime);
|
||||
if (elapsed.count() > args.simTime)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void Emulator::runSim()
|
||||
{
|
||||
while (!Verilated::gotFinish() && signal_received == 0 && !getArriveTime())
|
||||
{
|
||||
step();
|
||||
}
|
||||
dutPtr->final();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
namespace chrono = std::chrono;
|
||||
|
||||
#include <verilated.h>
|
||||
#include <Vretrosoc_top.h>
|
||||
#ifdef DUMP_WAVE_FST
|
||||
#include <verilated_fst_c.h>
|
||||
#endif
|
||||
#include "cxxopts.hpp"
|
||||
|
||||
class Emulator
|
||||
{
|
||||
public:
|
||||
Emulator(cxxopts::ParseResult &res);
|
||||
~Emulator();
|
||||
void reset();
|
||||
void step();
|
||||
void state();
|
||||
std::string getAppName(std::string str);
|
||||
bool getArriveTime();
|
||||
void runSim();
|
||||
|
||||
private:
|
||||
unsigned long long cycle = 0;
|
||||
chrono::system_clock::time_point startTime;
|
||||
VysyxSoCFull *dutPtr = nullptr;
|
||||
struct Args
|
||||
{
|
||||
bool dumpWave = false;
|
||||
unsigned long dumpBegin = 0UL;
|
||||
unsigned long dumpEnd = -1UL;
|
||||
unsigned long simTime = -1UL;
|
||||
std::string simMode = "";
|
||||
std::string image = "";
|
||||
} args;
|
||||
|
||||
#ifdef DUMP_WAVE_FST
|
||||
VerilatedFstC *wavePtr = nullptr;
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
// #include <iostream>
|
||||
|
||||
// class Utils
|
||||
// {
|
||||
// public:
|
||||
// static void log(string val)
|
||||
// {
|
||||
// std::cout << val << std::endl;
|
||||
// }
|
||||
// };
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,54 @@
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
|
||||
#include "verilated.h"
|
||||
#include "cxxopts.hpp"
|
||||
#include "rang.hpp"
|
||||
|
||||
#include "Emulator.h"
|
||||
|
||||
static Emulator *emu = nullptr;
|
||||
cxxopts::Options args("emu", "retroSoC Verilator Emulator");
|
||||
|
||||
void release()
|
||||
{
|
||||
if (emu != nullptr)
|
||||
{
|
||||
emu->state();
|
||||
delete emu;
|
||||
}
|
||||
}
|
||||
|
||||
void parseArgs(int argc, char *argv[])
|
||||
{
|
||||
// clang-format off
|
||||
args.add_options()
|
||||
("h,help", "print usage")
|
||||
("d,dump-wave", "dump vcd(fst) format waveform when log is enabled", cxxopts::value<bool>()->default_value("false"))
|
||||
("b,log-begin", "display log from NUM th cycle", cxxopts::value<unsigned long>()->default_value("0"))
|
||||
("e,log-end", "stop display log at NUM th cycle", cxxopts::value<unsigned long>()->default_value("0"))
|
||||
("t,sim-time", "stop simulation after NUM seconds", cxxopts::value<unsigned long>()->default_value("0"))
|
||||
("i,image", "run with this image file", cxxopts::value<std::string>());
|
||||
// clang-format on
|
||||
Verilated::commandArgs(argc, argv);
|
||||
}
|
||||
|
||||
extern void env_init();
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
env_init();
|
||||
atexit(release);
|
||||
parseArgs(argc, argv);
|
||||
auto res = args.parse(argc, argv);
|
||||
if (res.count("help"))
|
||||
{
|
||||
std::cout << args.help() << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
emu = new Emulator(res);
|
||||
std::cout << rang::fg::yellow << "[verilator]start simulating ..." << rang::fg::reset << std::endl;
|
||||
emu->runSim();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,502 @@
|
||||
#ifndef RANG_DOT_HPP
|
||||
#define RANG_DOT_HPP
|
||||
|
||||
#if defined(__unix__) || defined(__unix) || defined(__linux__)
|
||||
#define OS_LINUX
|
||||
#elif defined(WIN32) || defined(_WIN32) || defined(_WIN64)
|
||||
#define OS_WIN
|
||||
#elif defined(__APPLE__) || defined(__MACH__)
|
||||
#define OS_MAC
|
||||
#else
|
||||
#error Unknown Platform
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX) || defined(OS_MAC)
|
||||
#include <unistd.h>
|
||||
|
||||
#elif defined(OS_WIN)
|
||||
|
||||
#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600)
|
||||
#error \
|
||||
"Please include rang.hpp before any windows system headers or set _WIN32_WINNT at least to _WIN32_WINNT_VISTA"
|
||||
#elif !defined(_WIN32_WINNT)
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <memory>
|
||||
|
||||
// Only defined in windows 10 onwards, redefining in lower windows since it
|
||||
// doesn't gets used in lower versions
|
||||
// https://docs.microsoft.com/en-us/windows/console/getconsolemode
|
||||
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
namespace rang {
|
||||
|
||||
/* For better compability with most of terminals do not use any style settings
|
||||
* except of reset, bold and reversed.
|
||||
* Note that on Windows terminals bold style is same as fgB color.
|
||||
*/
|
||||
enum class style {
|
||||
reset = 0,
|
||||
bold = 1,
|
||||
dim = 2,
|
||||
italic = 3,
|
||||
underline = 4,
|
||||
blink = 5,
|
||||
rblink = 6,
|
||||
reversed = 7,
|
||||
conceal = 8,
|
||||
crossed = 9
|
||||
};
|
||||
|
||||
enum class fg {
|
||||
black = 30,
|
||||
red = 31,
|
||||
green = 32,
|
||||
yellow = 33,
|
||||
blue = 34,
|
||||
magenta = 35,
|
||||
cyan = 36,
|
||||
gray = 37,
|
||||
reset = 39
|
||||
};
|
||||
|
||||
enum class bg {
|
||||
black = 40,
|
||||
red = 41,
|
||||
green = 42,
|
||||
yellow = 43,
|
||||
blue = 44,
|
||||
magenta = 45,
|
||||
cyan = 46,
|
||||
gray = 47,
|
||||
reset = 49
|
||||
};
|
||||
|
||||
enum class fgB {
|
||||
black = 90,
|
||||
red = 91,
|
||||
green = 92,
|
||||
yellow = 93,
|
||||
blue = 94,
|
||||
magenta = 95,
|
||||
cyan = 96,
|
||||
gray = 97
|
||||
};
|
||||
|
||||
enum class bgB {
|
||||
black = 100,
|
||||
red = 101,
|
||||
green = 102,
|
||||
yellow = 103,
|
||||
blue = 104,
|
||||
magenta = 105,
|
||||
cyan = 106,
|
||||
gray = 107
|
||||
};
|
||||
|
||||
enum class control { // Behaviour of rang function calls
|
||||
Off = 0, // toggle off rang style/color calls
|
||||
Auto = 1, // (Default) autodect terminal and colorize if needed
|
||||
Force = 2 // force ansi color output to non terminal streams
|
||||
};
|
||||
// Use rang::setControlMode to set rang control mode
|
||||
|
||||
enum class winTerm { // Windows Terminal Mode
|
||||
Auto = 0, // (Default) automatically detects wheter Ansi or Native API
|
||||
Ansi = 1, // Force use Ansi API
|
||||
Native = 2 // Force use Native API
|
||||
};
|
||||
// Use rang::setWinTermMode to explicitly set terminal API for Windows
|
||||
// Calling rang::setWinTermMode have no effect on other OS
|
||||
|
||||
namespace rang_implementation {
|
||||
|
||||
inline std::atomic<control> &controlMode() noexcept
|
||||
{
|
||||
static std::atomic<control> value(control::Auto);
|
||||
return value;
|
||||
}
|
||||
|
||||
inline std::atomic<winTerm> &winTermMode() noexcept
|
||||
{
|
||||
static std::atomic<winTerm> termMode(winTerm::Auto);
|
||||
return termMode;
|
||||
}
|
||||
|
||||
inline bool supportsColor() noexcept
|
||||
{
|
||||
#if defined(OS_LINUX) || defined(OS_MAC)
|
||||
|
||||
static const bool result = [] {
|
||||
const char *Terms[]
|
||||
= { "ansi", "color", "console", "cygwin", "gnome",
|
||||
"konsole", "kterm", "linux", "msys", "putty",
|
||||
"rxvt", "screen", "vt100", "xterm" };
|
||||
|
||||
const char *env_p = std::getenv("TERM");
|
||||
if (env_p == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return std::any_of(std::begin(Terms), std::end(Terms),
|
||||
[&](const char *term) {
|
||||
return std::strstr(env_p, term) != nullptr;
|
||||
});
|
||||
}();
|
||||
|
||||
#elif defined(OS_WIN)
|
||||
// All windows versions support colors through native console methods
|
||||
static constexpr bool result = true;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef OS_WIN
|
||||
|
||||
|
||||
inline bool isMsysPty(int fd) noexcept
|
||||
{
|
||||
// Dynamic load for binary compability with old Windows
|
||||
const auto ptrGetFileInformationByHandleEx
|
||||
= reinterpret_cast<decltype(&GetFileInformationByHandleEx)>(
|
||||
GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"GetFileInformationByHandleEx"));
|
||||
if (!ptrGetFileInformationByHandleEx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE h = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that it's a pipe:
|
||||
if (GetFileType(h) != FILE_TYPE_PIPE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// POD type is binary compatible with FILE_NAME_INFO from WinBase.h
|
||||
// It have the same alignment and used to avoid UB in caller code
|
||||
struct MY_FILE_NAME_INFO {
|
||||
DWORD FileNameLength;
|
||||
WCHAR FileName[MAX_PATH];
|
||||
};
|
||||
|
||||
auto pNameInfo = std::unique_ptr<MY_FILE_NAME_INFO>(
|
||||
new (std::nothrow) MY_FILE_NAME_INFO());
|
||||
if (!pNameInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check pipe name is template of
|
||||
// {"cygwin-","msys-"}XXXXXXXXXXXXXXX-ptyX-XX
|
||||
if (!ptrGetFileInformationByHandleEx(h, FileNameInfo, pNameInfo.get(),
|
||||
sizeof(MY_FILE_NAME_INFO))) {
|
||||
return false;
|
||||
}
|
||||
std::wstring name(pNameInfo->FileName, pNameInfo->FileNameLength / sizeof(WCHAR));
|
||||
if ((name.find(L"msys-") == std::wstring::npos
|
||||
&& name.find(L"cygwin-") == std::wstring::npos)
|
||||
|| name.find(L"-pty") == std::wstring::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline bool isTerminal(const std::streambuf *osbuf) noexcept
|
||||
{
|
||||
using std::cerr;
|
||||
using std::clog;
|
||||
using std::cout;
|
||||
#if defined(OS_LINUX) || defined(OS_MAC)
|
||||
if (osbuf == cout.rdbuf()) {
|
||||
static const bool cout_term = isatty(fileno(stdout)) != 0;
|
||||
return cout_term;
|
||||
} else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) {
|
||||
static const bool cerr_term = isatty(fileno(stderr)) != 0;
|
||||
return cerr_term;
|
||||
}
|
||||
#elif defined(OS_WIN)
|
||||
if (osbuf == cout.rdbuf()) {
|
||||
static const bool cout_term
|
||||
= (_isatty(_fileno(stdout)) || isMsysPty(_fileno(stdout)));
|
||||
return cout_term;
|
||||
} else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) {
|
||||
static const bool cerr_term
|
||||
= (_isatty(_fileno(stderr)) || isMsysPty(_fileno(stderr)));
|
||||
return cerr_term;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using enableStd = typename std::enable_if<
|
||||
std::is_same<T, rang::style>::value || std::is_same<T, rang::fg>::value
|
||||
|| std::is_same<T, rang::bg>::value || std::is_same<T, rang::fgB>::value
|
||||
|| std::is_same<T, rang::bgB>::value,
|
||||
std::ostream &>::type;
|
||||
|
||||
|
||||
#ifdef OS_WIN
|
||||
|
||||
struct SGR { // Select Graphic Rendition parameters for Windows console
|
||||
BYTE fgColor; // foreground color (0-15) lower 3 rgb bits + intense bit
|
||||
BYTE bgColor; // background color (0-15) lower 3 rgb bits + intense bit
|
||||
BYTE bold; // emulated as FOREGROUND_INTENSITY bit
|
||||
BYTE underline; // emulated as BACKGROUND_INTENSITY bit
|
||||
BOOLEAN inverse; // swap foreground/bold & background/underline
|
||||
BOOLEAN conceal; // set foreground/bold to background/underline
|
||||
};
|
||||
|
||||
enum class AttrColor : BYTE { // Color attributes for console screen buffer
|
||||
black = 0,
|
||||
red = 4,
|
||||
green = 2,
|
||||
yellow = 6,
|
||||
blue = 1,
|
||||
magenta = 5,
|
||||
cyan = 3,
|
||||
gray = 7
|
||||
};
|
||||
|
||||
inline HANDLE getConsoleHandle(const std::streambuf *osbuf) noexcept
|
||||
{
|
||||
if (osbuf == std::cout.rdbuf()) {
|
||||
static const HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
return hStdout;
|
||||
} else if (osbuf == std::cerr.rdbuf() || osbuf == std::clog.rdbuf()) {
|
||||
static const HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
return hStderr;
|
||||
}
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
inline bool setWinTermAnsiColors(const std::streambuf *osbuf) noexcept
|
||||
{
|
||||
HANDLE h = getConsoleHandle(osbuf);
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
DWORD dwMode = 0;
|
||||
if (!GetConsoleMode(h, &dwMode)) {
|
||||
return false;
|
||||
}
|
||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
if (!SetConsoleMode(h, dwMode)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool supportsAnsi(const std::streambuf *osbuf) noexcept
|
||||
{
|
||||
using std::cerr;
|
||||
using std::clog;
|
||||
using std::cout;
|
||||
if (osbuf == cout.rdbuf()) {
|
||||
static const bool cout_ansi
|
||||
= (isMsysPty(_fileno(stdout)) || setWinTermAnsiColors(osbuf));
|
||||
return cout_ansi;
|
||||
} else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) {
|
||||
static const bool cerr_ansi
|
||||
= (isMsysPty(_fileno(stderr)) || setWinTermAnsiColors(osbuf));
|
||||
return cerr_ansi;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline const SGR &defaultState() noexcept
|
||||
{
|
||||
static const SGR defaultSgr = []() -> SGR {
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
WORD attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
||||
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),
|
||||
&info)
|
||||
|| GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE),
|
||||
&info)) {
|
||||
attrib = info.wAttributes;
|
||||
}
|
||||
SGR sgr = { 0, 0, 0, 0, FALSE, FALSE };
|
||||
sgr.fgColor = attrib & 0x0F;
|
||||
sgr.bgColor = (attrib & 0xF0) >> 4;
|
||||
return sgr;
|
||||
}();
|
||||
return defaultSgr;
|
||||
}
|
||||
|
||||
inline BYTE ansi2attr(BYTE rgb) noexcept
|
||||
{
|
||||
static const AttrColor rev[8]
|
||||
= { AttrColor::black, AttrColor::red, AttrColor::green,
|
||||
AttrColor::yellow, AttrColor::blue, AttrColor::magenta,
|
||||
AttrColor::cyan, AttrColor::gray };
|
||||
return static_cast<BYTE>(rev[rgb]);
|
||||
}
|
||||
|
||||
inline void setWinSGR(rang::bg col, SGR &state) noexcept
|
||||
{
|
||||
if (col != rang::bg::reset) {
|
||||
state.bgColor = ansi2attr(static_cast<BYTE>(col) - 40);
|
||||
} else {
|
||||
state.bgColor = defaultState().bgColor;
|
||||
}
|
||||
}
|
||||
|
||||
inline void setWinSGR(rang::fg col, SGR &state) noexcept
|
||||
{
|
||||
if (col != rang::fg::reset) {
|
||||
state.fgColor = ansi2attr(static_cast<BYTE>(col) - 30);
|
||||
} else {
|
||||
state.fgColor = defaultState().fgColor;
|
||||
}
|
||||
}
|
||||
|
||||
inline void setWinSGR(rang::bgB col, SGR &state) noexcept
|
||||
{
|
||||
state.bgColor = (BACKGROUND_INTENSITY >> 4)
|
||||
| ansi2attr(static_cast<BYTE>(col) - 100);
|
||||
}
|
||||
|
||||
inline void setWinSGR(rang::fgB col, SGR &state) noexcept
|
||||
{
|
||||
state.fgColor
|
||||
= FOREGROUND_INTENSITY | ansi2attr(static_cast<BYTE>(col) - 90);
|
||||
}
|
||||
|
||||
inline void setWinSGR(rang::style style, SGR &state) noexcept
|
||||
{
|
||||
switch (style) {
|
||||
case rang::style::reset: state = defaultState(); break;
|
||||
case rang::style::bold: state.bold = FOREGROUND_INTENSITY; break;
|
||||
case rang::style::underline:
|
||||
case rang::style::blink:
|
||||
state.underline = BACKGROUND_INTENSITY;
|
||||
break;
|
||||
case rang::style::reversed: state.inverse = TRUE; break;
|
||||
case rang::style::conceal: state.conceal = TRUE; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
inline SGR ¤t_state() noexcept
|
||||
{
|
||||
static SGR state = defaultState();
|
||||
return state;
|
||||
}
|
||||
|
||||
inline WORD SGR2Attr(const SGR &state) noexcept
|
||||
{
|
||||
WORD attrib = 0;
|
||||
if (state.conceal) {
|
||||
if (state.inverse) {
|
||||
attrib = (state.fgColor << 4) | state.fgColor;
|
||||
if (state.bold)
|
||||
attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;
|
||||
} else {
|
||||
attrib = (state.bgColor << 4) | state.bgColor;
|
||||
if (state.underline)
|
||||
attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;
|
||||
}
|
||||
} else if (state.inverse) {
|
||||
attrib = (state.fgColor << 4) | state.bgColor;
|
||||
if (state.bold) attrib |= BACKGROUND_INTENSITY;
|
||||
if (state.underline) attrib |= FOREGROUND_INTENSITY;
|
||||
} else {
|
||||
attrib = state.fgColor | (state.bgColor << 4) | state.bold
|
||||
| state.underline;
|
||||
}
|
||||
return attrib;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void setWinColorAnsi(std::ostream &os, T const value)
|
||||
{
|
||||
os << "\033[" << static_cast<int>(value) << "m";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void setWinColorNative(std::ostream &os, T const value)
|
||||
{
|
||||
const HANDLE h = getConsoleHandle(os.rdbuf());
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
setWinSGR(value, current_state());
|
||||
// Out all buffered text to console with previous settings:
|
||||
os.flush();
|
||||
SetConsoleTextAttribute(h, SGR2Attr(current_state()));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline enableStd<T> setColor(std::ostream &os, T const value)
|
||||
{
|
||||
if (winTermMode() == winTerm::Auto) {
|
||||
if (supportsAnsi(os.rdbuf())) {
|
||||
setWinColorAnsi(os, value);
|
||||
} else {
|
||||
setWinColorNative(os, value);
|
||||
}
|
||||
} else if (winTermMode() == winTerm::Ansi) {
|
||||
setWinColorAnsi(os, value);
|
||||
} else {
|
||||
setWinColorNative(os, value);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
#else
|
||||
template <typename T>
|
||||
inline enableStd<T> setColor(std::ostream &os, T const value)
|
||||
{
|
||||
return os << "\033[" << static_cast<int>(value) << "m";
|
||||
}
|
||||
#endif
|
||||
} // namespace rang_implementation
|
||||
|
||||
template <typename T>
|
||||
inline rang_implementation::enableStd<T> operator<<(std::ostream &os,
|
||||
const T value)
|
||||
{
|
||||
const control option = rang_implementation::controlMode();
|
||||
switch (option) {
|
||||
case control::Auto:
|
||||
return rang_implementation::supportsColor()
|
||||
&& rang_implementation::isTerminal(os.rdbuf())
|
||||
? rang_implementation::setColor(os, value)
|
||||
: os;
|
||||
case control::Force: return rang_implementation::setColor(os, value);
|
||||
default: return os;
|
||||
}
|
||||
}
|
||||
|
||||
inline void setWinTermMode(const rang::winTerm value) noexcept
|
||||
{
|
||||
rang_implementation::winTermMode() = value;
|
||||
}
|
||||
|
||||
inline void setControlMode(const control value) noexcept
|
||||
{
|
||||
rang_implementation::controlMode() = value;
|
||||
}
|
||||
|
||||
} // namespace rang
|
||||
|
||||
#undef OS_LINUX
|
||||
#undef OS_WIN
|
||||
#undef OS_MAC
|
||||
|
||||
#endif /* ifndef RANG_DOT_HPP */
|
||||
@@ -0,0 +1,49 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstring>
|
||||
#include <svdpi.h>
|
||||
|
||||
#define Assert(cond, ...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
fflush(stdout); \
|
||||
fprintf(stderr, "\33[1;31m"); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\33[0m\n"); \
|
||||
assert(cond); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define FLASH_SIZE (256 * 1024 * 1024) // 256MB
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define PG_ALIGN __attribute((aligned(PAGE_SIZE)))
|
||||
|
||||
static inline bool in_flash(uint64_t addr) {
|
||||
return (addr < FLASH_SIZE);
|
||||
}
|
||||
|
||||
static uint8_t flash[FLASH_SIZE] PG_ALIGN = {};
|
||||
|
||||
extern "C" void flash_read(uint64_t addr, uint64_t *data) {
|
||||
if (!data) return;
|
||||
Assert(in_flash(addr), "Flash address 0x%lx out of bound", addr);
|
||||
*data = *(uint64_t *)(flash + addr);
|
||||
}
|
||||
|
||||
extern "C" void flash_init(char *img) {
|
||||
FILE *fp = fopen(img, "rb");
|
||||
Assert(fp, "Can not open '%s'", img);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
uint64_t size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
assert(fread(flash, size, 1, fp) == 1);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
extern "C" void flash_memcpy(uint8_t* src, size_t len) {
|
||||
memcpy(flash, src, len);
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* PicoSoC - A simple example SoC using PicoRV32
|
||||
*
|
||||
* Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
* Copyright (C) 2025 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module retrosoc_top (
|
||||
input wire ext_clk_i,
|
||||
input wire rst_n_i
|
||||
);
|
||||
|
||||
wire s_uart_tx;
|
||||
wire s_flash_csb;
|
||||
wire s_flash_clk;
|
||||
wire s_flash_io0;
|
||||
wire s_flash_io1;
|
||||
wire s_flash_io2;
|
||||
wire s_flash_io3;
|
||||
wire s_cust_psram_sclk;
|
||||
wire s_cust_psram_ce;
|
||||
wire s_cust_psram_sio0;
|
||||
wire s_cust_psram_sio1;
|
||||
wire s_cust_psram_sio2;
|
||||
wire s_cust_psram_sio3;
|
||||
wire s_cust_spfs_clk_o;
|
||||
wire s_cust_spfs_cs_o;
|
||||
wire s_cust_spfs_mosi_o;
|
||||
wire s_cust_spfs_miso_i;
|
||||
|
||||
retrosoc_asic u_retrosoc_asic (
|
||||
.xi_i_pad ('0),
|
||||
.xo_o_pad (),
|
||||
.extclk_i_pad (ext_clk_i),
|
||||
`ifdef CORE_MDD
|
||||
.core_mdd_sel_0_i_pad ('0),
|
||||
.core_mdd_sel_1_i_pad ('0),
|
||||
.core_mdd_sel_2_i_pad ('0),
|
||||
.core_mdd_sel_3_i_pad ('0),
|
||||
.core_mdd_sel_4_i_pad ('0),
|
||||
`endif
|
||||
`ifdef IP_MDD
|
||||
.ip_mdd_sel_0_i_pad ('0),
|
||||
.ip_mdd_sel_1_i_pad ('0),
|
||||
.ip_mdd_sel_2_i_pad ('0),
|
||||
.ip_mdd_sel_3_i_pad ('0),
|
||||
.ip_mdd_sel_4_i_pad ('0),
|
||||
.ip_mdd_gpio_0_io_pad (),
|
||||
.ip_mdd_gpio_1_io_pad (),
|
||||
.ip_mdd_gpio_2_io_pad (),
|
||||
.ip_mdd_gpio_3_io_pad (),
|
||||
.ip_mdd_gpio_4_io_pad (),
|
||||
.ip_mdd_gpio_5_io_pad (),
|
||||
.ip_mdd_gpio_6_io_pad (),
|
||||
.ip_mdd_gpio_7_io_pad (),
|
||||
.ip_mdd_gpio_8_io_pad (),
|
||||
.ip_mdd_gpio_9_io_pad (),
|
||||
.ip_mdd_gpio_10_io_pad (),
|
||||
.ip_mdd_gpio_11_io_pad (),
|
||||
.ip_mdd_gpio_12_io_pad (),
|
||||
.ip_mdd_gpio_13_io_pad (),
|
||||
.ip_mdd_gpio_14_io_pad (),
|
||||
.ip_mdd_gpio_15_io_pad (),
|
||||
`endif
|
||||
`ifdef HAVE_PLL
|
||||
.pll_cfg_0_i_pad ('0),
|
||||
.pll_cfg_1_i_pad ('0),
|
||||
.pll_cfg_2_i_pad ('0),
|
||||
`endif
|
||||
.clk_bypass_i_pad ('1),
|
||||
.ext_rst_n_i_pad (rst_n_i),
|
||||
.sys_clkdiv4_o_pad (),
|
||||
.uart_tx_o_pad (s_uart_tx),
|
||||
.uart_rx_i_pad (),
|
||||
.gpio_0_io_pad (),
|
||||
.gpio_1_io_pad (),
|
||||
.gpio_2_io_pad (),
|
||||
.gpio_3_io_pad (),
|
||||
.gpio_4_io_pad (),
|
||||
.gpio_5_io_pad (),
|
||||
.gpio_6_io_pad (),
|
||||
.gpio_7_io_pad (),
|
||||
.gpio_8_io_pad (),
|
||||
.gpio_9_io_pad (),
|
||||
.gpio_10_io_pad (),
|
||||
.gpio_11_io_pad (),
|
||||
.gpio_12_io_pad (),
|
||||
.gpio_13_io_pad (),
|
||||
.gpio_14_io_pad (),
|
||||
.gpio_15_io_pad (),
|
||||
.irq_pin_i_pad (),
|
||||
.cust_uart_tx_o_pad (),
|
||||
.cust_uart_rx_i_pad (),
|
||||
.cust_pwm_pwm_0_o_pad (),
|
||||
.cust_pwm_pwm_1_o_pad (),
|
||||
.cust_pwm_pwm_2_o_pad (),
|
||||
.cust_pwm_pwm_3_o_pad (),
|
||||
.cust_ps2_ps2_clk_i_pad (),
|
||||
.cust_ps2_ps2_dat_i_pad (),
|
||||
.cust_i2c_scl_io_pad (),
|
||||
.cust_i2c_sda_io_pad (),
|
||||
.cust_qspi_spi_clk_o_pad (),
|
||||
.cust_qspi_spi_csn_0_o_pad(),
|
||||
.cust_qspi_spi_csn_1_o_pad(),
|
||||
.cust_qspi_spi_csn_2_o_pad(),
|
||||
.cust_qspi_spi_csn_3_o_pad(),
|
||||
.cust_qspi_dat_0_io_pad (),
|
||||
.cust_qspi_dat_1_io_pad (),
|
||||
.cust_qspi_dat_2_io_pad (),
|
||||
.cust_qspi_dat_3_io_pad (),
|
||||
.cust_psram_sclk_o_pad (s_cust_psram_sclk),
|
||||
.cust_psram_ce_o_pad (s_cust_psram_ce),
|
||||
.cust_psram_sio0_io_pad (s_cust_psram_sio0),
|
||||
.cust_psram_sio1_io_pad (s_cust_psram_sio1),
|
||||
.cust_psram_sio2_io_pad (s_cust_psram_sio2),
|
||||
.cust_psram_sio3_io_pad (s_cust_psram_sio3),
|
||||
.cust_spfs_clk_o_pad (s_cust_spfs_clk_o),
|
||||
.cust_spfs_cs_o_pad (s_cust_spfs_cs_o),
|
||||
.cust_spfs_mosi_o_pad (s_cust_spfs_mosi_o),
|
||||
.cust_spfs_miso_i_pad (s_cust_spfs_miso_i)
|
||||
);
|
||||
|
||||
N25Qxxx u_N25Qxxx (
|
||||
.C_ (s_cust_spfs_clk_o),
|
||||
.S (s_cust_spfs_cs_o),
|
||||
.DQ0 (s_cust_spfs_mosi_o),
|
||||
.DQ1 (s_cust_spfs_miso_i),
|
||||
.HOLD_DQ3 (),
|
||||
.Vpp_W_DQ2(),
|
||||
.Vcc ('d3000)
|
||||
);
|
||||
|
||||
rs232 u_rs232_0 (
|
||||
.rs232_rx_i(s_uart_tx),
|
||||
.rs232_tx_o()
|
||||
);
|
||||
|
||||
ESP_PSRAM64H u_ESP_PSRAM64H (
|
||||
.sclk(s_cust_psram_sclk),
|
||||
.csn (s_cust_psram_ce),
|
||||
.sio ({s_cust_psram_sio3, s_cust_psram_sio2, s_cust_psram_sio1, s_cust_psram_sio0})
|
||||
);
|
||||
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,105 @@
|
||||
`timescale 1ns / 10ps
|
||||
|
||||
|
||||
module spiFlash (
|
||||
input clk,
|
||||
input cs,
|
||||
input mosi,
|
||||
output wire miso
|
||||
);
|
||||
|
||||
typedef enum [2:0] { cmd_t, addr_t, data_t, err_t } state_t;
|
||||
|
||||
wire reset;
|
||||
reg [ 2:0] state;
|
||||
reg [ 7:0] counter;
|
||||
reg [ 7:0] cmd;
|
||||
reg [21:0] addr;
|
||||
reg [63:0] data;
|
||||
wire ren;
|
||||
wire [63:0] rdata;
|
||||
wire [63:0] raddr;
|
||||
|
||||
assign reset = cs[0];
|
||||
assign miso = data[63];
|
||||
assign ren = (state == addr_t) && (counter == 8'd22);
|
||||
assign raddr = {40'd0, addr, 2'd0};
|
||||
|
||||
FlashRead flashRead (
|
||||
.clock(clk),
|
||||
.ren (ren),
|
||||
.addr (raddr),
|
||||
.data (rdata)
|
||||
);
|
||||
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) state <= cmd_t;
|
||||
else begin
|
||||
case (state)
|
||||
cmd_t: state <= (counter == 8'd7) ? addr_t : state;
|
||||
addr_t: state <= (cmd != 8'h3) ? err_t : (counter == 8'd23) ? data_t : state;
|
||||
data_t: state <= state;
|
||||
|
||||
default: begin
|
||||
state <= state;
|
||||
$fwrite(32'h80000002, "Assertion failed: only support `03h` read command\n");
|
||||
$fatal;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) counter <= 8'd0;
|
||||
else begin
|
||||
case (state)
|
||||
cmd_t: counter <= (counter < 8'd7) ? counter + 8'd1 : 8'd0;
|
||||
addr_t: counter <= (counter < 8'd23) ? counter + 8'd1 : 8'd0;
|
||||
default: counter <= counter + 8'd1;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) cmd <= 8'd0;
|
||||
else if (state == cmd_t) cmd <= {cmd[6:0], mosi};
|
||||
end
|
||||
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) addr <= 22'd0;
|
||||
else if (state == addr_t && counter < 8'd22) addr <= {addr[20:0], mosi};
|
||||
end
|
||||
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) data <= 64'd0;
|
||||
else if (state == addr_t && counter == 8'd23)
|
||||
data <= {
|
||||
rdata[7:0],
|
||||
rdata[15:8],
|
||||
rdata[23:16],
|
||||
rdata[31:24],
|
||||
rdata[39:32],
|
||||
rdata[47:40],
|
||||
rdata[55:48],
|
||||
rdata[63:56]
|
||||
};
|
||||
else if (state == data_t) data <= {data[62:0], data[63]};
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
import "DPI-C" function void flash_read(
|
||||
input longint addr,
|
||||
output longint data
|
||||
);
|
||||
|
||||
module FlashRead (
|
||||
input clock,
|
||||
input ren,
|
||||
input [63:0] addr,
|
||||
output reg [63:0] data
|
||||
);
|
||||
always @(posedge clock) begin
|
||||
if (ren) flash_read(addr, data);
|
||||
end
|
||||
endmodule
|
||||
Reference in new issue
Block a user