diff options
author | Tristan Gingold <tgingold@free.fr> | 2019-10-19 10:13:04 +0200 |
---|---|---|
committer | Tristan Gingold <tgingold@free.fr> | 2019-10-19 10:13:04 +0200 |
commit | 2141001bc795cd4fd12c9bb3a0f5d689c7840ef5 (patch) | |
tree | 1b3781c0d23d10c1ff7205c0331e2a65c808fc46 | |
parent | 0b29a7cb792bd07b112671a264defcb1085ba402 (diff) | |
download | ghdl-yosys-plugin-2141001bc795cd4fd12c9bb3a0f5d689c7840ef5.tar.gz ghdl-yosys-plugin-2141001bc795cd4fd12c9bb3a0f5d689c7840ef5.tar.bz2 ghdl-yosys-plugin-2141001bc795cd4fd12c9bb3a0f5d689c7840ef5.zip |
Initial support of memories.
-rw-r--r-- | src/ghdl.cc | 170 |
1 files changed, 152 insertions, 18 deletions
diff --git a/src/ghdl.cc b/src/ghdl.cc index d6c3cba..d0c3c35 100644 --- a/src/ghdl.cc +++ b/src/ghdl.cc @@ -53,12 +53,21 @@ static std::string to_str(Sname name) return res; } -static RTLIL::SigSpec get_src(std::vector<RTLIL::Wire *> &net_map, Net n) +static Wire *get_wire(std::vector<RTLIL::Wire *> &net_map, Net n) { log_assert(n.id != 0); // Search if N is the output of a cell. Wire *res = n.id < net_map.size() ? net_map.at(n.id) : nullptr; + return res; +} + +static RTLIL::SigSpec get_src(std::vector<RTLIL::Wire *> &net_map, Net n) +{ + log_assert(n.id != 0); + + // Search if N is the output of a cell. + Wire *res = get_wire(net_map, n); if (res != nullptr) return res; @@ -215,7 +224,6 @@ static RTLIL::SigSpec get_src(std::vector<RTLIL::Wire *> &net_map, Net n) log_cmd_error("wire not found for %s\n", to_str(get_module_name(get_module(inst))).c_str()); break; } - return SigSpec(); } static bool is_set(std::vector<RTLIL::Wire *> &net_map, Net n) @@ -236,6 +244,107 @@ static void set_src(std::vector<RTLIL::Wire *> &net_map, Net n, Wire *wire) net_map[n.id] = wire; } +static void import_memory(RTLIL::Module *module, std::vector<RTLIL::Wire *> &net_map, Instance inst) +{ + Input port_inp; + Instance port; + Net mem_o = get_output(inst, 0); + Net port_o; + unsigned prio = 0; + std::string mem_str = to_str(get_instance_name(inst)); + + // Memories appear only once. + log_assert(!is_set(net_map, mem_o)); + + // Create memory. + RTLIL::Memory *memory = new RTLIL::Memory; + memory->name = mem_str; + + // Will be set later. + memory->width = 0; + memory->size = 0; + memory->start_offset = 0; + + port_inp = get_first_sink(mem_o); + port = get_input_parent(port_inp); + + // Add it to module. + module->memories[memory->name] = memory; + + // TODO: initial value. + + // Generate cells. + while (port_inp.id != 0) { + unsigned port_width; + unsigned port_abits; + + port = get_input_parent(port_inp); + switch(get_id(port)) { + case Id_Mem_Rd: + { + Net o = get_output(port, 1); + port_width = get_width(o); + port_abits = get_width(get_input_net(port, 1)); + RTLIL::Cell *cell = module->addCell(to_str(get_instance_name(port)), "$memrd"); + RTLIL::Wire *wire = module->addWire(to_str(get_output_name(get_module(port), 1)), port_width); + + cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1)); + cell->setPort("\\EN", RTLIL::SigSpec(RTLIL::State::Sx, 1)); + // Set laster in pass 2 + // cell->setPort("\\ADDR", addr_sig); + cell->setPort("\\DATA", RTLIL::SigSpec(wire)); + + cell->parameters["\\MEMID"] = RTLIL::Const(mem_str); + cell->parameters["\\ABITS"] = RTLIL::Const(port_abits); + cell->parameters["\\WIDTH"] = RTLIL::Const(port_width); + + cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0); + cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0); + cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0); + + set_src(net_map, o, wire); + + port_o = get_output(port, 0); + set_src(net_map, port_o, reinterpret_cast<Wire*>(cell)); + } + break; + case Id_Mem_Wr_Sync: + { + RTLIL::Cell *cell = module->addCell(to_str(get_instance_name(port)), "$memwr"); + + port_width = get_width(get_input_net(port, 4)); + port_abits = get_width(get_input_net(port, 1)); + + // Set later: addr, data, clk, en + + cell->parameters["\\MEMID"] = RTLIL::Const(mem_str); + cell->parameters["\\ABITS"] = RTLIL::Const(port_abits); + cell->parameters["\\WIDTH"] = RTLIL::Const(port_width); + + cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1); + cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(1); + + cell->parameters["\\PRIORITY"] = RTLIL::Const(prio++); + + port_o = get_output(port, 0); + set_src(net_map, port_o, reinterpret_cast<Wire*>(cell)); + } + break; + default: + log_assert(0); + } + + if (memory->width == 0) { + memory->width = port_width; + memory->size = get_width(mem_o) / memory->width; + } else { + log_assert(port_width == (unsigned)memory->width); + } + + port_inp = get_first_sink(port_o); + } +} + static void import_module(RTLIL::Design *design, GhdlSynth::Module m) { std::string module_name = to_str(get_module_name(m)); @@ -261,23 +370,23 @@ static void import_module(RTLIL::Design *design, GhdlSynth::Module m) if (!is_valid(self_inst)) { // blackbox module->set_bool_attribute("\\blackbox"); - Port_Idx nbr_inputs = get_nbr_inputs(m); - for (Port_Idx idx = 0; idx < nbr_inputs; idx++) { - RTLIL::Wire *wire = module->addWire( - to_str(get_input_name(m, idx)), - get_input_width(m, idx)); - wire->port_input = true; - } - Port_Idx nbr_outputs = get_nbr_outputs(m); - for (Port_Idx idx = 0; idx < nbr_outputs; idx++) { - RTLIL::Wire *wire = module->addWire( - to_str(get_output_name(m, idx)), - get_output_width(m, idx)); - wire->port_output = true; - } - module->fixup_ports(); + Port_Idx nbr_inputs = get_nbr_inputs(m); + for (Port_Idx idx = 0; idx < nbr_inputs; idx++) { + RTLIL::Wire *wire = module->addWire( + to_str(get_input_name(m, idx)), + get_input_width(m, idx)); + wire->port_input = true; + } + Port_Idx nbr_outputs = get_nbr_outputs(m); + for (Port_Idx idx = 0; idx < nbr_outputs; idx++) { + RTLIL::Wire *wire = module->addWire( + to_str(get_output_name(m, idx)), + get_output_width(m, idx)); + wire->port_output = true; + } + module->fixup_ports(); return; - } + } // Create input ports. // They correspond to ouputs of the self instance. @@ -368,6 +477,13 @@ static void import_module(RTLIL::Design *design, GhdlSynth::Module m) } } break; + case Id_Memory: + import_memory(module, net_map, inst); + break; + case Id_Mem_Rd: + case Id_Mem_Wr_Sync: + // Handle by import_memory. + break; case Id_Signal: case Id_Isignal: case Id_Output: @@ -568,6 +684,24 @@ static void import_module(RTLIL::Design *design, GhdlSynth::Module m) case Id_Cover: module->addCover(to_str(iname), IN(0), State::S1); break; + case Id_Memory: + break; + case Id_Mem_Rd: + { + RTLIL::Cell *cell = reinterpret_cast<RTLIL::Cell*>(get_wire(net_map, get_output(inst, 0))); + cell->setPort("\\ADDR", IN(1)); + } + break; + case Id_Mem_Wr_Sync: + { + RTLIL::Cell *cell = reinterpret_cast<RTLIL::Cell*>(get_wire(net_map, get_output(inst, 0))); + SigSpec data = IN(4); + cell->setPort("\\ADDR", IN(1)); + cell->setPort("\\CLK", IN(2)); + cell->setPort("\\EN", SigSpec(SigBit(IN(3)), data.size())); + cell->setPort("\\DATA", data); + } + break; case Id_Const_UB32: case Id_Const_SB32: case Id_Const_UL32: |