scasm 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in scasm.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Rich Lane
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ SCASM
2
+ =====
3
+
4
+ Introduction
5
+ ------------
6
+
7
+ SCASM is an assembler for the DCPU-16 architecture used in the game 0x10c.
8
+ See the game's [official website](http://0x10c.com/) for details on the
9
+ instruction set. This assembler is different and powerful because the
10
+ code you write is actually Ruby, meaning you can use all the capabilities
11
+ of a high-level programming language to help generate the final machine code.
12
+
13
+ Installation
14
+ ------------
15
+
16
+ gem install scasm
17
+
18
+ Example
19
+ -------
20
+
21
+ foo = A
22
+ bar = B
23
+ offset = 42
24
+ add [foo, offset], bar
25
+
26
+ See the examples directory for more sample code.
27
+
28
+ Syntax
29
+ ------
30
+
31
+ SCASM input is Ruby code, but you won't need a deep understanding of Ruby to
32
+ get started. Simple statements like `add A, 1` work just like you expect. This
33
+ section will cover the SCASM-specific syntax.
34
+
35
+ ### Registers
36
+
37
+ Ruby variables named `A`, `B`, `C`, `X`, `Y`, `Z`, `I`, and `J` are provided to refer to the
38
+ processor registers.
39
+
40
+ ### Memory
41
+
42
+ Memory references are of the form `[register, offset]`. Either `register` or
43
+ `offset` can be omitted.
44
+
45
+ Examples:
46
+
47
+ * `[A]`
48
+ * `[0x100]`
49
+ * `[A, 2]`
50
+
51
+ ### Literals
52
+
53
+ Literal values are just given as integers. Example: `42` or `0x200`.
54
+
55
+ ### Miscellaneous
56
+
57
+ These values have the same meaning as in the spec:
58
+
59
+ * `pop`
60
+ * `peek`
61
+ * `push`
62
+ * `sp`
63
+ * `pc`
64
+ * `o`
65
+
66
+ Contributing
67
+ ------------
68
+
69
+ Fork the project on GitHub and send me a pull request.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/bin/scasm ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+ require 'trollop'
3
+ require 'scasm/assembler'
4
+
5
+ opts = Trollop.options do
6
+ banner <<-EOS
7
+ scasm - the Ship Computer Assembler
8
+
9
+ SCASM is an assembler for the DCPU-16 computer used in the game 0x10c.
10
+ CPU specs: http://0x10c.com/doc/dcpu-16.txt
11
+
12
+ Usage:
13
+ scasm [options] [file]
14
+
15
+ where [options] are:
16
+ EOS
17
+
18
+ opt :output, "Output filename", :short => 'o', :type => :string
19
+ opt :help, "Show this message", :short => 'h'
20
+
21
+ text <<-EOS
22
+
23
+ If no input file is given input is read from stdin. If no output file is given
24
+ the output will be written to filename.bin or stdout.
25
+ EOS
26
+ end
27
+
28
+ if ARGV[0]
29
+ input_io = File.open(ARGV[0])
30
+ else
31
+ input_io = $stdin
32
+ end
33
+
34
+ if opts[:output]
35
+ output_io = File.open(opts[:output], 'w')
36
+ elsif input_io != $stdin
37
+ filename = File.join(File.dirname(input_io.path), File.basename(input_io.path, '.scasm') + '.bin')
38
+ output_io = File.open(filename, 'w')
39
+ else
40
+ output_io = $stdout
41
+ end
42
+
43
+ as = SCASM::Assembler.new
44
+ as.eval input_io.read
45
+ output_io.write as.assemble
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env ruby
2
+ require 'trollop'
3
+ require 'scasm/isa'
4
+ require 'scasm/statement'
5
+ require 'scasm/value'
6
+
7
+ include SCASM
8
+
9
+ opts = Trollop.options do
10
+ banner <<-EOS
11
+ scasm-disassembler - Disassemble DCPU-16 binaries.
12
+
13
+ Usage:
14
+ scasm-disassembler [options] [file]
15
+
16
+ where [options] are:
17
+ EOS
18
+ end
19
+
20
+ mem = ARGF.read.unpack("v*")
21
+ addr = 0
22
+ basic_opcode_map = SCASM::BASIC_OPCODES.invert
23
+ extended_opcode_map = SCASM::EXTENDED_OPCODES.invert
24
+ register_map = SCASM::REGISTERS.invert
25
+
26
+ next_word = lambda do
27
+ word = mem[addr]
28
+ addr += 1
29
+ word
30
+ end
31
+
32
+ decode_value = lambda do |value|
33
+ if value <= 0x07
34
+ Register.new register_map[value]
35
+ elsif value <= 0x0f
36
+ RegisterMemory.new register_map[value-0x08]
37
+ elsif value <= 0x17
38
+ OffsetRegisterMemory.new register_map[value-0x10], next_word[]
39
+ elsif value == 0x18
40
+ Pop.new
41
+ elsif value == 0x19
42
+ Peek.new
43
+ elsif value == 0x1a
44
+ Push.new
45
+ elsif value == 0x1b
46
+ SP.new
47
+ elsif value == 0x1c
48
+ PC.new
49
+ elsif value == 0x1d
50
+ O.new
51
+ elsif value == 0x1e
52
+ ImmediateMemory.new next_word[]
53
+ elsif value == 0x1f
54
+ Immediate.new next_word[]
55
+ elsif value < 0x3f
56
+ Immediate.new(value-0x20)
57
+ end
58
+ end
59
+
60
+ # Create statements for each instruction
61
+ stmts = []
62
+ jumps = Hash.new { |h,k| h[k] = [] }
63
+ while addr < mem.size
64
+ start_addr = addr
65
+ word = next_word[]
66
+ opcode = word & 0xf
67
+ code_a = (word >> 4) & 0x3f
68
+ code_b = (word >> 10) & 0x3f
69
+
70
+ if opcode != 0 then
71
+ opsym = basic_opcode_map[opcode] or fail "unknown opcode #{opcode} at #{start_addr}"
72
+ a = decode_value[code_a]
73
+ b = decode_value[code_b]
74
+ else
75
+ opsym = extended_opcode_map[code_a] or fail "unknown extended opcode #{code_a} at #{start_addr}"
76
+ a = decode_value[code_b]
77
+ b = nil
78
+ end
79
+
80
+ if opsym == :set and a.is_a? PC and b.is_a? Immediate
81
+ imm = b.value
82
+ b = ImmediateLabel.new "L#{b.value}"
83
+ b.resolve imm
84
+ jumps[imm] << b
85
+ elsif opsym == :jsr and a.is_a? Immediate
86
+ imm = a.value
87
+ a = ImmediateLabel.new "L#{a.value}"
88
+ a.resolve imm
89
+ jumps[imm] << a
90
+ end
91
+
92
+ inst = Instruction.new(opsym, a, b)
93
+ inst.addr = start_addr
94
+ stmts << inst
95
+ end
96
+
97
+ # Create labels and fixup jumpers
98
+ labelled_stmts = []
99
+ stmts.each do |stmt|
100
+ if jumps.member? stmt.addr
101
+ jumpers = jumps[stmt.addr]
102
+ lbl = Label.new("L#{stmt.addr}")
103
+ lbl.addr = stmt.addr
104
+ labelled_stmts << lbl
105
+ end
106
+ labelled_stmts << stmt
107
+ end
108
+
109
+ # Output each statement
110
+ labelled_stmts.each do |stmt|
111
+ printf "%-40s # pc=%d\n" % [stmt, stmt.addr]
112
+ end
@@ -0,0 +1,29 @@
1
+ # Translation of the example code from the DPU-16 spec.
2
+
3
+ # Try some basic stuff
4
+ set A, 48
5
+ set [4096], 32
6
+ sub A, [4096]
7
+ ifn A, 16
8
+ set pc, "crash"
9
+
10
+ # Do a loopy thing
11
+ set I, 10
12
+ set A, 8192
13
+ label "loop"
14
+ set [I, 8192], [A]
15
+ sub I, 1
16
+ ifn I, 0
17
+ set pc, "loop"
18
+
19
+ # Call a subroutine
20
+ set X, 4
21
+ jsr "testsub"
22
+ set pc, "crash"
23
+ label "testsub"
24
+ shl X, 4
25
+ set pc, pop
26
+
27
+ # Hang forever. X should now be 0x40 if everything went right.
28
+ label "crash"
29
+ set pc, "crash"
@@ -0,0 +1,152 @@
1
+ require 'stringio'
2
+ require 'scasm/isa'
3
+ require 'scasm/statement'
4
+ require 'scasm/value'
5
+
6
+ module SCASM
7
+
8
+ class Assembler < BasicObject
9
+ def initialize
10
+ @stmts = []
11
+ @relocations = []
12
+ end
13
+
14
+ def eval code
15
+ instance_eval code
16
+ end
17
+
18
+ def assemble
19
+ resolve_labels
20
+ io = ::StringIO.new
21
+ @stmts.each { |stmt| stmt.assemble io }
22
+ io.string
23
+ end
24
+
25
+ def inst opsym, a, b
26
+ a = parse_value a
27
+ b = parse_value b
28
+ @stmts << Instruction.new(opsym, a, b)
29
+ end
30
+
31
+ def label name
32
+ ::Kernel.raise "label names must be strings" unless name.is_a? ::String
33
+ @stmts << Label.new(name)
34
+ end
35
+
36
+ def reg regsym
37
+ Register.new regsym
38
+ end
39
+
40
+ def regmem regsym
41
+ RegisterMemory.new regsym
42
+ end
43
+
44
+ def iregmem regsym, imm
45
+ OffsetRegisterMemory.new regsym, imm
46
+ end
47
+
48
+ def pop
49
+ Pop.new
50
+ end
51
+
52
+ def peek
53
+ Peek.new
54
+ end
55
+
56
+ def push
57
+ Push.new
58
+ end
59
+
60
+ def sp
61
+ SP.new
62
+ end
63
+
64
+ def pc
65
+ PC.new
66
+ end
67
+
68
+ def o
69
+ O.new
70
+ end
71
+
72
+ def imem imm
73
+ ImmediateMemory.new imm
74
+ end
75
+
76
+ def imm imm
77
+ Immediate.new imm
78
+ end
79
+
80
+ def l name
81
+ ::Kernel.raise "label names must be strings" unless name.is_a? ::String
82
+ ImmediateLabel.new(name).tap { |x| @relocations << x }
83
+ end
84
+
85
+ # Add a method for each instruction
86
+ BASIC_OPCODES.each do |opsym,opcode|
87
+ define_method(opsym) { |a,b| inst opsym, a, b }
88
+ end
89
+
90
+ EXTENDED_OPCODES.each do |opsym,opcode|
91
+ define_method(opsym) { |a| inst opsym, a, nil }
92
+ end
93
+
94
+ # Add a constant for each register
95
+ REGISTERS.each do |regsym,regnum|
96
+ const_set regsym, regsym
97
+ end
98
+
99
+ private
100
+
101
+ def resolve_labels
102
+ label_addrs = {}
103
+
104
+ addr = 0
105
+ @stmts.each do |stmt|
106
+ if stmt.is_a? Label
107
+ label_addrs[stmt.name] = addr
108
+ end
109
+ addr += stmt.length
110
+ end
111
+
112
+ @relocations.each do |x|
113
+ addr = label_addrs[x.name] or ::Kernel.raise "undefined label #{x.name.inspect}"
114
+ x.resolve addr
115
+ end
116
+ end
117
+
118
+ # Shorter notation for values
119
+ def parse_value x
120
+ case x
121
+ when Value, ::NilClass
122
+ x
123
+ when ::Array
124
+ x1, x2, = x
125
+ if x1.is_a? ::Symbol and x2 == nil
126
+ # [reg]
127
+ regmem x1
128
+ elsif x1.is_a? ::Symbol and x2.is_a? ::Integer
129
+ # [reg, imm]
130
+ iregmem x1, x2
131
+ elsif x1.is_a? ::Integer
132
+ # [imm]
133
+ imem x1
134
+ else
135
+ ::Kernel.fail "invalid memory access syntax"
136
+ end
137
+ when ::Symbol
138
+ # register
139
+ reg x
140
+ when ::String
141
+ # label
142
+ l x
143
+ when ::Integer
144
+ # immediate
145
+ imm x
146
+ else
147
+ ::Kernel.raise "unexpected value class #{x.class}"
148
+ end
149
+ end
150
+ end
151
+
152
+ end
data/lib/scasm/isa.rb ADDED
@@ -0,0 +1,37 @@
1
+ module SCASM
2
+
3
+ BASIC_OPCODES = {
4
+ :ext => 0x0,
5
+ :set => 0x1,
6
+ :add => 0x2,
7
+ :sub => 0x3,
8
+ :mul => 0x4,
9
+ :div => 0x5,
10
+ :mod => 0x6,
11
+ :shl => 0x7,
12
+ :shr => 0x8,
13
+ :and_ => 0x9, # "and" is a reserved word
14
+ :bor => 0xa,
15
+ :xor => 0xb,
16
+ :ife => 0xc,
17
+ :ifn => 0xd,
18
+ :ifg => 0xe,
19
+ :ifb => 0xf,
20
+ }
21
+
22
+ EXTENDED_OPCODES = {
23
+ :jsr => 0x01,
24
+ }
25
+
26
+ REGISTERS = {
27
+ :A => 0,
28
+ :B => 1,
29
+ :C => 2,
30
+ :X => 3,
31
+ :Y => 4,
32
+ :Z => 5,
33
+ :I => 6,
34
+ :J => 7,
35
+ }
36
+
37
+ end
@@ -0,0 +1,74 @@
1
+ require 'stringio'
2
+
3
+ module SCASM
4
+
5
+ class Statement
6
+ attr_accessor :addr
7
+
8
+ def assemble io
9
+ fail 'unimplemented'
10
+ end
11
+
12
+ def to_s
13
+ fail 'unimplemented'
14
+ end
15
+
16
+ # XXX HACK
17
+ def length
18
+ io = StringIO.new
19
+ assemble io
20
+ io.length/2
21
+ end
22
+ end
23
+
24
+ class Instruction < Statement
25
+ attr_reader :opsym, :a, :b
26
+ attr_writer :b # for disassembler
27
+
28
+ def initialize opsym, a, b
29
+ @opsym = opsym
30
+ @a = a
31
+ @b = b
32
+ end
33
+
34
+ def assemble io
35
+ if opcode = BASIC_OPCODES[@opsym]
36
+ code_a, imm_a = @a.assemble
37
+ code_b, imm_b = @b.assemble
38
+ code = opcode | (code_a<<4) | (code_b<<10)
39
+ io.write [code, imm_a, imm_b].compact.pack('v*')
40
+ elsif opcode = EXTENDED_OPCODES[@opsym]
41
+ code_a, imm_a = @a.assemble
42
+ fail unless @b == nil
43
+ code = (opcode<<4) | (code_a<<10)
44
+ io.write [code, imm_a].compact.pack('v*')
45
+ else
46
+ fail "unknown opsym #{@opsym.inspect}"
47
+ end
48
+ end
49
+
50
+ def to_s
51
+ "%s %s, %s" % [@opsym, @a, @b]
52
+ end
53
+ end
54
+
55
+ class Data < Statement
56
+ end
57
+
58
+ class Label < Statement
59
+ attr_reader :name
60
+
61
+ def initialize name
62
+ @name = name
63
+ end
64
+
65
+ def assemble io
66
+ # nop
67
+ end
68
+
69
+ def to_s
70
+ "label #{@name.inspect}"
71
+ end
72
+ end
73
+
74
+ end
@@ -0,0 +1,178 @@
1
+ module SCASM
2
+
3
+ class Value
4
+ def assemble
5
+ fail "not implemented"
6
+ end
7
+
8
+ def to_s
9
+ fail "not implemented"
10
+ end
11
+ end
12
+
13
+ class Register < Value
14
+ def initialize regsym
15
+ fail "invalid register #{regsym.inspect}" unless REGISTERS.member? regsym
16
+ @regsym = regsym
17
+ end
18
+
19
+ def assemble
20
+ return REGISTERS[@regsym]
21
+ end
22
+
23
+ def to_s
24
+ "reg(#@regsym)"
25
+ end
26
+ end
27
+
28
+ class RegisterMemory < Value
29
+ def initialize regsym
30
+ fail "invalid register #{regsym.inspect}" unless REGISTERS.member? regsym
31
+ @regsym = regsym
32
+ end
33
+
34
+ def assemble
35
+ return 0x08 + REGISTERS[@regsym]
36
+ end
37
+
38
+ def to_s
39
+ "regmem(#@regsym)"
40
+ end
41
+ end
42
+
43
+ class OffsetRegisterMemory < Value
44
+ def initialize regsym, imm
45
+ fail "invalid register #{regsym.inspect}" unless REGISTERS.member? regsym
46
+ @regsym = regsym
47
+ @imm = imm
48
+ end
49
+
50
+ def assemble
51
+ return (0x10 + REGISTERS[@regsym]), @imm
52
+ end
53
+
54
+ def to_s
55
+ "iregmem(#@regsym, #@imm)"
56
+ end
57
+ end
58
+
59
+ class Pop < Value
60
+ def assemble
61
+ return 0x18
62
+ end
63
+
64
+ def to_s
65
+ 'pop'
66
+ end
67
+ end
68
+
69
+ class Peek < Value
70
+ def assemble
71
+ return 0x19
72
+ end
73
+
74
+ def to_s
75
+ 'peek'
76
+ end
77
+ end
78
+
79
+ class Push < Value
80
+ def assemble
81
+ return 0x1a
82
+ end
83
+
84
+ def to_s
85
+ 'push'
86
+ end
87
+ end
88
+
89
+ class SP < Value
90
+ def assemble
91
+ return 0x1b
92
+ end
93
+
94
+ def to_s
95
+ 'sp'
96
+ end
97
+ end
98
+
99
+ class PC < Value
100
+ def assemble
101
+ return 0x1c
102
+ end
103
+
104
+ def to_s
105
+ 'pc'
106
+ end
107
+ end
108
+
109
+ class O < Value
110
+ def assemble
111
+ return 0x1d
112
+ end
113
+
114
+ def to_s
115
+ 'o'
116
+ end
117
+ end
118
+
119
+ class ImmediateMemory < Value
120
+ def initialize imm
121
+ @imm = imm
122
+ end
123
+
124
+ def assemble
125
+ return 0x1e, @imm
126
+ end
127
+
128
+ def to_s
129
+ "imem(#@imm)"
130
+ end
131
+ end
132
+
133
+ class Immediate < Value
134
+ def initialize imm
135
+ @imm = imm
136
+ end
137
+
138
+ def assemble
139
+ if @imm <= 0x1f
140
+ return 0x20 + @imm
141
+ else
142
+ return 0x1f, @imm
143
+ end
144
+ end
145
+
146
+ def to_s
147
+ "imm(#@imm)"
148
+ end
149
+
150
+ def value
151
+ @imm
152
+ end
153
+ end
154
+
155
+ class ImmediateLabel < Value
156
+ attr_reader :name
157
+
158
+ def initialize name
159
+ @name = name
160
+ @imm = nil
161
+ end
162
+
163
+ def resolve imm
164
+ fail if @imm
165
+ @imm = imm
166
+ end
167
+
168
+ def assemble
169
+ #fail unless @imm
170
+ return 0x1f, (@imm||0) # HACK
171
+ end
172
+
173
+ def to_s
174
+ "l(#{@name.inspect})"
175
+ end
176
+ end
177
+
178
+ end
@@ -0,0 +1,3 @@
1
+ module Scasm
2
+ VERSION = "0.0.1"
3
+ end
data/scasm.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/scasm/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Rich Lane"]
6
+ gem.email = ["rlane@club.cc.cmu.edu"]
7
+ gem.description = %q{}
8
+ gem.summary = %q{A Ruby DSL for DCPU-16 assembly code}
9
+ gem.homepage = "https://github.com/rlane/scasm"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "scasm"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Scasm::VERSION
17
+
18
+ gem.add_dependency 'trollop'
19
+ end
data/test/foo.scasm ADDED
@@ -0,0 +1,14 @@
1
+ set reg(A), reg(B)
2
+ add reg(A), regmem(C)
3
+ sub reg(A), iregmem(X, 1)
4
+ div reg(A), pop
5
+ mod reg(A), peek
6
+ shl reg(A), push
7
+ shr reg(A), sp
8
+ and_ reg(A), pc
9
+ bor reg(A), o
10
+ xor reg(A), imem(5)
11
+ ife reg(A), imm(1)
12
+ ifn reg(A), imm(32)
13
+ ifg reg(I), reg(Y)
14
+ ifb reg(J), reg(Z)
@@ -0,0 +1,133 @@
1
+ require 'test/unit'
2
+ require 'scasm/assembler'
3
+
4
+ class AssemblerTest < Test::Unit::TestCase
5
+ def setup
6
+ @expected = nil
7
+ end
8
+
9
+ def teardown
10
+ end
11
+
12
+ def expect words
13
+ @expected = words
14
+ end
15
+
16
+ def check code
17
+ as = SCASM::Assembler.new
18
+ as.eval code
19
+ result = as.assemble
20
+ result_words = result.unpack('v*')
21
+ assert_equal @expected, result_words
22
+ end
23
+
24
+ def test_empty
25
+ expect []
26
+ check ''
27
+ end
28
+
29
+ def test_reg
30
+ expect [
31
+ 0x0401,
32
+ 0x0c21,
33
+ 0x1441,
34
+ 0x1c61,
35
+ ]
36
+
37
+ check <<-EOS
38
+ set reg(A), reg(B)
39
+ set reg(C), reg(X)
40
+ set reg(Y), reg(Z)
41
+ set reg(I), reg(J)
42
+ EOS
43
+
44
+ check <<-EOS
45
+ set A, B
46
+ set C, X
47
+ set Y, Z
48
+ set I, J
49
+ EOS
50
+ end
51
+
52
+ def test_regmem
53
+ expect [0x0cb1]
54
+ check "set regmem(X), reg(X)"
55
+ check "set [X], X"
56
+ end
57
+
58
+ def test_iregmem
59
+ expect [0x0d31, 0x002a]
60
+ check 'set iregmem(X, 42), reg(X)'
61
+ check 'set [X,42], X'
62
+ end
63
+
64
+ def test_misc
65
+ expect [0x6181]
66
+ check 'set pop, pop'
67
+
68
+ expect [0x6591]
69
+ check 'set peek, peek'
70
+
71
+ expect [0x69a1]
72
+ check 'set push, push'
73
+
74
+ expect [0x6db1]
75
+ check 'set sp, sp'
76
+
77
+ expect [0x71c1]
78
+ check 'set pc, pc'
79
+
80
+ expect [0x75d1]
81
+ check 'set o, o'
82
+ end
83
+
84
+ def test_imem
85
+ expect [0x7801, 0x1000]
86
+ check 'set reg(A), imem(0x1000)'
87
+ check 'set A, [0x1000]'
88
+ end
89
+
90
+ def test_imm
91
+ expect [0xfc01]
92
+ check "set reg(A), imm(31)"
93
+ check "set A, 31"
94
+
95
+ expect [0x7c01, 0x0020]
96
+ check "set reg(A), imm(32)"
97
+ check "set A, 32"
98
+
99
+ expect [0x7df1, 0xffff, 0x0020]
100
+ check "set imm(65535), imm(32)"
101
+ check "set 65535, 32"
102
+ end
103
+
104
+ def test_label
105
+ expect [
106
+ 0xb401,
107
+ 0x8402,
108
+ 0x7dc1, 0x0001,
109
+ ]
110
+
111
+ check <<-EOS
112
+ set reg(A), imm(13)
113
+ label 'loop'
114
+ add reg(A), imm(1)
115
+ set pc, l('loop')
116
+ EOS
117
+
118
+ check <<-EOS
119
+ set A, 13
120
+ label 'loop'
121
+ add A, 1
122
+ set pc, 'loop'
123
+ EOS
124
+ end
125
+
126
+ def test_ext_insts
127
+ expect [0x0010]
128
+ check 'jsr A'
129
+
130
+ expect [0x7c10, 0x0020]
131
+ check 'jsr 32'
132
+ end
133
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: scasm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Rich Lane
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: trollop
16
+ requirement: &15992680 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *15992680
25
+ description: ''
26
+ email:
27
+ - rlane@club.cc.cmu.edu
28
+ executables:
29
+ - scasm
30
+ - scasm-disassemble
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - .gitignore
35
+ - Gemfile
36
+ - LICENSE
37
+ - README.md
38
+ - Rakefile
39
+ - bin/scasm
40
+ - bin/scasm-disassemble
41
+ - examples/spec.scasm
42
+ - lib/scasm/assembler.rb
43
+ - lib/scasm/isa.rb
44
+ - lib/scasm/statement.rb
45
+ - lib/scasm/value.rb
46
+ - lib/scasm/version.rb
47
+ - scasm.gemspec
48
+ - test/foo.scasm
49
+ - test/test_assembler.rb
50
+ homepage: https://github.com/rlane/scasm
51
+ licenses: []
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 1.8.17
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: A Ruby DSL for DCPU-16 assembly code
74
+ test_files:
75
+ - test/foo.scasm
76
+ - test/test_assembler.rb