Skip to footer navigation.

« Oatmeal

Posts tagged assembly

Follow this tag's bespoke rss feed or return to the list of all tags.

uxn exit

This evening I sat down on the couch sleepy. We’d just gotten the kids into bed. I hadn’t planned on writing any code but figured I’d round the evening out with some reading.

First I read through the docs and glossary of uf, a forth system for uxn. Then I read through an example program provided by uf.

…with my palette whetted I re-visited some other forth documentation.

Then I put things down and did the dishes. After doing the dishes I found myself back at a keyboard ready to write some code.

My first thought was to re-implement the unix command cat in uxntal. After a bit of noodling I decided to go with echo instead of cat. I banged away at echo for a bit but then remembered the very first program demonstrated in a book I’m currently reading, Programming from the Ground Up, by Jonathan Bartlett. The first sample program there is one that exits. That is about it.

Exiting felt achievable.

Here is a teeny tiny program that prints the string Hello Uxn! and then exits.

( exit )

|10 @Console &vector $2 &read $1 &pad $5 &write $1 &error $1

|0100 ( -> )

    ( print hello )
    ;hello-txt

    &while
        LDAk .Console/write DEO
        INC2 LDAk ,&while JCN
    POP2

    ( exit )
    #010f DEO

BRK


@hello-txt "Hello 20 "Uxn! $1

It isn’t much, but it is a start.

Some handy resources I poured over over this evenings explorations include:

Also, big thanks to Devine Lu Linvenga, a primary force behind uxn, for pointing me in the right direction and suggesting some optimizations.

I’m not sure if I’ll have it in me to write code every night moving forward, but this was a lot of fun and I still have big dreams for a homespun cat.tal

uxn laboratory

As I look to assembly nights 2 and think of trying my own take on it, I wanna have a cozy space ready to play with uxn.

The setup I’ve landed on is sort of inspired by plan9port.

Prepare the way

  • in home directory, create a u directory
  • in u clone uxn and build it
  • add ~/u/uxn/ to your path as $UXN
  • add $UXN/bin to your path
  • moving forward we’ll put any and all *.rom files into $UXN/bin

Utility scripts

  • create script called u that contains the following
#!/bin/sh

UXN=${UXN:-$HOME/u/uxn}
export UXN

case "$PATH" in
$UXN/bin:*)
    ;;
*)
    PATH=$UXN/bin:$PATH
    export PATH
    ;;
esac

case $# in
[1-9]*)
       exec "$@"
       ;;
esac
  • make u executable with chmod +x and mv it to /usr/local/bin or some similar space

  • in $UXN/bin add the following scripts, make each executable with chmod +x

  • lin, used to lint *.tal files before assembly.

# script name: lin
#!/bin/sh

u uxncli uxnlin.rom $1
  • asm, used to assemble *.tal files into executable *.roms.
# script name: asm
#!/bin/sh

u uxnasm $1 $2
  • run, used to run *.roms in the sdl2 uxn emulator.
# script name: run
#!/bin/sh

u uxnemu $1
  • cli, used to run command line *.roms into stdin/stdout at the shell prompt.
# script name: cli
#!/bin/sh

u uxncli $1
# script name: drif
#!/bin/sh

u uxncli drifblim.rom $1 $2

rom library

  • wget the following roms into $UXN/bin
wget https://rabbits.srht.site/left/left.rom
wget https://rabbits.srht.site/drifblim/drifblim.rom

rock and roll

At this point everything is set and cozy to start exploring!

Do that like so:

  • to lint a *.tal file,
u lin rad.tal
  • to assemble a *.tal file using an assembler that supports macros,
u asm rad.tal rad.rom
  • to assemble a *.tal file using the selfhosted assembler,
u drif rad.tal rad.rom
  • to run a rom in the emulator
u run rad.rom
  • to run a rom at the prompt
u cli rad.rom
  • to edit something using left,
u uxnemu left.rom -s 2 rad.tal

NOTE: the -s 2 bit makes the program run zoomed…I’ve got bad eyesight and have a high DPI screen, you may not need that flag.

