z80_disassembler 0.1.5 → 0.2.4

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: 05e63db7e5146f7f893ac8ac3cf7b6e6f6085382f067ff86d7c291c9685ecef0
4
- data.tar.gz: 04407ab09433c4f7d19333c9979d0186afaad6814e57b18cd1f79b8fe005235d
3
+ metadata.gz: 5fe96f8335ed977825007f7846ed1b5b515ee9bab79fad0c67976504926c827e
4
+ data.tar.gz: c9341766fb32cf922aea077fa5968755b05e05ac03b45d277b8cc9de023f5b46
5
5
  SHA512:
6
- metadata.gz: 108465c7f06352d29a0c8973fe27691e5b76324e1e9d33fda8597ba794bcf994bcedb55f47047b2d659c4dea4f28dbf43ae83c61c279d185e74e355dfc59d541
7
- data.tar.gz: d0e1ecd67efc481410f4c75b695ea143b9394438883b52c7a26b65a61f17b46caff12b58fc8a869fdc349c8ac0d22101aba3be2e041641ba69b2258c70732a16
6
+ metadata.gz: 4fabf9e9a350e8ddedbc85acb8c8f738fd471e347591107f81a169c14c5d3dbca0f779f7706294ec6a3fde06895d6d5a429b6c6c48c8f9e5e84ba2de29097539
7
+ data.tar.gz: cc8e487897234f43ddc6962d1ce979704b9295a7f99551d592db7413acb5d985ccf0d394952b26d0e08e84caafb91e31a96b1a1abe94f48a154b2cc3332e9010
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- z80_disassembler (0.1.5)
4
+ z80_disassembler (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -27,10 +27,10 @@ Or install it yourself as:
27
27
 
28
28
  - example: parse.C >> parse.C.txt and compare with parse.txt
29
29
  ```ruby
30
- Z80Disassembler::Disassembler.new(params[:file], 32768).start
30
+ z = Z80Disassembler::Disassembler.new(params[:file], 32768)
31
+ z.start # return [ [25114, "#621A", "LD IX,#6300", "DD 21 00 63", " ! c"], [...], ... ]
32
+ z.text # return " LD IX,link_1 ; #621A / 25114 ; DD 21 00 63 ; ! c ;\n"
31
33
  ```
32
- return hash { 32768=>["#8000", "PUSH IY", "fd e5"], 32770=>[...], ... }
33
-
34
34
  ## Development
35
35
 
36
36
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -6,6 +6,8 @@ module Z80Disassembler
6
6
  class Error < StandardError; end
7
7
 
8
8
  class Disassembler
9
+ attr_reader :org
10
+
9
11
  # 0 1 2 3 4 5 6 7
10
12
  T_R = [ 'B', 'C', 'D', 'E', 'H', 'L', '(HL)', 'A'].freeze
11
13
  T_CC = [ 'NZ', 'Z', 'NC', 'C', 'PO', 'PE', 'P', 'M'].freeze
@@ -14,52 +16,138 @@ module Z80Disassembler
14
16
  T_IM = [ '0', '0/1', '1', '2', '0', '0/1', '1', '2'].freeze
15
17
  T_RP = [ 'BC', 'DE', 'HL', 'SP'].freeze
16
18
  T_RP2 = [ 'BC', 'DE', 'HL', 'AF'].freeze
19
+ ASCII = [
20
+ ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/',
21
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
22
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
23
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\',']', '^', '_',
24
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
25
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~'
26
+ ].freeze
17
27
 
18
- def initialize(file_name, addr = 32_768)
19
- @file_name = file_name; @addr = addr.to_i
28
+ def initialize(file, org = 32_768)
29
+ @file = file; @org = org.to_i
30
+ if file.original_filename[-3..-1] == '.$C'
31
+ File.open(@file) do |f|
32
+ z = f.read(17)
33
+ @file_name = "#{z[0..7]}.#{z[8]}"
34
+ @org = bytes_to_int(z[ 9..10])
35
+ @file_size = bytes_to_int(z[11..12])
36
+ @sectors = bytes_to_int(z[13..14])
37
+ checksum1 = bytes_to_int(z[15..16])
38
+ checksum2 = (z[0..14].sum * 257 + 105).to_s(16)[-4..-1].hex
39
+ @code = f.read(@file_size).bytes if checksum1 == checksum2
40
+ end
41
+ end
42
+ @code ||= File.open(@file).read.bytes
43
+ @file_size ||= @file.size
20
44
  @x = 0; @y = 0; @z = 0; @p = 0; @q = 0; @xx = nil
