The Intel 8085 is an 8-bit microprocessor that was launched by Intel in 1977 and hence is something that we have never seen around. So why do we need to learn about the assembly of this old microprocessor?
The microprocessors we use are all for general-purpose computing, but there are other applications of computers such as making automatic solar-tracking-panels, automatic power-controls, or security control systems. For such applications, general-purpose CPUs are unnecessary — a waste of resources; a low-powered CPU is what we need. The Intel 8085 is one of the candidates.
To program this piece of hardware, we first need to know the programming model — the logical structure of the programmable registers, flags, and the instruction set. The Intel 8085 has seven internal general-purpose 8-bit registers A, B, C, D, E, H, L and 5 flags — S (sign), Z (zero), AC (Aux Carry), P (Parity) and CY (Carry). The BC, DE and HL registers can be used as register pairs and work as 16-bit registers, with some specific instructions. Besides these, there are two other registers: one is the program counter (PC), which is a 16-bit register, and always points to the memory address of the next instruction to be processed; the other is the stack pointer (SP), a 16-bit register that points to the top of the stack.
The processor has a total of 246 instructions with which we can manipulate data in the processor registers and memory, and also perform conditional branching in code with the help of flag values, which are set by the instructions, depending on the result. This is a brief overview of the programming model; see the References section at the end of this article for links to more information.
Programming the Intel 8085 or similar microprocessors is not like present-day programming — there is no editor, compiler or assembler, and not even a monitor. You can probably have a 7-segment display, which has to be manually interfaced, to show the memory content. You need to burn in the assembled program (essentially, some numbers in memory), connect the memory with the processor, and the microprocessor starts to run the code.
There are programmers to burn the code into memory, and microprocessor kits that help you program the microprocessor interactively by providing additional controllers, 7-segment displays, a 4×4 keyboard, the interfacing, etc. However, you still have to hand-assemble the code.
Now, no code is perfect the first time; that’s why we have bugs. Debugging code on an 8085 itself is a real pain. Even if you use a microprocessor kit with a debugging facility, the limited debugging features make it a complex and slow process, not suited for a beginner. So, essentially, to know if your code is correct or not, completely depends on your skills, the expected outputs of the code, and the minimal debugging interface.
Wouldn’t it be great to be able to test the code and develop it completely before even touching the actual processor? This is what a simulator lets you do — the very purpose of the GNUSim8085 Intel 8085 Microprocessor Simulator.
About the simulator
The 8085 microprocessor simulator simulates the Intel 8085 programming model, with the same instructions available as on the real system. The input and the output of the actual machine and the simulator are identical, although the internal processing method may differ. The simulator lets you view the contents of the registers, the memory and I/O port values, execute one instruction at a time, and also write code in mnemonics instead of hand-assembled code.
While I was pursuing my undergraduate course, I began to look for a FOSS-based 8085 simulator. Simulators supplied with text books, and others available on the Internet either did not fulfil my needs, or were not FOSS. Then I recalled that LINUX For You had once published a review of GNUSim8085, and downloaded the software. The basic features listed on the official site are:
- It comes with an 8085 assembler.
- The editor has syntax highlighting.
- Register and Flags display are available.
- Has a hex-to-decimal converter.
- Provides a view of memory, I/O and stack contents.
- Step-by-step execution support.
- Print support.
- Has UI in different languages.
Now, let’s take a detailed look at this software.
When the software is launched, the editor starts with a template — sample code you can edit — or, you can open a new file, and start coding. The editor lines are numbered. The code highlighting is good, and makes it easier to read the code. To run or assemble code, you need to save it first, before compilation is allowed.
On the left-hand pane, all the registers and flags are listed in a very easy-to-read manner. All the register values are displayed in hexadecimal format. The hex-to-decimal conversion box, which is very useful in such applications, is in this pane. Personally, I feel that the implementation ought to have been a bit different. To convert from decimal to hex, or vice-versa, you need to type in the number and click the correct button to make the conversion. I would have liked it if it automatically converted as the input box value change; this would make things much faster and more convenient.
Then the I/O Ports space is displayed as a spin-box. The spin-box index is the port number, and the text box beside it shows the contents of this I/O port. Similarly, the memory space is shown with another spin-box. Note that the values shown in both are all in decimal. The default input for these is in decimal, but to enter a value in hex, you add an h after it; if the number starts with a letter of the alphabet, you need to add a zero before it. For example, AB is entered as
On the right-hand side, there are three tabs. The Data tab shows the data variables you have defined with the assembler EQU pseudo opcode (discussed later). The next tab shows the stack state. After you initialise the stack pointer (SP) and execute PUSH, CALL or other stack-manipulation instructions, this tab will show the address and value of the entire stack, along with the associated pushed register pair or program label (for call).
This is especially helpful when you are debugging code with many nested subroutines, or using stack-manipulation instructions like XTHL. When pushing the contents of the PSW register (Accumulator and Flags), the Register name under the Proc/Reg field is incorrect, although the performed operations have no problem. This is a really helpful tool for debugging.
The third tab contains a virtual keypad, consisting of keys corresponding to each instruction. It looks good, but I do not think this is a feature that will get used a lot. It is much easier and simpler to type in mnemonics, than to click buttons to code.
In the text box on the top labelled “Load me at”, you can enter an address location, and make the assembled code load, starting at that memory location. The default input is decimal; to enter hex, use the same rules as before. An empty or invalid address means the program will be loaded at 4200h by default.
The Assembler menu has three items. The first, Assemble (F8), is used to assemble the program and load it into memory (at the load address). There is no practical use of only assembling the code in the current version, as you cannot generate an output assembled binary file that you could burn into the 8085’s memory. The next, Execute (F9), would execute the compiled program.
The following entry is Show Listing (Ctrl + L), which shows you the assembled machine code, along with the memory address opcodes, mnemonics and comments. This window is especially useful when you have successfully run a program in the simulator, and are ready to run it on the actual 8085; you simply need to enter the proper load location, and then either display the listing, or save it into a file and print it out, before entering it into the actual machine. This saves you from the hassles of hand assembly.
The Debug menu has the Step in (F5), Step Over(F6) and Step Out(F7) options, along with the program breakpoint management. These features are very helpful for debugging code by inspecting the register and memory contents at each step, or at breakpoints.
From the Reset menu, you can reset the state of registers, I/O ports, flags and memory, individually or all at once. It is useful when you want to remove old data from the simulator without writing extra 8085 code.
The toolbar is concise and clutter-free. It contains the normal save, load and new icons, apart from execution and debug shortcut buttons. The icon of the big red cross is to stop (terminate) execution when you are stepping through code, or in between.
At the bottom of the window is the assembler error message output panel, where you see any errors, with the line number and a brief description of the error. Clicking the error message highlights the line with the error.
This simulator comes with an assembler: you write the code in Intel 8085 mnemonics, and it is converted to machine code by the assembler, freeing you from the pain of hand assembly. The assembler supports four types of syntax parts:
- The assembler Intel 8085 mnemonics: The instruction strings as in the manuals.
- Labels: A named point in the code, the target for JMP or CALL instructions.
- Comments: Anything on a line after a semicolon (
;) is ignored by the assembler, and used to write comments explaining the code.
- Pseudo opcodes: Are not actual opcodes, but instructions to the assembler that provide some features to ease the coding process.
Instead of repeating the assembler features of the simulator here, I recommend you read the official site, where every detail is documented. From version 1.3.7, this assembler tutorial is included with the software, available at Help –> Assembler Tutorial.
After using this software for quite a long time, I have found some positive and negative points about it, which I will discuss below.
The highs (and the lows)
- Has a detection mechanism for when your code goes wild. For example, if you forget to place a HLT to stop processing, the simulator will automatically stop program execution and warn you about this.
- If you do more POP operations than PUSH, the simulator stops execution and tells you to check the logic. Although there is no warning on the real 8085 (it cannot — it would simply take the contents of SP as the top of the stack), this is very helpful, because such unbalanced stack operations are hard to detect in a large program.
- The stack view and tracing is a good feature and is really helpful for debugging code with many subroutines and a lot of PUSH, POP and other stack-related instructions.
- Like most simulators, this has a very good and easy-to-read register and flag views, which helps in programming.
- It provides an assembler and lets you enter the program in Intel 8085 mnemonics instead of hand assembly as on the real 8085 (when programmed manually).
- Has debugging features.
- Has assembler listing with address location, opcodes, mnemonics and comments — all as a single list. This listing can be followed when entering the code manually on the real 8085, and also keep the mnemonics of the opcodes at hand. Good for documentation.
- The editor has good highlighting, which makes the code easier to read.
- Most importantly, it has a very simple and clutter-free interface.
Here are some points that I felt needed improvement:
- The label line needs to be assigned at least a line of code. For example, if you do something like the following:
mvi c, 0ah mvi b, 05h xra a loop: add b dcr c jnz loop
The above code would not assemble, as the line with the label “loop” does not have any code. Either you have to move the ADD B to the “loop:” label line, or simply include a NOP beside the label “loop”.
- The memory and I/O contents are displayed in decimal, which causes a lot of confusion as the registers’ displays are in hex. Thus, each time, you need to convert the values and check the output. Also, because of this difference, if you are working with code that manipulates a good amount of data from memory, it becomes even more difficult to trace, as each time you need to pay attention to the base of the number you are looking at.
- Representation of the I/O, and the memory editing with the spin-box makes memory data entry and inspection very slow. For example, if you enter some data manually in memory, then you need to: click on the text box, enter data, click Update… and continue like this. I would recommend that memory and I/O should be editable with the mouse and also with easy keyboard shortcuts. For example, a grid display with scrollbars showing 10-20 memory locations, navigable with the keyboard, would be extremely helpful.
- The editor has only one tab — so if you open another file when one file is already open, the new replaces the old. An MDI feature would be great, but as it is, this is not much trouble, in my opinion. (See the Bugs section below for more on this)
While using and testing the 8085, I have found some potential problems, bugs and glitches in the simulator, which are listed here.
- The PUSH PSW shows an invalid string for the register name in the Stack debugging tab.
- There is a bug related to opening and closing files. When you are working with one file and then open another, the editor displays the new file — but what is not obvious is that the old file (which you were working on) is not closed. This is not much trouble, since the limit for the maximum open files is quite large by default (run
ulimit -n), but this should be fixed. You can check it by first launching the program, and then keeping an eye on the output of
watch ls -l /proc/$(pidof gnusim8085)/fd.
- There is a severe problem with the simulator if you accidentally or intentionally put your code in an infinite loop — the simulator freezes, looping forever, and there is no way you can stop it except by killing it. The interface does not work in such a case. Running the interface and the execution module in separate threads would help, I guess.
- A minor glitch detected while boundary testing is that if you attempt to enter a negative program-load address, or an address greater than
65535in decimal, the simulator does not complain, but automatically detects an invalid range and loads the assembled code at the default loading address,
4200h. But consider this scenario: you load code at
fff0h, and the length of your code is more than 15 (which will try to go beyond the
ffffhmemory limit). With this, if you assemble/run the code, the simulator immediately crashes. This should wrap around memory and continue to be executed from
0000hafter reaching the limit
ffffh, or simply notify the user about this and stop.
- Although this is a minor bug, I think it is worth pointing it out: if you enter an invalid decimal value in the decimal text box, the hexadecimal conversion shows an invalid value in the hexadecimal box. I think giving some warning of an invalid input would help users.
Version 1.3.7 v/s 1.3.5
Version 1.3.7 came out recently, almost one year after the last one. On the official website, the 1.3.7 Windows binary (with and without GTK runtime) and the 1.3.7 source code is available. The
.deb is obsolete. There are not many externally visible differences in these two versions, but some nasty bugs were killed.
Version 1.3.6 was released in March 2010, but did not fix the real bugs in 1.3.5 — like in 1.3.5, clicking Help –> About would crash the program immediately. If you changed source code in an open file and clicked new, loaded another file, or simply closed it, there was no prompt to save the document. These were fixed in 1.3.7.
The really nasty DAA bug was killed in 1.3.7, for which reason you should avoid using 1.3.5. In 1.3.5, if you ran DAA after adding
01h, the accumulator ought to have contained
00h, and the carry flag should have been set, but though the accumulator was
00h, the carry flag would not get set. Try adding
45h and then apply DAA. The result would be in an invalid BCD form. Thankfully, this nasty bug was killed in 1.3.7. I would like to make you aware that there are a lot of simulators that have implemented DAA incorrectly, so please confirm DAA operation with the above sample, or with the real machine.
Some other bugs have been fixed as well, so I recommend you download the latest version 1.3.7 if it is available from your distro repository, or if not, install from source.
Have a look at the version release notes here.
Still to implement
- The RST instructions (a 1-byte call instruction, jumping to a predetermined jump location).
- RIM and SIM instructions — you would not be able to test any interrupt or serial I/O-related code. You would notice the Int-reg register in the simulator interface, which apparently represents the interrupt register that holds the masks, the pending interrupts, etc. This is non-functional.
- There are problems when printing on Windows, and the Linux environment implementation is very primitive.
- If you carefully look at the opcodes, you will notice that there are some unused ones that have no mnemonics associated. These unused opcodes are actually used, and are undocumented instructions, of which the Intel 8085 has 10 (they are not documented because they are not supported by 8086 and higher processors). These instructions and the related undocumented flags are not supported by the simulator. This will not bother many people, since, being “undocumented”, they are not generally used. Implementation of these is not that urgent, but the availability of the undocumented instructions would definitely make this simulator special and draw attention as these instructions can make some composite operation with a single instruction.
What you need to remember…
This is essentially a very good simulator to work with for educational purposes. If you have to practice code for your college exam, or to test the code in the practical copies, then I would recommend that this simulator. Some of my friends and I have used it during our engineering course, and had no problems. It has a very simple and clutter-free interface, an assembler, and the best part is that being under GPL v3, you can see the code and even edit it if you like — or request any feature update from the developers.
Programming in the simulator is easy, but it should be kept in that mind that if you are doing a course, then you need to hand-assemble and enter the code when presented with the actual 8085 in your college course. It is good to make a habit of hand-assembling and directly entering code on the actual machine, to keep in touch.