Can we just appreciate that this dude truly made a hello world from true scratch in assembly on an ancient processor and documented it in an easy to follow way for all of us to see and learn with?
That's why we're here; we appreciate it. I did do some machine language programming on some of these old processors including the 6502 in one of my college classes. They plugged into these boards that we used to enter opcodes and values into memory and then we could step it forward and examine the values to see what the processor was doing. (I wish I could remember what those boards were called.) Ben definitely takes it another step though.
@@chitlitlah I wish my college had that much. Although we did get some hands on, it was very little and the equipment was not up to the task. Ben's projects are what I had expected computer engineering school to be before facing uncaring reality.
this is going to be a stupid question, but could you code this in c and then use a compiler that's been specifically designed to output 6502 machine code?
@@russianvideovlogguy that’s what most people do. And modern compilers are more efficient than human coders 99.9% of the time (not always true even in the 90s). That’s why hand-coding assembly in this day and age is such a madlad endeavour! Fun fact: when assemblers were first invented, the computer scientists who learned to keep track of all their memory and instruction addresses by hand viewed _assembly_ as the easy-mode cheat for modern hacks, much as present-day C aficionados view Python!
It is the fun of programming, you wrote your code, checked it, and still something is wrong. And you need to find out what, a missed part of syntax, a wrong label or variable name or just your code wrong.
Using an 8bit pointer to create an “automatic” circular buffer was brilliant. I kept waiting for a modulus, but no, you one-upped my expectations. Fantastic as always.
Except that writep = readp when the buffer is empty and when it's full, the way the program is written. Easy fix, just keep track of the buffer length and only write when length is less than 256 and read when it's greater than 0. That is if you want to read then inc and write then inc.
Note, there should be a separate flag for the right and left shifts, because with one flag I could press LSHFT, RSHFT then release RSHFT and it would count as released even though LSHFT is still pressed (and same vise versa)
After following Ben Eater's Videos for several years now, I still don't understand how anyone can "dislike" his videos... for the content that he provides, it is the best that is currently available on the net anywhere... even better than most college or university content that is publicly and freely available... if I could like more than once, I wouldn't hesitate to do so!
I wouldn't be surprised if they were all accidental. Like Václav said, or perhaps some little kid randomly clicking around on UA-cam. Any intentional dislikes are probably just trolls.
The final code still has another bug: pressing both Shift keys at the same time breaks it 😂 When the first is released, letters will go back to lower-case even though you're still pressing the second; and when the second is released, because he's using xor ("eor") to clear the flag, it'll turn shift on permanently until you press and release Shift once again. So... definitely a fallible human 😁
@@nilswegner2881 its still a bug that someone could accidentally activate. when your programming u have to not only think of the correct use case but also the incorrect edge case, it is on the edge case that most bugs exist
@@nilswegner2881 I occasionally do just as I tap keys randomly as I fidget. But when designing software, you should *never* assume your users "would never" do something -- always code to cover all your bases.
Typically, an interrupt service routine (ISR) does the minimum possible to deal with the peripheral, and then it returns, and it's up to some other routines to interpret the retrieved data. One thing to remember is that when an interrupt is processed, interrupts are disabled until either they're explicitly enabled or the return from interrupt instruction is executed. Therefore any other interrupts (from other devices) will be blocked, and possibly missed. So the routine to read the keyboard port would just fill the buffer, and any program/subroutine which reads the buffer would do the handling of modifier keys like shift. In this case, it really doesn't matter, because there isn't another device competing for CPU cycles via interrupts. But for more complex systems this sort of thing should be kept in mind.
May I be the first to congratulate you on accidentally reviving the concept of "Shift-Lock". As you're toggling the flag when shift is released but setting it when pressed, pressing both shift keys together and then releasing them will toggle the shift bit back to on. :) [Edit: Typo correction]
Explain your thought process. humans aren't accurate enough for "same time" conditions, one will always be first or polling would cause one to be first. My thought is you would lose caps holding both, then still have no caps releasing them both. With even boolean operations, it always returns to the default state.
Depending how you implement it, either holding both shift keys gives you lowercase, or holding both and then letting go of one gives you lowercase, or as in the existing implementation holding both and letting go of both gives you uppercase. I consider all three of these to be incorrect behavior.
I found your 8 bit build videos probably a year ago and was glued to the screen in a way I didn’t expect. The final videos on conditional jumps and control word logic felt like the climax in an action flick. I soon discovered an alternative purpose for the videos: highly effective sleep aid. I’m not insinuating your videos are boring. Far from it. Rather the tone and cadence of your voice and and the quiet sound of assembling tiny components on a breadboard knock me right out. It’s like magic. I love these videos when I want to be awake, and I love them when I want to be asleep. Someday I’ll order a kit and see if my kid’s attention spans are as as solid as mine. Perhaps I could even lull them into a nap.
I literally swear i've learn't more information about lower level computing from this channel than I did across my whole compsci degree. Great video as always ben!
@@jgharston Yeah I get that and know the difference... But in my opinion understanding of lower level functionality of a computer helps re-enforce knowledge and understanding within higher level computing. did a little comp enginnering stuff on my degree but it was taught so half assed it was useless. Fun fact: I've regretted since the begining of my second year not choosing a computer engineering degree but was too late by that point.
@@jordy15322 Yeah, me too exactly. I was three years into my CompSci degree and still thinking "when are we going to get to some, y'know *actual* computing?" It was years after that I realised I should have looked for something with "engineering" in the course title. It was only in my very final semester that I put together hardware interfaces for controlling a set of LEDs and a printer, and wrote a PDP11 assembler - both of which I just did a brain-dump of stuff I'd done more than six years previously.
@@jordy15322 I can't speak to now, but depending where one went to school a couple decades back it was practically assured one would get a CE minor pursuing a CS major (and vice versa) at the BS level, and putting in two extra years one could graduate with a BS in each CS, CE and Math
I recently hooked a 6551 up to my bread boarded 6502, been having a blast with the kit and plan to eventually build my own sound card. Thanks for the videos, been using a circular buffer like this for processing serial input and other interrupt-y situations. A nice generally useful technique for working with input, thanks for showcasing it.
@Stephen Anthony I happen to have a SY6551, but the WDC65C51 has well known work arounds, so it isn't a deal breaker just a little less performance at the same clock rate.
Good stuff , but that interrupt routine is doing quite a bit. Usually you want to keep interrupts doing a minimal amount of work so the execution gets back to the main loop. Probably for better performance just capture scan codes in the buffer, and then dispatch a key translation when the main loop reads the next key value. For more advanced projects, you can then have context based key mappings.
You're not complaining, you are pointing out an interesting fact. Thank you for sharing! :) One thing that I was thinking of: When he was implementing the shifted keymap, instead of a branch insn, he could have just set the shift flag to be 0x100 and added it to the keymap's address. In both cases this will do a load from 0xfd00 if the shift flag is 0 and load from 0xff00 if the shift flag is 1, so... yeah... this doesn't make it *better*, per se, but the code would be cuter. I would like to say, though: indirection at the cost of complexity for efficiency ((when you don't need the added efficiency to function)) is bad. I think Ben rightfully and consistently chooses simplicity over performance, and I praise him for it.
@@arisweedler4703 it's arguably better-ish because there's less jumping around... but tracking separate shift states for left and right shift would become impossible with that.
Back in the day, when I was just starting assembly language, I would get anxious, as the number of lines of code kept increasing, that the code I was writing would take an age to execute. After assembling, it usually executed in the blink of an eye. One reason is that much of the code is skipped. When I write "usually", I mean when there are no loops. Loops in an interrupt routine can be a real problem.
@@willofirony Loops in general can be problematic; I remember that when I started looking into some PHP coding, I had a section that would take a very long time to show results, and upon closer inspection I was able to track it down to a couple of nested loops. The solution was to reverse the order of nesting, i.e. the inner loop became the outer one and vice versa. This blew my mind, so to speak.
If you follow along all the videos from the beginning, it shouldn't be too hard. Almost everything he did here was introduced and explained in a previous video.
Having actually (re-)written a keyboard driver / scancode translator I appreciate this. In case anybody is wondering why a different map for upper case, well just look at an actual ASCII table and compare that to the scancode table. He'd need at least another ten minutes to explain the mapping shift, so fodder for later.
I love how he kinda skipped right over needing to replace the quotations with apostrophe's on line 50 of the shifted key matrix. Took me a minute to figure out what was going on. I should have realized something was different right away when my line turned 3 different colors. Absolutely great video! I actually like that it doesn't just work right away every time. I feel like I learn more when I have to troubleshoot crazy problems.
I don't understand how anyone, let alone 16 people could dislike a Ben Eater video. This is better than anything I learned in university when getting my CpE degree. Thank you Ben for all that you do.
I think if you press (and hold) both left shift and right shift, then release them, it will eventually set (not unset) SHIFT flag, because your code will EOR the flag twice.
I love these videos. Working at this level of simplicity in 8bits is extremely satisfying because everything just makes sense on the surface, without need for too many abstractions.
Problem is, he would need some kind of font handler and a graphics driver aswell, which sounds like it would be a pain and a half to program in Assembly.
The sei and cli aren’t actually necessary. kb_ptr is only modified outside of the interrupt handler so it doesn’t need to be in critical section and kb_wptr is read atomically (since it’s a single byte) so the read doesn’t need a critical section either.
Just been following along with your 6502 Computer videos. I can tell that lots of effort goes into these videos, thanks for the great content, and keep up the good work!
I did stuff like this (circular buffers) with a 6800 back in 1979. Thanks for inspiring me to get back into hardware again. I bought your 6502 kits, but it wasn't enough. I upgraded to a 65C816 running at 8Mhz. It now has 1Mb ram and 96K of eeprom and an NHD-0440WH 40 x 4 display. I finally figured out how to get a PCF8584 working so I have I2C to a DS3231 for date/time and more I2C peripherals in the pipeline. I can't seem to get my AM9511A-4 (FPU) working and I'm about to give up and look into alternatives. Thanks again.
OMG, this popped up as possible interest to me and I watched this to the end as it brought back memories to my life in the mid 70s to 80s. I was watching the assembler instructions and surprising to me, I was recognizing all the 6502 instruction set you typed in. Thanks for the memories ...
This is an amazing training session for 6502 assembly! I didn't think I could follow this, but I got it all the way. Thank you! I'm tempted to type up the code so I can learn from the mimicry. This would be like typing the Basic programs from a 1980s magazine.
This video tied it all nicely. As I'm tying this comment out, I'm imagining the little transistors in all of the circuits flipping on and off like crazy. Your videos really make it easier to understand than when I was in school. My teachers were great, but maybe my Interest then wasn't as great as it is now. So, thank you!
Very nice video. Regarding the shift key handling, I do think that handling two keys with only one flag might cause a little glitch: if you press both shift keys, and then release only one of them, software will behave as if you did not hold the latter; it will print non-capitalised letters. It's allways fun trying to find any "errors" in the work presented; however one can only be grateful for this opportunity, thanks to your great work!
I'm switching back and forth between Z80 and 6502, and it always feels like switching between C++ and BASIC. Luckily I love both. (except BASIC, I don't love that)
If there were massive destruction of this earth, this is the only guy who can make computers from scratch! Following you since last 6 years. Huge #respect
This series really reinforces to me how creative and inventive early computer people had to be to make all this work. You take things like the keyboard just plug and play and off you go but never really think about how much is happening behind the scenes just to type some characters. PS. Thank you for making these videos!!
Hi! First of all, "Great Videos", its always nice to remember the basics and the importance of some "minor" details. As for this specific video, I think your ISR is being overloaded. I would suggest a minimal ISR just to stuff the bytes in the FIFO buffer, and move all the processing/decoding to the main program body. The usual rule of thumb is to keep an ISR as short and fast as possible.
the most amazing part about this is how you typed the keymap scan code table from scratch so quickly. I thought it was fast enough as random jibberish. until it actually worked! - and then my mind was blown.
He's not really doing it from scratch - he's got a copy of what he needs to type offscreen and is reading that while he types. Plus the video is sped up there, which hides any delays as he looks back and forth between the screen and his offscreen copy.
@@RedwoodRhiadra Isn't it just traversing the keyboard with a particular zig zag pattern, i.e. start with a key on the bottom row, then the key slightly to the left on the next row, followed by the key on the third row just to the right of that one and the key on the fourth row to the left of that. Repeat for each column of keys.
Very grateful for all your work Mr. Eater. QMK Finally just made sense in just 20 minutes. Thanks! I'm looking forward to starting kits 1-4!! Shout out from TX
Hi Ben, you added all this new hardware to detect and create a clean IRQ pulse when you didn't have too.... you already had the hardware in place with the 6522. All you needed to do was use the Timer 2 in "Pulse Counting mode", and voila! Just set it up to count down 11 pulses applied to PB6 and it automatically fires the IRQ output when it reached zero. Then read in the data from your shift register into PortB, and you're good. You'll just need to add more code to check the IFR to see what generated the interupt. Would be a good way to show how to handle multiple interupts anyway. Keep up the good work man!
I was just recommended this channel, and how happy I am! Watching you gradually add function to your interface was extremely satisfying and calming. Thanks for the great content!
Your mention of a keyboard buffer explained to me why frozen Windows programs sometimes spring back into action processing all the keystrokes you entered while it was frozen.
Hi Ben, love your videos! In the handling of the release of the shift keys, you used "eor", which would flip the bit. This means that if the following key sequence happened, the shift flag would stay enabled with no shift key being pressed: - Press left shift (sets the shift flag) - Press right shift (does nothing, since the flag is already set) - Release one shift (clears the shift flag) - Release the other shift (sets the shift flag, because of the XOR) Maybe the only way to solve this case is to handle each shift key in its own flag?
@@JoeldaSilvaVicenteFilho however this would mean that after releasing the first shift key, but keeping the other pressed, the letters would be written in lowercase
Or yknow, do it properly lda kb_flags and #~SHIFT ;vasm allows that. I checked. sta kb_flags I cringed when he did "eor" because that is asking for bugs. Though I didn't spot that specific one.
Lovely. Thanks! It brings back memories of learning some very simple assembly on my C64 when I was in my teens (a time almost beyond living memory now!). While I'd never want to go back to passing carries around for multi-byte arithmetic, I do miss most other aspects of the simplicity of 6502 assembly!
This is a great example of just how efficient assembly language can be. Each feature is implemented in just a handful of instructions. Each instruction is just a few bytes. I didn’t count, but the key map probably takes up more memory than all the rest of the code.
maybe it's because of growing up with 6502 computers and peeks and pokes, but I'm not so impressed with assembly efficiency. That's literally what it's made to be for, a step above hexadecimal(which is almost always only used for reverse-engineering, not coding!) I guess if your first programming language was something like Python, or even Perl, you'd be impressed with assembler.
@@squirlmy Oh, I grew up with 6502 programming too, mostly BASIC and assembly. Certainly comparing to an interpreted language accentuates this sense that assembly is efficient; a modern compiled language is more on par with assembly in practice. I just like how what we call "lines of code" and perhaps envision as sophisticated control structures with a lot of machinery behind them...can often be expressed in machine language as just a handful of bytes that perform very simple state changes in the processor. It's neat.
I sincerely hope you are wrong there, but who knows. For what it's worth I taught degree / masters level computer architecture for years and even wrote a book on computer architecture.... And Ben Eater is teaching me stuff! Thanks Ben, I'm having a brilliant time playing with hardware again and coding 6502 for the first time in 30 years.
I love your channel, and I love what you do with the hardware. I think your software is a little basic, however. Someone already mentioned not differentiating between the shifts, thus losing state. A few others: - You disable interrupts. The algorithm you use, however, is a wait-free algorithm. It works even if interrupted. - If the interrupt handler takes too long, the next key-code might arrive. If that happens, the code might drop it. It would have been better to store the raw key-codes in the buffer, and do the decoding outside the interrupt handler. - This would also obviate the need for a "key down" state. If the code is "key down", just immediately fall through to fetching the next key (when it's available) and ignoring it. - Instead of parsing the keyboard's state every time, parse it when it changes, and store it in the Y register. You can then use the indirect+Y addressing mode to fetch the actual translated code, and simplify the code fetch. To reiterate: I _love_ what you're doing here. This are fairly minor nitpicks on how you can make things even greater.
As a barely beyond beginner vim user, I noticed you're not utilizing the power of vim for more powerful editing commands. Want to uppercase all letters in a string? Move the cursor inside, then type: gUi" The command gU changes charact to uppercase and takes a range. i" is that range, meaning inside (hence the i) the double quotes. It's tricks like these that made me fall in love with vim, hence why I am sharing it. It's so powerful! Nevertheless, great and interesting video!
At about 3:20 you have a branch around a jump. Is there some reason I'm missing for this? To clarify, you have: loop: ... bne key_pressed jmp loop key_pressed: ... Instead of the simpler looking: loop: ... beq loop ...
You know that many code compilers are written in their own language? A C++ compiler is written in C++ (just the previous version), obviously the first one had to be written in another language (assembly) though..
@@ScienceDiscoverer Actually, the first assembler was present in the very first core memory module installed in an electronic computer. Nobody knows how it got there.
Instead of using a different keymap for shift you could just set the fifth bit to 0. That will make any letter uppercase. You would have to handle numbers and special character differently, but it would take less memory.
26 bytes can be a lot, especially when you're programming an embedded system. The 6502 can handle a relatively huge amount of ram at 64k, but it's still a good idea to save all the memory you can, since it will add up.
I appreciate that he’s using the Model M to type the code to run the Model M 😆 I can’t wait to go back to the office where I have desk space to use mine again.
I hope the graphics interface will make another appearance, and replace the LCD screen - then there will be the opportunity for a mouse-controlled cursor. I'm surprised that a dot-matrix printer has not (yet) made an appearance as an essential output peripheral!
I'm wondering if he will attempt to make a simple game like hangman on the lcd. Just to show everything coming together and interacting. That said, in his patreon, he did hint that he wants to do another video comparing the PS/2 interface with USB, but the 6502 is too slow for USB, so it will be a stand-alone demo rather than a 6502 breadboard project.
Serial communications, storage, and graphics ability would be the most likely candidates, I would think. Mouse, not so much. Mice didn't come into common usage until the 16-bit GUI days, and this computer is pretty far from that at this point.
Are you aware of Soarer's Converter? or all the TMK-based projects? github.com/tmk/tmk_keyboard/wiki/TMK-Based-Projects ? I wasn't sure at first if your the Atari ST has the ATmega, because your converter could also use an ATmega. It would be funny if your keyboard is more powerful than the CPU!
Hi Ben, I haven't snooped through all your videos but have you ever thought of explaining I2C and SPI and how you can drive those cheap mini lcd color displays? I have been playing around with an RPI4B and SPI/GPIO and managed to drive 5 SPI LCD displays (128x128 1.44 inch and 240x240 1.3 inch) over SPI/GPIO simultaneously with multithreading. I am suggesting this for other who might find this interesting because it really is a lot of fun. With a slightly bigger display (4 inch) you could work your way to making a simple gui for your breadboard computer. There are SPI controller chips (i.e. MC33781)which you can just plug into your breadboard, take serialand parallel commands/data and can be driven up to 10 MHz (SPI speed) and support pwm on the outputs for clocks. I can imagine you could think a load of side projects too, like a Z buffer etc :)
Ben is the person that convinced me to learn 6502 assembly -- I love it! (unlike amd64 assembly. it's awful and ridiculously too complex for my brain. congrats to those who wrote the first compilers for this architecture)
1. You do not need SEI / CLI in the 'loop:' - this wastes 2 bytes. Wrtiting to kb_wptr in the interrupt is an atomic operation, we do not have to stop the interrupt for that. 2. Shouldn't the interrupt handler preserve the processor status register (PHP/PLP)? 3. The 'kb_flags' should store flags in bits 6 and 7. This way you could use BIT instruction together with BMI and BVS to check the flags, there would be no need for AND. 4. The 'JMP push_key' probably wastes 1 byte; if none of the codes translates to 0, than it would be shorter to write 'BNE push_key' instead. 5. What exactly CPU do you have? If this is a 65C02 (not a pure 6502) you have instructions like BRA, STZ, PHX, PLX, and possibly SMB, RMB, BBR, BBS - they would make you code significantly shorter.
I'd actually really like to see is how this is done *inside* the keyboard. What's the output controller like? Is every key an independent switch that triggers a specific hardwired signal generation circuit, or did they do something a bit more clever? How do they prevent key signals from interfering with each other if you hit them too close together? How hard would it be to convert a modern USB keyboard PS/2?
Great content which I just recently discovered. Question, @3:40 you used a jmp instruction rather than an rts instruction, which seems more appropriate. Would you be able to explain why? Seems like the jmp instruction would eventually cause a stack overflow.
There was no need to branch like that to a different table at the end. Upper case ascii is 32 greater than lower case (or maybe 64, going from memory here) so a better solution would be to extend the key map to include upper case and then use the shift bit to add 32 onto the result. That way everything is on one map. Bit more elegant / performant / simpler.
You just used a keyboard to make a program to read data from a keyboard. How did the first keyboard driver exist? (I know how, it started with puch cards > hardware systems > etc)
Why on Earth would you do all that scan code processing in the interrupt and not in the main loop? Or, better yet, in separate read key block. You certainly have enough buffer space to delay the processing until it is appropriate
In visual mode: gU to uppercase everything selected ;) Granted, that doesn't help with the numbers and symbols, but hey - that's 26 characters you didn't need to replace :P
If you're going to expand the functionality to use interrupts for multiple things, be sure to save the previous inerrupt state and restore it when done (instead of enabling interrupts when done). :-)
Probably a minor issue, but since both shift keys handle the same flag bit, if both are pressed and one is released, before the key repeat timer there may be a period where the shift bit is off despite a shift key being held
Can we just appreciate that this dude truly made a hello world from true scratch in assembly on an ancient processor and documented it in an easy to follow way for all of us to see and learn with?
That's why we're here; we appreciate it. I did do some machine language programming on some of these old processors including the 6502 in one of my college classes. They plugged into these boards that we used to enter opcodes and values into memory and then we could step it forward and examine the values to see what the processor was doing. (I wish I could remember what those boards were called.) Ben definitely takes it another step though.
@@chitlitlah I wish my college had that much. Although we did get some hands on, it was very little and the equipment was not up to the task. Ben's projects are what I had expected computer engineering school to be before facing uncaring reality.
No!
this is going to be a stupid question, but could you code this in c and then use a compiler that's been specifically designed to output 6502 machine code?
@@russianvideovlogguy that’s what most people do. And modern compilers are more efficient than human coders 99.9% of the time (not always true even in the 90s). That’s why hand-coding assembly in this day and age is such a madlad endeavour!
Fun fact: when assemblers were first invented, the computer scientists who learned to keep track of all their memory and instruction addresses by hand viewed _assembly_ as the easy-mode cheat for modern hacks, much as present-day C aficionados view Python!
"And that didn't do anything!" I relate to that hahaha
For me it's more like ohh that broke even more
I love that you leave that stuff in. It's so critical to see and understand it's just part of the process
It is the fun of programming, you wrote your code, checked it, and still something is wrong. And you need to find out what, a missed part of syntax, a wrong label or variable name or just your code wrong.
Using an 8bit pointer to create an “automatic” circular buffer was brilliant. I kept waiting for a modulus, but no, you one-upped my expectations. Fantastic as always.
Same here! I suppose AND would be the way to go with any power-of-two buffer size if you didn't have the luxury of small pointers on your CPU.
@@musicalfringe A 128-byte buffer would be almost as easy - the negative flag is set when the pointer reaches 128 so it's easy to detect.
Except that writep = readp when the buffer is empty and when it's full, the way the program is written. Easy fix, just keep track of the buffer length and only write when length is less than 256 and read when it's greater than 0. That is if you want to read then inc and write then inc.
Either way Ben's the man
Note, there should be a separate flag for the right and left shifts, because with one flag I could press LSHFT, RSHFT then release RSHFT and it would count as released even though LSHFT is still pressed (and same vise versa)
Pressing and releasing both shifts at the same time would give you a special shift-lock mode
I'm studying master in computer engineering and these videos from Ben are the best in the field
Nice, what’s your thesis on?
@@wicket4969 I don't know if you need to write a thesis for a masters in CS. I don't think you do
@@arisweedler4703 yes you do
@@dr.palsonp.h.d815 it depends on which country you’re from. There is no universal regulatory body for Computer Science that I’m aware of.
@@blablabla7796 usually all western masters programs require a thesis, the ones that dont are the exception
After following Ben Eater's Videos for several years now, I still don't understand how anyone can "dislike" his videos... for the content that he provides, it is the best that is currently available on the net anywhere... even better than most college or university content that is publicly and freely available... if I could like more than once, I wouldn't hesitate to do so!
Missing the "like" button on a small touchscreen. This just happened to me but I thankfully noticed immediately
I wouldn't be surprised if they were all accidental. Like Václav said, or perhaps some little kid randomly clicking around on UA-cam. Any intentional dislikes are probably just trolls.
Must be because he's using vim and not emacs
@@franchufranchu119 Or how he uses VIM. Some VIM users are quite finnicky about using VIM "properly"
@@ecosta Or maybe they just don't understand
He threw in the 0x0F bug to appear human, but he's clearly a god 😏. Another amazing video sir!
But for real: it's nice that he keeps in the issues he experiences so we can learn from them and be ready for a bug like that.
The final code still has another bug: pressing both Shift keys at the same time breaks it 😂 When the first is released, letters will go back to lower-case even though you're still pressing the second; and when the second is released, because he's using xor ("eor") to clear the flag, it'll turn shift on permanently until you press and release Shift once again. So... definitely a fallible human 😁
@@IceMetalPunk yeah but who presses both shift keys at the same time? That doesn't make much sense
@@nilswegner2881 its still a bug that someone could accidentally activate. when your programming u have to not only think of the correct use case but also the incorrect edge case, it is on the edge case that most bugs exist
@@nilswegner2881 I occasionally do just as I tap keys randomly as I fidget. But when designing software, you should *never* assume your users "would never" do something -- always code to cover all your bases.
that sped-up typing sound at 6:05 sounds so cool
it sounds like a dying floppy drive
The keyboard sounds triggers the "[Applause]" in the auto captions.
Keyboard ASMR
@@yousorooo exactly
Aphex Twin samples
Typically, an interrupt service routine (ISR) does the minimum possible to deal with the peripheral, and then it returns, and it's up to some other routines to interpret the retrieved data. One thing to remember is that when an interrupt is processed, interrupts are disabled until either they're explicitly enabled or the return from interrupt instruction is executed. Therefore any other interrupts (from other devices) will be blocked, and possibly missed. So the routine to read the keyboard port would just fill the buffer, and any program/subroutine which reads the buffer would do the handling of modifier keys like shift.
In this case, it really doesn't matter, because there isn't another device competing for CPU cycles via interrupts. But for more complex systems this sort of thing should be kept in mind.
yea the way he did it was messy
Mercy! I needed to know this back in the late '60s and early '70s. So here we are fifty plus years later as I slip into my second childhood. 😆
May I be the first to congratulate you on accidentally reviving the concept of "Shift-Lock".
As you're toggling the flag when shift is released but setting it when pressed, pressing both shift keys together and then releasing them will toggle the shift bit back to on. :)
[Edit: Typo correction]
Yeah, I think to be fully correct you'd have to implement the two shift keys as separate flags.
Explain your thought process. humans aren't accurate enough for "same time" conditions, one will always be first or polling would cause one to be first.
My thought is you would lose caps holding both, then still have no caps releasing them both. With even boolean operations, it always returns to the default state.
Depending how you implement it, either holding both shift keys gives you lowercase, or holding both and then letting go of one gives you lowercase, or as in the existing implementation holding both and letting go of both gives you uppercase. I consider all three of these to be incorrect behavior.
@@anschelsc Or implement ShiftUp as AND #NOT(SHIFT) instead of EOR #SHIFT.
@@jgharston Then when you hold down both shifts, and let one up, you'll be in lowercase even though you're still holding down one of the shift keys.
I found your 8 bit build videos probably a year ago and was glued to the screen in a way I didn’t expect. The final videos on conditional jumps and control word logic felt like the climax in an action flick. I soon discovered an alternative purpose for the videos: highly effective sleep aid. I’m not insinuating your videos are boring. Far from it. Rather the tone and cadence of your voice and and the quiet sound of assembling tiny components on a breadboard knock me right out. It’s like magic. I love these videos when I want to be awake, and I love them when I want to be asleep. Someday I’ll order a kit and see if my kid’s attention spans are as as solid as mine. Perhaps I could even lull them into a nap.
No I feel it dude, total same here. Its a great series to both learn from, and relax to.
Thanks to you Ben will start a ASMR series of video ;)
I literally swear i've learn't more information about lower level computing from this channel than I did across my whole compsci degree. Great video as always ben!
CompSci != CompEng.
@@jgharston Yeah I get that and know the difference... But in my opinion understanding of lower level functionality of a computer helps re-enforce knowledge and understanding within higher level computing. did a little comp enginnering stuff on my degree but it was taught so half assed it was useless.
Fun fact: I've regretted since the begining of my second year not choosing a computer engineering degree but was too late by that point.
@@jordy15322 Yeah, me too exactly. I was three years into my CompSci degree and still thinking "when are we going to get to some, y'know *actual* computing?" It was years after that I realised I should have looked for something with "engineering" in the course title. It was only in my very final semester that I put together hardware interfaces for controlling a set of LEDs and a printer, and wrote a PDP11 assembler - both of which I just did a brain-dump of stuff I'd done more than six years previously.
@@jordy15322 I can't speak to now, but depending where one went to school a couple decades back it was practically assured one would get a CE minor pursuing a CS major (and vice versa) at the BS level, and putting in two extra years one could graduate with a BS in each CS, CE and Math
@@jordy15322 Computer Science is arguable much harder than Computer Eng, stick to it, its worth much more than being able to write assembly
Ben posts, I like.
1st comment, nice
Also, r u a patreon bec u got access to the video before it was public lmao
I was rewatching his older videos and I was like "hey how have I not seen that one yet"
20 mins ago
oh, that's how
OH WAIT
@@loneranger4282 Yes I am.
like then watch :)
I recently hooked a 6551 up to my bread boarded 6502, been having a blast with the kit and plan to eventually build my own sound card. Thanks for the videos, been using a circular buffer like this for processing serial input and other interrupt-y situations. A nice generally useful technique for working with input, thanks for showcasing it.
@Stephen Anthony I happen to have a SY6551, but the WDC65C51 has well known work arounds, so it isn't a deal breaker just a little less performance at the same clock rate.
I love the way the captions hear the keyboard sound as applause. It makes it look like he’s giving an inspiring speech about handling keypresses.
Good stuff , but that interrupt routine is doing quite a bit. Usually you want to keep interrupts doing a minimal amount of work so the execution gets back to the main loop. Probably for better performance just capture scan codes in the buffer, and then dispatch a key translation when the main loop reads the next key value. For more advanced projects, you can then have context based key mappings.
Good point.
You're not complaining, you are pointing out an interesting fact. Thank you for sharing! :)
One thing that I was thinking of: When he was implementing the shifted keymap, instead of a branch insn, he could have just set the shift flag to be 0x100 and added it to the keymap's address. In both cases this will do a load from 0xfd00 if the shift flag is 0 and load from 0xff00 if the shift flag is 1, so... yeah... this doesn't make it *better*, per se, but the code would be cuter.
I would like to say, though: indirection at the cost of complexity for efficiency ((when you don't need the added efficiency to function)) is bad. I think Ben rightfully and consistently chooses simplicity over performance, and I praise him for it.
@@arisweedler4703 it's arguably better-ish because there's less jumping around... but tracking separate shift states for left and right shift would become impossible with that.
Back in the day, when I was just starting assembly language, I would get anxious, as the number of lines of code kept increasing, that the code I was writing would take an age to execute. After assembling, it usually executed in the blink of an eye. One reason is that much of the code is skipped. When I write "usually", I mean when there are no loops. Loops in an interrupt routine can be a real problem.
@@willofirony Loops in general can be problematic; I remember that when I started looking into some PHP coding, I had a section that would take a very long time to show results, and upon closer inspection I was able to track it down to a couple of nested loops. The solution was to reverse the order of nesting, i.e. the inner loop became the outer one and vice versa. This blew my mind, so to speak.
Some day in the future, I will look back at these videos and understand every single line of code.
If you follow along all the videos from the beginning, it shouldn't be too hard. Almost everything he did here was introduced and explained in a previous video.
Having actually (re-)written a keyboard driver / scancode translator I appreciate this.
In case anybody is wondering why a different map for upper case, well just look at an actual ASCII table and compare that to the scancode table. He'd need at least another ten minutes to explain the mapping shift, so fodder for later.
It's more than 30 years ago, I've learned writing code for the 6502. But it's still amazing and I love your series about this small computer.
Let's see, C64 came out in 80's, so to me it's about 40 years.
I love how he kinda skipped right over needing to replace the quotations with apostrophe's on line 50 of the shifted key matrix. Took me a minute to figure out what was going on. I should have realized something was different right away when my line turned 3 different colors. Absolutely great video! I actually like that it doesn't just work right away every time. I feel like I learn more when I have to troubleshoot crazy problems.
I don't understand how anyone, let alone 16 people could dislike a Ben Eater video. This is better than anything I learned in university when getting my CpE degree. Thank you Ben for all that you do.
I think if you press (and hold) both left shift and right shift, then release them, it will eventually set (not unset) SHIFT flag, because your code will EOR the flag twice.
ahh man you open my mind to hole new level. programming for 10 years and I just realize how small I know things. good work
I love these videos. Working at this level of simplicity in 8bits is extremely satisfying because everything just makes sense on the surface, without need for too many abstractions.
Thank you Ben, now you should use this and the "worst" graphic card, to print some text on the monitor! :)
give him time... I'm sure that's next! He's building a word processor from scratch! :P
It'll be self hosting soon
Problem is, he would need some kind of font handler and a graphics driver aswell, which sounds like it would be a pain and a half to program in Assembly.
The sei and cli aren’t actually necessary. kb_ptr is only modified outside of the interrupt handler so it doesn’t need to be in critical section and kb_wptr is read atomically (since it’s a single byte) so the read doesn’t need a critical section either.
i like how this started as building a System and now it's turning into a system programming set of videos for the most part.
Just been following along with your 6502 Computer videos. I can tell that lots of effort goes into these videos, thanks for the great content, and keep up the good work!
I wholeheartedly concur with this concise and accurate statement, ☺
I did stuff like this (circular buffers) with a 6800 back in 1979. Thanks for inspiring me to get back into hardware again. I bought your 6502 kits, but it wasn't enough. I upgraded to a 65C816 running at 8Mhz. It now has 1Mb ram and 96K of eeprom and an NHD-0440WH 40 x 4 display. I finally figured out how to get a PCF8584 working so I have I2C to a DS3231 for date/time and more I2C peripherals in the pipeline. I can't seem to get my AM9511A-4 (FPU) working and I'm about to give up and look into alternatives. Thanks again.
OMG, this popped up as possible interest to me and I watched this to the end as it brought back memories to my life in the mid 70s to 80s. I was watching the assembler instructions and surprising to me, I was recognizing all the 6502 instruction set you typed in. Thanks for the memories ...
I’m amazed by how much footage there is on this channel of you removing the eeprom from the programmer and putting it back on the breadboard
Does he reuse the same clip each time...?
@@JoshHeidenreich I was wondering that but I think it’s different each time. Either that or very well edited
EEPROM installation supercut, anyone?
Super video! I applauded for $2.00 👏
This is an amazing training session for 6502 assembly! I didn't think I could follow this, but I got it all the way. Thank you!
I'm tempted to type up the code so I can learn from the mimicry. This would be like typing the Basic programs from a 1980s magazine.
Or it would be like Mozart copying Bach in order to study/learn.
the 65c02 has phx, phy, plx, and ply opcodes btw :) (4:32)
Super video! I applauded for NOK 20.00 👏
This video tied it all nicely. As I'm tying this comment out, I'm imagining the little transistors in all of the circuits flipping on and off like crazy. Your videos really make it easier to understand than when I was in school. My teachers were great, but maybe my Interest then wasn't as great as it is now. So, thank you!
Super video! I applauded for £5.00 👏👏
Very nice video.
Regarding the shift key handling, I do think that handling two keys with only one flag might cause a little glitch: if you press both shift keys, and then release only one of them, software will behave as if you did not hold the latter; it will print non-capitalised letters.
It's allways fun trying to find any "errors" in the work presented; however one can only be grateful for this opportunity, thanks to your great work!
I was thinking the same thing about the handling.
Holy Moly! This is really cool! Even though I speak Z80 Assembler natively, I'm slowly beginning to understand 6502 coding. Big thanks to Ben. 😁
I'm switching back and forth between Z80 and 6502, and it always feels like switching between C++ and BASIC. Luckily I love both. (except BASIC, I don't love that)
Wonderful!
This takes me back to 1983 when I bought an Apple II and a copy of the ORCA/M assembler.
Thanks Ben.
If there were massive destruction of this earth, this is the only guy who can make computers from scratch! Following you since last 6 years. Huge #respect
Awesome as always. You editing skills are at another level too. I can understand amount of effort put into make this video. Much appreciated Ben.
This series really reinforces to me how creative and inventive early computer people had to be to make all this work. You take things like the keyboard just plug and play and off you go but never really think about how much is happening behind the scenes just to type some characters.
PS. Thank you for making these videos!!
Thanks, Ben, for this fantastic material.
Vim has a Ctrl+N shortcut to autocomplete a word. Extremely useful.
Super video! I applauded for CHF 5.00 👏👏
6502 assembler is SO much more relaxing when someone else is writing it... Excellent series. Thank you.
Hi!
First of all, "Great Videos", its always nice to remember the basics and the importance of some "minor" details.
As for this specific video, I think your ISR is being overloaded. I would suggest a minimal ISR just to stuff the bytes in the FIFO buffer, and move all the processing/decoding to the main program body. The usual rule of thumb is to keep an ISR as short and fast as possible.
the most amazing part about this is how you typed the keymap scan code table from scratch so quickly.
I thought it was fast enough as random jibberish. until it actually worked! - and then my mind was blown.
He's not really doing it from scratch - he's got a copy of what he needs to type offscreen and is reading that while he types. Plus the video is sped up there, which hides any delays as he looks back and forth between the screen and his offscreen copy.
@@RedwoodRhiadra Isn't it just traversing the keyboard with a particular zig zag pattern, i.e. start with a key on the bottom row, then the key slightly to the left on the next row, followed by the key on the third row just to the right of that one and the key on the fourth row to the left of that. Repeat for each column of keys.
@@normanstevens4924 It's been a while since I looked at the video, but I don't think it's that simple.
This series is just fantastic. I know just some basic x86 asm but it's close enough I can go along here. Thank you!
Video stupendo! Ho applaudito per 2,00 € 👏
Very grateful for all your work Mr. Eater. QMK Finally just made sense in just 20 minutes. Thanks! I'm looking forward to starting kits 1-4!! Shout out from TX
Hi Ben, you added all this new hardware to detect and create a clean IRQ pulse when you didn't have too.... you already had the hardware in place with the 6522. All you needed to do was use the Timer 2 in "Pulse Counting mode", and voila! Just set it up to count down 11 pulses applied to PB6 and it automatically fires the IRQ output when it reached zero. Then read in the data from your shift register into PortB, and you're good. You'll just need to add more code to check the IFR to see what generated the interupt. Would be a good way to show how to handle multiple interupts anyway. Keep up the good work man!
These videos have been instrumental in helping me understand and appreciate how the very basics of computers work. I can't wait to see more.
I was just recommended this channel, and how happy I am! Watching you gradually add function to your interface was extremely satisfying and calming. Thanks for the great content!
This is so cool!! Ben has reached the "Hello, world!" stage now :D
Your mention of a keyboard buffer explained to me why frozen Windows programs sometimes spring back into action processing all the keystrokes you entered while it was frozen.
2:40 What a lovely sound of those buckling springs in that IBM Model M(?) as you're typing. :-)
2090 Building an A.I. that can simulate the human mind from scratch.
On a 6502 of course
3450: Programming GTA X on 6502
@@realdragon ez for this god of a man
seems like a content worth to wait for
That he will offload his consciousness to.
Hi Ben, love your videos!
In the handling of the release of the shift keys, you used "eor", which would flip the bit. This means that if the following key sequence happened, the shift flag would stay enabled with no shift key being pressed:
- Press left shift (sets the shift flag)
- Press right shift (does nothing, since the flag is already set)
- Release one shift (clears the shift flag)
- Release the other shift (sets the shift flag, because of the XOR)
Maybe the only way to solve this case is to handle each shift key in its own flag?
or instead of flipping the flag, set it to the actual value
@@JoeldaSilvaVicenteFilho however this would mean that after releasing the first shift key, but keeping the other pressed, the letters would be written in lowercase
I came looking for this same comment. I think you’d need a separate flag for each shift key.
@@aritzh true
Or yknow, do it properly
lda kb_flags
and #~SHIFT ;vasm allows that. I checked.
sta kb_flags
I cringed when he did "eor" because that is asking for bugs. Though I didn't spot that specific one.
There's something magical about seeing the letters appear on the tiny screen as you type them!
Lovely. Thanks! It brings back memories of learning some very simple assembly on my C64 when I was in my teens (a time almost beyond living memory now!). While I'd never want to go back to passing carries around for multi-byte arithmetic, I do miss most other aspects of the simplicity of 6502 assembly!
This is a great example of just how efficient assembly language can be. Each feature is implemented in just a handful of instructions. Each instruction is just a few bytes. I didn’t count, but the key map probably takes up more memory than all the rest of the code.
maybe it's because of growing up with 6502 computers and peeks and pokes, but I'm not so impressed with assembly efficiency. That's literally what it's made to be for, a step above hexadecimal(which is almost always only used for reverse-engineering, not coding!) I guess if your first programming language was something like Python, or even Perl, you'd be impressed with assembler.
@@squirlmy Oh, I grew up with 6502 programming too, mostly BASIC and assembly. Certainly comparing to an interpreted language accentuates this sense that assembly is efficient; a modern compiled language is more on par with assembly in practice. I just like how what we call "lines of code" and perhaps envision as sophisticated control structures with a lot of machinery behind them...can often be expressed in machine language as just a handful of bytes that perform very simple state changes in the processor. It's neat.
People who are disliking Ben Eater's awesome videos are school professors
I sincerely hope you are wrong there, but who knows. For what it's worth I taught degree / masters level computer architecture for years and even wrote a book on computer architecture.... And Ben Eater is teaching me stuff! Thanks Ben, I'm having a brilliant time playing with hardware again and coding 6502 for the first time in 30 years.
I love your channel, and I love what you do with the hardware. I think your software is a little basic, however. Someone already mentioned not differentiating between the shifts, thus losing state. A few others:
- You disable interrupts. The algorithm you use, however, is a wait-free algorithm. It works even if interrupted.
- If the interrupt handler takes too long, the next key-code might arrive. If that happens, the code might drop it. It would have been better to store the raw key-codes in the buffer, and do the decoding outside the interrupt handler.
- This would also obviate the need for a "key down" state. If the code is "key down", just immediately fall through to fetching the next key (when it's available) and ignoring it.
- Instead of parsing the keyboard's state every time, parse it when it changes, and store it in the Y register. You can then use the indirect+Y addressing mode to fetch the actual translated code, and simplify the code fetch.
To reiterate: I _love_ what you're doing here. This are fairly minor nitpicks on how you can make things even greater.
4:06 The sped-up typing is insanely satisfying
As a barely beyond beginner vim user, I noticed you're not utilizing the power of vim for more powerful editing commands. Want to uppercase all letters in a string? Move the cursor inside, then type: gUi"
The command gU changes charact to uppercase and takes a range. i" is that range, meaning inside (hence the i) the double quotes.
It's tricks like these that made me fall in love with vim, hence why I am sharing it. It's so powerful!
Nevertheless, great and interesting video!
At about 3:20 you have a branch around a jump. Is there some reason I'm missing for this? To clarify, you have:
loop:
...
bne key_pressed
jmp loop
key_pressed:
...
Instead of the simpler looking:
loop:
...
beq loop
...
"Writing code with a keyboard to make a keyboard work, now
Thats thight!"
:)
You know that many code compilers are written in their own language? A C++ compiler is written in C++ (just the previous version), obviously the first one had to be written in another language (assembly) though..
@@sly1024 And think about how first assembly was written? In binary!
@@ScienceDiscoverer Actually, the first assembler was present in the very first core memory module installed in an electronic computer. Nobody knows how it got there.
Instead of using a different keymap for shift you could just set the fifth bit to 0. That will make any letter uppercase. You would have to handle numbers and special character differently, but it would take less memory.
That only handles 26 keys, out of ~90. That doesn't sound like it would save memory or time.
26 bytes can be a lot, especially when you're programming an embedded system. The 6502 can handle a relatively huge amount of ram at 64k, but it's still a good idea to save all the memory you can, since it will add up.
Caps lock and shift are totally two different things.
Awesome!! I think you’ll need one of those 4 line LCD displays, cuz a “Vim on 6502” is on the way I can sense that :D
I appreciate that he’s using the Model M to type the code to run the Model M 😆
I can’t wait to go back to the office where I have desk space to use mine again.
Sir, thanks for all these videos. you are a real hero for me. thanks a lot
Awesome Ben! I am curious how you will expand this project from here.
I hope the graphics interface will make another appearance, and replace the LCD screen - then there will be the opportunity for a mouse-controlled cursor. I'm surprised that a dot-matrix printer has not (yet) made an appearance as an essential output peripheral!
A mouse to move the curser on the screen!
I'm wondering if he will attempt to make a simple game like hangman on the lcd. Just to show everything coming together and interacting.
That said, in his patreon, he did hint that he wants to do another video comparing the PS/2 interface with USB, but the 6502 is too slow for USB, so it will be a stand-alone demo rather than a 6502 breadboard project.
Serial communications, storage, and graphics ability would be the most likely candidates, I would think. Mouse, not so much. Mice didn't come into common usage until the 16-bit GUI days, and this computer is pretty far from that at this point.
You remind me so much of John Carmack! Your voice, inflections, and brilliance. ❤
Always enjoy watching your videos! Brings back fond memories of my college days! :)
ive gotta learn about this .byte stuff memory map or are those the bytes that are coming?
Super helpful animations within the vid, loved it!
You have that ability to make things appears so simple. It's great !
This is so useful! I am about to build a PS2 interface to my Atari ST, with a ATmega CPU, but still.. All the workings and concepts are here. Thanks!
Are you aware of Soarer's Converter? or all the TMK-based projects? github.com/tmk/tmk_keyboard/wiki/TMK-Based-Projects ? I wasn't sure at first if your the Atari ST has the ATmega, because your converter could also use an ATmega. It would be funny if your keyboard is more powerful than the CPU!
Watching this series has taught me how to write and understand basic assembly language, which is so cool! Thank you Ben!
Always great, Ben! Can't wait to pick up a kit of my own!
Hi Ben, I haven't snooped through all your videos but have you ever thought of explaining I2C and SPI and how you can drive those cheap mini lcd color displays? I have been playing around with an RPI4B and SPI/GPIO and managed to drive 5 SPI LCD displays (128x128 1.44 inch and 240x240 1.3 inch) over SPI/GPIO simultaneously with multithreading. I am suggesting this for other who might find this interesting because it really is a lot of fun. With a slightly bigger display (4 inch) you could work your way to making a simple gui for your breadboard computer. There are SPI controller chips (i.e. MC33781)which you can just plug into your breadboard, take serialand parallel commands/data and can be driven up to 10 MHz (SPI speed) and support pwm on the outputs for clocks. I can imagine you could think a load of side projects too, like a Z buffer etc :)
This is more assembly programming than computer architecture, but still fun to watch.
I’m just blown away that, given the amount of times Ben wrote the word “shift”, he didn’t once forget the “f” :-)
wonderful as always!
Ben is the person that convinced me to learn 6502 assembly -- I love it!
(unlike amd64 assembly. it's awful and ridiculously too complex for my brain. congrats to those who wrote the first compilers for this architecture)
1. You do not need SEI / CLI in the 'loop:' - this wastes 2 bytes. Wrtiting to kb_wptr in the interrupt is an atomic operation, we do not have to stop the interrupt for that.
2. Shouldn't the interrupt handler preserve the processor status register (PHP/PLP)?
3. The 'kb_flags' should store flags in bits 6 and 7. This way you could use BIT instruction together with BMI and BVS to check the flags, there would be no need for AND.
4. The 'JMP push_key' probably wastes 1 byte; if none of the codes translates to 0, than it would be shorter to write 'BNE push_key' instead.
5. What exactly CPU do you have? If this is a 65C02 (not a pure 6502) you have instructions like BRA, STZ, PHX, PLX, and possibly SMB, RMB, BBR, BBS - they would make you code significantly shorter.
wow, very informed comment
Nice optimizations, but not the point here. This is targeted at beginners. The easier the better. Less commands are good.
I'd actually really like to see is how this is done *inside* the keyboard.
What's the output controller like?
Is every key an independent switch that triggers a specific hardwired signal generation circuit, or did they do something a bit more clever?
How do they prevent key signals from interfering with each other if you hit them too close together?
How hard would it be to convert a modern USB keyboard PS/2?
Great content which I just recently discovered.
Question, @3:40 you used a jmp instruction rather than an rts instruction, which seems more appropriate. Would you be able to explain why? Seems like the jmp instruction would eventually cause a stack overflow.
There was no need to branch like that to a different table at the end. Upper case ascii is 32 greater than lower case (or maybe 64, going from memory here) so a better solution would be to extend the key map to include upper case and then use the shift bit to add 32 onto the result. That way everything is on one map. Bit more elegant / performant / simpler.
You just used a keyboard to make a program to read data from a keyboard. How did the first keyboard driver exist? (I know how, it started with puch cards > hardware systems > etc)
Ben you got me back into retro tech and now my house is so full of it I can’t walk! It’s a hazard now! The city is gonna condemn my house Ben!
I can't explain why this is so captivating
Why on Earth would you do all that scan code processing in the interrupt and not in the main loop? Or, better yet, in separate read key block. You certainly have enough buffer space to delay the processing until it is appropriate
Let me like before watching. I have the guarantee that I will never be disappointed by Ben.
In visual mode: gU to uppercase everything selected ;)
Granted, that doesn't help with the numbers and symbols, but hey - that's 26 characters you didn't need to replace :P
or simply press ~ and wait for repeats :)
If you're going to expand the functionality to use interrupts for multiple things, be sure to save the previous inerrupt state and restore it when done (instead of enabling interrupts when done). :-)
Probably a minor issue, but since both shift keys handle the same flag bit, if both are pressed and one is released, before the key repeat timer there may be a period where the shift bit is off despite a shift key being held
Quite possibly the most involved "Hello, World" application I have ever seen in my 27 years of programming.