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

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.61/] [tools/] [bin/] [asm-11] - Blame information for rev 40

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 19 wfjm
#!/usr/bin/perl -w
2 25 wfjm
# $Id: asm-11 575 2014-07-27 20:55:41Z mueller $
3 19 wfjm
#
4 25 wfjm
# Copyright 2013-2014 by Walter F.J. Mueller 
5 19 wfjm
#
6
# This program is free software; you may redistribute and/or modify it under
7
# the terms of the GNU General Public License as published by the Free
8
# Software Foundation, either version 2, or at your option any later version.
9
#
10
# This program is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
12
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13
# for complete details.
14
#
15
#  Revision History:
16
# Date         Rev Version  Comment
17 25 wfjm
# 2014-07-26   575   1.0.3  add 'call' and 'return' to pst (as in macro-11)
18 19 wfjm
# 2013-04-07   503   1.0.2  list dot for .even,.dot,.blkb,.blkw
19
# 2013-04-01   502   1.0.1  BUGFIX: -2(r0),@-2(r0) was broken, parser fixed
20
#                           add -lsm (lsmem format) output; add implicit .word
21
# 2013-03-29   501   1.0    Initial version
22
# 2013-03-22   498   0.5    Second draft (functional, but limited...)
23
# 2013-03-07   496   0.1    First draft
24
#
25
 
26
use 5.10.0;                                 # require Perl 5.10 or higher
27
use strict;                                 # require strict checking
28
use FileHandle;
29
 
30
use Getopt::Long;
31
 
32
use constant TMASK_STRING     => 0x0001;
33
use constant TMASK_STRINGEXP  => 0x0002;
34
 
35
my %opts = ();
36
 
37
GetOptions(\%opts, "help",
38
                   "tpass1", "tpass2",
39
                   "dsym1",  "dsym2",
40
                   "ttoken", "tparse", "temit", "tout",
41
                   "I=s@",
42
                   "lst", "olst=s",
43
                   "lda", "olda=s",
44
                   "cof", "ocof=s",
45
                   "lsm", "olsm=s"
46
          )
47
  or exit 1;
48
 
49
unshift @{$opts{I}}, ".";                  # ./ is first in include path
50
push @{$opts{I}}, "$ENV{RETROBASE}/tools/asm-11" if defined $ENV{RETROBASE};
51
 
52
sub create_fname;
53
sub read_file;
54
sub parse_line;
55
sub walign;
56
sub add_err;
57
sub prt_err;
58
sub setdot;
59
sub incdot;
60
sub getdot;
61
sub setsym;
62
sub getsym;
63
sub lst_checkmdef;
64
sub eval_exp;
65
sub check_llbl;
66
sub check_reg;
67
sub check_token;
68
sub pushback_token;
69
sub get_token;
70
sub get_token1;
71
sub to_rad50;
72
sub pass2;
73
sub pass2_out;
74
sub pass2_lst_beg;
75
sub pass2_lst_end;
76
sub pass2_lst_line;
77
sub out_w;
78
sub out_b;
79
sub out_opcode;
80
sub out_opcode_n;
81
sub out_opcode_o;
82
sub out_opdata;
83
sub emitw;
84
sub emitb;
85
sub write_lda;
86
sub write_cof;
87
sub write_lsm;
88
sub dump_rl;
89
sub dump_sym;
90
sub prt76o;
91
sub prt43o;
92
sub save66o;
93
sub savestr;
94
sub savestr1;
95
sub print_help;
96
 
97
# Permanant symbol table
98
my %pst = (
99
# directives
100
 '.include' => {typ=>'dir'},                #
101
 '.word'    => {typ=>'dir'},                #
102
 '.byte'    => {typ=>'dir'},                #
103
 '.blkw'    => {typ=>'dir'},                #
104
 '.blkb'    => {typ=>'dir'},                #
105
 '.ascii'   => {typ=>'dir'},                #
106
 '.asciz'   => {typ=>'dir'},                #
107
 '.even'    => {typ=>'dir'},                #
108
 '.odd'     => {typ=>'dir'},                #
109
 '.asect'   => {typ=>'dir'},                #
110
 '.end'     => {typ=>'dir'},                #
111
#register defs
112
 'r0'     => {typ=>'reg', val=>0},
113
 'r1'     => {typ=>'reg', val=>1},
114
 'r2'     => {typ=>'reg', val=>2},
115
 'r3'     => {typ=>'reg', val=>3},
116
 'r4'     => {typ=>'reg', val=>4},
117
 'r5'     => {typ=>'reg', val=>5},
118
 'sp'     => {typ=>'reg', val=>6},
119
 'pc'     => {typ=>'reg', val=>7},
120
#opcodes
121
 'halt'   => {typ=>'op', val=>0000000, fmt=>'-'  },
122
 'wait'   => {typ=>'op', val=>0000001, fmt=>'-'  },
123
 'rti'    => {typ=>'op', val=>0000002, fmt=>'-'  },
124
 'bpt'    => {typ=>'op', val=>0000003, fmt=>'-'  },
125
 'iot'    => {typ=>'op', val=>0000004, fmt=>'-'  },
126
 'reset'  => {typ=>'op', val=>0000005, fmt=>'-'  },
127
 'rtt'    => {typ=>'op', val=>0000006, fmt=>'-'  },
128
 'mfpt'   => {typ=>'op', val=>0000007, fmt=>'-'  },
129
 'jmp'    => {typ=>'op', val=>0000100, fmt=>'g'  },
130
 'rts'    => {typ=>'op', val=>0000200, fmt=>'r'  },
131 25 wfjm
 'return' => {typ=>'op', val=>0000207, fmt=>'-'  }, # alias for rts pc
132 19 wfjm
 'spl'    => {typ=>'op', val=>0000230, fmt=>'n3' },
133
 'nop'    => {typ=>'op', val=>0000240, fmt=>'-'  },
134
 'clc'    => {typ=>'op', val=>0000241, fmt=>'-'  },
135
 'clv'    => {typ=>'op', val=>0000242, fmt=>'-'  },
136
 'clz'    => {typ=>'op', val=>0000244, fmt=>'-'  },
137
 'cln'    => {typ=>'op', val=>0000250, fmt=>'-'  },
138
 'ccc'    => {typ=>'op', val=>0000257, fmt=>'-'  },
139
 'sec'    => {typ=>'op', val=>0000261, fmt=>'-'  },
140
 'sev'    => {typ=>'op', val=>0000262, fmt=>'-'  },
141
 'sez'    => {typ=>'op', val=>0000264, fmt=>'-'  },
142
 'sen'    => {typ=>'op', val=>0000270, fmt=>'-'  },
143
 'scc'    => {typ=>'op', val=>0000277, fmt=>'-'  },
144
 'swab'   => {typ=>'op', val=>0000300, fmt=>'g'  },
145
 'br'     => {typ=>'op', val=>0000400, fmt=>'s8' },
146
 'bne'    => {typ=>'op', val=>0001000, fmt=>'s8' },
147
 'beq'    => {typ=>'op', val=>0001400, fmt=>'s8' },
148
 'bge'    => {typ=>'op', val=>0002000, fmt=>'s8' },
149
 'blt'    => {typ=>'op', val=>0002400, fmt=>'s8' },
150
 'bgt'    => {typ=>'op', val=>0003000, fmt=>'s8' },
151
 'ble'    => {typ=>'op', val=>0003400, fmt=>'s8' },
152
 'jsr'    => {typ=>'op', val=>0004000, fmt=>'rg' },
153 25 wfjm
 'call'   => {typ=>'op', val=>0004700, fmt=>'g'  }, # alias for jsr pc,
154 19 wfjm
 'clr'    => {typ=>'op', val=>0005000, fmt=>'g'  },
155
 'com'    => {typ=>'op', val=>0005100, fmt=>'g'  },
156
 'inc'    => {typ=>'op', val=>0005200, fmt=>'g'  },
157
 'dec'    => {typ=>'op', val=>0005300, fmt=>'g'  },
158
 'neg'    => {typ=>'op', val=>0005400, fmt=>'g'  },
159
 'adc'    => {typ=>'op', val=>0005500, fmt=>'g'  },
160
 'sbc'    => {typ=>'op', val=>0005600, fmt=>'g'  },
161
 'tst'    => {typ=>'op', val=>0005700, fmt=>'g'  },
162
 'ror'    => {typ=>'op', val=>0006000, fmt=>'g'  },
163
 'rol'    => {typ=>'op', val=>0006100, fmt=>'g'  },
164
 'asr'    => {typ=>'op', val=>0006200, fmt=>'g'  },
165
 'asl'    => {typ=>'op', val=>0006300, fmt=>'g'  },
166
 'mark'   => {typ=>'op', val=>0006400, fmt=>'n6' },
167
 'mfpi'   => {typ=>'op', val=>0006500, fmt=>'g'  },
168
 'mtpi'   => {typ=>'op', val=>0006600, fmt=>'g'  },
169
 'sxt'    => {typ=>'op', val=>0006700, fmt=>'g'  },
170
 'csm'    => {typ=>'op', val=>0007000, fmt=>'g'  },
171
 'tstset' => {typ=>'op', val=>0007200, fmt=>'g'  },
172
 'wrtlck' => {typ=>'op', val=>0007300, fmt=>'g'  },
173
 'mov'    => {typ=>'op', val=>0010000, fmt=>'gg' },
174
 'cmp'    => {typ=>'op', val=>0020000, fmt=>'gg' },
175
 'bit'    => {typ=>'op', val=>0030000, fmt=>'gg' },
176
 'bic'    => {typ=>'op', val=>0040000, fmt=>'gg' },
177
 'bis'    => {typ=>'op', val=>0050000, fmt=>'gg' },
178
 'add'    => {typ=>'op', val=>0060000, fmt=>'gg' },
179
 'mul'    => {typ=>'op', val=>0070000, fmt=>'gr' },
180
 'div'    => {typ=>'op', val=>0071000, fmt=>'gr' },
181
 'ash'    => {typ=>'op', val=>0072000, fmt=>'gr' },
182
 'ashc'   => {typ=>'op', val=>0073000, fmt=>'gr' },
183
 'xor'    => {typ=>'op', val=>0074000, fmt=>'rg' },
184
 'sob'    => {typ=>'op', val=>0077000, fmt=>'ru6'},
185
 'bpl'    => {typ=>'op', val=>0100000, fmt=>'s8' },
186
 'bmi'    => {typ=>'op', val=>0100400, fmt=>'s8' },
187
 'bhi'    => {typ=>'op', val=>0101000, fmt=>'s8' },
188
 'blos'   => {typ=>'op', val=>0101400, fmt=>'s8' },
189
 'bvc'    => {typ=>'op', val=>0102000, fmt=>'s8' },
190
 'bvs'    => {typ=>'op', val=>0102400, fmt=>'s8' },
191
 'bcc'    => {typ=>'op', val=>0103000, fmt=>'s8' },
192
 'bhis'   => {typ=>'op', val=>0103000, fmt=>'s8' }, #alias
193
 'bcs'    => {typ=>'op', val=>0103400, fmt=>'s8' },
194
 'blo'    => {typ=>'op', val=>0103400, fmt=>'s8' }, #alias
195
 'emt'    => {typ=>'op', val=>0104000, fmt=>'n8' },
196
 'trap'   => {typ=>'op', val=>0104400, fmt=>'n8' },
197
 'clrb'   => {typ=>'op', val=>0105000, fmt=>'g'  },
198
 'comb'   => {typ=>'op', val=>0105100, fmt=>'g'  },
199
 'incb'   => {typ=>'op', val=>0105200, fmt=>'g'  },
200
 'decb'   => {typ=>'op', val=>0105300, fmt=>'g'  },
201
 'negb'   => {typ=>'op', val=>0105400, fmt=>'g'  },
202
 'adcb'   => {typ=>'op', val=>0105500, fmt=>'g'  },
203
 'sbcb'   => {typ=>'op', val=>0105600, fmt=>'g'  },
204
 'tstb'   => {typ=>'op', val=>0105700, fmt=>'g'  },
205
 'rorb'   => {typ=>'op', val=>0106000, fmt=>'g'  },
206
 'rolb'   => {typ=>'op', val=>0106100, fmt=>'g'  },
207
 'asrb'   => {typ=>'op', val=>0106200, fmt=>'g'  },
208
 'aslb'   => {typ=>'op', val=>0106300, fmt=>'g'  },
209
 'mtps'   => {typ=>'op', val=>0106400, fmt=>'g'  },
210
 'mfpd'   => {typ=>'op', val=>0106500, fmt=>'g'  },
211
 'mtpd'   => {typ=>'op', val=>0106600, fmt=>'g'  },
212
 'mfps'   => {typ=>'op', val=>0106700, fmt=>'g'  },
213
 'movb'   => {typ=>'op', val=>0110000, fmt=>'gg' },
214
 'cmpb'   => {typ=>'op', val=>0120000, fmt=>'gg' },
215
 'bitb'   => {typ=>'op', val=>0130000, fmt=>'gg' },
216
 'bicb'   => {typ=>'op', val=>0140000, fmt=>'gg' },
217
 'bisb'   => {typ=>'op', val=>0150000, fmt=>'gg' },
218
 'sub'    => {typ=>'op', val=>0160000, fmt=>'gg' },
219
 'cfcc'   => {typ=>'op', val=>0170000, fmt=>'-'  ,fpp=>1 },
220
 'setf'   => {typ=>'op', val=>0170001, fmt=>'-'  ,fpp=>1 },
221
 'setd'   => {typ=>'op', val=>0170011, fmt=>'-'  ,fpp=>1 },
222
 'seti'   => {typ=>'op', val=>0170002, fmt=>'-'  ,fpp=>1 },
223
 'setl'   => {typ=>'op', val=>0170012, fmt=>'-'  ,fpp=>1 },
224
 'ldfps'  => {typ=>'op', val=>0170100, fmt=>'g'  ,fpp=>1 },
225
 'stfps'  => {typ=>'op', val=>0170200, fmt=>'g'  ,fpp=>1 },
226
 'stst'   => {typ=>'op', val=>0170300, fmt=>'g'  ,fpp=>1 },
227
 'clrf'   => {typ=>'op', val=>0170400, fmt=>'g'  ,fpp=>1 },
228
 'clrd'   => {typ=>'op', val=>0170400, fmt=>'g'  ,fpp=>1 }, # alias
229
 'tstf'   => {typ=>'op', val=>0170500, fmt=>'g'  ,fpp=>1 },
230
 'tstd'   => {typ=>'op', val=>0170500, fmt=>'g'  ,fpp=>1 }, # alias
231
 'absf'   => {typ=>'op', val=>0170600, fmt=>'g'  ,fpp=>1 },
232
 'absd'   => {typ=>'op', val=>0170600, fmt=>'g'  ,fpp=>1 }, # alias
233
 'negf'   => {typ=>'op', val=>0170700, fmt=>'g'  ,fpp=>1 },
234
 'negd'   => {typ=>'op', val=>0170700, fmt=>'g'  ,fpp=>1 }, # alias
235
 'mulf'   => {typ=>'op', val=>0171000, fmt=>'gr' ,fpp=>1 },
236
 'muld'   => {typ=>'op', val=>0171000, fmt=>'gr' ,fpp=>1 }, # alias
237
 'modf'   => {typ=>'op', val=>0171400, fmt=>'gr' ,fpp=>1 },
238
 'modd'   => {typ=>'op', val=>0171400, fmt=>'gr' ,fpp=>1 }, # alias
239
 'addf'   => {typ=>'op', val=>0172000, fmt=>'gr' ,fpp=>1 },
240
 'addd'   => {typ=>'op', val=>0172000, fmt=>'gr' ,fpp=>1 }, # alias
241
 'ldf'    => {typ=>'op', val=>0172400, fmt=>'gr' ,fpp=>1 },
242
 'ldd'    => {typ=>'op', val=>0172400, fmt=>'gr' ,fpp=>1 }, # alias
243
 'subf'   => {typ=>'op', val=>0173000, fmt=>'gr' ,fpp=>1 },
244
 'subd'   => {typ=>'op', val=>0173000, fmt=>'gr' ,fpp=>1 }, # alias
245
 'cmpf'   => {typ=>'op', val=>0173400, fmt=>'gr' ,fpp=>1 },
246
 'cmpd'   => {typ=>'op', val=>0173400, fmt=>'gr' ,fpp=>1 }, # alias
247
 'stf'    => {typ=>'op', val=>0174000, fmt=>'rg' ,fpp=>1 },
248
 'std'    => {typ=>'op', val=>0174000, fmt=>'rg' ,fpp=>1 }, # alias
249
 'divf'   => {typ=>'op', val=>0174400, fmt=>'gr' ,fpp=>1 },
250
 'divd'   => {typ=>'op', val=>0174400, fmt=>'gr' ,fpp=>1 }, # alias
251
 'stexp'  => {typ=>'op', val=>0175000, fmt=>'rg' ,fpp=>1 },
252
 'stcfi'  => {typ=>'op', val=>0175400, fmt=>'rg' ,fpp=>1 },
253
 'stcfl'  => {typ=>'op', val=>0175400, fmt=>'rg' ,fpp=>1 }, # alias
254
 'stcdi'  => {typ=>'op', val=>0175400, fmt=>'rg' ,fpp=>1 }, # alias
255
 'stcdl'  => {typ=>'op', val=>0175400, fmt=>'rg' ,fpp=>1 }, # alias
256
 'stcfd'  => {typ=>'op', val=>0176000, fmt=>'rg' ,fpp=>1 },
257
 'stcdf'  => {typ=>'op', val=>0176000, fmt=>'rg' ,fpp=>1 }, # alias
258
 'ldexp'  => {typ=>'op', val=>0176400, fmt=>'gr' ,fpp=>1 },
259
 'ldcif'  => {typ=>'op', val=>0177000, fmt=>'gr' ,fpp=>1 },
260
 'ldcid'  => {typ=>'op', val=>0177000, fmt=>'gr' ,fpp=>1 }, # alias
261
 'ldclf'  => {typ=>'op', val=>0177000, fmt=>'gr' ,fpp=>1 }, # alias
262
 'ldcld'  => {typ=>'op', val=>0177000, fmt=>'gr' ,fpp=>1 }, # alias
263
 'ldcdf'  => {typ=>'op', val=>0177400, fmt=>'gr' ,fpp=>1 },
264
 'ldcfd'  => {typ=>'op', val=>0177400, fmt=>'gr' ,fpp=>1 }  # alias
265
);
266
 
