-
Notifications
You must be signed in to change notification settings - Fork 10
PutFullData
This page deals with the elaboration of PutFullData
operation. This operation is initiated by the host on channel A and expects a response of AccessAck
from the device on channel D.
The main difference between PutFullData
and PutPartialData
is that the former operation must write all the data indicated by a_size
while the latter can write all the data indicated by a_size
or it can write less than it depending upon the configuration of a_mask
.
The other difference that the specification indicates is that in PutFullData
the a_mask
must have contiguous bits set for example in a 2 byte data write, a_mask
can only be 'b0011
or 'b1100
not 'b0101
or any other configuration like this, however there is no such contiguous bits restriction for the a_mask
in the PutPartialData
operation.
Note: For our implementation we make sure that PutPartialData
also has contiguous bits of a_mask
set.
For this overview we will be using this figure of memory for convenience:
This means that the host wants to write 2a_size = 20 = 1 byte of data. The address can be word aligned as well as subword aligned which means we do not need to check for address, what matters is a_mask
. This is exactly the same as we discussed in the Get:(a_size = 0) operation earlier. Read the Get operation first before reading further as that section elaborates in detail what is happening. Following are the possibilities of a_address
and a_mask
as covered previously:
a_address[31:0] | a_mask[3:0] |
---|---|
'd0 | 'b0001 |
'd1 | 'b0010 |
'd2 | 'b0100 |
'd3 | 'b1000 |
'd4 | 'b0001 |
'd5 | 'b0010 |
'd6 | 'b0100 |
'd7 | 'b1000 |
. | . |
. | . |
Note: The 'd in above table indicates decimal representation and the 'b indicates binary representation.
For this, we will set the a_mask = 'b0001
and a_address = 'h0
. This will write one byte of data to the memory at address 0 on the byte lane set by a_mask
.
Here is a little animation to demonstrate what is happening:
For PutFullData
we just create one additional check fulldata_chk
which is only used when the opcode is of PutFullData
.
// Our own mask created using the a_address
// If data bus width (DBW) is 32-bits then 32/8 = 4 bytes so a_mask uses 4 bits to represent the active byte lane.
val mask = Wire(UInt((DBW/8).W))
mask := (1 << a_address(1,0))
// Creating two wires of Chisel.Bool type in order to set them `true.B` if the check is passed or `false.B` if the check is failed.
val addr_chk = Wire(Bool())
val mask_chk = Wire(Bool())
val fulldata_chk = Wire(Bool()) // This is the new line added
when(a_size === 0.U) {
addr_chk := true.B
mask_chk := ~((a_mask & ~mask).orR)
fulldata_chk := (a_mask & mask).orR // This is the new line added
}
Note: This is the code that is elaborated in the Get(a_size = 0) with additional code lines marked with the comments.
The logic (a_mask & mask).orR
is the new one added for the PutFullData
. This ensures that a_size
matches with a_mask
.
a_address[31:0] | a_size[1:0] | a_mask[3:0] |
---|---|---|
'h0 | 'h0 | 'b0001 |
With these inputs incoming let's analyse what is happening in the wires mask
and fulldata_chk
.
mask = (1 << a_address(1,0))
a_address bits are as follows:
a_address[31] | a_address[30] | ... | a_address[1] | a_address[0] |
---|---|---|---|---|
0 | 0 | ... | 0 | 0 |
Since we extract the first two bits of a_address
we get 'b00
So 'b0001 << 'b00
results in the same 'b0001
or 'd1
Which means,
mask := 1.U
We are using the mask
and a_mask
to set this wire. Currently we have mask := 'b0001
and a_mask := 'b0001
.
In the first step we do a bitwise AND operation between a_mask
and mask
as:
a_mask & mask
This results in
'b0001 & 'b0001 = 'b0001
The .orR
is a Chisel function for OR Reduction. Which returns true if any bit is set. Here it checks if any bit is set or not. As seen above there is a bit set so,
'b0001.orR
returns true. Which makes the fulldata_chk := true.B
and passes the check. ✅
a_address[31:0] | a_size[1:0] | a_mask[3:0] |
---|---|---|
'h0 | 'h0 | 'b0100 |
With these inputs incoming let's analyse what is happening in the wires mask
and fulldata_chk
.
Since the a_address = 'h0
same as the above Input 1 the mask
would be set as:
mask := 1.U
We are using the mask
and a_mask
to set this wire. Currently we have mask := 'b0001
and a_mask := 'b0100
.
In the first step we do a bitwise AND operation between a_mask
and mask
as:
a_mask & mask
This results in
'b0001 & 'b0100 = 'b0000
The .orR
is a Chisel function for OR Reduction. Which returns true if any bit is set. Here it checks if any bit is set or not. As seen above there is no bit set so,
'b0000.orR
returns false. Which makes the fulldata_chk := false.B
and fails the check. ❌
This check rightly fails since the a_address
and a_mask
are not aligned. If a_address = 'h0
then a_mask
must only be 'b0001
to write the first byte of data on to the first address location. According to the tilelink specification a_address
, a_size
and a_mask
must correspond with one another. (See page 56)