yosys/kernel/ff.h

202 lines
6.6 KiB
C++

/*
* 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 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