z80_disassembler 0.1.3 → 0.2.3

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: 10ca0748d50c8d00bb27bc23da607dc4c749d9c017348d20046ca37776aed136
4
- data.tar.gz: 2407cc63119e48386a33bb0e448428423c820bde25e85c79a5a93c700c106251
3
+ metadata.gz: 7fda0599a6e835b5063fc6115dcdc364cfc895b2a7cbf1dba8f57965698526a5
4
+ data.tar.gz: 705361c3aa8d088e967411643e9774a1d1cbc169a9e7ce57d8ffa8087a833f68
5
5
  SHA512:
6
- metadata.gz: 0c08d4acbf8e07f739f383e963d0a4c36573b3c1c4a7b53389d2fb00e1973f1cca95af6ee1462d702d213fd185f10e6ae662f427e2000ef84a48b2bf28c201ca
7
- data.tar.gz: 8c24ea1e6c040901e7d8409d9cd8f44913a5ed426adba4bca0e09080af091a55b9eacbdf007c57ca9db2a74a0ff268b966f8c4dec54c74acd93eeb3fc69903bf
6
+ metadata.gz: 6b2b887c58d4bf48e32094f9753e71520ff3b1c12d7d7ab46870c0179628005b3e13be8c191c0fd305e78004c3b2b630833536fceb77ff49f004ed19cb17b59e
7
+ data.tar.gz: cfd8680fc373ed1031ffd89af3ad8ff7c1cdb67f6fa5e5aa53f15b9f1d4e172c7c5983f14d62914f2baa3e0d49249472f744cb851b69770c546205e51f3c4b5e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- z80_disassembler (0.1.1)
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,50 +16,120 @@ 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, @bytes = []
45
+ @lambda = nil; @prefix = nil; @prev = nil; @result = []
22
46
  end
23
47
 
24
48
  def start
25
- result = {}
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
- @bytes << @prev.rjust(2, '0')
55
+ ascii << ((32..126).include?(byte) ? ASCII[byte - 32] : ' ')
56
+ bytes << @prev.rjust(2, '0').upcase
50
57
  next unless str
51
58
 
