Results 1 to 4 of 4

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    EmuTalk Member
    Join Date
    Oct 2011
    Posts
    11
    Mentioned
    0 Post(s)

    Intel 8080 emulator: need help finding bug(s)

    As the title says, I think I need some help tracking down a bug in an 8080 emulator that I've been writing in C over the last couple of days. I wrote it from scratch based on Intel documentation. It mostly seems to work, but there is clearly some issue with it. If I run the "8080 instruction exerciser" in the emulator, here are my results:



    Code:
    8080 instruction exerciser (KR580VM80A CPU)
    dad <b,d,h,sp>................  ERROR **** crc expected:14474ba6 found:33b6a681
    aluop nn......................  ERROR **** crc expected:9e922f9e found:284aecbe
    aluop <b,c,d,e,h,l,m,a>.......  ERROR **** crc expected:cf762c86 found:0c2144eb
    <daa,cma,stc,cmc>.............  ERROR **** crc expected:bb3f030c found:797efb2b
    <inr,dcr> a...................  ERROR **** crc expected:adb6460e found:0e5332db
    <inr,dcr> b...................  ERROR **** crc expected:83ed1345 found:9fc94769
    <inx,dcx> b...................  ERROR **** crc expected:f79287cd found:eb7d1a2b
    <inr,dcr> c...................  ERROR **** crc expected:e5f6721b found:1695262e
    <inr,dcr> d...................  ERROR **** crc expected:15b5579a found:d594aa97
    <inx,dcx> d...................  ERROR **** crc expected:7f4e2501 found:63a1b8e7
    <inr,dcr> e...................  ERROR **** crc expected:cf2ab396 found:2b639ce1
    <inr,dcr> h...................  ERROR **** crc expected:12b2952c found:9bee5682
    <inx,dcx> h...................  ERROR **** crc expected:9f2b23c0 found:83c4be26
    <inr,dcr> l...................  ERROR **** crc expected:ff57d356 found:1d476ec3
    <inr,dcr> m...................  ERROR **** crc expected:92e963bd found:28f7092b
    <inx,dcx> sp..................  ERROR **** crc expected:d5702fab found:c99fb24d
    lhld nnnn.....................  ERROR **** crc expected:a9c3d5cb found:6d1eeb35
    shld nnnn.....................  ERROR **** crc expected:e8864f26 found:2c5b71d8
    lxi <b,d,h,sp>,nnnn...........  OK
    ldax <b,d>....................  ERROR **** crc expected:2b821d5f found:06cfc034
    mvi <b,c,d,e,h,l,m,a>,nn......  OK
    mov <bcdehla>,<bcdehla>.......  ERROR **** crc expected:10b58cee found:dfe39de0
    sta nnnn / lda nnnn...........  ERROR **** crc expected:ed57af72 found:c01a7219
    <rlc,rrc,ral,rar>.............  ERROR **** crc expected:e0d89235 found:4bae6af9
    stax <b,d>....................  ERROR **** crc expected:2b0471e9 found:b726a433
    Tests complete
    The fact that there are apparently errors in SO MANY opcodes leads me to believe that the bug has something to do with a common piece of code used by some or many of them. Perhaps something like decoding register fields or the like. Although, I've already tried to find issues there, and I'm not able to see one. Either that, or it's a problem in an opcode that the test software uses to calculate the CRC of the results. Unfortunately, I can't find the source code to this test software. Or maybe it's an issue with flag calculation(s)?? Could be so many things, that's the hard part about writing CPU emulators, the debugging!

    Here is the source code: https://pastebin.com/mweNgfae (Note: It doesn't have cycle timing implemented yet)

    It DOES run Space Invaders, but there is a bug there where rows of enemies don't get cleared from the screen at the top as they move down the play field as you can see below. Maybe this will help someone. Thanks for any help you guys can provide.

    Last edited by miker00lz; April 9th, 2018 at 03:39. Reason: Forgot to link source code.

  2. #2
    EmuTalk Member Iconoclast's Avatar
    Join Date
    Aug 2006
    Posts
    904
    Mentioned
    1 Post(s)
    This may not be related to your bugs in either Space Invaders or 8080 Instruction Exerciser.

    Briefly looking at your source, I can see that your implementation of the HLT op-code is unreachable.
    Code:
    ...
            else if (opcode == 0x76) { //HLT - halt processor
                reg_PC--;
            }
    ...
    A problem here is that, way above this check at the top, you have this:
    Code:
        while (cycles--) {
            opcode = i8080_read(reg_PC++);
     
            if ((opcode & 0xC0) == 0x40) { //MOV D,S - move register to register
                write_reg8((opcode >> 3) & 7, read_reg8(opcode & 7));
            }
    Because of the order of if statements here, the former code is unreachable.
    i.e., if your opcode variable is 0x76, the condition ((opcode & 0xC0) == 0x40) was already satisfied first, incorrectly interpreting the operation as a MOV instead of a HLT.



    On a related note, I would seriously recommend not having a chain of if statements like that. You may get to have fun by documenting the individual bit-masking tricks with decoding each field of op-codes, but it's confusing to re-validate, read and maintain. (There is also a significant performance hit in your function from potentially almost always going down nearly the entire ladder of ifs until the correct branch is found.)

    By using either an array of pointers to functions or a switch statement, you'll save a fair deal of overhead with program size as well as performance. You'll also render the outcome of duplicate or mis-ordered (because there is no dynamic ordering) op-code implementations an impossibility. Things will be smaller, faster, and static.

    An ideal implementation with switch would go something like:
    Code:
    void
    i8080_exec(int cycles)
    {
    
        uint8_t opcode, temp8, reg;
        uint16_t temp16;
    
        uint32_t temp32;
     
        while (cycles--) {
            opcode = i8080_read(reg_PC++);
            switch (opcode & 0xFF) {
            case 0x76: /* HLT:  halt processor */
                reg_PC--;
                break;
    
            case 0x40:  case 0x41:  case 0x42:  case 0x43:
            case 0x44:  case 0x45:  case 0x46:  case 0x47:
            case 0x48:  case 0x49:  case 0x4A:  case 0x4B:
            case 0x4C:  case 0x4D:  case 0x4E:  case 0x4F:
            case 0x50:  case 0x51:  case 0x52:  case 0x53:
            case 0x54:  case 0x55:  case 0x56:  case 0x57:
            case 0x58:  case 0x59:  case 0x5A:  case 0x5B:
            case 0x5C:  case 0x5D:  case 0x5E:  case 0x5F:
            case 0x60:  case 0x61:  case 0x62:  case 0x63:
            case 0x64:  case 0x65:  case 0x66:  case 0x67:
            case 0x68:  case 0x69:  case 0x6A:  case 0x6B:
            case 0x6C:  case 0x6D:  case 0x6E:  case 0x6F:
            case 0x70:  case 0x71:  case 0x72:  case 0x73:
            case 0x74:  case 0x75:              case 0x77:
            case 0x78:  case 0x79:  case 0x7A:  case 0x7B:
            case 0x7C:  case 0x7D:  case 0x7E:  case 0x7F: /* MOV D,S */
                write_reg8((opcode >> 3) & 7, read_reg8(opcode & 7));
                break;
    
            case 0x06:  case 0x0E:
            case 0x16:  case 0x1E:
            case 0x26:  case 0x2E:
            case 0x36:  case 0x3E: /* MVI D,#:  move immediate to register */
                write_reg8((opcode >> 3) & 7, i8080_read(reg_PC++));
                break;
    
            /* ... and so on ... */
    
            default:
                printf("UNRECOGNIZED INSTRUCTION @ %04Xh: %02X\n", reg_PC - 1, opcode);
                exit(0);
            }
        }
    }
    I did not finish analyzing the entire function to see if HLT was the only bugged op-code affected by this design problem. To avoid distractions caused by design issues like these while hunting for bugs that may (or may not) turn out to be entirely unrelated, I would go with a switch.

  3. #3
    EmuTalk Member
    Join Date
    Oct 2011
    Posts
    11
    Mentioned
    0 Post(s)
    Good points, and I did know the performance would be worse. My previous emulators (8086 and 6502) have all used a switch block or a function pointer array. I just changed this one to a switch block. Turns out the only conflict with the masking was with MOV and HLT at instruction 76h which you pointed out. Unfortunately, this did not fix any CPU bugs other than HLT not being usable, which I expected after I saw that was the only opcode conflict.

    I'll just have to keep combing through the code and comparing with the documentation. Possibly a flags issue. Getting the flags right was hell on the 8086 emu, but the 8080 seems simpler in that regard.

  4. #4
    EmuTalk Member
    Join Date
    Oct 2011
    Posts
    11
    Mentioned
    0 Post(s)
    I've gotten a lot closer. I was already forcing bit 1 of the flags register to appear set, but neglected to mask out bits 3 and 5. I think the instruction exerciser POPs the flags and inserts them into the calculation for the CRC, so this could have caused issues if the program manually set the PSW somewhere with bits 3 and/or 5 set.

    Code:
    8080 instruction exerciser (KR580VM80A CPU)
    dad <b,d,h,sp>................  OK
    aluop nn......................  ERROR **** crc expected:9e922f9e found:fd2bdf95
    aluop <b,c,d,e,h,l,m,a>.......  ERROR **** crc expected:cf762c86 found:63dcfef6
    <daa,cma,stc,cmc>.............  ERROR **** crc expected:bb3f030c found:02e11466
    <inr,dcr> a...................  ERROR **** crc expected:adb6460e found:0f15bffe
    <inr,dcr> b...................  ERROR **** crc expected:83ed1345 found:adcd6374
    <inx,dcx> b...................  OK
    <inr,dcr> c...................  ERROR **** crc expected:e5f6721b found:17d3ab0b
    <inr,dcr> d...................  ERROR **** crc expected:15b5579a found:e7908e8a
    <inx,dcx> d...................  OK
    <inr,dcr> e...................  ERROR **** crc expected:cf2ab396 found:1967b8fc
    <inr,dcr> h...................  ERROR **** crc expected:12b2952c found:a9ea729f
    <inx,dcx> h...................  OK
    <inr,dcr> l...................  ERROR **** crc expected:ff57d356 found:1c01e3e6
    <inr,dcr> m...................  ERROR **** crc expected:92e963bd found:29b1840e
    <inx,dcx> sp..................  OK
    lhld nnnn.....................  OK
    shld nnnn.....................  OK
    lxi <b,d,h,sp>,nnnn...........  OK
    ldax <b,d>....................  OK
    mvi <b,c,d,e,h,l,m,a>,nn......  OK
    mov <bcdehla>,<bcdehla>.......  OK
    sta nnnn / lda nnnn...........  OK
    <rlc,rrc,ral,rar>.............  OK
    stax <b,d>....................  OK
    Tests complete
    Now it seems to just mainly be something going awry in the 8-bit ALU operations. This narrows my debugging scope by quite a bit!

Posting Permissions

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