267
# operand formats
268
my %opfmt = (
269
 '-'   => [],                                                  # halt,...
270
 'n3'  => [{typ=>'e', pref=>''}],                              # spl
271
 'n6'  => [{typ=>'e', pref=>''}],                              # mark
272
 'n8'  => [{typ=>'e', pref=>''}],                              # trap,emt
273
 'r'   => [{typ=>'r', pref=>'o1'}],                            # rts
274
 'g'   => [{typ=>'g', pref=>'o1'}],                            # inc,...
275
 'rg'  => [{typ=>'r', pref=>'o1'}, {typ=>'g', pref=>'o2'}],    # xor,jsr
276
 'gr'  => [{typ=>'g', pref=>'o2'}, {typ=>'r', pref=>'o1'}],    # ash,...
277
 'gg'  => [{typ=>'g', pref=>'o1'}, {typ=>'g', pref=>'o2'}],    # add,...
278
 's8'  => [{typ=>'e', pref=>''}],                              # br,...
279
 'ru6' => [{typ=>'r', pref=>'o1'}, {typ=>'e', pref=>''}]       # sob
280
);
281
 
282
# psect table
283
my %psect =
284
('.abs.'  => {dot=>0, dotmax=>0}
285
);
286
my $cur_psect = '.abs.';                    # current psect
287
 
288
# local symbol table
289
my %lst =
290
('.'       => {name=>'.', typ=>'dot', val=>0,  psect=>'.abs.'}
291
);
292
my $llbl_scope = '0';                       # current local label scope
293
my $llbl_ascope = 0;                        # annonymous local label scope count
294
 
295
# macro table
296
my %mst;
297
 
298
my @flist;                                  # list of filenames
299
my $fstem;                                  # stem or last file name
300
my $lst_do;                                 # generate listing
301
my $lst_fname;                              # listing file name
302
my $lda_do;                                 # generate lda output
303
my $lda_fname;                              # lda file name
304
my $cof_do;                                 # generate cof output
305
my $cof_fname;                              # cof file name
306
my $lsm_do;                                 # generate lsm output
307
my $lsm_fname;                              # lsm file name
308
 
309
my @src;
310
my %errcnt;                                 # error tag counter
311
my $errcnt_tot=0;                           # total error count
312
my $pass;
313
 
314
my @t_pushback;
315
 
316
my $out_dot;                                # current . for output
317
my @out_data;                               # output data
318
my $out_start = 1;                          # absolute start address
319
 
320
autoflush STDOUT 1 if (-p STDOUT);          # autoflush if output into pipe
321
 
322
if (exists $opts{help}) {
323
  print_help;
324
  exit 0;
325
}
326
 
327
if (scalar(@ARGV) == 0) {
328
  print STDERR "asm-11-F: no input files specified, quiting..\n";
329
  print_help;
330
  exit 1;
331
}
332
 
333
# find stem of last file name
334
$fstem = $ARGV[-1];
335
$fstem =~ s|^.*/||;                         # drop leading dirs
336
$fstem =~ s|\.mac$||;                       # drop trailing '.mac'
337
 
338
if ($opts{lst} || $opts{olst}) {
339
  $lst_do = 1;
340
  $lst_fname = create_fname($opts{olst},'.lst');
341
}
342
 
343
if ($opts{lda} || $opts{olda}) {
344
  $lda_do = 1;
345
  $lda_fname = create_fname($opts{olda},'.lda');
346
}
347
 
348
if ($opts{cof} || $opts{ocof}) {
349
  $cof_do = 1;
350
  $cof_fname = create_fname($opts{ocof},'.cof');
351
}
352
 
353
if ($opts{lsm} || $opts{olsm}) {
354
  $lsm_do = 1;
355
  $lsm_fname = create_fname($opts{olsm},'.lsm');
356
}
357
 
358
# do pass 1
359
$pass = 1;
360
foreach my $fname (@ARGV) {
361
  read_file($fname);
362
}
363
dump_sym() if $opts{dsym1};
364
 
365
# prepare pass 2
366
 
367
foreach (keys %psect) {
368
  $psect{$_}{dot} = 0;
369
}
370
 
371
$lst{'.'}->{val} = 0;
372
$lst{'.'}->{psect} = '.abs.';
373
 
374
$cur_psect  = '.abs.';
375
$llbl_scope = '0';
376
 
377
# do pass 2
378
$pass = 2;
379
pass2();
380
dump_sym() if $opts{dsym2};
381
 
382
# create object output files
383
write_lda($lda_fname) if $lda_do;
384
write_cof($cof_fname) if $cof_do;
385
write_lsm($lsm_fname) if $lsm_do;
386
 
387
# and exit
388
if ($errcnt_tot > 0) {
389
  print "asm-11-E: compilation errors:";
390
  foreach my $err (sort keys %errcnt) {
391
    printf "  %s: %d", $err, $errcnt{$err};
392
  }
393
  print "\n";
394
  exit 1;
395
}
396
exit 0;
397
 
398
#-------------------------------------------------------------------------------
399
 
400
sub create_fname {
401
  my ($fname,$suff) = @_;
402
  if (defined $fname) {
403
    $fname =~ s|\%|$fstem|;
404
    return $fname;
405
  }
406
  $fname = $fstem;
407
  $fname .= $suff unless $fname eq '-';
408
  return $fname;
409
}
410
 
411
#-------------------------------------------------------------------------------
412
 
413
sub read_file {
414
  my ($fname) = @_;
415
  my $fh;
416
  if ($fname eq "-") {
417
    $fh = *STDIN;
418
  } else {
419
    if (not -r $fname) {
420
      print STDERR "asm-11-F: '$fname' not found or readable, quiting..\n";
421
      exit 1;
422
    }
423
    $fh = new FileHandle;
424
    $fh->open($fname) or die "failed to open '$fname'";
425
  }
426
 
427
  push @flist, $fname;
428
 
429
  my $lineno = 0;
430
  my $fileno = scalar(@flist);
431
  while (<$fh>) {
432
    chomp;
433
    my $line = $_;
434
    $lineno += 1;
435
    my $rl = parse_line($fileno, $lineno, $line);
436
    dump_rl($rl) if $opts{tpass1};
437
    push @src, $rl;
438
 
439
    # handle .include
440
    if (defined $$rl{oper} && $$rl{oper} eq '.include' && defined $$rl{ifile}) {
441
      my $fnam = $$rl{ifile};
442
      unless ($fnam =~ m|^/|) {
443
        foreach (@{$opts{I}}) {
444
          if (-r "$_/$fnam") {
445
            $fnam = "$_/$fnam";
446
            last;
447
          }
448
        }
449
      }
450
      read_file($fnam);
451
    }
452
 
453
  }
454
 
455
  return;
456
}
457
 
458
#-------------------------------------------------------------------------------
459
 
