feat: add verilator sim env

This commit is contained in:
maksyuki committed 2025-08-12 19:47:50 +08:00
1 parent b810468684
commit 58ee96e9ab
9 files changed
+3664

No files matched your search

+129
View File
@@ -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();
}
+44
View File
@@ -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
};
+10
View File
@@ -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
+54
View File
@@ -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;
}
+502
View File
@@ -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 &current_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 */
+49
View File
@@ -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);
}
+160
View File
@@ -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
+105
View File
@@ -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