21
- @lambda = nil; @prefix = nil; @prev = nil
22
- @bytes = []; @ascii = []; @result = {}
45
+ @lambda = nil; @prefix = nil; @prev = nil; @result = []
23
46
  end
24
47
 
25
48
  def start
26
- File.open(@file_name).each_byte do |byte|
49
+ addr = @org
50
+ bytes = []; ascii = []
51
+ @code.each do |byte|
27
52
  load_vars(byte)
28
- str = case @prefix
29
- when 'cb' then @prefix = nil; cb_prefix
30
- when 'ed' then @prefix = nil; ed_prefix
31
- when 'dd' then @xx = 'IX'; xx_prefix(byte)
32
- when 'fd' then @xx = 'IY'; xx_prefix(byte)
33
- when 'xx' then temp = @temp; @temp = nil; displacement(byte, temp)
34
- when 2 then @prefix -= 1; @temp = byte.to_s(16).rjust(2, '0').upcase; nil
35
- when 1
36
- resp = @lambda.call(@arg, byte.to_s(16).rjust(2, '0').upcase)
37
- @prefix = nil; temp = @temp; @temp = nil
38
- if temp && resp.include?(')')
39
- resp = @xx ? displacement(temp.hex, resp) : resp.sub(')', "#{temp})").sub('(', '(#')
40
- elsif temp
41
- resp += temp
42
- end
43
- resp = hl_to_xx(resp, @xx) unless @xx.nil?
44
- @xx = nil
45
- resp
46
- else command
47
- end
53
+ str = command_from_byte(byte)
48
54
  @prev = byte.to_s(16)
49
- @ascii << ((32..126).include?(byte) ? ascii[byte - 32] : '.')
50
- @bytes << @prev.rjust(2, '0')
55
+ ascii << ((32..126).include?(byte) ? ASCII[byte - 32] : ' ')
56
+ bytes << @prev.rjust(2, '0').upcase
51
57
  next unless str
52
58
 
53
- @result[@addr] = ["##{@addr.to_s(16)}".upcase, str, @bytes.join(' '), @ascii]
54
- @addr += @bytes.size
55
- @bytes = []
56
- @ascii = []
59
+ @result << [addr, "##{addr.to_s(16)}".upcase, str, bytes.join(' '), ascii.join]
60
+ addr += bytes.size
61
+ bytes = []
62
+ ascii = []
57
63
  end
58
64
  @result
59
65
  end
60
66
 
