42

This question may have the apparent form of a question soliciting a "list" answer, but I'm expecting the list to be very short, so please bear with me.

What "unusual" syntax assembly languages are/were there? My reason for asking this was that the first assembly language programming I did was on the English Electric KDF9, whose weird and wonderful assembly syntax is described below.

That needs some explanation for sure.

Most assembly languages for current hardware follow a fairly similar lexical structure. The opcode maps to a alphabetic symbol (occasionally augmented by digits or a couple of other characters, for example period or underscore), generally suggesting a verb. An instruction has an optional label, followed by the opcode symbol, followed by the operands. The operands may include a handful of symbols which indicate indexing, indirection, address mode, etc.

That is, despite the variation in specifics, the general pattern is like

LABEL:  LOAD REG,FOO
        ADD REG,BAR
        STORE REG,FOO 

So that's the sort of pattern I'm not interested in, for this question. A few weird delimiters added to the above don't count either.

In pre-standard days, though, there were sometimes interesting variations.

Example 1

KDF9 Usercode, admittedly a fairly impoverished assembly language (no arbitrary user-defined symbols!) had what has been described as 'distributed syntax'. For example, an indexed load from memory to stack ("nest" in KDF9 terminology) is written like

V42M7Q;

V42 is the name of some data item (no arbitrary user-defined symbols!), M7 means 'modified by register 7', and Q means that the modifier is to be incremented afterwards. (Where other machines had 'index registers', KDF9 had 'Q-registers', divided into modifier, counter, and increment parts, useful for indexing, base addresses, counting, and array access). The operation was implicitly a fetch; store would be indicated by =.

Adding two numbers would thus look like

V42;  V43; +;  =V42;  (FOO = FOO + BAR);

This is "fetch V42 to stack; fetch V43 to stack; add top 2 stack words and leave sum on stack; pop stack and store in V42". The addition operation is indicated by '+' and not by, say, 'ADD'. It's a zero-address machine so the operands are implicit. The parenthetical clause is a comment. And newlines have no significance - this was fairly common in paper-tape cultures.

There were some data-manipulation instructions that did use 'words' for them, when there was no reasonably mnemonic symbol in the Flexowriter repertoire. For example, DUP; duplicated the top-of-stack value (i.e., pushed another copy on the stack).

Example 2

Manchester University's MU5 also had an interesting syntax. The addition example would be written as

      ACC = FOO
      ACC + BAR
      ACC => FOO

ACC is the name of a machine register, obviously the accumulator. The rest of the symbols should be self-explanatory.

