A simple assembly compiler for the Intel 8080 based chip used at the electronics practical course (Elektronikpraktikum) at the University of Bonn.
View latex-syntax-highlighting.tex
for simple assembly syntax highlighting in LaTeX.
ℹ︎ This program and the documentation refer to the EP manual from April, 2024. (SoSe 2024.) However, the instructions should not change very often. The program should still be up-to-date in the future. A careful look at the hex output is still advisable. Please do not hesitate to contact me via my e-mail if you have any questions or problems (regarding the compiler!):
mika.t (@) uni-bonn (dot) de
.
- What it does
- What it does not
- How to use from the command line
- How to use from an IDE of your choice
- Known instructions
- Known registers
- Other supported features
- Limitations & Requirements
- How to add/edit a instruction
- How to add/edit a register
- This compiler translates assembly code into hex code as required by the course. (The compiler prints each instruction to a new line. Ignore all line breaks when you copy the code to the chip to assure correct line jumping.)
- It informs you if a instruction or a register is not known (to the compiler) or if they might be used incorrectly.
- Additionally, it is also possible to compile to binary (by setting the third argument to
binary
as described below).
- The compiler does not actually execute your code. To test the code’s behaviour I recommend https://eliben.org/js8080/ by Eli Bendersky. (Please note that this online simulator does not support
IN
orOUT
, but it shows the content of each register.) - The compiler does not know every instruction specified in the table of the EP manual, as well as defined by the Intel 8080 assembly documentation. For a list of known instructions see below. (If you know some Java or C basics, it might be easy to add your own instructions though!)
Please also read limitations and requirements further below.
For this approach the Java 8 JDK is required. Setting the third argument to debug
is highly recommended as it increases the readability when copying the code to the computer used at the course.
- Download the latest release or clone this repository (to build it yourself).
- Navigate to the
.jar
-file from your terminal. - Run
java -jar [enter release file path here] [assembly source file path] [hex destination file] {hex/binary} {debug/standard}
(without the brackets, curly brackets are optional),
for examplejava -jar EPAssemblyCompiler.jar aufgabe1/source.asm aufgabe1/source_hex.txt hex debug
. - The compiled hex code should be written to the destination file.
- Download or clone this repository.
- Import the
EPAssembly
folder to your IDE (this process varies for each IDE). (Eclipse | IntelliJ IDEA | VS Code.) - Edit the run configuration to specify arguments for the
main
-method as above. (Eclipse | IntelliJ IDEA | VS Code.) - Run the project. The compiled hex code should be written to the destination file.
Please read the EP manual for more information about each instruction. Also take a look at allowed registers for the placeholders N
, E
and O
right below. Instructions whose description has been marked with “⚠︎” have not yet been tested on the chip of the experiment.
Usage |
Args | Description | Example |
---|---|---|---|
MVI N, n | 2 | Moves a decimal number n ≤ 2^8 into the register N. |
MVI A,0 (Sets the accumulator register A to zero.) |
MOV M, N |
2 | Copies the content of a register N into register M. |
MOV B,A (Sets B to the content of the accumulator A.) |
INR N |
1 | Increases the content of the register N by 1. |
INR A (Increases the accumulator by one.) |
DCR N |
1 | Decreases the content of the register N by 1. |
DCR C (Increases the register C by one.) |
CMP N |
1 | Compares the content of N with the content of the accumulator. Sets the flag Z = 1 if they are equals. |
CMP B JZ EQUALS (Jumps to label 'EQUALS' if B is equals to A.) |
ADI n |
1 | Adds the decimal number n ≤ 2^8 to the accumulator A. | ADI 13 (Adds 13 to the content of A.) |
DAD Y |
1 | Adds a double to another double. Doubles are saved in multiple registers. (Please read the EP manual for more details.) | DAD B (Adds the double contained in the registers B, C to H, L.) |
ANA N |
1 | Performs a bitwise AND operation between A and N and saves the result to A. | MVI A,6 ; Sets A = 0000 0110 MVI B,10 ; Sets B = 0000 1010 ANA B (Puts A = 0000 0010 into the accumulator A.) |
ORA N |
1 | Performs a bitwise OR operation between A and N and saves the result to A. |
MVI A,6 MVI B,10 ORA B (Puts A = 0000 1110 into the accumulator A.) |
XRA N |
1 | Performs a bitwise XOR operation between A and N and saves the result to A. |
MVI A,6 MVI B,10 XRA B (Puts A = 0000 1100 into the accumulator A.) |
JMP L |
1 | Jumps to the label L. (Sets the program counter to the address at L.) |
LABEL: JMP LABEL (Jumps back to LABEL and stays in a never ending loop.) |
JZ L |
1 | Jumps to the label L if the Flag Z is 1. |
CMP B JZ L (Jumps to the label L if the accumulator A is equals to B.) |
JNZ L |
1 | Jumps to the label L if the Flag Z is 0. |
CMP B JNZ L (Jumps to the label L if the accumulator A is not equals to B.) |
CALL L |
1 | ⚠︎ Jumps to the label L. (Sets the program counter to the address at L.) Puts the relative address of the following instruction on the stack to jump back when return is called. |
CALL LABEL LABEL: RET (Jumps to LABEL and returns immediately, staying in a never ending loop.) |
CZ L |
1 | ⚠︎ Jumps to the label L and puts the relative address on the stack (waiting for return) if the Flag Z is 1. |
CZ LABEL LABEL: RET (Jumps to LABEL if the accumulator A is 0.) |
CNZ L |
1 | ⚠︎ Jumps to the label L and puts the relative address on the stack (waiting for return) if the Flag Z is 0. |
CNZ LABEL LABEL: RET (Jumps to LABEL if the accumulator A is not 0.) |
RET |
0 | ⚠︎ Returns the program counter to the relative address sitting on the stack. |
CALL LABEL HLT LABEL: RET (Jumps ot LABEL and returns immediately to HLT.) |
RZ |
0 | ⚠︎ Returns the program counter to the relative address sitting on the stack if the flag Z is 1. |
CALL LABEL HLT LABEL: RZ (Jumps ot LABEL and returns immediately to HLT if the accumulator A is 0.) |
RNZ |
0 | ⚠︎ Returns the program counter to the relative address sitting on the stack if the flag Z is 0. |
CALL LABEL HLT LABEL: RNZ (Jumps ot LABEL and returns immediately to HLT if the accumulator A is not 0.) |
IN E |
1 | Loads the content of the input register E to the accumulator A. |
IN B MOV B,A (Loads the input from the input register B to A and then A to the [output] register B. The Bs are not the same!) |
OUT O |
1 | Loads the content of the accumulator A to the output register O. |
MVI A,0 OUT DAC (Puts a voltage of 0 to the digital-analog converter.) |
HLT | 0 |
Stops the program. |
L: HLT JMP L (Halts at the first iteration of the loop.) |
This lists contains all allowed registers for the instructions listed above.
- For N: A (accumulator), B, C, D, E, H and L.
- For E: A, B, C and ADC. (Input.)
- For O: X, R, DAC and ADC. (Output.)
To add or edit registers read further below.
The compiler supports/ignores (single line) comments indicated by a semicolon.
START:
MVI C,10 ; This is a single line comment
IN B ; Text behind semicolons is going to be ignored
MOV B,A
CMP C
JNZ START
EQUALS:
OUT R
JMP START
Per default the compiler compiles to hex. To compile to binary the third argument on execution must be set to lowercased binary
.
The Compiler.java
-class contains a boolean named DEBUG
which is false
by default, but can be set by writing lowercased debug
as the fourth argument. If true, the compiler will show the following extra information.
- The current line while compiling (to the console).
- The corresponding (original) line next to each hex code line (to the destination file, separated by an '@' character).
- Requires Java 8 JDK (either installed on your computer or by your IDE).
- The compiler does not support instructions right behind a label declaration.
Instead of
A_LABEL: MVI A,0
JMP A_LABEL
write (as recommended anyways):
A_LABEL:
MVI A,0
JMP A_LABEL
- Open
src/compiler/Instructions.java
. - This class contains a static Instruction[]-array named
instructions
. It includes every instruction known to the compiler. Each instruction is defined similar as follows.Thenew Instruction("INSTRUCTION_TITLE", 1, "10101010") { // The instruction title, the amount of required arguments and the binary representation. @Override // This method defines how this instruction should be translated to binary public ArrayList<String> run(String[] args, int line, Compiler compiler) throws CompileException { // This list will be returned, contains the 8-bit binary strings that represent this instruction // Please assure that each string you add consists of eight characters of only '0' and '1' ArrayList<String> r = new ArrayList<>(); // Adds the binary representation set above ("10101010") to the output r.add(this.binaryRepr); // Example call of a register. // In this case, the register title (such as 'A' or 'B') is received from the first instruction argument args[0] // The line variable indicates where the compiler is currently working. It should be passed unchanged for error messages Register register = Compiler.getRegisterByTitle(args[0], line); // Registers may contain up to three register identifier: inputAddress, outputAddress and its associated binary representation ("ddd" or "sss"). // Please check whether the required address is defined (is not null) if(register.inputAddress == null) { throw new CompileException(line, "Unknown input address for register " + register.title + ". The register might not be designed for this usage. " + "Please reassure correct usage of this register and add the required information to its initialization in the Compiler.java class."); } // Adds the register address to the output r.add(register.inputAddress); // Return the binary representation of this instruction return r; } }
instructions
-array contains multiple examples. Please scroll down toHLT
to see an instruction that requires no argument. SeeINR
orANA
for instructions that make use of the "ddd" or "sss" register representation.MOV
andMVI
require two arguments.MVI
andADI
accept an integer. Modify or add your instruction accordingly. - If you want to add a new instruction, paste its code into the array. Make sure to add a comma after the previous element/in front of the next element.
- Open
src/compiler/Compiler.java
and scroll down to the initialization of the staticRegister[]
-arrayregisters
. - Each register is defined as follows.
The first argument defines the title of this register. The second argument defines its 3-bit representation ("ddd" or "sss"). The third argument describes its input address, the fourth argument describes its output address. The C register, for example, is represented by "001". (According to the EP manual, tab 8.8.) The input address 02_16 = 00000010_2 is described in section 8.3.3. There is no "output register" called C, which is why it is set to
new Register("NAME", "111", "11111111", "00000000")
null
. Read the other initializations of the other registers for more examples. Modify or add your register accordingly.