So, how DOES a computer work?

I was reading Cecil’s old column (this isn’t a comment on it, so much as a setup for my question) on this issue but it seems to only address the lowest (physical) level of the question. While I know that technically everything that happens exists on the physical plane in electronic signals and magnetic fields and whatnot I’m quite interested in how the lower level languages (i.e. Machine/Native Code, Assembly Language - going a little higher, FORTRAN etc) tell the physical layer of the machine to do what it does.

I’d be particularly interested in a diagram from, assuming a freshly booted up computer, tracing me pressing a button that prints “Hello World” in an application written in say, C++, down to what exactly happens in the machine (i.e. you compile, gets translated to… hard drive reads… sends signal out to, etc).

Or is this one of those “we’re not entirely certain” things? (Or alternatively “to even understand a tiny fragment you’re looking at 8 years of college” things)

It’s definitely not one of those “we’re not entirely certain” things. In a digital computer, at the lowest level you just have batteries of swithes going on or off. Every step from you pressing the enter key to the screen showing “Hello World” is a logical succession controlling those switches.

Having said that I don’t think, even if I could remember all the steps, I could explain them in a post on a forum - more a couple of months intensive study or a fraction of a two/three year college course.

(I had an advantage when I studied this back at the beginning of the 80s. Microprocessors were just getting going in a big way and were simple enough to get your head round :smiley: )

It’s still the same process. There’s just one or two more of them on the chip. :stuck_out_tongue:

Computers only understand two things - 1 and 0. On and off.

Essentially on the computer chip (CPU) and other technological devices (GPU) are all tiny small switches which keep track of its state (1 or 0). Using binary, it is possible to represent numbers, and by extension, text, graphical data, pictures, video, audio and etc - this is what is meant by ‘digital’ as opposed to analog.

The RAM holds instruction for the CPU. Everything you write in C++ are translated to machine code which is directly popped into the RAM. Those instructions in RAM in turn directly manipulate registers in the CPU (think of them as high-speed RAM) and other part of the memory. This is how you get pixel display on the screen - the CPU inserts the RGB value directly into the memory area which is responsible for display (or the GPU inserts - depending on your hardware)

So how are those machine code instructions executed? They are hot-wired, finally. It’s nothing but circuit board shrink down to a very, very, very small size. There is a particular set of circuit for adding 2 numbers, one set of circuit for division and etc. Those circuit are usually consist of logic gates - AND, OR, NOT, XOR. With a combination of those 4 gates you can handle most numerical operations (if not all).

All this requires the computer’s power to be on, as electrical current is used to keep track of the state of the circuit (technically, it is not zero volt, but below a certain voltage). The RAM is basically a series of something which is called a flip-flop - it’s a combination of AND and NOT gates arranged in a mind-bending manner.

One important thing as to how the computer work is the clock. Most of those circuit are plugged into a clock and only activated when an electric current come from the clock. The clock is within the CPU and is pretty much the heartbeat of the entire computer; this is why over-clocking speeds up the computer – and may burn it out…

I hope this helps.

I think it’s neither of the cases you mentioned. It’s rather a case of “So many things happen that it’s impractical to explain the details instead of abstracting.”

Oh, it can be diagrammed. Just search for ‘processor timing diagram’ or ‘pipeline timing diagram’.

Nevermind – having reread the OP, this isn’t quite what was asked.

For a more nitty-gritty explanation see the link below. Long(ish) article but understandable to the layman. The fiddly details can get quite complex but this is a good start. Despite the title it covers a lot of computery ground.

How a CPU works

Hard wired into the CPU is a starting address. It’s a memory address there the first instruction to execute is located. On a PC, this is a pointer into the BIOS, which is a program that takes over an initiates everything. When the BIOS is done, it will look into a boot record, and hand off control to the operating system. These are all programs. Your operating system is a program with a lot of libraries that other programs can use. Libraries are predefined functions that programs use so as to not re-invent the wheel. For example, drawing a pushbutton should be consistent in Windows, because a library does that for you.

At the processor level, everything is assembly language. Now you can do some basic reading on x86 processors, programs counters, stacks, registers, and op codes, and have a pretty good idea how everything comes together on the high end. The program counter indicates which memory address the current op-code lives. The op-code tells the processor what to do (it’s an instruction). Some op-codes are jumps, which change where the program counter is pointing to. Stacks are first in, last out storage locations (typically in RAM). Registers are temporary storage locations, generally in the processor. Calculations are performed on one or more registers (they can act like variables). You have some special registers like error registers that indicate processor states.

