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

Subversion Repositories w11

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

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

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

powered by: WebSVN 2.1.0

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