-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCPUCore.rb
151 lines (136 loc) · 3.32 KB
/
CPUCore.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
144
145
146
147
148
149
150
151
class Array
def pop_zero
j=self.pop
j=0 if j==nil
return j
end
def round(x)
return self[x % self.length]
end
end
class String
def round(x)
return self[x % self.length]
end
end
class CPUCore
def initialize()
@core = CPULoader.new()
@core.load(ARGV[0])
end
def begin
# debug @core.inspect
@core.run
# puts @core.inspect
end
end
class CPULoader
def initialize()
@opcodes = {}
@regs = []
@special_mode = []
@special_modes = {}
@pc_block = nil
@pc_args = {}
end
def debug(a)
# puts a
end
def load(*args, &block)
# Convert a parameter to a hash.
options = args.last.is_a?(Hash) ? args.pop : {}
args.each { |arg| load options.merge(:file=>arg) }
return unless args.empty?
if options[:file]
file = options[:file]
load :string => File.read(file), :name => options[:name] || file
elsif options[:string]
instance_eval(options[:string], options[:name]|| "<eval>")
end
end
def opcode(*args,&block)
options = args.last.is_a?(Hash) ? args.pop : {}
args.each { |arg| opcode options.merge(:opcode=>arg), &block }
return unless args.empty?
debug "Defining opcode " + (options.inspect)
options[:block]=block
opcode = options[:opcode]
opcode = opcode[0] if opcode.is_a?(String)
@opcodes[opcode] = options
end
def special_mode(*args,&block)
options = args.last.is_a?(Hash) ? args.pop : {}
args.each { |arg| special_mode options.merge(:opcode=>arg), &block }
return unless args.empty?
debug "Defining special mode " + (options.inspect)
opcode = options[:opcode]
opcode = opcode[0] if opcode.is_a?(String)
@special_modes[opcode] = block
end
def mem(args)
@mem="\0" * args[:size]
end
def pc(args,&block)
@pc_args = args
@pc=args[:start]
@pc_block = block
debug args.inspect
end
def register(args)
args[:initial] = 0 unless args.include? :initial
instance_variable_set(args[:name],args[:initial])
@regs << args[:name]
debug args.inspect
end
def rom(options)
if options[:file]
file = options[:file]
rom :string => File.read(file), :name => options[:name] || file
elsif options[:string]
@rom = options[:string]
end
debug options.inspect
end
def push_special_mode(mode)
@special_mode.push(mode)
debug "Entering special mode"
end
def pop_special_mode()
@special_mode.pop()
debug "Exiting special mode"
end
def run()
while true
j = @rom[@pc] unless @pc_args.include? :pc_read
j = @pc_args[:pc_read].call if @pc_args.include? :pc_read
return if nil == j
values = {:instruction_size=>1}
#debug "%x PC: %i %i %i" % [j, @pc, @dp, @mem[@dp]]
#debug "%c PC: %i %s" % [j, @pc, @stack.inspect]
if nil != @special_mode[-1]
debug "Special mode %s" % j
if @special_modes.include?(@special_mode[-1][0])
debug @special_modes[j].inspect
k = @special_modes[@special_mode[-1][0]].call(j)
values.merge!(k) if k.is_a?(Hash)
debug "Return : " + k.inspect
end
else
if @opcodes.include?(j)
values.merge!(@opcodes[j]) # Take the options for this opcode.
#debug @opcodes[j].inspect
k = @opcodes[j][:block].call
values.merge!(k) if k.is_a?(Hash)
debug "Return : " + k.inspect
else
$stderr.puts "Warning unknown opcode %x" % (j)
end
end
if nil == @pc_block
@pc+=values[:instruction_size]
else
@pc_block.call(values)
end
end
end
end