Sega Genesis Dev Kit (SGDK)

SGDK only sub forum

Moderator: Stef

Mixail
Very interested
Posts: 133
Joined: Thu Nov 18, 2010 4:47 pm

Post by Mixail » Tue Feb 21, 2012 4:42 pm

How simultaneously to lose music and a sound. For example Wav and TFC.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Wed Feb 22, 2012 12:31 am

Thats is not possible, no Z80 drivers support that for the moment.
I plan to add better drivers later though :)

Shiru
Very interested
Posts: 786
Joined: Sat Apr 07, 2007 3:11 am
Location: Russia, Moscow
Contact:

Post by Shiru » Wed Feb 22, 2012 12:47 am

It is rather easy if you play TFC on M68K side and samples on Z80 side - you don't need a special driver to do this. You only need to modify TFC player a bit, by stopping Z80 before writing to YM2612 registers and selecting DAC register after write and running Z80 again.

By the way, Stef, it seems that waiting for busreq with while(*ptr&0x100) is incorrect, it should be 1 instead of 0x100. Compare compiled C code with code from any old game - games always check bit 0 while compiled C code with 0x100 checks bit 8. In real programs it works on hardware either way, I guess it is because other code create a large enough delay.

Mixail
Very interested
Posts: 133
Joined: Thu Nov 18, 2010 4:47 pm

Post by Mixail » Wed Feb 22, 2012 8:10 am

Stef wrote:Thats is not possible, no Z80 drivers support that for the moment.
I plan to add better drivers later though :)
How many it will occupy time?

Mixail
Very interested
Posts: 133
Joined: Thu Nov 18, 2010 4:47 pm

Post by Mixail » Thu Feb 23, 2012 4:21 pm

How to make, that rom (bin file) weighed not so much? At me at empty compilation it turns out 384 kb.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Fri Feb 24, 2012 9:15 am

Shiru wrote:It is rather easy if you play TFC on M68K side and samples on Z80 side - you don't need a special driver to do this. You only need to modify TFC player a bit, by stopping Z80 before writing to YM2612 registers and selecting DAC register after write and running Z80 again.

By the way, Stef, it seems that waiting for busreq with while(*ptr&0x100) is incorrect, it should be 1 instead of 0x100. Compare compiled C code with code from any old game - games always check bit 0 while compiled C code with 0x100 checks bit 8. In real programs it works on hardware either way, I guess it is because other code create a large enough delay.
Err you're right... the correct code should be equivalent to :

Code: Select all

while(!Z80_isBusTaken());
and this is not the case, i inverted the bit check :p
Thanks for notifying it :)
Both Double Dragon 1 and Double Dragon 2 does the same mistake in their code, i remember i was very confused with these games when i developed Gens (i experienced many Z80 issues because of that).

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Fri Feb 24, 2012 9:19 am

Mixail wrote:
Stef wrote:Thats is not possible, no Z80 drivers support that for the moment.
I plan to add better drivers later though :)
How many it will occupy time?
Don't expect it *soon*, it's somewhat planned but i cannot give any date...
You should follow Shiru advice about how mix TFM play on 68k and sample play on Z80.
How to make, that rom (bin file) weighed not so much? At me at empty compilation it turns out 384 kb.
Unfortunately SGDK library requires that minimum space for the moment.
But i think i will re enable optionals tables to minimize that requirement.
The problem is that without these tables some methods (math related stuff mainly) cannot work.

Shiru
Very interested
Posts: 786
Joined: Sat Apr 07, 2007 3:11 am
Location: Russia, Moscow
Contact:

Post by Shiru » Fri Feb 24, 2012 10:34 am

Here is what should be done to make TFC C player work with any Z80 sample player:

Code: Select all

void ym2612wr(u8 reg,u8 val,u8 bank)
{
    volatile u16 *pz;
    volatile u8 *pw,*pa,*pd;
 
    pz=(u16*)Z80_HALT; //stop Z80 to prevent it from corrupting a register write
    *pz=0x100;
    while(*pz&1); //wait for busreq
 
    pw=(u8*)YM2612_A0;
 
    if(!bank)
    {
        pa=(u8*)YM2612_A0;
        pd=(u8*)YM2612_D0;
    }
    else
    {
        pa=(u8*)YM2612_A1;
        pd=(u8*)YM2612_D1;
    }
 
    while(*pw&0x80); //select register
    *pa=reg;
    while(*pw&0x80); //write value
    *pd=val;
    while(*pw&0x80); //now select DAC register back
    *pa=0x2a;	//so it is always selected from Z80 point of view
 
    *pz=0; //run Z80 again
}
Make sure that Z80 code does not attempt to select any register and only writes data.

There are alternatives possible to minimize jitter introduced by this method. For example, you can buffer all the writes from TFC player into an array, then do them all in a single burst, so you only stop and restart Z80 once per frame and minimize the overall time when it is stopped.

