- Group:
- Tech Member: Tech Members
- Active Posts:
- 748 (0.33 per day)
- Most Active In:
- Technical Discussion (188 posts)
- Joined:
- 10-April 09
- Profile Views:
- 4491
- Last Active:
Feb 07 2015 07:30 PM- Currently:
- Offline
My Information
- Age:
- 49 years old
- Birthday:
- August 24, 1965
- Gender:
-
Male
Contact Information
- E-mail:
- Private
- Website:
-
http://groups.google.com/group/chilly-willys-ice-flow/?hl=en
Previous Fields
- Project:
- Doom 32X
- National Flag:
- None
Latest Visitors
-
Super Egg 
16 Jun 2015 - 22:23 -
Shockwave 
13 Apr 2015 - 14:50 -
Varion Icaria 
16 Nov 2014 - 00:44 -
Eric Wright 
02 Oct 2014 - 13:32 -
nineko 
24 Aug 2014 - 08:02
Topics I've Started
-
Supporting HINT vector for 32X
03 October 2012 - 04:11 PM
The 32X emulation doesn't support changing the HINT vector ($70). This is how you add it to r7:
Edit mem_m68k_32x.asm, change the first lines of the write tables so it looks like this
global SYM(_32X_M68K_Write_Byte_Table) SYM(_32X_M68K_Write_Byte_Table): dd M68K_Write_Byte_Bios_32X, ; 0x000000 - 0x0FFFFF dd M68K_Write_Bad, ; 0x100000 - 0x1FFFFF dd M68K_Write_Byte_SRAM, ; 0x200000 - 0x2FFFFF dd M68K_Write_Bad, ; 0x300000 - 0x3FFFFF dd M68K_Write_Bad, ; 0x400000 - 0x4FFFFF dd M68K_Write_Bad, ; 0x500000 - 0x5FFFFF dd M68K_Write_Bad, ; 0x600000 - 0x6FFFFF dd SYM(M68K_Write_Byte_32X_FB0), ; 0x700000 - 0x7FFFFF dd SYM(M68K_Write_Byte_32X_FB1), ; 0x800000 - 0x8FFFFF dd M68K_Write_Bad, ; 0x900000 - 0x9FFFFF dd M68K_Write_Byte_Misc_32X, ; 0xA00000 - 0xAFFFFF dd M68K_Write_Bad, ; 0xB00000 - 0xBFFFFF dd M68K_Write_Byte_VDP, ; 0xC00000 - 0xCFFFFF dd M68K_Write_Bad, ; 0xD00000 - 0xDFFFFF dd M68K_Write_Byte_Ram, ; 0xE00000 - 0xEFFFFF dd M68K_Write_Byte_Ram, ; 0xF00000 - 0xFFFFFF global SYM(_32X_M68K_Write_Word_Table) SYM(_32X_M68K_Write_Word_Table): dd M68K_Write_Word_Bios_32X, ; 0x000000 - 0x0FFFFF dd M68K_Write_Bad, ; 0x100000 - 0x1FFFFF dd M68K_Write_Word_SRAM, ; 0x200000 - 0x2FFFFF dd M68K_Write_Bad, ; 0x300000 - 0x3FFFFF dd M68K_Write_Bad, ; 0x400000 - 0x4FFFFF dd M68K_Write_Bad, ; 0x500000 - 0x5FFFFF dd M68K_Write_Bad, ; 0x600000 - 0x6FFFFF dd SYM(M68K_Write_Word_32X_FB0), ; 0x700000 - 0x7FFFFF dd SYM(M68K_Write_Word_32X_FB1), ; 0x800000 - 0x8FFFFF dd M68K_Write_Bad, ; 0x900000 - 0x9FFFFF dd M68K_Write_Word_Misc_32X, ; 0xA00000 - 0xAFFFFF dd M68K_Write_Bad, ; 0xB00000 - 0xBFFFFF dd M68K_Write_Word_VDP, ; 0xC00000 - 0xCFFFFF dd M68K_Write_Bad, ; 0xD00000 - 0xDFFFFF dd M68K_Write_Word_Ram, ; 0xE00000 - 0xEFFFFF dd M68K_Write_Word_Ram, ; 0xF00000 - 0xFFFFFF
Then add this right before M68K_Write_Byte_Misc_32X
align 64 M68K_Write_Byte_Bios_32X: cmp ebx, 0x74 jae short .bad cmp ebx, 0x70 jb short .bad xor ebx, byte 1 mov [SYM(_32X_Genesis_Rom) + ebx], al pop ecx pop ebx ret align 16 .bad: pop ecx pop ebx ret align 16 M68K_Write_Byte_Misc_32X:
and this right before M68K_Write_Word_Misc_32X
align 64 M68K_Write_Word_Bios_32X: cmp ebx, 0x74 jae short .bad cmp ebx, 0x70 jb short .bad mov [SYM(_32X_Genesis_Rom) + ebx], ax pop ecx pop ebx ret align 16 .bad: pop ecx pop ebx ret align 16 M68K_Write_Word_Misc_32X:
It then passes the HINT vector test in the 32X check rom.
There's also a bug in the byte read bios code... it uses 3FF as the mask and 400 as the comparison when it should be FF and 100, like this
M68K_Read_Byte_Bios_32X: and ebx, 0xFF xor ebx, byte 1 mov al, [SYM(_32X_Genesis_Rom) + ebx] pop ebx ret align 16 M68K_Read_Byte_BiosR_32X: cmp ebx, 0x100 jae short .Rom xor ebx, byte 1 mov al, [SYM(_32X_Genesis_Rom) + ebx] pop ebx ret
It's right for word reads, just goofed up for byte reads. -
Interrupt-Driven DMA PWM on the 32X
26 September 2012 - 12:08 AM
This is how you do interrupt driven DMA PWM audio on the 32X. The first thing to ask is, why? If you wish to do more than just audio on the slave sh2, you need to make your audio code interrupt driven. That way when you do something that takes a long time, the audio will interrupt the task as needed to generate audio. Otherwise you are stuck trying to break the tasks into small enough pieces that it doesn't interfere with your polled audio. With DMA'd buffers, that is a decent amount of time, but not enough for some things.
This method works on real hardware and on Fusion 3.64 (remember that 3.63 sounds like crap). If you use Gens/GS release 7 with my DMA PWM modifications, you need to make one more change to pwm.c to use int-driven dma pwm:
Change this
if (PWM_Mode & 0x0080) { // RPT => generate DREQ1 as well as INT SH2_DMA1_Request(&M_SH2, 1); SH2_DMA1_Request(&S_SH2, 1); }
to this
if (PWM_Mode & 0x0080) { // RPT => generate DREQ1 as well as INT SH2_DMA1_Request(&M_SH2, 1); SH2_DMA1_Request(&S_SH2, 1); if ((SH2_Read_Long(&S_SH2, 0xFFFFFF9C) & 7) == 7) SH2_Interrupt_Internal(&S_SH2, (SH2_Read_Long(&S_SH2, 0xFFFFFFA8)<<8) | ((SH2_Read_Word(&S_SH2, 0xFFFFFEE2) >> 8) & 0x000F)); }
So how do we do interrupt driven dma pwm audio? First, assign the dma an exception entry in the exception table... I suggest the exception right after the autovectors since it's the first free entry not used by anything else, and easy to find. So your table looks like this at the end:
.long slave_pwm /* PWM interupt (Level 6 & 7) */ .long slave_cmd /* Command interupt (Level 8 & 9) */ .long slave_hbi /* H Blank interupt (Level 10 & 11 */ .long slave_vbi /* V Blank interupt (Level 12 & 13) */ .long slave_rst /* Reset Button (Level 14 & 15) */ .long slave_dma1 /* DMA1 TE INT */
Make sure you're using the slave table, not the master. Now you need the code for that exception.
!----------------------------------------------------------------------- ! Slave DMA 1 TE INT handler !----------------------------------------------------------------------- slave_dma1: ! save registers sts.l pr,@-r15 mov.l r0,@-r15 mov.l r1,@-r15 mov.l r2,@-r15 mov.l r3,@-r15 mov.l r4,@-r15 mov.l r5,@-r15 mov.l r6,@-r15 mov.l r7,@-r15 mov.l sd1_handler,r0 jsr @r0 nop ! restore registers mov.l @r15+,r7 mov.l @r15+,r6 mov.l @r15+,r5 mov.l @r15+,r4 mov.l @r15+,r3 mov.l @r15+,r2 mov.l @r15+,r1 mov.l @r15+,r0 lds.l @r15+,pr rte nop .align 2 sd1_handler: .long _slave_dma1_handler
We push the registers that aren't saved by C, then call the C function, slave_dma1_handler(). Before I talk about that function, we need to see how to set up the dma in the slave code.
void slave(void) { uint16_t sample, ix; // init DMA SH2_DMA_SAR0 = 0; SH2_DMA_DAR0 = 0; SH2_DMA_TCR0 = 0; SH2_DMA_CHCR0 = 0; SH2_DMA_DRCR0 = 0; SH2_DMA_SAR1 = 0; SH2_DMA_DAR1 = 0x20004034; // storing a long here will set left and right SH2_DMA_TCR1 = 0; SH2_DMA_CHCR1 = 0; SH2_DMA_DRCR1 = 0; SH2_DMA_DMAOR = 1; // enable DMA SH2_DMA_VCR1 = 72; // set exception vector for DMA channel 1 SH2_INT_IPRA = (SH2_INT_IPRA & 0xF0FF) | 0x0F00; // set DMA INT to priority 15 // init the sound hardware MARS_PWM_MONO = 1; MARS_PWM_MONO = 1; MARS_PWM_MONO = 1; if (MARS_VDP_DISPMODE & MARS_NTSC_FORMAT) MARS_PWM_CYCLE = (((23011361 << 1)/SAMPLE_RATE + 1) >> 1) + 1; // for NTSC clock else MARS_PWM_CYCLE = (((22801467 << 1)/SAMPLE_RATE + 1) >> 1) + 1; // for PAL clock MARS_PWM_CTRL = 0x0185; // TM = 1, RTP, RMD = right, LMD = left sample = SAMPLE_MIN; /* ramp up to SAMPLE_CENTER to avoid click in audio (real 32X) */ while (sample < SAMPLE_CENTER) { for (ix=0; ix<(SAMPLE_RATE*2)/(SAMPLE_CENTER - SAMPLE_MIN); ix++) { while (MARS_PWM_MONO & 0x8000) ; // wait while full MARS_PWM_MONO = sample; } sample++; } // initialize mixer MARS_SYS_COMM6 = MIXER_UNLOCKED; // sound subsystem running fill_buffer(&snd_buffer[0]); // fill first buffer slave_dma1_handler(); // start DMA SetSH2SR(2); while (1) { if (MARS_SYS_COMM4 == SSH2_WAITING) continue; // wait for command // do command in COMM4 // done MARS_SYS_COMM4 = SSH2_WAITING; } }
Notice that the VCR for DMA1 is set to 72. That's that exception vector we added to the slave table. Notice that IPRA bits 12 to 8 are set to 0xF (15). That's the exception priority. Tailor that to your needs knowing that CMD is 8, HBlank is 10, VBlank is 12, and the reset button is 14. Other than that, we do a "standard" set up of the audio. We fill the first buffer and call the handler to start off the dma. After that, the transfer-end dma interrupt will continue the process. We then fall in a loop where we look at COMM4 for a command from the Master SH2 or 68K. That's where you stick any tasks that take a long time for the slave to do. Those tasks may/will be interrupted by the dma interrupt as needed to fill buffers and start the next dma operation.
So how about that exception function?
void slave_dma1_handler(void) { static int32_t which = 0; while (MARS_SYS_COMM6 == MIXER_LOCK_MSH2) ; // locked by MSH2 SH2_DMA_CHCR1; // read TE SH2_DMA_CHCR1 = 0; // clear TE if (which) { // start DMA on first buffer and fill second SH2_DMA_SAR1 = ((uint32_t)&snd_buffer[0]) | 0x20000000; SH2_DMA_TCR1 = num_samples; // number longs SH2_DMA_CHCR1 = 0x18E5; // dest fixed, src incr, size long, ext req, dack mem to dev, dack hi, dack edge, dreq rising edge, cycle-steal, dual addr, intr enabled, clear TE, dma enabled fill_buffer(&snd_buffer[MAX_NUM_SAMPLES * 2]); } else { // start DMA on second buffer and fill first SH2_DMA_SAR1 = ((uint32_t)&snd_buffer[MAX_NUM_SAMPLES * 2]) | 0x20000000; SH2_DMA_TCR1 = num_samples; // number longs SH2_DMA_CHCR1 = 0x18E5; // dest fixed, src incr, size long, ext req, dack mem to dev, dack hi, dack edge, dreq rising edge, cycle-steal, dual addr, intr enabled, clear TE, dma enabled fill_buffer(&snd_buffer[0]); } which ^= 1; // flip audio buffer }
Note that read TE/clear TE set of lines - those are REQUIRED for dma interrupts to occur properly. Took a while to figure that out. Then it's merely a matter of starting the next DMA on the proper buffer, then calling fill_buffer on the other buffer. We're then done until the next interrupt.
See how easy that is?
Here is the full source code. There is an arc with my current linker scripts for the compiler, an arc with the xm player library and converter tool, and an arc with the 32X code:
ldscripts-32X.7z
libxmp-v1.1.7z
xmplayer-v1.1
The resultant binaries:
xmp-Doom-Wolf3D.zip
UP/DOWN immediately goes to the previous/next songs, LEFT/RIGHT changes the volume down/up (it starts at max volume), and START pauses/resumes.
If you have any questions, be sure to ask. -
32X and Mode 1
23 February 2012 - 04:04 PM
I ran into an interesting quirk the other day. I was adding CD sound to my 32X projects and found that Mode 1 doesn't work with the 32X in any emulator. It works fine on real hardware. When RV=0, the SCD is present at 0x400000 to 0x7FFFFFF just like in Genesis mode (no 32X), and you can use the SCD exactly the same as with the Genesis. Here's a version of my Wolf32X that inits the CD for mode 1, and plays tracks off the CD. It works great on real hardware.
http://www.fileden.c...de1-20120223.7z
You can use any CD with at least 27 tracks, but if you want to use the tracks from here, you need to reorder the tracks like this:
Quote
00_-_Wolfenstein_3D_-_DOS_-_Enemy_Around_the_Corner.ogg
01_-_Wolfenstein_3D_-_DOS_-_Into_the_Dungeons.ogg
02_-_Wolfenstein_3D_-_DOS_-_The_March_to_War.ogg
03_-_Wolfenstein_3D_-_DOS_-_Get_Them_Before_They_Get_You.ogg
04_-_Wolfenstein_3D_-_DOS_-_Pounding_Headache.ogg
05_-_Wolfenstein_3D_-_DOS_-_Hitler_Waltz.ogg
06_-_Wolfenstein_3D_-_DOS_-_Kill_the_S.O.B..ogg
07_-_Wolfenstein_3D_-_DOS_-_Horst-Wessel-Lied.ogg
08_-_Wolfenstein_3D_-_DOS_-_Nazi_Anthem.ogg
09_-_Wolfenstein_3D_-_DOS_-_P.O.W..ogg
10_-_Wolfenstein_3D_-_DOS_-_Salute.ogg
11_-_Wolfenstein_3D_-_DOS_-_Searching_For_the_Enemy.ogg
12_-_Wolfenstein_3D_-_DOS_-_Suspense.ogg
13_-_Wolfenstein_3D_-_DOS_-_Victors.ogg
14_-_Wolfenstein_3D_-_DOS_-_Wondering_About_My_Loved_Ones.ogg
15_-_Wolfenstein_3D_-_DOS_-_Funk_You!.ogg
16_-_Wolfenstein_3D_-_DOS_-_End_of_Level.ogg
17_-_Wolfenstein_3D_-_DOS_-_Going_After_Hitler.ogg
18_-_Wolfenstein_3D_-_DOS_-_Lurking....ogg
19_-_Wolfenstein_3D_-_DOS_-_The_Ultimate_Challenge.ogg
20_-_Wolfenstein_3D_-_DOS_-_The_Nazi_Rap.ogg
21_-_Wolfenstein_3D_-_DOS_-_Zero_Hour.ogg
22_-_Wolfenstein_3D_-_DOS_-_Twelfth_Hour.ogg
23_-_Wolfenstein_3D_-_DOS_-_Roster.ogg
24_-_Wolfenstein_3D_-_DOS_-_U_R_A_Hero.ogg
25_-_Wolfenstein_3D_-_DOS_-_Victory_March.ogg
26_-_Wolfenstein_3D_-_DOS_-_Wolf_Pac.ogg
For SoD from here, reorder the tracks like this:
Quote
00_-_Spear_of_Destiny_-_DOS_-_Funkie_Colonel_Bill.ogg
01_-_Spear_of_Destiny_-_DOS_-_Into_the_Dungeons.ogg
02_-_Spear_of_Destiny_-_DOS_-_Death_to_the_Nazis.ogg
03_-_Spear_of_Destiny_-_DOS_-_Get_Them_Before_They_Get_You.ogg
04_-_Spear_of_Destiny_-_DOS_-_Tiptoeing_Around.ogg
05_-_Spear_of_Destiny_-_DOS_-_Going_After_Hitler.ogg
06_-_Spear_of_Destiny_-_DOS_-_U_R_A_Hero.ogg
07_-_Spear_of_Destiny_-_DOS_-_Is_This_THE_END.ogg
08_-_Spear_of_Destiny_-_DOS_-_Nazi_Anthem.ogg
09_-_Spear_of_Destiny_-_DOS_-_P.O.W..ogg
10_-_Spear_of_Destiny_-_DOS_-_Twelfth_Hour.ogg
11_-_Spear_of_Destiny_-_DOS_-_Searching_For_the_Enemy.ogg
12_-_Spear_of_Destiny_-_DOS_-_Suspense.ogg
13_-_Spear_of_Destiny_-_DOS_-_Zero_Hour.ogg
14_-_Spear_of_Destiny_-_DOS_-_Wondering_About_My_Loved_Ones.ogg
15_-_Spear_of_Destiny_-_DOS_-_The_Ultimate_Challenge.ogg
16_-_Spear_of_Destiny_-_DOS_-_End_of_Level.ogg
17_-_Spear_of_Destiny_-_DOS_-_Evil_Incarnate.ogg
18_-_Spear_of_Destiny_-_DOS_-_Jazzin'_Them_Nazis.ogg
19_-_Spear_of_Destiny_-_DOS_-_Hitler_Waltz.ogg
20_-_Spear_of_Destiny_-_DOS_-_Award_Ceremony.ogg
21_-_Spear_of_Destiny_-_DOS_-_Puttin'_It_to_the_Enemy.ogg
22_-_Spear_of_Destiny_-_DOS_-_The_SS_Gonna_Get_You.ogg
23_-_Spear_of_Destiny_-_DOS_-_The_Tower.ogg -
Time to update to gcc 4.6.2
13 February 2012 - 01:37 AM
Building a Genesis/32X toolchain
1 - Go here and download the following:
gcc-4.6.2.tar.bz2
Decompress it to wherever you keep your projects; you should end up with a folder called gcc-4.6.2.
2.1 - Go here and download mpfr-2.4.2.tar.bz2.
2.2 - Go here and download mpc-0.9.tar.gz.
2.3 - Go here and download gmp-5.0.4.tar.bz2.
Decompress them all in the same folder. You should have three folders called mpfr-2.4.2, mpc-0.9, and gmp-5.0.4. Rename them to get rid of the version numbers, leaving you with mpfr, mpc, and gmp. Copy them into the gcc-4.6.2 folder.
3 - Go here and download binutils-2.22.tar.bz2.
Decompress it in the same folder as the gcc folder so that you have two folders - gcc-4.6.2 and binutils-2.22.
4 - Go here and download newlib-1.20.0.tar.gz.
Decompress it in the same folder as gcc and binutils, leaving you with the folders - gcc-4.6.2, binutils-2.22, and newlib-1.20.0.
5 - Get this archive and decompress it to the same place as the previous directories. You should have two more directories, bin and ldscripts, in addition to the file, makefile-sega.
6 - If you wish to leave the makefile with the default path of /opt/toolchains/sega, make sure you have permission to write to /opt or the toolchain will fail to install to the path. Since there's nothing critical in /opt, it's easiest just to do "sudo chmod 777 -R /opt" which allows anyone to do anything they want in /opt.
7 - Run "make -f makefile-sega" - depending on the speed of your computer, in an hour or two you should have two toolchains in /opt/toolchains/sega: m68k-elf and sh-elf. Copy the ldscripts and bin directories to /opt/toolchains/sega.
You now have the latest gcc, binutils, and newlib for both the 68000 and the SH2. Both have compilers for C, C++, Objective-C, and Objective-C++. The bin directory has a few common tools one might use for compiling Z80 code for the MD. Copy whatever other tools you use into it, like sixpack or bin2c.
Note: The size of the built toolchain can be reduced by stripping the debug symbols from the executables in the bin directories, and by deleting the libraries meant for CPUs other than the 68000 and SH2. For example, you don't need the libraries for the 68020 or 68040 or SH3 or SH4, etc.
Here is an archive with example code - it includes Tic-Tac-Toe in both C and C++ for both the MD and the 32X. You should be able to compile them with the toolchain you just built. They should run on an emulator like Kega Fusion or Gens/GS, or on a real MD/32X with a flash cart.
Here are a few archives of things I've built for the 32X using the toolchain. They should all build and run fine using this toolchain.
32xrick-20120212.7z
Wolf32X-20120212.7z
TremorTest-20120212.7z
yeti3d-20120212.7z
Here is an archive with three libraries. You will need them for the Tremor example. Build them BEFORE trying to build the Tremor test. Be sure to run "make install" to install the libraries into the toolchain so it can find them.
Note: You don't need to set any environment variables for this toolchain as long as you use the default path for the toolchain (/opt/toolchains/sega). The examples and games come with a binary image for people who wish to try them without needing to build anything. -
SEGA CD Mode 1 Player
16 December 2011 - 09:26 PM
There's been a lot of talk since the release of Sonic 1 with Redbook Audio, mainly people asking for code. I can see why they might not want to post their code since it's probably hacked into Sonic 1 pretty bad. However, there still exists a need to show how to use Mode 1. To that end, I did a small demo - this is a tiny CD player done using Mode 1 of the SEGA CD, and includes full source. From this, you should get a good idea of how Mode 1 works. If not, ask questions in the thread here and I'll answer them. THIS is the place for Mode 1 questions, not the Sonic1Mode1 thread.
The project was compiled with my gcc toolchain, but it wouldn't take much work to convert the code to whatever you normally use. The player goes beyond what you would use in a game, but it's an example.
Controls:
A - play from current track to end of disc
B - play current track once
C - stop playing
X - show current track info
Y - play current track repeatedly
Z - pause/resume
START - check disc
Notes: The TOC is invalid until you check the disc. The CDBIOS doesn't initialize its TOC until you call DRVINIT (which is what my check disc routine does). So when you first start the player, the status may show wildly wrong disc info (first and last tracks being over 99, e.g.). If the tray/lid is open, it will show that. Insert a disc and press START - you should get proper disc info after the status is done showing "Reading TOC" and goes to "PAUSED". The current track may not be the same as the playing track - you can start a track playing and then change the "current" track to something else. Pressing X to see the track info shows the info for the current track displayed on the screen, not the track playing. The track info consists of the track time and track type; the track type is pretty straightforward - it's either a DATA track (track 1 of mixed mode discs), or a CDDA track for audio tracks. The track time shows the BCD minutes/seconds/frames/track number as MMSSFFTN. It shows where the track starts, while the track number is the same as the track number you asked for info on, or 00 is an error occured.
While this example is a CD audio player, I could have easily also read data discs, showing sector data. I did the audio player since that's mainly what people wanted - to see how to play CDDA from a game in rom. The Sub-CPU program is really simple - wait for commands from the Main-CPU, then do them. The commands all pertain to handling the CD audio, but they could as easily use the ASIC, use the PCM chip, read data from sectors, etc. When I start doing some ASIC tests, this will be the test bed to start from as it's easier for me to write the test file to SD card and run in Mode 1 than to keep burning CDRs.
I've tested this on a Model 2 Genesis + Model 2 CD and on a CDX. Let me know if you have any trouble on other models, but it SHOULD work on anything.
mode1player.zip
Update - 20111219: Should work WonderMega and X'Eye and might work on LaserActive; also inits drive on startup if a disc is in place from the start.
mode1player2.zip
Update - 20111228: It's been tried on the LaserActive and doesn't work. Still looking into the issue there, but it's currently the only system known not to work.
Update - 20120105: Now works with LaserActive.
Mode1Example-20120104.zip
Friends
Chilly Willy hasn't added any friends yet.

Find My Content
Feb 07 2015 07:30 PM
Male