gasm 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd06be7e5047c313deeb459a869c00cbf56ff8efd4d3d4190cd825ba09353eb3
4
- data.tar.gz: da6ddd558a76a47819abe388c3cd57564c89530ec762f6493c793d6a81225a2b
3
+ metadata.gz: ccae527d5bcdb0a59180066a9afc933419b48651c30db1d91f7e76f0ba94a2c0
4
+ data.tar.gz: 19b1662105f3125c1d53f98039191eb68664ad035033c354659c8283d5e5f8eb
5
5
  SHA512:
6
- metadata.gz: 68e594afb0d28eb6b22bf9e8fb126881157f2e447edbeac877cf86e0320665534b451ce96bb239cfa976389acebe669d0d05b1c3c440cb3c348e246749e9b26d
7
- data.tar.gz: 57f58715abe134ed443389ab2d432b454f4239b6dcf6ebd3703f80fed67da13533d9ad2fcad05930d8055a11be814b1d241c6ffa0e6659eb3b1f129954f44dd3
6
+ metadata.gz: c58736d7157d72eef6ae7566d41cc001f0be3bf177063647119f17c98133ef839ef3720ae38143d9629bf08e4bb1a724593958d3da22253cf6af390361c3665a
7
+ data.tar.gz: a649646e47bd77f3dce4ceafc0659825055ca0911ae4eca5bfacb658bdf2057a170615fb736f4b61709999933b0eac25ac07054c8eaf28c40f26bc3ed896adbf
@@ -10,7 +10,7 @@ asm do
10
10
  opcodes.each_with_index do |opcode, oi|
11
11
  addrmodes.each_with_index do |(pattern, zeropage, operands), ai|
12
12
  next if pattern.nil?
13
- next if pattern == '___'
13
+ next if opcode.start_with? '__'
14
14
 
15
15
  a = oi.to_s(2).rjust(3, '0')
16
16
  b = ai.to_s(2).rjust(3, '0')
@@ -3,7 +3,7 @@ asm do
3
3
  # Generate matchers for hex values for register
4
4
  def vp(pattern, bits)
5
5
  if pattern.include?('V<x>')
6
- hex_letters = %w[a b c d e f A B C D E F]
6
+ hex_letters = %w[0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F]
7
7
  hex_letters.each do |register_x|
8
8
  pattern_a = pattern.gsub('V<x>', "V#{register_x}")
9
9
  bits_a = bits.gsub('xxxx', "#{register_x.to_i(16).to_s(2)}")
data/exe/gasm CHANGED
@@ -4,6 +4,13 @@ require 'gasm'
4
4
 
5
5
  include Gasm
6
6
 
7
+ disasm = false
8
+
9
+ if ARGV[0] == '-d'
10
+ disasm = true
11
+ ARGV.shift
12
+ end
13
+
7
14
  asm_desc = ARGV[0]
8
15
  asm_file = ARGV[1]
9
16
 
@@ -61,17 +68,28 @@ rescue => e
61
68
  exit(1)
62
69
  end
63
70
 
71
+ reader = Asm
72
+
73
+ # disassembly mode
74
+ if disasm
75
+ STDERR.puts 'Disassembling...'
76
+ reader = Disasm
77
+ else
78
+ STDERR.puts 'Assembling...'
79
+ end
64
80
 
65
81
  asm = if asm_file == '-'
66
- Asm.new(STDIN.read, matcher)
82
+ reader.new(STDIN.read, matcher)
67
83
 
68
84
  else
69
85
  if !File.exist?(asm_file)
70
- STDERR.puts "'#{asm_file}' asm does not exist"
86
+ STDERR.puts "File '#{asm_file}' does not exist"
71
87
  exit(1)
72
88
  end
73
-
74
- Asm.new(File.read(asm_file), matcher)
89
+
90
+ file = File.open(asm_file, "rb")
91
+ contents = file.read
92
+ reader.new(contents, matcher)
75
93
  end
76
94
 
77
- puts asm.compiled
95
+ puts asm.output
data/lib/gasm/asm.rb CHANGED
@@ -5,7 +5,7 @@ module Gasm
5
5
  @contents = contents
6
6
  end
7
7
 
8
- def compiled
8
+ def output
9
9
  lines = @contents.split("\n")
10
10
  offset = 0
11
11
 
@@ -0,0 +1,24 @@
1
+ module Gasm
2
+ class Disasm
3
+ def initialize(contents, gasm)
4
+ @gasm = gasm
5
+ @contents = contents
6
+ end
7
+
8
+ def output
9
+ result = []
10
+
11
+ index = 0
12
+ loop do
13
+ res = @gasm.disparse(@contents, index)
14
+ index += res[:amountread]
15
+ result << res[:instruction]
16
+ break if index >= @contents.length
17
+ rescue => e
18
+ result << "// -incomplete- disassembling stopped: #{e.message} at index 0x#{index.to_s(16)} '0x#{@contents[index].unpack('C')[0].to_s(16)}'"
19
+ break
20
+ end
21
+ result.join("\n")
22
+ end
23
+ end
24
+ end
@@ -11,8 +11,55 @@ module Gasm
11
11
  def strip_comment(line)
