-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProcessor.rb
227 lines (187 loc) · 6.14 KB
/
Processor.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# Copyright (c) 2021 [hds536jhmk](https://github.com/hds536jhmk/pemu-RubyProcessor)
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
require "PEMUJRubyPluginAPI"
require_relative "Utils.rb"
require_relative "localization/Translations.rb"
# This class is a copy-paste of PEMU::Processor (But written in Ruby):
# https://github.com/hds536jhmk/ProcessorEmulator/blob/master/src/main/java/io/github/hds/pemu/processor/Processor.java
class Processor
protected
attr_accessor :is_running
attr_accessor :register_words
attr_accessor :reserved_stack_elements
attr_accessor :flags_words
attr_accessor :memory
attr_accessor :clock
attr_accessor :instruction_set
attr_accessor :history
attr_accessor :registers
attr_accessor :flags
attr_accessor :char_pressed
attr_accessor :key_pressed
attr_accessor :start_timestamp
attr_accessor :is_paused
attr_accessor :stepping
public
# Implementing interface PEMU::IProcessor
include PEMU::IProcessor
def initialize(config)
self.is_running = false
self.register_words = 2
self.reserved_stack_elements = 1
self.flags_words = 1
self.memory = PEMU::Memory.new(
config.memory_size,
PEMU::Word.getClosestWord(config.bits)
)
self.clock = PEMU::Clock.new config.clock_frequency
self.instruction_set = config.instruction_set
self.history = PEMU::InstructionHistory.new
self.registers = PEMU::RegisterHolder.new(
PEMU::MemoryRegister.new(getProgramAddress() , "Instruction Pointer", self.memory, 0),
PEMU::MemoryRegister.new(self.memory.size - 1, "Stack Pointer" , self.memory, 1)
)
self.flags = PEMU::FlagHolder.new(
PEMU::MemoryFlag.new(false, "Zero Flag" , self.memory, self.register_words, 0),
PEMU::MemoryFlag.new(false, "Carry Flag", self.memory, self.register_words, 1)
)
self.char_pressed = "\0"
self.key_pressed = PEMU::KeyEvent::VK_UNDEFINED
self.start_timestamp = 0
self.is_paused = false
self.stepping = false
end
def self.getDummyProcessor(config)
return PEMU::DummyProcessor.new(
config,
[ PEMU::DummyMemoryRegister.new("Instruction Pointer"), PEMU::DummyMemoryRegister.new("Stack Pointer") ],
[ PEMU::DummyMemoryFlag.new("Zero Flag"), PEMU::DummyMemoryFlag.new("Carry Flag") ]
)
end
def getFlags()
return self.flags.toArray
end
def getRegisters()
return self.registers.toArray
end
def getFlag(shortName)
return self.flags.getFlag shortName
end
def getRegister(shortName)
return self.registers.getRegister shortName
end
def getMemory()
return self.memory
end
def getClock()
return self.clock
end
def getInstructionSet()
return self.instruction_set
end
def getKeyPressed()
return self.key_pressed
end
def setKeyPressed(key)
self.key_pressed = key
end
def getCharPressed()
return self.char_pressed
end
def setCharPressed(char)
self.char_pressed = char
end
def getInfo()
current_translation = Translations.instance.current_translation
return PEMU::StringUtils.format(
"\t{0}:\t#{ PEMU::StringUtils.getEngNotation(self.clock.getFrequency(), "Hz") }\n"\
"\t{1}:\t#{ self.memory.getSize() }x#{ self.memory.getWord().TOTAL_BYTES } Bytes\n"\
"\t{2}:\t#{ self.instruction_set.getSize() }\n",
current_translation.getOrDefault("messages.clock"),
current_translation.getOrDefault("messages.memory"),
current_translation.getOrDefault("messages.instructions")
);
end
def getInstructionHistory()
return self.history
end
def getTimeRunning()
return -1 if !self.is_running
return get_time_millis() - self.start_timestamp
end
def loadProgram(program)
return Translations.instance.current_translation.getOrDefault("messages.processorOutOfMemory") if program.length > self.memory.getSize() - getReservedWords()
self.memory.setValuesAt(getProgramAddress(), program)
return nil
end
def getProgramAddress()
return self.register_words + self.flags_words
end
def getReservedWords()
return self.register_words + self.flags_words + self.reserved_stack_elements
end
def isRunning()
return self.is_running
end
def run()
return if self.is_running
self.start_timestamp = get_time_millis()
self.is_running = true
while self.is_running do
if self.clock.update() && (self.stepping || !self.is_paused) then
self.stepping = false
ip = self.registers.getRegister("IP")
if ip.getValue() >= self.memory.getSize() then
stop()
else
currentIP = ip.getValue()
instruction = self.instruction_set.getInstruction(self.memory.getValueAt(currentIP))
raise PEMU::InstructionError.new("Unknown", "Unknown Instruction", currentIP) if instruction == nil
self.history.put(currentIP.to_i, instruction.getKeyword())
ip.setValue(currentIP + instruction.getWords())
begin
instruction.execute(
self, instruction.getArgumentsCount() == 0 ? [] : self.memory.getValuesAt(currentIP + 1, instruction.getArgumentsCount())
)
rescue Exception => err
raise PEMU::InstructionError.new(instruction.getKeyword(), err.to_s, currentIP)
end
end
end
end
end
def stop()
self.is_running = false
end
def isPaused()
return self.is_paused
end
def pause()
self.is_paused = true
end
def resume()
self.is_paused = false
end
def step()
self.stepping = true
end
end