52
- result[@addr] = ["##{@addr.to_s(16)}".upcase, str, @bytes.join(' ')]
53
- @addr += @bytes.size
54
- @bytes = []
59
+ @result << [addr, "##{addr.to_s(16)}".upcase, str, bytes.join(' '), ascii.join]
60
+ addr += bytes.size
61
+ bytes = []
62
+ ascii = []
63
+ end
64
+ @result
65
+ end
66
+
67
+ def text
68
+ hash_links = {}
69
+ del_links = []
70
+ link_num = 0
71
+ int_addrs = @org..(@org + @file_size)
72
+ with_links = @result.select { |z| z[2] =~ /#[0-F]{4}/ && int_addrs.include?(z[2].split('#').last[0..3].hex) }
73
+ with_links.each do |x|
74
+ z = "##{x[2].split('#').last[0..3]}"
75
+ hash_links[z] = "link_#{link_num += 1}" unless hash_links[z]
55
76
  end
56
- result
77
+
78
+ code = @result.map do |addr, addr16, str, bytes, ascii|
79
+ del_links << hash_links[addr16] if hash_links[addr16]
80
+ link = (hash_links[addr16] || '').ljust(16, ' ')
81
+ adr = '#' + str.split('#').last[0..3]
82
+ string = hash_links.keys.include?(adr) ? str.sub(adr, hash_links[adr]) : str
83
+ "#{link} #{string.ljust(16, ' ')}; #{addr16.ljust(5, ' ')} / #{addr.to_s.ljust(5, ' ')} ; #{bytes.ljust(14, ' ')} ; #{ascii.ljust(4, ' ')} ;"
84
+ end.join("\n")
85
+
86
+ [
87
+ ' device zxspectrum48',
88
+ ' ORG #' + @org.to_s(16),
89
+ hash_links.map { |key, val| "#{val.ljust(16, ' ')} equ #{key}" unless del_links.include?(val) }.compact.join("\n"),
90
+ 'begin:',
91
+ code,
92
+ 'end:',
93
+ ' savesna "disasm.sna", begin',
94
+ ' savebin "disasm.C", begin, end - begin',
95
+ ''
96
+ ].join("\n")
57
97
  end
58
98
 
59
99
  private
60
100
 
101
+ def bytes_to_int(array)
102
+ array.bytes.reverse.map { |x| x.to_s(16).rjust(2, "0") }.join.hex
103
+ end
104
+
105
+ def command_from_byte(byte)
106
+ case @prefix
107
+ when 'cb' then @prefix = nil; cb_prefix
108
+ when 'ed' then @prefix = nil; ed_prefix
109
+ when 'dd' then @xx = 'IX'; xx_prefix(byte)
110
+ when 'fd' then @xx = 'IY'; xx_prefix(byte)
111
+ when 'xx' then temp = @temp; @temp = nil; displacement(byte, temp)
112
+ when 2 then @prefix -= 1; @temp = byte.to_s(16).rjust(2, '0').upcase; nil
113
+ when 1
114
+ resp = @lambda.call(@arg, byte.to_s(16).rjust(2, '0').upcase)
115
+ @prefix = nil; temp = @temp; @temp = nil
116
+ if temp && resp.include?(')')
117
+ resp = @xx ? displacement(temp.hex, resp) : resp.sub(')', "#{temp})").sub('(', '(#')
118
+ elsif temp
119
+ resp += temp
120
+ end
121
+ resp = hl_to_xx(resp, @xx) unless @xx.nil?
122
+ @xx = nil
123
+ if resp.include?('JR') || resp.include?('DJNZ')
124
+ z = resp.split('#')
125
+ z[1] = z[1].hex < 127 ? "$+#{z[1].hex}" : "$-#{255 - z[1].hex}"
126
+ resp = z.join
127
+ end
128
+ resp
129
+ else command
130
+ end
131
+ end
132
+
61
133
  def hl_to_xx(temp, reg)
62
134
  if temp.include?('HL')
63
135
  temp.sub('HL', reg)
@@ -98,8 +170,8 @@ module Z80Disassembler
98
170
  case @y
99
171
  when 0 then 'NOP'
100
172
  when 1 then 'EX AF, AF\''
101
- when 2 then calc_bytes(->(a, b){ "DJNZ ##{b}" }, nil, 1)
102
- when 3 then calc_bytes(->(a, b){ "JR ##{b}" }, nil, 1)
173
+ when 2 then calc_bytes(->(a, b){ "DJNZ ##{b}" }, nil, 1)
174
+ when 3 then calc_bytes(->(a, b){ "JR ##{b}" }, nil, 1)
103
175
  else calc_bytes(->(a, b){ "JR #{a},##{b}" }, T_CC[@y - 4], 1)
104
176
  end
105
177
  when 1 then @q ? "ADD HL,#{T_RP[@p]}" : calc_bytes(->(a, b){ "LD #{a},##{b}" }, T_RP[@p], 2)
@@ -164,7 +236,7 @@ module Z80Disassembler
164
236
  elsif ['dd', 'fd'].include?(@prev) && @temp
165
237
  temp = @temp; @temp = nil; @prefix = nil; xx = @xx; @xx = nil
166
238
  hl_to_xx(temp, xx)
167
- elsif @lambda && !@arg.include?('HL')
239
+ elsif @lambda && !@arg&.include?('HL')
168
240
  @prefix = 1; @temp
169
241
  else
170
242
  @prefix = 2; @temp
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Z80Disassembler
4
- VERSION = '0.1.3'
4
+ VERSION = '0.2.3'
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.3
4
+ version: 0.2.3
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-07 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: