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
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
|
(* Pakete:
1. setup eumel modulzugriffe
Abstrakter Datentyp MODUL : Typ, Datenraumtyp, Zugriffsoperationen
2. setup eumel modul und shard zugriffe
Zugriffe in Module und SHards (Datentyp MODUL) mit Strukturwissen
*)
(**************************************************************************)
(***** Datentyp MODUL und Zugriffsoperationen dafür ****************)
(***** Copyright (c) 1987, 1988 by ****************)
(***** Lutz Prechelt, Karlsruhe ****************)
(**************************************************************************)
PACKET setup eumel modulzugriffe (* Copyright (c) 1987 by *)
DEFINES int, byte, text, unsigned, (* Lutz Prechelt, Karlsruhe *)
dtcb abfragen, ccb abfragen, (* Stand : 12.03.88 1.1 *)
dtcb refinements, ccb refinements, (* Eumel 1.8.1 *)
info,
page,
copy,
datenraumtyp modul,
MODUL :
(* Dies Paket realisiert gezielte Zugriffe in einen Struct vom Typ MODUL.
Dies ist das Format eines SHard Moduls. Der Typ wird auch verwendet, um
das SHard-Hauptmodul oder einzelne ccbs zu handhaben!
Für die Adressierung der Bytes werden REAL-Werte verwendet, damit die
Größe nicht auf maxint beschränkt ist. Dies ist normalerweise sicher
(wegen der BCD-Arithmetik des Eumel), jedoch sind sinnlose nichtganzzahlige
Adressen dadurch möglich. Das wird aus Effizienzgründen nicht abgefangen,
die korrekte Benutzung liegt in der Verantwortung des Aufrufers.
Es sollen alle Zugriffe auf Module nur mit den Prozeduren dieses Pakets
abgewickelt werden.
*)
INT CONST high only ::-256,
low only :: 255;
LET max page = 128;
TYPE MODUL = STRUCT (ALIGN dummy, ROW 256 INT header,
ROW max page ROW 256 INT b,
INT dtcb abfragen, ccb abfragen,
TEXT dtcb ref, ccb ref, info);
(* Der Typ kann wegen des ALIGN direkt auf einen Datenraum (für ein Modul)
gelegt werden. Der Teil b fasst 64kB Daten und kann direkt für blockout
verwendet werden. Die restlichen Teile sind nur für Module relevant.
*)
INT CONST datenraumtyp modul :: 5687; (* Typ eines MODUL als Datenraum *)
(*********************** INT ********************************************)
INT PROC int (MODUL CONST m, REAL CONST byte nr) :
(* liefert das INT aus dem Modul m, das bei Byte "byte nr" beginnt *)
INT VAR page :: int (byte nr DIV 512.0) + 1,
nr :: int (byte nr MOD 512.0) DIV 2 + 1;
INT VAR whole int :: m.b[page][nr];
IF byte nr MOD 2.0 <> 0.0
THEN rotate (whole int, 8); (* high und low byte vertauschen *)
(whole int AND low only) + next byte in high
ELSE whole int FI.
next byte in high :
IF nr = 256 THEN nr := 1; page INCR 1 ELSE nr INCR 1 FI;
INT VAR help :: m.b[page][nr] AND low only;
rotate (help, 8);
help.
END PROC int;
INT PROC int (MODUL CONST m, INT CONST byte nr) :
int (m, real (byte nr))
END PROC int;
PROC int (MODUL VAR m, REAL CONST byte nr, INT CONST new) :
(* schreibt den neuen 16-Bit Wert new ab dem Byte "byte nr" in den Teil b
des Moduls m. Hier kommt es nicht sehr aufs Tempo an, deshalb benutzen
wir hier einfach "byte".
*)
INT VAR value :: new;
rotate (value, 8); (* high byte zu low byte machen *)
byte (m, byte nr, new AND low only);
byte (m, byte nr + 1.0, value AND low only);
END PROC int;
PROC int (MODUL VAR m, INT CONST byte nr, INT CONST new) :
int (m, real (byte nr), new)
END PROC int;
(************************** BYTE *******************************************)
INT PROC byte (MODUL CONST m, REAL CONST byte nr) :
(* liefert das Byte mit der Nummer "byte nr" aus dem Teil b des Moduls m.
Das erste Byte hat die Nummer 0
*)
INT CONST page :: int (byte nr DIV 512.0) + 1,
nr :: int (byte nr MOD 512.0) DIV 2 + 1;
INT VAR whole int :: m.b[page][nr];
IF byte nr MOD 2.0 <> 0.0
THEN rotate (whole int, 8); (* high und low byte vertauschen *) FI;
whole int AND low only.
END PROC byte;
INT PROC byte (MODUL CONST m, INT CONST byte nr) :
byte (m, real (byte nr))
END PROC byte;
PROC byte (MODUL VAR m, REAL CONST byte nr, INT CONST new) :
(* Schreibt die unteren 8 bit von new an das Byte der Stelle byte nr im
Modul m
*)
INT CONST page :: int (byte nr DIV 512.0) + 1,
nr :: int (byte nr MOD 512.0) DIV 2 + 1;
INT VAR new byte :: new AND low only,
whole int :: m.b[page][nr];
m.b[page][nr] := new int.
new int :
IF byte nr MOD 2.0 = 0.0 (* low byte ändern ? *)
THEN (whole int AND high only) + new byte
ELSE rotate (new byte, 8); (* new nach high rotieren *)
new byte + (whole int AND low only)
FI.
END PROC byte;
PROC byte (MODUL VAR m, INT CONST byte nr, INT CONST new) :
byte (m, real (byte nr), new)
END PROC byte;
(*********************** TEXT ********************************************)
TEXT PROC text (MODUL CONST m, REAL CONST first byte nr, INT CONST length) :
(* Extrahiert die naechsten length bytes aus m ab byte nr als TEXT *)
REAL VAR i :: first byte nr;
TEXT VAR result :: "";
WHILE i < first byte nr + real (length) REP
result CAT code (byte (m, i));
i INCR 1.0
PER;
result.
END PROC text;
TEXT PROC text (MODUL CONST m, INT CONST first byte nr, INT CONST length) :
text (m, real (first byte nr), length)
END PROC text;
(* Ein schreibendes Analogon zu "text" gibt es nicht. *)
(*********************** unsigned *****************************************)
REAL PROC unsigned (INT CONST sixteen bits) :
(* hiermit kann man die Vorzeichenprobleme umschiffen, die der Eumel bei
INTs über maxint macht.
Liefert das INT als 16-Bit unsigned Wert interpretiert im REAL-Format.
*)
real (text (sixteen bits, dec))
END PROC unsigned;
INT PROC unsigned (REAL CONST sixteen bit value) :
(* Umkehrung des obigen : REAL 0..65536 rein, passenden 16 bit unsigned
Wert raus
*)
TEXT CONST t :: text (sixteen bit value);
int (unsigned (value text)).
value text :
IF pos (t, ".") <> 0
THEN subtext (t, 1, pos (t, ".") - 1)
ELSE t
FI.
END PROC unsigned;
(******************** dtcb, ccb, info **************************************)
INT PROC dtcb abfragen (MODUL CONST m) :
m.dtcb abfragen
END PROC dtcb abfragen;
PROC dtcb abfragen (MODUL VAR m, INT CONST neu) :
m.dtcb abfragen := neu
END PROC dtcb abfragen;
TEXT PROC dtcb refinements (MODUL CONST m) :
m.dtcb ref
END PROC dtcb refinements;
PROC dtcb refinements (MODUL VAR m, TEXT CONST neu) :
m.dtcb ref := neu
END PROC dtcb refinements;
INT PROC ccb abfragen (MODUL CONST m) :
m.ccb abfragen
END PROC ccb abfragen;
PROC ccb abfragen (MODUL VAR m, INT CONST neu) :
m.ccb abfragen := neu
END PROC ccb abfragen;
TEXT PROC ccb refinements (MODUL CONST m) :
m.ccb ref
END PROC ccb refinements;
PROC ccb refinements (MODUL VAR m, TEXT CONST neu) :
m.ccb ref := neu
END PROC ccb refinements;
TEXT PROC info (MODUL CONST m) :
m.info
END PROC info;
PROC info (MODUL VAR m, TEXT CONST neu) :
m.info := neu
END PROC info;
(********************* page **********************************************)
(* Die Prozedur page dient dazu, aus dem Datenbereich b eines MODULs
einzelne Seiten (512 Byte Blöcke) in Form eines ROW 256 INT anzusprechen
um damit blockin/blockout zu machen.
Die Seitennummern gehen von 1 bis max page
*)
ROW 256 INT PROC page (MODUL CONST m, INT CONST page nr) :
m.b[page nr]
END PROC page;
PROC page (MODUL VAR m, INT CONST page nr, ROW 256 INT CONST new page) :
m.b[page nr] := new page
END PROC page;
(*********************** copy ********************************************)
PROC copy (MODUL CONST from, REAL CONST origin,
MODUL VAR to, REAL CONST destination, INT CONST length) :
(* Kopiert schnell eine Anzahl von Bytes aus einem Modul in ein anderes
die Optimierung klappt nur, wenn von einer geraden Adresse an eine
gerade Adresse kopiert wird oder von ungerade nach ungerade.
Macht cout.
*)
INT VAR i, interval :: cout interval;
REAL VAR offset :: 0.0;
IF length < 0 THEN errorstop ("copy : length = " + text (length)) FI;
IF origin MOD 2.0 <> destination MOD 2.0
THEN copy slow
ELSE copy fast FI;
cout (length).
cout interval :
IF length > 1024 THEN 32
ELIF length > 64 THEN 8
ELSE 1 FI.
copy slow :
FOR i FROM 1 UPTO length REP
IF i MOD 2*interval = 0 THEN cout (i) FI;
byte (to, destination + offset, byte (from, origin + offset));
offset INCR 1.0
PER.
copy fast :
IF origin MOD 2.0 <> 0.0 AND length > 0
THEN byte (to, destination, byte (from, origin));
offset := 1.0
FI;
FOR i FROM 1 UPTO (length - int (origin MOD 2.0)) DIV 2 REP
INT CONST page1 :: int ((origin+offset) DIV 512.0) + 1,
nr1 :: int ((origin+offset) MOD 512.0) DIV 2 + 1,
page2 :: int ((destination+offset) DIV 512.0) + 1,
nr2 :: int ((destination+offset) MOD 512.0) DIV 2 + 1;
to.b[page2][nr2] := from.b[page1][nr1];
IF i MOD interval = 0 THEN cout (2*i) FI;
offset INCR 2.0
PER;
IF length - int (offset) = 1
THEN byte (to, destination + offset, byte (from, origin + offset)) FI.
END PROC copy;
(************************ Hilfsprozeduren ********************************)
REAL OP DIV (REAL CONST a, b) :
floor (a/b)
END OP DIV;
END PACKET setup eumel modulzugriffe;
(**************************************************************************)
(***** Zugriffe in Module mit Strukturwissen ****************)
(***** Copyright (c) 1988 by ****************)
(***** Lutz Prechelt, Karlsruhe ****************)
(**************************************************************************)
PACKET setup eumel modul und shard zugriffe (* Copyright (c) 1988 by *)
DEFINES sh dtcb offset, (* Lutz Prechelt, Karlsruhe *)
sh ccb offset, (* Stand : 23.04.88 1.2 *)
get new channel table, (* Eumel 1.8.1 *)
init modules list,
all modules,
module type,
module name:
(* Dieses Paket definiert Operationen zum Zugriff auf bestimmte Daten in
SHardmodulen und SHards. Es ist hierin Wissen über die Struktur dieser
Teile enthalten.
Beschreibung des SHardformats siehe setup eumel 4: modulkonfiguration
*)
LET nr of channels total = 40,
offset channel table pointer = 10;
THESAURUS VAR all the beautiful modules we know :: emptythesaurus;
(******************* Kanaltabelle lesen/schreiben **************************)
(* Hier geht schöne Struktur (und damit zugleich einfache Programmierung)
über gute Performance. (Wir lesen einiges mehrfach)
*)
REAL PROC sh dtcb offset (MODUL CONST shard, INT CONST kanal) :
unsigned (int (shard, ct + 4 * kanal)).
ct :
int (shard, offset channel table pointer).
END PROC sh dtcb offset;
REAL PROC sh ccb offset (MODUL CONST shard, INT CONST kanal) :
unsigned (int (shard, ct + 4 * kanal + 2)).
ct :
int (shard, offset channel table pointer).
END PROC sh ccb offset;
PROC sh dtcb offset (MODUL VAR shard, INT CONST kanal, REAL CONST value) :
int (shard, ct + 4 * kanal, unsigned (value)).
ct :
int (shard, offset channel table pointer).
END PROC sh dtcb offset;
PROC sh ccb offset (MODUL VAR shard, INT CONST kanal, REAL CONST value) :
int (shard, ct + 4 * kanal + 2, unsigned (value)).
ct :
int (shard, offset channel table pointer).
END PROC sh ccb offset;
PROC get new channel table (MODUL CONST new shard,
ROW 256 INT VAR channel table of new shard) :
(* Kopiert die Kanaltabelle aus new shard nach
channel table of new shard
*)
INT VAR offset :: int (new shard, offset channel table pointer);
INT VAR i;
FOR i FROM 1 UPTO 2 * nr of channels total REP
channel table of new shard [i] := int (new shard, offset);
offset INCR 2
PER.
END PROC get new channel table;
(********************* modules list handling *****************************)
TEXT VAR m list;
PROC init modules list :
(* Baut in der Variablen m list einen "Assoziativspeicher" für
Modulnamen <--> Modultyp auf und erstellt eine Liste aller
Shardmoduldateinamen für "all modules"
Der Text m list enthält für jede Datei, die ein SHardmodul enthält,
einen Eintrag folgender Form :
""0"", modultyp, ""0"", Dateiname, ""0""
Dabei ist modultyp genau 4 Byte lang.
Diese Eintragsform ermöglicht ein (auf dem Eumel) sehr effizientes
Suchen, sowohl von Modultypen zu Modulnamen als auch umgekehrt.
Die Prozedur macht cout (dateinummer)
*)
INT VAR i;
TEXT VAR t;
m list := ""; all the beautiful modules we know := empty thesaurus;
FOR i FROM 1 UPTO highest entry (all) REP
cout (i);
t := name (all, i);
IF t <> "" CAND type (old (t)) = datenraumtyp modul
THEN add t FI
PER.
add t :
insert (all the beautiful modules we know, t);
TEXT CONST typ :: read module type (t);
m list cat typmarker;
m list CAT t;
m list CAT ""0"".
m list cat typmarker :
m list CAT ""0"";
m list CAT typ;
m list CAT ""0"".
END PROC init modules list;
THESAURUS PROC all modules :
all the beautiful modules we know.
END PROC all modules;
TEXT PROC read module type (TEXT CONST datei) :
(* Liefert den 4-Byte Modultyp des in der Datei datei enthaltenen
SHardmoduls, falls möglich, andernfalls ""
*)
IF NOT exists (datei) COR type (old (datei)) <> datenraumtyp modul
THEN ""
ELSE BOUND MODUL CONST m :: old (datei);
text (m, int (m, 8), 4)
FI.
END PROC read module type;
TEXT PROC module type (TEXT CONST module name) :
(* Liefert den 4-Byte Modultyp zu module name aus m list, sofern vorhanden
andernfalls ""
*)
INT CONST p :: pos (m list, ""0"" + module name + ""0"");
IF p = 0
THEN ""
ELSE subtext (m list, p - 4, p - 1) FI.
END PROC module type;
TEXT PROC module name (TEXT CONST module type) :
(* Liefert den Moduldateinamen zum 4-Byte Modultyp module type, oder
"" falls kein solches Modul vorhanden.
*)
INT VAR p :: pos (m list, ""0"" + module type + ""0"");
IF p = 0
THEN ""
ELSE p INCR 6;
subtext (m list, p, pos (m list, ""0"", p) - 1)
FI.
END PROC module name;
END PACKET setup eumel modul und shard zugriffe;
|