12 #include "rapidjson/filewritestream.h"
13 #include "rapidjson/prettywriter.h"
23 if (gate_lib ==
nullptr)
25 log_error(
"hgl_writer",
"received a nullptr as gate library.", file_path.string());
29 FILE* fp = fopen(file_path.string().c_str(),
"w");
32 log_error(
"hgl_writer",
"unable to open '{}' for writing.", file_path.string());
36 rapidjson::Document document;
39 if (!write_gate_library(document, gate_lib))
45 char writeBuffer[65536];
46 rapidjson::FileWriteStream os(fp, writeBuffer,
sizeof(writeBuffer));
48 rapidjson::PrettyWriter<rapidjson::FileWriteStream> writer(os);
49 document.Accept(writer);
56 bool HGLWriter::write_gate_library(rapidjson::Document& document,
const GateLibrary* gate_lib)
58 rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
61 document.AddMember(
"version", HGL_FORMAT_VERSION, allocator);
64 document.AddMember(
"library", gate_lib->
get_name(), allocator);
67 rapidjson::Value gate_locs(rapidjson::kObjectType);
70 gate_locs.AddMember(
"data_x_identifier", location_identifiers.first, allocator);
71 gate_locs.AddMember(
"data_y_identifier", location_identifiers.second, allocator);
72 document.AddMember(
"gate_locations", gate_locs, allocator);
75 std::vector<GateType*> gate_types;
79 if ((gt.first !=
"HAL_GND") && (gt.first !=
"HAL_VDD"))
81 gate_types.push_back(gt.second);
85 std::sort(gate_types.begin(), gate_types.end(), [](GateType* l, GateType* r) { return l->get_id() < r->get_id(); });
87 rapidjson::Value cells(rapidjson::kArrayType);
88 for (
const auto gt : gate_types)
90 rapidjson::Value cell(rapidjson::kObjectType);
93 cell.AddMember(
"name", gt->get_name(), allocator);
96 std::set<GateTypeProperty> properties = gt->get_properties();
98 rapidjson::Value bts(rapidjson::kArrayType);
100 for (
const auto& property : properties)
102 std::string bt_str = enum_to_string<GateTypeProperty>(property);
103 bts.PushBack(rapidjson::Value{}.SetString(bt_str.c_str(), bt_str.length(), allocator), allocator);
106 cell.AddMember(
"types", bts, allocator);
110 const auto& parameters = gt->get_parameters();
111 if (!parameters.empty())
113 rapidjson::Value params_array(rapidjson::kArrayType);
114 for (
const auto& [pname, p] : parameters)
116 rapidjson::Value entry(rapidjson::kObjectType);
117 entry.AddMember(
"name", rapidjson::Value{}.SetString(pname.c_str(), pname.length(), allocator), allocator);
118 switch (p.get_type())
121 entry.AddMember(
"type",
"boolean", allocator);
124 entry.AddMember(
"type",
"bit_vector", allocator);
125 entry.AddMember(
"size",
static_cast<u32>(p.get_size()), allocator);
128 entry.AddMember(
"type",
"logic_vector", allocator);
129 entry.AddMember(
"size",
static_cast<u32>(p.get_size()), allocator);
132 entry.AddMember(
"type",
"integer", allocator);
135 entry.AddMember(
"type",
"string", allocator);
138 entry.AddMember(
"type",
"float", allocator);
141 entry.AddMember(
"type",
"time", allocator);
144 entry.AddMember(
"type",
"enum", allocator);
145 rapidjson::Value values_array(rapidjson::kArrayType);
146 for (
const auto& v : p.get_enum_values())
148 values_array.PushBack(rapidjson::Value{}.SetString(v.c_str(), v.length(), allocator), allocator);
150 entry.AddMember(
"values", values_array, allocator);
154 entry.AddMember(
"default", rapidjson::Value{}.SetString(p.get_default_value().c_str(), p.get_default_value().length(), allocator), allocator);
155 params_array.PushBack(entry, allocator);
157 cell.AddMember(
"parameters", params_array, allocator);
160 std::unordered_map<std::string, BooleanFunction> functions = gt->get_boolean_functions();
163 if (LUTComponent* lut_component = gt->get_component_as<LUTComponent>([](
const GateTypeComponent* c) { return LUTComponent::is_class_of(c); }); lut_component !=
nullptr)
165 rapidjson::Value lut_config(rapidjson::kObjectType);
167 rapidjson::Value output_pins(rapidjson::kArrayType);
168 const auto& pin_configs = lut_component->get_output_pin_configs();
169 for (
const GatePin* pin : gt->get_pins([](
const GatePin* p) { return p->get_type() == PinType::lut; }))
171 const std::string& pin_name = pin->get_name();
172 rapidjson::Value entry(rapidjson::kObjectType);
173 entry.AddMember(
"pin", rapidjson::Value{}.SetString(pin_name.c_str(), pin_name.length(), allocator), allocator);
174 const auto it = pin_configs.find(pin_name);
175 if (it == pin_configs.end())
177 log_error(
"hgl_writer",
"LUT gate type '{}': output pin '{}' has no INIT config — skipping.", gt->get_name(), pin_name);
180 const auto& cfg = it->second;
181 entry.AddMember(
"data_identifier", rapidjson::Value{}.SetString(cfg.init_identifier.c_str(), cfg.init_identifier.length(), allocator), allocator);
182 entry.AddMember(
"bit_offset", cfg.bit_offset, allocator);
183 entry.AddMember(
"bit_count", cfg.bit_count, allocator);
184 entry.AddMember(
"is_ascending", cfg.is_ascending, allocator);
185 rapidjson::Value input_pins_arr(rapidjson::kArrayType);
186 for (
const auto& ip : cfg.input_pins)
188 input_pins_arr.PushBack(rapidjson::Value{}.SetString(ip.c_str(), ip.length(), allocator), allocator);
190 entry.AddMember(
"input_pins", input_pins_arr, allocator);
191 output_pins.PushBack(entry, allocator);
193 lut_config.AddMember(
"output_pins", output_pins, allocator);
194 cell.AddMember(
"lut_config", lut_config, allocator);
196 else if (FFComponent* ff_component = gt->get_component_as<FFComponent>([](
const GateTypeComponent* c) { return FFComponent::is_class_of(c); }); ff_component !=
nullptr)
198 rapidjson::Value ff_config(rapidjson::kObjectType);
200 StateComponent* state_component = ff_component->get_component_as<StateComponent>([](
const GateTypeComponent* c) {
return StateComponent::is_class_of(c); });
201 if (state_component ==
nullptr)
203 log_error(
"hgl_writer",
"missing StateComponent for FF state identifiers of gate type '{}'.", gt->get_name());
207 ff_config.AddMember(
"state", state_component->get_state_identifier(), allocator);
208 ff_config.AddMember(
"neg_state", state_component->get_neg_state_identifier(), allocator);
210 InitComponent* init_component = state_component->get_component_as<InitComponent>([](
const GateTypeComponent* c) {
return InitComponent::is_class_of(c); });
211 if (init_component !=
nullptr)
214 ff_config.AddMember(
"data_category", init_component->get_init_category(), allocator);
215 ff_config.AddMember(
"data_identifier", init_component->get_init_identifiers().front(), allocator);
219 ff_config.AddMember(
"next_state", ff_component->get_next_state_function().to_string(), allocator);
220 ff_config.AddMember(
"clocked_on", ff_component->get_clock_function().to_string(), allocator);
221 if (BooleanFunction bf = ff_component->get_async_reset_function(); !bf.is_empty())
223 ff_config.AddMember(
"clear_on", bf.to_string(), allocator);
225 if (BooleanFunction bf = ff_component->get_async_set_function(); !bf.is_empty())
227 ff_config.AddMember(
"preset_on", bf.to_string(), allocator);
230 std::pair<AsyncSetResetBehavior, AsyncSetResetBehavior> cp_behav = ff_component->get_async_set_reset_behavior();
233 ff_config.AddMember(
"state_clear_preset", enum_to_string<AsyncSetResetBehavior>(cp_behav.first), allocator);
237 ff_config.AddMember(
"neg_state_clear_preset", enum_to_string<AsyncSetResetBehavior>(cp_behav.second), allocator);
240 cell.AddMember(
"ff_config", ff_config, allocator);
242 else if (LatchComponent* latch_component = gt->get_component_as<LatchComponent>([](
const GateTypeComponent* c) { return LatchComponent::is_class_of(c); }); latch_component !=
nullptr)
244 rapidjson::Value latch_config(rapidjson::kObjectType);
246 StateComponent* state_component = latch_component->get_component_as<StateComponent>([](
const GateTypeComponent* c) {
return StateComponent::is_class_of(c); });
247 if (state_component ==
nullptr)
249 log_error(
"hgl_writer",
"missing StateComponent for latch state identifiers of gate type '{}'.", gt->get_name());
253 latch_config.AddMember(
"state", state_component->get_state_identifier(), allocator);
254 latch_config.AddMember(
"neg_state", state_component->get_neg_state_identifier(), allocator);
257 if (BooleanFunction bf = latch_component->get_data_in_function(); !bf.is_empty())
259 latch_config.AddMember(
"data_in", bf.to_string(), allocator);
261 if (BooleanFunction bf = latch_component->get_enable_function(); !bf.is_empty())
263 latch_config.AddMember(
"enable_on", bf.to_string(), allocator);
265 if (BooleanFunction bf = latch_component->get_async_reset_function(); !bf.is_empty())
267 latch_config.AddMember(
"clear_on", bf.to_string(), allocator);
269 if (BooleanFunction bf = latch_component->get_async_set_function(); !bf.is_empty())
271 latch_config.AddMember(
"preset_on", bf.to_string(), allocator);
274 std::pair<AsyncSetResetBehavior, AsyncSetResetBehavior> cp_behav = latch_component->get_async_set_reset_behavior();
277 latch_config.AddMember(
"state_clear_preset", enum_to_string<AsyncSetResetBehavior>(cp_behav.first), allocator);
281 latch_config.AddMember(
"neg_state_clear_preset", enum_to_string<AsyncSetResetBehavior>(cp_behav.second), allocator);
284 cell.AddMember(
"latch_config", latch_config, allocator);
286 else if (RAMComponent* ram_component = gt->get_component_as<RAMComponent>([](
const GateTypeComponent* c) { return RAMComponent::is_class_of(c); }); ram_component !=
nullptr)
288 rapidjson::Value ram_config(rapidjson::kObjectType);
290 rapidjson::Value identifiers(rapidjson::kArrayType);
291 for (
const std::string&
identifier : ram_component->get_init_identifiers())
293 identifiers.PushBack(rapidjson::Value{}.SetString(
identifier.c_str(),
identifier.length(), allocator), allocator);
295 ram_config.AddMember(
"data_identifiers", identifiers, allocator);
296 ram_config.AddMember(
"bit_size", ram_component->get_bit_size(), allocator);
298 rapidjson::Value ram_ports(rapidjson::kArrayType);
299 for (
const GateTypeComponent* component : ram_component->get_components([](
const GateTypeComponent* c) { return RAMPortComponent::is_class_of(c); }))
301 const RAMPortComponent* port_component = component->convert_to<RAMPortComponent>();
302 if (port_component ==
nullptr)
307 rapidjson::Value port(rapidjson::kObjectType);
308 port.AddMember(
"data_group", port_component->get_data_group(), allocator);
309 port.AddMember(
"address_group", port_component->get_address_group(), allocator);
310 port.AddMember(
"clocked_on", port_component->get_clock_function().to_string(), allocator);
311 port.AddMember(
"enabled_on", port_component->get_enable_function().to_string(), allocator);
312 port.AddMember(
"is_write", port_component->is_write_port(), allocator);
313 ram_ports.PushBack(port, allocator);
315 ram_config.AddMember(
"ram_ports", ram_ports, allocator);
316 cell.AddMember(
"ram_config", ram_config, allocator);
320 const auto pin_groups = gt->get_pin_groups();
321 rapidjson::Value pg_array(rapidjson::kArrayType);
322 for (
const auto* group : pin_groups)
324 rapidjson::Value pg_val(rapidjson::kObjectType);
325 pg_val.AddMember(
"name", group->get_name(), allocator);
326 pg_val.AddMember(
"direction",
enum_to_string(group->get_direction()), allocator);
327 pg_val.AddMember(
"type",
enum_to_string(group->get_type()), allocator);
328 pg_val.AddMember(
"ascending", group->is_ascending(), allocator);
329 pg_val.AddMember(
"start_index", group->get_start_index(), allocator);
330 pg_val.AddMember(
"ordered", group->is_ordered(), allocator);
333 rapidjson::Value p_array(rapidjson::kArrayType);
334 for (
const auto* pin : group->get_pins())
336 rapidjson::Value p_val(rapidjson::kObjectType);
337 p_val.AddMember(
"name", pin->get_name(), allocator);
338 p_val.AddMember(
"direction",
enum_to_string(pin->get_direction()), allocator);
339 p_val.AddMember(
"type",
enum_to_string(pin->get_type()), allocator);
344 if (
const auto it = functions.find(pin->get_name()); it != functions.end())
346 p_val.AddMember(
"function", it->second.to_string(), allocator);
349 if (
const auto it = functions.find(pin->get_name() +
"_undefined"); it != functions.end())
351 p_val.AddMember(
"x_function", it->second.to_string(), allocator);
354 if (
const auto it = functions.find(pin->get_name() +
"_tristate"); it != functions.end())
356 p_val.AddMember(
"z_function", it->second.to_string(), allocator);
360 p_array.PushBack(p_val, allocator);
363 pg_val.AddMember(
"pins", p_array, allocator);
364 pg_array.PushBack(pg_val, allocator);
367 cell.AddMember(
"pin_groups", pg_array, allocator);
368 cells.PushBack(cell, allocator);
371 document.AddMember(
"cells", cells, allocator);
376 std::vector<HGLWriter::PinCtx> HGLWriter::get_pins(GateType* gt,
const std::unordered_map<std::string, BooleanFunction>& functions)
378 std::vector<PinCtx> res;
379 for (
const auto* pin : gt->get_pins())
382 res_pin.name = pin->get_name();
388 if (
const auto it = functions.find(pin->get_name()); it != functions.end())
390 res_pin.function = it->second.to_string();
393 if (
const auto it = functions.find(pin->get_name() +
"_undefined"); it != functions.end())
395 res_pin.x_function = it->second.to_string();
398 if (
const auto it = functions.find(pin->get_name() +
"_tristate"); it != functions.end())
400 res_pin.z_function = it->second.to_string();
404 res.push_back(res_pin);
const std::pair< std::string, std::string > & get_gate_location_data_identifiers() const
std::unordered_map< std::string, GateType * > get_gate_types(const std::function< bool(const GateType *)> &filter=nullptr) const
std::string get_name() const
const std::string & get_gate_location_data_category() const
bool write(const GateLibrary *gate_lib, const std::filesystem::path &file_path) override
static bool is_class_of(const GateTypeComponent *component)
static bool is_class_of(const GateTypeComponent *component)
#define log_error(channel,...)
std::string enum_to_string(T e)