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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +3 -3
- data/lib/z80_disassembler.rb +105 -33
- data/lib/z80_disassembler/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7fda0599a6e835b5063fc6115dcdc364cfc895b2a7cbf1dba8f57965698526a5
|
4
|
+
data.tar.gz: 705361c3aa8d088e967411643e9774a1d1cbc169a9e7ce57d8ffa8087a833f68
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b2b887c58d4bf48e32094f9753e71520ff3b1c12d7d7ab46870c0179628005b3e13be8c191c0fd305e78004c3b2b630833536fceb77ff49f004ed19cb17b59e
|
7
|
+
data.tar.gz: cfd8680fc373ed1031ffd89af3ad8ff7c1cdb67f6fa5e5aa53f15b9f1d4e172c7c5983f14d62914f2baa3e0d49249472f744cb851b69770c546205e51f3c4b5e
|
data/Gemfile.lock
CHANGED
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)
|
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.
|
data/lib/z80_disassembler.rb
CHANGED
@@ -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(
|
19
|
-
@
|
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
|
45
|
+
@lambda = nil; @prefix = nil; @prev = nil; @result = []
|
22
46
|
end
|
23
47
|
|
24
48
|
def start
|
25
|
-
|
26
|
-
|
49
|
+
addr = @org
|
50
|
+
bytes = []; ascii = []
|
51
|
+
@code.each do |byte|
|
27
52
|
load_vars(byte)
|
28
|
-
str =
|
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
|
-
|
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[
|
53
|
-
|
54
|
-
|
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
|
-
|
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}"
|
102
|
-
when 3 then calc_bytes(->(a, b){ "JR ##{b}"
|
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
|
239
|
+
elsif @lambda && !@arg&.include?('HL')
|
168
240
|
@prefix = 1; @temp
|
169
241
|
else
|
170
242
|
@prefix = 2; @temp
|
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.
|
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-
|
11
|
+
date: 2021-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|