Assembly Language Design
An assembly language is fundamentally a set of mnemonics for machine instructions. It is a way of writing machine instructions using something that looks more like a human readable language. The simplest assembly languages require line numbers and do not allow the use of symbols to represent addresses in program or data memory.
A more sophisticated assembler allows the user to put labels into the code to represent memory addresses. For example, when branching, it is convenient to be able to label a location in the program and then use the label in a branch instruction instead of an actual memory address. It allows the assembler to assign the line numbers, releiving the programmer of that responsibility.
The assembly language for the simple CPU allows the programmer to use arbitrary symbols for program memory locations, mnemonics for the instructions, and mnemonics for the various registers.
The assembler uses the following rules for syntax.
- One instruction or label per line.
- An instruction line must start with one of the instruction symbols in the table below.
- Use the symbols in the register symbol table to specify a register in an instruction.
- All immediate values and data addresses are interpreted as decimal values (base 10).
- Blank lines are ignored.
- All characters on a line after a # are ignored (use for comments)
- Spaces delimit all instructions and other tokens.
- A label can be a mix of alphanumeric characters, and it must end with a colon.
- Addresses must be positive.
- Negative immediate data values must have a preceeding '-' with no space between the negative sign and the number.
|LOAD D A||Load from address A (0..255) to register D|
|LOADA D A||Load from address [A + RE] to register D|
|STORE S A||Store the value in register S to address A (0..255)|
|STOREA S A||Store the value in register S to address [A + RE]|
|BRA L||Unconditional branch to label L|
|BRAZ L||Branch to label L if the CR zero flag is set|
|BRAN L||Branch to label L if the CR negative flag is set|
|BRAO L||Branch to label L if the CR overflow flag is set|
|BRAC L||Branch to label L if the CR carry flag is set|
|PUSH S||Push register S onto the stack and increment SP|
|POP S||Decrement SP and put the top value on the stack into register S|
|OPORT S||Send register S to the output port|
|IPORT D||Assign to register D the value of the input port|
|ADD A B C||Execute C <= A + B, where A, B, C are registers|
|SUB A B C||Execute C <= A - B, where A, B, C are registers|
|AND A B C||Execute C <= A and B, bitwise, where A, B, C are registers|
|OR A B C||Execute C <= A or B, bitwise, where A, B, C are registers|
|XOR A B C||Execute C <= A xor B, bitwise, where A, B, C are registers|
|SHIFTL A C||Execute C <= A shifted left by 1, where A, C are registers|
|SHIFTR A C||Execute C <= A shifted right by 1, where A, C are registers|
|ROTL A C||Execute C <= A rotated left by 1, where A, C are registers|
|ROTR A C||Execute C <= A rotated right by 1, where A, C are registers|
|MOVE A C||Execute C <= A where A and C are registers|
|MOVEI A C||Execute C <= A where A is an 8-bit 2's complement value and C is a register|
This is the assembly version of the test program.mif file from last week. It should assemble to the identical MIF file.
tart: movei 8 RA movei 8 RB movei 8 RC movei 1 RD movei 2 RE add RD RE RA sub RD RE RB BRA start
Here is the expected output.
-- program memory file for test.a DEPTH = 256; WIDTH = 16; ADDRESS_RADIX = HEX; DATA_RADIX = BIN; CONTENT BEGIN 00 : 1111000100001000; 01 : 1111001100001000; 02 : 1111010100001000; 03 : 1111011100000001; 04 : 1111100100000010; 05 : 1000011000100000; 06 : 1001011001100000; 07 : 0010000000000000; [08..FF] : 1111111111111111; END
This is assembly to find the sum of the first 10 non-zero odd integers.
# setup MOVEI 1 RA MOVEI 0 RB MOVEI 2 RC MOVEI 10 RD # loop loop: ADD RA RB RB ADD RA RC RA ADD ONES RD RD BRAZ breakout BRA loop breakout: # RB contains the sum OPORT RB
Here is the expected output.
-- program memory file for sumten.a DEPTH = 256; WIDTH = 16; ADDRESS_RADIX = HEX; DATA_RADIX = BIN; CONTENT BEGIN 00 : 1111000100000001; 01 : 1111001100000000; 02 : 1111010100000010; 03 : 1111011100001010; 04 : 1000000001001000; 05 : 1000000000010000; 06 : 1000111011011000; 07 : 0011000000001001; 08 : 0010000000000100; 09 : 0110001000000000; [0A..FF] : 1111111111111111; END