Page 2 of 3
Posted: Mon Jan 06, 2014 11:48 pm
by Chilly Willy
If you're trying to use 2M mode (one block of 256KB of word ram), you need to request 2M mode from the CD side, then wait for the MD to set 2M mode on it's side, like this
CD side
Code: Select all
andi.b #0xE2,0x8003.w /* Priority Mode = off, 2M mode */
move.b #'I,0x800F.w /* send MD init handshake to MD */
MD side
Code: Select all
| wait for MD init handshake from CD
0:
cmpi.b #'I,0x200F(a5)
bne.b 0b
bset #1,0x2003(a5) /* give Sub-CPU Word RAM */
move.b #'B,0x200E(a5) /* main comm port - do boot */
The CD side would wait for the B to appear to know the ram is now under Sub-CPU control.
If you're trying to use 1M mode (two blocks of 128KB of word ram), you may be using the wrong address.
Also, you need to set an extra register telling the BIOS how the data will be transferred. See page 26 of the CD hardware manual. But in general, if you are using the CPU for the CD data transfer (as opposed to DMA), you do this before reading
Code: Select all
/* set CDC Mode destination device to Sub-CPU */
andi.w #0xF8FF,0x8004.w
ori.w #0x0300,0x8004.w
You have to do that every time through the loop right before CDCREAD. Look at my CD boot code for details on reading ISO9660 discs.
Posted: Tue Jan 07, 2014 10:23 am
by Orion_
ok, after carefully reading the sega cd doc, I found that the WordRam can only be given to sub cpu by main cpu, and sub cpu can only return it to the main cpu.
I thought the wordram could be switched in both direction from both main & sub cpu.
so ... I did some synchronizing to give/get back the word ram between the main/sub cpu like you suggested, and I still got stuck reading info from the main cpu, but it's because in mode1 (booting from cart) the word ram (from main cpu) is also not mapped to $200000, but at $600000 instead ..
now it's fully working !
I can now clean my code, and try to boot a real cd to check this
Posted: Tue Jan 07, 2014 5:02 pm
by Orion_
I Just tried the code on a real mega cd and it's fully working, I'm glad \o/
I made a little trampoline code, so in my maincpu boot code, I load data from cd to word ram, then jump at the end of MD ram, copy the data from word ram to the start of md ram, and jump to the start of md ram, so then my final game program sits in MD ram and have the word ram free to load data from cd =)
I just got something strange:
This little code works perfectly on the megacd hardware, but not on Kega Fusion or Gens emulator
Code: Select all
.waitW:
bset.b #1,$A12003 ; Wait for WordRam to be given to CD SubCPU
bne.s .waitW
For emulator I need to use this code instead:
Code: Select all
lea $A12003,a0
ori.b #2,(a0)
.waitW:
move.b (a0),d0
andi.b #2,d0
beq.s .waitW
I guess this could be a little emu protection code
Posted: Tue Jan 07, 2014 5:11 pm
by l_oliveira
Orion_ wrote:I guess this could be a little emu protection code
You're a little evil ....
But now the trick is exposed ...
Posted: Tue Jan 07, 2014 8:41 pm
by Orion_
I won't make another topic for this but, I have a little problem with the DMA transfer.
When I transfer the data from the wordram to vram using 68k, it works ok (left picture), but when I do DMA to VRAM, I get errors on tile (right picture)
Have you experienced this already ?
My code is executing from the MD Ram, here is my DMA routine:
Code: Select all
TransferDMAtoVRAM: ; d0 = Data Address, d1 = Vram Address, d2 = Data Size
movem.l d3/a0,-(a7)
lea VDP_CTRL,a0
lsr.w #1,d2 ; lenght in word
move.w #$9300,d3
move.b d2,d3 ; low
move.w d3,(a0)
lsr.w #8,d2 ; high
or.w #$9400,d2
move.w d2,(a0)
lsr.l #1,d0 ; address in word
move.w #$9500,d3
move.b d0,d3 ; low
move.w d3,(a0)
lsr.w #8,d0
or.w #$9600,d0 ; mid
move.w d0,(a0)
swap d0
or.w #$9700,d0 ; high
move.w d0,(a0)
move.w d1,d0 ; Tile VRAM address
bsr SetVramAddressDMA
movem.l (a7)+,d3/a0
rts
SetVramAddressDMA: ; d0 = Address
movem.l d1-d2,-(a7)
move.l #$804000,d1
move.w d0,d2 ; Address
and.w #$3FFF,d2 ; Lower Bits
or.w d1,d2 ; Add VDP Command
swap d1
swap d2
move.w d0,d2 ; Address
lsr.w #8,d2
lsr.w #14-8,d2 ; Upper Bits
or.b d1,d2 ; Add VDP Command
move.l d2,VDP_CTRL
movem.l (a7)+,d1-d2
rts
Posted: Tue Jan 07, 2014 9:53 pm
by Nemesis
I'm sure I've read someone else here talk about that before. It seems that the wordram doesn't respond to reads fast enough to keep up with DMA access from the VDP. This results in a phenomenon where the wordram is actually returning data for a previous read when the VDP is attempting to latch data for a later read. It seems to be stable and repeatable from what I've heard, and apart from the returned data being "out of sync" with the DMA, the operation itself works. If you start the DMA operation from the target address in wordram, but write it to 1 word earlier in VRAM than you want it to appear, then let the DMA operation run for 1 word extra, you'll get the result you want, with the exception that you'll have one extra corrupted word transferred to VRAM before your data. You could do a VRAM read operation to retrieve this data, then re-write it from the 68k after your DMA operation completes, in which case, you'll get working DMA from word ram without having to worry about corrupting that single word of data before the target.
Posted: Tue Jan 07, 2014 10:25 pm
by Chilly Willy
Yes, I don't remember where that is in the docs offhand, but Sega recommends setting the SOURCE to one word past the start, doing a DMA of N words, then writing the FIRST word using the CPU. That avoids any corruption in the vram. They even provided a snippet of example code that did that. Now if I could just remember where that was...
Posted: Tue Jan 07, 2014 10:48 pm
by l_oliveira
Chilly Willy wrote:Yes, I don't remember where that is in the docs offhand, but Sega recommends setting the SOURCE to one word past the start, doing a DMA of N words, then writing the FIRST word using the CPU. That avoids any corruption in the vram. They even provided a snippet of example code that did that. Now if I could just remember where that was...
Page 61 of the hardware manual mentions that ... (and a few don't"s" to go along with it at page 62 ...)
Page 63 has source code with an example for a solution.
Posted: Tue Jan 07, 2014 11:15 pm
by Orion_
I remembered a doc from the SVP about setting the DMA to 2 bytes after the start address like on the sega cd.
So I tried and set the DMA Source at Data Address + 2 and it's working !
I can't even see the missing first word of data (at least on emulator, because on my TV the left border is a bit hidden)
Posted: Thu Jan 09, 2014 5:23 pm
by Orion_
I'm trying to play audio track now, I have strange behavior.
When playing the audio track straight from start, it works, but If I try to load data before and then play audio cd, it seems like the cd is reading but no sound output :/
now ... if I keep the lid of the megacd open while my init code is waiting for the cd to be ready, and then I close the lid, then everythings works fine, (load data, play audio, stop, load data, play audio again), that's so strange %)
Posted: Thu Jan 09, 2014 8:45 pm
by Chilly Willy
Are you calling CDCSETMODE when you switch from data to audio and back? You'll notice that my data code calls CDCSETMODE to allow the CD to read mode 1 data. My code for playing tracks doesn't set the mode, but it does init the drive, which leaves it in cdda mode by default on audio discs. For a data disc with cdda tracks, you probably need to explicitly set cdda mode before playing a track.
Posted: Thu Jan 09, 2014 9:04 pm
by Orion_
I can't find a documentation on the CDCSETMODE call (nothing in the sega cd doc)
so I'm calling it with moveq #0,d1 before loading data, but I don't know how to call it for audio.
For Audio I'm doing:
Code: Select all
move.w #$0002,d0 ; MSCSTOP
jsr CDBIOS.w
lea InitParam,a0
move.w #$0010,d0 ; DRVINIT
jsr CDBIOS.w
lea BiosParams,a0
move.w #MSCPLAY1,d0
jsr CDBIOS.w
for data:
Code: Select all
move.w #$0089,d0 ; CDCSTOP
jsr CDBIOS.w
move.w #0,d1 ; Mode 1
move.w #$0096,d0 ; CDCSETMODE
jsr CDBIOS.w
; Set CDC Mode destination device to SubCPU
andi.w #$F8FF,$FFFF8004.w
ori.w #$0300,$FFFF8004.w
lea BiosParams,a0
move.w #$0020,d0 ; ROMREADN
jsr CDBIOS.w
etc...
Posted: Fri Jan 10, 2014 10:29 am
by Orion_
Well, I just burnt a CD to test on the real hardware and it's working ... so I guess I'm ready for making a game now
Posted: Fri Jan 10, 2014 8:18 pm
by Chilly Willy
Code: Select all
;-----------------------------------------------------------------------
; BIOS_CDCSETMODE - Tells the BIOS which mode to read the CD in. Accepts
; bit flags that allow selection of the three basic CD modes as follows:
;
; Mode 0 (CD-DA) 2
; Mode 1 (CD-ROM with full error correction) 0
; Mode 2 (CD-ROM with CRC only) 1
;
; input:
; d1.w FEDCBA9876543210
; ||||
; |||+--> CD Mode 2
; ||+---> CD-DA mode
; |+----> transfer error block with data
; +-----> re-read last data
;
; returns:
; nothing
;-----------------------------------------------------------------------
BIOS_CDCSETMODE macro
CDBIOS #CDCSETMODE
endm
Setting the mode to CDDA should be much better than reseting the drive every time you play a track.
Do you plan on using the PCM chip in the SCD? If so, you might want to look at the pcm library I wrote for the SCD that I posted along with the MOD/Mikmod players. The existing examples of using the PCM chip are all wrong and don't work on real hardware - even Sega's PCM example doesn't work! It took a while for me to figure out how to get real hardware to work; it still works with emulators as well. All that went into the pcm library. It also allows you to use the SCD timer (used by the MOD/Mikmod players for the beat, as an example).
Posted: Fri Jan 10, 2014 8:32 pm
by Orion_
Thank you, I will try this instead
about the pcm lib, I already downloaded it and put it in my "to watch" list, I will try it soon to use it for sfx
Thanks for your work on the megacd and for sharing your source, it was so much helpful !