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

Subversion Repositories ssbcc

[/] [ssbcc/] [trunk/] [core/] [9x8/] [asm] - Blame information for rev 12

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 sinclairrf
#!/usr/bin/python2.7
2
 
3
################################################################################
4
#
5 12 sinclairrf
# Copyright 2012-2015, Sinclair R.F., Inc.
6 2 sinclairrf
#
7
# Assembler for SSBCC 9x8 processor
8
#
9
################################################################################
10
 
11
# global modules
12
import argparse
13 11 sinclairrf
import os
14 2 sinclairrf
import re
15
import sys
16
 
17
# User defined modules
18
import asmDef
19
 
20
################################################################################
21
#
22
# Surround the program with a try ... except clause
23
#
24
################################################################################
25
 
26
try:
27
 
28
  ################################################################################
29
  #
30
  # The main loop:
31
  #
32
  # - Process the command line arguments.
33
  #
34
  ################################################################################
35
 
36
  #
37
  # Construct the command-line argument list parser
38
  #
39
 
40
  def validateFile(filename):
41
    try:
42
      return file(filename,'r');
43
    except:
44
      raise asmDef.AsmException('Error opening "%s"' % filename);
45
 
46
  argListParser = argparse.ArgumentParser(description='SSBCC 9x8 assembler');
47
  argListParser.add_argument('-C', metavar='CONSTANT=value', action='append', help='Constant definition');
48 9 sinclairrf
  argListParser.add_argument('-D', metavar='define', type=str, action='append', help='Define symbol (must start with "D_")');
49 2 sinclairrf
  argListParser.add_argument('-G', metavar='parametername', action='append', help='parameter names');
50
  argListParser.add_argument('-I', metavar='PORT=index', action='append', help='Input port names');
51
  argListParser.add_argument('-L', metavar='librarypath', action='append', help='Library search path');
52 3 sinclairrf
  argListParser.add_argument('-M', metavar='macropath', action='append', help='Macro search path');
53 2 sinclairrf
  argListParser.add_argument('-O', metavar='PORT=index', action='append', help='Output port names');
54
  argListParser.add_argument('-R', metavar='PORT=index', action='append', help='Strobe-only output port names');
55
  argListParser.add_argument('-S', metavar='MEMORY=length', action='append', help='Memory length');
56 11 sinclairrf
  argListParser.add_argument('--help-macro', metavar='macroName', type=str, help='Display usage message for the specified macro');
57 2 sinclairrf
  argListParser.add_argument('-i', action='store_true', help='enable/require interrupt');
58 11 sinclairrf
  argListParser.add_argument('--list-macros', action='store_true', help='list the built-in and user-defined macros');
59 2 sinclairrf
  argListParser.add_argument('-o', metavar='outfile', type=argparse.FileType('w'), required =True, help='output metafile');
60
  argListParser.add_argument('-s', metavar='STACK_NAME=length', action='append', help='Stack length');
61
  argListParser.add_argument('filename', metavar='filename', nargs='+', type=validateFile, help='required list of files');
62
  argList = argListParser.parse_args();
63
 
64 12 sinclairrf
  # Determine whether or not interrupts are enabled
65
  interruptsEnabled = True if argList.i else False;
66
 
67 2 sinclairrf
  # Construct the keyword parser
68
  from asmDef_9x8 import asmDef_9x8
69 12 sinclairrf
  ad = asmDef_9x8(interruptsEnabled);
70 2 sinclairrf
 
71
  # Record the constants in the program symbol table.
72
  if argList.C:
73
    for constant in argList.C:
74 9 sinclairrf
      a=re.findall(r'^(C_\w+)=(-?[1-9]\d*|\w+)$',constant);
75 2 sinclairrf
      if not a:
76
        raise asmDef.AsmException('Malformed -C argument: "%s"' % constant);
77
      a = list(a[0]);
78
      try:
79
        a[1] = eval(a[1]);
80
      except:
81
        raise asmDef.AsmException('Cannot evaluate "%s"' % a[1]);
82
      if ad.IsSymbol(a[0]):
83
        raise asmDef.AsmException('Command line constant "%s" already defined' % a[0]);
