Is Anyone Willing to Explain This C++ Code?

You can talk about almost anything that you want to on this board.

Moderator: Moderators

User avatar
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?

Post by Drew Sebastino »

Well, I've been looking, and I think this says how each sprite is set up?

Code: Select all

392 void m92_state::ppan_draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect) 
393 { 
394 	UINT16 *source = m_spriteram->live(); // sprite buffer control is never triggered 
395 	int offs, layer; 
396 
 
397 	for (layer = 0; layer < 8; layer++) 
398 	{ 
399 		for (offs = 0; offs < m_sprite_list; ) 
400 		{ 
401 			int x = source[offs+3] & 0x1ff; 
402 			int y = source[offs+0] & 0x1ff; 
403 			int code = source[offs+1]; 
404 			int color = source[offs+2] & 0x007f; 
405 			int pri = (~source[offs+2] >> 6) & 2; 
406 			int curlayer = (source[offs+0] >> 13) & 7; 
407 			int flipx = (source[offs+2] >> 8) & 1; 
408 			int flipy = (source[offs+2] >> 9) & 1; 
409 			int numcols = 1 << ((source[offs+0] >> 11) & 3); 
410 			int numrows = 1 << ((source[offs+0] >> 9) & 3); 
411 			int row, col, s_ptr; 
I know by looking through one of the files that oam (or "sprite ram" as it's called here) is located at "0xe0000" through "0xeffff". I actually haven't even found out how many sprites there are, so if you get the space for how large "sprite ram" is (2048 bytes, I'm pretty sure) and divide it by how many bytes each entry is, you should get the answer.

You know, this is kind of random, but is the self test something that goes on in software? I would have thought it would have done it even before it looked at any of the code, but it doesn't. One really weird thing is that cgram is filled out even if you don't write anything. (The red color that was being loaded to color 0 just wrote over the first black color, but everything else is still filled out. I would have thought all the colors would have been black from start up.)
lidnariq
Posts: 10677
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Is Anyone Willing to Explain This C++ Code?

Post by lidnariq »

Espozo wrote:Well, I've been looking, and I think this says how each sprite is set up?
Yup.
I actually haven't even found out how many sprites there are, so if you get the space for how large "sprite ram" is (2048 bytes, I'm pretty sure) and divide it by how many bytes each entry is, you should get the answer.
Well, first, since that table shows indexing as offs+0, +1, +2, +3 it's four words per entry.
Also, right after what you quoted, offs += 4 * numcols;... looks like it has the ability to staple multiple entries together for some kind of metasprite support.
Also the loop iterates to a maximum of m_sprite_list, which elsewhere appears to provide the ability to dynamically choose the number of entries in OAM, up to a maximum of 1024 words of sprites = 2048 bytes you saw = 256 entries.

The format appears to be:

Code: Select all

  fedc ba98 7654 3210
0 LLLW WHHy yyyy yyyy
1 tttt tttt tttt tttt
2        YX plll llll
3         x xxxx xxxx
L - layer
W,H - width, height (0,1,2,3 = 1,2,4,8)
X,Y - reflect X,Y
x,y - x,y coordinate
t - tile ("code")
p - priority
l - color
You know, this is kind of random, but is the self test something that goes on in software?
Should be...
I would have thought all the colors would have been black from start up.)
RAM rarely contains a specific value on power-up...
Joe
Posts: 469
Joined: Mon Apr 01, 2013 11:17 pm

Re: Is Anyone Willing to Explain This C++ Code?

Post by Joe »

koitsu wrote:But the IDT is still there today, workin' as designed.
What you described is the IVT, which is still there today... right up until the OS starts to boot and throws it away in favor of the IDT. (And even then, only if the computer still has BIOS compatibility. UEFI machines without BIOS compatibility won't have an IVT at all.)

So much for nostalgia, huh? :P
Espozo wrote:

Code: Select all

392 void m92_state::ppan_draw_sprites(...
Careful; that function is only used as part of the "ppan" driver. You're using "gunforc2", which uses m92_state::draw_sprites().
Espozo wrote:is the self test something that goes on in software?
Yes.
Espozo wrote:One really weird thing is that cgram is filled out even if you don't write anything.
MAME's M92 driver doesn't appear to be very accurate. You will need to test on a real M92 to verify behavior.
User avatar
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?

Post by Drew Sebastino »

lidnariq wrote:2 YX plll llll
3 x xxxx xxxx
Now I know why arcade machines are known to be "ineficient". They could have saved an entire byte (and I'm sure they could have done something to put the other 5 unused bytes to use.) Didn't the Genesis actually have 8 bytes per sprite, or am I just hallucinating?
lidnariq wrote:("code")
Why they named it "code" is completely beyond me.

You know, I've now been trying to change the "code" of sprite 0 to where it is using tile 1 instead of 0 (tile 0 is completely transparent). I am guessing this should show a 16x16 sprite in the top left corner of the screen, but I don't know if this is correct:

Code: Select all

  mov ax, 0xE000
  mov ds, ax
  mov byte [0x002], 0x01
The problem is that I still don't get the whole 20 bit address thing. What is the relationship between the number we are first moving to ax, and the second number (the [0x002])? Why are we moving a number to ax instead of ds in the first place? Is it because there isn't an instruction for it? Does storing a number to ds for 20 bit addresses? The number of the address is supposed to be "E0002", but I don't know if it is here.
Joe wrote:MAME's M92 driver doesn't appear to be very accurate.
No kidding. :roll: Look at the cut scenes in Ninja Baseball Bat Man. (In earlier versions of Mame, it also used to sound awful.)
Joe wrote:You will need to test on a real M92 to verify behavior.
I'm up for donations. :wink:
lidnariq
Posts: 10677
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Is Anyone Willing to Explain This C++ Code?

Post by lidnariq »

Espozo wrote:Now I know why arcade machines are known to be "inefficient". They could have saved an entire byte
Except that they're working with 16-bit quantities there, and you can't fit four words into seven bytes...

Code: Select all

  mov ax, 0xE000
  mov ds, ax
  mov byte [0x002], 0x01
The problem is that I still don't get the whole 20 bit address thing.
It was an awkward hack originally intended for extensibility that got enshrined verbatim. (no, seriously, they originally intended to allow the amount of overlap—the 16 in segment*16+offset—to change) Oops.
What is the relationship between the number we are first moving to ax, and the second number (the [0x002])?
They're just a particular splitting of the 20-bit pointer into two 16-bit words, one of 4000 different possible ones. (Because of how 16-bit pointers overflow, they also can be used to ensure that memory access only happens to a specific 64 KiB window)
Why are we moving a number to ax instead of ds in the first place? Is it because there isn't an instruction for it?
Exactly.
Does storing a number to ds for 20 bit addresses?
I don't understand the question...
The number of the address is supposed to be "E0002", but I don't know if it is here.
Yeah, E000:0002 is equal to the flat pointer E0002.
User avatar
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?

Post by Drew Sebastino »

lidnariq wrote:
Espozo wrote:Now I know why arcade machines are known to be "inefficient". They could have saved an entire byte
Except that they're working with 16-bit quantities there, and you can't fit four words into seven bytes...
Why does it have to be words and not bytes? The processor seems capable of working with bytes, as evidenced by writing "1F" to cgram.
lidnariq wrote:[
Does storing a number to ds for 20 bit addresses?
I don't understand the question...
Yeah, I didn't mean to say that. :lol: What I meant to say is that does storing the number to ds make it to where it is 20 bit. I assume so.

You know, so far, It seems that 65xx assembly has proven to be the most structurally sound assembly language I've seen. What I was trying to do above could have just been

Code: Select all

lda #$01
sta $0E0002
on the SNES. I originally thought it was cool that you could essentially get rid of "lda" and just load and store in one instruction, but it isn't good when you have to do it 3 times...

Anyway, I actually did try my code, but I don't see anything, and tile number 1 does have something, unlike 0. I assume there is a register somewhere that controls if sprites or BGs are on or off, like on the SNES.
lidnariq
Posts: 10677
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Is Anyone Willing to Explain This C++ Code?

Post by lidnariq »

Espozo wrote:Why does it have to be words and not bytes? The processor seems capable of working with bytes, as evidenced by writing "1F" to cgram.
Oh, sure, but multiplying by eight (by SHL AL, 1 three times, or MOV CL,3 / SHL AL,CL) is faster than multiplying by seven. (MUL is slooooow. IMUL is sloooooooower)
does storing the number to ds make it to where it is 20 bit?
Mm. So the 65816 supports three different ways of talking about memory access:
* direct page, 8 bits immediate (with a 16-bit offset) ( i.e. value of 16-bit D register + value of immediate)
* 16 bits immediate (with a 8-bit "bank") (value of 8-bit B register * 65536 + immediate)
* literal 24-bit pointer

In contrast, the 8086 only supports something that's closest to the middle of the three. (segment * 16 + offset). If you omit the explicit segment, it'll pick one for you (usually DS, but occasionally SS or ES, depending)

Also, even as crippled as the 8086's memory addressing was, it does support adding multiple registers together on a single access. (e.g. mov [BX+SI+7], al)
I originally thought it was cool that you could essentially get rid of "lda" and just load and store in one instruction, but it isn't good when you have to do it 3 times...
That's a sign you shouldn't be doing it three times ;)

e.g. instead, try using the rep movsb or rep stosb (or movsw or stosw) instructions.
User avatar
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?

Post by Drew Sebastino »

Well, relating to sprites, I forgot about how I found something called "sprite control" located at 0xF9000 through 0xF900F, so it's only 16 bits long. I look at the other file, and this is what I found:

Code: Select all

62 WRITE16_MEMBER(m92_state::m92_spritecontrol_w) 
63 { 
64 	COMBINE_DATA(&m_spritecontrol[offset]); 
65 	// offset0: sprite list size (negative) 
66 	// offset1: ? (always 0) 
67 	// offset2: sprite control 
68 	// offset3: ? (always 0) 
69 	// offset4: sprite dma 
70 	// offset5: ? 
71 
 
72 	/* Sprite control - display all sprites, or partial list */ 
73 	if (offset==2 && ACCESSING_BITS_0_7) 
74 	{ 
75 		if ((data & 0xff) == 8) 
76 			m_sprite_list = (((0x100 - m_spritecontrol[0]) & 0xff) * 4); 
77 		else 
78 			m_sprite_list = 0x400; 
79 
 
80 		/* Bit 0 is also significant */ 
81 	} 
82 
 
83 	/* Sprite buffer - the data written doesn't matter (confirmed by several games) */ 
84 	if (offset==4) 
85 	{ 
86 		/* this implementation is not accurate: still some delayed sprites in gunforc2 (might be another issue?) */ 
87 		m_spriteram->copy(); 
88 		m_sprite_buffer_busy = 0; 
89 
 
90 		/* Pixel clock is 26.6666MHz (some boards 27MHz??), we have 0x800 bytes, or 0x400 words to copy from 
91 		spriteram to the buffer.  It seems safe to assume 1 word can be copied per clock. */ 
92 		timer_set(attotime::from_hz(XTAL_26_66666MHz) * 0x400, TIMER_SPRITEBUFFER); 
93 	} 
94 //  logerror("%04x: m92_spritecontrol_w %08x %08x\n",space.device().safe_pc(),offset,data); 
95 } 
So if you write a number to offset 0, (which is 0xF9000?) the number of sprites will be the same as the number you moved there? What's up with this then?

Code: Select all

67 	// offset2: sprite control
...
72 	/* Sprite control - display all sprites, or partial list */ 
73 	if (offset==2 && ACCESSING_BITS_0_7) 
Joe
Posts: 469
Joined: Mon Apr 01, 2013 11:17 pm

Re: Is Anyone Willing to Explain This C++ Code?

Post by Joe »

That code says you need to write a value to 0xF9000 that will determine how many sprites to draw, then write 8 (or a word with 8 in the low byte) to 0xF9004 to make the sprite drawing logic use that number. Afterwards, write any value to 0xF9008 to copy the sprites from sprite RAM to the internal drawing buffer.

It looks like this logic was designed specifically for rep movsw.

Edit: these registers start at 0xF9000, not 0xF0000.
Last edited by Joe on Sun Apr 12, 2015 6:16 pm, edited 1 time in total.
User avatar
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?

Post by Drew Sebastino »

You know, this is horribly inefficient, (I'm still learning) but I expanded upon the older code to try to make it display the one sprite, but it doesn't appear to work. Do you see a problem (other than it's horribly inefficient)?

Code: Select all

cpu 80186

section code vstart=0 align=16

main_code:
  mov ax, 0xF800
  mov ds, ax
  mov byte [0x800], 0x1F

  mov ax, 0xE000
  mov ds, ax
  mov byte [0x002], 0x01

  mov ax, 0xF000
  mov ds, ax
  mov byte [0x000], 0x01

  mov ax, 0xF000
  mov ds, ax
  mov byte [0x004], 0x08

  mov ax, 0xF000
  mov ds, ax
  mov byte [0x008], 0x01

infinite_loop:
  jmp infinite_loop

section reset start=0x7fff0 vstart=0

  cli
  jmp (section.code.start >> 4):main_code
  
  times 16-($-$$) db 0
I'm just curious Joe, but are you interested in this?
Joe
Posts: 469
Joined: Mon Apr 01, 2013 11:17 pm

Re: Is Anyone Willing to Explain This C++ Code?

Post by Joe »

Espozo wrote:Do you see a problem (other than it's horribly inefficient)?
The addresses I wrote in my previous post are wrong, so that's part of the reason why it doesn't work! :oops: (I'd better go back and fix that.)

Anyway, here are the three address ranges you want:

Code: Select all

	AM_RANGE(0xf8000, 0xf87ff) AM_RAM AM_SHARE("spriteram")
	AM_RANGE(0xf8800, 0xf8fff) AM_READWRITE(m92_paletteram_r, m92_paletteram_w)
	AM_RANGE(0xf9000, 0xf900f) AM_WRITE(m92_spritecontrol_w) AM_SHARE("spritecontrol")
It looks like you want your second write to go to 0xF8002 instead of 0xE0002, and the third through fifth to go to 0xF9000 instead of 0xF0000.
Espozo wrote:I'm just curious Joe, but are you interested in this?
Low-level programming is fun. Granted, I prefer to focus my efforts on PCs and game consoles rather than arcade machines, but at the end of the day it's all pretty similar.
User avatar
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?

Post by Drew Sebastino »

Well, I guess this is kind of like a PC game console, because it is like a game console (obviously) but it uses the x86 architecture (I don't know of any game console that does, or at least any one from this time period.)
Part of the reason I'm doing this is for the novelty of it, but I also like overdraw, but I don't want to do anything on the GBA because I'm not a huge fan of the screen... It's also cool that it's by Irem.
lidnariq
Posts: 10677
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Is Anyone Willing to Explain This C++ Code?

Post by lidnariq »

Espozo wrote:I don't know of any game console that does, or at least any one from this time period.
IBM was seriously trying to make the PCjr count as a game console. They rather screwed it up, though.

That said, the Tandy 1000 fixed most of the stupid. In fact, so successfully that people forgot that both the extended video modes and sound were originally due to IBM.

As far as arcade hardware goes, x86-based PCs seemed to be the preferred controller for laserdisc games. Not really clear why...
User avatar
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?

Post by Drew Sebastino »

I guess I just can't make up my mind, because I think I actually want to look at the Irem M107, which was actually Irem's last and most powerful arcade board, instead of the M92. Don't worry though, they're pretty much the same as they have the same CPU (except the one in the M107 is clocked 5Mhz faster, bringing it to 14 from 9) and nearly the same video hardware, except it had 4 BG layers instead of 3, has 16 instead of 15 bit color (I'm not sure what the last bit does, but it should be easy to figure out) and has 512 sprites instead of 256. (I'm not sure if the overdraw changed any, but I wasn't even sure what the M92's was to begin with). Because of the increased sprite ram, it appears many things have been shifted, like cgram. I found this page that helps a bit: https://github.com/Neo2003/mame4all-pi- ... s/m107.cpp I made the screen turn red on the M107 as a test, and here is the picture: (The display is sideways because the game I'm using as a base is a vertical shooter, but you can rotate the screen in Mame in the settings.)
M107.png
M107.png (2.34 KiB) Viewed 3353 times
I'm probably not going to be doing anything on this for quite a while though, because I want to do some more SNES stuff first.
User avatar
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?

Post by Drew Sebastino »

Well, I was bored and I thought I might try something, so I looked at the tile data for 4 of the rom chips in an M107 game and put them through a program katsumi made that interweaves the bits from 4 different files together, and I did this on two different sets of files and I got this:
Tile Data.png
So not only do the bits from the 4 files get interweaved, each tile from the 2 sets of 4 files does also. Why did they make it so complex, dang it! :x
Post Reply