Emulating a CPU in C++ #2 (6502) - Unit Testing

แชร์
ฝัง
  • เผยแพร่เมื่อ 21 พ.ย. 2024

ความคิดเห็น • 63

  • @AlanKrause
    @AlanKrause 3 ปีที่แล้ว +29

    Another good test to add would be for the program counter - make sure it is advanced the correct # of bytes, etc.

  • @alienrenders
    @alienrenders 3 ปีที่แล้ว +15

    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.

  • @willofirony
    @willofirony 2 ปีที่แล้ว +7

    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.

    • @DavePoo
      @DavePoo  2 ปีที่แล้ว +4

      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.

  • @nev6502
    @nev6502 3 ปีที่แล้ว +3

    Learning about googletest was very valuable to me! Got it all set up now, thank you!

    • @DavePoo
      @DavePoo  3 ปีที่แล้ว

      Yeah, it's super useful

  • @jkobain
    @jkobain ปีที่แล้ว

    FFS, I just clicked the second episode, and YT suggests me #35 in this series. Eyyy, it appears to be quite a journey.

  • @JeroenDeMeyer
    @JeroenDeMeyer 3 ปีที่แล้ว +6

    Another good test to add is to load x00 in de A register and test if the Zero flag is set.

    • @DavePoo
      @DavePoo  3 ปีที่แล้ว

      I definitely do add that test at some point as it's in the final source code "LDAImmediateCanAffectTheZeroFlag"

  • @StrangeLake
    @StrangeLake 3 ปีที่แล้ว +4

    15:38-15:44 resonates with me on a personal level
    Joking aside though, great video!

    • @DavePoo
      @DavePoo  3 ปีที่แล้ว +3

      Never trust anything that works first time

  • @jotecch-br
    @jotecch-br ปีที่แล้ว

    I liked. Great didactic explanation. Congratulations

  • @julianbrown1331
    @julianbrown1331 3 ปีที่แล้ว +7

    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

    • @DavePoo
      @DavePoo  3 ปีที่แล้ว

      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)

    • @julianbrown1331
      @julianbrown1331 3 ปีที่แล้ว +3

      @@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

  • @stuartmcconnachie
    @stuartmcconnachie 3 ปีที่แล้ว +7

    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.

    • @DavePoo
      @DavePoo  3 ปีที่แล้ว +1

      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.

  • @jakobflocke134
    @jakobflocke134 ปีที่แล้ว

    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

  • @CZghost
    @CZghost 3 ปีที่แล้ว +3

    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 :)

  • @arkanjo7509
    @arkanjo7509 3 ปีที่แล้ว +2

    thanks

  • @christianlett
    @christianlett 3 ปีที่แล้ว +13

    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 :)

    • @DavePoo
      @DavePoo  3 ปีที่แล้ว +1

      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.

    • @dvogel2010
      @dvogel2010 3 ปีที่แล้ว +1

      @@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

    • @idjles
      @idjles 3 ปีที่แล้ว +1

      @@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.

  • @oglothenerd
    @oglothenerd 3 หลายเดือนก่อน +1

    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.

  • @HarleyKinney-c3c
    @HarleyKinney-c3c ปีที่แล้ว

    Mais estou gostando . I liked. Great didactic explanation. Congratulations.

  • @nullntr
    @nullntr ปีที่แล้ว +1

    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

  • @MrRobbyvent
    @MrRobbyvent 3 ปีที่แล้ว

    This google's test thing complicated what I was already struggling to understand!

    • @DavePoo
      @DavePoo  3 ปีที่แล้ว

      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.

  • @CB3ROB-CyberBunker
    @CB3ROB-CyberBunker ปีที่แล้ว

    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

  • @jarisipilainen3875
    @jarisipilainen3875 3 ปีที่แล้ว +1

    0:21 i would just print changes so see them action lol

    • @DavePoo
      @DavePoo  3 ปีที่แล้ว

      It's common for tests that pass to pass silently. You are talking about logging not testing.

  • @xsamuelx3603
    @xsamuelx3603 6 หลายเดือนก่อน +1

    :)

  • @Voando44S
    @Voando44S 4 ปีที่แล้ว +2

    Mais estou gostando 👍

  • @tcratius1748
    @tcratius1748 3 ปีที่แล้ว

    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.

    • @DavePoo
      @DavePoo  3 ปีที่แล้ว +3

      I've no idea. I've never done a CS course.

    • @lijnk
      @lijnk 3 ปีที่แล้ว +1

      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.

    • @tcratius1748
      @tcratius1748 3 ปีที่แล้ว

      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.

  • @kimo3813
    @kimo3813 7 หลายเดือนก่อน

    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

  • @fire7878
    @fire7878 2 หลายเดือนก่อน

    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...

    • @fire7878
      @fire7878 2 หลายเดือนก่อน

      you just started this video with file of code but like i don't know how to follow along without doing so

  • @marsovac
    @marsovac ปีที่แล้ว

    Well you are using visual studio, might as well have gone the MS route in that case.

  • @Xenthera
    @Xenthera 2 หลายเดือนก่อน

    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

  • @clonkex
    @clonkex 3 ปีที่แล้ว +3

    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.

    • @DavePoo
      @DavePoo  3 ปีที่แล้ว +14

      I don't trust the squiggles in VS, they have lied to me too often. I don't even notice the squiggles.

    • @clonkex
      @clonkex 3 ปีที่แล้ว +2

      @@DavePoo Weird, they've always worked perfectly for me 🤔

  • @amithr1491
    @amithr1491 3 ปีที่แล้ว

    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 ?

  • @stevencoil1844
    @stevencoil1844 2 ปีที่แล้ว

    source code repository not available how I add one

  • @afkafkafk
    @afkafkafk 3 ปีที่แล้ว

    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

    • @afkafkafk
      @afkafkafk 3 ปีที่แล้ว

      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

  • @fate9958
    @fate9958 2 ปีที่แล้ว

    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

    • @DavePoo
      @DavePoo  2 ปีที่แล้ว

      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.

  • @Cieric
    @Cieric 3 ปีที่แล้ว +3

    "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?

    • @DavePoo
      @DavePoo  3 ปีที่แล้ว +1

      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.

    • @Cieric
      @Cieric 3 ปีที่แล้ว

      @@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.

    • @RuiMartins
      @RuiMartins 3 ปีที่แล้ว +12

      @@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.

    • @jorenheit
      @jorenheit 3 ปีที่แล้ว

      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.

  • @dejanpopovic7903
    @dejanpopovic7903 3 ปีที่แล้ว

    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.

    • @DavePoo
      @DavePoo  3 ปีที่แล้ว

      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.

  • @worldwarwitt2760
    @worldwarwitt2760 2 ปีที่แล้ว

    Now remake it in C#

    • @OpenGL4ever
      @OpenGL4ever 8 หลายเดือนก่อน

      Rust, not C#.

  • @Voando44S
    @Voando44S 4 ปีที่แล้ว +1

    Melhor ainda se fosse em português