SNES dev newbie questions

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
tepples
Posts: 22861
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: SNES dev newbie questions

Post by tepples »

If you can think of a good place to split it, send me a PM.
User avatar
juef
Posts: 67
Joined: Thu Jul 15, 2010 8:20 am
Location: Québec, Canada

Re: SNES dev newbie questions

Post by juef »

Well, most of the questions I have been asking were about SNES initalisation, so perhaps the topic should simply be renamed. I can't say I understand all of this, but I haven't studied how DMA works at all yet. Thanks everyone for contributing to the discussion, I am learning a lot.
doppelganger
Posts: 183
Joined: Tue Apr 05, 2005 7:30 pm

Re: SNES dev newbie questions

Post by doppelganger »

koitsu wrote: I've read this paragraph 4 times now, and it's bloody confusing. I can't reliably say I understand what it means, specifically the phrases "attempting a DMA from WRAM to this register" and "attempting a DMA from this register to WRAM". The only conclusion I've been able to reach is that the author of those lines is trying to say "Don't use general DMA to read from banks $7e/7f + write to $2180, and don't use general DMA to read from $2180 + write to banks $7e/7f", and if that's the case, then I can see some legitimacy in that.

But neither case is what my code was doing. The code uses general DMA to read from $000000 (fixed address) and writes to $2180. I'm aware of the RAM mirroring (banks $00-3f, ranges $0000-1fff, from banks $7e/7f). If what you're saying is that the above code won't work, then that brings into question byuu's statement that general DMA can be used to clear WRAM.

It's really good that we're discussing all this and probably confusing the hell out of the OP. *rolls eyes*
The paragraph is saying "don't attempt to do general DMA from WRAM to WRAM." That includes the mirrored sections in banks $00-$3f and the WRAM banks $7e and $7f. In order to use general DMA to clear WRAM, you would have to store a zero value in the ROM itself somewhere (or possibly external RAM) and have the general DMA use that as the A-bus fixed source.

I'm with whoever wants to split this discussion into another thread, by the way.
Be whatever the situation demands.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: SNES dev newbie questions

Post by Near »

doppleganger is correct.

The original quote is just a more verbose way of saying WRAM A <> WRAM B does not work, regardless of DMA transfer direction. Think about it from a hardware perspective: how can the same chip with one address+data bus be read from and written to at the same time at different locations?

So use an A-bus address ($43x2-4) that is not WRAM (nor a mirror of it.) ROM is the surefire method, but you could also do SRAM if you have some.
tepples
Posts: 22861
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: SNES dev newbie questions

Post by tepples »

Do otherwise unused DMA registers work as a readable A-bus address for this?
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: SNES dev newbie questions

Post by koitsu »

Okay, then that also means the ClearVRAM routine written by Neviksti is wrong as well. *shakes head* So much broken code...

I'm going to generally bow out of assisting at this point. The reason has to do with the fact that all of this quickly becomes assembler-focused (meaning the code written has more and more of a dependency and requirement relating to the assembler being used and its related syntax requirements), and since I don't know WLA and find its documentation a bit of a mess, I choose to opt out. :D

The information being provided here is great/fantastic, however.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: SNES dev newbie questions

Post by Near »

> Do otherwise unused DMA registers work as a readable A-bus address for this?

No, $21xx, $40xx, $41xx, $42xx, $43xx don't work. You either get open bus or 0x00 (depending on register and model) when you specify them as the A-bus address.

I don't even want to imagine how much "fun" you could have DMA'ing data directly to $420b (DMA enable)

> Okay, then that also means the ClearVRAM routine written by Neviksti is wrong as well.

ClearVRAM should work fine. It's transferring from WRAM to VRAM.

The problem is only with going from WRAM to WRAM.

> and since I don't know WLA and find its documentation a bit of a mess, I choose to opt out. :D

Unfortunately we can't all agree to use the same assembler. Even when we make our own, we often want to improve it and remove past mistakes. All I can recommend for writing truly portable code is to stick to straight opcodes and labels:

"lda #$00", "lda #$ffff" (no .b, .w), "label:" (no -/+, no .label, etc.)

Skip the macros, the directives, the defines, etc.
User avatar
juef
Posts: 67
Joined: Thu Jul 15, 2010 8:20 am
Location: Québec, Canada

Re: SNES dev newbie questions

Post by juef »

Thanks to everyone, I'm finally feeling like I'm getting things done! :D If anyone's curious, here's what I have so far:
  • MSU1 detection: screen turns green if MSU1 hardware is available, red otherwise. Includes the manifest and XML files to use with your favorite emulator or hardware MSU1 implementation.
  • Seizure trigger: WARNING, color changes every frame, epileptics beware!
The color one, I made mostly to play around with instructions, WRAM, and other things I'm not experienced with. Basically, every color has its intensity increased by 1, 2 and 3 respectively (looping around), one color per frame. I would very much appreciate if someone could give my code a quick check to see if there are obvious no-no's or code that could be simplified (I know not everything's optimal, I could save a few jumps here and there, but I included them just for clarity):

Code: Select all

lda #$80			   ; Bit 7 of $4200 must be set to enable NMI...
sta $4200
sep #%00110000		; Set the A, X/Y registers to 8-bit.

lda #%00001111		; Full brightness
sta $2100
wai

; Define color addresses so I don't mess up
.define GREEN       $0000
.define RED         $0001
.define BLUE        $0002
.define NEXTCOLOR   $0003	; 0 = GREEN, 1 = RED, 2 = BLUE

; Set all colors to half intensity at first (because why not)
lda #%00010000
sta RED
sta BLUE
sta GREEN
	
Forever:

	stz $2121			; We'll want BG0 only

	IncNextColor:		; One color is updated per frame, find out which out for this iteration
		inc NEXTCOLOR
		lda NEXTCOLOR
		and #%00000011	; This is a weird way I thought about to keep looping between 0 through 2
		sta NEXTCOLOR
		cmp #%00000011
		beq IncNextColor
	cmp #$00
	beq Update_Green
	cmp #$01
	beq Update_Red
	cmp #$02
	beq Update_Blue

	; The following blocks increment the colors by 1, 2 and 3 respectively
	Update_Green:		; low: #%11100000, high: #%00000011
	lda GREEN
	adc #%00000001
	and #%00011111		; so that it's never above 31
	sta GREEN
	jmp Update_Color
	
	Update_Red:			; low: #%00011111, high: #%00000000
	lda RED
	adc #%00000010
	and #%00011111
	sta RED
	jmp Update_Color
	
	Update_Blue:		; low: #%00000000, high: #%01111100
	lda BLUE
	adc #%00000011
	and #%00011111
	sta BLUE
	jmp Update_Color
	
	Update_Color:		; let's "build" the full color bytes
		lda GREEN
		asl a
		asl a
		asl a
		asl a
		asl a
		adc RED
		sta $2122		; low byte (#%GGGRRRRR)
		lda GREEN
		lsr a
		lsr a
		lsr a
		ror a
		ror a
		adc BLUE
		rol a
		rol a
		sta $2122		; high byte (#%0BBBBBGG)
		wai

jmp Forever
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: SNES dev newbie questions

Post by koitsu »

I think you're missing clc before your adc statements.
User avatar
juef
Posts: 67
Joined: Thu Jul 15, 2010 8:20 am
Location: Québec, Canada

Re: SNES dev newbie questions

Post by juef »

Indeed! Thank you.
User avatar
juef
Posts: 67
Joined: Thu Jul 15, 2010 8:20 am
Location: Québec, Canada

Re: SNES dev newbie questions

Post by juef »

Quoted from this topic:
byuu wrote:It takes about 20 minutes to patch a game to use CD-audio: trace out writes to $214x, walk up the stack until you find it loading a track# and calling the "play track" function (every game I've looked at had one), and modify that routine to test if MSU1 is present. If so, play with MSU1. If not, call original function so the game still works just with the regular audio.
I successfully managed to get SMW playing PCM audio tracks with MSU1, but that was with the help from this document. I did try to trace writes to $214x beforehand, but there sure were a lot of those. Typically, how does one find out where the "play track" function is located? Or more generally, how does one discriminate "interesting" writes to $214x versus the others which do something else?

Other unrelated question: for another project, I used functions from this document by blargg to make sure the SNES DSP isn't muted. Since this is the only single thing I am interested in doing with the DSP right now, I was wondering if I overlooked a faster way to do this? It's not too bad, but it seems to me it's still a lot just to make sure a bit isn't set.

Thank you for reading!
User avatar
juef
Posts: 67
Joined: Thu Jul 15, 2010 8:20 am
Location: Québec, Canada

Re: SNES dev newbie questions

Post by juef »

Quick question about rotating bits in accumulator: in the following, I was expecting the 8-bit accumulator to become $80 after the final ROR, but it seems like the set bit just disappeared. This is the bottom code of this post.

Code: Select all

$00/81EF AD 00 00    LDA $0000  [$00:0000]   A:0000 X:0000 Y:0000 P:envMXdiZc
$00/81F2 4A          LSR A                   A:0010 X:0000 Y:0000 P:envMXdizc
$00/81F3 4A          LSR A                   A:0008 X:0000 Y:0000 P:envMXdizc
$00/81F4 4A          LSR A                   A:0004 X:0000 Y:0000 P:envMXdizc
$00/81F5 6A          ROR A                   A:0002 X:0000 Y:0000 P:envMXdizc
$00/81F6 6A          ROR A                   A:0001 X:0000 Y:0000 P:envMXdizc
$00/81F7 2A          .....                   A:0000 X:0000 Y:0000 P:envMXdiZC
I understand that the carry flag becomes set, but I truly hoped for the bit to go around. What am I missing?
User avatar
Jarhmander
Formerly ~J-@D!~
Posts: 570
Joined: Sun Mar 12, 2006 12:36 am
Location: Rive nord de Montréal

Re: SNES dev newbie questions

Post by Jarhmander »

The result is correct. Think of the rotate instructions as "rotate operand and carry": if A is 8-bit, ROL/ROR rotate through 9 bits, A and carry. That means it requires 9 successive ROLs/RORs to get in A the original value, not 8. That's because the vacant bit gets the carry THEN the carry get the shifted-out bit. Example:

Code: Select all

   lda #2  ; assume A is 8 bits.
   clc     ; A = $02, C = 0
   ror a   ; A = $01, C = 0
   ror a   ; A = $00, C = 1
   ror a   ; A = $80, C = 0
((λ (x) (x x)) (λ (x) (x x)))
User avatar
juef
Posts: 67
Joined: Thu Jul 15, 2010 8:20 am
Location: Québec, Canada

Re: SNES dev newbie questions

Post by juef »

This makes perfect sense, thank you. The assembly tutorial I read didn't mention this, but then again it wasn't for 65816...
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: SNES dev newbie questions

Post by koitsu »

juef wrote:This makes perfect sense, thank you. The assembly tutorial I read didn't mention this, but then again it wasn't for 65816...
In this case what's being described applies to 6502 and 65c02 as well. There is nothing different about ROR/ROL on the 65816 compared to the 6502/65c02.
Post Reply