460
sub parse_line {
461
  my ($fileno,$lineno,$line) = @_;
462
 
463
  my %l = ( fileno => $fileno,              # file number
464
            lineno => $lineno,              # line number
465
            line   => $line,                # line
466
            cl     => [split '',$line],     # char list
467
            tl     => [],                   # token list
468
            err    => '',                   # error tags
469
            psect  => $cur_psect,           # current psect
470
            dot    => getdot(),             # current dot
471
            outw   => [],                   # output: words
472
            outb   => []                    # output: bytes
473
          );
474
 
475
  my $state = 'start';                      # parser state
476
 
477
  my $op_code;                              # op code
478
  my $op_fmt;                               # op format
479
  my $op_fpp;                               # true if floating opcode
480
  my @op_ops;                               # list of operands
481
  my $op_rop;                               # ref of current operand dsc
482
 
483
  my $s_incok;
484
  my $op_ibeg;
485
  my $op_creg;
486
  my $op_cmod;
487
  my $op_cmod_def;
488
 
489
  my @e_pbeg;
490
  my $e_ibeg;
491
  my $e_iend;
492
 
493
  my $a_sym;
494
  my $a_typ;
495
 
496
  my $d_dire;
497
  my @d_elist;
498
 
499
  my $c;
500
  my $rt;
501
  my $tmask = 0;
502
 
503
  my @stack;
504
 
505
  @t_pushback = ();
506
 
507
  printf "-- parse: '$line'\n" if $opts{tparse} || $opts{ttoken};
508
 
509
  # quit if illegal character found (non 7 bit ascii in asm-11)
510
  foreach my $c (@{$l{cl}}) {
511
    if (ord($c) > 127) {
512
      add_err(\%l, 'I');
513
      return \%l;
514
    }
515
  }
516
 
517
  while (1) {
518
    if ($opts{tparse}) {
519
      printf "-- state = $state";
520
      printf ", nest = %d", scalar(@e_pbeg) if $state =~ m/^e_/;
521
      print  "\n";
522
    }
523
 
524
    if ($state eq 'start') {                # state: start -------------------
525
      $rt = get_token(\%l, $tmask);
526
 
527
      # end of line seen ?
528
      if      ($$rt{tag} eq 'EOL') {
529
        last;
530
 
531
      # name seen
532
      } elsif ($$rt{tag} eq 'SYM') {
533
        # directive name seen ?
534
        if (exists $pst{$$rt{val}} && $pst{$$rt{val}}{typ} eq 'dir') {
535
          $state = 'oper';
536
 
537
        # otherwise check for label or assignment
538
        } else {
539
          my $isllbl = check_llbl($$rt{val});
540
          $rt = get_token(\%l, $tmask);
541
          # handle local labels
542
          if      ($isllbl) {
543
            if ($$rt{tag} eq 'LBL') {
544
              setsym(\%l, 'lbl' ,$l{tl}[-2]{val}, getdot());
545
              $l{lscope} = $llbl_scope;
546
              $l{label} = $l{tl}[-2]{val};
547
              $state = 'start1';
548
            } else {
549
              $state = 'q';
550
            }
551
          # handle assignments
552
          } elsif ($$rt{tag} eq 'ASS') {
553
            $a_sym = $l{tl}[-2]{val};
554
            $a_typ = $l{tl}[-1]{val};
555
            push @stack, 'a_end';
556
            $state = 'e_beg';
557
          # handle normal labels
558
          } elsif ($$rt{tag} eq 'LBL') {
559
            setsym(\%l, 'lbl' ,$l{tl}[-2]{val}, getdot());
560
            $llbl_scope = $l{tl}[-2]{val};
561
            $l{lscope} = $l{tl}[-2]{val};
562
            $l{label} = $l{tl}[-2]{val};
563
            $state = 'start1';
564
          # if neither label or assigmnent, handle as operation or directive
565
          } else {
566
            pushback_token(\%l);
567
            $state = 'oper';
568
          }
569
        }
570
 
571
      # anything else seen, treat a implicit .word
572
      } else {
573
        pushback_token(\%l);
574
        $state = 'iword';
575
      }
576
 
577
    } elsif ($state eq 'start1') {          # state: start1 ------------------
578
      $rt = get_token(\%l, $tmask);
579
      if      ($$rt{tag} eq 'EOL') {
580
        last;
581
      } elsif ($$rt{tag} eq 'SYM') {
582
        $state = 'oper';
583
      } else {                              # not symbol -> implicit .word
584
        pushback_token(\%l);
585
        $state = 'iword';
586
      }
587
 
588
    } elsif ($state eq 'oper') {            # state: oper --------------------
589
      # Note: state oper is entered with token already on tl list !!
590
      my $rt0 = $l{tl}[-1];
591
      my $op = $$rt0{val};
592
      $l{oper} = $op;
593
      if (exists $pst{$op}) {
594
        my $rs = $pst{$op};
595
        if ($$rs{typ} eq 'dir') {           # directives ------------------
596
          $d_dire = $op;
597
          if      ($op eq '.word' ||          # .word
598
                   $op eq '.byte') {          # .byte
599
            $state = 'dl_beg';
600
 
601
          } elsif ($op eq '.blkw' ||          # .blkw
602
                   $op eq '.blkb') {          # .blkb
603
            $state = 'dl_beg';
604
 
605
          } elsif ($op eq '.ascii' ||         # .ascii
606
                   $op eq '.asciz') {         # .asciz
607
            $tmask = TMASK_STRING;
608
            $state = 'al_next';
609
 
610
          } elsif ($op eq '.even' ||          # .even
611
                   $op eq '.odd') {           # .odd
612
            my $dot = getdot();
613
            my $inc = 0;
614
            $inc = 1 if $op eq '.even' && ($dot&01)==1;
615
            $inc = 1 if $op eq '.odd'  && ($dot&01)==0;
616
            incdot(1) if $inc;
617
            $l{typ}    = 'data';
618
            $l{incdot} = $inc;
619
            $l{lstdot} = 1;
620
            $state = 'end';
621
 
622
          } elsif ($op eq '.asect') {         # .asect
623
            # .asect is currently a noop because asect is start default
624
            $l{lstdot} = 1;
625
            $state = 'end';
626
 
627
          } elsif ($op eq '.include') {       # .include
628
            $rt = get_token(\%l, TMASK_STRING);
629
            if ($$rt{tag} eq 'STR') {
630
              my $ifile = $$rt{val};
631
              my $rt = get_token(\%l, TMASK_STRING);
632
              if ($$rt{tag} eq 'EOL') {
633
                $l{ifile} = substr($ifile,1,-1) unless $l{err} ne '';
634
                $state = 'end';
635
              } else {
636
                $state = 'q';
637
              }
638
            } else {
639
              $state = 'q';
640
            }
641
 
642
          } elsif ($op eq '.end') {           # .end
643
            $state = 'dl_beg';
644
 
645
          } else {
646
            die "BUGCHECK: op = '$op' in pst but no handler";
647
          }
648
 
649
        } elsif ($$rs{typ} eq 'op') {       # or opcodes ------------------
650
          walign(\%l);
651
          $l{typ}  = 'code';
652
          $op_code = $$rs{val};
653
          $op_fmt  = $$rs{fmt};
654
          $op_fpp  = $$rs{fpp};
655
          die "BUGCHECK: op_fmt = '$op_fmt' unknown in opfmt"
656
            unless defined $opfmt{$op_fmt};
657
 
658
          $l{opcode} = $op_code;
659
          $l{opfmt}  = $op_fmt;
660
 
661
          @op_ops  = @{$opfmt{$op_fmt}};
662
 
663
          if (scalar(@op_ops) == 0) {
664
            incdot(2);
665
            $state = 'end';
666
          } else {
667
            $op_rop = shift @op_ops;
668
            $state = 'op_beg';
669
          }
670
 
671
        }
672
      } else {                              # oper noy in pst --> implicit .word
673
        pushback_token(\%l);
674
        $state = 'iword';
675
      }
676
 
677
    } elsif ($state eq 'op_beg') {          # state: op_beg ------------------
678
      $op_ibeg = scalar(@{$l{tl}});
679
      $op_creg = undef;
680
      $op_cmod = undef;
681
      $op_cmod_def = undef;
682
      $e_ibeg = undef;
683
      $e_iend = undef;
684
      if      ($$op_rop{typ} eq 'r') {      # operand: register
685
        $rt = get_token(\%l, $tmask);
686
        $op_creg = check_reg($rt);
687
        if (defined $op_creg) {
688
          if ($op_fpp && $op_creg > 3) {      # fpp ac must be r0:r3
689
            $op_creg &= 03;
690
            add_err(\%l, 'T');
691
          }
692
          $op_cmod = 0;
693
          $state = 'op_end';
694
        } else {
695
          $state = 'q';
696
        }
697
      } elsif ($$op_rop{typ} eq 'e') {      # operand: expression
698
        push @stack, 'op_end';
699
        $state = 'e_beg';
700
      } elsif ($$op_rop{typ} eq 'g') {     # operand: general
701
        push @stack, 'op_end';
702
        $state = 'g_beg';
703
      } else {
704
        die "BUGCHECK: unexpected op typ '$$op_rop{typ}'";
705
      }
706
 
707
    } elsif ($state eq 'op_end') {          # state: op_end ------------------
708
      my $op_iend = scalar(@{$l{tl}})-1;
709
      $l{tl}[$op_ibeg]->{om} = '<';
710
      $l{tl}[$op_iend]->{om} = ($l{tl}[$op_iend]->{om}) ? '<>' : '>';
711
 
712
      my $pref = $$op_rop{pref};
713
      if      ($$op_rop{typ} =~  m/^[gr]$/) {
714
        $l{$pref.'reg'} = $op_creg;
715
        $l{$pref.'mod'} = $op_cmod;
716
        if (defined $e_ibeg) {
717
          $l{$pref.'ebeg'} = $e_ibeg;
718
          $l{$pref.'eend'} = $e_iend;
719
        }
720
      } elsif ($$op_rop{typ} eq  'e') {
721
        if (defined $e_ibeg) {
722
          $l{ebeg} = $e_ibeg;
723
          $l{eend} = $e_iend;
724
        }
725
      }
726
 
727
      if (scalar(@op_ops)) {                # second operand
728
        $rt = get_token(\%l, $tmask);
729
        if (check_token($rt, 'DEL', ',')) {
730
          $op_rop = shift @op_ops;
731
          $state = 'op_beg';
732
        } else {
733
          $state = 'q';
734
        }
735
 
736
      } else {                              # all operands seen
737
        my $nword = 1;
738
        $nword += 1 if defined $l{o1ebeg};
739
        $nword += 1 if defined $l{o2ebeg};
740
        incdot(2*$nword);
741
        $state = 'end';
742
      }
743
 
744
    } elsif ($state eq 'g_beg') {           # state: g_beg -------------------
745
      $rt = get_token(\%l, $tmask);
746
      if      (defined check_reg($rt)) {           # R !
747
        $op_creg = check_reg($rt);
748
        $op_cmod = 0;
749
        $state = 'g_end';
750
      } elsif (check_token($rt, 'DEL', '(')) {     # (  R),R)+
751
        $state = 'g_inc1';
752
      } elsif (check_token($rt, 'OP',  '@')) {     # @  R,(R)+,-(R),E(R),#E,E
753
        $op_cmod_def = 1;
754
        $state = 'g_def1';
755
      } elsif (check_token($rt, 'OP',  '-')) {     # -  (R)
756
        $rt = get_token(\%l, $tmask);
757
        if (check_token($rt, 'DEL', '(')) {          # next (
758
          pushback_token(\%l);
759
          $state = 'g_dec1';                         # go for -(R)
760
        } else {
761
          pushback_token(\%l);
762
          pushback_token(\%l);
763
          push @stack, 'g_ind1';                     # otherwise -E..
764
          $state = 'e_beg';
765
        }
766
      } elsif (check_token($rt, 'OP',  '#')) {     # #  E
767
        push @stack, 'g_imm1';
768
        $state = 'e_beg';
769
      } else {
770
        pushback_token(\%l);
771
        push @stack, 'g_ind1';                     # E ! (R)
772
        $state = 'e_beg';
773
      }
774
 
775
    } elsif ($state eq 'g_inc1') {          # state: g_inc1 ------------------
776
      $rt = get_token(\%l, $tmask);
777
      $op_creg = check_reg($rt);
778
      if (defined $op_creg) {
779
        $rt = get_token(\%l, $tmask);
780
        if (check_token($rt, 'DEL', ')')) {
781
          $rt = get_token(\%l, $tmask);
782
          if (check_token($rt, 'OP', '+')) {
783
            $op_cmod = $op_cmod_def ? 3 : 2;
784
            $state = 'g_end';
785
          } else {
786
            if ($op_cmod_def) {
787
              $state = 'q';
788
            } else {
789
              pushback_token(\%l);
790
              $op_cmod = 1;
791
              $state = 'g_end';
792
            }
793
          }
794
        } else {
795
          $state = 'q';
796
        }
797
      } else {
798
        $state = 'q';
799
      }
800
 
801
    } elsif ($state eq 'g_def1') {          # state: g_def1 ------------------
802
      $rt = get_token(\%l, $tmask);
803
      if (defined check_reg($rt)) {               # R
804
        $op_creg = check_reg($rt);
805
        $op_cmod = 1;
806
        $state = 'g_end';
807
      } elsif (check_token($rt, 'DEL', '(')) {    # ( -> R+
808
        $state = 'g_inc1';
809
      } elsif (check_token($rt, 'OP',  '-')) {    # - -> (R)
810
        $rt = get_token(\%l, $tmask);
811
        if (check_token($rt, 'DEL', '(')) {          # next (
812
          pushback_token(\%l);
813
          $state = 'g_dec1';                         # go for -(R)
814
        } else {
815
          pushback_token(\%l);
816
          pushback_token(\%l);
817
          push @stack, 'g_ind1';                     # otherwise -E..
818
          $state = 'e_beg';
819
        }
820
      } elsif (check_token($rt, 'OP',  '#')) {    # # -> #
821
        push @stack, 'g_imm1';
822
        $state = 'e_beg';
823
      } else {                                    # E -> !, (R)
824
        pushback_token(\%l);
825
        push @stack, 'g_ind1';
826
        $state = 'e_beg';
827
      }
828
 
829
    } elsif ($state eq 'g_ind1') {          # state: g_ind1 ------------------
830
      $rt = get_token(\%l, $tmask);
831
      if (check_token($rt, 'DEL', '(')) {
832
        $rt = get_token(\%l, $tmask);
833
        $op_creg = check_reg($rt);
834
        if (defined $op_creg) {
835
          $rt = get_token(\%l, $tmask);
836
          $op_cmod = $op_cmod_def ? 7 : 6;
837
          $state = check_token($rt, 'DEL', ')') ? 'g_end' : 'q';
838
        } else {
839
          $state = 'q';
840
        }
841
      } else {
842
        pushback_token(\%l);
843
        $op_creg = 7;
844
        $op_cmod = $op_cmod_def ? 7 : 6;
845
        $state = 'g_end';
846
      }
847
 
848
    } elsif ($state eq 'g_dec1') {          # state: g_dec1 ------------------
849
      $rt = get_token(\%l, $tmask);
850
      if (check_token($rt, 'DEL', '(')) {
851
        $rt = get_token(\%l, $tmask);
852
        $op_creg = check_reg($rt);
853
        if (defined $op_creg) {
854
          $rt = get_token(\%l, $tmask);
855
          $op_cmod = $op_cmod_def ? 5 : 4;
856
          $state = check_token($rt, 'DEL', ')') ? 'g_end' : 'q';
857
        } else {
858
          $state = 'q';
859
        }
860
      } else {
861
        $state = 'q';
862
      }
863
 
864
    } elsif ($state eq 'g_imm1') {          # state: g_imm1 ------------------
865
      $op_creg = 7;
866
      $op_cmod = $op_cmod_def ? 3 : 2;
867
      $state = 'g_end';
868
 
869
    } elsif ($state eq 'g_end') {           # state: g_end -------------------
870
        $state = pop @stack;
871
 
872
    } elsif ($state eq 'e_beg') {           # state: e_beg -------------------
873
      $e_ibeg = scalar(@{$l{tl}});
874
      @e_pbeg = ();
875
      $state = 'e_uop';
876
 
877
    } elsif ($state eq 'e_uop') {           # state: e_uop -------------------
878
      $rt = get_token(\%l, $tmask);
879
      if      ($$rt{tag} eq 'OP' && $$rt{typ}=~'u') { # OP(u)
880
        $$rt{typ}='u';
881
        $state = 'e_uop';
882
      } elsif ($$rt{tag} eq 'NUM' || $$rt{tag} eq 'SYM') {
883
        $state = 'e_bop';
884
      } elsif (check_token($rt, 'DEL', '<')) {
885
        push @e_pbeg, scalar(@{$l{tl}})-1;
886
        $state = 'e_uop';
887
      } else {
888
        $state = 'q';
889
      }
890
 
891
    } elsif ($state eq 'e_bop') {           # state: e_bop -------------------
892
      $rt = get_token(\%l, $tmask);
893
      if      ($$rt{tag} eq 'OP' && $$rt{typ}=~'b') { # OP(b)
894
        $$rt{typ}='b';
895
        $state = 'e_bop1';
896
      } elsif (check_token($rt, 'DEL', '>')) {
897
        if (scalar(@e_pbeg) == 0) {
898
          $state = 'q';
899
        } else {
900
          my $pbeg = pop @e_pbeg;
901
          $l{tl}[$pbeg]->{pend} = scalar(@{$l{tl}})-1;
902
          if ($tmask & TMASK_STRINGEXP) {
903
            $state = 'e_end';
904
          } else {
905
            $state = 'e_bop';
906
          }
907
        }
908
      } else {
909
        pushback_token(\%l);
910
        $state = 'e_end';
911
      }
912
 
913
    } elsif ($state eq 'e_bop1') {          # state: e_bop1 ------------------
914
      $rt = get_token(\%l, $tmask);
915
      if      ($$rt{tag} eq 'NUM' || $$rt{tag} eq 'SYM') {
916
        $state = 'e_bop';
917
      } elsif (check_token($rt, 'DEL', '<')) {
918
        push @e_pbeg, scalar(@{$l{tl}})-1;
919
        $state = 'e_uop';
920
      } else {
921
        $state = 'q';
922
      }
923
 
924
    } elsif ($state eq 'e_end') {           # state: e_end -------------------
925
      $e_iend = scalar(@{$l{tl}})-1;
926
      $l{tl}[$e_ibeg]->{em} = '<>';
927
      if ($e_iend != $e_ibeg) {
928
        $l{tl}[$e_ibeg]->{em} = '<';
929
        $l{tl}[$e_iend]->{em} = '>';
930
      }
931
      $state = (scalar(@e_pbeg)==0) ? pop @stack : 'q';
932
 
933
    } elsif ($state eq 'a_end') {           # state: a_end -------------------
934
      my $val = eval_exp(\%l, $e_ibeg, $e_iend);
935
      my $typ = ($a_typ =~ m/:/) ? 'pass' : 'ass';
936
      setsym(\%l, $typ, $a_sym, $val);
937
      $l{typ}   = 'ass';
938
      $l{atyp}  = $typ;
939
      $l{asym}  = $a_sym;
940
      $l{ebeg} = $e_ibeg;
941
      $l{eend} = $e_iend;
942
      $state = 'end';
943
 
944
    } elsif ($state eq 'dl_beg') {          # state: dl_beg ------------------
945
      $rt = get_token(\%l, $tmask);
946
      if      ($$rt{tag} eq 'EOL') {
947
        $state = 'dl_end';
948
      } elsif (check_token($rt, 'DEL', ',')) {
949
        pushback_token(\%l);
950
        $e_ibeg = undef;
951
        $e_iend = undef;
952
        $state = 'dl_next';
953
      } else {
954
        pushback_token(\%l);
955
        $e_ibeg = undef;
956
        $e_iend = undef;
957
        push @stack, 'dl_next';
958
        $state = 'e_beg';
959
      }
960
 
961
    } elsif ($state eq 'dl_next') {         # state: dl_next -----------------
962
      push @d_elist, {ibeg=>$e_ibeg, iend=>$e_iend};
963
      $rt = get_token(\%l, $tmask);
964
      if      ($$rt{tag} eq 'EOL') {
965
        $state = 'dl_end';
966
      } elsif (check_token($rt, 'DEL', ',')) {
967
        $rt = get_token(\%l, $tmask);
968
        if ($$rt{tag} eq 'EOL' || check_token($rt, 'DEL', ',')) {
969
          pushback_token(\%l);
970
          $e_ibeg = undef;
971
          $e_iend = undef;
972
          $state = 'dl_next';
973
        } else {
974
          pushback_token(\%l);
975
          $e_ibeg = undef;
976
          $e_iend = undef;
977
          push @stack, 'dl_next';
978
          $state = 'e_beg';
979
        }
980
      } else {
981
        $state = 'q';
982
      }
983
 
984
    } elsif ($state eq 'dl_end') {          # state: dl_end ------------------
985
      $state = 'end';
986
      if      ($d_dire eq '.word') {
987
        walign(\%l);
988
        if (scalar(@d_elist)) {
989
          $l{typ} = 'data';
990
          $l{delist} = \@d_elist;
991
          incdot(2*scalar(@d_elist));
992
        } else {
993
          $state = 'q';
994
        }
995
      } elsif ($d_dire eq '.byte') {
996
        if (scalar(@d_elist)) {
997
          $l{typ} = 'data';
998
          $l{delist} = \@d_elist;
999
          incdot(1*scalar(@d_elist));
1000
        } else {
1001
          $state = 'q';
1002
        }
1003
      } elsif ($d_dire eq '.blkw' || $d_dire eq '.blkb') {
1004
        $l{lstdot} = 1;
1005
        walign(\%l) if $d_dire eq '.blkw';
1006
        my $val;
1007
        if (scalar(@d_elist) == 0) {
1008
          $val = 1;
1009
        } elsif (scalar(@d_elist) == 1) {
1010
          $val = eval_exp(\%l, $d_elist[0]{ibeg}, $d_elist[0]{iend});
1011
        } else {
1012
          $state = 'q';
1013
        }
1014
 
1015
        if (defined $val) {
1016
          my $size = ($d_dire eq '.blkw') ? 2 : 1;
1017
          incdot($size * $val);
1018
          $l{typ}    = 'data';
1019
          $l{incdot} = $size * $val;
1020
        } else {
1021
          add_err(\%l, 'A');
1022
        }
1023
 
1024
      } elsif ($d_dire eq '.end') {
1025
        my $val;
1026
        if (scalar(@d_elist) == 0) {
1027
          $val = 1;
1028
        } elsif (scalar(@d_elist) == 1) {
1029
          $val = eval_exp(\%l, $d_elist[0]{ibeg}, $d_elist[0]{iend});
1030
        } else {
1031
          $state = 'q';
1032
        }
1033
        if (defined $val) {
1034
          $l{lstval} = $val;                # set aval to get it in listing
1035
          $out_start = $val;
1036
        } else {
1037
          $l{lstval} = 0;
1038
          add_err(\%l, 'U');
1039
        }
1040
 
1041
      } else {
1042
        die "BUGCHECK: unexpected d_dire = '$d_dire'";
1043
      }
1044
 
1045
    } elsif ($state eq 'al_next') {         # state: al_next -----------------
1046
      $rt = get_token(\%l, $tmask);
1047
      if      ($$rt{tag} eq 'STR') {
1048
        push @d_elist, {str=>$$rt{val}};
1049
      } elsif ($$rt{tag} eq 'EOL') {
1050
        $state = 'al_end';
1051
      } elsif (check_token($rt, 'DEL', '<')) {
1052
        pushback_token(\%l);
1053
        $tmask = TMASK_STRINGEXP;
1054
        push @stack, 'al_exp';
1055
        $e_ibeg = undef;
1056
        $e_iend = undef;
1057
        $state = 'e_beg';
1058
      } else {
1059
        $state = 'q';
1060
      }
1061
 
1062
    } elsif ($state eq 'al_exp') {          # state: al_exp ------------------
1063
      push @d_elist, {ibeg=>$e_ibeg, iend=>$e_iend};
1064
      $tmask = TMASK_STRING;
1065
      $state = 'al_next';
1066
 
1067
    } elsif ($state eq 'al_end') {          # state: al_end ------------------
1068
      my $size = 0;
1069
      foreach (@d_elist) {
1070
        if (defined $$_{str}) {
1071
          $size += length($$_{str}) - 2;
1072
        } else {
1073
          $size += 1;
1074
        }
1075
      }
1076
      $size += 1 if $d_dire eq '.asciz';
1077
      incdot($size);
1078
      $l{typ} = 'data';
1079
      $l{delist} = \@d_elist;
1080
      $state = 'end';
1081
 
1082
    } elsif ($state eq 'iword') {           # state: iword -------------------
1083
      $l{oper} = $d_dire = '.word';           # setup implicit .word directive
1084
      $state = 'dl_beg';
1085
 
1086
    } elsif ($state eq 'end') {             # state: end ---------------------
1087
      # unless EOL already seen fetch next token
1088
      if (scalar(@{$l{tl}}) && $l{tl}[-1]{tag} eq 'EOL') {
1089
        $rt = $l{tl}[-1];
1090
      } else {
1091
        $rt = get_token(\%l, $tmask);
1092
      }
1093
      # if at EOL fine, otherwise mark syntax error
1094
      if ($$rt{tag} eq 'EOL') {
1095
        last;
1096
      } else {
1097
        $state = 'q';
1098
      }
1099
 
1100
    } elsif ($state eq 'q') {               # state: q -----------------------
1101
      add_err(\%l, 'Q');                    # set Q error flag
1102
      last;                                 # and quit this line
1103
 
1104
    } else {
1105
      die "BUGCHECK: unexpected state '$state'\n";
1106
    }
1107
  }
1108
 
1109
  return \%l;
1110
}
1111
 
