Skip to content

Commit 8322817

Browse files
committed
Working conditionals in Ruby!
Tested and working in Quartus
1 parent f56173a commit 8322817

File tree

5 files changed

+169
-69
lines changed

5 files changed

+169
-69
lines changed

lib/Computer.Build.rb

+100-25
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
require 'computer_build/vhdl'
22
require 'computer_build/state_machine'
33

4-
5-
class Fixnum
6-
def to_logic(width)
7-
str = self.to_s(2)
8-
return "0"*(width-str.length) + str
9-
end
10-
end
11-
124
class Computer
5+
include VHDL::Helpers
6+
137
def self.Build(name)
148
instance = Computer.new(name)
159
yield(instance)
@@ -23,6 +17,7 @@ def initialize(name)
2317
@instructions = []
2418
end
2519

20+
# DSL method
2621
def instruction(name)
2722
inst = Instruction.new(name)
2823
yield(inst)
@@ -37,11 +32,12 @@ def generate
3732

3833
control = state_machine("control_unit") do |m|
3934
m.input :reset, VHDL::STD_LOGIC
35+
m.input :condition, VHDL::STD_LOGIC
4036
m.inout :system_bus, VHDL::STD_LOGIC_VECTOR(7..0)
37+
m.output :alu_operation, VHDL::STD_LOGIC_VECTOR(2..0)
4138
control_signals.each do |sig|
4239
m.output sig, VHDL::STD_LOGIC
4340
end
44-
m.output :alu_operation, VHDL::STD_LOGIC_VECTOR(2..0)
4541

4642
m.signal :opcode,
4743
VHDL::STD_LOGIC_VECTOR((opcode_length-1)..0)
@@ -73,13 +69,18 @@ def generate
7369
end
7470

7571
if name == 'store_instruction'
76-
s.if event(:clock), equal(:clock,"0") do |thn|
72+
s.if event(:clock), VHDL::Equal.new(:clock,"0") do |thn|
7773
thn.assign :opcode, "#{opcode_length-1} downto 0", :system_bus, "7 downto #{7-opcode_length+1}"
7874
end
7975
end
8076
end
8177

82-
m.transition :from => name, :to => state.next if state.next
78+
if state.condition
79+
m.transition :from => name, :to => state.next, :on => VHDL::Equal.new(:condition, "0")
80+
m.transition :from => name, :to => name+"_0", :on => VHDL::Equal.new(:condition, "1")
81+
else
82+
m.transition :from => name, :to => state.next if state.next
83+
end
8384
end
8485

8586
# instruction decode
@@ -96,6 +97,7 @@ def generate
9697

9798
e.signal :system_bus, VHDL::STD_LOGIC_VECTOR(7..0)
9899
e.signal :alu_operation, VHDL::STD_LOGIC_VECTOR(2..0)
100+
e.signal :alu_condition, VHDL::STD_LOGIC
99101

100102
control_signals.each do |sig|
101103
e.signal sig, VHDL::STD_LOGIC
@@ -136,25 +138,27 @@ def generate
136138
c.in :wr_a, VHDL::STD_LOGIC
137139
c.in :wr_b, VHDL::STD_LOGIC
138140
c.in :rd, VHDL::STD_LOGIC
141+
c.out :condition, VHDL::STD_LOGIC
139142
end
140143

141144
e.component :control_unit do |c|
142145
c.in :clock, VHDL::STD_LOGIC
143146
c.in :reset, VHDL::STD_LOGIC
144-
c.inout :system_bus, VHDL::STD_LOGIC_VECTOR(7..0)
147+
c.in :condition, VHDL::STD_LOGIC
145148
c.out :alu_operation, VHDL::STD_LOGIC_VECTOR(2..0)
146149
control_signals.each do |sig|
147150
c.out sig, VHDL::STD_LOGIC
148151
end
152+
c.inout :system_bus, VHDL::STD_LOGIC_VECTOR(7..0)
149153
end
150154

151155
e.behavior do |b|
152156
b.instance :program_counter, "pc", :clock, :system_bus, :system_bus, :wr_pc, :rd_pc, :inc_pc
153157
b.instance :reg, "ir", :clock, :system_bus, :system_bus, :wr_IR, :rd_IR
154158
b.instance :reg, "A", :clock, :system_bus, :system_bus, :wr_A, :rd_A
155159
b.instance :ram, "main_memory", :clock, :system_bus, :system_bus, subbits(:system_bus, 4..0), :wr_MD, :wr_MA, :rd_MD
156-
b.instance :alu, "alu0", :clock, :system_bus, :system_bus, :alu_operation, :wr_alu_a, :wr_alu_b, :rd_alu
157-
b.instance :control_unit, "control0", [:clock, :reset, :system_bus, :alu_operation] + control_signals
160+
b.instance :alu, "alu0", :clock, :system_bus, :system_bus, :alu_operation, :wr_alu_a, :wr_alu_b, :rd_alu, :alu_condition
161+
b.instance :control_unit, "control0", [:clock, :reset, :alu_condition, :alu_operation] + control_signals + [:system_bus]
158162
b.assign :bus_inspection, :system_bus
159163
end
160164
end
@@ -184,7 +188,11 @@ def move(target, source)
184188
end
185189

186190
def microcode
187-
steps.map &:to_microcode
191+
steps.map(&:to_microcode).flatten
192+
end
193+
194+
def if(condition, &body)
195+
@steps << Conditional.new(condition, &body)
188196
end
189197
end
190198

@@ -198,15 +206,61 @@ def initialize(op, *operands)
198206

