Fixing obscure 8080 emulator bug?

Heavily limited premature compiler translates text into excecutable python code

Can humans ever directly see a few photons at a time? Can a human see a single photon?

Count All Possible Unique Combinations of Letters in a Word

LWC - Local Dev - How can I run the local server on HTTPS?

Android Material and appcompat Manifest merger failed in react-native or ExpoKit

Did the CIA blow up a Siberian pipeline in 1982?

Should I include an appendix for inessential, yet related worldbuilding to my story?

What is appropriate short form for "laboratoires" in French?

Why is it recommended to mix yogurt starter with a small amount of milk before adding to the entire batch?

Prime sieve in Python

Do I have to explain the mechanical superiority of the player-character within the fiction of the game?

Methodology: Writing unit tests for another developer

Hit the Bulls Eye with T in the Center

How to make clear to people I don't want to answer their "Where are you from?" question?

How to maintain a closed environment for one person for a long period of time

Do I need a shock-proof watch for cycling?

Confusion over 220 and 230 volt outlets

What's currently blocking the construction of the wall between Mexico and the US?

How do I professionally let my manager know I'll quit over an issue?

Why isn't my calculation that we should be able to see the sun well beyond the observable universe valid?

Is there any proof that high saturation and contrast makes a picture more appealing in social media?

Understanding the reasoning of the woman who agreed with Shlomo to "cut the baby in half"

Why tighten down in a criss-cross pattern?

Is "Busen" just the area between the breasts?



Fixing obscure 8080 emulator bug?







.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








37















I'm using the cpudiag.bin from http://www.emulator101.com/files/cpudiag.bin to test my emulator. I've already implemented the CP/M CALL function at 0x05, offset the program at 0x100 and fixed the offset at byte 112 + 0x100 as per this site.
http://emulator101.com/



I get the error



 CPU HAS FAILED! ERROR EXIT=78=:


and added myself that there was a
JMP to 0000 from 0x698. Here are the last 10 instructions run by the emulator before failing:



Instructions Ran: 79
Program Counter: 016C
Memory Immediate: 0xFA
Instruction: JM adr 71 1
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
Stack Pointer: 7A7
Cycles: 724
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 80
Program Counter: 0171
Memory Immediate: 0xC6
Instruction: ADI D8 30
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
Stack Pointer: 7A7
Cycles: 734
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 81
Program Counter: 0173
Memory Immediate: 0xC9
Instruction: RET
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A7
Cycles: 741
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 82
Program Counter: 0160
Memory Immediate: 0x5F
Instruction: MOV E, A
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 751
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 83
Program Counter: 0161
Memory Immediate: 0xC3
Instruction: JMP adr 4E 1
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 756
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 84
Program Counter: 014E
Memory Immediate: 0x0E
Instruction: MVI C, D8 2
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 766
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 85
Program Counter: 0150
Memory Immediate: 0xCD
Instruction: CALL adr 5 0
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 773
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 86
Program Counter: 0005
Memory Immediate: 0xC9
Instruction: RET
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A7
Cycles: 790
Interrupt enabled: false
Interrupt op:
-------------------
:Instructions Ran: 87
Program Counter: 0153
Memory Immediate: 0xC9
Instruction: RET
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 800
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 88
Program Counter: 0698
Memory Immediate: 0xC3
Instruction: JMP adr 0 0
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7AB
Cycles: 810
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 89
Program Counter: 0000
Memory Immediate: 0x00
Instruction: NOP
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7AB
Cycles: 820
Interrupt enabled: false
Interrupt op:
-------------------
JMP to 0000 from 0x698


I'm new to emulating so could anyone give me a hint or point me in the right direction on how to debug this?



Edit: code https://github.com/hydratedcabbage/space-invaders










share|improve this question



















  • 1





    How much of the site is needed to find the reference about using an offset of 0x0100? Also, the source of the program helps when debugging.

    – UncleBod
    Jun 4 at 4:34











  • On the site the information for cpudiag.bin can be found under "Full 8080 Emulation". I added a link to a GitHub repository that I just put up with the code. Also I'm completely open to suggestions or recommendations on how I could improve the code :)

    – David Tran
    Jun 4 at 4:36







  • 2





    The code is for running on a CP/M system at two places it jumps to 0x000, the warm boot routine. So, what happens is that the test either failed or completed. Without seeing what was outputted by the CP/M outchar routine, it is hard to say what happened.

    – UncleBod
    Jun 4 at 5:05






  • 1





    It jumps to 0x0000, where you have empty memory. The reason why it jumps there is not clear. Either the test are ready, or a test failed. I suspect it failed at 0x01d, but I need to assemble the code to see what instruction is there. If noone else beats me to it, I will have a look tonight.

    – UncleBod
    Jun 4 at 5:17






  • 1





    see Writing a graphical Z80 emulator in C or C++ I know its aimed towards Z80 but the debugging approach is relevant for any emulator

    – Spektre
    Jun 4 at 8:35

















37















I'm using the cpudiag.bin from http://www.emulator101.com/files/cpudiag.bin to test my emulator. I've already implemented the CP/M CALL function at 0x05, offset the program at 0x100 and fixed the offset at byte 112 + 0x100 as per this site.
http://emulator101.com/



I get the error



 CPU HAS FAILED! ERROR EXIT=78=:


and added myself that there was a
JMP to 0000 from 0x698. Here are the last 10 instructions run by the emulator before failing:



Instructions Ran: 79
Program Counter: 016C
Memory Immediate: 0xFA
Instruction: JM adr 71 1
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
Stack Pointer: 7A7
Cycles: 724
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 80
Program Counter: 0171
Memory Immediate: 0xC6
Instruction: ADI D8 30
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
Stack Pointer: 7A7
Cycles: 734
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 81
Program Counter: 0173
Memory Immediate: 0xC9
Instruction: RET
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A7
Cycles: 741
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 82
Program Counter: 0160
Memory Immediate: 0x5F
Instruction: MOV E, A
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 751
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 83
Program Counter: 0161
Memory Immediate: 0xC3
Instruction: JMP adr 4E 1
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 756
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 84
Program Counter: 014E
Memory Immediate: 0x0E
Instruction: MVI C, D8 2
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 766
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 85
Program Counter: 0150
Memory Immediate: 0xCD
Instruction: CALL adr 5 0
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 773
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 86
Program Counter: 0005
Memory Immediate: 0xC9
Instruction: RET
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A7
Cycles: 790
Interrupt enabled: false
Interrupt op:
-------------------
:Instructions Ran: 87
Program Counter: 0153
Memory Immediate: 0xC9
Instruction: RET
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 800
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 88
Program Counter: 0698
Memory Immediate: 0xC3
Instruction: JMP adr 0 0
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7AB
Cycles: 810
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 89
Program Counter: 0000
Memory Immediate: 0x00
Instruction: NOP
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7AB
Cycles: 820
Interrupt enabled: false
Interrupt op:
-------------------
JMP to 0000 from 0x698


