I just got a job at a major chipset and GPU manufacturer this week as a driver, BIOS and firmware developer. Thank you Benjamin, your videos have been a MAJOR inspiration to me!
Noice, I'm just doing driver + firmware on the audio side at a decently major manufacturer. It's fun, despite being quite hard. You want to appreciate the hard parts.
On button press, you could disable CA1 interrupts and instead enable a timer, then when the timer expires turn on CA1 interrupts again. That should succeed in debouncing without having to spin inside the interrupt handler, plus it would show off timer functionality.
I was thinking of clearing the interrupt, and then just test the interrupt flag again after you're done with the ISR, and if it's set again by a bounce, clear it again (and then, repeat.. possibly with a VERY short delay). That should be good enough, and not cause the huge delay his 64k counter caused.. Of course, hardware would be better..
The most simple circuitry to use is a capacitor and a Schmitt trigger. If the button is active high (ie, 0 to 5v) it will charged the cap, but the cap doesn’t have time to discharge before each subsequent bounce recharges the cap. Once the bouncing stops the cap discharges. The Schmitt trigger tidies up the voltage output to ensure a nice square pulse is created. Essentially it works the same active low, and by employing different resistors, a smaller one on the button and a larger on the discharge circuit, you can minimise the rise time and maximise the fall time to eliminate bounce completely. Hackaday has a good article on alternatives. hackaday.com/2015/12/09/embed-with-elliot-debounce-your-noisy-buttons-part-i/
A idea I had to demonstrate the timer would be to move the debounce to the 6522. 1)Add code to see if the source is ca1 or timer. when ca1 do: a)set the timer as the interrupt source b)Clear ca1 as a interrupt handler c)clear ca1's interrupt. d)set a 500 ms timer. When timer: a)clear the timer as interrupt source b)clear the timer interrupt c)Enable ca1 as a interrupt source again.
May be a better way is to just use the timer to generate an interrupt at suitable interval, and connect the switch(es) to the input(s) of the 6522 and see what button is pressed. If you use a matrix keyboard, (set an output to select a row, and then read which of the columns is energised via a switch), you can scan at a much higher rate and make the system quite responsive.
There are quite a few ways to scan keys and debounce in software. Probably as many as people who's opinion you can ask. 😋 In one of my own projects involving a Z80 I use a similar method - I scan at a regular interval and keep a note of which buttons are seen as pressed consistently for at least a couple of scan intervals, and then update a variable to indicate which buttons are considered pressed. The rest of the software only looks at that variable, so doesn't have to worry about delaying or doing anything funky itself. When it sees a bit set, it knows the button is pressed. I also use a second variable to "acknowledge" a button press which basically just masks it out of the first variable until the button is released. This way I can either take a button press as a "one shot", or implement "long presses with increasing velocity", for example.
@@TomStorey96 I was thinking the same, (although hadn't considered detecting a long press). A nice design having the application only have to check a memory location to see which key is pressed. The interesting thing is, that although Ben is using the 6522 PIO chip, and I think Zilog had an equivalent one for the Z80, I don't think any (mass production) computers of the early 1980's ever used them. Rather IO was done via custom ULA (or equivalent), which could do all the keyboard decoding using logic gates; the easiest way being to have the switch set a flip-flop, and then poll the flip flop output periodically and then reset it.
Another great video, huge thanks Ben. Just a heads up for others following along, at 20:05 you can use the *phx* and *phy* opcodes of the *65c02* to push the x and y registers to the stack directly. Similarly, you can pop them off with the *plx* and *ply* opcodes.
Hi, I believe the vasm referred by Ben here does not support these opcodes. I tried and got an error: vasm6502_oldstyle.exe Interrupt_VIA.s -Fbin -o Interrupt_VIA.out -dotdir vasm 1.8g (c) in 2002-2019 Volker Barthelmann vasm 6502 cpu backend 0.8 (c) 2002,2006,2008-2012,2014-2018 Frank Wille vasm oldstyle syntax module 0.13f (c) 2002-2018 Frank Wille vasm binary output module 1.8a (c) 2002-2009,2013,2015,2017 Volker Barthelmann error 9 in line 177 of "Interrupt_VIA.s": instruction not supported on selected architecture > phx error 9 in line 178 of "Interrupt_VIA.s": instruction not supported on selected architecture > phy error 9 in line 192 of "Interrupt_VIA.s": instruction not supported on selected architecture > ply error 9 in line 193 of "Interrupt_VIA.s": instruction not supported on selected architecture > plx
@@ParthSarthiSharma yeah, ben is trying to make it accessible to anyone with a 6502, not just 65c02 or wdc 65c02. for vasm you need to add "-c02" if you want to use 65c02 opcodes.
20:00: you say, you can't push X and Y registers to stack directly and have to use "TXA/ PHA" instead. That's not correct for the WDC W65C02S, that you use in your projects. The W65C02S has opCodes for PHX, PHY, PHA and PHP. For pushing the registers directly. And you can use PLX, PLY, PLA and PLP to pull the values from stack again.
I've been thinking a lot about working on his breadboard computer then framing it when I'm done and maybe leave it running while hanging on the wall, with all the blinkenlights, running some kind of demoscene maybe
This videos are the best!!! Thanks for this content. I am currently finishing my physics major and this kind of content is the perfect addition to my theoretical knowledge. Sadly so many physicists disregard the importance of having at least some engineering knowledge, but I hope I can be a better professional thanks to the knowledge I aquire with your videos.
For debouncing, I just add a small ceramic capacitor across the two leads of a (normally open) momentary push button. It works really well with arduino and AVR projects. It's a really simple analog solution to the problem.
@@renakunisaki You're literally shorting a capacitor by the button. It will arc. A 100nF capacitor obviously won't instantly vaporize the button, but it does speed up the wear of the contacts.
Back when I was in school learning these things, that was exactly my response to this problem. But the teacher said "Don't use analog solutions for digital problems." I was so confused ... But now I know what he meant: By adding a capacitor you don't have nice "digital" signals any more. Beause as the cap is charging or discharging, you get all sorts of voltages between 0 and 5 volts. The microprocessor does not like that! So you would also need a schmitt-trigger to make the signal from the switch "digital" again.
Great video. A simple way to make a digital switch debouncer and not use an analog 555 timer with the capacitor and resistors is to use a push button switch that has both normally open (NO) and normally closed (NC) contacts. You feed that into 2 NAND gates with cross feedback to form a latch. The NO side of the switch goes to one NAND gate pin with a 10k pullup, and the NC side of the switch goes to a pin with another 10k pullup on the other NAND gate. That was a good idea to show how debounce can be done in software as well. Sometimes when I don't care how long the Interrupt Service Routine (ISR) is I just throw in a loop like you did. Also, to the viewers: It is a good idea that when you first learn to code ISRs, to have a template that you can cut and paste from your "repertoire" code. I suggest you learn how to save the ENTIRE state of the CPU on the Stack as you enter the ISR and pop it all off the Stack before you return from the ISR. This is handy when you will do context switching (like in multithreading) as you get more advanced. Coders sometimes forget to push the CPU Flags register on the Stack, do this first because many op codes do effect the flags and they too should be exactly as they were before the interrupt was handled (called). So having a full context save of the CPU is good to have at hand even if your ISR does not change everything in the CPU, but you can trim out what you don't need if you need to make your ISR as short (fast) as possible, but don't forget the save the Flags register on the Stack first in almost all cases.
Your videos are so clear and interesting that I am just binging on them. It is amazing. Minor nitpick on your aside on having multiple IRQ inputs. You mention at 23:25 that we could "AND them together in some way". I think you mean to OR them together. Unless you're building a system that is extremely discerning to inputs, of course :)
It's been decades since I used a 6502 CPU. I remember using a flip flop to control the IRQnot pin on it. I would set a flip-flop which would force its Qnot output to go low and make IRQnot active low to request the interrupt, and then some of the signals from the CPU could be decoded to clear the flip-flop (Qnot, thus IRQnot, goes back to inactive high) as its enters the Interrupt Service Routine to generate only one interrupt per interrupt signal edge.
Just finished watching the entire series and even though I don't have breadboards, chips and all the stuff to follow, still I've managed to get the very gist of the tutorials to pick up those key parts that are required for cycle accurate emulation of a 6502 based computer. Thank you so much Ben for making such a detailed series explaining every single bit of information I could've ever dreamed to learn from a single source in regards to 6502 emulation.
Interesting. I didn’t know the 6502 automatically pushed the flags register onto the stack and pulled it from it. Coming from the Z80 background, I learned it the hard way a long time ago to push and pull the AF register (you can only push and pull sixteen-bit registers, so the flags register and the accumulator are pushed and pulled together). Pushing and pulling can be expensive, though, so there are much quicker EXchange instructions that switch between the two sets of registers in the Z80.
The Z80's NMI is edge triggered, thus solving the problem of re-entering over and over again for level-triggering. Too many microcontrollers have the same problem of "exchange register": there's no way to track for double-flips. The Z80, as Moore said, has the exchange-register command. The Microchip PIC-18 similarly has "shadow registers" that are easily clobbered. Use in only ONE place for ONE situation. I doubt there's any auto-checker to flag possible double-use cases :-(
I'm familiar with the Z80 more than 6502 as well but I've never been able to get my hands on any hardware so since I was always using an emulator I never needed interrupts. Right now I'm designing a z80 computer hardware though so maybe one day I'll be able to actually play with the real thing...
@@JeffreySJonas I guess the way you're supposed to deal with double flips is: only ever use the shadow registers in IRQs, never allow nested interrupts, and be very careful.
At 13:51: PortA has 8 bits, true you could OR them so 8 different sources can generate the CA1 interrupt, but I think the more popular use was to provide an 8-bit interrupt vector for CA1. This way, when the interrupting device (say a disk drive) initiates CA1, it puts an 8-bit value on PortA so the Interrupt Service Routine (ISR) can read PortA (IRA), which clears the interrupt while telling the ISR something about the interrupt, like say, $21 (disk head is on requested track), or $20 (disk head is home)... things along those lines. But there are many more ways to use these interrupts.
Love how you can create read in multiple inputs as interrupts. One project, we used one of the timers as a 'watchdog' that would verify the main CPU program wasn't 'stuck' as well. (a bit of code, setting a semaphore in main code and testing in watch-dog's handler). Delay loops in the handlers can be a bit 'kludgy' though. If there's a second event while in delay, miss it completely. But you covered that, so.... great video. I've unmasked my interrupt, ready to detect the next video release. :)
I've been a software guy for my entire career and now I'm retired and learning about hardware. Back in the day I had an Apple //e that I programmed mostly in assembler, so a lot of what you've been going over is familiar, but I never did any hardware back then. So it's been fascinating to see how you might interface the familiar old 6502 to various hardware. Thanks!
The last time I was writing 6502 interrupt code was on a wire wrapped pin board in the middle 1980s. It was a home-brew midi sequencer that connected serially to a PDP11. That said, software delay loops are inadvisable. Software delay loops at interrupt level are unfortunate. If you really need software denounce, there are so many better ways to do it. The VIA timer was what came to mind while watching, but I am far too late to be the first to suggest it.
Ben You are a fantastic teacher. I hope you will continue with this 6502 project... I can see, perhaps, we are on our way to a breadboard Apple I computer.... all we need is a few more things... keyboard... storage... primitive monitor (OS) program.... and so on...
EDIT: nevermind since X gets decremented again it just loops back to 255 anyway. But it would be nice to be explicit :p Ignore this comment I guess it's just here for historical reasons. Dunno if this is a mistake but when the outer loop loops it doesn't reset x register for the inner loop. Idk if I explained well so I'll just write some code: (I don't know 6502 assembly but it should be close enough) ldy 0xFF outer: ;this is the bit that's missing ldx 0xFF inner: decx bne inner decy bne outer ;don't go back to the same bit
Ohhh I was thinking the same thing, but your right. Although, even if x wasn't decremented it would just loop 510 times, which i thought before was what he was doing.
Glad I found this. I was wondering, if X can be negative or what happens when calling DEX after X already is 0. So now I asusme, DEX (with X being 0) would then set X to 255 again. Then Ben's code makes totally sense to me (finally).
This is like the wayback machine for me. Back in the early 80s I was writing interrupt service routines and terminate and state resident programs in ASM to handle input from various sensors like strain gauges and tilt/inclinometers through a custom device I built. Now I just use a Raspberry Pi, Arduino and or ESP32.
dude, these videos are awesome. i just finished the last one you have in this playlist and have also done the breadboard computer series. i am also building the breadboard computer, but with a twist of making the components plug into a motherboard type bus. i really want to keep playing, but i find the wires on breadboard are a little frustrating for long term use. these videos have finally given me the ability to truly umderstand how things work within the cpu and then how it interects with the outside world. thanks again for your great passion for the topic and your teaching skills. i am so bumping up my patreon support for you. please please keep adding to both those playlist. cheers
Nice to see people still know how to use a data sheet and program in anything other than arduino or raspberry pi, gives some hope to humanity. BTW, nice job at wiring as well. You made your mentor proud even if you learned it from your own research.
Yes, it's not a good idea to put a delay in an interrupt handler. A better solution, instead of incrementing the counter in the interrupt, is to flag the button press in memory, and then move the increment and the debounce delay into the main code loop. Delaying in an interrupt would effectively freeze all other interrupt handling. Obviously it's not a problem in this particular case, but something to keep in mind for other interrupts. As a bonus side effect, from the main code, you could update the output immediately, and then run the debounce delay loop.
Also I just want to say watching around 15 of your videos taught me more about assembly and actual hardware than my entire bachelor's in CS did. Great stuff! Wish I could pay the student loans to you instead of the govt
An easy way to debounce the switch would be to add a capacitor in parallel with the pull up resistor. A time constant (R times C) of about 10ms would be about right from my experience.
I saw this video yesterday, thought I would watch it someday after I finish with ben eater's earlier videos, and then today I was doing something with interrupts and just to brush up on the subject I searched on UA-cam "interrupt handling" never actually remembering this was the title of the video.
In the delay function you're Dec x to zero, then y by one, then Dec x again to nonzero (likely ff, but depends on cpu complement system) then Dec x to zero again before Dec y again. So it's delaying for (0xFF)×(0xFF) loops instead of (0xFF)+(0xFF) . Break it to two delay loops or call delay twice to fix the latency issue
"Likely ff but depends on cpu complement system"? No need to guess! We know the CPU. The 6502 is of course twos-complement as God intended. (And yes, he knows you're getting 255×256-1 instead of 255+255 iterations. That was the point. He did mention you could probably go significantly shorter if you wanted to spend time tuning it. Just initialize Y to a smaller value.)
Thanks Ben. In future videos, please do one on timers and implement a paced function (eg. 10ms_cyclic) and move that debouncing loop out of irq handler. I know the cpu isn't doing nothing else. But putting a spin delay in irq handler is doing my head in :(
Initialising registers is of course important, but it also provides a place in your code to document stuff you’ve read in the datasheet. Everything you’ve browsed deserves a place in your code, even if it isn’t quite relevant now. 6 months on, you will pleasantly surprised to be reminded of obscure control registers and such.
this video could not have come at a more perfect time. im designing something that uses an fpga to talk with the 6502s big brother, the 65c816. i had a plan on what to do and this confirms I'm on the right track.
@@Tuxfanturnip I was looking through the comments to see if anyone had noticed that the X register was never set back to $FF. I missed the fact that DEX would cause $00 to become $FF. I've never programmed the 6502, (Z80 fan boy), so was reading up the 6502 instruction set to verify your comment. As DEX will set the Negative Flag if the bit 7 is 1, then starting at $FF is a bit naughty as we'll be counting -1 to -128 then flick over 127 and count down to 0.
@@axelBr1 The X and Y registers are unsigned. Sure they set the negative flag but in all operations which matter, like the index indirect and indirect index addressing modes they X and Y register are used as an unsigned values.
This is awesome stuff. Now I would like to see you marry your world's worst video card with the 6502 and have it display the RAM contents then the dreams of my childhood will finally be fulfilled :P
It's actually very simple, I'm currently working on connecting that video card to my Z80 computer. Just replace the EEPROM with dual-port RAM, with one side connected to the video card and the other side to the CPU.
@@k4ktus Not that easy, because now you need some kind of bootstrapper to get your program in memory. That's usually done by BIOS to load the first sector or whatever, so you would have to implement something similar with a wait state for the CPU while the firmware executes and loads your program.
@@k4ktus You'll have to allocate some memory area (called video memory), the videocard will be rendering from. When you want to render something, you'll need to put a contents into that area. Ben Eater is rendering from eeprom, but it can easily be replaced with allocated RAM area. But to render some image next you need to imagine how to translate commands to some kind of figures or anything else you want to display. For example, for rendering circle you need to integrate the circle equation (x-a)^2+(y-b)^2=R^2 and bound it with user parameters (such as a, b, etc). The result array of this equation must be placed into that allocated video memory. Then you'll se a circle on a display.
Now to add an interrupt dispatcher. And a timer queue. Oh, and do that timer debounce thing everyone is suggesting. Also, an event queue so that the main program can reach a safe position before handling the events.
If you want to initialize everything properly, I think you should disable all the other interrupts in the interrupt enable register, just as you enabled the CA1 interrupt. I guess they're already being initialized as disabled though, otherwise the program would probably have got stuck servicing interrupts forever.
That delay loop though. I think it works because X underflows and implicitely resets to ff from zero at dex immediately after the jump back after dey, so you don't need to explicitly reset X at every iteration on Y. But you didn't say that out loud, so it's a bit confusing
Yes, think the intention was probably to write the loop at 19:37 as ldy #$ff delay_outer ldx #$ff delay_inner: dex bne delay_inner dey bne delay_outer instead of ldy #$ff ldx #$ff delay: dex bne delay dey bne delay But as I'm sure you already figured out, we could have had e g ldx #$0 instead, and that would work to loop 256 times, because the first time through the loop would decrement x to make it wrap around to 255, and then it's not zero so the bne would jump. So when bne delay after dey jumps back, x is 0 and the next x loop will go around 256 times.
I have followed this series from start to finish and find it fascinating and very well explained. (TLDR; Thankyou Ben) It would be cool if the interrupt handling could be used to implement an approximation of concurrency with multiple processes Something like..... Set up the 6522 to generate an interrupt every ms. The interrupt handler saves the AXY registers on the stack It then sets some (new) address decoding logic to swap out the stack for another page of memory (holding another stack for anther process) We pull that stacks registers back to AXY RTI would then return to the new process Repeated timer interrupts would effectively swap between processes? It struck me that the memory chip is only being half utilised so maybe could use the extra memory for the paged stacks (This struck me as a good idea for one of your future videos. Hint hint.)
Ben, are there any plans to add a keypad to this system for viewing and adding programs directly into memory as well as to view and set register values? Similar to a KIM-1 or any other CPU trainer?
Why not port the KIM-1 monitor to this board? This will give us cassette recording and ASR-33 interface. Source code can be found online. I still have a KIM-1 in working condition. Purchased in 1981 when I was 21 years old.
Hi Ben, I think that it would be really interesting to use some form of PLA to create a more efficient memory map. Do you think that would be possible for you to do?
Hello Ben! After this series is finished, do you think there will be any possibility of making a video about hooking this up to the "worst video card" you made a year ago. That'd be amazing.
i think there should have a strong community for microcontroller and electronics engineers such as we see that AI, ML, web developers, app developers has.
Do you have a description of the overall goal of these videos? You've got me wondering if I can manage to build my own BASIC executing PC, like the color maximite , from scratch, including writing the OS rom. It's starting to sound like a fun project. I'm wondering how far your videos would get me to that. Thanks!
1986: to play this game with a working soundcard on my dos 1.1 computer i need to edit some strange irq setting in bios 2021: find this video on my smartphone and fully anderstand every detail of what i was doing back then thanks a lot!
Ben the delay is slow because it starts delay and DeX and then goes back to delay when x is equal it goes to dey and hen go back to delay so it's going through the full DeX for every 1 of the dey's so its 65535 times the #of clock cycles in 2 branch instruns and 2 decrement instructions
Instead of the debounce software, I stuck a 100nF cap across the switch and it seems to work well. EDIT: Though not perfectly. 2nd EDIT: Now it's a 555 monostable circuit with a 10nF cap across the switch as well.
From the data sheet ( eater.net/datasheets/w65c22.pdf ): "Both PA and PB operate in conjunction with a Data Direction Register (DDRA or DDRB). Under program control, the DDRA and DDRB specify which pins within the port bus are to be designated as inputs or outputs. Logic 0 in any bit position of the register will cause the corresponding pin to serve as an input; while a logic 1 will cause the pin to serve as an output." Each pin is a single bit, so you can set the directions for different bits within the same register byte independently of each other.
@@chrisbattey Ah. You're right, I'm wrong, egg on my face. I hadn't cottoned on to the fact that these aren't just bits toggling the ports in or out wholesale, but that there's an actual byte-for-byte and bit-for-bit correspondence between the 8-bit ports and 8-bit registers. The link parser has eaten your bracket though, so you might wish to edit that for the link to be easier to click, so people won't have to manually delete the closing bracket for it to work. Thanks.
@@ropersonline Yeah, when that first came up a few videos back I thought it was kinda weird at the time, but the idea of handling multiple separate single-bit interrupt lines through the 6522 makes it seem a lot more reasonable. (And thanks for letting me know about the link - enough sites have figured out how to be smart about that by now that I keep getting caught off-guard by the ones that aren't...)
Could you use one of the 6522 timers for debouncing? If the switch remains in the same state without changing for longer than it takes the timer to run out, it must not be bouncing .....
Most of my lectures in college were an hour of a complicated solution for a problem to teach a concept, and then right at the end the lecturer would reveal that you'd never actually do it because there's a much easier way.
Not gonna help. The switch is still gonna be low for a long period of time and trigger multiple interrupts, since it's not triggered by a level change, but by low signal
Could you re-implement the busyflag polling with interrupts and WTI instruction? Not immediately obvious how to do that but it should be possible I think -- after all the 6522 is designed to do this sort of thing. One way of doing it I think is tie busyflag output (pin 3 of LCD) to CB1 and in our lcd_wait routine to enable interrupts on CB1; then we could read B and as long as it's not busy, disable the interrupt. There might be some undesirable bouncing on ORB but actually checking the busy bit should take care of that I think.
Interrupt Handling: how I responded to the notification for this video.
Lol mee to!
David Taylor I think you’re basically saying that a Ben Eater video alert is a Non Maskable Interrupt! :)
@@gregclare Absolutely. Hard coded: stop everything and Pay Attention!
> notification
Mr. Fancy pants. I have to keep polling since august :(
And definitely wasn't masked.
I just got a job at a major chipset and GPU manufacturer this week as a driver, BIOS and firmware developer. Thank you Benjamin, your videos have been a MAJOR inspiration to me!
This would have been an insanely good comment if you stopped at "as a driver."
Noice, I'm just doing driver + firmware on the audio side at a decently major manufacturer. It's fun, despite being quite hard. You want to appreciate the hard parts.
@@typedef_ Um, alright. But I wasn't trying to be funny.
Do us a favor and leave a backdoor in the driver/firmware validation so we can use open source stuff?
@@Aeroshogun Yeah, ok lol
35 years after me fiddling with the 6502 when it was hot and I in a tender age, Ben Eater makes the perfect tutorial how to do it right.
Im curious. Did you manage to do something with it?
@@ignaciosavi7739 idk i am not him
@@plutarian7396 Ice age baby
@@ignaciosavi7739 agreed
On button press, you could disable CA1 interrupts and instead enable a timer, then when the timer expires turn on CA1 interrupts again. That should succeed in debouncing without having to spin inside the interrupt handler, plus it would show off timer functionality.
I've been reading the datasheet to figure out how to do that since the last video. Hopefully that's where he goes with the next video.
I was thinking of clearing the interrupt, and then just test the interrupt flag again after you're done with the ISR, and if it's set again by a bounce, clear it again (and then, repeat.. possibly with a VERY short delay). That should be good enough, and not cause the huge delay his 64k counter caused.. Of course, hardware would be better..
The most simple circuitry to use is a capacitor and a Schmitt trigger. If the button is active high (ie, 0 to 5v) it will charged the cap, but the cap doesn’t have time to discharge before each subsequent bounce recharges the cap. Once the bouncing stops the cap discharges. The Schmitt trigger tidies up the voltage output to ensure a nice square pulse is created. Essentially it works the same active low, and by employing different resistors, a smaller one on the button and a larger on the discharge circuit, you can minimise the rise time and maximise the fall time to eliminate bounce completely.
Hackaday has a good article on alternatives. hackaday.com/2015/12/09/embed-with-elliot-debounce-your-noisy-buttons-part-i/
A capacitor across a switch can also debounce. But it's not so funny.
A idea I had to demonstrate the timer would be to move the debounce to the 6522.
1)Add code to see if the source is ca1 or timer. when ca1 do:
a)set the timer as the interrupt source
b)Clear ca1 as a interrupt handler
c)clear ca1's interrupt.
d)set a 500 ms timer.
When timer:
a)clear the timer as interrupt source
b)clear the timer interrupt
c)Enable ca1 as a interrupt source again.
You probably don't need 500ms (maybe 50ms max), but otherwise the logic is sound
May be a better way is to just use the timer to generate an interrupt at suitable interval, and connect the switch(es) to the input(s) of the 6522 and see what button is pressed. If you use a matrix keyboard, (set an output to select a row, and then read which of the columns is energised via a switch), you can scan at a much higher rate and make the system quite responsive.
There are quite a few ways to scan keys and debounce in software. Probably as many as people who's opinion you can ask. 😋
In one of my own projects involving a Z80 I use a similar method - I scan at a regular interval and keep a note of which buttons are seen as pressed consistently for at least a couple of scan intervals, and then update a variable to indicate which buttons are considered pressed.
The rest of the software only looks at that variable, so doesn't have to worry about delaying or doing anything funky itself. When it sees a bit set, it knows the button is pressed.
I also use a second variable to "acknowledge" a button press which basically just masks it out of the first variable until the button is released. This way I can either take a button press as a "one shot", or implement "long presses with increasing velocity", for example.
@@TomStorey96 I was thinking the same, (although hadn't considered detecting a long press). A nice design having the application only have to check a memory location to see which key is pressed.
The interesting thing is, that although Ben is using the 6522 PIO chip, and I think Zilog had an equivalent one for the Z80, I don't think any (mass production) computers of the early 1980's ever used them. Rather IO was done via custom ULA (or equivalent), which could do all the keyboard decoding using logic gates; the easiest way being to have the switch set a flip-flop, and then poll the flip flop output periodically and then reset it.
@@axelBr1 C64 had two 6522s if I am not mistaken. Or at least something which was very similar.
Another great video, huge thanks Ben. Just a heads up for others following along, at 20:05 you can use the *phx* and *phy* opcodes of the *65c02* to push the x and y registers to the stack directly. Similarly, you can pop them off with the *plx* and *ply* opcodes.
Hi, I believe the vasm referred by Ben here does not support these opcodes. I tried and got an error:
vasm6502_oldstyle.exe Interrupt_VIA.s -Fbin -o Interrupt_VIA.out -dotdir
vasm 1.8g (c) in 2002-2019 Volker Barthelmann
vasm 6502 cpu backend 0.8 (c) 2002,2006,2008-2012,2014-2018 Frank Wille
vasm oldstyle syntax module 0.13f (c) 2002-2018 Frank Wille
vasm binary output module 1.8a (c) 2002-2009,2013,2015,2017 Volker Barthelmann
error 9 in line 177 of "Interrupt_VIA.s": instruction not supported on selected architecture
> phx
error 9 in line 178 of "Interrupt_VIA.s": instruction not supported on selected architecture
> phy
error 9 in line 192 of "Interrupt_VIA.s": instruction not supported on selected architecture
> ply
error 9 in line 193 of "Interrupt_VIA.s": instruction not supported on selected architecture
> plx
@@ParthSarthiSharma yeah, ben is trying to make it accessible to anyone with a 6502, not just 65c02 or wdc 65c02. for vasm you need to add "-c02" if you want to use 65c02 opcodes.
20:00: you say, you can't push X and Y registers to stack directly and have to use "TXA/ PHA" instead.
That's not correct for the WDC W65C02S, that you use in your projects. The W65C02S has opCodes for PHX, PHY, PHA and PHP.
For pushing the registers directly. And you can use PLX, PLY, PLA and PLP to pull the values from stack again.
I don't think he's really used to the 65C02. He used JMP instead of BRA, too, in previous videos.
This should be as study in school, high school, this is very important information, a circuit board class is needed.
I was just thinking I could start working on your breadboard computer, and then you post. Thanks!
I've been thinking a lot about working on his breadboard computer then framing it when I'm done and maybe leave it running while hanging on the wall, with all the blinkenlights, running some kind of demoscene maybe
This videos are the best!!! Thanks for this content. I am currently finishing my physics major and this kind of content is the perfect addition to my theoretical knowledge. Sadly so many physicists disregard the importance of having at least some engineering knowledge, but I hope I can be a better professional thanks to the knowledge I aquire with your videos.
For debouncing, I just add a small ceramic capacitor across the two leads of a (normally open) momentary push button. It works really well with arduino and AVR projects. It's a really simple analog solution to the problem.
It will also drastically shorten the button's life.
@@404Anymouse ...how?
@@renakunisaki You're literally shorting a capacitor by the button. It will arc. A 100nF capacitor obviously won't instantly vaporize the button, but it does speed up the wear of the contacts.
Back when I was in school learning these things, that was exactly my response to this problem.
But the teacher said "Don't use analog solutions for digital problems."
I was so confused ...
But now I know what he meant:
By adding a capacitor you don't have nice "digital" signals any more.
Beause as the cap is charging or discharging, you get all sorts of voltages between 0 and 5 volts.
The microprocessor does not like that!
So you would also need a schmitt-trigger to make the signal from the switch "digital" again.
Love you man for doing this great series consistently over a long period. I'm so grateful to you
"When the button was DePressed" I feel sorry for that button now :(
Meanwhile the button:
Dame da ne! Dame yo! Dame na no yo!
Anata ga suki de sukisugite!
Dore dake tsuyoi osake demo,
Yugamanai, omoide ga, baka mitai!
So the TL;DR is basically:
*interrupt happens*
CPU: emergency meeting
that would be a maskable one coz you can't call it during the emergency
@@not_just_burnt Exactly, you can't call an emergency meeting during a sabotage emergency, so it's maskable by the sabotage
NMI happens
CPU: dead body reported
@@paulstelian97 lol exactly
that's why its called an "interrupt": it interrupts whatever's going on to call the emergency meeting.
Great video. A simple way to make a digital switch debouncer and not use an analog 555 timer with the capacitor and resistors is to use a push button switch that has both normally open (NO) and normally closed (NC) contacts. You feed that into 2 NAND gates with cross feedback to form a latch. The NO side of the switch goes to one NAND gate pin with a 10k pullup, and the NC side of the switch goes to a pin with another 10k pullup on the other NAND gate. That was a good idea to show how debounce can be done in software as well. Sometimes when I don't care how long the Interrupt Service Routine (ISR) is I just throw in a loop like you did.
Also, to the viewers: It is a good idea that when you first learn to code ISRs, to have a template that you can cut and paste from your "repertoire" code.
I suggest you learn how to save the ENTIRE state of the CPU on the Stack as you enter the ISR and pop it all off the Stack before you return from the ISR. This is handy when you will do context switching (like in multithreading) as you get more advanced. Coders sometimes forget to push the CPU Flags register on the Stack, do this first because many op codes do effect the flags and they too should be exactly as they were before the interrupt was handled (called). So having a full context save of the CPU is good to have at hand even if your ISR does not change everything in the CPU, but you can trim out what you don't need if you need to make your ISR as short (fast) as possible, but don't forget the save the Flags register on the Stack first in almost all cases.
Your videos are a NMI. And worth it. Thanks for a GREAT video.
Brilliant work, BOSS. Please do stay your course.
6502 changed a lot of us.
Never clicked so fast on a video, it definitely interrupted me
true
Same here. Fred
It's amazing how your videos can explain stuff in minutes which "teachers" failed to explain to me in years.
Your videos are so clear and interesting that I am just binging on them. It is amazing. Minor nitpick on your aside on having multiple IRQ inputs. You mention at 23:25 that we could "AND them together in some way". I think you mean to OR them together. Unless you're building a system that is extremely discerning to inputs, of course :)
actually, just realized the 6502's IRO is active low, so I'm the one with egg on my face now... :-D
It's been decades since I used a 6502 CPU. I remember using a flip flop to control the IRQnot pin on it. I would set a flip-flop which would force its Qnot output to go low and make IRQnot active low to request the interrupt, and then some of the signals from the CPU could be decoded to clear the flip-flop (Qnot, thus IRQnot, goes back to inactive high) as its enters the Interrupt Service Routine to generate only one interrupt per interrupt signal edge.
You can go directly to the top of the file in Vim by pressing "gg" in normal mode.
G to jump to the bottom
Just finished watching the entire series and even though I don't have breadboards, chips and all the stuff to follow, still
I've managed to get the very gist of the tutorials to pick up those key parts that are required for cycle accurate emulation
of a 6502 based computer. Thank you so much Ben for making such a detailed series explaining every single bit of
information I could've ever dreamed to learn from a single source in regards to 6502 emulation.
Interesting. I didn’t know the 6502 automatically pushed the flags register onto the stack and pulled it from it. Coming from the Z80 background, I learned it the hard way a long time ago to push and pull the AF register (you can only push and pull sixteen-bit registers, so the flags register and the accumulator are pushed and pulled together). Pushing and pulling can be expensive, though, so there are much quicker EXchange instructions that switch between the two sets of registers in the Z80.
The Z80's NMI is edge triggered, thus solving the problem of re-entering over and over again for level-triggering. Too many microcontrollers have the same problem of "exchange register": there's no way to track for double-flips. The Z80, as Moore said, has the exchange-register command. The Microchip PIC-18 similarly has "shadow registers" that are easily clobbered. Use in only ONE place for ONE situation. I doubt there's any auto-checker to flag possible double-use cases :-(
I'm familiar with the Z80 more than 6502 as well but I've never been able to get my hands on any hardware so since I was always using an emulator I never needed interrupts. Right now I'm designing a z80 computer hardware though so maybe one day I'll be able to actually play with the real thing...
@@JeffreySJonas I guess the way you're supposed to deal with double flips is: only ever use the shadow registers in IRQs, never allow nested interrupts, and be very careful.
At 13:51: PortA has 8 bits, true you could OR them so 8 different sources can generate the CA1 interrupt, but I think the more popular use was to provide an 8-bit interrupt vector for CA1. This way, when the interrupting device (say a disk drive) initiates CA1, it puts an 8-bit value on PortA so the Interrupt Service Routine (ISR) can read PortA (IRA), which clears the interrupt while telling the ISR something about the interrupt, like say, $21 (disk head is on requested track), or $20 (disk head is home)... things along those lines. But there are many more ways to use these interrupts.
Thanks!
damn I did not change the message :) very cool content, you have a gift, you explain things extremely well :)
Love how you can create read in multiple inputs as interrupts. One project, we used one of the timers as a 'watchdog' that would verify the main CPU program wasn't 'stuck' as well. (a bit of code, setting a semaphore in main code and testing in watch-dog's handler). Delay loops in the handlers can be a bit 'kludgy' though. If there's a second event while in delay, miss it completely. But you covered that, so.... great video. I've unmasked my interrupt, ready to detect the next video release. :)
I was going on a date with my girlfriend, but new Ben's video came out, so now I have to stay home and watch
with her?
@@robertroxxor nope, she has lower priority
@@andrsam3682 LOL Ben's video NMI; GF IRQ
@@andrsam3682 Then your relationship won't last.
I've been a software guy for my entire career and now I'm retired and learning about hardware. Back in the day I had an Apple //e that I programmed mostly in assembler, so a lot of what you've been going over is familiar, but I never did any hardware back then. So it's been fascinating to see how you might interface the familiar old 6502 to various hardware. Thanks!
Thanks to your video i got the highest grade in architectures of digital system, very well done man, helped a lot
The last time I was writing 6502 interrupt code was on a wire wrapped pin board in the middle 1980s. It was a home-brew midi sequencer that connected serially to a PDP11.
That said, software delay loops are inadvisable. Software delay loops at interrupt level are unfortunate. If you really need software denounce, there are so many better ways to do it.
The VIA timer was what came to mind while watching, but I am far too late to be the first to suggest it.
Ben
You are a fantastic teacher.
I hope you will continue with this 6502 project... I can see, perhaps, we are on our way to a breadboard Apple I computer.... all we need is a few more things... keyboard... storage... primitive monitor (OS) program.... and so on...
If that's a 65C02 you can push and pull X and Y with the additional opcodes (PHX, PHY, PLX, and PLY) it supports.
Ben: "We can't push X and Y onto the stack directly."
65C02 with PHX and PHY opcodes: "Am I a joke to you?"
I totally expected him to change all that stuff to PHX and PHY later on 😂
EDIT: nevermind since X gets decremented again it just loops back to 255 anyway. But it would be nice to be explicit :p
Ignore this comment I guess it's just here for historical reasons.
Dunno if this is a mistake but when the outer loop loops it doesn't reset x register for the inner loop. Idk if I explained well so I'll just write some code: (I don't know 6502 assembly but it should be close enough)
ldy 0xFF
outer: ;this is the bit that's missing
ldx 0xFF
inner:
decx
bne inner
decy
bne outer ;don't go back to the same bit
Thanks for the comment, I actually thought the same thing before I read the edit :P
Ohhh I was thinking the same thing, but your right. Although, even if x wasn't decremented it would just loop 510 times, which i thought before was what he was doing.
Glad I found this. I was wondering, if X can be negative or what happens when calling DEX after X already is 0. So now I asusme, DEX (with X being 0) would then set X to 255 again. Then Ben's code makes totally sense to me (finally).
@@tychobra1 yep I believe X is unsigned, but anyway it would have been a tonne clearer to just set it back to 0xff imo
@@KingJellyfishII Sure, your approach is better readable/understandable - at least for guys like me who are not that used to the assembly language :-)
This is like the wayback machine for me. Back in the early 80s I was writing interrupt service routines and terminate and state resident programs in ASM to handle input from various sensors like strain gauges and tilt/inclinometers through a custom device I built. Now I just use a Raspberry Pi, Arduino and or ESP32.
Your videos are so, so fantastic and I’ve learned so much from them, just want to say thank you for putting in the time and effort to make them :)
dude, these videos are awesome. i just finished the last one you have in this playlist and have also done the breadboard computer series. i am also building the breadboard computer, but with a twist of making the components plug into a motherboard type bus. i really want to keep playing, but i find the wires on breadboard are a little frustrating for long term use. these videos have finally given me the ability to truly umderstand how things work within the cpu and then how it interects with the outside world. thanks again for your great passion for the topic and your teaching skills. i am so bumping up my patreon support for you. please please keep adding to both those playlist. cheers
Nice to see people still know how to use a data sheet and program in anything other than arduino or raspberry pi, gives some hope to humanity.
BTW, nice job at wiring as well. You made your mentor proud even if you learned it from your own research.
Fantastic series for how to start to work with the 6502's! Super impressive.
I thought for sure you were going to use the timer in the 6522 to do the debouncing... maybe that can be the next video
Yes, that would have been cool.
Loving these tutorials. Please keep them coming.
Me: looks at notification, says 3 hours ago, quickly jumps in to joke about interrupt handling, finds 30 out of 33 comments doing the same.
That's what happens when you debounce with a loop.
Yes, it's not a good idea to put a delay in an interrupt handler. A better solution, instead of incrementing the counter in the interrupt, is to flag the button press in memory, and then move the increment and the debounce delay into the main code loop. Delaying in an interrupt would effectively freeze all other interrupt handling. Obviously it's not a problem in this particular case, but something to keep in mind for other interrupts. As a bonus side effect, from the main code, you could update the output immediately, and then run the debounce delay loop.
Also I just want to say watching around 15 of your videos taught me more about assembly and actual hardware than my entire bachelor's in CS did. Great stuff! Wish I could pay the student loans to you instead of the govt
An easy way to debounce the switch would be to add a capacitor in parallel with the pull up resistor. A time constant (R times C) of about 10ms would be about right from my experience.
Man you are genius! and very good at explaining things too!
Consider making a course about electronics and embedded systems it will be a huge help
Well, my interrupt flag for new Ben Eater videos was set, so here I am
I've learned so much from you Benji!! I'd love to see your breadboard robot talk to a modern(-ish) computer via RS-232
I saw this video yesterday, thought I would watch it someday after I finish with ben eater's earlier videos, and then today I was doing something with interrupts and just to brush up on the subject I searched on UA-cam "interrupt handling" never actually remembering this was the title of the video.
Your videos are like interrupts but for real people
In the delay function you're Dec x to zero, then y by one, then Dec x again to nonzero (likely ff, but depends on cpu complement system) then Dec x to zero again before Dec y again. So it's delaying for (0xFF)×(0xFF) loops instead of (0xFF)+(0xFF) . Break it to two delay loops or call delay twice to fix the latency issue
"Likely ff but depends on cpu complement system"? No need to guess! We know the CPU. The 6502 is of course twos-complement as God intended.
(And yes, he knows you're getting 255×256-1 instead of 255+255 iterations. That was the point. He did mention you could probably go significantly shorter if you wanted to spend time tuning it. Just initialize Y to a smaller value.)
@@ps.2 Or X as multiplication is symmetric. Doing 10 loops of 2 loops is same as doing 2 loops of 10 loops.
Thanks Ben. In future videos, please do one on timers and implement a paced function (eg. 10ms_cyclic) and move that debouncing loop out of irq handler. I know the cpu isn't doing nothing else. But putting a spin delay in irq handler is doing my head in :(
Don't you use a 65C02? I'll ask because the C variant has PHX, PHY, PLX and PLY instructions.
Yes he is! Don't know why he didn't use those
@@Eliasdefi Only reason I can think of is that he wan't to keep the videos strictly plain old 6502.
@@Martin.Krischik Probably, The Only Reason He Mentioned to use Modern Variant is Because of It's Static Nature rather than Original Dynamic Nature
Thanks someone finally noticed it!
that one moment in a month when you get that notification...muuuuaaa.
Let me just push this video onto the stack
Initialising registers is of course important, but it also provides a place in your code to document stuff you’ve read in the datasheet. Everything you’ve browsed deserves a place in your code, even if it isn’t quite relevant now. 6 months on, you will pleasantly surprised to be reminded of obscure control registers and such.
this video could not have come at a more perfect time.
im designing something that uses an fpga to talk with the 6502s big brother, the 65c816.
i had a plan on what to do and this confirms I'm on the right track.
21:00 the loop will load x and y at the beginning, then decrement and branch on x, but it never sets x back to $FF before looping on y.
Basically, it only loops $FF * 2 times. Obviously too long, but if you meant to make it loop $FF * $FF times, not as long as you tried to demonstrate.
it does, though: it decrements x before the next comparison, overflowing it back to $FF from $00
@@Tuxfanturnip I was looking through the comments to see if anyone had noticed that the X register was never set back to $FF. I missed the fact that DEX would cause $00 to become $FF. I've never programmed the 6502, (Z80 fan boy), so was reading up the 6502 instruction set to verify your comment. As DEX will set the Negative Flag if the bit 7 is 1, then starting at $FF is a bit naughty as we'll be counting -1 to -128 then flick over 127 and count down to 0.
@@axelBr1 The X and Y registers are unsigned.
Sure they set the negative flag but in all operations which matter, like the index indirect and indirect index addressing modes they X and Y register are used as an unsigned values.
@@Tuxfanturnip Ahh, fair point. I see, Ben Eater outsmarted my outsmarting lol
The notification triggered my NMI and made me watch this instead
So helpful! Thanks for another great video.
You can jump to the top of the file you're editing in vim bu pressing 'g' twice in normal mode. Shift+g jumps to the bottom
You know how to use VIM?
Well, do you know how to quit?
ZZ - save a quit :)
HIS BREADBOARDS ARE UPSIDE DOWN I CAN'T
Kitulous Gamedev Channel Looks fine for me. I’m in Australia.
Your videos are the best ben!
They could have used this video at the Presidential debate, lol
when new ben eater video, me:
i need some 7400 chips and even more breadboards!!!
I just finish a University Assignment about MIPS interupts and this video comes out.
This is awesome stuff. Now I would like to see you marry your world's worst video card with the 6502 and have it display the RAM contents then the dreams of my childhood will finally be fulfilled :P
It's actually very simple, I'm currently working on connecting that video card to my Z80 computer. Just replace the EEPROM with dual-port RAM, with one side connected to the video card and the other side to the CPU.
@@k4ktus Not that easy, because now you need some kind of bootstrapper to get your program in memory. That's usually done by BIOS to load the first sector or whatever, so you would have to implement something similar with a wait state for the CPU while the firmware executes and loads your program.
And then program a game
@@BitwiseMobile I meant the image EEPROM from video card, not the program EEPROM on the 6502 computer.
@@k4ktus You'll have to allocate some memory area (called video memory), the videocard will be rendering from. When you want to render something, you'll need to put a contents into that area. Ben Eater is rendering from eeprom, but it can easily be replaced with allocated RAM area. But to render some image next you need to imagine how to translate commands to some kind of figures or anything else you want to display. For example, for rendering circle you need to integrate the circle equation (x-a)^2+(y-b)^2=R^2 and bound it with user parameters (such as a, b, etc). The result array of this equation must be placed into that allocated video memory. Then you'll se a circle on a display.
Been looking forward to the next instalment 👍👍
this video interrupts just in time
Now to add an interrupt dispatcher. And a timer queue. Oh, and do that timer debounce thing everyone is suggesting. Also, an event queue so that the main program can reach a safe position before handling the events.
If you want to initialize everything properly, I think you should disable all the other interrupts in the interrupt enable register, just as you enabled the CA1 interrupt. I guess they're already being initialized as disabled though, otherwise the program would probably have got stuck servicing interrupts forever.
Actually, you can push X and Y to the stack.
PHX and PHY are instructions. As are PLX and PLY.
Good to see u still upload
That delay loop though. I think it works because X underflows and implicitely resets to ff from zero at dex immediately after the jump back after dey, so you don't need to explicitly reset X at every iteration on Y. But you didn't say that out loud, so it's a bit confusing
Yes, think the intention was probably to write the loop at 19:37 as
ldy #$ff
delay_outer
ldx #$ff
delay_inner:
dex
bne delay_inner
dey
bne delay_outer
instead of
ldy #$ff
ldx #$ff
delay:
dex
bne delay
dey
bne delay
But as I'm sure you already figured out, we could have had e g ldx #$0 instead, and that would work to loop 256 times, because the first time through the loop would decrement x to make it wrap around to 255, and then it's not zero so the bne would jump. So when bne delay after dey jumps back, x is 0 and the next x loop will go around 256 times.
I have followed this series from start to finish and find it fascinating and very well explained. (TLDR; Thankyou Ben)
It would be cool if the interrupt handling could be used to implement an approximation of concurrency with multiple processes
Something like.....
Set up the 6522 to generate an interrupt every ms.
The interrupt handler saves the AXY registers on the stack
It then sets some (new) address decoding logic to swap out the stack for another page of memory (holding another stack for anther process)
We pull that stacks registers back to AXY
RTI would then return to the new process
Repeated timer interrupts would effectively swap between processes?
It struck me that the memory chip is only being half utilised so maybe could use the extra memory for the paged stacks
(This struck me as a good idea for one of your future videos. Hint hint.)
Ben, are there any plans to add a keypad to this system for viewing and adding programs directly into memory as well as to view and set register values? Similar to a KIM-1 or any other CPU trainer?
Why not port the KIM-1 monitor to this board? This will give us cassette recording and ASR-33 interface. Source code can be found online. I still have a KIM-1 in working condition. Purchased in 1981 when I was 21 years old.
Hi Ben,
I think that it would be really interesting to use some form of PLA to create a more efficient memory map.
Do you think that would be possible for you to do?
Great video as usual!
I wish one day I could be a great man like you...Ben Eater.
Hello Ben! After this series is finished, do you think there will be any possibility of making a video about hooking this up to the "worst video card" you made a year ago. That'd be amazing.
Your CPU is a 65C02 so you can use PHX PHY PLY PLX instead of using A to push. That's 8 cycles gained per interrupt.
i think there should have a strong community for microcontroller and electronics engineers such as we see that AI, ML, web developers, app developers has.
Do you have a description of the overall goal of these videos? You've got me wondering if I can manage to build my own BASIC executing PC, like the color maximite , from scratch, including writing the OS rom. It's starting to sound like a fun project. I'm wondering how far your videos would get me to that. Thanks!
Ben, will you be creating a video on wiring, configuring and using a UART like the W65C51?
He did do serial communication, not sure if you've seen the video yet! Came out last month.
@@JustinKoenigSilica I saw the hardware video but the software video has not been made available yet.
1986: to play this game with a working soundcard on my dos 1.1 computer i need to edit some strange irq setting in bios
2021: find this video on my smartphone and fully anderstand every detail of what i was doing back then
thanks a lot!
please make full course in one video
At 21:00 because we're doing a pla, we don't need the bit operation anymore isn't it?
Ben the delay is slow because it starts delay and DeX and then goes back to delay when x is equal it goes to dey and hen go back to delay so it's going through the full DeX for every 1 of the dey's so its 65535 times the #of clock cycles in 2 branch instruns and 2 decrement instructions
what a wonderful world we are living in now a days ! never too late to learn stuff
Instead of the debounce software, I stuck a 100nF cap across the switch and it seems to work well.
EDIT: Though not perfectly.
2nd EDIT: Now it's a 555 monostable circuit with a 10nF cap across the switch as well.
2:03: "We can also set the data direction for each bit."
Or byte, rather. EDIT: No, Ben was right, as per Chris's correction below.
From the data sheet ( eater.net/datasheets/w65c22.pdf ): "Both PA and PB operate in conjunction with a Data Direction Register (DDRA or DDRB). Under program
control, the DDRA and DDRB specify which pins within the port bus are to be designated as inputs or outputs. Logic 0 in any bit position of the register will cause the corresponding pin to serve as an input; while a logic 1 will cause the pin to serve as an output." Each pin is a single bit, so you can set the directions for different bits within the same register byte independently of each other.
@@chrisbattey Ah. You're right, I'm wrong, egg on my face. I hadn't cottoned on to the fact that these aren't just bits toggling the ports in or out wholesale, but that there's an actual byte-for-byte and bit-for-bit correspondence between the 8-bit ports and 8-bit registers. The link parser has eaten your bracket though, so you might wish to edit that for the link to be easier to click, so people won't have to manually delete the closing bracket for it to work. Thanks.
@@ropersonline Yeah, when that first came up a few videos back I thought it was kinda weird at the time, but the idea of handling multiple separate single-bit interrupt lines through the 6522 makes it seem a lot more reasonable.
(And thanks for letting me know about the link - enough sites have figured out how to be smart about that by now that I keep getting caught off-guard by the ones that aren't...)
@@chrisbattey You're welcome, and thanks again. :)
Could you use one of the 6522 timers for debouncing? If the switch remains in the same state without changing for longer than it takes the timer to run out, it must not be bouncing .....
Very nice Video please make more really enjoyed it
Just use a capacitor to debounce the switch.
Most of my lectures in college were an hour of a complicated solution for a problem to teach a concept, and then right at the end the lecturer would reveal that you'd never actually do it because there's a much easier way.
Not gonna help. The switch is still gonna be low for a long period of time and trigger multiple interrupts, since it's not triggered by a level change, but by low signal
@@dmsalomon Ben is fixing the length of time problem using the 6522 to only generate an interrupt on the falling edge.
@Add channel name Sounds impossible.
I stop watching a video to come over here it's an interupt video 🤣🤣
we can't use interrupts When we touch a metal object to the pins of the IC, it branches into the cutting program or resets it.
Your all videos are so help full plz make some projects on 8085 & 8086 microprocessors
Could you re-implement the busyflag polling with interrupts and WTI instruction? Not immediately obvious how to do that but it should be possible I think -- after all the 6522 is designed to do this sort of thing.
One way of doing it I think is tie busyflag output (pin 3 of LCD) to CB1 and in our lcd_wait routine to enable interrupts on CB1; then we could read B and as long as it's not busy, disable the interrupt.
There might be some undesirable bouncing on ORB but actually checking the busy bit should take care of that I think.
Thank you