Initial commit

This commit is contained in:
shylie 2026-03-25 00:56:44 -04:00
commit 36e067cbf6
10 changed files with 272 additions and 0 deletions

12
.clang-format Normal file
View File

@ -0,0 +1,12 @@
BasedOnStyle: GNU
SpaceBeforeParens: ControlStatementsExceptControlMacros
PointerAlignment: Left
UseTab: Never
IndentWidth: 2
ContinuationIndentWidth: 2
ConstructorInitializerIndentWidth: 2
BreakAfterReturnType: Automatic
BreakConstructorInitializers: AfterColon
PackConstructorInitializers: Never
IncludeBlocks: Regroup
BreakBeforeBraces: Allman

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.cache/
build/

13
CMakeLists.txt Normal file
View File

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.20)
project(vcppd)
add_library(vcppd src/vcd.cpp src/builder.cpp)
target_include_directories(vcppd PUBLIC include)
set_target_properties(vcppd PROPERTIES CXX_STANDARD 20)
if(PROJECT_IS_TOP_LEVEL)
add_executable(vcppd-test test/test.cpp)
target_link_libraries(vcppd-test PUBLIC vcppd)
set_target_properties(vcppd-test PROPERTIES CXX_STANDARD 20)
endif()

42
include/vcppd/builder.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef VCPPD_VCD_BUILDER_H
#define VCPPD_VCD_BUILDER_H
#include "vcppd/vcd.h"
#include <format>
namespace vcppd
{
class Builder
{
friend Vcd;
friend Scope<Builder>;
public:
Builder(std::ostream& stream);
Vcd build() const;
Scope<Builder> scope(const std::string& name);
private:
template <typename U>
void trace(const std::string& name, const U& ref,
const std::string& short_name)
{
stream << std::format("$var wire {} {} {} $end", sizeof(U) * 8, name,
short_name)
<< std::endl;
variables[name] = detail::variable_entry{ &ref, sizeof(U) };
}
void unscope();
std::ostream& stream;
detail::variable_map variables;
};
}
#endif // VCPPD_VCD_BUILDER_H

57
include/vcppd/scope.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef VCPPD_VCD_SCOPE_H
#define VCPPD_VCD_SCOPE_H
#include "vcppd/vcd.h"
#include <string>
namespace vcppd
{
template <typename T> class Scope
{
friend T;
public:
Scope(const Scope&) = delete;
Scope& operator=(const Scope&) = delete;
Scope<Scope> scope(const std::string& name)
{
return Scope<Scope>(name, *this);
}
T& unscope()
{
parent.unscope();
return parent;
}
template <typename U> Scope& trace(const std::string& name, const U& ref)
{
parent.trace(this->name + "_" + name, ref, name);
return *this;
}
private:
Scope(const std::string& name, T& parent) :
name(name),
parent(parent)
{
}
template <typename U>
Scope& trace(const std::string& name, const U& ref,
const std::string& short_name)
{
parent.trace(this->name + "_" + name, ref, short_name);
return *this;
}
std::string name;
T& parent;
};
}
#endif // VCPPD_VCD_SCOPE_H

45
include/vcppd/vcd.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef VCPPD_VCD_H
#define VCPPD_VCD_H
#include <cstddef>
#include <iostream>
#include <string>
#include <unordered_map>
namespace vcppd
{
namespace detail
{
struct variable_entry
{
const void* ref;
size_t size;
};
using variable_map = std::unordered_map<std::string, variable_entry>;
}
template <typename T> class Scope;
class Builder;
class Vcd
{
friend Builder;
public:
~Vcd();
void tick();
private:
Vcd(const Builder&);
std::ostream& stream;
unsigned int current_time;
detail::variable_map variables;
};
}
#endif // VCPPD_VCD_H

8
include/vcppd/vcppd.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef VCPPD_H
#define VCPPD_H
#include "vcppd/builder.h"
#include "vcppd/scope.h"
#include "vcppd/vcd.h"
#endif // VCPPD_H

34
src/builder.cpp Normal file
View File

@ -0,0 +1,34 @@
#include "vcppd/builder.h"
#include "vcppd/scope.h"
#include <ctime>
#include <iomanip>
using namespace vcppd;
Builder::Builder(std::ostream& stream) :
stream(stream)
{
auto t = std::time(nullptr);
auto tm = *std::localtime(&t);
stream << "$version Generated by vcppd $end" << std::endl;
stream << "$date " << std::put_time(&tm, "%A %B %e %T %Y") << " $end"
<< std::endl;
stream << "$timescale 1ns $end" << std::endl;
}
Vcd Builder::build() const
{
stream << "$enddefinitions $end" << std::endl;
return Vcd(*this);
}
Scope<Builder> Builder::scope(const std::string& name)
{
stream << "$scope module " << name << " $end" << std::endl;
return Scope<Builder>(name, *this);
}
void Builder::unscope() { stream << "$upscope $end" << std::endl; }

37
src/vcd.cpp Normal file
View File

@ -0,0 +1,37 @@
#include "vcppd/vcd.h"
#include "vcppd/builder.h"
#include <cstdint>
#include <cstring>
#include <format>
using namespace vcppd;
Vcd::Vcd(const Builder& builder) :
stream(builder.stream),
variables(builder.variables),
current_time(0)
{
}
Vcd::~Vcd() { stream << std::format("#{}", current_time) << std::endl; }
void Vcd::tick()
{
stream << std::format("#{}", current_time) << std::endl;
for (const auto& [name, entry] : variables)
{
stream << "b";
for (int i = 0; i < entry.size; i++)
{
uint8_t byte;
memcpy(&byte, static_cast<const uint8_t*>(entry.ref), 1);
stream << std::format("{0:b}", byte);
}
stream << " " << name << std::endl;
}
current_time += 1;
}

22
test/test.cpp Normal file
View File

@ -0,0 +1,22 @@
#include "vcppd/vcppd.h"
int main(int argc, char** argv)
{
uint8_t eae = 0;
uint8_t eae2 = 0;
auto vcd = vcppd::Builder(std::cout)
.scope("TOP")
.trace("eae", eae)
.trace("eae2", eae2)
.unscope()
.build();
for (int i = 0; i < 10; i++)
{
vcd.tick();
eae += 1;
eae2 += 2;
}
return 0;
}