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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ __pycache__/
.doit.db

docs/_build
docs/autoapi
.cache
78 changes: 78 additions & 0 deletions chipflow_lib/common/sim/main.cc.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#undef NDEBUG

#include <cxxrtl/cxxrtl.h>
#include <cxxrtl/cxxrtl_server.h>
#include "sim_soc.h"
{% for include in includes %}
#include "{{include}}"
{% endfor %}

#include <fstream>
#include <filesystem>

using namespace cxxrtl::time_literals;
using namespace cxxrtl_design;
using namespace chipflow;

int main(int argc, char **argv) {
p_sim__top top;

{% for initialiser in initialisers %}
{{initialiser}};
{% endfor %}

cxxrtl::agent agent(cxxrtl::spool("spool.bin"), top);
if (getenv("DEBUG")) // can also be done when a condition is violated, etc
std::cerr << "Waiting for debugger on " << agent.start_debugging() << std::endl;

open_event_log(BUILD_DIR "/sim/events.json");
open_input_commands(PROJECT_ROOT "/design/tests/input.json");

unsigned timestamp = 0;
auto tick = [&]() {
{% for interface in interfaces %}
{{interface}}.step(timestamp);
{% endfor %}

// FIXME: Currently we tick all clocks together, this need fixing..
{% for clock in clocks %}
top.{{clock}}.set(false);
{% endfor %}
agent.step();
agent.advance(1_us);
++timestamp;

{% for clock in clocks %}
top.{{clock}}.set(true);
{% endfor %}
agent.step();
agent.advance(1_us);
++timestamp;

// if (timestamp == 10)
// agent.breakpoint(CXXRTL_LOCATION);
};

{% for data in data_load %}
{{data.model_name}}.load_data("{{data.file_name}}", {{data.args | join(', ')}});
{% endfor %}

agent.step();
agent.advance(1_us);

{% for reset in resets %}
top.{{reset}}.set(false);
{% endfor %}

tick();

{% for reset in resets %}
top.{{reset}}.set(true);
{% endfor %}

for (int i = 0; i < {{num_steps}}; i++)
tick();

close_event_log();
return 0;
}
50 changes: 10 additions & 40 deletions chipflow_lib/common/sim/models.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <unordered_map>
#include "models.h"

