Skip to content

Commit 64e9244

Browse files
committed
Upstreaming inter-level logical partitioning
1 parent 9e5a6ba commit 64e9244

File tree

9 files changed

+889
-462
lines changed

9 files changed

+889
-462
lines changed

hardware/bbq/generator/bbq.py

Lines changed: 267 additions & 151 deletions
Large diffs are not rendered by default.

hardware/bbq/generator/bbq_level.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
11
#!/usr/bin/python3
2+
from __future__ import annotations
3+
4+
import typing
25
from abc import ABC, abstractmethod
36

47
from codegen import CodeGen
58

9+
# Hack for type hinting with circular imports
10+
if typing.TYPE_CHECKING: from bbq import BBQ
11+
612

713
class BBQLevel(ABC):
814
"""Represents a generic BBQ level."""
9-
def __init__(self, start_cycle: int, num_levels: int) -> None:
15+
def __init__(self, bbq: BBQ, start_cycle: int) -> None:
16+
self.bbq = bbq # Pointer to BBQ instance
1017
self.start_cycle = start_cycle # Starting pipeline cycle
11-
self.num_bitmap_levels = num_levels # Number of bitmap levels
1218

1319
# Housekeeping
1420
self.prev_level: BBQLevel = None # Pointer to the prev level
1521
self.next_level: BBQLevel = None # Pointer to the next level
1622

17-
# Miscellaneous
18-
self.fl_rd_delay: int = None # Free-list read delay
23+
24+
@property
25+
def num_bitmap_levels(self) -> int:
26+
"""Returns the bitmap level count."""
27+
return self.bbq.num_bitmap_levels
1928

2029