Onward!

Now, I’ll be honest — I don’t know if I’ll actually do my own flavor of assembly nights with uxn, but I’m really pleased with this little setup…so, that is a step in the right direction. The other step in the right direction I’ve taken is that I started to read Programming from the Ground Up by Jonathan Bartlett…so far, 2 chapters in, I am enjoying it a lot.

What is an addressing mode?

In a recent post I referenced addressing modes. But what the heck are they!?

Setting the stage

The instruction register holds the program instruction that is currently being run.

A fixed number of bits within the instruction register represent the operation, e.g. “op. code” — examples of these instructions include things like add, subtract, load, and store. We can imagine the instruction register like this:

ASCII diagram of an instruction register. Links to a txt of the same diagram.

There’s a fixed number of bits allocated to the op. code (the 6 left-most boxes), and then a fixed number of bits that hold the operand/s being operated on (remaining 10 boxes). An operand could be a value, a CPU register, or a memory address. This set of fixed bits is referred to as the address field.”

The number of bits allocated to the address field determines the amount of memory that can be addressed. The number of bits allocated to the op. codes determines how expressive the op. codes can be (or at least how many of them there can be).

Addressing modes provide different ways to use the addressable memory.

In my diagram, 2 bits of the operation code are used to determine the addressing mode. The addressing mode tells the processor how the bits in the address field should be interpreted.

For example…

  LDA #80
  LDA $80

These similar looking instructions are pretty different.

# tells us that the number following is a literal value.

$ tells us that the number following references a memory address.

So, LDA #80 loads the literal decimal value 80 into the A register and LDA $80 loads the value located at memory address $80 into the A register.

#80 is known as immediate mode because we are directly, or immediately, loading a value, while $80 is known as absolute, or zero page, mode.

What about a literal hex value?

BOOM!

  LDA #$80

This loads the literal hex value $80 (e.g. 128) into the A register.

Other resources

Notes on 6502 Assembly

The NES runs a very slightly modified 6502 processor. What follows are some very introductory, and not at all exhaustive notes on 6502 Assembly, or ASM.

If you find this at all interesting, Easy 6502 is a really great introductory primer on 6502 Assembly that lets you get your hands dirty right from a web browser.

Numbers

Numbers prefixed with one of the following:

  • $ are hexadecimal format
  • # are literal numbers

Any other number without either of these prefixes refers to a memory location.

So,

    LDA #$01

Loads the hex value $01 into register A.

Registers and flags

There are 3 primary registers,

  • A
  • X
  • Y

A is usually called the accumulator.

Each register holds a single byte

SP is the stack pointer, a register that is decremented every time a byte is pushed onto the stack and incremented whenever a byte is popped off the stack.

PC is the program counter. PC is how the processor keeps track of where in the currently running program it is.

Processor flags

Each flag is 1 bit, so all 7 flags can live in a single byte

More info on registers and flags.

Instructions

In 6502 Assembly instructions are like words in Forth, or functions in a higher order programming language. Every instruction takes 0 or 1 arguments.

An example of some instructions,

    LDA #$c0  ; Load the hex value $c0 into the A register
    TAX       ; Transfer the value in the A register to X
    INX       ; Increment the value in the X register
    ADC #$c4  ; Add the hex value $c4 to the A register
    BRK       ; Break - we're done

For a full list of 6502 ASM instructions see,

6502 ASM has a handful of branching instructions — they almost all rely on flags to determine what branch to follow.

Addressing modes

The 6502 has 65536 bytes of available memory. These bytes are typically described using the HEX range $0000 - $ffff.

When the 6502 refers to addressing modes, it really means What is the source of the data used in this instruction?”

The different modes are,

Absolute: $c000

With absolute addressing, the full memory location is used as the argument to the instruction.

Zero page: $c0

All instructions that support absolute addressing (with the exception of the jump instructions) also have the option to take a single-byte address. This type of addressing is called zero page” - only the first page (the first 256 bytes) of memory is accessible. This is faster, as only one byte needs to be looked up, and takes up less space in the assembled code as well.