I'm new to emulating so could anyone give me a hint or point me in the right direction on how to debug this?



Edit: code https://github.com/hydratedcabbage/space-invaders










share|improve this question



















  • 1





    How much of the site is needed to find the reference about using an offset of 0x0100? Also, the source of the program helps when debugging.

    – UncleBod
    Jun 4 at 4:34











  • On the site the information for cpudiag.bin can be found under "Full 8080 Emulation". I added a link to a GitHub repository that I just put up with the code. Also I'm completely open to suggestions or recommendations on how I could improve the code :)

    – David Tran
    Jun 4 at 4:36







  • 2





    The code is for running on a CP/M system at two places it jumps to 0x000, the warm boot routine. So, what happens is that the test either failed or completed. Without seeing what was outputted by the CP/M outchar routine, it is hard to say what happened.

    – UncleBod
    Jun 4 at 5:05






  • 1





    It jumps to 0x0000, where you have empty memory. The reason why it jumps there is not clear. Either the test are ready, or a test failed. I suspect it failed at 0x01d, but I need to assemble the code to see what instruction is there. If noone else beats me to it, I will have a look tonight.

    – UncleBod
    Jun 4 at 5:17






  • 1





    see Writing a graphical Z80 emulator in C or C++ I know its aimed towards Z80 but the debugging approach is relevant for any emulator

    – Spektre
    Jun 4 at 8:35













37












37








37


7






I'm using the cpudiag.bin from http://www.emulator101.com/files/cpudiag.bin to test my emulator. I've already implemented the CP/M CALL function at 0x05, offset the program at 0x100 and fixed the offset at byte 112 + 0x100 as per this site.
http://emulator101.com/



I get the error



 CPU HAS FAILED! ERROR EXIT=78=:


and added myself that there was a
JMP to 0000 from 0x698. Here are the last 10 instructions run by the emulator before failing:



Instructions Ran: 79
Program Counter: 016C
Memory Immediate: 0xFA
Instruction: JM adr 71 1
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
Stack Pointer: 7A7
Cycles: 724
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 80
Program Counter: 0171
Memory Immediate: 0xC6
Instruction: ADI D8 30
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
Stack Pointer: 7A7
Cycles: 734
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 81
Program Counter: 0173
Memory Immediate: 0xC9
Instruction: RET
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A7
Cycles: 741
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 82
Program Counter: 0160
Memory Immediate: 0x5F
Instruction: MOV E, A
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 751
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 83
Program Counter: 0161
Memory Immediate: 0xC3
Instruction: JMP adr 4E 1
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 756
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 84
Program Counter: 014E
Memory Immediate: 0x0E
Instruction: MVI C, D8 2
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 766
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 85
Program Counter: 0150
Memory Immediate: 0xCD
Instruction: CALL adr 5 0
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 773
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 86
Program Counter: 0005
Memory Immediate: 0xC9
Instruction: RET
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A7
Cycles: 790
Interrupt enabled: false
Interrupt op:
-------------------
:Instructions Ran: 87
Program Counter: 0153
Memory Immediate: 0xC9
Instruction: RET
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 800
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 88
Program Counter: 0698
Memory Immediate: 0xC3
Instruction: JMP adr 0 0
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7AB
Cycles: 810
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 89
Program Counter: 0000
Memory Immediate: 0x00
Instruction: NOP
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7AB
Cycles: 820
Interrupt enabled: false
Interrupt op:
-------------------
JMP to 0000 from 0x698


I'm new to emulating so could anyone give me a hint or point me in the right direction on how to debug this?



Edit: code https://github.com/hydratedcabbage/space-invaders










share|improve this question
















I'm using the cpudiag.bin from http://www.emulator101.com/files/cpudiag.bin to test my emulator. I've already implemented the CP/M CALL function at 0x05, offset the program at 0x100 and fixed the offset at byte 112 + 0x100 as per this site.
http://emulator101.com/



I get the error



 CPU HAS FAILED! ERROR EXIT=78=:


and added myself that there was a
JMP to 0000 from 0x698. Here are the last 10 instructions run by the emulator before failing:



Instructions Ran: 79
Program Counter: 016C
Memory Immediate: 0xFA
Instruction: JM adr 71 1
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
Stack Pointer: 7A7
Cycles: 724
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 80
Program Counter: 0171
Memory Immediate: 0xC6
Instruction: ADI D8 30
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
Stack Pointer: 7A7
Cycles: 734
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 81
Program Counter: 0173
Memory Immediate: 0xC9
Instruction: RET
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A7
Cycles: 741
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 82
Program Counter: 0160
Memory Immediate: 0x5F
Instruction: MOV E, A
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 751
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 83
Program Counter: 0161
Memory Immediate: 0xC3
Instruction: JMP adr 4E 1
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 756
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 84
Program Counter: 014E
Memory Immediate: 0x0E
Instruction: MVI C, D8 2
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 766
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 85
Program Counter: 0150
Memory Immediate: 0xCD
Instruction: CALL adr 5 0
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 773
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 86
Program Counter: 0005
Memory Immediate: 0xC9
Instruction: RET
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A7
Cycles: 790
Interrupt enabled: false
Interrupt op:
-------------------
:Instructions Ran: 87
Program Counter: 0153
Memory Immediate: 0xC9
Instruction: RET
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7A9
Cycles: 800
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 88
Program Counter: 0698
Memory Immediate: 0xC3
Instruction: JMP adr 0 0
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7AB
Cycles: 810
Interrupt enabled: false
Interrupt op:
-------------------
Instructions Ran: 89
Program Counter: 0000
Memory Immediate: 0x00
Instruction: NOP
Registers (B/C/D/E/H/L/A): 00 02 00 3A 01 DA 3A
Flags (Z/S/P/C/AC): 0 0 1 0 1
Stack Pointer: 7AB
Cycles: 820
Interrupt enabled: false
Interrupt op:
-------------------
JMP to 0000 from 0x698


I'm new to emulating so could anyone give me a hint or point me in the right direction on how to debug this?



Edit: code https://github.com/hydratedcabbage/space-invaders







8080






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jun 4 at 4:37







David Tran

















asked Jun 4 at 2:23









David TranDavid Tran

38038