(Bio note: I have programmed on the KDF9. I never met the MU5, though it was discussed in undergrad courses as an exciting example of a machine designed for higher-level languages, that the guys over in Manchester were inventing. I know there's at least one MU5 programmer in this site).

Not an example

I'm excluding things like Turing's programming system at Manchester, since that just consisted in typing whatever teleprinter symbol made up the next 5 bits of the instruction stream.


So: was that the extent of the scenic detour off the highway to dull standardization, or are there other interesting examples?

Clarification: for this question, the assembly language should have been intended in principle for human programmers to use to write programs. Languages only intended for communication between programs, say as communication between different stages of a programming system, are excluded. Also, I'm only interested in actual code. No pseudo-ops, no directives, no macro definitions or calls, and not data declarations either.

14
  • 8
    Most Forth implementations had a reverse polish assembler.
    – NomadMaker
    Commented Apr 18, 2020 at 13:09
  • 6
    Not at all retro, but Analog Devices' Blackfin CPUs use a very high-level-looking assembly language: R0 = R1 + R2 for example. Commented Apr 18, 2020 at 13:16
  • 4
    Current count for this "not a list" answer is already up to 7. Highest voted answer should probably be converted to a Community Wiki.
    – Brian H
    Commented Apr 18, 2020 at 14:19
  • 3
    @BrianH re list count. Indeed. There are more weird syntaxes in heaven and earth than are dreamt of in my philosophy! I should get out more.
    – dave
    Commented Apr 18, 2020 at 14:23
  • 3
    How high level are you willing to consider as 'assembly' language? There are at least a few hardware/VHDL implementations of runtime VM's out there (Jazelle on ARM for example, and there have been research projects to do soft-core implementations of BEAM and the CIL runtime in hardware). Depending on how you consider those, that expands the list quite significantly. Commented Apr 19, 2020 at 16:41

16 Answers 16

33

Example 1

The PDP-8 had only 8 kinds of instructions, but one of them was "microcoded" operate command: Different bits in this command would turn on different operations, which could be combined. Here's a list of the first group of such commands:

7000 NOP   no operation
7001 IAC   increment acc
7002 BSW   byte swap (-> rotate twice)
7004 RAL   rotate acc and link left one
7006 RTL   rotate acc and link left two
7010 RAR   rotate acc and link right one
7012 RTR   rotate acc and link right two
7020 CML   complement link
7040 CMA   complement acc
7100 CLL   clear link
7200 CLA   clear acc

So if you wanted to clear the accumulator and then increment it, effectively loading the constant 1 into the accumolator, you could combine the opcodes:

CLA IAC

and the assembler would OR the corresponding bit patterns to give you 7201 as the octal opcode.

The same worked for all other combinations (but not all of them would do something useful).

Example 2

There are CPUs that use a subset of Forth as their assembly language, and Forth is of course quite different from the "standard" assmbler syntax you describe in the question.

One relatively modern example is an FPGA implementation called J1 Forth CPU. Here you can see how the Forth operations are defined in terms of this "machine language".

Example 3

The CDC 6000 series had a variation of the "standard" assembly syntax where you could mix in an arithmetic symbol on the right hand side, making it more look like a mathematical formula. Also, the result register was part of the operand mnemonic. So

BX1   X2 * X3

would calculate the logical product ("AND") of registers X2 and X3 and store it in register X1, while

BX1  -X2 + X3

would complement register X2, and then form the logical sum ("OR") with register X3 and store it in register X1. Both of these had a single opcode each.

Similarly,

FX1   X2 + X3

would calculate the floating point sum of X2 and X3, and store it in X1.

Example 4

The IAS family (ENIAC etc.) also had an assembler notation that looked more mathematical. Note that no actual assembler as a program existed, these were translated by hand into opcodes. An example from this site:

; adds up the values n+...+3+2+1(+0) in a loop and stores
; the sum in memory at the location labeled "sum"

loop:   S(x)->Ac+  n    ;load n into AC
        Cc->S(x)   pos  ;if AC >= 0, jump to pos
        halt            ;otherwise done
        .empty          ;a 20-bit 0
pos:    S(x)->Ah+  sum  ;add n to the sum
        At->S(x)   sum  ;put total back at sum
        S(x)->Ac+  n    ;load n into AC
        S(x)->Ah-  one  ;decrement n
        At->S(x)   n    ;store decremented n
        Cu->S(x)   loop ;go back and do it again   

n:     .data 5  ;will loop 6 times total
one:   .data 1  ;constant for decrementing n
sum:   .data 0  ;where the running/final total is kept

Example 5

As @ninjalj mentions in the comment, the VT52 also had a "microcoded" instruction set: 3 bits of the opcode select an instruction group, and 4 bits select operations in this group that are then executed in parallel [1]. This leads to assembly code like in [2] line 95

 DXDY!M2A!URJ    ;IS UART FLAG SET ?

which decrements X and Y register (DXDY), loads AC from memory (M2A), and jumps if the UART flag is set (URJ), in a single opcode.

Possible other examples

I guess there's more, in particular for very early computers, assembler notation was all over the place. The reason for that is that the "standard" assembler notation makes it easy for an actual assembler program to do the translation. With translations done by hand, as in the above example, there is no pressure to make the notation easy to parse by a program.

16
  • 1
    Example 1 sounds quite similar to the HP 1000 series CPU. It's assembly language contained two "groups" called "alter / skip" and "shift / rotate", in which instructions could be combined by ORing them. Commented Apr 18, 2020 at 6:47
  • 1
    I was going to mention Forth CPUs, the example I was thinking of was the GreenArrays GA144 - which will seem familiar to those who have played TIS-100 :) . Example MD5 implementation on a GA144 : greenarraychips.com/home/documents/greg/AN001-141023-MD5.pdf
    – matja
    Commented Apr 18, 2020 at 7:49
  • 1
    Maybe SHARC DSPs assembly, using infix notation and showing parallel execution of load/store, ALU...
    – Grabul
    Commented Apr 18, 2020 at 10:47
  • 1
    If I recall correctly, PAL-8 syntax is just to 'or' together expressions it finds on the same line.
    – dave
    Commented Apr 21, 2020 at 23:06
  • 1
    The VT52 is similar to that PDP-8 operation: instructions are 8 bits, bits are named ABCDEFGH, if A=0, BCD select from 8 instruction groups, and each of E, F, G, H select an action, with an additional action for EFGH all zero. vt100.net/docs/vt52-mm/chapter4.html#S4.3.1.3
    – ninjalj
    Commented Apr 24 at 10:13
