News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - Stef

Pages: [1]
1
On the same idea than the SF2 patch : http://www.romhacking.net/forum/index.php/topic,18561.0.html
I patched the Super Street Fighter 2 game (megadrive) to fix the sound driver and improve the SFX quality :)
You can find the IPS patch here (for the US version of the game) :
https://dl.dropboxusercontent.com/u/93332624/dev/megadrive/ssf2/SSF2_mod.ips

2
Hi folks,

I also posted it on other forum but it might be better placed it after all :)

I guess everyone know this famous game and its reputation for having scratchy voices. One of my crazy projects i had in mind was to rewrite the Z80 PCM sound driver for this game to improve the voices output as the Megadrive is perfectly able of playing them well, it just requires good programming... something that Capcom never (wanted to) achieved on the Sega Megadrive.

Some days ago i finally decided to get a shoot in that project and i started by disassembling the Z80 driver. I don't know if it has already be made before but i did not found any informations about it...
Anyway i was very surprised by the size of the driver, it's very simple and short (code size = 358 bytes).
So for those who are curious you can see the source code of SF2 Z80 driver at the end of this post.
I commented, equated and modified it a bit (replaced some JR (PC+2) by 3 NOP) to make it more readable.
I even fixed a bug in the driver ! Because of it the channel 2 can miss one sample from time to time, not very important but still it shows how developer was lazy about it. Also the code is definitely not optimized, of course it do not use buffering but even worse, it uses lazy and slow memory access for many thing and never take advantage of SP register.
The loop is 749 cycles length (i do not count special case of new command) which mean the sample rate is about 4.8 Khz.
That is really bad, one of the first driver i wrote (which was not using any buffering) was able to play 2 channels at 14 Khz.

It took me about 3h to reverse engineer the driver, that was the easy part ;) Now what i need to do is to mimic this driver but replacing it by something safe against DMA. I will use the same method i used in my bad apple demo. The idea is to buffer sample from ROM in Z80 ram during the active period and use them to read sample during DMA which should occurs in VBlank period. Problem is that SF2 is extending VBlank a bit and i don't know if DMA is effectly used before the VInt occurs. If that is the case i will have to "count" to find the correct period where i need to stop ROM accesses... Then i will need to patch some 68k code, i guess they disable Z80 during DMA which we should avoid for instance, same for IO access (but not as important).

Ok, that was my initial message to introduce the project and you can find more technical details on Sega-16 forum :
http://www.sega-16.com/forum/showthread.php?28108-Street-Fighter-2-new-Z80-PCM-sound-driver-project

Now the patch is done, i had some hard time in fixing a stupid bug but finally i come with a 100% working version.

Here is the last version of patched rom :
https://dl.dropboxusercontent.com/u/93332624/dev/megadrive/sf2/sf2_mod_v7.bin

And here a video comparing before and after the patch (sorry for the awful quality of the video) :
https://www.youtube.com/watch?v=-iE5GJNkOqs


August 27, 2014, 05:30:43 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Code: [Select]
; BC = bank register

COUNTER     EQU     $1FF0           ; 16 bits counter
COMM_CH0    EQU     $1FFE           ; FF = done, < 80 = SFX ID to play
COMM_CH1    EQU     $1FFF           ; FF = done, < 80 = SFX ID to play

FM_ACCESS   EQU     $1FFD           ; indicate that Z80 is accessing DAC register (00 = ok, 2A = DAC access)

CH0_PRIO    EQU     $1FE0           ; channel 0 priority
CH0_LEN     EQU     $1FE1           ; channel 0 length (2 bytes: LH)
CH0_ADDR    EQU     $1FE3           ; channel 0 address (3 bytes: LMH)

CH1_PRIO    EQU     $1FE8           ; channel 1 priority
CH1_LEN     EQU     $1FE9           ; channel 1 length (2 bytes: LH)
CH1_ADDR    EQU     $1FEB           ; channel 1 address (3 bytes: LMH)

            ORG     $0000

init
            DI                      ; disable ints
            IM      $01             ; set int mode 1
            LD      SP, $1000       ; setup stack

            ld      A,0xff
            ld      (COMM_CH0),a        ; clear command ch 0
            ld      (COMM_CH1),a        ; clear command ch 1

            ld      hl,(0x1001)         ; load empty sample param
            ld      (CH0_ADDR),hl
            ld      (CH1_ADDR),hl
            ld      a,(0x1003)
            ld      (CH0_ADDR+2),a
            ld      (CH1_ADDR+2),a
            ld      bc,0x6000           ; init BC

loop
            ld      hl,(COUNTER)
            inc     hl                  ; inc counter
            ld      (COUNTER),hl        ;                                       =38

do_com0
            ld      a,(COMM_CH0)
            or      a                   ; read command channel 0
            jp      m,do_com1           ; if (a & 0x80) goto do_com1            =27

            ld      l,a                 ; A = SFX ID
            ld      h,0x00
            add     hl,hl
            add     hl,hl
            add     hl,hl
            ex      de,hl
            ld      ix,0x1000
            add     ix,de               ; IX = SFX DATA ADDR                    =+77

            ld      a,(CH0_PRIO)
            ld      e,a                 ; E = old prio
            ld      a,(ix+0)            ; A = new prio                          =+36

            cp      e                   ; if (new_prio > old_prio)
            jr      c,com0_done         ; {                                     =+11/16

            ld      (CH0_PRIO),a        ;   load prio
            ld      l,(ix+4)
            ld      h,(ix+5)
            ld      (CH0_LEN),hl        ;   load lenght
            ld      l,(ix+1)
            ld      h,(ix+2)
            ld      (CH0_ADDR),hl       ;   load address
            ld      a,(ix+3)
            ld      (CH0_ADDR+2),a      ; }                                     =+153

com0_done
            ld      a,0xff
            ld      (COMM_CH0),a        ; command channel 0 done                =+20

do_com1
            ld      a,(COMM_CH1)
            or      a                   ; read command channel 1
            jp      m,set_bank0         ; if (a & 0x80) goto set_bank0          =27

            ld      l,a                 ; A = SFX ID
            ld      h,0x00
            add     hl,hl
            add     hl,hl
            add     hl,hl
            ex      de,hl
            ld      ix,0x1000
            add     ix,de               ; IX = SFX DATA ADDR                    =+77

            ld      a,(CH1_PRIO)
            ld      e,a                 ; E = old prio
            ld      a,(ix+0)            ; A = new prio                          =+36

            cp      e                   ; if (new_prio > old_prio)
            jr      c,com1_done         ; {                                     =+11/16

            ld      (CH1_PRIO),a        ;   load prio
            ld      l,(ix+4)
            ld      h,(ix+5)
            ld      (CH1_LEN),hl        ;   load lenght
            ld      l,(ix+1)
            ld      h,(ix+2)
            ld      (CH1_ADDR),hl       ;   load address
            ld      a,(ix+3)
            ld      (CH1_ADDR+2),a      ; }                                     =+153

com1_done
            ld      a,0xff
            ld      (COMM_CH1),a        ; command channel 1 done                =+20

set_bank0
            ld      hl,(CH0_ADDR)       ; HL = sample 0 addr (ML)
            ld      a,h
            rlca
            ld      (bc),a              ; bank = addr bit 15                    =31

            ld      a,(CH0_ADDR+2)      ; A = sample 0 addr (H)
            ld      (bc),a              ; bank = addr bit 16
            rrca
            ld      (bc),a
            rrca
            ld      (bc),a
            rrca
            ld      (bc),a
            rrca
            ld      (bc),a
            rrca
            ld      (bc),a
            rrca
            ld      (bc),a
            rrca
            ld      (bc),a              ; bank = addr bit 23                    =97

read0
            set     7,h                 ; HL = sample ch0 addr banked
            ld      a,(hl)
            ex      af,af'              ; A' = sample ch0                       =19

set_bank1
            ld      hl,(CH1_ADDR)       ; HL = sample 1 addr (ML)
            ld      a,h
            rlca
            ld      (bc),a              ; bank = addr bit 15                    =31

            ld      a,(CH1_ADDR+2)      ; A = sample 1 addr (H)
            ld      (bc),a              ; bank = addr bit 16
            rrca
            ld      (bc),a
            rrca
            ld      (bc),a
            rrca
            ld      (bc),a
            rrca
            ld      (bc),a
            rrca
            ld      (bc),a
            rrca
            ld      (bc),a
            rrca
            ld      (bc),a              ; bank = addr bit 23                    =97

read1
            set     7,h                 ; HL = sample ch1 addr banked           =8

            ld      de,FM_ACCESS
            ld      a,0x2a
            ld      (de),a              ; indicate Z80 is accessing YM DAC register
            ld      (0x4000),a          ; prepare DAC write                     =37

mix
            ex      af,af'              ; A = sample ch0 (7 bits)
            add     a,(hl)              ; A = mixed sample (8 bits)
            rra                         ; A = mixed sample (7 bits)
            ld      (0x4001),a          ; write sample to DAC                   =28

            xor     a
            ld      (de),a              ; Z80 release YM access                 =11

update0
            ld      hl,(CH0_LEN)        ; HL = ch0.len
            ld      a,h
            or      l                   ; if (ch0.len == 0)
            jr      z,play_fixed0       ;   goto play_fixed0                    =31

            dec     hl
            ld      (CH0_LEN),hl        ; ch0.len--
            ld      a,h
            or      l                   ; if (ch0.len == 0)
            jr      z,play_done0        ;   goto play_done0                     =37

            ld      hl,CH0_ADDR
            inc     (hl)                ; ch0.addr.l++
            jr      nz,play_done0_1                                             =28

            ld      hl,(CH0_ADDR+1)
            inc     hl                  ; ch0.addr.mh++
            ld      (CH0_ADDR+1),hl
            jp      update1             ; goto update1                          =48

play_fixed0
            ld      a,0x05
play_f0_wait
            dec     a
            jr      nz,play_f0_wait                                             =+87+5

            nop                         ; waste some cycles
            jr      update1             ; goto update_ch1                       =+16

play_done0
            xor     a
            ld      (CH0_PRIO),a        ; no more playing ch0
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            jr      update1             ; waste some cycles                     =+61+5

play_done0_1
            ld      a,0x00
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop                         ; waste some cycles                     =+43+5

update1
            ld      hl,(CH1_LEN)        ; HL = ch1.len
            ld      a,h
            or      l                   ; if (ch1.len == 0)
            jr      z,play_fixed1       ;   goto play_fixed1                    =31

            dec     hl
            ld      (CH1_LEN),hl        ; ch1.len--
            ld      a,h
            or      l                   ; if (ch1.len == 0)
            jr      z,play_done1        ;   goto play_done1                     =37

            ld      hl,CH1_ADDR
            inc     (hl)                ; ch1.addr.l++
            jr      nz,play_done0_1                                             =28

            ld      hl,(CH1_ADDR+1)
            inc     hl                  ; ch1.addr.mh++
            ld      (CH1_ADDR+1),hl
            jp      next                ; goto next                             =48
; note that in the original driver it was jumping to 'update1' instead
; that is probably a copy/paste bug and lead to some missed sample

play_fixed1
            ld      a,0x05
play_f1_wait
            dec     a
            jr      nz,play_f1_wait                                             =+87+5

            nop                         ; waste some cycles
            jr      next                ; goto next                             =+16

play_done1
            xor     a
            ld      (CH1_PRIO),a        ; no more playing ch1
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            jr      next                ; waste some cycles                     =+61+5

play_done1_1
            ld      a,0x00
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop                         ; waste some cycles                     =+43+5

next
            jp loop                                                             =10

                                        ; total cycles per loop = 749 ~ 4.8 Khz

            BLOCK   $1000-$

; SFX DATA
; --------
; format : PP AA AA AA LL LL 00 00
; PP = priority
; AA = address (LMH)
; LL = length (LH)
;
; 001000    00 00 00 28 52 05 00 00         SFX 0
;           00 52 05 28 e7 0d 00 00         SFX 1
; 001010    00 39 13 28 b9 05 00 00         .....
;           00 f2 18 28 ca 05 00 00
; 001020    00 bc 1e 28 d1 06 00 00 00 8d 25 28 97 05 00 00
; 001030    00 24 2b 28 c8 05 00 00 00 ec 30 28 fe 06 00 00
; ...
; 0013f0    ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
;
; NOT USED
; 001400    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
; ...