38038







  • 1





    How much of the site is needed to find the reference about using an offset of 0x0100? Also, the source of the program helps when debugging.

    – UncleBod
    Jun 4 at 4:34











  • On the site the information for cpudiag.bin can be found under "Full 8080 Emulation". I added a link to a GitHub repository that I just put up with the code. Also I'm completely open to suggestions or recommendations on how I could improve the code :)

    – David Tran
    Jun 4 at 4:36







  • 2





    The code is for running on a CP/M system at two places it jumps to 0x000, the warm boot routine. So, what happens is that the test either failed or completed. Without seeing what was outputted by the CP/M outchar routine, it is hard to say what happened.

    – UncleBod
    Jun 4 at 5:05






  • 1





    It jumps to 0x0000, where you have empty memory. The reason why it jumps there is not clear. Either the test are ready, or a test failed. I suspect it failed at 0x01d, but I need to assemble the code to see what instruction is there. If noone else beats me to it, I will have a look tonight.

    – UncleBod
    Jun 4 at 5:17






  • 1





    see Writing a graphical Z80 emulator in C or C++ I know its aimed towards Z80 but the debugging approach is relevant for any emulator

    – Spektre
    Jun 4 at 8:35












  • 1





    How much of the site is needed to find the reference about using an offset of 0x0100? Also, the source of the program helps when debugging.

    – UncleBod
    Jun 4 at 4:34











  • On the site the information for cpudiag.bin can be found under "Full 8080 Emulation". I added a link to a GitHub repository that I just put up with the code. Also I'm completely open to suggestions or recommendations on how I could improve the code :)

    – David Tran
    Jun 4 at 4:36







  • 2





    The code is for running on a CP/M system at two places it jumps to 0x000, the warm boot routine. So, what happens is that the test either failed or completed. Without seeing what was outputted by the CP/M outchar routine, it is hard to say what happened.

    – UncleBod
    Jun 4 at 5:05






  • 1





    It jumps to 0x0000, where you have empty memory. The reason why it jumps there is not clear. Either the test are ready, or a test failed. I suspect it failed at 0x01d, but I need to assemble the code to see what instruction is there. If noone else beats me to it, I will have a look tonight.

    – UncleBod
    Jun 4 at 5:17






  • 1





    see Writing a graphical Z80 emulator in C or C++ I know its aimed towards Z80 but the debugging approach is relevant for any emulator

    – Spektre
    Jun 4 at 8:35







1




1





How much of the site is needed to find the reference about using an offset of 0x0100? Also, the source of the program helps when debugging.

– UncleBod
Jun 4 at 4:34





How much of the site is needed to find the reference about using an offset of 0x0100? Also, the source of the program helps when debugging.

– UncleBod
Jun 4 at 4:34













On the site the information for cpudiag.bin can be found under "Full 8080 Emulation". I added a link to a GitHub repository that I just put up with the code. Also I'm completely open to suggestions or recommendations on how I could improve the code :)

– David Tran
Jun 4 at 4:36






On the site the information for cpudiag.bin can be found under "Full 8080 Emulation". I added a link to a GitHub repository that I just put up with the code. Also I'm completely open to suggestions or recommendations on how I could improve the code :)

– David Tran
Jun 4 at 4:36





2




2





The code is for running on a CP/M system at two places it jumps to 0x000, the warm boot routine. So, what happens is that the test either failed or completed. Without seeing what was outputted by the CP/M outchar routine, it is hard to say what happened.

– UncleBod
Jun 4 at 5:05





The code is for running on a CP/M system at two places it jumps to 0x000, the warm boot routine. So, what happens is that the test either failed or completed. Without seeing what was outputted by the CP/M outchar routine, it is hard to say what happened.

– UncleBod
Jun 4 at 5:05




1




1





It jumps to 0x0000, where you have empty memory. The reason why it jumps there is not clear. Either the test are ready, or a test failed. I suspect it failed at 0x01d, but I need to assemble the code to see what instruction is there. If noone else beats me to it, I will have a look tonight.

– UncleBod
Jun 4 at 5:17





It jumps to 0x0000, where you have empty memory. The reason why it jumps there is not clear. Either the test are ready, or a test failed. I suspect it failed at 0x01d, but I need to assemble the code to see what instruction is there. If noone else beats me to it, I will have a look tonight.

– UncleBod
Jun 4 at 5:17




1




1





see Writing a graphical Z80 emulator in C or C++ I know its aimed towards Z80 but the debugging approach is relevant for any emulator

– Spektre
Jun 4 at 8:35





see Writing a graphical Z80 emulator in C or C++ I know its aimed towards Z80 but the debugging approach is relevant for any emulator

– Spektre
Jun 4 at 8:35










1 Answer
1






active

oldest

votes


















94














The General Advice Answer



For a failure that happens so quickly (at most 89 instructions) I'd recommend simply looking at what your emulator does at each instruction and determine if did everything correctly.



If the error occurs after thousands or millions of instructions then it would be more fruitful to compare it against an 8080 emulator that gets the correct output. Have the correct emulator and yours output the program counter for each instruction executed. When they differ your know your emulator made a mistake and it will likely be at the instruction or a few before it. Though not necessarily. Sometimes a mistake can be made, the results saved into memory and only when read back much later is the difference in program counter apparent. In those cases a full trace showing all register contents and values being read from or written to memory can catch the mistake quicker.



The Very Specific Answer



Here's the first two instructions you posted (slightly abridged):



Instructions Ran: 79
Program Counter: 016C
Memory Immediate: 0xFA
Instruction: JM adr 71 1
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
-------------------
Instructions Ran: 80
Program Counter: 0171
Memory Immediate: 0xC6
Instruction: ADI D8 30
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0


Look very closely and you'll find that JM did something wrong. I'll tell you what that is at the end of the question to not spoil your examination.



The Using All We Know Answer



There's not really a need to trace. cpudiag.asm is designed to point out the general location of the error. Notice that it will run an 8080 instruction or two and if it doesn't get the results it expects a CALL CPUER is done. That routine is at 0x689 so you could stop your emulator when it reaches there and note the return address indicates which of the many CALL CPUER instructions was hit. Or even just detect CALL CPUER as a special case.



But cpudiag.asm tries to help you as much as possible. Looking at CPUER you can see that it is printing the return address after the CPU HAS FAILED! ERROR EXIT= message. Though instead of a hexadecimal address your emulator printed 78=:. In other words, it would seem your 8080 emulator is failing on the code to convert a binary value to hexadecimal in ASCII. Which is the BYTEO routine and in particular BYT02 which converts the bottom 4 bits of A register into an ASCII character.



