Page 1 of 14 12311 ... LastLast
Results 1 to 10 of 133

Thread: Gameboy Advance

  1. #1
    EmuTalk Member
    Join Date
    Feb 2014
    Location
    Niedersachsen, Germany
    Posts
    87
    Mentioned
    8 Post(s)

    Gameboy Advance

    Hello
    I thought it would be useful to open a thread for information exchange about programme gameboy advance emulators.
    And there I go with my first question



    I'm currently writing the function that decodes thumb instructions. Currently I have to approaches for executing and decoding those instructions:
    1. Decode opcode information to an struct at corresponding decode stage of the pipeline and execute it with the information from the struct at execution stage.
    This approach would strictly follow the rules of pipelining. Also this is my current approach
    2. Do nothing at instruction corresponding decode stage and do both decoding and execution at the execution stage.

    What do you think would be better for my emulator?

    This is my current code:
    Code:
    #define OPERAND_REG 0
    #define OPERAND_IMM 1
    
    typedef struct _DecodeData
    {
        uint32_t opcode;
    
        uint32_t instruction;
        uint32_t operand1;
        uint32_t operand2;
        uint32_t operand3;
        uint8_t operand1_type;
        uint8_t operand2_type;
        uint8_t operand3_type;
        uint8_t operand_count;
    
        uint8_t condition;
        uint32_t instWidth;
    } DecodeData;
    
    #define OP_LSL 0
    #define OP_LSR 1
    #define OP_ASR 2
    #define OP_ADD 3
    #define OP_SUB 4
    #define OP_MOV 5
    #define OP_CMP 6
    #define OP_AND 7
    #define OP_EOR 8
    #define OP_ADC 9
    #define OP_SBC 10
    #define OP_ROR 11
    #define OP_TST 12
    #define OP_NEG 13
    #define OP_CMN 14
    #define OP_ORR 15
    #define OP_MUL 16
    #define OP_BIC 17
    #define OP_MVN 18
    
    void arm7_decode_thumb(uint32_t opcode, DecodeData* dec)
    {
        /* Decode logic goes here! */
        uint8_t identifier = opcode >> 8;
    
        memset(dec, 0, sizeof(DecodeData));
    
        dec->opcode = opcode;
        dec->condition = 0xE; // execute always
    
        if (identifier < 0b00011000) // Move shifted register
        {
            dec->operand1 = opcode & 7;
            dec->operand1_type = OPERAND_REG;
            dec->operand2 = (opcode >> 3) & 7;
            dec->operand2_type = OPERAND_REG;
            dec->operand3 = (opcode >> 6) & 0x1F;
            dec->operand3_type = OPERAND_IMM;
            dec->operand_count = 3;
            switch (identifier & 0b00011000)
            {
            case 0b00000000: dec->instruction = OP_LSL; break;
            case 0b00001000: dec->instruction = OP_LSR; break;
            case 0b00010000: dec->instruction = OP_ASR; break;
            }
        } else if (identifier < 0b00100000) { // Add / Subtract
            dec->operand1 = opcode & 7;
            dec->operand1_type = OPERAND_REG;
            dec->operand2 = (opcode >> 3) & 7;
            dec->operand2_type = OPERAND_REG;
            dec->operand3 = (opcode >> 6) & 7;
            dec->operand_count = 3;
            if ((identifier & 0b00000100) == 0b00000100) // Immediate?
                dec->operand3_type = OPERAND_IMM;
            else
                dec->operand3_type = OPERAND_REG;
            if ((identifier & 0b00000010) == 0b00000010) // Subtraction or addition?
                dec->instruction = OP_SUB;
            else
                dec->instruction = OP_ADD;
        } else if (identifier < 0b01000000) { // Move / compare / add / subtract immediate
            dec->operand1 = (opcode >> 8) & 7;
            dec->operand1_type = OPERAND_REG;
            dec->operand2 = opcode & 0xFF;
            dec->operand2_type = OPERAND_IMM;
            dec->operand_count = 2;
            switch (identifier & 0b00011000)
            {
            case 0b00000000: dec->instruction = OP_MOV; break;
            case 0b00001000: dec->instruction = OP_CMP; break;
            case 0b00010000: dec->instruction = OP_ADD; break;
            case 0b00011000: dec->instruction = OP_SUB; break;
            }
        } else if ((identifier & 0b11111100) == 0b01000000) { // ALU operations
            dec->operand1 = opcode & 7;
            dec->operand1_type = OPERAND_REG;
            dec->operand2 = (opcode >> 3) & 7;
            dec->operand2_type = OPERAND_REG;
            dec->operand_count = 2;
            switch ((opcode >> 6) & 0xF)
            {
            case 0x0: dec->instruction = OP_AND; break;
            case 0x1: dec->instruction = OP_EOR; break;
            case 0x2: dec->instruction = OP_LSL; break;
            case 0x3: dec->instruction = OP_LSR; break;
            case 0x4: dec->instruction = OP_ASR; break;
            case 0x5: dec->instruction = OP_ADC; break;
            case 0x6: dec->instruction = OP_SBC; break;
            case 0x7: dec->instruction = OP_ROR; break;
            case 0x8: dec->instruction = OP_TST; break;
            case 0x9: dec->instruction = OP_NEG; break;
            case 0xA: dec->instruction = OP_CMP; break;
            case 0xB: dec->instruction = OP_CMN; break;
            case 0xC: dec->instruction = OP_ORR; break;
            case 0xD: dec->instruction = OP_MUL; break;
            case 0xE: dec->instruction = OP_BIC; break;
            case 0xF: dec->instruction = OP_MVN; break;
            }
        }
    
        dec->instWidth = 2;
    }
    Greetz Flerovium
    Last edited by Flerovium; February 2nd, 2017 at 20:36.

  2. #2
    Moderator Cyberman's Avatar
    Join Date
    Nov 2001
    Posts
    1,928
    Mentioned
    1 Post(s)
    Quote Originally Posted by Flerovium View Post
    Hello
    I thought it would be useful to open a thread for information exchange about programme gameboy advance emulators.
    And there I go with my first question

    I'm currently writing the function that decodes thumb instructions. Currently I have to approaches for executing and decoding those instructions:
    1. Decode opcode information to an struct at corresponding decode stage of the pipeline and execute it with the information from the struct at execution stage.
    This approach would strictly follow the rules of pipelining. Also this is my current approach
    2. Do nothing at instruction corresponding decode stage and do both decoding and execution at the execution stage.

    What do you think would be better for my emulator?

    This is my current code:

    Greetz Flerovium

    1. Its your emulator
    2. What are you trying to acomplish?


    You can use this data in a number of ways.
    For example you can run it through an interpretor for step by step execution
    You could have a dynamic recompilor generate pointers to function calls.
    You could have a quasi static recompilor generate intermediate data that can be used to generate code to run in the emulator with self modifying code detection.
    Not sure how much memory you plan on using and each approach has different requirements.

    Anyhow you should expiriment see what works best for what you want to do.

    Cyb
    Progress (n.):
    The process through which the Internet has evolved from smart people in front of dumb terminals to dumb people in front of smart terminals.
    -------------------------------------------------------------------
    Recursive (adj):
    see Recursive

  3. #3
    EmuTalk Member
    Join Date
    Mar 2014
    Location
    Chicago, IL
    Posts
    165
    Mentioned
    27 Post(s)
    I think Flerovium was asking if it's strictly necessary to emulate the decoding stage as a separate stage (true to a real ARM processor) or if the decoding and execution stage can be lumped together.

    In the end though, I don't think it matters. I emulate the pipeline stage-by-stage, but this is actually a matter of preference. It might be easier in your codebase to put the decoding and execution stages together, or you might want them separate to be explicit about how the emulator works. I have not delved too deeply into the GBA's ARM CPU, but ordinarily I would not expect the two approaches you listed to cause two different results.

    Also, looks like you beat me to making this thread. In the spirit of the other emulator programming threads, I'll post some helpful links:

    http://problemkaputt.de/gbatek.htm - GBATEK, the king of GBA and DS documentation
    http://simplemachines.it/doc/arm_inst.pdf - Generic ARM instruction overview
    http://www.gbadev.org/ - Demos, homebrew, tutorials and more
    http://exophase.devzero.co.uk/armwrestler.zip - ARMWrestler, a test ROM for verifying the accuracy of ARM and THUMB instructions (like blargg's GB CPU tests).

    Guess I should get back to work. I haven't touched my GBA emulator in a bit. Implementing ARM and THUMB instructions myself as a learning experience, but it's not exactly a fast learning experience you know.

  4. #4
    Moderator Cyberman's Avatar
    Join Date
    Nov 2001
    Posts
    1,928
    Mentioned
    1 Post(s)
    I suppose I may have too stick this, (LOL).
    The irony of the discussion regarding ARM emulation is it can be difficult to emulate an ARM on an ARM, as all instructions sets are not the same on the ARM.
    For the GBA programmers often had 2 sets of code. A tight library that executed from the internal RAM that was almost purely tradional ARM code (mostly sound processing and things like JPEG DCT things)
    and a set in Thumb mode which was executed from the ROM space. Slow stuff was kept in ROM space along with data. I was always facinated by how good a job they had done for what space they had.

    Erstwhile some 'stuff' may be added too this thread by me if I get some time.

    Cyb
    Progress (n.):
    The process through which the Internet has evolved from smart people in front of dumb terminals to dumb people in front of smart terminals.
    -------------------------------------------------------------------
    Recursive (adj):
    see Recursive

  5. #5
    EmuTalk Member
    Join Date
    Mar 2014
    Location
    Chicago, IL
    Posts
    165
    Mentioned
    27 Post(s)
    Spent a lot of time today working on ARM emulation (more so today than in days before). For the most part I have ARM.3 through ARM.5 done (Branches + Data Processing basically), and THUMB.1 and THUMB.2 done. I thought I'd tackle ARM first given how complex it is, but I seem to be shifting back to THUMB. THUMB really is reduced in scope, just like they say (not complaining, that makes it easy to implement ) I think the bulk of the work one has to do with emulating the ARM instructions is with Data Processing and coming up with an efficient design for that. Everything else doesn't seem so bad after that. Big step up from a modified Z80 though.

    Still some little nagging TODO stuff (like flushing the pipeline whenever an instruction manually changes the PC) but I'm really enjoying this, now that I've got a feel for how the GBA's CPU works. No timing implemented just yet (no need to, no code worth running can run). Long ways to go. We'll see where I am next weekend

  6. #6
    EmuTalk Member
    Join Date
    Feb 2014
    Location
    Niedersachsen, Germany
    Posts
    87
    Mentioned
    8 Post(s)
    Quote Originally Posted by Shonumi View Post
    http://exophase.devzero.co.uk/armwrestler.zip - ARMWrestler, a test ROM for verifying the accuracy of ARM and THUMB instructions (like blargg's GB CPU tests).

    Guess I should get back to work. I haven't touched my GBA emulator in a bit. Implementing ARM and THUMB instructions myself as a learning experience, but it's not exactly a fast learning experience you know.
    This is actually really nice! I think that this will help me a lot!

  7. #7
    EmuTalk Member
    Join Date
    Mar 2014
    Location
    Chicago, IL
    Posts
    165
    Mentioned
    27 Post(s)
    So, is any one working on anything? Been quite busy myself. I have made two small test ROMs with a focus on LCD emulation at the most basic level. Currently I have most of the THUMB instructions finished (just two more to implement) and I've got LCD emulation too. I'm aiming to make this emulator as cycle-accurate as I can, and everything runs on a per-pixel basis at the moment. I figured I'd share the test ROMs for anyone else interested in writing a GBA emulator for themselves. When I was making GB Enhanced, Imran Nazar gave a lot of little ROMs that demonstrated key concepts in action and was a good way to measure how well progress on one's own emulator was coming along. Hopefully I can do the same.

    Stripes Demo #1 - Displays alternating black and white vertical bars on the screen. The file is called checkerboard, but I was too lazy to make a checkerboard pattern :p Later versions will actually have the checkerboard pattern by manipulating BG scrolling.


    checker_board_final.gba
    Source Code

    TV Test #1 - Displays colored stripes, similar to some of the old test patterns found on TVs. This is the first version, more will come to test even more aspects of the GBA LCD. For now, something simple.


    tv_test_final.gba
    Source Code

    Hope this helps someone. Please note that this was all written by hand with a hex editor so the "source code" isn't something you can run through a compiler. They're more like super-detailed notes. They only detail the THUMB instructions. Each Test ROM runs in ARM mode for a few instructions just to switch to THUMB mode.

    At any rate, I'm still a bit too far from being able to test commercial games, and I still need to get a Flash Cart to verify my own homebrew tests (these work in VBA-M and naturally my own WIP emulator though). Next up, more tests, more ARM7 emulation, and more tests

  8. #8
    EmuTalk Member
    Join Date
    Feb 2014
    Location
    Niedersachsen, Germany
    Posts
    87
    Mentioned
    8 Post(s)
    I've been too lazy in last time to write on my emulator =P
    Still haven't finished thumb lol. Maybe I get myself the next days to pickup work again =)
    Your doing great progress! BTW: Why don't you use an assembler? There are quite good ones out there =)
    I like to use the one provided by GCC for ARM.

  9. #9
    EmuTalk Member
    Join Date
    Mar 2014
    Location
    Chicago, IL
    Posts
    165
    Mentioned
    27 Post(s)
    Well, unless that assembler will attach a GBA ROM header and make sure the bytes are little-endian, there's still a lot to do to produce a functioning GBA ROM. An assembler dedicated for the GBA sounds better to me.

    I have a little JavaScript that builds the code I need for several instructions. I just copy and paste the hex output into a hex editor. That's as close to an assembler as I get. You know me though, I do things with the bare minimum tools :p

    I think I'll tackle interrupts next, at least the VBlank interrupt. We'll see how it goes.
    Last edited by Shonumi; August 28th, 2014 at 06:39.

  10. #10
    EmuTalk Member
    Join Date
    Feb 2014
    Location
    Niedersachsen, Germany
    Posts
    87
    Mentioned
    8 Post(s)
    Sometime ago I wrote some small demos in Assembler, creating a header should be quite easy.

    Code:
    .align 4
    .arm
    
    header:
    b main_arm
    @ If you want, you can define the header values here, but for emulators they aren't required in most cases
    
    .org 0xC0
    main_arm:
    @ If you want, you can setup CPU mode etc here, I never did it back then :D
    ldr r0, =0x080000E1
    bx r0
    
    .align 2
    .thumb
    
    .org 0xE0
    main:
    @ Your thumb code here =D
    This should generate a executable and at least Visual Boy Advance should be able to run.

Page 1 of 14 12311 ... LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •