I've written a tiny program or two using nothing but a hex editor... And while for the most part entering machine code directly as numbers rather than using assembly isn't THAT much of a headache, jump instructions (especially relative jumps) are extremely painful to handle manually. You can see why they wanted to move away from that in the early days. XD
It used to be that machine time was more expensive than programmer time, when that flipped, it finally made sense to have the machine do more of the grunt work.
my first pc had real copper memory it weighed about 40 pounds and blasted heat out when you used it. we gave it to a family friend it was worth about 11 dollars then it prolly has a modern scrap value of 300 dollars now lol.
copper mesh? I'm fairly certain he explained several videos ago that this was all before such memory. EDSAC's memory was sound waves transmitted through mercury tubes.
I started writing maschine code age 14 on my C-128 in it's build in editor. It would encode and decode mnemonics and while inputting instructions increase the next address based on the length of the opcode and data. I never got my hands on a real assembler on that maschine. But on my 286 that i build from leftover parts i came across TASM. The table driven assembler. It had macros, labels and all the good stuff. It was like it stopped raining and the sun came out :) Oh and it could generate 6502 code. I wrote a simple programmes on the commodore and the pc and transferred my code from the printer port to the user port with a minimalistic hw handshake. While not all in binary, i was quite good at thinking in hexadecimal.... since i never got my hands scientific calculator that would help me with adresses and bit masks and so on. Working on the bare minimum teaches you a lot of stuff... not all, but a lot. Good old times :)
It helps to know the opcodes for instructions to do certain things efficiently. Example: sometimes I used to scroll thru the code/data in hex mode because if someone else wrote the code and embedded data in between code modules and all you had was the executable file you had to do that to find out which bytes were code and which bytes were data. Each time I found what seemed to be the beginning of code then I would switch to mnemonic mode so I could read instructions easily and scroll again etc. repeat as necessary. You have to go thru that process if you want to make mods to the code and/or data. You have to know the code very well so you can make mods which will not result in bugs. For example say you have a game that is so difficult you lose your lives quickly before you can make much progress. Then you need to understand at least part of the code well enough to mod it to prevent the game from subtracting one from your lives *without* causing a bug.
Well, _Ant Attack_ for the Spectrum was hand-assembled by Sandy White. He wrote assembly mnemonics for it on paper, and then simply entered the opcodes by hand. Now, _that’s_ dedication.
Always love Prof. Brailsford, So much information about computing history, a great deal of which still underpins modern computing! Not to knock the other guests, but there always seems to be so much more information and background in his videos.
A real programmer knows his op-codes in hex or octal or in binary. Real programmer are dragged screaming to the asylum. But I still have op-codes popping up (along the irregular Latin verbs and the orders of Insecta/Hexapoda).
This reminds me of earlier (before ARM) and later days (after EDSAC) in the 1980s. We had a Research Machines 380Z at school... which had a "front panel" in ROM that let you enter machine code in hex (things had moved on a little from Von Neuman's Binary) which meant we had all those lovely Z80 registers but we had to hand assemble everything in exercise books fist (it's just dawned on me, I'm sad, I can no longer remember the opcode for LDIR)... Then the physics department got hold of a BBC Micro and we had to learn to cope with having "no" registers... but being able to type in assembly language and never have to calculate an offset again.... ahhh, bliss!
Funny how the binary vs assembly argument hasn't gone away, it's just evolved. We used to have arguments about whether to use C++ instead of C. We still have arguments about whether to utilize multi-threading. x86_64 vs i386 was a tough few years. Loading data from configuration files instead of compiling it into the program, the use of scripting languages, or the use of higher-level apps like Unity or Matlab to generate code for us are all still vigorusly argued.
Those aren't really the same arguments. The problem with using multithreading is taht it comes with a very real overhead at runtime and has a lot of potential to break stuff. It can be very useful but should be avoided when tangible because of the added complexity. Also I haven't heared anyone arguing against scripting languages in general possibly ever. It all depends on the usecase. And compiling data into the program is just bad practice unless you are on some microcontroller or something where every byte matters.
Great to see you go over the von Neumann story. Now we just need someone to discuss _The Story of Mel, A Real Programmer_ ... hopefully Prof. Brailsford, as he covers these early tales so vividly, though I don't know if he is personally familiar with that particular case or not.
Curtis Jones I used MS Debug quite a lot (both as a learning and testing tool). It works perfectly well for small programs, though I ended up 'padding' to fill in for labels. Removing the padding was an optional 2nd step, which made the executable more compact, though modifying all the jumps was tedious.
Being of the same generation, I'm surprised that you didn't mention the revolution that the IBM360 assembler introduced. It was a world of difference to the 7044, 1401 (and dare I say it the CDC6000 with it's implicit registers). Even in the early 70's I had a job as an Applications Assembler programmer (writing a Macro library for PL/1 data structures to allow assembler programmers to interface to PL/1 programs). Great credit for the IBM assembler also goes to the IBM user group SHARE which lobbied for the inclusion of many features to make the language useable and supportable by ordinary people not just genii.
I learned an 'Assembler' language on a Cromemco Z2D back in the early eighties. I don't have clue 1 now. Can also remember learning Basic (not Q basic or anything like that but BASIC) I remember using it to run a temperature maintenance program, using PEEK and POKE instructions
I wish I had someone like professor Brailsford teach me the x86 assembly language we had in school. We had such an awful teacher that to this day I'm totally dumb when it comes to x86 assembler :D Next year we had C with the same prof, and if wouldn't have learned PHP in the summer break, I would have had serious problems with C as well...
My university used a 808x emulator on SunOS to teach assembly. Having written x86 assembly since 13 years old, I thought "peace of cake I'll show my prof (Tanenbaum) who's daddy". But my implementation of the first exercise PANICt the machine every-time whilst running fine on real x86 hw; turned out I found a bug in the emulator on my first try :)
It's all assuming your computer has a character rom, or in modern terms, a font to print those character codes to a bitmap on the screen. When you don't have that, you'd also have to map character codes to character bitmaps, and convert them to the signal necessary for the screen output , which is not that uncommon for a lot of systems, and what's essentially going on all computers at a certain level, worked on and made by people, right now and today. Most programmers don't care, don't want to know, and mostly hate those details. Actually today there's even a lot more going on given the variety and complexity of different typefaces. They are typically vector data that describe how the glyphs look in terms of points, lines and curves. You need to somehow convert them to "rasterize" them, and handle things like scaling (i.e. zooming, which has all its own problems to solve). Given today's programmable GPUs, you'd have to "somehow" read that typeface data, cache that properly, either render into a bitmap texture, or render as vectors on the fly by the GPU, depending on your requirements of fidelity with different performance and complexity costs. And hook things all the way from the GPU to the application interface where you don't care how all these are handled. So "Hello, world!" is still a huge lot of work in today's computers unlike the minimalitsic EDSAC or home micro computers of the 80s.
It's a wonderful view into the past: to before high-level programming languages, back to when computers were designed and built to perform computation and assist in solving math problems, not do anything as pedestrian as "interact" with the user.
My first introduction to assembly was on the Commodore 64. I loved 6510 Assembly, it was so easy and fun to use. I have looked into programming assembly on Windows and it actually doesn't look that bad. I've never been a "high level language" type of person. I still code in C to this day (which is not considered a high level language these days). It's amazing the size difference when you code in assembly, your programs are so much smaller and more efficient.
Most assembly programs might look smaller in size, but when run on modern machines they are terribly inefficent compared to stuff that the LLVM can put out. I doubt you do loop unrolling, dead branch removal, loop fission, smart subroutine inlining and any other crazy machine code optimization that don't map at all to how a human would reason about a program, even when writing assembly. Well except if the program are all the size of an Hello World program, in that case the missing runtime loading might make it faster. In fact, most of the "transparent abstraction" that CPU vendors slap on your modern cpu to pretend that they are still x86 machine deriving from the PDP-11 architecture are not transparent at all and lead to hardware bugs, worst cost, impared performance and wasted silicon of the CPUs; just to pretend that a modern CPU can be reasoned like any old machine from the 80s and 90s and that C and assembly are still adequate representatation of the low level hardware while they are just representing all the advanced microcode machinery that is hiding the out-of-order, multi registry, multicore machine hidden within so we can avoid recompiling our code.
The 6502 family (which includes the 6510) was a highly-respected chip in its day. And the Commodore 64 was a pretty respectable machine, at least in the early 1980s, too.
and it is found in many industrial type controllers that are still in use today - in fact, you can still buy brand new 6502-chips manufactured by WDC. So it is in fact a very respected chip even today. Not bad for a 40+ year old design!
Actually, you can make a simple one-pass assembler that will allow relocation. All you need is for the assembler to output the relevant relocation information at the end of the code and then have the ability to read the result in reverse order when loading the program into memory. With paper tape, and two tapes, this quite is doable. First tape contains the loader. Once loaded, insert the tape with your program but backwards. The loader reads the tape, discovers the relocation information, and proceeds to load the program into memory while simultaneously patching the addresses using the relocation information.
12:43 The answer is stored in a set of flag bits known as the “condition codes”. Conditional instructions can change their behaviour depending on the settings of these flags.
17:30 I remember dreaming in FORTRAN 66. I'd go in to work and code like crazy for a couple hours and pretty much be spent for the day. My best work was done when I was sleeping. Of course I had to stay to collect pay, so I used the rest of the day to put together test data and write documentation. There was a corporate mandate that all code had to be written in FORTRAN. Structured programming was just being introduced, and required a considerable paradigm shift. Some gentlemen from Reed College brought in a copy of Ratfor. Von Neumann would be rolling in his grave using a preprocessor to generate labels and keep things tidy. There was actually resistance from management regarding using it! After significant productivity gains were demonstrated, they finally recanted and begrudgingly allowed rat4 code into the source library.
@11:13 he says about the byte address of H and how it may as well be 0 because of "it being the first thing that happens in the program". Now, I am not an ARM Assembly language programmer, the last time I touched Assembly was for the Atari STFM computer, a 16-bit machine. But I am sure the branch command he has put in at the start is actually the first thing that happens and it uses some bytes, so the H can never be at program address 0.
I find myself more and more curious about earlier iterations of software etc... Basically have a general understanding of things but being trained in electronics makes me feel like there is a "missing link" to my understanding of computing. Obviously most of it goes right over my head but other times something will stick and I will have an ah ha moment.
Real programmers use a Turing machine! XD Seriously tho microprocessors are essentially sophisticated Turing machines. If a microprocessor was designed to be absolutely as minimalist as possible then that would be a pure Turing machine. People write virtual Turing machines but it would be cool if someone made a simple hardware Turing computer, wrote an assembler, disassembler, and editor for it. I'm not a hardware expert but I suppose with current technology a tiny simple Turing MPU could be clocked much faster than a normal microprocessor.
Every CS course should include a semester of Assembler. Preferable an 8 bit machine with no more than 16K of memory. Too many folks coming into the workforce have place no value on efficiency in either processor speed or memory used. Both are a lot less expensive now than when I started programming in 1969 - but resources are still finite.
@@IkarusKommt Pointers are both quite easy and very powerful to the experienced assembler programmer. The only real limitation would be with the processor.
@@IkarusKommt without manually interacting with assembly I think it's a lot harder to internalize the stack and heap, and also to understand issues of float precision, underflows overflows etc
I started with machine code on my altair in the late 70's, assembling by hand and inputing on the front panel switches in hex. Later moved to an assembler for the 8080. Eventually switched to CP/M on a Z80 processor and modified the bios to access 8 inch high density floppy disks. When everyone else switched to DOS, I lost interest in assmbler and started learning 'C'.
My first assembler was from a magazine. Had to enter it manually as PAGES of comma delimited DATA statements. After the agony of that, learning assembly language was relatively easy.
Why didn't you re-use existing characters? There's no reason to store 3 L's or 2 O's at different addresses, you could have used O18@ O18@ for the LL combination, for instance.
There is a critique somewhere by Martin Richards written after his experience porting BCPL to the PDP-11. He was pretty scathing of its byte-addressability. BCPL originated before the era of byte-addressability, and did not seem to adapt well to that.
Yes, I've never used BCPL but my understanding is that it's solidly "Word based" . If you listen to the first few minutes of Brian Kernighan's "C programming language" video for "Computerphile" he tells the story of the BCPL -> B -> C transitions and how Dennis Ritchie realised, in creating C ,that hardware-supported entities of varying lengths (e.g. char, short, int) needed also to be properly supported in any new system implementation language. And, yes, it was the PDP11 architecture that brought these issues into sharp focus.
You could make a video about undefined behavior, how it makes C portable and which optimizations it allows (like "I have dereferenced a pointer, the if-branch after the dereference, which tests against null, can be eliminated..."). And even to introduce intended undefined behavior, to optimize the code, like `if(x > 42) 1/0;`/ `if(x > 42) __builtin_unreachable();`. This is like telling the compiler, assume that this condition is never true, so ignore this cases.
I don't think "Hello, World!" shows that you've _mastered_ a language, rather it's a single step up from the most minimal program possible. the most minimal program would execute and immediately end. "Hello, World!" executes, _prints a single message_ , and then exits, so that it at least does 1 tiny thing more than nothing.
I was going to say essentially the same thing. Generally, "Hello, World!" is at the other end of the learning process. It shows that you you know how to turn a program in some language into an executable. Until you can do that, you cannot begin to master a computer program language.
The Sun? No, real men just train their own internal body clocks to nanosecond precision. Because then you can still tell the time, even as you're doing all your manly coal mining down the pit and such.
"Considered harmful" is a bit of a meme within computer science academia, starting with Edsger Dijkstra's letter called "Go To Statement Considered Harmful". A counterargument was provided in a later letter with the title "'GOTO Considered Harmful' Considered Harmful", and two months later the conversation resulted in the article "'"GOTO Considered Harmful" Considered Harmful' Considered Harmful?". Dijkstra, not impressed by memery, responded with an article called "On a Somewhat Disappointing Correspondence", but the "considered harmful" meme lives on critical articles and papers in the field.
"Hello World!" is nothing to do with _mastery._ It's the canonical _introductory_ program. It's the first thing you write as you're trying to get your head around a new language. You use it because it's simple and its output makes it obvious when you've got it right. "Okay, got 'Hello World!' working, now to try something slightly harder..."
I'd like to see him code efficiently with the Intel extended instruction set on a modern 64-bit CPU while "keeping it all in his head" because "real programmers use assembler".
have to say, i feel the same towards variables as jon did to absolute addresses i.e. you should know your own variables without ide's to tell you what you declared and don't write monolithic functions
Compare that to a modern language like Python3 where a hello world program is just def generateFunction(functionImputs,functionOutputs): def generatedFunction(*functionImputs): return functionOutputs return generatedFunction def generateGetFunction(propertyToGetAsString): def generatedFunction(item): return item.__dict__[propertyToGetAsString] return generatedFunction def generateCombineFunction(metaFunction,parameters): def generatedFunction(self): return metaFunction(self).apply(*parameters)(self) return generatedFunction class FunctionApplier: def apply(self,function,*parameterArray,**parameterDict): return function(*parameterArray,**parameterDict) functionApplier=FunctionApplier() class CodeFunctionFactory: def __init__(self,functionApplier,**codeFunctionDict): self.functionApplier=functionApplier getFunctionApplier=self.functionApplier.apply(generateFunction,[self],functionApplier) codeFunctionDict["getFunctionApplier"]=getFunctionApplier class CodeFunction: for codeFunction in codeFunctionDict: locals()[codeFunction]=codeFunctionDict[codeFunction] self.CodeFunction=CodeFunction locals()["getCodeFunction"]=generateCombineFunction(generateGetFunction("functionApplier"),[generateGetFunction,"CodeFunction"]) def codeFunction__init__(self,functionsDict): self.functionsDict=functionsDict def codeFunctionRun(self,functionKey,parameterArray,parameterDict): return self.getFunctionApplier().apply(self.functionsDict[functionKey],*parameterArray,**parameterDict) codeFunctionFactoryInstance=functionApplier.apply(CodeFunctionFactory,functionApplier,__init__=codeFunction__init__,codeFunctionRun=codeFunctionRun) codeFunctionClass=functionApplier.apply(codeFunctionFactoryInstance.getCodeFunction) def generateFunctionsFromFunction(self,functionKey,function,parameter): def generatedFunction(*otherParameters,**namedParameters): return function(parameter,*otherParameters,**namedParameters) self.functionsDict[functionKey]=generatedFunction codeFunctionInstance=functionApplier.apply(codeFunctionClass,{"generateFunctionsFromFunction":generateFunctionsFromFunction}) functionApplier.apply(codeFunctionInstance.codeFunctionRun,"generateFunctionsFromFunction",[codeFunctionInstance,"message printer",print,"Hello World!"],{}) functionApplier.apply(codeFunctionInstance.codeFunctionRun,"message printer",[],{})
Instead of repeating the same "output character" instruction over and over again, could you write a loop that worked by literally altering the actual instructions in the program itself? So you have just one "output character" instruction, with the address of the letter H in it; but each time around the loop, you increase the number in that location; which will increase the address from which the character to be output is read? The program trashes itself as it runs, so you probably would have to start by putting the address of the H in the instruction at the beginning, before you started. (You could do it at the end, but this relies on the program running correctly that far.) Obviously you have to know the addresses of the instruction you are altering and where the text is being kept, and this would never work on a system with only ROM .....
You certainly can! It's called self-modifying code and it's a very common trick on the z80 and 6502. Oh, and even if your code is in ROM you can just copy it to RAM and mod it there instead.
So if you manually typed in bytes in a hex editor, you could write machine code, but you had to keep track of memory location, since you don't have labels in machine code? I'm guessing labels in assembly are basicly static or relative memory variables, to where the location in your program it need to go.
Correct. In fact I think there's a video on YT somewhere, where someone uses Paint to put pixels of various colors into a block, and then saves it as a raw binary file, and executes it. And it prints some message or something. Basically it was just a fancy way of writing raw data into a file, which could then be executed. Completely useless, but an interesting exercise!
Labels in assembly aren't variables, in that they can vary during execution, but rather addresses which are filled in after the rest of the code has been translated to machine code. The assembler turns the assembly code into machine code but leaves the addresses which are addressed by labels blank (something like "jump to [fill address here]" but in machine code, so "0x4C 0x00 0x00" in 6502 instructions), then passes over the code a second time and writes these addresses into the blanks. The assembler knows now where all addresses are and where they are mentioned, and can fill in "jump to 0x1337" (0x4C 0x37 0x13 for the 6502 instruction set). The end result is exactly the same as if you manually kept track of all these addresses, minus the bugs that happen when you forget to update one address after changing "hello world" to "hello, world!" or something similar.
Maybe variables was the wrong word of choice, but I can tell it seems I was half right and half wrong. I was actually thinking of labels as memory addresses to where the next execution should jump to as virtual / relative address delivered by the OS or static address if you work in real x86 mode.
Professor Brailsford is one of my favorite persons on computerphile!
Same here, he does a great job of explaining things and making it interesting
On YT
Agreed. Knowledgeable, yet easy to understand. Wish I'd had him at my University when I was studying Computer Science.
He's the reason I subbed.
My two favorite professors are both at Notttingham. Brailsford, and Poliakoff from Periodic Videos
I've written a tiny program or two using nothing but a hex editor...
And while for the most part entering machine code directly as numbers rather than using assembly isn't THAT much of a headache, jump instructions (especially relative jumps) are extremely painful to handle manually.
You can see why they wanted to move away from that in the early days. XD
It used to be that machine time was more expensive than programmer time, when that flipped, it finally made sense to have the machine do more of the grunt work.
Real programmers wire grids of relays and account for overall conductor path lengths.
I programmed like that on IBM unit record equipment (407s and such
@@rty1955 I've heard you're very popular with the ladies. What an absolute chad.
@@VivekYadav-ds8oz and I heard your very popular with men
What??? Real programmers tie knots at different lengths of strings and account for overall weights, like Hero of Alexandria apparently did
Professor Brailsford should have his own channel really.
It's so interesting to hear him talk about all of this
He has his own account for replying to comments, he should start uploading.
At least you didn't have to manually weave the memory together out of copper mesh.
I used to have a TRS-80 model 1 with homemade memory which was wire-wrapped around these poles (not made by me). So it was done. ;)
my first pc had real copper memory it weighed about 40 pounds and blasted heat out when you used it. we gave it to a family friend it was worth about 11 dollars then it prolly has a modern scrap value of 300 dollars now lol.
copper mesh? I'm fairly certain he explained several videos ago that this was all before such memory. EDSAC's memory was sound waves transmitted through mercury tubes.
You people had magnetic core memory with late 70's early 80's microcomputers?
... That sounds like a disaster waiting to happen. XD
it had deskmate disk mod and could run a dot matrix printer very swanky.
I started writing maschine code age 14 on my C-128 in it's build in editor. It would encode and decode mnemonics and while inputting instructions increase the next address based on the length of the opcode and data. I never got my hands on a real assembler on that maschine. But on my 286 that i build from leftover parts i came across TASM. The table driven assembler.
It had macros, labels and all the good stuff. It was like it stopped raining and the sun came out :)
Oh and it could generate 6502 code. I wrote a simple programmes on the commodore and the pc and transferred my code from the printer port to the user port with a minimalistic hw handshake.
While not all in binary, i was quite good at thinking in hexadecimal.... since i never got my hands scientific calculator that would help me with adresses and bit masks and so on.
Working on the bare minimum teaches you a lot of stuff... not all, but a lot.
Good old times :)
Impressive...
John von Neumann: the gatekeeper to end all gatekeepers
nah, just a badass
Storing the "L" and "O" twice ... what a waste of precious memory space !
Hadrien Croubois that annoyed me as well. Storing L three times ...
..add pointer to the L & O address..now it will print " Hello World..with all it's glory & splendor"
This is the best guy on Computerphile - keep him talking forever
It helps to know the opcodes for instructions to do certain things efficiently.
Example: sometimes I used to scroll thru the code/data in hex mode because if someone else wrote the code and embedded data in between code modules and all you had was the executable file you had to do that to find out which bytes were code and which bytes were data. Each time I found what seemed to be the beginning of code then I would switch to mnemonic mode so I could read instructions easily and scroll again etc. repeat as necessary. You have to go thru that process if you want to make mods to the code and/or data. You have to know the code very well so you can make mods which will not result in bugs. For example say you have a game that is so difficult you lose your lives quickly before you can make much progress. Then you need to understand at least part of the code well enough to mod it to prevent the game from subtracting one from your lives *without* causing a bug.
Well, _Ant Attack_ for the Spectrum was hand-assembled by Sandy White. He wrote assembly mnemonics for it on paper, and then simply entered the opcodes by hand. Now, _that’s_ dedication.
Always love Prof. Brailsford, So much information about computing history, a great deal of which still underpins modern computing!
Not to knock the other guests, but there always seems to be so much more information and background in his videos.
I absolutely love this dude. He explains it so clearly and it's simply a delight to listen to!
There is no other person on this planet who can give me more enthusiasm for programming than Professor Brailsford. Thank you.
I wonder what von Neumann's reaction would be when confronted with a bunch of python code.
"Why are you presenting me english? Get that out of here useless person."
mi ez a pitonos hülyeség? az agyadat rettenetes angol komédiaprogramok figyelemmel kísérte.
I wonder what he'd have said about COBOL.
Man you want to kill him again?
Don't even bring up COBOL -.-
The history of computer science is amazing and amusing. Hearing about it from the prof is mesmerizing. Thank you, professor.
💯agree.
A real programmer knows his op-codes in hex or octal or in binary.
Real programmer are dragged screaming to the asylum.
But I still have op-codes popping up (along the irregular Latin verbs and the orders of Insecta/Hexapoda).
This reminds me of earlier (before ARM) and later days (after EDSAC) in the 1980s.
We had a Research Machines 380Z at school... which had a "front panel" in ROM that let you enter machine code in hex (things had moved on a little from Von Neuman's Binary) which meant we had all those lovely Z80 registers but we had to hand assemble everything in exercise books fist (it's just dawned on me, I'm sad, I can no longer remember the opcode for LDIR)... Then the physics department got hold of a BBC Micro and we had to learn to cope with having "no" registers... but being able to type in assembly language and never have to calculate an offset again.... ahhh, bliss!
Some would say that the 6502 in the Beeb had 256 semi-registers in page 0.
Software guy: Hello World!
Hardware guy: Blink!
:o)
RoGeorgeRoGeorge exactly!
RoGeorgeRoGeorge and Data Analysts ?
They just wait for more data to be input.
Shellcode: calculator
HDL guy: Flipflop
John Von Neumann was a gift from Another Universe that crossed timelines and blessed us with his genius
Funny how the binary vs assembly argument hasn't gone away, it's just evolved. We used to have arguments about whether to use C++ instead of C. We still have arguments about whether to utilize multi-threading. x86_64 vs i386 was a tough few years. Loading data from configuration files instead of compiling it into the program, the use of scripting languages, or the use of higher-level apps like Unity or Matlab to generate code for us are all still vigorusly argued.
Those aren't really the same arguments. The problem with using multithreading is taht it comes with a very real overhead at runtime and has a lot of potential to break stuff. It can be very useful but should be avoided when tangible because of the added complexity. Also I haven't heared anyone arguing against scripting languages in general possibly ever. It all depends on the usecase. And compiling data into the program is just bad practice unless you are on some microcontroller or something where every byte matters.
Great to see you go over the von Neumann story. Now we just need someone to discuss _The Story of Mel, A Real Programmer_ ... hopefully Prof. Brailsford, as he covers these early tales so vividly, though I don't know if he is personally familiar with that particular case or not.
While I'm a bit younger , the very first assembly I did was using MS debug. I can definitely attest that labels help.
Curtis Jones I used MS Debug quite a lot (both as a learning and testing tool). It works perfectly well for small programs, though I ended up 'padding' to fill in for labels. Removing the padding was an optional 2nd step, which made the executable more compact, though modifying all the jumps was tedious.
I love professor David Brailsford so much
Being of the same generation, I'm surprised that you didn't mention the revolution that the IBM360 assembler introduced. It was a world of difference to the 7044, 1401 (and dare I say it the CDC6000 with it's implicit registers). Even in the early 70's I had a job as an Applications Assembler programmer (writing a Macro library for PL/1 data structures to allow assembler programmers to interface to PL/1 programs). Great credit for the IBM assembler also goes to the IBM user group SHARE which lobbied for the inclusion of many features to make the language useable and supportable by ordinary people not just genii.
I learned an 'Assembler' language on a Cromemco Z2D back in the early eighties. I don't have clue 1 now.
Can also remember learning Basic (not Q basic or anything like that but BASIC) I remember using it to run a temperature maintenance program, using PEEK and POKE instructions
I wish I had someone like professor Brailsford teach me the x86 assembly language we had in school. We had such an awful teacher that to this day I'm totally dumb when it comes to x86 assembler :D Next year we had C with the same prof, and if wouldn't have learned PHP in the summer break, I would have had serious problems with C as well...
My university used a 808x emulator on SunOS to teach assembly. Having written x86 assembly since 13 years old, I thought "peace of cake I'll show my prof (Tanenbaum) who's daddy". But my implementation of the first exercise PANICt the machine every-time whilst running fine on real x86 hw; turned out I found a bug in the emulator on my first try :)
It's all assuming your computer has a character rom, or in modern terms, a font to print those character codes to a bitmap on the screen. When you don't have that, you'd also have to map character codes to character bitmaps, and convert them to the signal necessary for the screen output , which is not that uncommon for a lot of systems, and what's essentially going on all computers at a certain level, worked on and made by people, right now and today. Most programmers don't care, don't want to know, and mostly hate those details. Actually today there's even a lot more going on given the variety and complexity of different typefaces. They are typically vector data that describe how the glyphs look in terms of points, lines and curves. You need to somehow convert them to "rasterize" them, and handle things like scaling (i.e. zooming, which has all its own problems to solve). Given today's programmable GPUs, you'd have to "somehow" read that typeface data, cache that properly, either render into a bitmap texture, or render as vectors on the fly by the GPU, depending on your requirements of fidelity with different performance and complexity costs. And hook things all the way from the GPU to the application interface where you don't care how all these are handled. So "Hello, world!" is still a huge lot of work in today's computers unlike the minimalitsic EDSAC or home micro computers of the 80s.
It's a wonderful view into the past: to before high-level programming languages, back to when computers were designed and built to perform computation and assist in solving math problems, not do anything as pedestrian as "interact" with the user.
My first introduction to assembly was on the Commodore 64. I loved 6510 Assembly, it was so easy and fun to use. I have looked into programming assembly on Windows and it actually doesn't look that bad. I've never been a "high level language" type of person. I still code in C to this day (which is not considered a high level language these days). It's amazing the size difference when you code in assembly, your programs are so much smaller and more efficient.
Your programs may be smaller, but they are also way more difficult to read than properly written C code :)
on the contrary: if you write a code C then it is more difficult to read in asm (like in Reverse Engineering) :P
Most assembly programs might look smaller in size, but when run on modern machines they are terribly inefficent compared to stuff that the LLVM can put out. I doubt you do loop unrolling, dead branch removal, loop fission, smart subroutine inlining and any other crazy machine code optimization that don't map at all to how a human would reason about a program, even when writing assembly. Well except if the program are all the size of an Hello World program, in that case the missing runtime loading might make it faster. In fact, most of the "transparent abstraction" that CPU vendors slap on your modern cpu to pretend that they are still x86 machine deriving from the PDP-11 architecture are not transparent at all and lead to hardware bugs, worst cost, impared performance and wasted silicon of the CPUs; just to pretend that a modern CPU can be reasoned like any old machine from the 80s and 90s and that C and assembly are still adequate representatation of the low level hardware while they are just representing all the advanced microcode machinery that is hiding the out-of-order, multi registry, multicore machine hidden within so we can avoid recompiling our code.
The 6502 family (which includes the 6510) was a highly-respected chip in its day. And the Commodore 64 was a pretty respectable machine, at least in the early 1980s, too.
and it is found in many industrial type controllers that are still in use today - in fact, you can still buy brand new 6502-chips manufactured by WDC. So it is in fact a very respected chip even today. Not bad for a 40+ year old design!
Your voice is relaxing.
I keep coming back to this video, and each time, I jump towards the like button. Too bad you can't like a video twice.
Fascinating! Standing on the shoulders of giants!
6:34 reference to JVNeumann... wow!! "The Computer and the Brain" still so pertinent today!
Actually, you can make a simple one-pass assembler that will allow relocation. All you need is for the assembler to output the relevant relocation information at the end of the code and then have the ability to read the result in reverse order when loading the program into memory.
With paper tape, and two tapes, this quite is doable. First tape contains the loader. Once loaded, insert the tape with your program but backwards. The loader reads the tape, discovers the relocation information, and proceeds to load the program into memory while simultaneously patching the addresses using the relocation information.
Professor Brailsford has so many beautiful stories
12:43 The answer is stored in a set of flag bits known as the “condition codes”. Conditional instructions can change their behaviour depending on the settings of these flags.
10 Print "Hello World"
was the standard BASIC starting point even in the 60's.
Fascinating video and world changing idea, the assembler, thanks!
Coming from this time, I remember how hard it was to use 16 bit registers of the extremely modern Z80 CPU in order to access memory on tape. 😄
The Z80 was an 8 bit processor
Yes but it had 16 bit registers and could do limited 16-bit work
17:30 I remember dreaming in FORTRAN 66. I'd go in to work and code like crazy for a couple hours and pretty much be spent for the day. My best work was done when I was sleeping. Of course I had to stay to collect pay, so I used the rest of the day to put together test data and write documentation.
There was a corporate mandate that all code had to be written in FORTRAN. Structured programming was just being introduced, and required a considerable paradigm shift. Some gentlemen from Reed College brought in a copy of Ratfor. Von Neumann would be rolling in his grave using a preprocessor to generate labels and keep things tidy. There was actually resistance from management regarding using it! After significant productivity gains were demonstrated, they finally recanted and begrudgingly allowed rat4 code into the source library.
I tried to learn Assembler in the 80/90s. Fortran too. What sorcerer was that? Just insane! pURE INsanitY!
Most people print out "Hello World." Not me. I print out, "Hello, is it me you're looking for?"
and in Assembly Language it took You "All Night long"
Often we forget how far development of computer goes, amazing.
4:09 Ah, the joys of Baudot code ...
Baudot gave his name to the unit “baud” ... which is another term you don’t hear used much any more ...
@2:24 use of a primitive pointer.
I see what you did there
@11:13 he says about the byte address of H and how it may as well be 0 because of "it being the first thing that happens in the program". Now, I am not an ARM Assembly language programmer, the last time I touched Assembly was for the Atari STFM computer, a 16-bit machine. But I am sure the branch command he has put in at the start is actually the first thing that happens and it uses some bytes, so the H can never be at program address 0.
Yes, you're right. Many apologies - slipped up there
It's so worth watching until the end.
I find myself more and more curious about earlier iterations of software etc...
Basically have a general understanding of things but being trained in electronics makes me feel like there is a "missing link" to my understanding of computing.
Obviously most of it goes right over my head but other times something will stick and I will have an ah ha moment.
Real programmers use a Turing machine! XD Seriously tho microprocessors are essentially sophisticated Turing machines. If a microprocessor was designed to be absolutely as minimalist as possible then that would be a pure Turing machine. People write virtual Turing machines but it would be cool if someone made a simple hardware Turing computer, wrote an assembler, disassembler, and editor for it. I'm not a hardware expert but I suppose with current technology a tiny simple Turing MPU could be clocked much faster than a normal microprocessor.
Every CS course should include a semester of Assembler. Preferable an 8 bit machine with no more than 16K of memory. Too many folks coming into the workforce have place no value on efficiency in either processor speed or memory used. Both are a lot less expensive now than when I started programming in 1969 - but resources are still finite.
Why? The only topic that is easier to explain in Assembly is pointers - but you cannot do anything interesting with them due to asm's primitiveness.
@@IkarusKommt Pointers are both quite easy and very powerful to the experienced assembler programmer. The only real limitation would be with the processor.
@@IkarusKommt without manually interacting with assembly I think it's a lot harder to internalize the stack and heap, and also to understand issues of float precision, underflows overflows etc
You could maybe have omitted the "B main" or explained what branch main does, that it basically means "start executing things here".
I love him. Reminds me of my late programmer friend.
This bloke is the David Attenborough of programming
Man that was a great video!! I learn so much cool stuff here, thanks!!
Kind of curious about KoMoDo now, can we see a video on it?
16:47: There's a Wikipedia article on the JOHNNIAC, and the RAND Corporation has a PDF online titled The History of the JOHNNIAC.
I started with machine code on my altair in the late 70's, assembling by hand and inputing on the front panel switches in hex. Later moved to an assembler for the 8080. Eventually switched to CP/M on a Z80 processor and modified the bios to access 8 inch high density floppy disks. When everyone else switched to DOS, I lost interest in assmbler and started learning 'C'.
As xkcd so boldly stated: Real programmers use a magnetized needle and a steady hand.
My first assembler was from a magazine. Had to enter it manually as PAGES of comma delimited DATA statements. After the agony of that, learning assembly language was relatively easy.
Real programmers don't need computers. They just write the program and simulate the computer in their head.
Why didn't you re-use existing characters? There's no reason to store 3 L's or 2 O's at different addresses, you could have used O18@
O18@
for the LL combination, for instance.
How much does he sound like David Attenborough
martin seal Professor Brailsford: the David Attenborough of Computer Science :D
They both have an educated British accent.
There is a critique somewhere by Martin Richards written after his experience porting BCPL to the PDP-11. He was pretty scathing of its byte-addressability. BCPL originated before the era of byte-addressability, and did not seem to adapt well to that.
Yes, I've never used BCPL but my understanding is that it's solidly "Word based" . If you listen to the first few minutes of Brian Kernighan's "C programming language" video for "Computerphile" he tells the story of the
BCPL -> B -> C transitions and how Dennis Ritchie realised, in creating C ,that hardware-supported entities of varying lengths (e.g. char, short, int) needed also to be properly supported in any new system implementation language.
And, yes, it was the PDP11 architecture that brought these issues into sharp focus.
I thought this guy was the host of computerphile, until the actual host started speaking XD
Long life to assembly language!
Did he retire? We only see him in his house. Such a knowledgeable fellow is necessity for students :)
Why is the webcam pointed down? Has someone been naughty? :D
Only a naughty will notice :)
By that logic I'm also a wall, since I notice them too....
You never know, he may make the keyboard-typing ASMR videos I just found.
Now I understand why C works how it works.
6:11 closed captions: i think that would be called sarcasm, not irony
Howdy, planet.
Electric sheeps? Pfft! I dream in BINARY!
-J.V. Neumann
I hope he became less paranoid on assembling everything manually as the computers got better
The ultimate RISC machine!
Von Neumann, the first Techpriest?
Should the carriage return have taken the cursor back to the beginning of the line? Or is that just not displayed?
You could make a video about undefined behavior, how it makes C portable and which optimizations it allows (like "I have dereferenced a pointer, the if-branch after the dereference, which tests against null, can be eliminated..."). And even to introduce intended undefined behavior, to optimize the code, like `if(x > 42) 1/0;`/ `if(x > 42) __builtin_unreachable();`. This is like telling the compiler, assume that this condition is never true, so ignore this cases.
Hey, I demand dot-matrix printer paper! Is this even Computerphile?
No such paper exists. You mean 11 x 17 pinfeed paper?
Wait, is it just me or does TH-cam say this is a Warner Bros video when in full screen mode?
I knew it from the first place hello world is for the high language programming codes only
I don't think "Hello, World!" shows that you've _mastered_ a language, rather it's a single step up from the most minimal program possible. the most minimal program would execute and immediately end. "Hello, World!" executes, _prints a single message_ , and then exits, so that it at least does 1 tiny thing more than nothing.
I was going to say essentially the same thing. Generally, "Hello, World!" is at the other end of the learning process. It shows that you you know how to turn a program in some language into an executable. Until you can do that, you cannot begin to master a computer program language.
True, but if you manage Hello World in absolute binary, at least you've proven you're not weak brained.
I think he meant you show a master programmer how to do hello world to introduce them to a new language
Or maybe it is, that you just lack the sense for sarcasm.
Sahuagin , you missed the sarcasm / British humor there... But it's ok.
EZPF = Easy Print Format. Its not that BUT I'll stick to that cause its WAY cooler
What's next? Is using a clock considered harmful?
MattyFez real men use the sun you weak minded
The Sun?
No, real men just train their own internal body clocks to nanosecond precision.
Because then you can still tell the time, even as you're doing all your manly coal mining down the pit and such.
"Considered harmful" is a bit of a meme within computer science academia, starting with Edsger Dijkstra's letter called "Go To Statement Considered Harmful". A counterargument was provided in a later letter with the title "'GOTO Considered Harmful' Considered Harmful", and two months later the conversation resulted in the article "'"GOTO Considered Harmful" Considered Harmful' Considered Harmful?". Dijkstra, not impressed by memery, responded with an article called "On a Somewhat Disappointing Correspondence", but the "considered harmful" meme lives on critical articles and papers in the field.
"Hello World!" is nothing to do with _mastery._ It's the canonical _introductory_ program.
It's the first thing you write as you're trying to get your head around a new language. You use it because it's simple and its output makes it obvious when you've got it right.
"Okay, got 'Hello World!' working, now to try something slightly harder..."
Clever title, referring I assume to Dijkstra on BASIC? A GOTO by any other name...
Love your monitor ;)
I'd like to see him code efficiently with the Intel extended instruction set on a modern 64-bit CPU while "keeping it all in his head" because "real programmers use assembler".
Do you suppose that if a malevolent super AI is created, that it will utter "Hello, World!" prior to conquering us?
Real programmers use toggle switches :)
I used plugboard wiring, then punch cards
have to say, i feel the same towards variables as jon did to absolute addresses i.e. you should know your own variables without ide's to tell you what you declared and don't write monolithic functions
Compare that to a modern language like Python3 where a hello world program is just
def generateFunction(functionImputs,functionOutputs):
def generatedFunction(*functionImputs):
return functionOutputs
return generatedFunction
def generateGetFunction(propertyToGetAsString):
def generatedFunction(item):
return item.__dict__[propertyToGetAsString]
return generatedFunction
def generateCombineFunction(metaFunction,parameters):
def generatedFunction(self):
return metaFunction(self).apply(*parameters)(self)
return generatedFunction
class FunctionApplier:
def apply(self,function,*parameterArray,**parameterDict):
return function(*parameterArray,**parameterDict)
functionApplier=FunctionApplier()
class CodeFunctionFactory:
def __init__(self,functionApplier,**codeFunctionDict):
self.functionApplier=functionApplier
getFunctionApplier=self.functionApplier.apply(generateFunction,[self],functionApplier)
codeFunctionDict["getFunctionApplier"]=getFunctionApplier
class CodeFunction:
for codeFunction in codeFunctionDict:
locals()[codeFunction]=codeFunctionDict[codeFunction]
self.CodeFunction=CodeFunction
locals()["getCodeFunction"]=generateCombineFunction(generateGetFunction("functionApplier"),[generateGetFunction,"CodeFunction"])
def codeFunction__init__(self,functionsDict):
self.functionsDict=functionsDict
def codeFunctionRun(self,functionKey,parameterArray,parameterDict):
return self.getFunctionApplier().apply(self.functionsDict[functionKey],*parameterArray,**parameterDict)
codeFunctionFactoryInstance=functionApplier.apply(CodeFunctionFactory,functionApplier,__init__=codeFunction__init__,codeFunctionRun=codeFunctionRun)
codeFunctionClass=functionApplier.apply(codeFunctionFactoryInstance.getCodeFunction)
def generateFunctionsFromFunction(self,functionKey,function,parameter):
def generatedFunction(*otherParameters,**namedParameters):
return function(parameter,*otherParameters,**namedParameters)
self.functionsDict[functionKey]=generatedFunction
codeFunctionInstance=functionApplier.apply(codeFunctionClass,{"generateFunctionsFromFunction":generateFunctionsFromFunction})
functionApplier.apply(codeFunctionInstance.codeFunctionRun,"generateFunctionsFromFunction",[codeFunctionInstance,"message printer",print,"Hello World!"],{})
functionApplier.apply(codeFunctionInstance.codeFunctionRun,"message printer",[],{})
Real programmers use a magnetised needle and a steady hand.
as soon as the video starts, just keep hitting the left arrow key.
or zero or 01234000000000
nice
Still out here on Windows XP in 2018
Instead of repeating the same "output character" instruction over and over again, could you write a loop that worked by literally altering the actual instructions in the program itself? So you have just one "output character" instruction, with the address of the letter H in it; but each time around the loop, you increase the number in that location; which will increase the address from which the character to be output is read? The program trashes itself as it runs, so you probably would have to start by putting the address of the H in the instruction at the beginning, before you started. (You could do it at the end, but this relies on the program running correctly that far.)
Obviously you have to know the addresses of the instruction you are altering and where the text is being kept, and this would never work on a system with only ROM .....
You certainly can! It's called self-modifying code and it's a very common trick on the z80 and 6502. Oh, and even if your code is in ROM you can just copy it to RAM and mod it there instead.
When this man talks, you shut up and listen.
Classic stuff, Mr. Von Neumann must not have discovered the demoscene :(
Makes me wonder why you couldn't just put three characters in each word.
What OS is that? You guys make videos about security
So are Assembler messages like the preprocessor?
So if you manually typed in bytes in a hex editor, you could write machine code, but you had to keep track of memory location, since you don't have labels in machine code?
I'm guessing labels in assembly are basicly static or relative memory variables, to where the location in your program it need to go.
Correct. In fact I think there's a video on YT somewhere, where someone uses Paint to put pixels of various colors into a block, and then saves it as a raw binary file, and executes it. And it prints some message or something. Basically it was just a fancy way of writing raw data into a file, which could then be executed. Completely useless, but an interesting exercise!
Labels in assembly aren't variables, in that they can vary during execution, but rather addresses which are filled in after the rest of the code has been translated to machine code. The assembler turns the assembly code into machine code but leaves the addresses which are addressed by labels blank (something like "jump to [fill address here]" but in machine code, so "0x4C 0x00 0x00" in 6502 instructions), then passes over the code a second time and writes these addresses into the blanks. The assembler knows now where all addresses are and where they are mentioned, and can fill in "jump to 0x1337" (0x4C 0x37 0x13 for the 6502 instruction set). The end result is exactly the same as if you manually kept track of all these addresses, minus the bugs that happen when you forget to update one address after changing "hello world" to "hello, world!" or something similar.
Maybe variables was the wrong word of choice, but I can tell it seems I was half right and half wrong. I was actually thinking of labels as memory addresses to where the next execution should jump to as virtual / relative address delivered by the OS or static address if you work in real x86 mode.