Machine and Assembly Language are the base languages for computers. In this article I will provide a high level overview of both languages and how they work with the computer.
How Machine and Assembly Language Works
The two base languages for microcomputers are machine and assembly language. Machine language is the direct way to work with a CPU. The language is made of numerical codes that are fed directly to the CPU. When a higher level software language is compiled it is translated into the numerical language that is machine code. On older computers the instructions would be read in on paper tape and displayed using a series of buttons. The computers displayed in old movies and television shows were emulating the display of this data in their blinking light displays. They were a physical representation of the 0’s and 1’s stored in the computer.
However, reading machine language is not easy, it requires memorization of many codes for CPU instructions. If one bit in the command is entered incorrectly, the software may operate in a different and unexpected process. A review of machine language software is required before entering the commands into the CPU. At this level of operation an incorrect command could cause damage to the computer or device it is controlling. An example of machine language is included at the end of this article.
Due to the difficulties of writing and debugging machine language, assembly language is a translation of machine language into mnemonics that humans can read. The codes are translated into very basic instructions. This makes assembly language slightly easier to read than machine language. The example below includes the assembly language translation of the machine language listing.
Machine and assembly language are also useful for directly interfacing with hardware devices. Hardware devices may have their own CPU or firmware that can work with commands sent by the CPU. Hardware devices are usually accessed through a shared memory or bus that connects the CPU and the hardware. The driver acts to translate the CPU commands into something that the hardware controllers can understand. The commands are sent to the device and the results are sent back to the CPU.
Machine language and assembly language are the most direct ways to program a computer. At the current time they are most often used for writing low level routines for drivers that access hardware or for real time processing where speed is important. A knowledge of machine language and assembly language is also needed for writing compilers, in order to create files that can be run on the computer. There are tools that help automate the development of a compiler or development of hardware drives. However, a knowledge of machine language can be helpful in troubleshooting and correcting errors that might be generated by the tools.
The Impacts of Machine and Assembly Language
Machine language and storing the instructions in RAM allowed the programming of computers. However, with a language based on numbers, with very simplistic commands, it requires precision and attention to detail to develop software in machine language. Assembly language added a layer of abstraction by allowing the use of alphanumeric mnemonics which are easier for humans to read and review.
While these low level languages allowed the development of software, they were still difficult to read and create. A simple program like printing “Hello World” on a computer monitor might only take 1-3 lines of code in a higher level language, it could require tens of lines of codes to write in assembly language. The more lines of code in a software program require more time to review and debug the software. A 1-3 line software program is much easier to review and debug than a 50 line assembly line program. Using a simpler command set does not convert into reducing the amount of time to write and debug the software.
Most software in current times is developed using a higher level language, like Python, C++, Java or even older languages like FORTRAN and COBOL. However, all of these languages are translated into machine language so that the CPU can recognize the commands. Machine and assembly language are still used for processing efficiency and speed. There are applications that are required to process data in what is called ‘real time’ processing instead of batch processing. In batch processing the commands are queued up and processed when the operating systems allows the software to run. This allows other software to run and share a CPU at the same time. Processing of data may be slower.
For real time processing, the software is expected to read data from active sources and process the data as it is received. The operating systems prioritizes the software application and its commands are processed before other software on the machine. This allows the software to respond as quickly as possible. Examples of uses of real time processing are in manufacturing processes where a delay in reacting to data could lead to the shutdown or worse the failure of a manufacturing line. Incorrectly feeding parts to a machine or incorrectly stopping the manufacturing process could cause many problems. Another example is communications systems that are processing messages. Imagine a conversation on the phone where the words were transmitted only a few syllables every minutes. Someone calling in a warning would not get the warning out before the event happened.
In real time processing software is optimized to read and write data quickly. Low level languages can be the most efficient method of prioritizing data handling and the cost of writing assembly language is worth the gains in processing time. Higher level languages are turned into machine language but they do it based on a translation set that requires handling many cases. As a result, the generated machine language may not be as small as it could be if it was written specifically for a task.
I saw an example of the differences in processing speed. I worked on a system that needed to read data from a communication device and display the results on screen. The information was received every second and needed to be read, formatted and redisplayed on the screen. A programmer wrote a routine in Pascal to do this task. The routine worked but it could not keep up with the flow of data. The update was visible on the screen and quickly fell behind in processing the data.
Another member of our software team had experience with assembly language for this system. He spent a weekend rewriting the software for display in assembly language. The assembly language used an interface with Pascal so that the Pascal software could call the display routine that was written in assembly language. The routine was called to read, format and write the data on screen. The rewritten routine easily kept up with the data flow and display on the screen. In this case the higher level language, Pascal, was used to manage the main screen that started reading the data. When it was time to display the data read from the communications device, the assembly language routine was used for real time processing of the data.
The basic building blocks of these low level languages help to form the workings of a higher level language like C or Java. Just like different building materials change the look and a feel of a building, these basic software building blocks affect how higher level languages are designed. Since the lower level commands are based on moving numbers from the CPU to RAM, making comparisons and following logic trees, higher level languages include these elements. If a computer somehow had basic blocks that equated to natural language, computer languages would look more like human languages. Although these building blocks are limited, complex algorithms can be built with them. Over the years, libraries of common functions have been built and used to support increased functionality in computers.
Originally when constructing a building, the builders would have to cut wood, shape it and build the structure. Eventually lumber mills would cut the wood and builders could use ready-made items like 2×4’s, plywood and other wooden items for building. Software programs have been built the same way. In the early days, each programmer had to write basic functions just to read and write data to the screen. Eventually companies started focusing on developing libraries of software functions that could read and write data. Developers used these libraries and focused on building applications that used these functions in forms. There is now a large number of software libraries that software developers can use for many different functions. These libraries help to reduce development time and improve the quality of the software with reviewed and debugged code.
Machine and assembly language are the basic building blocks for doing useful things with a computer. Their use is hidden within higher level languages but they are still an important part of the software for computers. These languages are also an important part of reading and displaying information on a computer monitor. While I went over basic Input/Output (I/O) functions in a previous article, I felt it would be worthwhile to review a specific output device, the computer display. In my next article, I’ll explore how the display of data on a computer works and why generating graphics is a function that is well suited for computers.
*Machine and Assembly Language example. The machine language instructions are written in hexadecimal in order to save space. The machine language is for a 6502 processor. Here is a link for more examples of 6502 machine language and assembly language routines.
- Memory Location – The location in RAM where the machine language instructions are located. In modern computers the operating system manages the memory locations for software. In older computers, the developer had to manage the location of their programs on their own. This meant that it was possible for the software to overwrite critical programs if the software had a bug or the developer loaded the software in the wrong place
- Machine language – The numbered codes for the CPU. Consists of one by for a command and 1-2 bytes for the address or register to act on
- Assembly Language Label – A label used to identify reusable parts of the software. Other software can branch to this location by referencing the label in the command target. This would be the equivalent of a subroutine, function, or procedure in a higher level language.
- Assembly Language – This is the alphanumeric mnemonic used to reference the machine language instruction. As seen in the example, the instructions are very simple. The 6502 machine language was relatively simple with only 50 distinct commands. Modern processors can have around 3,000 commands, which would be a lot to memorize for programming
- LDA, LDX – Load information from memory
- JSR – Jump Subroutine
- CMP – compare a value in memory with a value in a register
- BEQ, BNE – compare two values and branch to another location if the result is true (Value of 1)
- Command Target – The memory address that is the target of the command
Memory Location |
Machine Language |
Assembly Language – Label |
Assembly Language Command |
Command Target |
8000 |
20 58 FC |
START |
JSR |
HOME |
8003 |
A9 FB |
|
LDA |
# |
8005 |
A2 80 |
|
LDX |
#>COPYR |
8007 |
20 RF 82 |
|
JSR |
|
800A |
A9 17 |
|
LDA |
#23 |
800C |
20 58 FB |
|
JSR |
TABV |
800F |
A9 89 |
|
LDA |
# |
8011 |
A2 80 |
|
LDX |
#>TEXT |
8013 |
20 4F 82 |
|
JSR |
|
8016 |
A9 04 |
|
LDA |
#4 |
8018 |
20 58 FB |
|
JSR |
TABV |
801B |
A9 51 |
|
LDA |
# |
801D |
A2 80 |
|
LDX |
#>PARMS |
801F |
20 3F 81 |
|
JSR |
MENU |
8022 |
C9 FF |
|
CMP |
#$FF |
8024 |
F0 DA |
|
BEQ |
START |
8026 |
C9 01 |
|
CMP |
#$01 |
8028 |
D0 03 |
|
BNE |
WRMSTRT |
802A |
4C D0 03 |
|
JMP |
WRMSTRT |
802D |
C9 02 |
START1 |
CMP |
#$02 |
802F |
D0 10 |
|
BNE |
START2 |
8031 |
20 58 FC |
|
JSR |
HOME |
Pictures by J.T. Harpster, prints of selected photos can be found at our Redbubble shop
Help support our work on Patreon, get access to short stories and news about Shell Creek Publishing.
tamara.harpster
Mon, 08/01/2022 – 20:14