From db8f286b248638f04b0e643405ae1f76348f3b7b Mon Sep 17 00:00:00 2001 From: Liu Xiaoyi Date: Thu, 13 Apr 2023 19:42:01 +0800 Subject: [PATCH 1/5] WIP: Structural memory --- spec.md | 173 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 99 insertions(+), 74 deletions(-) diff --git a/spec.md b/spec.md index 53998a99..111e108d 100644 --- a/spec.md +++ b/spec.md @@ -1671,18 +1671,18 @@ by the following parameters. 2. A positive integer literal representing the number of elements in the memory. -3. A variable number of named ports, each being a read port, a write port, or - readwrite port. - -4. A non-negative integer literal indicating the read latency, which is the - number of cycles after setting the port's read address before the - corresponding element's value can be read from the port's data field. - -5. A positive integer literal indicating the write latency, which is the number - of cycles after setting the port's write address and data before the - corresponding element within the memory holds the new value. - -6. A read-under-write flag indicating the behavior when a memory location is +3. A variable number of named ports, each having following parameters: + 1. A read flag indicating the reading capability of this port. + 2. A write flag indicating the writing capability of this port. + 3. If the port can read, a non-negative integer literal indicating the read + latency, which is the number of cycles after setting the port's read + address before the corresponding element's value can be read from the + port's rdata field. + 4. If the port can write, a positive integer literal indicating the write + latency, which is the number of cycles after setting the port's write + address and wdata before the corresponding element within the memory holds + the new value. +4. A read-under-write flag indicating the behavior when a memory location is written to while a read to that location is in progress. Integer literals for the number of elements and the read/write latencies _may @@ -1691,20 +1691,28 @@ not be string-encoded integer literals_. The following example demonstrates instantiating a memory containing 256 complex numbers, each with 16-bit signed integer fields for its real and imaginary components. It has two read ports, `r1`{.firrtl} and `r2`{.firrtl}, and one -write port, `w`{.firrtl}. It is combinationally read (read latency is zero -cycles) and has a write latency of one cycle. Finally, its read-under-write +write port, `w`{.firrtl}, with the ability to do partial writes using a mask. +All of its read ports is combinationally read (read latency is zero cycles) and +its write port has a write latency of one cycle. Finally, its read-under-write behavior is undefined. ``` firrtl mem mymem : data-type => {real:SInt<16>, imag:SInt<16>} depth => 256 - reader => r1 - reader => r2 - writer => w - read-latency => 0 - write-latency => 1 read-under-write => undefined + port r1: + read => yes + write => no + read-latency => 0 + port r2: + read => yes + write => no + read-latency => 0 + port w: + read => no + write => with-mask + write-latency => 1 ``` In the example above, the type of `mymem`{.firrtl} is: @@ -1713,44 +1721,49 @@ In the example above, the type of `mymem`{.firrtl} is: {flip r1: {addr: UInt<8>, en: UInt<1>, clk: Clock, - flip data: {real: SInt<16>, imag: SInt<16>}}, + flip rdata: {real: SInt<16>, imag: SInt<16>}}, flip r2: {addr: UInt<8>, en: UInt<1>, clk: Clock, - flip data: {real: SInt<16>, imag: SInt<16>}}, + flip rdata: {real: SInt<16>, imag: SInt<16>}}, flip w: {addr: UInt<8>, en: UInt<1>, clk: Clock, - data: {real: SInt<16>, imag: SInt<16>}, + wdata: {real: SInt<16>, imag: SInt<16>}, mask: {real: UInt<1>, imag: UInt<1>}}} ``` The following sections describe how a memory's field types are calculated and the behavior of each type of memory port. -### Read Ports +### Ports -If a memory is declared with element type `T`{.firrtl}, has a size less than or -equal to $2^N$, then its read ports have type: +Ports can have the following read capability: -``` firrtl -{addr: UInt, en: UInt<1>, clk: Clock, flip data: T} -``` +- `no`{.firrtl}: This port cannot read from the memory +- `yes`{.firrtl}: THis port can read from the memory -If the `en`{.firrtl} field is high, then the element value associated with the -address in the `addr`{.firrtl} field can be retrieved by reading from the -`data`{.firrtl} field after the appropriate read latency. If the `en`{.firrtl} -field is low, then the value in the `data`{.firrtl} field, after the appropriate -read latency, is undefined. The port is driven by the clock signal in the -`clk`{.firrtl} field. +Ports can have the following write capability: -### Write Ports +- `no`{.firrtl}: This port cannot write into the memory +- `no-mask`{.firrtl}: This port can only do full writes into the memory +- `with-mask`{.firrtl}: This port can do partial writes into the memory If a memory is declared with element type `T`{.firrtl}, has a size less than or -equal to $2^N$, then its write ports have type: +equal to $2^N$, then a port with maximum capability (read => yes, write => +with-mask) have type: ``` firrtl -{addr: UInt, en: UInt<1>, clk: Clock, data: T, mask: M} +{ + clk: Clock, + en: UInt<1>, + addr: UInt, + wmode: UInt<1>, + + flip rdata: T, + wdata: T, + wmask: M +} ``` where `M`{.firrtl} is the mask type calculated from the element type @@ -1758,31 +1771,39 @@ where `M`{.firrtl} is the mask type calculated from the element type element type except with all ground types replaced with a single bit unsigned integer type. The *non-masked portion* of the data value is defined as the set of data value leaf sub-elements where the corresponding mask leaf sub-element is -high. - -If the `en`{.firrtl} field is high, then the non-masked portion of the -`data`{.firrtl} field value is written, after the appropriate write latency, to -the location indicated by the `addr`{.firrtl} field. If the `en`{.firrtl} field -is low, then no value is written after the appropriate write latency. The port -is driven by the clock signal in the `clk`{.firrtl} field. - -### Readwrite Ports - -Finally, the readwrite ports have type: - -``` firrtl -{addr: UInt, en: UInt<1>, clk: Clock, flip rdata: T, wmode: UInt<1>, - wdata: T, wmask: M} -``` - -A readwrite port is a single port that, on a given cycle, can be used either as -a read or a write port. If the readwrite port is not in write mode (the -`wmode`{.firrtl} field is low), then the `rdata`{.firrtl}, `addr`{.firrtl}, -`en`{.firrtl}, and `clk`{.firrtl} fields constitute its read port fields, and -should be used accordingly. If the readwrite port is in write mode (the -`wmode`{.firrtl} field is high), then the `wdata`{.firrtl}, `wmask`{.firrtl}, -`addr`{.firrtl}, `en`{.firrtl}, and `clk`{.firrtl} fields constitute its write -port fields, and should be used accordingly. +high, or the entire data value if no mask is present. + +Some of those fields are absent if the capability is reduced. The +functionalities and the condition of their presense is as followed: + +- `clk`{.firrtl}: Always presents. + The clock driving this port. +- `en`{.firrtl}: Always presents. + When high, enables this port, and the read / write at that clock edge + initiates. Otherwise, no operation initiates at that clock edge. +- `addr`{.firrtl}: Always presents. + The address of a read / write operation at a certain clock edge. +- `wmode`{.firrtl}: Only presents if the read capability is `yes`{.firrtl}, and + the write capability is `no-mask`{.firrtl} or `with-mask`{.firrtl}. + This field decides whether a port having both read and write capability + functions as a read port or a write port at a certain clock edge. If + `en`{.firrtl} is high and `wmode`{.firrtl} is low, a read operation initiates. + If `en`{.firrtl} is high and `wmode`{.firrtl} is low, a read operation + initiates. +- `rdata`{.firrtl}: Only presents if the read capability is `yes`{firrtl}. + Reading this field gives the element value associated with the address of a + read operation that initiated `read-latency`{.firrtl} cycles prior on this + port. If no read operations initiated at that clock edge (including the case + that a write operation initiated), the value in this field is undefined. +- `wdata`{.firrtl}: Only presents if the write capability is `no-mask` or + `with-mask`. + When a write opartion initiates, the non-masked portion of the + `wdata`{.firrtl} field value is written, after the `write-latency` cycles, to + the location indicated by the address of the write operation. +- `mask`{.firrtl}: Only presents if the write capability is + `with-mask`{.firrtl}. + The value of this field acts as the mask for the write operation taking effect + that cycle, if any. ### Read Under Write Behavior @@ -1807,12 +1828,12 @@ memory after delaying the read address by the appropriate read latency. If the read-under-write flag is set to `undefined`{.firrtl}, then the value held by the read port after the appropriate read latency is undefined. -For the purpose of defining such collisions, an "active write port" is a write -port or a readwrite port that is used to initiate a write operation on a given -clock edge, where `en`{.firrtl} is set and, for a readwriter, `wmode`{.firrtl} -is set. An "active read port" is a read port or a readwrite port that is used to +For the purpose of defining such collisions, an "active write port" is a port +with write capability that is used to initiate a write operation on a given +clock edge, where `en`{.firrtl} is set and, if presents, `wmode`{.firrtl} +is set. An "active read port" is a port with read capability that is used to initiate a read operation on a given clock edge, where `en`{.firrtl} is set and, -for a readwriter, `wmode`{.firrtl} is not set. Each operation is defined to be +if presents, `wmode`{.firrtl} is not set. Each operation is defined to be "active" for the number of cycles set by its corresponding latency, starting from the cycle where its inputs were provided to its associated port. Note that this excludes combinational reads, which are simply modeled as combinationally @@ -1833,8 +1854,8 @@ same cycle, the stored value is undefined. ### Constant memory type A memory with a constant data-type represents a ROM and may not have -write-ports. It is beyond the scope of this specification how ROMs are -initialized. +ports with write capability. It is beyond the scope of this specification how +ROMs are initialized. ## Instances @@ -3599,15 +3620,19 @@ ref_expr = ( "probe" | "rwprobe" ) , "(" , static_reference , ")" (* Memory *) ruw = ( "old" | "new" | "undefined" ) ; +read_cap = ( "no" | "yes" ) ; +write_cap = ( "no" | "no-mask" | "with-mask" ) ; +memory_port = "port" , id , ":" , [ info ] , newline , indent , + "read" , "=>" , read_cap , newline , + "write" , "=>" , write_cap , newline , + [ "read-latency" , "=>" , int , newline ], + [ "write-latency" , "=>" , int , newline ], + dedent ; memory = "mem" , id , ":" , [ info ] , newline , indent , "data-type" , "=>" , type , newline , "depth" , "=>" , int , newline , - "read-latency" , "=>" , int , newline , - "write-latency" , "=>" , int , newline , "read-under-write" , "=>" , ruw , newline , - { "reader" , "=>" , id , newline } , - { "writer" , "=>" , id , newline } , - { "readwriter" , "=>" , id , newline } , + { "port" , "=>" , memory_port , newline } , dedent ; (* Force and Release *) From 9f1ba2fcdf3f9dcf03584213afdb166e79eb78b5 Mon Sep 17 00:00:00 2001 From: Liu Xiaoyi Date: Thu, 13 Apr 2023 19:51:50 +0800 Subject: [PATCH 2/5] Syntax fixes --- spec.md | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/spec.md b/spec.md index 111e108d..73f7162a 100644 --- a/spec.md +++ b/spec.md @@ -1672,16 +1672,16 @@ by the following parameters. memory. 3. A variable number of named ports, each having following parameters: - 1. A read flag indicating the reading capability of this port. - 2. A write flag indicating the writing capability of this port. - 3. If the port can read, a non-negative integer literal indicating the read - latency, which is the number of cycles after setting the port's read - address before the corresponding element's value can be read from the - port's rdata field. - 4. If the port can write, a positive integer literal indicating the write - latency, which is the number of cycles after setting the port's write - address and wdata before the corresponding element within the memory holds - the new value. + 1. A read flag indicating the read capability of this port. + 2. A write flag indicating the write capability of this port. + 3. If the port can read, a non-negative integer literal indicating the read + latency, which is the number of cycles after setting the port's read + address before the corresponding element's value can be read from the + port's rdata field. + 4. If the port can write, a positive integer literal indicating the write + latency, which is the number of cycles after setting the port's write + address and wdata before the corresponding element within the memory + holds the new value. 4. A read-under-write flag indicating the behavior when a memory location is written to while a read to that location is in progress. @@ -1738,20 +1738,20 @@ the behavior of each type of memory port. ### Ports -Ports can have the following read capability: +Ports can have one of the following read capabilities: - `no`{.firrtl}: This port cannot read from the memory -- `yes`{.firrtl}: THis port can read from the memory +- `yes`{.firrtl}: This port can read from the memory -Ports can have the following write capability: +Ports can have one of the following write capabilities: - `no`{.firrtl}: This port cannot write into the memory - `no-mask`{.firrtl}: This port can only do full writes into the memory - `with-mask`{.firrtl}: This port can do partial writes into the memory If a memory is declared with element type `T`{.firrtl}, has a size less than or -equal to $2^N$, then a port with maximum capability (read => yes, write => -with-mask) have type: +equal to $2^N$, then a port with maximum capability ( +`read => yes, write => with-mask`{.firrtl}) has type: ``` firrtl { @@ -1777,32 +1777,39 @@ Some of those fields are absent if the capability is reduced. The functionalities and the condition of their presense is as followed: - `clk`{.firrtl}: Always presents. + The clock driving this port. - `en`{.firrtl}: Always presents. + When high, enables this port, and the read / write at that clock edge initiates. Otherwise, no operation initiates at that clock edge. - `addr`{.firrtl}: Always presents. + The address of a read / write operation at a certain clock edge. - `wmode`{.firrtl}: Only presents if the read capability is `yes`{.firrtl}, and the write capability is `no-mask`{.firrtl} or `with-mask`{.firrtl}. + This field decides whether a port having both read and write capability functions as a read port or a write port at a certain clock edge. If `en`{.firrtl} is high and `wmode`{.firrtl} is low, a read operation initiates. - If `en`{.firrtl} is high and `wmode`{.firrtl} is low, a read operation + If `en`{.firrtl} is high and `wmode`{.firrtl} is low, a write operation initiates. - `rdata`{.firrtl}: Only presents if the read capability is `yes`{firrtl}. + Reading this field gives the element value associated with the address of a read operation that initiated `read-latency`{.firrtl} cycles prior on this port. If no read operations initiated at that clock edge (including the case that a write operation initiated), the value in this field is undefined. - `wdata`{.firrtl}: Only presents if the write capability is `no-mask` or `with-mask`. + When a write opartion initiates, the non-masked portion of the `wdata`{.firrtl} field value is written, after the `write-latency` cycles, to the location indicated by the address of the write operation. -- `mask`{.firrtl}: Only presents if the write capability is +- `wmask`{.firrtl}: Only presents if the write capability is `with-mask`{.firrtl}. - The value of this field acts as the mask for the write operation taking effect + + The value of this field acts as the mask for the write operation initiating that cycle, if any. ### Read Under Write Behavior From 98c815e60c8c5d69aa59565d28323017fbb718a7 Mon Sep 17 00:00:00 2001 From: Liu Xiaoyi Date: Mon, 24 Apr 2023 03:32:33 +0800 Subject: [PATCH 3/5] Add changes to revision history --- revision-history.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/revision-history.yaml b/revision-history.yaml index 7eb2a75d..9d9c46a8 100644 --- a/revision-history.yaml +++ b/revision-history.yaml @@ -4,6 +4,7 @@ revisionHistory: # populated using the "version" that the Makefile grabs from git. Notable # additions to the specification should append entries here. thisVersion: + - Added fine-grind parameters and capabilities for memories. - Fix typos in force/release examples, force takes expr not int literal. - Delineate string and single-quoted/double-quoted string in grammar. - Deprecate reference-first statements. From 72007feed6b54e12f6f587b845b2fe875d2e72ae Mon Sep 17 00:00:00 2001 From: Liu Xiaoyi Date: Mon, 24 Apr 2023 19:52:28 +0800 Subject: [PATCH 4/5] Addressed custom ports in memories --- spec.md | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/spec.md b/spec.md index 73f7162a..b459a154 100644 --- a/spec.md +++ b/spec.md @@ -1684,6 +1684,9 @@ by the following parameters. holds the new value. 4. A read-under-write flag indicating the behavior when a memory location is written to while a read to that location is in progress. +5. An optional type representing the custom port of this memory. This custom + port is intended for post-synthesis flows, and should be ignored in + behavioral simulation. Integer literals for the number of elements and the read/write latencies _may not be string-encoded integer literals_. @@ -1713,6 +1716,7 @@ mem mymem : read => no write => with-mask write-latency => 1 + custom-port => {a:UInt<4>, flip b:UInt<2>} ``` In the example above, the type of `mymem`{.firrtl} is: @@ -1730,7 +1734,8 @@ In the example above, the type of `mymem`{.firrtl} is: en: UInt<1>, clk: Clock, wdata: {real: SInt<16>, imag: SInt<16>}, - mask: {real: UInt<1>, imag: UInt<1>}}} + mask: {real: UInt<1>, imag: UInt<1>}}, + custom: {a:UInt<4>, flip b:UInt<2>}} ``` The following sections describe how a memory's field types are calculated and @@ -1773,8 +1778,8 @@ integer type. The *non-masked portion* of the data value is defined as the set of data value leaf sub-elements where the corresponding mask leaf sub-element is high, or the entire data value if no mask is present. -Some of those fields are absent if the capability is reduced. The -functionalities and the condition of their presense is as followed: +Some of those fields are absent if the capability is reduced. Their +functionalities and the condition of their presense are as followed: - `clk`{.firrtl}: Always presents. @@ -1864,6 +1869,18 @@ A memory with a constant data-type represents a ROM and may not have ports with write capability. It is beyond the scope of this specification how ROMs are initialized. + +### Custom port + +Custom ports are intended for post synthesis flows that require memory instances +to have additional control signals. Behavorial simulators should ignore these +ports, in the following way: + +- All input signals (into the memory) should be treated as dangling + wires. +- All output signals (from the memory) have unspecified (implementation defined) + values. + ## Instances FIRRTL modules are instantiated with the instance statement. The following @@ -3632,14 +3649,15 @@ write_cap = ( "no" | "no-mask" | "with-mask" ) ; memory_port = "port" , id , ":" , [ info ] , newline , indent , "read" , "=>" , read_cap , newline , "write" , "=>" , write_cap , newline , - [ "read-latency" , "=>" , int , newline ], - [ "write-latency" , "=>" , int , newline ], + [ "read-latency" , "=>" , int , newline ] , + [ "write-latency" , "=>" , int , newline ] , dedent ; memory = "mem" , id , ":" , [ info ] , newline , indent , "data-type" , "=>" , type , newline , "depth" , "=>" , int , newline , "read-under-write" , "=>" , ruw , newline , { "port" , "=>" , memory_port , newline } , + [ "custom-port" , "=>" , type , newline ] , dedent ; (* Force and Release *) From e6311a7d8c645ed8ea3698eb56b81fc399d418c3 Mon Sep 17 00:00:00 2001 From: Liu Xiaoyi Date: Tue, 25 Apr 2023 19:29:19 +0800 Subject: [PATCH 5/5] Various fixes regarding the new memory statment --- spec.md | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/spec.md b/spec.md index b459a154..6d8c8a00 100644 --- a/spec.md +++ b/spec.md @@ -1671,7 +1671,8 @@ by the following parameters. 2. A positive integer literal representing the number of elements in the memory. -3. A variable number of named ports, each having following parameters: +3. A variable number of named ports, each having the following parameters in + this order: 1. A read flag indicating the read capability of this port. 2. A write flag indicating the write capability of this port. 3. If the port can read, a non-negative integer literal indicating the read @@ -1716,7 +1717,7 @@ mem mymem : read => no write => with-mask write-latency => 1 - custom-port => {a:UInt<4>, flip b:UInt<2>} + custom-port custom => {a:UInt<4>, flip b:UInt<2>} ``` In the example above, the type of `mymem`{.firrtl} is: @@ -1869,17 +1870,12 @@ A memory with a constant data-type represents a ROM and may not have ports with write capability. It is beyond the scope of this specification how ROMs are initialized. - ### Custom port Custom ports are intended for post synthesis flows that require memory instances -to have additional control signals. Behavorial simulators should ignore these -ports, in the following way: - -- All input signals (into the memory) should be treated as dangling - wires. -- All output signals (from the memory) have unspecified (implementation defined) - values. +to have additional control signals. During behavioral simulations, the behavior +of custom ports is undefined. Behavorial simulators may reject custom ports, +either by a compilation error, or a runtime error. ## Instances @@ -3656,8 +3652,8 @@ memory = "mem" , id , ":" , [ info ] , newline , indent , "data-type" , "=>" , type , newline , "depth" , "=>" , int , newline , "read-under-write" , "=>" , ruw , newline , - { "port" , "=>" , memory_port , newline } , - [ "custom-port" , "=>" , type , newline ] , + { memory_port , newline } , + [ "custom-port" , id , "=>" , type , newline ] , dedent ; (* Force and Release *)