99512458053b5116a71667070e6e9a67aec11c72
2 # An In-order cycle-accurate model of a Power ISA 3.0 hardware implementation
6 # Bugs: https://bugs.libre-soc.org/show_bug.cgi?id=1039
10 Decode <- works out read/write regs
12 Issue <- checks read-regs, sets write-regs
14 Execute -> stages (countdown) clears write-regs
21 RegisterWrite: contains the set of Read-after-Write Hazards.
22 Anything in this set must be a STALL at Decode phase because the
23 answer has still not popped out the end of a pipeline
28 def expect_write(self
, regs
):
29 return self
.storage
.update(regs
)
31 def write_expected(self
, regs
):
32 return (len(self
.storage
.intersection(regs
)) != 0)
34 def retire_write(self
, regs
):
35 return self
.storage
.difference_update(regs
)
40 Execute Pipeline: keeps a countdown-sorted list of instructions
41 to expect at a future cycle (tick). Anything at zero is processed
42 by assuming it is completed, and wishes to write to the regfile.
43 However there are only a limited number of regfile write ports,
44 so they must be handled a few at a time. under these circumstances
45 STALL condition is returned, and the "processor" must *NOT* tick().
47 def __init__(self
, cpu
):
51 def add_stage(self
, cycles_away
, stage
):
52 while cycles_away
> len(self
.stages
):
53 self
.stages
.append([])
54 self
.stages
[cycles_away
].append(stage
)
56 def add_instruction(self
, insn
, writeregs
):
57 self
.add_stage(2, {'insn': insn
, 'writes': writeregs
})
60 self
.stages
.pop(0) # tick drops anything at time "zero"
62 def process_instructions(self
, stall
):
63 instructions
= self
.stages
[0] # get list of instructions
64 to_write
= set() # need to know total writes
65 for instruction
in instructions
:
66 to_write
.update(instruction
['writes'])
67 # see if all writes can be done, otherwise stall
68 writes_possible
= self
.cpu
.writes_possible(to_write
):
69 if writes_possible
!= to_write
:
71 # retire the writes that are possible in this cycle (regfile writes)
72 self
.cpu
.regs
.retire_write(writes_possible
)
73 # and now go through the instructions, removing those regs written
74 for instruction
in instructions
:
75 instruction
['writes'].difference_update(writes_possible
)
81 Fetch: reads the next log-entry and puts it into the queue.
83 def __init__(self
, cpu
):
84 self
.stages
= [None] # only ever going to be 1 long but hey
90 def process_instructions(self
, stall
):
91 if stall
: return stall
92 insn
= self
.stages
[0] # get current instruction
94 self
.cpu
.decode
.add_instructions(insn
) # pass on instruction
95 # read from log file, write into self.stages[0]
102 Decode: performs a "decode" of the instruction. identifies and records
103 read/write regs. the reads/writes possible should likely not all be here,
104 perhaps split across "Issue"?
106 def __init__(self
, cpu
):
107 self
.stages
= [None] # only ever going to be 1 long but hey
110 def add_instruction(self
, insn
):
111 # get the read and write regs
112 writeregs
= get_input_regs(insn
)
113 readregs
= get_output_regs(insn
)
114 assert self
.stages
[0] is None # must be empty (tick or stall)
115 self
.stages
[0] = (insn
, writeregs
, readregs
)
118 self
.stages
[0] = None
120 def process_instructions(self
, stall
):
121 if stall
: return stall
122 # get current instruction
123 insn
, writeregs
, readregs
= self
.stages
[0]
124 # check that the readregs are all available
125 reads_possible
= self
.cpu
.reads_possible(readregs
):
126 stall
= reads_possible
!= readregs
127 # perform the "reads" that are possible in this cycle
128 readregs
.difference_update(reads_possible
)
129 # and "Reserves" the writes
130 self
.cpu
.expect_write(writeregs
)
131 # now pass the instruction on to Issue
132 self
.cpu
.issue
.add_instruction(insn
, writeregs
)
138 Issue phase: if not stalled will place the instruction into execute.
139 TODO: move the reading and writing of regs here.
141 def __init__(self
, cpu
):
142 self
.stages
= [None] # only ever going to be 1 long but hey
145 def add_instruction(self
, insn
, writeregs
):
146 # get the read and write regs
147 assert self
.stages
[0] is None # must be empty (tick or stall)
148 self
.stages
[0] = (insn
, writeregs
)
151 self
.stages
[0] = None
153 def process_instructions(self
, stall
):
154 if stall
: return stall
155 self
.cpu
.execute
.add_instructions(self
.stages
[0])
161 CPU: contains Fetch, Decode, Issue and Execute pipelines, and regs.
162 Reads "instructions" from a file, starts putting them into a pipeline,
163 and monitors hazards. first version looks only for register hazards.
166 self
.regs
= RegisterWrite()
167 self
.fetch
= Fetch(self
)
168 self
.decode
= Decode(self
)
169 self
.issue
= Issue(self
)
170 self
.exe
= Execute(self
)
173 def reads_possible(self
, regs
):
174 # TODO: subdivide this down by GPR FPR CR-field.
175 # currently assumes total of 3 regs are readable at one time
178 while len(possible
) < 3 and len(r
) > 0:
179 possible
.add(r
.pop())
182 def writess_possible(self
, regs
):
183 # TODO: subdivide this down by GPR FPR CR-field.
184 # currently assumes total of 1 reg is possible regardless of what it is
187 while len(possible
) < 1 and len(r
) > 0:
188 possible
.add(r
.pop())
191 def process_instructions(self
):
193 stall
= self
.fetch
.process_instructions(stall
)
194 stall
= self
.decode
.process_instructions(stall
)
195 stall
= self
.issue
.process_instructions(stall
)
196 stall
= self
.exe
.process_instructions(stall
)