12
12
  line.split('//')[0]
13
13
  end
14
+
15
+ def disparse(contents, index)
16
+ match = nil
17
+
18
+ @desc['asm']['instructions'].each do |k, info|
19
+ bitpattern = info[:bits].tr(' ', '')
20
+
21
+ vars = {}
22
+ match = [k, info, vars, bitpattern.length >> 3]
23
+ bitpattern.split('').each_with_index do |chr, i|
24
+ byte_index = (i >> 3) + index
25
+ bit_index = i % 8
26
+
27
+ if byte_index >= contents.length
28
+ match = nil
29
+ next
30
+ end
31
+
32
+ contentbits = contents[byte_index].unpack("C")[0].to_s(2).rjust(8, '0')
33
+
34
+ c = contentbits[bit_index]
35
+ if chr == '0' || chr == '1'
36
+ if c != chr
37
+ match = nil
38
+ break
39
+ end
40
+ else
41
+ vars[chr] ||= ''
42
+ vars[chr] += c
43
+ end
44
+ end
45
+
46
+ break if match
47
+ end
48
+
49
+ raise 'unknown pattern' if match.nil?
50
+
51
+ result = match[0]
52
+ match[2].each do |var, val|
53
+ result.gsub!("<#{var}>", "$#{val.to_i(2).to_s(16)}")
54
+ end
55
+
56
+ {
57
+ amountread: match[3],
58
+ instruction: result
59
+ }
60
+ end
14
61
 
15
- NUMCHARS = %[0 1 2 3 4 5 6 7 8 9 a b c d e f o x b $ %]
62
+ NUMCHARS = %[0 1 2 3 4 5 6 7 8 9 a b c d e f o x $ %]
16
63
  def parse(line)
17
64
  line = strip_comment(line)
18
65
  line = strip_spaces(line)
@@ -21,6 +68,7 @@ module Gasm
21
68
  result = ''
22
69
  values = {}
23
70
  idx = 0
71
+ pattern = ''
24
72
 
25
73
  @desc['asm']['instructions'].each do |k, info|
26
74
  result = info[:bits]
@@ -105,6 +153,8 @@ module Gasm
105
153
  unless info[:condition].call(values.map{|k,v| [k.to_sym, v.to_i(2)]}.to_h)
106
154
  result = nil
107
155
  end
156
+
157
+ pattern = info[:bits]
108
158
 
109
159
  break unless result.nil?
110
160
  end
@@ -121,7 +171,7 @@ module Gasm
121
171
  lastvar = ' '
122
172
  output = ''
123
173
 
124
- evalues = endiannize(values)
174
+ evalues = endiannize(values, pattern)
125
175
  loop do
126
176
 
127
177
  if result[idx] == lastvar
@@ -170,20 +220,20 @@ module Gasm
170
220
  ].join("\n")
171
221
  end
172
222
 
173
- def littleendian(bitstr)
223
+ def littleendian(bitstr, len)
174
224
  # flips a bit string around to blocks of 8 little endian bytes
175
225
  # 1. reverse the string
176
226
  # 2. cut it into blocks of 8
177
227
  # 3. reverse each block of 8
178
228
  # 4. et voila
179
- bitstr.split('').reverse.each_slice(8).map{|x| x.reverse}.flatten.join('')
229
+ bitstr.rjust(len, '0').split('').reverse.each_slice(8).map{|x| x.reverse}.flatten.join('')
180
230
  end
181
231
 
182
- def endiannize(values)
232
+ def endiannize(values, pattern)
183
233
  # transforms the values array into big and small endian versions
184
234
  result = {}
185
235
  values.each do |k,v|
186
- result[k] = littleendian(v)
236
+ result[k] = littleendian(v, pattern.count(k))
187
237
  result[k.upcase] = v
188
238
  end
189
239
  result
data/lib/gasm/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Gasm
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.1'
5
5
  end
data/lib/gasm.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'gasm/gasm_loader'
2
2
  require 'gasm/ruby_desc'
3
+ require 'gasm/disasm'
3
4
  require 'gasm/asm'
4
5
  require 'gasm/gasm_matcher'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gasm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Siaw
@@ -41,6 +41,7 @@ files:
41
41
  - gasm.gemspec
42
42
  - lib/gasm.rb
43
43
  - lib/gasm/asm.rb
44
+ - lib/gasm/disasm.rb
44
45
  - lib/gasm/gasm_loader.rb
45
46
  - lib/gasm/gasm_matcher.rb
46
47
  - lib/gasm/instruction_section.rb