sega16
Very interested
Posts: 251
Joined: Sat Jan 29, 2011 3:16 pm
Location: U.S.A.

Post by sega16 » Fri Feb 24, 2012 2:36 pm

What if you add macros that pre-calculate the stuff that normally requires tables but of course this will only work for stuff that has a constant number and will end up with the same result every time any ways and not a variable but for variables if you want you could just do it in software but that may be slightly slower.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Wed Mar 14, 2012 11:35 pm

Shiru wrote: By the way, Stef, it seems that waiting for busreq with while(*ptr&0x100) is incorrect, it should be 1 instead of 0x100. Compare compiled C code with code from any old game - games always check bit 0 while compiled C code with 0x100 checks bit 8. In real programs it works on hardware either way, I guess it is because other code create a large enough delay.
I realized my last modification broke my code, i mis read your initial post and just inverted my test which was incorrect.
Then i had a llok back to officials sega genesis tech stuff and it seems you have to test bit 8 and not bit 0 to ensure that BUS has be taken.
I remember that a lot of game were setting BUSREQ with word operation then testing with byte operation, maybe it's why you saw it tested with bit 0.

sega16
Very interested
Posts: 251
Joined: Sat Jan 29, 2011 3:16 pm
Location: U.S.A.

Post by sega16 » Mon Mar 19, 2012 12:55 am

I have noticed that this function

Code: Select all

void VDP_drawText(const char *str, u16 x, u16 y)
{
    // use A plan & high priority by default
    VDP_drawTextBG(APLAN, str, textBasetile, x, y);
}
just called another function so I commented it out and edited the header and ended up with

Code: Select all

//void VDP_drawText(const char *str, u16 x, u16 y);
#define VDP_drawText(str, x, y) \
VDP_drawTextBG(APLAN, str, textBasetile, x, y);
so that it only calls one function it worked but you have to put

Code: Select all

extern u16 textBasetile;
in (if your project has it) global.h or put it in genesis.h either of those will work.
and at first when I was doing the makelib I got a few errors so I included vdp.h and put the extern mentioned above

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Mon Mar 19, 2012 9:40 am

sega16 wrote:I have noticed that this function

Code: Select all

void VDP_drawText(const char *str, u16 x, u16 y)
{
    // use A plan & high priority by default
    VDP_drawTextBG(APLAN, str, textBasetile, x, y);
}
just called another function so I commented it out and edited the header and ended up with

Code: Select all

//void VDP_drawText(const char *str, u16 x, u16 y);
#define VDP_drawText(str, x, y) \
VDP_drawTextBG(APLAN, str, textBasetile, x, y);
so that it only calls one function it worked but you have to put

Code: Select all

extern u16 textBasetile;
in (if your project has it) global.h or put it in genesis.h either of those will work.
and at first when I was doing the makelib I got a few errors so I included vdp.h and put the extern mentioned above
If GCC was smart enough having inner calls this way would not be a problem as inlining would be automatically applied. Unfortunately GCC 3.4.6 is not inlining anything, even if you specify manually the inline keyword...
Anyway VDP_drawText is not a critical method, you usually don't call it too much and you can always directly call the other method if speed is a problem.

fdarkangel
Interested
Posts: 24
Joined: Sun Dec 17, 2006 8:28 pm
Location: Osaka, Japan

Post by fdarkangel » Sun Mar 25, 2012 7:52 pm

Stef wrote:If GCC was smart enough having inner calls this way would not be a problem as inlining would be automatically applied. Unfortunately GCC 3.4.6 is not inlining anything, even if you specify manually the inline keyword...
The inline keyword is a hint to the compiler. You should specify the always_inline attribute if you want it to be inlined no matter what.

Relevant page from the GCC 3.4.6 manual.

sega16
Very interested
Posts: 251
Joined: Sat Jan 29, 2011 3:16 pm
Location: U.S.A.

Post by sega16 » Mon Mar 26, 2012 2:48 pm

As far as I am aware all inlining would do is copy all the code from VDP_drawTextBG and put it into VDP_drawText but what if you want to call VDP_drawTextBG directly you would end up having two copies of the same code. So with my way it just replaces all the references of VDP_drawText with VDP_drawTextBG and uses the constant perimeters that VDP_drawText had.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Tue Mar 27, 2012 5:59 am

fdarkangel wrote:
Stef wrote:If GCC was smart enough having inner calls this way would not be a problem as inlining would be automatically applied. Unfortunately GCC 3.4.6 is not inlining anything, even if you specify manually the inline keyword...
The inline keyword is a hint to the compiler. You should specify the always_inline attribute if you want it to be inlined no matter what.

Relevant page from the GCC 3.4.6 manual.
Unfortunately inline is just *not supported* in the m68k-elf GCC 3.4.6 whatever the switch you try to specify, this is really a pity as this is the best GCC version for this target (in term of code generation).
To reply to sega16, inlining a function is exactly the same as doing a macro but the function code looks better :)

Post Reply