Initial commit

This commit is contained in:
Jeff Epler 2014-08-07 18:57:30 -05:00
commit 0b7557de0f
8 changed files with 597 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.pyc

100
README Normal file
View file

@ -0,0 +1,100 @@
ptasm (1)
=========
NAME
----
ptasm - Table driven assembler
SYNOPSIS
--------
[verse]
'ptasm' [-t table.py] [file|'-']
DESCRIPTION
-----------
ptasm is a table-driven assembler written primarily to assemble code
for simple embedded cores like Peter Wallace's "DumbAss8" family.
However, the passive voice hopes it is suitable to target other CPU
architectures.
OPTIONS
-------
-t::
Specify the instruction set table, which is a Python file that
calls Insn() repeatedly to specify each instruction format. The
default is +d8_tab.py+.
COPYRIGHT
---------
While some files may offer a more permissive license, the project
as a whole is under the following disjunctive dual license giving you the
choice of one of the two following sets of free software/open source licensing
terms:
* GNU General Public License (GPL), version 2.0 or later
* 3-clause BSD License
The GNU GPL License
~~~~~~~~~~~~~~~~~~~
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
The 3-clause BSD License
~~~~~~~~~~~~~~~~~~~~~~~~
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
* Neither the name of Mesa Electronics nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior written
permission.
Disclaimer:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright of this README file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without any warranty.

22
d8.a Normal file
View file

@ -0,0 +1,22 @@
; A trivial file exercising the d8 assembler subset implemented so far
; Copying and distribution of this file, with or without modification,
; are permitted in any medium without royalty provided the copyright
; notice and this notice are preserved. This file is offered as-is,
; without any warranty.
nop
nop
nop
start:
ldib 0x0
stab ledloc
ldib 0xff
stab ledloc
jmp start
ledloc = 0x123
ldab @x
ldab @x, 0
ldab @x, 19

17
d8_tab.py Normal file
View file

@ -0,0 +1,17 @@
# -*- python -*-
# (subset) table for "DumbAss8" embedded computing core
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved. This file is offered as-is,
# without any warranty.
from pta.BasicWordInstruction import *
Insn('ldib *', I8, 0x01)
Insn('stab *', I10, 0xB1)
Insn('jmp *', I11, 0x10)
Insn('nop', I0, 0x00)
Insn('ldab @x', I0, 0x74)
Insn('ldab @x,*', I7, 0x74)

View file

@ -0,0 +1,95 @@
# -*- python coding: utf-8 -*-
#
# Copyright © 2014 Jeff Epler http://emergent.unpythonic.net
#
# This program is is licensed under a disjunctive dual license giving you
# the choice of one of the two following sets of free software/open source
# licensing terms:
#
# * GNU General Public License (GPL), version 2.0 or later
# * 3-clause BSD License
#
#
# The GNU GPL License:
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
#
# The 3-clause BSD License:
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# * Neither the name of Mesa Electronics nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
#
# Disclaimer:
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
def nbits(b, v):
if v >= (1<<b) or (b > 1 and v <= -(1<<(b-1))):
raise ValueError, "%d (0x%x) doesn't fit in %d bits" % (v, v, b)
return v & ((1<<b) - 1)
_8 = lambda v: nbits(8)
def unbits(b, v):
if v >= (1<<b) or v < 0:
raise ValueError, "%d (0x%x) doesn't fit in %d bits" % (v, v, b)
return v
class BasicInstruction:
def __init__(self, hi8, _, arg=0):
self.hi8 = hi8
self.arg = arg
@property
def length(self): return 1
def assemble(self, assembler):
v = assembler.symval(self.arg)
return [(self.hi8 << 8) | nbits(self.argwidth, v)]
class I0(BasicInstruction): argwidth=0
class I7(BasicInstruction): argwidth=7
class I8(BasicInstruction): argwidth=8
class I10(BasicInstruction): argwidth=10
class I11(BasicInstruction): argwidth=11
class I16(BasicInstruction): argwidth=16

65
pta/__init__.py Normal file
View file

@ -0,0 +1,65 @@
# -*- python coding: utf-8 -*-
#
# Copyright © 2014 Jeff Epler http://emergent.unpythonic.net
#
# This program is is licensed under a disjunctive dual license giving you
# the choice of one of the two following sets of free software/open source
# licensing terms:
#
# * GNU General Public License (GPL), version 2.0 or later
# * 3-clause BSD License
#
#
# The GNU GPL License:
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
#
# The 3-clause BSD License:
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# * Neither the name of Mesa Electronics nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
#
# Disclaimer:
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
__all__ = ['grammar']

108
pta/grammar.py Normal file
View file

