2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 #include "kernel/yosys.h"
24 #include "kernel/ffinit.h"
28 struct MemRd
: RTLIL::AttrObject
{
32 bool clk_enable
, clk_polarity
, ce_over_srst
;
33 Const arst_value
, srst_value
, init_value
;
34 // One bit for every write port, true iff simultanous read on this
35 // port and write on the other port will bypass the written data
36 // to this port's output (default behavior is to read old value).
37 // Can only be set for write ports that have the same clock domain.
38 std::vector
<bool> transparency_mask
;
39 // One bit for every write port, true iff simultanous read on this
40 // port and write on the other port will return an all-X (don't care)
41 // value. Mutually exclusive with transparency_mask.
42 // Can only be set for write ports that have the same clock domain.
43 // For optimization purposes, this will also be set if we can
44 // determine that the two ports can never be active simultanously
45 // (making the above vacuously true).
46 std::vector
<bool> collision_x_mask
;
47 SigSpec clk
, en
, arst
, srst
, addr
, data
;
49 MemRd() : removed(false), cell(nullptr), wide_log2(0), clk_enable(false), clk_polarity(true), ce_over_srst(false), clk(State::Sx
), en(State::S1
), arst(State::S0
), srst(State::S0
) {}
51 // Returns the address of given subword index accessed by this port.
52 SigSpec
sub_addr(int sub
) {
54 for (int i
= 0; i
< wide_log2
; i
++)
55 res
[i
] = State(sub
>> i
& 1);
60 struct MemWr
: RTLIL::AttrObject
{
64 bool clk_enable
, clk_polarity
;
65 std::vector
<bool> priority_mask
;
66 SigSpec clk
, en
, addr
, data
;
68 MemWr() : removed(false), cell(nullptr) {}
70 // Returns the address of given subword index accessed by this port.
71 SigSpec
sub_addr(int sub
) {
73 for (int i
= 0; i
< wide_log2
; i
++)
74 res
[i
] = State(sub
>> i
& 1);
78 std::pair
<SigSpec
, std::vector
<int>> compress_en();
79 SigSpec
decompress_en(const std::vector
<int> &swizzle
, SigSpec sig
);
82 struct MemInit
: RTLIL::AttrObject
{
88 MemInit() : removed(false), cell(nullptr) {}
91 struct Mem
: RTLIL::AttrObject
{
97 int width
, start_offset
, size
;
98 std::vector
<MemInit
> inits
;
99 std::vector
<MemRd
> rd_ports
;
100 std::vector
<MemWr
> wr_ports
;
102 // Removes this memory from the module. The data in helper structures
103 // is unaffected except for the cell/mem fields.
106 // Commits all changes in helper structures into the module — ports and
107 // inits marked as removed are actually removed, new ports/inits create
108 // new cells, modified port/inits are commited into their existing
109 // cells. Note that this reindexes the ports and inits array (actually
110 // removing the ports/inits marked as removed).
113 // Marks all inits as removed.
116 // Coalesces inits: whenever two inits have overlapping or touching
117 // address ranges, they are combined into one, with the higher-priority
118 // one's data overwriting the other. Running this results in
119 // an inits list equivalent to the original, in which all entries
120 // cover disjoint (and non-touching) address ranges, and all enable
122 void coalesce_inits();
124 // Checks consistency of this memory and all its ports/inits, using
128 // Gathers all initialization data into a single big const covering
129 // the whole memory. For all non-initialized bits, Sx will be returned.
130 Const
get_init_data() const;
132 // Constructs and returns the helper structures for all memories
134 static std::vector
<Mem
> get_all_memories(Module
*module
);
136 // Constructs and returns the helper structures for all selected
137 // memories in a module.
138 static std::vector
<Mem
> get_selected_memories(Module
*module
);
140 // Converts a synchronous read port into an asynchronous one by
141 // extracting the data (or, in some rare cases, address) register
142 // into a separate cell, together with any soft-transparency
143 // logic necessary to preserve its semantics. Returns the created
144 // register cell, if any. Note that in some rare cases this function
145 // may succeed and perform a conversion without creating a new
146 // register — a nullptr result doesn't imply nothing was done.
147 Cell
*extract_rdff(int idx
, FfInitVals
*initvals
);
149 // Splits all wide ports in this memory into equivalent narrow ones.
150 // This function performs no modifications at all to the actual
151 // netlist unless and until emit() is called.
154 // If write port idx2 currently has priority over write port idx1,
155 // inserts extra logic on idx1's enable signal to disable writes
156 // when idx2 is writing to the same address, then removes the priority
157 // from the priority mask. If there is a memory port that is
158 // transparent with idx1, but not with idx2, that port is converted
159 // to use soft transparency logic.
160 void emulate_priority(int idx1
, int idx2
, FfInitVals
*initvals
);
162 // Creates soft-transparency logic on read port ridx, bypassing the
163 // data from write port widx. Should only be called when ridx is
164 // transparent wrt widx in the first place. Once we're done, the
165 // transparency_mask bit will be cleared, and the collision_x_mask
166 // bit will be set instead (since whatever value is read will be
167 // replaced by the soft transparency logic).
168 void emulate_transparency(int widx
, int ridx
, FfInitVals
*initvals
);
170 // Prepares for merging write port idx2 into idx1 (where idx1 < idx2).
171 // Specifically, takes care of priority masks: any priority relations
172 // that idx2 had are replicated onto idx1, unless they conflict with
173 // priorities already present on idx1, in which case emulate_priority
174 // is called. Likewise, ensures transparency and undefined collision
175 // masks of all read ports have the same values for both ports,
176 // calling emulate_transparency if necessary.
177 void prepare_wr_merge(int idx1
, int idx2
, FfInitVals
*initvals
);
179 // Prepares for merging read port idx2 into idx1.
180 // Specifically, makes sure the transparency and undefined collision
181 // masks of both ports are equal, by changing undefined behavior
182 // of one port to the other's defined behavior, or by calling
183 // emulate_transparency if necessary.
184 void prepare_rd_merge(int idx1
, int idx2
, FfInitVals
*initvals
);
186 // Prepares the memory for widening a port to a given width. This
187 // involves ensuring that start_offset and size are aligned to the
189 void widen_prep(int wide_log2
);
191 // Widens a write port up to a given width. The newly port is
192 // equivalent to the original, made by replicating enable/data bits
193 // and masking enable bits with decoders on the low part of the
195 void widen_wr_port(int idx
, int wide_log2
);
197 // Emulates a sync read port's enable functionality in soft logic,
198 // changing the actual read port's enable to be always-on.
199 void emulate_rden(int idx
, FfInitVals
*initvals
);
201 // Emulates a sync read port's initial/reset value functionality in
202 // soft logic, removing it from the actual read port.
203 void emulate_reset(int idx
, bool emu_init
, bool emu_arst
, bool emu_srst
, FfInitVals
*initvals
);
205 // Given a read port with ce_over_srst set, converts it to a port
206 // with ce_over_srst unset without changing its behavior by adding
208 void emulate_rd_ce_over_srst(int idx
);
210 // Given a read port with ce_over_srst unset, converts it to a port
211 // with ce_over_srst set without changing its behavior by adding
213 void emulate_rd_srst_over_ce(int idx
);
215 // Returns true iff emulate_read_first makes sense to call.
216 bool emulate_read_first_ok();
218 // Emulates all read-first read-write port relationships in terms of
219 // all-transparent ports, by delaying all write ports by one cycle.
220 // This can only be used when all read ports and all write ports are
221 // in the same clock domain.
222 void emulate_read_first(FfInitVals
*initvals
);
224 Mem(Module
*module
, IdString memid
, int width
, int start_offset
, int size
) : module(module
), memid(memid
), packed(false), mem(nullptr), cell(nullptr), width(width
), start_offset(start_offset
), size(size
) {}