CHIP8 thread

Discussion in 'Web development / Programming' started by Dax, Nov 21, 2008.

  1. Shendo

    Shendo Moderator Staff Member Moderator

    Messages:
    5,154
    Likes Received:
    45
    Hey, no need to apologize. Your post was just a bit confusing to understand.
    From what I can tell you are referring to the "half pixel scroll" which from what I can tell works fine on your emulator.

    There was a discussion regarding the mentioned issue at EmuTalk, it might help you.
  2. KrossX

    KrossX クロスエクス

    Messages:
    4,664
    Likes Received:
    125
    Ouch, that thread looks long and I'm just at page 6 of this thread... >_<

    However..... COLORS!
    [​IMG]
    It's a start. =D

    #EDIT: Weeeeeee~ :x3:

    [​IMG]

    #EDIT2: :D

    [​IMG]

    Evilness... I had to --index the palette index. Meh...
    Last edited: Oct 1, 2012
  3. KrossX

    KrossX クロスエクス

    Messages:
    4,664
    Likes Received:
    125
    There are still some programs with problems, like Animal Race... looking really garbled. You can download it from HERE.
  4. ehal256

    ehal256 New Member

    Messages:
    1
    Likes Received:
    0
    If anyone's interested, I'm writing a chip-8 emulator in Common Lisp. Interpreter works, but graphics and sound aren't implemented yet.

    Obviously, it's kinda silly for such a simple system, but I've also started working on dynamically (and maybe statically) recompiling the interpreted code by translating it into Lisp and then running it through the lisp compiler (which is available at runtime).

    https://github.com/ehaliewicz/cl-chip8
  5. nondescript

    nondescript New Member

    Messages:
    11
    Likes Received:
    0
    hello everybody,

    I have finished implementing all the opcodes. Now, I am trying to make the main loop. I was wondering when should the screen be updated. Should it be updated during VBLANK? if so after how many cycles. Any help is appreciated!! Thanks again!
  6. nondescript

    nondescript New Member

    Messages:
    11
    Likes Received:
    0
    reading c8 binary in java

    So, when you are reading the rom for chip 8, is it safe to put the content in memory directly

    RandomAccessFile in = new RandomAccessFile("c:\\test.c8", "r");

    byte[] tempId = new byte[(int)in.length()];

    in.read(tempId, 0, (int)in.length());

    and start executing...or do we have to worry about isolating headers. Thanks :) The chip 8 is coming along nicely.:thumb:
  7. nondescript

    nondescript New Member

    Messages:
    11
    Likes Received:
    0
    question regarding the SUB opcode

    i just had a question looking at the chip 8 specs.

    8xy4 - ADD Vx, Vy
    Set Vx = Vx + Vy, set VF = carry.

    The values of Vx and Vy are added together. If the result is greater than 8 bits (i.e., > 255,) VF is set to 1, otherwise 0. Only the lowest 8 bits of the result are kept, and stored in Vx.


    8xy5 - SUB Vx, Vy
    Set Vx = Vx - Vy, set VF = NOT borrow.

    If Vx > Vy, then VF is set to 1, otherwise 0. Then Vy is subtracted from Vx, and the results stored in Vx.


    So, looking at the flag condition for SUB, is it wrong there? shouldnt the flag be set if
    Vx < Vy so that the result is negative....
  8. Shendo

    Shendo Moderator Staff Member Moderator

    Messages:
    5,154
    Likes Received:
    45
    If it should be NOT borrow then that is ok.
  9. nondescript

    nondescript New Member

    Messages:
    11
    Likes Received:
    0
    clarification

    Thanks! Shendo

    For the following opcode, do we have to worry about setting carry flags like in
    ADD Vx, Vy.

    7xkk - ADD Vx, byte
    Set Vx = Vx + kk.

    Adds the value kk to the value of register Vx, then stores the result in Vx.
  10. Chopin

    Chopin New Member

    Messages:
    1
    Likes Received:
    0
    Hi,

    To begin, I apologize for my English (I'm French).

    I am trying to develop an emulator Mega Chip 8.
    The problem is that I can not display color sprites with SDL.


    Here is the code I use.

    Code:
    // 01NN
    void opCode_01NN(Uint8 NN)
    {
        pc += 2;
        I = (NN << 16) + (memory[pc] << 8) + memory[pc + 1];
    }
    // 03NN
    Uint8 spriteMegaWidth = 0;
    void opCode_01NN(Uint8 NN)
    {
        spriteMegaWidth = NN == 0 ? 256 : NN;
    }
    // 04NN
    Uint8 spriteMegaHeight = 0;
    void opCode_01NN(Uint8 NN)
    {
        spriteMegaHeight = NN;
    }
    // Sprite Mega Chip 8
    void opCode_Mega_DXYN(Uint8 X, Uint8 Y)
    {
        Uint8 x = 0, y = 0;
        Uint8 iLine = 0;
        Uint8 iPixel = 0;
        Uint16 iM = 0;
        Uint8 a/*, r, g, b*/;
    
        // Y
        for (iLine = 0; iLine < spriteMegaHeight; iLine++)
        {
            y = (V[Y] + iLine) % heightSystem;
    
            // X
            for (iPixel = 0; iPixel < spriteMegaWidth; iPixel++)
            {
                x = (V[X] + iPixel) % widthSystem;
    
                // a = memory[I + iM]; // A
                /*
                iM++;
                r = memory[I + iM]; iM++; // R
                g = memory[I + iM]; iM++; // G
                b = memory[I + iM]; iM++; // B
                #BUG Color#
                */
    
                a = memory[I + iM]; iM++;
                setPixel(x, y, (a << 16) + (a << 8) + a);
            }
        }
    }

    Here is the result :'(
    Mega Minimal, Mega Particle Demo and Twister Demo

    [​IMG] [​IMG] [​IMG]


    Help me please :'( :'(
  11. marco9999

    marco9999 New Member

    Messages:
    7
    Likes Received:
    2
    (Reviving a dead thread here..hehe)

    First of all, I have made a chip8 emulator with both interpreter and dynamic recompilation (just-in-time) cores... It was an exercise to learn about dynamic recompilation (and it was a lot of work!).

    See here:
    Interpreter: github dot com/marco9999/Super8
    Dynarec: github dot com/marco9999/Super8_jitcore

    And now a question:
    Has anyone else encountered a bug with Space Invaders (INVADERS) rom? (using v0.9 by David Winter).. Seems like it corrupts the stack gradually and finally stops displaying any meaningful data after roughly 13 or 14 rounds of the game (due to running out of stack space on a 16 levels implementation).

    I have investigated it a bit, and found that after the game over screen, each time it draws the title screen, it makes a call and puts 0x0245 onto the stack (opcode is 2387 - stack jump to 0x0387).. but the call is never removed from the stack - ie: no 00EE opcode. Im not sure where the 00EE call should happen either.

    It happens on both my interpreter and dynarec emulators, and also on this emulator:
    multigesture dot net/articles/how-to-write-an-emulator-chip-8-interpreter/

    Also if anyone is interested, I will probably write up an 'introduction to dynamic recompilation'... I know there are already some resources on the internet, but there is no concrete example of one being created, and what ideas are used in creating one (such as a jump table used in mine).
  12. icsiwtf

    icsiwtf New Member

    Messages:
    3
    Likes Received:
    0
    I'd love to see a tutorial/guide for dynamic recompilation. In particular, doing it on Linux/OSX. I took a look at your projects, pretty cool! I've been reading your dynarec emulator source code (and starred it on GitHub ;)).

    I haven't been able to follow it completely. Part of the problem is I can't build it (I don't have a Windows machine). It seems like you're lazily compiling the routines that Chip-8 supports but not compiling blocks of code. I thought dynamic recompilers would compile all instructions up to a jump or branch instruction? Maybe I am reading the code incorrectly.

    I've done a Chip-8 emulator as well (interpreted). Check it out here! I've also completed a Chip-8 disassembler, you can check that out here.

    I have only found one bug with my Chip-8 emulator. It seems the game Blitz behaves oddly, once the plane goes off the screen it crashes. I have never been able to figure out why :mad:
  13. marco9999

    marco9999 New Member

    Messages:
    7
    Likes Received:
    2
    I apologise for the messiness of the project... Havent had time to clean it up yet or anything!

    For linux and OS X specifics, all you would need to change is how caches are allocated (in WIn32 its though the VirtualAlloc function)... see the allocNewCacheByC8PC function in Chip8Engine_CacheHandler.cpp. All the VirtualAlloc function does is give you a block of memory that has executable privileges set, since the new operator or malloc doesn't. So if you can find a replacement for that, you're good to go. I believe SDL runs under linux and OS X also, so thats good. In my setup however I have used the static link files (.lib) with the header directory included and the SDL2.dll etc files... Not sure how that works under Linux/Os X.

    With the blocks of code... I'm not entirely sure how other emulators handle recompiling code but heres how I have done it: (you are correct that blocks always end in a jump/branch... this is actually a very important concept! well done for getting this!!! :) )
    Initially, as soon as you run the program, a single cache is setup with no code in it - this produces a OUT_OF_CODE interrupt as soon as it tries to run it.. which invokes the translatorLoop() function in Chip8Engine.cpp. This function is basically responsible for turning C8 opcodes into x86 opcodes, and it does so 16 opcodes at a time (ignoring the other condition it checks for now), then transfers control back to the emulation loop. So in a way, yes it is kind of a lazy way of doing it. I chose 16 so it was easier to debug, but it could easily be 128 or something. However it would also be quite easy to change this so that it would compile up until a jump is encountered. (ie: have a variable that is set to 1 when a jump opcode is translated, then exit the translator loop by checking this variable).

    In the end, it doesnt really matter. After those 16 opcodes have been recompiled, they will never be touched again. When the caches run the next time and it gets to the end of the 16 opcodes, it will again invoke a OUT_OF_CODE interrupt, which takes us back into the translator loop. This time it processes the next 16 opcodes.

    So eventually, it will recompile all of the code, but it just does it 16 opcodes at a time. The caches are seperated by jumps however, and this is marked by the stop_write_flag struct member of CACHE_REGION, which is set to 1 every time a jump is reached (see 0x1NNN opcode in Chip8Engine_Dynarec.cpp for example. It contains: cache->setStopWriteFlagCurrent();). If this flag is set, then the translator loop will most likely allocate a new cache.. the cache selection logic is handled by (within translatorLoop() ):

    // Select the right cache to use & switch
    int32_t cache_index = cache->getCacheWritableByC8PC(C8_STATE::cpu.pc);
    cache->switchCacheByIndex(cache_index);

    If you are worried about the overhead speed penalty or anything else like that then I can tell you it is not significant for the C8.. I wrote this dynarec emulator more as a proof of concept that it works than being focused on speed. But that is a good question to ask other developers... how much code they recompile at one time.

    Phew, sorry if it doesnt make sense haha.. its 1am here and I need some sleep.

    I also tried to get your emulator working, and I got it to almost build but SDL2_mixer is not playing nicely with VS2015 for some reason.. (its not a problem from your code though).
    Blitz on my emulators is just a block moving right so.... I didnt even know it was a game :D! Ill take a look when I get it working.
    icsiwtf likes this.
  14. icsiwtf

    icsiwtf New Member

    Messages:
    3
    Likes Received:
    0
    Thanks!

    Sorry you couldn't run my emulator-- I've never tested it on Windows. I am fairly confident it _could_ run, but the libraries/headers may need to be setup with your compiler and worse case, may have to rewrite the SDL2 includes if they are not part of the system's search paths. I think everything besides the build process is cross platform.

    The Blitz game doesn't crash on me per-say, but when the ship reaches the other side of the screen it shows "Game Over". Other emulators show the ship looping around and lowers the ship a little. I have never been able to debug it :eek:.

    I've tried INVADERS on my emulator, haven't see any issues even after 15-20 games. Not sure if helps, but may give you something to compare it with :D

    Let me know if you decide to write up a JIT/dynamic recompilation guide. I'd love to give it a read. I've been learning more and more-- I can now execute dynamic code blocks on OS X and Linux using the POSIX versions of the memory allocation/options, but having a hard time figuring out how to architect the emulator to best take advantage of it.

    I think I will read through your emulator more and try to grasp it better :). There's a _lot_ of code in there! I feel like I need to draw out the main components to really grasp the flow of data/instructions. In my mind I visualize the C/C++ code executing but also have this parallel universe where the code is executing natively and data is being passed back to the C/C++ world. I think the part that perplexes me the most is how/when to pass data back to the C/C++ control flow.

    I'd love to see some performance benchmarks between JIT based emulation and interpreted emulation. I don't think there would be much of difference with Chip-8, but it would be interesting. I'd also like to know more about when to use JIT versus interpreted approaches. It's hard to make a judgement call without some kind of benchmarks/data.
    Last edited: Nov 15, 2015
  15. marco9999

    marco9999 New Member

    Messages:
    7
    Likes Received:
    2
    Yep I am currently writing up the guide now, but I'm trying to do it properly as its hard to teach. No ETA but about 1/3 done.

    I managed to get your emulator running, and it does indeed suffer from the same problem (INVADERS). The reason why it still works is because there appears to be no bounds checking of the stack after 16 levels... I have a hunch that at least visual studio compiles with stack corruption protection, so its probably the same for XCode etc. See here in the watch tab: http://imgur.com/vE2Y9Ax. Notice sp = 0x15 (hex) = 21, so you have gone over the 16 levels of c8 stack allocated, even though it still runs fine.

    If you turn all compiler optimisations on, I'm sure something will break. Havent checked into blitz yet though.

    By the way, I should have mentioned that I have the code set in my emulator (and yours) for key[5] = 1 always, not just when it expects user input. So as far as im aware, its a bug with invaders.

    I wanted to touch on this too: "In my mind I visualize the C/C++ code executing but also have this parallel universe where the code is executing natively and data is being passed back to the C/C++ world. I think the part that perplexes me the most is how/when to pass data back to the C/C++ control flow."

    Dont worry, it took me a while to understand it all too.

    The c++ code has nothing to do with any of the C8 system. It is only there to handle interrupts, which are generated from the native code (and as apart of the interrupts, one is OUT_OF_CODE which is to translate code). Generally, the c++ part does not ever touch the V or I "registers", only the native code does this (minor exception to this rule is when a USE_INTERPRETER interrupt is generated, there is an indirect jump, or there is self modifying code). If you manage to get it to compile and run you will be able to see much clearly whats going on.

    EDIT: yep, invaders crashes at around 148 runs of the game for me with full optimisations turned on.. access violation exception raised from writing.
    Last edited: Nov 16, 2015
  16. marco9999

    marco9999 New Member

    Messages:
    7
    Likes Received:
    2
    I have just looked at the BLITZ rom too using your emulator, and it contains at location 0x02D7 the opcode 12D7 - jump to itself (infinite loop). So its designed to stop at the game over screen it appears... Nothing you can do except modify the rom to jump back to 0x0200 after clearing all the registers, screen etc so it basically resets itself.
  17. icsiwtf

    icsiwtf New Member

    Messages:
    3
    Likes Received:
    0
    Thanks! I didn't realize I didn't check the stack boundary. I am going to have to do that. Glad you got it running, cool to see someone else running it :)

    Really looking forward to the guide-- I bet everyone is!
  18. Keithster

    Keithster New Member

    Messages:
    2
    Likes Received:
    0
    Hi all, basic question here.

    I'm a bit confused implementing 8XY6: "Shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift."

    I wrote:
    VF = VX & 0x80;
    VX >>= 1;
    PC += 2;

    My confusion is in the LSB of VX. My understanding is that Chip-8 is Big Endian, so the LSB is all the way to the right, and MSB to the left (correct me if I'm wrong). So to take the LSB of VX, I AND with 0x80 which is 1000000.

    Other implementations I saw them just AND with 0x1 (shouldn't that return the MSB and not LSB? again, Big Endian...)

    Which is the correct way to get the LSB/MSB of a Big Endian byte?

    Any help is appreciated. Thanks!
  19. marco9999

    marco9999 New Member

    Messages:
    7
    Likes Received:
    2
    Hi, You are correct that the Chip8 is big endian... However the endianness does not matter once you use it in a high level language - it is automatically handled by the compiler (except in a few situations, such as directly accessing the Chip8 memory). For example if you had a value such as 0xABCD assigned to a variable within C/C++, it wont matter what the underlying endianness is as it will always appear to you as 0xABCD while in C/C++.

    Also I believe endianness is related only to bytes, not bits. So this means a single byte number say 0x02 will always be stored in memory as 0b00000010, no matter what system you are on (maybe im wrong about this). Anyway this is the case on x86 platforms which ill assume is what you're developing on.

    Therefore in order to get the LSB, you just need to AND with 0x01 = 0b00000001

    Good question!
  20. Keithster

    Keithster New Member

    Messages:
    2
    Likes Received:
    0
    Thanks for the reply. I got my Ch8 interpreter working fine. Ch8 is pretty cool because it gives a good introduction to emulator programming. Any idea what would be the next system of choice to emulate in terms of difficulty? Original Gameboy? Atari 2600? pico-8?

Share This Page