Jump to content

My experiments with Atari 7800


Recommended Posts

Well, it still might be a problem. The number of scanlines is hardcoded into Maria, so an NTSC deck won't display all of the lines in a PAL game. When running PAL on NTSC, best case you'll get a cropped screen and a game that runs a bit too fast, worst case the game will crash due to an expected-but-missing interrupt in the cropped portion of the screen.

Link to comment
Share on other sites

Yes I know. But I have few ideas. 

Today OutRun - Last Wave (No Waves)




Also I've made some PAL test with Miker songs and he reported that 2 instruments was too loud.

So there is some bug/feature in Deflamask with TL in OP4 ;)

After changing TL to 25 for this instruments everything start playing as normal.



  • Like 2
Link to comment
Share on other sites

Thanks @DrVenkman

So I can publish beta version Deflamask VGM player.

Yo can use in PAL mode as well so you need change 

sub_frame = pal_wait

and header (byte 57 -> 1)


Save song in Deflamask as VGM

Unfortunately song can't be longer than 44kb (for now)

Player in MADS format.




		icl 'maria.h'

		opt f+h-

		org $40
dest 	.ds 2 		;2 bytes
sour	.ds 2
counter .ds 2

          ORG     $4000-128
HEADER       .byte    1  			; 0   Header version     - 1 byte
        .by    "ATARI7800       "	; 1..16  "ATARI7800   "  - 16 bytes
        .by    "VGMPlayer YM2151"	; 17..48 Cart title      - 32 bytes
        .by    "   2021 Eagle   "	; 2 line
        DTA r	($C000)				; 49..52 data length      - 4 bytes (Big-endian format)
        .byte    $08,$08  			; 53..54 cart type      - 2 bytes
    ;    bit 0 - pokey at $4000
    ;    bit 1 - supergame bank switched
    ;    bit 2 - supergame ram at $4000
    ;    bit 3 - rom at $4000
    ;    bit 4 - bank 6 at $4000
    ;    bit 5 - supergame banked ram
    ;    bit 6 - pokey at $450
    ;    bit 7 - mirror ram at $4000
    ;    bit 8-15 - Special
    ;   0 = Normal cart
        .byte     2  ; 55   controller 1 type  - 1 byte
        .byte     0  ; 56   controller 2 type  - 1 byte
    ;    0 = None
    ;    1 = Joystick
    ;    2 = Light Gun
        .byte    0  ; 57 0 = NTSC 1 = PAL
        .byte    0  ; 58   Save data peripheral - 1 byte (version 2)
    ;    0 = None / unknown (default)
    ;    1 = High Score Cart (HSC)
    ;    2 = SaveKey
        .byte 0,0,0,0	;ORG     HEADER+63
        .byte    0  ; 63   Expansion module
    ;    0 = No expansion module (default on all currently released games)
    ;    1 = Expansion module required
	.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
     ;   ORG     HEADER+100      ; 100..127 "ACTUAL CART DATA STARTS HERE" - 28 bytes

	.macro clear_ram
	ldy #$00
	MWA #:1 dest
	lda #$00
@	sta (dest),y
	INW dest
	lda dest+1
	cmp #>[:2+1]
	bne @-

            org $4000
fnt 	ins 'cmc.fnt'
vgm_data = vgm_header+$80
		ins 'squadron.vgm'

		sei					;Disable interrupts
		cld					;Clear decimal mode
		ldx	#$FF			;Reset stack pointer
;Clear zeropage,stack,RAM
		clear_ram $42,$FF	;skip $40&$41 (dest)
		clear_ram $140,$1FF
		clear_ram $1800,$1FFF
		clear_ram $2200,$27FF
; copy Display List List To RAM
      	ldy #0
copy  	MVA .adr(DLLs),y DLLs,y+
	    cpy #.len DLLs
	    bne copy
		MVA #<DLLs DPPL\ MVA #>DLLs DPPH	;set display list list address
		jsr	WaitVBLANK						;wait until no DMA would happen

		MVA	#>fnt	CHBASE
		MVA	#$40	CTRL

		MWA #vgm_data sour
		MWA #$00 counter

;set colors
		MVA	#$00 BACKGRND\ MVA #$02 P0C1\ MVA #$04 P0C2\ MVA #$0c P0C3
endloop		jmp endloop
;Yamaha 2151 player 
YM2151BASE 		= $460
YM_Data 		= $54
wait_n_sample 	= $61	;44100 samples per second
wait_ntsc_frame	= $62
wait_pal_frame	= $63
endsong 		= $66
w7x				= $70
pcm				= $c0
ntsc_wait		= $2df
pal_wait		= $372

