Skip to content

Commit 7a19e08

Browse files
authored
[LSQ] Minor fixes and simplifications (#993)
This includes a number of small fixes and improvements to the LSQ generator that have been cherry-picked from my semester project code. - Clean up computation of `empty{Ld,St}AddrW` in the configuration - Add assertions to ensure load/store queues are large enough so that all groups can be allocated. - Add missing pipeline register `ldq_head_oh_pcomp` - Simplify the `IntToBits` helper function and add clear error messages (e.g., for negative inputs)
1 parent 6a85347 commit 7a19e08

3 files changed

Lines changed: 24 additions & 24 deletions

File tree

tools/backend/lsq-generator-python/core_gen/configs.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,10 @@ def __init__(self, config: dict) -> None:
9393
self.ldqAddrW = math.ceil(math.log2(self.numLdqEntries))
9494
self.stqAddrW = math.ceil(math.log2(self.numStqEntries))
9595

96-
# Original empty assignment assumes the size of load or store queue to be always a multiple of 2
97-
if (self.numLdqEntries & (self.numLdqEntries % 2 == 0)):
98-
self.emptyLdAddrW = math.ceil(math.log2(self.numLdqEntries+1))
99-
else:
100-
self.emptyLdAddrW = math.ceil(math.log2(self.numLdqEntries)) + 1
101-
102-
if (self.numStqEntries & (self.numStqEntries % 2 == 0)):
103-
self.emptyStAddrW = math.ceil(math.log2(self.numStqEntries+1))
104-
else:
105-
self.emptyStAddrW = math.ceil(math.log2(self.numStqEntries)) + 1
96+
# Use one more bit to be able to represent the empty state of the queue when the number of entries is a power of 2
97+
self.emptyLdAddrW = self.ldqAddrW + 1
98+
self.emptyStAddrW = self.stqAddrW + 1
99+
106100
# Check the number of ports, if num*Ports == 0, set it to 1
107101
self.ldpAddrW = math.ceil(math.log2(self.numLdPorts if self.numLdPorts > 0 else 1))
108102
self.stpAddrW = math.ceil(math.log2(self.numStPorts if self.numStPorts > 0 else 1))
@@ -120,3 +114,8 @@ def __init__(self, config: dict) -> None:
120114
assert (len(self.gaLdOrder) == self.numGroups)
121115
assert (len(self.gaLdPortIdx) == self.numGroups)
122116
assert (len(self.gaStPortIdx) == self.numGroups)
117+
118+
# An LSQ with N load/store entries can only support up to N-1 loads/stores per group.
119+
for i in range(self.numGroups):
120+
assert self.gaNumLoads[i] < self.numLdqEntries, f"group {i}: too many loads ({self.gaNumLoads[i]}) for load queue with {self.numLdqEntries} entries!"
121+
assert self.gaNumStores[i] < self.numStqEntries, f"group {i}: too many stores ({self.gaNumStores[i]}) for store queue with {self.numStqEntries} entries!"

tools/backend/lsq-generator-python/core_gen/generators/lsq.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,8 @@ def generate(self, lsq_submodules, path_rtl) -> None:
599599
if self.configs.pipe0:
600600
can_bypass_p0.regInit(init=[0]*self.configs.numLdqEntries)
601601

602+
ldq_head_oh_pcomp = LogicVec(
603+
ctx, 'ldq_head_oh_pcomp', pipe_comp_type, self.configs.numLdqEntries)
602604
ldq_alloc_pcomp = LogicArray(
603605
ctx, 'ldq_alloc_pcomp', pipe_comp_type, self.configs.numLdqEntries)
604606
ldq_addr_valid_pcomp = LogicArray(
@@ -626,6 +628,7 @@ def generate(self, lsq_submodules, path_rtl) -> None:
626628
store_completed = LogicArray(ctx, 'store_completed', 'w', self.configs.numStqEntries)
627629

628630
if self.configs.pipeComp:
631+
ldq_head_oh_pcomp.regInit(init=0)
629632
ldq_alloc_pcomp.regInit(init=[0]*self.configs.numLdqEntries)
630633
ldq_addr_valid_pcomp.regInit()
631634
stq_alloc_pcomp.regInit(init=[0]*self.configs.numStqEntries)
@@ -635,6 +638,7 @@ def generate(self, lsq_submodules, path_rtl) -> None:
635638
addr_same_pcomp.regInit()
636639
store_is_older_pcomp.regInit()
637640

641+
arch += Op(ctx, ldq_head_oh_pcomp, ldq_head_oh)
638642
for i in range(0, self.configs.numLdqEntries):
639643
arch += Op(ctx, (ldq_alloc_pcomp, i), (ldq_alloc, i))
640644
arch += Op(ctx, (ldq_addr_valid_pcomp, i),
@@ -747,7 +751,7 @@ def generate(self, lsq_submodules, path_rtl) -> None:
747751
ctx, 'ldq_head_oh_p0', pipe0_type, self.configs.numLdqEntries)
748752
if self.configs.pipe0:
749753
ldq_head_oh_p0.regInit()
750-
arch += Op(ctx, ldq_head_oh_p0, ldq_head_oh)
754+
arch += Op(ctx, ldq_head_oh_p0, ldq_head_oh_pcomp)
751755

752756
can_load_list = []
753757
can_load_list.append(can_load)

tools/backend/lsq-generator-python/core_gen/utils.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -420,22 +420,19 @@ def MaskLess(din, size) -> str:
420420

421421
def IntToBits(din, size=None) -> str:
422422
if size == None:
423-
if din:
423+
if din == 1:
424424
return "'1'"
425-
else:
425+
elif din == 0:
426426
return "'0'"
427+
else:
428+
raise ValueError("IntToBits: Invalid value for size=None! Cannot represent the value as a single bit!")
427429
else:
428-
str_ret = '"'
429-
for i in range(0, size):
430-
if din % 2 == 0:
431-
str_ret = "0" + str_ret
432-
else:
433-
str_ret = "1" + str_ret
434-
din = din // 2
435-
str_ret = '"' + str_ret
436-
if din != 0:
437-
raise ValueError("Unknown value!")
438-
return str_ret
430+
if din < 0:
431+
raise ValueError("IntToBits: Negative value cannot be converted to bits!")
432+
if din >= (1 << size):
433+
raise ValueError(f"IntToBits: Value {din} cannot be represented with {size} bit(s)!")
434+
bits = f"{din:0{size}b}"
435+
return f'"{bits}"'
439436

440437

441438
def Zero(size) -> str:

0 commit comments

Comments
 (0)