Zero page,X: $c0,X

In this mode, a zero page address is given, and then the value of the X register is added.

Zero page,Y: $c0,Y

This is the equivalent of zero page,X, but can only be used with LDX and STX.

Absolute,X and absolute,Y: $c000,X and $c000,Y

These are the absolute addressing versions of zero page,X and zero page,Y.

Immediate: #$c0

Immediate addressing doesn’t strictly deal with memory addresses - this is the mode where actual values are used. For example, LDX #$01 loads the value $01 into the X register. This is very different to the zero page instruction LDX $01 that loads the value at memory location $01 into the X register.

Relative: $c0 (or label)

Relative addressing is used for branching instructions. These instructions take a single byte, which is used as an offset from the following instruction.

Implicit

Some instructions don’t deal with memory locations, for example, INX - increment the X register. These have implicit addressing because the argument is implied by the instruction.

Indirect: ($c000)

Indirect addressing uses an absolute address to look up another address. The first address gives the least significant byte of the address, and the following byte gives the most significant byte.

Indexed indirect: ($c0,X)

This one’s kinda weird. It’s like a cross between zero page,X and indirect. Basically, you take the zero page address, add the value of the X register to it, then use that to look up a two-byte address.

Indirect indexed: ($c0),Y

Indirect indexed is like indexed indirect, but instead of adding the X register to the address before de-referencing, the zero page address is de-referenced, and the Y register is added to the resulting address.

For more on the different modes of addressing,

The stack

The current depth of the stack is measured by the stack pointer, a special register. The stack lives in memory between $0100 and $01ff. The stack pointer is initially $ff, which points to memory location $01ff. When a byte is pushed onto the stack, the stack pointer becomes $fe, or memory location $01fe, and so on.

Jumping

Jumping is like branching with two main differences:

  • First, jumps are not conditionally executed
  • Second, they take a two-byte absolute address

For small programs, this second detail isn’t important, as you’ll be using labels, and the assembler works out the correct memory location from the label. For larger programs though, jumping is the only way to move from one section of the code to another.

Other Resources

Because these are but the barest of minimum notes, here are some more resources for continued reference.

How to install Uxn on macOS

Uxn is an esoteric stack-machine with 32 bit instructions. It exists someplace at the intersection of a GameBoy, 6502 ASM, an Apple II, Forth, RetroForth, the z80, a Sinclair ZX Spectrum, and what if Nausicaä from Studio Ghibli’s Nausicaä of the Valley of the Wind used a computer?” It is tiny, unlike most anything else around these days, and, once you wrap your head around it, pretty fun.

I won’t go into how to develop for it here (mostly because I’m not heaps good at that, not yet) but will walk you though how to get it running under a relatively recent release of macOS.

For more info on how to use it and develop programs for it see:

Assumptions

I’m assuming that you, at a minimum know how to find and launch the terminal application on macOS. Opening Launchpad or Spotlight and typing Terminal” should do the trick. Beyond being able to start the terminal application this assumes no prior knowledge of the command line nor Unix.

To run a Uxn rom you’ll need a Uxn emulator. There are a few of these out and about, but I’ll focus on the reference implementation here, Uxnemu.

This implementation has only one dependency, SDL2. SDL2 provides the audio/video bindings, as well as a few other niceties, to the host OS.

If you’ll be building Uxnemu from source you’ll need SDL2 to be installed on your machine. I’ll provide more information about that further on.

Quick and easy

If you don’t want to bother with installing anything other than Uxnemu you can download a build of it that includes SDL2 here.

When this downloads it’ll look sort of like a text file, not a normal application like you are probably used to. Before you run it you’ll need to change permissions on it to make the file executable (able to be run as a program). To do this you’ll have to launch the macOS’ terminal.

Once you’ve launched the terminal, either drag your downloads directory on to the terminal and press return on your keyboard, or type the following (assuming you’ve not changed the location of your system-standard downloads folder),

cd ~/Downloads

Then press retrun on your keyboard.

