LCC Assembly — Syntax Highlighting

Curated samples and the full alphabet demo suite, highlighted with the custom TextMate grammar (docs/lcc.tmLanguage.json) via Shiki. Grammar covers core LCC and LCC+ instruction sets.

Curated samples

demos/helloWorld.a Hello, World! — lea, sout, halt
; helloWorld.a: print Hello, World! and halt
        lea r0, msg
        sout r0
        nl
        halt
msg:    .string "Hello, World!"

Alphabet demo suite (demoA – demoZ)

demos/demoA.a demoA.a: simple program assembly/execution and test input/output caching
; demoA.a: simple program assembly/execution and test input/output caching
    mov r0, 5
    dout r0
    nl
    halt
demos/demoB.a example program to test string input and output
; example program to test string input and output
; furthermore, this program will also be used to
; test lst/bst file generation with comments and
; blank lines when lcc.js is used to assemble and
; interpret from a .a file all in one go, versus 
; when using interpreter.js by itself on a .e file
    lea r0, ask ; example comment on a line of code
    sout r0
    lea r0, buffer1    
    sin r0
    lea r1, hi
    sout r1
    lea r0, buffer1
    sout r0
    lea r1, period
    sout r1
    nl
    lea r1, ask2
    sout r1
    lea r1, buffer2
    sin r1
    lea r2, hi
    sout r2
    sout r0
    lea r2, space
    sout r2
    sout r1
    lea r2, period
    sout r2 
    halt ; the next 2 lines are intentionally blank


ask:  .string "What's your first name? "
ask2: .string "What's your last name? "
hi:   .string "Hi, "
period: .string "."
space: .string " "
buffer1: .zero 10
buffer2: .zero 10
demos/demoC.a demos/demoC.a
    ld r0, x
    add r0, r0, 2
    dout r0
    nl
    halt

x:  .word 5
demos/demoD.a demos/demoD.a
    ; mova r0, 5
    mov r0, 5
    add r0, r0, 2
    dout r0
    nl
    mov r1, r0
    add r1, r1, 3
    dout r1
    nl
    mvi r2, 2
    dout r2
    nl
    mvr r3, r2
    add r3, r3, 1
    dout r3
    nl
    dout
    nl
    halt
demos/demoE.a demos/demoE.a
startup:    bl main
            halt

main:       push lr
            push fp
            mov fp, sp

            ld r0, x
            add r0, r0, 2
            dout r0
            nl

            mov sp, fp
            pop fp
            pop lr
            ret

x:          .word 5
demos/demoF.a demos/demoF.a
    mov r0, 'B'
    aout r0
    nl
    mov r0, 65
    dout r0
    nl
    aout r0
    nl
    mov r0, 0xff
    hout r0
    nl
    mov r0, -15
    udout r0
    nl
    dout r0
    nl
    ld r0, x
    dout r0
    nl
    udout r0
    nl
    hout r0
    nl
    add r0, r0, 1
    dout r0
    nl
    udout r0
    nl
    halt

x:  .word 0xffff
demos/demoG.a demos/demoG.a
    lea r0, prompt3
    sout r0
    ain r0
    lea r1, reply
    sout r1
    aout r0
    nl

    lea r0, prompt1
    sout r0
    din r0
    lea r1, reply
    sout r1
    dout r0
    lea r1, signed
    sout r1
    nl
    lea r1, reply
    sout r1
    udout r0
    lea r1, unsigned
    sout r1
    nl

    lea r0, prompt2
    sout r0
    hin r0
    lea r1, reply
    sout r1
    hout r0

    halt

prompt1: .string "Enter a negative number: "
prompt2: .string "Enter a hex number: "
prompt3: .string "Enter a single character: "
reply: .string "You entered: "
signed: .string " signed"
unsigned: .string " unsigned"
demos/demoH.a demos/demoH.a
    ld r0, x
    dout r0
    nl
    mov r1, -5
    dout r1
    nl
    mov r2, 10
    add r2, r2, -12
    dout r2
    nl
    mov r3, 5
    sub r3, r3, 8
    dout r3
    halt

x: .word -100
demos/demoI.a demos/demoI.a
          mov r0, 10
start:    cmp r0, 0
          bre end
          dout r0
          nl
          sub r0, r0, 1
          br start
end:      halt
demos/demoJ.a demos/demoJ.a
            mov r1, 'a'
outerloop:  ld r2, lastchar
            cmp r1, r2
            bre postoloop
            mov r0, 0
innerloop:  cmp r0, -1
            bre postiloop
            aout r1
            hout r0
            nl
            add r0, r0, 1
            br innerloop
postiloop:  add r1, r1, 1
            br outerloop
postoloop:  halt