However, looking at the 78=: we can come up with a pretty good guess what went wrong. Note that the code looks at the value in A register. If it is less 10 then 0x30 is added to A register. This covers the digits '0' through '9'. But if it is greater than or equal to 10 then we add 7 and then add 0x30. 10 + 7 + 0x30 = 65 which is the letter 'A' so that part is handling digits 'A' through 'F'.



The ASCII value for ':' is 0x3A. So one has to wonder if maybe the test failed and we didn't add the 7. And the '=' would correspond to 'D'. Meanwhile, the '78' seems odd. That is way beyond the end of the program so it can't possibly correspond to a CALL CPUER. In fact, the program fails so quickly I would doubt it has even reached 0x1FF. But if the test is wrong, 7 will be added to the decimal digits. A zero will become '7' and a '1' will become '8'. Aha, that address is probably 0x01DA.



We can immediately conclude that JM is backwards. Perhaps a copy and paste error from JP.



Moreover, we see that the CALL CPUER that failed is this one as its return address will be 0x01DA:



J040: JNZ J050 ;TEST "JNZ"
JC J050 ;TEST "JC"
JPO J050 ;TEST "JPO"
JM J050 ;TEST "JM"
JMP J060 ;TEST "JMP" (IT'S A LITTLE LATE,BUT WHAT THE HELL!
J050: CALL CPUER


There are 4 instructions that jump directly to J050 and a JMP that goes over it. And of those instructions could be wrong, but JMP is likely right. And given that the hexadecimal output showed JM being wrong then I'll bet it is JM that is jumping to the CALL CPUER.



The Very Specific Answer Answer



The JM is taken even though the S flag is not set. That's wrong.



A Final Note



I started out by looking at the cpudiag.asm source code. The significance of CPUER was pretty clear and I got curious about where that exit code came from. Once I figured out it was the return address of the CALL CPUER instruction it got me wondering why your emulator wasn't printing out a hexadecimal address. At that point numerology pointed out JM in the binary to hexadecimal conversion routine and also gave me an address to look at what had actually failed. Then after all that I looked at your instruction trace and noticed by pure luck that the first instruction you listed made a wrong turn.



A reasonable approach, if you're familiar with 8080 code, and especially with writing it so you can see what a program would normally be expected to do. If you're new to 8080, then I think a lower-level inspection, as suggested in the "General Advice" section will be more fruitful.






share|improve this answer




















  • 15





    As well as (what I feel safe to assume is) the answer, a superb "how to find the answer" answer.

    – TripeHound
    Jun 4 at 8:48






  • 2





    " if you're familiar with 8080 code..." Speaking as somebody who went through the same process with a Z80 emulator, I can guarantee that @DavidTran will be very familiar with 8080 by the end.

    – JeremyP
    Jun 4 at 8:54











  • Wow thanks for the detailed answer! But why would the P(arity) flag affect JM? Shouldn't that depend on the S(ign) flag, (specifically, that it's false which means sign is negative)?

    – David Tran
    Jun 4 at 15:55











  • @DavidTran: The S flag is set (1) when the result is negative. In instruction step 79, S is 0, so the result was positive. (I.e., S tells you if there is a negative sign at the front of your result. 0 is no, 1 is yes.)

    – Eric Towers
    Jun 4 at 18:42






  • 2





    You're right, it should be S not P. Edited answer to reflect that. Note that the sign bit is a copy of the top bit of the result so it will be 0 for a positive result and 1 for negative.

    – George Phillips
    Jun 4 at 18:45











Your Answer








StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "648"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
noCode: true, onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fretrocomputing.stackexchange.com%2fquestions%2f11223%2ffixing-obscure-8080-emulator-bug%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









94














The General Advice Answer



For a failure that happens so quickly (at most 89 instructions) I'd recommend simply looking at what your emulator does at each instruction and determine if did everything correctly.



If the error occurs after thousands or millions of instructions then it would be more fruitful to compare it against an 8080 emulator that gets the correct output. Have the correct emulator and yours output the program counter for each instruction executed. When they differ your know your emulator made a mistake and it will likely be at the instruction or a few before it. Though not necessarily. Sometimes a mistake can be made, the results saved into memory and only when read back much later is the difference in program counter apparent. In those cases a full trace showing all register contents and values being read from or written to memory can catch the mistake quicker.



The Very Specific Answer



Here's the first two instructions you posted (slightly abridged):



Instructions Ran: 79
Program Counter: 016C
Memory Immediate: 0xFA
Instruction: JM adr 71 1
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
-------------------
Instructions Ran: 80
Program Counter: 0171
Memory Immediate: 0xC6
Instruction: ADI D8 30
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0


Look very closely and you'll find that JM did something wrong. I'll tell you what that is at the end of the question to not spoil your examination.



The Using All We Know Answer



There's not really a need to trace. cpudiag.asm is designed to point out the general location of the error. Notice that it will run an 8080 instruction or two and if it doesn't get the results it expects a CALL CPUER is done. That routine is at 0x689 so you could stop your emulator when it reaches there and note the return address indicates which of the many CALL CPUER instructions was hit. Or even just detect CALL CPUER as a special case.



But cpudiag.asm tries to help you as much as possible. Looking at CPUER you can see that it is printing the return address after the CPU HAS FAILED! ERROR EXIT= message. Though instead of a hexadecimal address your emulator printed 78=:. In other words, it would seem your 8080 emulator is failing on the code to convert a binary value to hexadecimal in ASCII. Which is the BYTEO routine and in particular BYT02 which converts the bottom 4 bits of A register into an ASCII character.



However, looking at the 78=: we can come up with a pretty good guess what went wrong. Note that the code looks at the value in A register. If it is less 10 then 0x30 is added to A register. This covers the digits '0' through '9'. But if it is greater than or equal to 10 then we add 7 and then add 0x30. 10 + 7 + 0x30 = 65 which is the letter 'A' so that part is handling digits 'A' through 'F'.



The ASCII value for ':' is 0x3A. So one has to wonder if maybe the test failed and we didn't add the 7. And the '=' would correspond to 'D'. Meanwhile, the '78' seems odd. That is way beyond the end of the program so it can't possibly correspond to a CALL CPUER. In fact, the program fails so quickly I would doubt it has even reached 0x1FF. But if the test is wrong, 7 will be added to the decimal digits. A zero will become '7' and a '1' will become '8'. Aha, that address is probably 0x01DA.



We can immediately conclude that JM is backwards. Perhaps a copy and paste error from JP.



Moreover, we see that the CALL CPUER that failed is this one as its return address will be 0x01DA:



