XaiJu
beneater
beneater

patreon


How do hardware timers work?

New video! Back to the 6502 computer, this video looks at some of the unexplored functionality of the 6522 versatile interface adapter chip. Specifically, I cover the timers and how a CPU and software make use of hardware timers and timer interrupts.

As always, I appreciate your support. And please let me know if you catch any errors or confusing bits.

Thanks again!

-Ben

How do hardware timers work?

Comments

Thank you for your help. I’m new to the asm, and I’m not familiar processing Multiple interrupts, i have been unable to find an explanation in how to process them, not the code, but the idea and what to look while processing them. Jose

Jo Ga

Make sure you have the two 6522's responding at different memory addresses. Assuming you're using the 'S' version as in Ben's design then yes, the 74hc21 quad input and gate would allow you to connect both 6522 IRQ outputs to the 6502 IRQ input (tie the unused inputs high.) Then in the interrupt handler code you need to check each 6522 in turn to see which one caused the interrupt (e.g. by checking bit 7 of the IFR) and perform the appropriate logic for keyboard or for the timer accordingly. Also, keep in mind you could use the timer interrupt AND the CA1 interrupt (for the keyboard) at the same time within a single 6522 if you wanted to. One more thing... r/beneater on reddit is another place you could check out to ask this kind of question.

Phil Dennis

Guys I need some help. I did add a second VIA 6522. In VIA1 I have the keyboard working, and VIA2 I have the timer interrupt, they work individually but not both together. I have seen some solutions using a 74hc21 from Dawid Buchwald. But in software side, the keyboard code interrupt , plus the timer interrupt they are not perfect working together. When I press a key the timer led is at one speed for a while and then I press esc and go back to normal speed. How to proper handle multiple interrupt hardware and software ? Example the keyboard, the timer, etc

Jo Ga

Why didn't you have to initialize the stack pointer?

Stefano Nicolini

A quick visual reviewing the addressing scheme would be helpful to those that haven’t watched the earlier 6502 videos.

Jim Kelly

Interestingly, on page 30 in Table 7-1, it mentions that there are several 1-cycle NOPs: X3, 0B-BB, EB, FB. I don't know if this is _actually_ the case because I can't test it. :-)

Ian Flanigan

Same and same; please please keep building on the 6502 platform - a merge or evolution of worlds-worst-video and the 6502 series and PS/2 would be amazing.

Michael Weitman

Thanks Ben. Keep producing these great videos and I hope you setup a Meet And Greet with your fans. If not your entire youtube base, then at least with your Patreon base.

Al Leitch

I stand corrected.

Shachar Shemesh

So glad you returned to the 6502 series. I think I'm one of many who started building one based on your videos, and every update is much appreciated.

Elekes Karoly

For the `update_lcd` function it is reading ticks and ticks +1 and displaying the 16 bit value in decimal. It's in the last minute or so of the video, at ~29:00

solderspot

I don't think he does read 16 bit values. He only writes to it from inside the interrupt handler.

Shachar Shemesh

You definitely need a `sei` and `cli` when reading the 16 bit value of ticks. An interrupt can happen between the first and second read of the register. In fact I thought the reason you introduced the 32 bit register was so that you could explain "volatile" memory locations and the need for mutual exclusion.

solderspot

Seen the video. I liked it very much. With that in mind, I have a few suggestions. They are all petty, but I hope they will be useful. Others have already mentioned the wrong cycle counts. 17:51 - just a VIM trick you may find useful. Capital "R" puts VIM into multi-character replace mode. Instead of hitting "r" number move "r" number, you can do "R" two numbers ESC. 19:38 - "Will read it without doing anything with any of the registers". That's not actually true. It will change the status registers. Those will get restored by the RTI command, so that's fine, but I think it should be pointed out. Interrupt programming is _hard_. It's good hygiene to always keep in mind which registers are safe and which need to be protected. 21:40 - This one's particularly petty. When testing for overflow, it seems obvious to use the carry. Of course, INC doesn't update the carry, only N and Z, but it was worth a mention to me. 22:43 - I don't know whether you're trying to avoid wd65c02 specific commands, but using STZ here seemed obvious. 25:16 - ticks may have changed between the first and second times you read it. This would introduce a drift. It's fairly small, but you have X and Y readily available to keep the value around until you need it again. Again, good software hygiene. 29:50 - Again, wd65c02 specific command, but this one is really close to my heart. I'd put a WEI in the loop. It would make a HUGE difference in power consumption, if nothing else. Most of those are a little petty, but I think they would make a great video even better.

Shachar Shemesh

I'm implementing the wd65c02 in verilog right now. Yes, the "one clock cycle" comment was particularly painful to hear. Page 20 of the wd65c02 datasheet has how long each instruction takes based on its addressing mode. No command takes less than 2 clock cycles, including NOP that, literally, does nothing in its second cycle.

Shachar Shemesh

28:50 - there’s a race condition in the code which copies ticks to value - if the timer interrupt occurs between reading the low and high byte of ticks and the low byte rolls over from ff to 0, then the value copied will be off by 255. One obvious fix is to temporarily disable interrupts while reading ticks. 20:20 - the content is a little misleading since the assembler will use zero page addressing based on address <= $ff regardless of whether it is written as $00xx or $xx 1:30 and 2:50 - NOP and DEX take 2 clock cycles/microseconds, not 1 as the video stares (and the branch instruction takes 2 or 3 cycles depending on whether the branch is taken)

Phil Dennis

I was wondering about the overflow math issue too. Maybe it would make for a separate video?

Dan Ozeran

Remember that 10ms is 10,000 clock cycles. You're right that if we really did a lot of processing, it could overshoot. But in the example I've got, we're doing well less than 10,000 clock cycles of stuff, so all the processing takes less than 1 tick and it isn't an issue. As for overflowing when subtracting the low byte, that is an interesting side note that I could have gone into more. When it overflows, lcd_time will record 250 as the last time the LCD updated and the low byte of ticks will roll over. When ticks is 260, the low byte will be 4. The subtraction of 4 - 250 = -246. If you represent -246 in binary twos-complement, the least significant 8 bits are 00001010, or in decimal, just 10, i.e., the difference between 260 - 250. This is one of those remarkable properties of twos complement that lets us take this shortcut and it's pretty neat. Probably could have added another 10 minutes to the video going down this rabbit trail though, so I was hoping no one would notice... :)

Ben Eater

Good call. I just added a link there. (And re-uploaded the video since the audio levels were too low)

Ben Eater

I also was wondering about the accuracy. I was confused about only subtracting the lowest byte of the timer for the comparison. The timer keeps running and the low byte will overflow at 256. Wouldn't that add 6 cycles between the 10th and 11th ticks, and continue to skew on every overflow?

David

and of course , once again a great video

Michael McDonnell

it would be interesting to come up with a library for cc65 with all the functions of the BE6502.

Michael McDonnell

I was confused at times why the clock cycles checking ticks and updating toggle_time weren't skewing the timing. I get that the timer counter is counting clock cycles completely independently of anything else. But you load ticks, compare it to 25, then several clock cycles later re-load ticks to update toggle_time. Is it that there's no way 10ms can elapse there so we're guaranteed to have the same ticks value both times? Is there not an edge case where the first read is right at the end of a timer cycle and the second read at the start of the next? Also, why do we never overshoot? Why do we never miss it at exactly 1.00s and only catch it at, say, 1.01s for the display refresh? Is it because we're sampling so many times per 10ms? Could that sampling rate be affected by the length of our program?

Artem Kreimer

This is great! I'm glad you went back to the 6502. Specifically for this video, I did not recall how the 6502 handles an IRQ. So I was briefly lost when you went to the code and typed in the "IRQ" reference and label. Would it be helpful to viewers like me to reference (perhaps with pop-up text like later in the video) to point the viewer to the video in which IRQ handling was described?

Shelton

This stuff is just so very cool! Originally, I bought all the parts to build this, but got distracted with life and set it all aside (who knows where)... so I'm going to have to buy the kit so I can play with this programming too. You are such a great teacher!

xedover


More Creators