34

This is a frame challenge answer.

The Burroughs Large Systems B5000 was specifically designed for being able to run programs in high-level languages (meaning COBOL, ALGOL, FORTRAN), multiprocessing, virtual memory. It had tagged memory, and builtin concurrency and multiprocessing.

The feature relevant to this particular question, is rather lack of a feature: the B5000 doesn't have an assembly language. Its "lowest" system programming language is Executive Systems Problem Oriented Language (ESPOL), an extension of ALGOL 60.

ESPOL, however, does have direct equivalents for all low-level instructions.

The B5000 was a big influence on Alan Kay both in the design of OO in general and the design of the Smalltalk VM. It was also reportedly an influence on the Pascal P-Code system (which was also an influence on the Smalltalk VM). The Smalltalk VM and P-Code, in turn, were an influence on the JVM. So, in the biological sense of "success" (spreading your genes), it is one of the most successful hardware architectures in the history of computing.

14
  • 2
    And of course the KDF9 mentioned in the question was a big influence on the Burroughs B5000, so it's not that surprising you also get a similar syntax.
    – dirkt
    Commented Apr 18, 2020 at 14:05
  • 3
    I claim that a non-existent language doesn't have unusual syntax. I can think of lots of languages that don't exist, and they all have the exact same written form :-)
    – dave
    Commented Apr 18, 2020 at 14:08
  • 4
    @another-dave: As I wrote in the preface, this is a frame challenge answer. I would argue that the language on the B5000 which plays the role that assembly languages play on almost all other architectures, has an unusual syntax for an assembly language. Now, the reason for that is, of course, that it isn't an assembly language, it is a high-level language in the ALGOL family which also has different semantics, but nevertheless, it is used in domains where you would otherwise use assembly language, and it is used by engineers who would otherwise use assembly language. Commented Apr 19, 2020 at 7:13
  • 3
    @another-dave This would lead to the meta question: What is an assembly language? Does a Forth CPU that is programmed in a subset of Forth have an assembly language? Does that make (that subset of) Forth an assembly language? Commented Apr 19, 2020 at 7:14
  • 1
    @MichaelGraf My notes for the Burrough have a quote by Gary Kildall that says this series is an "offshoot of the English Electric KDF-9". I have not writting down the source of the quote, and I cannot find it quickly. I also didn't verify it. So it might be that Gary Kildall was mistaken, that the quote is wrong, or that the development of the B5000 series actually was inspired by the development of the KDF9, no matter which was released earlier - I don't know, and I didn't check. But they do look similar enough, if you look at it, so there's definitely an influence, in whatever direction.
    – dirkt
    Commented Apr 19, 2020 at 8:06
19

[Preface: This question is not only quite broad, but as well rather opinion based. After all, what is 'unusual' depends a lot on personal experience and preference. To me for example GNU assembler's inversion of target and source is quite unusual.

Having said that, I feel the question gives a great chance to create some overview]


As I understand it, the question is about how an Instruction Set Architecture (ISA) is represented in its (native) assembler, and what variations exist. It's important to keep in mind that this is strongly influenced by the way an ISA is viewed (*1)

Basic Schools

There are several basic schools of ISA representation in Assembler:

