OpenCores
URL https://opencores.org/ocsvn/eco32/eco32/trunk

Subversion Repositories eco32

[/] [eco32/] [trunk/] [fp/] [implementation/] [mmix/] [mmotype.w] - Blame information for rev 15

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 15 hellwig
% This file is part of the MMIXware package (c) Donald E Knuth 1999
2
@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
3
 
4
\def\title{MMOTYPE}
5
\def\MMIX{\.{MMIX}}
6
\def\MMIXAL{\.{MMIXAL}}
7
\def\Hex#1{\hbox{$^{\scriptscriptstyle\#}$\tt#1}} % experimental hex constant
8
 
9
@* Introduction. This program reads a binary \.{mmo} file output by
10
the \MMIXAL\ processor and lists it in human-readable form. It lists
11
only the symbol table, if invoked with the \.{-s} option. It lists
12
also the tetrabytes of input, if invoked with the \.{-v} option.
13
 
14
@s tetra int
15
 
16
@c
17
#include 
18
#include 
19
#include 
20
#include 
21
@@;
22
@@;
23
@@;
24
@@;
25
@#
26
int main(argc,argv)
27
  int argc;@+char*argv[];
28
{
29
  register int j,delta,postamble=0;
30
  register char *p;
31
  @;
32
  @;
33
  @;
34
  do @@;@+while (!postamble);
35
  @;
36
  @;
37
  return 0;
38
}
39
 
40
@ @=
41
listing=1, verbose=0;
42
for (j=1;j
43
  if (argv[j][1]=='s') listing=0;
44
  else if (argv[j][1]=='v') verbose=1;
45
  else break;
46
}
47
if (j!=argc-1) {
48
  fprintf(stderr,"Usage: %s [-s] [-v] mmofile\n",argv[0]);
49
@.Usage: ...@>
50
  exit(-1);
51
}
52
 
53
@ @=
54
mmo_file=fopen(argv[argc-1],"rb");
55
if (!mmo_file) {
56
  fprintf(stderr,"Can't open file %s!\n",argv[argc-1]);
57
@.Can't open...@>
58
  exit(-2);
59
}
60
 
61
@ @=
62
int listing; /* are we listing everything? */
63
int verbose; /* are we also showing the tetras of input as they are read? */
64
FILE *mmo_file; /* the input file */
65
 
66
@ @=
67
#ifdef __STDC__
68
#define ARGS(list) list
69
#else
70
#define ARGS(list) ()
71
#endif
72
 
73
@ A complete definition of \.{mmo} format appears in the \MMIXAL\ document.
74
Here we need to define only the basic constants used for interpretation.
75
 
76
@d mm 0x98 /* the escape code of \.{mmo} format */
77
@d lop_quote 0x0 /* the quotation lopcode */
78
@d lop_loc 0x1 /* the location lopcode */
79
@d lop_skip 0x2 /* the skip lopcode */
80
@d lop_fixo 0x3 /* the octabyte-fix lopcode */
81
@d lop_fixr 0x4 /* the relative-fix lopcode */
82
@d lop_fixrx 0x5 /* extended relative-fix lopcode */
83
@d lop_file 0x6 /* the file name lopcode */
84
@d lop_line 0x7 /* the file position lopcode */
85
@d lop_spec 0x8 /* the special hook lopcode */
86
@d lop_pre 0x9 /* the preamble lopcode */
87
@d lop_post 0xa /* the postamble lopcode */
88
@d lop_stab 0xb /* the symbol table lopcode */
89
@d lop_end 0xc /* the end-it-all lopcode */
90
 
91
@* Low-level arithmetic. This program is intended to work correctly
92
whenever an |int| has at least 32 bits.
93
 
94
@=
95
typedef unsigned char byte; /* a monobyte */
96
typedef unsigned int tetra; /* a tetrabyte */
97
typedef struct {@+tetra h,l;}@+octa; /* an octabyte */
98
 
