z80_disassembler 0.2.0 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|