;TV system for player
sub_frame = ntsc_wait
;sub_frame = pal_wait

		bit counter+1
		beq check_counter
		jmp	substract
		bit counter
		bne subframe
		jmp read_data

		.align 256

;skip 1 vblank
;commands $62 and $63
	MWA #$00 counter		;just in case
	INW sour

; skip PCM entry 4 bytes
; format $C0,$xx,$xx,$xx
	adw sour #4 sour

;reading VGM data
		ldy #$00
		lda (sour),y
		cmp #YM_Data
		beq YM_store
		cmp #wait_n_sample
		beq	check_wait_n_sample
		cmp #pcm
		beq skip_pcm
		cmp #wait_pal_frame
		beq wait_frame
		cmp #wait_ntsc_frame
		beq wait_frame
		cmp #endsong 
		beq set_restart_song
		and #$F0
		cmp #w7x
		beq skip_n_sample
		jmp error_read	;color bars if unknown command

		INW sour
		and #$0F
		beq Read_Data_noY
@		dex
		bne @-
		jmp Read_Data_noY		

; $66 = end off VGM data (restart song)
; TO DO - 
		MWA #vgm_data sour
		MWA #$00 counter

;write data to Yamaha 2151
		INW sour
		lda (sour),y
		sta YM2151BASE
		INW sour
		lda (sour),y
		sta YM2151BASE+1
		INW sour	
;saving 3 cycles per data read 
		lda (sour),y
		cmp #YM_Data
		beq YM_store

		jmp skip_YM_data
;delay $xxxx/$0372 frames (PAL)
;delay $xxxx/$02DF frames (NTSC)
		INW sour
		lda (sour),y
		sta counter
		INW sour
		lda (sour),y
		sta counter+1
		INW sour
		SBW counter #sub_frame

; loop - color bars when error
		sta WSYNC
		jmp error_read

;End of Player

;DLI Interrupt
		JSR	Play_Yamaha


		bit		MSTAT
		bmi		WaitVBoff
		bit		MSTAT
		bpl		WaitVBon

		ORG	$1800,*
.local DLLs
	:3	.byte	$0F,>emptyline,<emptyline
		.byte	$07,>line,<line
		.byte	$0F,>emptyline,<emptyline
		.byte	$8f,>emptyline,<emptyline		;$8x DLI interrupt
	:24	.byte	$0F,>emptyline,<emptyline

	.byte 0
line		.byte <text,$60,>text,0,20
emptyline	.byte $00,$00

text	.sb 'YM2151 VGM Player by Eagle               '

;************** Cart reset vector **************************

	 ORG	$fff8
	.byte	$FF		;Region verification
	.byte	$47		;ROM start $8000
	.word	NMI
	.word	START
	.word	IRQ


PlayerVGM_NTSC.asm CMC.FNT maria.h squadron.vgm

  • Like 3
Link to comment
Share on other sites

Some MADS macros explained 


INW dest

inw dest  ->       inc dest
          ->       bne skip
          ->       inc dest+1
          ->  skip      

MVA src dest


    lda src    ->  mva src dst
    sta dst    ->

MWA #adr dst

    lda <adr    ->  mwa #adr dst
    sta dst     ->
    lda >adr    ->
    sta dst+1   ->

SBW src #$4080


  SBW SRC #$4080 -> SEC  
                 -> LDA SRC
                 -> SBC <$4080
                 -> STA SRC
                 -> LDA SRC+1
                 -> SBC >$4080
                 -> STA SRC+1 

ADW src #$40 src


  ADW SRC #$40 SRC -> CLC
                   -> LDA SRC
                   -> ADC #$40
                   -> STA SRC
                   -> LDA SRC+1
                   -> ADC #$00
                   -> STA SRC+1



  PHR  -> PHA         PLR  -> PLA
       -> TXA              -> TAY
       -> PHA              -> PLA
       -> TYA              -> TAX
       -> PHA              -> PLA


  • Like 1
Link to comment
Share on other sites

The YM capability in a7800 and js7800 are currently designed to emulate the XM, so you need to hit the XM $470 register with $84 to enable the YM. I confirmed that doing that manually in the a7800 debugger enabled your demo to play. Pretty sure js7800 will work once you do the same.


Also, the rom@4000 bit in the a78 header is a modifier for supergame format. It's not needed for 48k.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

  • 3 weeks later...
