Skip to content

PutFullData

Muhammad Hadir Khan edited this page Aug 12, 2020 · 7 revisions

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:

Memory

When a_size = 0

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.

Example 1: Writing Byte FF to Memory at address 0.

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:

PutFullData Write

Functional verification design

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.

Test Case: Example 1 (Writing Byte FF to Memory)

Input 1:
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

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
fulldata_chk

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. ✅

Input 2:
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
fulldata_chk

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)

Clone this wiki locally