84
      ad.AddSymbol(a[0], 'constant', body=[a[1]]);
85
 
86 9 sinclairrf
  # Record the defines.
87
  if argList.D:
88
    for name in argList.D:
89
      if not re.match('D_',name):
90 12 sinclairrf
        raise asmDef.AsmException('Argument "%s" to "%s" should start with "D_"' % (name,sys.argv[0],));
91 9 sinclairrf
      ad.AddSymbol(name, 'define');
92
 
93 2 sinclairrf
  # Record the input names and values in the appropriate record type
94
  if argList.G:
95
    for parameter in argList.G:
96
      a = re.findall(r'^([LG]_\w+)$',parameter);
97
      if not a:
98
        raise asmDef.AsmException('Malformed -G argument: "%s"' % parameter);
99
      if ad.IsSymbol(a[0]):
100
        raise asmDef.AsmException('Program Bug -- repeated symbol "%s"' % a[0]);
101
      ad.RegisterParameterName(a[0]);
102
  if argList.I:
103
    for inport in argList.I:
104
      a=re.findall(r'^(I_\w+)=(0|[1-9]\d*)$',inport);
105
      if not a:
106
        raise asmDef.AsmException('Malformed -I argument: "%s"' % inport);
107
      a = a[0];
108
      if ad.IsSymbol(a[0]):
109
        raise Exception('Program Bug -- repeated symbol "%s"' % a[0]);
110
      ix = int(a[1]);
111
      if not (0 <= ix < 256):
112
        raise asmDef.AsmException('Out-of-range inport index:  "%s"' % inport);
113
      ad.RegisterInport(a[0],ix);
114
  if argList.O:
115
    for outport in argList.O:
116
      a=re.findall(r'^(O_\w+)=(0|[1-9]\d*)$',outport);
117
      if not a:
118
        raise asmDef.AsmException('Malformed -O argument: "%s"' % outport);
119
      a = a[0];
120
      if ad.IsSymbol(a[0]):
121
        raise asmDef.AsmException('Program Bug -- repeated symbol "%s"' % a[0]);
122
      ix = int(a[1]);
123
      if not (0 <= ix < 256):
124
        raise asmDef.AsmException('Out-of-range outport index:  "%s"' % outport);
125
      ad.RegisterOutport(a[0],ix);
126
  if argList.R:
127
    for outstrobe in argList.R:
128
      a=re.findall(r'^(O_\w+)=(0|[1-9]\d*)$',outstrobe);
129
      if not a:
130
        raise asmDef.AsmException('Malformed -R argument: "%s"' % outstrobe);
131
      a = a[0];
132
      if ad.IsSymbol(a[0]):
133
        raise asmDef.AsmException('Program Bug -- repeated symbol "%s"' % a[0]);
134
      ix = int(a[1]);
135
      if not (0 <= ix < 256):
136
        raise asmDef.AsmException('Out-of-range strobe-only outport index:  "%s"' % outstrobe);
137
      ad.RegisterOutstrobe(a[0],ix);
138
  if argList.S:
139
    for memory in argList.S:
140
      a=re.findall(r'^(\w+)=(0|[1-9]\d*)$',memory);
141
      if not a:
142
        raise asmDef.AsmException('Malformed -S argument: "%s"' % memory);
143
      a=a[0];
144
      length = int(a[1]);
145
      if not (0 < length <= 256):
146
        raise asmDef.AsmException('Out-of-range memory length:  "%s"' % outport);
147
      ad.RegisterMemoryLength(a[0],length);
148
  if argList.s:
149
    for stack in argList.s:
150
      a=re.findall(r'^(\w+)=(0|[1-9]\d*)$',stack);
151
      if not a:
152
        raise asmDef.AsmException('Malformed -s argument: "%s"' % stack);
153
      a = a[0];
154
      ad.RegisterStackLength(a[0],int(a[1]));
155
 
156
  # Construct the iterator that loops through the code bodies.
157
  fbi = asmDef.FileBodyIterator(argList.filename,ad);
158 3 sinclairrf
 
159
  # Add paths for the ".include" directive.
160 2 sinclairrf
  if argList.L:
161
    for path in argList.L:
