Skip to content

Get: (a_size = 1)

Muhammad Hadir Khan edited this page Aug 11, 2020 · 6 revisions

This page deals with the configuration when a_size = 1. This means that the Host wants to read 2 bytes of data since 21 = 2 bytes.

For this overview we will assume the following memory organisation

Memory

a_address and a_mask Possibilities

Since we are reading two bytes (a_size = 1) the a_address will only have even addressing as shown in the figure above. The a_mask selects the two byte lanes to read from. a_mask must have two contiguous bits set meaning 'b0011 and 'b1100 are the only options when a_size = 1. Which means if we want to read from the zeroth and first byte lanes then a_mask = 'b0011. One HIGH bit of a_mask indicates the active byte lane.

a_address[31:0] a_mask[3:0]
'd0 'b0011
'd2 'b1100
'd4 'b0011
'd6 'b1100
'd8 'b0011
. .
. .

Note: The 'd in above table indicates decimal representation and the 'b indicates binary representation.

Example 1: Reading two bytes 2F FF from Memory

If we want to read two bytes 2F FF from memory the even address to access it will be a_address = 'd6 and mask should be a_mask = 'b1100. This reads 0x2FFF from the memory as shown above in the diagram as well.

Example 2: Reading two bytes E0 AB from Memory

If we want to read two bytes E0 AB from memory the even address to access it will be a_address = 'd8 and mask should be a_mask = 'b0011. This read 0xE0AB from the memory.

Functional verification design

Following are the points needed to be considered when dealing with reading two bytes (Get: a_size = 1)

  1. a_address should only be even (0, 2, 4, 6, 8, 10, 12, 14, 16 ...)
  2. a_mask must have only two bits active and contiguous at any given time.
  3. a_mask must be aligned with a_address at any given time according to the table given above.
// 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())

when(a_size === 0.U) {    // 1 Byte covered in Get: (a_size = 0)
  addr_chk := true.B
  mask_chk := ~((a_mask & ~mask).orR)  
} .elsewhen(a_size === 1.U) {    // 2 Bytes
  addr_chk := ~a_address(0)
  mask_chk := Mux(a_address(1), ~((a_mask & "b0011".U).orR), ~((a_mask & "b1100".U).orR))
}

Note: The code above is taken from the previous case where a_size = 0 and was modified to deal with a_size = 1 as well.

This time we need to check the a_address as well since it must be even. So we extract the zeroth bit of a_address with a_address(0). If this bit is set then the address would be odd and we would invert the result to 'b0 in order to make the addr_chk := false.B.

The logic for handling mask_chk ensures that any given time only two bits are HIGH due to a_size = 1 and they must be contiguous and must only be either 'b0011 or 'b1100 according to the address provided.

We will go through some test cases to explain the reasoning for this logic and ensure the logic works well i.e passes the check when inputs are correct and fails them if the inputs are wrong.

Test Case: Example 1 (Reading two bytes 2FFF from Memory)

Input 1:
a_address[31:0] a_size[1:0] a_mask[3:0]
'h6 'h1 'b1100

With these inputs incoming let's analyse what is happening in the wires we declared addr_chk, mask_chk. Note: We won't be using the mask wire in this condition.

addr_chk

The addr_chk is wired with the logic which ensures that the zeroth bit must not be set in order to ensure even addressing.

Since we extract the zeroth bit and invert it ~a_address(0) so we get,

addr_chk := true.B

because a_address(0) gives 'b0 in this case and inverting it results in 'b1 or true.B

mask_chk

We know that a_mask in this condition must always have 2 bits HIGH, they must be contiguous and they must be select either the LSB byte lanes 'b0011 or the MSB byte lanes 'b1100.

In this condition we have a_mask = 'b1100 as input coming in. We use a Mux() construct of Chisel to control the wiring of mask_chk. The condition for the Mux is the first bit of a_address. If this bit is set it means the address we are getting is not word aligned and can be the following (2, 6, 10, 14, 18, 22 ... ) and we use this logic ~((a_mask & "b0011".U).orR) to set the mask_chk. Otherwise, if the first bit of a_address is not set, we use the next logic ~((a_mask & "b1100".U).orR) to set the mask_chk.

Clone this wiki locally