crownedbishop said:
I'm looking for resources that discuss how a high level language works from a fundamental level. I'm not looking for something that just says if you put this in your program, this is what will happen. I looked at your programming resources page, and that is all it gives lend to. I'm looking for a text or resource which starts and the particle level (i.e. the movement of electrons), and describes a high level language in terms of transistors and other components that are fundamentally explained in terms of physical phenomena. I couldn't find any text that goes over this. Anything I find has a black box approach on how the program actually works, and doesn't go into any physical phenomena. I would greatly appreciate if you know of any resources that go from physical phenomena and rigorously take that all the way up to some high level language.
OK. There's actually a few technology paths from electron to "class". Here's a list of basics for one path:
Complimentary Metal Oxide Semiconductor (CMOS): This is one integrated circuit (IC) technology.
Field Effect Transistors (FETs): If you want to know what the electrons are doing, you need to study these things.
Basic Logic Gates: Using a high or low voltage level to encode "true" (or 1) and "false" (0) FET circuits can be designed for simple functions such as "NOT", "NOR", "NAND", "OR", "AND", and "XOR" (Exclusive Or).
Quartz Oscillator: Quartz is a piezoelectric material. A small carefully cut quartz crystal can be made to physically and electrically vibrate. The output can the be amplified and clipped to for a square wave of very consistent frequency. Of course, this can be used to establish a timebase (time of day) for the computer, but more basically, it can pace and synchronize logic. In essence, everything is done in "steps" as the signal from the quartz clocks some of the larger logic gates...
More logic gates: Those basic logic gates can be used to built larger gates such as set/reset
flip-flops (to store a single bit), toggle flip-flops (counting), binary adders (bit plus bit plus carry yields units and carry).
Major circuits: When the clock pulse is combined with these larger gates, major function blocks can be designed. Single bit gates are arrayed in sets of 16, 32, or more so that multibit word values can be handled throughout the circuit. For example, Arithmetic Logic Units (ALU) combine Add, Complement, Multiply, and sometime Divide circuits to allow words to be arithmetically combined based on other "command" bits. A more sophisticated circuit is a floating point processor that can operate on larger word values (32, 64, or more bits) that encode an exponent and mantissa.
More technology: Many of these words will be coming from or going to main memory, USB flash drives, etc. Each of these devices involves technologies that are subjects to themselves.
THE Central Processing Unit (CPU): Major circuits (ALUs, FPPs, Memory Caching, etc) are combined in the design of a complete CPU, the "thinking" part of the computer.
The instruction set, machine language: The CPU has several important registers. First among them is the "Program Counter". This is a word (array of bits, held in an array of flip flops) that can be used to address main memory to fetch an instruction. The instruction is one or more words that control the operation of the CPU. For example, CPU gates may respond to a particular bit code by using the next memory word (from the instruction pointer) as a memory address and cause the contents of that memory location to be copied to an accumulator (another CPU register) - a "Load" operation. Another might cause that accumulator content to be copied to the memory location - a "Store" operation. That instruction pointer is normally incremented after every use - so it's always pointing to the next memory location - the next instruction. But there will be other instruction codes for comparing, and either conditionally or unconditionally loading a new value into the instruction register - a "Jump" operation.
Memory mapped I/O: As I said earlier, there are many paths between the electron and the "class" syntax. And there are several ways of handling how the CPU will control external devices. A common way is with memory mapped I/O. Those Load and Store operations can act on any memory location - or even on locations that are beyond the range of the actual main memory. Other device controllers can be placed on the memory address and data bus a designed to respond to certain addresses as though they were memory locations. In this way, programs can pump data out to devices causing them to operate under the control if the CPU.
Macro Assembler: There was a time when computers were commonly programmed in binary machine language. But if your sitting at a key punch machine, isn't it easier to type "STORE" than to remember the binary code for a Store operation. If no one has ever written a macro assembler, what you do is write a macro assembler in machine language. So you code the instruction for reading a punch card into an array of memory locations, check a particular column for a recognized opcode (STORE, LOAD, JMP, CMP, JNE (Jump is not equal), ADD, etc), build up machine instructions to another location in memory, check other columns on the card for other symbols, build up tables of symbols in another memory area, etc, etc, and then loop back to the top to read another card. And the first program you will write in your new macro assembler is the macro assembler. That way you can improve it without having to deal with those obscure instruction codes. But if someone already wrote a macroassembler - but not for you CPU, then you can code the macro assembler for your computer using their computer. That will keep you away from machine language all together.
Link editor: The next program you might want to write is a link editor. To do this you create a more sophisticated version of the macroassembler that creates linkable modules - machine code that can be relocated to any location in memory - with symbolic references to other linkable modules. The link editor then takes these linkable modules and combines them to form a since executable machine language file.
Libraries: Once you have your macro assembler, your next step will be to create software libraries. For example, the instructions for reading from that card reader may be fairly involved. So write that program once in the form of a subroutine and it will be available everytime you need it within your macroassembler or any other program. You can create whole libraries of IO routines, math routines, character string manipulation routines, etc. Keep these in libraries and the change your link editor so that it recognizes libraries and only copies the modules it needs into the final executable.
Operating System: Some of those libraries are awfully handy. In fact, as disk drives increase in capacity, you might decide that you should keep all your executables and other data files on disk. So those library routine that access the disk and deal with the disk directory structure should really be in memory all of the time. Also, you decide to enhance your CPU by having it support "interrupts", signals from external devices that indicate that it's time to "service" that device. In this case "service" simply means to operate it with addition Load and Store operations. Those interrupt routines also need to be in main memory all the time. And your operating system is born.
Compiler: Once again, we will assume that you don't already have a compiler on another type of CPU available to you. So you will need to use your macro assembler to write your compiler. The only conceptual differences between the compiler and the macroassembler are: 1) each command may code to several machine language instructions, and 2) the commands are generic to any CPU. But the effect is the same. The compiler reads in lines and generated relocatable object modules that can be linked with your link editor.