Class: FAM::Machine::CPU
- Includes:
- Syntax
- Defined in:
- lib/fam/machine/cpu.rb
Instance Attribute Summary collapse
-
#halted ⇒ Object
readonly
Returns the value of attribute halted.
-
#inputting ⇒ Object
readonly
Returns the value of attribute inputting.
-
#labels ⇒ Object
readonly
Returns the value of attribute labels.
-
#memory_aliases ⇒ Object
readonly
Returns the value of attribute memory_aliases.
-
#output ⇒ Object
readonly
Returns the value of attribute output.
-
#outputting ⇒ Object
readonly
Returns the value of attribute outputting.
-
#ram ⇒ Object
readonly
Returns the value of attribute ram.
-
#registers ⇒ Object
readonly
Returns the value of attribute registers.
Class Method Summary collapse
Instance Method Summary collapse
-
#cpu_input ⇒ Object
Ment to be changed.
-
#cpu_output(out, ascii = :PLAIN) ⇒ Object
Ment to be changed.
- #display ⇒ Object
- #execute(node) ⇒ Object
- #ExpectedNode(expect, got) ⇒ Object
-
#initialize(ram) ⇒ CPU
constructor
A new instance of CPU.
- #run(parsed, &block) ⇒ Object
- #step(parsed) ⇒ Object
- #UnexpectedNode(node, sub_node) ⇒ Object
Constructor Details
#initialize(ram) ⇒ CPU
Returns a new instance of CPU.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/fam/machine/cpu.rb', line 11 def initialize ram @ram = ram @registers = { :ACC => 0, :DAT => 0, :PC => 0 } @memory_aliases = Hash.new @labels = Hash.new @last_jump = nil @back_index = 0 @tree_index = -1 @halted = false @outputting = @inputting = false @output = String.new end |
Instance Attribute Details
#halted ⇒ Object (readonly)
Returns the value of attribute halted.
8 9 10 |
# File 'lib/fam/machine/cpu.rb', line 8 def halted @halted end |
#inputting ⇒ Object (readonly)
Returns the value of attribute inputting.
8 9 10 |
# File 'lib/fam/machine/cpu.rb', line 8 def inputting @inputting end |
#labels ⇒ Object (readonly)
Returns the value of attribute labels.
7 8 9 |
# File 'lib/fam/machine/cpu.rb', line 7 def labels @labels end |
#memory_aliases ⇒ Object (readonly)
Returns the value of attribute memory_aliases.
7 8 9 |
# File 'lib/fam/machine/cpu.rb', line 7 def memory_aliases @memory_aliases end |
#output ⇒ Object (readonly)
Returns the value of attribute output.
9 10 11 |
# File 'lib/fam/machine/cpu.rb', line 9 def output @output end |
#outputting ⇒ Object (readonly)
Returns the value of attribute outputting.
8 9 10 |
# File 'lib/fam/machine/cpu.rb', line 8 def outputting @outputting end |
#ram ⇒ Object (readonly)
Returns the value of attribute ram.
7 8 9 |
# File 'lib/fam/machine/cpu.rb', line 7 def ram @ram end |
#registers ⇒ Object (readonly)
Returns the value of attribute registers.
7 8 9 |
# File 'lib/fam/machine/cpu.rb', line 7 def registers @registers end |
Class Method Details
.quick_run(ram, parsed, &block) ⇒ Object
29 30 31 32 33 34 35 36 37 |
# File 'lib/fam/machine/cpu.rb', line 29 def self.quick_run ram, parsed, &block cpu = self.new ram if block_given? cpu.run parsed, &block else cpu.run parsed end cpu end |
Instance Method Details
#cpu_input ⇒ Object
Ment to be changed
160 161 162 163 |
# File 'lib/fam/machine/cpu.rb', line 160 def cpu_input # Ment to be changed print 'INPUT: ' $stdin.gets.to_i end |
#cpu_output(out, ascii = :PLAIN) ⇒ Object
Ment to be changed
165 166 167 168 |
# File 'lib/fam/machine/cpu.rb', line 165 def cpu_output out, ascii=:PLAIN # Ment to be changed show = ascii == :PLAIN ? out.to_s : out.chr puts "OUTPUT: #{show}" end |
#display ⇒ Object
151 152 153 154 155 156 157 158 |
# File 'lib/fam/machine/cpu.rb', line 151 def display puts "#{@ram.to_s}" puts @registers.each { |key, value| print "#{key} => #{value}\n" } puts # print "\033[F" * (self.to_s.count("\n")) # print "\n" * (@ram.to_s.count("\n") + 1) end |
#execute(node) ⇒ Object
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 144 145 146 147 148 149 |
# File 'lib/fam/machine/cpu.rb', line 69 def execute node @outputting = @inputting = false @registers[:PC] = @tree_index @block.call @registers[:PC] unless @block.nil? case node when AST::LabelNode @last_jump = node.label @labels[node.label] = @tree_index @back_index = @tree_index when AST::HaltNode return :STOP when AST::GotoNode back = @tree_index if @labels.include? node.ident.name @tree_index = @labels[node.ident.name] elsif node.ident.name == '_BACK' @tree_index = @back_index return :PASS else # Search ahead found = false @parsed.tree.each.with_index do |top_node, i| @tree_index = i if top_node.base_name == 'LabelNode' (found = true; break) if top_node.label == node.ident.name end end abort "Label: `#{node.label.name}` was not found. Execution HALTED!".red.bold unless found end @last_jump = node.ident.name @back_index = back when AST::StoreNode mem_index = case node.to when AST::AddressNode node.to.address when AST::IdentNode @memory_aliases[node.to.name] end @ram[mem_index] = get_value node, node.value when AST::LoadNode @registers[node.register.register.to_sym] = get_value node, node.value when AST::DataNode initial_value = get_value node, node.initial free_index = nil @ram.array.each.with_index { |value, i| if value == NULL then free_index = i; break; end } abort ("No free memory, allocation of `#{node.name.name}`,\n" + "cannot happen! Execution HALTED!").red.bold if free_index.nil? @memory_aliases[node.name.name] = free_index @ram[free_index] = initial_value when AST::InNode @registers[node.register.register.to_sym] = cpu_input when AST::OutNode, AST::AsciiNode @outputting = true value = get_value node, node.value @output = cpu_output(value, (node.base_name == 'OutNode' ? :PLAIN : :ASCII)) when AST::SubNode, AST::AddNode, AST::MulNode, AST::DivNode, AST::ModNode value = get_value node, node.value ExpectedNode 'REGISTER', node.to unless node.to.base_name == 'RegisterNode' if node.base_name[/Sub|Add/] @registers[node.to.register.to_sym] += value * (node.base_name == 'AddNode' ? 1 : -1) elsif node.base_name == 'Mul' @registers[node.to.register.to_sym] *= value elsif node.base_name == 'Div' @registers[node.to.register.to_sym] /= value else @registers[node.to.register.to_sym] %= value end when AST::EqualNode, AST::MoreNode, AST::LessNode left = get_value node, node.left right = get_value node, node.right if node.base_name == 'EqualNode' ? (left == right) : (node.base_name == 'MoreNode' ? (left > right) : (left < right)) execute node.valid else execute node.invalid end else print "\n" * (@ram.to_s.count("\n") + 1) if $VERBOSE abort ("Unknown Node: `#{node.base_name}`,\nparser generated an " + "unexecutable/unknown node... Execution HALTED!").red.bold end return :PASS end |
#ExpectedNode(expect, got) ⇒ Object
190 191 192 193 |
# File 'lib/fam/machine/cpu.rb', line 190 def ExpectedNode expect, got print "\n" * (@ram.to_s.count("\n") + 1) if $VERBOSE abort ("Expected: `#{expect}`, but insted got: `#{got}`").red.bold end |
#run(parsed, &block) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/fam/machine/cpu.rb', line 39 def run parsed, &block @block = block if block_given? @parsed = parsed while @tree_index < parsed.tree.size @tree_index += 1 sleep 1.0 / $CLOCK node = parsed[@tree_index] status = execute node break if status == :STOP next if status == :SKIP puts "\n _BACK: #{parsed[@back_index].inspect}\n " if $VERBOSE display if $VERBOSE end end |
#step(parsed) ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/fam/machine/cpu.rb', line 56 def step parsed @parsed = parsed return {:state => 'done'} if @tree_index >= parsed.tree.size || @halted @tree_index += 1 node = parsed[@tree_index] status = execute node if status == :STOP @halted = true return {:state => 'done'} end {:state => 'running', :input => @inputting, :output => @outputting} end |
#UnexpectedNode(node, sub_node) ⇒ Object
185 186 187 188 |
# File 'lib/fam/machine/cpu.rb', line 185 def UnexpectedNode node, sub_node print "\n" * (@ram.to_s.count("\n") + 1) if $VERBOSE abort ("Unexpected Node, you've given `#{sub_node.base_name}` AST::to Node: `#{node.base_name}`?").red.bold end |