2130
@property
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#!/usr/bin/python3
2+
from __future__ import annotations
3+
4+
import typing
5+
6+
from bbq_level import BBQLevel
7+
from codegen import CodeGen
8+
9+
# Hack for type hinting with circular imports
10+
if typing.TYPE_CHECKING: from bbq import BBQ
11+
12+
13+
class BBQLevelIngress(BBQLevel):
14+
"""Represents the ingress level in BBQ."""
15+
def __init__(self, bbq: BBQ, start_cycle: int) -> None:
16+
super().__init__(bbq, start_cycle)
17+
18+
19+
def name(self) -> str:
20+
"""Canonical level name."""
21+
return "ingress"
22+
23+
24+
def latency(self) -> int:
25+
"""Latency in cycles."""
26+
return 0
27+
28+
29+
def emit_stage_defs(self, cg: CodeGen) -> None:
30+
"""Emit per-stage definitions."""
31+
cycle = self.start_cycle
32+
33+
cg.comment("Stage {} metadata".format(cycle))
34+
cg.align_defs([
35+
("logic", "valid_s{};".format(cycle)),
36+
("counter_t", "old_occupancy_s{};".format(cycle)),
37+
("counter_t", "new_occupancy_s{};".format(cycle)),
38+
("counter_t", "reg_old_occupancy_s{};".format(cycle)),
39+
("counter_t", "reg_new_occupancy_s{};".format(cycle)),
40+
])
41+
cg.emit()
42+
cycle += 1
43+
44+
45+
def emit_state_dependent_combinational_logic(self, cg: CodeGen) -> None:
46+
"""Emit state-dependent combinational logic."""
47+
pass
48+
49+
50+
def emit_combinational_default_assigns(self, cg: CodeGen) -> None:
51+
"""Emit default assignments."""
52+
cycle = self.start_cycle
53+
cg.emit("valid_s{} = 0;".format(cycle))
54+
55+
if self.bbq.is_logically_partitioned:
56+
cg.emit("old_occupancy_s{} = occupancy[reg_bbq_id_s[{}]];"
57+
.format(cycle, cycle - 1))
58+
else:
59+
cg.emit("old_occupancy_s{} = occupancy;".format(cycle))
60+
61+
cycle += 1
62+
63+
64+
def emit_state_agnostic_combinational_logic(self, cg: CodeGen) -> None:
65+
"""Emit state-agnostic combinational logic."""
66+
seq_cycle = self.start_cycle - 1
67+
68+
old_occupancy = "old_occupancy_s{}".format(seq_cycle + 1)
69+
cg.comment([
70+
"Stage {}: Determine operation validity. Disables the pipeline".format(seq_cycle + 1),
71+
"stage if the BBQ is empty (deques), or FL is empty (enques).",
72+
], True)
73+
cg.start_conditional("if", "reg_valid_s[{}]".format(seq_cycle))
74+
cg.align_assignment("valid_s{}".format(seq_cycle + 1), [
75+
"(",
76+
"(reg_is_enque_s[{}] && !fl_empty) ||".format(seq_cycle),
77+
("(!reg_is_enque_s[{}] && ({}[0] |"
78+
.format(seq_cycle, old_occupancy)),
79+
80+
(" {}[WATERLEVEL_IDX])));"
81+
.format(old_occupancy))
82+
], "=", True)
83+
cg.end_conditional("if")
84+
85+
cg.comment("Update the occupancy counter")
86+
cg.align_ternary(
87+
"new_occupancy_s{}[WATERLEVEL_IDX-1:0]".format(seq_cycle + 1),
88+
["reg_is_enque_s[{}]".format(seq_cycle)],
89+
["({}[WATERLEVEL_IDX-1:0] + 1)".format(old_occupancy),
90+
"({}[WATERLEVEL_IDX-1:0] - 1)".format(old_occupancy)],
91+
"=", True, False)
92+
93+
cg.emit()
94+
cg.align_assignment(
95+
"new_occupancy_s{}[WATERLEVEL_IDX]".format(seq_cycle + 1),
96+
["(reg_is_enque_s[{}] ?".format(seq_cycle),
97+
"({0}[WATERLEVEL_IDX] | {0}[0]) :".format(old_occupancy),
98+
"((|{0}[WATERLEVEL_IDX-1:2]) | (&{0}[1:0])));".format(old_occupancy),
99+
],
100+
"=", True)
101+
102+
cg.emit()
103+
cg.comment("If enqueing, also deque the free list")
104+
cg.start_conditional("if", ("valid_s{} && reg_is_enque_s[{}]"
105+
.format(seq_cycle + 1, seq_cycle)))
106+
107+
cg.emit("fl_rdreq = 1;")
108+
cg.end_conditional("if")
109+
cg.emit()
110+
111+
112+
def emit_sequential_pipeline_logic(self, cg: CodeGen) -> None:
113+
"""Emit sequential logic for this level."""
114+
cycle = self.end_cycle
115+
cg.comment([
116+
"Stage {}: Determine operation validity. Disables the pipeline".format(cycle),
117+
"stage if the BBQ is empty (deques) or FL is empty (enqueues).",
118+
], True)
119+
120+
value_override = {"reg_valid_s": "valid_s{}".format(cycle)}
121+
self.bbq.emit_sequential_primary_signals(cycle, value_override)
122+
123+
cg.emit([
124+
"reg_old_occupancy_s{0} <= old_occupancy_s{0};".format(cycle),
125+
"reg_new_occupancy_s{0} <= new_occupancy_s{0};".format(cycle),
126+
])
127+
cg.emit()
128+
129+
cg.start_conditional("if", "valid_s{}".format(cycle))
130+
cg.emit("occupancy{} <= new_occupancy_s{};"
131+
.format("[reg_bbq_id_s[{}]]".format(cycle - 1) if
132+
self.bbq.is_logically_partitioned else "", cycle))
133+
134+
cg.end_conditional("if")
135+
cg.emit()
136+
137+
cg.start_ifdef("DEBUG")
138+
id_str_prefix = ("logical ID: %0d, "
139+
if self.bbq.is_logically_partitioned else "")
140+
141+
id_val_prefix = ("reg_bbq_id_s[{}], ".format(cycle - 1)
142+
if self.bbq.is_logically_partitioned else "")
143+
144+
cg.start_conditional("if", ("reg_valid_s[{}] && !valid_s{}"
145+
.format(cycle - 1, cycle)))
146+
cg.emit("$display(")
147+
cg.emit([
148+
("\"[BBQ] At S{0} ({1}op: %s), rejected at Stage {2}->{0}\","
149+
.format(cycle, id_str_prefix, cycle - 1)),
150+
151+
"{}reg_op_type_s[{}].name);".format(id_val_prefix, cycle - 1),
152+
], True, 4)
153+
cg.end_conditional("if")
154+
155+
cg.start_conditional("if", "valid_s{}".format(cycle))
156+
cg.emit("$display(")
157+
cg.emit([
158+
"\"[BBQ] At S{} ({}op: %s), updating occupancy\",".format(cycle, id_str_prefix),
159+
"{}reg_op_type_s[{}].name, \" from %0d to %0d\",".format(id_val_prefix, cycle - 1),
160+
"old_occupancy_s{}[WATERLEVEL_IDX-1:0],".format(cycle),
161+
"new_occupancy_s{}[WATERLEVEL_IDX-1:0]);".format(cycle),
162+
], True, 4)
163+
cg.end_conditional("if")
164+
cg.end_ifdef()
165+
cg.emit()

0 commit comments

Comments
 (0)