namespace cxxrtl_design {
namespace chipflow {

// Helper functions

Expand Down Expand Up @@ -134,8 +134,10 @@ void close_event_log() {
}
}

namespace models {

// SPI flash
void spiflash_model::load_data(const std::string &filename, unsigned offset) {
void spiflash::load_data(const std::string &filename, unsigned offset) {
std::ifstream in(filename, std::ifstream::binary);
if (offset >= data.size()) {
throw std::out_of_range("flash: offset beyond end");
Expand All @@ -145,7 +147,7 @@ void spiflash_model::load_data(const std::string &filename, unsigned offset) {
}
in.read(reinterpret_cast<char*>(data.data() + offset), (data.size() - offset));
}
void spiflash_model::step(unsigned timestamp) {
void spiflash::step(unsigned timestamp) {
auto process_byte = [&]() {
s.out_buffer = 0;
if (s.byte_count == 0) {
Expand Down Expand Up @@ -221,7 +223,7 @@ void spiflash_model::step(unsigned timestamp) {

// UART

void uart_model::step(unsigned timestamp) {
void uart::step(unsigned timestamp) {

for (auto action : get_pending_actions(name)) {
if (action.event == "tx") {
Expand Down Expand Up @@ -274,41 +276,8 @@ void uart_model::step(unsigned timestamp) {
}
}

// GPIO

void gpio_model::step(unsigned timestamp) {
uint32_t o_value = o.get<uint32_t>();
uint32_t oe_value = oe.get<uint32_t>();

for (auto action : get_pending_actions(name)) {
if (action.event == "set") {
auto bin = std::string(action.payload);
input_data = 0;
for (unsigned i = 0; i < width; i++) {
if (bin.at((width - 1) - i) == '1')
input_data |= (1U << i);
}
}
}

if (o_value != s.o_last || oe_value != s.oe_last) {
std::string formatted_value;
for (int i = width - 1; i >= 0; i--) {
if (oe_value & (1U << unsigned(i)))
formatted_value += (o_value & (1U << unsigned(i))) ? '1' : '0';
else
formatted_value += 'Z';
}
log_event(timestamp, name, "change", json(formatted_value));
}

i.set((input_data & ~oe_value) | (o_value & oe_value));
s.o_last = o_value;
s.oe_last = oe_value;
}

// Generic SPI model
void spi_model::step(unsigned timestamp) {
void spi::step(unsigned timestamp) {
for (auto action : get_pending_actions(name)) {
if (action.event == "set_data") {
s.out_buffer = s.send_data = uint32_t(action.payload);
Expand Down Expand Up @@ -341,7 +310,7 @@ void spi_model::step(unsigned timestamp) {
}

// Generic I2C model
void i2c_model::step(unsigned timestamp) {
void i2c::step(unsigned timestamp) {
bool sda = !bool(sda_oe), scl = !bool(scl_oe);

for (auto action : get_pending_actions(name)) {
Expand Down Expand Up @@ -403,4 +372,5 @@ void i2c_model::step(unsigned timestamp) {
scl_i.set(scl);
}

}
} //chipflow::models
} //chipflow
70 changes: 54 additions & 16 deletions chipflow_lib/common/sim/models.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include "vendor/nlohmann/json.hpp"


namespace cxxrtl_design {
namespace chipflow {

using namespace cxxrtl;

Expand All @@ -30,9 +30,12 @@ void log_event(unsigned timestamp, const std::string &peripheral, const std::str
std::vector<action> get_pending_actions(const std::string &peripheral);
void close_event_log();

struct spiflash_model {
namespace models {


struct spiflash {
std::string name;
spiflash_model(const std::string &name, const value<1> &clk, const value<1> &csn, const value<4> &d_o, const value<4> &d_oe, value<4> &d_i) :
spiflash(const std::string &name, const value<1> &clk, const value<1> &csn, const value<4> &d_o, const value<4> &d_oe, value<4> &d_i) :
name(name), clk(clk), csn(csn), d_o(d_o), d_oe(d_oe), d_i(d_i) {
data.resize(16*1024*1024);
std::fill(data.begin(), data.end(), 0xFF); // flash starting value
Expand Down Expand Up @@ -61,9 +64,9 @@ struct spiflash_model {
} s;
};

struct uart_model {
struct uart {
std::string name;
uart_model(const std::string &name, const value<1> &tx, value<1> &rx, unsigned baud_div = 25000000/115200) : name(name), tx(tx), rx(rx), baud_div(baud_div) {};
uart(const std::string &name, const value<1> &tx, value<1> &rx, unsigned baud_div = 25000000/115200) : name(name), tx(tx), rx(rx), baud_div(baud_div) {};

void step(unsigned timestamp);
private:
Expand All @@ -82,28 +85,62 @@ struct uart_model {
} s;
};

struct gpio_model {
static constexpr unsigned width = 8;
template<int pin_count>
struct gpio {
std::string name;
gpio_model(const std::string &name, const value<width> &o, const value<width> &oe, value<width> &i) : name(name), o(o), oe(oe), i(i) {};

gpio(const std::string &name, const value<pin_count> &o, const value<pin_count> &oe, value<pin_count> &i) : name(name), o(o), oe(oe), i(i) {};

void step(unsigned timestamp);

private:
uint32_t input_data = 0;
const value<width> &o;
const value<width> &oe;
value<width> &i;
const value<pin_count> &o;
const value<pin_count> &oe;
value<pin_count> &i;
struct {
uint32_t o_last = 0;
uint32_t oe_last = 0;
} s;
};


struct spi_model {
// GPIO
template<int pin_count>
void gpio<pin_count>::step(unsigned timestamp) {
uint32_t o_value = o.template get<uint32_t>();
uint32_t oe_value = oe.template get<uint32_t>();

for (auto action : get_pending_actions(name)) {
if (action.event == "set") {
auto bin = std::string(action.payload);
input_data = 0;
for (unsigned i = 0; i < pin_count; i++) {
if (bin.at((pin_count - 1) - i) == '1')
input_data |= (1U << i);
}
}
}

if (o_value != s.o_last || oe_value != s.oe_last) {
std::string formatted_value;
for (int i = pin_count - 1; i >= 0; i--) {
if (oe_value & (1U << unsigned(i)))
formatted_value += (o_value & (1U << unsigned(i))) ? '1' : '0';
else
formatted_value += 'Z';
}
log_event(timestamp, name, "change", json(formatted_value));
}

i.set((input_data & ~oe_value) | (o_value & oe_value));
s.o_last = o_value;
s.oe_last = oe_value;
}

struct spi {
std::string name;
spi_model(const std::string &name, const value<1> &clk, const value<1> &csn, const value<1> &copi, value<1> &cipo) :
spi(const std::string &name, const value<1> &clk, const value<1> &copi, value<1> &cipo, const value<1> &csn) :
name(name), clk(clk), csn(csn), copi(copi), cipo(cipo) {
};

Expand All @@ -125,9 +162,9 @@ struct spi_model {
} s;
};

struct i2c_model {
struct i2c {
std::string name;
i2c_model(const std::string &name, const value<1> &sda_oe, value<1> &sda_i, const value<1> &scl_oe, value<1> &scl_i) : name(name), sda_oe(sda_oe), sda_i(sda_i), scl_oe(scl_oe), scl_i(scl_i) {};
i2c(const std::string &name, const value<1> &scl_o, const value<1> &scl_oe, value<1> &scl_i, const value<1> &sda_o, const value<1> &sda_oe, value<1> &sda_i) : name(name), sda_oe(sda_oe), sda_i(sda_i), scl_oe(scl_oe), scl_i(scl_i) {};

void step(unsigned timestamp);
private:
Expand All @@ -150,6 +187,7 @@ struct i2c_model {
};


}
} //chipflow::simulation
} //chipflow

#endif
3 changes: 3 additions & 0 deletions chipflow_lib/config_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ class SiliconConfig(BaseModel):
debug: Optional[Dict[str, bool]] = None
# This is still kept around to allow forcing pad locations.

class SimulationConfig(BaseModel):
num_steps: int = 3000000

class ChipFlowConfig(BaseModel):
"""Root configuration for chipflow.toml."""
project_name: str
top: Dict[str, Any] = {}
steps: Optional[Dict[str, str]] = None
silicon: Optional[SiliconConfig] = None
simulation: SimulationConfig = SimulationConfig()
clock_domains: Optional[List[str]] = None


Expand Down
6 changes: 6 additions & 0 deletions chipflow_lib/platforms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@
)
from ._packages import PACKAGE_DEFINITIONS
from ._sky130 import Sky130DriveMode
from ._signatures import (
JTAGSignature, SPISignature, I2CSignature, UARTSignature, GPIOSignature, QSPIFlashSignature,
attach_simulation_data
)

__all__ = ['IO_ANNOTATION_SCHEMA', 'IOSignature',
'IOModel', 'IOModelOptions', 'IOTripPoint',
'OutputIOSignature', 'InputIOSignature', 'BidirIOSignature',
'SiliconPlatformPort', 'SiliconPlatform',
'SimPlatform',
'JTAGSignature', 'SPISignature', 'I2CSignature', 'UARTSignature', 'GPIOSignature', 'QSPIFlashSignature',
'attach_simulation_data',
'Sky130DriveMode',
'PACKAGE_DEFINITIONS']
Loading
Loading