You’ve navigated to your downloads directory! Next up, we’ll make the freshly downloaded Uxnemu executable. To do this, type the following:

First, ensure that the file is present in the downloads folder:

ls

Then hit return.

You should see a list of all the contents of your downloads directory, including uxnemu. If you don’t see uxnemu you are either in the wrong directory or didn’t download it.

If you need to troubleshoot: check what directory you are in — type pwd and then hit return. This will display the current directory, it should return a string of text that ends in Downloads.” If you are in the downloads directory and still don’t see uxnemu download it again and check to where it is being saved.

Once in your downloads folder with your fresh copy of uxnemu run the following commands to make it executable:

chmod a+x uxnemu

Hit return!

This command will make uxnemu executable. To test that it worked, run the following,

./uxnemu

Then hit return — you should see output like, usage: uxnemu file.rom. If you do, that means that it worked! You’ve now got yourself a working uxnemu emulator.

Snag a rom and go nuts!

Give it a go, download the piano.rom from here.

Now run,

./uxnemu piano.rom

A new window will open. You should see something along the lines of this!

Uxn’s piano rom

Slightly more involved

Now, if you wanna get a little deeper into the weeds, you can assemble uxnemu from source. To do that, you’ll need to have some more pieces in place.

Preparing the way

Before we get started ensure that you’ve got all the necessary tools to build unxnemu’s C source. The easiest way to do this is to use macOS’ deeply middling package manager, brew. Before you install it, you’ll need to install the Xcode Command Line Tools (if you haven’t already, or if you haven’t installed the full, GUI, version of Xcode).

Here are directions for how to do that. Or, tl;dr wanna live dangerously xcode-select --install!

If you don’t explicitly needs Xcode, I recommend the command line tools over the full Xcode GUI because Xcode is ginormous, and will devour a computer’s disk-space.

Once you’ve got the Xcode Command Line Tools and brew installed you are almost ready. As mentioned above, Uxn depends on SDL2. We’ll use brew to install that.

Check that brew is working by looking for SDL2,

brew info sdl2

It’ll output something sort of like this if everything is working to plan,

Brew info sdl2’s output

With that command we ensured that sdl2 is available through brew, but haven’t yet installed anything. Eyes on the prize, you are ready to install sdl2. Do that by running,

brew install sdl2

That will output something along the lines of,

Brew install sdl2’s output

Note that brew can sometimes be bananas slow. Patience is key to this step.

Once brew is done doing its thing, and sdl2 is installed you are ready to start cooking with fire!

Doing the thing

The first step is to obtain the uxn source code. We’ll use git to do that. At the terminal,

git clone https://git.sr.ht/~rabbits/uxn

Then return.

This will download the uxn project. It’ll look something a bit like this,

Cloneing uxn’s output

Once that has completed, enter the directory you just cloned using git by typing,

cd uxn

Then return — from within that directory, now type,

ls

And then hit return on your keyboard. You’ll see a listing of the directory’s contents, like this

The contents of uxn’s repo

Now we’re reading to do the thing! Uxn comes with a handy script called build.sh. The script is a little program that can build uxnemu and a few other programs for you. To run it,

./build.sh

And return!

Uxnemu build and run

That will run the build script. The build script will build, and then run a default rom, like this!

Uxn’s piano rom

At this point you should be good to go!

Building from source means that you have the uxnemu as well as the uxnasm.

The uxnemu is an emulator, capable of running assembled Uxn roms.

The uxnasm is an assembler, capable of assembling Uxntal files into roms for the uxnemu to run!

As I learn more about about Uxn I hope to write more about it, in the meantime, check out the great tutorial!

A screenshot of the Atari emulator Stella’s debugger.

I’ve been playing with a bit of 6502 and z80 assembly programming. I don’t plan to make anything substantial, but I’ve been learning a lot and having fun.

I love a system that I can hold in my head.

Can you spot the bug here? It took me ages to find, but there’s a classic here! Off by one! I needed to flip the decrement and setting bits of the loop so that it didn’t skip the last memory address while clearing memory.