• Login
  • Register
  • Dolphin Forums
  • Home
  • FAQ
  • Download
  • Wiki
  • Code


Dolphin, the GameCube and Wii emulator - Forums › Offtopic › Delfino Plaza v
« Previous 1 ... 60 61 62 63 64

Chip8 Emu Help
View New Posts | View Today's Posts

Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Thread Modes
Chip8 Emu Help
06-23-2009, 07:23 AM
#1
gergep
Unregistered
 
i have been trying to make a chip8 emu but have run into some problems
its been programmed on a mac using objective-c/cocoa with some c

1) i dont know how to do the draw opcode using opengl
2) whenever i run it, the app always freezes (rainbow swirling thing) a few seconds into the emulation

could anybody please help me (source is below)


and since this is my first post, let me say great job on the emu guys and continue the good work

any help would be appreciated

http://www.megaupload.com/?d=WKZ01OU2
( source code is in xcode 3.0 format )
thanks
Reply
06-23-2009, 06:40 PM
#2
thegamefreak0134 Offline
Exit Mouse
***
Posts: 165
Threads: 14
Joined: Mar 2009
The draw opcode is what makes the Chip8 tick. As I recall, it uses one register to point into memory at a byte, and some other registers to represent an x,y coordinate onscreen. To perform the draw, you *xor* the screen at that location for every 1 bit in the byte referenced. In other words, if the bit pattern for the byte you're drawing is:

10101010

then you're going to change the value of 4 pixels. Remember, this is an LCD screen, you get on or off only for your pixels. Importantly, and most game logic takes advantage of this, that opcode should also store a flag representing whether or not it "hit" something while it was drawing. In other words, if when inverting your pixels for this opcode any pixel turns *off*, it needs to set a flag. Games will often use this feature to "test" an area of the screen. For example, in a pong game, I could increment the ball position by 1 in both directions each time, and then use this flag to tell me if I hit a wall or a paddle. It's basic collision detection usually, although how its handled is largely up to the game logic.

I can't compile for mac or I would take a look at your code, but I wrote a similar project like this myself. I never got it finished (I was having some weird opcode handling bugs) but I got it working well enough that a bunch of the demo games would play just fine. I should actually try doing it again now that I think about it.

Good luck, and may the force be with you. If nothing else, this will at least teach you that emulation is not to be taken lightly. ^_^ Chip8 is as simple as it gets.

-gamefreak
The only good zombie is a live zombie.
Website Find
Reply
06-23-2009, 07:19 PM (This post was last modified: 06-23-2009, 07:20 PM by Thircase.)
#3
Thircase Offline
Muuuuuuuuuuuu!
**
Posts: 15
Threads: 1
Joined: Jun 2009
I don't undersand anything... Big Grin

Where is the download? LOOOOOOOL

Hahahahaha, So Newbie Stuff....
[Image: mifirmadefuego.jpg]
Favorite Band: Esacrih Airoth (Symphonic Black Metal From Chile) Tongue
Find
Reply
06-24-2009, 12:30 AM
#4
gergep
Unregistered
 
thanks for the quick reply, you explanation helped a lot but i dont understand why the app always freezes when emulating.

EDIT: now i have another problem in my CPU - i dont exactly get how you can tell what the opcode is
for example if the opcode is 0xE0 ( clear the screen ), then why is it written like

Code:
opcode = (memory[pc]<<8 + memory[pc+1]);

pc+=2;

switch ((opcode&0xF000)>>12)
{
     case 0x0:
     {
          if ((opcode& 0x00FF) == 0xE0)
          {
              // Clear the screen
              memset(chip8.display, 0, 64*32);
          }
          break;
     }
}

how do you tell how to sort the opcodes under 0x0, 0x1, 0x2 ....
and if the opcode is 1nnn how would you convert that to hex

thanks
Reply
06-24-2009, 08:28 PM
#5
gcp111
Unregistered
 
(06-24-2009, 12:30 AM)gergep Wrote: how do you tell how to sort the opcodes under 0x0, 0x1, 0x2 ....
and if the opcode is 1nnn how would you convert that to hex

I suggest you get some clean code for reference. I just tried to port a Chip8 emu over to C and it barely even works... Tongue Mine flickers, the DXYN or whatever opcode doesn't get called except on the Pong game, and everything else is blank. I don't know.

