A computer can be described , abstractly, by specifying and demonstrating its machine language capabilities. Seeing some low-level programs written in machine language helps us understand not only how to get the computer to do things, but also why its hardware was designed in a certain way. Machine language is the most profound interface in the overall computer enterprise—the fine line where hardware meets software. This the point where abstract thoughts and symbolic instructions are turned into physical operations performed in silicon.
A machine language can be viewed as an agreed-upon formalism, designed to manipulate a memory using a processor and a set of registers.
- Memory: refers loosely to the collection of hardware devices that store data and instructions. From a programmer’s standpoint, a memory is simply a contiguous array of cells (words) of some fixed width. A particular word can be accessed by specifying its address.
- Processor: or Central Processing Unit (CPU), is a device capable of performing a fixed set of elementary operations. These typically include arithmetic and logic operations, memory access operations, and control (branching) operations.
- Registers: Memory access is a relatively slow process. So most processors are equipped with several registers, each capable of holding a single value. Located in the processor’s immediate proximity, the registers serve as a high-speed local memory, allowing the processor to manipulate data and instructions quickly.
A machine language program is a series of coded instructions. For example, a typical instruction in a 16-bit computer may be
1010001100011001. To understand what this means, we’ll need to know the instruction set of the hardware.
The Daisy machine language is based on two 16-bit command types. The address instruction has the format
v being either 0 or 1. The instruction causes the computer to load the 15-bit constant
vvv...v into the
The compute instruction has the format
c- bits instruct the ALU which function to compute, the
d- bits instruct where to store the ALU output, and the
j- bits specify an optional jump condition.
Since binary codes are rather cryptic, machine languages are normally specified using both binary codes and symbolic labels. For example, the language designer could decide that the operation code
0010 will be represented by the mnemonic
ADD and that the registers will be symbolically referred to as
R0, R1 etc. Using these conventions one can specify a slightly more readable instruction such as
ADD R0, R1.
This symbolic notation is called assembly language and the program that translates from assembly to binary (machine code) is called assembler.
Daisy Language Specification
Memory Address Spaces
A Daisy programmer must be aware of two distinct address spaces: an instruction memory and a data memory. Both memories are 16-bit wide and have a 15-bit address space. This means the maximum addressable size of each memory is 215 = 32K, 16-bit words.
The CPU can only execute programs that reside in the instruction memory. The instruction memory is a read-only advice, and programs are loaded into it using some exogenous means. Loading a new program is done by replacing the entire ROM chip, similar to replacing a cartridge in a game console.
A Daisy programmer can make use of two 16-bit registers called
D is used solely to store data values,
A doubles as both a data register and an address register. These registers can be manipulated explicitly by arithmetic and logical instructions like
! means a 16-bit, bitwise Not operation.
A registers facilitates direct access to data memory (simply memory form now on). Since Daisy instructions are 16-bit wide, and since addresses are specified using 15 bits, it is impossible to pack both an operation code and an address in one instruction. Thus, the syntax of Daisy language mandates that memory access instructions operate on an implicit memory label
M always refers to the memory word whose address is the current value of the
A register. For example, to effect the operation
D = Memory + 1, we have to use one instruction to set the
A register to 516 (
@516), and a subsequent instruction to specify
D = M - 1.
A register also facilitates direct access to the instruction memory. This can be used to implement jump controls in code (if/else, goto etc.). Similarly to memory access convention, a Daisy jump instruction always effects a jump to the instruction located in the memory word address by
A. For example, to effect the operation
goto 36 we will first set the
A register to 36 (
@36), and then issue a second instruction with a
goto command without an address. This sequence causes the computer to fetch
ROM in the next clock cycle.
The Daisy assembly program to multiply two numbers:
// Multiplies R0 and R1 and stores the result in R2. // (R0, R1, R2 refer to RAM, RAM, and RAM, respectively.) @R2 M=0 // Initialise result memory @R1 D=M @END D;JEQ // If second number is 0, answer is 0, jump to end @R3 M=D // Set counter to second number (LOOP) @R0 D=M @END D;JEQ // If first number is 0, answer is 0, jump to end @R2 M=M+D @R3 M=M-1 @R3 D=M @END D;JLE // Exit loop if counter is less than or equal to 0 @LOOP 0;JMP (END) @END 0;JMP