J040: JNZ J050 ;TEST "JNZ"
JC J050 ;TEST "JC"
JPO J050 ;TEST "JPO"
JM J050 ;TEST "JM"
JMP J060 ;TEST "JMP" (IT'S A LITTLE LATE,BUT WHAT THE HELL!
J050: CALL CPUER


There are 4 instructions that jump directly to J050 and a JMP that goes over it. And of those instructions could be wrong, but JMP is likely right. And given that the hexadecimal output showed JM being wrong then I'll bet it is JM that is jumping to the CALL CPUER.



The Very Specific Answer Answer



The JM is taken even though the S flag is not set. That's wrong.



A Final Note



I started out by looking at the cpudiag.asm source code. The significance of CPUER was pretty clear and I got curious about where that exit code came from. Once I figured out it was the return address of the CALL CPUER instruction it got me wondering why your emulator wasn't printing out a hexadecimal address. At that point numerology pointed out JM in the binary to hexadecimal conversion routine and also gave me an address to look at what had actually failed. Then after all that I looked at your instruction trace and noticed by pure luck that the first instruction you listed made a wrong turn.



A reasonable approach, if you're familiar with 8080 code, and especially with writing it so you can see what a program would normally be expected to do. If you're new to 8080, then I think a lower-level inspection, as suggested in the "General Advice" section will be more fruitful.






share|improve this answer




















  • 15





    As well as (what I feel safe to assume is) the answer, a superb "how to find the answer" answer.

    – TripeHound
    Jun 4 at 8:48






  • 2





    " if you're familiar with 8080 code..." Speaking as somebody who went through the same process with a Z80 emulator, I can guarantee that @DavidTran will be very familiar with 8080 by the end.

    – JeremyP
    Jun 4 at 8:54











  • Wow thanks for the detailed answer! But why would the P(arity) flag affect JM? Shouldn't that depend on the S(ign) flag, (specifically, that it's false which means sign is negative)?

    – David Tran
    Jun 4 at 15:55











  • @DavidTran: The S flag is set (1) when the result is negative. In instruction step 79, S is 0, so the result was positive. (I.e., S tells you if there is a negative sign at the front of your result. 0 is no, 1 is yes.)

    – Eric Towers
    Jun 4 at 18:42






  • 2





    You're right, it should be S not P. Edited answer to reflect that. Note that the sign bit is a copy of the top bit of the result so it will be 0 for a positive result and 1 for negative.

    – George Phillips
    Jun 4 at 18:45















94














The General Advice Answer



For a failure that happens so quickly (at most 89 instructions) I'd recommend simply looking at what your emulator does at each instruction and determine if did everything correctly.



If the error occurs after thousands or millions of instructions then it would be more fruitful to compare it against an 8080 emulator that gets the correct output. Have the correct emulator and yours output the program counter for each instruction executed. When they differ your know your emulator made a mistake and it will likely be at the instruction or a few before it. Though not necessarily. Sometimes a mistake can be made, the results saved into memory and only when read back much later is the difference in program counter apparent. In those cases a full trace showing all register contents and values being read from or written to memory can catch the mistake quicker.



The Very Specific Answer



Here's the first two instructions you posted (slightly abridged):



Instructions Ran: 79
Program Counter: 016C
Memory Immediate: 0xFA
Instruction: JM adr 71 1
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
-------------------
Instructions Ran: 80
Program Counter: 0171
Memory Immediate: 0xC6
Instruction: ADI D8 30
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0


Look very closely and you'll find that JM did something wrong. I'll tell you what that is at the end of the question to not spoil your examination.



The Using All We Know Answer



There's not really a need to trace. cpudiag.asm is designed to point out the general location of the error. Notice that it will run an 8080 instruction or two and if it doesn't get the results it expects a CALL CPUER is done. That routine is at 0x689 so you could stop your emulator when it reaches there and note the return address indicates which of the many CALL CPUER instructions was hit. Or even just detect CALL CPUER as a special case.



But cpudiag.asm tries to help you as much as possible. Looking at CPUER you can see that it is printing the return address after the CPU HAS FAILED! ERROR EXIT= message. Though instead of a hexadecimal address your emulator printed 78=:. In other words, it would seem your 8080 emulator is failing on the code to convert a binary value to hexadecimal in ASCII. Which is the BYTEO routine and in particular BYT02 which converts the bottom 4 bits of A register into an ASCII character.



However, looking at the 78=: we can come up with a pretty good guess what went wrong. Note that the code looks at the value in A register. If it is less 10 then 0x30 is added to A register. This covers the digits '0' through '9'. But if it is greater than or equal to 10 then we add 7 and then add 0x30. 10 + 7 + 0x30 = 65 which is the letter 'A' so that part is handling digits 'A' through 'F'.



The ASCII value for ':' is 0x3A. So one has to wonder if maybe the test failed and we didn't add the 7. And the '=' would correspond to 'D'. Meanwhile, the '78' seems odd. That is way beyond the end of the program so it can't possibly correspond to a CALL CPUER. In fact, the program fails so quickly I would doubt it has even reached 0x1FF. But if the test is wrong, 7 will be added to the decimal digits. A zero will become '7' and a '1' will become '8'. Aha, that address is probably 0x01DA.



We can immediately conclude that JM is backwards. Perhaps a copy and paste error from JP.



Moreover, we see that the CALL CPUER that failed is this one as its return address will be 0x01DA:



J040: JNZ J050 ;TEST "JNZ"
JC J050 ;TEST "JC"
JPO J050 ;TEST "JPO"
JM J050 ;TEST "JM"
JMP J060 ;TEST "JMP" (IT'S A LITTLE LATE,BUT WHAT THE HELL!
J050: CALL CPUER


There are 4 instructions that jump directly to J050 and a JMP that goes over it. And of those instructions could be wrong, but JMP is likely right. And given that the hexadecimal output showed JM being wrong then I'll bet it is JM that is jumping to the CALL CPUER.



The Very Specific Answer Answer



The JM is taken even though the S flag is not set. That's wrong.



A Final Note



I started out by looking at the cpudiag.asm source code. The significance of CPUER was pretty clear and I got curious about where that exit code came from. Once I figured out it was the return address of the CALL CPUER instruction it got me wondering why your emulator wasn't printing out a hexadecimal address. At that point numerology pointed out JM in the binary to hexadecimal conversion routine and also gave me an address to look at what had actually failed. Then after all that I looked at your instruction trace and noticed by pure luck that the first instruction you listed made a wrong turn.



A reasonable approach, if you're familiar with 8080 code, and especially with writing it so you can see what a program would normally be expected to do. If you're new to 8080, then I think a lower-level inspection, as suggested in the "General Advice" section will be more fruitful.






share|improve this answer




















  • 15





    As well as (what I feel safe to assume is) the answer, a superb "how to find the answer" answer.

    – TripeHound
    Jun 4 at 8:48






  • 2





    " if you're familiar with 8080 code..." Speaking as somebody who went through the same process with a Z80 emulator, I can guarantee that @DavidTran will be very familiar with 8080 by the end.

    – JeremyP
    Jun 4 at 8:54











  • Wow thanks for the detailed answer! But why would the P(arity) flag affect JM? Shouldn't that depend on the S(ign) flag, (specifically, that it's false which means sign is negative)?

    – David Tran
    Jun 4 at 15:55











  • @DavidTran: The S flag is set (1) when the result is negative. In instruction step 79, S is 0, so the result was positive. (I.e., S tells you if there is a negative sign at the front of your result. 0 is no, 1 is yes.)

    – Eric Towers
    Jun 4 at 18:42






  • 2





    You're right, it should be S not P. Edited answer to reflect that. Note that the sign bit is a copy of the top bit of the result so it will be 0 for a positive result and 1 for negative.

    – George Phillips
    Jun 4 at 18:45













