Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
${{ runner.os }}-${{ env.cache-name }}-

- name: Install Dependencies
run: brew tap Homebrew/bundle && brew bundle
run: brew bundle --file=./Brewfile

- name: Export the brew path
run: |
Expand Down
33 changes: 30 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
cmake_minimum_required(VERSION 3.19)

# CMake 4.0+ rejects subprojects that still declare cmake_minimum_required(VERSION 3.0)
# (e.g. FetchContent glucose). Raise the policy floor so dependency trees configure.
if(CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
set(CMAKE_POLICY_VERSION_MINIMUM "3.5" CACHE STRING "" FORCE)
endif()

# * Macro to exclude the directory from source
function(EXCLUDE_FROM_LIST REMOVE_LIST TARGET_LIST)
message(STATUS "Exclude the directory - ${${REMOVE_LIST}}")
Expand Down Expand Up @@ -44,9 +50,30 @@ project(
LANGUAGES CXX
VERSION 0.3.0)

# This project is configured as CXX-only, so CMAKE_C_COMPILER can be empty.
# External C projects (e.g. abc, vcd-parser) still require a valid C compiler.
if(CMAKE_C_COMPILER)
set(GV_C_COMPILER "${CMAKE_C_COMPILER}")
else()
set(GV_C_COMPILER "cc")
endif()

if(CMAKE_CXX_COMPILER)
set(GV_CXX_COMPILER "${CMAKE_CXX_COMPILER}")
else()
set(GV_CXX_COMPILER "c++")
endif()

# * Git clokne the ABC repo at build time
# * Run the BUILD_COMMAND "make libabc.a" for creating the ABC static library
set(LIBABC_NAME libabc.a)
if(APPLE AND CMAKE_OSX_SYSROOT)
set(ABC_CC "${GV_C_COMPILER} --sysroot=${CMAKE_OSX_SYSROOT}")
set(ABC_CXX "${GV_CXX_COMPILER} --sysroot=${CMAKE_OSX_SYSROOT}")
else()
set(ABC_CC "${GV_C_COMPILER}")
set(ABC_CXX "${GV_CXX_COMPILER}")
endif()
ExternalProject_Add(
engine-abc
GIT_REPOSITORY https://github.com/berkeley-abc/abc.git
Expand All @@ -58,7 +85,7 @@ ExternalProject_Add(
INSTALL_COMMAND ""
UPDATE_COMMAND ""
UPDATE_DISCONNECTED TRUE
BUILD_COMMAND $(MAKE) "CC=${CMAKE_C_COMPILER} --sysroot=${CMAKE_OSX_SYSROOT}" "CXX=${CMAKE_CXX_COMPILER} --sysroot=${CMAKE_OSX_SYSROOT}" ABC_USE_STDINT_H=1 ${LIBABC_NAME}
BUILD_COMMAND $(MAKE) "CC=${ABC_CC}" "CXX=${ABC_CXX}" ABC_USE_STDINT_H=1 ${LIBABC_NAME}
LOG_CONFIGURE ON
LOG_INSTALL ON
# LOG_BUILD ON
Expand Down Expand Up @@ -118,8 +145,8 @@ ExternalProject_Add(
BUILD_COMMAND
${CMAKE_COMMAND} -E env
SDKROOT=${CMAKE_OSX_SYSROOT}
CC=${CMAKE_C_COMPILER}
CXX=${CMAKE_CXX_COMPILER}
CC=${GV_C_COMPILER}
CXX=${GV_CXX_COMPILER}
$(MAKE) all
LOG_CONFIGURE ON
LOG_INSTALL ON
Expand Down
16 changes: 16 additions & 0 deletions src/cmd/gvCmdMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "gvCmdMgr.h"

#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <iostream>
Expand Down Expand Up @@ -63,6 +64,21 @@ bool GVCmdExec::lexSingleOption(const string& option, string& token, bool option
return true;
}

bool GVCmdExec::checkOptionToken(const string& token, const string& optionPattern, size_t mandatoryLen) const {
// Mandatory prefix must exist; optional suffix may be omitted, but any provided
// characters must match the pattern exactly (case-insensitive).
if (mandatoryLen == 0) return false;
if (optionPattern.size() < mandatoryLen) return false;
if (token.size() < mandatoryLen || token.size() > optionPattern.size()) return false;

for (size_t i = 0; i < token.size(); ++i) {
unsigned char lhs = static_cast<unsigned char>(token[i]);
unsigned char rhs = static_cast<unsigned char>(optionPattern[i]);
if (tolower(lhs) != tolower(rhs)) return false;
}
return true;
}

GVCmdExecStatus
GVCmdExec::errorOption(GVCmdOptionError err, const string& opt) const {
switch (err) {
Expand Down
1 change: 1 addition & 0 deletions src/cmd/gvCmdMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class GVCmdExec {
protected:
void lexOptions(const string&, vector<string>&) const;
bool lexSingleOption(const string&, string&, bool optional = true) const;
bool checkOptionToken(const string& token, const string& optionPattern, size_t mandatoryLen) const;
GVCmdExecStatus errorOption(GVCmdOptionError err, const string& opt) const;

private:
Expand Down
8 changes: 7 additions & 1 deletion src/ext/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@ file(GLOB MY_SOURCES "./*.cc")
# Make the plugin library with the .so suffix
set(CMAKE_SHARED_LIBRARY_SUFFIX ".so")

# random_sim shells out to compile .sim_main.cpp; use the same CXX as this build (not bare "g++").
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/sim_random_compile_config.h.in
${CMAKE_CURRENT_BINARY_DIR}/sim_random_compile_config.h
@ONLY)

# Compile each .cc file into a .so file
foreach(source_file ${MY_SOURCES})
# Extract the file name (without path and extension)
get_filename_component(name ${source_file} NAME_WE)
# Compile each .cc file into a .so file
add_library(${name} SHARED ${source_file})
set_property(TARGET ${name} PROPERTY POSITION_INDEPENDENT_CODE ON)
target_include_directories(${name} PRIVATE ${YOSYS_DIR})
target_include_directories(${name} PRIVATE ${YOSYS_DIR} ${CMAKE_CURRENT_BINARY_DIR})
if(APPLE)
target_link_options(${name} PRIVATE "-dynamic" "-undefined" "dynamic_lookup")
else()
Expand Down
132 changes: 111 additions & 21 deletions src/ext/sim.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include <iostream>
#include <string>
#include <vector>

#include "sim_random_compile_config.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

Expand Down Expand Up @@ -35,17 +38,20 @@ struct randomSim : public Pass {
log(" The reset_n name of the verilog file you want to simulate\n");
log(" Default to be \"reset_n\"\n");
log(" reset when reset_n = 0\n");
log(" Only one of reset and reset_n should be set\n");
log(" [-continue]\n");
log(" Continue from previous cycle and state\n");
log(" Only one of reset, reset_n and continue should be set\n");
log(" [-output]\n");
log(" The name of output file which contains the simulation result\n");
log(" [-v]\n");
log(" verbose print the result of simulation on the command line\n");
log(" [-Verbose_printing_results]\n");
log(" verbose print the result of simulation on the command line (also supports -V)\n");
}
void execute(std::vector<std::string> args, Design* design) override {
int sim_cycle = 20, property = -1;
size_t argidx, num_inputs = 0;
bool reset_set = false, property_set = false;
bool reset_n_set = false;
bool continue_set = false;
bool clk_set = false;
bool verbose = false, verilog_file_name_set = false;
bool output_file_set = false, top_module_name_set = false, stimulus = false;
Expand All @@ -67,20 +73,34 @@ struct randomSim : public Pass {
if (args[argidx] == "-reset" && argidx + 1 < args.size()) {
reset_name = args[++argidx];
reset_set = true;
if ((reset_set ? 1 : 0) + (reset_n_set ? 1 : 0) + (continue_set ? 1 : 0) > 1)
log_error("Only one of -reset, -reset_n and -continue should be set\n");
continue;
}
if (args[argidx] == "-reset_n" && argidx + 1 < args.size() && reset_set == false) {
reset_n_name = args[++argidx];
reset_n_set = true;
if ((reset_set ? 1 : 0) + (reset_n_set ? 1 : 0) + (continue_set ? 1 : 0) > 1)
log_error("Only one of -reset, -reset_n and -continue should be set\n");
continue;
}
if (args[argidx] == "-continue" || args[argidx] == "-Continue") {
continue_set = true;
if ((reset_set ? 1 : 0) + (reset_n_set ? 1 : 0) + (continue_set ? 1 : 0) > 1)
log_error("Only one of -reset, -reset_n and -continue should be set\n");
continue;
}
if (args[argidx] == "-clk" && argidx + 1 < args.size()) {
clk_name = args[++argidx];
clk_set = true;
continue;
}
if (args[argidx] == "-v") {
verbose = true;
if (args[argidx].rfind("-V", 0) == 0) {
// "-V" is mandatory substring, and the suffix "erbose_printing_results" is optional.
// Supported examples: "-V", "-Verbose_printing_results".
std::string suffix = args[argidx].substr(2); // after "-V"
if (suffix.empty() || suffix == "erbose_printing_results")
verbose = true;
continue;
}
if (args[argidx] == "-file" && argidx + 1 < args.size()) {
Expand Down Expand Up @@ -134,6 +154,8 @@ struct randomSim : public Pass {
ofs << "#include <stdlib.h>\n";
ofs << "#include <time.h>\n";
ofs << "#include <math.h>\n";
ofs << "#include <sstream>\n";
ofs << "#include <unordered_map>\n";
ofs << "#include <vector>\n";
ofs << "#include <backends/cxxrtl/cxxrtl_vcd.h>\n";
module_name = log_id(design->top_module()->name);
Expand Down Expand Up @@ -182,6 +204,49 @@ struct randomSim : public Pass {
ofs << "ofs.open(\"" << output_file_name << "\");\n";
}
ofs << " cxxrtl_design::p_" + module_name + " top;\n";
ofs << "long long base_cycle = 0;\n";
ofs << "const char* state_file = \".sim_state.txt\";\n";
ofs << "cxxrtl::debug_items state_items;\n";
ofs << "top.debug_info(state_items);\n";
if (continue_set) {
ofs << "std::unordered_map<std::string, cxxrtl::debug_item*> state_map;\n";
ofs << "for (auto &entry : state_items.table) {\n";
ofs << " for (size_t part = 0; part < entry.second.size(); ++part) {\n";
ofs << " auto *dbg = &entry.second[part];\n";
ofs << " if (dbg->next == nullptr) continue;\n";
ofs << " state_map[entry.first + \"#\" + std::to_string(part)] = dbg;\n";
ofs << " }\n";
ofs << "}\n";
ofs << "std::ifstream state_ifs(state_file);\n";
ofs << "if (state_ifs.good()) {\n";
ofs << " std::string line;\n";
ofs << " while (std::getline(state_ifs, line)) {\n";
ofs << " if (line.empty()) continue;\n";
ofs << " std::istringstream iss(line);\n";
ofs << " std::string key;\n";
ofs << " iss >> key;\n";
ofs << " if (key == \"__cycle__\") {\n";
ofs << " iss >> base_cycle;\n";
ofs << " continue;\n";
ofs << " }\n";
ofs << " auto it = state_map.find(key);\n";
ofs << " if (it == state_map.end()) continue;\n";
ofs << " cxxrtl::debug_item* item = it->second;\n";
ofs << " if (item->next == nullptr) continue;\n";
ofs << " size_t width = 0, chunks = 0;\n";
ofs << " iss >> width >> chunks;\n";
ofs << " if (width != item->width) continue;\n";
ofs << " for (size_t c = 0; c < chunks; ++c) {\n";
ofs << " std::string tok;\n";
ofs << " if (!(iss >> tok)) break;\n";
ofs << " uint32_t value = static_cast<uint32_t>(std::stoul(tok, nullptr, 16));\n";
ofs << " item->curr[c] = value;\n";
ofs << " item->next[c] = value;\n";
ofs << " }\n";
ofs << " }\n";
ofs << "}\n";
ofs << "state_ifs.close();\n";
}
// For VCD file.
if (vcd_file_set) {
ofs << "cxxrtl::debug_items all_debug_items;\n";
Expand All @@ -193,15 +258,17 @@ struct randomSim : public Pass {
ofs << "vcd.sample(0);\n";
}

ofs << "top.step();\n";
if (!continue_set)
ofs << "top.step();\n";
ofs << "for(int cycle=0;cycle<" << sim_cycle << ";++cycle){\n";
ofs << "long long display_cycle = base_cycle + cycle + 1;\n";
ofs << "top.p_" << clk_name << ".set<bool>(false);\n";
ofs << "top.step();\n";

// For VCD file.
if (vcd_file_set) ofs << "vcd.sample(cycle*2 + 0);\n";

if (reset_set || reset_n_set) {
if (!continue_set && (reset_set || reset_n_set)) {
ofs << "if(cycle == 0)\n";
if (reset_set) {
ofs << " top.p_" << reset_name << ".set<bool>(true);\n";
Expand All @@ -215,7 +282,10 @@ struct randomSim : public Pass {
}
}

ofs << "if(cycle > 0)\n";
if (continue_set)
ofs << "if(cycle >= 0)\n";
else
ofs << "if(cycle > 0)\n";
ofs << "{\n";
ofs << "size_t idx = 0;\n";
for (auto wire : design->top_module()->wires()) {
Expand Down Expand Up @@ -300,7 +370,7 @@ struct randomSim : public Pass {
if (verbose) {
ofs << "cout << \"==========================================\\n\";\n";
ofs << "cout << \"= cycle \""
<< " << cycle + 1 "
<< " << display_cycle "
<< "<< \"\\n\";\n";
ofs << "cout << \"==========================================\\n\";\n";
for (auto wire : design->top_module()->wires()) {
Expand Down Expand Up @@ -335,7 +405,7 @@ struct randomSim : public Pass {
if (output_file_set) {
ofs << "ofs << \"==========================================\\n\";\n";
ofs << "ofs << \"= cycle \""
<< " << cycle + 1 "
<< " << display_cycle "
<< "<< \"\\n\";\n";
ofs << "ofs << \"==========================================\\n\";\n";
for (auto wire : design->top_module()->wires()) {
Expand All @@ -350,6 +420,20 @@ struct randomSim : public Pass {
}

ofs << "}\n";
ofs << "std::ofstream state_ofs(state_file);\n";
ofs << "state_ofs << \"__cycle__ \" << (base_cycle + " << sim_cycle << ") << \"\\n\";\n";
ofs << "for (auto &entry : state_items.table) {\n";
ofs << " for (size_t part = 0; part < entry.second.size(); ++part) {\n";
ofs << " auto &item = entry.second[part];\n";
ofs << " if (item.depth != 1 || item.curr == nullptr || item.next == nullptr) continue;\n";
ofs << " size_t chunks = (item.width + 31) / 32;\n";
ofs << " state_ofs << entry.first << \"#\" << part << \" \" << item.width << \" \" << chunks;\n";
ofs << " for (size_t c = 0; c < chunks; ++c)\n";
ofs << " state_ofs << \" \" << std::hex << item.curr[c] << std::dec;\n";
ofs << " state_ofs << \"\\n\";\n";
ofs << " }\n";
ofs << "}\n";
ofs << "state_ofs.close();\n";
if (output_file_set) ofs << "ofs.close();\n";
ofs << "}\n";
ofs << "\n";
Expand All @@ -362,18 +446,24 @@ struct randomSim : public Pass {
if (slashPos != std::string::npos)
yosysConfig = yosysBin.substr(0, slashPos) + "/yosys-config";

std::string compileCmd =
" g++ -g -O3 -std=c++14 "
//"-isysroot `xcrun --sdk macosx --show-sdk-path` "
"-I `" +
yosysConfig +
" --datdir`/include "
//"-Wno-vla-cxx-extension -w "
"-w "
".sim_main.cpp -o .tb ";
// Must use the same toolchain as the GV build: bare "g++" may be Homebrew GCC without
// libc++ paths, while the project is often built with Apple or Homebrew Clang.
std::string compileCmd = "\"";
compileCmd += GV_RANDOM_SIM_CXX;
compileCmd += "\" -g -O3 -std=c++14 ";
#ifdef __APPLE__
compileCmd += "-stdlib=libc++ ";
#endif
compileCmd += "-I `" + yosysConfig + " --datdir`/include "
"-w "
".sim_main.cpp -o .tb ";

run_command(compileCmd);
run_command(" ./.tb ");
int compileRet = run_command(compileCmd);
if (compileRet != 0)
log_error("random_sim failed: could not compile generated simulator (.sim_main.cpp).\n");
int simRet = run_command(" ./.tb ");
if (simRet != 0)
log_error("random_sim failed: simulator process exited abnormally (./.tb).\n");
}
} randomSim;

Expand Down
3 changes: 3 additions & 0 deletions src/ext/sim_random_compile_config.h.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once
/* Generated by CMake: C++ driver used to build GV; random_sim uses it to compile .sim_main.cpp. */
#define GV_RANDOM_SIM_CXX "@CMAKE_CXX_COMPILER@"
Loading
Loading