But try searching around for some open source chip8 emu, and write it so you can understand which opcodes go where.

Also, 1NNN is just the "name" of the opcode, it means "jump to the address NNN"
Reply
06-25-2009, 01:02 AM
#6
gergep
Unregistered
 
(06-24-2009, 08:28 PM)gcp111 Wrote: I suggest you get some clean code for reference. I just tried to port a Chip8 emu over to C and it barely even works... Tongue Mine flickers, the DXYN or whatever opcode doesn't get called except on the Pong game, and everything else is blank. I don't know.

But try searching around for some open source chip8 emu, and write it so you can understand which opcodes go where.

Also, 1NNN is just the "name" of the opcode, it means "jump to the address NNN"

Sorry for all the annoying questions but i still dont get how the people who make the open source emulators know where to put the opcodes... and also if the is 1NNN how come all of the docs say that is the opcode in hexadecimal and if thats true, how would i get the value

sorry if im just being a noob
Reply
06-25-2009, 06:28 AM
#7
gcp111
Unregistered
 
(06-25-2009, 01:02 AM)gergep Wrote: Sorry for all the annoying questions but i still dont get how the people who make the open source emulators know where to put the opcodes... and also if the is 1NNN how come all of the docs say that is the opcode in hexadecimal and if thats true, how would i get the value

Hexadecimal is just a base-16 number system. You can represent hex humbers in, say, decimal, or better yet - binary.

You take the opcodes from the file 2 bytes (hint: a short) at a time.

The "& 0x0FFF" gets the last three nibbles (4 bits, half a byte) of the opcode. This is the NNN part. Remember, all Chip8 opcodes are 2 bytes long.

The first nibble of the opcode is taken from the first nibble, then some are taken from other parts (like ones from the same set - such as 8XY0 and 8XY1.)

I'm definitely not an expert, but go stare at the documentation, or find some code that names things. In my code, it names things like "op_firstnibble"

I still can't get mine to draw things right though. Tongue I think I'm going to make one in another language for right now.
Reply
06-25-2009, 07:11 AM
#8
gergep
Unregistered
 
thanks for your explanation, i finally get it
thanks i couldn't have completed the emulator without all of your help
Reply
06-25-2009, 08:47 AM
#9
gcp111
Unregistered
 
(06-25-2009, 07:11 AM)gergep Wrote: thanks for your explanation, i finally get it
thanks i couldn't have completed the emulator without all of your help

no problem Smile
Reply
06-26-2009, 10:09 AM
#10
gergep
Unregistered
 
now im having more problems....

every single time i get unkown opcode, is it the loading or the actual cpu

please help me out

