gruesome 0.0.1
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.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +35 -0
- data/Rakefile +15 -0
- data/bin/gruesome +9 -0
- data/gruesome.gemspec +25 -0
- data/lib/gruesome/cli.rb +70 -0
- data/lib/gruesome/logo.rb +28 -0
- data/lib/gruesome/machine.rb +17 -0
- data/lib/gruesome/version.rb +3 -0
- data/lib/gruesome/z/abbreviation_table.rb +30 -0
- data/lib/gruesome/z/decoder.rb +292 -0
- data/lib/gruesome/z/dictionary.rb +156 -0
- data/lib/gruesome/z/header.rb +46 -0
- data/lib/gruesome/z/instruction.rb +50 -0
- data/lib/gruesome/z/machine.rb +71 -0
- data/lib/gruesome/z/memory.rb +268 -0
- data/lib/gruesome/z/object_table.rb +430 -0
- data/lib/gruesome/z/opcode.rb +519 -0
- data/lib/gruesome/z/opcode_class.rb +15 -0
- data/lib/gruesome/z/operand_type.rb +15 -0
- data/lib/gruesome/z/processor.rb +399 -0
- data/lib/gruesome/z/zscii.rb +337 -0
- data/lib/gruesome.rb +7 -0
- data/spec/z/memory_spec.rb +90 -0
- data/spec/z/processor_spec.rb +1956 -0
- data/test/logo.txt +77 -0
- metadata +118 -0
@@ -0,0 +1,337 @@
|
|
1
|
+
module Gruesome
|
2
|
+
module Z
|
3
|
+
|
4
|
+
# This translates between the special ZSCII character encoding
|
5
|
+
# to ASCII / UNICODE
|
6
|
+
module ZSCII
|
7
|
+
|
8
|
+
ALPHABET_TABLES = [
|
9
|
+
"abcdefghijklmnopqrstuvwxyz",
|
10
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
11
|
+
" \n0123456789.,!?_#'\"/\\-:()"
|
12
|
+
]
|
13
|
+
|
14
|
+
V1_A2 = " 0123456789.,!?_#'\"/\\<-:()"
|
15
|
+
|
16
|
+
UNICODE_TRANSLATION_TABLE = {
|
17
|
+
155 => "\u00e4", 156 => "\u00f6", 157 => "\u00fc", 158 => "\u00c4", 159 => "\u00d6",
|
18
|
+
160 => "\u00dc", 161 => "\u00df", 162 => "\u00bb", 163 => "\u00ab", 164 => "\u00eb",
|
19
|
+
165 => "\u00ef", 166 => "\u00ff", 167 => "\u00cb", 168 => "\u00cf", 169 => "\u00e1",
|
20
|
+
170 => "\u00e9", 171 => "\u00ed", 172 => "\u00f3", 173 => "\u00fa", 174 => "\u00fd",
|
21
|
+
175 => "\u00c1", 176 => "\u00c9", 177 => "\u00cd", 178 => "\u00d3", 179 => "\u00da",
|
22
|
+
180 => "\u00dd", 181 => "\u00e0", 182 => "\u00e8", 183 => "\u00ec", 184 => "\u00f2",
|
23
|
+
185 => "\u00f9", 186 => "\u00c0", 187 => "\u00c8", 188 => "\u00cc", 189 => "\u00d2",
|
24
|
+
190 => "\u00d9", 191 => "\u00e2", 192 => "\u00ea", 193 => "\u00ee", 194 => "\u00f4",
|
25
|
+
195 => "\u00fb", 196 => "\u00c2", 197 => "\u00ca", 198 => "\u00ce", 199 => "\u00d4",
|
26
|
+
200 => "\u00db", 201 => "\u00e5", 202 => "\u00c5", 203 => "\u00f8", 204 => "\u00d8",
|
27
|
+
205 => "\u00e3", 206 => "\u00f1", 207 => "\u00f5", 208 => "\u00c3", 209 => "\u00d1",
|
28
|
+
210 => "\u00d5", 211 => "\u00e6", 212 => "\u00c6", 213 => "\u00e7", 214 => "\u00c7",
|
29
|
+
215 => "\u00fe", 216 => "\u00f0", 217 => "\u00de", 218 => "\u00d0", 219 => "\u00a3",
|
30
|
+
220 => "\u0153", 221 => "\u0152", 222 => "\u00a1", 223 => "\u00bf"
|
31
|
+
}
|
32
|
+
|
33
|
+
# figure out if a shift lock is pressed and return it
|
34
|
+
def ZSCII.eval_alphabet(initial_alphabet, version, codes)
|
35
|
+
if version < 3
|
36
|
+
else
|
37
|
+
initial_alphabet
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def ZSCII.translate_Zchar(zchar)
|
42
|
+
if zchar == 9
|
43
|
+
"\t"
|
44
|
+
elsif zchar == 11
|
45
|
+
" "
|
46
|
+
elsif zchar == 13
|
47
|
+
"\n"
|
48
|
+
elsif zchar >= 32 and zchar <= 126
|
49
|
+
zchar.chr
|
50
|
+
elsif zchar >= 155 and zchar <= 223
|
51
|
+
UNICODE_TRANSLATION_TABLE[zchar]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def ZSCII.translate_char_to_zchar(chr, version)
|
56
|
+
if chr == "\t"
|
57
|
+
9
|
58
|
+
elsif chr == " "
|
59
|
+
11
|
60
|
+
elsif chr == "\n"
|
61
|
+
13
|
62
|
+
elsif chr.getbyte(0) >= 32 and chr.getbyte(0) <= 126
|
63
|
+
chr.getbyte(0)
|
64
|
+
else
|
65
|
+
# XXX: Unicode Translation Table reversed
|
66
|
+
"?".getbyte(0)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Give array of Z-codes
|
71
|
+
def ZSCII.translate_char(chr, version)
|
72
|
+
ret = []
|
73
|
+
if chr >= 'a'[0] and chr <= 'z'[0]
|
74
|
+
# A0
|
75
|
+
chr = chr.getbyte(0) - 'a'.getbyte(0)
|
76
|
+
chr += 6
|
77
|
+
ret << chr
|
78
|
+
elsif chr >= 'A'[0] and chr <= 'Z'[0]
|
79
|
+
# A1
|
80
|
+
chr = chr.getbyte(0) - 'A'.getbyte(0)
|
81
|
+
chr += 6
|
82
|
+
|
83
|
+
ret << 4
|
84
|
+
ret << chr
|
85
|
+
elsif chr == " "
|
86
|
+
ret << 0
|
87
|
+
elsif chr == "\n"
|
88
|
+
if version == 1
|
89
|
+
# use 10-bit code since newline is not in the alphabet 2
|
90
|
+
ret << 5
|
91
|
+
ret << 6
|
92
|
+
ret << 0
|
93
|
+
ret << 13
|
94
|
+
else
|
95
|
+
ret << 5
|
96
|
+
ret << 7
|
97
|
+
end
|
98
|
+
elsif chr >= '0'[0] and chr <= '9'[0]
|
99
|
+
chr = chr[0] - '0'[0]
|
100
|
+
if version == 1
|
101
|
+
chr += 7
|
102
|
+
else
|
103
|
+
chr += 8
|
104
|
+
end
|
105
|
+
ret << 5
|
106
|
+
ret << chr
|
107
|
+
elsif chr == "."
|
108
|
+
ret << 5
|
109
|
+
if version == 1
|
110
|
+
ret << 17
|
111
|
+
else
|
112
|
+
ret << 18
|
113
|
+
end
|
114
|
+
elsif chr == ","
|
115
|
+
ret << 5
|
116
|
+
if version == 1
|
117
|
+
ret << 18
|
118
|
+
else
|
119
|
+
ret << 19
|
120
|
+
end
|
121
|
+
elsif chr == "!"
|
122
|
+
ret << 5
|
123
|
+
if version == 1
|
124
|
+
ret << 19
|
125
|
+
else
|
126
|
+
ret << 20
|
127
|
+
end
|
128
|
+
elsif chr == "?"
|
129
|
+
ret << 5
|
130
|
+
if version == 1
|
131
|
+
ret << 20
|
132
|
+
else
|
133
|
+
ret << 21
|
134
|
+
end
|
135
|
+
elsif chr == "_"
|
136
|
+
ret << 5
|
137
|
+
if version == 1
|
138
|
+
ret << 21
|
139
|
+
else
|
140
|
+
ret << 22
|
141
|
+
end
|
142
|
+
elsif chr == "#"
|
143
|
+
ret << 5
|
144
|
+
if version == 1
|
145
|
+
ret << 22
|
146
|
+
else
|
147
|
+
ret << 23
|
148
|
+
end
|
149
|
+
elsif chr == "'"
|
150
|
+
ret << 5
|
151
|
+
if version == 1
|
152
|
+
ret << 23
|
153
|
+
else
|
154
|
+
ret << 24
|
155
|
+
end
|
156
|
+
elsif chr == "\""
|
157
|
+
ret << 5
|
158
|
+
if version == 1
|
159
|
+
ret << 24
|
160
|
+
else
|
161
|
+
ret << 25
|
162
|
+
end
|
163
|
+
elsif chr == "/"
|
164
|
+
ret << 5
|
165
|
+
if version == 1
|
166
|
+
ret << 25
|
167
|
+
else
|
168
|
+
ret << 26
|
169
|
+
end
|
170
|
+
elsif chr == "\\"
|
171
|
+
ret << 5
|
172
|
+
if version == 1
|
173
|
+
ret << 26
|
174
|
+
else
|
175
|
+
ret << 27
|
176
|
+
end
|
177
|
+
elsif chr == "<"
|
178
|
+
if version == 1
|
179
|
+
ret << 5
|
180
|
+
ret << 27
|
181
|
+
else
|
182
|
+
# use 10-bit
|
183
|
+
ret << 5
|
184
|
+
ret << 6
|
185
|
+
ret << 0
|
186
|
+
ret << '<'[0]
|
187
|
+
end
|
188
|
+
elsif chr == "-"
|
189
|
+
ret << 5
|
190
|
+
ret << 28
|
191
|
+
elsif chr == ":"
|
192
|
+
ret << 5
|
193
|
+
ret << 29
|
194
|
+
elsif chr == "("
|
195
|
+
ret << 5
|
196
|
+
ret << 30
|
197
|
+
elsif chr == ")"
|
198
|
+
ret << 5
|
199
|
+
ret << 30
|
200
|
+
end
|
201
|
+
# TODO: Unicode
|
202
|
+
|
203
|
+
ret
|
204
|
+
end
|
205
|
+
|
206
|
+
def ZSCII.encode_to_zchars(string, version)
|
207
|
+
codes = []
|
208
|
+
string.each_char do |chr|
|
209
|
+
codes << ZSCII.translate_char_to_zchar(chr, version)
|
210
|
+
end
|
211
|
+
|
212
|
+
codes
|
213
|
+
end
|
214
|
+
|
215
|
+
def ZSCII.encode(string, version)
|
216
|
+
codes = []
|
217
|
+
string.each_char do |chr|
|
218
|
+
subcodes = ZSCII.translate_char(chr, version)
|
219
|
+
subcodes.each do |code|
|
220
|
+
codes << code
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# pad codes to be divisible by three
|
225
|
+
# and pad with '5' shift code
|
226
|
+
(codes.length % 3).times do
|
227
|
+
codes << 5
|
228
|
+
end
|
229
|
+
|
230
|
+
# encode the z-codes
|
231
|
+
words = []
|
232
|
+
|
233
|
+
word = 0
|
234
|
+
codes.each_with_index do |code, i|
|
235
|
+
if (i % 3) == 0
|
236
|
+
word = (code & 0b11111) << 10
|
237
|
+
elsif (i % 3) == 1
|
238
|
+
word |= (code & 0b11111) << 5
|
239
|
+
else
|
240
|
+
word |= code & 0b11111
|
241
|
+
words << word
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# Give single that it is the last word
|
246
|
+
words[-1] |= 0b10000000_00000000
|
247
|
+
|
248
|
+
words
|
249
|
+
end
|
250
|
+
|
251
|
+
# return the utf8 string for the given ZSCII code
|
252
|
+
def ZSCII.translate(initial_alphabet, version, zscii_str, abbreviation_table = nil, table = nil)
|
253
|
+
str = ""
|
254
|
+
|
255
|
+
alphabet = initial_alphabet
|
256
|
+
|
257
|
+
# for abbreviations
|
258
|
+
next_is_abbrev = false
|
259
|
+
abbrev_alphabet = 0
|
260
|
+
|
261
|
+
# for 10-bit characters
|
262
|
+
next_is_big_char_top = false
|
263
|
+
next_is_big_char_bottom = false
|
264
|
+
big_char = 0
|
265
|
+
|
266
|
+
zscii_str.each do |c|
|
267
|
+
if next_is_big_char_top
|
268
|
+
next_is_big_char_top = false
|
269
|
+
next_is_big_char_bottom = true
|
270
|
+
|
271
|
+
big_char = c
|
272
|
+
elsif next_is_big_char_bottom
|
273
|
+
next_is_big_char_bottom = false
|
274
|
+
|
275
|
+
big_char = big_char << 5
|
276
|
+
big_char |= c
|
277
|
+
|
278
|
+
str += translate_Zchar(big_char)
|
279
|
+
elsif next_is_abbrev
|
280
|
+
next_is_abbrev = false
|
281
|
+
|
282
|
+
str += abbreviation_table.lookup(abbrev_alphabet, c, 0)
|
283
|
+
elsif (version < 3 and c == 2) or c == 4
|
284
|
+
# handle shift characters
|
285
|
+
alphabet = (alphabet + 1) % 3
|
286
|
+
if version < 3 and c == 2
|
287
|
+
initial_alphabet = alphabet
|
288
|
+
end
|
289
|
+
elsif (version < 3 and c == 3) or c == 5
|
290
|
+
# handle shift characters
|
291
|
+
alphabet = (alphabet - 1) % 3
|
292
|
+
if version < 3 and c == 3
|
293
|
+
initial_alphabet = alphabet
|
294
|
+
end
|
295
|
+
elsif (version >= 2 and c == 1) or (version >= 3 and (c == 2 or c == 3))
|
296
|
+
# the next code will decide the character to pull from the table
|
297
|
+
if abbreviation_table != nil
|
298
|
+
next_is_abbrev = true
|
299
|
+
abbrev_alphabet = c - 1
|
300
|
+
end
|
301
|
+
else
|
302
|
+
# translate character
|
303
|
+
if alphabet == 2 and c == 6
|
304
|
+
# 10 bit ZSCII code follows
|
305
|
+
# next c gives top 5 bits
|
306
|
+
# c after that gives bottom 5 bits
|
307
|
+
next_is_big_char_top = true
|
308
|
+
elsif c == 0
|
309
|
+
# space
|
310
|
+
str += " "
|
311
|
+
elsif version == 1 and c == 1
|
312
|
+
# newline
|
313
|
+
str += "\n"
|
314
|
+
elsif version == 1 and alphabet == 2
|
315
|
+
alphabet_char_idx = c - 6
|
316
|
+
str += V1_A2[alphabet_char_idx]
|
317
|
+
elsif version <= 4 or table == nil
|
318
|
+
# normal translation
|
319
|
+
# c will always be > 5 here
|
320
|
+
alphabet_char_idx = c - 6
|
321
|
+
str += ALPHABET_TABLES[alphabet][alphabet_char_idx]
|
322
|
+
elsif version >= 5
|
323
|
+
# table is not nil, use it to determine the letter
|
324
|
+
# XXX: Use included table (array of three strings)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
if c < 2 or c > 5
|
329
|
+
alphabet = initial_alphabet
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
return str
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
data/lib/gruesome.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require_relative '../../lib/gruesome/z/memory'
|
2
|
+
|
3
|
+
describe Gruesome::Z::Memory do
|
4
|
+
before(:each) do
|
5
|
+
zork = File.open('test/zork1.z3', 'r')
|
6
|
+
@zork_memory = Gruesome::Z::Memory.new(zork.read(zork.size))
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#readb" do
|
10
|
+
it "should read a byte in header" do
|
11
|
+
@zork_memory.readb(0x0).should eql(3)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should read a byte in dynamic memory" do
|
15
|
+
@zork_memory.readb(0x100).should eql(32)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should read a byte in static memory" do
|
19
|
+
@zork_memory.readb(0x2E53).should eql(47)
|
20
|
+
@zork_memory.readb(0x4E36).should eql(0)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should not read a byte in high memory" do
|
24
|
+
lambda {@zork_memory.readb(0x4E37)}.should raise_error(RuntimeError)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#readw" do
|
29
|
+
it "should read a word in header" do
|
30
|
+
@zork_memory.readw(0x0).should eql(768)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should read a word in dynamic memory" do
|
34
|
+
@zork_memory.readw(0x100).should eql(8403)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should read a word in static memory" do
|
38
|
+
@zork_memory.readw(0x2E53).should eql(12127)
|
39
|
+
@zork_memory.readw(0x4E35).should eql(256)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should not read a word in high memory" do
|
43
|
+
lambda{@zork_memory.readw(0x4E36)}.should raise_error(RuntimeError)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#writeb" do
|
48
|
+
it "should write a byte in dynamic memory" do
|
49
|
+
@zork_memory.writeb(0x100, 128)
|
50
|
+
@zork_memory.readb(0x100).should eql(128)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not write a byte in static memory" do
|
54
|
+
@zork_memory.force_writeb(0x2E53, 123)
|
55
|
+
lambda{@zork_memory.writeb(0x2E53, 128)}.should raise_error(RuntimeError)
|
56
|
+
@zork_memory.readb(0x2E53).should eql(123)
|
57
|
+
@zork_memory.force_writeb(0x4E36, 123)
|
58
|
+
lambda{@zork_memory.writeb(0x4E36, 128)}.should raise_error(RuntimeError)
|
59
|
+
@zork_memory.readb(0x4E36).should eql(123)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should not write a byte in high memory" do
|
63
|
+
@zork_memory.force_writeb(0x4E37, 123)
|
64
|
+
lambda{@zork_memory.writeb(0x4E37, 128)}.should raise_error(RuntimeError)
|
65
|
+
@zork_memory.force_readb(0x4E37).should eql(123)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#writew" do
|
70
|
+
it "should write a word in dynamic memory" do
|
71
|
+
@zork_memory.writew(0x100, 12345)
|
72
|
+
@zork_memory.readw(0x100).should eql(12345)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should not write a word in static memory" do
|
76
|
+
@zork_memory.force_writew(0x2E53, 23456)
|
77
|
+
lambda{@zork_memory.writew(0x2E53, 12345)}.should raise_error(RuntimeError)
|
78
|
+
@zork_memory.readw(0x2E53).should eql(23456)
|
79
|
+
@zork_memory.force_writew(0x4E35, 23456)
|
80
|
+
lambda{@zork_memory.writew(0x4E35, 12345)}.should raise_error(RuntimeError)
|
81
|
+
@zork_memory.readw(0x4E35).should eql(23456)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should not write a word in high memory" do
|
85
|
+
@zork_memory.force_writew(0x4E36, 23456)
|
86
|
+
lambda{@zork_memory.writew(0x4E36, 12345)}.should raise_error(RuntimeError)
|
87
|
+
@zork_memory.force_readw(0x4E36).should eql(23456)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|