lastchar: .word 'c'
demos/demoK.a program that tests the m command
; program that tests the m command
; demonstrates that disassembly of programs
; with unused labels outputs unlabeled data
        m
        nl

        mov r2, 11
        st r2, x
        m

        halt

x:      .word 7
y:      .word 23
demos/demoL.a program that tests the r command
; program that tests the r command
        r
        nl

        mov r0, 3
        mov r1, 3
        mov r2, 11

        r
        nl

        mov r0, -1
        mov r1, 1
        add r2, r0, r1

        r 

        halt
demos/demoM.a program that tests the s command
; program that tests the s command
; and also compares .lst/.bst file
; generation with empty lines at
; the end of the file
startup:  s
          nl
          
          mov r0, 3
          push r0

          s
          nl

          bl main
          add sp, sp, 1
          halt

main:     push lr
          push fp
          mov fp, sp

          s
          nl

          mov r0, 5
          push r0
          mov r0, 10
          push r0
          
          s
          nl

          mov sp, fp
          pop fp
          pop lr
          ret
demos/demoN.a demo program that tests the detection of division by zero
; demo program that tests the detection of division by zero
    mov r0, 3
    mov r1, 0
    div r0, r1
    dout r0
    nl
    halt
demos/demoO.a demoO.a: program that tests IO and LST generation thoroughly
; demoO.a: program that tests IO and LST generation thoroughly
            lea r0, prompt
            sout r0
            lea r0, buffer
            sin r0
            lea r1, hi
            sout r1
            sout r0
            nl
            m
            halt
prompt:     .string "Name: "
hi:         .string "Hi "
buffer:     .zero 10
demos/demoP.a demoP.a tests the setting of the entry point
; demoP.a tests the setting of the entry point
; via the S header while leaving the load point 
; at the default 0
       .start main
hi:    lea r0, msg
       sout r0
       ret
msg:   .string "Hi\n"
;===============
main:  bl hi ; entry point is here
       bl hi
       halt
demos/demoQ.a demoQ.a tests using labels as operands to .word
; demoQ.a tests using labels as operands to .word
; directives. The program should output 10.
; Also, what would happen if we were to run
; this program using a load point of 0x3000?
    ld r0, x  ; 0
    dout r0   ; 1
    halt      ; 2
x:  .word y   ; 3
y:  .word 10  ; 4
demos/demoR.a demoR.a: Demonstrating shift commands srl, sra, sll
; demoR.a: Demonstrating shift commands srl, sra, sll
;
; This program shows the effects of shifting operations 
; on positive and negative numbers.
; We use dout to display the results and nl for new lines.

        ; Initialize r0 with a positive number
        mov r0, 16      ; r0 = 16 (binary 0000 0000 0001 0000)
        ; Shift r0 right logically by 1 (divide by 2, zeros shifted in)
        srl r0, 1       ; r0 = r0 >> 1 (logical shift right)
        ; After srl, r0 should be 8 (binary 0000 0000 0000 1000)
        dout r0         ; Output: 8
        nl

        ; Initialize r1 with a negative number
        mov r1, -16     ; r1 = -16 (binary 1111 1111 1111 0000)
        ; Shift r1 right logically by 1 (zeros shifted in)
        srl r1, 1       ; r1 = r1 >> 1 (logical shift right)
        ; After srl, r1 becomes a large positive number due to zeros shifted in
        dout r1         ; Output: 32760
        nl

        ; Now shift r1 right arithmetically by 1 (sign bit replicated)
        mov r1, -16     ; Reset r1 to -16
        sra r1, 1       ; r1 = r1 >> 1 (arithmetic shift right)
        ; After sra, r1 remains negative
        dout r1         ; Output: -8
        nl

        ; Shift r0 left logically by 1 (multiply by 2)
        mov r0, 16      ; Reset r0 to 16
        sll r0, 1       ; r0 = r0 << 1 (logical shift left)
        ; After sll, r0 should be 32 (binary 0000 0000 0010 0000)
        dout r0         ; Output: 32
        nl

        ; Demonstrate that shifting left multiplies by powers of 2
        ; Shift r0 left by 2 (multiply by 4)
        mov r0, 3       ; r0 = 3
        sll r0, 2       ; r0 = r0 << 2
        ; After sll, r0 should be 12 (3 * 4)
        dout r0         ; Output: 12
        nl

        halt