1112
#-------------------------------------------------------------------------------
1113
 
1114
sub walign {
1115
  my ($rl) = @_;
1116
  my $dot = getdot();
1117
  if ($dot & 0x1) {                         # odd address ?
1118
    incdot(1);
1119
    add_err($rl, 'B');
1120
    $$rl{dot} = getdot() if ($pass == 2);   # fixup . in rl context in pass 2
1121
  }
1122
  return;
1123
}
1124
 
1125
#-------------------------------------------------------------------------------
1126
 
1127
sub add_err {
1128
  my ($rl,$err) = @_;
1129
  return if index($$rl{err}, $err) >= 0;    # prevent multiple error tags
1130
  $$rl{err} .= $err;                        # set error tag
1131
  $errcnt{$err} += 1;                       # and count them
1132
  $errcnt_tot += 1;
1133
  return;
1134
}
1135
 
1136
#-------------------------------------------------------------------------------
1137
 
1138
sub prt_err {
1139
  my ($rl) = @_;
1140
  return join '', sort split '', $$rl{err};
1141
}
1142
 
1143
#-------------------------------------------------------------------------------
1144
 
1145
sub setdot {
1146
  my ($val) = @_;
1147
  return unless defined $val;
1148
  $lst{'.'}->{val} = $val;
1149
  $psect{$cur_psect}{dot} = $val;
1150
  $psect{$cur_psect}{dotmax} = $val if $psect{$cur_psect}{dotmax} < $val;
1151
  return;
1152
}
1153
 