Compilers and assemblers do all the work of generating the machine language for you.

With eight years of college, you could understand pretty much all of it. But the modern computer is an incredibly complex machine, so you’re not going to get a succinct answer on a message board.

It’s not that hard to give a broad overview.

Power hits the motherboard, and the clock starts. The CPU gets power, and a small capacitor starts charging. Once this has charged, the capacitor discharges and sends a signal via a Non-Maskable interrupt to initiate a hardwired reset. This small delay ensures that everything has power and clock before the CPU starts processing. The Reset NMI triggers some hardcoded processor activity that sets the Address Lines on the CPU to specific values, reads the Data Lines from that address, and loads the Program Counter internal register from Data Lines, and then starts executing code from the Program Counter. To execute an instruction, the value in the PC is transferred to the Address Lines, the Data lines read the instruction and the CPU interprets this data as an instruction. If the instruction does not explicitly set the Program Counter to a new value, the PC is incremented to the next instruction, and the cycle starts again.

This has the effect of accessing the BIOS and starting the BIOS setup code. The BIOS code than spends time initialising and checking memory and hardware. This is the Power On Self Test phase of a PC startup. These days, the BIOS does not do much, as most of the hardware is initialised by the OS. Eventually, the BIOS startup finishes, and the BIOS looks for a bootable device. The Boot block is read directly into memory from the boot device, and the PC is set to the start of the boot block code. The computer is now in the boot loader. The boot loader has the job of determining what to boot from the disk, where to find the data, letting the user choose what to boot, then loading that into memory and launching the execution of the OS.

It’s a high level overview, but covers the basics - the Address Lines are set from the Program Counter, the Data lines read the instruction, the CPU reads and reacts to the instruction, the PC updates, and the cycle starts again.

and on preview: lots of other better answers <sigh>

Si

This is a bit of a nit, but at the level of detail the OP is looking for, it matters: At the processor level, everything is in binary. Assembly language is a human readable translation of the binary instructions. You can’t get from the executable program to assembly language without a dis-assembler program or laborious manual dis-assembly.

ETA:
One thing not yet mentioned upthread:

Each binary instruction is often the address of a very small program inside the processor, that lays out all the steps the processor must do to complete that instruction. These are in so called “micro code” that is typically unique to each processor. In some cases (RISC processors) this is not really a program but a dedicated logic circuit for that instruction.

Some of the early Pentium processors had a bug in the microcode.

According to my mom, it’s all down to a little Japanese leprechaun who sits inside the box and does all the work. When the repairman comes, all he’s really doing is slipping the wee fellow some sushi and soda bread. And sake and Guinness, if it’s a serious problem.

According to some of the EE students I’ve taught, they work by magic blue smoke. The evidence of this is, if you ever accidentally let the magic blue smoke out of a computer, it stops working.

I recommend a book by Andrew Tanenbaum called Structured Computer Organization (Amazon link). It’s quite technical, not a ‘For Dummies’ kind of book, but it works through the operations of a computer from the lowest-level elements (transistors) on up. To be honest I’ve never made it much past the digital logic level before my head starts to spin, but it’s all there.

I got the 3rd edition for cheap; it’s pretty out-of-date, but the fundamental concepts are still there and I’m guessing they haven’t changed much.

Easy – Read Chapter 2 in this book “How Computers Work”

The first program I ever wrote was in pure machine language, and the first assembler I ever used I wrote myself. My PhD is in Computer Architecture, specifically microprogramming, so I’ve mucked around at the lowest level for quite some time.

For some background, look at the first chapters of a computer architecture text. I’d bet Hennessey and Patterson is good, I’ve not looked at it, but it seems to be the standard. But here is a real basic overview. I’m omitting what most transistors are spent on today, which is improving processing speed, so this architecture is a real simple one from 50 years ago.

