11import 'package:rohd/rohd.dart' ;
22import 'package:rohd_hcl/rohd_hcl.dart' ;
33
4+ /// Streams configuration bits into the FPGA fabric config chain.
45class FabricConfigLoader extends Module {
56 Logic get clk => input ('clk' );
67 Logic get start => input ('start' );
@@ -37,92 +38,81 @@ class FabricConfigLoader extends Module {
3738 final wordWidth = readPort.data.width;
3839 final wordsNeeded = (totalBits + wordWidth - 1 ) ~ / wordWidth;
3940
40- // Use rohd_hcl Deserializer to collect words from memory into a
41- // flat LogicArray, then a Serializer to shift them out bit-by-bit.
4241 final active = Logic (name: 'active' );
4342 final wordAddr = Logic (width: readPort.addr.width, name: 'wordAddr' );
44- final wordCount = Logic (width: wordsNeeded.bitLength, name: 'wordCount' );
45- final fetchDone = Logic (name: 'fetchDone' );
46-
47- // --- Word fetch FSM: reads words from memory sequentially ---
48- Sequential (clk, [
49- If (
50- start,
51- then: [
52- active < Const (1 ),
53- wordAddr < Const (0 , width: wordAddr.width),
54- wordCount < Const (0 , width: wordCount.width),
55- fetchDone < Const (0 ),
56- ],
57- orElse: [
58- If (
59- active & ~ fetchDone,
60- then: [
61- wordCount < wordCount + 1 ,
62- wordAddr < wordAddr + 1 ,
63- If (
64- wordCount.eq (Const (wordsNeeded - 1 , width: wordCount.width)),
65- then: [fetchDone < Const (1 )],
66- ),
67- ],
68- ),
69- ],
70- ),
71- ]);
72-
73- readPort.en <= active & ~ fetchDone;
74- readPort.addr <= wordAddr;
75-
76- // --- Deserializer: collects words into a wide register ---
77- final deser = Deserializer (
78- readPort.data,
79- wordsNeeded,
80- clk: clk,
81- reset: start,
82- enable: active & ~ fetchDone,
43+ final wordBuf = Logic (width: wordWidth, name: 'wordBuf' );
44+ final bitIdx = Logic (width: wordWidth.bitLength, name: 'bitIdx' );
45+ final totalShifted = Logic (
46+ width: totalBits.bitLength,
47+ name: 'totalShifted' ,
8348 );
84-
85- // --- Serializer: shifts the collected words out bit-by-bit ---
86- // We need to serialize the deserialized array one bit at a time.
87- // Use a simple bit counter + shift approach on the deserialized output.
88- final bitCounter = Logic (width: totalBits.bitLength, name: 'bitCounter' );
8949 final shifting = Logic (name: 'shifting' );
90- final shiftDone = Logic (name: 'shiftDone' );
91-
92- // Flatten the deserialized array into a single wide bus
93- final flatBits = Logic (width: wordsNeeded * wordWidth, name: 'flatBits' );
94- flatBits <=
95- deser.deserialized.elements
96- .map ((e) => e)
97- .toList ()
98- .reversed
99- .toList ()
100- .swizzle ();
101-
102- // Latch the flat bits when deserialization completes
103- final latchedBits = Logic (
104- width: wordsNeeded * wordWidth,
105- name: 'latchedBits' ,
106- );
50+ final wordReady = Logic (name: 'wordReady' );
51+ final allDone = Logic (name: 'allDone' );
10752
10853 Sequential (
10954 clk,
11055 [
11156 If (
112- deser.done & active ,
57+ start ,
11358 then: [
114- latchedBits < flatBits,
115- shifting < Const (1 ),
116- bitCounter < Const (0 , width: bitCounter.width),
59+ active < Const (1 ),
60+ wordAddr < Const (0 , width: wordAddr.width),
61+ bitIdx < Const (0 , width: bitIdx.width),
62+ totalShifted < Const (0 , width: totalShifted.width),
63+ shifting < Const (0 ),
64+ wordReady < Const (0 ),
65+ allDone < Const (0 ),
11766 ],
11867 orElse: [
11968 If (
120- shifting ,
69+ active & ~ allDone ,
12170 then: [
122- bitCounter < bitCounter + 1 ,
12371 If (
124- bitCounter.eq (Const (totalBits - 1 , width: bitCounter.width)),
125- then: [shifting < Const (0 ), shiftDone < Const (1 )],
72+ ~ shifting & ~ wordReady,
73+ then: [
74+ wordBuf < readPort.data,
75+ wordReady < Const (1 ),
76+ bitIdx < Const (0 , width: bitIdx.width),
77+ ],
78+ orElse: [
79+ If (
80+ wordReady & ~ shifting,
81+ then: [shifting < Const (1 )],
82+ orElse: [
83+ If (
84+ shifting,
85+ then: [
86+ bitIdx < bitIdx + 1 ,
87+ totalShifted < totalShifted + 1 ,
88+ If (
89+ totalShifted.eq (
90+ Const (totalBits - 1 , width: totalShifted.width),
91+ ),
92+ then: [
93+ // All bits shifted
94+ allDone < Const (1 ),
95+ shifting < Const (0 ),
96+ ],
97+ orElse: [
98+ If (
99+ bitIdx.eq (
100+ Const (wordWidth - 1 , width: bitIdx.width),
101+ ),
102+ then: [
103+ // Word exhausted, fetch next
104+ shifting < Const (0 ),
105+ wordReady < Const (0 ),
106+ wordAddr < wordAddr + 1 ,
107+ ],
108+ ),
109+ ],
110+ ),
111+ ],
112+ ),
113+ ],
114+ ),
115+ ],
126116 ),
127117 ],
128118 ),
@@ -131,15 +121,22 @@ class FabricConfigLoader extends Module {
131121 ],
132122 reset: start,
133123 resetValues: {
124+ active: Const (0 ),
134125 shifting: Const (0 ),
135- shiftDone: Const (0 ),
136- bitCounter: Const (0 , width: bitCounter.width),
137- latchedBits: Const (0 , width: latchedBits.width),
126+ wordReady: Const (0 ),
127+ allDone: Const (0 ),
128+ wordAddr: Const (0 , width: wordAddr.width),
129+ wordBuf: Const (0 , width: wordWidth),
130+ bitIdx: Const (0 , width: bitIdx.width),
131+ totalShifted: Const (0 , width: totalShifted.width),
138132 },
139133 );
140134
141- cfgIn <= mux (shifting, latchedBits[bitCounter], Const (0 ));
142- cfgLoad <= shiftDone;
143- done <= shiftDone & ~ active;
135+ readPort.en <= active & ~ allDone & ~ shifting & ~ wordReady;
136+ readPort.addr <= wordAddr;
137+
138+ cfgIn <= mux (shifting, wordBuf[bitIdx], Const (0 ));
139+ cfgLoad <= allDone;
140+ done <= allDone;
144141 }
145142}
0 commit comments