(I tried to use as modern examples as possible to ease reading)

  1. One Opcode one Mnemonic

    Each and every binary opcode gets its own mnemonic. A typical example would be the Datapoint 2200 or Intel's 8008. Here each opcode gets its own name:

  • LAB - Load register A with the content of register B

  • LAM - Load register A with the memory content addressed by the Memory pointer (HL)

  • LA # - Load register A with the constant # given as parameter

    Assemblers of this kind can be written very fast as all they have to follow is a one-on-one replacement of the mnemonic to an opcode and optionally turning a simple, usually numeric, value into a byte/word sized parameter. They are extremely close to the binary ISA representation. These tend to be quite small and are often the first stage to get a system running. The 6502 and the first cross-assembler running on a timeshare system are good examples.

  1. One Mnemonic many opcodes

    Here each mnemonic describes a function; the opcode used is to be derived from the parameter given. The most radical or clean, as one prefers, of the classic 8-bit age might be the Z80. Here all 161 possible encodings for data transfer between registers and register and memory are summarized in one mnemonic LD.

    This clearly eases learning as a new programmer can focus more on generic function used than specific encoding. Of course it comes with a more complex assembler structure, as now parameters must be scanned before deciding on the opcode to be generated - and its parameter - accordingly. It may end up with source constructions in need of additional specifiers to pick the right opcode - Motorola's 68000 .b/.w/.l postfix notation, for example. Or the unique (*2) address syntax on a 6502.

  2. Encoding like Structure

    While this may sound like a sub section to #1, it's not much about giving a distinct encoding to each instruction, but about the mnemonic being the instruction - effectively reducing the assembler even more. An example would be the IBM TPM (Tape Processing Machine) and its 701 follow-up, where the opcodes were directly related to 5-bit TTY encoding. Like A for Add, W for Write - of course, it did work out way less easy to remember for many other instructions :)

  3. Synthetic Mnemonics

    Here no fixed opcodes are given, but an operation is synthesized from a set of symbols. It works somewhat like qualifiers, except that none of the elements are a base opcode. Operation is usually VLIW-like. The most prominent example here is maybe the Zuse Z22.

  4. Single Parameter

    These syntaxes try to limit parameters to a single one, even if the abstract logic of the instruction is about two independent ones. This is much like the #1 attempt for opcodes. The 6502/6800 make good examples by encoding one parameter into the instruction:

    • LDA - Load register A
    • LDY - Load register Y
    • LDAB- Load Accumulator B
  5. Multiple Parameters

    Others allow for two or more distinct parameters. While limited two-address ISAs can get around with byzantine mnemonic constructions (such as 6800's LDAA), full two-address must go that way.

    This is much related to the move from a type #1 mnemonic structure to a type #2. And like it, an assembler handling such source statements will need to be more complex in its decision tree - for example decoding different addressing modes and selecting the opcode accordingly.

  6. Embedded Parameter

    These syntaxes do not spread out parameters over separate elements (words) but concatenate them into the instruction. While this is to some degree true for #5 syntax, it goes beyond, as no spaces or delimiters are used at all. 'Freiburger' Code for the Z22 for example goes that way:

    • T5000T is a pseudo op working much like ORG in other assemblers, setting Drum location 5000 as next target.
    • CB3000 instruction to load a word from address 3000
  7. Parameter Order or Left to Right vs. Right to Left?

    Should parameters be given as source first or destination first? This is as much a source of holy wars (*3) as it is about history. Early (Load/Store) architectures often encoded one parameter as part of the instruction, inherently using both ways:

    • The 6502's LDA/X/Y: the register mentioned in the mnemonic would be the first parameter, so making it destination, source, while
    • its STA/X/Y turns it into source, destination.
    • Transfers (Txx) also use source, destination.

    Since most instructions, except stores, use the destination-first notation, it does seem more natural when assemblers evolved/had to evolve from single to multiple parameter. Then again, some two-address machines' ISAs were structured as source,destination from the very first iteration on.

    Of course, with more than two parameters, it gets even more arbitrary.

Real Assemblers:

While some assemblers are direct implementations of one of these schools (and mentioned above), many are combinations. Examples may be:

  • 8080 and 6800/6502 are mixtures of #1 and #2.

    • While Intel did unify some instructions on the move from 8008 to 8080, like turning all loads between registers into a single MOV mnemonic, it kept a separate mnemonic all other data transfers.

    • 6800/6502 did unify most instructions of the same function into a single mnemonic and have the parameter addressing decide which encoding, but at the same time all register to register transfers got their own mnemonic (TAX, TXA, ...)

  • 'Freiburger Code' might be something in between assembler, loader and script processor. Its basic syntax is meant to create the various bit of the instruction, but it can also execute an instruction while assembling/loading if an E is appended. Using an E as prefix in turn can load any instruction from memory and execute it (E4010 -> execute instruction at memory location 4010). There are several other such pseudo-instructions and instruction modifiers as well - effectively blurring borders between assembler source, compiler script, command script and application.


*1 For example a /360 is usually seen as a single opcode to mnemonic relation (#1), as that's the way it is used in all documentation. But no-one stops us from seeing the opcodes as structured in a 2+6 fashion with the top two bits holding the addressing modes (for most instructions).

*2 - But not always simple/intuitive.

*3 - Quite much like the war between using 'Move' vs. 'Load/Store'. While I, as a /360 guy, would like to see both, I've experienced quite fierce discussions favouring either.

5
  • 3
    The gas syntax is also unusual and much less readable to me (esp. the memory dereference syntax). They made things even far worse by making everything harder to look up in the CPU manual
    – phuclv
    Commented Apr 18, 2020 at 16:57
  • 3
    @phuclv: GAS was just being compatible with an existing Unix assembler for some existing 386 Unix at the time. That made sense at the time. It's really unfortunate that whoever those clowns were picked some craptastic syntax different from the Intel manuals, influenced by PDP11. What was the original reason for the design of AT&T assembly syntax? (And they even got the operands reversed vs. the normal AT&T convention for some x87 non-commutative instructions.) So blame them, not GNU; At least most tools can use .intel_syntax noprefix these days Commented Apr 19, 2020 at 2:24
  • 1
    re: gas syntax - as a non-x86-assembly programmer who occasionally needed to read it, I found the Intel syntax to be incoherent. I think it's a matter of what you're used to.
    – dave
    Commented Apr 19, 2020 at 13:18
  • 2
    @PeterCordes The Gnu Assembler was written originally for VAX/11 which used a source first format. Also Stallman started writing Gnu on a 68000 system, again a source first format. It was also expected to be used mainly as a backend for gcc generated output, not for humans to write in.
    – JeremyP
    Commented Apr 20, 2020 at 9:15
  • 2
    @JeremyP: I guess that would explain why GAS picked the (pre-existing I think) source-first AT&T syntax for x86, then. GAS for ARM, MIPS, and plenty of other ISAs is destination-first, using the only syntax that ever existed for those platforms. (\@another-dave: if you want incomprehensible, PowerPC does it for me. So much functionality packed into each instruction, multiple immediate fields for (very nice) insns like rlwinm, but hard-to-read choices for mnemonics, numbering bits IBM-style from the top of the register, and there's even an eieio mnemonic.) Commented Apr 20, 2020 at 9:29
15

SHARC and Blackfin architectures processors are said to have "rich algebraic assembly language syntax" and are unsual in their own way. The syntax is somewhat C-like

#ifdef INCLUDE_BUFFER3
.VAR buffer3[ 0x100];
#endif

outer:
[I1] = R0;
R1 = 0X1234;

LSETUP (begin_loop, end_loop) LC0 = P1;
begin_loop:
        R1 *= R2;
        R2 = [I0++];
end_loop:
         R0= R0 + R1 (NS) || R1 = [P0++] || NOP
R0 = R0 + R1
JUMP outer;

R0 = DLAB | EPS (z);
cc = BITSET (R0, BITPOS(DLAB));

The TigerSHARC variant is a VLIW architecture and has similar highly readable instructions:

start:
XR0 = CB [J3 += 1];;
if NLC0E, jump start;;
1
  • TI TMS320 series also often have algebraic syntax Commented Apr 18, 2020 at 22:05
12

It would be remiss if we're talking about assembler syntax to leave out the clever assemblers for Forth.

Clever in that writing assemblers for Forth is quite straightforward and historically requires very little code.

Forth assemblers are noted for their prefix syntax and they're idiomatic use of higher level branching and looping constructs in contrast to typical assembly leveraging comparisons, branch instructions, jumping and looping. Forth assemblers tend to not rely on things like labels. (They exist, they're simply not common in use.)

Forth assembly is also typically done in small chunks.

CODE (FIND)   (S here alf -- cfa flag | here false )
  DX POP   DX DX OR  0= IF   AX AX SUB   1PUSH   THEN            
  BEGIN   DX BX MOV   BX INC   BX INC                            
    DI POP  ( here )  DI PUSH   0 [BX] AL MOV                    
    0 [DI] AL XOR   63 # AL AND   0=                             
    IF  BEGIN  BX INC   DI INC   0 [BX] AL MOV                   
          0 [DI] AL XOR   0<> UNTIL   127 # AL AND   0=          
        IF   DI POP   BX INC   BX PUSH   DX BX MOV               
             BX INC   BX INC  0 [BX] AL MOV   64 # AL AND   0<>  
          IF   1 # AX MOV   ELSE   -1 # AX MOV   THEN   1PUSH    
    THEN  THEN   DX BX MOV  0 [BX] DX MOV                        
  DX DX OR   0=  UNTIL   AX AX SUB   1PUSH   END-CODE 

Commonly found is Forth meta-compilers that build Forth from Forth, the FIND routine is often one of the largest assembly routines in the system. But it shows off the assembler handily. Above is the (FIND) primitive in 8086 from F83.

This shows off the prefix format DX POP vs conventionally POP DX. The 0 [BX] AL MOV is normally MOV AL, [BX+0]. Finally, 63 # AL AND is AND AL, #63.

It also shows the use of the 0= IF ... THEN block. The 0= is testing the Zero flag, if true, it executes the block delimited by the IF and THEN. No labels here. Similarly, the BEGIN ... UNTIL syntax. It also shows simple macros like 1PUSH.

Finally it represents the nature of a bunch of assembly code arranged to fit on a single 1K byte, 64x16 screen of Forth source code.

1
  • There are also Forth CPU for which the instruction set is simply a binary encoded version of Forth assembly. These are typically implemented as a subset of Forth and more complex instructions like the FIND above will be implemented as libraries
    – slebetman
    Commented Apr 20, 2020 at 8:46
10

An honourable mention goes to Programma 101, arguably the first desktop computer. The "programming" was done essentially in an "assembler" corresponding to keystrokes, looking like this (taken from here):

A V
S
B M↑
B ← M
A / A↑
D / A↓

This style has been generally carried on by other programming calculators, though later they started to include a general purpose CPU (with its own, hidden from the user, machine code).

1
  • 1
    Oh, I even used one of those! How could I have forgotten it?
    – dave
    Commented Apr 20, 2020 at 13:17
8

I'm not 100% sure whether this answer qualifies, as the assembler it relates to is still available and updated for at least relatively modern architectures, but it does originally go baack to the 80s and supported 16-bit 8086 compatible CPUs, so perhaps it's appropriate:

Terse is an x86 assembler with a rather unique syntax, designed to resemble high level languages. An example from the web site is this code:

eax = ebx; bx + dog; cat - 14; cx & 0Fh; dx - 123?

Which is equivalent to the following traditional 8086 instruction sequence:

Mov eax,ebx
Add bx,dog
Sub cat,14
And cx,0Fh
Cmp dx,123

The language supports chaining multiple operations that use the same destination register in a single statement, and also higher level concepts like loops, if statements with blocks, and so on.

7

This thread would not be complete without a reference to The Story of Mel. According to the story, this was a Royal McBee RPC-4000, and its assembler was unique because

The new computer had a one-plus-one
addressing scheme,
in which each machine instruction,
in addition to the operation code
and the address of the needed operand,
had a second address that indicated where, on the revolving drum,
the next instruction was located.

In modern parlance,
every single instruction was followed by a GO TO!
3
  • 7
    The assembler had it because the machine did it like that - no program counter, but each instruction specified its successor. That seems to have been common on machines where primary memory was rotating (either magnetic drum or ultrasonic storage). See Optimum Programming on Wikipedia, or the IBM 650 (page 10, instruction format) for a specific example. Eventually there were assemblers that did that for you.
    – dave
    Commented Apr 19, 2020 at 20:38
  • @another-dave Sure, and that's basically true of all assemblers - they're really just a mnemonic layer on top of the hardware features. The structure of the processor's memory, whether that's rotating or RAM-based, Von Neumann or Harvard, and any registers, is always reflected in the assembler mnemonics and how they are fed input and output values.
    – Graham
    Commented Apr 21, 2020 at 10:12
  • But my point for this topic is that the 1+1 address format does not make it syntactically strange.
    – dave
    Commented Apr 21, 2020 at 12:19
4

I used an assembler that did this:

  ;...
  call #function
  ;...

function:
  add  v_spc, #1
  ;...
function_ret:
  ret

Seems pretty pedestrian until you take note of what happens. Trying to compile this

  ;...
  call #function
  ;...

function:
  add  v_spc, #1
  ;...
  ret

(missing function_ret) yielded an error message at the site of the call operation. function could still be compiled and jumped to, but calling it was an error. The disassembly revealed the truth.

  ;...
  jmpret  L15, #L13
  ;...

L13:
  add L16, #1
  ;...
L15:
  jmpret nw 0, #0

The processor is stackless, and the assembler is generating the necessary stuff for function calls to work on the processor.

3
  • IIRC that's similar to how the Parallax Propeller does subroutine calls. Commented Apr 24, 2020 at 4:48
  • 1
    @AlexHajnal: This is the Parallax Propeller processor.
    – Joshua
    Commented Apr 24, 2020 at 16:29
  • LOL. That would explain the similarity! Commented Apr 24, 2020 at 18:27
4

The UNIVAC I had an assembly language that was mostly single-letter opcodes. Here is the "Code Card" developed by Grace Hopper:

UNIVAC I Code Card

2

Control Data had the only reasonable syntax I’ve ever seen in the COMPASS assembler for CDC 60 bit computers. Most instructions were one letter for the type of instruction, followed by the destination register, followed by any expression that would fit into one instruction. For example:

SA4 A5+B7 - Set register A4 to sum of A5 and B7
IX2 X3-X4 - Integer expression, X2 = X3 -X4
IX2 X3/X4 - Integer expression, X2 = X3 divided by X4.

So no separate add/subtract/multiply/divide instructions in the assembly language.

0
2

It's time for the trump card... may I present the MAC-8. Here is an example of its assembler code:

#define NBYTES 100
char array[NBYTES];

sum()
{
  b0 = &array;
  a1 = 0;

  for (a2 = 0; a2 < NBYTES; ++a2) {
     a1 =+ b0;
     ++b0; 
  }
}

"Wait," you cry, "that's not assembler, that's C!"

Nope, that is indeed its assembler language.

This was the first of Bell Labs' many-year approach to designing a CPU that would efficiently run C, which led to the Bellmac 32 and finally Hobbit. None of these were ultimately very impressive and in the era before C had taken over everything, had no real compelling arguments for use. By the time Hobbit was out, RISC crushed them.

1

SDS/Xerox Meta-Symbol was essentially a list processing language designed to generate machine code through side effects.

https://www.livingcomputers.org/UI/UserDocs/CP-V/4_MetaSymbol_Assembler_Language_Reference.pdf

1

I guess this is a "on the way to assembler" answer.

The FA-5 "Automatic coding system" for BESK doesn't have mnemonics for instructions, those are just notated in normal octal. But, it allows symbolic addressing, computed at "assembly time". The assembled program was printed out, with symbolic addresses replaced by real addresses. It was also (if short enough) stored in RAM, and could be punched to tape, for later loading.

0

Want an early, somewhat exotic example? Take the Zuse Z-3 instruction set (1941). It was on the one hand very, very limited (no loops for example. Zuse implemented loops as "physical" ones by gluing the punch tape to a ring, later revisions implemented conditional and non-conditional branches), on the other hand, there was a machine instruction to calculate the square root.

  • Read from keyboard
  • Display result
  • Read address x
  • Write to address x
  • Multiply
  • Divide
  • Square root
  • Add
  • Subtract
-3

Some people call the (original K&R) C programming language an assembly language for PDP-11's.

3
  • 5
    They do, but they're wrong, at least on the basis of ++ and --, according to Dennis Ritchie. I'm inclined to consider him as authoritative. :-).
    – dave
    Commented Apr 25, 2020 at 23:00
  • 1
    @another-dave The line between Assembler and HLL gets blurry anyway as soon as assemblers offer more than a linear mnemonic/opcode and label/address mapping.
    – Raffzahn
    Commented Oct 31, 2020 at 19:14
  • 1
    C is a high level language and always has been. The joke isn't even original. I had a professor at University who called Fortran (which he hated) "IBM 704 assembler".
    – JeremyP
    Commented Apr 25 at 9:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .