-
Notifications
You must be signed in to change notification settings - Fork 0
/
cpu_components.rb
145 lines (124 loc) · 3.19 KB
/
cpu_components.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
class Control
include CircuitComponent
RTYPE = 0x00
ADDI = 0x08
BEQ = 0x04
J = 0x02
LW = 0x23
SW = 0x2B
HLT = 0x3F
inputs :opcode
outputs :reg_dst, :jump, :branch, :mem_to_reg, :mem_read,
:alu_op, :mem_write, :alu_src, :reg_write, :debug_name,
:terminate
NAME = {0x00 => "rtype", 0x08 => "addi", 0x04 => "beq",
0x02 => "j", 0x23 => "lw", 0x2b => "sw", 0x3f => "hlt"}
def execute
output.branch = input.opcode == BEQ ? 1 : 0
output.jump = input.opcode == J ? 1 : 0
output.mem_write = input.opcode == SW ? 1 : 0
output.reg_write = [RTYPE, ADDI, LW].include?(input.opcode) ? 1 : 0
output.reg_dst = input.opcode == RTYPE ? 1 : 0
output.alu_src = [ADDI, LW, SW].include?(input.opcode) ? 1 : 0
output.mem_to_reg = input.opcode == LW ? 1 : 0
output.mem_read = input.opcode == LW ? 1 : 0
output.debug_name = Control.instr_name(input.opcode)
output.alu_op = case input.opcode
when RTYPE; :f
when BEQ; :-
else :+
end
output.terminate = input.opcode == HLT ? 1 : 0
end
def Control.instr_name(opcode)
NAME[opcode]
end
end
class ALUControl
include CircuitComponent
inputs :function, :alu_op
outputs :control
def execute
if input.alu_op == :f
case input.function
when 0x20
output.control = :+
end
else
output.control = input.alu_op
end
end
end
class ForwardingUnit
include CircuitComponent
inputs :ex_mem_reg_write, :mem_wb_reg_write,
:ex_mem_reg_rd, :mem_wb_reg_rd,
:id_ex_reg_rt, :id_ex_reg_rs
outputs :forward_a, :forward_b
def execute
# Copied from textbook (with bug fix)
if (input.ex_mem_reg_write == 1 &&
input.ex_mem_reg_rd != 0 &&
input.ex_mem_reg_rd == input.id_ex_reg_rs)
output.forward_a = 2
elsif (input.mem_wb_reg_write==1 &&
input.mem_wb_reg_rd != 0 &&
input.mem_wb_reg_rd == input.id_ex_reg_rs)
output.forward_a = 1
else
output.forward_a = 0
end
if (input.ex_mem_reg_write == 1 &&
input.ex_mem_reg_rd != 0 &&
input.ex_mem_reg_rd == input.id_ex_reg_rt)
output.forward_b = 2
elsif (input.mem_wb_reg_write==1 &&
input.mem_wb_reg_rd != 0 &&
input.mem_wb_reg_rd == input.id_ex_reg_rt)
output.forward_b = 1
else
output.forward_b = 0
end
end
end
class HazardDetectionUnit
include CircuitComponent
inputs :id_ex_mem_read, :id_ex_reg_rt,
:if_id_reg_rs, :if_id_reg_rt
outputs :pc_write, :if_id_write, :nop
def execute
if (input.id_ex_mem_read == 1 &&
(input.id_ex_reg_rt == input.if_id_reg_rs ||
input.id_ex_reg_rt == input.if_id_reg_rt))
output.nop = 1
output.pc_write = 0
output.if_id_write = 0
else
output.nop = 0
output.pc_write = 1
output.if_id_write = 1
end
end
end
class System
include CircuitComponent
inputs :terminate
inputs :real
def tick_prep
@_terminate = input.terminate
@_real = input.real
end
def tick
@terminate = @_terminate
@count ||= 0
if @_real == 1
@count += 1
end
end
def terminate?
@terminate==1
end
def instructions
@count
end
end