mirror of https://github.com/YosysHQ/yosys.git
Add memory_libmap pass.
This commit is contained in:
parent
9450f308f0
commit
7c5dba8b77
|
@ -29,10 +29,12 @@ X(A_SIGNED)
|
||||||
X(A_WIDTH)
|
X(A_WIDTH)
|
||||||
X(B)
|
X(B)
|
||||||
X(BI)
|
X(BI)
|
||||||
|
X(BITS_USED)
|
||||||
X(blackbox)
|
X(blackbox)
|
||||||
X(B_SIGNED)
|
X(B_SIGNED)
|
||||||
X(bugpoint_keep)
|
X(bugpoint_keep)
|
||||||
X(B_WIDTH)
|
X(B_WIDTH)
|
||||||
|
X(BYTE)
|
||||||
X(C)
|
X(C)
|
||||||
X(cells_not_processed)
|
X(cells_not_processed)
|
||||||
X(CE_OVER_SRST)
|
X(CE_OVER_SRST)
|
||||||
|
@ -116,6 +118,8 @@ X(keep_hierarchy)
|
||||||
X(L)
|
X(L)
|
||||||
X(lib_whitebox)
|
X(lib_whitebox)
|
||||||
X(localparam)
|
X(localparam)
|
||||||
|
X(logic_block)
|
||||||
|
X(lram)
|
||||||
X(LUT)
|
X(LUT)
|
||||||
X(lut_keep)
|
X(lut_keep)
|
||||||
X(M)
|
X(M)
|
||||||
|
@ -145,6 +149,9 @@ X(PRIORITY_MASK)
|
||||||
X(Q)
|
X(Q)
|
||||||
X(qwp_position)
|
X(qwp_position)
|
||||||
X(R)
|
X(R)
|
||||||
|
X(ram_block)
|
||||||
|
X(ram_style)
|
||||||
|
X(ramstyle)
|
||||||
X(RD_ADDR)
|
X(RD_ADDR)
|
||||||
X(RD_ARST)
|
X(RD_ARST)
|
||||||
X(RD_ARST_VALUE)
|
X(RD_ARST_VALUE)
|
||||||
|
@ -164,6 +171,9 @@ X(RD_TRANSPARENT)
|
||||||
X(RD_WIDE_CONTINUATION)
|
X(RD_WIDE_CONTINUATION)
|
||||||
X(reg)
|
X(reg)
|
||||||
X(reprocess_after)
|
X(reprocess_after)
|
||||||
|
X(rom_block)
|
||||||
|
X(rom_style)
|
||||||
|
X(romstyle)
|
||||||
X(S)
|
X(S)
|
||||||
X(SET)
|
X(SET)
|
||||||
X(SET_POLARITY)
|
X(SET_POLARITY)
|
||||||
|
@ -186,6 +196,8 @@ X(STATE_NUM_LOG2)
|
||||||
X(STATE_RST)
|
X(STATE_RST)
|
||||||
X(STATE_TABLE)
|
X(STATE_TABLE)
|
||||||
X(submod)
|
X(submod)
|
||||||
|
X(syn_ramstyle)
|
||||||
|
X(syn_romstyle)
|
||||||
X(S_WIDTH)
|
X(S_WIDTH)
|
||||||
X(T)
|
X(T)
|
||||||
X(TABLE)
|
X(TABLE)
|
||||||
|
|
|
@ -9,4 +9,6 @@ OBJS += passes/memory/memory_map.o
|
||||||
OBJS += passes/memory/memory_memx.o
|
OBJS += passes/memory/memory_memx.o
|
||||||
OBJS += passes/memory/memory_nordff.o
|
OBJS += passes/memory/memory_nordff.o
|
||||||
OBJS += passes/memory/memory_narrow.o
|
OBJS += passes/memory/memory_narrow.o
|
||||||
|
OBJS += passes/memory/memory_libmap.o
|
||||||
|
|
||||||
|
OBJS += passes/memory/memlib.o
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,171 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 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 MEMLIB_H
|
||||||
|
#define MEMLIB_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace MemLibrary {
|
||||||
|
|
||||||
|
enum class RamKind {
|
||||||
|
Auto,
|
||||||
|
Logic,
|
||||||
|
NotLogic,
|
||||||
|
Distributed,
|
||||||
|
Block,
|
||||||
|
Huge,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class WidthMode {
|
||||||
|
Single,
|
||||||
|
Global,
|
||||||
|
PerPort,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class MemoryInitKind {
|
||||||
|
None,
|
||||||
|
Zero,
|
||||||
|
Any,
|
||||||
|
NoUndef,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class PortKind {
|
||||||
|
Sr,
|
||||||
|
Ar,
|
||||||
|
Sw,
|
||||||
|
Srsw,
|
||||||
|
Arsw,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ClkPolKind {
|
||||||
|
Anyedge,
|
||||||
|
Posedge,
|
||||||
|
Negedge,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class RdWrKind {
|
||||||
|
Undefined,
|
||||||
|
NoChange,
|
||||||
|
New,
|
||||||
|
Old,
|
||||||
|
NewOnly,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ResetValKind {
|
||||||
|
None,
|
||||||
|
Zero,
|
||||||
|
Any,
|
||||||
|
NoUndef,
|
||||||
|
Init,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SrstKind {
|
||||||
|
None,
|
||||||
|
Ungated,
|
||||||
|
GatedClkEn,
|
||||||
|
GatedRdEn,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class WrTransTargetKind {
|
||||||
|
All,
|
||||||
|
Group,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class WrTransKind {
|
||||||
|
New,
|
||||||
|
Old,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WrTransDef {
|
||||||
|
WrTransTargetKind target_kind;
|
||||||
|
int target_group;
|
||||||
|
WrTransKind kind;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortVariant {
|
||||||
|
dict<std::string, Const> options;
|
||||||
|
PortKind kind;
|
||||||
|
int clk_shared;
|
||||||
|
ClkPolKind clk_pol;
|
||||||
|
bool clk_en;
|
||||||
|
bool width_tied;
|
||||||
|
int min_wr_wide_log2;
|
||||||
|
int max_wr_wide_log2;
|
||||||
|
int min_rd_wide_log2;
|
||||||
|
int max_rd_wide_log2;
|
||||||
|
bool rd_en;
|
||||||
|
RdWrKind rdwr;
|
||||||
|
ResetValKind rdinitval;
|
||||||
|
ResetValKind rdarstval;
|
||||||
|
ResetValKind rdsrstval;
|
||||||
|
SrstKind rdsrstmode;
|
||||||
|
bool rdsrst_block_wr;
|
||||||
|
bool wrbe_separate;
|
||||||
|
std::vector<int> wrprio;
|
||||||
|
std::vector<WrTransDef> wrtrans;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortGroup {
|
||||||
|
bool optional;
|
||||||
|
bool optional_rw;
|
||||||
|
std::vector<std::string> names;
|
||||||
|
std::vector<PortVariant> variants;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RamClock {
|
||||||
|
std::string name;
|
||||||
|
bool anyedge;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Ram {
|
||||||
|
IdString id;
|
||||||
|
RamKind kind;
|
||||||
|
dict<std::string, Const> options;
|
||||||
|
std::vector<PortGroup> port_groups;
|
||||||
|
bool prune_rom;
|
||||||
|
int abits;
|
||||||
|
std::vector<int> dbits;
|
||||||
|
WidthMode width_mode;
|
||||||
|
std::string resource_name;
|
||||||
|
int resource_count;
|
||||||
|
double cost;
|
||||||
|
double widthscale;
|
||||||
|
int byte;
|
||||||
|
MemoryInitKind init;
|
||||||
|
std::vector<std::string> style;
|
||||||
|
std::vector<RamClock> shared_clocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Library {
|
||||||
|
std::vector<Ram> rams;
|
||||||
|
};
|
||||||
|
|
||||||
|
Library parse_library(const std::vector<std::string> &filenames, const pool<std::string> &defines);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,505 @@
|
||||||
|
# The `memory_libmap` pass
|
||||||
|
|
||||||
|
The `memory_libmap` pass is used to map memories to hardware primitives. To work,
|
||||||
|
it needs a description of available target memories in a custom format.
|
||||||
|
|
||||||
|
|
||||||
|
## Basic structure
|
||||||
|
|
||||||
|
A basic library could look like this:
|
||||||
|
|
||||||
|
# A distributed-class RAM called $__RAM16X4SDP_
|
||||||
|
ram distributed $__RAM16X4SDP_ {
|
||||||
|
# Has 4 address bits (ie. 16 rows).
|
||||||
|
abits 4;
|
||||||
|
# Has 4 data bits.
|
||||||
|
width 4;
|
||||||
|
# Cost for the selection heuristic.
|
||||||
|
cost 4;
|
||||||
|
# Can be initialized to any value on startup.
|
||||||
|
init any;
|
||||||
|
# Has a synchronous write port called "W"...
|
||||||
|
port sw "W" {
|
||||||
|
# ... with a positive edge clock.
|
||||||
|
clock posedge;
|
||||||
|
}
|
||||||
|
# Has an asynchronous read port called "R".
|
||||||
|
port ar "R" {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# A block-class RAM called $__RAMB9K_
|
||||||
|
ram block $__RAMB9K_ {
|
||||||
|
# Has 13 address bits in the base (most narrow) data width.
|
||||||
|
abits 13;
|
||||||
|
# The available widths are:
|
||||||
|
# - 1 (13 address bits)
|
||||||
|
# - 2 (12 address bits)
|
||||||
|
# - 4 (11 address bits)
|
||||||
|
# - 9 (10 address bits)
|
||||||
|
# - 18 (9 address bits)
|
||||||
|
# The width selection is per-port.
|
||||||
|
widths 1 2 4 9 18 per_port;
|
||||||
|
# Has a write enable signal with 1 bit for every 9 data bits.
|
||||||
|
byte 9;
|
||||||
|
cost 64;
|
||||||
|
init any;
|
||||||
|
# Has two synchronous read+write ports, called "A" and "B".
|
||||||
|
port srsw "A" "B" {
|
||||||
|
clock posedge;
|
||||||
|
# Has a clock enable signal (gates both read and write).
|
||||||
|
clken;
|
||||||
|
# Has three per-port selectable options for handling read+write behavior:
|
||||||
|
portoption "RDWR" "NO_CHANGE" {
|
||||||
|
# When port is writing, reading is not done (output register keeps
|
||||||
|
# its value).
|
||||||
|
rdwr no_change;
|
||||||
|
}
|
||||||
|
portoption "RDWR" "OLD" {
|
||||||
|
# When port is writing, the data read is the old value (before the
|
||||||
|
# write).
|
||||||
|
rdwr old;
|
||||||
|
}
|
||||||
|
portoption "RDWR" "NEW" {
|
||||||
|
# When port is writing, the data read is the new value.
|
||||||
|
rdwr new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
The pass will automatically select between the two available cells and
|
||||||
|
the logic fallback (mapping the whole memory to LUTs+FFs) based on required
|
||||||
|
capabilities and cost function. The selected memories will be transformed
|
||||||
|
to intermediate `$__RAM16X4SDP_` and `$__RAMB9K_` cells that need to be mapped
|
||||||
|
to actual hardware cells by a `techmap` pass, while memories selected for logic
|
||||||
|
fallback will be left unmapped and will be later mopped up by `memory_map` pass.
|
||||||
|
|
||||||
|
## RAM definition blocks
|
||||||
|
|
||||||
|
The syntax for a RAM definition is:
|
||||||
|
|
||||||
|
ram <kind: distributed|block|huge> <name> {
|
||||||
|
<ram properties>
|
||||||
|
<ports>
|
||||||
|
}
|
||||||
|
|
||||||
|
The `<name>` is used as the type of the mapped cell that will be passed to `techmap`.
|
||||||
|
The memory kind is one of `distributed`, `block`, or `huge`. It describes the general
|
||||||
|
class of the memory and can be matched on by manual selection attributes.
|
||||||
|
|
||||||
|
The available ram properties are:
|
||||||
|
|
||||||
|
- `abits <address bits>;`
|
||||||
|
- `width <width>;`
|
||||||
|
- `widths <width 1> <width 2> ... <width n> <global|per_port>;`
|
||||||
|
- `byte <width>;`
|
||||||
|
- `cost <cost>;`
|
||||||
|
- `widthscale [<factor>];`
|
||||||
|
- `resource <name> <count>;`
|
||||||
|
- `init <none|zero|any|no_undef>;`
|
||||||
|
- `style "<name 1>" "<name 2>" "<name 3>" ...;`
|
||||||
|
- `prune_rom;`
|
||||||
|
|
||||||
|
### RAM dimensions
|
||||||
|
|
||||||
|
The memory dimensions are described by `abits` and `width` or `widths` properties.
|
||||||
|
|
||||||
|
For a simple memory cell with a fixed width, use `abits` and `width` like this:
|
||||||
|
|
||||||
|
abits 4;
|
||||||
|
width 4;
|
||||||
|
|
||||||
|
This will result in a `2**abits × width` memory cell.
|
||||||
|
|
||||||
|
Multiple-width memories are also possible, and use the `widths` property instead.
|
||||||
|
The rules for multiple-width memories are:
|
||||||
|
|
||||||
|
- the widths are given in `widths` property in increasing order
|
||||||
|
- the value in the `abits` property corresponds to the most narrow width
|
||||||
|
- every width in the list needs to be greater than or equal to twice
|
||||||
|
the previous width (ie. `1 2 4 9 18` is valid, `1 2 4 7 14` is not)
|
||||||
|
- it is assumed that, for every width in progression, the word in memory
|
||||||
|
is made of two smaller words, plus optionally some extra bits (eg. in the above
|
||||||
|
list, the 9-bit word is made of two 4-bit words and 1 extra bit), and thus
|
||||||
|
each sequential width in the list corresponds to one fewer usable address bit
|
||||||
|
- all addresses connected to memory ports are always `abits` bits wide, with const
|
||||||
|
zero wired to the unused bits corresponding to wide ports
|
||||||
|
|
||||||
|
When multiple widths are specified, they can be `per_port` or `global`.
|
||||||
|
For the `global` version, the pass has to pick one width for the whole cell,
|
||||||
|
and it is set on the resulting cell as the `WIDTH` parameter. For the `per_port`
|
||||||
|
version, the selection is made on per-port basis, and passed using `PORT_*_WIDTH`
|
||||||
|
parameters. When the mode is `per_port`, the width selection can be fine-tuned
|
||||||
|
with the port `width` property.
|
||||||
|
|
||||||
|
Specifying dimensions is mandatory.
|
||||||
|
|
||||||
|
|
||||||
|
### Byte width
|
||||||
|
|
||||||
|
If the memory cell has per-byte write enables, the `byte` property can be used
|
||||||
|
to define the byte size (ie. how many data bits correspond to one write enable
|
||||||
|
bit).
|
||||||
|
|
||||||
|
The property is optional. If not used, it is assumed that there is a single
|
||||||
|
write enable signal for each writable port.
|
||||||
|
|
||||||
|
The rules for this property are as follows:
|
||||||
|
|
||||||
|
- for every available width, the width needs to be a multiple of the byte size,
|
||||||
|
or the byte size needs to be larger than the width
|
||||||
|
- if the byte size is larger than the width, the byte enable signel is assumed
|
||||||
|
to be one bit wide and cover the whole port
|
||||||
|
- otherwise, the byte enable signal has one bit for every `byte` bits of the
|
||||||
|
data port
|
||||||
|
|
||||||
|
The exact kind of byte enable signal is determined by the presence or absence
|
||||||
|
of the per-port `wrbe_separate` property.
|
||||||
|
|
||||||
|
|
||||||
|
### Cost properties
|
||||||
|
|
||||||
|
The `cost` property is used to estimate the cost of using a given mapping.
|
||||||
|
This is the cost of using one cell, and will be scaled as appropriate if
|
||||||
|
the mapping requires multiple cells.
|
||||||
|
|
||||||
|
If the `widthscale` property is specified, the mapping is assumed to be flexible,
|
||||||
|
with cost scaling with the percentage of data width actually used. The value
|
||||||
|
of the `widthscale` property is how much of the cost is scalable as such.
|
||||||
|
If the value is omitted, all of the cost is assumed to scale.
|
||||||
|
Eg. for the following properties:
|
||||||
|
|
||||||
|
width 14;
|
||||||
|
cost 8;
|
||||||
|
widthscale 7;
|
||||||
|
|
||||||
|
The cost of a given cell will be assumed to be `(8 - 7) + 7 * (used_bits / 14)`.
|
||||||
|
|
||||||
|
If `widthscale` is used, The pass will attach a `BITS_USED` parameter to mapped
|
||||||
|
calls, with a bitmask of which data bits of the memory are actually in use.
|
||||||
|
The parameter width will be the widest width in the `widths` property, and
|
||||||
|
the bit correspondence is defined accordingly.
|
||||||
|
|
||||||
|
The `cost` property is mandatory.
|
||||||
|
|
||||||
|
|
||||||
|
### `init` property
|
||||||
|
|
||||||
|
This property describes the state of the memory at initialization time. Can have
|
||||||
|
one of the following values:
|
||||||
|
|
||||||
|
- `none`: the memory contents are unpredictable, memories requiring any sort
|
||||||
|
of initialization will not be mapped to this cell
|
||||||
|
- `zero`: the memory contents are zero, memories can be mapped to this cell iff
|
||||||
|
their initialization value is entirely zero or undef
|
||||||
|
- `any`: the memory contents can be arbitrarily selected, and the initialization
|
||||||
|
will be passes as the `INIT` parameter to the mapped cell
|
||||||
|
- `no_undef`: like `any`, but only 0 and 1 bit values are supported (the pass will
|
||||||
|
convert any x bits to 0)
|
||||||
|
|
||||||
|
The `INIT` parameter is always constructed as a concatenation of words corresponding
|
||||||
|
to the widest available `widths` setting, so that all available memory cell bits
|
||||||
|
are covered.
|
||||||
|
|
||||||
|
This property is optional and assumed to be `none` when not present.
|
||||||
|
|
||||||
|
|
||||||
|
### `style` property
|
||||||
|
|
||||||
|
Provides a name (or names) for this definition that can be passed to the `ram_style`
|
||||||
|
or similar attribute to manually select it. Optional and can be used multiple times.
|
||||||
|
|
||||||
|
|
||||||
|
### `prune_rom` property
|
||||||
|
|
||||||
|
Specifying this property disqualifies the definition from consideration for source
|
||||||
|
memories that have no write ports (ie. ROMs). Use this on definitions that have
|
||||||
|
an obviously superior read-only alternative (eg. LUTRAMs) to make the pass skip
|
||||||
|
them over quickly.
|
||||||
|
|
||||||
|
|
||||||
|
## Port definition blocks
|
||||||
|
|
||||||
|
The syntax for a port group definition is:
|
||||||
|
|
||||||
|
port <ar|sr|sw|arsw|srsw> "NAME 1" "NAME 2" ... {
|
||||||
|
<port properties>
|
||||||
|
}
|
||||||
|
|
||||||
|
A port group definition defines a group of ports with identical properties.
|
||||||
|
There are as many ports in a group as there are names given.
|
||||||
|
|
||||||
|
Ports come in 5 kinds:
|
||||||
|
|
||||||
|
- `ar`: asynchronous read port
|
||||||
|
- `sr`: synchronous read port
|
||||||
|
- `sw`: synchronous write port
|
||||||
|
- `arsw`: simultanous synchronous write + asynchronous read with common address (commonly found in LUT RAMs)
|
||||||
|
- `srsw`: synchronous write + synchronous read with common address
|
||||||
|
|
||||||
|
The port properties available are:
|
||||||
|
|
||||||
|
- `width <tied|mix>;`
|
||||||
|
- `width <width 1> <width 2> ...;`
|
||||||
|
- `width <tied|mix> <width 1> <width 2> ...;`
|
||||||
|
- `width rd <width 1> <width 2> ... wr <width 1> <width 2> ...;`
|
||||||
|
- `clock <posedge|negedge|anyedge> ["SHARED_NAME"];`
|
||||||
|
- `clken;`
|
||||||
|
- `rden;`
|
||||||
|
- `wrbe_separate;`
|
||||||
|
- `rdwr <undefined|no_change|new|old|new_only>;`
|
||||||
|
- `rdinit <none|zero|any|no_undef>;`
|
||||||
|
- `rdarst <none|zero|any|no_undef|init>;`
|
||||||
|
- `rdsrst <none|zero|any|no_undef|init> <ungated|gatec_clken|gated_rden> [block_wr];`
|
||||||
|
- `wrprio "NAME" "NAME" ...;`
|
||||||
|
- `wrtrans <"NAME"|all> <old|new>;`
|
||||||
|
- `optional;`
|
||||||
|
- `optional_rw;`
|
||||||
|
|
||||||
|
The base signals connected to the mapped cell for ports are:
|
||||||
|
|
||||||
|
- `PORT_<name>_ADDR`: the address
|
||||||
|
- `PORT_<name>_WR_DATA`: the write data (for `sw`/`arsw`/`srsw` ports only)
|
||||||
|
- `PORT_<name>_RD_DATA`: the read data (for `ar`/`sr`/`arsw`/`srsw` ports only)
|
||||||
|
- `PORT_<name>_WR_EN`: the write enable or enables (for `sw`/`arsw`/`srsw` ports only)
|
||||||
|
|
||||||
|
The address is always `abits` wide. If a non-narrowest width is used, the appropriate low
|
||||||
|
bits will be tied to 0.
|
||||||
|
|
||||||
|
|
||||||
|
### Port `width` prooperty
|
||||||
|
|
||||||
|
If the RAM has `per_port` widths, the available width selection can be further described
|
||||||
|
on per-port basis, by using one of the following properties:
|
||||||
|
|
||||||
|
- `width tied;`: any width from the master `widths` list is acceptable, and
|
||||||
|
(for read+write ports) the read and write width has to be the same
|
||||||
|
- `width tied <width 1> <width 2> ...;`: like above, but limits the width
|
||||||
|
selection to the given list; the list has to be a contiguous sublist of the
|
||||||
|
master `widths` list
|
||||||
|
- `width <width 1> <width 2> ...;`: alias for the above, to be used for read-only
|
||||||
|
or write-only ports
|
||||||
|
- `width mix;`: any width from the master `widths` list is acceptable, and
|
||||||
|
read width can be different than write width (only usable for read+write ports)
|
||||||
|
- `width mix <width 1> <width 2> ...;`: like above, but limits the width
|
||||||
|
selection to the given list; the list has to be a contiguous sublist of the
|
||||||
|
master `widths` list
|
||||||
|
- `width rd <width 1> <width 2> ... wr <width 1> <width 2> ...;`: like above,
|
||||||
|
but the limitted selection can be different for read and write widths
|
||||||
|
|
||||||
|
If `per_port` widths are in use and this property is not specified, `width tied;` is assumed.
|
||||||
|
|
||||||
|
The parameters attached to the cell in `per_port` widths mode are:
|
||||||
|
|
||||||
|
- `PORT_<name>_WIDTH`: the selected width (for `tied` ports)
|
||||||
|
- `PORT_<name>_RD_WIDTH`: the selected read width (for `mix` ports)
|
||||||
|
- `PORT_<name>_WR_WIDTH`: the selected write width (for `mix` ports)
|
||||||
|
|
||||||
|
|
||||||
|
### `clock` property
|
||||||
|
|
||||||
|
The `clock` property is used with synchronous ports (and synchronous ports only).
|
||||||
|
It is mandatory for them and describes the clock polarity and clock sharing.
|
||||||
|
`anyedge` means that both polarities are supported.
|
||||||
|
|
||||||
|
If a shared clock name is provided, the port is assumed to have a shared clock signal
|
||||||
|
with all other ports using the same shared name. Otherwise, the port is assumed to
|
||||||
|
have its own clock signal.
|
||||||
|
|
||||||
|
The port clock is always provided on the memory cell as `PORT_<name>_CLK` signal
|
||||||
|
(even if it is also shared). Shared clocks are also provided as `CLK_<shared_name>`
|
||||||
|
signals.
|
||||||
|
|
||||||
|
For `anyedge` clocks, the cell gets a `PORT_<name>_CLKPOL` parameter that is set
|
||||||
|
to 1 for `posedge` clocks and 0 for `negedge` clocks. If the clock is shared,
|
||||||
|
the same information will also be provided as `CLK_<shared_name>_POL` parameter.
|
||||||
|
|
||||||
|
|
||||||
|
### `clken` and `rden`
|
||||||
|
|
||||||
|
The `clken` property, if present, means that the port has a clock enable signal
|
||||||
|
gating both reads and writes. Such signal will be provided to the mapped cell
|
||||||
|
as `PORT_<name>_CLK_EN`. It is only applicable to synchronous ports.
|
||||||
|
|
||||||
|
The `rden` property, if present, means that the port has a read clock enable signal.
|
||||||
|
Such signal will be provided to the mapped cell as `PORT_<name>_RD_EN`. It is only
|
||||||
|
applicable to synchronous read ports (`sr` and `srsw`).
|
||||||
|
|
||||||
|
For `sr` ports, both of these options are effectively equivalent.
|
||||||
|
|
||||||
|
|
||||||
|
### `wrbe_separate` and the write enables
|
||||||
|
|
||||||
|
The `wrbe_separate` property specifies that the write byte enables are provided
|
||||||
|
as a separate signal from the main write enable. It can only be used when the
|
||||||
|
RAM-level `byte` property is also specified.
|
||||||
|
|
||||||
|
The rules are as follows:
|
||||||
|
|
||||||
|
If no `byte` is specified:
|
||||||
|
|
||||||
|
- `wrbe_separate` is not allowed
|
||||||
|
- `PORT_<name>_WR_EN` signal is single bit
|
||||||
|
|
||||||
|
If `byte` is specified, but `wrbe_separate` is not:
|
||||||
|
|
||||||
|
- `PORT_<name>_WR_EN` signal has one bit for every data byte
|
||||||
|
- `PORT_<name>_WR_EN_WIDTH` parameter is the width of the above (only present for multiple-width cells)
|
||||||
|
|
||||||
|
If `byte` is specified and `wrbe_separate` is present:
|
||||||
|
|
||||||
|
- `PORT_<name>_WR_EN` signal is single bit
|
||||||
|
- `PORT_<name>_WR_BE` signal has one bit for every data byte
|
||||||
|
- `PORT_<name>_WR_BE_WIDTH` parameter is the width of the above (only present for multiple-width cells)
|
||||||
|
- a given byte is written iff all of `CLK_EN` (if present), `WR_EN`, and the corresponding `WR_BE` bit are one
|
||||||
|
|
||||||
|
This property can only be used on write ports.
|
||||||
|
|
||||||
|
|
||||||
|
### `rdwr` property
|
||||||
|
|
||||||
|
This property is allowed only on `srsw` ports and describes read-write interactions.
|
||||||
|
|
||||||
|
The possible values are:
|
||||||
|
|
||||||
|
- `no_change`: if write is being performed (any bit of `WR_EN` is set),
|
||||||
|
reading is not performed and the `RD_DATA` keeps its old value
|
||||||
|
- `undefined`: all `RD_DATA` bits corresponding to enabled `WR_DATA` bits
|
||||||
|
have undefined value, remaining bits read from memory
|
||||||
|
- `old`: all `RD_DATA` bits get the previous value in memory
|
||||||
|
- `new`: all `RD_DATA` bits get the new value in memory (transparent write)
|
||||||
|
- `new_only`: all `RD_DATA` bits corresponding to enabled `WR_DATA` bits
|
||||||
|
get the new value, all others are undefined
|
||||||
|
|
||||||
|
If this property is not found on an `srsw` port, `undefined` is assumed.
|
||||||
|
|
||||||
|
|
||||||
|
### Read data initial value and resets
|
||||||
|
|
||||||
|
The `rdinit`, `rdarst`, and `rdsrst` are applicable only to synchronous read
|
||||||
|
ports.
|
||||||
|
|
||||||
|
`rdinit` describes the initial value of the read port data, and can be set to
|
||||||
|
one of the following:
|
||||||
|
|
||||||
|
- `none`: initial data is indeterminate
|
||||||
|
- `zero`: initial data is all-0
|
||||||
|
- `any`: initial data is arbitrarily configurable, and the selected value
|
||||||
|
will be attached to the cell as `PORT_<name>_RD_INIT_VALUE` parameter
|
||||||
|
- `no_undef`: like `any`, but only 0 and 1 bits are allowed
|
||||||
|
|
||||||
|
`rdarst` and `rdsrst` describe the asynchronous and synchronous reset capabilities.
|
||||||
|
The values are similar to `rdinit`:
|
||||||
|
|
||||||
|
- `none`: no reset
|
||||||
|
- `zero`: reset to all-0 data
|
||||||
|
- `any`: reset to arbitrary value, the selected value
|
||||||
|
will be attached to the cell as `PORT_<name>_RD_ARST_VALUE` or
|
||||||
|
`PORT_<name>_RD_SRST_VALUE` parameter
|
||||||
|
- `no_undef`: like `any`, but only 0 and 1 bits are allowed
|
||||||
|
- `init`: reset to the initial value, as specified by `rdinit` (which must be `any`
|
||||||
|
or `no_undef` itself)
|
||||||
|
|
||||||
|
If the capability is anything other than `none`, the reset signal
|
||||||
|
will be provided as `PORT_<name>_RD_ARST` or `PORT_<name>_RD_SRST`.
|
||||||
|
|
||||||
|
For `rdsrst`, the priority must be additionally specified, as one of:
|
||||||
|
|
||||||
|
- `ungated`: `RD_SRST` has priority over both `CLK_EN` and `RD_EN` (if present)
|
||||||
|
- `gated_clken`: `CLK_EN` has priority over `RD_SRST`; `RD_SRST` has priority over `RD_EN` if present
|
||||||
|
- `gated_rden`: `RD_EN` and `CLK_EN` (if present) both have priority over `RD_SRST`
|
||||||
|
|
||||||
|
Also, `rdsrst` can optionally have `block_wr` specified, which means that sync reset
|
||||||
|
cannot be performed in the same cycle as a write.
|
||||||
|
|
||||||
|
If not provided, `none` is assumed for all three properties.
|
||||||
|
|
||||||
|
|
||||||
|
### Write priority
|
||||||
|
|
||||||
|
The `wrprio` property is only allowed on write ports and defines a priority relationship
|
||||||
|
between port — when `wrprio "B";` is used in definition of port `"A"`, and both ports
|
||||||
|
simultanously write to the same memory cell, the value written by port `"A"` will have
|
||||||
|
precedence.
|
||||||
|
|
||||||
|
This property is optional, and can be used multiple times as necessary. If no relationship
|
||||||
|
is described for a pair of write ports, no priority will be assumed.
|
||||||
|
|
||||||
|
|
||||||
|
### Write transparency
|
||||||
|
|
||||||
|
The `wrtrans` property is only allowed on write ports and defines behavior when
|
||||||
|
another synchronous read port reads from the memory cell at the same time as the
|
||||||
|
given port writes it. The values are:
|
||||||
|
|
||||||
|
- `old`: the read port will get the old value of the cell
|
||||||
|
- `new`: the read port will get the new value of the cell
|
||||||
|
|
||||||
|
This property is optional, and can be used multiple times as necessary. If no relationship
|
||||||
|
is described for a pair of ports, the value read is assumed to be indeterminate.
|
||||||
|
|
||||||
|
Note that this property is not used to describe the read value on the port itself for `srsw`
|
||||||
|
ports — for that purpose, the `rdwr` property is used instead.
|
||||||
|
|
||||||
|
|
||||||
|
### Optional ports
|
||||||
|
|
||||||
|
The `optional;` property will make the pass attach a `PORT_<name>_USED` parameter
|
||||||
|
with a boolean value specifying whether a given port was meaningfully used in
|
||||||
|
mapping a given cell. Likewise, `optional_rw;` will attach `PORT_<name>_RD_USED`
|
||||||
|
and `PORT_<name>_WR_USED` the specify whether the read / write part in particular
|
||||||
|
was used. These can be useful if the mapping has some meaningful optimization
|
||||||
|
to apply for unused ports, but doesn't otherwise influence the selection process.
|
||||||
|
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
For highly configurable cells, multiple variants may be described in one cell description.
|
||||||
|
All properties and port definitions within a RAM or port definition can be put inside
|
||||||
|
an `option` block as follows:
|
||||||
|
|
||||||
|
option "NAME" <value> {
|
||||||
|
<properties, ports, ...>
|
||||||
|
}
|
||||||
|
|
||||||
|
The value and name of an option are arbitrary, and the selected option value
|
||||||
|
will be provided to the cell as `OPTION_<name>` parameter. Values can be
|
||||||
|
strings or integers.
|
||||||
|
|
||||||
|
|
||||||
|
Likewise, for per-port options, a `portoption` block can be used:
|
||||||
|
|
||||||
|
portoption "NAME" <value> {
|
||||||
|
<properties, ...>
|
||||||
|
}
|
||||||
|
|
||||||
|
These options will be provided as `PORT_<pname>_OPTION_<oname>` parameters.
|
||||||
|
|
||||||
|
The library parser will simply expand the RAM definition for every possible combination
|
||||||
|
of option values mentioned in the RAM body, and likewise for port definitions.
|
||||||
|
This can lead to a combinatorial explosion.
|
||||||
|
|
||||||
|
If some option values cannot be used together, a `forbid` pseudo-property can be used
|
||||||
|
to discard a given combination, eg:
|
||||||
|
|
||||||
|
option "ABC" 1 {
|
||||||
|
portoption "DEF" "GHI" {
|
||||||
|
forbid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
will disallow combining the RAM option `ABC = 2` with port option `DEF = "GHI"`.
|
||||||
|
|
||||||
|
|
||||||
|
## Ifdefs
|
||||||
|
|
||||||
|
To allow reusing a library for multiple FPGA families with slighly differing
|
||||||
|
capabilities, `ifdef` (and `ifndef`) blocks are provided:
|
||||||
|
|
||||||
|
ifdef IS_FANCY_FPGA_WITH_CONFIGURABLE_ASYNC_RESET {
|
||||||
|
rdarst any;
|
||||||
|
} else {
|
||||||
|
rdarst zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
Such blocks can be enabled by passing the `-D` option to the pass.
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue