Multi-processor program structure
Moderator: BigEvilCorporation
-
- Very interested
- Posts: 2984
- Joined: Fri Aug 17, 2007 9:33 pm
-
- Very interested
- Posts: 124
- Joined: Sun Jan 29, 2012 2:10 pm
- Location: North America
- Contact:
In sh2_crt0.s I found where it is being setChilly Willy wrote:My examples normally set FM in one of two places: in the MD init code right before allowing the Master to run, or in the 32X crt0.s Master init code, right after starting the Slave. If you don't find it in one of those two spots, you need to add it.
Code: Select all
! let Slave SH2 run
mov #0,r1
mov.l r1,@(4,r0) /* clear slave status */
mov #0x80,r0
mov.l _master_adapter,r1
mov.b r0,@r1 /* set FM */
mov #0x00,r0
mov.b r0,@(1,r1) /* set int enables */
mov #0x20,r0
ldc r0,sr /* allow ints */
Code: Select all
_master_adapter:
.long 0x20004000
Code: Select all
__m68k_start:
move.b #1,0xA15107 /* set RV */
move.b #2,0xA130F1 /* SRAM disabled, write protected */
move.b #0,0xA15107 /* clear RV */
move.w 0xA15100,d0
or.w #0x8000,d0
move.w d0,0xA15100 /* set FM - allow SH2 access to MARS hw */
move.l #0,0xA15120 /* let Master SH2 run */
lea vert_blank(pc),a0
move.l a0,0xFF0FFC /* set vertical blank interrupt handler */
move.w #0x2000,sr /* enable interrupts */
Since it doesn't distinguish between master/slave when bit is 1, then it should be working right?Access to the 32X VDP
The FM (VDP access authorization) bit number must be 0 before the MEGA Drive can
access the Mars frame buffer, overwrite images, VDP register or color palette. When the
bit is 1, reads are undefined and writes are ignored. Color palette access is words only, not
bytes.
The frame buffer, overwrite image, VDP register, and color palette can be accessed from
the MEGA Drive side only when the FM (VDP access authorization) bit is 0. . When the
bit is 1, reads are undefined and writes are ignored. Color palette access is words only, not
bytes.
-
- Very interested
- Posts: 2984
- Joined: Fri Aug 17, 2007 9:33 pm
-
- Very interested
- Posts: 124
- Joined: Sun Jan 29, 2012 2:10 pm
- Location: North America
- Contact:
Well I am not sure if this was the only problem, I abandoned trying to draw to FB using the slave CPU.
So instead I flipped it around
Master = Handle Input, Draw graphics
Slave = Game logic/screen location calculations
This still didn't work. But that seemed to be a synchronization issue between the slave and master.
When I added a back and forth communication using COMM6 port to gate the slave from entering it's main loop.
Master:
Slave:
This worked! In the sense that the slave did something and could update shared variables correctly! But, this sort of ran "too fast" as the game logic appears to be much less work than drawing all the graphics, so it becomes jerky as the ai updates things too quickly. So I have to artificially slow down the slave's loop using delays, making it's updates a fixed frequency i.e. each slave's while loop iteration takes 3 vcount ticks, so after doing the work in elapsed time of "n" vcount ticks. I have to wait for at most 3 - n more counts if that makes sense. I also use the same COMM6 port to control when the game logic or main updates the shared variables (characters, level state, "camera location", etc..). Don't want to be drawing sprites while updating the characters at the same time!
p.s. how many absolute vcount "ticks" will there be per second in 32X? is it constant?
So instead I flipped it around
Master = Handle Input, Draw graphics
Slave = Game logic/screen location calculations
This still didn't work. But that seemed to be a synchronization issue between the slave and master.
When I added a back and forth communication using COMM6 port to gate the slave from entering it's main loop.
Master:
Code: Select all
main(){
//do ALL init code
...
MARS_SYS_COMM6 = 1; // tells slave to start
while(1){
//handle input
//draw graphics
...
}
}
Code: Select all
slave(){
...
//wait for main to initialize stuff
while (MARS_SYS_COMM6 != 1) ; // wait until master has signaled to start
MARS_SYS_COMM6 = 2; //tell master slave is starting
while(1){
//update game state/logic
...
}
}
p.s. how many absolute vcount "ticks" will there be per second in 32X? is it constant?
-
- Very interested
- Posts: 2984
- Joined: Fri Aug 17, 2007 9:33 pm
Well, it should work the other way around as well. There's really no difference at all between the master and slave other than the master is started first, and then the slave. You could use the slave for everything while the master idles, for example. If I had to guess, you probably had a cache issue somewhere in your code... I do that all the time when trying to use both CPUs with shared variables.ammianus wrote:Well I am not sure if this was the only problem, I abandoned trying to draw to FB using the slave CPU.
So instead I flipped it around
Master = Handle Input, Draw graphics
Slave = Game logic/screen location calculations
This still didn't work. But that seemed to be a synchronization issue between the slave and master.
When I added a back and forth communication using COMM6 port to gate the slave from entering it's main loop.
Master:Slave:Code: Select all
main(){ //do ALL init code ... MARS_SYS_COMM6 = 1; // tells slave to start while(1){ //handle input //draw graphics ... } }
This worked! In the sense that the slave did something and could update shared variables correctly! But, this sort of ran "too fast" as the game logic appears to be much less work than drawing all the graphics, so it becomes jerky as the ai updates things too quickly. So I have to artificially slow down the slave's loop using delays, making it's updates a fixed frequency i.e. each slave's while loop iteration takes 3 vcount ticks, so after doing the work in elapsed time of "n" vcount ticks. I have to wait for at most 3 - n more counts if that makes sense. I also use the same COMM6 port to control when the game logic or main updates the shared variables (characters, level state, "camera location", etc..). Don't want to be drawing sprites while updating the characters at the same time!Code: Select all
slave(){ ... //wait for main to initialize stuff while (MARS_SYS_COMM6 != 1) ; // wait until master has signaled to start MARS_SYS_COMM6 = 2; //tell master slave is starting while(1){ //update game state/logic ... } }
p.s. how many absolute vcount "ticks" will there be per second in 32X? is it constant?
Yes, the SH2's will be WAY TOO FAST for the game logic of many simple games. That's where timing comes in. You can use the ticks for "crude" timing. A tick is every vertical blank, so 50 per second on PAL, and 60 on NTSC. "32x.h" has equates for checking PAL/NTSC as you can see in the slave() init where I set the PWM frequency based on PAL vs NTSC.
For more precise timing, you can use the free-run timers - although SEGA restricted use of the FRTs in the devkit because of a bug in the interrupts on the developer hardware, it should be fine to use the FRTs for your own usage on consumer boards. Most of my examples either init the FRT for nothing, or don't init them at all.
Another timing method is to use the audio period - depending on the number of samples you play, you could have timing based on a DMA block of samples giving anywhere from 20 Hz to 200 Hz.