The basic execution cycle is

  1. Fetch the next instruction, pointed to by the PC or program counter

  2. Decode the instruction. Is it arithmetic, how many operands does it have, is it a jump?

  3. Fetch the operands. The machine I first used was an accumulator machine - one operand was in the ACC and the other in memory. The one in memory was fetched to a temporary register (invisible to the programmer) before the operation was performed. Most machines have arrays of registers, so many instructions are register to register. In some cases the register contains an address of the instruction, so we see lots of addressing modes, but this is another complication.

  4. Do the operation - add, multiply, etc. Simple addition and logical operations are done by the Arithmetic Logic Unit (ALU). Faster machines have multipliers, slower ones did the multiply as a microcode subroutine. Real slow ones, like the IBM 1620, did it in software.

  5. Place the result in a destination register or address.

  6. Calculate the address of the next instruction. In most cases, you do this by simply incrementing the PC. You might store the next address in your instruction, for a branch. You might use a register for the address, as in a return from subroutine call. You can do arithmetic on the address.

  7. Go to step 1.

The complications come from pipelining this in order to be faster, from the fact that multiplies are slower than adds, and from the fact that memory accesses are very slow, relative to basic CPU speeds. Thus, you pre-fetch instructions so they’re available when you need them. But, if you have a branch, which result do you prefetch? You try to guess, but if you’re wrong you may have to throw away instructions, and it all gets complicated.

Most RISCy machines today are hardwired, in that all this is done in hardware only. CISCy machines, like the x86 family, are still microcoded, in that you can think of the results of instruction decode going to lots of subroutines written in a very simple lower level machine language. But hardware and software are basically equivalent.

Then you got I/O, and interrupts, and talking to memory, and other complications, but the seven step instruction execution cycle above is at the heart of how computers work.

Quibble. Not the actual address, but it decodes to a pointer to a ROM or Writable Control Store Location with the beginning of the decode subroutine.

[/quote]

Heh. All processors with microcode had bugs.

One thing done by earlier computers was to allow users to load the microstore with a program emulating another computer. The early 360s, which were microcoded (the slower ones, anyhow) could emulate some of their installed base, so people buying them could toss their old machines and have their code run faster. It was a big selling point.

Seconded. I am never parting with my dog-eared, scribbled-in, battered, bruised, bought-in-1987 copy of Tanenbaum, ever. It’s the book to read on this subject.

I don’t fully recall what I wrote and don’t want to go back through everything I wrote in this old post, but I’d recommend reading it.

http://www.charlespetzold.com/code/

That’s exactly what this delightful book is for.

I think another important idea when learning how computers work is the way in which things are built on top of the next. Essentially what you do is once a certain layer is working you can sort of forget about it. Software is simply too big these days to do in machine language. We are at the point now to where the time to code is more important than time to execute. You could write a modern OS in assembly language, but it’d take forever and a day to do. The time it takes to develop and maintain things is most important now rather than machine speed. In the end, from an economical standpoint, which is cheaper? Hiring a programmer to waste all of those man-hours that would end up saving very few once it is implemented?

So you end up with varying levels. When you produce a post on the internet, you’re relying on a program, probably written in a high-level language that interacts with the operating system, which relies on various architecture features such as instruction sets. Programs don’t interact with the hardware at all anymore. This is all done by the OS which does it on the program’s behalf. This is slower, but it’s far easier to let the OS people build a single interface and let everyone plug in their pieces.

Hardware manufacturers make drivers that interface with hardware which eventually has a known, and pretty standard interface with the OS. Software interacts in a similar way with a standardized set of instructions (like the windows API). Otherwise, Firefox would need to interact with your soundcard to play a sound file. The old DOS games did just this as you’d have to select your soundcard to play. I’m pretty sure this is what DirextX was all about.

The OS does all of the interacting with the processor for these systems. They were designed by people who probably never will write operating systems. Now there is some help coming down from below too. Processors do include features to make the OS designer’s job a bit easier. There is, for example, a cache designed exclusively to hold a virtual memory page table. It’s a lot faster than going to memory for it.

Anyway, I know very little about OS design, yet I can still write a program in C++ that allows me to add something. And then later on, someone might rely on my code to do something they need to. Maybe it’d be more efficient if they would write everything they needed from scratch to really optimize what they needed. But if my program is already there they just use it like they would any other pre-existing resource. You don’t need to know how to do everything below you in order to provide a base for people above you. Maybe sometime in the future someone would use his program that used mine and so on.

You can make or find tools that do the dirty work for you and once they’re complete you don’t need to know about it anymore. It’s less efficient to go through all of these layers but it is efficient in terms of human comprehension. The history of computers has followed this model. As time has gone by, we’ve progressively built and built up everything to the point it’s at today.

Originally computers had to be fed in binary punch-cards. As mentioned previously, “machine language” is simply just a way to translate processor instrucitons into something more readable. From there people built more abstract languages which allowed them to build more complex operating systems.