Георги обнови решението на 15.01.2014 15:33 (преди почти 11 години)
+module Asm
+ def self.asm(&block)
+ Cpu.new.execute &block
+ end
+
+ module TransferInstructions
+ def mov(register, value)
+ @microinstructions << proc { registers[register] = registers[value] }
+ end
+ end
+
+ module ArithmeticInstructions
+ def inc(register, value = 1)
+ @microinstructions << proc { registers[register] += registers[value] }
+ end
+
+ def dec(register, value = 1)
+ @microinstructions << proc { registers[register] -= registers[value] }
+ end
+ end
+
+ module LogicalInstructions
+ def cmp(register, value)
+ @microinstructions << proc do
+ registers[:flag] = registers[register] <=> registers[value]
+ end
+ end
+ end
+
+ module BranchInstructions
+ branch_conditions = {
+ jmp: ->(x) { true },
+ je: ->(x) { x == 0 },
+ jne: ->(x) { x != 0 },
+ jl: ->(x) { x < 0 },
+ jle: ->(x) { x <= 0 },
+ jg: ->(x) { x > 0 },
+ jge: ->(x) { x >= 0 },
+ }
+
+ jump_instruction = proc do |instruction_index, condition|
+ proc do
+ if condition.call(registers[:flag])
+ @instruction_pointer = labels[instruction_index] - 1
+ end
+ end
+ end
+
+ branch_conditions.each do |instruction_name, condition|
+ define_method instruction_name do |instruction_index|
+ @microinstructions << jump_instruction.call(instruction_index, condition)
+ end
+ end
+ end
+
+ class DecodeUnit
+ include TransferInstructions
+ include ArithmeticInstructions
+ include LogicalInstructions
+ include BranchInstructions
+
+ attr_reader :ax, :bx, :cx, :dx, :flag
+
+ def initialize
+ @ax = :ax
+ @bx = :bx
+ @cx = :cx
+ @dx = :dx
+ @flag = :flag
+
+ @microinstructions = []
+ @labels = Hash.new { |hash, key| key }
+ end
+
+ def decode(&block)
+ instance_eval &block
+
+ [@microinstructions, @labels]
+ end
+
+ def method_missing(method, *args, &block)
+ method
+ end
+
+ def label(name)
+ @labels[name] = @microinstructions.length
+ end
+ end
+
+ class ExecutionUnit
+ REGISTER_NAMES = [:ax, :bx, :cx, :dx, :flag]
+
+ attr_accessor :registers, :labels, :instruction_pointer
+
+ def initialize(microinstructions, labels)
+ @labels = labels
+ @instructions = microinstructions
+ @instruction_pointer = 0
+
+ @registers = Hash.new do |hash, key|
+ REGISTER_NAMES.member?(key) ? 0 : key
+ end
+ end
+
+ def execute
+ while @instruction_pointer < @instructions.length
+ instance_eval &@instructions[@instruction_pointer]
+ @instruction_pointer += 1
+ end
+
+ REGISTER_NAMES[0...-1].map { |register| @registers[register] }
+ end
+ end
+
+ class Cpu
+ def execute(&block)
+ microcode = DecodeUnit.new.decode(&block)
+ ExecutionUnit.new(*microcode).execute
+ end
+ end
+end