| {{% lowrisc-doc-hdr Primitive Component: Packer }} |
| |
| {{% section1 Overview }} |
| |
| `prim_packer` is a module that receives partial writes then packs and creates |
| full configurable width writes. It is one of a set of shared primitive modules |
| available for use within OpenTitan as referred to in the Comportability |
| Specification section on shared primitives. |
| |
| {{% section2 Parameters }} |
| |
| Name | type | Description |
| -----|------|------------- |
| InW | int | Input data width |
| OutW | int | Output data width |
| |
| {{% section2 Signal Interfaces }} |
| |
| Name | In/Out | Description |
| -------------|--------|------------- |
| valid_i | input | |
| data_i[InW] | input | |
| mask_i[InW] | input | input bit mask. ones in the mask_i shall be contiguous. |
| ready_o | output | Indicates if prim_packer is able to accept the data or not. |
| valid_o | output | |
| data_o[OutW] | output | |
| mask_o[OutW] | output | |
| ready_i | input | |
| flush_i | input | If 1, send out remnant and clear state |
| flush_done_o | output | Indicates flush operation is completed |
| |
| {{% section1 Theory of Opeations }} |
| |
| ```code |
| /----------\ |
| valid_i | | valid_o |
| ---------->| |---------------> |
| data_i | stacked | data_o |
| =====/====>| register |=======/=======> |
| [InW] | | [OutW] |
| mask_i | | mask_o |
| =====/====>| InW+OutW |=======/=======> |
| ready_o |----------| ready_i |
| <----------| |<--------------- |
| | | |
| \----------/ |
| ``` |
| |
| `prim_packer` accepts `InW` bits of data and bitmask signals. If `valid_i` is |
| asserted, `prim_packer` stores it to internal register if the size isn't big |
| enough to `OutW` data width and repeats it until it exceeds `OutW`. In most |
| case, `mask_o` is full bits write, `{OutW{1'b1}}`. But when `flush_i` is |
| asserted, `prim_packer` tries to sends out any remaining data in the internal |
| storage. In this case, `mask_o` may become partial 1. |
| |
| The internal register size is `InW + OutW` bits to safely store the incoming |
| data and sends out the data to `data_o` port. |
| |
| |
| ```wavejson |
| { signal: [ |
| { name: 'valid_i', wave: '01.01.....0.'}, |
| { name: 'data_i[3:0]', wave: 'x==x===.==x.', data:'0 1 2 3 4 5 6'}, |
| { name: 'mask_i[3:0]', wave: 'x==x===.==x.', data:'F F F F F F F'}, |
| { name: 'ready_o', wave: '1.....01....'}, |
| { name: 'valid_o', wave: '0.10101.1010'}, |
| { name: 'data_o[5:0]', wave: 'x.=x=x=.=x=x', data:'10h 08h 03h 15h 06h'}, |
| { name: 'mask_o[5:0]', wave: 'x.=x=x=.=x=x', data:'3Fh 3Fh 3Fh 3Fh Fh '}, |
| { name: 'ready_i', wave: '1.....01....'}, |
| { name: 'flush_i', wave: '0.........10'}, |
| ], |
| |
| head:{ |
| text: 'prim_packer', |
| tick: ['0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 '] |
| } |
| } |
| ``` |
| |
| Above waveform shows the case of InW := 4 and OutW := 6. After the first |
| transaction, `prim_packer` has `0h` in the storage. So when second `valid_i` is |
| asserted, it combines `0h` and incoming data `1h` and creates output `10h`, |
| `6'b01_0000`. And store `2'b00` into the internal storage from `data_i[3:2]`. |
| Next transaction combines this and input data `2h` then creates `6'b00_1000`. |
| |
| If `read_i` is dropped as seen at pos 6, `prim_packer` drops the `ready_o` as it |
| cannot store the incoming data. To reduce the internal logic complexity, it |
| drops the ready even above case can store the incoming data as 4bit is |
| available. |
| |
| At the end of the transaction, if `flush_i` is asserted, it sends out the |
| remaining data. In this case, `mask_o` isn't full ones but representing only |
| available bits `6'b00_1111`. |
| |
| `prim_packer` only supports pack to right. If any design to support pack to left |
| (filling MSB first), the design needs to reverse the bit order (in some case, |
| reversing the byte-order is necessary like HMAC) before pushing to the packer |
| and reverse back after the data output. |