94












94








94







The General Advice Answer



For a failure that happens so quickly (at most 89 instructions) I'd recommend simply looking at what your emulator does at each instruction and determine if did everything correctly.



If the error occurs after thousands or millions of instructions then it would be more fruitful to compare it against an 8080 emulator that gets the correct output. Have the correct emulator and yours output the program counter for each instruction executed. When they differ your know your emulator made a mistake and it will likely be at the instruction or a few before it. Though not necessarily. Sometimes a mistake can be made, the results saved into memory and only when read back much later is the difference in program counter apparent. In those cases a full trace showing all register contents and values being read from or written to memory can catch the mistake quicker.



The Very Specific Answer



Here's the first two instructions you posted (slightly abridged):



Instructions Ran: 79
Program Counter: 016C
Memory Immediate: 0xFA
Instruction: JM adr 71 1
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
-------------------
Instructions Ran: 80
Program Counter: 0171
Memory Immediate: 0xC6
Instruction: ADI D8 30
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0


Look very closely and you'll find that JM did something wrong. I'll tell you what that is at the end of the question to not spoil your examination.



The Using All We Know Answer



There's not really a need to trace. cpudiag.asm is designed to point out the general location of the error. Notice that it will run an 8080 instruction or two and if it doesn't get the results it expects a CALL CPUER is done. That routine is at 0x689 so you could stop your emulator when it reaches there and note the return address indicates which of the many CALL CPUER instructions was hit. Or even just detect CALL CPUER as a special case.



But cpudiag.asm tries to help you as much as possible. Looking at CPUER you can see that it is printing the return address after the CPU HAS FAILED! ERROR EXIT= message. Though instead of a hexadecimal address your emulator printed 78=:. In other words, it would seem your 8080 emulator is failing on the code to convert a binary value to hexadecimal in ASCII. Which is the BYTEO routine and in particular BYT02 which converts the bottom 4 bits of A register into an ASCII character.



However, looking at the 78=: we can come up with a pretty good guess what went wrong. Note that the code looks at the value in A register. If it is less 10 then 0x30 is added to A register. This covers the digits '0' through '9'. But if it is greater than or equal to 10 then we add 7 and then add 0x30. 10 + 7 + 0x30 = 65 which is the letter 'A' so that part is handling digits 'A' through 'F'.



The ASCII value for ':' is 0x3A. So one has to wonder if maybe the test failed and we didn't add the 7. And the '=' would correspond to 'D'. Meanwhile, the '78' seems odd. That is way beyond the end of the program so it can't possibly correspond to a CALL CPUER. In fact, the program fails so quickly I would doubt it has even reached 0x1FF. But if the test is wrong, 7 will be added to the decimal digits. A zero will become '7' and a '1' will become '8'. Aha, that address is probably 0x01DA.



We can immediately conclude that JM is backwards. Perhaps a copy and paste error from JP.



Moreover, we see that the CALL CPUER that failed is this one as its return address will be 0x01DA:



J040: JNZ J050 ;TEST "JNZ"
JC J050 ;TEST "JC"
JPO J050 ;TEST "JPO"
JM J050 ;TEST "JM"
JMP J060 ;TEST "JMP" (IT'S A LITTLE LATE,BUT WHAT THE HELL!
J050: CALL CPUER


There are 4 instructions that jump directly to J050 and a JMP that goes over it. And of those instructions could be wrong, but JMP is likely right. And given that the hexadecimal output showed JM being wrong then I'll bet it is JM that is jumping to the CALL CPUER.



The Very Specific Answer Answer



The JM is taken even though the S flag is not set. That's wrong.



A Final Note



I started out by looking at the cpudiag.asm source code. The significance of CPUER was pretty clear and I got curious about where that exit code came from. Once I figured out it was the return address of the CALL CPUER instruction it got me wondering why your emulator wasn't printing out a hexadecimal address. At that point numerology pointed out JM in the binary to hexadecimal conversion routine and also gave me an address to look at what had actually failed. Then after all that I looked at your instruction trace and noticed by pure luck that the first instruction you listed made a wrong turn.



A reasonable approach, if you're familiar with 8080 code, and especially with writing it so you can see what a program would normally be expected to do. If you're new to 8080, then I think a lower-level inspection, as suggested in the "General Advice" section will be more fruitful.






share|improve this answer















The General Advice Answer



For a failure that happens so quickly (at most 89 instructions) I'd recommend simply looking at what your emulator does at each instruction and determine if did everything correctly.



If the error occurs after thousands or millions of instructions then it would be more fruitful to compare it against an 8080 emulator that gets the correct output. Have the correct emulator and yours output the program counter for each instruction executed. When they differ your know your emulator made a mistake and it will likely be at the instruction or a few before it. Though not necessarily. Sometimes a mistake can be made, the results saved into memory and only when read back much later is the difference in program counter apparent. In those cases a full trace showing all register contents and values being read from or written to memory can catch the mistake quicker.



The Very Specific Answer



Here's the first two instructions you posted (slightly abridged):



Instructions Ran: 79
Program Counter: 016C
Memory Immediate: 0xFA
Instruction: JM adr 71 1
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0
-------------------
Instructions Ran: 80
Program Counter: 0171
Memory Immediate: 0xC6
Instruction: ADI D8 30
Registers (B/C/D/E/H/L/A): 00 02 00 3D 01 DA 0A
Flags (Z/S/P/C/AC): 1 0 1 0 0


Look very closely and you'll find that JM did something wrong. I'll tell you what that is at the end of the question to not spoil your examination.



The Using All We Know Answer



There's not really a need to trace. cpudiag.asm is designed to point out the general location of the error. Notice that it will run an 8080 instruction or two and if it doesn't get the results it expects a CALL CPUER is done. That routine is at 0x689 so you could stop your emulator when it reaches there and note the return address indicates which of the many CALL CPUER instructions was hit. Or even just detect CALL CPUER as a special case.



But cpudiag.asm tries to help you as much as possible. Looking at CPUER you can see that it is printing the return address after the CPU HAS FAILED! ERROR EXIT= message. Though instead of a hexadecimal address your emulator printed 78=:. In other words, it would seem your 8080 emulator is failing on the code to convert a binary value to hexadecimal in ASCII. Which is the BYTEO routine and in particular BYT02 which converts the bottom 4 bits of A register into an ASCII character.



However, looking at the 78=: we can come up with a pretty good guess what went wrong. Note that the code looks at the value in A register. If it is less 10 then 0x30 is added to A register. This covers the digits '0' through '9'. But if it is greater than or equal to 10 then we add 7 and then add 0x30. 10 + 7 + 0x30 = 65 which is the letter 'A' so that part is handling digits 'A' through 'F'.



The ASCII value for ':' is 0x3A. So one has to wonder if maybe the test failed and we didn't add the 7. And the '=' would correspond to 'D'. Meanwhile, the '78' seems odd. That is way beyond the end of the program so it can't possibly correspond to a CALL CPUER. In fact, the program fails so quickly I would doubt it has even reached 0x1FF. But if the test is wrong, 7 will be added to the decimal digits. A zero will become '7' and a '1' will become '8'. Aha, that address is probably 0x01DA.



We can immediately conclude that JM is backwards. Perhaps a copy and paste error from JP.



Moreover, we see that the CALL CPUER that failed is this one as its return address will be 0x01DA:



J040: JNZ J050 ;TEST "JNZ"
JC J050 ;TEST "JC"
JPO J050 ;TEST "JPO"
JM J050 ;TEST "JM"
JMP J060 ;TEST "JMP" (IT'S A LITTLE LATE,BUT WHAT THE HELL!
J050: CALL CPUER


There are 4 instructions that jump directly to J050 and a JMP that goes over it. And of those instructions could be wrong, but JMP is likely right. And given that the hexadecimal output showed JM being wrong then I'll bet it is JM that is jumping to the CALL CPUER.



The Very Specific Answer Answer



The JM is taken even though the S flag is not set. That's wrong.



A Final Note



I started out by looking at the cpudiag.asm source code. The significance of CPUER was pretty clear and I got curious about where that exit code came from. Once I figured out it was the return address of the CALL CPUER instruction it got me wondering why your emulator wasn't printing out a hexadecimal address. At that point numerology pointed out JM in the binary to hexadecimal conversion routine and also gave me an address to look at what had actually failed. Then after all that I looked at your instruction trace and noticed by pure luck that the first instruction you listed made a wrong turn.



A reasonable approach, if you're familiar with 8080 code, and especially with writing it so you can see what a program would normally be expected to do. If you're new to 8080, then I think a lower-level inspection, as suggested in the "General Advice" section will be more fruitful.







share|improve this answer














share|improve this answer



share|improve this answer








edited Jun 4 at 18:39

























answered Jun 4 at 8:37









George PhillipsGeorge Phillips

4,3861924




4,3861924







  • 15





    As well as (what I feel safe to assume is) the answer, a superb "how to find the answer" answer.

    – TripeHound
    Jun 4 at 8:48






  • 2





    " if you're familiar with 8080 code..." Speaking as somebody who went through the same process with a Z80 emulator, I can guarantee that @DavidTran will be very familiar with 8080 by the end.

    – JeremyP
    Jun 4 at 8:54











  • Wow thanks for the detailed answer! But why would the P(arity) flag affect JM? Shouldn't that depend on the S(ign) flag, (specifically, that it's false which means sign is negative)?

    – David Tran
    Jun 4 at 15:55











  • @DavidTran: The S flag is set (1) when the result is negative. In instruction step 79, S is 0, so the result was positive. (I.e., S tells you if there is a negative sign at the front of your result. 0 is no, 1 is yes.)

    – Eric Towers
    Jun 4 at 18:42






  • 2





    You're right, it should be S not P. Edited answer to reflect that. Note that the sign bit is a copy of the top bit of the result so it will be 0 for a positive result and 1 for negative.

    – George Phillips
    Jun 4 at 18:45












  • 15





    As well as (what I feel safe to assume is) the answer, a superb "how to find the answer" answer.

    – TripeHound
    Jun 4 at 8:48






  • 2





    " if you're familiar with 8080 code..." Speaking as somebody who went through the same process with a Z80 emulator, I can guarantee that @DavidTran will be very familiar with 8080 by the end.

    – JeremyP
    Jun 4 at 8:54











  • Wow thanks for the detailed answer! But why would the P(arity) flag affect JM? Shouldn't that depend on the S(ign) flag, (specifically, that it's false which means sign is negative)?

    – David Tran
    Jun 4 at 15:55











  • @DavidTran: The S flag is set (1) when the result is negative. In instruction step 79, S is 0, so the result was positive. (I.e., S tells you if there is a negative sign at the front of your result. 0 is no, 1 is yes.)

    – Eric Towers
    Jun 4 at 18:42






  • 2





    You're right, it should be S not P. Edited answer to reflect that. Note that the sign bit is a copy of the top bit of the result so it will be 0 for a positive result and 1 for negative.

    – George Phillips
    Jun 4 at 18:45







15




15





As well as (what I feel safe to assume is) the answer, a superb "how to find the answer" answer.

– TripeHound
Jun 4 at 8:48





As well as (what I feel safe to assume is) the answer, a superb "how to find the answer" answer.

– TripeHound
Jun 4 at 8:48




2




2





" if you're familiar with 8080 code..." Speaking as somebody who went through the same process with a Z80 emulator, I can guarantee that @DavidTran will be very familiar with 8080 by the end.

– JeremyP
Jun 4 at 8:54





" if you're familiar with 8080 code..." Speaking as somebody who went through the same process with a Z80 emulator, I can guarantee that @DavidTran will be very familiar with 8080 by the end.

– JeremyP
Jun 4 at 8:54













Wow thanks for the detailed answer! But why would the P(arity) flag affect JM? Shouldn't that depend on the S(ign) flag, (specifically, that it's false which means sign is negative)?

