Skip to main content

Emulator Deep Dive - The Instruction Set: Part 2

This is the second post in this series, and will cover stack manipulation instructions. You can find a table of all the stack instructions at the end of this post.

You can find the first post here.

Prerequisites

There are a couple of prerequisites to fully understanding this post. It will assume you know what a stack is (but I've included a refresher) and that you have some knowledge of assembly language. But the content could still be interesting even without that knowledge. I'll leave it to you to decide.

Notation

The table at the end of this post uses a stack effect notation typically used by Forth. These effect notations are enclosed in parentheses, and consist of a before state and an after state, separated by two dashes. For instance, the swap instruction exchanges the top two items on the stack. This would be noted as (a b -- b a), showing that before the instruction is executed, b is at the top of the stack, and a is one below the top of the stack. After the execution a is on the top of the stack and b is one below the top.

Stacks

A stack is a last-in, first-out data structure. The location of the last item added to it is called the top of the stack, and the number of items on the stack is the depth. Most stack instructions only operate on the top of the stack, but there are some exceptions, such as the roll instructions.

The emulator operates two 256-byte stacks: the data stack and the return address stack. Neither is directly accessible, but the data stack can be manipulated using the instructions covered in this post. Eventually, there will also be instructions to move or copy items from one of the stacks to the other, but this is as yet unimplemented. The main use for this functionality would be in implementing interpreted languages like Forth.

Push-me Pull-you

To push a value to a stack means to place a new value on top of the current stack. To pull, or pop, a value means to remove the value at the top of the stack. The RX-9000 instruction set contains a number of push/pull pairs, such as pushi/pop, pushx/pullx, etc.

While pulling a value that is larger than the depth of the stack is a logical error, the behaviour of such a pull is undefined. In the current implementation the stack pointer will end up rolling over, changing the depth of the stack and leaving the contents of the stack undefined.

Value size

In order to support both single and double byte values, the instruction mnemonic for a single byte value, like pushi, is followed by a w for two byte values. So to push an immediate one byte value you would use pushi, and for a two byte value pushiw.

The exceptions to this are when the size is implicit in the instruction, such as setting or retrieving a value in a register.

Register/Stack transfers

In order to set the DP or X registers, the desired value needs to be on the top of the stack. Then the pulldp or pullx instructions, respectively, take that value off the stack and store it in the respective register. pulldp pulls a single byte from the stack, whereas pullx pulls two bytes.

Alternatively, to place the value of either DP or X on the stack, you would use pushdp or pushx respectively.

Register indexed transfers (aka memory/stack transfers)

This is perhaps the least intuitive part of the instruction set. I'll try to make it as clear as possible, but if you have any questions don't hesitate to ask them in the comments.

The DP or X registers are required to move items between the stack and memory. In RX-9000 assembly this is noted with the register in square brackets, such as pull [DP] to pop the top byte from the stack and place its value at the memory location pointed to by DP. push [DP] takes the byte pointed to by DP and pushes it onto the top of the stack.

The width of the transfer can be expanded to two bytes by adding w to either the push or pull instruction. The width of the register itself is irrelevant. If both DP and X contain the same value, push [DP] is equivalent to push [X].

In addition, the register used can be either decremented or incremented, either before or after the operation takes place. This change can either be by one byte or two. For instance, to put the value at DP on top of the stack, and then increment DP by one byte, you would write push [DP+]. In order to increment by two bytes, you would write push [DP++]. This allows both DP and X to be used as stack pointers as well, and allows for easy array access through these registers.

What next?

I plan to cover arithmetic and logic unit (ALU) instructions in the next post. These instructions operate only on items at the top of the stack and include addition, subtraction, logical AND, among others.

Instruction table

Each of these instructions is listed with its single byte variant, but any of these instructions can have a w added to them to cause them to operate on two byte values instead. The exceptions to this are the pulldp/pushdp/pullx/pushx instructions, whose bit counts are implicit.

Added to the tables of instructions involving the registers are the condition register flags that can be changed by the operation. The condition code (CC) register will be explained further in the post on ALU operations.

Stack manipulation

Instruction

Stack effect

Description

pushi

( -- i)

Pushes the immediate value to the stack. The immediate byte or word value follows the instruction.

pop

(a -- )

Removes the top item on the stack, discarding it

dup

(a -- a a)

Duplicates the top item on the stack

swap

(a b -- b a)

Exchanges the top two items on the stack

roll

(a item[0] item[1] ... item[a] -- item[a] item[0] item[1] ...)

Moves an item ‘a’ items deep in the stack to the top of the stack

depth

( -- d)

Pushes the number of bytes on the data stack, not including the newly pushed byte.

Register manipulation

Instruction

Stack effect

Description

CC

pushdp

( -- DP)

Pushes the byte value of DP onto the stack

ZN

pushx

( -- X)

Pushes the word value of X onto the stack

ZN


Instruction

Stack effect

Description

CC

pulldp

(a -- ) a -> DP

Pulls the top byte from the stack and puts it in DP

ZN

pullx

(a -- ) a -> X

Pulls the top word from the stack and puts it in X

ZN

Register indexed

These instructions support pre/post-increment/decrements.

Instruction

Stack effect

Description

CC

push [dp]

( -- [DP])

Pushes the value at DP onto the stack

ZN

push [x]

( -- [X])

Pushes the value at X onto the stack

ZN


Instruction

Stack effect

Description

CC

pull [dp]

(a -- ) a -> [DP]

Pulls the top value from the stack and places it at DP

ZN

pull [x]

(a -- ) a -> [X]

Pulls the top value from the stack and places it at X

ZN

Comments

Popular posts from this blog

Am I Jonesing for the Internet?

I’m feeling a little agitated and jittery today. My internet access is down due to some nasty snow and wind. Are the two related? They might be. I know I’m certainly missing my twitter friends and feeling less in touch with the world. How long is this weather going to hold? I can’t look that up. Sure, I could pull out a radio and listen in, if I had one. I might somewhere, but I’m at the mercy of the broadcaster to decide when to report the weather and how much of it to report. Some argue that internet access should be a basic human right. Does this point of view hold water? I suppose it could be argued that since the internet allows us to draw together into a larger community that it is an essential part of improving the human condition. Its use in political organizing and to connect dissidents in repressive regimes can certainly help make the case for it as a basic human right. Is the jitteriness really from not having the internet? My doctor did just increase my dose of modafi

What Kind of Games?

I started programming when I was young, with the hopes of writing video games. I think a lot of kids start that way. When you like something, or someone, you try to emulate what you’re seeing. But how has that early dream turned out? They tell writers to write what they know. It’s good advice. How can you write about life in the Serengeti without have someone to give you a first hand account or having been there yourself? You can always use your imagination, and that’s all you can really do when writing fantasy or science fiction. It works for writing video games. How can you expect to write a genre you don’t immerse yourself in? These days I spend most of my gaming time playing casual games. I’m busy doing other things, and don’t want to spend long stretches just sitting at the console or computer. Recently I read an article about the kind of video games the most people tend to flock to. Typically they’re games that are relatively simple and involve sorting things in some way. It

Piet - an esoteric programming language

There’s a certain group of programmers out there that like to come up with programming languages just for the fun of it. Some of them have profanity as their names , and some are based on internet memes . Whatever the case may be, some individual out there enjoyed thinking up the language, and many of these languages are actually useable. One esoteric language that stands out, for me, at least, is Piet , created by David Morgan-Mar. Based on the idea of making programs that look like abstract art, Piet allows the programmer to express their software in the form of coloured blocks. Numbers are represented by blocks of pixels containing a pixel count equal to the number itself. Operations are performed by changes in hue or darkness. As an example, here is a Piet program I wrote to output the string “Hello World”. This image is in fact the entirety of the program, and can be run in any of the Piet interpreters out there. Other examples of Hello World programs are available on David’s si