; Practical applications:
; - Left shift (`sll`) is used for fast multiplication by 
;   powers of 2.
; - Right shift (`sra`) is used for division by powers of 
;   2 while preserving the sign.
; - Logical right shift (`srl`) is useful for unsigned 
;   binary arithmetic and bit manipulation.
demos/demoS.a demoS.a: Demonstrating rotate commands rol, ror
; demoS.a: Demonstrating rotate commands rol, ror
;
; This program shows how bits are rotated in registers.

        ; Initialize r0 with a specific bit pattern
        ld r0, num  ; r0 = binary 1000 0000 0000 0001
        ; Rotate r0 left by 1
        hout r0
        nl
	
        rol r0, 1       ; r0 = rol(r0, 1)
        ; After rol, r0 should be 0x0003 (binary 0000 0000 0000 0011)
        hout r0         ; Output: 3
        nl

        ; Rotate r0 right by 1
        ror r0, 1       ; r0 = ror(r0, 1)
        ; After ror, r0 should be back to 0x8001
        hout r0         ; Output: 8001
        nl

        ; Rotate r1 left by 4
        ld r1, num2  ; r1 = binary 0001 0010 0011 0100
        hout r1
        nl

        rol r1, 4       ; r1 = rol(r1, 4)
        ; After rol, r1 should be 0x2341 (rotated bits)
        hout r1         ; Output: 2341
        nl

        ; Rotate r1 right by 4
        ror r1, 4       ; r1 = ror(r1, 4)
        ; After ror, r1 should be back to 0x1234
        hout r1         ; Output: 1234
        nl

        halt

num: .word 0x8001
num2: .word 0x1234

; Practical applications:
; - Rotate operations are used in cryptography algorithms like RSA and AES for data scrambling.
; - Rotating bits helps implement circular buffers and cyclic redundancy checks (CRCs).
; - Useful in graphics programming for color transformations and pixel manipulations.
demos/demoT.a demoT.a: Demonstrating bitwise operations and, or, xor
; demoT.a: Demonstrating bitwise operations and, or, xor
;
; This program shows how to use bitwise operations for masking and modifying bits.
; We use dout and hout to display the results.

        ; Initialize r0 with a value
        mov r0, 0xAA    ; r0 = 0x00AA

        ; Use AND to clear bits (masking)
        mov r1, 0xF0    ; Mask to keep only the upper 4 bits
        and r2, r0, r1  ; r2 = r0 & r1
        hout r2         ; Output: 00A0
        nl

        ; Use OR to set bits
        mov r1, 0xF     ; Mask to set lower 4 bits
        or r0, r1       ; r0 = r0 | r1
        hout r0         ; Output: 00AF
        nl

        ; Use XOR to toggle bits
        mov r1, 0xFF    ; Mask to toggle all bits
        xor r0, r1      ; r0 = r0 ^ r1
        hout r0         ; Output: 50  
        nl

        ; Practical example: Checking if bit 3 is set (bit indexing from 0)
        ; Let's check if bit 3 (from LSB) is set in r0
        mov r1, 0x8     ; Mask for bit 3
        and r2, r0, r1
        cmp r2, 0
        bre bit_not_set
        lea r3, msg_set
        sout r3         ; Output: "Bit 3 is set"
        br end_msg
bit_not_set:
        lea r3, msg_not_set
        sout r3         ; Output: "Bit 3 is not set"
end_msg:
        nl

        halt

msg_set:     .string "Bit 3 is set"
msg_not_set: .string "Bit 3 is not set"

; Practical applications:
; - **AND** is used for masking bits to clear or check specific bits.
; - **OR** is used for setting specific bits without altering others.
; - **XOR** is used for toggling bits and is fundamental in encryption algorithms.
; - Bit manipulation is crucial in low-level programming, embedded systems, and optimization tasks.
demos/demoU.a demoU.a: Demonstrating the sext instruction
; demoU.a: Demonstrating the sext instruction
;
; This program shows how sign extension works.
        mov r0, 0xFF ; 0b 1111 1111
        hout r0
        nl
        mov r1, 3
        lea r2, adj
        sout r2
        dout r1
        nl
        sext r0, r1
        lea r2, result
        sout r2
        hout r0
        nl

        mov r0, 0x11 ; 0b 0001 0001
        hout r0
        nl
        mov r1, 5
        lea r2, adj
        sout r2
        dout r1
        nl
        sext r0, r1
        lea r2, result
        sout r2
        hout r0
        nl

        mov r1, 15
repeat:
        cmp r1, -1
        bre done
        ld r0, x ; 0b 0001 0010 0011 0100
        hout r0
        nl
        lea r2, adj
        sout r2
        dout r1
        nl
        sext r0, r1
        lea r2, result
        sout r2
        hout r0
        nl
        sub r1, r1, 1
        br repeat
done:
        halt

x:      .word 0x1234
adj:    .string "Sign extending field # "
result: .string "Result: "

; Practical applications:
; - Sign extension is necessary when converting smaller signed integers to larger ones.
; - Ensures correct arithmetic when dealing with data from sources with different bit widths.
demos/demoV.a demoV.a demos the usage of mul, div, and rem instructions
; demoV.a demos the usage of mul, div, and rem instructions
        mov r0, 10
        mov r1, 3
        mul r0, r1
        dout r0 ; should output 30
        nl

        mov r0, 10
        mov r1, 2
        div r0, r1
        dout r0 ; should output 5
        nl

        mov r0, 10
        mov r1, 3
        rem r0, r1
        dout r0 ; should output 1
        halt
