A universal assembler for TPT computers that aims to be as architecture-agnostic as possible and to support all computers ever made in TPT. If you're aware of one that I've missed, open an issue.
Computers currently supported (in alphabetical order):
- A728D280 and A728D28A by Sam_Hayzen
- B29K1QS60 by unnick
- I8M7D28S by Sam_Hayzen
- MAPS by drakide
- MICRO21 by RockerM4NHUN
- PTP7 by unnick
- R216K2A, R216K4A and R216K8B by LBPHacker
- Generic R3 (unreleased, under development) by LBPHacker
- Armatoste (unreleased, under development) by DanielUbTb
Because I finally made an assembler with nice enough features that it probably makes sense to not make another one but just support all future (and past) computers with this one instead.
You can run the assembler from TPT or really in any environment that's compatible with Lua 5.1. Running it from TPT has the benefit of actually allowing you to program computers.
The assembler takes both positional and named arguments. A positional string
argument of the format key=value
(^([^=]+)=(.+)$
, to be precise) becomes
a named argument, its name is set to key
and its value to value
, both
strings. The remaining positional arguments become the final positional
arguments.
All positional arguments have equivalent named counterparts.
position | name | type | description |
---|---|---|---|
1 | source | string | path to source to assemble |
2 | target | integer, string or table | identifier of the target CPU |
3 | log | string or handle | path to redirect log to |
4 | model | string | model number |
silent | any | don't log anything | |
anchor | string | spawn anchor for specified model | |
anchor_dx | integer | X component of anchor direction vector | |
anchor_dy | integer | Y component of anchor direction vector | |
anchor_prop | string | name of property for anchor to use | |
anchor_id | integer | CPU identifier to encode in the anchor | |
detect | any | list recognisable CPUs with model and ID | |
export_labels | string | path to export labels to | |
allow_model_mismatch | any | throw only warnings instead of errors |
There's also a way to pass arguments by simply passing a table as the first argument. In this case its integer-keyed pairs will become the positional arguments (the ones that adhere to Lua's definition of arrays anyway) and all other pairs become named arguments. Don't worry, the examples below will make all this clear.
target
may be a string, in which case the opcodes are dumped into the file this string refers to, in little endian encoding (refer to the corresponding architecture module for number of bytes in such an opcode; generally it will be the opcode width passed toopcode.make
multiplied by 4)target
may be a table, in which case the opcodes are copied into it and no flashing attempts occur (useful when you're using TPTASM outside TPT)- if
target
is not specified, the assembler looks for the first CPU that matches the model name passed (or any CPU if it wasn't passed); if the anchor particle of a CPU happens to be directly under your TPT cursor, it's selected as the target log
may also be an object with a:write
method (e.g. a file object), in which case output is redirected to that object by means of calling:write
(:close
is never called and doesn't have to be present)silent
andallow_model_mismatch
are checked for truthiness by Lua's definitions, so they're considered true if they're notfalse
ornil
(likewise, useful when you're using TPTASM outside TPT)(anchor_dx, anchor_dy)
defaults to the vector(1, 0)
, as anchors are generally horizontal and are read from the left to the rightanchor_prop
defaults to"ctype"
, as anchors tend to be lines of FILT, which can be easily located visually if they contain ASCII data
Install the Script Manager, then install TPTASM with it. Once done, usage is as simple as:
-- install TPTASM with the script manager
-- see https://starcatcher.us/scripts?view=316
tptasm("/path/to/source.asm") -- assemble source
tptasm("/path/to/source.asm", 0xDEAD) -- specify target CPU
tptasm("/path/to/source.asm", nil, "log.log") -- specify file to log output to
tptasm("/path/to/source.asm", nil, nil, "R3") -- specify model name
For example, download micro21/demo.asm, navigate to save id:1599945 and execute this:
tptasm("/path/to/downloads/micro21/demo.asm") -- adjust /path/to/downloads to match your system
Advanced functionality example:
-- let's say this is not TPT's console but some script executed in TPT by some other means
opcodes = {}
tptasm({ source = "/path/to/source.asm", target = opcodes, model = "R3" })
print(opcodes[0x1337]:dump())
Download the latest release and use loadfile
to get access to the tptasm
function in any Lua environment:
tptasm = loadfile("/path/to/tptasm.lua")
Releases from this repo are also what get published on the Script Manager, so if you have already installed TPTASM with the Script Manager, you can just use it directly from TPT's data folder.
Command line usage is also possible:
$ luajit /path/to/tptasm.lua ...
Assuming the current directory is this repo, submodules have been fetched with
git submodule update --init
, and LuaJIT or some other
Lua 5.x version has been installed:
# currently quite pointless to do but possible nonetheless
$ luajit TPT-Script-Manager/modulepack.lua modulepack.conf run /path/to/source.asm model=R3
TPTASM can be run from other current directories by passing modulepack.lua and modulepack.conf with appropriately relative or absolute paths.
The file referred to by export_labels
will look something like this
(see examples/micro21/demo.asm):
start 0x0
start.jump_table 0x6
demo_addition 0x2C
demo_odds 0x33
demo_odds.get_number 0x34
demo_odds.get_number.done 0x3A
demo_odds.count_odds 0x3B
...
That is, it'll have one fully qualified label and the corresponding address in hexadecimal per line, separated by one space character.
Things I still want to do but don't know when I'll have the time:
- support Harvard architecture computers more, as currently there is no
way to address their memory through labels, only preprocessor macros
(
%define
,%eval
, etc.) - clean up and comment code as much as possible
- add support for more computers
- possibly replace postfix syntax in expression blocks (
{ }
blocks) with infix syntax - possibly add support to recognise expression blocks and implicitly evaluate them at assemble time, thus eliminating the need to wrap them in curly brackets
- check if this thing works on Windows at all and fix it if it doesn't
PRs are welcome, especially if they add support for computers. Yes, I do realise my code is a huge mess. Good luck figuring it out.