diff options
Diffstat (limited to 'kernel/ff.h')
-rw-r--r-- | kernel/ff.h | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/kernel/ff.h b/kernel/ff.h new file mode 100644 index 000000000..5a629d5dd --- /dev/null +++ b/kernel/ff.h @@ -0,0 +1,216 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef FF_H +#define FF_H + +#include "kernel/yosys.h" +#include "kernel/ffinit.h" + +YOSYS_NAMESPACE_BEGIN + +// Describes a flip-flop or a latch. +// +// If has_gclk, this is a formal verification FF with implicit global clock: +// Q is simply previous cycle's D. +// +// Otherwise, the FF/latch can have any number of features selected by has_* +// attributes that determine Q's value (in order of decreasing priority): +// +// - on start, register is initialized to val_init +// - if has_sr is present: +// - sig_clr is per-bit async clear, and sets the corresponding bit to 0 +// if active +// - sig_set is per-bit async set, and sets the corresponding bit to 1 +// if active +// - if has_arst is present: +// - sig_arst is whole-reg async reset, and sets the whole register to val_arst +// - if has_aload is present: +// - sig_aload is whole-reg async load (aka latch gate enable), and sets the whole +// register to sig_ad +// - if has_clk is present, and we're currently on a clock edge: +// - if has_ce is present and ce_over_srst is true: +// - ignore clock edge (don't change value) unless sig_ce is active +// - if has_srst is present: +// - sig_srst is whole-reg sync reset and sets the register to val_srst +// - if has_ce is present and ce_over_srst is false: +// - ignore clock edge (don't change value) unless sig_ce is active +// - set whole reg to sig_d +// - if nothing of the above applies, the reg value remains unchanged +// +// Since the yosys FF cell library isn't fully generic, not all combinations +// of the features above can be supported: +// +// - only one of has_srst, has_arst, has_sr can be used +// - if has_clk is used together with has_aload, then has_srst, has_arst, +// has_sr cannot be used +// +// The valid feature combinations are thus: +// +// - has_clk + optional has_ce [dff/dffe] +// - has_clk + optional has_ce + has_arst [adff/adffe] +// - has_clk + optional has_ce + has_aload [aldff/aldffe] +// - has_clk + optional has_ce + has_sr [dffsr/dffsre] +// - has_clk + optional has_ce + has_srst [sdff/sdffe/sdffce] +// - has_aload [dlatch] +// - has_aload + has_arst [adlatch] +// - has_aload + has_sr [dlatchsr] +// - has_sr [sr] +// - has_arst [does not correspond to a native cell, represented as dlatch with const D input] +// - empty set [not a cell — will be emitted as a simple direct connection] + +struct FfData { + Module *module; + FfInitVals *initvals; + Cell *cell; + IdString name; + // The FF output. + SigSpec sig_q; + // The sync data input, present if has_clk or has_gclk. + SigSpec sig_d; + // The async data input, present if has_aload. + SigSpec sig_ad; + // The sync clock, present if has_clk. + SigSpec sig_clk; + // The clock enable, present if has_ce. + SigSpec sig_ce; + // The async load enable, present if has_aload. + SigSpec sig_aload; + // The async reset, preset if has_arst. + SigSpec sig_arst; + // The sync reset, preset if has_srst. + SigSpec sig_srst; + // The async clear (per-lane), present if has_sr. + SigSpec sig_clr; + // The async set (per-lane), present if has_sr. + SigSpec sig_set; + // True if this is a clocked (edge-sensitive) flip-flop. + bool has_clk; + // True if this is a $ff, exclusive with every other has_*. + bool has_gclk; + // True if this FF has a clock enable. Depends on has_clk. + bool has_ce; + // True if this FF has async load function — this includes D latches. + // If this and has_clk are both set, has_arst and has_sr cannot be set. + bool has_aload; + // True if this FF has sync set/reset. Depends on has_clk, exclusive + // with has_arst, has_sr, has_aload. + bool has_srst; + // True if this FF has async set/reset. Exclusive with has_srst, + // has_sr. If this and has_clk are both set, has_aload cannot be set. + bool has_arst; + // True if this FF has per-bit async set + clear. Exclusive with + // has_srst, has_arst. If this and has_clk are both set, has_aload + // cannot be set. + bool has_sr; + // If has_ce and has_srst are both set, determines their relative + // priorities: if true, inactive ce disables srst; if false, srst + // operates independent of ce. + bool ce_over_srst; + // True if this FF is a fine cell, false if it is a coarse cell. + // If true, width must be 1. + bool is_fine; + // Polarities, corresponding to sig_*. True means active-high, false + // means active-low. + bool pol_clk; + bool pol_ce; + bool pol_aload; + bool pol_arst; + bool pol_srst; + bool pol_clr; + bool pol_set; + // The value loaded by sig_arst. + Const val_arst; + // The value loaded by sig_srst. + Const val_srst; + // The initial value at power-up. + Const val_init; + // The FF data width in bits. + int width; + dict<IdString, Const> attributes; + + FfData(Module *module = nullptr, FfInitVals *initvals = nullptr, IdString name = IdString()) : module(module), initvals(initvals), cell(nullptr), name(name) { + width = 0; + has_clk = false; + has_gclk = false; + has_ce = false; + has_aload = false; + has_srst = false; + has_arst = false; + has_sr = false; + ce_over_srst = false; + is_fine = false; + pol_clk = false; + pol_aload = false; + pol_ce = false; + pol_arst = false; + pol_srst = false; + pol_clr = false; + pol_set = false; + } + + FfData(FfInitVals *initvals, Cell *cell_); + + // Returns a FF identical to this one, but only keeping bit indices from the argument. + FfData slice(const std::vector<int> &bits); + + void add_dummy_ce(); + void add_dummy_srst(); + void add_dummy_arst(); + void add_dummy_aload(); + void add_dummy_sr(); + void add_dummy_clk(); + + void arst_to_aload(); + void arst_to_sr(); + + void aload_to_sr(); + + // Given a FF with both has_ce and has_srst, sets ce_over_srst to the given value and + // fixes up control signals appropriately to preserve semantics. + void convert_ce_over_srst(bool val); + + void unmap_ce(); + void unmap_srst(); + + void unmap_ce_srst() { + unmap_ce(); + unmap_srst(); + } + + Cell *emit(); + + // Removes init attribute from the Q output, but keeps val_init unchanged. + // It will be automatically reattached on emit. Use this before changing sig_q. + void remove_init() { + if (initvals) + initvals->remove_init(sig_q); + } + + void remove(); + + // Flip the sense of the given bit slices of the FF: insert inverters on data + // inputs and output, flip the corresponding init/reset bits, swap clr/set + // inputs with proper priority fix. + void flip_bits(const pool<int> &bits); +}; + +YOSYS_NAMESPACE_END + +#endif |