Connecting Hardware to Software
Key Concepts |
|
Introduction
Computer Science courses focus primarily on software (File Systems, Operating Systems, Network Protocols, Bits and Bytes). Computer Engineering courses focus primarily on hardware (Processors, Storage, Data Buses, Voltage and Current)
Computer Organization connects those to worlds, and explores how they work together to provide today's modern computer systems
To discuss the interface between Hardware and Software, we need to dive down into the lowest levels of the Computer Abstraction Layers. We will learn how a 5-volt current becomes a bit of data, Why the timing of hardware is essential of digital data integrity, and How a set of electronic circuits can reliably manipulate bits into useful data
Differences Between High-Level Programming Language and Assembly
You have likely worked with programming languages such as Java, Python, or JavaScript. These and many, many others are in a class of high-level programming languages. High-level indicates that these languages include utilities and tools that convert the source code you write into low-level machine code (strings of 1s and 0s) that the CPU can use to execute your program.
There are several layers of conversions that may take place, depending on the high-level language used, and the CPU that will execute that program.
A simple Hello World program written in Java example code is likely to result in a different set of bits for an Intel, AMD, or Apple CPU. The Java tools detect the target processor and use the correct conversion tools to create and execute the program.
TIP
Java, and other interpreted high-level languages actually have a more complex set of tools than non-interpreted languages. It is beyond the scope of this class, but look around online if you are interested
Example High- and Low-Level Program
A language like Java provides a function like System.out.println
to print a string of characters with a newline character at the end.
System.out.println("Hello, World!");
In assembly the program must create the string in memory, check with the display to see it it is ready for a character, send characters, and send the newline to accomplish the same result.
.ORIG x3000
LEA R0, HW; Load address of first character
Main LDR R1, R0, #0; Load character
BRz Done ; If loaded character was zero, jump down to Done
; Got a character, print it
WAIT1 LDI R5, DSR ; Check DSR for ready
BRzp WAIT1 ; loop until DSR is empty/ready
STI R1, DDR ; Copy character to display buffer...it will then be displayed
ADD R0, R0, 1 ; change to reference to the address of the next character
BR Main ; Loop back up and do it again
; We are here when all characters are written
; Write the NewLine character to the display
Done LD R0, NewLine
; Write characher to screen
WAIT2 LDI R1, DSR ; Check DSR for ready
BRzp WAIT2 ; loop until DSR is empty/ready
STI R0, DDR ; Update DDR to display character
HALT ;End of Program
;Data Declarations-------------
HW .STRINGZ "Hello, World!"; String to print
NewLine .FILL #13 ; Newline character
;Display registers
DSR .FILL xFE04 ; Status Register
DDR .FILL xFE06 ; Data Buffer Register
.END
It is an understatement to say that assembly is more Hands On than high-level languages like Java.
In the above assembly program, the programmer must:
- Define the Hello World string in memory (HW, line 28)
- Load the memory address of the first character of HW (line 3)
- Check for the end-of-string indication (0 value, line 6)
- Wait for the display to be ready to receive a character (lines 9-10)
- Send the character to the display to be printed (line 11)
- Move the character address to the next memory address and loop back up to do it all again
- Once the end-of-string is detected (line 6) jump out of the loop to Done
- Load the newline code (line 19)
- Wait for the display to be ready to receive a character (lines 21-22)
- Send the character to the display to be printed (line 23)
- End the program at line 25
Conclusion
All programs at any level are executed as assembly code by the microarchitecture. High-level languages allow programs to use complex instruction that are compiled into a set of assembly instructions before they can be executed.