Class: PipelineSim
- Inherits:
-
Object
- Object
- PipelineSim
- Defined in:
- pipeline_simulation.rb
Overview
This class represents a simulation of a computer pipeline. Initialization:
simulation = PipelineSim.new(starting_address)
simulation.runthrough(instructions)
Definition of parameters:
starting_address: starting address of the first instruction (in hex)
instructions: array of mips instructions, in hex
Example:
> instructions = ["0x00a63820",
"0x8d0f0004",
"0xad09fffc",
"0x00625022",
"0x00000000",
"0x00000000",
"0x00000000",
"0x00000000"]
> simulation = PipelineSim.new("0x70000")
> simulation.runthrough(instructions)
Defined Under Namespace
Classes: MainMem, PipelineRegister, Regs
Instance Attribute Summary collapse
-
#cycle_num ⇒ Integer
Returns (and sets) cycle number.
-
#ExMemRegister ⇒ PipelineRegister
Returns (and sets) current content of the EX/MEM Register.
-
#IdExRegister ⇒ PipelineRegister
Returns (and sets) current content of the ID/EX Register.
-
#IfIdRegister ⇒ PipelineRegister
Returns (and sets) current content of the IF/ID Register.
-
#mainMem ⇒ MainMem
Returns (and sets) main memory.
-
#MemWbRegister ⇒ PipelineRegister
Returns (and sets) current content of the MEM/WB Register.
-
#regs ⇒ Regs
Returns (and sets) registers.
-
#starting_address ⇒ String
readonly
Returns starting_address.
Instance Method Summary collapse
-
#copyWriteToRead ⇒ void
Copies the write side of each PipelineRegister to the read side of that register.
-
#exStage ⇒ void
exStage: Execute Performs the instruction from the read side of the ID/EX Register and writes the results to the write side of the ID/EX Register.
-
#idStage ⇒ void
idStage: Instruction Decode Reads the instruction from the read side of the IF/ID Register, decodes it, and writes the results to the write side of the ID/EX Register.
-
#ifStage(instruction) ⇒ void
ifStage: Instruction Fetch Fetch the next instruction and write it to the write side of the IF/ID Register.
-
#initialize(starting_address) ⇒ PipelineSim
constructor
Initializes new PipelineSim object.
-
#memStage ⇒ void
memStage: Memory Access If the instruction is a load, then we get the data from the address calculated in the Execute stage and store it in the register.
-
#printOutEverything ⇒ void
Prints out current clock cycle, registers, and all contents of the pipeline registers.
-
#runthrough(instructions) ⇒ Object
MEM/WB Register Read ——————– control = 000000000.
-
#wbStage ⇒ void
wbStage: Register Write Back If writing to registers (add, sub, or load), then write the given value to the register.
Constructor Details
#initialize(starting_address) ⇒ PipelineSim
With this simulation, there are 32 registers and a 1K main memory
Initializes new PipelineSim object
52 53 54 55 56 57 58 59 60 61 |
# File 'pipeline_simulation.rb', line 52 def initialize(starting_address) @mainMem = MainMem.new('7FF'.to_i(16)) @regs = Regs.new(32) @cycle_num = 0 @starting_address = starting_address @IfIdRegister = PipelineRegister.new("IF/ID Register", {instruction: "0x00000000"}) @IdExRegister = PipelineRegister.new("ID/EX Register", {control: "000000000"}) @ExMemRegister = PipelineRegister.new("EX/MEM Register", {control: "000000000"}) @MemWbRegister = PipelineRegister.new("MEM/WB Register", {control: "000000000"}) end |
Instance Attribute Details
#cycle_num ⇒ Integer
Returns (and sets) cycle number
45 46 47 |
# File 'pipeline_simulation.rb', line 45 def cycle_num @cycle_num end |
#ExMemRegister ⇒ PipelineRegister
Returns (and sets) current content of the EX/MEM Register
30 31 32 |
# File 'pipeline_simulation.rb', line 30 def ExMemRegister @ExMemRegister end |
#IdExRegister ⇒ PipelineRegister
Returns (and sets) current content of the ID/EX Register
27 28 29 |
# File 'pipeline_simulation.rb', line 27 def IdExRegister @IdExRegister end |
#IfIdRegister ⇒ PipelineRegister
Returns (and sets) current content of the IF/ID Register
24 25 26 |
# File 'pipeline_simulation.rb', line 24 def IfIdRegister @IfIdRegister end |
#mainMem ⇒ MainMem
Returns (and sets) main memory
36 37 38 |
# File 'pipeline_simulation.rb', line 36 def mainMem @mainMem end |
#MemWbRegister ⇒ PipelineRegister
Returns (and sets) current content of the MEM/WB Register
33 34 35 |
# File 'pipeline_simulation.rb', line 33 def MemWbRegister @MemWbRegister end |
#regs ⇒ Regs
Returns (and sets) registers
39 40 41 |
# File 'pipeline_simulation.rb', line 39 def regs @regs end |
#starting_address ⇒ String (readonly)
Returns starting_address
42 43 44 |
# File 'pipeline_simulation.rb', line 42 def starting_address @starting_address end |
Instance Method Details
#copyWriteToRead ⇒ void
So it doesn't use the exact same hash object, we use #clone to copy from write to read.
This method returns an undefined value.
Copies the write side of each PipelineRegister to the read side of that register.
351 352 353 354 355 356 |
# File 'pipeline_simulation.rb', line 351 def copyWriteToRead [@IfIdRegister, @IdExRegister, @ExMemRegister, @MemWbRegister].each do |register| register.read = register.write.clone register.read[:control] = register.write[:control].clone if register.write[:control] end end |
#exStage ⇒ void
This method returns an undefined value.
exStage: Execute Performs the instruction from the read side of the ID/EX Register and writes the results to the write side of the ID/EX Register.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'pipeline_simulation.rb', line 213 def exStage # noop if @IdExRegister.read[:control] == "000000000" @ExMemRegister.write = {control: "000000000" } else # if this is the first one, set control to a hash if @ExMemRegister.write[:control] == "000000000" @ExMemRegister.write[:control] = {} end # copy control variables that need to go to Ex/Mem to Ex/Mem write @ExMemRegister.write[:control][:memWrite] = @IdExRegister.read[:control][:memWrite] @ExMemRegister.write[:control][:memRead] = @IdExRegister.read[:control][:memRead] @ExMemRegister.write[:control][:memToReg] = @IdExRegister.read[:control][:memToReg] @ExMemRegister.write[:control][:regWrite] = @IdExRegister.read[:control][:regWrite] @ExMemRegister.write[:control][:branch] = @IdExRegister.read[:control][:branch] @ExMemRegister.write[:incrPC] = @IdExRegister.read[:incrPC] # read in needed variables for later execution aLUSrc = @IdExRegister.read[:control][:aLUSrc] aLUOp = @IdExRegister.read[:control][:aLUOp] reg1 = @IdExRegister.read[:readReg1Value].to_i(16) reg2 = @IdExRegister.read[:readReg2Value].to_i(16) regDest = @IdExRegister.read[:control][:regDest] # if the first register, use 20-16 # if the second, use 15-11 # otherwise, it shouldn't be writing to a register, so don't care if regDest == 0 @ExMemRegister.write[:writeRegNum] = @IdExRegister.read[:writeReg_20_16] elsif regDest == 1 @ExMemRegister.write[:writeRegNum] = @IdExRegister.read[:writeReg_15_11] else @ExMemRegister.write[:writeRegNum] = "X" end # calculate ALUResult if @IdExRegister.read[:function] == "22" # sub aLUResult = (reg1 - reg2).to_s(16) elsif @IdExRegister.read[:function] == "20" # add aLUResult = (reg2 + reg1).to_s(16) else # lb & sb aLUResult = (reg1 + convert_to_signed_binary(@IdExRegister.read[:sEOffset].to_i(16).to_s(2))).to_s(16) end # this project is not handling branches @ExMemRegister.write[:calcBTA] = "X" @ExMemRegister.write[:zero] = "F" @ExMemRegister.write[:aLUResult] = aLUResult @ExMemRegister.write[:sWValue] = reg2.to_s(16) end end |
#idStage ⇒ void
Determines whether instruction is r-format or i-format and uses the relevant function to further decode instructions
This method returns an undefined value.
idStage: Instruction Decode Reads the instruction from the read side of the IF/ID Register, decodes it, and writes the results to the write side of the ID/EX Register.
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'pipeline_simulation.rb', line 185 def idStage instruction = @IfIdRegister.read[:instruction] address = @IfIdRegister.read[:incrPC] if instruction.to_i(16) == 0 # this is a noop @IdExRegister.write = {control: "000000000"} else # convert to binary binary_instr = sprintf("%b", instruction).rjust(32, '0') first_six = binary_instr[-32..-27].to_i(2) # determine if r or i, then decode if first_six == 0 translate_r_format(binary_instr) else translate_i_format(binary_instr, address) end # regardless of type, add write/read values and incrPC @IdExRegister.write[:writeReg_15_11] = binary_instr[-16..-12].to_i(2) @IdExRegister.write[:writeReg_20_16] = binary_instr[-21..-17].to_i(2) @IdExRegister.write[:readReg1Value] = @regs.content[binary_instr[-26..-22].to_i(2)] @IdExRegister.write[:readReg2Value] = @regs.content[binary_instr[-21..-17].to_i(2)] @IdExRegister.write[:incrPC] = address if address end end |
#ifStage(instruction) ⇒ void
If the IF/ID Register already has an incrPC value, then increase it by 4. Otherwise, take the starting address
This method returns an undefined value.
ifStage: Instruction Fetch Fetch the next instruction and write it to the write side of the IF/ID Register
172 173 174 175 176 177 178 179 |
# File 'pipeline_simulation.rb', line 172 def ifStage(instruction) @IfIdRegister.write = { instruction: instruction } if @IfIdRegister.read[:incrPC] @IfIdRegister.write[:incrPC] = (@IfIdRegister.read[:incrPC].to_i(16) + 4).to_s(16) else @IfIdRegister.write[:incrPC] = (@starting_address.to_i(16) + 4).to_s(16) end end |
#memStage ⇒ void
This method returns an undefined value.
memStage: Memory Access If the instruction is a load, then we get the data from the address calculated in the Execute stage and store it in the register. If it is a store, then we store the result in main memory.
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'pipeline_simulation.rb', line 269 def memStage # noop if @ExMemRegister.read[:control] == "000000000" @MemWbRegister.write = {control: "000000000" } else # if this is the first one, set control to a hash if @MemWbRegister.write[:control] == "000000000" @MemWbRegister.write[:control] = {} end memRead = @ExMemRegister.read[:control][:memRead] memWrite = @ExMemRegister.read[:control][:memWrite] if memRead == 1 @MemWbRegister.write[:lWDataValue] = @mainMem.content[@ExMemRegister.read[:aLUResult].to_i(16)] elsif memWrite == 1 @mainMem.content[@ExMemRegister.read[:aLUResult].to_i(16)] = @ExMemRegister.read[:sWValue] else @MemWbRegister.write[:lWDataValue] = "X" end @MemWbRegister.write[:aLUResult] = @ExMemRegister.read[:aLUResult] @MemWbRegister.write[:writeRegNum] = @ExMemRegister.read[:writeRegNum] @MemWbRegister.write[:control][:memToReg] = @ExMemRegister.read[:control][:memToReg] @MemWbRegister.write[:control][:regWrite] = @ExMemRegister.read[:control][:regWrite] end end |
#printOutEverything ⇒ void
This method returns an undefined value.
Prints out current clock cycle, registers, and all contents of the pipeline registers.
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'pipeline_simulation.rb', line 315 def printOutEverything puts "-----------------" puts "| Clock Cycle #{@cycle_num} |" puts "-----------------" @regs.show puts "" puts "" [@IfIdRegister, @IdExRegister, @ExMemRegister, @MemWbRegister].each do |register| [:write, :read].each do |side| puts register.title + " " + side.to_s.capitalize puts "--------------------" other_keys = "" # for each side, get the keys and values register.send(side).each do |key, value| # if it is the control hash if value.is_a?(Hash) control = key.to_s.capitalize + ": " value.each do |key, value| control += key.to_s + " = " + value.to_s + ", " end puts control # otherwise, it's just normal contents else other_keys += key.to_s + " = " + value.to_s + " " end end puts other_keys puts "" end puts "" end end |
#runthrough(instructions) ⇒ Object
MEM/WB Register Read
--------------------
control = 000000000
153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'pipeline_simulation.rb', line 153 def runthrough(instructions) @cycle_num += 1 instructions.each do | instruction | ifStage(instruction) idStage exStage memStage wbStage printOutEverything copyWriteToRead @cycle_num += 1 end end |
#wbStage ⇒ void
This method returns an undefined value.
wbStage: Register Write Back If writing to registers (add, sub, or load), then write the given value to the register.
298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'pipeline_simulation.rb', line 298 def wbStage return if @MemWbRegister.read[:control].is_a? String regWrite = @MemWbRegister.read[:control][:regWrite] memToReg = @MemWbRegister.read[:control][:memToReg] if regWrite == 1 if memToReg == 1 @regs.content[@MemWbRegister.read[:writeRegNum]] = @MemWbRegister.read[:lWDataValue] elsif memToReg == 0 @regs.content[@MemWbRegister.read[:writeRegNum]] = @MemWbRegister.read[:aLUResult] else raise ArgumentError.new("Expecting 1 or 0 for memToReg. Got #{memToReg}.") end end end |