{"id":35222119,"url":"https://github.com/irmen/64tass","last_synced_at":"2026-04-01T21:50:58.092Z","repository":{"id":52079669,"uuid":"107466112","full_name":"irmen/64tass","owner":"irmen","description":"64tass - cross assembler for 6502 etc. microprocessors - by soci/singular - [git clone from the original sourceforge repo]","archived":false,"fork":false,"pushed_at":"2026-03-04T22:08:37.000Z","size":9361,"stargazers_count":48,"open_issues_count":0,"forks_count":9,"subscribers_count":6,"default_branch":"master","last_synced_at":"2026-03-28T01:54:28.271Z","etag":null,"topics":["assembler","assembly-6502","c64","commodore-64","retro","retrocomputing"],"latest_commit_sha":null,"homepage":"http://sourceforge.net/projects/tass64/","language":"C","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/irmen.png","metadata":{"files":{"readme":"README","changelog":"NEWS","contributing":null,"funding":null,"license":"LICENSE-GPL-2.0","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-10-18T21:39:51.000Z","updated_at":"2026-03-04T22:08:42.000Z","dependencies_parsed_at":"2023-12-13T21:53:16.635Z","dependency_job_id":"cf19ece5-262e-4767-9ec5-cf42fd30c2df","html_url":"https://github.com/irmen/64tass","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/irmen/64tass","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/irmen%2F64tass","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/irmen%2F64tass/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/irmen%2F64tass/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/irmen%2F64tass/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/irmen","download_url":"https://codeload.github.com/irmen/64tass/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/irmen%2F64tass/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31292578,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assembler","assembly-6502","c64","commodore-64","retro","retrocomputing"],"created_at":"2025-12-30T00:17:16.600Z","updated_at":"2026-04-01T21:50:58.072Z","avatar_url":"https://github.com/irmen.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"64tass v1.60 r3243 reference manual\n\nThis is the manual for 64tass, the multi pass optimizing macro assembler for\nthe 65xx series of processors. Key features:\n\n  * Open source portable C with minimal dependencies\n  * Familiar syntax to Omicron TASS and TASM\n  * Supports 6502, 65C02, R65C02, W65C02, 65CE02, 65816, DTV, 65EL02, 4510,\n    45GS02\n  * Arbitrary-precision integers and bit strings, double precision floating\n    point numbers\n  * Character and byte strings, array arithmetic\n  * Handles UTF-8, UTF-16 and 8 bit RAW encoded source files, Unicode character\n    strings\n  * Supports Unicode identifiers with compatibility normalization and optional\n    case insensitivity\n  * Built-in `linker' with section support\n  * Various memory models, binary targets and text output formats (also Hex/\n    S-record)\n  * Assembly and label listings available for debugging or exporting\n  * Conditional compilation, macros, structures, unions, scopes\n\nContrary how the length of this document suggests 64tass can be used with just\nbasic 6502 assembly knowledge in simple ways like any other assembler. If some\nadvanced functionality is needed then this document can serve as a reference.\n\nThis is a development version. Features or syntax may change as a result of\ncorrections in non-backwards compatible ways in some rare cases. It's difficult\nto get everything `right' first time.\n\nProject page: https://sourceforge.net/projects/tass64/\n\nThe page hosts the latest and older versions with sources and a bug and a\nfeature request tracker.\n\n-------------------------------------------------------------------------------\n\nTable of Contents\n\n  * Table of Contents\n  * Usage tips\n  * Expressions and data types\n      + Integer constants\n      + Bit string constants\n      + Floating point constants\n      + Character string constants\n      + Byte string constants\n      + Lists and tuples\n      + Dictionaries\n      + Code\n      + Addressing modes\n      + Uninitialized memory\n      + Booleans\n      + Types\n      + Symbols\n          o Regular symbols\n          o Local symbols\n          o Anonymous symbols\n          o Constant and re-definable symbols\n          o The star label\n      + Built-in functions\n          o Mathematical functions\n          o Byte string functions\n          o Other functions\n      + Expressions\n          o Operators\n          o Comparison operators\n          o Bit string extraction operators\n          o Conditional operators\n          o Address length forcing\n          o Compound assignment\n          o Slicing and indexing\n  * Compiler directives\n      + Controlling the compile offset and program counter\n      + Aligning data or code\n      + Dumping data\n          o Storing numeric values\n          o Storing string values\n      + Text encoding\n      + Structured data\n          o Structure\n          o Union\n          o Combined use of structures and unions\n      + Macros\n          o Parameter references\n          o Text references\n      + Custom functions\n      + Conditional assembly\n          o If, else if, else\n          o Switch, case, default\n          o Comment\n      + Repetitions\n      + Including files\n      + Scopes\n      + Sections\n      + 65816 related\n      + Controlling errors\n      + Target\n      + Misc\n      + Printer control\n  * Pseudo instructions\n      + Aliases\n      + Generic instructions\n      + Always taken branches\n      + Long branches\n  * Original turbo assembler compatibility\n      + How to convert source code for use with 64tass\n      + Differences to the original turbo ass macro on the C64\n      + Labels\n      + Expression evaluation\n      + Macros\n      + Bugs\n  * Command line options\n      + Output options\n      + Operation options\n      + Diagnostic options\n      + Target selection on command line\n      + Symbol listing\n      + Assembly listing\n      + Other options\n      + Command line from file\n  * Messages\n      + Warnings\n      + Errors\n      + Fatal errors\n  * Credits\n  * Default translation and escape sequences\n      + Raw 8-bit source\n          o The none encoding for raw 8-bit\n          o The screen encoding for raw 8-bit\n      + Unicode and ASCII source\n          o The none encoding for Unicode\n          o The screen encoding for Unicode\n  * Opcodes\n      + Standard 6502 opcodes\n      + 6502 illegal opcodes\n      + 65DTV02 opcodes\n      + Standard 65C02 opcodes\n      + R65C02 opcodes\n      + W65C02 opcodes\n      + W65816 opcodes\n      + 65EL02 opcodes\n      + 65CE02 opcodes\n      + CSG 4510 opcodes\n      + 45GS02 opcodes\n  * Appendix\n      + Assembler directives\n      + Built-in functions\n      + Built-in types\n\n-------------------------------------------------------------------------------\n\nUsage tips\n\n64tass is a command line assembler, the source can be written in any text\neditor. As a minimum the source filename must be given on the command line. The\n`-a' command line option is highly recommended if the source is Unicode or\nASCII.\n\n64tass -a src.asm\n\nThere are also some useful parameters which are described later.\n\nFor comfortable compiling I use such `Makefile's (for make):\n\ndemo.prg: source.asm macros.asm pic.drp music.bin\n        64tass -C -a -B -i source.asm -o demo.tmp\n        pucrunch -ffast -x 2048 demo.tmp \u003edemo.prg\n\nThis way `demo.prg' is recreated by compiling `source.asm' whenever\n`source.asm', `macros.asm', `pic.drp' or `music.bin' had changed.\n\nOf course it's not much harder to create something similar for win32\n(make.bat), however this will always compile and compress:\n\n64tass.exe -C -a -B -i source.asm -o demo.tmp\npucrunch.exe -ffast -x 2048 demo.tmp \u003edemo.prg\n\nHere's a slightly more advanced Makefile example with default action as testing\nin VICE, clean target for removal of temporary files and compressing using an\nintermediate temporary file:\n\nall: demo.prg\n        x64 -autostartprgmode 1 -autostart-warp +truedrive +cart $\u003c\n\ndemo.prg: demo.tmp\n        pucrunch -ffast -x 2048 $\u003c \u003e$@\n\ndemo.tmp: source.asm macros.asm pic.drp music.bin\n        64tass -C -a -B -i $\u003c -o $@\n\n.INTERMEDIATE: demo.tmp\n.PHONY: all clean\nclean:\n        $(RM) demo.prg demo.tmp\n\nIt's useful to add a basic header to your source files like the one below, so\nthat the resulting file is directly runnable without additional compression:\n\n*       = $0801\n        .word (+), 2005  ;pointer, line number\n        .null $9e, format(\"%4d\", start);will be sys 4096\n+       .word 0          ;basic line end\n\n*       = $1000\n\nstart   rts\n\nA frequently coming up question is, how to automatically allocate memory,\nwithout hacks like *=*+1? Sure there's .byte and friends for variables with\ninitial values but what about zero page, or RAM outside of program area? The\nsolution is to not use an initial value by using `?' or not giving a fill byte\nvalue to .fill.\n\n*       = $02\np1      .addr ?         ;a zero page pointer\ntemp    .fill 10        ;a 10 byte temporary area\n\nSpace allocated this way is not saved in the output as there's no data to save\nat those addresses.\n\nWhat about some code running on zero page for speed? It needs to be relocated,\nand the length must be known to copy it there. Here's an example:\n\n        ldx #size(zpcode)-1;calculate length\n-       lda zpcode,x\n        sta wrbyte,x\n        dex             ;install to zero page\n        bpl -\n        jsr wrbyte\n        rts\n;code continues here but is compiled to run from $02\nzpcode  .logical $02\nwrbyte  sta $ffff       ;quick byte writer at $02\n        inc wrbyte+1\n        bne +\n        inc wrbyte+2\n+       rts\n        .endlogical\n\nThe assembler supports lists and tuples, which does not seems interesting at\nfirst as it sound like something which is only useful when heavy scripting is\ninvolved. But as normal arithmetic operations also apply on all their elements\nat once, this could spare quite some typing and repetition.\n\nLet's take a simple example of a low/high byte jump table of return addresses,\nthis usually involves some unnecessary copy/pasting to create a pair of tables\nwith constructs like \u003e(label-1).\n\njumpcmd lda hibytes,x   ; selected routine in X register\n        pha\n        lda lobytes,x   ; push address to stack\n        pha\n        rts             ; jump, rts will increase pc by one!\n; Build a list of jump addresses minus 1\n_       := (cmd_p, cmd_c, cmd_m, cmd_s, cmd_r, cmd_l, cmd_e)-1\nlobytes .byte \u003c_        ; low bytes of jump addresses\nhibytes .byte \u003e_        ; high bytes\n\nThere are some other tips below in the descriptions.\n\n-------------------------------------------------------------------------------\n\nExpressions and data types\n\nInteger constants\n\nInteger constants can be entered as decimal digits of arbitrary length. An\nunderscore can be used between digits as a separator for better readability of\nlong numbers. The following operations are accepted:\n\n            Integer operators and functions\nx + y    add x to y                       2 + 2 is 4\nx - y    subtract y from x                4 - 1 is 3\nx * y    multiply x with y                2 * 3 is 6\nx / y    integer divide x by y            7 / 2 is 3\nx % y    integer modulo of x divided by y 5 % 2 is 1\nx ** y   x raised to power of y           2 ** 4 is 16\n-x       negated value                    -2 is -2\n+x       unchanged                        +2 is 2\n~x       -x - 1                           ~3 is -4\nx | y    bitwise or                       2 | 6 is 6\nx ^ y    bitwise xor                      2 ^ 6 is 4\nx \u0026 y    bitwise and                      2 \u0026 6 is 2\nx \u003c\u003c y   logical shift left               1 \u003c\u003c 3 is 8\nx \u003e\u003e y   arithmetic shift right           -8 \u003e\u003e 3 is -1\n\nIntegers are automatically promoted to floats as necessary in expressions.\nOther types can be converted to integer using the integer type int.\n\nInteger division is a floor division (rounding down) so 7 / 4 is 1 and not\n1.75. If ceiling division is required (rounding up) that can be done by\nnegating both the divident and the result. Typically it's done like 0 - -5 / 4\nwhich results in 2.\n\n        .byte 23        ; as unsigned\n        .char -23       ; as signed\n\n; using negative integers as immediate values\n        ldx #-3         ; works as '#-' is signed immediate\nnum     = -3\n        ldx #+num       ; needs explicit '#+' for signed 8 bits\n\n        lda #((bitmap \u003e\u003e 10) \u0026 $0f) | ((screen \u003e\u003e 6) \u0026 $f0)\n        sta $d018\n\nBit string constants\n\nBit string constants can be entered in hexadecimal form with a leading dollar\nsign or in binary with a leading percent sign. An underscore can be used\nbetween digits as a separator for better readability of long numbers. The\nfollowing operations are accepted:\n\n       Bit string operators and functions\n~x     invert bits         ~%101 is ~%101\ny .. x concatenate bits    $a .. $b is $ab\ny x n  repeat              %101 x 3 is %101101101\nx[n]   extract bit(s)      $a[1] is %1\nx[s]   slice bits          $1234[4:8] is $3\nx | y  bitwise or          ~$2 | $6 is ~$0\nx ^ y  bitwise xor         ~$2 ^ $6 is ~$4\nx \u0026 y  bitwise and         ~$2 \u0026 $6 is $4\nx \u003c\u003c y bitwise shift left  $0f \u003c\u003c 4 is $0f0\nx \u003e\u003e y bitwise shift right ~$f4 \u003e\u003e 4 is ~$f\n\nLength of bit string constants are defined in bits and is calculated from the\nnumber of bit digits used including leading zeros.\n\nBit strings are automatically promoted to integer or floating point as\nnecessary in expressions. The higher bits are extended with zeros or ones as\nneeded.\n\nBit strings support indexing and slicing. This is explained in detail in\nsection `Slicing and indexing'.\n\nOther types can be converted to bit string using the bit string type bits.\n\n        .byte $33       ; 8 bits in hexadecimal\n        .byte %00011111 ; 8 bits in binary\n        .text $1234     ; $34, $12 (little endian)\n\n        lda $01\n        and #~$07       ; 8 bits even after inversion\n        ora #$05\n        sta $01\n\n        lda $d015\n        and #~%00100000 ;clear a bit\n        sta $d015\n\nFloating point constants\n\nFloating point constants have a radix point in them and optionally an exponent.\nA decimal exponent is `e' while a binary one is `p'. An underscore can be used\nbetween digits as a separator for better readability. The following operations\ncan be used:\n\n             Floating point operators and functions\nx + y       add x to y                       2.2 + 2.2 is 4.4\nx - y       subtract y from x                4.1 - 1.1 is 3.0\nx * y       multiply x with y                1.5 * 3 is 4.5\nx / y       integer divide x by y            7.0 / 2.0 is 3.5\nx % y       integer modulo of x divided by y 5.0 % 2.0 is 1.0\nx ** y      x raised to power of y           2.0 ** -1 is 0.5\n-x          negated value                    -2.0 is -2.0\n+x          unchanged                        +2.0 is 2.0\n~x          almost -x                        ~2.1 is almost -2.1\nx | y       bitwise or                       2.5 | 6.5 is 6.5\nx ^ y       bitwise xor                      2.5 ^ 6.5 is 4.0\nx \u0026 y       bitwise and                      2.5 \u0026 6.5 is 2.5\nx \u003c\u003c y      logical shift left               1.0 \u003c\u003c 3.0 is 8.0\nx \u003e\u003e y      arithmetic shift right           -8.0 \u003e\u003e 4 is -0.5\n\nAs usual comparing floating point numbers for (non) equality is a bad idea due\nto rounding errors.\n\nThe only predefined constant is pi.\n\nFloating point numbers are automatically truncated to integer as necessary.\nOther types can be converted to floating point by using the type float.\n\nFixed point conversion can be done by using the shift operators. For example an\n8.16 fixed point number can be calculated as (3.14 \u003c\u003c 16) \u0026 $ffffff. The binary\noperators operate like if the floating point number would be a fixed point one.\nThis is the reason for the strange definition of inversion.\n\n        .byte 3.66e1       ; 36.6, truncated to 36\n        .byte $1.8p4       ; 4:4 fixed point number (1.5)\n        .sint 12.2p8       ; 8:8 fixed point number (12.2)\n\nCharacter string constants\n\nCharacter strings are enclosed in single or double quotes and can hold any\nUnicode character.\n\nOperations like indexing or slicing are always done on the original\nrepresentation. The current encoding is only applied when it's used in\nexpressions as numeric constants or in context of text data directives.\n\nDoubling the quotes inside string literals escapes them and results in a single\nquote.\n\n    Character string operators and functions\ny .. x concatenate strings  \"a\" .. \"b\" is \"ab\"\ny in x is substring of      \"b\" in \"abc\" is true\na x n  repeat               \"ab\" x 3 is \"ababab\"\na[i]   character from start \"abc\"[1] is \"b\"\na[-i]  character from end   \"abc\"[-1] is \"c\"\na[:]   no change            \"abc\"[:] is \"abc\"\na[s:]  cut off start        \"abc\"[1:] is \"bc\"\na[:-s] cut off end          \"abc\"[:-1] is \"ab\"\na[s]   reverse              \"abc\"[::-1] is \"cba\"\n\nCharacter strings are converted to integers, byte and bit strings as necessary\nusing the current encoding and escape rules. For example when using a sane\nencoding \"z\"-\"a\" is 25.\n\nOther types can be converted to character strings by using the type str or by\nusing the repr and format functions.\n\nCharacter strings support indexing and slicing. This is explained in detail in\nsection `Slicing and indexing'.\n\nmystr   = \"oeU\"         ; character string constant\n        .text 'it''s'   ; it's\n        .word \"ab\"+1    ; conversion result is \"bb\" usually\n\n        .text \"text\"[:2]     ; \"te\"\n        .text \"text\"[2:]     ; \"xt\"\n        .text \"text\"[:-1]    ; \"tex\"\n        .text \"reverse\"[::-1]; \"esrever\"\n\nByte string constants\n\nByte strings are like character strings, but hold bytes instead of characters.\n\nQuoted character strings prefixing by `b', `l', `n', `p', `s', `x' or `z'\ncharacters can be used to create byte strings. The resulting byte string\ncontains what .text, .shiftl, .null, .ptext and .shift would create. Direct\nhexadecimal entry can be done using the `x' prefix and `z' denotes a z85\nencoded byte string. Spaces can be used between pairs of hexadecimal digits as\na separator for better readability.\n\n          Byte string operators and functions\ny .. x concatenate strings x\"12\" .. x\"34\" is x\"1234\"\ny in x is substring of     x\"34\" in x\"1234\" is true\na x n  repeat              x\"ab\" x 3 is x\"ababab\"\na[i]   byte from start     x\"abcd12\"[1] is x\"cd\"\na[-i]  byte from end       x\"abcd\"[-1] is x\"cd\"\na[:]   no change           x\"abcd\"[:] is x\"abcd\"\na[s:]  cut off start       x\"abcdef\"[1:] is x\"cdef\"\na[:-s] cut off end         x\"abcdef\"[:-1] is x\"abcd\"\na[s]   reverse             x\"abcdef\"[::-1] is x\"efcdab\"\n\nByte strings support indexing and slicing. This is explained in detail in\nsection `Slicing and indexing'.\n\nOther types can be converted to byte strings by using the type bytes.\n\n        .enc \"screen\"   ;use screen encoding\nmystr   = b\"oeU\"        ;convert text to bytes, like .text\n        .enc \"none\"     ;normal encoding\n\n        .text mystr     ;text as originally encoded\n        .text s\"p1\"     ;convert to bytes like .shift\n        .text l\"p2\"     ;convert to bytes like .shiftl\n        .text n\"p3\"     ;convert to bytes like .null\n        .text p\"p4\"     ;convert to bytes like .ptext\n\nBinary data may be embedded in source code by using hexadecimal byte strings.\nThis is more compact than using .byte followed by a lot of numbers. As expected\n1 byte becomes 2 characters.\n\n        .text x\"fce2\"   ;2 bytes: $fc and $e2 (big endian)\n\nIf readability is not a concern then the more compact z85 encoding may be used\nwhich encodes 4 bytes into 5 characters. Data lengths not a multiple of 4 are\nhandled by omitting leading zeros in the last group.\n\n        .text z\"FiUj*2M$hf\";8 bytes: 80 40 20 10 08 04 02 01\n\nFor data lengths of multiple of 4 bytes any z85 encoder will do. Otherwise the\nsimplest way to encode a binary file into a z85 string is to create a source\nfile which reads it using the line `label = binary('filename')'. Now if the\nlabels are listed to a file then there will be a z85 encoded definition for\nthis label.\n\nLists and tuples\n\nLists and tuples can hold a collection of values. Lists are defined from values\nseparated by comma between square brackets [1, 2, 3], an empty list is [].\nTuples are similar but are enclosed in parentheses instead. An empty tuple is\n(), a single element tuple is (4,) to differentiate from normal numeric\nexpression parentheses. When nested they function similar to an array. Both\ntypes are immutable.\n\n          List and tuple operators and functions\ny .. x   concatenate lists    [1] .. [2] is [1, 2]\ny in x   is member of list    2 in [1, 2, 3] is true\na x n    repeat               [1, 2] x 2 is [1, 2, 1, 2]\na[i]     element from start   (\"1\", 2)[1] is 2\na[-i]    element from end     (\"1\", 2, 3)[-1] is 3\na[:]     no change            (1, 2, 3)[:] is (1, 2, 3)\na[s:]    cut off start        (1, 2, 3)[1:] is (2, 3)\na[:-s]   cut off end          (1, 2.0, 3)[:-1] is (1, 2.0)\na[s]     reverse              (1, 2, 3)[::-1] is (3, 2, 1)\n*a       convert to arguments format(\"%d: %s\", *mylist)\n... op a left fold            ... + (1, 2, 3) is ((1+2)+3)\na op ... right fold           (1, 2, 3) - ... is (1-(2-3))\n\nArithmetic operations are applied on the all elements recursively, therefore\n[1, 2] + 1 is [2, 3], and abs([1, -1]) is [1, 1].\n\nArithmetic operations between lists are applied one by one on their elements,\nso [1, 2] + [3, 4] is [4, 6].\n\nWhen lists form an array and columns/rows are missing the smaller array is\nstretched to fill in the gaps if possible, so [[1], [2]] * [3, 4] is [[3, 4],\n[6, 8]].\n\nLists and tuples support indexing and slicing. This is explained in detail in\nsection `Slicing and indexing'.\n\nmylist  = [1, 2, \"whatever\"]\nmytuple = (cmd_e, cmd_g)\n\nmylist  = (\"e\", cmd_e, \"g\", cmd_g, \"i\", cmd_i)\nkeys    .text mylist[::2]    ; keys (\"e\", \"g\", \"i\")\ncall_l  .byte \u003cmylist[1::2]-1; routines (\u003ccmd_e-1, \u003ccmd_g-1, \u003ccmd_i-1)\ncall_h  .byte \u003emylist[1::2]-1; routines (\u003ecmd_e-1, \u003ecmd_g-1, \u003ecmd_i-1)\n\nAlthough lists elements of variables can't be changed using indexing (at the\nmoment) the same effect can be achieved by combining slicing and concatenation:\n\nlst     := lst[:2] .. [4] .. lst[3:]; same as lst[2] := 4 would be\n\nFolding is done on pair of elements either forward (left) or reverse (right).\nThe list must contain at least one element. Here are some folding examples:\n\nminimum = size([part1, part2, part3]) \u003c? ...\nmaximum = size([part1, part2, part3]) \u003e? ...\nsum     = size([part1, part2, part3]) + ...\nxorall  = list_of_numbers ^ ...\njoin    = list_of_strings .. ...\nallbits = sprites.(left, middle, right).bits | ...\nall     = [true, true, true, true] \u0026\u0026 ...\nany     = [false, false, false, true] || ...\n\nThe range(start, end, step) built-in function can be used to create lists of\nintegers in a range with a given step value. At least the end must be given,\nthe start defaults to 0 and the step to 1. Sounds not very useful, so here are\na few examples:\n\n;Bitmask table, 8 bits from left to right\n        .byte %10000000 \u003e\u003e range(8)\n;Classic 256 byte single period sinus table with values of 0-255.\n        .byte 128 + 127.5 * sin(range(256) * pi / 128)\n;Screen row address tables\n_       := $400 + range(0, 1000, 40)\nscrlo   .byte \u003c_\nscrhi   .byte \u003e_\n\nDictionaries\n\nDictionaries hold key and value pairs normally but can be used as sets too if\nsimple values are used. In the latter case the values are the keys for\nthemselves.\n\nA dictionary is defined with coma separated values between curly brackets. An\nempty one is {}. Key and value pairs are separated with colon, like { \u003ckey\u003e:\n\u003cvalue\u003e }. A default value for missing items is can be defined by leaving out\nthe key before the colon, like { :\u003cdefault\u003e }. Simple value don't use a colon {\n\u003cvalue\u003e }.\n\nLooking up a non-existing key is an error unless a default value is given.\nDictionaries are immutable. There are limitations what may be used as a key but\nthe value can be anything. As the keys are used for lookups these must be\nunique.\n\n                  Dictionary operators and functions\ny .. x combine dictionaries {1:2, 3:4} .. {2:3, 3:1} is {1:2, 2:3, 3:1}\nx[i]   value lookup         {\"1\":2}[\"1\"] is 2\nx.i    symbol lookup        {.ONE:1, .TWO:2}.ONE is 1\ny in x is a key             1 in {1:2} is true\n\n; Simple lookup\n        .text {1:\"one\", 2:\"two\"}[2]; \"two\"\n; 16 element \"fader\" table 1-\u003e15-\u003e12-\u003e11-\u003e0\n        .byte {1:15, 15:12, 12:11, :0}[range(16)]\n; Variables can be used to build dictionaries incrementally.\nmd      := {1:2}\nmd      ..= {3:4}\n\nThe keys can be symbols as well, this allows simple definition of data\nstructures or enumerations.\n\n; Symbol accessible values. May be useful as a function return value too.\ncoords  = {.x: 24, .y: 50}\n        ldx #coords.x\n        ldy #coords.y\n; Simple enumeration where red = 0, green = 1, blue = 2\ncolors  = dict(.(red, green, blue), range(3))\n        lda #color.green\n; Enumerate register bits as %1, %10, %100, ...\nirqbits = dict(.(ta, tb, tod, serial, flag), %1 \u003c\u003c range(5))\n        and #irqbits.flag\n\nCode\n\nCode holds the result of compilation in binary and other enclosed objects. In\nan arithmetic operation it's used as the numeric address of the memory where it\nstarts. The compiled content remains static even if later parts of the source\noverwrite the same memory area.\n\nIndexing and slicing of code to access the compiled content might be\nimplemented differently in future releases. Use this feature at your own risk\nfor now, you might need to update your code later.\n\n           Label operators and functions\na.b     b member of a           label.locallabel\n.b in a if a has symbol b       .locallabel in label\na[i]    element from start      label[1]\na[-i]   element from end        label[-1]\na[:]    copy as tuple           label[:]\na[s:]   cut off start, as tuple label[1:]\na[:-s]  cut off end, as tuple   label[:-1]\na[s]    reverse, as tuple       label[::-1]\n\nmydata  .word 1, 4, 3\nmycode  .block\nlocal   lda #0\n        .endblock\n\n        ldx #size(mydata) ;6 bytes (3*2)\n        ldx #len(mydata)  ;3 elements\n        ldx #mycode[0]    ;lda instruction, $a9\n        ldx #mydata[1]    ;2nd element, 4\n        jmp mycode.local  ;address of local label\n\nAddressing modes\n\nAddressing modes are used for determining addressing modes of instructions.\n\nFor indexing there must be no white space between the comma and the register\nletter, otherwise the indexing operator is not recognized. On the other hand\nput a space between the comma and a single letter symbol in a list to avoid it\nbeing recognized as an operator.\n\n   Addressing mode operators\n#   immediate\n#+  signed immediate\n#-  signed immediate\n( ) indirect\n[ ] long indirect\n,b  data bank indexed\n,d  direct page indexed\n,k  program bank indexed\n,r  data stack pointer indexed\n,s  stack pointer indexed\n,x  x register indexed\n,y  y register indexed\n,z  z register indexed\n\nParentheses are used for indirection and square brackets for long indirection.\nThese operations are only available after instructions and functions to not\ninterfere with their normal use in expressions.\n\nSeveral addressing mode operators can be combined together. Currently the\ncomplexity is limited to 4 operators. This is enough to describe all addressing\nmodes of the supported CPUs.\n\n                  Valid addressing mode operator combinations\n#             immediate                            lda #$12\n#+            signed immediate                     lda #+127\n#-            signed immediate                     lda #-128\n#addr,#addr   move                                 mvp #5,#6\naddr          direct or relative                   lda $12 lda $1234 bne $1234\nbit,addr      direct page bit                      rmb 5,$12 smb #$80,$12\nbit,addr,addr direct page bit relative jump        bbs 5,$12,$1 bbr #$40,$12,$2\n(addr)        indirect                             lda ($12) jmp ($1234)\n(addr),y      indirect y indexed                   lda ($12),y\n(addr),z      indirect z indexed                   lda ($12),z\n(addr,x)      x indexed indirect                   lda ($12,x) jmp ($1234,x)\n[addr]        long indirect                        lda [$12] jmp [$1234]\n[addr],y      long indirect y indexed              lda [$12],y\n#addr,b       data bank indexed                    lda #0,b\n#addr,b,x     data bank x indexed                  lda #0,b,x\n#addr,b,y     data bank y indexed                  lda #0,b,y\n#addr,d       direct page indexed                  lda #0,d\n#addr,d,x     direct page x indexed                lda #0,d,x\n#addr,d,y     direct page y indexed                ldx #0,d,y\n(#addr,d)     direct page indirect                 lda (#$12,d)\n(#addr,d,x)   direct page x indexed indirect       lda (#$12,d,x)\n(#addr,d),y   direct page indirect y indexed       lda (#$12,d),y\n(#addr,d),z   direct page indirect z indexed       lda (#$12,d),z\n[#addr,d]     direct page long indirect            lda [#$12,d]\n[#addr,d],y   direct page long indirect y indexed  lda [#$12,d],y\n#addr,k       program bank indexed                 jsr #0,k\n(#addr,k,x)   program bank x indexed indirect      jmp (#$1234,k,x)\n#addr,r       data stack indexed                   lda #1,r\n(#addr,r),y   data stack indexed indirect y        lda (#$12,r),y\n              indexed\n#addr,s       stack indexed                        lda #1,s\n(#addr,s),y   stack indexed indirect y indexed     lda (#$12,s),y\naddr,x        x indexed                            lda $12,x\naddr,y        y indexed                            lda $12,y\n\nDirect page, data bank, program bank indexed and long addressing modes of\ninstructions are intelligently chosen based on the instruction type, the\naddress ranges set up by .dpage, .databank and the current program counter\naddress. Therefore the `,d', `,b' and `,k' indexing is only used in very\nspecial cases.\n\nThe immediate direct page indexed `#0,d' addressing mode is usable for direct\npage access. The 8 bit constant is a direct offset from the start of actual\ndirect page. Alternatively it may be written as `0,d'.\n\nThe immediate data bank indexed `#0,b' addressing mode is usable for data bank\naccess. The 16 bit constant is a direct offset from the start of actual data\nbank. Alternatively it may be written as `0,b'.\n\nThe immediate program bank indexed `#0,k' addressing mode is usable for program\nbank jumps, branches and calls. The 16 bit constant is a direct offset from the\nstart of actual program bank. Alternatively it may be written as `0,k'.\n\nThe immediate stack indexed `#0,s' and data stack indexed `#0,r' accept 8 bit\nconstants as an offset from the start of (data) stack. These are sometimes\nwritten without the immediate notation, but this makes it more clear what's\ngoing on. For the same reason the move instructions are written with an\nimmediate addressing mode `#0,#0' as well.\n\nThe immediate (#) addressing mode expects unsigned values of byte or word size.\nTherefore it only accepts constants of 1 byte or in range 0-255 or 2 bytes or\nin range 0-65535.\n\nThe signed immediate (#+ and #-) addressing mode is to allow signed numbers to\nbe used as immediate constants. It accepts a single byte or an integer in range\n-128-127, or two bytes or an integer of -32768-32767.\n\nThe use of signed immediate (like #-3) is seamless, but it needs to be\nexplicitly written out for variables or expressions (#+variable). In case the\nunsigned variant is needed but the expression starts with a negation then it\nneeds to be put into parentheses (#(-variable)) or else it'll change the\naddress mode to signed.\n\nNormally addressing mode operators are used in expressions right after\ninstructions. They can also be used for defining stack variable symbols when\nusing a 65816, or to force a specific addressing mode.\n\nparam   = #1,s            ;define a stack variable\nconst   = #1              ;immediate constant\n        lda #0,b          ;always \"absolute\" lda $0000\n        lda param         ;results in lda #$01,s\n        lda param+1       ;results in lda #$02,s\n        lda (param),y     ;results in lda (#$01,s),y\n        ldx const         ;results in ldx #$01\n        lda #-2           ;negative constant, $fe\n\nUninitialized memory\n\nThere's a special value for uninitialized memory, it's represented by a\nquestion mark. Whenever it's used to generate data it creates a `hole' where\nthe previous content of memory is visible.\n\nUninitialized memory holes without previous content are not saved unless it's\nreally necessary for the output format, in that case it's replaced with zeros.\n\nIt's not just data generation statements (e.g. .byte) that can create\nuninitialized memory, but .fill, .align or address manipulation as well.\n\n*       = $200          ;bytes as necessary\n        .word ?         ;2 bytes\n        .fill 10        ;10 bytes\n        .align 64       ;bytes as necessary\n\nBooleans\n\nThere are two predefined boolean constant variables, true and false.\n\nBooleans are created by comparison operators (\u003c, \u003c=, !=, ==, \u003e=, \u003e), logical\noperators (\u0026\u0026, ||, ^^, !), the membership operator (in) and the all and any\nfunctions.\n\nNormally in numeric expressions true is 1 and false is 0, unless the `\n-Wstrict-bool' command line option was used.\n\nOther types can be converted to boolean by using the type bool.\n\n         Boolean values of various types\nbits  At least one non-zero bit\nbool  When true\nbytes At least one non-zero byte\ncode  Address is non-zero\nfloat Not 0.0\nint   Not zero\nstr   At least one non-zero byte after translation\n\nTypes\n\nThe various types mentioned earlier have predefined names. These can used for\nconversions or type checks.\n\n       Built-in type names\naddress Address type\nbits    Bit string type\nbool    Boolean type\nbytes   Byte string type\ncode    Code type\ndict    Dictionary type\nfloat   Floating point type\ngap     Uninitialized memory type\nint     Integer type\nlist    List type\nstr     Character string type\nsymbol  Symbol type\ntuple   Tuple type\ntype    Type type\n\nBit and byte string conversions can take a second parameter to specify an exact\nsize. Values which can fit in shorter space will be padded but longer ones give\nan error.\n\nbits(\u003cexpression\u003e[, \u003cbit count\u003e])\n    Convert to the specific number of bits. If the number of bits is negative\n    then it's a signed.\nbytes(\u003cexpression\u003e[, \u003cbyte count\u003e])\n    Convert to the specific number of bytes. If the number of bits is negative\n    then it's a signed.\n\nDictionaries can be built from a single iterable of key and value pairs, or\nfrom two iterables where the keys come from the first and the values from the\nsecond parameter.\n\ndict(\u003citerable\u003e[, \u003cvalues iterable\u003e])\n    Build dictionary from iterables\n\n        .cerror type(var) != str, \"Not a string!\"\n        .text str(year)   ; convert to string\n\nSymbols\n\nSymbols are used to reference objects. Regularly named, anonymous and local\nsymbols are supported. These can be constant or re-definable.\n\nScopes are where symbols are stored and looked up. The global scope is always\ndefined and it can contain any number of nested scopes.\n\nSymbols must be uniquely named in a scope, therefore in big programs it's hard\nto come up with useful and easy to type names. That's why local and anonymous\nsymbols exists. And grouping certain related symbols into a scope makes sense\nsometimes too.\n\nScopes are usually created by .proc and .block directives, but there are a few\nother ways. Symbols in a scope can be accessed by using the dot operator, which\nis applied between the name of the scope and the symbol (e.g.\nmyconsts.math.pi).\n\nRegular symbols\n\nRegular symbol names are starting with a letter and containing letters, numbers\nand underscores. Unicode letters are allowed if the `-a' command line option\nwas used. There's no restriction on the length of symbol names.\n\nCare must be taken to not use duplicate names in the same scope when the symbol\nis used as a constant as there can be only one definition for them.\n\nDuplicate names in parent scopes are not a problem and this gives the ability\nto override names defined in lower scopes. However this can just as well lead\nto mistakes if a lower scoped symbol with the same name was meant so there's a\n`-Wshadow' command line option to warn if such ambiguity exists.\n\nCase sensitivity can be enabled with the `-C' command line option, otherwise\nall symbols are matched case insensitive.\n\nFor case insensitive matching it's possible to check for consistent symbol name\nuse with the `-Wcase-symbol' command line option.\n\nA regular symbol is looked up first in the current scope, then in lower scopes\nuntil the global scope is reached.\n\nf       .block\ng        .block\nn        nop            ;jump here\n         .endblock\n        .endblock\n\n        jsr f.g.n       ;reference from a scope\nf.x     = 3             ;create x in scope f with value 3\n\nLocal symbols\n\nLocal symbols have their own scope between two regularly named code symbols and\nare assigned to the code symbol above them.\n\nTherefore they're easy to reuse without explicit scope declaration directives.\n\nNot all regularly named symbols can be scope boundaries just plain code symbol\nones without anything or an opcode after them (no macros!). Symbols defined as\nprocedures, blocks, macros, functions, structures and unions are ignored. Also\nsymbols defined by .var, := or = don't apply, and there are a few more\nexceptions, so stick to using plain code labels.\n\nThe name must start with an underscore (_), otherwise the same character\nrestrictions apply as for regular symbols. There's no restriction on the length\nof the name.\n\nCare must be taken to not use the duplicate names in the same scope when the\nsymbol is used as a constant.\n\nA local symbol is only looked up in it's own scope and nowhere else.\n\nincr    inc ac\n        bne _skip\n        inc ac+1\n_skip   rts\n\ndecr    lda ac\n        bne _skip\n        dec ac+1\n_skip   dec ac          ;symbol reused here\n        jmp incr._skip  ;this works too, but is not advised\n\nAnonymous symbols\n\nAnonymous symbols don't have a unique name and are always called as a single\nplus or minus sign. They are also called as forward (+) and backward (-)\nreferences.\n\nWhen referencing them `-' means the first backward, `--' means the second\nbackwards and so on. It's the same for forward, but with `+'. In expressions it\nmay be necessary to put them into brackets.\n\n        ldy #4\n-       ldx #0\n-       txa\n        cmp #3\n        bcc +\n        adc #44\n+       sta $400,x\n        inx\n        bne -\n        dey\n        bne --\n\nExcessive nesting or long distance references create poorly readable code. It's\nalso very easy to copy-paste a few lines of code with these references into a\ncode fragment already containing similar references. The result is usually a\nlong debugging session to find out what went wrong.\n\nThese references are also useful in segments, but this can create a nice trap\nwhen segments are copied into the code with their internal references.\n\n        bne +\n        #somemakro      ;let's hope that this segment does\n+       nop             ;not contain forward references...\n\nAnonymous symbols are looked up first in the current scope, then in lower\nscopes until the global scope is reached.\n\nAnonymous labels within conditionally assembled code are counted even if the\ncode itself is not compiled and the label won't get defined. This ensures that\nanonymous labels are always at the same \"distance\" independent of the\nconditions in between.\n\nConstant and re-definable symbols\n\nConstant symbols can be created with the equal sign. These are not\nre-definable. Forward referencing of them is allowed as they retain the objects\nover compilation passes.\n\nSymbols in front of code or certain assembler directives are created as\nconstant symbols too. They are bound to the object following them.\n\nRe-definable symbols can be created by the .var directive or := construct.\nThese are also called as variables. They don't carry their content over from\nthe previous pass therefore it's not possible to use them before their\ndefinition.\n\nIf the variable already exists in the current scope it'll get updated. If an\nexisting variable needs to be updated in a parent scope then the ::= variable\nreassign operator is able to do that.\n\nVariables can be conditionally defined using the :?= construct. If the variable\nwas defined already then the original value is retained otherwise a new one is\ncreated with this value.\n\nWIDTH   = 40            ;a constant\n        lda #WIDTH      ;lda #$28\nvariabl .var 1          ;a variable\nvar2    := 1            ;another variable\nvariabl .var variabl + 1;update it verbosely\nvar2    += 1            ;compound assignment (add one)\nvar3    :?= 5           ;assign 5 if undefined\n\nThe star label\n\nThe `*' symbol denotes the current program counter value. When accessed it's\nvalue is the program counter at the beginning of the line. Assigning to it\nchanges the program counter and the compiling offset.\n\nBuilt-in functions\n\nBuilt-in functions are pre-assigned to the symbols listed below. If you reuse\nthese symbols in a scope for other purposes then they become inaccessible, or\ncan perform a different function.\n\nBuilt-in functions can be assigned to symbols (e.g. sinus = sin), and the new\nname can be used as the original function. They can even be passed as\nparameters to functions.\n\nMathematical functions\n\nfloor(\u003cexpression\u003e)\n    Round down. E.g. floor(-4.8) is -5.0\nround(\u003cexpression\u003e)\n    Round to nearest away from zero. E.g. round(4.8) is 5.0\nceil(\u003cexpression\u003e)\n    Round up. E.g. ceil(1.1) is 2.0\ntrunc(\u003cexpression\u003e)\n    Round down towards zero. E.g. trunc(-1.9) is -1\nfrac(\u003cexpression\u003e)\n    Fractional part. E.g. frac(1.1) is 0.1\nsqrt(\u003cexpression\u003e)\n    Square root. E.g. sqrt(16.0) is 4.0\ncbrt(\u003cexpression\u003e)\n    Cube root. E.g. cbrt(27.0) is 3.0\nlog10(\u003cexpression\u003e)\n    Common logarithm. E.g. log10(100.0) is 2.0\nlog(\u003cexpression\u003e[, \u003cexpression base\u003e])\n    Logarithm, natural by default. E.g. log(1) is 0.0\nexp(\u003cexpression\u003e)\n    Exponential. E.g. exp(0) is 1.0\npow(\u003cexpression a\u003e, \u003cexpression b\u003e)\n    A raised to power of B. E.g. pow(2.0, 3.0) is 8.0\nsin(\u003cexpression\u003e)\n    Sine. E.g. sin(0.0) is 0.0\nasin(\u003cexpression\u003e)\n    Arc sine. E.g. asin(0.0) is 0.0\nsinh(\u003cexpression\u003e)\n    Hyperbolic sine. E.g. sinh(0.0) is 0.0\ncos(\u003cexpression\u003e)\n    Cosine. E.g. cos(0.0) is 1.0\nacos(\u003cexpression\u003e)\n    Arc cosine. E.g. acos(1.0) is 0.0\ncosh(\u003cexpression\u003e)\n    Hyperbolic cosine. E.g. cosh(0.0) is 1.0\ntan(\u003cexpression\u003e)\n    Tangent. E.g. tan(0.0) is 0.0\natan(\u003cexpression\u003e)\n    Arc tangent. E.g. atan(0.0) is 0.0\ntanh(\u003cexpression\u003e)\n    Hyperbolic tangent. E.g. tanh(0.0) is 0.0\nrad(\u003cexpression\u003e)\n    Degrees to radian. E.g. rad(0.0) is 0.0\ndeg(\u003cexpression\u003e)\n    Radian to degrees. E.g. deg(0.0) is 0.0\nhypot([\u003cexpression\u003e, ...])\n    Euclidean distance, any dimensions. E.g. hypot(4.0, 3.0) is 5.0\natan2(\u003cexpression y\u003e, \u003cexpression x\u003e)\n    Polar angle in -pi to +pi range. E.g. atan2(0.0, 3.0) is 0.0\nabs(\u003cexpression\u003e)\n    Absolute value. E.g. abs(-1) is 1\nsign(\u003cexpression\u003e)\n    Returns the sign of value as -1, 0 or 1 for negative, zero and positive.\n    E.g. sign(-5) is -1\n\nByte string functions\n\nThese functions return byte strings of various lengths for signed numbers,\nunsigned numbers and addresses.\n\nThe naming of functions is not a coincidence and they return the bytes what the\ndata directives with the same names normally emit.\n\nbyte(\u003cexpression\u003e)\nchar(\u003cexpression\u003e)\n    Return a single byte string from a 8 bit unsigned (0-255) or signed number\n    (-128-127). E.g. byte(0) is x\"00\" and char(-1) is x\"ff\"\nword(\u003cexpression\u003e)\nsint(\u003cexpression\u003e)\n    Return a little endian byte string of 2 bytes from a 16 bit unsigned\n    (0-65535) or signed number (-32768-32767). E.g. word(1024) is x\"0004\" and\n    sint(-1) is x\"ffff\"\nlong(\u003cexpression\u003e)\nlint(\u003cexpression\u003e)\n    Return a little endian byte string of 3 bytes from a 24 bit unsigned\n    (0-16777216) or signed number (-8388608-8388607). E.g. long(123456) is\n    x\"40E201\" and lint(-1) is x\"ffffff\"\ndword(\u003cexpression\u003e)\ndint(\u003cexpression\u003e)\n    Return a little endian byte string of 4 bytes from a 32 bit unsigned\n    (0-4294967296) or signed number (-2147483648-2147483647). E.g. dword(\n    123456789) is x\"15CD5B07\" and dint(-1) is x\"ffffffff\"\naddr(\u003cexpression\u003e)\n    Return a little endian byte string of 2 bytes from an address in the\n    current program bank. E.g. addr(start) is x\"0d08\"\nrta(\u003cexpression\u003e)\n    Return a little endian byte string of 2 bytes from a return address in the\n    current program bank. E.g. rta(4096) is x\"ff0f\"\n\nOther functions\n\nall(\u003cexpression\u003e)\n    Return truth for various definitions of `all'.\n\n                                 All function\n    all bits set or no bits at all        all($f) is true\n    all characters non-zero or empty      all(\"c\") is true\n    string\n    all bytes non-zero or no bytes        all(x\"ac24\") is true\n    all elements true or empty list       all([true, true, false]) is false\n\n    Only booleans in a list are accepted with the `-Wstrict-bool' command line\n    option.\n\nany(\u003cexpression\u003e)\n    Return truth for various definitions of `any'.\n\n                            Any function\n    at least one bit set             any(~$f) is false\n    at least one non-zero character  any(\"c\") is true\n    at least one non-zero byte       any(x\"ac24\") is true\n    at least one true element        any([true, true, false]) is true\n\n    Only booleans in a list are accepted with the `-Wstrict-bool' command line\n    option.\n\nbinary(\u003cstring expression\u003e[, \u003coffset\u003e[, \u003clength\u003e]])\n    Returns the binary file content as bytes.\n\n    This function reads the content of a binary file as a byte string. It also\n    accepts optional offset and length parameters.\n\n           Binary function invocation types\n    Read everything        binary(name)\n    Skip starting bytes    binary(name, offset)\n    Some bytes from offset binary(name, offset, length)\n\n    sid     = binary(\"music.sid\"); read in the SID file as bytes\n    offs    := sid[[$7, $6]]     ; data offset (big endian)\n    load    := sid[[$9, $8]]     ; load address (big endian)\n    init    = sid[[$b, $a]]      ; init address (big endian)\n    play    = sid[[$d, $c]]      ; play address (big endian)\n\n    ; if load address is zero then it's the first 2 bytes of data\n            .if load == 0\n    load    := sid[offs:offs+2]  ; load address (little endian)\n    offs    += 2                 ; skip load address bytes\n            .endif\n\n    *       = load               ; set pc to load address\n            .text sid[offs:]     ; dump music data\n\nformat(\u003cstring expression\u003e[, \u003cexpression\u003e, ...])\n    Create string from values according to a format string.\n\n    The format function converts a list of values into a character string. The\n    converted values are inserted in place of the % sign. Optional conversion\n    flags and minimum field length may follow, before the conversion type\n    character. These flags can be used:\n\n                  Formatting flags\n    #     alternate form (-$a, ~$a, -%10, ~%10, -10.)\n    *     width/precision from list\n    .     precision\n    0     pad with zeros\n    -     left adjusted (default right)\n          blank when positive or minus sign\n    +     sign even if positive\n    ~     binary and hexadecimal as bits\n\n    The following conversion types are implemented:\n\n      Formatting conversion types\n    b     binary\n    c     Unicode character\n    d     decimal\n    e E   exponential float (uppercase)\n    f F   floating point (uppercase)\n    g G   exponential/floating point\n    s     string\n    r     representation\n    x X   hexadecimal (uppercase)\n    %     percent sign\n\n            .text format(\"%#04x bytes left\", 1000); $03e8 bytes left\n\nlen(\u003cexpression\u003e)\n    Returns the number of elements.\n\n                   Length of various types\n    bit string       length in bits       len($034) is 12\n    character string number of characters len(\"abc\") is 3\n    byte string      number of bytes      len(x\"abcd23\") is 3\n    tuple, list      number of elements   len([1, 2, 3]) is 3\n    dictionary       number of elements   len({1:2, 3:4]) is 2\n    code             number of elements   len(label)\n\nrandom([\u003cexpression\u003e, ...])\n    Returns a pseudo random number.\n\n    The sequence does not change across compilations and is the same every\n    time. Different sequences can be generated by seeding with .seed.\n\n             Random function invocation types\n    floating point number 0.0 \u003c= x \u003c 1.0   random()\n    integer in range of 0 \u003c= x \u003c e         random(e)\n    integer in range of s \u003c= x \u003c e         random(s, a)\n    integer in range of s \u003c= x \u003c e, step t random(s, a, t)\n\n            .seed 1234      ; default is boring, seed the generator\n            .byte random(256); a pseudo random byte (0-255)\n            .byte random([16] x 8); 8 pseudo random bytes (0-15)\n\nrange(\u003cexpression\u003e[, \u003cexpression\u003e, ...])\n    Returns a list of integers in a range, with optional stepping.\n\n                 Range function invocation types\n    integers from 0 to e-1                         range(e)\n    integers from s to e-1                         range(s, a)\n    integers from s to e (not including e), step t range(s, a, t)\n\n            .byte range(16) ; 0, 1, ..., 14, 15\n            .char range(-5, 6); -5, -4, ..., 4, 5\n    mylist  = range(10, 0, -2); [10, 8, 6, 4, 2]\n\nrepr(\u003cexpression\u003e)\n    Returns a string representation of value.\n\n            .warn repr(var) ; pretty print value, for debugging\n\nsize(\u003cexpression\u003e)\n    Returns the size of code, structure or union in bytes.\n\n    var     .word 0, 0, 0\n            ldx #size(var)  ; 6 bytes\n    var2    = var + 2       ; start 2 bytes later\n            ldx #size(var2) ; what remains is 4 bytes\n\nsort(\u003clist expression\u003e)\n    Returns a sorted list or tuple.\n\n    If the original list contains further lists then these must be all of the\n    same length. In this case the order of lists is determined by comparing\n    their elements from the start until a difference is found. The sort is\n    stable.\n\n    ; sort IRQ routines by their raster lines\n    sorted  = sort([(60, irq1), (50, irq2)])\n    lines   .byte sorted[:, 0] ; 50, 60\n    irqs    .addr sorted[:, 1] ; irq2, irq1\n\nExpressions\n\nOperators\n\nThe following operators are available. Not all are defined for all types of\narguments and their meaning might slightly vary depending on the type.\n\n                                Unary operators\n-     negative                          +     positive\n!     not                               ~     invert\n*     convert to arguments              ^     decimal string\n\nThe `^' decimal string operator will be changed to mean the bank byte soon.\nPlease update your sources to use format(\"%d\", xxx) instead! This is done to be\nin line with it's use in most other assemblers.\n\n                               Binary operators\n+     add                               -     subtract\n*     multiply                          /     divide\n%     modulo                            **    raise to power\n|     binary or                         ^     binary xor\n\u0026     binary and                        \u003c\u003c    shift left\n\u003e\u003e    shift right                       .     member\n..    concat                            x     repeat\nin    contains                          !in   excludes\n\nSpacing must be used for the `x' and `in' operators or else they won't be\nrecognized as such. For example the expression `[1,2]x2' should be written as\n`[1,2]x 2' instead.\n\nParenthesis (( )) can be used to override operator precedence. Don't forget\nthat they also denote indirect addressing mode for certain opcodes.\n\n        lda #(4+2)*3\n\nComparison operators\n\nTraditional comparison operators give false or true depending on the result.\n\nThe compare operator (\u003c=\u003e) gives -1 for less, 0 for equal and 1 for more.\n\n                             Comparison operators\n\u003c=\u003e   compare\n==    equals                            !=    not equal\n\u003c     less than                         \u003e=    more than or equals\n\u003e     more than                         \u003c=    less than or equals\n===   identical                         !==   not identical\n\nBit string extraction operators\n\nThese unary operators extract 8 or 16 bits. Usually they are used to get parts\nof a memory address.\n\n                        Bit string extraction operators\n\u003c     lower byte                        \u003e     higher byte\n\u003c\u003e    lower word                        \u003e`    higher word\n\u003e\u003c    lower byte swapped word           `     bank byte\n\n        lda #\u003clabel     ; low byte of address\n        ldy #\u003elabel     ; high byte of address\n        jsr $ab1e\n\n        ldx #\u003c\u003esource   ; word extraction\n        ldy #\u003c\u003edest\n        lda #size(source)-1\n        mvn #`source, #`dest; bank extraction\n\nPlease note that these prefix operators are not strongly binding like negation\nor inversion. Instead they apply to the whole expression to the right. This may\nbe unexpected but is required for compatibility with old sources which expect\nthis behaviour.\n\n        lda #\u003clabel+10  ;This is \u003c(label+10) and not (\u003clabel)+10\n\n;The check below is wrong and should be written as (\u003estart) != (\u003eend)\n        .cerror \u003estart != \u003eend;Effectively this is \u003e(start != (\u003eend))\n\nConditional operators\n\nBoolean conditional operators give false or true or one of the operands as the\nresult.\n\n              Logical and conditional operators\nx || y      if x is true then x otherwise y\nx ^^ y      if both false or true then false otherwise x || y\nx \u0026\u0026 y      if x is true then y otherwise x\n!x          if x is true then false otherwise true\nc ? x : y   if c is true then x otherwise y\nc ?? x : y  if c is true then x otherwise y (broadcasting)\nx \u003c? y      if x is smaller then x otherwise y\nx \u003e? y      if x is greater then x otherwise y\n\n;Silly example for 1=\u003e\"simple\", 2=\u003e\"advanced\", else \"normal\"\n        .text MODE == 1 \u0026\u0026 \"simple\" || MODE == 2 \u0026\u0026 \"advanced\" || \"normal\"\n        .text MODE == 1 ? \"simple\" : MODE == 2 ? \"advanced\" : \"normal\"\n;Limit result to 0 .. 8\nlight   .byte 0 \u003e? range(-16, 101)/6 \u003c? 8\n\nPlease note that these are not short circuiting operations and both sides are\ncalculated even if thrown away later.\n\nWith the `-Wstrict-bool' command line option booleans are required as arguments\nand only the `?' operator may return something else.\n\nAddress length forcing\n\nSpecial addressing length forcing operators in front of an expression can be\nused to make sure the expected addressing mode is used. Only applicable when\nused directly at the mnemonic.\n\n           Address size forcing\n@b          to force 8 bit address\n@w          to force 16 bit address\n@l          to force 24 bit address (65816)\n\n        lda @w $0000    ; force the use of 2 byte absolute addressing\n        bne @b label    ; prevent upgrade to beq+jmp with long branches in use\n        lda @w #$00     ; use 2 bytes independent of accumulator size\n\nCompound assignment\n\nThese assignment operators are short hands for updating variables. Constants\ncan't be changed of course.\n\nThe variables on the left must be defined beforehand by `:=' or `.var'.\n\nCompound assignment operators can modify variables defined in parent scopes as\nwell.\n\n                             Compound assignments\n+=    add                               -=    subtract\n*=    multiply                          /=    divide\n%=    modulo                            **=   raise to power\n|=    binary or                         ^=    binary xor\n\u0026=    binary and                        ||=   logical or\n\u0026\u0026=   logical and                       \u003c\u003c=   shift left\n\u003e\u003e=   shift right                       ..=   concat\n\u003c?=   smaller                           \u003e?=   greater\nx=    repeat                            .=    member\n\nv       += 1            ; same as 'v ::= v + 1'\n\nSlicing and indexing\n\nLists, character strings, byte strings and bit strings support various slicing\nand indexing possibilities through the [] operator.\n\nIndexing elements with positive integers is zero based. Negative indexes are\ntransformed to positive by adding the number of elements to them, therefore -1\nis the last element. Indexing with list of integers is possible as well so [1,\n2, 3][(-1, 0, 1)] is [3, 1, 2].\n\nSlicing is an operation when parts of sequence is extracted from a start\nposition to an end position with a step value. These parameters are separated\nwith colons enclosed in square brackets and are all optional. Their default\nvalues are [start:maximum:step=1]. Negative start and end characters are\nconverted to positive internally by adding the length of string to them.\nNegative step operates in reverse direction, non-single steps will jump over\nelements.\n\nThis is quite powerful and therefore a few examples will be given here:\n\nPositive indexing a[x]\n    It'll simply extracts a numbered element. It is zero based, therefore\n    \"abcd\"[1] results in \"b\".\nNegative indexing a[-x]\n    This extracts an element counted from the end, -1 is the last one. So\n    \"abcd\"[-2] results in \"c\".\nCut off end a[:to]\n    Extracts a continuous range stopping before `to'. So [10,20,30,40][:-1]\n    results in [10,20,30].\nCut off start a[from:]\n    Extracts a continuous range starting from `from'. So [10,20,30,40][-2:]\n    results in [30,40].\nSlicing a[from:to]\n    Extracts a continuous range starting from element `from' and stopping\n    before `to'. The two end positions can be positive or negative indexes. So\n    [10,20,30,40][1:-1] results in [20,30].\nEverything a[:]\n    Giving no start or end will cover everything and therefore results in a\n    complete copy.\nReverse a[::-1]\n    This gives everything in reverse, so \"abcd\"[::-1] is \"dcba\".\nStepping through a[from:to:step]\n    Extracts every `step'th element starting from `from' and stopping before\n    `to'. So \"abcdef\"[1:4:2] results in \"bd\". The `from' and `to' can be\n    omitted in case it starts from the beginning or end at the end. If the\n    `step' is negative then it's done in reverse.\nExtract multiple elements a[list]\n    Extract elements based on a list. So \"abcd\"[[1,3]] will be \"bd\".\n\nThe fun start with nested lists and tuples, as these can be used to create a\nmatrix. The examples will be given for a two dimensional matrix for easier\nunderstanding, but this also works in higher dimensions.\n\nExtract row a[x]\n    Given a [(1,2),(3,4)] matrix [0] will give the first row which is (1,2)\nExtract row range a[from:to]\n    Given a [(1,2),(3,4),(5,6),(7,8)] matrix [1:3] will give [(3,4),(5,6)]\nExtract column a[x]\n    Given a [(1,2),(3,4)] matrix [:,0] will give the first column of all rows\n    which is [1,3]\nExtract column range a[:,from:to]\n    Given a [(1,2,3,4),(5,6,7,8)] matrix [:,1:3] will give [(2,3),(6,7)]\n\nAnd it works for list of indexes, negative indexes, stepped ranges, reversing,\netc. on all axes in too many ways to show all possibilities.\n\nBasically it's just the indexing and slicing applied on nested constructs,\nwhere each nesting level is separated by a comma.\n\n-------------------------------------------------------------------------------\n\nCompiler directives\n\nControlling the compile offset and program counter\n\nTwo counters are used while assembling.\n\nThe compile offset is where the data and code ends up in memory (or in image\nfile).\n\nThe program counter is what labels get set to and what the special star label\nrefers to.\n\nNormally both are the same (code is compiled to the location it runs from) but\nit does not need to be.\n\n*= \u003cexpression\u003e\n    The compile offset is adjusted so that the program counter will match the\n    requested address in the expression.\n\n    ;Offset ;PC     ;Hex            ;Monitor        ;Source\n                                                    *       = $0800\n    .0800                                           label1\n                                                            .logical $1000\n    .0800   1000                                    label2\n                                                    *       = $1200\n    .0a00   1200                                    label3\n                                                            .endlogical\n    .0a00                                           label4\n\n.offs \u003cexpression\u003e\n    Sets the compile offset relative to the program counter.\n\n    Popular in old TASM code where this was the only way to create relocated\n    code, otherwise it's use is not recommended as there are easier to use\n    alternatives below.\n\n    ;Offset ;PC     ;Hex            ;Monitor        ;Source\n                                                    *       = $1000\n    .1000           ea              nop                     nop\n                                                            .offs 100\n    .1065   1001    ea              nop                     nop\n\n.logical \u003cexpression\u003e\n    Starts a relocation block\n.here\n.endlogical\n    Ends a relocation block\n\n    Changes the program counter only, the compile offset is not changed. When\n    finished all continues where it was left off before.\n\n    The naming is not logical at all for relocated code, but that's how it was\n    named in old 6502tass.\n\n    It's used for code copied to it's proper location at runtime. Can be nested\n    of course.\n\n    ;Offset ;PC     ;Hex            ;Monitor        ;Source\n                                                    *       = $1000\n                                                            .logical $300\n    .1000   0300     a9 80          lda #$80        drive   lda #$80\n    .1002   0302     85 00          sta $00                 sta $00\n    .1004   0304     4c 00 03       jmp $0300               jmp drive\n                                                            .endlogical\n\n.virtual [\u003cexpression\u003e]\n    Starts a virtual block\n.endv\n.endvirtual\n    Ends a virtual block\n\n    Changes the program counter to the expression (if given) and discards the\n    result of compilation. This is useful to define structures to fixed\n    addresses.\n\n            .virtual $d400  ; base address\n    sid     .block\n    freq    .word ?         ; frequency\n    pulsew  .word ?         ; pulse width\n    control .byte ?         ; control\n    ad      .byte ?         ; attack/decay\n    sr      .byte ?         ; sustain/release\n            .endblock\n            .endvirtual\n\n    Or to define stack \"allocated\" variables on 65816.\n\n            .virtual #1,s\n    p1      .addr ?         ; at #1,s\n    tmp     .byte ?         ; at #3,s\n            .endvirtual\n            lda (p1),y      ; lda ($01,s),y\n\nAligning data or code\n\nAlignment is about constraining data/code placement in memory.\n\nThe processor architecture doesn't have hard constraints on instruction or data\nplacement still pages (256 bytes) come up quite often in instruction cycle\ntimes tables. Or even in errata like the indirect JMP bug which happens only if\nthe word of the vector is crossing such page.\n\nOther components like video chips can only display object if placed at an\naddress divisible by 64 for example.\n\nFor code half of an address table might be spared if it's known that all the\naddresses have the same high bytes. Or if all interrupt routines are on the\nsame page then it's enough to change the low byte of the vector when selecting\nanother one.\n\nNow it shouldn't come as a surprise that the following directives are mainly\nconcerned about how dividing the program counter address gives a certain\nremainder.\n\nThe divisor in this context is called the alignment interval and is usually a\nnumber which is a power of two. Quite often 256, so that's the default.\n\nThe remainder is called offset and is by default 0. Negative offsets are a\nconvenience feature and are internally corrected by adding the interval to it.\n\nAn interval sized memory area is called a page. It's boundary is at it's start.\nIf data spans more than one page it's known as a page boundary cross.\n\nHaving a non-zero offset effectively shifts the boundary of a page in memory\nfurther up or down (if negative). An interval of 256 with offset of 8 gives\npage boundaries of $1008, $1108 or $1208 for example.\n\nIf the alignment is not good enough some alignment directives might try to\ncorrect it by adding padding. This is by default uninitialized (skip forward)\nbut may be a fixed byte or anything more complex similarly to what the .fill\ndirective accepts.\n\nWhen alignment is done within named structures then it's relative to the start\nof the structure. This means the structure layout will always be the same\nindependent of which address it's instantiated at. Anonymous structures do not\nchange the way the alignment works.\n\nThe `-Walign' command line option can be used to emit warnings on where and how\nmuch padding was necessary for alignment.\n\n.page [\u003cinterval\u003e[, \u003coffset\u003e]]\n    Start of page check block\n.endp\n.endpage\n    End of page check block\n\n    This directive is a passive assertion and checks for a page difference or\n    page crossing.\n\n    By default or with a negative interval parameter it verifies that the start\n    and end directives are on the same page. This is what's needed to guard\n    relative branches against jumping across pages:\n\n            ldx #3\n            .page           ;now this will execute\n    -       dex             ;in 14 cycles for sure\n            bne -\n            .endpage\n\n    With a positive size parameter it verifies that there's no page cross in\n    the memory range between the directives. This is what's needed to guard\n    against indexed access page cross cycle penalties:\n\n    *       = $10c0\n            .page 256\n    table   .fill $40       ;table within the same page\n            .endpage        ;different page here but no crossing\n\n    Normally a page check results in an error but the `-Wno-error=page' command\n    line option can reduce it into a warning.\n\n    Once this directive reports an error it's time to rearrange the source in a\n    way that the check passes. Or alternatively the alignment directives below\n    can be used to avoid violating the assertion.\n\n.align [\u003cinterval\u003e[, \u003cfill\u003e[, \u003coffset\u003e]]]\n    Align the program counter to a page boundary\n\n    This directive is useful when code/data needs to be placed exactly to a\n    page boundary. If that's not already the case sufficient padding is added\n    until the next one is reached.\n\n            .align $40      ;sprite bitmap (64 byte aligned)\n    sprite  .fill 63\n            .align $400     ;screen memory (1024 byte aligned)\n    screen  .fill 1000\n            .align $400, ?, -8;sprite pointers (last 8 bytes)\n    spritep .fill 8\n            .align          ; page sized buffer at page boundary\n    sendbuf .fill 256       ;to avoid indexing penalty cycles\n\n.alignblk [\u003cinterval\u003e[, \u003cfill\u003e[, \u003coffset\u003e]]]\n    Starts alignment block.\n.endalignblk\n    Ends alignment block.\n\n    Often the start address is not important only avoiding the page boundary\n    matters.\n\n    This often can be achieved without any padding at all. If padding is\n    necessary then this directive works the same as .align including alignment\n    within structures.\n\n    It's typically used to place tables so that absolute indexed read accesses\n    won't suffer page crossing cycle penalties.\n\n            .alignblk       ;avoid page cross\n    table   .byte 0, 1, 2, 3, 4, 5, 6, 7\n            .endalignblk\n            lda table,x     ;no cycles wasted on access\n\n    In case the stronger guarantee of having both the start and the end\n    directives in the same page is required then the alignment interval needs\n    to be given as a negative number (e.g. -256). This may be necessary for\n    aligning code with relative branches.\n\n    If the block size varies based on its memory location then doing the\n    alignment may become impossible.\n\n.alignpageind \u003ctarget\u003e[, \u003cinterval\u003e[, \u003cfill\u003e[, \u003coffset\u003e]]]\n    Alignment of a page block indirectly.\n\n    Using .alignblk in the middle of executable code is usually problematic as\n    the alignment is done there as well. This directive can do the alignment\n    padding outside of the execution flow.\n\n            rts\n            .alignpageind pageblk;add alignment padding here\n    wait    ldx #3\n    pageblk .page           ;now this will execute\n    -       dex             ;in 14 cycles for sure\n            bne -\n            .endpage\n\n    By default and with a negative interval it tries to avoids page\n    differences. With positive intervals page crosses. Same as the .page\n    assertion block.\n\n    It is assumed that the padding inserted will move the target block as if\n    it'd be right in front of it. If this isn't the case the alignment will\n    fail.\n\n    If the block size varies based on its memory location then doing the\n    alignment may become impossible.\n\n.alignind \u003ctarget\u003e[, \u003cinterval\u003e[, \u003cfill\u003e[, \u003coffset\u003e]]]\n    Align the target location to a page boundary indirectly\n\n    This directive tries to align the target to a page boundary. If not already\n    on one then sufficient padding will be added until the next one is reached.\n\n    ;Align \"pos\" to page boundary. It must come right after \"neg\".\n            .alignind pos\n    neg     .fill 8\n    pos     .fill 8\n            .cerror (\u003cpos) != 0, \"pos should be page aligned\"\n            .cerror pos - neg != size(neg), \"there should be no gap\"\n\n    It is assumed that the padding inserted will move the target as if it'd be\n    right in front of it. If this isn't the case the alignment will fail.\n\n.fill \u003clength\u003e\n    Usually the .fill directive is used to reserve space but it may be useful\n    to do alignments as well.\n\n    ;replacement for a .cerror overrun check and *= combo\n            .fill start_address - *\n    ;align the vectors \"block\" so it ends at end_address\n            .fill end_address - size(vectors) - *\n    vectors .logical *      ;dummy non-scoped block for size()\n    ...\n    ;screen memory is needed but if at $9xxx then take $a000 instead\n            .align $400     ;next 1024 byte alignment\n            .fill (* \u003e\u003e 12) == $9 ? ($a000 - *) : 0\n    screen  .fill 1000\n\nDumping data\n\nStoring numeric values\n\nMulti byte numeric data is stored in the little-endian order, which is the\nnatural byte order for 65xx processors. Numeric ranges are enforced depending\non the directives used. Signed numbers are stored as two's complement.\n\nWhen using lists or tuples their content will be used one by one. Uninitialized\ndata (`?') creates holes of different sizes. Character string constants are\nconverted using the current encoding.\n\nPlease note that multi character strings usually don't fit into 8 bits and\ntherefore the .byte directive is not appropriate for them. Use .text instead\nwhich accepts strings of any length.\n\n.byte \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Create bytes from 8 bit unsigned constants (0-255)\n.char \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Create bytes from 8 bit signed constants (-128-127)\n\n    \u003e1000  ff 03                             .byte 255, $03\n    \u003e1002  41                                .byte \"a\"\n    \u003e1003                                    .byte ?        ; reserve 1 byte\n    \u003e1004  fd                                .char -3\n    ;Store 4.4 signed fixed point constants\n    \u003e1005  c8 34 32                          .char (-3.5, 3.25, 3.125) * 1p4\n    ;Compact computed jumps using self modifying code\n    .1008  bd 0f 10  lda $1010,x             lda jumps,x\n    .100b  8d 0e 10  sta $100f               sta smod+1\n    .100e  d0 fe     bne $100e       smod    bne *\n    ;Routines nearby (-128 to 127 bytes)\n    \u003e1010  23 49                     jumps   .char (routine1, routine2)-smod-2\n\n.word \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Create bytes from 16 bit unsigned constants (0-65535)\n.sint \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Create bytes from 16 bit signed constants (-32768-32767)\n\n    \u003e1000  42 23 55 45                       .word $2342, $4555\n    \u003e1004                                    .word ?        ; reserve 2 bytes\n    \u003e1006  eb fd 51 11                       .sint -533, 4433\n    ;Store 8.8 signed fixed point constants\n    \u003e100a  80 fc 40 03 20 03                 .sint (-3.5, 3.25, 3.125) * 1p8\n    .1010  bd 19 10  lda $1019,x             lda texts,x\n    .1013  bc 1a 10  ldy $101a,x             ldy texts+1,x\n    .1016  4c 1e ab  jmp $ab1e               jmp $ab1e\n    \u003e1019  33 10 59 10               texts   .word text1, text2\n\n.addr \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Create 16 bit address constants for addresses (in current program bank)\n.rta \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Create 16 bit return address constants for addresses (in current program\n    bank)\n\n                                            *       = $12000\n    .012000 7c 03 20        jmp ($012003,x)         jmp (jumps,x)\n    \u003e012003 50 20 32 03 92 15               jumps   .addr $12050, routine1, routine2\n    ;Computed jumps by using stack (current bank)\n                                            *       = $103000\n    .103000 bf 0c 30 10     lda $10300c,x           lda rets+1,x\n    .103004 48              pha                     pha\n    .103005 bf 0b 30 10     lda $10300b,x           lda rets,x\n    .103009 48              pha                     pha\n    .10300a 60              rts                     rts\n    \u003e10300b ff ef a1 36 f3 42               rets    .rta $10f000, routine1, routine2\n\n.long \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Create bytes from 24 bit unsigned constants (0-16777215)\n.lint \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Create bytes from 24 bit signed constants (-8388608-8388607)\n\n    \u003e1000   56 34 12                         .long $123456\n    \u003e1003                                    .long ?        ; reserve 3 bytes\n    \u003e1006   eb fd ff 51 11 00                .lint -533, 4433\n    ;Store 8.16 signed fixed point constants\n    \u003e100c   5d 8f fc 66 66 03 1e 85          .lint (-3.44, 3.4, 3.52) * 1p16\n    \u003e1014   03\n    ;Computed long jumps with jump table (65816)\n    .1015   bd 2a 10        lda $102a,x      lda jumps,x\n    .1018   8d 11 03        sta $0311        sta ind\n    .101b   bd 2b 10        lda $102b,x      lda jumps+1,x\n    .101e   8d 12 03        sta $0312        sta ind+1\n    .1021   bd 2c 10        lda $102c,x      lda jumps+2,x\n    .1024   8d 13 03        sta $0313        sta ind+2\n    .1027   dc 11 03        jmp [$0311]      jmp [ind]\n    \u003e102a   32 03 01 92 05 02        jumps   .long routine1, routine2\n\n.dword \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Create bytes from 32 bit unsigned constants (0-4294967295)\n.dint \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Create bytes from 32 bit signed constants (-2147483648-2147483647)\n\n    \u003e1000   78 56 34 12             .dword $12345678\n    \u003e1004                           .dword ?        ; reserve 4 bytes\n    \u003e1008   5d 7a 79 e7             .dint -411469219\n    ;Store 16.16 signed fixed point constants\n    \u003e100c   5d 8f fc ff 66 66 03 00 .dint (-3.44, 3.4, 3.52) * 1p16\n    \u003e1014   1e 85 03 00\n\n.text bits(\u003cexpression\u003e[, \u003cbit count\u003e])\n    Create bytes from arbitrary precision unsigned and signed numbers.\n.text bytes(\u003cexpression\u003e[, \u003cbyte count\u003e])\n    Create bytes from arbitrary precision unsigned and signed numbers.\n\n    For cases not covered by the numeric store directives above it's possible\n    to convert numbers to byte or bit strings and store the resulting string.\n    If the count expression of bytes() and bits() is negative then the stored\n    number is signed otherwise unsigned.\n\n    \u003e1000   74 65 78 74 00 00 00 00 .text bytes(\"text\", 8);pad up to 8 bytes\n    \u003e1008   f4 ff ff ff ff ff ff ff .text bytes(-12, -8)  ;8 bytes signed\n    \u003e1010   00 04 00 00 00 00       .text bits(1024, 48)  ;48 bits unsigned\n    \u003e1016   f4 ff ff ff ff ff       .text bits(-12, -48)  ;48 bits signed\n\nStoring string values\n\nThe following directives store strings of characters, bytes or bits as bytes.\nSmall numeric constants can be mixed in to represent single byte control\ncharacters.\n\nWhen using lists or tuples their content will be used one by one. Uninitialized\ndata (`?') creates byte sized holes. Character string constants are converted\nusing the current encoding.\n\n.text \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Assemble strings into 8 bit bytes.\n\n    \u003e1000   4f 45 d5  .text \"oeU\"\n    \u003e1003   4f 45 d5  .text 'oeU'\n    \u003e1006   17 33     .text 23, $33  ; bytes\n    \u003e1008   0d 0a     .text $0a0d    ; $0d, $0a, little endian!\n    \u003e100a   1f        .text %00011111; more bytes\n\n.fill \u003clength\u003e[, \u003cfill\u003e]\n    Reserve space (using uninitialized data), or fill with repeated bytes.\n\n    \u003e1000             .fill $100      ;no fill, just reserve $100 bytes\n    \u003e1100   00 00 00  .fill $4000, 0  ;16384 bytes of 0\n    ...\n    \u003e5100   55 aa 55  .fill 8000, [$55, $aa];8000 bytes of alternating $55, $aa\n    ...\n    \u003e7040   ff ff ff  .fill $8000 - *, $ff;fill up rest of EPROM with $ff\n    ...\n\n.shift \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Assemble strings of 7 bit bytes and mark the last byte by setting it's most\n    significant bit.\n\n    Any byte which already has the most significant bit set will cause an\n    error. The last byte can't be uninitialized or missing of course.\n\n    The naming comes from old TASM and is a reference to setting the high bit\n    of alphabetic letters which results in it's uppercase version in PETSCII.\n\n    .1000   a2 00         ldx #$00                ldx #0\n    .1002   bd 10 10      lda $1010,x     loop    lda txt,x\n    .1005   08            php                     php\n    .1006   29 7f         and #$7f                and #$7f\n    .1008   20 d2 ff      jsr $ffd2               jsr $ffd2\n    .100b   e8            inx                     inx\n    .100c   28            plp                     plp\n    .100d   10 f3         bpl $1002               bpl loop\n    .100f   60            rts                     rts\n    \u003e1010   53 49 4e 47 4c 45 20 53       txt     .shift \"single\", 32, \"string\"\n    \u003e1018   54 52 49 4e c7\n\n.shiftl \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Assemble strings of 7 bit bytes shifted to the left once with the last\n    byte's least significant bit set.\n\n    Any byte which already has the most significant bit set will cause an error\n    as this is cut off on shifting. The last byte can't be uninitialized or\n    missing of course.\n\n    The naming is a reference to left shifting.\n\n    .1000   a2 00         ldx #$00                ldx #0\n    .1002   bd 0d 10      lda $100d,x     loop    lda txt,x\n    .1005   4a            lsr a                   lsr a\n    .1006   9d 00 04      sta $0400,x             sta $400,x      ;screen memory\n    .1009   e8            inx                     inx\n    .100a   90 f6         bcc $1002               bcc loop\n    .100c   60            rts                     rts\n                                                  .enc \"screen\"\n    \u003e100d   a6 92 9c 8e 98 8a 40 a6       txt     .shiftl \"single\", 32, \"string\"\n    \u003e1015   a8 a4 92 9c 8f                        .enc \"none\"\n\n.null \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Same as .text, but adds a zero byte to the end. An existing zero byte is an\n    error as it'd cause a false end marker.\n\n    .1000   a9 07         lda #$07                lda #\u003ctxt\n    .1002   a0 10         ldy #$10                ldy #\u003etxt\n    .1004   20 1e ab      jsr $ab1e               jsr $ab1e\n    \u003e1007   53 49 4e 47 4c 45 20 53       txt     .null \"single\", 32, \"string\"\n    \u003e100f   54 52 49 4e 47 00\n\n.ptext \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Same as .text, but prepend the number of bytes in front of the string\n    (pascal style string). Therefore it can't do more than 255 bytes.\n\n    .1000   a9 1d         lda #$1d                lda #\u003ctxt\n    .1002   a2 10         ldx #$10                ldx #\u003etxt\n    .1004   20 08 10      jsr $1008               jsr print\n    .1007   60            rts                     rts\n\n    .1008   85 fb         sta $fb         print   sta $fb\n    .100a   86 fc         stx $fc                 stx $fc\n    .100c   a0 00         ldy #$00                ldy #0\n    .100e   b1 fb         lda ($fb),y             lda ($fb),y\n    .1010   f0 0a         beq $101c               beq null\n    .1012   aa            tax                     tax\n    .1013   c8            iny             -       iny\n    .1014   b1 fb         lda ($fb),y             lda ($fb),y\n    .1016   20 d2 ff      jsr $ffd2               jsr $ffd2\n    .1019   ca            dex                     dex\n    .101a   d0 f7         bne $1013               bne -\n    .101c   60            rts             null    rts\n    \u003e101d   0d 53 49 4e 47 4c 45 20       txt     .ptext \"single\", 32, \"string\"\n    \u003e1025   53 54 52 49 4e 47\n\nText encoding\n\n64tass supports sources written in UTF-8, UTF-16 (be/le) and RAW 8 bit\nencoding. To take advantage of this capability custom encodings can be defined\nto map Unicode characters to 8 bit values in strings. Even in plain ASCII\nsources it could be useful to define escape sequences for control codes.\n\n.enc \u003cexpression\u003e\n    Selects text encoding by a character string name or from an encoding object\n\n    Predefined encodings names are `none' and `screen' (screen code), anything\n    else is user defined. All user encodings start without any character or\n    escape definitions, add some as required. Please note that the encoding\n    names are global.\n\n    This directive changes the text encoding after it therefore it's usually\n    placed somewhere at the beginning of the source to make sure everything is\n    covered.\n\n    While it is possible to juggle with multiple encodings throughout the\n    source code using the .enc directive this is not recommended. For such use\n    case .encode is better suited.\n\n    In the past the .enc directive accepted an unquoted string but currently it\n    needs to be an expression.\n\n                                    .enc \"screen\";screen code mode\n    \u003e1000   13 03 12 05 05 0e 20 03 .text \"screen codes\"\n    \u003e1008   0f 04 05 13\n    .100c   c9 15    cmp #$15       cmp #\"u\"    ;compare screen code\n                                    .enc \"none\" ;normal mode again\n    .100e   c9 55    cmp #$55       cmp #\"u\"    ;compare PETSCII\n\n.encode [\u003cexpression\u003e]\n    Encoding area start\n.endencode\n    Encoding area end\n\n    This directive either creates a new text encoding (if used without a\n    parameter) or makes the one in the parameter effective within the enclosed\n    area.\n\n    The text encoding can be assigned to a symbol in front of the directive so\n    it can be reused whenever it's needed. This symbol can also act as a\n    conversion function which converts a character string to a byte string\n    using the encoding.\n\n            .encode         ;starts anonymous local encoding scope\n            .enc \"titlefont\";special character set\n            .text \"game title\"\n            .endencode      ;restores original encoding\n\n    vt100   .encode         ;define custom encoding\n            .cdef \" ~\", 32\n            .edef \"{esc}\", 27;add escape codes\n            .edef \"{moff}\", [27, \"[\", \"m\"]\n            .edef \"{bold}\", [27, \"[\", \"1\", \"m\"]\n            .endencode\n\n            .encode vt100   ;use custom encoding from here\n            .text \"{bold}bold{moff} text\"\n            lda #\"{esc}\"\n            .endencode      ;restores original encoding\n            cmp #vt100(\"{esc}\");conversion when not in scope\n            .enc vt100      ;select custom encoding (at start of source)\n\n.cdef \u003cstart\u003e, \u003cend\u003e, \u003ccoded\u003e [, \u003cstart\u003e, \u003cend\u003e, \u003ccoded\u003e, ...]\n.cdef \"\u003cstart\u003e\u003cend\u003e\", \u003ccoded\u003e [, \"\u003cstart\u003e\u003cend\u003e\", \u003ccoded\u003e, ...]\n    Assigns characters in a range to single bytes.\n\n    This is a simple single character to byte translation definition. It's\n    useful to map a range of Unicode characters to a range of bytes. The start\n    and end positions are Unicode character codes either by numbers or by\n    typing them. Overlapping ranges are not allowed.\n\n            .enc \"ascii\"    ;define an ascii encoding\n            .cdef \" ~\", 32  ;identity mapping for printable\n\n.tdef \u003cexpression\u003e, \u003cexpression\u003e [, \u003cexpression\u003e, \u003cexpression\u003e, ...]\n    Assign single characters to byte values.\n\n    Similar to .cdef it is a single character to byte translation definition.\n    It's easier to use when the character codes are not consecutive.\n    Overlapping ranges with the former and itself are not allowed.\n\n    It tries to assign Unicode character codes from the first expression to\n    byte values from the second. More than one pair of such assignments can be\n    given.\n\n    If the byte value expression is not iterable then it will get incremented\n    for each character definition. This allows easy assignment of randomly\n    scattered Unicode values to a consecutive range of bytes values.\n\n            .tdef \"A\", 65   ;A -\u003e 65\n            .tdef \"ACX\", 65 ;A -\u003e 65, C-\u003e 66, X -\u003e 67\n            .tdef \"ACX\", [65, 33, 11];A -\u003e 65, C-\u003e 33, X -\u003e 11\n\n.edef \"\u003cescapetext\u003e\", \u003cvalue\u003e [, \"\u003cescapetext\u003e\", \u003cvalue\u003e, ...]\n    Assigns strings to byte sequences as a translated value.\n\n    When these substrings are found in a text they are replaced by bytes\n    defined here. When strings with common prefixes are used the longest match\n    wins. Useful for defining non-typeable control code aliases, or as a simple\n    tokeniser.\n\n            .edef \"\\n\", 13  ;one byte control codes\n            .edef \"{clr}\", 147\n            .edef \"{crlf}\", [13, 10];two byte control code\n            .edef \"\u003cnothing\u003e\", [];replace with no bytes\n\nThe example below shows how all this fits together:\n\npetscii .namespace\ncommon  .segment;common definitions\n        .cdef \" @\", $20;32-64 is identical\n        .tdef \"[?]??\", $5b, \"???\", $db\n        .edef \"{clr}\", 147, \"{cr}\", 13\n        .endsegment\nupper   .encode;uppercase PETSCII\n        #common\n        .cdef \"AZ\", $41\n        .tdef \"????????????????????????????????\", $a1\n        .tdef \"??????????????????????????\", $c1\n        .tdef \"????\", [$df, $ff, $c0, $dd]\n        .endencode\n\nlower   .encode;lowercase PETSCII\n        #common\n        .cdef \"az\", $41, \"AZ\", $c1;the easy ranges\n        .tdef \"????????????????????????????????\", $a1\n        .tdef \"????\", [$df, $ff, $c0, $dd];random one to ones\n        .endencode\n        .endnamespace\n\n                                    .encode petscii.lower\n\u003e1000   93 d4 45 58 54 20 49 4e    .text \"{clr}Text in PETSCII{cr}\"\n\u003e1008   20 d0 c5 d4 d3 c3 c9 c9 0d\n                                    .endencode\n\nStructured data\n\nStructures and unions can be defined to create complex data types. The offset\nof fields are available by using the definition's name. The fields themselves\nby using the instance name.\n\nThe initialization method is very similar to macro parameters, the difference\nis that unset parameters always return uninitialized data (`?') instead of an\nerror.\n\nStructure\n\nStructures are for organizing sequential data, so the length of a structure is\nthe sum of lengths of all items.\n\n.struct [\u003cname\u003e][=\u003cdefault\u003e]][, [\u003cname\u003e][=\u003cdefault\u003e] ...]\n    Begins a structure block\n.ends [\u003cresult\u003e][, \u003cresult\u003e ...]\n.endstruct [\u003cresult\u003e][, \u003cresult\u003e ...]\n    Ends a structure block\n\n    Structure definition, with named parameters and default values\n\n.dstruct \u003cname\u003e[, \u003cinitialization values\u003e]\n.\u003cname\u003e [\u003cinitialization values\u003e]\n    Create instance of structure with initialization values\n\n        .struct         ;anonymous structure\nx       .byte 0         ;labels are visible\ny       .byte 0         ;content compiled here\n        .endstruct      ;useful inside unions\n\nnn_s    .struct col, row;named structure\nx       .byte \\col      ;labels are not visible\ny       .byte \\row      ;no content is compiled here\n        .endstruct      ;it's just a definition\n\nnn      .dstruct nn_s, 1, 2;structure instance (within label)\n\n        lda nn.x        ;direct field access\n        ldy #nn_s.x     ;get offset of field\n        lda nn,y        ;and use it indirectly\n\nnnarray .brept 4        ;4 element \"array\" here\n        .dstruct nn_s   ;fields directly here (without a label)\n        .endrept\n\n        lda nnarray[0].y;access of \"array\" field\n\ncoords2 .bfor x2, y2 in [(1,3),(4,2),(7,5)]\n        .dstruct nn_s, x2, y2\n        .endfor         ;initialized \"array\" from list\n\nUnion\n\nUnions can be used for overlapping data as the compile offset and program\ncounter remains the same on each line. Therefore the length of a union is the\nlength of it's longest item.\n\n.union [\u003cname\u003e][=\u003cdefault\u003e]][, [\u003cname\u003e][=\u003cdefault\u003e] ...]\n    Begins a union block\n.endu\n.endunion\n    Ends a union block\n\n    Union definition, with named parameters and default values\n\n.dunion \u003cname\u003e[, \u003cinitialization values\u003e]\n.\u003cname\u003e [\u003cinitialization values\u003e]\n    Create instance of union with initialization values\n\n        .union          ;anonymous union\nx       .byte 0         ;labels are visible\ny       .word 0         ;content compiled here\n        .endunion\n\nnn_u    .union          ;named union\nx       .byte ?         ;labels are not visible\ny       .word \\1        ;no content is compiled here\n        .endunion       ;it's just a definition\n\nnn      .dunion nn_u, 1 ;union instance here\n\n        lda nn.x        ;direct field access\n        ldy #nn_u.x     ;get offset of field\n        lda nn,y        ;and use it indirectly\n\nCombined use of structures and unions\n\nThe example below shows how to define structure to a binary include.\n\n        .union\n        .binary \"pic.drp\", 2\n        .struct\ncolor   .fill 1024\nscreen  .fill 1024\nbitmap  .fill 8000\nbackg   .byte ?\n        .endstruct\n        .endunion\n\nAnonymous structures and unions in combination with sections are useful for\noverlapping memory assignment. The example below shares zero page allocations\nfor two separate parts of a bigger program. The common subroutine variables are\nassigned after in the `zp' section.\n\n*       = $02\n        .union          ;spare some memory\n         .struct\n          .dsection zp1 ;declare zp1 section\n         .endstruct\n         .struct\n          .dsection zp2 ;declare zp2 section\n         .endstruct\n        .endunion\n        .dsection zp    ;declare zp section\n\nMacros\n\nMacros can be used to reduce typing of frequently used source lines. Each\ninvocation is a copy of the macro's content with parameter references replaced\nby the parameter texts.\n\n.segment [\u003cname\u003e][=\u003cdefault\u003e]][, [\u003cname\u003e][=\u003cdefault\u003e] ...]\n    Start of segment block\n.endsegment [\u003cresult\u003e][, \u003cresult\u003e ...]\n    End of segment block\n\n    Copies the code segment as it is, so symbols can be used from outside, but\n    this also means repeated use can result in double defines unless anonymous\n    labels are used.\n\n.macro [\u003cname\u003e][=\u003cdefault\u003e]][, [\u003cname\u003e][=\u003cdefault\u003e] ...]\n    Start of macro block\n.endmacro [\u003cresult\u003e][, \u003cresult\u003e ...]\n    End of macro block\n\n    The code is enclosed in it's own block so symbols inside are\n    non-accessible, unless a label is prefixed at the place of use, then local\n    labels can be accessed through that label.\n\n    A side effect of this is that trying to use a local symbol's name as a\n    parameter will likely fail. The reason is it'll be looked up in the macro's\n    own scope but that's not where it is. To avoid such surprises it's advised\n    to use .segment instead whenever possible.\n\n#\u003cname\u003e [\u003cparam\u003e][[,][\u003cparam\u003e] ...]\n.\u003cname\u003e [\u003cparam\u003e][[,][\u003cparam\u003e] ...]\n    Invoke the macro after `#' or `.' with the parameters. Normally the name of\n    the macro is used, but it can be any expression.\n.endm [\u003cresult\u003e][, \u003cresult\u003e ...]\n    Closing directive of .macro and .segment for compatibility.\n\n;A simple macro\ncopy    .macro\n        ldx #size(\\1)\nlp      lda \\1,x\n        sta \\2,x\n        dex\n        bpl lp\n        .endmacro\n\n        #copy label, $500\n\n;Use macro as an assembler directive\nlohi    .macro\nlo      .byte \u003c(\\@)\nhi      .byte \u003e(\\@)\n        .endmacro\n\nvar     .lohi 1234, 5678\n\n        lda var.lo,y\n        ldx var.hi,y\n\nParameter references\n\nThe first 9 parameters can be referenced by `\\1'-`\\9'. The entire parameter\nlist including separators is `\\@'.\n\nname    .macro\n        lda #\\1         ;first parameter 23+1\n        .endmacro\n\n        #name 23+1      ;call macro\n\nParameters can be named, and it's possible to set a default value after an\nequal sign which is used as a replacement when the parameter is missing.\n\nThese named parameters can be referenced by \\name or \\{name}. Names must match\ncompletely, if unsure use the quoted name reference syntax.\n\nname    .macro first, b=2, , last\n        lda #\\first     ;first parameter\n        lda #\\b         ;second parameter\n        lda #\\3         ;third parameter\n        lda #\\last      ;fourth parameter\n        .endmacro\n\n        #name 1, , 3, 4 ;call macro\n\nText references\n\nIn the original turbo assembler normal references are passed by value and can\nonly appear in place of one. Text references on the other hand can appear\neverywhere and will work in place of e.g. quoted text or opcodes and labels.\nThe first 9 parameters can be referenced as text by @1-@9.\n\nname    .macro\n        jsr print\n        .null \"Hello @1!\";first parameter\n        .endm\n\n        #name \"wth?\"    ;call macro\n\nCustom functions\n\nBeyond the built-in functions mentioned earlier it's possible to define custom\nones for frequently used calculations.\n\n.sfunction [\u003cname\u003e[:\u003cexpression\u003e][=\u003cdefault\u003e], ...][*\u003cname\u003e,] \u003cexpression\u003e\n    Defines a simple function to return the result of a parametrised expression\n.function \u003cname\u003e[:\u003cexpression\u003e][=\u003cdefault\u003e]], \u003cname\u003e[=\u003cdefault\u003e] ...][, *\n    \u003cname\u003e]\n    Defines a multi line function\n.endf [\u003cresult\u003e][, \u003cresult\u003e ...]\n.endfunction [\u003cresult\u003e][, \u003cresult\u003e ...]\n    End of a multi line function\n#\u003cname\u003e [\u003cparam\u003e][[,][\u003cparam\u003e] ...]\n.\u003cname\u003e [\u003cparam\u003e][[,][\u003cparam\u003e] ...]\n\u003cname\u003e [\u003cparam\u003e][[,][\u003cparam\u003e] ...]\n    Invoke a multi line function like a macro, directive or pseudo instruction\n\nFunction parameters are assigned to comma separated variable names on\ninvocation. These variables are visible in the function scope.\n\nParameter values may be converted using a function whose name can be given\nafter a colon following the variable name.\n\nDefault values may be supplied for each parameter after an equal sign. These\nvalues are calculated at function definition time only and are used when a\nparameter was not specified.\n\nExtra parameters are not accepted, unless the last parameter symbol is preceded\nwith a star, in this case these parameters are collected into a tuple.\n\nOnly those external variables and functions are available which were accessible\nat the place of definition, but not those at the place of invocation.\n\nvicmem  .sfunction _font, _scr=0, ((_font \u003e\u003e 10) \u0026 $0f) | ((_scr \u003e\u003e 6) \u0026 $f0)\n\n        lda #vicmem($2000, $0400); calculate constant\n        sta $d018\n\nIf a multi line function is used in an expression only the returned result is\nused. If multiple values are returned these will form a tuple.\n\nIf a multi line function is used as macro, directive or pseudo instruction and\nthere's a label in front then the returned value is assigned to it. If nothing\nis returned then it's used as regular label.\n\nmva     .function value, target\n        lda value\n        sta target\n        .endfunction\n\n        mva #1, label\n\nConditional assembly\n\nTo prevent parts of source from compiling conditional constructs can be used.\nThis is useful when multiple slightly different versions needs to be compiled\nfrom the same source.\n\nAnonymous labels are still recognized in the non-compiling parts even if they\nwon't get defined. This ensures consistent relative referencing across\nconditionally compiled areas with such labels.\n\nIf, else if, else\n\n.if \u003ccondition\u003e\n    Compile if condition is true\n.elsif \u003ccondition\u003e\n    Compile if previous conditions were not met and the condition is true\n.else\n    Compile if previous conditions were not met\n.ifne \u003cvalue\u003e\n    Compile if value is not zero\n.ifeq \u003cvalue\u003e\n    Compile if value is zero\n.ifpl \u003cvalue\u003e\n    Compile if value is greater or equal zero\n.ifmi \u003cvalue\u003e\n    Compile if value is less than zero\n\n    The .ifne, .ifeq, .ifpl and .ifmi directives exists for compatibility only,\n    in practice it's better to use comparison operators instead.\n\n            .if wait==2     ;2 cycles\n            nop\n            .elsif wait==3  ;3 cycles\n            bit $ea\n            .elsif wait==4  ;4 cycles\n            bit $eaea\n            .else           ;else 5 cycles\n            inc $2\n            .endif\n\n.fi\n.endif\n    End of conditional compilation.\n.elif \u003ccondition\u003e\n    Same as .elsif because it's a popular typo and it's difficult to notice.\n\nSwitch, case, default\n\nSimilar to the .if, .elsif, .else, .endif construct, but the compared value\nneeds to be written only once in the switch statement.\n\n.switch \u003cexpression\u003e\n    Evaluate expression and remember it\n.case \u003cexpression\u003e[, \u003cexpression\u003e ...]\n    Compile if the previous conditions were all skipped and one of the values\n    equals\n.default\n    Compile if the previous conditions were all skipped\n\n            .switch wait\n            .case 2         ;2 cycles\n            nop\n            .case 3         ;3 cycles\n            bit $ea\n            .case 4         ;4 cycles\n            bit $eaea\n            .default        ;else 5 cycles\n            inc $2\n            .endswitch\n\n.endswitch\n    End of .switch conditional compilation block.\n\nComment\n\n.comment\n    Never compile.\n\n            .comment\n            lda #1          ;this won't be compiled\n            sta $d020\n            .endcomment\n\n.endc\n.endcomment\n    End of .comment block.\n\nRepetitions\n\nThere are multiple directives which can be used to repeat lines of code.\n\nThe regular non-scoped variants cover most cases except when normal labels are\nrequired as those will be double defined.\n\nScoped variants (those starting with the letter `b') create a new scope for\neach iteration. This allows normal labels without collision but it's a bit more\nresource intensive.\n\nIf the scoped variant is prefixed with a label then the list of individual\nscopes for each iteration will be assigned to it. This allows accessing labels\nwithin.\n\n.for [\u003cassignment\u003e], [\u003ccondition\u003e], [\u003cassignment\u003e]\n.bfor [\u003cassignment\u003e], [\u003ccondition\u003e], [\u003cassignment\u003e]\n    Assign initial value, loop while the condition is true and modify value.\n\n    First a variable is set, usually this is used for counting. This is\n    optional, the variable may be set already before the loop.\n\n    Then the condition is checked and the enclosed lines are compiled if it's\n    true. If there's no condition then it's an infinite loop and .break must be\n    used to terminate it.\n\n    After an iteration the second assignment is calculated, usually it's\n    updating the loop counter variable. This is optional as well.\n\n    All three expressions are free form and can be almost anything which makes\n    this style of loop very flexible. A good example is this loop which\n    processes a multipart data structure having a word sized length field in\n    front of each part:\n\n            .for pos := 0, pos \u003c len(data), pos += data[pos : pos + 2]\n            ...\n            .endfor\n\n    Still in it's most typical application it just increments a counter from\n    start to end by constant steps:\n\n            .for counter := start, counter \u003c end, counter += step\n            ...\n            .endfor\n\n    If the loop counter only runs through a range of integers then this\n    iterative form is recommended instead:\n\n    ;Iterative for loop (start to end with steps, not including end)\n            .for counter in range(start, end, step)\n    ;Can be shorter if step is 1 (start to end-1)\n            .for counter in range(start, end)\n    ;Or even shorter if start is 0 (0 to end-1)\n            .for counter in range(end)\n\n    That's not only more compact it also has the advantage that the counter\n    name doesn't need to be repeated 3 times.\n\n    If the counter isn't used in the loop body then a simple repetition is\n    better:\n\n            .rept count\n            ...\n            .endrept\n\n    A for loop can also act as a while loop when the assignment expressions are\n    left empty. That was useful in the past but there's a .while now.\n\n.for \u003cvariable\u003e[, \u003cvariable\u003e, ...] in \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n.bfor \u003cvariable\u003e[, \u003cvariable\u003e, ...] in \u003cexpression\u003e[, \u003cexpression\u003e, ...]\n    Assign variable(s) to values in sequence one-by-one in order.\n\n    Usually one variable is used to loop through all values. The values can be\n    supplied by range function or some sort of list.\n\n    ;loop through on iterable or on comma separated values\n            .for col in 0, 11, 12, 15, 1\n            lda #col         ;0, 11, 12, 15 and 1\n            sta $d020\n            .endfor\n\n    It's also possible to use more than one variable for each iteration. These\n    can be assigned to a collection of values each time (row oriented) or a\n    single value from each collection (column oriented).\n\n    A row oriented for loop expects collections of the same number of values as\n    the number of variables as each variable gets assigned to one of them. The\n    loop iteration count depends on how many such collections were supplied.\n\n    ;row oriented iterating for loop, on list of tuples\n            .for dest, val in [($d011, $3b), ($d020, 0), ($d018, $18)]\n            lda #val\n            sta dest\n            .endfor\n\n    A column oriented for loop expects the same number of collections (comma\n    separated) as the number of variables. On each iteration a single value is\n    taken from each and is assigned to the matching variable. All collections\n    should have the same length so that all variables can be assigned. This\n    length also determines the loop iteration count.\n\n    ;column oriented iterating for loop, one iterable for each variable.\n            .for dest, val in ($d011, $d020, $d018), ($3b, 0, $18)\n            lda #val\n            sta dest\n            .endfor\n\n.endfor\n    End of a .for or .bfor loop block\n.rept \u003cexpression\u003e\n.brept \u003cexpression\u003e\n    Repeat enclosed lines the specified number of times.\n\n    This style of loop is for simple repetitions where no loop variable is\n    needed.\n\n            lda pos\n            .rept 3         ;multiply pos by 8\n            asl a\n            rol pos+1\n            .endrept\n            adc #\u003cstart\n\n    As .rept simply repeats lines anonymous labels are preferred in the loop\n    body. Using anonymous scopes to enclose parts with regular labels is also a\n    working strategy to get around redefinition errors.\n\n            lsr a           ;result = a * (x + 1)\n            sta result\n            stx tmp\n            lda #0\n            .rept 8         ;unroll for speed\n            bcc +\n            adc tmp\n    +       ror a\n            ror result\n            .endrept\n            sta r","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Firmen%2F64tass","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Firmen%2F64tass","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Firmen%2F64tass/lists"}