aboutsummaryrefslogtreecommitdiff
path: root/tester
diff options
context:
space:
mode:
Diffstat (limited to 'tester')
-rw-r--r--tester/build.68k22
-rw-r--r--tester/core/entry.68k170
-rw-r--r--tester/core/header.68k37
-rw-r--r--tester/core/menu.68k141
-rw-r--r--tester/core/songlist.68k73
-rw-r--r--tester/core/vars.68k12
-rw-r--r--tester/input/joypad.68k43
-rw-r--r--tester/sound/bgms.68k38
-rw-r--r--tester/sound/echo.68k263
-rw-r--r--tester/sound/esf.68k161
-rw-r--r--tester/sound/list.68k230
-rw-r--r--tester/sound/sfxs.68k26
-rw-r--r--tester/video/bg.68k43
-rw-r--r--tester/video/text.68k108
-rw-r--r--tester/video/vsync.68k19
15 files changed, 1386 insertions, 0 deletions
diff --git a/tester/build.68k b/tester/build.68k
new file mode 100644
index 0000000..15dc6b6
--- /dev/null
+++ b/tester/build.68k
@@ -0,0 +1,22 @@
+Echo_ProgFile equs "bin/prog-z80.bin"
+
+ include "tester/core/header.68k"
+ include "tester/core/entry.68k"
+ include "tester/core/menu.68k"
+ include "tester/core/songlist.68k"
+
+ include "tester/video/text.68k"
+ include "tester/video/bg.68k"
+ include "tester/video/vsync.68k"
+
+ include "tester/input/joypad.68k"
+
+ include "tester/sound/echo.68k"
+ include "tester/sound/esf.68k"
+ include "tester/sound/list.68k"
+ include "tester/sound/bgms.68k"
+ include "tester/sound/sfxs.68k"
+
+ cnop 0, $8000
+
+ include "tester/core/vars.68k"
diff --git a/tester/core/entry.68k b/tester/core/entry.68k
new file mode 100644
index 0000000..5da6abc
--- /dev/null
+++ b/tester/core/entry.68k
@@ -0,0 +1,170 @@
+;****************************************************************************
+; EntryPoint
+; Where the program starts
+;****************************************************************************
+
+EntryPoint:
+ move.w #$2700, sr ; Disable interrupts
+
+ move.b ($A10001), d0 ; Disable TMSS if needed
+ and.b #$0F, d0
+ beq.s @NoTMSS
+ move.l #"SEGA", ($A14000)
+@NoTMSS:
+
+ bsr InitJoypad ; Init joypad
+
+ lea ($C00004), a0 ; Init VDP
+ move.w #$8004, (a0) ; No IRQ4, no HV latch
+ move.w #$8114, (a0) ; Disable display
+ move.w #$8230, (a0) ; Scroll A: $C000
+ move.w #$8407, (a0) ; Scroll B: $E000
+ move.w #$8578, (a0) ; Sprites: $F000
+ move.w #$8700, (a0) ; Background: pal 0, color 0
+ move.w #$8B00, (a0) ; No IRQ2, full scroll
+ move.w #$8C81, (a0) ; H40, no S/H, no interlace
+ move.w #$8D3E, (a0) ; HScroll: $F800
+ move.w #$8F02, (a0) ; Autoincrement: 2 bytes
+ move.w #$9001, (a0) ; Scroll size: 64x32
+ move.w #$9100, (a0) ; Hide window plane
+ move.w #$9200, (a0) ; " " "
+
+ moveq #0, d0 ; Clear VRAM
+ move.l #$40000000, (a0)
+ lea ($C00000), a1
+ move.w #$800-1, d1
+@ClearVRAM:
+ move.l d0, (a1)
+ move.l d0, (a1)
+ move.l d0, (a1)
+ move.l d0, (a1)
+ move.l d0, (a1)
+ move.l d0, (a1)
+ move.l d0, (a1)
+ move.l d0, (a1)
+ dbf d1, @ClearVRAM
+
+ move.l #$C0000000, (a0) ; Clear CRAM
+ moveq #8-1, d1
+@ClearCRAM:
+ move.l d0, (a1)
+ move.l d0, (a1)
+ move.l d0, (a1)
+ move.l d0, (a1)
+ dbf d1, @ClearCRAM
+
+ move.l #$40000010, (a0) ; Clear VSRAM
+ move.l d0, (a1)
+
+ lea (PointerList), a0 ; Initialize Echo
+ bsr Echo_Init
+
+ bsr LoadFont ; Load font
+
+ lea ($C00004), a0 ; Load palette
+ lea ($C00000), a1
+ move.l #$C0020000, (a0)
+ move.l #$066600CE, (a1)
+ move.l #$000E000E, (a1)
+ move.l #$C0220000, (a0)
+ move.l #$06660EEE, (a1)
+ move.l #$000E000E, (a1)
+ move.l #$C0420000, (a0)
+ move.l #$04440E88, (a1)
+ move.l #$C0620000, (a0)
+ move.l #$04440888, (a1)
+
+ move.l #$C00A0000, (a0)
+ move.l #$02220444, (a1)
+ move.l #$02240024, (a1)
+ move.l #$02440020, (a1)
+ move.w #$0040, (a1)
+
+ move.l #$58000000, (a0) ; Load graphics
+ lea (@Gfx_Arrows), a2
+ moveq #12-1, d7
+@LoadGfx:
+ move.l (a2)+, (a1)
+ move.l (a2)+, (a1)
+ move.l (a2)+, (a1)
+ move.l (a2)+, (a1)
+ move.l (a2)+, (a1)
+ move.l (a2)+, (a1)
+ move.l (a2)+, (a1)
+ move.l (a2)+, (a1)
+ dbf d7, @LoadGfx
+
+ move.l #$44880003, (a0) ; Write left arrow
+ move.l #$00C000C1, (a1)
+ move.l #$45080003, (a0)
+ move.l #$00C200C3, (a1)
+
+ move.l #$44C40003, (a0) ; Write right arrow
+ move.l #$28C128C0, (a1)
+ move.l #$45440003, (a0)
+ move.l #$28C328C2, (a1)
+
+ moveq #2, d0 ; Write title
+ moveq #1, d1
+ move.w #$8000, d2
+ lea (@Str_Title1), a0
+ bsr WriteString
+ addq.w #2, d1
+ move.w #$E000, d2
+ lea (@Str_Title2), a0
+ bsr WriteString
+
+ moveq #20-(24/2), d0 ; Write instructions
+ moveq #23, d1
+ lea (@Str_Instr1), a0
+ bsr WriteString
+ moveq #20-(18/2), d0
+ addq.w #2, d1
+ lea (@Str_Instr2), a0
+ bsr WriteString
+
+ bsr DrawBG ; Draw background
+
+ move.w #$8154, ($C00004) ; Enable display
+ bra MainMenu ; Go into the main menu
+
+;****************************************************************************
+
+@Gfx_Arrows:
+ dc.l $00000000, $00000000, $00000000, $00000000
+ dc.l $00000034, $00004343, $00343434, $43434343
+ dc.l $00000034, $00004343, $00343434, $43434343
+ dc.l $34343434, $43434343, $34343434, $43434343
+ dc.l $34343434, $00434343, $00003434, $00000043
+ dc.l $00000000, $00000000, $00000000, $00000000
+ dc.l $34343434, $43434343, $34343434, $43434343
+ dc.l $34343434, $00434343, $00003434, $00000043
+
+@Gfx_BG:
+ dc.l $55555555, $55555555, $55555555, $55555555
+ dc.l $55555555, $55555555, $55555555, $55555555
+ dc.l $00000000, $00000000, $00000000, $00000000
+ dc.l $00000000, $00000000, $00000000, $00000000
+ dc.l $66666666, $66666666, $66666666, $66666666
+ dc.l $66666666, $66666666, $66666666, $66666666
+
+ dc.l $78787878, $87878787, $78787878, $87878787
+ dc.l $78787878, $87878787, $78787878, $87878787
+ dc.l $79797979, $97979797, $79797979, $97979797
+ dc.l $79797979, $97979797, $79797979, $97979797
+
+ dc.l $AAAAAAAA, $AAAAAAAA, $AAAAAAAA, $AAAAAAAA
+ dc.l $AAAAAAAA, $AAAAAAAA, $AAAAAAAA, $AAAAAAAA
+ dc.l $BABABABA, $ABABABAB, $BABABABA, $ABABABAB
+ dc.l $BABABABA, $ABABABAB, $BABABABA, $ABABABAB
+
+ dc.l $56565656, $65656565, $56565656, $65656565
+ dc.l $56565656, $65656565, $56565656, $65656565
+
+ ; 123456789012345678901234567890123456
+
+@Str_Title1: dc.b "Echo sound engine", 0
+@Str_Title2: dc.b "Version 0.9 by Sik", 0
+@Str_Instr1: dc.b "Use D-pad to select song", 0
+@Str_Instr2: dc.b "A/C: play, B: stop", 0
+ even
diff --git a/tester/core/header.68k b/tester/core/header.68k
new file mode 100644
index 0000000..fde18ee
--- /dev/null
+++ b/tester/core/header.68k
@@ -0,0 +1,37 @@
+;****************************************************************************
+; 68000 vectors
+;****************************************************************************
+
+ dc.l $1000000
+ dc.l EntryPoint
+ dcb.l 62, ErrorInt
+
+;****************************************************************************
+; Mega Drive header
+;****************************************************************************
+
+ dc.b "SEGA MEGA DRIVE "
+ dc.b "(C) SIK 2010.NOV"
+ dc.b "ECHO TESTER PROGRAM"
+ dcb.b $150-*, $20
+ dc.b "ECHO TESTER PROGRAM"
+ dcb.b $180-*, $20
+ dc.b "XX XXXXXXXX-00"
+ dc.w $0000
+ dc.b "J"
+ dcb.b $1A0-*, $20
+ dc.l $000000, $3FFFFF
+ dc.l $FF0000, $FFFFFF
+ dcb.b 12, $20
+ dcb.b 12, $20
+ dcb.b 40, $20
+ dc.b "JUE"
+ dcb.b $200-*, $20
+
+;****************************************************************************
+; ErrorInt
+; Generic error handler routine (hangs up)
+;****************************************************************************
+
+ErrorInt:
+ bra.s *
diff --git a/tester/core/menu.68k b/tester/core/menu.68k
new file mode 100644
index 0000000..d5f7914
--- /dev/null
+++ b/tester/core/menu.68k
@@ -0,0 +1,141 @@
+;****************************************************************************
+; MainMenu
+; Menu where you get to select the song and such
+; The main screen, bah...
+;****************************************************************************
+
+MainMenu:
+ move.w #0, (RAM_CurrSong) ; Selected song
+ bsr UpdateMenu ; Show description of first song
+
+ move.l #0, (RAM_LArrowAnim) ; Reset arrows anim
+ move.w #$8407, (RAM_BGAnim) ; Reset background anim
+
+@MainLoop:
+ move.b (RAM_JoyPress), d0 ; Get joypad input
+
+ btst.l #2, d0 ; Previous song?
+ beq.s @NoLeft
+
+ move.w (RAM_CurrSong), d7 ; Select previous song
+ bne.s @NotTooLeft
+ move.w #NumSongs, d7
+@NotTooLeft:
+ subq.w #1, d7
+ move.w d7, (RAM_CurrSong)
+
+ bsr UpdateMenu ; Update current song
+ move.w #28, (RAM_LArrowAnim) ; Animate left arrow
+ lea (SFX_Beep), a0 ; Beep!
+ bsr Echo_PlaySFX
+@NoLeft:
+
+ btst.l #3, d0 ; Next song?
+ beq.s @NoRight
+
+ move.w (RAM_CurrSong), d7 ; Select next song
+ addq.w #1, d7
+ cmp.w #NumSongs, d7
+ blt.s @NotTooRight
+ moveq #0, d7
+@NotTooRight:
+ move.w d7, (RAM_CurrSong)
+ bsr UpdateMenu ; Update current song
+
+ move.w #28, (RAM_RArrowAnim) ; Animate right arrow
+ lea (SFX_Beep), a0 ; Beep!
+ bsr Echo_PlaySFX
+@NoRight:
+
+ btst.l #5, d0 ; Play song?
+ bne.s @DoPlay
+ btst.l #6, d0
+ beq.s @NoPlay
+@DoPlay:
+ lea (SongList), a1 ; Get song address
+ move.w (RAM_CurrSong), d7
+ lsl.w #4, d7
+ lea (a1,d7.w), a1
+ move.l (a1), a0
+ bsr Echo_PlayBGM ; Play song
+@NoPlay:
+
+ btst.l #4, d0 ; Stop song?
+ beq.s @NoStop
+ bsr Echo_StopBGM
+@NoStop:
+
+ btst.l #7, d0 ; Debug key
+ beq.s @NoDebug
+ lea (BGM_Test), a0 ; Play test BGM
+ ;bsr Echo_PlayBGM
+ lea (SFX_Test), a0 ; Play test SFX
+ bsr Echo_PlaySFX
+@NoDebug:
+
+ lea (@ArrowPal), a0
+
+ move.w (RAM_LArrowAnim), d0 ; Animate left arrow
+ move.l (a0,d0.w), d1
+ move.l #$C0060000, ($C00004)
+ move.l d1, ($C00000)
+ subq.w #2, d0
+ bge.s @NoLArrowOver
+ moveq #0, d0
+@NoLArrowOver:
+ move.w d0, (RAM_LArrowAnim)
+
+ move.w (RAM_RArrowAnim), d0 ; Animate right arrow
+ move.l (a0,d0.w), d1
+ move.l #$C0260000, ($C00004)
+ move.l d1, ($C00000)
+ subq.w #2, d0
+ bge.s @NoRArrowOver
+ moveq #0, d0
+@NoRArrowOver:
+ move.w d0, (RAM_RArrowAnim)
+
+ move.w (RAM_BGAnim), d0 ; Animate background
+ bchg.l #1, d0
+ move.w d0, (RAM_BGAnim)
+ move.w d0, ($C00004)
+
+ bsr VSync ; Next frame
+ bsr ReadJoypad
+ bra @MainLoop
+
+;****************************************************************************
+
+@ArrowPal:
+ dc.w $00E, $00E, $02E, $02E, $04E, $04E, $06E, $06E
+ dc.w $28E, $28E, $4AE, $4AE, $6CE, $6CE, $8EE, $8EE
+
+;****************************************************************************
+; UpdateMenu
+; Shows the current option on screen
+;****************************************************************************
+
+UpdateMenu:
+ bsr ClearLines ; Clear lines
+
+ lea (SongList), a1 ; Get address of song data
+ move.w (RAM_CurrSong), d0
+ lsl.w #4, d0
+ lea (a1,d0.w), a1
+ addq.l #4, a1
+
+ moveq #7, d0 ; Write song title
+ moveq #9, d1
+ move.w #$A000, d2
+ move.l (a1)+, a0
+ bsr WriteString
+
+ addq.w #2, d1 ; Write song description
+ move.w #$C000, d2
+ move.l (a1)+, a0
+ bsr WriteString
+ addq.w #2, d1
+ move.l (a1)+, a0
+ bsr WriteString
+
+ rts ; End of subroutine
diff --git a/tester/core/songlist.68k b/tester/core/songlist.68k
new file mode 100644
index 0000000..527ea6d
--- /dev/null
+++ b/tester/core/songlist.68k
@@ -0,0 +1,73 @@
+;****************************************************************************
+; SongList
+; List of songs that appear on the menu
+;****************************************************************************
+
+SongList:
+ dc.l BGM_Midnas, @Str_Midnas_1, @Str_Midnas_2, @Str_Midnas_3
+ dc.l BGM_Nelpel, @Str_Nelpel_1, @Str_Nelpel_2, @Str_Nelpel_3
+ dc.l BGM_Megajysays, @Str_Megajysays_1, @Str_Megajysays_2, @Str_Megajysays_3
+ dc.l BGM_Doomsday, @Str_Doomsday_1, @Str_Doomsday_2, @Str_Doomsday_3
+ dc.l BGM_PianoTest, @Str_PianoTest_1, @Str_PianoTest_2, @Str_Null
+ dc.l BGM_SquSawTest2, @Str_SquSawTest_1a, @Str_SquSawTest_2, @Str_SquSawTest_3a
+ dc.l BGM_SquSawTest1, @Str_SquSawTest_1b, @Str_SquSawTest_2, @Str_SquSawTest_3b
+ dc.l BGM_PSGTest, @Str_PSGTest_1, @Str_PSGTest_2, @Str_Null
+ dc.l BGM_DrumTest, @Str_DrumTest_1, @Str_DrumTest_2, @Str_Null
+ dc.l BGM_FluteTest, @Str_FluteTest_1, @Str_FluteTest_2, @Str_FluteTest_3
+
+ ; 012345678901234567890123456
+@Str_Null: dc.b 0
+@Str_Untitled: dc.b "[untitled]", 0
+
+ ; 012345678901234567890123456
+@Str_Midnas_1: dc.b "Midna's Desperate Hour", 0
+@Str_Midnas_2: dc.b "Composed by Koji Kondo", 0
+@Str_Midnas_3: dc.b "Transcribed by Aivi Tran", 0
+
+ ; 012345678901234567890123456
+@Str_Nelpel_1: dc.b "Nelpel Four (crappy ver.)", 0
+@Str_Nelpel_2: dc.b "XM > MIDI > ESF conversion", 0
+@Str_Nelpel_3: dc.b "and really bad instruments", 0
+
+ ; 012345678901234567890123456
+@Str_Megajysays_1: dc.b "Megajysays", 0
+@Str_Megajysays_2: dc.b "That second A should have", 0
+@Str_Megajysays_3: dc.b "two dots on top of it.", 0
+
+ ; 012345678901234567890123456
+@Str_Doomsday_1: dc.b "The Doomsday Project", 0
+@Str_Doomsday_2: dc.b "Another module conversion.", 0
+@Str_Doomsday_3: dc.b "Like I give a crap :P", 0
+
+ ; 012345678901234567890123456
+@Str_PianoTest_1: dc.b "test-piano.mid", 0
+@Str_PianoTest_2: dc.b "Some generic piano...", 0
+
+ ; 012345678901234567890123456
+@Str_SquSawTest_1a: dc.b "test-squsaw-2ch.mid", 0
+@Str_SquSawTest_1b: dc.b "test-squsaw-1ch.mid", 0
+@Str_SquSawTest_2: dc.b "FM square and sawtooth", 0
+@Str_SquSawTest_3a: dc.b "2 channels version", 0
+@Str_SquSawTest_3b: dc.b "1 channel version", 0
+
+ ; 012345678901234567890123456
+@Str_PSGTest_1: dc.b "test-psg.mid", 0
+@Str_PSGTest_2: dc.b "Two square PSG channels.", 0
+
+ ; 012345678901234567890123456
+@Str_DrumTest_1: dc.b "test-drums.mid", 0
+@Str_DrumTest_2: dc.b "Snare and kicks!", 0
+
+ ; 012345678901234567890123456
+@Str_FluteTest_1: dc.b "test-flute.mid", 0
+@Str_FluteTest_2: dc.b "Flute and a seashore.", 0
+@Str_FluteTest_3: dc.b "Feels so calm...", 0
+
+ even
+
+;****************************************************************************
+; NumSongs
+; Number of songs in song list
+;****************************************************************************
+
+NumSongs equ 10
diff --git a/tester/core/vars.68k b/tester/core/vars.68k
new file mode 100644
index 0000000..8097c73
--- /dev/null
+++ b/tester/core/vars.68k
@@ -0,0 +1,12 @@
+;****************************************************************************
+; Where program variables are defined
+;****************************************************************************
+
+ rsset $FF0000
+
+RAM_JoyHold rs.b 1 ; Current "held" joypad status
+RAM_JoyPress rs.b 1 ; Current "pressed" joypad status
+RAM_LArrowAnim rs.w 1 ; Animation for left arrow
+RAM_RArrowAnim rs.w 1 ; Animation for right arrow
+RAM_BGAnim rs.w 1 ; Animation for background
+RAM_CurrSong rs.w 1 ; Selected song
diff --git a/tester/input/joypad.68k b/tester/input/joypad.68k
new file mode 100644
index 0000000..f33d000
--- /dev/null
+++ b/tester/input/joypad.68k
@@ -0,0 +1,43 @@
+;****************************************************************************
+; InitJoypad
+; Initializes the joypad
+;****************************************************************************
+
+InitJoypad:
+ move.b #$40, ($A10009) ; Initialize I/O ports
+ move.b #$40, ($A10003)
+ move.w #0, (RAM_JoyHold) ; Initialize status
+ rts ; End of subroutine
+
+;****************************************************************************
+; ReadJoypad
+; Reads the joypad status
+;****************************************************************************
+
+ReadJoypad:
+ lea ($A10003), a6 ; I/O data port
+
+ move.b #$40, (a6) ; Read D-pad, B and C
+ nop
+ nop
+ move.b (a6), d7
+ move.b #$00, (a6) ; Read A and Start
+ nop
+ nop
+ move.b (a6), d6
+
+ and.b #$3F, d7 ; Process input
+ and.b #$30, d6
+ add.b d6, d6
+ add.b d6, d6
+ or.b d6, d7
+ not.b d7
+
+ lea (RAM_JoyHold), a6 ; Store new joypad status
+ move.b (a6), d6
+ move.b d7, (a6)+
+ not.b d6
+ and.b d6, d7
+ move.b d7, (a6)
+
+ rts ; End of subroutine
diff --git a/tester/sound/bgms.68k b/tester/sound/bgms.68k
new file mode 100644
index 0000000..4069628
--- /dev/null
+++ b/tester/sound/bgms.68k
@@ -0,0 +1,38 @@
+;****************************************************************************
+; BGM_Test
+; Generic BGM to test events
+;****************************************************************************
+
+BGM_Test:
+ dc.b $FF
+
+;****************************************************************************
+; Some conversions
+;****************************************************************************
+
+BGM_Midnas:
+ incbin "data/music/midnas.esf"
+BGM_Nelpel:
+ incbin "data/music/nelpel.esf"
+BGM_Megajysays:
+ incbin "data/music/megajysays.esf"
+BGM_Doomsday:
+ incbin "data/music/doomsday.esf"
+
+;****************************************************************************
+; Several tests used for midi2esf
+;****************************************************************************
+
+BGM_PianoTest:
+ incbin "data/music/test-piano.esf"
+BGM_SquSawTest2:
+ incbin "data/music/test-squsaw-2ch.esf"
+BGM_SquSawTest1:
+ incbin "data/music/test-squsaw-1ch.esf"
+BGM_PSGTest:
+ incbin "data/music/test-psg.esf"
+BGM_DrumTest:
+ incbin "data/music/test-drums.esf"
+BGM_FluteTest:
+ incbin "data/music/test-flute.esf"
+
diff --git a/tester/sound/echo.68k b/tester/sound/echo.68k
new file mode 100644
index 0000000..1d02800
--- /dev/null
+++ b/tester/sound/echo.68k
@@ -0,0 +1,263 @@
+;****************************************************************************
+; Echo_Z80Request
+; Requests the Z80 bus
+;****************************************************************************
+
+Echo_Z80Request macro
+ move.w #$100, ($A11100) ; Request Z80 bus
+@Echo_WaitZ80\@:
+ btst.b #0, ($A11100) ; Did we get it yet?
+ bne.s @Echo_WaitZ80\@ ; Keep waiting
+ endm ; End of macro
+
+;****************************************************************************
+; Echo_Z80Release
+; Releases the Z80 bus
+;****************************************************************************
+
+Echo_Z80Release macro
+ move.w #$000, ($A11100) ; Release Z80 bus
+ endm ; End of macro
+
+;****************************************************************************
+; Echo_Z80Reset
+; Resets the Z80 and YM2612
+;****************************************************************************
+
+Echo_Z80Reset macro
+ move.w #$000, ($A11200) ; Assert reset line
+ rept $10 ; Wait until hardware resets
+ nop ; ...
+ endr ; ...
+ move.w #$100, ($A11200) ; Release reset line
+ endm ; End of macro
+
+;****************************************************************************
+; Echo_Init
+; Initializes Echo
+;
+; input a0.l ... Address of pointer list
+;****************************************************************************
+
+Echo_Init:
+ movem.l d0/a0-a1, -(sp) ; Save registers
+
+ Echo_Z80Reset ; May not work without this...
+ Echo_Z80Request ; We need the Z80 bus
+
+ move.b #$01, ($A01FFF) ; Command: load pointer list
+
+ move.l a0, d0 ; Easier to manipulate here
+ move.b d0, ($A01FFD) ; Store low address byte
+ lsr.l #7, d0 ; Get high address byte
+ lsr.b #1, d0 ; We skip one bit
+ bset.l #7, d0 ; Point into bank window
+ move.b d0, ($A01FFE) ; Store high address byte
+ lsr.w #8, d0 ; Get bank byte
+ move.w d0, d1 ; Parse 32X bit separately
+ lsr.w #1, d1 ; Put 32X bit in place
+ and.b #$7F, d0 ; Filter out unused bit from addresses
+ and.b #$80, d1 ; Filter out all but 32X bit
+ or.b d1, d0 ; Put everything together
+ move.b d0, ($A01FFC) ; Store bank byte
+
+ lea @Z80Program(pc), a0 ; Where Z80 program starts
+ lea ($A00000), a1 ; Where Z80 RAM starts
+ move.w #@Z80ProgSize-1, d0 ; Size of Z80 program (DBF adjusted)
+@LoadLoop: ; Go through all the program
+ move.b (a0)+, (a1)+ ; Copy byte into Z80 RAM
+ dbf d0, @LoadLoop ; Go for next byte
+
+ Echo_Z80Reset ; Now reset for real
+ Echo_Z80Release ; Let the Z80 go!
+
+ movem.l (sp)+, d0/a0-a1 ; Restore registers
+ rts ; End of subroutine
+
+;****************************************************************************
+; Echo Z80 program
+; It should be located wherever Echo_ProgFile was defined
+;****************************************************************************
+
+@Z80Program: incbin "\Echo_ProgFile"
+@Z80ProgSize equ *-@Z80Program
+ even
+
+;****************************************************************************
+; Echo_SendCommand
+; Sends an Echo command (no address parameter)
+;
+; input d0.b ... Echo command
+;****************************************************************************
+
+Echo_SendCommand:
+ move.w d1, -(sp) ; Save register
+
+ Echo_Z80Request ; We need the Z80 bus
+
+@Try:
+ tst.b ($A01FFF) ; Check if Echo is ready
+ beq.s @Ready ; Too busy?
+ Echo_Z80Release ; Let Echo continue
+ move.w #$FF, d1 ; Give it some time
+ dbf d1, * ; ...
+ Echo_Z80Request ; Get Z80 bus back
+ bra.s @Try ; Try again
+
+@Ready:
+ move.b d0, ($A01FFF) ; Write command ID
+ Echo_Z80Release ; We're done with the Z80 bus
+
+ move.w (sp)+, d1 ; Restore register
+ rts ; End of subroutine
+
+;****************************************************************************
+; Echo_SendCommandEx
+; Sends an Echo command (with address parameter)
+;
+; input d0.b ... Echo command
+; input a0.l ... Address parameter
+;****************************************************************************
+
+Echo_SendCommandEx:
+ movem.l d0-d1, -(sp) ; Save register
+
+ Echo_Z80Request ; We need the Z80 bus
+
+@Try:
+ tst.b ($A01FFF) ; Check if Echo is ready
+ beq.s @Ready ; Too busy?
+ Echo_Z80Release ; Let Echo continue
+ move.w #$FF, d1 ; Give it some time
+ dbf d1, * ; ...
+ Echo_Z80Request ; Get Z80 bus back
+ bra.s @Try ; Try again
+
+@Ready:
+ move.b d0, ($A01FFF) ; Write command ID
+
+ move.l a0, d0 ; Easier to manipulate here
+ move.b d0, ($A01FFD) ; Store low address byte
+ lsr.l #7, d0 ; Get high address byte
+ lsr.b #1, d0 ; We skip one bit
+ bset.l #7, d0 ; Point into bank window
+ move.b d0, ($A01FFE) ; Store high address byte
+
+ lsr.w #8, d0 ; Get bank byte
+ move.w d0, d1 ; Parse 32X bit separately
+ lsr.w #1, d1 ; Put 32X bit in place
+ and.b #$7F, d0 ; Filter out unused bit from addresses
+ and.b #$80, d1 ; Filter out all but 32X bit
+ or.b d1, d0 ; Put everything together
+ move.b d0, ($A01FFC) ; Store bank byte
+
+ Echo_Z80Release ; We're done with the Z80 bus
+
+ movem.l (sp)+, d0-d1 ; Restore register
+ rts ; End of subroutine
+
+;****************************************************************************
+; Echo_PlaySFX
+; Plays a SFX
+;
+; input a0.l ... Pointer to SFX data
+;****************************************************************************
+
+Echo_PlaySFX:
+ move.w d0, -(sp) ; Save register
+ move.b #$02, d0 ; Command $02 = play SFX
+ bsr Echo_SendCommandEx ; Send command to Echo
+ move.w (sp)+, d0 ; Restore register
+ rts ; End of subroutine
+
+;****************************************************************************
+; Echo_StopSFX
+; Stops SFX playback
+;****************************************************************************
+
+Echo_StopSFX:
+ move.w d0, -(sp) ; Save register
+ move.b #$03, d0 ; Command $03 = stop SFX
+ bsr Echo_SendCommand ; Send command to Echo
+ move.w (sp)+, d0 ; Restore register
+ rts ; End of subroutine
+
+;****************************************************************************
+; Echo_PlayBGM
+; Plays a BGM
+;
+; input a0.l ... Pointer to BGM data
+;****************************************************************************
+
+Echo_PlayBGM:
+ move.w d0, -(sp) ; Save register
+ move.b #$04, d0 ; Command $04 = play BGM
+ bsr Echo_SendCommandEx ; Send command to Echo
+ move.w (sp)+, d0 ; Restore register
+ rts ; End of subroutine
+
+;****************************************************************************
+; Echo_StopBGM
+; Stops BGM playback
+;****************************************************************************
+
+Echo_StopBGM:
+ move.w d0, -(sp) ; Save register
+ move.b #$05, d0 ; Command $05 = stop BGM
+ bsr Echo_SendCommand ; Send command to Echo
+ move.w (sp)+, d0 ; Restore register
+ rts ; End of subroutine
+
+;****************************************************************************
+; Echo_ResumeBGM
+; Resumes BGM playback
+;****************************************************************************
+
+Echo_ResumeBGM:
+ move.w d0, -(sp) ; Save register
+ move.b #$06, d0 ; Command $06 = resume BGM
+ bsr Echo_SendCommand ; Send command to Echo
+ move.w (sp)+, d0 ; Restore register
+ rts ; End of subroutine
+
+;****************************************************************************
+; Echo_GetStatus
+; Gets the current status of Echo
+;
+; output d0.w ... Echo status
+; Bit #0: SFX is playing
+; Bit #1: BGM is playing
+; Bit #15: command still not parsed
+;****************************************************************************
+
+Echo_GetStatus:
+ moveq #0, d0
+ Echo_Z80Request ; We need the Z80 bus
+ move.b ($A01FF0), d0 ; Get the status flags
+ tst.b ($A01FFF) ; Check if command still has to be parsed
+ beq.s @NotBusy ; Any commands left to be parsed?
+ bset.l #15, d0 ; If so, set the relevant flag
+@NotBusy:
+ Echo_Z80Release ; Let the Z80 go!
+ rts ; End of subroutine
+
+;****************************************************************************
+; Echo_ListEntry
+; Defines an entry in a pointer list
+;****************************************************************************
+
+Echo_ListEntry macro addr
+ dc.b $80|((addr)>>8&$7F) ; High byte of address
+ dc.b (addr)&$FF ; Low byte of address
+ dc.b ((addr)>>15&$7F)|((addr)>>16&$80) ; Bank number
+ endm
+
+;****************************************************************************
+; Echo_ListEnd
+; Ends a pointer list
+;****************************************************************************
+
+Echo_ListEnd macro
+ dc.b $00 ; End of list mark
+ even ; Just in case...
+ endm
diff --git a/tester/sound/esf.68k b/tester/sound/esf.68k
new file mode 100644
index 0000000..6abecd1
--- /dev/null
+++ b/tester/sound/esf.68k
@@ -0,0 +1,161 @@
+;****************************************************************************
+; Channel ID constants
+;****************************************************************************
+
+ESF_FM1 equ $00 ; FM channel #1
+ESF_FM2 equ $01 ; FM channel #2
+ESF_FM3 equ $02 ; FM channel #3
+ESF_FM4 equ $04 ; FM channel #4
+ESF_FM5 equ $05 ; FM channel #5
+ESF_FM6 equ $06 ; FM channel #6
+ESF_PSG1 equ $08 ; PSG square channel #1
+ESF_PSG2 equ $09 ; PSG square channel #2
+ESF_PSG3 equ $0A ; PSG square channel #3
+ESF_PSG4 equ $0B ; PSG noise channel
+ESF_PCM equ $0C ; PCM channel
+
+;****************************************************************************
+; ESF_NoteOn
+; Start playing a note.
+;----------------------------------------------------------------------------
+; For FM channels:
+; ESF_NoteOn channel, octave, semitone
+; For square PSG channels:
+; ESF_NoteOn channel, octave, semitone
+; For noise PSG channel:
+; ESF_NoteOn channel, type
+; For PCM channel:
+; ESF_NoteOn channel, instrument
+;----------------------------------------------------------------------------
+; param channel ...... channel to play on
+; param octave ....... octave (0 to 7 for FM, 0 to 5 for PSG)
+; param semitone ..... semitone (0 to 11)
+; param type ......... noise type ($00 to $07)
+; param instrument ... drum instrument ID ($00 to $FF)
+;****************************************************************************
+
+ESF_NoteOn macro
+ dc.b $00+(\1)
+ if (\1)<ESF_PSG1
+ dc.b (\2)*32+(\3)*2+1
+ elseif (\1)<ESF_PSG4
+ dc.b (\2)*24+(\3)*2
+ else
+ dc.b \2
+ endc
+ endm
+
+;****************************************************************************
+; ESF_NoteOff
+; Stop playing a note.
+;----------------------------------------------------------------------------
+; Format:
+; ESF_NoteOff channel
+;----------------------------------------------------------------------------
+; param channel ...... channel to stop
+;****************************************************************************
+
+ESF_NoteOff macro
+ dc.b $10+(\1)
+ endm
+
+;****************************************************************************
+; ESF_SetVol
+; Set the volume of a channel.
+;----------------------------------------------------------------------------
+; Format:
+; ESF_SetVol channel, volume
+;----------------------------------------------------------------------------
+; param channel ... channel to modify
+; param volume .... new volume ($00 to $7F for FM, $00 to $0F for PSG)
+;****************************************************************************
+
+ESF_SetVol macro
+ dc.b $20+(\1)
+ dc.b (\2)
+ endm
+
+;****************************************************************************
+; ESF_SetFreq
+; Sets the frequency of a channel (allows note slides).
+;----------------------------------------------------------------------------
+; For FM channels:
+; ESF_SetFreq channel, octave, frequency
+; For square PSG channels:
+; ESF_SetFreq channel, frequency
+; For noise PSG channel:
+; ESF_SetFreq channel, type
+;----------------------------------------------------------------------------
+; param channel ..... affected channel
+; param octave ...... octave
+; param frequency ... frequency (0 to $7FF for FM, 0 to $3FF for PSG)
+; param type ........ noise type ($00 to $07)
+;****************************************************************************
+
+ESF_SetFreq macro
+ dc.b $30+(\1)
+ if (\1)<ESF_PSG1
+ dc.b ((\2)<<3)|((\3)>>8)
+ dc.b (\3)&$FF
+ elseif (\1)<ESF_PSG4
+ dc.b (\2)&$0F
+ dc.b (\2)>>6
+ else
+ dc.b (\2)
+ endc
+ endm
+
+;****************************************************************************
+; ESF_SetInstr
+; Set the instrument of a channel.
+;----------------------------------------------------------------------------
+; Format:
+; ESF_SetInstr channel, instrument
+;----------------------------------------------------------------------------
+; param channel ...... Channel to lock
+; param instrument ... Instrument ID ($00 to $FF)
+;****************************************************************************
+
+ESF_SetInstr macro
+ dc.b $40+(\1)
+ dc.b (\2)
+ endm
+
+;****************************************************************************
+; ESF_Lock
+; Lock SFX channel.
+;----------------------------------------------------------------------------
+; Format:
+; ESF_Lock channel
+;----------------------------------------------------------------------------
+; param channel ... Channel to lock
+;****************************************************************************
+
+ESF_Lock macro
+ dc.b $E0
+ dc.b (\1)
+ endm
+
+;****************************************************************************
+; ESF_Delay
+; Stop event.
+;----------------------------------------------------------------------------
+; Format:
+; ESF_Delay ticks
+;----------------------------------------------------------------------------
+; param ticks ... Ticks to wait (60 = 1 second)
+;****************************************************************************
+
+ESF_Delay macro
+ dc.b $FE
+ dc.b (\1)
+ endm
+
+;****************************************************************************
+; ESF_Stop
+; Stop event.
+;****************************************************************************
+
+ESF_Stop macro
+ dc.b $FF
+ endm
diff --git a/tester/sound/list.68k b/tester/sound/list.68k
new file mode 100644
index 0000000..10f7a42
--- /dev/null
+++ b/tester/sound/list.68k
@@ -0,0 +1,230 @@
+;****************************************************************************
+; PointerList
+; Pointer list used by Echo
+;****************************************************************************
+
+PointerList:
+ Echo_ListEntry Instr_PSGFlat ; $00 [PSG] Flat PSG instrument
+ Echo_ListEntry Instr_DGuitar ; $01 [FM] Distortion guitar
+ Echo_ListEntry Instr_Snare ; $02 [PCM] Snare drum
+ Echo_ListEntry Instr_Kick ; $03 [PCM] Bass drum (kick)
+ Echo_ListEntry Instr_Strings ; $04 [FM] String ensemble
+ Echo_ListEntry Instr_Bass ; $05 [FM] Standard bass
+ Echo_ListEntry Instr_SoftPSG ; $06 [PSG] Soft PSG envelope
+ Echo_ListEntry Instr_PianoPSG ; $07 [PSG] Piano PSG instrument
+ Echo_ListEntry Instr_MidiPSG ; $08 [PSG] MIDI square lead
+ Echo_ListEntry Instr_MidiPiano ; $09 [FM] MIDI piano
+ Echo_ListEntry Instr_MidiLead1 ; $0A [FM] MIDI square lead
+ Echo_ListEntry Instr_MidiLead2 ; $0B [FM] MIDI sawtooth lead
+ Echo_ListEntry Instr_MidiFlute ; $0C [FM] MIDI flute
+ Echo_ListEntry Instr_NepelPSG ; $0D [PSG] Nepel Four PSG instr.
+ Echo_ListEntry Instr_MidiSynthBass ; $0E [FM] MIDI synth bass
+ Echo_ListEntry Instr_MidiLead1F ; $0F [FM] MIDI square (filtered)
+ Echo_ListEntry Instr_MidiLead2F ; $10 [FM] MIDI sawtooth (filtered)
+ Echo_ListEntry Instr_Seashore ; $11 [PSG] Seashore
+ Echo_ListEntry Instr_HitHat ; $12 [PSG] Hit-hat
+ Echo_ListEntry Instr_PSGString ; $13 [PSG] PSG string
+ Echo_ListEntry Instr_EGuitar ; $14 [FM] Electric guitar
+ Echo_ListEnd
+
+;****************************************************************************
+; Instrument $00 [PSG]
+; Flat PSG instrument (no envelope)
+;****************************************************************************
+
+Instr_PSGFlat:
+ dc.b $FE,$00,$FF
+
+;****************************************************************************
+; Instrument $01 [FM]
+; Distortion guitar
+;****************************************************************************
+
+Instr_DGuitar:
+ incbin "data/fm/dguitar.eif"
+
+;****************************************************************************
+; Instrument $02 [PCM]
+; Snare drum
+;****************************************************************************
+
+Instr_Snare:
+ incbin "data/pcm/snare.ewf"
+
+;****************************************************************************
+; Instrument $03 [PCM]
+; Bass drum
+;****************************************************************************
+
+Instr_Kick:
+ incbin "data/pcm/kick.ewf"
+
+;****************************************************************************
+; Instrument $04 [FM]
+; String ensemble
+;****************************************************************************
+
+Instr_Strings:
+ incbin "data/fm/string.eif"
+
+;****************************************************************************
+; Instrument $05 [FM]
+; Standard bass
+;****************************************************************************
+
+Instr_Bass:
+ incbin "data/fm/bass.eif"
+
+;****************************************************************************
+; Instrument $06 [PSG]
+; "Soft" PSG envelope
+;****************************************************************************
+
+Instr_SoftPSG:
+ dc.b $00,$01,$01,$02,$02,$02,$03,$03,$03,$03,$FE,$04,$FF
+
+;****************************************************************************
+; Instrument $07 [PSG]
+; Piano-like PSG instrument
+;****************************************************************************
+
+Instr_PianoPSG:
+ dc.b $00,$01,$02,$03,$04,$04,$05,$05
+ dc.b $06,$06,$07,$07,$08,$08,$08,$08
+ dc.b $09,$09,$09,$09,$0A,$0A,$0A,$0A
+ dc.b $0B,$0B,$0B,$0B,$0C,$0C,$0C,$0C
+ dc.b $0C,$0C,$0C,$0C,$0D,$0D,$0D,$0D
+ dc.b $0D,$0D,$0D,$0D,$0E,$0E,$0E,$0E
+ dc.b $0E,$0E,$0E,$0E,$FE,$0F,$FF
+
+;****************************************************************************
+; Instrument $08 [PSG]
+; MIDI square wave instrument (GM81)
+;****************************************************************************
+
+Instr_MidiPSG:
+ dc.b $00,$01,$02,$FE,$03,$FF
+
+;****************************************************************************
+; Instrument $09 [FM]
+; MIDI acoustic piano (GM01)
+;****************************************************************************
+
+Instr_MidiPiano:
+ incbin "data/fm/piano.eif"
+
+;****************************************************************************
+; Instrument $0A [FM]
+; MIDI square wave instrument (GM81)
+;****************************************************************************
+
+Instr_MidiLead1:
+ incbin "data/fm/square.eif"
+
+;****************************************************************************
+; Instrument $0B [FM]
+; MIDI sawtooth wave instrument (GM82)
+;****************************************************************************
+
+Instr_MidiLead2:
+ incbin "data/fm/saw.eif"
+
+;****************************************************************************
+; Instrument $0C [FM]
+; MIDI flute instrument (GM74)
+;****************************************************************************
+
+Instr_MidiFlute:
+ incbin "data/fm/flute.eif"
+
+;****************************************************************************
+; Instrument $0D [PSG]
+; Nepel Four PSG instrument
+;****************************************************************************
+
+Instr_NepelPSG:
+ dc.b $05,$06,$FE,$07,$FF
+
+;****************************************************************************
+; Instrument $0E [FM]
+; MIDI synth bass (GM39)
+;****************************************************************************
+
+Instr_MidiSynthBass:
+ incbin "data/fm/ebass.eif"
+
+;****************************************************************************
+; Instrument $0F [FM]
+; MIDI square wave instrument (GM81) (filtered)
+;****************************************************************************
+
+Instr_MidiLead1F:
+ incbin "data/fm/squaref.eif"
+
+;****************************************************************************
+; Instrument $10 [FM]
+; MIDI sawtooth wave instrument (GM82) (filtered)
+;****************************************************************************
+
+Instr_MidiLead2F:
+ incbin "data/fm/sawf.eif"
+
+;****************************************************************************
+; Instrument $11 [PSG]
+; Seashore
+;****************************************************************************
+
+Instr_Seashore:
+ dcb.b 4, $0E
+ dcb.b 4, $0D
+ dcb.b 4, $0C
+ dcb.b 4, $0B
+ dcb.b 4, $0A
+ dcb.b 4, $09
+ dcb.b 4, $08
+ dcb.b 4, $07
+ dcb.b 4, $06
+ dcb.b 60, $05
+ dcb.b 4, $06
+ dcb.b 4, $07
+ dcb.b 4, $08
+ dcb.b 4, $09
+ dcb.b 4, $0A
+ dcb.b 4, $0B
+ dcb.b 4, $0C
+ dcb.b 4, $0D
+ dcb.b 4, $0E
+ dc.b $FE, $0F, $FF
+
+;****************************************************************************
+; Instrument $12 [PSG]
+; Hit-hat
+;****************************************************************************
+
+Instr_HitHat:
+ dc.b $00, $01, $02, $04, $06, $08, $0C
+ dc.b $FE, $0F, $FF
+
+;****************************************************************************
+; Instrument $13 [PSG]
+; PSG string
+;****************************************************************************
+
+Instr_PSGString:
+ dcb.b 4, $0E
+ dcb.b 4, $0D
+ dcb.b 4, $0C
+ dcb.b 4, $0B
+ dcb.b 4, $0A
+ dcb.b 4, $09
+ dcb.b 4, $08
+ dc.b $FE, $07, $FF
+
+;****************************************************************************
+; Instrument $14 [FM]
+; Electric guitar
+;****************************************************************************
+
+Instr_EGuitar:
+ incbin "data/fm/eguitar.eif"
+
diff --git a/tester/sound/sfxs.68k b/tester/sound/sfxs.68k
new file mode 100644
index 0000000..ac969dc
--- /dev/null
+++ b/tester/sound/sfxs.68k
@@ -0,0 +1,26 @@
+;****************************************************************************
+; SFX_Test
+; Generic SFX to test events
+;****************************************************************************
+
+SFX_Test:
+ dc.b $E8,$E9,$EA
+ dc.b $28,$00,$48,$00
+ dc.b $29,$08,$49,$00
+ dc.b $2A,$08,$4A,$00
+
+ dc.b $08,12,$09,24,$0A,36, $FE,$10, $18,$19,$1A, $FE,$10
+ dc.b $08,12,$09,24,$0A,36, $FE,$10, $18,$19,$1A, $FE,$10
+ dc.b $08,14,$09,26,$0A,38, $FE,$10, $18,$19,$1A, $FE,$10
+
+ dc.b $FF
+
+;****************************************************************************
+; SFX_Beep
+; Beep SFX
+;****************************************************************************
+
+SFX_Beep:
+ dc.b $EA,$1A,$4A,$00,$2A,$00
+ dc.b $0A,2*36,$FE,4
+ dc.b $FF
diff --git a/tester/video/bg.68k b/tester/video/bg.68k
new file mode 100644
index 0000000..c64e287
--- /dev/null
+++ b/tester/video/bg.68k
@@ -0,0 +1,43 @@
+;****************************************************************************
+; DrawBG
+; Draws the background
+;****************************************************************************
+
+DrawBG:
+ lea ($C00004), a2
+ lea ($C00000), a1
+
+ lea (@BGData), a0
+ move.l #$60000003, d0
+ moveq #28-1, d6
+@YLoop:
+ move.l d0, (a2)
+ moveq #40-1, d7
+@XLoop:
+ move.w (a0)+, (a1)
+ dbf d7, @XLoop
+ add.l #$00800000, d0
+ dbf d6, @YLoop
+
+ lea (@BGData), a0
+ move.l #$60000002, d0
+ moveq #28-1, d6
+@YLoop2:
+ move.l d0, (a2)
+ moveq #40-1, d7
+@XLoop2:
+ move.w (a0)+, d1
+ bset.l #11, d1
+ move.w d1, (a1)
+ dbf d7, @XLoop2
+ add.l #$00800000, d0
+ dbf d6, @YLoop2
+
+ rts ; End of subroutine
+
+;****************************************************************************
+; Background data
+;****************************************************************************
+
+@BGData:
+ incbin "data/bg.bin"
diff --git a/tester/video/text.68k b/tester/video/text.68k
new file mode 100644
index 0000000..832605e
--- /dev/null
+++ b/tester/video/text.68k
@@ -0,0 +1,108 @@
+;****************************************************************************
+; LoadFont
+; Loads the font in VRAM
+;****************************************************************************
+
+LoadFont:
+ move.l #$40000000, ($C00004) ; Where font will be stored
+
+ lea (@Font), a0 ; Font data
+ lea ($C00000), a1 ; VDP data port
+ move.w #96*16-1, d7 ; Go through all lines
+@Loop:
+
+ move.b (a0)+, d0 ; Fetch next line
+ moveq #0, d1 ; Initial color
+ moveq #8-1, d6 ; Go through all pixels
+@ILoop:
+
+ add.b d0, d0 ; Get pixel color
+ bcc.s @Transparent
+ moveq #3, d1
+@Transparent:
+ subq.b #1, d1
+ bgt.s @NoUnderflow
+ moveq #0, d1
+@NoUnderflow:
+
+ lsl.l #4, d2 ; Make room for pixel
+ or.b d1, d2 ; Store pixel
+ dbf d6, @ILoop ; Next pixel
+
+ move.l d2, (a1) ; Store line in VRAM
+ dbf d7, @Loop ; Next line
+
+ rts ; End of subroutine
+
+@Font:
+ incbin "data/font.bin"
+
+;****************************************************************************
+; WriteString
+; Writes a string on screen
+;
+; input d0.w ... X coordinate
+; input d1.w ... Y coordinate
+; input d2.w ... FX and such
+; input a0.l ... String
+;****************************************************************************
+
+WriteString:
+ movem.l d0-d2, -(sp) ; Save registers
+
+ lsl.w #6, d1 ; Calculate address
+ add.w d1, d0
+ add.w d0, d0
+
+ and.l #$FFFF, d0 ; Tell VDP the address
+ or.l #$00034000, d0
+ swap d0
+ move.l d0, ($C00004)
+
+ lea ($C00000), a5 ; VDP data port
+ moveq #2-1, d7 ; Go through both lines
+@Loop:
+
+ move.l a0, a6
+@ILoop:
+ move.b (a6)+, d1 ; Get next character
+ beq.s @End ; End of string?
+
+ sub.b #$20, d1 ; Write tile in VRAM
+ and.w #$7F, d1
+ add.w d1, d1
+ add.w d2, d1
+ move.w d1, (a5)
+
+ bra.s @ILoop ; Next character
+
+@End:
+ add.l #$80<<16, d0
+ move.l d0, ($C00004)
+ addq.w #1, d2 ; Next line
+ dbf d7, @Loop
+
+ movem.l (sp)+, d0-d2 ; Restore registers
+ rts ; End of subroutine
+
+;****************************************************************************
+; ClearLines
+; Clears the description lines
+;****************************************************************************
+
+ClearLines:
+ move.l #$448E0003, d0 ; Initial position to clear
+ lea ($C00004), a0 ; VDP control port
+ lea ($C00000), a1 ; VDP data port
+
+ moveq #7-1, d1 ; Clear all lines
+ moveq #0, d2
+@Loop:
+ move.l d0, (a0)
+ rept 26/2
+ move.l d2, (a1)
+ endr
+ add.l #$80<<16, d0
+ dbf d1, @Loop
+
+ rts ; End of subroutine
diff --git a/tester/video/vsync.68k b/tester/video/vsync.68k
new file mode 100644
index 0000000..ed5ac17
--- /dev/null
+++ b/tester/video/vsync.68k
@@ -0,0 +1,19 @@
+;****************************************************************************
+; VSync
+; Waits until the next frame
+;****************************************************************************
+
+VSync:
+ lea ($C00004), a6
+
+@Loop1: ; Wait until current VBlank is over
+ move.w (a6), d7
+ btst.l #3, d7
+ bne.s @Loop1
+
+@Loop2: ; Wait until next VBlank starts
+ move.w (a6), d7
+ btst.l #3, d7
+ beq.s @Loop2
+
+ rts ; End of subroutine