99
@ The |incr| subroutine adds a signed integer to an (unsigned) octabyte.
100
 
101
@=
102
octa incr @,@,@[ARGS((octa,int))@];
103
octa incr(o,delta)
104
  octa o;
105
  int delta;
106
{
107
  register tetra t;
108
  octa x;
109
  if (delta>=0) {
110
    t=0xffffffff-delta;
111
    if (o.l<=t) x.l=o.l+delta, x.h=o.h;
112
    else x.l=o.l-t-1, x.h=o.h+1;
113
  } else {
114
    t=-delta;
115
    if (o.l>=t) x.l=o.l-t, x.h=o.h;
116
    else x.l=o.l+(0xffffffff+delta)+1, x.h=o.h-1;
117
  }
118
  return x;
119
}
120
 
121
@* Low-level input. The tetrabytes of an \.{mmo} file are stored in
122
friendly big-endian fashion, but this program is supposed to work also
123
on computers that are little-endian. Therefore we read four successive bytes
124
and pack them into a tetrabyte, instead of reading a single tetrabyte.
125
 
126
@=
127
void read_tet @,@,@[ARGS((void))@];
128
void read_tet()
129
{
130
  if (fread(buf,1,4,mmo_file)!=4) {
131
    fprintf(stderr,"Unexpected end of file after %d tetras!\n",count);
132
@.Unexpected end of file...@>
133
    exit(-3);
134
  }
135
  yz=(buf[2]<<8)+buf[3];
136
  tet=(((buf[0]<<8)+buf[1])<<16)+yz;
137
  if (verbose) printf("  %08x\n",tet);
138
  count++;
139
}
140
 
141
@ @=
142
byte read_byte @,@,@[ARGS((void))@];
143
byte read_byte()
144
{
145
  register byte b;
146
  if (!byte_count) read_tet();
147
  b=buf[byte_count];
148
  byte_count=(byte_count+1)&3;
149
  return b;
150
}
151
 
152
@ @=
153
int count; /* the number of tetrabytes we've read */
154
int byte_count; /* index of the next-to-be-read byte */
155
byte buf[4]; /* the most recently read bytes */
156
int yz; /* the two least significant bytes */
157
tetra tet; /* |buf| bytes packed big-endianwise */
158
 
159
@ @=
160
count=byte_count=0;
161
 
162
@* The main loop. Now for the bread-and-butter part of this program.
163
 
164
@=
165
{
166
  read_tet();
167
 loop:@+if (buf[0]==mm) switch (buf[1]) {
168
   case lop_quote:@+if (yz!=1)
169
       err("YZ field of lop_quote should be 1");
170
@.YZ field...should be 1@>
171
    read_tet();@+break;
172
   @t\4@>@@;
173
   default: err("Unknown lopcode");
174
@.Unknown lopcode@>
175
  }
176
  if (listing) @;
177
}
178
 
179
@ We want to catch all cases where the rules of \.{mmo} format are
180
not obeyed. The |err| macro ameliorates this somewhat tedious chore.
181
 
182
@d err(m) {@+fprintf(stderr,"Error in tetra %d: %s!\n",count,m);@+ continue;@+}
183
@.Error in tetra...@>
184
 
185
@ In a normal situation, the newly read tetrabyte is simply supposed
186
to be loaded into the current location. We list not only the current
187
location but also the current file position, if |cur_line| is nonzero
188
and |cur_loc| belongs to segment~0.
189
 
190
@=
191
{
192
  printf("%08x%08x: %08x",cur_loc.h,cur_loc.l,tet);
193
  if (!cur_line) printf("\n");
194
  else {
195
    if (cur_loc.h&0xe0000000) printf("\n");
196
    else {
197
      if (cur_file==listed_file) printf(" (line %d)\n",cur_line);
198
      else {
199
        printf(" (\"%s\", line %d)\n", file_name[cur_file], cur_line);
200
        listed_file=cur_file;
201
      }
202
    }
203
    cur_line++;
204
  }
205
  cur_loc=incr(cur_loc,4);@+ cur_loc.l &=-4;
206
}
207
 
208
@ @=
209
octa cur_loc; /* the current location */
210
int listed_file; /* the most recently listed file number */
211
int cur_file; /* the most recently selected file number */
212
int cur_line; /* the current position in |cur_file| */
213
char *file_name[256]; /* file names seen */
214
octa tmp; /* an octabyte of temporary interest */
215
 
216
@ @=
217
cur_loc.h=cur_loc.l=0;
218
listed_file=cur_file=-1;
219
cur_line=0;
220
 
221
@* The simple lopcodes. We have already implemented |lop_quote|, which
222
falls through to the normal case after reading an extra tetrabyte.
223
Now let's consider the other lopcodes in turn.
224
 
225
@d y buf[2] /* the next-to-least significant byte */
226
@d z buf[3] /* the least significant byte */
227
 
228
@=
229
case lop_loc:@+if (z==2) {
230
   j=y;@+ read_tet();@+ cur_loc.h=(j<<24)+tet;
231
 }@+else if (z==1) cur_loc.h=y<<24;
232
 else err("Z field of lop_loc should be 1 or 2");
233
@:Z field of lop_loc...}\.{Z field of lop\_loc...@>
234
 read_tet();@+ cur_loc.l=tet;
235
 continue;
236
case lop_skip: cur_loc=incr(cur_loc,yz);@+continue;
237
 
238
@ Fixups load information out of order, when future references have
239
been resolved. The current file name and line number are not considered
240
relevant.
241
 
242
@=
243
case lop_fixo:@+if (z==2) {
244
   j=y;@+ read_tet();@+ tmp.h=(j<<24)+tet;
245
 }@+else if (z==1) tmp.h=y<<24;
246
 else err("Z field of lop_fixo should be 1 or 2");
247
@:Z field of lop_fixo...}\.{Z field of lop\_fixo...@>
248
 read_tet();@+ tmp.l=tet;
249
 if (listing) printf("%08x%08x: %08x%08x\n",tmp.h,tmp.l,cur_loc.h,cur_loc.l);
250
 continue;
251
case lop_fixr: delta=yz; goto fixr;
252
case lop_fixrx:j=yz;@+if (j!=16 && j!=24)
253
    err("YZ field of lop_fixrx should be 16 or 24");
254
@:YZ field of lop_fixrx...}\.{YZ field of lop\_fixrx...@>
255
 read_tet(); delta=tet;
256
 if (delta&0xfe000000) err("increment of lop_fixrx is too large");
257
@.increment...too large@>
258
fixr: tmp=incr(cur_loc,-(delta>=0x1000000? (delta&0xffffff)-(1<
259
 if (listing) printf("%08x%08x: %08x\n",tmp.h,tmp.l,delta);
260
 continue;
261
 
262
@ The space for file names isn't allocated until we are sure we need it.
263
 
264
@=
265
case lop_file:@+if (file_name[y]) {
266
   for (j=z;j>0;j--) read_tet();
267
   cur_file=y;
268
   if (z) err("Two file names with the same number");
269
@.Two file names...@>
270
 }@+else {
271
   if (!z) err("No name given for newly selected file");
272
@.No name given...@>
273
   file_name[y]=(char*)calloc(4*z+1,1);
274
   if (!file_name[y]) {
275
     fprintf(stderr,"No room to store the file name!\n");@+exit(-4);
276
@.No room...@>
277
   }
278
   cur_file=y;
279
   for (j=z,p=file_name[y]; j>0; j--,p+=4) {
280
     read_tet();
281
     *p=buf[0];@+*(p+1)=buf[1];@+*(p+2)=buf[2];@+*(p+3)=buf[3];
282
   }
283
 }
284
 cur_line=0;@+continue;
285
case lop_line:@+if (cur_file<0) err("No file was selected for lop_line");
286
@.No file was selected...@>
287
 cur_line=yz;@+continue;
288
 
289
@ Special bytes in the file might be in synch with the current location
290
and/or the current file position, so we list those parameters too.
291
 
292
@=
293
case lop_spec:@+if (listing) {
294
   printf("Special data %d at loc %08x%08x", yz, cur_loc.h, cur_loc.l);
295
   if (!cur_line) printf("\n");
296
   else if (cur_file==listed_file) printf(" (line %d)\n",cur_line);
297
   else {
298
     printf(" (\"%s\", line %d)\n", file_name[cur_file], cur_line);
299
     listed_file=cur_file;
300
   }
301
 }
302
 while(1) {
303
   read_tet();
304
   if (buf[0]==mm) {
305
     if (buf[1]!=lop_quote || yz!=1) goto loop; /* end of special data */
306
     read_tet();
307
   }
308
   if (listing) printf("                   %08x\n",tet);
309
 }
310
 
311
@ The other cases shouldn't appear in the main loop.
312
 
313
@=
314
case lop_pre: err("Can't have another preamble");
315
@.Can't have another...@>
316
case lop_post: postamble=1;
317
 if (y) err("Y field of lop_post should be zero");
318
@:Y field of lop_post...}\.{Y field of lop\_post...@>
319
 if (z<32) err("Z field of lop_post must be 32 or more");
320
@:Z field of lop_post...}\.{Z field of lop\_post...@>
321
 continue;
322
case lop_stab: err("Symbol table must follow postamble");
323
@.Symbol table...@>
324
case lop_end: err("Symbol table can't end before it begins");
325
 
326
@* The preamble and postamble. Now here's what we do before and after
327
the main loop.
328
 
329
@=
330
read_tet(); /* read the first tetrabyte of input */
331
if (buf[0]!=mm || buf[1]!=lop_pre) {
332
  fprintf(stderr,"Input is not an MMO file (first two bytes are wrong)!\n");
333
@.Input is not...@>
334
  exit(-5);
335
}
336
if (y!=1) fprintf(stderr,
337
    "Warning: I'm reading this file as version 1, not version %d!\n",y);
338
@.I'm reading this file...@>
339
if (z>0) {
340
  j=z;
341
  read_tet();
342
  if (listing)
343
    printf("File was created %s",asctime(localtime((time_t*)&tet)));
344
  for (j--;j>0;j--) {
345
    read_tet();
346
    if (listing) printf("Preamble data %08x\n",tet);
347
  }
348
}
349
 
350
@ @=
351
for (j=z;j<256;j++) {
352
  read_tet();@+tmp.h=tet;@+read_tet();
353
  if (listing) {
354
    if (tmp.h || tet) printf("g%03d: %08x%08x\n",j,tmp.h,tet);
355
    else printf("g%03d: 0\n",j);
356
  }
357
}
358
 
359
@* The symbol table. Finally we come to the symbol table, which is
360
the most interesting part of this program because it recursively
361
traces an implicit ternary trie structure.
362
 
363
@=
364
read_tet();
365
if (buf[0]!=mm || buf[1]!=lop_stab) {
366
  fprintf(stderr,"Symbol table does not follow the postamble!\n");
367
@.Symbol table...@>
368
  exit(-6);
369
}
370
if (yz) fprintf(stderr,"YZ field of lop_stab should be zero!\n");
371
@.YZ field...should be zero@>
372
printf("Symbol table (beginning at tetra %d):\n",count);
373
stab_start=count;
374
sym_ptr=sym_buf;
375
print_stab();
376
@;
377
 
378
@ The main work is done by a recursive subroutine called |print_stab|,
379
which manipulates a global array |sym_buf| containing the current
380
symbol prefix; the global variable |sym_ptr| points to the first
381
unfilled character of that array.
382
 
383
@=
384
void print_stab @,@,@[ARGS((void))@];
385
void print_stab()
386
{
387
  register int m=read_byte(); /* the master control byte */
388
  register int c; /* the character at the current trie node */
389
  register int j,k;
390
  if (m&0x40) print_stab(); /* traverse the left subtrie, if it is nonempty */
391
  if (m&0x2f) {
392
    @;
393
    *sym_ptr++=c;
394
    if (sym_ptr==&sym_buf[sym_length_max]) {
395
      fprintf(stderr,"Oops, the symbol is too long!\n");@+exit(-7);
396
@.Oops...too long@>
397
    }
398
    if (m&0xf)
399
      @;
400
    if (m&0x20) print_stab(); /* traverse the middle subtrie */
401
    sym_ptr--;
402
  }
403
  if (m&0x10) print_stab(); /* traverse the right subtrie, if it is nonempty */
404
}
405
 
406
@ The present implementation doesn't support Unicode; characters with
407
more than 8-bit codes are printed as `\.?'. However, the changes
408
for 16-bit codes would be quite easy if proper fonts for Unicode output
409
were available. In that case, |sym_buf| would be an array of wyde characters.
410
@^Unicode@>
411
@^system dependencies@>
412
 
413
@=
414
if (m&0x80) j=read_byte(); /* 16-bit character */
415
else j=0;
416
c=read_byte();
417
if (j) c='?'; /* oops, we can't print |(j<<8)+c| easily at this time */
418
 
419
@ @=
420
{
421
  *sym_ptr='\0';
422
  j=m&0xf;
423
  if (j==15) sprintf(equiv_buf,"$%03d",read_byte());
424
  else if (j<=8) {
425
    strcpy(equiv_buf,"#");
426
    for (;j>0;j--) sprintf(equiv_buf+strlen(equiv_buf),"%02x",read_byte());
427
    if (strcmp(equiv_buf,"#0000")==0) strcpy(equiv_buf,"?"); /* undefined */
428
  }@+else {
429
    strncpy(equiv_buf,"#20000000000000",33-2*j);
430
    equiv_buf[33-2*j]='\0';
431
    for (;j>8;j--) sprintf(equiv_buf+strlen(equiv_buf),"%02x",read_byte());
432
  }
433
  for (j=k=read_byte();; k=read_byte(),j=(j<<7)+k) if (k>=128) break;
434
    /* the serial number is now $j-128$ */
435
  printf("    %s = %s (%d)\n",sym_buf+1,equiv_buf,j-128);
436
}
437
 
438
@ @d sym_length_max 1000
439
 
440
@=
441
int stab_start; /* where the symbol table began */
442
char sym_buf[sym_length_max];
443
   /* the characters on middle transitions to current node */
444
char *sym_ptr; /* the character in |sym_buf| following the current prefix */
445
char equiv_buf[20]; /* equivalent of the current symbol */
446
 
447
@ @=
448
while (byte_count)
449
  if (read_byte()) fprintf(stderr,"Nonzero byte follows the symbol table!\n");
450
@.Nonzero byte follows...@>
451
read_tet();
452
if (buf[0]!=mm || buf[1]!=lop_end)
453
  fprintf(stderr,"The symbol table isn't followed by lop_end!\n");
454
@.The symbol table isn't...@>
455
else if (count!=stab_start+yz+1)
456
  fprintf(stderr,"YZ field at lop_end should have been %d!\n",count-yz-1);
457
@:YZ field at lop_end...}\.{YZ field at lop\_end...@>
458
else {
459
  if (verbose) printf("Symbol table ends at tetra %d.\n",count);
460
  if (fread(buf,1,1,mmo_file))
461
    fprintf(stderr,"Extra bytes follow the lop_end!\n");
462
@.Extra bytes follow...@>
463
}
464
 
465
 
466
@* Index.

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.