199207
def opcode
200208
return {
209+
:and => "001",
210+
:or => "010",
201211
:complement => "011",
202-
:and => "001",
203-
:add => "100",
204-
:subtract => "101"}[@op]
212+
:add => "100",
213+
:subtract => "101",
214+
:equal => "110",
215+
:lessthan => "111"}[@op]
205216
end
206217
end
207218

208219
private
209220

221+
class Conditional
222+
def initialize(condition)
223+
@condition = condition # instance of ALUOperation
224+
@steps = []
225+
@true_body = []
226+
yield self
227+
end
228+
229+
# DSL method
230+
def move(target, source)
231+
@steps << RTL.new(target, source)
232+
end
233+
234+
def to_microcode
235+
steps = []
236+
steps << MicrocodeState.new do |state|
237+
state.control_signals = ["rd_#{@condition.operands.first}", "wr_alu_a"]
238+
state.alu_op = @condition
239+
end
240+
conditional = MicrocodeState.new do |state|
241+
op = @condition.operands.last
242+
state.control_signals = ["wr_alu_b"]
243+
244+
if op.is_a? Fixnum
245+
state.constant_value = op
246+
else
247+
state.control_signals += "rd_#{op}"
248+
end
249+
250+
state.alu_op = @condition
251+
state.condition = @condition
252+
end
253+
steps << conditional
254+
255+
body = @steps.map(&:to_microcode).flatten
256+
conditional.body_size = body.length
257+
258+
body.each {|state| state.conditional = conditional}
259+
260+
return steps + body
261+
end
262+
end
263+
210264
class RTL
211265
def initialize(target, source)
212266
@target = target
@@ -251,7 +305,9 @@ def to_microcode
251305
end
252306

253307
class MicrocodeState
254-
attr_accessor :control_signals, :alu_op, :constant_value, :next
308+
attr_accessor :control_signals, :alu_op, :constant_value, :next,
309+
:condition, :conditional, :body_size, :index
310+
255311
def initialize(&blk)
256312
yield(self) if blk
257313
end
@@ -260,14 +316,29 @@ def initialize(&blk)
260316
def make_states(instructions)
261317
states = {}
262318
instructions.each do |instr|
263-
steps = instr.microcode.flatten
264-
steps.each_with_index do |step, index|
265-
if index + 1 < steps.length
266-
step.next = instr.name+"_"+(index+1).to_s
319+
steps = instr.microcode
320+
indexes = {nil => 0}
321+
steps.each do |step|
322+
indexes[step.conditional] ||= 0
323+
index = indexes[step.conditional]
324+
325+
if step.conditional
326+
if index < step.conditional.body_size - 1
327+
step.next = instr.name+"_"+(step.conditional.index.to_s)+"_"+(index+1).to_s
328+
else
329+
step.next = step.conditional.next
330+
end
331+
states[instr.name+"_"+(step.conditional.index.to_s)+"_"+index.to_s] = step
267332
else
268-
step.next = :fetch
333+
if index < steps.reject(&:conditional).length - 1
334+
step.next = instr.name+"_"+(index+1).to_s
335+
else
336+
step.next = :fetch
337+
end
338+
states[instr.name+"_"+index.to_s] = step
269339
end
270-
states[instr.name+"_"+index.to_s] = step
340+
step.index = index
341+
indexes[step.conditional] += 1
271342
end
272343
end
273344

@@ -320,3 +391,7 @@ def bitwise_and(operand1, operand2)
320391
def subtract(operand1, operand2)
321392
Computer::ALUOperation.new(:subtract, operand1, operand2)
322393
end
394+
395+
def equal(operand1, operand2)
396+
Computer::ALUOperation.new(:equal, operand1, operand2)
397+
end

lib/McCalla.rb

+6
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,10 @@
4444
computer.instruction "jmp" do |i|
4545
i.move :pc, bitwise_and(:IR, 0x0F)
4646
end
47+
48+
computer.instruction "bra0" do |i|
49+
i.if equal(:A, 0) do |thn|
50+
thn.move :pc, bitwise_and(:IR, 0x0F)
51+
end
52+
end
4753
end

lib/computer_build/state_machine.rb

+13-9
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ def initialize(options)
2727
end
2828

2929
class StateMachine
30+
include VHDL::Helpers
3031
def initialize(name, body)
3132
@name = name
32-
@inputs = {}
33-
@outputs = {}
34-
@inouts = {}
33+
@inputs = []
34+
@outputs = []
35+
@inouts = []
3536
@signals = []
3637
@states = []
3738
@transitions = []
@@ -44,19 +45,19 @@ def inputs(*rest)
4445
end
4546

4647
def input(name, type)
47-
@inputs[name] = type
48+
@inputs << [name, type]
4849
end
4950

5051
def outputs(*rest)
5152
@outputs = rest
5253
end
5354

5455
def output(name, type)
55-
@outputs[name] = type
56+
@outputs << [name, type]
5657
end
5758

5859
def inout(name, type)
59-
@inouts[name] = type
60+
@inouts << [name, type]
6061
end
6162

6263
def signal(*rest)
@@ -83,15 +84,18 @@ def generate(out)
8384
representation = entity(@name) do |e|
8485
e.port "clock", :in, VHDL::STD_LOGIC
8586

86-
@inputs.each do |name, type|
87+
@inputs.each do |pair|
88+
name, type = pair
8789
e.port name, :in, type
8890
end
8991

90-
@outputs.each do |name, type|
92+
@outputs.each do |pair|
93+
name, type = pair
9194
e.port name, :out, type
9295
end
9396

94-
@inouts.each do |name, type|
97+
@inouts.each do |pair|
98+
name, type = pair
9599
e.port name, :inout, type
96100
end
97101

0 commit comments

Comments
 (0)