-
Notifications
You must be signed in to change notification settings - Fork 10
Get: (a_size = 1)
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
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.
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.
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.
Following are the points needed to be considered when dealing with reading two bytes (Get: a_size = 1
)
-
a_address
should only be even (0, 2, 4, 6, 8, 10, 12, 14, 16 ...) -
a_mask
must have only two bits active and contiguous at any given time. -
a_mask
must be aligned witha_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.
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.
Let's visualise the a_address bits in a concise way:
a_address[31] | a_address[30] | ... | a_address[2] | a_address[1] | a_address[0] |
---|---|---|---|---|---|
0 | 0 | ... | 1 | 1 | 0 |
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
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
.
In our case (considering the input we receive), the first bit of a_address
is set as can be seen above where we visualise the a_address
bits which means the address we receive would be even but not word aligned. So the first condition of Mux()
would be used to wire the mask_chk
.
Let's see what is happening in the logic ~((a_mask & "b0011".U).orR)
. This logic needs to ensure that the received a_mask
must be set as 'b1100
.
We AND the a_mask
with "b0011".U
which results in 1100 & 0011 = 0000
.
Then we use the .orR
OR reduction to check if any bits are set. Here 'b0000.orR
returns false.B
since no bits are set.
Finally, we invert the result ~false.B
which results in:
mask_chk := true.B
This means that since Input 1 parameters were correct our logic correctly ensures they are right and passes the check. ✅
Let's repeat the same test case with wrong a_address and then with wrong a_mask.
a_address[31:0] | a_size[1:0] | a_mask[3:0] |
---|---|---|
'h7 | 'h1 | 'b1100 |
We just changed the a_address
and kept the a_size
and a_mask
same.
With these inputs incoming let's analyse what is happening in the wires we declared addr_chk
, mask_chk
.
Let's visualise the a_address
bits:
a_address[31] | a_address[30] | ... | a_address[2] | a_address[1] | a_address[0] |
---|---|---|---|---|---|
0 | 0 | ... | 1 | 1 | 1 |
Since we extract the zeroth bit and invert it ~a_address(0)
so we get,
addr_chk := false.B
because a_address(0) gives 'b1
in this case and inverting it results in 'b0
or false.B
This means that our address check fails and even if a_mask
is set correctly and mask_chk
passes, we have a wrong address and this will generate an error and our test case with these inputs, fails. ❌
Now let's try with the correct address but wrong alignment of a_mask
.
a_address[31:0] | a_size[1:0] | a_mask[3:0] |
---|---|---|
'h6 | 'h1 | 'b0011 |
Here the a_address
is correct but since the address is not word aligned a_mask
cannot select LSB byte lanes 'b0011
. Let's see if you verification logic correctly catches the error and fails the mask_chk
.
Let's visualise the a_address
bits:
a_address[31] | a_address[30] | ... | a_address[2] | a_address[1] | a_address[0] |
---|---|---|---|---|---|
0 | 0 | ... | 1 | 1 | 0 |
In this condition we have a_mask = 'b0011
as input coming in. Since the first bit of a_address
is set as shown above, the Mux()
would wire the mask_chk
with this logic ~((a_mask & "b0011".U).orR)
.
We AND the a_mask
with "b0011".U
which results in 0011 & 0011 = 0011
.
Then we use the .orR
OR reduction to check if any bits are set. Here 'b0011.orR
returns true.B
since some bits are set.
Finally, we invert the result ~true.B
which results in:
mask_chk := false.B
And this correctly ensures that our check fails the input case where the a_mask
was incorrectly configured. ❌