Rdcpu16 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +21 -0
- data/README.rdoc +10 -0
- data/Rakefile +42 -0
- data/lib/dcpu16/cpu/instructions.rb +137 -0
- data/lib/dcpu16/cpu.rb +111 -0
- data/lib/dcpu16/instruction.rb +57 -0
- data/lib/dcpu16/literal.rb +19 -0
- data/lib/dcpu16/memory.rb +40 -0
- data/lib/dcpu16/operand.rb +61 -0
- data/lib/dcpu16/register.rb +35 -0
- data/lib/dcpu16/support/debug.rb +47 -0
- data/lib/dcpu16/version.rb +4 -0
- data/lib/dcpu16/word.rb +20 -0
- data/lib/dcpu16.rb +6 -0
- data/spec/integration/example1_spec.rb +28 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/dcpu16_cpu_spec.rb +45 -0
- data/spec/unit/dcpu16_instruction_spec.rb +28 -0
- data/spec/unit/dcpu16_instructions_spec.rb +255 -0
- data/spec/unit/dcpu16_memory_spec.rb +16 -0
- data/spec/unit/dcpu16_operand_spec.rb +78 -0
- data/spec/unit/dcpu16_register_spec.rb +6 -0
- data/spec/unit/dcpu16_word_spec.rb +17 -0
- data/spec/unit/support/sample_observer.rb +14 -0
- metadata +90 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright 2012 Patrick Helm
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
##!/usr/bin/env rake
|
2
|
+
##include Rake::DSL
|
3
|
+
|
4
|
+
require "bundler/gem_tasks"
|
5
|
+
|
6
|
+
#begin
|
7
|
+
# require 'bundler/setup'
|
8
|
+
#rescue LoadError
|
9
|
+
# puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
10
|
+
#end
|
11
|
+
#begin
|
12
|
+
# require 'rdoc/task'
|
13
|
+
#rescue LoadError
|
14
|
+
# require 'rdoc/rdoc'
|
15
|
+
# require 'rake/rdoctask'
|
16
|
+
# RDoc::Task = Rake::RDocTask
|
17
|
+
#end
|
18
|
+
|
19
|
+
#RDoc::Task.new(:rdoc) do |rdoc|
|
20
|
+
# rdoc.rdoc_dir = 'rdoc'
|
21
|
+
# rdoc.title = 'RubyRescuetime'
|
22
|
+
# rdoc.options << '--line-numbers'
|
23
|
+
# rdoc.rdoc_files.include('README.rdoc')
|
24
|
+
# rdoc.rdoc_files.include('lib/**/*.rb')
|
25
|
+
#end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
#Bundler::GemHelper.install_tasks
|
30
|
+
|
31
|
+
## require 'rake/testtask'
|
32
|
+
|
33
|
+
##Rake::TestTask.new(:test) do |t|
|
34
|
+
## t.libs << 'lib'
|
35
|
+
## t.libs << 'test'
|
36
|
+
## t.pattern = 'test/**/*_test.rb'
|
37
|
+
## t.verbose = true
|
38
|
+
##end
|
39
|
+
|
40
|
+
|
41
|
+
##task :default => :test
|
42
|
+
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module DCPU16
|
2
|
+
module Instructions
|
3
|
+
# sets a to b
|
4
|
+
def set(a, b)
|
5
|
+
@cycle += 1
|
6
|
+
b
|
7
|
+
end
|
8
|
+
|
9
|
+
# sets a to a+b, sets O to 0x0001 if there's an overflow, 0x0 otherwise
|
10
|
+
def add(a, b)
|
11
|
+
@cycle += 2
|
12
|
+
(a + b > 0xFFFF) ? @O.write(0x0001) : @O.write(0x0)
|
13
|
+
a + b
|
14
|
+
end
|
15
|
+
|
16
|
+
# sets a to a-b, sets O to 0xffff if there's an underflow, 0x0 otherwise
|
17
|
+
def sub(a, b)
|
18
|
+
@cycle += 2
|
19
|
+
(b > a) ? @O.write(0xffff) : @O.write(0x0)
|
20
|
+
a - b
|
21
|
+
end
|
22
|
+
|
23
|
+
# sets a to a*b, sets O to
|
24
|
+
def mul(a, b)
|
25
|
+
@cycle += 2
|
26
|
+
@O.write( ( (a * b) >> 16) & 0xffff )
|
27
|
+
a * b
|
28
|
+
end
|
29
|
+
|
30
|
+
# sets a to a/b, sets O to ((a<<16)/b)&0xffff. if b==0, sets a and O to 0 instead.
|
31
|
+
def div(a, b)
|
32
|
+
@cycle += 3
|
33
|
+
if b == 0
|
34
|
+
@O.write(0)
|
35
|
+
return 0
|
36
|
+
else
|
37
|
+
@O.write( ( (a << 16) / b) & 0xffff )
|
38
|
+
return (a / b)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# sets a to a%b. if b==0, sets a to 0 instead.
|
43
|
+
def mod(a, b)
|
44
|
+
@cycle += 3
|
45
|
+
(b == 0) ? 0 : a % b
|
46
|
+
end
|
47
|
+
|
48
|
+
# sets a to a<<b, sets O to ((a<<b)>>16)&0xffff
|
49
|
+
def shl(a, b)
|
50
|
+
@cycle += 2
|
51
|
+
@O.write( ( (a << b) >> 16 ) & 0xffff )
|
52
|
+
a << b
|
53
|
+
end
|
54
|
+
|
55
|
+
# sets a to a>>b, sets O to ((a<<16)>>b)&0xffff
|
56
|
+
def shr(a, b)
|
57
|
+
@cycle += 2
|
58
|
+
@O.write( ( (a << 16) >> b) & 0xffff )
|
59
|
+
a >> b
|
60
|
+
end
|
61
|
+
|
62
|
+
# sets a to a & b
|
63
|
+
def and(a, b)
|
64
|
+
@cycle += 1
|
65
|
+
a & b
|
66
|
+
end
|
67
|
+
|
68
|
+
# sets a to a | b
|
69
|
+
def bor(a, b)
|
70
|
+
@cycle += 1
|
71
|
+
a | b
|
72
|
+
end
|
73
|
+
|
74
|
+
# sets a to a ^ b
|
75
|
+
def xor(a, b)
|
76
|
+
@cycle += 1
|
77
|
+
a ^ b
|
78
|
+
end
|
79
|
+
|
80
|
+
# performs next instruction only if a == b
|
81
|
+
def ife(a, b)
|
82
|
+
@cycle += 2
|
83
|
+
@skip = !(a == b)
|
84
|
+
@cycle += 1 unless a == b
|
85
|
+
|
86
|
+
return nil
|
87
|
+
end
|
88
|
+
|
89
|
+
# performs next instruction only if a != b
|
90
|
+
def ifn(a, b)
|
91
|
+
@cycle += 2
|
92
|
+
@skip = !(a != b)
|
93
|
+
@cycle += 1 unless a != b
|
94
|
+
|
95
|
+
return nil
|
96
|
+
end
|
97
|
+
|
98
|
+
# performs next instruction only if a > b
|
99
|
+
def ifg(a, b)
|
100
|
+
@cycle += 2
|
101
|
+
@skip = !(a > b)
|
102
|
+
@cycle += 1 unless a > b
|
103
|
+
|
104
|
+
return nil
|
105
|
+
end
|
106
|
+
|
107
|
+
# performs next instruction only if (a & b) != 0
|
108
|
+
def ifb(a, b)
|
109
|
+
@cycle += 2
|
110
|
+
@skip = !((a & b) != 0)
|
111
|
+
@cycle += 1 unless (a & b) != 0
|
112
|
+
|
113
|
+
return nil
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
class Reserved < StandardError; end
|
118
|
+
|
119
|
+
### NON - Basic ###
|
120
|
+
def reserved(a)
|
121
|
+
raise Reserved
|
122
|
+
end
|
123
|
+
|
124
|
+
# JSR a - pushes the address of the next instruction to the stack, then sets PC to a
|
125
|
+
def jsr(a)
|
126
|
+
@cycle += 2
|
127
|
+
|
128
|
+
# pushes the address of the next instruction to the stack
|
129
|
+
@SP -= 1
|
130
|
+
@memory.write(@SP, @PC.read)
|
131
|
+
|
132
|
+
@PC.write(a)
|
133
|
+
return nil
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
data/lib/dcpu16/cpu.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'dcpu16/support/debug'
|
2
|
+
|
3
|
+
require 'dcpu16/cpu/instructions'
|
4
|
+
|
5
|
+
require 'dcpu16/instruction'
|
6
|
+
require 'dcpu16/literal'
|
7
|
+
require 'dcpu16/memory'
|
8
|
+
require 'dcpu16/operand'
|
9
|
+
require 'dcpu16/register'
|
10
|
+
|
11
|
+
require "observer"
|
12
|
+
|
13
|
+
module DCPU16
|
14
|
+
class CPU
|
15
|
+
include DCPU16::Debug
|
16
|
+
include DCPU16::Instructions
|
17
|
+
include Observable
|
18
|
+
|
19
|
+
RAM_SIZE = 0x10000
|
20
|
+
REGISTERS = [:A, :B, :C, :X, :Y, :Z, :I, :J]
|
21
|
+
REGISTERS_COUNT = REGISTERS.length
|
22
|
+
CLOCK_CYCLE = 100000 # cycles per second
|
23
|
+
|
24
|
+
attr_accessor :cycle, :memory, :registers
|
25
|
+
|
26
|
+
# program counter (PC), stack pointer (SP), overflow (O)
|
27
|
+
attr_accessor :PC, :SP, :O
|
28
|
+
|
29
|
+
# HACK: actually used to determine if we need to skip next instruction
|
30
|
+
attr_accessor :skip
|
31
|
+
|
32
|
+
attr_accessor :clock_cycle
|
33
|
+
|
34
|
+
def initialize(memory = [])
|
35
|
+
@cycle = 0
|
36
|
+
@memory = DCPU16::Memory.new(memory)
|
37
|
+
@registers = Array.new(REGISTERS_COUNT) { DCPU16::Register.new }
|
38
|
+
@PC = DCPU16::Register.new(0x0)
|
39
|
+
@SP = DCPU16::Register.new(0xFFFF)
|
40
|
+
@O = DCPU16::Register.new(0x0)
|
41
|
+
|
42
|
+
@clock_cycle = CLOCK_CYCLE
|
43
|
+
@debug = true
|
44
|
+
@skip = false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Define alias_methods for Registers: A(), B(), ...
|
48
|
+
REGISTERS.each_with_index { |k, v| define_method(k) { registers[v] } }
|
49
|
+
|
50
|
+
# Run in endless loop
|
51
|
+
def run
|
52
|
+
@started_at = Time.now
|
53
|
+
max_cycles = 1
|
54
|
+
|
55
|
+
while true do
|
56
|
+
if @cycle < max_cycles
|
57
|
+
step
|
58
|
+
else
|
59
|
+
diff = Time.now - @started_at
|
60
|
+
max_cycles = (diff * @clock_cycle)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Resets the CPU and its sub-systems (registers, memory, ...)
|
66
|
+
def reset
|
67
|
+
@cycle = 0
|
68
|
+
@memory.reset
|
69
|
+
@registers.each { |r| r.reset }
|
70
|
+
@PC.reset
|
71
|
+
@SP.reset
|
72
|
+
@O.reset
|
73
|
+
end
|
74
|
+
|
75
|
+
# DOC
|
76
|
+
def last_instruction
|
77
|
+
@instruction
|
78
|
+
end
|
79
|
+
|
80
|
+
# Perform a single step
|
81
|
+
# TODO: Refacor if/else/if/else ...
|
82
|
+
def step
|
83
|
+
@instruction = Instruction.new(@memory.read(@PC))
|
84
|
+
@PC += 1
|
85
|
+
|
86
|
+
op = @instruction.op
|
87
|
+
a = get_operand(@instruction.a)
|
88
|
+
b = get_operand(@instruction.b) if @instruction.b
|
89
|
+
|
90
|
+
if @skip
|
91
|
+
@skip = false
|
92
|
+
else
|
93
|
+
if b
|
94
|
+
result = self.send(op, a.value, b.value)
|
95
|
+
else
|
96
|
+
result = self.send(op, a.value)
|
97
|
+
end
|
98
|
+
a.write(result) if result
|
99
|
+
end
|
100
|
+
|
101
|
+
changed
|
102
|
+
notify_observers(self)
|
103
|
+
end
|
104
|
+
|
105
|
+
# TODO: May be removed
|
106
|
+
def get_operand(value)
|
107
|
+
DCPU16::Operand.new(self, value)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Instructions are 1-3 words long and are fully defined by the first word.
|
2
|
+
# In a basic instruction, the lower four bits of the first word of the instruction are the opcode,
|
3
|
+
# and the remaining twelve bits are split into two six bit values, called a and b.
|
4
|
+
# a is always handled by the processor before b, and is the lower six bits.
|
5
|
+
|
6
|
+
# In bits (with the least significant being last),
|
7
|
+
# a basic instruction has the format: bbbbbbaaaaaaoooo
|
8
|
+
|
9
|
+
# bbbb bbaa aaaa oooo
|
10
|
+
# 0000 0000 0000 1111 -> 0x000f
|
11
|
+
# 0000 0011 1111 0000 -> 0x03f0
|
12
|
+
# 1111 1100 0000 0000 -> 0xfc00
|
13
|
+
|
14
|
+
# Non-basic opcodes always have their lower four bits unset, have one value and a six bit opcode.
|
15
|
+
# In binary, they have the format: aaaaaaoooooo0000
|
16
|
+
|
17
|
+
# aaaa aaoo oooo 0000
|
18
|
+
# 0000 0011 1111 0000 -> 0x03f0
|
19
|
+
# 1111 1100 0000 0000 -> 0xfc00
|
20
|
+
|
21
|
+
module DCPU16
|
22
|
+
class Instruction
|
23
|
+
INSTRUCTIONS = [
|
24
|
+
:reserved,
|
25
|
+
:set, :add, :sub, :mul, :div, :mod,
|
26
|
+
:shl, :shr,
|
27
|
+
:and, :bor, :xor,
|
28
|
+
:ife, :ifn, :ifg, :ifb
|
29
|
+
]
|
30
|
+
|
31
|
+
NON_BASIC_INSTRUCTIONS = [
|
32
|
+
:reserved,
|
33
|
+
:jsr
|
34
|
+
]
|
35
|
+
|
36
|
+
attr_reader :opcode, :a, :b, :word
|
37
|
+
|
38
|
+
def initialize(word = nil)
|
39
|
+
@word = word.value
|
40
|
+
@opcode = @word & 0x000F
|
41
|
+
|
42
|
+
if @opcode == 0x0
|
43
|
+
@non_basic = true
|
44
|
+
@opcode = (@word >> 4) & 0x3f
|
45
|
+
@a = @word >> 10
|
46
|
+
else
|
47
|
+
@a = (@word >> 4) & 0x3f
|
48
|
+
@b = @word >> 10
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def op
|
53
|
+
@non_basic ? NON_BASIC_INSTRUCTIONS[@opcode] : INSTRUCTIONS[@opcode]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Ruby, Y U NO INHERIT FROM INTEGER?
|
2
|
+
module DCPU16
|
3
|
+
class Literal
|
4
|
+
def initialize(value)
|
5
|
+
@value = value
|
6
|
+
end
|
7
|
+
|
8
|
+
def value
|
9
|
+
@value
|
10
|
+
end
|
11
|
+
alias_method :read, :value
|
12
|
+
|
13
|
+
# If any instruction tries to assign a literal value, the assignment fails silently
|
14
|
+
def write(value)
|
15
|
+
# pass
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'dcpu16/word'
|
2
|
+
|
3
|
+
module DCPU16
|
4
|
+
class Memory < Array
|
5
|
+
SIZE = 0x10000
|
6
|
+
DEFAULT_VALUE = 0x0
|
7
|
+
|
8
|
+
def initialize(default = [])
|
9
|
+
super(SIZE, DEFAULT_VALUE)
|
10
|
+
default.each_with_index { |word, offset| write(offset, word) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def read(offset)
|
14
|
+
# HACK: so we can just pass a Fixnum or a Register
|
15
|
+
offset = offset.value if offset.respond_to? :value
|
16
|
+
|
17
|
+
DCPU16::Word.new(self[offset], self, offset)
|
18
|
+
end
|
19
|
+
|
20
|
+
def write(offset, value)
|
21
|
+
# HACK: so we can just pass a Fixnum or a Register
|
22
|
+
offset = offset.value if offset.respond_to? :value
|
23
|
+
|
24
|
+
self[offset] = value
|
25
|
+
end
|
26
|
+
|
27
|
+
def reset
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def [](key)
|
32
|
+
super(key)
|
33
|
+
end
|
34
|
+
|
35
|
+
def []=(key, value)
|
36
|
+
super(key, value)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# TODO: Test && Refacoring
|
2
|
+
module DCPU16
|
3
|
+
class Operand
|
4
|
+
class NotFound < StandardError; end
|
5
|
+
|
6
|
+
def self.new(cpu, value)
|
7
|
+
if (0x00..0x07).include?(value)
|
8
|
+
# register (A, B, C, X, Y, Z, I or J, in that order)
|
9
|
+
return cpu.registers[value]
|
10
|
+
elsif (0x08..0x0f).include?(value)
|
11
|
+
# [register]
|
12
|
+
register = cpu.registers[value - DCPU16::CPU::REGISTERS_COUNT]
|
13
|
+
return cpu.memory.read(register)
|
14
|
+
elsif (0x10..0x17).include?(value)
|
15
|
+
cpu.cycle += 1
|
16
|
+
offset = cpu.memory.read(cpu.PC).value
|
17
|
+
cpu.PC += 1
|
18
|
+
return cpu.memory.read(offset + cpu.registers[value - 0x10].read)
|
19
|
+
elsif value == 0x18
|
20
|
+
# POP / [SP++]
|
21
|
+
r = cpu.memory.read(cpu.SP)
|
22
|
+
cpu.SP += 1
|
23
|
+
return r
|
24
|
+
elsif value == 0x19
|
25
|
+
# PEEK / [SP]
|
26
|
+
return cpu.memory.read(cpu.SP)
|
27
|
+
elsif value == 0x1a
|
28
|
+
# PUSH / [--SP]
|
29
|
+
cpu.SP -= 1
|
30
|
+
cpu.memory.read(cpu.SP)
|
31
|
+
elsif value == 0x1b
|
32
|
+
# SP
|
33
|
+
return cpu.SP
|
34
|
+
elsif value == 0x1c
|
35
|
+
# PC
|
36
|
+
return cpu.PC
|
37
|
+
elsif value == 0x1d
|
38
|
+
# O
|
39
|
+
return cpu.O
|
40
|
+
elsif value == 0x1e
|
41
|
+
# [next word]
|
42
|
+
cpu.cycle += 1
|
43
|
+
offset = cpu.memory.read(cpu.PC)
|
44
|
+
cpu.PC += 1
|
45
|
+
return cpu.memory.read(offset)
|
46
|
+
elsif value == 0x1f
|
47
|
+
# next word (literal)
|
48
|
+
cpu.cycle += 1
|
49
|
+
r = cpu.memory.read(cpu.PC)
|
50
|
+
cpu.PC += 1
|
51
|
+
return r
|
52
|
+
elsif (0x20..0x3f).include?(value)
|
53
|
+
# literal value 0x00-0x1f (literal)
|
54
|
+
DCPU16::Literal.new(value - 0x20)
|
55
|
+
else
|
56
|
+
raise NotFound
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module DCPU16
|
2
|
+
class Register
|
3
|
+
attr_reader :value
|
4
|
+
|
5
|
+
def initialize(value = 0x0)
|
6
|
+
@default_value = value
|
7
|
+
reset
|
8
|
+
end
|
9
|
+
|
10
|
+
def value
|
11
|
+
warn "[Register #{self}] No Value defined" unless @value
|
12
|
+
@value
|
13
|
+
end
|
14
|
+
alias_method :read, :value
|
15
|
+
|
16
|
+
def +(value)
|
17
|
+
@value += value
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def -(value)
|
22
|
+
@value -= value
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def write(value)
|
27
|
+
@value = value
|
28
|
+
end
|
29
|
+
|
30
|
+
def reset
|
31
|
+
@value = @default_value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# Just a simple Debugger class
|
2
|
+
module DCPU16
|
3
|
+
module Debug
|
4
|
+
# Debug-mode turned on?
|
5
|
+
def debug?
|
6
|
+
@debug ||= false
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
# Debug-Wrapper
|
11
|
+
def debug(msg = nil, &block)
|
12
|
+
return unless debug?
|
13
|
+
|
14
|
+
puts "\n[DEBUG] - #{caller.first}"
|
15
|
+
msg.each { |m| puts(m) } if msg.is_a?(Array)
|
16
|
+
|
17
|
+
if msg.is_a?(Hash)
|
18
|
+
msg.each do |k, v|
|
19
|
+
puts "[#{k.to_s}]"
|
20
|
+
|
21
|
+
if v.is_a?(Array)
|
22
|
+
v.each {|m| puts(m) }
|
23
|
+
else
|
24
|
+
puts v
|
25
|
+
end
|
26
|
+
end
|
27
|
+
elsif (msg.is_a?(String) || msg.is_a?(Symbol))
|
28
|
+
puts msg.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
yield if block_given?
|
32
|
+
puts "\n"
|
33
|
+
end
|
34
|
+
|
35
|
+
# DCPU16::CPU
|
36
|
+
def debug_state
|
37
|
+
debug do
|
38
|
+
puts "Cycle:\t#{@cycle}"
|
39
|
+
puts "PC:\t#{@PC}"
|
40
|
+
puts "SP:\t#{@SP}"
|
41
|
+
puts "O:\t#{@O}"
|
42
|
+
puts "R:\t#{@registers}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
data/lib/dcpu16/word.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module DCPU16
|
2
|
+
class Word
|
3
|
+
def initialize(value, memory = nil, offset = nil)
|
4
|
+
@value = value
|
5
|
+
@memory = memory
|
6
|
+
@offset = offset
|
7
|
+
end
|
8
|
+
|
9
|
+
def value
|
10
|
+
@value
|
11
|
+
end
|
12
|
+
alias_method :read, :value
|
13
|
+
|
14
|
+
def write(value)
|
15
|
+
@value = value
|
16
|
+
@memory.write(@offset, value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
data/lib/dcpu16.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe DCPU16::CPU do
|
4
|
+
describe "quick example by notch" do
|
5
|
+
let(:dump) do
|
6
|
+
[ 0x7c01, 0x0030, 0x7de1, 0x1000, 0x0020, 0x7803, 0x1000, 0xc00d,
|
7
|
+
0x7dc1, 0x001a, 0xa861, 0x7c01, 0x2000, 0x2161, 0x2000, 0x8463,
|
8
|
+
0x806d, 0x7dc1, 0x000d, 0x9031, 0x7c10, 0x0018, 0x7dc1, 0x001a,
|
9
|
+
#0x9037, 0x61c1, 0x7dc1, 0x001a, 0x0000, 0x0000, 0x0000, 0x0000 ]
|
10
|
+
0x9037, 0x61c1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 ]
|
11
|
+
end
|
12
|
+
|
13
|
+
subject { DCPU16::CPU.new(dump) }
|
14
|
+
|
15
|
+
# Just double-check that memory is loaded
|
16
|
+
specify { subject.memory.read(0x0).value.should == 0x7c01 }
|
17
|
+
# specify { subject.memory.read(0x1b).value.should == 0x001a }
|
18
|
+
|
19
|
+
specify do
|
20
|
+
expect { subject.run }.to raise_error
|
21
|
+
|
22
|
+
subject.cycle.should == 104
|
23
|
+
subject.A.value.should == 0x2000
|
24
|
+
subject.X.value.should == 0x40
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
require 'unit/support/sample_observer'
|
3
|
+
|
4
|
+
describe DCPU16::CPU do
|
5
|
+
# Initialize with non failing memory dump
|
6
|
+
subject { DCPU16::CPU.new( Array.new(10000, 0x01) ) }
|
7
|
+
|
8
|
+
describe "Register" do
|
9
|
+
its(:registers) { subject.length == 8 }
|
10
|
+
its(:registers) { subject[0] == be_kind_of(DCPU16::Register) }
|
11
|
+
|
12
|
+
its(:PC) { should be_kind_of(DCPU16::Register) }
|
13
|
+
its(:SP) { should be_kind_of(DCPU16::Register) }
|
14
|
+
its(:O) { should be_kind_of(DCPU16::Register) }
|
15
|
+
end
|
16
|
+
|
17
|
+
its(:cycle) { should == 0 }
|
18
|
+
its(:memory) { should be_kind_of(DCPU16::Memory) }
|
19
|
+
|
20
|
+
|
21
|
+
describe "#reset" do
|
22
|
+
it "resets its #cycle" do
|
23
|
+
subject.cycle = 2
|
24
|
+
subject.reset
|
25
|
+
subject.cycle.should == 0
|
26
|
+
end
|
27
|
+
it "resets its #memory" do
|
28
|
+
subject.memory.should_receive(:reset)
|
29
|
+
subject.reset
|
30
|
+
end
|
31
|
+
it "resets its #registers" do
|
32
|
+
subject.registers.each { |register| register.should_receive(:reset) }
|
33
|
+
subject.reset
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "Observable" do
|
38
|
+
let(:observer) { DCPU16::SampleObserver.new }
|
39
|
+
specify do
|
40
|
+
subject.add_observer(observer)
|
41
|
+
expect { subject.step }.to change{observer.cycle}.by(1)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe DCPU16::Instruction do
|
4
|
+
context "when initialized with 0x00" do
|
5
|
+
let(:word) { DCPU16::Word.new(0x00) }
|
6
|
+
subject { DCPU16::Instruction.new(word) }
|
7
|
+
its(:opcode) { should == 0 }
|
8
|
+
its(:a) { should == 0 }
|
9
|
+
its(:b) { should be_nil }
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when initialized with 0x0001" do
|
13
|
+
let(:word) { DCPU16::Word.new(0x0001) }
|
14
|
+
subject { DCPU16::Instruction.new(word) }
|
15
|
+
its(:opcode) { should == 1 }
|
16
|
+
its(:a) { should == 0 }
|
17
|
+
its(:b) { should == 0 }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when initialized with 0xa861" do
|
21
|
+
let(:word) { DCPU16::Word.new(0xa861) }
|
22
|
+
subject { DCPU16::Instruction.new(word) }
|
23
|
+
its(:opcode) { should == 1 }
|
24
|
+
its(:a) { should == 0x6 }
|
25
|
+
its(:b) { should == 0xa + 0x20 } # Literal value (offset += 0x20)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,255 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe DCPU16::Instructions do
|
4
|
+
subject { DCPU16::CPU.new }
|
5
|
+
let(:a) { 0x01 }
|
6
|
+
let(:b) { 0x02 }
|
7
|
+
|
8
|
+
|
9
|
+
describe "#set" do
|
10
|
+
it "sets a to b" do
|
11
|
+
subject.set(a, b).should == b
|
12
|
+
end
|
13
|
+
it "take 1 cycle, plus the cost of a and b" do
|
14
|
+
expect { subject.set(a, b) }.to change{subject.cycle}.by(1)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
describe "#add" do
|
20
|
+
it "sets a to a+b" do
|
21
|
+
subject.add(2, 3).should == 5
|
22
|
+
end
|
23
|
+
context "with overflow" do
|
24
|
+
it "sets O to 0x0001" do
|
25
|
+
subject.add(0xFFFE, 2)
|
26
|
+
subject.O.value.should == 0x0001
|
27
|
+
end
|
28
|
+
end
|
29
|
+
context "without overflow" do
|
30
|
+
it "sets O to 0x0" do
|
31
|
+
subject.add(0xFFFE, 1)
|
32
|
+
subject.O.value.should == 0x0
|
33
|
+
end
|
34
|
+
end
|
35
|
+
it "take 2 cycles, plus the cost of a and b" do
|
36
|
+
expect { subject.add(a, b) }.to change{subject.cycle}.by(2)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
describe "#sub" do
|
42
|
+
it "sets a to a-b" do
|
43
|
+
subject.sub(3, 2).should == 1
|
44
|
+
end
|
45
|
+
context "with underflow" do
|
46
|
+
it "set O to 0xffff" do
|
47
|
+
subject.sub(2, 3)
|
48
|
+
subject.O.value.should == 0xffff
|
49
|
+
end
|
50
|
+
end
|
51
|
+
context "without underflow" do
|
52
|
+
it "set O to 0x0" do
|
53
|
+
subject.sub(2, 2)
|
54
|
+
subject.O.value.should == 0x0
|
55
|
+
end
|
56
|
+
end
|
57
|
+
it "take 2 cycles, plus the cost of a and b" do
|
58
|
+
expect { subject.sub(a, b) }.to change{subject.cycle}.by(2)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
describe "#mul" do
|
64
|
+
it "sets a to a*b" do
|
65
|
+
subject.mul(2, 3).should == 6
|
66
|
+
end
|
67
|
+
it "sets O to ((a*b)>>16)&0xffff" do
|
68
|
+
subject.mul(256, 256)
|
69
|
+
subject.O.value.should == ((256*256)>>16) & 0xFFFF
|
70
|
+
end
|
71
|
+
it "take 2 cycles, plus the cost of a and b" do
|
72
|
+
expect { subject.mul(a, b) }.to change{subject.cycle}.by(2)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
describe "#div" do
|
78
|
+
it "sets a to a/b" do
|
79
|
+
subject.div(9, 3).should == 3
|
80
|
+
subject.div(8, 3).should == 2
|
81
|
+
end
|
82
|
+
context "when b != 0" do
|
83
|
+
it "sets O to ((a<<16)/b)&0xffff" do
|
84
|
+
subject.div(1, 2)
|
85
|
+
subject.O.value.should == ((1 << 16)/2) & 0xFFFF
|
86
|
+
end
|
87
|
+
end
|
88
|
+
context "when b == 0" do
|
89
|
+
it "sets a and O to 0" do
|
90
|
+
subject.div(3, 0).should == 0
|
91
|
+
subject.O.value.should == 0
|
92
|
+
end
|
93
|
+
end
|
94
|
+
it "take 3 cycles, plus the cost of a and b" do
|
95
|
+
expect { subject.div(a, b) }.to change{subject.cycle}.by(3)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
describe "#mod" do
|
101
|
+
context "when b != 0" do
|
102
|
+
it "sets a to a % b" do
|
103
|
+
subject.mod(3, 2).should == 1
|
104
|
+
end
|
105
|
+
end
|
106
|
+
context "when b == 0" do
|
107
|
+
it "sets a to 0" do
|
108
|
+
subject.mod(3, 0).should == 0
|
109
|
+
end
|
110
|
+
end
|
111
|
+
it "take 3 cycles, plus the cost of a and b" do
|
112
|
+
expect { subject.mod(a, b) }.to change{subject.cycle}.by(3)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
describe "#shl" do
|
118
|
+
it "sets a to a<<b" do
|
119
|
+
subject.shl(4, 2).should == 16
|
120
|
+
end
|
121
|
+
it "sets O to ((a<<b)>>16)&0xffff" do
|
122
|
+
subject.shl(1, 17)
|
123
|
+
subject.O.value.should == ((1 << 17) >> 16)&0xffff
|
124
|
+
end
|
125
|
+
it "take 2 cycles, plus the cost of a and b" do
|
126
|
+
expect { subject.shl(a, b) }.to change{subject.cycle}.by(2)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
describe "#shr" do
|
132
|
+
it "sets a to a>>b" do
|
133
|
+
subject.shr(4, 2).should == 1
|
134
|
+
end
|
135
|
+
it "sets O to ((a<<16)>>b)&0xffff" do
|
136
|
+
subject.shr(2, 2)
|
137
|
+
subject.O.value.should == ((2 << 16) >> 2) & 0xffff
|
138
|
+
end
|
139
|
+
it "take 2 cycles, plus the cost of a and b" do
|
140
|
+
expect { subject.shr(a, b) }.to change{subject.cycle}.by(2)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
describe "#and" do
|
146
|
+
it "sets a to a&b" do
|
147
|
+
subject.and(1, 2).should == 0
|
148
|
+
subject.and(1, 3).should == 1
|
149
|
+
end
|
150
|
+
it "take 1 cycles, plus the cost of a and b" do
|
151
|
+
expect { subject.and(a, b) }.to change{subject.cycle}.by(1)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
describe "#bor" do
|
157
|
+
it "sets a to a|b" do
|
158
|
+
subject.bor(1, 2).should == 3
|
159
|
+
end
|
160
|
+
it "take 1 cycles, plus the cost of a and b" do
|
161
|
+
expect { subject.bor(a, b) }.to change{subject.cycle}.by(1)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
describe "#xor" do
|
167
|
+
it "sets a to a^b" do
|
168
|
+
subject.xor(1, 3).should == 2
|
169
|
+
end
|
170
|
+
it "take 1 cycles, plus the cost of a and b" do
|
171
|
+
expect { subject.xor(a, b) }.to change{subject.cycle}.by(1)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
describe "#ife" do
|
177
|
+
it "performs next instruction only if a==b" do
|
178
|
+
subject.ife(1, 1)
|
179
|
+
subject.skip.should be_false
|
180
|
+
subject.ife(1, 2)
|
181
|
+
subject.skip.should be_true
|
182
|
+
end
|
183
|
+
context "if test passes" do
|
184
|
+
it "take 2 cycles, plus the cost of a and b" do
|
185
|
+
expect { subject.ife(2, 2) }.to change{subject.cycle}.by(2)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
context "if test fails" do
|
189
|
+
it "take 3 cycles, plus the cost of a and b" do
|
190
|
+
expect { subject.ife(2, 3) }.to change{subject.cycle}.by(3)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
describe "#ifn" do
|
197
|
+
it "performs next instruction only if a!=b" do
|
198
|
+
subject.ifn(1, 1)
|
199
|
+
subject.skip.should be_true
|
200
|
+
subject.ifn(1, 2)
|
201
|
+
subject.skip.should be_false
|
202
|
+
end
|
203
|
+
context "if test passes" do
|
204
|
+
it "take 2 cycles, plus the cost of a and b" do
|
205
|
+
expect { subject.ifn(1, 2) }.to change{subject.cycle}.by(2)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
context "if test fails" do
|
209
|
+
it "take 3 cycles, plus the cost of a and b" do
|
210
|
+
expect { subject.ifn(2, 2) }.to change{subject.cycle}.by(3)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
describe "#ifg" do
|
217
|
+
it "performs next instruction only if a > b" do
|
218
|
+
subject.ifg(1, 2)
|
219
|
+
subject.skip.should be_true
|
220
|
+
subject.ifg(2, 1)
|
221
|
+
subject.skip.should be_false
|
222
|
+
end
|
223
|
+
context "if test passes" do
|
224
|
+
it "take 2 cycles, plus the cost of a and b" do
|
225
|
+
expect { subject.ifg(3, 2) }.to change{subject.cycle}.by(2)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
context "if test fails" do
|
229
|
+
it "take 3 cycles, plus the cost of a and b" do
|
230
|
+
expect { subject.ifg(2, 3) }.to change{subject.cycle}.by(3)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
describe "#ifb" do
|
237
|
+
it "performs next instruction only if (a&b)!=0" do
|
238
|
+
subject.ifb(1, 3)
|
239
|
+
subject.skip.should be_false
|
240
|
+
subject.ifb(1, 2)
|
241
|
+
subject.skip.should be_true
|
242
|
+
end
|
243
|
+
context "if test passes" do
|
244
|
+
it "take 2 cycles, plus the cost of a and b" do
|
245
|
+
expect { subject.ifb(1, 3) }.to change{subject.cycle}.by(2)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
context "if test fails" do
|
249
|
+
it "take 3 cycles, plus the cost of a and b" do
|
250
|
+
expect { subject.ifb(1, 2) }.to change{subject.cycle}.by(3)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe DCPU16::Memory do
|
4
|
+
its(:length) { should == 0x10000 }
|
5
|
+
|
6
|
+
describe "#read" do
|
7
|
+
specify { subject.read(0).should be_a_kind_of(DCPU16::Word) }
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
specify "#write" do
|
12
|
+
subject.write(0x1000, 42)
|
13
|
+
subject.read(0x1000).value.should == 42
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe DCPU16::Instructions do
|
4
|
+
let(:cpu) { DCPU16::CPU.new }
|
5
|
+
|
6
|
+
context "when value is between 0x00 and 0x07" do
|
7
|
+
specify { DCPU16::Operand.new(cpu, 0x0).should == cpu.A }
|
8
|
+
specify { DCPU16::Operand.new(cpu, 0x1).should == cpu.B }
|
9
|
+
specify { DCPU16::Operand.new(cpu, 0x2).should == cpu.C }
|
10
|
+
specify { DCPU16::Operand.new(cpu, 0x3).should == cpu.X }
|
11
|
+
specify { DCPU16::Operand.new(cpu, 0x4).should == cpu.Y }
|
12
|
+
specify { DCPU16::Operand.new(cpu, 0x5).should == cpu.Z }
|
13
|
+
specify { DCPU16::Operand.new(cpu, 0x6).should == cpu.I }
|
14
|
+
specify { DCPU16::Operand.new(cpu, 0x7).should == cpu.J }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when value is between 0x08 and 0x17" do
|
18
|
+
before(:all) do
|
19
|
+
cpu.memory.write(0x1000, 0x2a)
|
20
|
+
cpu.registers.each { |r| r.write(0x1000) }
|
21
|
+
end
|
22
|
+
|
23
|
+
specify { DCPU16::Operand.new(cpu, 0x8).value.should == 0x2a }
|
24
|
+
specify { DCPU16::Operand.new(cpu, 0xF).value.should == 0x2a }
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
context "when value is between 0x10 and 0x17" do
|
29
|
+
pending
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when value is 0x18" do
|
33
|
+
pending
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when value is 0x19" do
|
37
|
+
pending
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when value is 0x1A" do
|
41
|
+
pending
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when value is 0x1B" do
|
45
|
+
pending
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when value is 0x1C" do
|
49
|
+
pending
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when value is 0x1D" do
|
53
|
+
pending
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when value is 0x1E" do
|
57
|
+
pending
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when value is 0x1F" do
|
61
|
+
pending
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when value is between 0x20 and 0x3f" do
|
65
|
+
specify { DCPU16::Operand.new(cpu, 0x20).should be_a_kind_of(DCPU16::Literal) }
|
66
|
+
specify { DCPU16::Operand.new(cpu, 0x20).value.should == 0x0 }
|
67
|
+
specify { DCPU16::Operand.new(cpu, 0x3f).value.should == 0x1f }
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when value is > 0x3f" do
|
71
|
+
specify do
|
72
|
+
expect {
|
73
|
+
DCPU16::Operand.new(cpu, 0x40)
|
74
|
+
}.to raise_error(DCPU16::Operand::NotFound)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe DCPU16::Word do
|
4
|
+
let(:memory) { DCPU16::Memory.new }
|
5
|
+
subject { DCPU16::Word.new(2, memory, 0) }
|
6
|
+
|
7
|
+
specify { subject.should be_a_kind_of(DCPU16::Word) }
|
8
|
+
its(:value) { should == 2 }
|
9
|
+
its(:read) { should == 2 }
|
10
|
+
|
11
|
+
describe "#write" do
|
12
|
+
before { subject.write(42) }
|
13
|
+
its(:value) { should == 42 }
|
14
|
+
specify { memory.read(0).value.should == 42 }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Rdcpu16
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Patrick Helm
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &74148950 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.6'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *74148950
|
25
|
+
description: This is a simple Ruby port of the fictive 16-bit-cpu DCPU16.
|
26
|
+
email:
|
27
|
+
- deradon87@gmail.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- lib/dcpu16/cpu.rb
|
33
|
+
- lib/dcpu16/operand.rb
|
34
|
+
- lib/dcpu16/memory.rb
|
35
|
+
- lib/dcpu16/word.rb
|
36
|
+
- lib/dcpu16/version.rb
|
37
|
+
- lib/dcpu16/cpu/instructions.rb
|
38
|
+
- lib/dcpu16/support/debug.rb
|
39
|
+
- lib/dcpu16/literal.rb
|
40
|
+
- lib/dcpu16/instruction.rb
|
41
|
+
- lib/dcpu16/register.rb
|
42
|
+
- lib/dcpu16.rb
|
43
|
+
- MIT-LICENSE
|
44
|
+
- Rakefile
|
45
|
+
- README.rdoc
|
46
|
+
- spec/integration/example1_spec.rb
|
47
|
+
- spec/unit/dcpu16_word_spec.rb
|
48
|
+
- spec/unit/support/sample_observer.rb
|
49
|
+
- spec/unit/dcpu16_register_spec.rb
|
50
|
+
- spec/unit/dcpu16_cpu_spec.rb
|
51
|
+
- spec/unit/dcpu16_memory_spec.rb
|
52
|
+
- spec/unit/dcpu16_instructions_spec.rb
|
53
|
+
- spec/unit/dcpu16_operand_spec.rb
|
54
|
+
- spec/unit/dcpu16_instruction_spec.rb
|
55
|
+
- spec/spec_helper.rb
|
56
|
+
homepage: https://github.com/Deradon/Rdcpu16
|
57
|
+
licenses: []
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 1.8.10
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: Ruby port of DCPU16
|
80
|
+
test_files:
|
81
|
+
- spec/integration/example1_spec.rb
|
82
|
+
- spec/unit/dcpu16_word_spec.rb
|
83
|
+
- spec/unit/support/sample_observer.rb
|
84
|
+
- spec/unit/dcpu16_register_spec.rb
|
85
|
+
- spec/unit/dcpu16_cpu_spec.rb
|
86
|
+
- spec/unit/dcpu16_memory_spec.rb
|
87
|
+
- spec/unit/dcpu16_instructions_spec.rb
|
88
|
+
- spec/unit/dcpu16_operand_spec.rb
|
89
|
+
- spec/unit/dcpu16_instruction_spec.rb
|
90
|
+
- spec/spec_helper.rb
|