1154
#-------------------------------------------------------------------------------
1155
 
1156
sub incdot {
1157
  my ($inc) = @_;
1158
  return unless defined $inc;
1159
  setdot(getdot() + $inc);
1160
  return;
1161
}
1162
 
1163
#-------------------------------------------------------------------------------
1164
 
1165
sub getdot {
1166
  return $lst{'.'}{val};
1167
}
1168
 
1169
#-------------------------------------------------------------------------------
1170
 
1171
sub setsym {
1172
  my ($rl,$typ,$name,$val) = @_;
1173
  ##print "+++set: pass=$pass; $llbl_scope : $name; typ=$typ\n";
1174
  if ($name eq '.') {
1175
    if ($typ eq 'ass') {
1176
      setdot($val);
1177
    } else {
1178
      add_err($rl, 'A');
1179
    }
1180
    return;
1181
  }
1182
 
1183
  my $isllbl = check_llbl($name);
1184
  if (check_llbl($name)) {
1185
    if ($typ eq 'lbl') {
1186
      $name = $llbl_scope . ':' . $name if $isllbl;
1187
      $typ  = 'llbl';
1188
    } else {
1189
      die "BUGCHECK: name looks like local label, but typ=$typ";
1190
    }
1191
  }
1192
 
1193
  my $namelc = lc($name);
1194
 
1195
  if ($typ ne 'ass' && exists $lst{$namelc} &&
1196
      $lst{$namelc}{typ} ne 'udef' && $pass==1) {
1197
    # Note: 'M' etaging done in pass 2!
1198
    $lst{$namelc}{mdef} = 1;
1199
    return;
1200
  }
1201
 
1202
  $lst{$namelc}{name}  = $name;
1203
  $lst{$namelc}{val}   = $val;
1204
  $lst{$namelc}{typ}   = $typ;
1205
  $lst{$namelc}{psect} = $cur_psect;
1206
 
1207
  return;
1208
}
1209
 
1210
#-------------------------------------------------------------------------------
1211
 
1212
sub getsym {
1213
  my ($rl, $name, $noxref) = @_;
1214
  ##print "+++get: pass=$pass; $llbl_scope : $name\n";
1215
  $name = $llbl_scope . ':' . $name if check_llbl($name);
1216
  my $namelc = lc($name);
1217
 
1218
  # if not yet defined, add it in lst with typ='udef'
1219
  if (not exists $lst{$namelc}) {           # not yet in lst
1220
    if (exists $pst{$namelc} &&               # but known as opcode
1221
        $pst{$namelc}{typ} eq 'op') {
1222
      return $pst{$namelc}{val};              # return that value
1223
    } else {
1224
      $lst{$namelc} = { name  => $name,
1225
                        val   => undef,
1226
                        typ   => 'udef',
1227
                        psect => ''
1228
                      };
1229
      return undef;
1230
    }
1231
  }
1232
 
1233
  unless ($noxref) {
1234
    if ($lst{$namelc}{mdef}) {
1235
      add_err($rl, 'D');
1236
    }
1237
  }
1238
 
1239
  return $lst{$namelc}{val};
1240
}
1241
 
1242
#-------------------------------------------------------------------------------
1243
 
1244
sub lst_checkmdef {
1245
  my ($name) = @_;
1246
  $name = $llbl_scope . ':' . $name if check_llbl($name);
1247
  my $namelc = lc($name);
1248
  return $lst{$namelc}{mdef};
1249
}
1250
 
1251
#-------------------------------------------------------------------------------
1252
 
1253
sub eval_exp {
1254
  my ($rl,$ibeg,$iend,$nest) = @_;
1255
  my $rtl = $$rl{tl};
1256
  my @uop;
1257
  my $bop;
1258
  my @val;
1259
 
1260
  return undef unless defined $ibeg && defined $iend;
1261
  return undef unless defined $$rtl[$ibeg] || $nest; # FIXME_code: test em !!
1262
 
1263
  for (my $i=$ibeg; $i<=$iend; $i++) {
1264
    my $rt = $$rtl[$i];
1265
    my $do_uop = 0;
1266
    if      ($$rt{tag} eq 'NUM') {
1267
      push @val, $$rt{nval};
1268
 
1269
    } elsif ($$rt{tag} eq 'SYM') {
1270
      push @val, getsym($rl, $$rt{val});
1271
 
1272
    } elsif ($$rt{tag} eq 'OP' && $$rt{typ} eq 'u') {
1273
      push @uop, $$rt{val};
1274
 
1275
    } elsif ($$rt{tag} eq 'OP' && $$rt{typ} eq 'b') {
1276
      $bop = $$rt{val};
1277
 
1278
    } elsif ($$rt{val} eq '<') {
1279
      my $pend = $$rt{pend};
1280
      die "BUGCHECK: pend not found for rtl[$i]" unless defined $pend;
1281
      push @val, eval_exp($rl,$i+1,$pend-1,1);
1282
      $i = $pend;
1283
 
1284
    } else {
1285
      die "BUGCHECK: tag='$$rt{tag}', val='$$rt{val}'\n";
1286
    }
1287
 
1288
    # if stack non-empty: return undef on undef, apply unary operators
1289
    if (scalar(@val) > 0) {
1290
      return undef unless defined $val[-1];
1291
      my $o;
1292
      while($o = pop @uop) {
1293
        my $v = pop @val;
1294
        if      ($o eq '+') {
1295
        } elsif ($o eq '-') {
1296
          $v = -$v;
1297
        } elsif ($o eq '^c') {
1298
          $v = ~$v;
1299
        } else {
1300
          die "BUGCHECK: tag='OP(u)', val='$o'\n";
1301
        }
1302
        push @val, (0177777 & $v);
1303
      }
1304
    }
1305
 
1306
    # if stack has 2 operands: apply binary operator
1307
    if (scalar(@val) == 2) {
1308
      die "BUGCHECK: bop not defined" unless defined $bop;
1309
      my $v2 = pop @val;
1310
      my $v1 = pop @val;
1311
      return undef unless defined $v1 && defined $v2;
1312
      if      ($bop eq '+') {
1313
        push @val, int($v1) + int($v2);
1314
      } elsif ($bop eq '-') {
1315
        push @val, int($v1) - int($v2);
1316
      } elsif ($bop eq '*') {
1317
        push @val, int($v1) * int($v2);
1318
      } elsif ($bop eq '/') {
1319
        push @val, int(int($v1) / int($v2));
1320
      } elsif ($bop eq '&') {
1321
        push @val, int($v1) & int($v2);
1322
      } elsif ($bop eq '!') {
1323
        push @val, int($v1) | int($v2);
1324
      } else {
1325
        die "BUGCHECK: tag='OP(b)', val='$bop'\n";
1326
      }
1327
      $bop = undef;
1328
    }
1329
 
1330
  }
1331
  return pop @val;
1332
}
1333
 
1334
#-------------------------------------------------------------------------------
1335
# returns true if symbol looks like a local label (1234$)
1336
 
1337
sub check_llbl {
1338
  my ($name) = @_;
1339
  return ($name =~ m/^\d+\$/) ? 1 : 0;
1340
}
1341
 
1342
#-------------------------------------------------------------------------------
1343
# returns register number if register symbol, or undef
1344
 
1345
sub check_reg {
1346
  my ($rt) = @_;
1347
  return undef unless $$rt{tag} eq 'SYM';
1348
  my $pse = $pst{$$rt{val}};
1349
  return undef unless defined $pse;
1350
  return undef unless $$pse{typ} eq 'reg';
1351
  return $$pse{val};
1352
}
1353
 
1354
#-------------------------------------------------------------------------------
1355
# returns true if token has specific tag/val
1356
 
1357
sub check_token {
1358
  my ($rt, $tag, $val) = @_;
1359
  return undef unless $$rt{tag} eq $tag;
1360
  return $$rt{val} eq $val;
1361
}
1362
 
1363
#-------------------------------------------------------------------------------
1364
 
1365
sub pushback_token {
1366
  my ($rl) = @_;
1367
 
1368
  my $rt = pop @{$$rl{tl}};
1369
  push @t_pushback, $rt;
1370
 
1371
  if ($opts{ttoken}) {
1372
    printf "-- token-back:  tag=%-3s val='%s'\n",
1373
      $$rt{tag}, savestr($$rt{val});
1374
  }
1375
 
1376
  return;
1377
}
1378
 
1379
#-------------------------------------------------------------------------------
1380
 
1381
sub get_token {
1382
  my ($rl, $tmask) = @_;
1383
  my $rt;
1384
 
1385
  if (scalar(@t_pushback)) {
1386
    $rt = pop @t_pushback;
1387
    if ($opts{ttoken}) {
1388
      printf "-- token-reget: tag=%-3s val='%s'\n",
1389
        $$rt{tag}, savestr($$rt{val});
1390
    }
1391
 
1392
  } else {
1393
    $rt = get_token1($rl, $tmask);
1394
    if ($opts{ttoken}) {
1395
      printf "-- token-get:   tag=%-3s val='%s'\n",
1396
        $$rt{tag}, savestr($$rt{val});
1397
    }
1398
  }
1399
 
1400
  push @{$$rl{tl}}, $rt;
1401
 
1402
  return $rt;
1403
}
1404
 
1405
#-------------------------------------------------------------------------------
1406
 
1407
sub finish_token {
1408
  my $rt = shift @_;
1409
  while (scalar(@_)) {
1410
    my $tag = shift @_;
1411
    my $val = shift @_;
1412
    $$rt{$tag} = $val;
1413
  }
1414
  return $rt;
1415
}
1416
 
1417
#-------------------------------------------------------------------------------
1418
 