demos/demoW.a demoW.a tests flag setting and branching instructions
; demoW.a tests flag setting and branching instructions
        mov r0, 1
        mov r1, 2
        sub r0, r0, r1
        dout r0 ; prints -1
        nl
        brn @L1
        halt
@L1     mov r0, 3
        mov r1, 4
        add r0, r0, r1
        dout r0 ; prints 7
        nl
        brp @L2
        halt
@L2:    mov r0, 5
        mov r1, 5
        sub r0, r0, r1
        dout r0 ; prints 0
        nl
        brz @L3
        halt
@L3     mov r0, 6
        cmp r0, 5
        dout r0 ; prints 6
        nl
        brgt @L4
        halt
@L4:    mov r0, 7
        cmp r0, 8
        dout r0 ; prints 7
        nl
        brlt @L5
        halt
@L5:    mov r0, 1
        cmp r0, 0
        dout r0 ; prints 1
        nl
        brnz @L6
        halt
@L6:    ld r0, x
        add r0, r0, 1
        dout r0 ; prints 0
        nl
        brc @L7
        halt
@L7:    ld r0, x
        hout r0 ; prints ffff
        halt
        
x:     .word 0xffff
demos/demoX.a demoX.a uses hex arguments, implicit r0 for out commands, and cea
; demoX.a uses hex arguments, implicit r0 for out commands, and cea
startup:        bl main
                halt

main:           push lr 
                push fp
                mov fp, sp ; comment 

                cea r0, 0x0 ; compute effective address, same as `add r0, fp, 0x0`
                hout r0
                nl
                mov r0, 0xf
                hout r0
                nl
                mov r0, 0x00ff
                hout ; same as `hout r0`
                nl
                mvi r0, -256  ; was mov r0, 0xff00 — invalid (>imm9 range); mvi -256 produces same machine code
                add r0, r0, 0xf
                hout r0
                nl
                dout ; same as `dout r0`
                nl 
                ld r0, x 
                hout r0

                mov sp, fp
                pop fp ; comment
                pop lr
                ret

x:             .word 0xffff
demos/demoY.a demoY.a uses label offsets for ld and .word
; demoY.a uses label offsets for ld and .word
          ld r0, x     ; loads 5
          dout
          nl
          ld r1, x+1   ; loads 11
          dout r1
          nl
          ld r2, x+2   ; loads 17
          dout r2
          nl
          ld r3, y-2   ; loads 5
          dout r3
          nl
          ld r0, a    ; loads 20
          dout r0
          nl
          ld r4, z     ; loads 21
          dout r4
          nl
          halt
x:        .word 5
          .word 11
y:        .word 17
z:        .word x+2    ; assembled to the address of y
a:        .word y-1    ; assembled to the address of x+1
demos/demoZ.a demoZ.a uses label offsets with st, br, and lea
; demoZ.a uses label offsets with st, br, and lea
    ld r0, a ; loads 5
    dout r0 ; prints 5
    nl
    ld r0, a+1 ; loads 11
    dout r0 ; prints 11
    nl
    ld r0, c ; loads the address of a, which is 24dec
    dout r0 ; prints 24
    nl
    ld r0, d ; loads the address of a, which is 24, +1 = 25
    dout r0 ; prints 25
    nl
    add r0, r0, 5
    st r0, c-1 ; stores 30 at b
    ld r1, b
    dout r1 ; prints 30
    nl
    br e+1
e:  add r1, r1, 5 ; this line gets skipped
f:  dout r1 ; prints 30 again
    nl
    lea r0, a ; loads the address of a, which is 24
    dout r0 ; prints 24
    halt
a: .word 5
b: .word 11
c: .word a
d: .word a+1

LCC+ demos

plusdemos/charTypewriter.ap LCC+ — clear, sleep, aout loop
; plusB.ap: clear and sleep
; This program prints out the letters 'a' through 'f'
; in the terminal 'typewriter' style
     .lccplus
      clear ; clears the screen of anything else that was in the terminal
      ld r1, onesecond ; load 1000 into r1 to represent milliseconds
      mov r0, 'a' ; our initialized 'current char' to print goes into r0
      mov r2, 'f' ; this is our 'terminal char'
loop: cmp r0, r2 ; check to see how the current compares with the terminal
      brgt done ; if the current is greater than the terminal, branch to done label
      aout r0 ; print the current char
      sleep r1 ; pause for 1 second
      add r0, r0, 1 ; increment the char
      br loop ; go back to the loop label
done: nl
      halt ; end the program

onesecond: .word 1000