@ -0,0 +1,108 @@
# -*- python coding: utf-8 -*-
#
# Copyright © 2014 Jeff Epler http://emergent.unpythonic.net
#
# This program is is licensed under a disjunctive dual license giving you
# the choice of one of the two following sets of free software/open source
# licensing terms:
#
# * GNU General Public License (GPL), version 2.0 or later
# * 3-clause BSD License
#
#
# The GNU GPL License:
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
#
# The 3-clause BSD License:
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# * Neither the name of Mesa Electronics nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
#
# Disclaimer:
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from pyparsing import *
if not hasattr(Forward, "__ilshift__"):
Forward.__ilshift__ = Forward.__lshift__
PLUS = (None, 1)
STAR = (None, None)
Identifier = Word( srange("[a-zA-Z_]"), srange("[a-zA-Z0-9_]") )
Number = Regex(r"[-+]?(?:0x[0-9a-fA-F]*|0[0-7]*|[1-9][0-9]*|0)")
Label = (Identifier + ":").setParseAction(lambda s, loc, toks: toks[0]
).setResultsName("label")
Expression = Forward().setName("expression")
Value = Identifier | Number | ('(' + Expression + ')')
Product = Value + (Word('*/', max=1) + Value) * STAR
Sum = Product + (Word('-+', max=1) + Product) * STAR
PyExpression = QuotedString("`", escChar="\\", unquoteResults=True)
Expression <<= Sum | PyExpression
PyCode = QuotedString("```", escChar="\\", unquoteResults=True
).setResultsName("pycode")
Assignment = (Identifier.setResultsName("id") + "=" + Combine(Expression).setResultsName("expr")
).setResultsName("assignment")
OpaquePart = Regex('[a-zA-Z0-9_]+|[^\s*,]')
Instruction = Identifier + (OpaquePart | "," | "*")*STAR
def InstructionPatternToParseElement(s, f):
p = Instruction.parseString(s, True)
indices = [0]
parts = []
for i, si in enumerate(p):
if si == "*":
indices.append(i)
parts.append(Combine(Expression))
else:
parts.append(Literal(si))
def extractparts(s, l, toks):
return f(*(toks[i] for i in indices))
rule = And(parts)
# setParseAction's wrapper balls us up real bad
rule.parseAction = [extractparts]
return rule

189
ptasm.py Normal file
View file

@ -0,0 +1,189 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright © 2014 Jeff Epler http://emergent.unpythonic.net
#
# This program is is licensed under a disjunctive dual license giving you
# the choice of one of the two following sets of free software/open source
# licensing terms:
#
# * GNU General Public License (GPL), version 2.0 or later
# * 3-clause BSD License
#
#
# The GNU GPL License:
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
#
# The 3-clause BSD License:
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# * Neither the name of Mesa Electronics nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
#
# Disclaimer:
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import getopt
import os
import sys
from pta.grammar import *
Instruction = Forward()
Org = (Literal(".org") + Combine(Expression)).setResultsName("origin")
Grammar = (
Assignment
#| (PyCode).setResultsName("pycode")
| (Optional(Label) + Instruction.setResultsName("instruction"))
| Label
| Org) * (None, 1)
def strip(line):
return line.strip().split(";", 1)[0]
class Assembler:
def __init__(self):
self.InstructionSet = {}
def run(self, program, filename):
self.rom = {}
self.symbols = {}
self.input(program, filename)
self.pass1()
self.pass2()
def input(self, program, filename):
self.filename = filename
program = ((i+1, strip(line))
for i, line in enumerate(program.split("\n")))
self.program = [(i, Grammar.parseString(line, True))
for i, line in program if line]
def symval(self, expr):
if not expr: return 0
return eval(expr, self.symbols)
def error(self, lno, err):
print "%s:%d: %s" % (self.filename, lno, err)
raise SystemExit
def pass1(self):
self.symbols['__passno__'] = 1
addr = 0
lno = 0
for lno, line in self.program:
self.symbols['__lno__'] = lno
self.symbols['__addr__'] = addr
if line.origin:
addr = self.symval(line.origin[1])
if line.label:
self.symbols[line.label] = addr
if line.instruction:
instruction = line.instruction[0]
addr += instruction.length
if line.assignment:
self.symbols[line.id] = self.symval(line.expr)
def pass2(self):
self.symbols['__passno__'] = 2
addr = 0
for lno, line in self.program:
self.symbols['__lno__'] = lno
self.symbols['__addr__'] = addr
if line.origin:
addr = self.symval(line.origin[1])
if line.instruction:
instruction = line.instruction[0]
for i, w in enumerate(instruction.assemble(self)):
self.rom[addr + i] = w
addr += instruction.length
def main():
tabname = "d8_tab.py"
opts, args = getopt.getopt(sys.argv[1:], "t:")
if not args:
filename = '-'
elif len(args) > 1:
raise SystemExit, "usage: %s [-t table] [filename]" % sys.argv[0]
else: filename = args[0]
for k, v in opts:
if k == '-t': tabname = v
if filename == '-': program = sys.stdin.read()
else: program = open(filename).read()
assembler = Assembler()
def Insn(a, b, *args, **kw):
def inner(*toks):
if toks is None: return
return b(*args + toks, **kw)
assembler.InstructionSet[a] = inner
Value = lambda v: assembler.symval(v)
ns = {'__name__': os.path.splitext(os.path.basename(tabname))[0],
'Insn': Insn, 'assembler': assembler, 'Value': Value}
execfile(tabname, ns)
global Instruction
Instruction <<= Or(Group(InstructionPatternToParseElement(k, v))
for k, v in assembler.InstructionSet.items())
assembler.run(program, filename)
max_insn = max(assembler.rom.keys())
rom = [assembler.rom.get(i) for i in range(max_insn + 1)]
for i in range(0, len(rom), 8):
print "%04x:" % i,
for b in rom[i:i+8]:
print "%04x" % (b or 0),
print
if __name__ == '__main__': main()