z80_disassembler 0.2.0 → 0.2.5
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/README.md +3 -3
- data/lib/z80_disassembler.rb +120 -38
- data/lib/z80_disassembler/version.rb +1 -1
- metadata +2 -3
- data/z80_disassembler-0.1.5.gem +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9970749ade07cf2808e1e6792d3c45f26d8325e6fc2fd492d6b3f88c4d843c40
|
4
|
+
data.tar.gz: ebbfd99ccff00c4e86e5a8e09e31774359c7798d13ed847c65d1b0e95ccf04e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8455ef820171b02eb4e886a7a37ef4dc43679c0c8bf4b777d9dc73e93732c4ec8899da13b4ea73d38f4704d5b8487ba42ab722cda462b11a7a33f7b46f68eefc
|
7
|
+
data.tar.gz: cecc4ee2168d08c0e1a373209f472cc78936f69e8f6ad067b04e9632e44c9d7291b3027215c5a6329d2226dfeb8a208b1aa28adb9c2ba6b56e400785f74e51c2
|
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,7 +16,6 @@ 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
|
17
|
-
|
18
19
|
ASCII = [
|
19
20
|
' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/',
|
20
21
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
|
@@ -24,52 +25,133 @@ module Z80Disassembler
|
|
24
25
|
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~'
|
25
26
|
].freeze
|
26
27
|
|
27
|
-
def initialize(
|
28
|
-
@
|
28
|
+
def initialize(file, org = 32_768)
|
29
|
+
@file = file; @org = 25108 # 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
|
29
44
|
@x = 0; @y = 0; @z = 0; @p = 0; @q = 0; @xx = nil
|
30
|
-
@lambda = nil; @prefix = nil; @prev = nil
|
31
|
-
@bytes = []; @ascii = []; @result = {}
|
45
|
+
@lambda = nil; @prefix = nil; @prev = nil; @result = []
|
32
46
|
end
|
33
47
|
|
34
48
|
def start
|
35
|
-
|
49
|
+
addr = @org
|
50
|
+
bytes = []; ascii = []
|
51
|
+
@code.each do |byte|
|
36
52
|
load_vars(byte)
|
37
|
-
str =
|
38
|
-
when 'cb' then @prefix = nil; cb_prefix
|
39
|
-
when 'ed' then @prefix = nil; ed_prefix
|
40
|
-
when 'dd' then @xx = 'IX'; xx_prefix(byte)
|
41
|
-
when 'fd' then @xx = 'IY'; xx_prefix(byte)
|
42
|
-
when 'xx' then temp = @temp; @temp = nil; displacement(byte, temp)
|
43
|
-
when 2 then @prefix -= 1; @temp = byte.to_s(16).rjust(2, '0').upcase; nil
|
44
|
-
when 1
|
45
|
-
resp = @lambda.call(@arg, byte.to_s(16).rjust(2, '0').upcase)
|
46
|
-
@prefix = nil; temp = @temp; @temp = nil
|
47
|
-
if temp && resp.include?(')')
|
48
|
-
resp = @xx ? displacement(temp.hex, resp) : resp.sub(')', "#{temp})").sub('(', '(#')
|
49
|
-
elsif temp
|
50
|
-
resp += temp
|
51
|
-
end
|
52
|
-
resp = hl_to_xx(resp, @xx) unless @xx.nil?
|
53
|
-
@xx = nil
|
54
|
-
resp
|
55
|
-
else command
|
56
|
-
end
|
53
|
+
str = command_from_byte(byte)
|
57
54
|
@prev = byte.to_s(16)
|
58
|
-
|
59
|
-
|
55
|
+
ascii << ((32..126).include?(byte) ? ASCII[byte - 32] : ' ')
|
56
|
+
bytes << @prev.rjust(2, '0').upcase
|
60
57
|
next unless str
|
61
58
|
|
62
|
-
@result[
|
63
|
-
|
64
|
-
|
65
|
-
|
59
|
+
@result << [addr, "##{addr.to_s(16)}".upcase, str, bytes.join(' '), ascii.join]
|
60
|
+
addr += bytes.size
|
61
|
+
bytes = []
|
62
|
+
ascii = []
|
66
63
|
end
|
67
64
|
@result
|
68
65
|
end
|
69
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
|
+
|
70
117
|
private
|
71
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?('(HL)')
|
135
|
+
resp += temp
|
136
|
+
elsif temp && resp.include?(')')
|
137
|
+
# resp = @xx ? displacement(temp.hex, resp) :
|
138
|
+
resp = resp.sub(')', "#{temp})").sub('(', '(#')
|
139
|
+
elsif temp
|
140
|
+
resp += temp
|
141
|
+
end
|
142
|
+
resp = hl_to_xx(resp, @xx) unless @xx.nil?
|
143
|
+
if resp.include?('JR') || resp.include?('DJNZ')
|
144
|
+
z = resp.split('#')
|
145
|
+
z[1] = z[1].hex < 127 ? "$+#{z[1].hex + 2}" : "$-#{255 - z[1].hex - 1}"
|
146
|
+
resp = z.join
|
147
|
+
end
|
148
|
+
resp
|
149
|
+
else command
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
72
153
|
def hl_to_xx(temp, reg)
|
154
|
+
@xx = nil
|
73
155
|
if temp.include?('HL')
|
74
156
|
temp.sub('HL', reg)
|
75
157
|
elsif temp.include?(' L')
|
@@ -88,7 +170,7 @@ module Z80Disassembler
|
|
88
170
|
def displacement(byte, temp)
|
89
171
|
@prefix = nil
|
90
172
|
byte -= 256 if byte > 127
|
91
|
-
des = ['', "+#{byte.to_s
|
173
|
+
des = ['', "+#{byte.to_s}", byte.to_s][byte <=> 0]
|
92
174
|
temp.sub('HL', @xx + des)
|
93
175
|
end
|
94
176
|
|
@@ -109,8 +191,8 @@ module Z80Disassembler
|
|
109
191
|
case @y
|
110
192
|
when 0 then 'NOP'
|
111
193
|
when 1 then 'EX AF, AF\''
|
112
|
-
when 2 then calc_bytes(->(a, b){ "DJNZ ##{b}"
|
113
|
-
when 3 then calc_bytes(->(a, b){ "JR ##{b}"
|
194
|
+
when 2 then calc_bytes(->(a, b){ "DJNZ ##{b}" }, nil, 1)
|
195
|
+
when 3 then calc_bytes(->(a, b){ "JR ##{b}" }, nil, 1)
|
114
196
|
else calc_bytes(->(a, b){ "JR #{a},##{b}" }, T_CC[@y - 4], 1)
|
115
197
|
end
|
116
198
|
when 1 then @q ? "ADD HL,#{T_RP[@p]}" : calc_bytes(->(a, b){ "LD #{a},##{b}" }, T_RP[@p], 2)
|
@@ -173,9 +255,9 @@ module Z80Disassembler
|
|
173
255
|
if @temp&.include?('(')
|
174
256
|
@prefix = 'xx'; nil
|
175
257
|
elsif ['dd', 'fd'].include?(@prev) && @temp
|
176
|
-
temp = @temp; @temp = nil; @prefix = nil
|
177
|
-
hl_to_xx(temp, xx)
|
178
|
-
elsif @lambda && !@arg
|
258
|
+
temp = @temp; @temp = nil; @prefix = nil
|
259
|
+
hl_to_xx(temp, @xx)
|
260
|
+
elsif @lambda && !@arg&.include?('HL')
|
179
261
|
@prefix = 1; @temp
|
180
262
|
else
|
181
263
|
@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.2.
|
4
|
+
version: 0.2.5
|
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-12 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -30,7 +30,6 @@ files:
|
|
30
30
|
- bin/setup
|
31
31
|
- lib/z80_disassembler.rb
|
32
32
|
- lib/z80_disassembler/version.rb
|
33
|
-
- z80_disassembler-0.1.5.gem
|
34
33
|
- z80_disassembler.gemspec
|
35
34
|
homepage: ''
|
36
35
|
licenses:
|
data/z80_disassembler-0.1.5.gem
DELETED
Binary file
|