3 hours ago, Eagle said:

I don't have a frame of reference for the others, but this one is fabulous, thanks for converting it.


Stickerbush Symphony is also very mellow, I like that one.


I'd love to be able to include a YM tune in my future projects, but I wouldn't have the first clue about getting this working in 7800 Basic.


Thanks for sharing!

  • Like 1
Link to comment
Share on other sites

@Muddyfunster when I finish should be easy to adapt for Basic


VGM Player with Huffmunch decompressor (not finished yet) - no RAM used 

Stickerbush Symphony from 46KB down to 9700B

SexySix from 22KB to 3.62KB (Deflemask file was 2.87KB) and I'm sure that I can reduce to 3KB easily

I can change VGM format for my player from 0x54,xx,xx,0x54,xx,xx........ to for example 0x54,yy,xx,xx,xx,xx,xx,xx,xx..... (yy-how many times read pairs of xx)


ps. crashing at the end (no loop yet)





  • Like 1
Link to comment
Share on other sites

The Neverending story full version compressed (120KB -> 21KB) - Sometimes "dropping a frame" due decompression and heavy instruments changes but using only 9 bytes of ram. 

Silent  compressed from 60KB -> 9KB - also heavy CPU usage

I will change VGM to my format. Less data and CPU usage. I'll spread decompression equally to frames between playing music (probably will have to use some small buffer) 

Seems like emulator ignoring waiting for YM when real HW not.




Neverending Story NTSC




RayFuture 112KB ->12KB


RayFuture 2203



Neverending120to21KB.a78 Silent60to9KB.a78

  • Like 1
Link to comment
Share on other sites

@SlidellMan thanks I didn't know this.

I will try add missing sample soon.


Few more tests today.

Al Capone 50KB ->7KB (no sample version) cover by LukeMcQueen

The Cheetahmen 83KB ->11KB by SuperJet Spade

Opmeridian 87KB ->15KB by SuperJet Spade


AlCapone - link JS7800


The Cheetahamen - link JS7800


Opmeridian - link JS7800

AlCapone_Michael_Jackson_cover_NTSC.a78 TheCheetahmen_NTSC.a78 opmeridian_NTSC.a78

Link to comment
Share on other sites

I have changed the VGM format to my own and also decompress the data stream to a 256 byte buffer in the background.

But I ran in to problem with YM timing (?). Looks like after waiting for Write Busy Flag I can't write data straight away. 

If I not put Nop's after reading Write Busy Flag, music not playing good on Dragonfly (sounds ok on emulator)

@RevEng sorry for calling you again but you may know answer. I have no idea what's going on :( Looks like I need put minimum 3 NOP after BIT

I know that YM need 68 internal clocks before writing again (about 35 cycles 6502) but should be no problem after checking flag 

I attached examples (PAL unfortunately)

		iny			;2
		lda (sour),y		;5
@		bit YM2151BASE		;4
		bmi @-			;3
		:3 nop			;3*2=6
		sta YM2151BASE		;4
		iny			;2
		lda (sour),y		;5
@		bit YM2151BASE+1	;4
		bmi @-			;3
		:3 nop			;3*2=6
		sta YM2151BASE+1	;4
		dec licznik		;5
		bne copy_ym_data	;3


PlayerEYP_noNOP.a78 PlayerEYP_2x1NOP.a78 PlayerEYP_2x2NOP.a78 PlayerEYP_2x3NOP.a78

Link to comment
Share on other sites

It's nothing I've run into before... if this is the only code accessing the YM at the same time (i.e. there isn't access happening on both interrupts and the main code loop) then it would seem to be a timing quirk.


Try throwing a single NOP before each BIT test loop. Maybe it takes a few more cycles to chew on the last input before the YM realizes it needs to raise it's busy flag. Something to try anyway.


(Adding @tep392 in case he's seen it before)

  • Thanks 1
Link to comment
Share on other sites

It's only writing YM on Interrupt, main loop writing in to the buffer.

17 minutes ago, RevEng said:

Try throwing a single NOP before each BIT test loop. Maybe it takes a few more cycles to chew on the last input before the YM realizes it needs to raise it's busy flag. Something to try anyway.

I had to put 5 NOP's before BIT to make this sounds ok.

Link to comment
Share on other sites

Ok, so it doesn't sound like my guess is right.


Is it purely a sound quality thing, or are notes actually dropped from the transfer? If you send a note-off very shortly after a note-on on the same channel, you get distortion. I think that's just a quirk of the YM.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...