Code:
// Fetch opcode
    chip8.opcode = memory[chip8.pc << 8] | memory[chip8.pc+1];
    
    // Set Some Values
    chip8.regs[(chip8.opcode & 0x0F00) >> 8] = chip8.VX;
    chip8.regs[(chip8.opcode & 0x00F0) >> 4] = chip8.VY;
    chip8.regs[15] = chip8.VF;
    chip8.KK = chip8.opcode & 0x00FF;
    
    // Next Instruction for next execute
    chip8.pc += 2;
    
    // Emulate the opcode
    switch (((chip8.opcode & 0xF000)>>12))
    {
        case 0x0:
        {
            switch ((chip8.opcode&0xFFF))
            {
                case 0xE0:        // Clear the screen
                {
                    memset(chip8.display, 0, 64*32);
                    break;
                }
                case 0xEE:        // Return from a subroutine
                {
                    chip8.pc = chip8.stack[chip8.sp];
                    chip8.sp--;
                    break;
                }
                default:
                {
                    UnkownOpcode();
                    break;
                }
            }
            break;
        }
        case 0x1:        // Jump to address NNN
        {
            chip8.pc = (chip8.opcode&0xFFF);
            break;
        }
        case 0x2:        // Cals subroutine at NNN
        {
            chip8.sp++;
            chip8.stack[chip8.sp] = chip8.pc;
            chip8.pc = (chip8.opcode&0xFFF);
            break;
        }
        case 0x3:        // Skips next instruction if chip8.VX == NN
        {
            if (chip8.VX == chip8.KK)
                chip8.pc += 2;
            
            break;
        }
        case 0x4:        // Skips next intruction if chip8.VX != NN
        {
            if (chip8.VX != chip8.KK)
                chip8.pc += 2;
            
            break;
        }
        case 0x5:        // Skips next intruction if chip8.VX == chip8.VY
        {
            if (chip8.VX == chip8.VY)
                chip8.pc += 2;
            
            break;
        }
        case 0x6:        // Set chip8.VX to NN
        {
            chip8.VX = chip8.KK;
            
            break;
        }
        case 0x7:        // Adds NN to chip8.VX
        {
            chip8.VX += chip8.KK;
            
            break;
        }
        case 0x8:
        {
            switch ((chip8.opcode&0x00FF))
            {
                case 0x0:    // Sets chip8.VX to chip8.VY
                    chip8.VX = chip8.VY;
                    break;
                case 0x1:    // Sets chip8.VX to chip8.VX or chip8.VY
                    chip8.VX |= chip8.VY;
                    break;
                case 0x2:    // Sets chip8.VX to chip8.VX and chip8.VY
                    chip8.VX &= chip8.VY;
                    break;
                case 0x3:    // Sets chip8.VX to chip8.VX xor chip8.VY
                    chip8.VX ^= chip8.VY;
                    break;
                case 0x4:    // Adds chip8.VY to chip8.VX.  chip8.VF is set to 1 if there's a carry, otherwise chip8.VF = 0
                    chip8.VF = (chip8.VX += chip8.VY) >> 8;
                    break;
                case 0x5:    // chip8.VY is subtracted from chip8.VX.  chip8.VF is set 0 if there is borrow, else chip8.VF = 1
                    chip8.VF = (chip8.VX > chip8.VY);
                    chip8.VX -= chip8.VY;
                    break;
                case 0x6:    // chip8.VX Shifts right by one.  chip8.VF = least significant bit value of chip8.VX before shift
                    chip8.VF = (chip8.VX & 0x1);
                    chip8.VX >>= 0x1;
                    break;
                case 0x7:    // chip8.VX -= chip8.VY  chip8.VF is set to 0 if theres a borrow, otherwise chip8.VF = 1
                    chip8.VF = (chip8.VY > chip8.VX);
                    chip8.VX = chip8.VY - chip8.VX;
                    break;
                case 0x0E:    // Shifts chip8.VX to left by one.  chip8.VF is set to the most significant bit of chip8.VX before shift
                    chip8.VF = (chip8.VX & 0x80);
                    chip8.VX <<= 0x1;
                    break;
                default:    // Unkown Opcode
                    UnkownOpcode();
                    break;
            }
            break;
        }
        case 0x09:        // Skips next instruction if chip8.VX != chip8.VY
            if (chip8.VX != chip8.VY)
                chip8.pc += 2;
            break;
        case 0x0A:        // Sets I to the address NNN
            chip8.I = (chip8.opcode&0xFFF);
            break;
        case 0x0B:        // Jumps to address NNN + V0
            chip8.pc = (chip8.opcode&0xFFF)+chip8.regs[0];
            break;
        case 0x0C:        // Sets chip8.VX to a random number and NN
            chip8.VX = (unsigned int)(rand() & chip8.KK );
            break;
        case 0x0D:    
        {
            /*
             * Draws a sprite at (chip8.VX, chip8.VY) with a width of 8 pixels and a height of N pixels
             * chip8.VF is set to 1 if any screen pixels are flipped from set to unset when the
             * sprite is drawn, and to 0 if that doesn't happen.
             */
            
            break;
        }
        case 0x0E:
        {
            switch ((chip8.opcode&0x00FF))
            {
                case 0x9E:        // Skips the next instruction if the key stored in chip8.VX is pressed
                    if (keys[chip8.VX])
                        chip8.pc += 2;
                    break;
                case 0xA1:        // Skips the next instruction if the key stored in chip8.VX isn't pressed
                    if (!keys[chip8.VX])
                        chip8.pc += 2;
                    break;
                default:
                    UnkownOpcode();
                    break;
                    
            }
            break;
        }
        case 0x0F:
        {
            switch ((chip8.opcode&0x00FF))
            {
                case 0x07:        // Sets chip8.VX to the vaue of the delay timer
                    chip8.VX = chip8.delayTimer;
                    break;
                case 0x0A:        // A key press is awaited, then stored in chip8.VX;
                    if (key == -1)
                        chip8.pc -= 2;
                    else
                        chip8.VX = key;
                    break;
                case 0x15:        // Sets the delay timer to chip8.VX
                    chip8.delayTimer = chip8.VX;
                    break;
                case 0x18:        // Sets the sound timer to chip8.VX
                    chip8.soundTimer = chip8.VX;
                    break;
                case 0x1E:        // Adds chip8.VX to I
                    chip8.VX += chip8.I;
                    break;
                case 0x29:        
                {
                    /*
                     * Sets I to the location of the sprite for the character in chip8.VX
                     * Characters 0-F (in hexadecimal) are represented by a 4x5 font
                     */
                    
                    chip8.I = chip8.VX*5;
                    
                    break;
                }
                case 0x33:    
                {
                    /*
                     * Stores the binary coded decimal representation of chip8.VX at the a
                     * the adresses I, I + 1, and I + 2
                     */
                    
                    memory[chip8.I] = chip8.VX / 100;
                    memory[chip8.I+1] = (chip8.VX/10) % 10;
                    memory[chip8.I+2] = chip8.VX % 10;
                    
                    break;
                }
                case 0x55:    // Stores V0 to chip8.VX in memory starting at address I
                    memcpy(&memory[chip8.I], chip8.regs, 16);
                    break;
                case 0x65:    // Fills V0 to chip8.VX with values from memory starting at adress I
                    memcpy(chip8.regs, &memory[chip8.I], 16);
                    break;
                default:
                    UnkownOpcode();
                    break;
            }
            break;
        }
        default:
        {
            UnkownOpcode();
            break;
        }
    }