– David Tran
Jun 4 at 15:55





Wow thanks for the detailed answer! But why would the P(arity) flag affect JM? Shouldn't that depend on the S(ign) flag, (specifically, that it's false which means sign is negative)?

– David Tran
Jun 4 at 15:55













@DavidTran: The S flag is set (1) when the result is negative. In instruction step 79, S is 0, so the result was positive. (I.e., S tells you if there is a negative sign at the front of your result. 0 is no, 1 is yes.)

– Eric Towers
Jun 4 at 18:42





@DavidTran: The S flag is set (1) when the result is negative. In instruction step 79, S is 0, so the result was positive. (I.e., S tells you if there is a negative sign at the front of your result. 0 is no, 1 is yes.)

– Eric Towers
Jun 4 at 18:42




2




2





You're right, it should be S not P. Edited answer to reflect that. Note that the sign bit is a copy of the top bit of the result so it will be 0 for a positive result and 1 for negative.

– George Phillips
Jun 4 at 18:45





You're right, it should be S not P. Edited answer to reflect that. Note that the sign bit is a copy of the top bit of the result so it will be 0 for a positive result and 1 for negative.

– George Phillips
Jun 4 at 18:45

















draft saved

draft discarded
















































Thanks for contributing an answer to Retrocomputing Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fretrocomputing.stackexchange.com%2fquestions%2f11223%2ffixing-obscure-8080-emulator-bug%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Club Baloncesto Breogán Índice Historia | Pavillón | Nome | O Breogán na cultura popular | Xogadores | Adestradores | Presidentes | Palmarés | Historial | Líderes | Notas | Véxase tamén | Menú de navegacióncbbreogan.galCadroGuía oficial da ACB 2009-10, páxina 201Guía oficial ACB 1992, páxina 183. Editorial DB.É de 6.500 espectadores sentados axeitándose á última normativa"Estudiantes Junior, entre as mellores canteiras"o orixinalHemeroteca El Mundo Deportivo, 16 setembro de 1970, páxina 12Historia do BreogánAlfredo Pérez, o último canoneiroHistoria C.B. BreogánHemeroteca de El Mundo DeportivoJimmy Wright, norteamericano do Breogán deixará Lugo por ameazas de morteResultados de Breogán en 1986-87Resultados de Breogán en 1990-91Ficha de Velimir Perasović en acb.comResultados de Breogán en 1994-95Breogán arrasa al Barça. "El Mundo Deportivo", 27 de setembro de 1999, páxina 58CB Breogán - FC BarcelonaA FEB invita a participar nunha nova Liga EuropeaCharlie Bell na prensa estatalMáximos anotadores 2005Tempada 2005-06 : Tódolos Xogadores da Xornada""Non quero pensar nunha man negra, mais pregúntome que está a pasar""o orixinalRaúl López, orgulloso dos xogadores, presume da boa saúde económica do BreogánJulio González confirma que cesa como presidente del BreogánHomenaxe a Lisardo GómezA tempada do rexurdimento celesteEntrevista a Lisardo GómezEl COB dinamita el Pazo para forzar el quinto (69-73)Cafés Candelas, patrocinador del CB Breogán"Suso Lázare, novo presidente do Breogán"o orixinalCafés Candelas Breogán firma el mayor triunfo de la historiaEl Breogán realizará 17 homenajes por su cincuenta aniversario"O Breogán honra ao seu fundador e primeiro presidente"o orixinalMiguel Giao recibiu a homenaxe do PazoHomenaxe aos primeiros gladiadores celestesO home que nos amosa como ver o Breo co corazónTita Franco será homenaxeada polos #50anosdeBreoJulio Vila recibirá unha homenaxe in memoriam polos #50anosdeBreo"O Breogán homenaxeará aos seus aboados máis veteráns"Pechada ovación a «Capi» Sanmartín e Ricardo «Corazón de González»Homenaxe por décadas de informaciónPaco García volve ao Pazo con motivo do 50 aniversario"Resultados y clasificaciones""O Cafés Candelas Breogán, campión da Copa Princesa""O Cafés Candelas Breogán, equipo ACB"C.B. Breogán"Proxecto social"o orixinal"Centros asociados"o orixinalFicha en imdb.comMario Camus trata la recuperación del amor en 'La vieja música', su última película"Páxina web oficial""Club Baloncesto Breogán""C. B. Breogán S.A.D."eehttp://www.fegaba.com

Vilaño, A Laracha Índice Patrimonio | Lugares e parroquias | Véxase tamén | Menú de navegación43°14′52″N 8°36′03″O / 43.24775, -8.60070

Cegueira Índice Epidemioloxía | Deficiencia visual | Tipos de cegueira | Principais causas de cegueira | Tratamento | Técnicas de adaptación e axudas | Vida dos cegos | Primeiros auxilios | Crenzas respecto das persoas cegas | Crenzas das persoas cegas | O neno deficiente visual | Aspectos psicolóxicos da cegueira | Notas | Véxase tamén | Menú de navegación54.054.154.436928256blindnessDicionario da Real Academia GalegaPortal das Palabras"International Standards: Visual Standards — Aspects and Ranges of Vision Loss with Emphasis on Population Surveys.""Visual impairment and blindness""Presentan un plan para previr a cegueira"o orixinalACCDV Associació Catalana de Cecs i Disminuïts Visuals - PMFTrachoma"Effect of gene therapy on visual function in Leber's congenital amaurosis"1844137110.1056/NEJMoa0802268Cans guía - os mellores amigos dos cegosArquivadoEscola de cans guía para cegos en Mortágua, PortugalArquivado"Tecnología para ciegos y deficientes visuales. Recopilación de recursos gratuitos en la Red""Colorino""‘COL.diesis’, escuchar los sonidos del color""COL.diesis: Transforming Colour into Melody and Implementing the Result in a Colour Sensor Device"o orixinal"Sistema de desarrollo de sinestesia color-sonido para invidentes utilizando un protocolo de audio""Enseñanza táctil - geometría y color. Juegos didácticos para niños ciegos y videntes""Sistema Constanz"L'ocupació laboral dels cecs a l'Estat espanyol està pràcticament equiparada a la de les persones amb visió, entrevista amb Pedro ZuritaONCE (Organización Nacional de Cegos de España)Prevención da cegueiraDescrición de deficiencias visuais (Disc@pnet)Braillín, un boneco atractivo para calquera neno, con ou sen discapacidade, que permite familiarizarse co sistema de escritura e lectura brailleAxudas Técnicas36838ID00897494007150-90057129528256DOID:1432HP:0000618D001766C10.597.751.941.162C97109C0155020