Is Anyone Willing to Explain This C++ Code?
Moderator: Moderators
Re: Is Anyone Willing to Explain This C++ Code?
Older machines like the 8086 and 80186 don't TRAP on invalid instructions, and will do something random instead. Usually NOP, but not always:
http://stackoverflow.com/questions/2811 ... el-8086-88
http://stackoverflow.com/questions/2811 ... el-8086-88
Re: Is Anyone Willing to Explain This C++ Code?
I, personally, would use section directives to force the assembler to output data in a certain way.Espozo wrote:How do you do that though? I know this is probably basic stuff...
For example:
Code: Select all
section reset start=0x7fff0 vstart=0
cli
jmp ...Yes.Espozo wrote:You mean like numbers that don't respond to anything?
Padding for the unused part of the ROM. The MAME debugger doesn't know what's code and what isn't, so it assumes everything is code.Espozo wrote:What are they even doing there?
Like most x86-compatible CPUs, the V33 will invoke interrupt 6 when it encounters an invalid opcode. In this case, I doubt it ever tries to execute those invalid opcodes.Espozo wrote:How does the processor even handle something like that?
Re: Is Anyone Willing to Explain This C++ Code?
The 80186 does.lidnariq wrote:Older machines like the 8086 and 80186 don't TRAP on invalid instructions,
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Is Anyone Willing to Explain This C++ Code?
Well, I wrote this:
and I assembled it, and ran it through the file splitter. I then made it into the rom and tried it, and then I changed the order of the files and tried it.
Unfortunatelly, none of them worked and this is what I got:
Code: Select all
CPU 80186
section reset start=0x7fff0 vstart=0
cli
jmp main_code
main_code:
mov ax, 0xF800
mov ds, ax
mov byte [0x800], 0x1F
infinite_loop:
jmp infinite_loopUnfortunatelly, none of them worked and this is what I got:
Re: Is Anyone Willing to Explain This C++ Code?
First, you need a separate section directive for the rest of your code. (Later, you'll probably need more section directives.) Second, you must use a far jump to reach the rest of your code, not a near jump. For example:Espozo wrote:Well, I wrote this:
Code: Select all
section code vstart=0 align=16
main_code:
mov ax, 0xF800
mov ds, ax
mov byte [0x800], 0x1F
infinite_loop:
jmp infinite_loop
section reset start=0x7fff0 vstart=0
cli
jmp (section.code.start >> 4):main_codeIt looks like one of the two files you're using is full of zeroes instead of containing the correct data.Espozo wrote:Unfortunatelly, none of them worked and this is what I got:
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Is Anyone Willing to Explain This C++ Code?
I actually tried you code, (with "CPU 80186" at the beginning) but the debugger just shows the instruction for the value 0 all the way through and obviously doesn't work. One strange thing I noticed is that each file is 256KB long, and it used to be 6 bytes with the code that showed something in the debugger. Is there something wrong with your code?
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Is Anyone Willing to Explain This C++ Code?
You know, could someone actually just tell me what everything means here? I switched the order you had the code to where the bottom is now at the top like so:
and this is what I get in the debugger, which is at least better than having nothing like it used to:
I'm guessing that it jumps to an area with no code in it instead of the correct area, because if I let it run, it fills up with "add [bw+ix],al".
This has proven to be far more complicated than I had originally anticipated...
Code: Select all
CPU 80186
section reset start=0x7fff0 vstart=0
cli
jmp (section.code.start >> 4):main_code
section code vstart=0 align=16
main_code:
mov ax, 0xF800
mov ds, ax
mov byte [0x800], 0x1F
infinite_loop:
jmp infinite_loopI'm guessing that it jumps to an area with no code in it instead of the correct area, because if I let it run, it fills up with "add [bw+ix],al".
This has proven to be far more complicated than I had originally anticipated...
Re: Is Anyone Willing to Explain This C++ Code?
Edit: Never mind. I just found the key piece of information: viewtopic.php?p=144842#p144842
Upon reviewing Chapter 3, I was greeted with official definitions for all registers (BW = general-purpose register, IX = index register), and Chapter 3.6 clearly denotes that there are BR and DI opcodes on the V30 CPU. The Appendix List has a chart of all the opcodes. BR = Branch, DI = I have not the slightest idea ("CPU control" is too vague). There doesn't appear to be a "clear" definition of what all the opcodes do.
Skimming more of the instruction set of that PDF shows me that there are many opcodes and registers that are "similar" to 8086/8088 but the official explanations of them all is missing (there's the Appendix but it really doesn't describe their functionality).
So I'm left thinking this:
DI = NEC V30 opcode for what Intel calls CLI
BR = NEC V30 opcode for what Intel calls JMP
IX = NEC V30 register for some particular Intel index register (there are multiples and I don't know which one)
BW = NEC V30 register for possibly Intel's BX register? Again not sure.
You basically get to learn the mapping between Intel and NEC V30 when looking at MAME's debugger -- unless someone know of a way to force the debugger to display Intel mnemonics.
Good luck with this -- this would drive me absolutely batshit crazy. "The code I write is technically working as intended, but what I see in real-time in the debugger isn't the syntax I use in the code itself".
Thus, you probably just need to execute the code/step through it. The MAME debugger documentation is abysmal, so I wish you luck there too. :-)
I Googled around and found this (PDF) for the NEC V30NX. I have to assume this CPU is extremely close to the V30/V33 used on this board, but I could easily be wrong.MAME is using mnemonics from NEC instead of Intel, which is why they don't look like x86 instructions.
Upon reviewing Chapter 3, I was greeted with official definitions for all registers (BW = general-purpose register, IX = index register), and Chapter 3.6 clearly denotes that there are BR and DI opcodes on the V30 CPU. The Appendix List has a chart of all the opcodes. BR = Branch, DI = I have not the slightest idea ("CPU control" is too vague). There doesn't appear to be a "clear" definition of what all the opcodes do.
Skimming more of the instruction set of that PDF shows me that there are many opcodes and registers that are "similar" to 8086/8088 but the official explanations of them all is missing (there's the Appendix but it really doesn't describe their functionality).
So I'm left thinking this:
DI = NEC V30 opcode for what Intel calls CLI
BR = NEC V30 opcode for what Intel calls JMP
IX = NEC V30 register for some particular Intel index register (there are multiples and I don't know which one)
BW = NEC V30 register for possibly Intel's BX register? Again not sure.
You basically get to learn the mapping between Intel and NEC V30 when looking at MAME's debugger -- unless someone know of a way to force the debugger to display Intel mnemonics.
Good luck with this -- this would drive me absolutely batshit crazy. "The code I write is technically working as intended, but what I see in real-time in the debugger isn't the syntax I use in the code itself".
Thus, you probably just need to execute the code/step through it. The MAME debugger documentation is abysmal, so I wish you luck there too. :-)
Re: Is Anyone Willing to Explain This C++ Code?
No, that's intentional. The assembler can automatically put code in the right place in the ROM file, so that's what I did. You should be able to just split the output file from my example and load it with MAME. (Now that I look, I forgot to pad it to the correct size. It probably should have been exactly 512kiB total/256kiB each, but it's a few bytes short.)Espozo wrote:One strange thing I noticed is that each file is 256KB long, and it used to be 6 bytes with the code that showed something in the debugger. Is there something wrong with your code?
I'll do my best.Espozo wrote:You know, could someone actually just tell me what everything means here?
That probably broke it.Espozo wrote:I switched the order you had the code to where the bottom is now at the top like so:
Anyway, time to explain things.
Code: Select all
section code vstart=0 align=16Code: Select all
main_code:
---snip---
jmp infinite_loopCode: Select all
section reset start=0x7fff0 vstart=0Code: Select all
cli
jmp (section.code.start >> 4):main_codeYou should probably step through it instead of letting it run. At least that way, you'll be able to see what it's doing right before it jumps off to nowhere. (Plus, if anything triggers a NMI, it'll jump off to nowhere anyway since you don't have a NMI handler yet.)Espozo wrote:I'm guessing that it jumps to an area with no code in it instead of the correct area, because if I let it run, it fills up with "add [bw+ix],al".
Don't worry. Once you've got the basic setup code functioning, it'll get easier.Espozo wrote:This has proven to be far more complicated than I had originally anticipated...
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Is Anyone Willing to Explain This C++ Code?
Well, I stepped through it, and this is where "br" brought me. The whole thing looks like that:koitsu wrote:Thus, you probably just need to execute the code/step through it. The MAME debugger documentation is abysmal, so I wish you luck there too.
That's the only way anything even showed up though. (The picture above was where the older code led.)Joe wrote:That probably broke it.
You know, when people talk about a reset vector, are they talking about the same thing on the SNES? Like the arcade board has a reset button on it? I originally thought the reset button just turned the system on and off, but games that normally can't save will often save high score and options in the options menu and whatnot.
By the way, I just posted something on some Mame forum about if there is a way to force it to display x86 instructions, so hopefully, I'll hear from them soon.
It still is kind of weird though, Joe, that what you wrote doesn't even display anything. I don't see anything wrong if you're describing it correctly. Is it because it needs to be exactly the right size or something like you kind of said?
Re: Is Anyone Willing to Explain This C++ Code?
All CPUs have a reset vector. When a CPU is powered on or reset, it begins executing the reset vector.Espozo wrote:You know, when people talk about a reset vector, are they talking about the same thing on the SNES?
As long as RAM contents are maintained, the CPU can't tell the difference between power-on and reset. For example, some NES games without nonvolatile RAM can also keep high scores across a reset.Espozo wrote:I originally thought the reset button just turned the system on and off, but games that normally can't save will often save high score and options in the options menu and whatnot.
It sounds like I'll need to check this out in the MAME debugger.Espozo wrote:It still is kind of weird though, Joe, that what you wrote doesn't even display anything. I don't see anything wrong if you're describing it correctly. Is it because it needs to be exactly the right size or something like you kind of said?
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Is Anyone Willing to Explain This C++ Code?
Well Joe, here you go. Best of luck! 
(Mod edit: ROM removal)
(Mod edit: ROM removal)
Last edited by Drew Sebastino on Sat Apr 11, 2015 9:39 am, edited 1 time in total.
Re: Is Anyone Willing to Explain This C++ Code?
It's probably a bad idea to post copyrighted ROMs.
So! As it turns out, you are correct: MAME doesn't load your replacement ROMs if they are too small.
With that in mind, I have made a slight correction:After padding the reset section to 16 bytes long, the entire file is exactly 512kiB, which is enough to make MAME load it as expected.
So! As it turns out, you are correct: MAME doesn't load your replacement ROMs if they are too small.
With that in mind, I have made a slight correction:
Code: Select all
cpu 80186
section code vstart=0 align=16
main_code:
mov ax, 0xF800
mov ds, ax
mov byte [0x800], 0x1F
infinite_loop:
jmp infinite_loop
section reset start=0x7fff0 vstart=0
cli
jmp (section.code.start >> 4):main_code
times 16-($-$$) db 0- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: Is Anyone Willing to Explain This C++ Code?
Oops...Joe wrote:It's probably a bad idea to post copyrighted ROMs.
I'll get rid of it pronto! (Although I doubt Irem is going to come back from the grave to get me.
Is that is what I think it is?Joe wrote:
Re: Is Anyone Willing to Explain This C++ Code?
Oh and one thing, Espozo: cli might confuse you because its behaviour is opposite on x86 compared to 65xxx:
65xxx = sei = disables interrupts (i of P becomes 1), cli = enables interrupts (i of P becomes 0)
x86 = sti = enables interrupts (i of FLAGS becomes 1), cli = disables interrupts (i of FLAGS becomes 0)
65xxx = P = 8-bit CPU flag/status register
x86 = FLAGS = 16-bit CPU flag/status register (later extended to 32-bits (EFLAGS) and 64-bits (RFLAGS))
And as Joe more or less said -- yes, every CPU has some form of vectors (reset, interrupt, etc.). You can stop reading here if you don't wanna get hung up on interrupt vectors and the like (i.e. I recommend you stop reading here, haha ;-) ).
x86's interrupt vectors are crazy -- way more advanced than 65xxx because there's so many different hardware interrupts: there's the capability for 256 independent interrupt vectors on the x86 through the IDT (which is just a dedicated 1024-byte area of memory in RAM (0x0000 to 0x03FF) entirely for 32-bit vectors address). The table there on Wikipedia should give you some idea of the kinds of (hardware) interrupts the x86 handles. Bytes 0-3 = division by zero handler, bytes 4-7 = debugger handler, bytes 8-11 = NMI handler, etc..
NMI will probably be the one that looks familiar to you from the SNES ("hey I know that / have heard of that one!") -- except with one huge difference: NMI on PC isn't tied to VBlank (often called Vsync on PC). Note that I said PC and not x86! -- it's completely possible at the hardware level to tie VBlank to NMI on the x86 (maybe arcade boards do this? Not sure!), but on PC architecture this is not how they did it. Instead, on PC architecture (during MS-DOS days, etc. -- things are different now with video cards today), waiting for Vsync on PC required that you sit in a loop waiting for bit 3 of I/O register 0x3DA (one of the VGA status registers) to become 0. See the bottom of this page (C code ahead, but it's easy to understand, kinda. They have two loops there: the first spins the CPU waiting for bit 3 to become 1 (waiting for VBlank to finish in case you're already in VBlank), the second spins the CPU waiting for bit 3 to become 0 (waiting for VBlank to start so you can begin doing your graphics updates/palette changes)).
P.S. -- Feeling big nostalgia for PC after writing this. It's all stuff that isn't used like how it was back in the early 90s -- now with more advanced OSes, 32-bit/64-bit stuff, crazy hardware, etc. lots of stuff is much more complex. But the IDT is still there today, workin' as designed.
65xxx = sei = disables interrupts (i of P becomes 1), cli = enables interrupts (i of P becomes 0)
x86 = sti = enables interrupts (i of FLAGS becomes 1), cli = disables interrupts (i of FLAGS becomes 0)
65xxx = P = 8-bit CPU flag/status register
x86 = FLAGS = 16-bit CPU flag/status register (later extended to 32-bits (EFLAGS) and 64-bits (RFLAGS))
And as Joe more or less said -- yes, every CPU has some form of vectors (reset, interrupt, etc.). You can stop reading here if you don't wanna get hung up on interrupt vectors and the like (i.e. I recommend you stop reading here, haha ;-) ).
x86's interrupt vectors are crazy -- way more advanced than 65xxx because there's so many different hardware interrupts: there's the capability for 256 independent interrupt vectors on the x86 through the IDT (which is just a dedicated 1024-byte area of memory in RAM (0x0000 to 0x03FF) entirely for 32-bit vectors address). The table there on Wikipedia should give you some idea of the kinds of (hardware) interrupts the x86 handles. Bytes 0-3 = division by zero handler, bytes 4-7 = debugger handler, bytes 8-11 = NMI handler, etc..
NMI will probably be the one that looks familiar to you from the SNES ("hey I know that / have heard of that one!") -- except with one huge difference: NMI on PC isn't tied to VBlank (often called Vsync on PC). Note that I said PC and not x86! -- it's completely possible at the hardware level to tie VBlank to NMI on the x86 (maybe arcade boards do this? Not sure!), but on PC architecture this is not how they did it. Instead, on PC architecture (during MS-DOS days, etc. -- things are different now with video cards today), waiting for Vsync on PC required that you sit in a loop waiting for bit 3 of I/O register 0x3DA (one of the VGA status registers) to become 0. See the bottom of this page (C code ahead, but it's easy to understand, kinda. They have two loops there: the first spins the CPU waiting for bit 3 to become 1 (waiting for VBlank to finish in case you're already in VBlank), the second spins the CPU waiting for bit 3 to become 0 (waiting for VBlank to start so you can begin doing your graphics updates/palette changes)).
P.S. -- Feeling big nostalgia for PC after writing this. It's all stuff that isn't used like how it was back in the early 90s -- now with more advanced OSes, 32-bit/64-bit stuff, crazy hardware, etc. lots of stuff is much more complex. But the IDT is still there today, workin' as designed.