{"id":1520,"date":"2021-05-15T07:30:19","date_gmt":"2021-05-15T05:30:19","guid":{"rendered":"https:\/\/www.pagetable.com\/?p=1520"},"modified":"2021-05-15T07:30:19","modified_gmt":"2021-05-15T05:30:19","slug":"commodores-assemblers-part-1-mos-cross-assembler","status":"publish","type":"post","link":"https:\/\/www.pagetable.com\/?p=1520","title":{"rendered":"Commodore&#039;s Assemblers: Part 1:\u00a0MOS Cross-Assembler"},"content":{"rendered":"<p>In the series about the assemblers Commodore used for developing the ROMs of their 8-bit computers, this article covers the 1975 &ldquo;MOS Cross-Assembler&rdquo;, which was available for various mainfraimes of the era.<\/p>\n<p><a href=\"https:\/\/archive.org\/details\/mos-6500-software-support\"><img decoding=\"async\" src=\"docs\/cbmasm\/cross-assembler.png\" alt=\"\" \/><\/a><\/p>\n<h2 id=\"series-overview\">Series Overview<\/h2>\n<ul>\n<li><a href=\"https:\/\/www.pagetable.com\/?p=1518\">Part 0:\u00a0Overview<\/a><\/li>\n<li><strong>Part 1:\u00a0MOS Cross-Assembler<\/strong> \u2190 this article<\/li>\n<li><a href=\"https:\/\/www.pagetable.com\/?p=1522\">Part 2:\u00a0MOS Resident Assembler<\/a><\/li>\n<li><a href=\"https:\/\/www.pagetable.com\/?p=1538\">Part 3:\u00a0BSO CY6502<\/a><\/li>\n<li><a href=\"https:\/\/www.pagetable.com\/?p=1540\">Part 4:\u00a0HCD65<\/a><\/li>\n<li><a href=\"https:\/\/www.pagetable.com\/?p=1542\">Part 5:\u00a06502ASM<\/a><\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"docs\/cbmasm\/cbmasm_history.png\" alt=\"\" \/><\/p>\n<h2 id=\"history\">History<\/h2>\n<p>MOS Technology, Inc. released two assemblers for the newly introduced 6502 architecture: the &ldquo;<strong>Cross-Assembler<\/strong>&rdquo;, available for various mainframes and minicomputers, and the &ldquo;<strong>Resident Assembler<\/strong>&rdquo;, running on natively on 6502 systems.<\/p>\n<p><a href=\"https:\/\/www.pagetable.com\/?p=1520#comment-694762\">According to Norm Farrington<\/a>, MOS contracted with the company COMPAS to write the Cross-Assembler. COMPAS specialized in 6502-related software and hardware and developed some of the official MOS peripherals for the KIM-1.<\/p>\n<p>The Cross-Assembler was <a href=\"https:\/\/archive.org\/details\/crossassemblersi886blan\">written in FORTRAN<\/a><sup id=\"fnref:1\"><a href=\"#fn:1\" rel=\"footnote\">1<\/a><\/sup> and used a 6-bit (i.e. all uppercase) character encoding. On a CDC Cyber 175 system, it required 120K (!) 60-bit words of memory to run and had &ldquo;generally acceptable&rdquo; response times.<\/p>\n<p>The Resident Assembler (<a href=\"https:\/\/www.pagetable.com\/?p=1522\">part 2<\/a> of the series) was then developed (also by COMPAS) using the Cross-Assembler, and designed to be compatible in that it understood the same source format, with the same math features and the same directives and options. This way, MOS defined the basic format supported by all future Commodore assemblers.<\/p>\n<h2 id=\"platforms\">Platforms<\/h2>\n<p>Today, you would expect a cross-assembler to run on Linux, Windows or Mac. But these were different times: When the 6502 was released, <em>micro<\/em>computers were just appearing \u2013 and the 6502 was a part of this shift \u2013 and even the first fridge-sized <em>mini<\/em>computers like the PDP series had only been introduced 10 years earlier. Most companies that used computers at the time used terminals that dialed into mainframes hosted in computing centers. And the market was very fragmented.<\/p>\n<p>The 6502 <a href=\"http:\/\/archive.6502.org\/books\/mcs6500_family_programming_manual.pdf\">Programming Manual (6500-50A)<\/a> states:<\/p>\n<blockquote>\n<p>The Cross Assembler is available on various time share systems or for batch use on the user&rsquo;s system.<\/p>\n<\/blockquote>\n<p>According to the 6502 <a href=\"docs\/cbmasm\/MCS6500%20Microcomputer%20Family%20Cross%20Assembler%20Manual.pdf\">Cross Assembler Manual (6500-60P)<\/a>, the supported platforms as of August 1975 were:<\/p>\n<ul>\n<li><a href=\"https:\/\/en.wikipedia.org\/wiki\/General_Electric\">GE<\/a> Timesharing, running on GE\/Honeywell mainframes<\/li>\n<li><a href=\"https:\/\/en.wikipedia.org\/wiki\/National_CSS\">National CSS<\/a> time-sharing, running VP\/CSS on IBM System\/360 and System\/370 mainframes<\/li>\n<\/ul>\n<p>And the 1975 <a href=\"https:\/\/www.team6502.org\/uploads\/1\/0\/6\/0\/106091831\/mos_brochure.pdf\">MOS Technology marketing brochure<\/a>:<\/p>\n<blockquote>\n<p>Current plans involve having the software available on several of the more popular Time Sharing services.<\/p>\n<p>In addition, it will be available for deck sales. Batch decks for the CDC, IBM, and PDP-11 class machines are available and we will support several other popular mini and major computer systems in the near future.<\/p>\n<\/blockquote>\n<p>Furthermore:<\/p>\n<ul>\n<li>The 1975 <a href=\"https:\/\/archive.org\/details\/mos-6500-software-support\">MCS6500 Microprocessor Software Support brochure<\/a> shows the Cross-Assembler running on the United Computing Systems (UCS) time-sharing service.<\/li>\n<li>A 1976 <a href=\"https:\/\/lib.dr.iastate.edu\/cgi\/viewcontent.cgi?article=6700&amp;context=rtd\">dissertation<\/a> shows that the Iowa State University ran the Cross-Assembler locally on an IBM 360\/370.<\/li>\n<li>A 1977 <a href=\"https:\/\/archive.org\/details\/bitsavers_ElectronicignV25N2119771011_176731913\">magazine article<\/a> mentions support for PDP-8, PDP-10 and PDP-11.<\/li>\n<\/ul>\n<p><!--  NASA was using Cross-Assembler 5.1: https:\/\/ia601203.us.archive.org\/23\/items\/NASA_NTRS_Archive_19800013494\/NASA_NTRS_Archive_19800013494.pdf \u2013 Not sure what hardware it was on, though... --><\/p>\n<h2 id=\"basic-syntax\">Basic Syntax<\/h2>\n<p>Back then, not all computer systems used the ASCII encoding, and some computers didn&rsquo;t even support lower case. The encoding of source files is therefore specific to the platform the Cross-Assembler runs on, and only uppercase characters were allowed.<\/p>\n<p>Here is an example from the manual:<\/p>\n<pre><code>;\n; 650X CROSS ASSEMBLER SAMPLE PROGRAM.\n;\n *=$C000     DEFINE ORIGIN.\n LDX #$FF    SET UP STACK.\n TXS         LOAD STACK POINTER.\n LDA #$F0    LOAD A WITH HEX F0.\n STA ASAVE   SAVE A IN ASAVE.\n;\n; ALLOCATE SAVE AREA.\n;\n *=$0000\nASAVE *=*\n .END\n<\/code><\/pre>\n<ul>\n<li>Lines starting with <code>;<\/code> are comments and will be ignored.<\/li>\n<li>Labels start at the first column, everything else is indented.<\/li>\n<li>Comments may follow the operand or the operand-less mnemonic. No <code>;<\/code> is necessary.<\/li>\n<li>The Cross-Assembler uses the <code>*=<\/code> syntax to define the current assembly address.<\/li>\n<\/ul>\n<p>The rule about the start columns of labels and assembly statements is actually more relaxed, as this very compressed example from the C64 KERNAL shows:<\/p>\n<pre><code>;COMMAND SERIAL BUS DEVICE TO LISTEN\n;\nLISTN ORA #$20 ;MAKE A LISTEN ADR\nJSR RSP232 ;PROTECT SELF FROM RS232 NMI'S\nLIST1 PHA\n<\/code><\/pre>\n<p>Since all mnemos and register names are reserved keywords and cannot be used for labels, the assembler does not enforce indenting for assembly statement. The <code>JSR RSP232<\/code> starting at the first column is legal. In fact, even labels may be indented. This example prepends comments after statements with <code>;<\/code>, which is legal because the assembler ignores everything after the statement anyway.<\/p>\n<p>If you want to go for maximum readability (and don&rsquo;t care about the size of the source), you could also indent the above example like this:<\/p>\n<pre><code>; COMMAND SERIAL BUS DEVICE TO LISTEN\n;\nLISTN  ORA #$20       ; MAKE A LISTEN ADR\n       JSR RSP232     ; PROTECT SELF FROM RS232 NMI'S\nLIST1  PHA\n<\/code><\/pre>\n<p>Labels can be up to 6 characters in length, so one could use 7 character indents for statements so that they always line up. That&rsquo;s also how the LST output is formatted, which will be described later.<\/p>\n<h2 id=\"assembly-statements\">Assembly Statements<\/h2>\n<p>The accepted syntax of assembly statements matches the one in the <a href=\"http:\/\/archive.6502.org\/books\/mcs6500_family_programming_manual.pdf\">6502 Programming Manual<\/a>. This includes the syntax for statements that take the accumulator as the argument:<\/p>\n<pre><code>ASL A\nLSR A\nROL A\nROR A\n<\/code><\/pre>\n<p>Modern assemblers usually allow omitting the <code>A<\/code>; the Cross-Assembler does not.<\/p>\n<p>One additional feature is an alternative syntax to the indirect, y-indexed addressing mode. In addition to<\/p>\n<pre><code>LDA (PNT),Y\n<\/code><\/pre>\n<p>the following syntax is accepted:<\/p>\n<pre><code>LDA (PNT)Y\n<\/code><\/pre>\n<h2 id=\"expressions\">Expressions<\/h2>\n<p>Operands of assembly statements can use hexadecimal (<code>$<\/code>), octal (<code>@<\/code>), binary (<code>%<\/code>) and decimal (no prefix) constants. Mathematical expressions using <code>+<\/code>, <code>-<\/code>, <code>*<\/code> and <code>\/<\/code> are possible, but they are always evaluated left-to-right with no operator precedence and no parenthetical grouping. Character\/string literals are prefixed with <code>'<\/code>.<\/p>\n<h2 id=\"directives\">Directives<\/h2>\n<p>The Cross-Assembler understands the following directives:<\/p>\n<ul>\n<li><code>.BYTE<\/code>: store one or more bytes<\/li>\n<li><code>.WORD<\/code>: store one or more words (little endian)<\/li>\n<li><code>.DBYTE<\/code>: store one or more words (big endian)<\/li>\n<li><code>.PAGE<\/code>: optionally set a section title, and cause an LST page break<\/li>\n<li><code>.SKIP<\/code>: insert a number of blank lines into the LST<\/li>\n<li><code>.END<\/code>: stop assembly; not required but suggested at end of file<\/li>\n<li><code>.OPT<\/code>: set or clear a list of options\n<ul>\n<li><code>XREF<\/code> &#8211; <code>NOXREF<\/code>: add a cross-reference to the end of the LST<\/li>\n<li><code>ERRORS<\/code> &#8211; <code>NOERRORS<\/code>: write errors into separate file<\/li>\n<li><code>COUNT<\/code>\/<code>CNT<\/code> &#8211; <code>NOCOUNT<\/code>: add mnemo statistics to the end of the LST<\/li>\n<li><code>LIST<\/code> &#8211; <code>NOLIST<\/code>: enable LST output<\/li>\n<li><code>MEMORY<\/code> &#8211; <code>NOMEMORY<\/code>: enable writing object file<\/li>\n<li><code>GENERATE<\/code> &#8211; <code>NOGENERATE<\/code>: verbose printing of character strings in the LST<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Only the first three characters after the period are actually checked.<\/p>\n<h2 id=\"lst-file\">LST File<\/h2>\n<p>Like most development tools from the 1970s, the assembler can create a so-called listing file (suggested file extension <code>.LST<\/code>) during assembly that shows the source and the generated bytes side-by-side and is meant to be printed on paper. Here is a example from the manual:<\/p>\n<pre><code> CARD # LOC     CODE        CARD\n    1                   CR=15\n    2                   LF=12\n    3                   ; LOW CORE DATA AREAS\n    4  0000  E7 06      TEMTBL   .WORD G3TEM, G1TEM\n    5  0002  E7 05\n    6                   GROUP=B10\n    7  0004  00         THI     .BYTE 0\n    8  0005  00         TLO     .BYTE 0\n    9  0006  00 00 00   3PER    .WORD 0\n***** ERROR ** LABEL DOESN'T BEGIN WITH ALPHABETIC CHARACTER - NEAR COLUMN 1\n   10  0009  B1 0E      NEXT    LDA (SAVIL)Y\n[...]\n  269  07C9  C9 3B              CMP #';\n  270  07CB  00 00              BEQ DONE\n*****  ERROR ** UNDEFINED SYMBOL - NEAR COLUMN 18\n  280                           .END\n\nEND OF MOS\/TECHNOLOGY 650X ASSEMBLY VERSION 4\nNUMBER OF ERRORS =    2,   NUMBER OF WARNINGS =    0\n<\/code><\/pre>\n<p>The first column (<code>CARD #<\/code>) is the line number in the source. The <code>LOC<\/code> field is the memory address, which is followed by the output bytes (<code>CODE<\/code>) and the source line (<code>CARD<\/code>), which the assembler re-indented for readability.<\/p>\n<p>The <code>CARD<\/code> nomenclature stems from 1960s mainframes, where each line of text was represented by one punch card.<\/p>\n<p>Error messages are shown as extra lines after the line that caused the error. Note that the assembler will keep working through the file no matter what, and will output placeholder bytes for lines with errors.<\/p>\n<p>The <a href=\"http:\/\/retro.hansotten.nl\/uploads\/files\/KIM%20ROM%20listings%20user%20manual.pdf\">original LST printout of the KIM-1 ROM<\/a>, which was part of the <a href=\"http:\/\/retro.hansotten.nl\/uploads\/6502docs\/usrman.htm\">user manual<\/a>, is a real-world example of a 1200-line LST file, with the symbol table and the mnemo statistics (<code>.OPT COUNT<\/code>) at the end.<\/p>\n<h2 id=\"obj-file\">OBJ File<\/h2>\n<p>The main output of the assembler is the binary program, which is in the form of a so-called &ldquo;interface file&rdquo; with a suggested file extension of <code>.OBJ<\/code>.<\/p>\n<p>The diverse set of platforms that the Cross-Assembler ran on all had different word sizes, and many of them measured memory only in words and did not even have a concept of (8-bit) &ldquo;bytes&rdquo;. Therefore, the assembler could not output a binary file, but instead wrote a portable, hex-encoded text file, like this:<\/p>\n<pre><code>;18E500A200A0DC60A228A01960B00786D684D3206CE5A6D6A4D3600D8C\n;18E51820A0E5A9008D910285CFA9488D8F02A9EB8D9002A90A8D890C62\n [...]\n;06FFFA43FEE2FC48FF0665\n;0001200021\n<\/code><\/pre>\n<p>Every line consists of the following characters:<\/p>\n<ul>\n<li><code>;<\/code>: first character of each record<\/li>\n<li>2 chars: number of data bytes to follow<\/li>\n<li>4 chars: load address of first byte of line<\/li>\n<li>2 chars (repeated): data byte<\/li>\n<li>4 chars: checksum<\/li>\n<\/ul>\n<p>The last line is<br \/>\n* <code>;00<\/code>: identifier for last line<br \/>\n* 4 chars: number of preceding lines<br \/>\n* 4 chars: checksum<\/p>\n<p>The checksum is calculated by adding <em>all<\/em> preceding bytes of the line together.<\/p>\n<p>This text-only file is platform-independent and can easily be transferred between different computer systems, and e.g. downloaded from a time-sharing system in order to write it to an EPROM.<\/p>\n<h2 id=\"use-at-commodore\">Use at Commodore<\/h2>\n<p>The Cross-Assembler was used at MOS to create the very first 6502 code, like the KIM-1 ROM (shown above), or the <a href=\"http:\/\/archive.6502.org\/books\/mos_tim_terminal_interface_monitor_manual_mar_1976.pdf\">TIM<\/a> ROM (MCS6530-004).<\/p>\n<p>A large amount of the <a href=\"https:\/\/github.com\/mist64\/cbmsrc\">original Commodore source code<\/a> has been preserved, and all code before 1984 is in a format very similar to the original MOS definition supported by both the Cross-Assembler and the Resident Assembler. So at first sight, it is not so clear which assembler Commodore used for developing ROMs of the PET, VIC-20 etc. and the disk drives.<\/p>\n<p>The <a href=\"https:\/\/www.pagetable.com\/?p=1522\">next article<\/a> in the series will discuss this topic further.<\/p>\n<div class=\"footnotes\">\n<hr\/>\n<ol>\n<li id=\"fn:1\">\n<p>An earlier version of the article stated that the original MOS Cross-Assembler had been implemented by a grad student at the University of Illinois at Urbana-Champaign. In fact, the linked paper is only <em>about<\/em> the COMPAS\/MOS Cross-Assembler as it was used on the university&rsquo;s CDC computer.<a href=\"#fnref:1\" rev=\"footnote\">&#8617;<\/a><\/p>\n<\/li>\n<\/ol>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>In the series about the assemblers Commodore used for developing the ROMs of their 8-bit computers, this article covers the 1975 &ldquo;MOS Cross-Assembler&rdquo;, which was available for various mainfraimes of the era. Series Overview Part 0:\u00a0Overview Part 1:\u00a0MOS Cross-Assembler \u2190 this article Part 2:\u00a0MOS Resident Assembler Part 3:\u00a0BSO CY6502 Part 4:\u00a0HCD65 Part 5:\u00a06502ASM History MOS &#8230; <a title=\"Commodore&#039;s Assemblers: Part 1:\u00a0MOS Cross-Assembler\" class=\"read-more\" href=\"https:\/\/www.pagetable.com\/?p=1520\" aria-label=\"Read more about Commodore&#039;s Assemblers: Part 1:\u00a0MOS Cross-Assembler\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,8],"tags":[],"class_list":["post-1520","post","type-post","status-publish","format-standard","hentry","category-2","category-commodore"],"_links":{"self":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/posts\/1520","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1520"}],"version-history":[{"count":0,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/posts\/1520\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1520"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1520"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1520"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}