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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +3 -3
- data/lib/z80_disassembler.rb +122 -45
- 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: 5fe96f8335ed977825007f7846ed1b5b515ee9bab79fad0c67976504926c827e
|
4
|
+
data.tar.gz: c9341766fb32cf922aea077fa5968755b05e05ac03b45d277b8cc9de023f5b46
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4fabf9e9a350e8ddedbc85acb8c8f738fd471e347591107f81a169c14c5d3dbca0f779f7706294ec6a3fde06895d6d5a429b6c6c48c8f9e5e84ba2de29097539
|
7
|
+
data.tar.gz: cc8e487897234f43ddc6962d1ce979704b9295a7f99551d592db7413acb5d985ccf0d394952b26d0e08e84caafb91e31a96b1a1abe94f48a154b2cc3332e9010
|
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,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(
|
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
|
22
|
-
@bytes = []; @ascii = []; @result = {}
|
45
|
+
@lambda = nil; @prefix = nil; @prev = nil; @result = []
|
23
46
|
end
|
24
47
|
|
25
48
|
def start
|
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
|
-
|
50
|
-
|
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[
|
54
|
-
|
55
|
-
|
56
|
-
|
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}"
|
104
|
-
when 3 then calc_bytes(->(a, b){ "JR ##{b}"
|
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
|
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
|
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.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-
|
11
|
+
date: 2021-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|