1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
;
; s.UnSqueeze by RCC 25-Aug-87
; This is a bit of code to be included in self-decompressing images to
; expand the image in place. See elsewhere for details of the compression
; algorithm.
;
; ***********************************
; *** C h a n g e L i s t ***
; ***********************************
; Date Name Description
; ---- ---- -----------
; 13-Feb-90 TDobson Minor optimisation which saves 1 instruction for
; every output word that isn't a "short" or a "long".
; 15-Feb-90 TDobson Started conversion for inclusion in RISC OS kernel
; GET Hdr:Debug
; Constants defining partition of nibble value space: these must match
; corresponding values in mod.squeeze.
NibsLong * 7
NibsShort * (14-NibsLong)
MinShort * (2+NibsLong)
MinLong * 2
; **************************************************************************
;
; CheckForSqueezedModule - Check whether a module is squeezed, and
; unsqueeze it if it is
;
; in: R9 -> module node
; R10 -> environment string
; R12 -> incarnation node
;
; out: R9 preserved, but module node pointed to may have code entry changed
; to point to expanded copy of module
; R10, R12 preserved
; R0-R6 may be corrupted
;
; If offset to init entry is negative, then (offset BIC &80000000) is the
; offset from the size of the encoded module. The last 5 words of this are
; as follows
^ -5*4
Squeeze_DecodedSize # 4 ; size of decoded image (bytes)
Squeeze_EncodedSize # 4 ; size of encoded image (--"--)
Squeeze_TablesSize # 4 ; size of short+long tables (--"--)
Squeeze_NShorts # 4 ; number of "short" entries
Squeeze_NLongs # 4 ; number of "long" entries
ASSERT @=0
CheckForSqueezedModule ROUT
CLRV ; prepare for normal exit (V clear)
LDR R6, [R9, #Module_code_pointer] ; R6 -> module code
LDR R5, [R6, #Module_Init] ; R5 = offset to init entry
EORS R5, R5, #&80000000 ; take off top bit
MOVMI PC, lr ; if -ve now, then it's a normal module, so exit doing nothing
; it's a squeezed module, R5 = size of compressed module
Push "R6-R12,lr" ; save other registers (and pointer to module base)
; DLINE "Unsqueezing module"
ADD R5, R6, R5 ; R5 -> byte after end of module
LDMDB R5!, {R8-R12} ; load all the data - R8=decoded size, R9=encoded size
; R10=tables size, R11=no. of shorts, R12=no. of longs
SUB R10, R5, R10 ; R10 -> start (lowest address) of encoded tables
; = highest address +1 of encoded data
SUB R9, R10, R9 ; R9 -> lowest address of encoded data
; DREG R8, "Claiming block for module of size "
MOV R3, R8 ; now claim a block for the expanded code
BL RMAClaim_Chunk
BVS ExpandFailed1
; DREG R2, "Successfully claimed block for expanded code at "
MOV R7, R2 ; R7 -> start of expanded module
ADD R3, R11, R12 ; R3 = no. of shorts and longs
MOV R3, R3, LSL #2 ; convert to bytes
; DREG R3, "Claiming block for shorts+longs of size "
BL RMAClaim_Chunk
BVS ExpandFailed2 ; must free module block before exiting!
; DREG R2, "Successfully claimed block for shorts+longs at "
MOV R6, R2 ; R6 -> start of expanded table of shorts+longs
ADD R8, R7, R8 ; R8 -> highest address of decoded image +1
; We only need nLongs and nShorts while we are decoding the tables.
; Afterwards we will re-use the registers for pointers to start of tables.
MOV R5, R10 ; R5 is ptr into encoded tables
MOV R4, #0 ; this is the first table el
; DLINE "Expanding shorts+longs table"
decodeTab
; Require: R11 -- no of els left to decode
; R6 -- ptr into decoded table
; R5 -- ptr into encoding
; R4 -- = 0 iff this is the shorts table (i.e. 4-byte vals)
; I believe this loop could be made good deal smaller and possibly
; faster, but it's only a couple of hundred bytes and it works.
MOV R2, R6 ; stash away base of first table
MOV R3, #-1 ; start as if previous entry was -1
decodeEntry
SUBS R11, R11, #1 ; while (--nEntries >= 0) {
BLT decodedTab ; assert: previous word is in R3
LDRB R1, [R5], #1 ; byte = *p++
SUBS R0, R1, #10
BGE greaterThan9
literalOrOnes
CMPS R1, #0
BNE ones
literal
LDRB R0, [R5], #1
LDRB R1, [R5], #1
ORR R0, R0, R1, LSL #8
LDRB R1, [R5], #1
ORR R0, R0, R1, LSL #16
CMPS R4, #0 ; in the 4-byte (short encodings) table?
LDREQB R1, [R5], #1 ; yes, so include the 4th byte
ORREQ R0, R0, R1, LSL #24 ; in the resultant word
ADD R3, R3, R0
STR R3, [R6], #4
B decodeEntry
ones
SUB R11, R11, R1
ADD R11, R11, #1
anotherOne ; Have number of increment-by-ones in R1
ADD R3, R3, #1
STR R3, [R6], #4
SUBS R1, R1, #1
BGT anotherOne
B decodeEntry
greaterThan9
CMPS R1, #92
ADDLT R3, R3, R0
STRLT R3, [R6], #4
BLT decodeEntry
greaterThan91
SUBS R0, R1, #174
BLT oneMore
twoMore
LDRB R1, [R5], #1
ORR R0, R1, R0, LSL #16
LDRB R1, [R5], #1
ORR R0, R0, R1, LSL #8
ADD R3, R3, R0
STR R3, [R6], #4
B decodeEntry
oneMore
SUBS R0, R1, #92
LDRB R1, [R5], #1
ORR R0, R1, R0, LSL #8
ADD R3, R3, R0
STR R3, [R6], #4
B decodeEntry ; } /* end while (--nEntries >= 0) { */
decodedTab
CMPS R4, #0 ; if isShorts then
BNE finishLongs ; else finishLongs
finishShorts
MOV R11, R12 ; no of els to decode = nLongs
MOV R12, R2 ; R12 = &shorts[0]
MOV R2, R6 ; stash away start of longs table
MOV R4, #1 ; next table is longs
B decodeTab
finishLongs
MOV R11, R2 ; R11 = &longs[0]
; DLINE "Finished expanding shorts+longs table"
decodedBothTabs
; Now have: R12 = &shorts[0]
; R11 = &longs[0]
; R10 = highest address +1 of encoded data
; R9 = lowest address of encoded data
; R8 = highest address +1 of decoded data
;
; R0..R7 are free for workspace
; DREG R12, "Shorts table at "
; DREG R11, "Longs table at "
; DREG R9, "Encoded data start "
; DREG R10, "Encoded data end+1 "
; DREG R8, "Decoded data end+1 "
decodePair
CMPS R10, R9 ; Have we reached the base ?
BLE doneDecode
LDRB R6, [R10, #-1]! ; byte value
; The words will be put in R4 and R5, to be STMDB'd
AND R3, R6, #15 ; first nibble
SUBS R0, R3, #MinShort ; idx = (val - 8)
BLT notshort0
short0
LDRB R1, [R10, #-1]!
ORR R0, R1, R0, LSL #8
LDR R4, [R12, R0, LSL #2] ; w = shorts[(nibble-8)<<8 | *p--]
B gotFirst
notshort0
SUBS R0, R3, #MinLong ; idx = (val - 2)
BLT notlong0
long0
LDRB R1, [R10, #-1]!
ORR R0, R1, R0, LSL #8
LDR R0, [R11, R0, LSL #2] ; w = longs[(nibble-2)<<8 | *p--]
LDRB R1, [R10, #-1]!
ORR R4, R1, R0, LSL #8
B gotFirst
notlong0
MOVS R4, R3 ; TMD 13-Feb-90: combine 2 instructions here
; used to be CMPS R3,#0; MOVEQ R4,R3
BEQ gotFirst
literal0
LDRB R0, [R10, #-1]!
LDRB R1, [R10, #-1]!
ORR R0, R0, R1, LSL #8
LDRB R1, [R10, #-1]!
ORR R0, R0, R1, LSL #16
LDRB R1, [R10, #-1]!
ORR R4, R0, R1, LSL #24
gotFirst
; Phew! We have the first word of the pair (in R4), now we have
; to do (almost) the same again, result in R5, and STMDB.
MOV R3, R6, LSR #4 ; second nibble
SUBS R0, R3, #MinShort ; idx = (val - 8)
BLT notshort1
short1
LDRB R1, [R10, #-1]!
ORR R0, R1, R0, LSL #8
LDR R5, [R12, R0, LSL #2] ; w = shorts[(nibble-8)<<8 | *p--]
STMDB R8!, {R4,R5}
B decodePair
notshort1
SUBS R0, R3, #MinLong ; idx = (val - 2)
BLT notlong1
long1
LDRB R1, [R10, #-1]!
ORR R0, R1, R0, LSL #8
LDR R0, [R11, R0, LSL #2] ; w = longs[(nibble-2)<<8 | *p--]
LDRB R1, [R10, #-1]!
ORR R5, R1, R0, LSL #8
STMDB R8!, {R4,R5}
B decodePair
notlong1
MOVS R5, R3 ; TMD 13-Feb-90: combine 2 instructions here
; used to be CMPS R3,#0; MOVEQ R5,R3
; This doesn't pay off much
STMEQDB R8!, {R4,R5} ; might be better to swap round
BEQ decodePair ; literal and zero, to save 3S on
literal1 ; the longer path ?
LDRB R0, [R10, #-1]!
LDRB R1, [R10, #-1]! ; If I had the right byte-sex and
ORR R0, R0, R1, LSL #8 ; a couple of registers to spare,
LDRB R1, [R10, #-1]! ; could do this in 15S instead of 22S
ORR R0, R0, R1, LSL #16 ; using the load non-aligned word code
LDRB R1, [R10, #-1]! ; given in ARM CPU Manual.
ORR R5, R0, R1, LSL #24
STMDB R8!, {R4,R5}
B decodePair
doneDecode
; DREG R8, "Finished decoding, module at "
; now R8 -> the completely unsqueezed module
; so first, free the shorts+longs table block
; R12 -> shorts, which is first of the two
MOV R2, R12
; DREG R2, "Freeing shorts+longs table at "
BL FreeRMABlock
; ignore any error from this
MOV R3, R8 ; save pointer to expanded module
Pull "R2,R7-R12" ; pull pointer to original module base into R2 and restore other registers
; DREG R2, "Freeing original module block at "
BL FreeRMABlock ; may fail because original module is in ROM, so ignore error
; DLINE "Returning new module to OS"
STR R3, [R9, #Module_code_pointer] ; point module node at expanded module
CLRV
Pull PC ; exit (VC)
; come here if failed to claim block for tables
ExpandFailed2
; DLINE "Failed to claim table block, freeing module block"
Push R0 ; save original error pointer
MOV R2, R7
BL FreeRMABlock
Pull R0 ; restore error pointer, and drop thru to ...
; come here if failed to claim block for expanded module
ExpandFailed1
SETV
Pull "R6-R12, pc" ; restore registers, and exit V set
; subroutine to free a block in RMA
; in: R2 -> block
; out: R0,R1 corrupted
FreeRMABlock Entry
; LDR R0, [R2, #-4]
; DREG R0, "FreeRMABlock called, block size purports to be "
MOV R0, #HeapReason_Free
MOV R1, #RMAAddress
SWI XOS_Heap
EXIT
; InsertDebugRoutines
END