; VARIABLES
; 001fe0    00 00 00 00 00 28 00 00 00 00 00 00 00 28 00 00
; 001ff0    53 30 00 00 00 00 00 00 00 00 00 00 00 00 ff ff

3
Programming / SGDK - Sega Genesis Development Kit
« on: December 17, 2012, 05:26:27 pm »
SGDK is a small development kit for the Sega Megadrive / Genesis system.
It exists since a bit of time now and becomes advanced enough to deserve a bit of promotion ^^

It's divided in 2 parts :
- GCC compiler & tools binaries (only for Windows platform currently, sorry for osx and linux users).
- Development library sources which provide facilities to develop on the Sega Megadrive/Genesis System.

I tried to keep only the strict minimum GCC binaries so the whole archive maintains a reasonable size (< 10 MB).

Download it here : http://code.google.com/p/sgdk/

You can find some tutorials about how use it in the Wiki section of project's page.
Free feel to post issues or requests, also if you want to contribute in some way you can contact me on the project page :)

Don't hesitate to post bugs or feature request in the issues tracker :
http://code.google.com/p/sgdk/issues/list


Version 0.93b changes log:

* Fixed a stupid bug in deprecated memory functions.
* Added Bitmap structure for easier bitmap manipulation (created from .bmp resources).
* Modified Plan A & Plan B location in VRAM.
* Added methods to modify Plan A, Plan B, Window, Sprites list and H Scroll table in VRAM.
Note that doing that you may have troubles with SGDK methods which use hardwired locations.
* VDP_setSpritesDirect(..) method so you can now send a SpriteDef array buffer directly to the VDP.
* Handle a new resource type : WAVPCM (.wavpcm)
The file is transformed to adpcm data and can be played directly through the 2 channels ADPCM driver.
Note that WAV sample rate should be at least equals to 22050 Hz.
* Fixed a bug in bintos tool.
* New wavtoraw tool, source is provided.
* Added tools sources.


Version 0.93 changes log:

* Simplified memory set/copy methods :
- 'Fastxxx' methods are now deprecated as basic generic methods are now optimized.
- 'memcpy' is now the only memory copy method.
* Added Z80 VGM driver (thanks to Sigflup which originally wrote it and to kubilus1 which improved it).
* Added SRAM support (thanks to Chilly Willy)
* Added preliminary support for ROM > 4MB (you can at least compile them now).
* Improved support for waitTick(..) and waitSubTick(..) calls during VBlank (still inaccurate).
* Added methods to get/set scrolling mode :
- VDP_getHorizontalScrollingMode()
- VDP_getVerticalScrollingMode()
- VDP_setScrollingMode(u16 hscroll, u16 vscroll)
- VDP_setHorizontalScroll(u16 plan, u16 value)
- VDP_setHorizontalScrollTile(u16 plan, u16 tile, u16* values, u16 len)
- VDP_setHorizontalScrollLine(u16 plan, u16 line, u16* values, u16 len)
- VDP_setVerticalScroll(u16 plan, u16 value)
- VDP_setVerticalScrollTile(u16 plan, u16 tile, u16* values, u16 len)
* Added methods to set/fill tile by index :
- VDP_clearTileMapRectByIndex(u16 plan, u16 ind, u16 num, u8 use_dma)
- VDP_fillTileMapRectIncByIndex(u16 plan, u16 basetile, u16 ind, u16 num)
- VDP_fillTileMapRectByIndex(u16 plan, u16 tile, u16 ind, u16 num)
- VDP_setTileMapByIndex(u16 plan, u16 tile, u16 ind)
- VDP_setTileMapRectByIndex(u16 plan, const u16 *data, u16 ind, u16 num, u8 use_dma)
- VDP_setTileMapRectExByIndex(u16 plan, const u16 *data, u16 baseindex, u16 baseflags, u16 ind, u16 num)
* Improved boot code so it should now init correctly on real hardware.
* Fixed Z80 driver uploading which may fails on real hardware in some condition.
* Modified 'sound' sample to add VGM play example.
* Minors fixes, improvements and cleanup.
* Some refactoring.

Pages: [1]