11//! Adapter from the RV32 pipeline simulator to the engine-level observer API.
22
33use crate :: capability:: {
4- PipelineEdge , PipelineEdgeKind , PipelineHazardKind , PipelineInspect , PipelineInstructionClass ,
5- PipelineSlotView , PipelineStageRole , PipelineStageView , PipelineStats , PipelineStatus ,
6- PipelineTimelineCell , PipelineTimelineRow , PipelineTimelineState , PipelineTraceKind ,
7- PipelineTraceView , PipelineUnitView ,
4+ PipelineEdge , PipelineEdgeKind , PipelineInspect , PipelineSlotView , PipelineStageRole ,
5+ PipelineStageView , PipelineStats , PipelineStatus , PipelineTimelineCell , PipelineTimelineRow ,
6+ PipelineTimelineState , PipelineTraceView , PipelineUnitView ,
87} ;
98
10- use super :: {
11- FuKind , GanttCell , HazardType , InstrClass , PipeSlot , PipelineSimState , Stage , TraceKind ,
12- } ;
13-
14- /// The one place RV32's stage names are mapped to their roles; the stage view
15- /// and the timeline both read it, so they cannot disagree.
16- fn stage_role ( stage : Stage ) -> PipelineStageRole {
17- match stage {
18- Stage :: IF => PipelineStageRole :: Fetch ,
19- Stage :: ID => PipelineStageRole :: Decode ,
20- Stage :: EX => PipelineStageRole :: Execute ,
21- Stage :: MEM => PipelineStageRole :: Memory ,
22- Stage :: WB => PipelineStageRole :: Writeback ,
23- }
24- }
25-
26- fn instruction_class ( class : InstrClass ) -> PipelineInstructionClass {
27- match class {
28- InstrClass :: Alu => PipelineInstructionClass :: Alu ,
29- InstrClass :: Mul => PipelineInstructionClass :: Multiply ,
30- InstrClass :: Div => PipelineInstructionClass :: Divide ,
31- InstrClass :: Load => PipelineInstructionClass :: Load ,
32- InstrClass :: Store => PipelineInstructionClass :: Store ,
33- InstrClass :: Branch => PipelineInstructionClass :: Branch ,
34- InstrClass :: Jump => PipelineInstructionClass :: Jump ,
35- InstrClass :: System => PipelineInstructionClass :: System ,
36- InstrClass :: Fp => PipelineInstructionClass :: FloatingPoint ,
37- InstrClass :: Unknown => PipelineInstructionClass :: Unknown ,
38- }
39- }
40-
41- fn hazard_kind ( hazard : HazardType ) -> PipelineHazardKind {
42- match hazard {
43- HazardType :: Raw => PipelineHazardKind :: ReadAfterWrite ,
44- HazardType :: LoadUse => PipelineHazardKind :: LoadUse ,
45- HazardType :: BranchFlush => PipelineHazardKind :: BranchFlush ,
46- HazardType :: FuBusy => PipelineHazardKind :: FunctionalUnitBusy ,
47- HazardType :: MemLatency => PipelineHazardKind :: MemoryLatency ,
48- HazardType :: Waw => PipelineHazardKind :: WriteAfterWrite ,
49- HazardType :: War => PipelineHazardKind :: WriteAfterRead ,
50- }
51- }
9+ use super :: { FuKind , GanttCell , PipeSlot , PipelineSimState , Stage , TraceKind } ;
5210
5311fn is_atomic ( slot : & PipeSlot ) -> bool {
5412 use crate :: falcon:: instruction:: Instruction ;
@@ -75,7 +33,7 @@ fn slot_view(slot: &PipeSlot) -> PipelineSlotView<'_> {
7533 PipelineSlotView {
7634 address : u64:: from ( slot. pc ) ,
7735 disassembly : & slot. disasm ,
78- class : instruction_class ( slot. class ) ,
36+ class : slot. class ,
7937 destination : slot. rd . map ( super :: sim:: reg_name) ,
8038 sources : [
8139 slot. rs1 . map ( super :: sim:: reg_name) ,
@@ -84,26 +42,12 @@ fn slot_view(slot: &PipeSlot) -> PipelineSlotView<'_> {
8442 bubble : slot. is_bubble ,
8543 speculative : slot. is_speculative ,
8644 predicted_taken : slot. predicted_taken ,
87- hazard : slot. hazard . map ( hazard_kind ) ,
45+ hazard : slot. hazard ,
8846 atomic : is_atomic ( slot) ,
8947 cycles_remaining : slot. fu_cycles_left ,
9048 }
9149}
9250
93- fn slot_belongs_to_unit ( slot : & PipeSlot , unit : FuKind ) -> bool {
94- match unit {
95- FuKind :: Alu => matches ! (
96- slot. class,
97- InstrClass :: Alu | InstrClass :: Branch | InstrClass :: Jump
98- ) ,
99- FuKind :: Mul => slot. class == InstrClass :: Mul ,
100- FuKind :: Div => slot. class == InstrClass :: Div ,
101- FuKind :: Fpu => slot. class == InstrClass :: Fp ,
102- FuKind :: Lsu => matches ! ( slot. class, InstrClass :: Load | InstrClass :: Store ) ,
103- FuKind :: Sys => slot. class == InstrClass :: System ,
104- }
105- }
106-
10751fn row_is_atomic ( disassembly : & str ) -> bool {
10852 [
10953 "lr.w" ,
@@ -143,6 +87,10 @@ impl PipelineInspect for PipelineSimState {
14387 branch_stalls : branch,
14488 functional_unit_stalls : unit,
14589 memory_stalls : memory,
90+ // This datapath retires in order, so a name hazard never costs it
91+ // a cycle. Only a dynamically scheduled model can report these.
92+ waw_stalls : 0 ,
93+ war_stalls : 0 ,
14694 flushes : self . flush_count ,
14795 branches : self . branches_executed ,
14896 }
@@ -157,7 +105,7 @@ impl PipelineInspect for PipelineSimState {
157105 Some ( PipelineStageView {
158106 name : stage. label ( ) ,
159107 slot : self . stages [ index] . as_ref ( ) . map ( slot_view) ,
160- role : stage_role ( stage) ,
108+ role : stage. role ( ) ,
161109 } )
162110 }
163111
@@ -194,7 +142,7 @@ impl PipelineInspect for PipelineSimState {
194142 ex. seq != 0
195143 && ex. seq == slot. seq
196144 && ex. pc == slot. pc
197- && slot_belongs_to_unit ( ex , kind )
145+ && kind . spec ( ) . handles ( ex . class )
198146 } ) ;
199147 if is_mirrored {
200148 mirrored = Some ( slot) ;
@@ -207,26 +155,14 @@ impl PipelineInspect for PipelineSimState {
207155 active += 1 ;
208156 first. get_or_insert_with ( || slot_view ( slot) ) ;
209157 }
210- let latency_class = match kind {
211- FuKind :: Alu => first. map_or ( PipelineInstructionClass :: Alu , |slot| slot. class ) ,
212- FuKind :: Mul => PipelineInstructionClass :: Multiply ,
213- FuKind :: Div => PipelineInstructionClass :: Divide ,
214- FuKind :: Fpu => PipelineInstructionClass :: FloatingPoint ,
215- FuKind :: Lsu => first. map_or ( PipelineInstructionClass :: Load , |slot| {
216- if slot. class == PipelineInstructionClass :: Store {
217- PipelineInstructionClass :: Store
218- } else {
219- PipelineInstructionClass :: Load
220- }
221- } ) ,
222- FuKind :: Sys => PipelineInstructionClass :: System ,
223- } ;
224158 Some ( PipelineUnitView {
225159 name : kind. label ( ) ,
226160 capacity : usize:: from ( self . fu_capacity [ kind. index ( ) ] . max ( 1 ) ) ,
227161 active,
228162 first,
229- latency_class,
163+ // Idle, the unit shows the work it exists for; busy, it shows what
164+ // it is actually running — a store in the LSU rather than a load.
165+ latency_class : first. map_or ( kind. spec ( ) . latency_class , |slot| slot. class ) ,
230166 // RV32's per-class latencies are tunable and live in the caller's
231167 // `PipelineTiming`, which is handed to each step rather than kept
232168 // here — so the total belongs to whoever owns that table.
@@ -240,10 +176,6 @@ impl PipelineInspect for PipelineSimState {
240176
241177 fn trace ( & self , index : usize ) -> Option < PipelineTraceView < ' _ > > {
242178 let trace = self . hazard_traces . get ( index) ?;
243- let kind = match trace. kind {
244- TraceKind :: Hazard ( hazard) => PipelineTraceKind :: Hazard ( hazard_kind ( hazard) ) ,
245- TraceKind :: Forward => PipelineTraceKind :: Forward ,
246- } ;
247179 let detail = if trace. detail . is_empty ( ) {
248180 match trace. kind {
249181 TraceKind :: Hazard ( hazard) => self
@@ -257,7 +189,7 @@ impl PipelineInspect for PipelineSimState {
257189 trace. detail . as_str ( )
258190 } ;
259191 Some ( PipelineTraceView {
260- kind,
192+ kind : trace . kind ,
261193 from_stage : trace. from_stage ,
262194 to_stage : trace. to_stage ,
263195 detail,
@@ -277,8 +209,9 @@ impl PipelineInspect for PipelineSimState {
277209 fn timeline_row ( & self , index : usize ) -> Option < PipelineTimelineRow < ' _ > > {
278210 let row = self . gantt . get ( index) ?;
279211 Some ( PipelineTimelineRow {
212+ address : u64:: from ( row. pc ) ,
280213 disassembly : & row. disasm ,
281- class : instruction_class ( row. class ) ,
214+ class : row. class ,
282215 first_cycle : row. first_cycle ,
283216 cells : row. cells . len ( ) ,
284217 atomic : row_is_atomic ( & row. disasm ) ,
@@ -292,7 +225,7 @@ impl PipelineInspect for PipelineSimState {
292225 GanttCell :: InStage ( stage) => (
293226 stage. label ( ) ,
294227 PipelineTimelineState :: Active ,
295- stage_role ( stage) ,
228+ stage. role ( ) ,
296229 ) ,
297230 GanttCell :: InFu ( _) => (
298231 "EX" ,
@@ -302,7 +235,7 @@ impl PipelineInspect for PipelineSimState {
302235 GanttCell :: Speculative ( stage) => (
303236 stage. label ( ) ,
304237 PipelineTimelineState :: Speculative ,
305- stage_role ( stage) ,
238+ stage. role ( ) ,
306239 ) ,
307240 GanttCell :: SpeculativeFu ( _) => (
308241 "EX" ,
@@ -379,7 +312,7 @@ mod tests {
379312 fn stage_views_widen_addresses_and_name_registers ( ) {
380313 let mut pipeline = PipelineSimState :: new ( ) ;
381314 let mut slot = PipeSlot :: from_word ( 0x1234 , 0x0015_8513 ) ; // addi a0, a1, 1
382- slot. hazard = Some ( HazardType :: Raw ) ;
315+ slot. hazard = Some ( HazardType :: ReadAfterWrite ) ;
383316 pipeline. stages [ Stage :: ID as usize ] = Some ( slot) ;
384317
385318 let stage = pipeline. stage ( Stage :: ID as usize ) . unwrap ( ) ;
0 commit comments