162
      fbi.AddSearchPath(path);
163
 
164 3 sinclairrf
  # Add paths for the ".macro" directive.
165
  if argList.M:
166
    for path in argList.M:
167
      ad.AddMacroSearchPath(path);
168
 
169 11 sinclairrf
  ##############################################################################
170
  #
171
  # Terminating help messages
172
  #
173
  ##############################################################################
174
 
175
  # If asked, print the usage for the specified macro.
176
  if argList.help_macro:
177
    macroName = argList.help_macro
178
    if macroName[0] != '.':
179
      macroName = '.%s' % macroName
180
    if macroName not in ad.macros['list']:
181
      try:
182
        ad.AddUserMacro(macroName[1:])
183
      except:
184
        pass
185
    if macroName in ad.macros['list']:
186
      ix = ad.macros['list'].index(macroName)
187
      if ad.macros['doc'][ix]:
188
        print '\n%s usage message:' % macroName
189
        print ad.macros['doc'][ix]
190
      else:
191
        print '\nNo usage message for %s\n' % macroName
192
    else:
193
      print 'Macro "%s" not recognized or malformed' % macroName
194
    print 'Assembler terminated by "--help-macro" option'
195
    sys.exit(1)
196
 
197
  # If asked, list the available macros.
198
  if argList.list_macros:
199
    print '\nBuilt-in macros\n'
200
    tmp = [name for name in ad.macros['builtIn']]
201
    tmp.sort()
202
    for name in tmp:
203
      print name
204
    for testPath in ad.macroSearchPaths:
205
      if not os.path.isdir(testPath):
206
        continue
207
      for testName in os.listdir(testPath):
208
        if not re.match(r'.*\.py$',testName):
209
          continue;
210
        fullFile = os.path.join(testPath,testName);
211
        if not os.path.isfile(fullFile):
212
          continue
213
        try:
214
          execfile(fullFile)
215
          exec('%s(ad)' % testName[:-3])
216
        except:
217
          pass
218
    print '\nUser-defined macros\n'
219
    tmp = [name for name in ad.macros['list'] if name not in ad.macros['builtIn']]
220
    tmp.sort()
221
    for name in tmp:
222
      print name
223
    print
224
    print 'Assembler terminated by "--list-macros" option'
225
    sys.exit(1)
226
 
227 2 sinclairrf
  ################################################################################
228
  #
229
  # Stage 1:  Parse the files.
230
  #
231
  # Read the entire file, doing the following while reading the file:
232
  # - Store the raw content of each line or group of lines for output to the
233
  #   assembled memory initialization.
234
  #   Note: A group of lines consists the comment lines preceding a directive and
235
  #         the body of the directive.
236
  # - Convert group of lines into an array of the raw tokens.
237
  # - Check the integrity of the bodies defined by the list of raw tokens.
238
  # - For each array of raw tokens, incorporate already-defined symbols and update
239
  #   the assembler dictionaries.
240
  #   Note: At this point the space required for the function or main program
241
  #     is fully computed.
242
  #
243
  ################################################################################
244
 
245
  #
246
  # Loop through the directive bodies in the input files (including ".include"d
247
  # files).
248
  #
249
 
250
  ifstackStack = list();
251
  ifstack = None;
252
  for bl in fbi:
253
    filename = bl[0];
254
    startLine = bl[1];
255
    body = bl[2:];
256
    flc_loc = filename + ' at line ' + str(startLine+len(body)-1);
257
    # Start-of-file processing.
258
    if startLine == 0:
259
      if ifstack != None:
260
        ifstackStack.append(ifstack);
261
      ifstack = list();
262
    # End-of-file processing.
263
    elif startLine == -1:
264
      if len(ifstack) != 0:
265
        raise asmDef.AsmException('%d unmatched .IFDEF/.IFNDEF(s) at the end of %s' % (len(ifstack),filename,));
266
      if ifstackStack:
267
        ifstack = ifstackStack.pop();
268
      else:
269
        ifstack = None;
270
    # Handle conditional compilation directives.
271
    elif re.match(r'\s*\.ELSE\b',body[-1]):
272
      if not re.match(r'\s*\.ELSE\s*(;.*)?$',body[-1]):
273
        raise asmDef.AsmException('Malformed ".ELSE" in %s' % flc_loc);
274
      if not ifstack:
275
        raise asmDef.AsmException('Unmatched ".ELSE" in %s' % flc_loc);
276
      ifstack[-1] ^= True;
277
    elif re.match(r'\s*\.ENDIF\b',body[-1]):
278
      if not re.match(r'\s*\.ENDIF\s*(;.*)?$',body[-1]):
279
        raise asmDef.AsmException('Malformed ".ENDIF" in %s' % flc_loc);
280
      if not ifstack:
281
        raise asmDef.AsmException('Unmatched ".ENDIF" in %s' % flc_loc);
282
      ifstack.pop();
283
    elif re.match(r'\s*\.IFN?DEF\b',body[-1]):
284
      a = re.findall(r'\s*(\.IFN?DEF)\s*(\S+)\b\s*(;.*)?$',body[-1]);
285
      if not a:
286
        raise asmDef.AsmException('Malformed .IFDEF or .IFNDEF in %s' % flc_loc);
287
      a = a[0];
288
      ifstack.append(ad.IsSymbol(a[1]));
289
      if a[0] == '.IFNDEF':
290
        ifstack[-1] ^= True;
291
    # Ignore bodies rejected by conditional compilation.
292
    elif ifstack and not ifstack[-1]:
293
      pass;
294
    # ".include" directives don't have an associated body
295
    elif re.match(r'\s*\.include\s',body[-1]):
296
      a = re.findall(r'\s*\.include\s+(\S+)(\s*|\s*;.*)$',body[-1]);
297
      if not a:
298
        raise asmDef.AsmException('Malformed .include directive in %s' % flc_loc);
299
      a = a[0];
300
      fbi.Include(a[0]);
301
    # Parse the body of all other directives and ensure that only one ".main"
302
    # and one ".interrupt" are defined.
303
    else:
304
      rawTokens = asmDef.RawTokens(ad,filename,startLine,body);
305
      if not rawTokens:
306
        continue;
307
      ad.CheckRawTokens(rawTokens);
308
      ad.FillRawTokens(rawTokens);
309
 
310
  #
311
  # Ensure a ".main" body was declared.
312
  #
313
 
314
  if not ad.Main():
315
    raise asmDef.AsmException('Required ".main" body not provided');
316
 
317
  #
318
  # Enforce consistency between the command-line "-i" flag and whether or not an
319
  # ".interrupt" body was declared.
320
  #
321
 
322
  if argList.i and not ad.Interrupt():
323
    raise asmDef.AsmException('Required ".interrupt" body not provided');
324
  if not argList.i and ad.Interrupt():
325
    raise asmDef.AsmException('".interrupt" body not allowed near %s' % ad.Interrupt()[0]['loc']);
326
 
327
  ################################################################################
328
  #
329
  # Stage 2:  Identify the required functions, compute their addresses, and set
330
  # the addresses for all "jump" and "call" macros.
331
  #
332
  ################################################################################
333
 
334
  ad.EvaluateMemoryTree();
335
  ad.EvaluateFunctionTree();
336
 
337
  ################################################################################
338
  #
339
  # Stage 3:  Emit the program
340
  #
341
  # Do the following:
342
  # - If interrupts are enabled, then set the first 4 instructions to be a "dis"
343
  #   and a ".jump" instruction to the ".interrupt" function.
344
  # - Write the instructions for the ".main" body.
345
  # - Loop through the ".function" list in the order in which they were defined
346
  #   and write their instructions.
347
  # - Print the memory and instruction usage statistics.
348
  #
349
  ################################################################################
350
 
351
  ad.EmitMemories(argList.o);
352
  ad.EmitProgram(argList.o);
353
  argList.o.close();
354
 
355
################################################################################
356
#
357
# Terminating except clause -- print fatal error message and indicate failure to
358
# the invoking program.
359
#
360
################################################################################
361
 
362
except asmDef.AsmException, msg:
363
  print >> sys.stderr, 'FATAL ERROR:  ' + str(msg);
364
  exit(1);

powered by: WebSVN 2.1.0

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