67
+ def text
68
+ hash_links = {}
69
+ del_links = []
70
+ link_num = 0
71
+ int_addrs = @org..(@org + @file_size)
72
+ @result.select { |z| z[2] =~ /#[0-F]{4}/ && int_addrs.include?(z[2].split('#').last[0..3].hex) }.each do |x|
73
+ z = "##{x[2].split('#').last[0..3]}"
74
+ hash_links[z] = "link_#{link_num += 1}" unless hash_links[z]
75
+ end
76
+ @result.select { |z| z[2] =~ /\$/ }.each do |x|
77
+ z = "##{ (x[0] + x[2].split('$').last.to_i).to_s(16).upcase }"
78
+ hash_links[z] = "link_#{link_num += 1}" unless hash_links[z]
79
+ end
80
+ code = @result.map do |addr, addr16, str, bytes, ascii|
81
+ del_links << hash_links[addr16] if hash_links[addr16]
82
+ link = (hash_links[addr16] ? (hash_links[addr16] + ':') : '').ljust(16, ' ')
83
+ substr, adr = if str.include?('$')
84
+ ["$#{str.split('$').last}", "##{(addr + str.split('$').last.to_i).to_s(16).upcase}"]
85
+ else
86
+ adr = "##{str.split('#').last[0..3]}"
87
+ [adr, adr]
88
+ end
89
+ string = hash_links.keys.include?(adr) ? str.sub(substr, hash_links[adr]) : str
90
+
91
+ "#{link} #{string.ljust(16, ' ')}; #{addr16.ljust(5, ' ')} / #{addr.to_s.ljust(5, ' ')} ; #{bytes.ljust(14, ' ')} ; #{ascii.ljust(4, ' ')} ;"
92
+ end.join("\n")
93
+
94
+ header = [
95
+ ";--- #{Date.today} --- https://rmda.su ",
96
+ '; _______ _/| __ ______ ____ ',
97
+ '; / __ // |/ \\\\ _ \ / \ ',
98
+ '; / _/ _// \\\\ \\\\ \\\\ \ \ ',
99
+ '; \___\ \\\\___\/___//______//__/\__\ ',
100
+ '; \__/ ',
101
+ ";--- size: #{@file_size} --- filename: #{@file_name} "
102
+ ]
103
+ [
104
+ *header,
105
+ ' device zxspectrum48',
106
+ ' ORG #' + @org.to_s(16),
107
+ hash_links.map { |key, val| "#{val.ljust(16, ' ')} equ #{key}" unless del_links.include?(val) }.compact.join("\n"),
108
+ 'begin:',
109
+ code,
110
+ 'end:',
111
+ ' savesna "disasm.sna", begin',
112
+ ' savebin "disasm.C", begin, end - begin',
113
+ ''
114
+ ].join("\n")
115
+ end
116
+
61
117
  private
62
118
 
119
+ def bytes_to_int(array)
120
+ array.bytes.reverse.map { |x| x.to_s(16).rjust(2, "0") }.join.hex
121
+ end
122
+
123
+ def command_from_byte(byte)
124
+ case @prefix
125
+ when 'cb' then @prefix = nil; cb_prefix
126
+ when 'ed' then @prefix = nil; ed_prefix
127
+ when 'dd' then @xx = 'IX'; xx_prefix(byte)
128
+ when 'fd' then @xx = 'IY'; xx_prefix(byte)
129
+ when 'xx' then temp = @temp; @temp = nil; displacement(byte, temp)
130
+ when 2 then @prefix -= 1; @temp = byte.to_s(16).rjust(2, '0').upcase; nil
131
+ when 1
132
+ resp = @lambda.call(@arg, byte.to_s(16).rjust(2, '0').upcase)
133
+ @prefix = nil; temp = @temp; @temp = nil
134
+ if temp && resp.include?(')')
135
+ resp = @xx ? displacement(temp.hex, resp) : resp.sub(')', "#{temp})").sub('(', '(#')
136
+ elsif temp
137
+ resp += temp
138
+ end
139
+ resp = hl_to_xx(resp, @xx) unless @xx.nil?
140
+ @xx = nil
141
+ if resp.include?('JR') || resp.include?('DJNZ')
142
+ z = resp.split('#')
143
+ z[1] = z[1].hex < 127 ? "$+#{z[1].hex + 2}" : "$-#{255 - z[1].hex - 1}"
144
+ resp = z.join
145
+ end
146
+ resp
147
+ else command
148
+ end
149
+ end
150
+
63
151
  def hl_to_xx(temp, reg)
64
152
  if temp.include?('HL')
65
153
  temp.sub('HL', reg)
@@ -100,8 +188,8 @@ module Z80Disassembler
100
188
  case @y
101
189
  when 0 then 'NOP'
102
190
  when 1 then 'EX AF, AF\''
103
- when 2 then calc_bytes(->(a, b){ "DJNZ ##{b}" }, nil, 1)
104
- when 3 then calc_bytes(->(a, b){ "JR ##{b}" }, nil, 1)
191
+ when 2 then calc_bytes(->(a, b){ "DJNZ ##{b}" }, nil, 1)
192
+ when 3 then calc_bytes(->(a, b){ "JR ##{b}" }, nil, 1)
105
193
  else calc_bytes(->(a, b){ "JR #{a},##{b}" }, T_CC[@y - 4], 1)
106
194
  end
107
195
  when 1 then @q ? "ADD HL,#{T_RP[@p]}" : calc_bytes(->(a, b){ "LD #{a},##{b}" }, T_RP[@p], 2)
@@ -166,7 +254,7 @@ module Z80Disassembler
166
254
  elsif ['dd', 'fd'].include?(@prev) && @temp
167
255
  temp = @temp; @temp = nil; @prefix = nil; xx = @xx; @xx = nil
168
256
  hl_to_xx(temp, xx)
169
- elsif @lambda && !@arg.include?('HL')
257
+ elsif @lambda && !@arg&.include?('HL')
170
258
  @prefix = 1; @temp
171
259
  else
172
260
  @prefix = 2; @temp
@@ -196,15 +284,4 @@ module Z80Disassembler
196
284
  end
197
285
  end
198
286
  end
199
-
200
- def ascii
201
- [
202
- ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/',
203
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
204
- '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
205
- 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\',']', '^', '_',
206
- '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
207
- 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~'
208
- ]
209
- end
210
287
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Z80Disassembler
4
- VERSION = '0.1.5'
4
+ VERSION = '0.2.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: z80_disassembler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - dvitvitskiy
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-06-03 00:00:00.000000000 Z
11
+ date: 2021-06-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: