hi68kASM, The 68000 Assembler

Author: Helmi bin Ibrahim
Contact: helmi03@yahoo.com
Website:https://mrhelmi.tripod.com/assembler
Date: 25 Feb 2004
Copyright: Malaysia Boleh!. This document has been placed in the public domain.

Table of Contents

Let me know any suggestions, bugs, and comments. Feedback from user is the main motivation for the open source project :)

Introduction

An assembler for the 68000 microprocessor system development. The program process an assembly code file (.asm) and create the listing file(.lst) as the output. The format of listing file is compared to the Flight68k Cross-Assembler. This program is inspired from Easy68k (another GPL project). You should use the Easy68k (or others) if you serious in developing 68000 based project. The program best use by combination with SciTE (I don't want to build another editor since SciTE is good for most of users, although I prefer Vim). Please read known limitations first before use hi68kASM. For programmers, you can refer the API for this project. View snapshots, outputgif, debuggif, output_cmd, debug_cmd.

I discover the Python programming language after introduced in my favorite Java book, Thinking in Java 1. I start study Python early Dec 2003 and start this project at middle of Dec 2003. The Python bite me! I really love the concise and clear syntax of this programming language. Highly recommended :-). Long live Python Community!

Objectives

  1. I want to learn the Python language and at the same time build a software.
  2. As an assembler for the 68000 Simulator (My final year project for Degree in Electrical Engr. at UiTM, Malaysia)
  3. Use the regular expression.

Features

Differences

Some differences compared to the Flight68k Cross-Assembler. Please refer to examples in directory examples and listing files in the directory test/lst.

  1. Detail error reporting. Refer test/witherrs.lst and test/witherrs2.lst:

    1. hi68kASM

      # Assembler used: Helmi's Assembler
      (truncate here...)
      
      ERRORS INFO:
      ============
      **** ERROR, File "D:\assembler\test\with_errs.asm", line 7
      Operand 2 not Immediate:     link    a3,^$12
      
      **** ERROR, File "D:\assembler\test\with_errs.asm", line 9
      Size not B: m    nbcd.^W    d2
      
      (truncate here...)
      
      Assembly FAILED
      13 errors
      0 warnings
      
    2. Flight68k Cross-Assembler

      witherrs.asm: **** ERROR at line 7       Bad addressing mode
          link    a3,$12^
      
      witherrs.asm: **** ERROR at line 9       Illegal forcing
      m    nbcd.W    ^d2
      
      (truncate here...)
      
      Pass 1 complete
      13 errors
      0 warnings
      
  2. Display symbol table. Refer test/withasm.lst. e.g:

    SYMBOL TABLE:
    
    Symbol    Value
    ------------------
    max       00400404
    

Known Limitations

  1. Cannot evaluate expression in operands. e.g:

    move    32+2-1,d0  ;can't evaluate 32+2-1
    
  2. Do not recognize symbol in addressing mode Adresss Register Indirect with Displacement and Address Register Indirect with Index. e.g:

    sym1    nop
            move    #$1234,sym1(a0)          ;don't know sym1
            move    #$1234,sym1(a0,d3)       ;don't know sym1
    
  3. Not implemented yet:

    • Instruction Movem
    • Addressing mode SP, PC with Displacement and PC with Index
    • Output for machine code (.bin)

Example of usage

An example of assembly code:

org         $400400

move.w      #$1234,d0
addi.b      #$34,d0
nop

end

Write the example above in a text editor, e.g. Notepad, SciTE 3, etc, and save as example.asm. View source for this example.

Assumed that you had installed the Python and the assembler in your platform, you can assemble this example by execute the command_line or execute in_SciTE.

TODO: Explain in SciTE then command line, state clearly diff win-binary dist and source dist

Command line

Write this command in a console, e.g. cmd.exe in WindowsXP. Assume that the assembler.py in current working directory:

python assembler.py example.asm

Then, the console will display the output as below.:

\/ Begin process example.asm
Commencing first pass ... OK

# Assembler used: Helmi's Assembler
# Source: File "example.asm"
# Created on: Sun 29 Feb 2004, 01:01 AM


LINE  LOCATION OBJECT CODE          SOURCE TEXT
----- -------- -------------------- ------------------------------
    1 00400400                          org       $400400
    2
    3 00400400 303C1234                 move.w    #$1234,d0
    4 00400404 06000034                 addi.b    #$34,d0
    5 00400408 4E71                     nop
    6
    7                                   end

Assembly complete
Bytes filed: 10
0 errors
0 warnings
/\ End process example.asm

To create a listing file, add flag -f in the command. e.g:

python assembler.py -f example.asm

A file, example.lst will be created. You can use this to simulate the operation in my 68000_Simulator.

Tips:

Try replace ``python`` to ``C:\Python23\python.exe`` 
(path where you installed the Python_)

See snapshots of a typical usage in my platform, output_cmd, debug_cmd

In SciTE

This is my favorite source editor :-). Open the SciTE 3 and choose menu Options>Open asm.properties. Add the following lines in the properties and save:

command.name.1.*.asm=assemble
command.1.*.asm=python assembler.py "$(FileNameExt)"
command.1.subsystem.*.asm=2

command.name.2.*.asm=assemble (create lst file)
command.2.*.asm=python assembler.py -f "$(FileNameExt)"
command.2.subsystem.*.asm=2

Open the example.asm. Choose Tools>assembler. assembler.py will process the file and display the expected outputgif at Output (choose menu View>Output or press F8).

Two new submenus in Tools will appear every time you open a file (.asm). Note at line command.1.*.asm. The format is command.1.*.asm= <Where is the Python> <Where is the assembler> <the filename>. In SciTE, $(FileNameExt) is the name for current file opened.

See snapshots of a typical usage in my platform, outputgif, debuggif

Discussions

What I like about Python!

Part of Python that I found elegant, concise, and readable. This part is for my reference and intended to who interested to programming using the Python language. I show part of the source code from hi68kASM that I used it.

  1. Data structure.

    • tuple. Refer operand.py:

      opList = (DnDirect, Abs, Imm, AnDirect, AnInd, AnIndPost,
               AnIndPre, AnIndDisp, AnIndIndex, PCDisp, PCIndex)
      
    • list. Refer method Assembler.process() in assembler.py:

      self.relocList = []
      
    • dictionary. Refer method Assembler.__init__() in assembler.py:

      self.symbolTable = {}
      

    tuple, list and dictionary are built in data types. For the Java programmers, the analogy are tuple = array, list = ArrayList/Vector, dictionary = HashMap.

  2. List comprehension.

    • filter. Refer class DataMode, in operand.py:

      modes = [op for op in opList if op is not AnDirect]
      
    • map. Refer method Directive.dc(), in assembler.py:

      val = [("%08X" % intPreSign(op))[-oft:] for op in self.ops.split(',')]
      
    • map and filter. Refer method _Opcode.extendOp(), in instruction.py:

      ext = [op.val for op in (self.op1, self.op2) if hasattr(op, "val")]
      

    A concise way to create a list by map, list, or both the values in the list/iterable. See also Python Tutorial, 5.1.4.

  3. Doctest 6.

    As example of usage and can run as a test script. Refer, assembler.py:

    class Directive:
       
        def __init__(self, asm, sym, size, ops):
             self.asm=asm; self.sym=sym; self.size=size; self.ops=ops
           
        def dc(self):
             """Define constant.
           
             >>> asm = Assembler()
             >>> ops = '$12,$13'
             >>> Directive(asm, '', 'b', ops).dc()
             '1213'
             >>> ops = '$12,$133'
             >>> Directive(asm, '', 'w', ops).dc()
             '00120133'
             >>> Directive(asm, '', 'l', ops).dc()
             '0000001200000133'
             """
             oft = {'b':2, 'l':8}.get(self.size, 4)  # Maybe size is None
             val = [("%08X" % intPreSign(op))[-oft:] for op in self.ops.split(',')]
             self.asm.incPc += oft*len(val)//2
             return "".join(val)
    
  4. Dynamic.

    • return type. Refer method Assembler.tokenize() in assembler.py:

      def tokenize(self, line, asList=False):
         ... (truncate..)
         res = sym, mne, ops
         if not asList:  # Return as dictionary.
             res = dict(zip(('sym', 'mne', 'ops'), res))
         return res      # Return as list.
      
    • import. Refer function my_import() in test_assembler.py:

      mod = __import__(name)
      
    • Getting object references. Refer method Assembler.assemble() in assembler.py:

      if hasattr(Directive, mne) and mne != '__init__':
          return getattr(Directive(self, sym, size, ops), mne)()
      
  5. New style class.

    • __getitem__. Refer class ListFile in listfile.py:

      def __getitem__(self, key):
          """
          >>> import assembler
          >>> lstFile = ListFile(assembler.Assembler(), 'Test')
          >>> lstFile.listTable.append('line 1')
          >>> print lstFile[0]
          line 1
          """
          try: 
              if self.errNo == 0:
                  return self.listTable[key]
              return self.listErr[key]
          except: return ''
      
  6. Regular Expressions.

    • Refer module operand.py:

      reReg = '(?P<reg>[0-7])'
      class DnDirect:    
          re1 = 'd%s' % reReg        
          def __init__(self, reg=None):
              """        
              >>> f = re.compile(DnDirect.re1).match("d3")
              >>> dn = DnDirect(**f.groupdict())
              >>> dn.reg
              3
              """
              self.reg = int(reg)
      

    Match a string to the regular expression. Then, get the found group as dict, and pass it as keyword to initialize a class.

Conclusion

TODO: Please refer API for the structure of classes, modules, etc for the 68000 Assembler.

instruction set
Design as classes not functions. Easy to extend, e.g. add method for the simulation.
operand parser
I had build a simple operand parser using regular expression. Recommend to refer EASy68K 4 for complete operand parser.
unit test
Build unit test before the code!. Make you confidence to refactor 5 the code. Provide doctest 6 is a good practice.
design pattern
Improve the design. Help for maintenance. I always keep refering to Patterns_in_Python and Thinking_in_Python.

License

GPL - General Public License


[1]page 75. You can download this book at http://www.bruceeckel.com
[2]I recommend you to buy the book. The online cookbook http://aspn.activestate.com/ASPN/Cookbook/Python
[3](1, 2) Scintilla Text Editor, http://www.scintilla.org/
[4]EASy68K Editor v1.7, http://www.wowgwep.com/EASy68K.htm
[5]refactor = process of taking working code and making it work better. 'better'='faster' or 'using less memory' or 'more elegantly'. See also, Dive into Python, http://diveintopython.org/.
[6](1, 2) doctest -- Testing docstrings represent reality. Chapter 5.2 in Python Library Reference.