@@ -18,6 +18,7 @@ def __init__(self, assembly, lineno):
18
18
self .fmt = 0
19
19
self .loc = None
20
20
self .base = - 1
21
+ self .litpool = []
21
22
22
23
def __str__ (self ):
23
24
return self .assembly
@@ -38,6 +39,8 @@ def listing_tuple(self):
38
39
if self .code != "" :
39
40
codefmt = "%%0%dX" % (self .fmt * 2 )
40
41
codefmt = codefmt % self .code
42
+ if any (self .litpool ):
43
+ locfmt = ""
41
44
return (self .lineno , locfmt , self .src .expandtabs (8 ), codefmt )
42
45
43
46
# class to store each program info
@@ -52,6 +55,8 @@ def __init__(self, source):
52
55
self .lineno = 0
53
56
self .content = list (Line (line .strip ('\n ' ), lineno ) for lineno , line in enumerate (open (source , "r" ).readlines (), 1 ))
54
57
self .symtab = PRELOAD_SYMTAB .copy ()
58
+ self .littab = {}
59
+ self .endlitpool = []
55
60
self .base = - 1
56
61
57
62
# print error message indicating the line number and throw the error
@@ -81,6 +86,10 @@ def assemble(self):
81
86
continue
82
87
else :
83
88
program .error ("Except a directive, opcde or label." )
89
+ end_LITPOOL (self )
90
+ for k , v in self .symtab .items ():
91
+ if type (v ) == list :
92
+ program .error ("Undefined symbol %s." % v )
84
93
85
94
# write assembly listing to file
86
95
def listing (self , filename ):
@@ -90,6 +99,23 @@ def listing(self, filename):
90
99
f .write (fmt % ("Lineno" , "LOCCTR" , "Source Statements" , "Object Code" ))
91
100
for line in self .content :
92
101
f .write (fmt % line .listing_tuple ())
102
+ if any (line .litpool ):
103
+ for lit in line .litpool :
104
+ code = lit [2 ]
105
+ if lit [1 ][0 ] == 'C' :
106
+ code = "%%0%dX" % (len (lit [1 ]) - 3 )
107
+ code = code % lit [2 ]
108
+ elif lit [1 ][0 ] == 'X' :
109
+ code = "%02X" % lit [2 ]
110
+ f .write (fmt % ("" , "%04X" % lit [0 ], "*\t " .expandtabs (8 ) + lit [1 ], code ))
111
+ for lit in self .endlitpool :
112
+ code = lit [2 ]
113
+ if lit [1 ][0 ] == 'C' :
114
+ code = "%%0%dX" % (len (lit [1 ]) - 3 )
115
+ code = code % lit [2 ]
116
+ elif lit [1 ][0 ] == 'X' :
117
+ code = "%02X" % lit [2 ]
118
+ f .write (fmt % ("" , "%04X" % lit [0 ], "*\t " .expandtabs (8 ) + lit [1 ], code ))
93
119
94
120
# get current line
95
121
def current_line (self ):
@@ -178,7 +204,7 @@ def handler_START(program, tokens):
178
204
program .current_line ().loc = None
179
205
180
206
def handler_END (program , tokens ):
181
- program .current_line ().loc = Nones
207
+ program .current_line ().loc = None
182
208
183
209
def handler_BYTE (program , tokens ):
184
210
if tokens [0 ] == "BYTE" :
@@ -252,6 +278,50 @@ def handler_NOBASE(program, tokens):
252
278
program .base = - 1
253
279
program .current_line ().loc = None
254
280
281
+ def handler_LTORG (program , tokens ):
282
+ for key , lit_lst in program .littab .items ():
283
+ if key [0 ] == 'C' :
284
+ hexstr = '' .join (["%2X" % c for c in key [2 :- 1 ].encode ()])
285
+ code = int (hexstr , 16 )
286
+
287
+ fill_lit (lit_lst , program .LOCCTR , program )
288
+ program .littab [key ] = program .LOCCTR
289
+ program .current_line ().litpool .append ((program .LOCCTR , key , code ))
290
+ program .LOCCTR += len (key [2 :- 1 ])
291
+ elif key [0 ] == 'X' :
292
+ try :
293
+ code = int (key [2 :- 1 ], 16 )
294
+ fill_lit (lit_lst , program .LOCCTR , program )
295
+ program .littab [key ] = program .LOCCTR
296
+ program .current_line ().litpool .append ((program .LOCCTR , key , code ))
297
+ program .LOCCTR += 1
298
+ except ValueError :
299
+ program .error ("The \" X\" requires a hex value, but %s is not." % value [2 :- 1 ])
300
+
301
+ def end_LITPOOL (program ):
302
+ for key , lit_lst in program .littab .items ():
303
+ if type (lit_lst ) != list :
304
+ continue
305
+ if key [0 ] == 'C' :
306
+ hexstr = '' .join (["%2X" % c for c in key [2 :- 1 ].encode ()])
307
+
308
+ fill_lit (lit_lst , program .LOCCTR , program )
309
+ program .littab [key ] = program .LOCCTR
310
+ program .endlitpool .append ((program .LOCCTR , key , hexstr ))
311
+ program .LOCCTR += len (key [2 :- 1 ])
312
+ elif key [0 ] == 'X' :
313
+ try :
314
+ code = int (key [2 :- 1 ], 16 )
315
+ fill_lit (lit_lst , program .LOCCTR , program )
316
+ program .littab [key ] = program .LOCCTR
317
+ program .endlitpool .append ((program .LOCCTR , key , code ))
318
+ program .LOCCTR += 1
319
+ except ValueError :
320
+ program .error ("The \" X\" requires a hex value, but %s is not." % value [2 :- 1 ])
321
+
322
+ def handler_EQU (program , tokens ):
323
+ print ("EQU" )
324
+
255
325
DIRTAB = {
256
326
"START" : handler_START ,
257
327
"END" : handler_END ,
@@ -261,6 +331,8 @@ def handler_NOBASE(program, tokens):
261
331
"RESW" : handler_RESW ,
262
332
"BASE" : handler_BASE ,
263
333
"NOBASE" : handler_NOBASE ,
334
+ "LTORG" : handler_LTORG ,
335
+ "EQU" : handler_EQU ,
264
336
}
265
337
266
338
# fill the instructions which referencing foward symbols
@@ -274,7 +346,7 @@ def fill_forward(fwd_lst, addr, program):
274
346
elif line .base != - 1 :
275
347
# if base is defined
276
348
if line .base in program .symtab and type (program .symtab [line .base ]) != list :
277
- disp = (program . symtab [ operand ] - program .symtab [line .base ])
349
+ disp = (addr - program .symtab [line .base ])
278
350
if 0 <= disp < 4096 :
279
351
code |= (disp & 0xFFF ) | BASE_RELATIVE
280
352
else :
@@ -295,6 +367,30 @@ def fill_forward(fwd_lst, addr, program):
295
367
else :
296
368
program .error ("no enough length to hold the displacement, try format 4." , line )
297
369
370
+ def fill_lit (lit_lst , addr , program ):
371
+ for line in lit_lst :
372
+ if line .fmt == 3 :
373
+ disp = (addr - (line .loc + line .fmt ))
374
+ if - 2048 <= disp < 2048 :
375
+ line .code |= (disp & 0xFFF ) | PC_RELATIVE
376
+ elif line .base != - 1 :
377
+ # if base is defined
378
+ if line .base in program .symtab and type (program .symtab [line .base ]) != list :
379
+ disp = (addr - program .symtab [line .base ])
380
+ if 0 <= disp < 4096 :
381
+ code |= (disp & 0xFFF ) | BASE_RELATIVE
382
+ else :
383
+ program .error ("no enough length to hold the displacement, try format 4." , line )
384
+ # forward base reference
385
+ elif line .base in program .symtab :
386
+ program .symtab [line .base ].append ((program .current_line (), REF_BASE ))
387
+ else :
388
+ program .symtab [line .base ] = [(program .current_line (), REF_BASE )]
389
+ else :
390
+ program .error ("no enough length to hold the displacement, try format 4." , line )
391
+ elif line .fmt == 4 :
392
+ line .code |= addr
393
+
298
394
def has_directives (program , tokens ):
299
395
for token in tokens :
300
396
if token in DIRTAB :
@@ -342,7 +438,7 @@ def has_instructions(program, tokens):
342
438
else :
343
439
if token .find (',' ) != - 1 :
344
440
operand , operand2 , * dummy = token .split (',' )
345
- if len (dummy ) > 1 :
441
+ if any (dummy ):
346
442
program .error ("too many operands" )
347
443
else :
348
444
operand = token
@@ -358,11 +454,12 @@ def has_instructions(program, tokens):
358
454
# validate the foramt
359
455
if (operand2 != "" and fmt != 2 ) and operand2 != 'X' :
360
456
program .error ("Only format 2 insturctions allow two operands." )
361
- if fmt < 3 and operand2 == 'X' :
362
- program .error ("Only format 3 and 4 allow indexed addresing " )
457
+ if fmt == 1 and operand != "" :
458
+ program .error ("Format 1 instructions should not have any operands. " )
363
459
364
460
# generate opcode
365
461
code = OPTAB [inst ].opcode
462
+ isLiteral = False
366
463
# parse the prefix for format 3 & 4 instructions
367
464
if (fmt == 3 or fmt == 4 ) and inst != "RSUB" :
368
465
prefix = ""
@@ -377,6 +474,17 @@ def has_instructions(program, tokens):
377
474
mask = IMM_ADDR
378
475
elif prefix == '@' :
379
476
mask = INDR_ADDR
477
+ elif prefix == '=' :
478
+ isLiteral = True
479
+ if operand not in program .littab :
480
+ program .littab [operand ] = [program .current_line ()]
481
+ # already defined or is not yet
482
+ elif operand in program .littab :
483
+ # try to use
484
+ # but if is too far, wait next
485
+ pass
486
+ else :
487
+ program .littab [operand ].append (program .current_line ())
380
488
elif prefix != "" :
381
489
program .error ("Unrecognized addressing prefix \" %s\" ." % prefix )
382
490
@@ -393,9 +501,9 @@ def has_instructions(program, tokens):
393
501
# shift format 4 instructions
394
502
if fmt == 4 :
395
503
code <<= BYTESIZE
396
-
504
+
397
505
# generate operand
398
- if inst != "RSUB" :
506
+ if inst != "RSUB" and not isLiteral :
399
507
if operand .isnumeric ():
400
508
operand = int (operand )
401
509
if (fmt == 3 and operand > 2 ** 12 - 1 ) or (fmt == 4 and operand > 2 ** 20 - 1 ):
0 commit comments