or load
Code:
// Load filename from the openPanel
        filename = [ NSString stringWithString:[ [ panel filenames ] objectAtIndex:0 ] ];
        
        // Load rom into memory
        FILE* file = fopen([ filename UTF8String ], "rb");
        
        // Get the file size
        fseek(file, 0, SEEK_END);
        size_t size = ftell(file);
        rewind(file);
        
        if (size > 3584)
        {
            // File is not valid
            fclose(file);
            NSRunAlertPanel(@"Error", @"Invalid Rom", @"Ok", nil, nil);
            [ NSApp terminate:self ];
        }
        
        [ console Log:[ NSString stringWithFormat:@"Rom Selected - %@\n\n", filename ] ];
        
        // Read the data into memory
        fread(&memory[0x200], 1, size, file);
        
        // Release the file
        fclose(file);
        
        // Log the memory that has a value
        for (int x = 0; x < 4096; x++)
        {
            if (memory[x] != 0)
            {
                [ console Log:[ NSString stringWithFormat:@"Memory[%i] = %i\n", x, memory[x] ] ];
            }
        }
        
        [ NSTimer scheduledTimerWithTimeInterval: 0.1 target:self selector:@selector( startGLWindow )
                                        userInfo:nil repeats:NO ];
    }
    else        // Exit the app if they don't open a file
        [ NSApp    terminate:self ];

theres some objective c in there but its a lot like c

memory is a unsigned char. is that right?

heres my startGLWindow

Code:
// Initialize
    glView = [ [ OpenGLView alloc ] initWithFrame:[ glWindow frame ] colorBits: 32
                                        depthBits: 32 fullscreen:NO ];
    
    if (glView == nil)
    {
        // Does not have a good enough graphics card
        
        NSRunAlertPanel(@"Error", @"Could not create OpenGL context.\nPress Ok to quit", @"Ok", nil, nil);
        [ self dealloc ];
        [ NSApp terminate:self ];
    }
    
    // Make eveything visible
    
    [ glWindow setContentView:glView ];
    [ glWindow makeKeyAndOrderFront:self ];
    
    // Get ready for emulating
    Reset();
    
    // Start looping
    
    for (;;)
    {
        Execute(console);
        
        [ self interrupt ];
        
        if (!running)
            break;
    }

thanks in advance

full source is included here - http://www.megaupload.com/?d=1BJPMRV1
Reply
« Next Oldest | Next Newest »


  • View a Printable Version
  • Subscribe to this thread
Forum Jump:


Users browsing this thread: 1 Guest(s)



Powered By MyBB | Theme by Fragma

Linear Mode
Threaded Mode