1419
sub get_token1 {
1420
  my ($rl, $tmask) = @_;
1421
  my $rcl = $$rl{cl};
1422
 
1423
  my $val;
1424
  my $ws = '';
1425
 
1426
  # drop any leading whitespace
1427
  while (scalar(@$rcl)) {
1428
    last if ($$rcl[0] !~ m/\s/);
1429
    $ws .= shift @$rcl;
1430
  }
1431
 
1432
  my %t = (mask => $tmask,
1433
           ws   => $ws
1434
          );
1435
 
1436
  # end of line ?
1437
  unless (scalar(@$rcl)) {
1438
    return finish_token(\%t, tag=>'EOL', val=>$val);
1439
  }
1440
 
1441
  # get leading char
1442
  my $c = $$rcl[0];
1443
 
1444
  # comment ? treated similar to end of line, comment saved in val
1445
  if($c eq ';') {
1446
    $val = join('',@$rcl);
1447
    @$rcl = ();
1448
    return finish_token(\%t, tag=>'EOL', val=>$val);
1449
  }
1450
 
1451
  # here context dependent tokens
1452
  if ($tmask & TMASK_STRING) {
1453
    my $del = shift @$rcl;
1454
    if ($del eq '<') {
1455
      return finish_token(\%t, tag=> 'DEL', val=> $del);
1456
    } else {
1457
      my $str = $del;
1458
      while (scalar(@$rcl)) {
1459
        my $c = shift @$rcl;
1460
        $str .= $c;
1461
        return finish_token(\%t, tag=> 'STR', val=> $str) if $c eq $del;
1462
      }
1463
      add_err($rl, 'A');
1464
      return finish_token(\%t, tag=> 'STR', val=> $str);
1465
    }
1466
  }
1467
 
1468
  # looks like symbol ?
1469
  if ($c =~ m/[a-zA-Z\$\.]/) {
1470
    while (scalar(@$rcl)) {
1471
      last if ($$rcl[0] !~ m/[a-zA-Z0-9\$\.]/);
1472
      $val .= shift @$rcl;
1473
    }
1474
    return finish_token(\%t, tag=> 'SYM', val=> $val);
1475
  }
1476
 
1477
  # looks like number or local label ?
1478
  if ($c =~ m/[0-9]/) {
1479
    while (scalar(@$rcl)) {
1480
      last if ($$rcl[0] !~ m/[0-9]/);
1481
      $val .= shift @$rcl;
1482
    }
1483
    # check for local label
1484
    if (scalar(@$rcl) && $$rcl[0] eq '$') {
1485
      # FIXME_code: reject labels with numbers >64k-1
1486
      $val .= shift @$rcl;
1487
      return finish_token(\%t, tag=> 'SYM', val=> $val);
1488
    }
1489
    # looks like numerical constant
1490
    my $nval = undef;
1491
    # if trailing '.' seen, add and handle as decimal, otherwise as octal
1492
    if (scalar(@$rcl) && $$rcl[0] eq '.') {
1493
      $nval =int($val);
1494
      $val .= shift @$rcl;
1495
      if ($nval > 65535) {
1496
        add_err($rl, 'T');
1497
        $nval &= 0177777;
1498
      }
1499
    } else {
1500
      $nval = 0;
1501
      foreach my $cc (split '',$val) {
1502
        $nval = ($nval<<3) + int($cc);
1503
        add_err($rl, 'N') unless $cc =~ m/[0-7]/;
1504
        add_err($rl, 'T') unless $nval <= 0177777;
1505
        $nval &= 0177777;
1506
      }
1507
    }
1508
    return finish_token(\%t, tag=> 'NUM', val=> $val, nval=>$nval);
1509
  }
1510
 
1511
  # looks like label delimiter (':' or '::') ?
1512
  if ($c eq ':') {
1513
    $val .= shift @$rcl;
1514
    $val .= shift @$rcl if (scalar(@$rcl) && $$rcl[0] eq ':');
1515
    return finish_token(\%t, tag=> 'LBL', val=> $val);
1516
  }
1517
 
1518
  # looks assignment delimiter ('=','=:','==','==:') ?
1519
  if ($c eq '=') {
1520
    $val .= shift @$rcl;
1521
    $val .= shift @$rcl if (scalar(@$rcl) && $$rcl[0] eq '=');
1522
    $val .= shift @$rcl if (scalar(@$rcl) && $$rcl[0] eq ':');
1523
    return finish_token(\%t, tag=> 'ASS', val=> $val);
1524
  }
1525
 
1526
  # operators
1527
  if ($c =~ m/^(\+|\-)$/ ) {                # unary/binary operators
1528
    return finish_token(\%t, tag=> 'OP', typ=> 'ub', val=> shift @$rcl);
1529
  }
1530
  if ($c =~ m/^(\*|\/|\&|\!)$/ ) {          # binary operators
1531
    return finish_token(\%t, tag=> 'OP', typ=> 'b',  val=> shift @$rcl);
1532
  }
1533
  if ($c =~ m/^(\#|\@)$/ ) {                # unary operators
1534
    return finish_token(\%t, tag=> 'OP', typ=> 'u',  val=> shift @$rcl);
1535
  }
1536
 
1537
  # ' and " operator
1538
  if ($c eq "'") {
1539
    $val .= shift @$rcl;
1540
    $c = shift @$rcl;
1541
    if (not defined $c) {
1542
      return finish_token(\%t, tag=> 'BAD', val=> $val);
1543
    }
1544
    $val .= $c;
1545
    return finish_token(\%t, tag => 'NUM', val=> $val, nval=>ord($c));
1546
  }
1547
 
1548
  if ($c eq '"') {
1549
    $val .= shift @$rcl;
1550
    my $c1 = shift @$rcl;
1551
    my $c2 = shift @$rcl;
1552
    if (! defined $c1 || ! defined $c2) {
1553
      return finish_token(\%t, tag=> 'BAD', val=> $val);
1554
    }
1555
    $val .= $c1;
1556
    $val .= $c2;
1557
    return finish_token(\%t, tag => 'NUM', val=> $val,
1558
                                           nval=>ord($c2)<<8|ord($c1));
1559
  }
1560
 
1561
  # universal ^ operator
1562
  if ($c eq '^') {
1563
    $val .= shift @$rcl;
1564
    $c = shift @$rcl;
1565
    if (not defined $c) {
1566
      return finish_token(\%t, tag=> 'BAD', val=> $val);
1567
    }
1568
    $val .= $c;
1569
    $c = lc($c);
1570
    if      ($c eq 'c') {
1571
      return finish_token(\%t, tag=> 'OP', typ=> 'u',  val=> $val);
1572
 
1573
    } elsif ($c eq 'b') {
1574
      my $nval = 0;
1575
      while (scalar(@$rcl)) {
1576
        last if ($$rcl[0] !~ m/[0-9]/);
1577
        my $cc = shift @$rcl;
1578
        $nval = ($nval<<1) + int($cc);
1579
        add_err($rl, 'N') unless $cc =~ m/[0-1]/;
1580
        add_err($rl, 'T') unless $nval <= 0177777;
1581
        $nval &= 0177777;
1582
        $val .= $cc;
1583
      }
1584
      return finish_token(\%t, tag=> 'NUM', val=> $val, nval=> $nval);
1585
 
1586
    } elsif ($c eq 'o') {
1587
      my $nval = 0;
1588
      while (scalar(@$rcl)) {
1589
        last if ($$rcl[0] !~ m/[0-9]/);
1590
        my $cc = shift @$rcl;
1591
        $nval = ($nval<<3) + int($cc);
1592
        add_err($rl, 'N') unless $cc =~ m/[0-7]/;
1593
        add_err($rl, 'T') unless $nval <= 0177777;
1594
        $nval &= 0177777;
1595
        $val .= $cc;
1596
      }
1597
      return finish_token(\%t, tag=> 'NUM', val=> $val, nval=> $nval);
1598
 
1599
    } elsif ($c eq 'd') {
1600
      my $nval = 0;
1601
      while (scalar(@$rcl)) {
1602
        last if ($$rcl[0] !~ m/[0-9]/);
1603
        my $cc = shift @$rcl;
1604
        $nval = 10*$nval + int($cc);
1605
        add_err($rl, 'T') unless $nval <= 0177777;
1606
        $nval &= 0177777;
1607
        $val .= $cc;
1608
      }
1609
      return finish_token(\%t, tag=> 'NUM', val=> $val, nval=> $nval);
1610
 
1611
    } elsif ($c eq 'x') {
1612
      my $nval = 0;
1613
      while (scalar(@$rcl)) {
1614
        last if ($$rcl[0] !~ m/[0-9a-fA-F]/);
1615
        my $cc = shift @$rcl;
1616
        $nval = ($nval<<4) + hex($cc);
1617
        add_err($rl, 'T') unless $nval <= 0177777;
1618
        $nval &= 0177777;
1619
        $val .= $cc;
1620
      }
1621
      return finish_token(\%t, tag=> 'NUM', val=> $val, nval=> $nval);
1622
 
1623
    } elsif ($c eq 'r') {
1624
      my $nval = 0;
1625
      for (my $i=0; $i<3; $i++) {
1626
        last unless defined $$rcl[0];
1627
        last unless $$rcl[0] =~ m/^[0-9a-zA-Z\.\$\ ]$/;
1628
        $nval = 050 * $nval + to_rad50($$rcl[0]);
1629
        $val .= shift @$rcl;
1630
      }
1631
      return finish_token(\%t, tag=> 'NUM', val=> $val, nval=>$nval);
1632
 
1633
    } else {
1634
      return finish_token(\%t, tag=> 'BAD', val=> $val);
1635
    }
1636
  }
1637
 
1638
  # delimiters
1639
  if ($c =~ m|^[\(\)\,\<\>]$|) {
1640
    return finish_token(\%t, tag=> 'DEL', val=> shift @$rcl);
1641
  }
1642
 
1643
  # can't handle stuff
1644
  $val = join('',@$rcl);
1645
  @$rcl = ();
1646
  return finish_token(\%t, tag=> 'BAD', val=> $val);
1647
}
1648
 
1649
#-------------------------------------------------------------------------------
1650
 
1651
sub to_rad50 {
1652
  my ($c) = @_;
1653
  return undef unless defined $c;
1654
  $c = lc($c);
1655
  return 0 if $c eq ' ';
1656
  return 001 + ord($c)-ord('a') if $c =~ m/^[a-z]$/;
1657
  return 033 if $c eq '$';
1658
  return 034 if $c eq '.';
1659
  return 036 + ord($c)-ord('0') if $c =~ m/^[0-9]$/;
1660
  return undef;
1661
}
1662
 
1663
#-------------------------------------------------------------------------------
1664
 
1665
sub pass2 {
1666
 
1667
  my $fh;
1668
  if ($lst_do) {
1669
    if ($lst_fname eq "-") {
1670
      $fh = *STDOUT;
1671
    } else {
1672
      $fh = new FileHandle;
1673
      unless (open($fh, ">", $lst_fname)) {
1674
        print STDERR "asm-11-F: '$lst_fname' not writable, quiting..\n";
1675
        exit 1;
1676
      }
1677
    }
1678
  }
1679
 
1680
  pass2_lst_beg($fh) if $lst_do;
1681
 
1682
  foreach my $rl (@src) {
1683
 
1684
    $$rl{dot} = getdot();
1685
    $llbl_scope = $$rl{lscope} if defined $$rl{lscope};
1686
 
1687
    # handle label definitions
1688
    if (defined $$rl{label}) {
1689
      if (lst_checkmdef($$rl{label})) {
1690
        add_err($rl, 'M');
1691
      } else {
1692
        my $val = getsym($rl, $$rl{label}, 1);
1693
        if (! defined $val || $val != getdot()) {
1694
          add_err($rl, 'P');
1695
        }
1696
      }
1697
    }
1698
 
1699
    # generate output data
1700
    pass2_out($rl);
1701
    # listing requested
1702
    pass2_lst_line($rl, $fh) if $lst_do;
1703
    # pass 2 dump requested
1704
    dump_rl($rl) if $opts{tpass2};
1705
 
1706
  }
1707
 
1708
  pass2_lst_end($fh) if $lst_do;
1709
 
1710
  return;
1711
}
1712
 
1713
#-------------------------------------------------------------------------------
1714
 
1715
sub pass2_out {
1716
  my ($rl) = @_;
1717
 
1718
  # quit without code generation for 'questionable syntax' lines
1719
  return if $$rl{err} =~ m/[IQ]/;
1720
 
1721
  # return if no pass2 action (typ not defined)
1722
  return unless defined $$rl{typ};
1723
 
1724
  # generate code
1725
  if      ($$rl{typ} eq 'code') {
1726
    walign($rl);
1727
    my $opcode = $$rl{opcode};
1728
    my $opfmt  = $$rl{opfmt};
1729
 
1730
    # printf "+++1 $$rl{typ},$$rl{oper},%s,%s\n",
1731
    #   savestr($opcode), savestr($opfmt);
1732
 
1733
    if      ($opfmt eq '-') {
1734
      out_opcode($rl, $opcode);
1735
 
1736
    } elsif ($opfmt eq 'g') {
1737
      out_opcode($rl, $opcode | $$rl{o1mod}<<3 | $$rl{o1reg});
1738
      out_opdata($rl, $$rl{o1mod}, $$rl{o1reg},
1739
                      $$rl{o1ebeg}, $$rl{o1eend});
1740
 
1741
    } elsif ($opfmt eq 'gg') {
1742
      out_opcode($rl, $opcode | $$rl{o1mod}<<9 | $$rl{o1reg}<<6 |
1743
                                $$rl{o2mod}<<3 | $$rl{o2reg});
1744
      out_opdata($rl, $$rl{o1mod}, $$rl{o1reg},
1745
                      $$rl{o1ebeg}, $$rl{o1eend});
1746
      out_opdata($rl, $$rl{o2mod}, $$rl{o2reg},
1747
                      $$rl{o2ebeg}, $$rl{o2eend});
1748
    } elsif ($opfmt eq 'r') {
1749
      out_opcode($rl, $opcode | $$rl{o1reg});
1750
    } elsif ($opfmt eq 'rg' || $opfmt eq 'gr') {
1751
      out_opcode($rl, $opcode | $$rl{o1reg}<<6 |
1752
                                $$rl{o2mod}<<3 | $$rl{o2reg});
1753
      out_opdata($rl, $$rl{o2mod}, $$rl{o2reg},
1754
                      $$rl{o2ebeg}, $$rl{o2eend});
1755
    } elsif ($opfmt eq 'n3') {
1756
      out_opcode_n($rl, $opcode, 07, $$rl{ebeg}, $$rl{eend});
1757
    } elsif ($opfmt eq 'n6') {
1758
      out_opcode_n($rl, $opcode, 077, $$rl{ebeg}, $$rl{eend});
1759
    } elsif ($opfmt eq 'n8') {
1760
      out_opcode_n($rl, $opcode, 0377, $$rl{ebeg}, $$rl{eend});
1761
    } elsif ($opfmt eq 's8') {
1762
      out_opcode_o($rl, $opcode, 's8', $$rl{ebeg}, $$rl{eend});
1763
    } elsif ($opfmt eq 'ru6') {
1764
      out_opcode_o($rl, $opcode|($$rl{o1reg}<<6), 'u6',
1765
                                 $$rl{ebeg}, $$rl{eend});
1766
    } else {
1767
      die "BUGCHECK: unknown opfmt '$opfmt'";
1768
    }
1769
 
1770
  # generate data
1771
  } elsif ($$rl{typ} eq 'data') {
1772
    if ($$rl{oper} eq '.word' || $$rl{oper} eq '.byte' ) {
1773
      walign($rl) if $$rl{oper} eq '.word';
1774
      my $size = ($$rl{oper} eq '.word') ? 2 : 1;
1775
      my $mask = ($size == 2) ? 0177777 : 0377;
1776
      foreach (@{$$rl{delist}}) {
1777
        my $ibeg = $$_{ibeg};
1778
        my $iend = $$_{iend};
1779
        my $val = 0;
1780
        if (defined $ibeg) {
1781
          $val = eval_exp($rl, $ibeg, $iend);
1782
          if (not defined $val) {
1783
            $val = 0;
1784
            add_err($rl, 'U');
1785
          }
1786
        }
1787
        # FIXME_code: handle T error here !!
1788
        $val &= $mask;
1789
        if ($$rl{oper} eq '.word') {
1790
          out_w($rl, $val);
1791
        } else {
1792
          out_b($rl, $val);
1793
        }
1794
      }
1795
 
1796
    } elsif ($$rl{oper} eq '.blkw' || $$rl{oper} eq '.blkb' ) {
1797
      walign($rl) if $$rl{oper} eq '.blkw';
1798
      incdot($$rl{incdot});
1799
 
1800
    } elsif ($$rl{oper} eq '.ascii' || $$rl{oper} eq '.asciz' ) {
1801
      foreach my $rd (@{$$rl{delist}}) {
1802
        if (defined $$rd{str}) {
1803
          my @chr = split '',$$rd{str};
1804
          shift @chr;
1805
          pop @chr;
1806
          foreach (@chr) {
1807
            push @{$$rl{outb}}, ord($_);
1808
          }
1809
        } else {
1810
          my $val = eval_exp($rl, $$rd{ibeg}, $$rd{iend});
1811
          if (not defined $val) {
1812
            $val = 0;
1813
            add_err($rl, 'U');
1814
          }
1815
          if ($val < 0 || $val > 0377) {
1816
            $val &= 0377;
1817
            add_err($rl, 'T');
1818
          }
1819
          push @{$$rl{outb}}, $val;
1820
        }
1821
      }
1822
      push @{$$rl{outb}}, 0 if $$rl{oper} eq '.asciz';
1823
      incdot(scalar(@{$$rl{outb}}));
1824
 
1825
    } elsif ($$rl{oper} eq '.even' || $$rl{oper} eq '.odd' ) {
1826
      if ($$rl{incdot}) {
1827
        push @{$$rl{outb}}, 0;
1828
        incdot(1);
1829
      }
1830
 
1831
    } else {
1832
      die "BUGCHECK: unknown data oper '$$rl{oper}'";
1833
    }
1834
 
1835
  # handle assignments
1836
  } elsif ($$rl{typ} eq 'ass') {
1837
    my $val = eval_exp($rl, $$rl{ebeg}, $$rl{eend});
1838
    if (defined $val) {
1839
      $$rl{lstval} = $val;
1840
      setsym($rl, $$rl{atyp}, $$rl{asym}, $val);
1841
    } else {
1842
      $$rl{lstval} = 0;
1843
      add_err($rl, 'U');
1844
    }
1845
 
1846
  } else {
1847
    die "BUGCHECK: unknown line typ '$$rl{typ}'";
1848
  }
1849
 
1850
  if      (scalar(@{$$rl{outw}})) {
1851
    emitw($$rl{dot}, $$rl{outw});
1852
  } elsif (scalar(@{$$rl{outb}})) {
1853
    emitb($$rl{dot}, $$rl{outb});
1854
  }
1855
 
1856
  return;
1857
}
1858
 
1859
#-------------------------------------------------------------------------------
1860
 
1861
sub pass2_lst_beg {
1862
  my ($fh) = @_;
1863
  printf $fh "; Input file list:\n";
1864
  my $fileno = 1;
1865
  foreach my $fname (@flist) {
1866
    $fname =~ s/^$ENV{RETROBASE}/\$RETROBASE/;
1867
    printf $fh ";  %2d: %s\n", $fileno, $fname;
1868
    $fileno += 1;
1869
  }
1870
  print $fh ";\n";
1871
  return;
1872
}
1873
 
1874
#-------------------------------------------------------------------------------
1875
 
1876
sub pass2_lst_end {
1877
  my ($fh) = @_;
1878
  if ($errcnt_tot) {
1879
    print $fh ";\n";
1880
    print $fh "; Error summary:\n";
1881
    foreach my $err (sort keys %errcnt) {
1882
      printf $fh ";  %s: %3d\n", $err, $errcnt{$err};
1883
    }
1884
  }
1885
  return;
1886
}
1887
 
1888
#-------------------------------------------------------------------------------
1889
# line format is
1890
# er fn lnum    dot       source
1891
# .. dd dddd oooooo oooooo oooooo oooooo 
1892
# ..                ooo ooo ooo ooo ooo  
1893
 
1894
sub pass2_lst_line {
1895
  my ($rl,$fh) = @_;
1896
 
1897
  my @ow = @{$$rl{outw}};
1898
  my @ob = @{$$rl{outb}};
1899
  my $str = '';
1900
  $str .= sprintf("%-2s", prt_err($rl));
1901
  $str .= sprintf(" %2d", $$rl{fileno});
1902
  $str .= sprintf(" %4d", $$rl{lineno});
1903
 
1904
  # print dot if data is generated for this line, or label
1905
  my $prtdot = defined $$rl{lstdot} ||
1906
               scalar(@{$$rl{outw}}) ||
1907
               scalar(@{$$rl{outb}}) ||
1908
               $$rl{label};
1909
  if ($prtdot) {
1910
    $str .= prt76o($$rl{dot});
1911
  } else {
1912
    $str .= '       ';
1913
  }
1914
 
1915
  if (defined $$rl{lstval}) {
1916
    $str .= prt76o($$rl{lstval});
1917
    $str .= ' ' x 14;
1918
  } elsif (scalar(@ow)) {
1919
    for (my $i=0; $i<3; $i++) { $str .= prt76o(shift @ow); }
1920
  } elsif (scalar(@ob)) {
1921
    for (my $i=0; $i<5; $i++) { $str .= prt43o(shift @ob); }
1922
    $str .= ' ';
1923
  } else {
1924
    $str .= ' ' x 21;
1925
  }
1926
 
1927
  $str .= '  ' . $$rl{line} . "\n";
1928
  print $fh $str;
1929
  if (1) {
1930
    while (scalar(@ow)) {
1931
      $str = '                 ';
1932
      for (my $i=0; $i<3; $i++) { $str .= prt76o(shift @ow); }
1933
      print $fh $str . "\n";
1934
    }
1935
    while (scalar(@ob)) {
1936
      $str = '                 ';
1937
      for (my $i=0; $i<5; $i++) { $str .= prt43o(shift @ob); }
1938
      print $fh $str . "\n";
1939
    }
1940
  }
1941
  return;
1942
}
1943
 
1944
#-------------------------------------------------------------------------------
1945
 
1946
sub out_w {
1947
  my ($rl,$word) = @_;
1948
  push @{$$rl{outw}}, $word;
1949
  incdot(2);
1950
  return;
1951
}
1952
 
1953
#-------------------------------------------------------------------------------
1954
 
1955
sub out_b {
1956
  my ($rl,$byte) = @_;
1957
  push @{$$rl{outb}}, $byte;
1958
  incdot(1);
1959
  return;
1960
}
1961
 
1962
#-------------------------------------------------------------------------------
1963
 
1964
sub out_opcode {
1965
  my ($rl,$code) = @_;
1966
  out_w($rl, $code);
1967
  return;
1968
}
1969
 
1970
#-------------------------------------------------------------------------------
1971
 
1972
sub out_opcode_n {
1973
  my ($rl,$code,$mask,$ebeg,$eend) = @_;
1974
  # FIXME_code: shouldn't we die here ?
1975
  return unless defined $ebeg;
1976
 
1977
  my $val = eval_exp($rl,$ebeg,$eend);
1978
  unless (defined $val) {
1979
    $val = 0;
1980
    add_err($rl, 'A');
1981
  }
1982
  if ($val & ~$mask) {
1983
    $val &= $mask;
1984
    add_err($rl, 'T');
1985
  }
1986
  out_w($rl, $code|$val);
1987
  return;
1988
}
1989
 
1990
#-------------------------------------------------------------------------------
1991
 
1992
sub out_opcode_o {
1993
  my ($rl,$code,$typ,$ebeg,$eend) = @_;
1994
  # FIXME_code: shouldn't we die here ?
1995
  return unless defined $ebeg;
1996
 
1997
  my $val = eval_exp($rl,$ebeg,$eend);
1998
  my $off;
1999
  if (defined $val) {
2000
    $off = ($val - (getdot()+2)) / 2;
2001
  } else {
2002
    $off = -1;
2003
    add_err($rl, 'U');
2004
  }
2005
 
2006
  if ($typ eq 's8') {
2007
    if ($off > 127 || $off < -128) {
2008
      add_err($rl, 'A');
2009
    }
2010
    $off &= 0377;
2011
  } else {
2012
    $off = -$off;
2013
    if ($off > 63 || $off < 0) {
2014
      add_err($rl, 'A');
2015
    }
2016
    $off &= 0077;
2017
  }
2018
  out_w($rl, $code|$off);
2019
  return;
2020
}
2021
 
2022
#-------------------------------------------------------------------------------
2023
 
2024
sub out_opdata {
2025
  my ($rl,$mod,$reg,$ebeg,$eend) = @_;
2026
  # FIXME_code: shouldn't we die here ?
2027
  return unless defined $ebeg;
2028
 
2029
  my $val = eval_exp($rl,$ebeg,$eend);
2030
  unless (defined $val) {
2031
    out_w($rl, 0);
2032
    add_err($rl, 'U');
2033
    return;
2034
  }
2035
  if ($mod>=6 && $reg==7) {
2036
    $val = ($val - (getdot()+2)) & 0177777;
2037
  }
2038
  out_w($rl, $val);
2039
  return;
2040
}
2041
 
2042
#-------------------------------------------------------------------------------
2043
 
2044
sub emitw {
2045
  my ($baddr,$rwl) = @_;
2046
  if ($opts{temit}) {
2047
    printf "-- emit: w %6.6o:", $baddr;
2048
    foreach my $w (@$rwl) { printf " %6.6o", $w; }
2049
    print "\n";
2050
  }
2051
  return unless scalar(@$rwl);
2052
 
2053
  if ((! defined $out_dot) || $out_dot!=$baddr || $out_data[-1]->{typ} ne 'w') {
2054
    push @out_data, {typ=> 'w', addr=>$baddr, data=>[@$rwl]};
2055
  } else {
2056
    my $rdata = $out_data[-1]->{data};
2057
    push @$rdata, @$rwl;
2058
  }
2059
  $out_dot = $baddr+2;
2060
  return;
2061
}
2062
 
2063
#-------------------------------------------------------------------------------
2064
 
2065
sub emitb {
2066
  my ($baddr,$rbl) = @_;
2067
  if ($opts{temit}) {
2068
    printf "-- emit: b %6.6o:", $baddr;
2069
    foreach my $b (@$rbl) { printf " %3.3o", $b; }
2070
    print "\n";
2071
  }
2072
  return unless scalar(@$rbl);
2073
 
2074
  if ((! defined $out_dot) || $out_dot!=$baddr || $out_data[-1]->{typ} ne 'b') {
2075
    push @out_data, {typ=> 'b', addr=>$baddr, data=>[@$rbl]};
2076
  } else {
2077
    my $rdata = $out_data[-1]->{data};
2078
    push @$rdata, @$rbl;
2079
  }
2080
  $out_dot = $baddr+1;
2081
  return;
2082
}
2083
 
2084
#-------------------------------------------------------------------------------
2085
 
2086
sub write_lda_frame {
2087
  my ($fh,$addr,$rblist) = @_;
2088
  my $len = 6 + scalar(@$rblist);
2089
  my @f;
2090
  push @f, 0x01;
2091
  push @f, 0x00;
2092
  push @f, $len & 0xff;
2093
  push @f, ($len>>8) & 0xff;
2094
  push @f, $addr & 0xff;
2095
  push @f, ($addr>>8) & 0xff;
2096
  push @f, @$rblist if $len;
2097
  my $csum = 0;
2098
  foreach (@f) { $csum = ($csum + $_) & 0xff; }
2099
  push @f, (-$csum) & 0xff;
2100
 
2101
  if ($opts{tout}) {
2102
    my $nval = 0;
2103
    printf "-- out: %6.6o:", $addr;
2104
    foreach (@f) {
2105
      if ($nval == 16) {
2106
        printf "\n               ";
2107
        $nval = 0;
2108
      }
2109
      printf " %3.3o", $_;
2110
      $nval += 1;
2111
    }
2112
    printf "\n";
2113
  }
2114
 
2115
  my $buf = pack("C*", @f);
2116
  my $rc = syswrite($fh, $buf, length($buf));
2117
  return;
2118
}
2119
 
2120
#-------------------------------------------------------------------------------
2121
 
2122
sub write_lda {
2123
  my ($fname) = @_;
2124
  my $fh;
2125
  if ($fname eq "-") {
2126
    $fh = *STDOUT;
2127
  } else {
2128
    $fh = new FileHandle;
2129
    unless (open($fh, ">:raw", $fname)) {
2130
      print STDERR "asm-11-F: '$fname' not writable, quiting..\n";
2131
      exit 1;
2132
    }
2133
  }
2134
 
2135
  my @blist;
2136
  my $base;
2137
  my $dot;
2138
  foreach my $rl (@src) {
2139
    die "BUGCHECK: both outb and outw contain data"
2140
      if scalar(@{$$rl{outb}}) && scalar(@{$$rl{outw}});
2141
 
2142
    my @byt = @{$$rl{outb}};
2143
    foreach (@{$$rl{outw}}) {
2144
      push @byt,  $_     & 0xff;
2145
      push @byt, ($_>>8) & 0xff;
2146
    }
2147
 
2148
    next unless scalar(@byt);
2149
 
2150
    # flush frame if new data not adjacent to old
2151
    if (scalar(@blist) && $dot!=$$rl{dot}) {
2152
      write_lda_frame($fh, $base, \@blist);
2153
      @blist = ();
2154
      $base = undef;
2155
      $dot  = undef;
2156
    }
2157
 
2158
    $dot = $base = $$rl{dot} unless defined $base;
2159
 
2160
    foreach (@byt) {
2161
      if (scalar(@blist) >= 2*168) {
2162
        write_lda_frame($fh, $base, \@blist);
2163
        @blist = ();
2164
        $base = $dot;
2165
      }
2166
      push @blist, $_ & 0xff;
2167
      $dot += 1;
2168
    }
2169
 
2170
  }
2171
 
2172
  # flush buffer
2173
  write_lda_frame($fh, $base, \@blist) if scalar(@blist);
2174
  @blist = ();
2175
 
2176
  # write terminating frame
2177
  write_lda_frame($fh, $out_start, \@blist);
2178
 
2179
  return;
2180
}
2181
 
2182
#-------------------------------------------------------------------------------
2183
 
2184
sub write_cof_frame {
2185
  my ($fh,$typ,$addr,$rlist) = @_;
2186
  my $fmt = ($typ eq 'w') ? '%6.6o' : '%3.3o';
2187
  my $max = ($typ eq 'w') ? 10 : 20 ;
2188
 
2189
  printf $fh "$typ %6.6o {\n", $addr;
2190
  my $i = 0;
2191
  foreach (@$rlist) {
2192
    $i += 1;
2193
    printf $fh "$fmt ", $_;
2194
    print $fh "\n" if $i%$max == 0;
2195
  }
2196
  print $fh "\n" unless $i%$max == 0;
2197
  print  $fh "}\n";
2198
  return;
2199
}
2200
 
2201
#-------------------------------------------------------------------------------
2202
 
2203
sub write_cof {
2204
  my ($fname) = @_;
2205
  my $fh;
2206
  if ($fname eq "-") {
2207
    $fh = *STDOUT;
2208
  } else {
2209
    $fh = new FileHandle;
2210
    unless (open($fh, ">:raw", $fname)) {
2211
      print STDERR "asm-11-F: '$fname' not writable, quiting..\n";
2212
      exit 1;
2213
    }
2214
  }
2215
 
2216
  print $fh "sym {\n";
2217
  foreach my $key (sort keys %lst) {
2218
    next unless $lst{$key}{typ} =~ m/^(lbl|llbl)$/;
2219
    printf $fh "%s => %s\n", $lst{$key}{name}, save66o($lst{$key}{val});
2220
  }
2221
  print $fh "}\n";
2222
  print $fh "dat {\n";
2223
 
2224
  my @list;
2225
  my $typ;
2226
  my $base;
2227
  my $dot;
2228
 
2229
  foreach my $rl (@src) {
2230
 
2231
    if (scalar(@{$$rl{outb}})) {
2232
      if (scalar(@list) && ($typ ne 'b' || $dot != $$rl{dot})) {
2233
        write_cof_frame($fh, $typ, $base, \@list);
2234
        @list = ();
2235
      }
2236
      unless (scalar(@list)) {
2237
        $typ = 'b';
2238
        $base = $dot = $$rl{dot};
2239
      }
2240
      push @list, @{$$rl{outb}};
2241
      $dot += scalar(@{$$rl{outb}});
2242
    }
2243
 
2244
    if (scalar(@{$$rl{outw}})) {
2245
      if (scalar(@list) && ($typ ne 'w' || $dot != $$rl{dot})) {
2246
        write_cof_frame($fh, $typ, $base, \@list);
2247
        @list = ();
2248
      }
2249
      unless (scalar(@list)) {
2250
        $typ = 'w';
2251
        $base = $dot = $$rl{dot};
2252
      }
2253
      push @list, @{$$rl{outw}};
2254
      $dot += 2 * scalar(@{$$rl{outw}});
2255
    }
2256
  }
2257
 
2258
  write_cof_frame($fh, $typ, $base, \@list)
2259
    if scalar(@list);
2260
 
2261
  print $fh "}\n";
2262
 
2263
  return;
2264
}
2265
 
2266
#-------------------------------------------------------------------------------
2267
 
2268
sub write_lsm {
2269
  my ($fname) = @_;
2270
  my $fh;
2271
  if ($fname eq "-") {
2272
    $fh = *STDOUT;
2273
  } else {
2274
    $fh = new FileHandle;
2275
    unless (open($fh, ">:raw", $fname)) {
2276
      print STDERR "asm-11-F: '$fname' not writable, quiting..\n";
2277
      exit 1;
2278
    }
2279
  }
2280
 
2281
  my %mem;
2282
 
2283
  foreach my $rl (@src) {
2284
 
2285
    my $dot = $$rl{dot};
2286
    if (scalar(@{$$rl{outb}})) {
2287
      foreach my $byte (@{$$rl{outb}}) {
2288
        my $addr = sprintf "%6.6o", $dot & 0xfffe;
2289
        $mem{$addr} = 0 unless exists $mem{$addr};
2290
        if ($dot & 0x1) {                   # odd byte
2291
          $mem{$addr} = (($byte&0xff)<<8) | ($mem{$addr} & 0xff);
2292
        } else {                            # even byte
2293
          $mem{$addr} = ($mem{$addr} & 0xff00) | ($byte&0xff);
2294
        }
2295
        $dot += 1;
2296
      }
2297
    }
2298
 
2299
    if (scalar(@{$$rl{outw}})) {
2300
      foreach my $word (@{$$rl{outw}}) {
2301
        my $addr = sprintf "%6.6o", $dot;
2302
        $mem{$addr} = $word;
2303
        $dot += 2;
2304
      }
2305
    }
2306
  }
2307
 
2308
  foreach my $addr (sort keys %mem) {
2309
    printf $fh "%s : %6.6o\n", $addr, $mem{$addr};
2310
  }
2311
 
2312
  return;
2313
}
2314
 
2315
#-------------------------------------------------------------------------------
2316
 
2317
sub dump_rl {
2318
  my ($rl) = @_;
2319
 
2320
  printf "-- line:   '%s'\n", $$rl{line};
2321
  printf "   err=%-3s, typ=%-4s, oper=%-6s, lineno=%3d, psect=%-6s, .=%6.6o\n",
2322
    prt_err($rl), savestr($$rl{typ}), savestr($$rl{oper}), $$rl{lineno},
2323
      $$rl{psect}, $$rl{dot};
2324
  my $i = 0;
2325
  foreach my $rt (@{$$rl{tl}}) {
2326
    printf "   tl[%2d]: tag=%-4s, om=%-2s, em=%-2s, val='%s'",
2327
      $i, $$rt{tag}, savestr1($$rt{om}), savestr1($$rt{em}),
2328
        savestr($$rt{val});
2329
    printf ", nval=%6.6o",$$rt{nval} if defined $$rt{nval};
2330
    printf ", pend=%d",$$rt{pend} if defined $$rt{pend};
2331
    printf "\n";
2332
    $i += 1;
2333
  }
2334
  if (defined $$rl{delist}) {
2335
    $i = 0;
2336
    my $rdl = $$rl{delist};
2337
    foreach my $rd (@$rdl) {
2338
      printf "   dl[%2d]:", $i;
2339
      printf " str='%s'",$$rd{str} if defined $$rd{str};
2340
      printf " ibeg=%s, iend=%s", savestr($$rd{ibeg}), savestr($$rd{iend})
2341
        if exists $$rd{ibeg};
2342
      printf "\n";
2343
      $i += 1;
2344
    }
2345
  }
2346
  if (defined $$rl{opcode}) {
2347
    printf "   code: %6.6o,fmt=%-2s", $$rl{opcode}, $$rl{opfmt};
2348
    if (defined $$rl{o1mod}) {
2349
      printf ", o1=%s%s", $$rl{o1mod},$$rl{o1reg};
2350
      printf ",ei=%d:%d,val=%s", $$rl{o1ebeg}, $$rl{o1eend},
2351
        save66o(eval_exp($rl, $$rl{o1ebeg}, $$rl{o1eend}))
2352
          if defined $$rl{o1ebeg};
2353
    }
2354
    if (defined $$rl{o2mod}) {
2355
      printf ", o2=%s%s", $$rl{o2mod},$$rl{o2reg};
2356
      printf ",ei=%d:%d,val=%s", $$rl{o2ebeg}, $$rl{o2eend},
2357
        save66o(eval_exp($rl, $$rl{o2ebeg}, $$rl{o2eend}))
2358
          if defined $$rl{o2ebeg};
2359
    }
2360
    printf " ex=%d:%d,val=%s", $$rl{ebeg}, $$rl{eend},
2361
      save66o(eval_exp($rl, $$rl{ebeg}, $$rl{eend}))
2362
        if defined $$rl{ebeg};
2363
    print "\n";
2364
  }
2365
  if (scalar(@{$$rl{outw}})) {
2366
    print "   outw:";
2367
    foreach (@{$$rl{outw}}) { printf " %6.6o", $_; }
2368
    print "\n";
2369
  }
2370
  if (scalar(@{$$rl{outb}})) {
2371
    print "   outb:";
2372
    foreach (@{$$rl{outb}}) { printf " %3.3o", $_; }
2373
    print "\n";
2374
  }
2375
  foreach my $key (sort keys %{$rl}) {
2376
    next if $key =~ m/^(line|err|typ|oper|lineno|psect|dot|opcode|opfmt|o[12](mod|reg|ebeg|eend)|ebeg|eend|tl|delist|outw|outb)$/;
2377
    printf "   %-6s: %s\n", $key, savestr($$rl{$key});
2378
  }
2379
  return;
2380
}
2381
 
2382
#-------------------------------------------------------------------------------
2383
 
2384
sub dump_sym {
2385
  print "\n";
2386
  print " psect    dot dotmax\n";
2387
  print "------ ------ ------\n";
2388
  foreach my $ps (sort keys %psect) {
2389
    printf "%-6s %6.6o %6.6o\n", $ps, $psect{$ps}{dot}, $psect{$ps}{dotmax};
2390
  }
2391
 
2392
  print "\n";
2393
  print "scope  symbol  typ  psect     val\n";
2394
  print "------ ------ ---- ------  ------\n";
2395
  foreach my $key (sort keys %lst) {
2396
    my $sym = $lst{$key}{name};
2397
    my $scope = '';
2398
    my $name = $sym;
2399
    if ($sym =~ m/^(.+):(.+)$/) {
2400
      $scope = $1;
2401
      $name  = $2;
2402
    }
2403
    printf "%-6s %-6s %-4s %-6s  %s\n", $scope, $name, $lst{$key}{typ},
2404
      $lst{$key}{psect}, save66o($lst{$key}{val});
2405
  }
2406
 
2407
  return;
2408
}
2409
 
2410
#-------------------------------------------------------------------------------
2411
 
2412
sub prt76o {
2413
  my ($val) = @_;
2414
  return '       ' unless defined $val;
2415
  return sprintf " %6.6o", $val;
2416
}
2417
 
2418
#-------------------------------------------------------------------------------
2419
 
2420
sub prt43o {
2421
  my ($val) = @_;
2422
  return '    ' unless defined $val;
2423
  return sprintf " %3.3o", $val;
2424
}
2425
 
2426
#-------------------------------------------------------------------------------
2427
 
2428
sub save66o {
2429
  my ($val) = @_;
2430
  return '' unless defined $val;
2431
  return sprintf "%6.6o", $val;
2432
}
2433
 
2434
#-------------------------------------------------------------------------------
2435
 
2436
sub savestr {
2437
  my ($str) = @_;
2438
  return '' unless defined $str;
2439
  return $str;
2440
}
2441
 
2442
#-------------------------------------------------------------------------------
2443
 
2444
sub savestr1 {
2445
  my ($str) = @_;
2446
  return '-' unless defined $str;
2447
  return $str;
2448
}
2449
 
2450
#-------------------------------------------------------------------------------
2451
 
2452
sub print_help {
2453 22 wfjm
  print "usage: asm-11 [OPTIONS]... [FILE]...\n";
2454
  print "  --I=path      adds path to the .include search path\n";
2455 19 wfjm
  print "  --lst         create listing (default file name)\n";
2456
  print "  --olst=fnam   create listing (concrete file name)\n";
2457
  print "  --lda         create absolute loader output (default file name)\n";
2458
  print "  --olda        create absolute loader output (concrete file name)\n";
2459
  print "  --cof         create compound output (default file name)\n";
2460
  print "  --ocof=fnam   create compound output (concrete file name)\n";
2461
  print "  --tpass1      trace line context in pass 1\n";
2462
  print "  --tpass2      trace line context in pass 2\n";
2463
  print "  --dsym1       dump psect and ust tables after pass 1\n";
2464
  print "  --dsym2       dump psect and ust tables after pass 2\n";
2465
  print "  --ttoken      trace tokenizer\n";
2466
  print "  --tparse      trace parser\n";
2467
  print "  --temit       trace code emit\n";
2468
  print "  --tout        trace output file write\n";
2469
  print "  --help        print this text and exit\n";
2470
  return;
2471
}

powered by: WebSVN 2.1.0

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