Keyboard interface software
Skills:
Tool Use & Function Calling80%
Key Takeaways
The video demonstrates how to create a keyboard interface software using a 6502 based computer and a PS2 keyboard, utilizing a keyboard buffer and scan codes to print actual letters typed.
Full Transcript
in my last video i built the hardware to interface a ps2 keyboard into the 6502 based computer and the program that's running right now is just printing out the scan code of the last or the last scan code that was received from the keyboard so if i press a key like spacebar you see that we get a scan code of 41 in decimal and that's the scan code for the space bar if i release a key then we actually get two scan codes we get one scan code saying that the key is being released and that's 240 and then we'll get another scan code telling us which key was released so if i release the space bar what happened was we got the 240 it printed that and then it printed the 41 on top of it since those scan codes come one right after the other and so that's as far as i got in the last video which you can check out there if you haven't already seen it but of course it's not the most interesting thing we could do with a keyboard so in this video what i want to do is write a better interrupt handler that actually interprets those scan codes uh and lets us print out the actual uh letters that are being typed so if we look at our program right now all we're doing when we get an interrupt that says a key was pressed is we're reading the scan code and putting that in this counter variable which is the thing that we're displaying to the screen i'll start by getting rid of all this counter stuff so we're not going to count anything and we don't really need to convert to decimal or anything in this program and replace it with basically a keyboard buffer this is pretty common where you'll have a buffer where every key that's pressed gets added to the buffer and then as the software reads keys it reads them out of the buffer that way if the user types a whole bunch of stuff before the software is ready to read it it can be read into that buffer and so we'll have two pointers for working with that buffer we'll have a right pointer and a read pointer so whenever you press a key it'll get put in the buffer at the offset specified by that right pointer and then whenever the program reads from the buffer it'll read at the offset specified by the read pointer and so if those two pointers are the same then that means that we've read everything out of the buffer and if those two pointers are different then that means there's some keys that have been typed that are in the buffer that haven't been read yet by the software and i'm setting the location of the keyboard buffer in memory as zero two zero zero through zero two ff so that gives us 256 bytes in the keyboard buffer and because the right pointer and read pointer are both eight bit values whenever either of them passes 255 they'll just wrap back around to zero and as long as we assume that the user is not going to be able to type more than 256 keystrokes before the program reads from the buffer we're never going to fill this up so the circular buffer ought to just work indefinitely i'll get rid of all this stuff that we're using for converting the counter to decimal and printing it out on the screen and all that stuff get rid of all that and the program is going to be pretty simple we're basically just going to sit in a loop and load the value of the read pointer which is just how far we've read into the keyboard buffer and then compare that to the right pointer which is how much has been written into the keyboard buffer by someone typing keys and if those aren't equal then that means that there's some keys that have been pressed that we haven't processed yet and so we'll go branch somewhere to deal with that otherwise we'll just sit in this loop and actually because these pointers are normally being updated in an interrupt we should disable interrupts just for the period of time where we're loading and comparing those so they don't get changed right in the middle of us comparing so we'll set interrupt disable and then clear interrupt disable just for that for that brief period there and then if a key is pressed [Applause] we'll get the value of the read pointer put that in the x register and then use that as an index into the keyboard buffer to get the next key that was that was written into the keyboard buffer that we haven't yet read and so now that we've got that key in the in the a register we can go ahead and print it to the screen and we'll just use the existing print care subroutine from previous videos and we'll increment the read pointer to indicate that we've read that character and then jump back up to the top uh where we'll wait for the next key or if or if additional keys are available already then the read pointer and right pointer still won't be equal yet and we'll just keep this process going until we've printed all the characters that are available and then we'll just sit in a loop and so that's the that's the program that i'm going to run and it's you know essentially it's assuming that there's uh keys in the keyboard buffer and it uses these pointers to tell us where we are but otherwise you know this is basically just a loop that prints whatever key is pressed out to the screen but of course the hard part is going to be populating that keyboard buffer based on um when we get an interrupt so let's go down here to our interrupt handler and of course this isn't uh incrementing a counter anymore so i'll rename this to keyboard interrupt i guess and we're already loading the key into the a register here from port a and so instead of storing it as the counter we'll store it at an offset into keyboard buffer and then that offset and the x register will load from the right pointer so this will put the key that was pressed into the keyboard buffer at the offset of the right pointer and of course once we do that we'll increment that pointer and now because we're using the x register in our interrupt handler we need to make sure we push the x register onto the stack at the beginning of the interrupt handler and pull it off at the end and we can only push pull a so we have to transfer x to a and vice versa so that'll make sure the keyboard interrupt handler leaves all the registers the way it found them and we actually have some initialization to do as well if we go back up here to the top right above our our main loop we want to initialize our right pointer and read pointer both to zero so that when we start out they're both pointing to the beginning of the keyboard buffer [Applause] and so this should work but it does have a pretty severe limitation which is that the the key that it's that it's outputting so when it's printing this character what it's doing is it's assuming that the value that's been that's in the buffer is an ascii character right because when we jump to the subroutine print care to print a character to the lcd it's expecting an ascii character but right now what we're putting in the keyboard buffer is just whatever we read from port a which is going to be a scan code and as we saw in the previous video the scan codes are not ascii characters so ideally what we would do here is we would do sort of a mapping between them and we we can do that we can actually just set up a mapping table to map the scan code to a character that way we're dealing with ascii characters once we've read it in and put it in the buffer so what i'll do is i'll just go to address fe 0 0 which is in rom and create this key map and it's just going to be a bunch of byte data and so this byte data will fill up 256 bytes in rom and each byte will correspond to a scan code and if that scan code corresponds to a character then i'll put that character in the appropriate position otherwise i'll just put a question mark that way if we get a scan code that we don't recognize we can just print it as a question mark otherwise it'll print as the the appropriate character [Applause] and so here we go we've got 256 bytes and so for example this this letter c corresponds with hex21 right so this this row here is 2 0 to 2f so that this is 2 0 it doesn't have a character associated with it and then scan code 2 1 is the scan code for the c character or for the c key i guess so in that case we'll print a c character so that's how this mapping works and we can use the mapping up here because we've read the scan code from the keyboard and that's in the a register and what we can do is we can take that scan code and put it in the x register by transferring a to x and then load the a register with a value from our key map offset by x which is the scan code and so that would pull a value out of the key map put it in the a register and that should be the character that's associated with the key that was pressed and then that's what we'll go ahead and you know get our right pointer and put it in a buffer in the appropriate place so if i go ahead and save this assemble it and write it to the eeprom and put the eeprom back in and reset everything now we've got a blank screen here and if i press a key on the keyboard so i press the a key we get well we get an a and then we get a question mark and another a and that question mark is because we get the the f0 scan code that indicates that a key is being released so really what this is saying is we pressed a and then we released a and so we press a few more keys you can see we see that same pattern so e release e a t release a release t e release e r uh and so on and i just ran off the screen there but we're getting the scan codes and we're interpreting them correctly and i guess if we really wanted to uh sort of go the extra step here we could modify our code to detect that release key and ignore the next character if all we care about is key presses so to do that we'll need a variable that indicates whether we've received that release key scan code that we can use as some state information to tell us whether we can ignore the next scan code we get so i'll just create another variable here in memory at address two called keyboard flags and then i'll have a flag called release which should just be that first bit in keyboard flags and you can imagine we could use this keyboard flags to keep track of other things like whether the shift key is currently pressed or the control key or whatever things like that but for now i'll just use this one flag here of whether we've just received a release key scan code and here we want to do is check and see if we're getting that special key release scan code so as soon as we load the scan code we'll compare it to 0f the key release scan code and if it matches we'll jump past all this stuff where we put the key in the buffer [Applause] instead what we'll do is we'll just flip the release bit in the flags that keeps track of the fact that the last scan code we got was that key release scan code and then of course if we didn't get a key really scan code then we'll just fall down here and we'll you know put the put the scan code into the buffer like we normally would and then of course we should skip this key release stuff and just exit the interrupt handler there so that's saying this question mark here that this is the f0 is this question mark it's saying when we get that flip that release bit so that we know when we get the next character in this case the second a we know basically we can just ignore it because we you know it's just telling us we released the a but we've already sort of put the a into the keyboard buffer once so we can just ignore that second one so now we just need to see if we receive another scan code right after that release scan code then we want to ignore it so for that we can just go right up to the top of our keyboard interrupt handler and basically the first thing we can do is check our flags and see if we're in that state where we just received the release scan code and if not then we want to go ahead and read the key and put it in the buffer like normal but if we are releasing a key then we basically don't want to do anything although we do want to reset that release flag we'll go ahead and flip the release bit and update the flags registered and then we really don't want to do anything else [Applause] although we should read from port a because that's what resets the interrupt so we'll get the next interrupt when we get the next key press but otherwise we don't really want to do anything we just want to ignore it so we can just exit the interrupt handler at this point let's save this assemble it and write it to the eeprom we'll put that back in and reset everything and that didn't do anything oh i see what i did the release scan code is f0 not 0f so let's fix that and try again [Applause] let's try this reset and that's more like it and obviously there's still some room for improvement for example shift is just going to give us a question mark whenever we print it because we're not doing anything special to handle it but let's see what it would take to handle shift properly if we go back up to the top here this keyboard flags variable i mentioned we could use it for other flags like shift that's what i'll do i'll use another bit in this flags to indicate whether the shift key is currently being held down and then we'll track that so whenever the shift key is pressed we'll flip that shift bit on and whenever the shift key is released we'll flip that shift bit off and that way at any point in time we'll know whether shift is currently being held down so flags will start out initialized to zero which did we do that we actually didn't do that so i should have done this before is initialize the keyboard flags to zero as well that way when our program starts it doesn't think we're in the middle of releasing a key or it doesn't think the shift key is currently held down and then to handle the pressing and releasing of shift we'll go back down to the keyboard interrupt handler and basically when we read a key in we want to check to see if it's the shift key so just like we were checking to see if we got the scan code for releasing a key we can check to see if it's the shift key so the key that's being pressed is the left shift key then we'll branch to a another label that we'll define down here called shift down and then we'll also check to see if it was the right shift key that was being pressed because there are two shift keys on the keyboard and we you know each of them sends a different scan code so we can need to check both of those but if either of those is pressed then we'll branch down to the shift down label and the code here is actually going to look very similar to the code for the key release because we basically just want to set a flag so we'll load the keyboard flags in this case we're going to flip the shift bit on to indicate that the shift key is down and then store those flags again and that's really all we want to do when the shift key is pressed so at that point we can just jump down and exit the inner paneler so that handles turning the shift flag on when we press the shift key now we need to handle turning the shift flag off when we release the shift key so when we release a shift key for example if we're releasing the left shift key we're going to get f0 and then we're going to get one two so we get the f0 we're going to get a keyboard interrupt with the f0 and then and we're going to handle that just like we would releasing any key we're going to compare it to f0 and we're going to branch to the key release thing where we set that release bit and then we're going to be done with that first interrupt then the second interrupt we're going to get we're going to get a 1 2 saying that the key that's being released is the left shift so we're going to get another interrupt with that one too at this point our flags are going to say that we're currently releasing a key which means we're not going to jump down to the read key instead we're going to basically do this block of code which right now this block of code is just saying to clear the releasing bit and then just read from the 6522 register to clear the interrupt and exit so at this point we're you know this is the point where we're reading the key that's being released but we're just ignoring it but now what we want to do is we want to read that key and then check what it is because we actually care what that key is that we're releasing because if it happens to be one of the shift keys then we want to clear the shift flag so we'll compare that value to see if it's the left shift and if it is then we'll branch to another part of the code that we'll write for handling when the shift key is being released and now we're no longer just reading this just to clear the interrupt we're actually reading the key value that's being released and looking at it and then we also want to check if the right shift was being released and do the same thing so in either case when we're releasing a shift key we want to flip that shift bit back presumably back to zero to indicate that the shift key is no longer pressed [Applause] and then once we've done that we're basically done processing that interrupt so at this point we aren't actually doing anything differently depending on whether shift is pressed or not but we are now keeping track of whether shift is pressed or not in our keyboard flags and so we have a bit now that's indicating whether shift is currently being held down and this will be kept up to date at all times so what do we do about that well if we come down here to where we're reading the key and right now what we're doing is we're reading the key into the a register and then we're using that putting that putting the a register into the x register and then using that as an index into the key map to get a particular character code what we want to do is we want to basically do the same thing but have two different key maps and if shift is being held down then we'll use one key map and if it's not being held down then we'll use the other key map so after we've got the scan code in the x register we can check the flags to see if the shift key is being pressed we'll load the keyboard flags and it with that shift bit [Applause] and then branch not equal which means if the result of that and is not a not zero to uh the shifted key and so if the shift if the key if the shift key is not being held down then it will just continue and do essentially what we're already doing so if shift is not being held down we'll just use the key map to map it to a character and then you know push it onto the keyboard buffer and i'll add a jump here so that we can add some other code here in between to handle the shifted case but for now this label and this jump aren't actually really doing anything because it's just jumping to the next line but in this case where the shift is being held down we're going to jump down or we're going to branch down to the shifted key i can stick that in here and here's where we can handle the case where shift is being held down and basically we're going to do the same thing and i can even copy and paste that line here but instead of mapping to a character code from keymap we can use keymap shifted which is just a different key map that will handle the case where the keys are shifted and so we have one mapping that's done if shift is not being held down and then we jump down to push key here or a different map that if shift is being held down we would jump over that part and use this other map to to map the character code based on a shifted key map so that shifted key map is just going to be a copy of this key map that will change to handle the the shifted stuff so i'm going to make a copy of this and i need to move this back to fd00 so we've got enough room at the end of memory for both of these so we've got our key map and then we'll have a key map shifted and so i'll just go through this key map and for each of the keys i will just change it to the shifted version which you know for letters is just going to be the capital version for numbers it'll be whatever symbol is associated with it and same with some of the other keys and so i'll just change that so that we get whichever character we you know we want to get for when we're holding down shift and we press the the relevant key [Applause] and so that's pretty much everything there so let's uh go ahead and give this a try we'll save it assemble it write it to the prom and let's give this a try reset so that's still working fine and if i hold down shift i get capital letters how about that so that looks like it's working so i think i'll leave it there because i think this gives you a pretty good idea of what's possible and you can certainly use your imagination to add your own functionality if you want like pressing enter to get to a new line or pressing escape maybe to clear the screen but hopefully with this video you've got the tools you need to come up with your own ideas and figure out how to implement them yourself and of course if you are interested in building your own computer check out eater.net 6502 for more details on how to get started including kits and hopefully that 6502 kit really is just a starting point because you can interface all sorts of things like i'm showing you here with the keyboard and you can come up with all kinds of your own designs and it's really cool to see what people have been doing with it so check it out and of course as always i want to thank all my patrons whose continuing support helps make all these videos and everything possible so thank you you
Original Description
Support these videos on Patreon: https://www.patreon.com/beneater or https://eater.net/support for other ways to support.
------------------
Social media:
Website: https://www.eater.net
Twitter: https://x.com/beneater
Patreon: https://patreon.com/beneater
Reddit: https://www.reddit.com/r/beneater
Special thanks to these supporters for making this video possible:
Aaron Todd, Aleksey Smolenchuk, Alexander Wendland, Andrew C. Young, Anson VanDoren, Anthanasius, anula, Armin Brauns, Asherah Connor, Ben Cochran, Ben Dyson, Ben Kamens, Ben Williams, Benny Olsson, Bill Cooksey, Binh Tran, Bouke Groenescheij, Bradley Pirtle, Bradley Stach, Brent Reusing, Brian T Hoover, Bryan Brickman, Bryan Glezerson, Carlos Ambrozak, Christopher Blackmon, Dale Andrew Darling, Daniel Jeppsson, Daniel Tang, dans, Dave Burley, Dave Walter, David Brown, David Clark, David Cox, David House, David Sastre Medina, David Turner, David Worsham, Dean Winger, Dissy, dko, Dmitry Guyvoronsky, Dušan Dželebdžić, Dzevad Trumic, Emilio Mendoza, Eric Dynowski, Erik Broeders, Eugene Bulkin, George Miroshnykov, Harry McDow, Ian Tait, Ingo Eble, Ivan Sorokin, James Capuder, james schaefer, Jared Dziedzic, Jason DeStefano, Jason Specland, JavaXP, Jaxon Ketterman, Jay Binks, Jayne Gabriele, Jeremy A., Jim Kelly, Jim Knowler, Jim Van Meggelen, Joe Beda, Joe OConnor, Joe Pregracke, Joel Miller, John Fenwick, John Meade, Jon Dugan, Joseph Portaro, Joshua King, Jurģis Brigmanis, Kai Wells, Kefen, Kenneth Christensen, Kent Collins, Kitick, Koreo, Lambda GPU Workstations, Larry, László Bácsi, Lucky Resistor, Lukasz Pacholik, Marcos Fujisawa, Marcus Classon, Mark Day, Martin Roth, Mats Fredriksson, Matt Krueger, Matthäus Pawelczyk, Matthew Duphily, melvin2001, Michael Tedder, Michael Timbrook, Michael Weitman, Miguel Ríos, mikebad, Mikel Lindsaar, Miles Macchiaroli, moi n, Nicholas Counts, Nicholas Moresco, Nick, Not Yet Wise, Örn Arnarson, Paul Pluzhnikov, Paul Randal, Pete Dietl, Phil Dennis, Philip Hofs
Watch on YouTube ↗
(saves to browser)
Sign in to unlock AI tutor explanation · ⚡30
Playlist
Uploads from Ben Eater · Ben Eater · 47 of 60
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
▶
48
49
50
51
52
53
54
55
56
57
58
59
60
KA 60 Minutes Sep 2013 rerun (10x speed)
Ben Eater
Frame formats | Networking tutorial (6 of 13)
Ben Eater
TCP: Transmission control protocol | Networking tutorial (12 of 13)
Ben Eater
Clock synchronization and Manchester coding | Networking tutorial (3 of 13)
Ben Eater
TCP connection walkthrough | Networking tutorial (13 of 13)
Ben Eater
Lower layers of the OSI model | Networking tutorial (7 of 13)
Ben Eater
Hop-by-hop routing | Networking tutorial (11 of 13)
Ben Eater
Sending digital information over a wire | Networking tutorial (1 of 13)
Ben Eater
ARP: Mapping between IP and Ethernet | Networking tutorial (9 of 13)
Ben Eater
Analyzing actual Ethernet encoding | Networking tutorial (4 of 13)
Ben Eater
Intro to fiber optics and RF encoding | Networking tutorial (2 of 13)
Ben Eater
The Internet Protocol | Networking tutorial (8 of 13)
Ben Eater
Looking at ARP and ping packets | Networking tutorial (10 of 13)
Ben Eater
The importance of framing | Networking tutorial (5 of 13)
Ben Eater
Programming my 8-bit breadboard computer
Ben Eater
Programming Fibonacci on a breadboard computer
Ben Eater
Connecting to a mystery signal | Digital electronics (4 of 10)
Ben Eater
Using a transistor to solve our problem | Digital electronics (8 of 10)
Ben Eater
Inverting the signal with a transistor | Digital electronics (9 of 10)
Ben Eater
8-bit computer update
Ben Eater
Bus architecture and how register transfers work - 8 bit register - Part 1
Ben Eater
RAM module build - part 2
Ben Eater
Using an EEPROM to replace combinational logic
Ben Eater
Build an Arduino EEPROM programmer
Ben Eater
Build an 8-bit decimal display for our 8-bit computer
Ben Eater
8-bit CPU control logic: Part 2
Ben Eater
Reprogramming CPU microcode with an Arduino
Ben Eater
Update and PODCAST ANNOUNCEMENT!
Ben Eater
The case against Net Neutrality?
Ben Eater
Making a computer Turing complete
Ben Eater
CPU flags register
Ben Eater
Conditional jump instructions
Ben Eater
“Hello, world” from scratch on a 6502 — Part 1
Ben Eater
What is a stack and how does it work? — 6502 part 5
Ben Eater
RAM and bus timing — 6502 part 6
Ben Eater
Subroutine calls, now with RAM — 6502 part 7
Ben Eater
Why build an entire computer on breadboards?
Ben Eater
How assembly language loops work
Ben Eater
Binary to decimal can’t be that hard, right?
Ben Eater
Hardware interrupts
Ben Eater
What is error correction? Hamming codes in hardware
Ben Eater
Installing the world’s worst video card
Ben Eater
World's worst video card gets better?
Ben Eater
Breadboarding tips
Ben Eater
So how does a PS/2 keyboard interface work?
Ben Eater
Keyboard interface hardware
Ben Eater
Keyboard interface software
Ben Eater
How does a USB keyboard work?
Ben Eater
How does USB device discovery work?
Ben Eater
How does n-key rollover work?
Ben Eater
SPI: The serial peripheral interface
Ben Eater
Why was Facebook down for five hours?
Ben Eater
How do hardware timers work?
Ben Eater
The RS-232 protocol
Ben Eater
Hacking a weird TV censoring device
Ben Eater
Let's build a voltage multiplier!
Ben Eater
6502 serial interface
Ben Eater
RS232 interface with the 6551 UART
Ben Eater
Fixing a hardware bug in software (65C51 UART)
Ben Eater
Running Apple 1 software on a breadboard computer (Wozmon)
Ben Eater
More on: Tool Use & Function Calling
View skill →Related Reads
📰
📰
📰
📰
Database Internals: 4 Things Every Developer Should Learn Before Writing More Code
Medium · Machine Learning
Ranking Numeric Values using Power Query(.pbix included)
Medium · Data Science
The Data Foundation for Finance Transformation at Enterprise Scale
Medium · Data Science
Your Pipeline Is 25.4h Behind: Catching Defence Sentiment Leads with Pulsebit
Dev.to · Pulsebit News Sentiment API
🎓
Tutor Explanation
DeepCamp AI