Wish I could upvote this more than once. Unit tests are so important. With this, you can feel safer that if you refactor something, you'll be notified if you break something by mistake. Unit testing is useful beyond the immediate knowledge that something behaves properly. It's also good for maintenance. Also, if you ever build this on a big endian machine, your unit tests will be very useful to start getting it working correctly.
A bit late to the party here. I have read quite a lot about Google tests and have found that the examples tend to use intrinsic types (as do most examples in C++ documentation). Thus one has to translate that to RL code. Observing a programmer doing this has simplified that process (in my mind). Thanks to you, I now think I could take on Google test. You have made an old man very happy; thank you.
Wouldn't it be smarter to execute the instructions before a HLT instruction is encountered? I am not familiar with 6502 ASM/ISA, but I bet it has a HLT instruction.
You really ought to correct the reset vector at 0xFFFC. It should contain a VECTOR, not any 6502 instructions. A vector is just the address where the first instruction is located: 2 bytes forming a 16 bit address, low byte first on 6502.
True, i should have done that. And if i ever got around to implementing an entire system i would. But for now it's good enough to get me going with making the processor emulation. I really wish i actually hadn't used that particular address as it was confusing to people. You'll see in tests in later videos i just pick a some other random address in memory, i'm not really too bothered about getting the correct/accurate reset process in these videos, just something that is good enough to start testing and writing code to bootstrap the emulator itself.
While I'm all for unit testing and more importantly TDD - the statement at the end that "we are testing everything" is far short of true it might need a new dictionary definition to cover it. A single test for each instruction is just about the bare minimum but with so many permutations of the effects on the status register it needs much, much more. Just copying the CPU to compare flags is also a dirty shortcut that really misses the point - you need to mock the status register and make sure that the flags are not being touched rather than simply come out unchanged. Yeah, I know I sound boring but those shortcuts are the source of so many little evils that it is amazing code like this doesn't feature dire warnings and a dodgy looking pentagram One last point (and I'm sure you work it out later). Requesting a number of cycles is a dead-end, it would be better to request a number of complete instructions and simply return how many cycles it took to complete. Each instruction should be "atomic" in this sense - halting the CPU halfway through the necessary microinstruction cycles would place the CPU in an indeterminate state and you wouldn't want to do so under normal circumstances. Making sure the expected number of cycles has passed on the other hand is so much more useful
You are right, i am not testing "everything", I am testing a lot. I can't remember what the final count was for all the instructions, it was more than 1 test per instruction, but i seem to remember saying that probably should have been a lot more. I don't think requesting a number of cycles is a dead-end as i imagined the scenario where i want to do X number of cycles, and i can't know ahead of time how many full instructions that's going to be? But i would want the entire instruction to complete (which is what the Execute() function does). I think at the time of this video i wasn't sure if the 6502 could be interrupted mid-instruction, but later i found out it can't (phew), but either way i stand by my Execute() function. I could make a SingleStep() function that just does 1 instruction then returns the number of cycles that it took. But even then i would just still want another function that would SingleStep() until a certain number of cycles had been taken (which is what the Execute() function does), and i can actually single step the CPU by just calling Execute(1) so i could easily make a SingleStep() function if i wanted one (and probably would if i got around to making a monitor/debugger)
@@DavePoo First of all I confess I've not looked ahead to see what happens later but I would look to isolate the ALU as a discrete component - prove that it behaves the way it is intended and then just test that a particular instruction engages the ALU in the intended manner rather than "lots" of tests for each and every instruction. A mock of the ALU or maybe just a spy, would be all that is needed in the tests. The whole reason I'm here looking is that I started a similar project and was looking for ALU approaches/solutions when I came across your videos - so far it is reassuring to see the approach but still haven't solved my ALU problem
Hi, tbh this was just way too much for me, I have never heard about unit testing or google test, then I come in you just say, you did this and that, but I have no idea how to do that myself xD
I'm not sure why you're executing an instruction having to specify the "cycles" parameter - surely the CPU "knows" how many cycles a given instruction should take - indeed there are some addressing modes that add a clock cycle if they roll over a page. You may change this as the series progresses, so apologies if you've already tackled this later. FWIW I have written a complete 6502 emulation in Processing so know a thing or two about 6502 microcode :)
If you are talking about the parameter to Execute() it's just so we execute a minimum of the given number of cycles and then return from the function, otherwise I'm trapped in there forever.
@@DavePoo I agree with Christian. Execute should execute a single instruction and return. Think of it as stepping through the code line by line. Also I’m just going through the series, so apologies if you changed directions already
@@dvogel2010 these guys are right - he needs to run one instruction and return. First in an infinite loop, and then add the interrupt handler. If he wants, he can add “break after 2 cycles” for testing.
it is strange to test cycles used because cycles must be zero at last, if we run cpu.execute(cnt_more_ticks_than_need, mem) for JSR instruction, the answer will be "cnt_more_ticks_than_need" rather than 9
The actual library definitions should actually go to a *.cpp file, *.h file is only for headers, in other words only declarations. Other than that, pretty good series actually :)
try this on it... using 'invalid' bcd digits to trigger a +1 carry to get the correct 0-9A-F hex output in ascii. quite few emulators fail on it cuz it's not quite clear from the datasheets :P (cmp does have 'most of' the side effects of sbc and as such, also... tadaa. decimal mode ;) but 0A is not a valid value in decimal mode. SED LDA P1SCOREA TAX LSR LSR LSR LSR CMP #$09+$01 ADC #$30 STA VRAMSTART+15 TXA AND #$0F CMP #$09+$01 ADC #$30 STA VRAMSTART+16 CLD
I really cant get the googletest working. I ran into so many errors such as gtest file not found, g++ compiler wrong version etc etc, to the point where I have no idea what Im doing. do you have any tips? I am using vscode
I am really struggling to set up the Gtests . Since i am using linux vscode can someone help me with setting up the project. The library is created in /6502Lib folder , but it /6502Tests i dont know how the "main_6502.h" just includes the header from another folder. I am trying to find out which CMake line includes the library into another folder. Can someone help me with this ?
I am having a hard time to put the whole google test on my project, could you help me with what to do? I was following curiously on your first video and started learning a lot about cpu 6502 but then I got stuck upon starting this episode and i want to keep going but I cant...
Missed the *or will it? at 17:25 and spent more time than i'm proud of trying to debug why asserting the negative flag as false was failing lol edit: wrote that before finishing the video lol
Struggling with google test, I am emulating a gameboy cpu, trying a LD B,0xff instruction, when I run the CPU in my main of my project, the register does become 0xff as it should. When I run google test, configured to run the same code the ram of the system corrupts as does the CPU registers and I am not sure why that is happening
Okay I spent a lot of hours on this but for some reason if I created the object using a unique_ptr then it worked completely fine, i assume new and delete would work the same
7:14 I find it really weird that you bother compiling when VS is already showing you the red squigglies. Like.... why compile? It's literally already telling you it won't work, and if you mouse-over the red, it'll tell you why.
At what level would a cs learn this, say at University or College? I guess I am curious how people learn this, like I have learnt python and R however I have never seen this before in my limited C++ experience. Why I say that is because it doesn't strike me as something popular coding course offer. Regardless, love the videos.
When it comes to unit testing, it depends on the university/college. A lot of them don't teach this on their own (which is a shame), but some might have an elective course such as "Introduction to Test Driven Development" which can go into the topic of unit testing. If you want a book recommendation on this, Test Driven Development By Example from Kent Beck is a good one to read. It'll teach you a bunch of ins and outs on structuring unit tests correctly, how to write them, etc.
There just does seem to be enough time. It almost seems that people need a life times of experience and then some, which is AI comes in I guess, a pity the word is not structured financial and pay wise to implement it. Might see our first billionaire after all and yet there are place in Nigeria without proper toilets.
The problem with some unit tests is it tends to obfuscate the non-unit test code with behavior that is used to produce test outcomes. e.g. returning s32 from execute for the purposes of testing. If there were no tests, it would return void. Wonder if theres another way around it.
True, but i think my theory there is i am going to need that information to correctly emulate a system if i want to sync up the CPU with another part of the architecture. It's possible that i was thinking too far ahead there and if i did a whole system i would implement it differently.
Guys I'm sorry, am I the only one that is not able to access the resources he is using? I get a weird page with amazon links when I try to open the link in the description
Looks like that page I used during these videos is now no longer online. You could try the waybackmachine to find an old copy, or google "6502 instruction set" to find some equivalent page.
"it's because everything is private in classes in c++ for some stupid reason" if they were public by default how would they be any different from a struct? In other words why don't you just use structs if you want everything public by default?
I think my point was, why did the C++ commitee add the "class" keyword, just so they could give classes a new default that was wrong? They could have just not bothered and saved themselves a new keyword in the language.
@@DavePoo It's a bit weird that you believe that private being the default is wrong. One goal of classes is abstraction (among others), so sharing or making internal state public by default would have been completely wrong. The main idea is that you should EXPLICITLY define what you want public. Better yet, you should have functions (AKA getters) to what you need to be public, because you don't want to tie the specific internal implementation (attribute/field name in this case) with the class public interface.
struct's existed pre-OOP, and it makes sense to have stuff private by default when objects take care of themselves, have private data and can be derived from. So yeah, you need a new keyword I guess. Whenever I'm prototyping and being lazy, I always use structs to not have to write public all the time. And everytime, I end up changing them to class. I'll never learn.
Another good test to add would be for the program counter - make sure it is advanced the correct # of bytes, etc.
Wish I could upvote this more than once. Unit tests are so important. With this, you can feel safer that if you refactor something, you'll be notified if you break something by mistake. Unit testing is useful beyond the immediate knowledge that something behaves properly. It's also good for maintenance. Also, if you ever build this on a big endian machine, your unit tests will be very useful to start getting it working correctly.
A bit late to the party here. I have read quite a lot about Google tests and have found that the examples tend to use intrinsic types (as do most examples in C++ documentation). Thus one has to translate that to RL code. Observing a programmer doing this has simplified that process (in my mind). Thanks to you, I now think I could take on Google test. You have made an old man very happy; thank you.
Glad to have helped. At the end of the day, unit test code isn't anything more than code than can call your code, and record a pass/fail result.
Learning about googletest was very valuable to me! Got it all set up now, thank you!
Yeah, it's super useful
Another good test to add is to load x00 in de A register and test if the Zero flag is set.
I definitely do add that test at some point as it's in the final source code "LDAImmediateCanAffectTheZeroFlag"
FFS, I just clicked the second episode, and YT suggests me #35 in this series. Eyyy, it appears to be quite a journey.
Wouldn't it be smarter to execute the instructions before a HLT instruction is encountered? I am not familiar with 6502 ASM/ISA, but I bet it has a HLT instruction.
I liked. Great didactic explanation. Congratulations
15:38-15:44 resonates with me on a personal level
Joking aside though, great video!
Never trust anything that works first time
You really ought to correct the reset vector at 0xFFFC. It should contain a VECTOR, not any 6502 instructions. A vector is just the address where the first instruction is located: 2 bytes forming a 16 bit address, low byte first on 6502.
True, i should have done that. And if i ever got around to implementing an entire system i would. But for now it's good enough to get me going with making the processor emulation. I really wish i actually hadn't used that particular address as it was confusing to people. You'll see in tests in later videos i just pick a some other random address in memory, i'm not really too bothered about getting the correct/accurate reset process in these videos, just something that is good enough to start testing and writing code to bootstrap the emulator itself.
While I'm all for unit testing and more importantly TDD - the statement at the end that "we are testing everything" is far short of true it might need a new dictionary definition to cover it. A single test for each instruction is just about the bare minimum but with so many permutations of the effects on the status register it needs much, much more. Just copying the CPU to compare flags is also a dirty shortcut that really misses the point - you need to mock the status register and make sure that the flags are not being touched rather than simply come out unchanged. Yeah, I know I sound boring but those shortcuts are the source of so many little evils that it is amazing code like this doesn't feature dire warnings and a dodgy looking pentagram
One last point (and I'm sure you work it out later). Requesting a number of cycles is a dead-end, it would be better to request a number of complete instructions and simply return how many cycles it took to complete. Each instruction should be "atomic" in this sense - halting the CPU halfway through the necessary microinstruction cycles would place the CPU in an indeterminate state and you wouldn't want to do so under normal circumstances. Making sure the expected number of cycles has passed on the other hand is so much more useful
You are right, i am not testing "everything", I am testing a lot. I can't remember what the final count was for all the instructions, it was more than 1 test per instruction, but i seem to remember saying that probably should have been a lot more.
I don't think requesting a number of cycles is a dead-end as i imagined the scenario where i want to do X number of cycles, and i can't know ahead of time how many full instructions that's going to be? But i would want the entire instruction to complete (which is what the Execute() function does). I think at the time of this video i wasn't sure if the 6502 could be interrupted mid-instruction, but later i found out it can't (phew), but either way i stand by my Execute() function. I could make a SingleStep() function that just does 1 instruction then returns the number of cycles that it took. But even then i would just still want another function that would SingleStep() until a certain number of cycles had been taken (which is what the Execute() function does), and i can actually single step the CPU by just calling Execute(1) so i could easily make a SingleStep() function if i wanted one (and probably would if i got around to making a monitor/debugger)
@@DavePoo First of all I confess I've not looked ahead to see what happens later but I would look to isolate the ALU as a discrete component - prove that it behaves the way it is intended and then just test that a particular instruction engages the ALU in the intended manner rather than "lots" of tests for each and every instruction. A mock of the ALU or maybe just a spy, would be all that is needed in the tests. The whole reason I'm here looking is that I started a similar project and was looking for ALU approaches/solutions when I came across your videos - so far it is reassuring to see the approach but still haven't solved my ALU problem
thanks
Hi, tbh this was just way too much for me, I have never heard about unit testing or google test, then I come in you just say, you did this and that, but I have no idea how to do that myself xD
I'm not sure why you're executing an instruction having to specify the "cycles" parameter - surely the CPU "knows" how many cycles a given instruction should take - indeed there are some addressing modes that add a clock cycle if they roll over a page. You may change this as the series progresses, so apologies if you've already tackled this later. FWIW I have written a complete 6502 emulation in Processing so know a thing or two about 6502 microcode :)
If you are talking about the parameter to Execute() it's just so we execute a minimum of the given number of cycles and then return from the function, otherwise I'm trapped in there forever.
@@DavePoo I agree with Christian. Execute should execute a single instruction and return. Think of it as stepping through the code line by line. Also I’m just going through the series, so apologies if you changed directions already
@@dvogel2010 these guys are right - he needs to run one instruction and return. First in an infinite loop, and then add the interrupt handler. If he wants, he can add “break after 2 cycles” for testing.
it is strange to test cycles used because cycles must be zero at last,
if we run cpu.execute(cnt_more_ticks_than_need, mem) for JSR instruction,
the answer will be "cnt_more_ticks_than_need" rather than 9
The actual library definitions should actually go to a *.cpp file, *.h file is only for headers, in other words only declarations. Other than that, pretty good series actually :)
Mais estou gostando . I liked. Great didactic explanation. Congratulations.
try this on it... using 'invalid' bcd digits to trigger a +1 carry to get the correct 0-9A-F hex output in ascii. quite few emulators fail on it cuz it's not quite clear from the datasheets :P (cmp does have 'most of' the side effects of sbc and as such, also... tadaa. decimal mode ;) but 0A is not a valid value in decimal mode.
SED
LDA P1SCOREA
TAX
LSR
LSR
LSR
LSR
CMP #$09+$01
ADC #$30
STA VRAMSTART+15
TXA
AND #$0F
CMP #$09+$01
ADC #$30
STA VRAMSTART+16
CLD
I really cant get the googletest working. I ran into so many errors such as gtest file not found, g++ compiler wrong version etc etc, to the point where I have no idea what Im doing. do you have any tips? I am using vscode
I am really struggling to set up the Gtests . Since i am using linux vscode can someone help me with setting up the project. The library is created in /6502Lib folder , but it /6502Tests i dont know how the "main_6502.h" just includes the header from another folder. I am trying to find out which CMake line includes the library into another folder. Can someone help me with this ?
I am having a hard time to put the whole google test on my project, could you help me with what to do?
I was following curiously on your first video and started learning a lot about cpu 6502 but then I got stuck upon starting this episode and i want to keep going but I cant...
you just started this video with file of code but like i don't know how to follow along without doing so
This google's test thing complicated what I was already struggling to understand!
Well yes, a little. But once it's setup and working, it saves a hell of a lot of time when testing and interating on the codebase.
source code repository not available how I add one
Missed the *or will it? at 17:25 and spent more time than i'm proud of trying to debug why asserting the negative flag as false was failing lol
edit: wrote that before finishing the video lol
Well you are using visual studio, might as well have gone the MS route in that case.
0:21 i would just print changes so see them action lol
It's common for tests that pass to pass silently. You are talking about logging not testing.
Struggling with google test, I am emulating a gameboy cpu, trying a LD B,0xff instruction, when I run the CPU in my main of my project, the register does become 0xff as it should.
When I run google test, configured to run the same code the ram of the system corrupts as does the CPU registers and I am not sure why that is happening
Okay I spent a lot of hours on this but for some reason if I created the object using a unique_ptr then it worked completely fine, i assume new and delete would work the same
Mais estou gostando 👍
7:14 I find it really weird that you bother compiling when VS is already showing you the red squigglies. Like.... why compile? It's literally already telling you it won't work, and if you mouse-over the red, it'll tell you why.
I don't trust the squiggles in VS, they have lied to me too often. I don't even notice the squiggles.
@@DavePoo Weird, they've always worked perfectly for me 🤔
:)
At what level would a cs learn this, say at University or College? I guess I am curious how people learn this, like I have learnt python and R however I have never seen this before in my limited C++ experience. Why I say that is because it doesn't strike me as something popular coding course offer. Regardless, love the videos.
I've no idea. I've never done a CS course.
When it comes to unit testing, it depends on the university/college. A lot of them don't teach this on their own (which is a shame), but some might have an elective course such as "Introduction to Test Driven Development" which can go into the topic of unit testing. If you want a book recommendation on this, Test Driven Development By Example from Kent Beck is a good one to read. It'll teach you a bunch of ins and outs on structuring unit tests correctly, how to write them, etc.
There just does seem to be enough time. It almost seems that people need a life times of experience and then some, which is AI comes in I guess, a pity the word is not structured financial and pay wise to implement it. Might see our first billionaire after all and yet there are place in Nigeria without proper toilets.
The problem with some unit tests is it tends to obfuscate the non-unit test code with behavior that is used to produce test outcomes. e.g. returning s32 from execute for the purposes of testing. If there were no tests, it would return void. Wonder if theres another way around it.
True, but i think my theory there is i am going to need that information to correctly emulate a system if i want to sync up the CPU with another part of the architecture. It's possible that i was thinking too far ahead there and if i did a whole system i would implement it differently.
Guys I'm sorry, am I the only one that is not able to access the resources he is using? I get a weird page with amazon links when I try to open the link in the description
Looks like that page I used during these videos is now no longer online. You could try the waybackmachine to find an old copy, or google "6502 instruction set" to find some equivalent page.
"it's because everything is private in classes in c++ for some stupid reason" if they were public by default how would they be any different from a struct? In other words why don't you just use structs if you want everything public by default?
I think my point was, why did the C++ commitee add the "class" keyword, just so they could give classes a new default that was wrong? They could have just not bothered and saved themselves a new keyword in the language.
@@DavePoo Okay fair enough, while I don't agree I can at least understand the sentiment. I'm enjoying the series so far, so thank you.
@@DavePoo It's a bit weird that you believe that private being the default is wrong.
One goal of classes is abstraction (among others), so sharing or making internal state public by default would have been completely wrong.
The main idea is that you should EXPLICITLY define what you want public.
Better yet, you should have functions (AKA getters) to what you need to be public, because you don't want to tie the specific internal implementation (attribute/field name in this case) with the class public interface.
struct's existed pre-OOP, and it makes sense to have stuff private by default when objects take care of themselves, have private data and can be derived from. So yeah, you need a new keyword I guess. Whenever I'm prototyping and being lazy, I always use structs to not have to write public all the time. And everytime, I end up changing them to class. I'll never learn.
Now remake it in C#
Rust, not C#.
Melhor ainda se fosse em português