From c1c4d8c86328fa378da5d8d306b2ec701768667a Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 11 Mar 2016 17:32:12 +0000 Subject: [PATCH 01/22] Fix bitmask merging in synthesis. A conditional clause that doesn't drive any bits of a particular nexus should not affect the bitmask generated for that nexus. The completely undriven case is handled by the enable signal. --- synth2.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/synth2.cc b/synth2.cc index b30b7576c..9dff45a0f 100644 --- a/synth2.cc +++ b/synth2.cc @@ -165,10 +165,10 @@ static void merge_sequential_masks(NetProc::mask_t&top_mask, NetProc::mask_t&sub static void merge_parallel_masks(NetProc::mask_t&top_mask, NetProc::mask_t&sub_mask) { - if (top_mask.size() == 0) + if (sub_mask.size() == 0) return; - if (sub_mask.size() == 0) { + if (top_mask.size() == 0) { top_mask = sub_mask; return; } From f176106c54a716c7616fb104371b358bcb5d4396 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 11 Mar 2016 18:35:13 +0000 Subject: [PATCH 02/22] Added notes on synthesis implementation. --- synth2.cc | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/synth2.cc b/synth2.cc index 9dff45a0f..64fc3957c 100644 --- a/synth2.cc +++ b/synth2.cc @@ -28,6 +28,52 @@ using namespace std; +/* General notes on enables and bitmasks. + * + * When synthesising an asynchronous process that contains conditional + * statements (if/case statements), we need to determine the conditions + * that cause each nexus driven by that process to be updated. If a + * nexus is not updated under all circumstances, we must infer a latch. + * To this end, we generate an enable signal for each output nexus. As + * we walk the statement tree for the process, for each substatement we + * pass the enable signals generated so far into the synth_async method, + * and on return from the synth_async method, the enable signals will be + * updated to reflect any conditions introduced by that substatement. + * Once we have synthesised all the statements for that process, if an + * enable signal is not tied high, we must infer a latch for that nexus. + * + * When synthesising a synchronous process, we use the synth_async method + * to synthesise the combinatorial inputs to the D pins of the flip-flops + * we infer for that process. In this case the enable signal can be used + * as a clock enable for the flip-flop. This saves us explicitly feeding + * back the flip-flop output to undriven inputs of any synthesised muxes. + * + * The strategy described above is not sufficient when not all bits in + * a nexus are treated identically (i.e. different conditional clauses + * drive differing parts of the same vector). To handle this properly, + * we would (potentially) need to generate a separate enable signal for + * each bit in the vector. This would be a lot of work, particularly if + * we wanted to eliminate duplicates. For now, the strategy employed is + * to maintain a bitmask for each output nexus that identifies which bits + * in the nexus are unconditionally driven (driven by every clause). When + * we finish synthesising an asynchronous process, if the bitmask is not + * all ones, we must infer a latch. This currently results in an error, + * because to safely synthesise such a latch we would need the bit-level + * gate enables. When we finish synthesising a synchronous process, if + * the bitmask is not all ones, we explicitly feed the flip-flop outputs + * back to undriven inputs of any synthesised muxes to ensure undriven + * parts of the vector retain their previous state when the flip-flop is + * clocked. + * + * The enable signals are passed as links to the current output nexus + * for each signal. If an enable signal is not linked, this is treated + * as if the signal was tied low. + * + * The bitmasks are passed as bool vectors. 'true' indicates a bit is + * unconditionally driven. An empty vector (size = 0) indicates that + * the current substatement doesn't drive any bits in the nexus. + */ + static void qualify_enable(Design*des, NetScope*scope, NetNet*qualifier, bool active_state, NetLogic::TYPE gate_type, Link&enable_i, Link&enable_o) From c92b6307289ccaa071904f950e73afb2145cf125 Mon Sep 17 00:00:00 2001 From: Johann Klammer Date: Thu, 10 Mar 2016 14:37:25 +0100 Subject: [PATCH 03/22] NetLatch class --- design_dump.cc | 8 ++++++++ emit.cc | 6 ++++++ functor.cc | 9 +++++++++ functor.h | 3 +++ netlist.cc | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ netlist.h | 29 +++++++++++++++++++++++++++ target.cc | 6 ++++++ target.h | 1 + 8 files changed, 116 insertions(+) diff --git a/design_dump.cc b/design_dump.cc index 5a97b5ec0..d7eb4027b 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -688,6 +688,14 @@ void NetFF::dump_node(ostream&o, unsigned ind) const dump_obj_attr(o, ind+4); } +void NetLatch::dump_node(ostream&o, unsigned ind) const +{ + o << setw(ind) << "" << "LPM_LATCH: " << name() + << " scope=" << scope_path(scope()) << endl; + dump_node_pins(o, ind+4); + dump_obj_attr(o, ind+4); +} + void NetLiteral::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "constant real " << real_ diff --git a/emit.cc b/emit.cc index bd46fc5c4..adc582293 100644 --- a/emit.cc +++ b/emit.cc @@ -123,6 +123,12 @@ bool NetFF::emit_node(struct target_t*tgt) const return true; } +bool NetLatch::emit_node(struct target_t*tgt) const +{ + tgt->lpm_latch(this); + return true; +} + bool NetLiteral::emit_node(struct target_t*tgt) const { return tgt->net_literal(this); diff --git a/functor.cc b/functor.cc index 75ed5a606..280a6f9aa 100644 --- a/functor.cc +++ b/functor.cc @@ -78,6 +78,10 @@ void functor_t::lpm_ff(Design*, NetFF*) { } +void functor_t::lpm_latch(Design*, NetLatch*) +{ +} + void functor_t::lpm_logic(Design*, NetLogic*) { } @@ -219,6 +223,11 @@ void NetFF::functor_node(Design*des, functor_t*fun) fun->lpm_ff(des, this); } +void NetLatch::functor_node(Design*des, functor_t*fun) +{ + fun->lpm_latch(des, this); +} + void NetLiteral::functor_node(Design*des, functor_t*fun) { fun->lpm_literal(des, this); diff --git a/functor.h b/functor.h index 63d85a755..716ceda64 100644 --- a/functor.h +++ b/functor.h @@ -75,6 +75,9 @@ struct functor_t { /* This method is called for each FF in the design. */ virtual void lpm_ff(class Design*des, class NetFF*); + /* This method is called for each LATCH in the design. */ + virtual void lpm_latch(class Design*des, class NetLatch*); + /* Handle LPM combinational logic devices. */ virtual void lpm_logic(class Design*des, class NetLogic*); diff --git a/netlist.cc b/netlist.cc index 211083a17..34b3ebf28 100644 --- a/netlist.cc +++ b/netlist.cc @@ -1306,6 +1306,60 @@ const verinum& NetFF::sset_value() const return sset_value_; } +/* + * The NetLatch class represents an LPM_LATCH device. The pinout is assigned + * like so: + * 0 -- Enable + * 1 -- Data + * 2 -- Q + */ + +NetLatch::NetLatch(NetScope*s, perm_string n, unsigned width__) +: NetNode(s, n, 3), width_(width__) +{ + pin_Enable().set_dir(Link::INPUT); + pin_Data().set_dir(Link::INPUT); + pin_Q().set_dir(Link::OUTPUT); +} + +NetLatch::~NetLatch() +{ +} + +unsigned NetLatch::width() const +{ + return width_; +} + +Link& NetLatch::pin_Enable() +{ + return pin(0); +} + +const Link& NetLatch::pin_Enable() const +{ + return pin(0); +} + +Link& NetLatch::pin_Data() +{ + return pin(1); +} + +const Link& NetLatch::pin_Data() const +{ + return pin(1); +} + +Link& NetLatch::pin_Q() +{ + return pin(2); +} + +const Link& NetLatch::pin_Q() const +{ + return pin(2); +} NetAbs::NetAbs(NetScope*s, perm_string n, unsigned w) : NetNode(s, n, 2), width_(w) diff --git a/netlist.h b/netlist.h index d6fe7358a..710aa4b82 100644 --- a/netlist.h +++ b/netlist.h @@ -1684,6 +1684,35 @@ class NetFF : public NetNode { verinum sset_value_; }; + +/* + * This class represents an LPM_LATCH device. There is no literal gate + * type in Verilog that maps, but gates of this type can be inferred. + */ +class NetLatch : public NetNode { + + public: + NetLatch(NetScope*s, perm_string n, unsigned vector_width); + ~NetLatch(); + + unsigned width() const; + + Link& pin_Enable(); + Link& pin_Data(); + Link& pin_Q(); + + const Link& pin_Enable() const; + const Link& pin_Data() const; + const Link& pin_Q() const; + + virtual void dump_node(ostream&, unsigned ind) const; + virtual bool emit_node(struct target_t*) const; + virtual void functor_node(Design*des, functor_t*fun); + + private: + unsigned width_; +}; + /* * This class implements a basic LPM_MULT combinational multiplier. It * is used as a structural representation of the * operator. The diff --git a/target.cc b/target.cc index a4fe8b44a..b268e5192 100644 --- a/target.cc +++ b/target.cc @@ -183,6 +183,12 @@ void target_t::lpm_ff(const NetFF*) "Unhandled NetFF." << endl; } +void target_t::lpm_latch(const NetLatch*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled NetLatch." << endl; +} + void target_t::lpm_mult(const NetMult*) { cerr << "target (" << typeid(*this).name() << "): " diff --git a/target.h b/target.h index ec834418d..39ddd7b8f 100644 --- a/target.h +++ b/target.h @@ -98,6 +98,7 @@ struct target_t { virtual void lpm_mult(const NetMult*); virtual void lpm_mux(const NetMux*); virtual void lpm_pow(const NetPow*); + virtual void lpm_latch(const NetLatch*); virtual bool concat(const NetConcat*); virtual bool part_select(const NetPartSelect*); From 81d3b7a25cd5b829b4f2f9fbea1d30a5c915758e Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 11 Mar 2016 23:14:55 +0000 Subject: [PATCH 04/22] Updated copyright notices. --- design_dump.cc | 2 +- emit.cc | 2 +- target.cc | 2 +- target.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index d7eb4027b..44a9b8ddc 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU diff --git a/emit.cc b/emit.cc index adc582293..6a08431f8 100644 --- a/emit.cc +++ b/emit.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU diff --git a/target.cc b/target.cc index b268e5192..15cc27c5c 100644 --- a/target.cc +++ b/target.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2013 Stephen Williams + * Copyright (c) 1998-2016 Stephen Williams * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU diff --git a/target.h b/target.h index 39ddd7b8f..be39f7ca4 100644 --- a/target.h +++ b/target.h @@ -1,7 +1,7 @@ #ifndef IVL_target_H #define IVL_target_H /* - * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -95,10 +95,10 @@ struct target_t { virtual void lpm_divide(const NetDivide*); virtual void lpm_modulo(const NetModulo*); virtual void lpm_ff(const NetFF*); + virtual void lpm_latch(const NetLatch*); virtual void lpm_mult(const NetMult*); virtual void lpm_mux(const NetMux*); virtual void lpm_pow(const NetPow*); - virtual void lpm_latch(const NetLatch*); virtual bool concat(const NetConcat*); virtual bool part_select(const NetPartSelect*); From 0e537c5465504dd29546097e3e21b0b61d889fa5 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 11 Mar 2016 23:29:38 +0000 Subject: [PATCH 05/22] Enable latch generation in synthesis. (reworked patch supplied by Johann Klammer) --- synth2.cc | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/synth2.cc b/synth2.cc index 64fc3957c..aab79ca88 100644 --- a/synth2.cc +++ b/synth2.cc @@ -1581,28 +1581,44 @@ bool NetProcTop::synth_async(Design*des) bool flag = statement_->synth_async(des, scope(), nex_set, nex_out, enables, bitmasks); if (!flag) return false; - bool latch_flag = false; - for (unsigned idx = 0 ; idx < enables.pin_count() ; idx += 1) { - if (!enables.pin(idx).is_linked(scope()->tie_hi())) { + flag = tie_off_floating_inputs_(des, nex_set, nex_in, bitmasks, false); + if (!flag) return false; + + for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) { + + if (enables.pin(idx).is_linked(scope()->tie_hi())) { + connect(nex_set[idx].lnk, nex_out.pin(idx)); + } else { cerr << get_fileline() << ": warning: " << "A latch has been inferred for '" << nex_set[idx].lnk.nexus()->pick_any_net()->name() << "'." << endl; - latch_flag = true; + + if (debug_synth2) { + cerr << get_fileline() << ": debug: " + << "Top level making a " + << nex_set[idx].wid << "-wide " + << "NetLatch device." << endl; + } + + NetLatch*latch = new NetLatch(scope(), scope()->local_symbol(), + nex_set[idx].wid); + des->add_node(latch); + latch->set_line(*this); + + NetNet*tmp = nex_out.pin(idx).nexus()->pick_any_net(); + tmp->set_line(*this); + assert(tmp); + + tmp = crop_to_width(des, tmp, latch->width()); + + connect(nex_set[idx].lnk, latch->pin_Q()); + connect(tmp->pin(0), latch->pin_Data()); + + assert (enables.pin(idx).is_linked()); + connect(enables.pin(idx), latch->pin_Enable()); } } - if (latch_flag) { - cerr << get_fileline() << ": sorry: Latches are not " - << "currently supported in synthesis." << endl; - des->errors += 1; - return false; - } - - flag = tie_off_floating_inputs_(des, nex_set, nex_in, bitmasks, false); - if (!flag) return false; - - for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) - connect(nex_set[idx].lnk, nex_out.pin(idx)); synthesized_design_ = des; return true; From 35a61b4680e6776f6b10ed699b6af40331375b70 Mon Sep 17 00:00:00 2001 From: Johann Klammer Date: Thu, 10 Mar 2016 22:13:27 +0100 Subject: [PATCH 06/22] Add LATCH to target interface --- ivl_target.h | 14 ++++++++++---- t-dll-api.cc | 7 +++++++ t-dll.cc | 39 +++++++++++++++++++++++++++++++++++++++ t-dll.h | 13 +++++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/ivl_target.h b/ivl_target.h index a5d27ed80..216ed39a2 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -336,7 +336,8 @@ typedef enum ivl_lpm_type_e { IVL_LPM_SUB = 8, IVL_LPM_SUBSTITUTE=39, /* IVL_LPM_RAM = 9, / obsolete */ - IVL_LPM_UFUNC = 14 + IVL_LPM_UFUNC = 14, + IVL_LPM_LATCH = 40 } ivl_lpm_type_t; /* The path edge type is the edge type used to select a specific @@ -1313,6 +1314,11 @@ extern unsigned ivl_lpm_lineno(ivl_lpm_t net); * single ivl_lpm_data input are the same with, ivl_lpm_width. This * device carries a vector like other LPM devices. * + * - Latch (IVL_LPM_LATCH) + * This data is an asynchronous latch. The ivl_lpm_q output and + * single ivl_lpm_data input are the same with, ivl_lpm_width. This + * device carries a vector like other LPM devices. + * * - Memory port (IVL_LPM_RAM) (deprecated in favor of IVL_LPM_ARRAY) * These are structural ports into a memory device. They represent * address/data ports of a memory device that the context can hook to @@ -1428,18 +1434,18 @@ extern unsigned ivl_lpm_negedge(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net); /* IVL_LPM_UFUNC */ extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net); - /* IVL_LPM_FF */ + /* IVL_LPM_FF IVL_LPM_LATCH*/ extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net); /* IVL_LPM_ADD IVL_LPM_CONCAT IVL_LPM_FF IVL_LPM_PART IVL_LPM_MULT IVL_LPM_MUX IVL_LPM_POW IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB - IVL_LPM_UFUNC IVL_LPM_SUBSTITUTE */ + IVL_LPM_UFUNC IVL_LPM_SUBSTITUTE IVL_LPM_LATCH*/ extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx); /* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_POW IVL_LPM_SUB IVL_LPM_CMP_EQ IVL_LPM_CMP_EEQ IVL_LPM_CMP_EQX IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE */ extern ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx); /* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_PART IVL_LPM_POW IVL_LPM_SUB IVL_LPM_UFUNC IVL_LPM_CMP_EEQ IVL_LPM_CMP_EQX - IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE IVL_LPM_SUBSTITUTE */ + IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE IVL_LPM_SUBSTITUTE IVL_LPM_LATCH*/ extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net); extern ivl_drive_t ivl_lpm_drive0(ivl_lpm_t net); extern ivl_drive_t ivl_lpm_drive1(ivl_lpm_t net); diff --git a/t-dll-api.cc b/t-dll-api.cc index 8cad0a4af..b739bd79b 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1148,6 +1148,8 @@ extern "C" ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net) switch (net->type) { case IVL_LPM_FF: return net->u_.ff.we; + case IVL_LPM_LATCH: + return net->u_.latch.we; default: assert(0); return 0; @@ -1220,6 +1222,9 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) case IVL_LPM_FF: assert(idx == 0); return net->u_.ff.d.pin; + case IVL_LPM_LATCH: + assert(idx == 0); + return net->u_.latch.d.pin; case IVL_LPM_CONCAT: case IVL_LPM_CONCATZ: @@ -1344,6 +1349,8 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net) case IVL_LPM_FF: return net->u_.ff.q.pin; + case IVL_LPM_LATCH: + return net->u_.latch.q.pin; case IVL_LPM_MUX: return net->u_.mux.q; diff --git a/t-dll.cc b/t-dll.cc index 93564e854..52bb17581 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -2051,6 +2051,45 @@ void dll_target::lpm_ff(const NetFF*net) nexus_lpm_add(obj->u_.ff.d.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); } +void dll_target::lpm_latch(const NetLatch*net) +{ + ivl_lpm_t obj = new struct ivl_lpm_s; + obj->type = IVL_LPM_LATCH; + obj->name = net->name(); + obj->scope = find_scope(des_, net->scope()); + assert(obj->scope); + FILE_NAME(obj, net); + + obj->width = net->width(); + + scope_add_lpm(obj->scope, obj); + + const Nexus*nex; + + /* If there is a clock enable, then connect it up to the FF + device. */ + if (net->pin_Enable().is_linked()) { + nex = net->pin_Enable().nexus(); + assert(nex->t_cookie()); + obj->u_.latch.we = nex->t_cookie(); + assert(obj->u_.latch.we); + nexus_lpm_add(obj->u_.latch.we, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + } else { + obj->u_.latch.we = 0; + } + + nex = net->pin_Q().nexus(); + assert(nex->t_cookie()); + obj->u_.latch.q.pin = nex->t_cookie(); + nexus_lpm_add(obj->u_.latch.q.pin, obj, 0, + IVL_DR_STRONG, IVL_DR_STRONG); + + nex = net->pin_Data().nexus(); + assert(nex->t_cookie()); + obj->u_.latch.d.pin = nex->t_cookie(); + nexus_lpm_add(obj->u_.latch.d.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); +} + /* * Make the NetMult object into an IVL_LPM_MULT node. */ diff --git a/t-dll.h b/t-dll.h index a94137383..7baa9263c 100644 --- a/t-dll.h +++ b/t-dll.h @@ -76,6 +76,7 @@ struct dll_target : public target_t, public expr_scan_t { void lpm_compare(const NetCompare*); void lpm_divide(const NetDivide*); void lpm_ff(const NetFF*); + void lpm_latch(const NetLatch*); void lpm_modulo(const NetModulo*); void lpm_mult(const NetMult*); void lpm_mux(const NetMux*); @@ -388,6 +389,18 @@ struct ivl_lpm_s { ivl_expr_t aset_value; ivl_expr_t sset_value; } ff; + struct ivl_lpm_latch_s { + unsigned negedge_flag :1; + ivl_nexus_t we; + union { + ivl_nexus_t*pins; + ivl_nexus_t pin; + } q; + union { + ivl_nexus_t*pins; + ivl_nexus_t pin; + } d; + } latch; struct ivl_lpm_mux_s { unsigned size; From d7736d7eba5cf35398972de687cad11e2b420653 Mon Sep 17 00:00:00 2001 From: Johann Klammer Date: Fri, 11 Mar 2016 21:46:31 +0100 Subject: [PATCH 07/22] latch for vvp output --- tgt-vvp/draw_net_input.c | 1 + tgt-vvp/vvp_scope.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index e2f94fb20..d8ce40d88 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -436,6 +436,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) if (lpm) switch (ivl_lpm_type(lpm)) { case IVL_LPM_FF: + case IVL_LPM_LATCH: case IVL_LPM_ABS: case IVL_LPM_ADD: case IVL_LPM_ARRAY: diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 9bd197df6..53b56dbc6 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1830,6 +1830,31 @@ static void draw_lpm_ff(ivl_lpm_t net) fprintf(vvp_out, ";\n"); } +/* + * Emit a LATCH primitive. This uses the following syntax: + * + * .latch , ; + */ +static void draw_lpm_latch(ivl_lpm_t net) +{ + ivl_nexus_t nex; + + unsigned width = ivl_lpm_width(net); + fprintf(vvp_out, "L_%p .latch %u ", net, width); + + nex = ivl_lpm_data(net,0); + assert(nex); + fprintf(vvp_out, "%s", draw_net_input(nex)); + assert(width_of_nexus(nex) == width); + + nex = ivl_lpm_enable(net); + assert(nex); + assert(width_of_nexus(nex) == 1); + fprintf(vvp_out, ", %s", draw_net_input(nex)); + + fprintf(vvp_out, ";\n"); +} + static void draw_lpm_shiftl(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); @@ -2160,6 +2185,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net) draw_lpm_ff(net); return; + case IVL_LPM_LATCH: + draw_lpm_latch(net); + return; + case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: case IVL_LPM_CMP_EQX: From 5dfc9fdefb3b465d1cb82277b9d6e3409d8531df Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 12 Mar 2016 00:10:47 +0000 Subject: [PATCH 08/22] Code and comment cleanup for latches in target interface. --- ivl_target.h | 18 +++++++++--------- t-dll-api.cc | 4 ++-- t-dll.cc | 18 ++++++------------ t-dll.h | 5 ++--- 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/ivl_target.h b/ivl_target.h index 216ed39a2..42dbe167b 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1,7 +1,7 @@ #ifndef IVL_ivl_target_H #define IVL_ivl_target_H /* - * Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -315,6 +315,7 @@ typedef enum ivl_lpm_type_e { IVL_LPM_CMP_NEE= 19, /* Case NE (!==) */ IVL_LPM_DIVIDE = 12, IVL_LPM_FF = 3, + IVL_LPM_LATCH = 40, IVL_LPM_MOD = 13, IVL_LPM_MULT = 4, IVL_LPM_MUX = 5, @@ -336,8 +337,7 @@ typedef enum ivl_lpm_type_e { IVL_LPM_SUB = 8, IVL_LPM_SUBSTITUTE=39, /* IVL_LPM_RAM = 9, / obsolete */ - IVL_LPM_UFUNC = 14, - IVL_LPM_LATCH = 40 + IVL_LPM_UFUNC = 14 } ivl_lpm_type_t; /* The path edge type is the edge type used to select a specific @@ -1310,13 +1310,13 @@ extern unsigned ivl_lpm_lineno(ivl_lpm_t net); * inputs and the Q. All the types must be exactly the same. * * - D-FlipFlop (IVL_LPM_FF) - * This data is an edge sensitive register. The ivl_lpm_q output and - * single ivl_lpm_data input are the same with, ivl_lpm_width. This + * This device is an edge sensitive register. The ivl_lpm_q output and + * single ivl_lpm_data input are the same width, ivl_lpm_width. This * device carries a vector like other LPM devices. * * - Latch (IVL_LPM_LATCH) - * This data is an asynchronous latch. The ivl_lpm_q output and - * single ivl_lpm_data input are the same with, ivl_lpm_width. This + * This device is an asynchronous latch. The ivl_lpm_q output and + * single ivl_lpm_data input are the same width, ivl_lpm_width. This * device carries a vector like other LPM devices. * * - Memory port (IVL_LPM_RAM) (deprecated in favor of IVL_LPM_ARRAY) @@ -1438,14 +1438,14 @@ extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net); /* IVL_LPM_ADD IVL_LPM_CONCAT IVL_LPM_FF IVL_LPM_PART IVL_LPM_MULT IVL_LPM_MUX IVL_LPM_POW IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB - IVL_LPM_UFUNC IVL_LPM_SUBSTITUTE IVL_LPM_LATCH*/ + IVL_LPM_UFUNC IVL_LPM_SUBSTITUTE IVL_LPM_LATCH */ extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx); /* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_POW IVL_LPM_SUB IVL_LPM_CMP_EQ IVL_LPM_CMP_EEQ IVL_LPM_CMP_EQX IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE */ extern ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx); /* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_PART IVL_LPM_POW IVL_LPM_SUB IVL_LPM_UFUNC IVL_LPM_CMP_EEQ IVL_LPM_CMP_EQX - IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE IVL_LPM_SUBSTITUTE IVL_LPM_LATCH*/ + IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE IVL_LPM_SUBSTITUTE IVL_LPM_LATCH */ extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net); extern ivl_drive_t ivl_lpm_drive0(ivl_lpm_t net); extern ivl_drive_t ivl_lpm_drive1(ivl_lpm_t net); diff --git a/t-dll-api.cc b/t-dll-api.cc index b739bd79b..9fe60d365 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -1149,7 +1149,7 @@ extern "C" ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net) case IVL_LPM_FF: return net->u_.ff.we; case IVL_LPM_LATCH: - return net->u_.latch.we; + return net->u_.latch.e; default: assert(0); return 0; diff --git a/t-dll.cc b/t-dll.cc index 52bb17581..626f3a74f 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -2066,17 +2066,11 @@ void dll_target::lpm_latch(const NetLatch*net) const Nexus*nex; - /* If there is a clock enable, then connect it up to the FF - device. */ - if (net->pin_Enable().is_linked()) { - nex = net->pin_Enable().nexus(); - assert(nex->t_cookie()); - obj->u_.latch.we = nex->t_cookie(); - assert(obj->u_.latch.we); - nexus_lpm_add(obj->u_.latch.we, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); - } else { - obj->u_.latch.we = 0; - } + nex = net->pin_Enable().nexus(); + assert(nex->t_cookie()); + obj->u_.latch.e = nex->t_cookie(); + assert(obj->u_.latch.e); + nexus_lpm_add(obj->u_.latch.e, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); nex = net->pin_Q().nexus(); assert(nex->t_cookie()); diff --git a/t-dll.h b/t-dll.h index 7baa9263c..b85bb2d43 100644 --- a/t-dll.h +++ b/t-dll.h @@ -1,7 +1,7 @@ #ifndef IVL_t_dll_H #define IVL_t_dll_H /* - * Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -390,8 +390,7 @@ struct ivl_lpm_s { ivl_expr_t sset_value; } ff; struct ivl_lpm_latch_s { - unsigned negedge_flag :1; - ivl_nexus_t we; + ivl_nexus_t e; union { ivl_nexus_t*pins; ivl_nexus_t pin; From b47482880cf5a560040c3d39c5fe89b2907b21dd Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 12 Mar 2016 09:03:42 +0000 Subject: [PATCH 09/22] Added support for LPM latches to stub target. --- tgt-stub/stub.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index eeab84e4c..ea71358be 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -559,6 +559,39 @@ static void show_lpm_ff(ivl_lpm_t net) } +static void show_lpm_latch(ivl_lpm_t net) +{ + ivl_nexus_t nex; + unsigned width = ivl_lpm_width(net); + + fprintf(out, " LPM_LATCH %s: \n", + ivl_lpm_basename(net), width); + + nex = ivl_lpm_enable(net); + fprintf(out, " E: %p\n", nex); + if (width_of_nexus(nex) != 1) { + fprintf(out, " E: ERROR: Nexus width is %u\n", + width_of_nexus(nex)); + stub_errors += 1; + } + + nex = ivl_lpm_data(net,0); + fprintf(out, " D: %p\n", nex); + if (width_of_nexus(nex) != width) { + fprintf(out, " D: ERROR: Nexus width is %u\n", + width_of_nexus(nex)); + stub_errors += 1; + } + + nex = ivl_lpm_q(net); + fprintf(out, " Q: %p\n", nex); + if (width_of_nexus(nex) != width) { + fprintf(out, " Q: ERROR: Nexus width is %u\n", + width_of_nexus(nex)); + stub_errors += 1; + } +} + static void show_lpm_mod(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); @@ -1017,6 +1050,10 @@ static void show_lpm(ivl_lpm_t net) show_lpm_ff(net); break; + case IVL_LPM_LATCH: + show_lpm_latch(net); + break; + case IVL_LPM_CMP_GE: show_lpm_cmp_ge(net); break; From 99afea6946cfa648aa2d4b04cd282a9676c0b49f Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 12 Mar 2016 09:04:51 +0000 Subject: [PATCH 10/22] Added support for LPM latches to vvp. --- vvp/Makefile.in | 2 +- vvp/compile.h | 6 +++- vvp/latch.cc | 88 +++++++++++++++++++++++++++++++++++++++++++++++++ vvp/latch.h | 45 +++++++++++++++++++++++++ vvp/lexor.lex | 3 +- vvp/parse.y | 9 +++-- 6 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 vvp/latch.cc create mode 100644 vvp/latch.h diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 35750f69d..faae3736a 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -72,7 +72,7 @@ V = vpi_modules.o vpi_callback.o vpi_cobject.o vpi_const.o vpi_darray.o \ vpip_to_dec.o vpip_format.o vvp_vpi.o O = main.o parse.o parse_misc.o lexor.o arith.o array_common.o array.o bufif.o compile.o \ - concat.o dff.o class_type.o enum_type.o extend.o file_line.o npmos.o part.o \ + concat.o dff.o class_type.o enum_type.o extend.o file_line.o latch.o npmos.o part.o \ permaheap.o reduce.o resolv.o \ sfunc.o stop.o \ substitute.o \ diff --git a/vvp/compile.h b/vvp/compile.h index 627eff35d..eda571e5a 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -1,7 +1,7 @@ #ifndef IVL_compile_H #define IVL_compile_H /* - * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -225,6 +225,10 @@ extern void compile_dff_aset(char*label, unsigned width, bool negedge, struct symb_s arg_a, char*asc_value); +extern void compile_latch(char*label, unsigned width, + struct symb_s arg_d, + struct symb_s arg_e); + extern void compile_enum2_type(char*label, long width, bool signed_flag, std::list*names); extern void compile_enum4_type(char*label, long width, bool signed_flag, diff --git a/vvp/latch.cc b/vvp/latch.cc new file mode 100644 index 000000000..acc8a4ece --- /dev/null +++ b/vvp/latch.cc @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2016 Martin Whitaker (icarus@martin-whitaker.me.uk) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "compile.h" +# include "schedule.h" +# include "latch.h" +# include +# include +# include +# include +# include + +/* We need to ensure an initial output value is propagated. This is + achieved by scheduling an initial value to be sent to port 3. Any + value received on port 3 will propagate an initial value of 'bx. */ + +vvp_latch::vvp_latch(unsigned width) +: en_(BIT4_X), d_(width, BIT4_X) +{ +} + +vvp_latch::~vvp_latch() +{ +} + +void vvp_latch::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, + vvp_context_t) +{ + vvp_bit4_t tmp; + + switch (port.port()) { + + case 0: // D + d_ = bit; + if (en_ == BIT4_1) + schedule_propagate_vector(port.ptr(), 0, d_); + break; + + case 1: // EN + assert(bit.size() == 1); + tmp = en_; + en_ = bit.value(0); + if (en_ == BIT4_1 && tmp != BIT4_1) + schedule_propagate_vector(port.ptr(), 0, d_); + break; + + case 2: + assert(0); + break; + + case 3: + port.ptr()->send_vec4(vvp_vector4_t(d_.size(), BIT4_X), 0); + break; + } +} + +void compile_latch(char*label, unsigned width, + struct symb_s arg_d, + struct symb_s arg_e) +{ + vvp_net_t*ptr = new vvp_net_t; + vvp_latch*fun = new vvp_latch(width); + + ptr->fun = fun; + define_functor_symbol(label, ptr); + free(label); + input_connect(ptr, 0, arg_d.text); + input_connect(ptr, 1, arg_e.text); + + vvp_vector4_t init_val = vvp_vector4_t(1, BIT4_1); + schedule_init_vector(vvp_net_ptr_t(ptr,3), init_val); +} diff --git a/vvp/latch.h b/vvp/latch.h new file mode 100644 index 000000000..daf396061 --- /dev/null +++ b/vvp/latch.h @@ -0,0 +1,45 @@ +#ifndef IVL_latch_H +#define IVL_latch_H +/* + * Copyright (c) 2016 Martin Whitaker (icarus@martin-whitaker.me.uk) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "vvp_net.h" + +/* + * The vvp_latch implements an arbitrary width D-type transparent latch. + * The latch enable is a single bit. Ports are: + * + * port-0: D input + * port-1: EN input + */ +class vvp_latch : public vvp_net_fun_t { + + public: + explicit vvp_latch(unsigned width); + ~vvp_latch(); + + void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, + vvp_context_t); + + private: + vvp_bit4_t en_; + vvp_vector4_t d_; +}; + +#endif /* IVL_latch_H */ diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 87f927623..d7e7d162f 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -4,7 +4,7 @@ %{ /* - * Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -168,6 +168,7 @@ static char* strdupnew(char const *str) ".functor" { return K_FUNCTOR; } ".import" { return K_IMPORT; } ".island" { return K_ISLAND; } +".latch" { return K_LATCH; } ".modpath" { return K_MODPATH; } ".net" { return K_NET; } ".net/2s" { return K_NET_2S; } diff --git a/vvp/parse.y b/vvp/parse.y index 832c53c98..eb207a0a7 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -86,7 +86,7 @@ static struct __vpiModPath*modpath_dst = 0; %token K_CONCAT K_CONCAT8 K_DEBUG K_DELAY K_DFF_N K_DFF_N_ACLR %token K_DFF_N_ASET K_DFF_P K_DFF_P_ACLR K_DFF_P_ASET %token K_ENUM2 K_ENUM2_S K_ENUM4 K_ENUM4_S K_EVENT K_EVENT_OR -%token K_EXPORT K_EXTEND_S K_FUNCTOR K_IMPORT K_ISLAND K_MODPATH +%token K_EXPORT K_EXTEND_S K_FUNCTOR K_IMPORT K_ISLAND K_LATCH K_MODPATH %token K_NET K_NET_S K_NET_R K_NET_2S K_NET_2U %token K_NET8 K_NET8_2S K_NET8_2U K_NET8_S %token K_PARAM_STR K_PARAM_L K_PARAM_REAL K_PART K_PART_PV @@ -522,6 +522,11 @@ statement | T_LABEL K_DFF_P_ASET T_NUMBER symbol ',' symbol ',' symbol ',' symbol ',' T_SYMBOL ';' { compile_dff_aset($1, $3, false, $4, $6, $8, $10, $12); } + /* LATCH nodes have an output and take 2 inputs. */ + + | T_LABEL K_LATCH T_NUMBER symbol ',' symbol ';' + { compile_latch($1, $3, $4, $6); } + /* The various reduction operator nodes take a single input. */ | T_LABEL K_REDUCE_AND symbol ';' From 89333fa3a581c4756d94028c99bcfafe0f4a7b9c Mon Sep 17 00:00:00 2001 From: Johann Klammer Date: Fri, 11 Mar 2016 21:45:51 +0100 Subject: [PATCH 11/22] add latch primitive for vlog95 --- tgt-vlog95/logic_lpm.c | 63 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 6f8e74b84..6cbd58724 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -364,6 +364,7 @@ static ivl_nexus_t get_lpm_output(ivl_scope_t scope, ivl_lpm_t lpm) case IVL_LPM_CONCATZ: case IVL_LPM_DIVIDE: case IVL_LPM_FF: + case IVL_LPM_LATCH: case IVL_LPM_MOD: case IVL_LPM_MULT: case IVL_LPM_MUX: @@ -1437,8 +1438,27 @@ static void emit_negedge_dff_prim(void) fprintf(vlog_out, "endprimitive\n"); } +static void emit_latch_prim(void) +{ + fprintf(vlog_out, "\n"); + fprintf(vlog_out, "/* Icarus generated UDP to represent a synthesized " + "LATCH. */\n"); + fprintf(vlog_out, "primitive IVL_LATCH " + "(q, en, d);\n"); + fprintf(vlog_out, "%*coutput q;\n", indent_incr, ' '); + fprintf(vlog_out, "%*cinput en, d;\n", indent_incr, ' '); + fprintf(vlog_out, "%*creg q;\n", indent_incr, ' '); + fprintf(vlog_out, "%*ctable\n", indent_incr, ' '); + fprintf(vlog_out, "%*c 1 0 : ? : 0 ;\n", 2*indent_incr, ' '); + fprintf(vlog_out, "%*c 1 1 : ? : 1 ;\n", 2*indent_incr, ' '); + fprintf(vlog_out, "%*c 0 ? : ? : - ;\n", 2*indent_incr, ' '); + fprintf(vlog_out, "%*cendtable\n", indent_incr, ' '); + fprintf(vlog_out, "endprimitive\n"); +} + static unsigned need_posedge_dff_prim = 0; static unsigned need_negedge_dff_prim = 0; +static unsigned need_latch_prim = 0; /* * Synthesis creates a D-FF LPM object. To allow this to be simulated as @@ -1456,7 +1476,7 @@ void emit_icarus_generated_udps() { /* Emit the copyright information and LGPL note and then emit any * needed primitives. */ - if (need_posedge_dff_prim || need_negedge_dff_prim) { + if (need_posedge_dff_prim || need_negedge_dff_prim || need_latch_prim) { fprintf(vlog_out, "\n" "/*\n" @@ -1484,6 +1504,7 @@ void emit_icarus_generated_udps() } if (need_posedge_dff_prim) emit_posedge_dff_prim(); if (need_negedge_dff_prim) emit_negedge_dff_prim(); + if (need_latch_prim) emit_latch_prim(); } static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) @@ -1606,6 +1627,41 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) need_posedge_dff_prim = 1; } +static void emit_lpm_latch(ivl_scope_t scope, ivl_lpm_t lpm) +{ + ivl_nexus_t nex; + unsigned emitted; + + fprintf(vlog_out, "%*c", indent, ' '); + fprintf(vlog_out, "IVL_LATCH"); + emit_lpm_strength(lpm); + /* The lpm LATCH does not support any delays. */ + /* The LATCH name is a temporary so we don't bother to print it unless + * we have a range. Then we need to use a made up name. */ + if (ivl_lpm_width(lpm) > 1) { + fprintf(vlog_out, " synth_%p [%u:0]", lpm, ivl_lpm_width(lpm)-1U); + } + fprintf(vlog_out, " ("); + /* Emit the q pin. */ + emit_name_of_nexus(scope, ivl_lpm_q(lpm), 0); + fprintf(vlog_out, ", "); + /* Emit the enable pin expression(s) if needed. */ + emitted = 0; + nex = ivl_lpm_enable(lpm); + if (nex) { + emit_nexus_as_ca(scope, nex, 0, 0); + emitted = 1; + } + if (!emitted) fprintf(vlog_out, "1'b1"); + fprintf(vlog_out, ", "); + /* Emit the data pin expression(s). */ + nex = ivl_lpm_data(lpm, 0); + assert (nex); + emit_nexus_as_ca(scope, nex, 0, 0); + fprintf(vlog_out, ");\n"); + need_latch_prim = 1; +} + static ivl_signal_t get_output_from_nexus(ivl_scope_t scope, ivl_nexus_t nex, int64_t*array_idx) { @@ -1729,6 +1785,10 @@ void emit_lpm(ivl_scope_t scope, ivl_lpm_t lpm) emit_lpm_ff(scope, lpm); return; } + if (type == IVL_LPM_LATCH) { + emit_lpm_latch(scope, lpm); + return; + } // HERE: Look for a select passed to a pull device (pr2019553). /* Skip assignments to a module instantiation input. */ if (output_is_module_instantiation_input(scope, output)) return; @@ -2199,6 +2259,7 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) case IVL_LPM_CMP_NEE: fprintf(stderr, "nee"); break; case IVL_LPM_DIVIDE: fprintf(stderr, "divide"); break; case IVL_LPM_FF: fprintf(stderr, "dff"); break; + case IVL_LPM_LATCH: fprintf(stderr, "latch"); break; case IVL_LPM_MOD: fprintf(stderr, "mod"); break; case IVL_LPM_MULT: fprintf(stderr, "mult"); break; case IVL_LPM_MUX: fprintf(stderr, "mux"); break; From c0542af6bfec1099f14d20bb0d9d1c6e9aaba930 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 12 Mar 2016 09:10:58 +0000 Subject: [PATCH 12/22] Updated copyright dates following previous patch. --- tgt-vlog95/logic_lpm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 6cbd58724..c0202b5bb 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2015 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2016 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1483,7 +1483,7 @@ void emit_icarus_generated_udps() " * This is the copyright information for the following primitive(s)\n" " * (library elements).\n" " *\n" -" * Copyright (C) 2011-2015 Cary R. (cygcary@yahoo.com)\n" +" * Copyright (C) 2011-2016 Cary R. (cygcary@yahoo.com)\n" " *\n" " * This library is free software; you can redistribute it and/or\n" " * modify it under the terms of the GNU Lesser General Public\n" @@ -1659,7 +1659,7 @@ static void emit_lpm_latch(ivl_scope_t scope, ivl_lpm_t lpm) assert (nex); emit_nexus_as_ca(scope, nex, 0, 0); fprintf(vlog_out, ");\n"); - need_latch_prim = 1; + need_latch_prim = 1; } static ivl_signal_t get_output_from_nexus(ivl_scope_t scope, ivl_nexus_t nex, From 22bc798696236cae38bae2ec829160d820a72977 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 12 Mar 2016 11:21:23 +0000 Subject: [PATCH 13/22] Added warning when a latch enable is a synthesised expression. --- synth2.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/synth2.cc b/synth2.cc index aab79ca88..91086870c 100644 --- a/synth2.cc +++ b/synth2.cc @@ -1594,11 +1594,18 @@ bool NetProcTop::synth_async(Design*des) << nex_set[idx].lnk.nexus()->pick_any_net()->name() << "'." << endl; + if (enables.pin(idx).nexus()->pick_any_net()->local_flag()) { + cerr << get_fileline() << ": warning: The latch " + "enable is connected to a synthesized " + "expression. The latch may be sensitive " + "to glitches." << endl; + } + if (debug_synth2) { cerr << get_fileline() << ": debug: " - << "Top level making a " - << nex_set[idx].wid << "-wide " - << "NetLatch device." << endl; + << "Top level making a " + << nex_set[idx].wid << "-wide " + << "NetLatch device." << endl; } NetLatch*latch = new NetLatch(scope(), scope()->local_symbol(), From b4d438ea9f5cfe07d29dd8a0dc810136e3c21408 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 12 Mar 2016 11:39:32 +0000 Subject: [PATCH 14/22] Fixed bug in vlog95 dff output when using asynchronous set. --- tgt-vlog95/logic_lpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index c0202b5bb..24b1371b7 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -1606,7 +1606,7 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) emitted = 1; } nex = ivl_lpm_async_set(lpm); - if (aset_bits && (aset_bits[0] != '0')) nex = 0; + if (!aset_bits || (aset_bits[0] != '0')) nex = 0; if (nex) { if (emitted) fprintf(vlog_out, " | "); emit_nexus_as_ca(scope, nex, 0, 0); From 708a7d06211ed08ded794b20a6fc9e0b7d01e0e3 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 12 Mar 2016 12:02:22 +0000 Subject: [PATCH 15/22] Move some redundant initialisation of bitmasks in synthesis. These are made obsolete by an earlier bugfix. --- synth2.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/synth2.cc b/synth2.cc index 91086870c..b42fc440d 100644 --- a/synth2.cc +++ b/synth2.cc @@ -942,10 +942,6 @@ bool NetCase::synth_async(Design*des, NetScope*scope, ena_mux[mdx] = new NetMux(scope, scope->local_symbol(), 1, mux_size, sel_need); - // Initialise the bitmasks appropriately for calculating - // the intersection of the individual clause bitmasks. - bitmasks[mdx] = mask_t (mux_width[mdx], true); - // Assume a full case to start with. We'll check this as // we synthesise each clause. full_case[mdx] = true; @@ -1311,7 +1307,6 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, continue; } - bitmasks[idx] = mask_t (nex_map[idx].wid, true); merge_parallel_masks(bitmasks[idx], a_masks[idx]); merge_parallel_masks(bitmasks[idx], b_masks[idx]); From 9d487c69517b152d645ad6af8d286cadb36a1c28 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 9 Mar 2016 11:30:11 +0100 Subject: [PATCH 16/22] vhdlpp: Fixed a few shadow warnings. --- vhdlpp/expression.cc | 4 ++-- vhdlpp/expression.h | 2 +- vhdlpp/sequential.cc | 4 ++-- vhdlpp/sequential.h | 2 +- vhdlpp/subprogram.h | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index d52fa4d11..9efe60931 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -875,8 +875,8 @@ double ExpTime::to_fs() const return val; } -ExpRange::ExpRange(Expression*left, Expression*right, range_dir_t direction) -: left_(left), right_(right), direction_(direction), range_expr_(false), +ExpRange::ExpRange(Expression*left_idx, Expression*right_idx, range_dir_t dir) +: left_(left_idx), right_(right_idx), direction_(dir), range_expr_(false), range_base_(NULL) { } diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index b1b6ae244..65e1934bd 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -1020,7 +1020,7 @@ class ExpRange : public Expression { typedef enum { DOWNTO, TO, AUTO } range_dir_t; // Regular range - ExpRange(Expression*left, Expression*right, range_dir_t direction); + ExpRange(Expression*left_idx, Expression*right_idx, range_dir_t dir); // 'range/'reverse range attribute ExpRange(ExpName*base, bool reverse_range); ~ExpRange(); diff --git a/vhdlpp/sequential.cc b/vhdlpp/sequential.cc index 3e572fce0..9f83c1372 100644 --- a/vhdlpp/sequential.cc +++ b/vhdlpp/sequential.cc @@ -304,7 +304,7 @@ WaitForStmt::WaitForStmt(Expression*delay) { } -WaitStmt::WaitStmt(wait_type_t type, Expression*expr) -: type_(type), expr_(expr) +WaitStmt::WaitStmt(wait_type_t typ, Expression*expr) +: type_(typ), expr_(expr) { } diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index 13a3f5947..b0fa8ac07 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -334,7 +334,7 @@ class WaitForStmt : public SequentialStmt { class WaitStmt : public SequentialStmt { public: typedef enum { ON, UNTIL, FINAL } wait_type_t; - WaitStmt(wait_type_t type, Expression*expression); + WaitStmt(wait_type_t typ, Expression*expression); void dump(ostream&out, int indent) const; int elaborate(Entity*ent, ScopeBase*scope); diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 08473239e..82ba804d1 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -146,9 +146,9 @@ class SubprogramHeader : public LineInfo { class SubprogramStdHeader : public SubprogramHeader { public: - SubprogramStdHeader(perm_string name, std::list*ports, + SubprogramStdHeader(perm_string nam, std::list*ports, const VType*return_type) : - SubprogramHeader(name, ports, return_type) {} + SubprogramHeader(nam, ports, return_type) {} virtual ~SubprogramStdHeader() {}; bool is_std() const { return true; } From dc189fec8cb28fa34d07904e37cb89f5cc6e5ee8 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 12 Mar 2016 12:14:03 +0000 Subject: [PATCH 17/22] Added new vvp latch statement to README file. --- vvp/README.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/vvp/README.txt b/vvp/README.txt index a6c014bba..e7a381062 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -195,7 +195,7 @@ combining up to four inputs down to one output. B | * * 1 -DFF STATEMENTS: +DFF AND LATCH STATEMENTS: The Verilog language itself does not have a DFF primitive, but post synthesis readily creates DFF devices that are best simulated with a @@ -219,6 +219,15 @@ rising edge causes the device to clear/set, forces the output to propagate, and disables the clock until the aynchronous input is deasserted. Thus, they implement DFF with asynchronous clr or set. +Similarly, synthesis creates D-type latches, so there is the LATCH +statement to support this: + +