Using the Z80 properly, as well as the PSG

I've mostly been studying on the VDP, but I recently started looking at using the Z80, and the PSG. There are a few things though, I can't get the PSG to even generate white noise. Also, I need to know if the Z80 is something you just start programming, or if it has some initialising code like the M68000, like a table of vectors and such. Any help would be appreciated.

main.asm:

...

z80set:

lea ($A11100).l, a0

lea ($A11200).l, a1

move.w #$100, (a0)

move.w #$100, (a1)

lea (z80driv).w, a2

lea ($A00000).l, a3

moveq #z80drivend-z80driv-1, d0

z80loop:

move.b (a2)+, (a3)+

dbra d0, z80loop

move.w #$0, (a1)

move.w #$0, (a0)

move.w #$100, (a1)

loop:

nop

bra.b loop

z80driv:

incbin "z80.bin"

z80drivend:

...

Z80.asm:

psginit:

di

im 1

ld A, F9H

ld (7F11H), A

whitenoise:

ld A, E6H

ld (7F11H), A

jp whitenoise
 
I'm not familiar with it, but from skimming docs here are some possible issues that jump out at me:

- Charles MacDonald's doc says to deassert /RESET before requesting the bus (you're doing it the other way around). It doesn't explicitly say that the other way around doesn't work, but that might be part of your problem.

- Similarly, the same doc says to release the bus before asserting /RESET.

- You don't seem to be waiting for the bus grant (bit 8 of word $A11100 = 0) before you start writing to Z80 RAM.

- You might want to stick in a few NOPs between asserting and deasserting /RESET ; I wouldn't count on one extra write instruction (or the hardware) to ensure that the pulse is wide enough to make the Z80 happy.
 
Here's my setup code on the 68k side (I've tested this on a real Megadrive):

Code:
xpmp_init:

	movem.l	a0/a1/d1/d2/d3,-(a7)

	/* BUS REQ ON, BUS RESET OFF */

        move.w  #0x100,0xA11100

        move.w  #0x100,0xA11200

_xpmp_init_wait:

	btst	#8,0xA11100

	bne	_xpmp_init_wait

	

	/* Copy sound driver */

        lea     z80driver_bin,a0

        lea     0xA00000,a1

        move.l  #(z80driver_bin_end-1),d0

        move.l  #z80driver_bin,d1

        sub.l   d1,d0

_xpmp_init_copy_driver:

        move.b  (a0)+,(a1)+

	dbra	d0,_xpmp_init_copy_driver

	/* BUS RESET ON, BUS REQ OFF, BUS RESET OFF */

        move.w  #0x0,0xA11200

	nop

	nop

	nop

	nop

        move.w  #0x0,0xA11100

	nop

	nop

	nop

	nop

        move.w  #0x100,0xA11200

	movem.l	(a7)+,a0/a1/d1/d2/d3

	rts

And on the Z80 side:

Code:
.bank 0 

.orga $0000

; Execution starts here when the Z80 is reset. Disable interrupts, set interrupt mode 1 and

; jump to the initialization code.

di

im	1

jp	start

; This code gets called when a VBlank IRQ occurs. Just re-enable interrupts and return.

.org $0038

	ei

	reti

start:

	ld	sp,$1FFE

        call your_init_function

	; Enable interrupts, then enter a loop where we wait for an interrupt (the Z80 only gets

	; VBlank interrupts), call the player update routine and repeat.

	ei

	forever:

		halt

		call	your_update_function

		jp 	forever

If you want to take a look at the full source code for my player you can find it here: http://jiggawatt.org/muzak/xpmck/xpmck-27.zip

The relevant files are \lib\gen\xpmp_gen.s and \src\z80driver\z80driver.asm
 
Okay, thanks. As for the order in which I do things, I just grabbed that out of the Genesis Technical Overview. I will get on fixing that soon. Thanks for the help.
 
Back
Top