Guide for programming h831 CPU in assembly langauge
This guide will cover the hardware features and serve as a reference for programming the H831 CPU using the assembly language.
The general syntax for H831 assembly follows the below pattern.
graph LR
arg0[Argument 0]
arg1[Argument 1]
arg2[Argument 2]
Instruction --- arg0
arg0 --- arg1
arg1 --- arg2
Some instructions take in 3 arguments, while some take 2, 1 or even none. The section will specify the arguments for each instruction one-by-one.
The assembly langauge of h831 makes extensive use of prefixes to extinguish different objects (such as registers, literals and addresses). When calling (specifying) these objects, you must use an appropritate prefix.
| Object | Prefix |
|---|---|
| General purpose registers | % |
| Internal registers | _ |
| RAM Addresses/ IO Addresses | $ |
| Literals (Immediate values) | $ |
| Code offsets (Labels) | . |
| Comments (Ignored by assembler) | ; |
The h831 comes with 8 8-bit-general-purpose registers. A list of such registers and their preferred uses are listed below.
| Register name | Assembly | Preferred purpose |
|---|---|---|
| x0 | %x0 |
Accmulator, Storing return values |
| x1 | %x1 |
No special purposes |
| x2 | %x2 |
No special purposes |
| x3 | %x3 |
No special purposes |
| x4 | %x4 |
No special purposes |
| x5 | %x5 |
No special purposes |
| x6 | %x6 |
No special purposes |
| x7 | %x7 |
Base pointer for stack (segmentation) |
Special note
%is defined to be a prefix for specifying the register names in the assembly. If you would like to operate on registers, you must add the%in front of their names.E.g.
mov %x0, %x1is valid, whilemov x0, x1is invalid.
Immediate values are the values that are hard-coded in the program code. There are 2 buses for immediate values, via A bus and B bus in the ALU. However, since B bus has some dedicated uses, the assembler will only use A bus for transferring immediate values.
The general syntax for specifying immediate values are as follows.
graph LR
$ --- var["Immediate value in decimal"]
A prefix, namely $, is required to be placed in front of the decimal of the immediate value.
To specify a 87, you would do $87.
In h831 assembly, you do not need to specify a fixed code offset when branching. You can use labels to mark the offset to be jumped to. However, do pay attention to the following remarks.
Labels is just an lexical symbol to mark the point where a new section of program (sometimes called subroutines) begins. The use of lexical symbols (often an english word) for labels may act as a heading for a section of code.
For an example,
.check: pop %x2 ; Read from stack 6
cmp %x0, %x2 ; If memory write incorrect 7
bnz .halt ; halt 8
dec %x0, %x0 ; Decrement x0 9
cmp %x0, $1 ; Do 32 times 10
bnz .check ; 11
not %x4,%x4 ; 12In the above, .check is the label, which checks the RAM content byte by byte in some program.
To create a label, add .labelName: to the beginning of the line that is intented to be marked.
Note that the dot . is the prefix for labels. (To let the computer distinguish whether it is instruction or a label), and the : denotes the beginning of a new section.
In the following assembly, line 1 is intented to be marked with a label named "loop".
push %x0 ; Write x0 to stack 3
inc %x0 ; Increment x0 by 1 4
cmp %x0, %x1 ; Compare x0 , x1 5
bnz .loop ;To mark it, add .loop: in the beginning of line 1.
.loop: push %x0 ; Write x0 to stack 3
inc %x0 ; Increment x0 by 1 4
cmp %x0, %x1 ; Compare x0 , x1 5
bnz ? ; Jump reference not specified yetTo jump to a specific code offset, specifying its label right after the branching instruction.
To jump back to push %x0, do bnz .loop in line 4.
.loop: push %x0 ; Write x0 to stack 3
inc %x0 ; Increment x0 by 1 4
cmp %x0, %x1 ; Compare x0 , x1 5
bnz .loop ;Internal registers prohibit direct writing. The symbol of _ is the prefix for internal registers.
CPSR stores the flags which describes the computational result from the ALU.
There are 3 flags available on this CPU. These are zero flag, carry flag and sign flag. The register _CPSR stores these flags.
CPSR stands for Current processor status register.
Future development
In later revisions there will be a trap flag, which halts the clock if it is called by breakpt instruction.
Stack index stores the index where the stack have grown to.
As of 2020-09-02, h831 supports a number of instructions. A table for them are below.
| Instruction mnemonic | Meaning | No. of arguments take |
|---|---|---|
| mov | Copies data between registers | 2 |
| movi | Copies immediate value to register | 2 |
| add | Add the value in 2 registers and store result in anoter one | 3 |
| addi | Add the value in a register with an immediate value and store result in another register | 3 |
| sub | Subtract the value in 2 registers and store result in anoter one | 3 |
| subi | Subtract the value in a register with an immediate value and store result in another register | 3 |
| tcp | Compute two's complement for the value in a register, and store it in another register | 2 |
| and | Perform bitwise AND between 2 registers, and put result in a separate register | 3 |
| andi | Perform bitwise AND between an register and an immediate value, and put result in a separate register | 3 |
| xor | Perform bitwise XOR between 2 registers, and put result in a separate register | 3 |
| xori | Perform bitwise XOR between an register and an immediate value, and put result in a separate register | 3 |
| not | Perform bitwise NOT in an register, and store result in a separate register | 2 |
| inc | Increment the value in a register, and put the result into a separate register | 2 |
| dec | Decrement the value in a register, and put the result into a separate register | 2 |
| cmp | Compare the values in 2 registers and sets the status register (Flags) | 2 |
| cmpi | Compare the values in a registers with an immediate value and sets the status register (Flags) | |
| b | Unconditional branch | 1 |
| bz | Branch if zero flag is True | 1 |
| bnz | Branch if zero flag is False | 1 |
| bs | Branch if sign flag is True | 1 |
| bns | Branch if sign flag is False | 1 |
| bc | Branch if carry flag is True | 1 |
| bnc | Branch if carry flag is False | 1 |
| str | Store a value from a register to an address as immediate value in RAM | 2 |
| ldr | Load a value from the RAM with address as immediate value to a register | 2 |
| push | Pushes a value from a register into the stack, requires a desired %x7 as base pointer |
1 |
| pop | Pops a value from the stack to a register, requires a desired %x7 as base pointer |
1 |
| stkz | Sets stack pointer (%SI) to be 0 |
0 |
| in | Read a value from an IO device to a register | 2 |
| out | Write a value from a register to an IO device | 2 |
| breakpt | Halts the clock | 1 |
| dbgout | Displays the value in data bus if attatched a debug 7-seg display | 1 |
A detailed description about each instruction are below.
Copies data between 2 registers.
Takes in 2 arguments.
dest: Register name, The register name to copy tosrc: Register name, The register name to copy from
mov dest, src;
mov %x0, %2;Copies immediate value to a register.
Takes in 2 arguments.
dest: Register name, The register name to copy toval: Literal, The immediate value to be copied
movi dest, val;
mov %x7, $87;Add the value in 2 registers and store result in anoter one.
Takes in 3 arguments.
dest: Register name, The register name to store the resultsrc0: Register name, The first value from the register to be addedsrc1: Register name, The second value from the register to be added
add dest, src0, src1;
add %x4, %x7, %x8;Add the value in a register with an immediate value and store result in another register.
Takes in 3 arguments.
dest: Register name, The register name to store the resultsrc: Register name, The source value from the register to be addedval: Literal, The immediate value to be added
addi dest, src, val;
addi %x0, %x0, $89;Subtract the value in 2 registers and store result in anoter one.
Takes in 3 arguments.
dest: Register name, The register name to store the resultsrc0: Register name, The first value from the register to subtractsrc1: Register name, The second value from the register to be subtracted
Notice subtraction of any number, say, src0 would be the negative number that is being "added".
sub dest, src0, src1
sub %x0, %x5, %x0;Subtract the value in a register with an immediate value and store result in another register.
Takes in 3 arguments.
dest: Register name, The register name to store the resultsrc: Register name, The first value from the register to be subtractedval: Literal, The immediate value to subtract
Notice subtraction of any number, say, src would be the negative number that is being "added".
subi dest, src, val
subi %x0, %x5, $4;Compute two's complement for the value in a register, and store it in another register.
Takes in 2 arguments.
dest: Register name, The register name to store the resultsrc: Register name, The source register containing the number to compute the two's complement
tcp dest, src
tcp %x5, %x5;Perform bitwise AND between 2 registers, and put result in a separate register
Takes in 3 arguments.
dest: Register name, The register name to store the resultsrc0: Register name, The first register containing the number to compute bitwise ANDsrc1: Register name, The second register containing the number to compute bitwise AND
and dest, src0, src1
and %x0, %x0, %x1;Perform bitwise AND between a register and an immediate value, and store result in a separate register.
Takes in 3 arguments.
dest: Register name, The register name to store the resultsrc: Register name, The source register containing the number to compute bitwise ANDval: Literal, The immediate value to compute bitwise AND
andi dest, src, val
andi %x0, %x0, $5;Perform bitwise XOR between 2 registers, and put result in a separate register
Takes in 3 arguments.
dest: Register name, The register name to store the resultsrc0: Register name, The first register containing the number to compute bitwise XORsrc1: Register name, The second register containing the number to compute bitwise XOR
xor dest, src0, src1
xor %x5, %x0, %x1;Perform bitwise XOR between a register and an immediate value, and store result in a separate register.
Takes in 3 arguments.
dest: Register name, The register name to store the resultsrc: Register name, The source register containing the number to compute bitwise XORval: Literal, The immediate value to compute bitwise XOR
xori dest, src, val
xori %x0, %x7, $5;Perform bitwise NOT of the value in a registe and store result in a separate register.
Takes in 2 arguments.
dest: Register name, The register name to store the resultsrc: Register name, The source register containing the number to compute bitwise NOT
not dest, src
not %x0, %x7;Increment the value in a register, and put the result into a separate register.
Takes in 2 arguments.
dest: Register name, The register name to store the resultsrc: Register name, The source register containing the number to increment
inc dest, src
inc %x2, %x7;Decrement the value in a register, and put the result into a separate register.
Takes in 2 arguments.
dest: Register name, The register name to store the resultsrc: Register name, The source register containing the number to decrement
dec dest, src
dec %x5, %x4;Compare the values in 2 registers and sets the status register (Flags).
Takes in 2 arguments.
src0: Register name, The value in the first register to be comparedsrc1: Register name, The value in the second register to be compared
cmp src0, src1
There are 3 flags available on this CPU. These are zero flag, carry flag and sign flag. The register _CPSR stores these flags.
CPSR stands for Current processor status register. The _ is the prefix for internal registers.
cmp %x5, %x4;Compare the values between a value in the register and an immediate value. Sets the status register (Flags).
Takes in 2 arguments.
src: Register name, The value in the register to be comparedval: Literal, The immediate value to be compared
cmpi src, val
There are 3 flags available on this CPU. These are zero flag, carry flag and sign flag. The register _CPSR stores these flags.
CPSR stands for Current processor status register. The _ is the prefix for internal registers.
cmpi %x5, $64;Unconditional branch.
Takes in 1 argument.
offset: Code offset, The label of marking the code offset to be jumped.
b offset
b .main; Provided that .main is declared aboveBranch if zero flag is True.
Takes in 1 argument.
offset: Code offset, The label of marking the code offset to be jumped.
bz offset
bz .loop; Provided that .loop is declared aboveBranch if zero flag is False.
Takes in 1 argument.
offset: Code offset, The label of marking the code offset to be jumped.
bnz offset
bnz .loop; Provided that .loop is declared aboveBranch if sign flag is True.
Takes in 1 argument.
offset: Code offset, The label of marking the code offset to be jumped.
bs offset
bs .redo; Provided that .redo is declared aboveBranch if sign flag is False.
Takes in 1 argument.
offset: Code offset, The label of marking the code offset to be jumped.
bns offset
bns .redo; Provided that .redo is declared aboveBranch if carry flag is True.
Takes in 1 argument.
offset: Code offset, The label of marking the code offset to be jumped.
bc offset
bc .recheck; Provided that .recheck is declared aboveBranch if carry flag is False.
Takes in 1 argument.
offset: Code offset, The label of marking the code offset to be jumped.
bnc offset
bnc .recheck; Provided that .recheck is declared aboveStore a value from a register to an address in RAM.
graph LR
Register -->|str| RAM
Takes in 2 arguments.
dest: RAM Address, The address pointing to a location in RAM to be readaddr: Register name, The value read from RAM is stored in this register.
str dest, addr
str $23, %x5;Load a value from an address in RAM to a register.
graph LR
RAM -->|ldr| Register
Takes in 2 arguments.
dest: Register name, The value read from RAM is stored in this register.addr: RAM Address, The address pointing to a location in RAM to be read
ldr dest, addr
ldr %x5, $23Pushes a value from a register into the stack, requires a desired %x7 as base pointer.
Takes in 1 argument.
src: Register name, The value in the register to be pushed.
push src
push %x5;Pops a value from a register into the stack, requires a desired %x7 as base pointer.
Takes in 1 argument.
dest: Register name, The register to store the popped value.
pop dest
pop %x0;Sets stack pointer (_SI) to be 0. Abbreviated from "Stack Zero".
Takes no arguments
stkz
stkz;Reads a value from an IO device to a register.
graph LR
IO -->|in| Register
Takes in 2 arguments.
dest: Register name, The register to store the value read from the IO device.src: IO Address, The IO device containg the value to be sent.
in dest, src
in %x4, $1;Outputs a value from an register to an IO device.
graph LR
Register -->|out| IO
Takes in 2 arguments.
dest: IO Address, The IO device to store the value read from the register.src: Register name, The register restoring the value to be sent
out dest, addr
out $5, %x1;Halts the clock unconditonally. Shorten from Breakpoint.
Future development
Halts the clock if the trap flag is set.
Takes no arguments.
breakpt
breakpt;Displays the value in data bus if attatched to a debug 7-seg display.
Takes no arguments.
dbgout
dbgout;- 2020-09-03 Revision. Added description for essential commands.
- Future development: Trap flag
Footnote
This is my first attempt on building a MC computer. There are design flaws everywhere, but I have a lot of fun building this. I would like to especially thanks to n00b_asaurus. I follow his great guide and tutorial videos on building this minecraft computer. I regret to watch it so late.