; ; File: atari2600.library.asm ; Author: Neil Cafferkey ; Copyright (C) 1999-2001 Neil Cafferkey ; ; This program is free software; you can redistribute it and/or ; modify it under the terms of the GNU General Public License ; as published by the Free Software Foundation; either version 2 ; of the License, or (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 59 Temple Place - Suite 330, Boston, ; MA 02111-1307, USA. ; ; This shared library provides an emulated Atari 2600 environment to ; translated Atari 2600 programs. ; Specify that this library contains code that requires at least ; a 68020 processor. machine 68020 ; Includes include "exec/types.i" include "exec/macros.i" include "exec/nodes.i" include "exec/initializers.i" include "exec/memory.i" include "exec/resident.i" include "intuition/screens.i" include "libraries/gadtools.i" include "graphics/text.i" include "graphics/displayinfo.i" include "utility/tagitem.i" include "workbench/workbench.i" include "workbench/startup.i" include "workbench/icon.i" include "devices/audio.i" include "exec/io.i" include "libraries/asl.i" include "libraries/atari2600.i" include "atari2600base.i" ; Constant definitions VERSION equ 2 REVISION equ 4 SCREEN_BUFFER_COUNT equ 3 SCREEN_DEPTH equ 7 X_MAG equ 2 VSYNC_SPEED_FACTOR equ 259 DEFAULT_START_LINE equ 30 ; officially 37 TV_WIDTH equ 160 DEFAULT_TV_HEIGHT equ 230 ; officially 192 TV_HEIGHT equ DEFAULT_TV_HEIGHT MENU_BAR_HEIGHT equ 11 BYTES_PER_LINE equ TV_WIDTH/8 SUMMARY_SIZE equ ((DEFAULT_TV_HEIGHT-1)>>2+1)<<2 PATTERN_SIZE equ SUMMARY_SIZE*BYTES_PER_LINE LIST_SIZE equ DEFAULT_TV_HEIGHT*3*8 BITDEF SWCHB,NORESET,0 BITDEF SWCHB,NOSELECT,1 BITDEF SWCHB,COLOUR,3 BITDEF SWCHB,P0PRO,6 BITDEF SWCHB,P1PRO,7 BITDEF SWCHA,P1UP,0 BITDEF SWCHA,P1DOWN,1 BITDEF SWCHA,P1LEFT,2 BITDEF SWCHA,P1RIGHT,3 BITDEF SWCHA,P0UP,4 BITDEF SWCHA,P0DOWN,5 BITDEF SWCHA,P0LEFT,6 BITDEF SWCHA,P0RIGHT,7 JOY_CODE equ $7f PADDLE_CHARGE_THRESHOLD equ 4000000 I4_LATCHES_MASK equ $40 ; Enumerated constants for graphics objects ENUM EITEM PF EITEM P0 EITEM P1 EITEM BL EITEM M0 EITEM M1 EITEM OBJECT_COUNT REDUCED_OBJECT_COUNT equ OBJECT_COUNT/2 BITDEF OBJECT,PF,PF BITDEF OBJECT,P0,P0 BITDEF OBJECT,P1,P1 BITDEF OBJECT,BL,BL BITDEF OBJECT,M0,M0 BITDEF OBJECT,M1,M1 ENUM EITEM PF_COLOUR EITEM P0_COLOUR EITEM P1_COLOUR EITEM BK_COLOUR EITEM PEN_COUNT PATTERN_COUNT equ OBJECT_COUNT+PEN_COUNT*SCREEN_DEPTH+1 REDUCED_PATTERN_COUNT equ REDUCED_OBJECT_COUNT+PEN_COUNT*SCREEN_DEPTH+1 OBJO_UNDELAYEDGRAPHICS EQU 24 OBJW_UNDELAYEDGRAPHICS EQU 8 OBJO_DELAYEDGRAPHICS EQU 16 OBJW_DELAYEDGRAPHICS EQU 8 OBJO_POSITION EQU 8 OBJW_POSITION EQU 8 BITDEF OBJ,REFLECTION,24 BITDEF OBJ,VDELAY,25 BITDEF OBJ,VBLANK,26 BITDEF OBJ,LOCKED,27 OBJO_NUMBERSIZE EQU 0 OBJW_NUMBERSIZE EQU 3 OBJO_WIDTH EQU 0 OBJW_WIDTH EQU 2 BITDEF OBJ,UNDELAYEDENABLE,0 BITDEF OBJ,DELAYEDENABLE,8 OBJO_GRAPHICS0 EQU 8 OBJW_GRAPHICS0 EQU 8 OBJO_GRAPHICS1 EQU 16 OBJW_GRAPHICS1 EQU 8 OBJO_GRAPHICS2 EQU 24 OBJW_GRAPHICS2 EQU 8 PENO_LEFTCOLOUR EQU 8 PENW_LEFTCOLOUR EQU 8 PENO_RIGHTCOLOUR EQU 16 PENW_RIGHTCOLOUR EQU 8 PENO_NORMALCOLOUR EQU 24 PENW_NORMALCOLOUR EQU 8 BITDEF PEN,VBLANK,26 BITDEF PEN,SCOREMODE,25 BITDEF PEN,NORMALENABLE,0 BITDEF PEN,RIGHTENABLE,8 BITDEF PEN,LEFTENABLE,16 BITDEF PRI,ON,0 SOUND_FREQUENCY equ 31400 SOUND_PERIOD equ (1000000000/280)/SOUND_FREQUENCY SOUND_PRIORITY equ 70 AUDIO_CHANNEL_COUNT equ 2 AUDIO_BUFFER_COUNT equ 2 FOUR_BIT_POLY_SIZE equ $f FIVE_BIT_POLY_SIZE equ $1f NINE_BIT_POLY_SIZE equ $1ff SLOW_PURE_SIZE equ 6 FIVE_BIT_POLY_PATTERN equ %0010110011111000110111010100001<<1 DIV_31_PATTERN equ %0100000000000000000100000000000<<1 SOUND_0_MULTIPLE equ 4 ;256 ; Must be multiple of four SOUND_1_MULTIPLE equ 2 ;16 ; Must be even SOUND_2_MULTIPLE equ 2 ; Must be even SOUND_3_MULTIPLE equ 2 ; Must be even SOUND_4_MULTIPLE equ 4 ;256 ; Must be multiple of four SOUND_6_MULTIPLE equ 2 ; Must be even SOUND_7_MULTIPLE equ 2 ; Must be even SOUND_8_MULTIPLE equ 2 ; Must be even SOUND_9_MULTIPLE equ 2 ; Must be even SOUND_12_MULTIPLE equ 1 ;42 SOUND_14_MULTIPLE equ 2 ; Must be even SOUND_15_MULTIPLE equ 2 ; Must be even ENUM EITEM NOCONTROLLER EITEM JOYSTICK EITEM PADDLES EITEM DRIVING EITEM KEYPAD EITEM CONTROLLER_COUNT SCREENMODE_STR_SIZE equ 12 ; The structure representing an Atari 2600 environment STRUCTURE Atari2600Env,0 APTR env_ProgramName APTR env_OriginalStackPtr FPTR env_ExitFunction APTR env_DiskObject APTR env_ProgramFileName ULONG env_HomeDirLock APTR env_ScreenTags APTR env_Screen APTR env_WindowTags APTR env_ScreenReq APTR env_ScreenReqTags ULONG env_ScreenModeID APTR env_ScreenModeString APTR env_Window APTR env_Menus APTR env_VisualInfo APTR env_UserPort STRUCT env_ScreenBitMaps,SCREEN_BUFFER_COUNT*4 STRUCT env_ScreenBuffers,SCREEN_BUFFER_COUNT*4 APTR env_SafeMsgPort APTR env_DispMsgPort APTR env_AboutRequester ULONG env_FrameCount ULONG env_PrevFrameCount ULONG env_SecondCount ULONG env_MillisecondCount UWORD env_FramesPerSecond BOOL env_VerticalSync ULONG env_ClockAtVSyncOn ULONG env_ClockAtPotDumpDisable ULONG env_ClockAtPaddleUpdate STRUCT env_PaddleCharges,4*4 STRUCT env_PaddlesCharged,4*2 APTR env_Data ULONG env_ClockOffset BOOL env_VerticalBlank UWORD env_StartingLineNo UWORD env_TVHeight UWORD env_TVHeightPad ULONG env_LineOffset APTR env_PlanePtrs STRUCT env_TempPlanePtrs,SCREEN_DEPTH*4 APTR env_DifferencePattern APTR env_ObjectDifferencePattern ULONG env_Timer UWORD env_TimerShift BOOL env_I4LatchEnable STRUCT env_Settings,PATTERN_COUNT*4 APTR env_PatternLine STRUCT env_Patterns,PATTERN_COUNT*4 STRUCT env_MergedPatterns,REDUCED_PATTERN_COUNT*(SCREEN_BUFFER_COUNT+1)*4 STRUCT env_PatternLists,PATTERN_COUNT*(SCREEN_BUFFER_COUNT+1)*4 STRUCT env_PatternListPtrs,PATTERN_COUNT*4 STRUCT env_PatternListLimits,PATTERN_COUNT*4 STRUCT env_DifferencePatterns,REDUCED_PATTERN_COUNT*4 STRUCT env_SummaryPatterns,OBJECT_COUNT*4 STRUCT env_CollisionPatterns,OBJECT_COUNT*(SCREEN_BUFFER_COUNT+1)*4 STRUCT env_MotionRates,OBJECT_COUNT*2 UWORD env_FrameSkipRatio UWORD env_VSyncOffAttempts UWORD env_IdealFrameRate UWORD env_SkipMenuOffset ULONG env_PatternSize ULONG env_ScreenHeight ULONG env_RoundedTVHeight APTR env_AudioIO APTR env_AudioMsgPort BOOL env_AudioOpen WORD env_AudioKey STRUCT env_AudioChannelMasks,AUDIO_CHANNEL_COUNT*4 STRUCT env_PerVolIO,AUDIO_CHANNEL_COUNT*4 STRUCT env_ToneTypeIO,AUDIO_CHANNEL_COUNT*AUDIO_BUFFER_COUNT*4 STRUCT env_ToneTypeNo,2 STRUCT env_FrequencyNo,2 STRUCT env_VolumeNo,2 BOOL env_SoundOn ULONG env_ScreenSwapWaitTime STRUCT env_ControllerTypes,2 BOOL env_WBStart BOOL env_PotsDumped UWORD env_MouseX IFD PROFILE STRUCT env_ProfileData,1024 ENDC LABEL env_SIZEOF code Start: ; Exit with an error if an attempt is made to run the library as a ; program. moveq #-1,d0 rts rom_tag: ; STRUCTURE RT,0 dc.w RTC_MATCHWORD ; UWORD RT_MATCHWORD dc.l rom_tag ; APTR RT_MATCHTAG dc.l end_of_library ; APTR RT_ENDSKIP dc.b RTF_AUTOINIT ; UBYTE RT_FLAGS dc.b VERSION ; UBYTE RT_VERSION dc.b NT_LIBRARY ; UBYTE RT_TYPE dc.b 0 ; BYTE RT_PRI dc.l library_name ; APTR RT_NAME dc.l id_string ; APTR RT_IDSTRING dc.l init_table ; APTR RT_INIT ; Declare the library's name library_name: dc.b "atari2600.library",0 ; Incorporate the version string id_string: dc.b "atari2600.library 2.4 (19.9.2001)",0 ; Declare the names of other libraries used intuition_name: dc.b "intuition.library",0 gadtools_name: dc.b "gadtools.library",0 graphics_name: dc.b "graphics.library",0 utility_name: dc.b "utility.library",0 icon_name: ICONNAME dos_name: dc.b "dos.library",0 asl_name: AslName audio_name: AUDIONAME cnop 0,2 init_table: ; Declare the auto-initialisation table referenced in the rom tag dc.l Atari2600Base_SIZEOF ; size of library base data space dc.l function_table ; pointer to function initializers dc.l data_table ; pointer to data initializers dc.l Initialise ; routine to run function_table: ; Standard system routines dc.l Open dc.l Close dc.l Expunge dc.l Null ; Stella functions ($0-$3f) dc.l VSync dc.l VBlank dc.l WSync dc.l NoFunction dc.l NuSiz0 dc.l NuSiz1 dc.l CoLuP0 dc.l CoLuP1 dc.l CoLuPF dc.l CoLuBk dc.l CtrlPF dc.l RefP0 dc.l RefP1 dc.l PF0 dc.l PF1 dc.l PF2 dc.l ResP0 dc.l ResP1 dc.l ResM0 dc.l ResM1 dc.l ResBl dc.l AudC0 dc.l AudC1 dc.l AudF0 dc.l AudF1 dc.l AudV0 dc.l AudV1 dc.l GrP0 dc.l GrP1 dc.l EnaM0 dc.l EnaM1 dc.l EnaBl dc.l HMP0 dc.l HMP1 dc.l HMM0 dc.l HMM1 dc.l HMBl dc.l VDelP0 dc.l VDelP1 dc.l VDelBl dc.l ResMP0 dc.l ResMP1 dc.l HMove dc.l HMClr dc.l CxClr dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction ; Stella function duplicates ($40-$7f) dc.l VSync dc.l VBlank dc.l WSync dc.l NoFunction dc.l NuSiz0 dc.l NuSiz1 dc.l CoLuP0 dc.l CoLuP1 dc.l CoLuPF dc.l CoLuBk dc.l CtrlPF dc.l RefP0 dc.l RefP1 dc.l PF0 dc.l PF1 dc.l PF2 dc.l ResP0 dc.l ResP1 dc.l ResM0 dc.l ResM1 dc.l ResBl dc.l AudC0 dc.l AudC1 dc.l AudF0 dc.l AudF1 dc.l AudV0 dc.l AudV1 dc.l GrP0 dc.l GrP1 dc.l EnaM0 dc.l EnaM1 dc.l EnaBl dc.l HMP0 dc.l HMP1 dc.l HMM0 dc.l HMM1 dc.l HMBl dc.l VDelP0 dc.l VDelP1 dc.l VDelBl dc.l ResMP0 dc.l ResMP1 dc.l HMove dc.l HMClr dc.l CxClr dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction ; Other functions dc.l OpenAtari2600 dc.l CloseAtari2600 dc.l InstallROM ; No functions ($83-$100) dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction ; Stella function duplicates ($100-$13f) dc.l VSync dc.l VBlank dc.l WSync dc.l NoFunction dc.l NuSiz0 dc.l NuSiz1 dc.l CoLuP0 dc.l CoLuP1 dc.l CoLuPF dc.l CoLuBk dc.l CtrlPF dc.l RefP0 dc.l RefP1 dc.l PF0 dc.l PF1 dc.l PF2 dc.l ResP0 dc.l ResP1 dc.l ResM0 dc.l ResM1 dc.l ResBl dc.l AudC0 dc.l AudC1 dc.l AudF0 dc.l AudF1 dc.l AudV0 dc.l AudV1 dc.l GrP0 dc.l GrP1 dc.l EnaM0 dc.l EnaM1 dc.l EnaBl dc.l HMP0 dc.l HMP1 dc.l HMM0 dc.l HMM1 dc.l HMBl dc.l VDelP0 dc.l VDelP1 dc.l VDelBl dc.l ResMP0 dc.l ResMP1 dc.l HMove dc.l HMClr dc.l CxClr dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction ; Stella function duplicates ($140-$17f) dc.l VSync dc.l VBlank dc.l WSync dc.l NoFunction dc.l NuSiz0 dc.l NuSiz1 dc.l CoLuP0 dc.l CoLuP1 dc.l CoLuPF dc.l CoLuBk dc.l CtrlPF dc.l RefP0 dc.l RefP1 dc.l PF0 dc.l PF1 dc.l PF2 dc.l ResP0 dc.l ResP1 dc.l ResM0 dc.l ResM1 dc.l ResBl dc.l AudC0 dc.l AudC1 dc.l AudF0 dc.l AudF1 dc.l AudV0 dc.l AudV1 dc.l GrP0 dc.l GrP1 dc.l EnaM0 dc.l EnaM1 dc.l EnaBl dc.l HMP0 dc.l HMP1 dc.l HMM0 dc.l HMM1 dc.l HMBl dc.l VDelP0 dc.l VDelP1 dc.l VDelBl dc.l ResMP0 dc.l ResMP1 dc.l HMove dc.l HMClr dc.l CxClr dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction ; No functions ($180-$27f) dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction ; Riot functions ; ($280-$2a0) dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l InTim dc.l Tim1T dc.l Tim8T dc.l Tim64T dc.l Tim1024T ; Skip to the $380th custom function dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction ; Riot function duplicates dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l NoFunction dc.l InTim dc.l Tim1T dc.l Tim8T dc.l Tim64T dc.l Tim1024T ; Function table end marker dc.l -1 ; Initialise the library's data table data_table: INITBYTE LN_TYPE,NT_LIBRARY INITLONG LN_NAME,library_name INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED INITWORD LIB_VERSION,VERSION INITWORD LIB_REVISION,REVISION INITLONG LIB_IDSTRING,id_string dc.l 0 even ;****i* atari2600.library/Initialise *** ; ; NAME ; Initialise ; ; SYNOPSIS ; success = Initialise(library,exec,seg_list) ; d0 a6 a0 ; ;*** ; ; Initialise: ; Push registers that should be preserved onto stack movem.l d2-d4/a2/a4-a5,-(sp) ; Store parameters move.l d0,a5 move.l a6,(ab_SysLib,a5) move.l a0,(ab_SegList,a5) ; Check exec.library is v36+ cmpi.w #36,(LIB_VERSION,a6) blo clean_up$ ; Open intuition.library v39+ lea intuition_name,a1 moveq #39,d0 JSRLIB OpenLibrary move.l d0,ab_IntuitionLib(a5) beq clean_up$ ; Open gadtools.library v39+ lea gadtools_name,a1 moveq #39,d0 JSRLIB OpenLibrary move.l d0,ab_GadtoolsLib(a5) beq clean_up$ ; Open graphics.library v39+ lea graphics_name,a1 moveq #39,d0 JSRLIB OpenLibrary move.l d0,ab_GraphicsLib(a5) beq clean_up$ ; Open utility.library v39+ lea utility_name,a1 moveq #39,d0 JSRLIB OpenLibrary move.l d0,(ab_UtilityLib,a5) beq clean_up$ ; Open any version of icon.library lea icon_name,a1 moveq #0,d0 JSRLIB OpenLibrary move.l d0,(ab_IconLib,a5) beq clean_up$ ; Open dos.library v36+ lea dos_name,a1 moveq #36,d0 JSRLIB OpenLibrary move.l d0,(ab_DosLib,a5) beq clean_up$ ; Open asl.library v38+ lea asl_name,a1 moveq #38,d0 JSRLIB OpenLibrary move.l d0,(ab_AslLib,a5) beq clean_up$ ; Allocate memory for word-to-long stretch table move.l #(1<<16)*4,d0 move.l #MEMF_PUBLIC,d1 JSRLIB AllocMem move.l d0,(ab_WordToLongTable,a5) beq clean_up$ ; Fill in word-to-long stretch table movea.l (ab_WordToLongTable,a5),a2 move.w #256-1,d1 movea.l #word_stretch_table,a1 upper_loop$: move.w (a1)+,d2 swap.w d2 move.w #256-1,d0 movea.l #word_stretch_table,a0 lower_loop$: move.w (a0)+,d2 move.l d2,(a2)+ dbra d0,lower_loop$ dbra d1,upper_loop$ ; Allocate memory for sound 0 move.l #SOUND_0_MULTIPLE,d0 move.l #MEMF_PUBLIC|MEMF_CHIP,d1 JSRLIB AllocMem move.l d0,(ab_Sounds,a5) move.l d0,(ab_Sounds+11*4,a5) beq clean_up$ ; Create sound 0 moveq #SOUND_0_MULTIPLE>>2-1,d2 movea.l d0,a0 sound_0_loop$: move.l #$7f7f7f7f,(a0)+ dbra d2,sound_0_loop$ ; Allocate memory for sound 1 move.l #FOUR_BIT_POLY_SIZE*SOUND_1_MULTIPLE,d0 move.l #MEMF_PUBLIC|MEMF_CHIP,d1 JSRLIB AllocMem move.l d0,(ab_Sounds+4,a5) beq clean_up$ ; Create sound 1 moveq #SOUND_1_MULTIPLE-1,d2 movea.l d0,a2 sound_1_loop$: movea.l #four_bit_poly_pattern,a0 movea.l a2,a1 move.l #FOUR_BIT_POLY_SIZE,d0 JSRLIB CopyMem adda.l #FOUR_BIT_POLY_SIZE,a2 dbra d2,sound_1_loop$ ; Allocate memory for sound 2 move.l #FIVE_BIT_POLY_SIZE*FOUR_BIT_POLY_SIZE*SOUND_2_MULTIPLE,d0 move.l #MEMF_PUBLIC|MEMF_CHIP,d1 JSRLIB AllocMem move.l d0,(ab_Sounds+2*4,a5) beq clean_up$ ; Create sound 2 moveq #SOUND_2_MULTIPLE-1,d2 movea.l d0,a0 moveq #-128,d0 sound_2_loop$: move.l #DIV_31_PATTERN,d1 moveq #FOUR_BIT_POLY_SIZE-1,d4 movea.l #four_bit_poly_pattern,a1 moveq #0,d3 sound_2_inner_loop$: rol.l #1,d1 bcc sound_2_no_change$ move.b (a1)+,d0 dbra d4,sound_2_no_change$ moveq #FOUR_BIT_POLY_SIZE-1,d4 movea.l #four_bit_poly_pattern,a1 sound_2_no_change$: cmpi.l #DIV_31_PATTERN>>1,d1 bne sound_2_no_adjust$ rol.l #1,d1 addq.b #1,d3 sound_2_no_adjust$: move.b d0,(a0)+ cmpi.b #FOUR_BIT_POLY_SIZE,d3 bne sound_2_inner_loop$ dbra d2,sound_2_loop$ ; Allocate memory for sound 3 move.l #FIVE_BIT_POLY_SIZE*FOUR_BIT_POLY_SIZE*SOUND_3_MULTIPLE,d0 move.l #MEMF_PUBLIC|MEMF_CHIP,d1 JSRLIB AllocMem move.l d0,(ab_Sounds+3*4,a5) beq clean_up$ ; Create sound 3 moveq #SOUND_3_MULTIPLE-1,d2 movea.l d0,a0 moveq #-128,d0 sound_3_loop$: move.l #FIVE_BIT_POLY_PATTERN,d1 moveq #FOUR_BIT_POLY_SIZE-1,d4 movea.l #four_bit_poly_pattern,a1 moveq #0,d3 sound_3_inner_loop$: rol.l #1,d1 bcc sound_3_no_change$ move.b (a1)+,d0 dbra d4,sound_3_no_change$ moveq #FOUR_BIT_POLY_SIZE-1,d4 movea.l #four_bit_poly_pattern,a1 sound_3_no_change$: cmpi.l #FIVE_BIT_POLY_PATTERN>>1,d1 bne sound_3_no_adjust$ rol.l #1,d1 addq.b #1,d3 sound_3_no_adjust$: move.b d0,(a0)+ cmpi.b #FOUR_BIT_POLY_SIZE,d3 bne sound_3_inner_loop$ dbra d2,sound_3_loop$ ; Allocate memory for sound 4 move.l #SOUND_4_MULTIPLE,d0 move.l #MEMF_PUBLIC|MEMF_CHIP,d1 JSRLIB AllocMem move.l d0,(ab_Sounds+4*4,a5) move.l d0,(ab_Sounds+5*4,a5) beq clean_up$ ; Create sound 4 moveq #SOUND_4_MULTIPLE>>2-1,d2 movea.l d0,a0 sound_4_loop$: move.l #$7f807f80,(a0)+ dbra d2,sound_4_loop$ ; Allocate memory for sound 6 move.l #31*SOUND_6_MULTIPLE,d0 move.l #MEMF_PUBLIC|MEMF_CHIP,d1 JSRLIB AllocMem move.l d0,(ab_Sounds+6*4,a5) move.l d0,(ab_Sounds+10*4,a5) beq clean_up$ ; Create sound 6 moveq #SOUND_6_MULTIPLE-1,d2 movea.l d0,a2 sound_6_loop$: movea.l #div_31_pattern,a0 movea.l a2,a1 move.l #31,d0 JSRLIB CopyMem adda.l #31,a2 dbra d2,sound_6_loop$ ; Allocate memory for sound 7 move.l #FIVE_BIT_POLY_SIZE*SOUND_7_MULTIPLE,d0 move.l #MEMF_PUBLIC|MEMF_CHIP,d1 JSRLIB AllocMem move.l d0,(ab_Sounds+7*4,a5) beq clean_up$ ; Create sound 7 moveq #SOUND_7_MULTIPLE-1,d2 movea.l d0,a0 moveq #-128,d0 sound_7_loop$: moveq #FIVE_BIT_POLY_SIZE-1,d3 move.l #FIVE_BIT_POLY_PATTERN,d1 sound_7_inner_loop$: lsl.l #1,d1 bcc sound_7_no_change$ not.b d0 sound_7_no_change$: move.b d0,(a0)+ dbra d3,sound_7_inner_loop$ dbra d2,sound_7_loop$ ; Allocate memory for sound 8 move.l #NINE_BIT_POLY_SIZE*SOUND_8_MULTIPLE,d0 move.l #MEMF_PUBLIC|MEMF_CHIP,d1 JSRLIB AllocMem move.l d0,(ab_Sounds+8*4,a5) beq clean_up$ ; Create sound 8 moveq #SOUND_8_MULTIPLE-1,d2 movea.l d0,a2 sound_8_loop$: movea.l #nine_bit_poly_pattern,a0 movea.l a2,a1 move.l #NINE_BIT_POLY_SIZE,d0 JSRLIB CopyMem adda.l #NINE_BIT_POLY_SIZE,a2 dbra d2,sound_8_loop$ ; Allocate memory for sound 9 move.l #FIVE_BIT_POLY_SIZE*SOUND_9_MULTIPLE,d0 move.l #MEMF_PUBLIC|MEMF_CHIP,d1 JSRLIB AllocMem move.l d0,(ab_Sounds+9*4,a5) beq clean_up$ ; Create sound 9 moveq #SOUND_9_MULTIPLE-1,d2 movea.l d0,a2 sound_9_loop$: movea.l #five_bit_poly_pattern,a0 movea.l a2,a1 move.l #FIVE_BIT_POLY_SIZE,d0 JSRLIB CopyMem adda.l #FIVE_BIT_POLY_SIZE,a2 dbra d2,sound_9_loop$ ; Allocate memory for sound 12 move.l #SLOW_PURE_SIZE*SOUND_12_MULTIPLE,d0 move.l #MEMF_PUBLIC|MEMF_CHIP,d1 JSRLIB AllocMem move.l d0,(ab_Sounds+12*4,a5) move.l d0,(ab_Sounds+13*4,a5) beq clean_up$ ; Create sound 12 moveq #SOUND_12_MULTIPLE-1,d2 movea.l d0,a2 sound_12_loop$: movea.l #slow_pure_pattern,a0 movea.l a2,a1 move.l #SLOW_PURE_SIZE,d0 JSRLIB CopyMem adda.l #SLOW_PURE_SIZE,a2 dbra d2,sound_12_loop$ ; Allocate memory for sound 14 move.l #93*SOUND_14_MULTIPLE,d0 move.l #MEMF_PUBLIC|MEMF_CHIP,d1 JSRLIB AllocMem move.l d0,(ab_Sounds+14*4,a5) beq clean_up$ ; Create sound 14 moveq #SOUND_14_MULTIPLE-1,d2 movea.l d0,a2 sound_14_loop$: movea.l #div_93_pattern,a0 movea.l a2,a1 move.l #93,d0 JSRLIB CopyMem adda.l #93,a2 dbra d2,sound_14_loop$ ; Allocate memory for sound 15 move.l #FIVE_BIT_POLY_SIZE*3*SOUND_15_MULTIPLE,d0 move.l #MEMF_PUBLIC|MEMF_CHIP,d1 JSRLIB AllocMem move.l d0,(ab_Sounds+15*4,a5) beq clean_up$ ; Create sound 15 moveq #SOUND_15_MULTIPLE-1,d2 movea.l d0,a0 moveq #-128,d0 sound_15_loop$: moveq #FIVE_BIT_POLY_SIZE-1,d3 move.l #FIVE_BIT_POLY_PATTERN,d1 sound_15_inner_loop$: lsl.l #1,d1 bcc sound_15_no_change$ not.b d0 sound_15_no_change$: move.b d0,(a0)+ move.b d0,(a0)+ move.b d0,(a0)+ dbra d3,sound_15_inner_loop$ dbra d2,sound_15_loop$ ; Set library pointer as return value move.l a5,d0 bra skip_clean_up$ clean_up$: ; Deallocate resources and set return value to nought bsr CleanUp moveq #0,d0 skip_clean_up$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d4/a2/a4-a5 rts ;****i* atari2600.library/Open *** ; ; NAME ; Open ; ; SYNOPSIS ; library_pointer = Open(library,version) ; d0 a6 d0 ; ;*** ; ; Open: ; Mark the library as having another user addq.w #1,(LIB_OPENCNT,a6) ; Prevent delayed expunges bclr #LIBB_DELEXP,(LIB_FLAGS,a6) ; Return with library pointer as result move.l a6,d0 rts ;****i* atari2600.library/Close *** ; ; NAME ; Close ; ; SYNOPSIS ; Close(library) ; a6 ; ;*** ; ; Close: ; Set the default return value moveq #0,d0 ; Mark the library as having one fewer users subq.w #1,(LIB_OPENCNT,a6) ; See if anyone still has the library open bne skip_expunge$ ; See if there is a delayed expunge pending btst #LIBB_DELEXP,(LIB_FLAGS,a6) beq skip_expunge$ ; Expunge the library bsr Expunge skip_expunge$: ; Return rts ;****i* atari2600.library/Expunge *** ; ; NAME ; Expunge ; ; SYNOPSIS ; Expunge(library) ; a6 ; ;*** ; ; Expunge: ; Push registers that should be preserved onto stack movem.l d2/a5/a6,-(sp) ; Store parameters move.l a6,a5 ; Check if anyone has this library open tst.w (LIB_OPENCNT,a5) beq skip_set_delayed_expunge$ ; Set the delayed-expunge flag, set return value to null and skip ; the rest of this function. bset #LIBB_DELEXP,(LIB_FLAGS,a5) moveq #0,d0 bra end$ skip_set_delayed_expunge$: ; Get the library's segment list move.l (ab_SegList,a5),d2 ; Unlink this library from the library list move.l a5,a1 move.l (ab_SysLib,a5),a6 JSRLIB Remove ; Deallocate the library's resources bsr CleanUp ; Set the library's segment list to be the return value move.l d2,d0 end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2/a5/a6 rts ;****i* atari2600.library/Null *** ; ; NAME ; Null ; ; SYNOPSIS ; Null(library) ; a6 ; ;*** ; ; Null: moveq #0,d0 rts ;****** atari2600.library/A2600_VSync *** ; ; NAME ; A2600_VSync -- Start or end an Atari 2600 video frame. ; ; SYNOPSIS ; A2600_VSync(new_state,clock,env) ; d0 d1 a1 ; ; VOID A2600_VSync(ULONG,ULONG,APTR); ; ; FUNCTION ; Signals the start or end of the emulated vertical retrace period, ; which occurs between every pair of consecutive frames. ; ; INPUTS ; new_state - Frame ends if bit 1 is set; otherwise a new frame is ; begun. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ; SEE ALSO ; A2600_VBlank() ; ;*** ; ; VSync: ; rts ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d7/a2-a6,-(sp) ; Store parameters movea.l a6,a5 movea.l a1,a3 move.l d0,d2 move.l d1,d3 ; See what the new state is btst #1,d2 beq off$ on$: ; Calculate current colour clock mulu.w #A2600_CLR_CLK_FACTOR,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Update all pattern lists moveq #PATTERN_COUNT-1,d2 pattern_update_loop$: move.l d3,d1 move.l d2,d0 movea.l a3,a1 bsr UpdatePatternList dbra d2,pattern_update_loop$ ; Check vsync isn't already on, then put it on tst.w (env_VerticalSync,a3) bne end$ move.w #1,(env_VerticalSync,a3) ; Finish the current frame movea.l a5,a6 movea.l a3,a1 bsr FinishFrame ; Repaint areas of screen buffer that should change movea.l a5,a6 movea.l a3,a1 bsr UpdateScreen ; Exchange hidden bitmap with visible one movea.l a5,a6 movea.l a3,a1 bsr ChangeDisplay bra end$ off$: ; Check vsync isn't already off tst.w (env_VerticalSync,a3) beq end$ ; Check if next frame should be skipped tst.w (env_VSyncOffAttempts,a3) beq reset_attempt_count$ subq.w #1,(env_VSyncOffAttempts,a3) bra end$ reset_attempt_count$: move.w (env_FrameSkipRatio,a3),d0 subq.w #1,d0 move.w d0,(env_VSyncOffAttempts,a3) ; Turn vsync off clr.w (env_VerticalSync,a3) ; Go back to first line move.l d3,d1 divu.w #A2600_LINE_CYCLES/3,d1 clr.w d1 swap.w d1 sub.l d1,d3 add.l d3,(env_ClockOffset,a3) sub.l d3,(env_Timer,a3) sub.l d3,(env_ClockAtPotDumpDisable,a3) sub.l d3,(env_ClockAtPaddleUpdate,a3) ; ; Calculate how many lines we've gone up during vsync ; move.w d4,d0 ; sub.w (env_ClockAtVSyncOn,a3),d0 ; mulu.w #VSYNC_SPEED_FACTOR,d0 ; divu.w #A2600_LINE_CYCLES/3*3,d0 ; ; Correct clock cycle counter to be less than one scanline ; move.l d4,d0 ; divu.w #TV_WIDTH,d0 ; clr.w d0 ; swap.w d0 ; move.l d4,d1 ; sub.l d0,d1 ; add.l d1,(env_ClockOffset,a3) ; Increment frame counter addq.l #1,(env_FrameCount,a3) ; Get and respond to input from menus, joysticks etc. bsr GetUserInput ; Initialise pattern lists for upcoming frame moveq #PATTERN_COUNT-1,d2 pattern_init_loop$: movea.l (env_PatternListPtrs,a3,d2*4),a0 move.l (env_Settings,a3,d2*4),(a0)+ move.l #0,(a0) dbra d2,pattern_init_loop$ end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d7/a2-a6 rts ;****** atari2600.library/A2600_VBlank *** ; ; NAME ; A2600_VBlank -- Turn Atari 2600 vertical blanking on or off. ; ; SYNOPSIS ; A2600_VBlank(new_state,clock,env) ; d0 d1 a1 ; ; VOID A2600_VBlank(ULONG,ULONG,APTR); ; ; FUNCTION ; Begins or ends the emulated vertical blanking period. ; ; INPUTS ; new_state - Vertical blanking begins if bit 1 is set; otherwise it ; ends. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; VBlank: ; rts ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 movem.l d2-d7/a2-a6,-(sp) ; Store parameters movea.l a6,a5 movea.l a1,a3 move.l d0,d5 move.l d1,d4 ; Calculate current colour clock mulu.w #A2600_CLR_CLK_FACTOR,d1 move.l d1,d3 ; Get update position movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Update all pattern lists moveq #PATTERN_COUNT-1,d2 pattern_update_loop$: move.l d3,d1 move.l d2,d0 movea.l a3,a1 bsr UpdatePatternList dbra d2,pattern_update_loop$ ; See if new vblank state is on or off btst.b #1,d5 beq off$ on$: ; Record that vertical blanking is on move.w #1,(env_VerticalBlank,a3) moveq #PATTERN_COUNT-1,d0 on_loop$: move.l (env_Settings,a3,d0*4),d1 bset.l #OBJB_VBLANK,d1 move.l d1,(env_Settings,a3,d0*4) dbra d0,on_loop$ bra skip_off$ off$: ; Record that vertical blanking is off clr.w (env_VerticalBlank,a3) moveq #PATTERN_COUNT-1,d0 off_loop$: move.l (env_Settings,a3,d0*4),d1 bclr.l #OBJB_VBLANK,d1 move.l d1,(env_Settings,a3,d0*4) dbra d0,off_loop$ skip_off$: ; Update paddle charge move.l d4,d1 movea.l a3,a1 bsr UpdatePaddleCharge ; Check new pot dump state btst.b #7,d5 beq dump_disabled$ ; Check pot dump isn't already enabled tst.w (env_PotsDumped,a3) bne no_dump_change$ move.w #1,(env_PotsDumped,a3) clr.l (env_PaddleCharges,a3) clr.w (env_PaddlesCharged,a3) ; Clear all pot bits movea.l (env_Data,a3),a0 moveq #$70,d0 pot_dump_enable_loop$: move.l #$7f7f7f7f,(A2600_INPT0,a0,d0) subi.l #$10,d0 bpl pot_dump_enable_loop$ bra no_dump_change$ dump_disabled$: clr.w (env_PotsDumped,a3) no_dump_change$: ; move.w d5,d0 ; and.w #I4_LATCHES_MASK,d5 ; move.w d0,env_I4LatchEnable(a3) ; ; tst.w d0 ; beq skip$ ; move.b.w #INPT4 ; move.b #$80,([env_Data,a3],INPT4) ; move.b #$80,([env_Data,a3],INPT5) ;skip$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d7/a2-a6 rts ;****** atari2600.library/A2600_WSync *** ; ; NAME ; A2600_WSync -- Wait for Atari 2600 horizontal synchronisation. ; ; SYNOPSIS ; A2600_WSync(clock,env) ; d1 a1 ; ; VOID A2600_WSync(ULONG,APTR); ; ; FUNCTION ; Moves the emulated clock ahead to the end of the current scanline. ; ; INPUTS ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; WSync: IFD PROFILE addq.l #1,(env_ProfileData+$2<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Store parameters move.l d1,a0 ; Calculate number of clock cycles since start of current line divu.w #A2600_LINE_CYCLES/3,d1 ; Check if we're already at end of line clr.w d1 swap.w d1 beq at_eol$ ; Get number of cycles until end of line moveq #A2600_LINE_CYCLES/3,d0 sub.w d1,d0 ; Adjust clock-cycle counter sub.l d0,(env_ClockOffset,a1) at_eol$: ; Update paddle charge move.l a0,d1 bsr UpdatePaddleCharge ; Return rts ;****** atari2600.library/A2600_NuSiz0 *** ; ; NAME ; A2600_NuSiz0 -- Set size and duplication for first player & missile. ; ; SYNOPSIS ; A2600_NuSiz0(num_size,clock,env) ; d0 d1 a1 ; ; VOID A2600_NuSiz0(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets size and duplication modes for first player and its associated ; missile. ; ; INPUTS ; num_size - the number and size of the first player and missile. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; NuSiz0: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$4<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d3/a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Calculate current colour clock plus delay move.l d1,d0 lsl.l #1,d0 add.l d0,d1 ; mulu.w #A2600_CLR_CLK_FACTOR,d1 add.l #12,d1 ; Get update position movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Update first player's pattern list move.l d3,d1 moveq #P0,d0 movea.l a3,a1 bsr UpdatePatternList ; Update first missile's pattern list move.l d3,d1 moveq #M0,d0 movea.l a3,a1 bsr UpdatePatternList ; Set missile width move.w d2,d0 lsr.w #4,d0 move.l (env_Settings+M0*4,a3),d1 bfins d0,d1{OBJO_WIDTH:OBJW_WIDTH} move.l d1,(env_Settings+M0*4,a3) ; Store first player's new number and size move.l (env_Settings+P0*4,a3),d0 bfins d2,d0{OBJO_NUMBERSIZE:OBJW_NUMBERSIZE} move.l d0,(env_Settings+P0*4,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a3 rts ;****** atari2600.library/A2600_NuSiz1 *** ; ; NAME ; A2600_NuSiz1 -- Set size and duplication for second player & missile. ; ; SYNOPSIS ; A2600_NuSiz1(num_size,clock,env) ; d0 d1 a1 ; ; VOID A2600_NuSiz1(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets size and duplication modes for first player and its associated ; missile. ; ; INPUTS ; num_size - the number and size of the second player and missile. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; NuSiz1: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$5<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d3/a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Calculate current colour clock plus delay move.l d1,d0 lsl.l #1,d0 add.l d0,d1 ; mulu.w #A2600_CLR_CLK_FACTOR,d1 add.l #12,d1 ; Get update position movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Update first player's pattern list move.l d3,d1 moveq #P1,d0 movea.l a3,a1 bsr UpdatePatternList ; Update first missile's pattern list move.l d3,d1 moveq #M1,d0 movea.l a3,a1 bsr UpdatePatternList ; Set missile width move.w d2,d0 lsr.w #4,d0 move.l (env_Settings+M1*4,a3),d1 bfins d0,d1{OBJO_WIDTH:OBJW_WIDTH} move.l d1,(env_Settings+M1*4,a3) ; Store first player's new number and size move.l (env_Settings+P1*4,a3),d0 bfins d2,d0{OBJO_NUMBERSIZE:OBJW_NUMBERSIZE} move.l d0,(env_Settings+P1*4,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a3 rts ;****** atari2600.library/A2600_CoLuP0 *** ; ; NAME ; A2600_CoLuP0 -- Set Atari 2600 player 0 colour. ; ; SYNOPSIS ; A2600_CoLuP0(colour,clock,env) ; d0 d1 a1 ; ; VOID A2600_CoLuP0(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets a new colour for an Atari 2600 environment's first player and ; its associated missile. ; ; INPUTS ; colour - A colour-luminescence value in the format that would be ; sent to the Stella chip. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; CoLuP0: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$6<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d4/a3,-(sp) ; Store parameters move.l d0,d2 move.l d1,d3 movea.l a1,a3 ; Calculate current colour clock move.l d3,d0 lsl.l #1,d0 add.l d0,d3 ; mulu.w #A2600_CLR_CLK_FACTOR,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Get new colour move.b (colour_remap_table.l,d2),d2 ; Initialise loop moveq #SCREEN_DEPTH-1,d4 rol.b #1,d2 colour_loop$: ; Update first player colour's pattern lists move.l d3,d1 moveq #OBJECT_COUNT+P0_COLOUR*SCREEN_DEPTH,d0 add.l d4,d0 movea.l a3,a1 bsr UpdatePatternList ; Update playfield colour's pattern lists move.l d3,d1 moveq #OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH,d0 add.l d4,d0 movea.l a3,a1 bsr UpdatePatternList ; Store one bit of new player 0 colour and playfield left colour rol.b #1,d2 move.l (env_Settings+(OBJECT_COUNT+P0_COLOUR*SCREEN_DEPTH)*4,a3,d4*4),d0 bfins d2,d0{31-PENB_NORMALENABLE:1} move.l d0,(env_Settings+(OBJECT_COUNT+P0_COLOUR*SCREEN_DEPTH)*4,a3,d4*4) move.l (env_Settings+(OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH)*4,a3,d4*4),d0 bfins d2,d0{31-PENB_LEFTENABLE:1} move.l d0,(env_Settings+(OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH)*4,a3,d4*4) ; Loop dbra d4,colour_loop$ ; Pop preserved registers off stack and return movem.l (sp)+,d2-d4/a3 rts ;****** atari2600.library/A2600_CoLuP1 *** ; ; NAME ; A2600_CoLuP1 -- Set Atari 2600 player 1 colour. ; ; SYNOPSIS ; A2600_CoLuP1(colour,clock,env) ; d0 d1 a1 ; ; VOID A2600_CoLuP1(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets a new colour for an Atari 2600 environment's second player and ; its associated missile. ; ; INPUTS ; colour - A colour-luminescence value in the format that would be ; sent to the Stella chip. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; CoLuP1: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$7<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d4/a3,-(sp) ; Store parameters move.l d0,d2 move.l d1,d3 movea.l a1,a3 ; Calculate current colour clock move.l d3,d0 lsl.l #1,d0 add.l d0,d3 ; mulu.w #A2600_CLR_CLK_FACTOR,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Get new colour move.b (colour_remap_table.l,d2),d2 ; Initialise loop moveq #SCREEN_DEPTH-1,d4 rol.b #1,d2 colour_loop$: ; Update second player colour's pattern lists move.l d3,d1 moveq #OBJECT_COUNT+P1_COLOUR*SCREEN_DEPTH,d0 add.l d4,d0 movea.l a3,a1 bsr UpdatePatternList ; Update playfield colour's pattern lists move.l d3,d1 moveq #OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH,d0 add.l d4,d0 movea.l a3,a1 bsr UpdatePatternList ; Store one bit of new player 0 colour and playfield right colour rol.b #1,d2 move.l (env_Settings+(OBJECT_COUNT+P1_COLOUR*SCREEN_DEPTH)*4,a3,d4*4),d0 bfins d2,d0{31-PENB_NORMALENABLE:1} move.l d0,(env_Settings+(OBJECT_COUNT+P1_COLOUR*SCREEN_DEPTH)*4,a3,d4*4) move.l (env_Settings+(OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH)*4,a3,d4*4),d0 bfins d2,d0{31-PENB_RIGHTENABLE:1} move.l d0,(env_Settings+(OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH)*4,a3,d4*4) ; Loop dbra d4,colour_loop$ ; Pop preserved registers off stack and return movem.l (sp)+,d2-d4/a3 rts ;****** atari2600.library/A2600_CoLuPF *** ; ; NAME ; A2600_CoLuPF -- Set Atari 2600 playfield colour. ; ; SYNOPSIS ; A2600_CoLuPF(colour,clock,env) ; d0 d1 a1 ; ; VOID A2600_CoLuPF(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets a new colour for an Atari 2600 environment's playfield and ; ball. ; ; INPUTS ; colour - A colour-luminescence value in the format that would be ; sent to the Stella chip. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; CoLuPF: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$8<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d4/a3,-(sp) ; Store parameters move.l d0,d2 move.l d1,d3 movea.l a1,a3 ; Calculate current colour clock move.l d3,d0 lsl.l #1,d0 add.l d0,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Get new colour move.b (colour_remap_table.l,d2),d2 ; Initialise playfield colour loop moveq #SCREEN_DEPTH-1,d4 rol.b #1,d2 pf_loop$: ; Update playfield colour's pattern lists move.l d3,d1 moveq #OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH,d0 add.l d4,d0 movea.l a3,a1 bsr UpdatePatternList ; Store one bit of new colour rol.b #1,d2 move.l (env_Settings+(OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH)*4,a3,d4*4),d0 bfins d2,d0{31-PENB_NORMALENABLE:1} move.l d0,(env_Settings+(OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH)*4,a3,d4*4) ; Loop dbra d4,pf_loop$ ; Pop preserved registers off stack and return movem.l (sp)+,d2-d4/a3 rts ;****** atari2600.library/A2600_CoLuBk *** ; ; NAME ; A2600_CoLuBk -- Set Atari 2600 background colour. ; ; SYNOPSIS ; A2600_CoLuBk(colour,clock,env) ; d0 d1 a1 ; ; VOID A2600_CoLuBk(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets a new colour for an Atari 2600 environment's background. ; ; INPUTS ; colour - A colour-luminescence value in the format that would be ; sent to the Stella chip. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; CoLuBk: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$9<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d4/a3,-(sp) ; Store parameters move.l d0,d2 move.l d1,d3 movea.l a1,a3 ; Calculate current colour clock move.l d3,d0 lsl.l #1,d0 add.l d0,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Get new colour move.b (colour_remap_table.l,d2),d2 ; Initialise background colour loop moveq #SCREEN_DEPTH-1,d4 rol.b #1,d2 bk_loop$: ; Update background colour's pattern lists move.l d3,d1 moveq #OBJECT_COUNT+BK_COLOUR*SCREEN_DEPTH,d0 add.l d4,d0 movea.l a3,a1 bsr UpdatePatternList ; Store one bit of new colour rol.b #1,d2 move.l (env_Settings+(OBJECT_COUNT+BK_COLOUR*SCREEN_DEPTH)*4,a3,d4*4),d0 bfins d2,d0{31-PENB_NORMALENABLE:1} move.l d0,(env_Settings+(OBJECT_COUNT+BK_COLOUR*SCREEN_DEPTH)*4,a3,d4*4) ; Loop dbra d4,bk_loop$ ; Pop preserved registers off stack and return movem.l (sp)+,d2-d4/a3 rts ;****** atari2600.library/A2600_CtrlPF *** ; ; NAME ; A2600_CtrlPF -- Set various playfield and ball modes. ; ; SYNOPSIS ; A2600_CtrlPF(modes,clock,env) ; d0 d1 a1 ; ; VOID A2600_CtrlPF(ULONG,ULONG,APTR); ; ; FUNCTION ; Determines the playfield's reflection mode, score mode and priority, ; and the ball's width. Details are provided below. ; ; INPUTS ; modes - The meaning of this parameter's bits is as follows: ; ; Bit 0 determines playfield reflection (1=on, 0=off). ; ; If bit 1 is set, the left-hand side of the playfield will have ; the first player's colour and the right-hand side will have the ; second player's colour. ; ; If bit 2 is set, the playfield and ball graphics will have ; priority over all other objects' graphics. Otherwise, the ; playfield and ball graphics will have least priority. ; ; The 5th and 4th bits form a two-bit number that sets the ball's ; width according to the following table: ; ; 00 - 1 colour clock ; 01 - 2 colour clocks ; 10 - 4 colour clocks ; 11 - 8 colour clocks ; ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; CtrlPF: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$a<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d4/a3,-(sp) ; Store parameters move.l d0,d2 move.l d1,d3 movea.l a1,a3 ; Calculate current colour clock move.l d3,d0 lsl.l #1,d0 add.l d0,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Initialise loop moveq #SCREEN_DEPTH-1,d4 colour_loop$: ; Update playfield colour's pattern lists move.l d3,d1 moveq #OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH,d0 add.l d4,d0 movea.l a3,a1 bsr UpdatePatternList ; Set playfield score mode move.w d2,d0 lsr.w #1,d0 move.l (env_Settings+(OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH)*4,a3,d4*4),d1 bfins d0,d1{31-PENB_SCOREMODE:1} move.l d1,(env_Settings+(OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH)*4,a3,d4*4) ; Loop dbra d4,colour_loop$ ; Update playfield's pattern list move.l d3,d1 moveq #PF,d0 movea.l a3,a1 bsr UpdatePatternList ; Update ball's pattern list move.l d3,d1 moveq #BL,d0 movea.l a3,a1 bsr UpdatePatternList ; Update playfield priority pattern list move.l d3,d1 moveq #PATTERN_COUNT-1,d0 movea.l a3,a1 bsr UpdatePatternList ; Set playfield copy/reflection mode move.l (env_Settings+PF*4,a3),d0 bfins d2,d0{31-OBJB_REFLECTION:1} move.l d0,(env_Settings+PF*4,a3) ; Set playfield priority move.w d2,d0 lsr.b #2,d0 move.l (env_Settings+(PATTERN_COUNT-1)*4,a3),d1 bfins d0,d1{31-PRIB_ON:1} move.l d1,(env_Settings+(PATTERN_COUNT-1)*4,a3) ; Set ball width move.w d2,d0 lsr.w #4,d0 move.l (env_Settings+BL*4,a3),d1 bfins d0,d1{OBJO_WIDTH:OBJW_WIDTH} move.l d1,(env_Settings+BL*4,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2-d4/a3 rts ;****** atari2600.library/A2600_RefP0 *** ; ; NAME ; A2600_RefP0 -- Set the reflection mode for player 0. ; ; SYNOPSIS ; A2600_RefP0(mode,clock,env) ; d0 d1 a1 ; ; VOID A2600_RefP0(ULONG,ULONG,APTR); ; ; FUNCTION ; Turns the first player's reflection on or off after a delay of one ; colour clock. ; ; INPUTS ; mode - Bit 3 of this specifies the reflection mode: 0 for off, 1 for ; on. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; RefP0: IFD PROFILE addq.l #1,(env_ProfileData+$b<<2,a1) ENDC ; rts ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d3/a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Calculate current colour clock plus delay move.l d1,d0 lsl.l #1,d0 add.l d0,d1 addq.l #1,d1 ; Get update position movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Update first player's pattern list move.l d3,d1 moveq #P0,d0 movea.l a3,a1 bsr UpdatePatternList ; Set player's reflection mode lsr.b #3,d2 move.l (env_Settings+P0*4,a3),d0 bfins d2,d0{31-OBJB_REFLECTION:1} move.l d0,(env_Settings+P0*4,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a3 rts ;****** atari2600.library/A2600_RefP1 *** ; ; NAME ; A2600_RefP1 -- Set the reflection mode for player 1. ; ; SYNOPSIS ; A2600_RefP1(mode,clock,env) ; d0 d1 a1 ; ; VOID A2600_RefP1(ULONG,ULONG,APTR); ; ; FUNCTION ; Turns the second player's reflection on or off after a delay of one ; colour clock. ; ; INPUTS ; mode - Bit 3 of this specifies the reflection mode: 0 for off, 1 for ; on. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; RefP1: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$c<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d3/a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Calculate current colour clock plus delay move.l d1,d0 lsl.l #1,d0 add.l d0,d1 addq.l #1,d1 ; Get update position movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Update first player's pattern list move.l d3,d1 moveq #P1,d0 movea.l a3,a1 bsr UpdatePatternList ; Set player's reflection mode lsr.b #3,d2 move.l (env_Settings+P1*4,a3),d0 bfins d2,d0{31-OBJB_REFLECTION:1} move.l d0,(env_Settings+P1*4,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a3 rts ;****** atari2600.library/A2600_PF0 *** ; ; NAME ; A2600_PF0 -- Set the first section of playfield graphics pattern. ; ; SYNOPSIS ; A2600_PF0(graphics,clock,env) ; d0 d1 a1 ; ; VOID A2600_PF0(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the leftmost four bits of the 20-bit playfield pattern. The ; new setting takes effect after a delay of between two and five ; colour clock cycles. ; ; INPUTS ; graphics - The upper nibble of the lowest byte is the first section ; of the playfield pattern. Bit four is leftmost while bit seven ; is rightmost. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; PF0: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$d<<2,a1) ENDC ; Check if pattern is changing move.b (byte_reverse_table.l,d0),d0 andi.b #$f,d0 cmp.b (env_Settings+PF*4+1,a1),d0 bne.s change$ rts change$: ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d3/a3,-(sp) ; Store parameters move.l d0,d2 move.l d1,d3 movea.l a1,a3 ; Calculate delay divu.w #A2600_LINE_CYCLES/3,d1 swap.w d1 moveq #0,d0 move.b (playfield_delay_table.l,d1),d0 ; Calculate current colour clock plus delay move.l d3,d1 lsl.l #1,d1 add.l d1,d3 add.l d0,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Update playfield's pattern list move.l d3,d1 moveq #PF,d0 movea.l a3,a1 bsr UpdatePatternList ; ; Load address of byte reverse table ; lea.l byte_reverse_table,a0 ; Write to first section of playfield graphics ; move.b (a0,d2),(env_Settings+PF*4+1,a3) move.b d2,(env_Settings+PF*4+1,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a3 rts ;****** atari2600.library/A2600_PF1 *** ; ; NAME ; A2600_PF1 -- Set the second section of playfield graphics pattern. ; ; SYNOPSIS ; A2600_PF1(graphics,clock,env) ; d0 d1 a1 ; ; VOID A2600_PF1(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets eight bits of the 20-bit playfield pattern, beginning with the ; fifth from the left. The new setting takes effect after a delay of ; between two and five colour clock cycles. ; ; INPUTS ; graphics - The lowest byte is the second section of the playfield ; pattern. Bit seven is leftmost while bit zero is rightmost. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; PF1: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$e<<2,a1) ENDC ; Check if pattern is changing cmp.b (env_Settings+PF*4+2,a1),d0 bne.s change$ rts change$: ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d3/a3,-(sp) ; Store parameters move.l d0,d2 move.l d1,d3 movea.l a1,a3 ; Calculate delay divu.w #A2600_LINE_CYCLES/3,d1 swap.w d1 moveq #0,d0 move.b (playfield_delay_table.l,d1),d0 ; Calculate current colour clock plus delay move.l d3,d1 lsl.l #1,d1 add.l d1,d3 add.l d0,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Update playfield's pattern list move.l d3,d1 moveq #PF,d0 movea.l a3,a1 bsr UpdatePatternList ; Write to second section of playfield graphics move.b d2,(env_Settings+PF*4+2,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a3 rts ;****** atari2600.library/A2600_PF2 *** ; ; NAME ; A2600_PF2 -- Set the third section of playfield graphics pattern. ; ; SYNOPSIS ; A2600_PF2(graphics,clock,env) ; d0 d1 a1 ; ; VOID A2600_PF2(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the rightmost eight bits of the 20-bit playfield pattern. The ; new setting takes effect after a delay of between two and five ; colour clock cycles. ; ; INPUTS ; graphics - The lowest byte is the third section of the playfield ; pattern. Bit zero is leftmost while bit seven is rightmost. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; PF2: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$f<<2,a1) ENDC ; Check if pattern is changing move.b (byte_reverse_table.l,d0),d0 cmp.b (env_Settings+PF*4+3,a1),d0 bne.s change$ rts change$: ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d3/a3,-(sp) ; Store parameters move.l d0,d2 move.l d1,d3 movea.l a1,a3 ; Calculate delay divu.w #A2600_LINE_CYCLES/3,d1 swap.w d1 moveq #0,d0 move.b (playfield_delay_table.l,d1),d0 ; Calculate current colour clock plus delay move.l d3,d1 lsl.l #1,d1 add.l d1,d3 add.l d0,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Update playfield's pattern list move.l d3,d1 moveq #PF,d0 movea.l a3,a1 bsr UpdatePatternList ; ; Load address of byte reverse table ; lea.l byte_reverse_table,a0 ; Write to third section of playfield graphics ; move.b (a0,d2),(env_Settings+PF*4+3,a3) move.b d2,(env_Settings+PF*4+3,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a3 rts ;****** atari2600.library/A2600_ResP0 *** ; ; NAME ; A2600_ResP0 -- Reset the position of player 0. ; ; SYNOPSIS ; A2600_ResP0(clock,env) ; d1 a1 ; ; VOID A2600_ResP0(ULONG,APTR); ; ; FUNCTION ; Sets the first player's horizontal position to the emulated video ; beam's current horizontal position plus five colour clocks. If this ; function is called during the emulated horizontal blank period, the ; player's position will be set to the third colour clock of the line. ; ; INPUTS ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; ResP0: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$10<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d3/a3,-(sp) ; Store parameters move.l d1,d3 movea.l a1,a3 ; Calculate current colour clock move.l d3,d0 lsl.l #1,d0 add.l d0,d3 ; mulu.w #A2600_CLR_CLK_FACTOR,d3 move.l d3,d2 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Update first player's pattern list move.l d3,d1 moveq #P0,d0 movea.l a3,a1 bsr UpdatePatternList ; Calculate first player's new position divu.w #A2600_LINE_CYCLES,d2 swap.w d2 sub.w #A2600_H_BLANK_CYCLES,d2 bhs not_in_hblank$ moveq #-2,d2 not_in_hblank$: addq.w #5,d2 cmpi.w #TV_WIDTH,d2 blo skip_wrap_around$ subi.w #TV_WIDTH,d2 skip_wrap_around$: ; Store first player's new position move.b d2,(env_Settings+P0*4+1,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a3 rts ;****** atari2600.library/A2600_ResP1 *** ; ; NAME ; A2600_ResP1 -- Reset the position of player 1. ; ; SYNOPSIS ; A2600_ResP1(clock,env) ; d1 a1 ; ; VOID A2600_ResP1(ULONG,APTR); ; ; FUNCTION ; Sets the second player's horizontal position to the emulated video ; beam's current horizontal position plus five colour clocks. If this ; function is called during the emulated horizontal blank period, the ; player's position will be set to the third colour clock of the line. ; ; INPUTS ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; ResP1: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$11<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d3/a3,-(sp) ; Store parameters move.l d1,d3 movea.l a1,a3 ; Calculate current colour clock move.l d3,d0 lsl.l #1,d0 add.l d0,d3 ; mulu.w #A2600_CLR_CLK_FACTOR,d3 move.l d3,d2 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Update second player's pattern list move.l d3,d1 moveq #P1,d0 movea.l a3,a1 bsr UpdatePatternList ; Calculate second player's new position divu.w #A2600_LINE_CYCLES,d2 swap.w d2 subi.w #A2600_H_BLANK_CYCLES,d2 bhs not_in_hblank$ moveq #-2,d2 not_in_hblank$: addq.w #5,d2 cmpi.w #TV_WIDTH,d2 blo skip_wrap_around$ subi.w #TV_WIDTH,d2 skip_wrap_around$: ; Store second player's new position move.b d2,(env_Settings+P1*4+1,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a3 rts ;****** atari2600.library/A2600_ResM0 *** ; ; NAME ; A2600_ResM0 -- Reset the position of missile 0. ; ; SYNOPSIS ; A2600_ResM0(clock,env) ; d1 a1 ; ; VOID A2600_ResM0(ULONG,APTR); ; ; FUNCTION ; Sets the first missile's horizontal position to the emulated video ; beam's current horizontal position plus four colour clocks. If this ; function is called during the emulated horizontal blank period, the ; missile's position will be set to the second colour clock of the ; line. ; ; INPUTS ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; ResM0: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$12<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d3/a3,-(sp) ; Store parameters move.l d1,d3 movea.l a1,a3 ; Calculate current colour clock move.l d3,d0 lsl.l #1,d0 add.l d0,d3 ; mulu.w #A2600_CLR_CLK_FACTOR,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition ; Update first missile's pattern list move.l d0,d1 moveq #M0,d0 movea.l a3,a1 bsr UpdatePatternList ; Store missile's new position divu.w #A2600_LINE_CYCLES,d3 swap.w d3 sub.w #A2600_H_BLANK_CYCLES,d3 bhs not_in_hblank$ moveq #-2,d3 not_in_hblank$: addq.w #4,d3 cmpi.w #TV_WIDTH,d3 blo skip_wrap_around$ subi.w #TV_WIDTH,d3 skip_wrap_around$: ; Store first missile's new position move.b d3,(env_Settings+M0*4+1,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d3/a3 rts ;****** atari2600.library/A2600_ResM1 *** ; ; NAME ; A2600_ResM1 -- Reset the position of missile 1. ; ; SYNOPSIS ; A2600_ResM1(clock,env) ; d1 a1 ; ; VOID A2600_ResM1(ULONG,APTR); ; ; FUNCTION ; Sets the second missile's horizontal position to the emulated video ; beam's current horizontal position plus four colour clocks. If this ; function is called during the emulated horizontal blank period, the ; missile's position will be set to the second colour clock of the ; line. ; ; INPUTS ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; ResM1: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$13<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d3/a3,-(sp) ; Store parameters move.l d1,d3 movea.l a1,a3 ; Calculate current colour clock move.l d3,d0 lsl.l #1,d0 add.l d0,d3 ; mulu.w #A2600_CLR_CLK_FACTOR,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition ; Update missile's pattern list move.l d0,d1 moveq #M1,d0 movea.l a3,a1 bsr UpdatePatternList ; Store missile's new position divu.w #A2600_LINE_CYCLES,d3 swap.w d3 sub.w #A2600_H_BLANK_CYCLES,d3 bhs not_in_hblank$ moveq #-2,d3 not_in_hblank$: addq.w #4,d3 cmpi.w #TV_WIDTH,d3 blo skip_wrap_around$ subi.w #TV_WIDTH,d3 skip_wrap_around$: ; Store missile's new position move.b d3,(env_Settings+M1*4+1,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d3/a3 rts ;****** atari2600.library/A2600_ResBl *** ; ; NAME ; A2600_ResBl -- Reset the position of the ball. ; ; SYNOPSIS ; A2600_ResBl(clock,env) ; d1 a1 ; ; VOID A2600_ResBl(ULONG,APTR); ; ; FUNCTION ; Sets the ball's horizontal position to the emulated video beam's ; current horizontal position plus four colour clocks. If this ; function is called during the emulated horizontal blank period, the ; ball's position will be set to the second colour clock of the line. ; ; INPUTS ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; ResBl: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$14<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d3/a3,-(sp) ; Store parameters move.l d1,d3 movea.l a1,a3 ; Calculate current colour clock move.l d3,d0 lsl.l #1,d0 add.l d0,d3 ; mulu.w #A2600_CLR_CLK_FACTOR,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition ; Update ball's pattern list move.l d0,d1 moveq #BL,d0 movea.l a3,a1 bsr UpdatePatternList ; Calculate ball's new position divu.w #A2600_LINE_CYCLES,d3 swap.w d3 sub.w #A2600_H_BLANK_CYCLES,d3 bhs not_in_hblank$ moveq #-2,d3 not_in_hblank$: addq.w #4,d3 cmpi.w #TV_WIDTH,d3 blo skip_wrap_around$ subi.w #TV_WIDTH,d3 skip_wrap_around$: ; Store ball's new position move.b d3,(env_Settings+BL*4+1,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d3/a3 rts ;****** atari2600.library/A2600_AudC0 *** ; ; NAME ; A2600_AudC0 -- Set the tone type for audio channel 0. (V2) ; ; SYNOPSIS ; A2600_AudC0(tone_num,clock,env) ; d0 d1 a1 ; ; VOID A2600_AudC0(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the tone type for an Atari 2600 environment's first audio ; channel. ; ; INPUTS ; tone_num - A four-bit number to select the tone type to use. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; AudC0: ; rts ; Push registers that should be preserved onto stack movem.l d2/a3/a5-a6,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 movea.l a6,a5 ; Check if sound is on tst.w (env_SoundOn,a1) beq.s end$ ; Check if tone type is unchanged andi.b #$f,d2 cmp.b (env_ToneTypeNo,a1),d2 beq end$ move.b d2,(env_ToneTypeNo,a1) ; Ensure that current IORequest is not in use movea.l (ab_SysLib,a5),a6 movea.l (env_ToneTypeIO,a3),a1 JSRLIB WaitIO ; Start new sound movea.l (env_ToneTypeIO,a3),a1 move.l (ab_Sounds,a5,d2*4),(ioa_Data,a1) move.l (sound_length_table.l,d2*4),(ioa_Length,a1) JSRLIB SendIO ; Rotate IORequests for this channel movea.l (env_ToneTypeIO+4,a3),a1 move.l (env_ToneTypeIO,a3),(env_ToneTypeIO+4,a3) movea.l a1,(env_ToneTypeIO,a3) ; Stop old sound JSRLIB AbortIO end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2/a3/a5-a6 rts ;****** atari2600.library/A2600_AudC1 *** ; ; NAME ; A2600_AudC1 -- Set the tone type for audio channel 1. (V2) ; ; SYNOPSIS ; A2600_AudC1(tone_num,clock,env) ; d0 d1 a1 ; ; VOID A2600_AudC1(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the tone type for an Atari 2600 environment's second audio ; channel. ; ; INPUTS ; tone_num - A four-bit number to select the tone type to use. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; AudC1: ; rts ; Push registers that should be preserved onto stack movem.l d2/a3/a5-a6,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 movea.l a6,a5 ; Check if sound is on tst.w (env_SoundOn,a1) beq.s end$ ; Check if tone type is unchanged andi.b #$f,d2 cmp.b (env_ToneTypeNo+1,a1),d2 beq end$ move.b d2,(env_ToneTypeNo+1,a1) ; Ensure that current IORequest is not in use movea.l (ab_SysLib,a5),a6 movea.l (env_ToneTypeIO+AUDIO_BUFFER_COUNT*4,a3),a1 JSRLIB WaitIO ; Start new sound movea.l (env_ToneTypeIO+AUDIO_BUFFER_COUNT*4,a3),a1 move.l (ab_Sounds,a5,d2*4),(ioa_Data,a1) move.l (sound_length_table.l,d2*4),(ioa_Length,a1) JSRLIB SendIO ; Rotate IORequests for this channel movea.l (env_ToneTypeIO+AUDIO_BUFFER_COUNT*4+4,a3),a1 move.l (env_ToneTypeIO+AUDIO_BUFFER_COUNT*4,a3),(env_ToneTypeIO+AUDIO_BUFFER_COUNT*4+4,a3) movea.l a1,(env_ToneTypeIO+AUDIO_BUFFER_COUNT*4,a3) ; Stop old sound JSRLIB AbortIO end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2/a3/a5-a6 rts ;****** atari2600.library/A2600_AudF0 *** ; ; NAME ; A2600_AudF0 -- Set the frequency for audio channel 0. (V2) ; ; SYNOPSIS ; A2600_AudF0(freq_num,clock,env) ; d0 d1 a1 ; ; VOID A2600_AudF0(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the sound frequency for the first audio channel. The new ; frequency is approximately 31KHz divided by one more than freq_num. ; ; INPUTS ; freq_num - One less than the divisor of the basic frequency. A five- ; bit number. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; AudF0: ; rts ; Push library pointer onto stack and load exec pointer move.l a6,-(sp) movea.l (ab_SysLib,a6),a6 ; Check if sound is on tst.w (env_SoundOn,a1) beq.s end$ ; Check if frequency is unchanged andi.b #$1f,d0 cmp.b (env_FrequencyNo,a1),d0 beq end$ move.b d0,(env_FrequencyNo,a1) ; Change frequency movea.l (env_PerVolIO,a1),a1 move.w (period_table.l,d0*2),(ioa_Period,a1) JSRLIB DoIO end$: ; Pop library pointer off stack and return movea.l (sp)+,a6 rts ;****** atari2600.library/A2600_AudF1 *** ; ; NAME ; A2600_AudF1 -- Set the frequency for audio channel 1. (V2) ; ; SYNOPSIS ; A2600_AudF1(freq_num,clock,env) ; d0 d1 a1 ; ; VOID A2600_AudF1(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the sound frequency for the first audio channel. The new ; frequency is approximately 31KHz divided by one more than freq_num. ; ; INPUTS ; freq_num - One less than the divisor of the basic frequency. A five- ; bit number. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; AudF1: ; rts ; Push library pointer onto stack and load exec pointer move.l a6,-(sp) movea.l (ab_SysLib,a6),a6 ; Check if sound is on tst.w (env_SoundOn,a1) beq.s end$ ; Check if frequency is unchanged andi.b #$1f,d0 cmp.b (env_FrequencyNo+1,a1),d0 beq end$ move.b d0,(env_FrequencyNo+1,a1) ; Change frequency movea.l (env_PerVolIO+4,a1),a1 move.w (period_table.l,d0*2),(ioa_Period,a1) JSRLIB DoIO end$: ; Pop library pointer off stack and return movea.l (sp)+,a6 rts ;****** atari2600.library/A2600_AudV0 *** ; ; NAME ; A2600_AudV0 -- Set the volume for audio channel 0. (V2) ; ; SYNOPSIS ; A2600_AudV0(volume,clock,env) ; d0 d1 a1 ; ; VOID A2600_AudV0(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the volume for audio channel 0. ; ; INPUTS ; volume - A four-bit number to specify the new volume. 0 is quietest, ; 15 is loudest. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; AudV0: ; rts ; Push library pointer onto stack and load exec pointer move.l a6,-(sp) movea.l (ab_SysLib,a6),a6 ; Check if sound is on tst.w (env_SoundOn,a1) beq.s end$ ; Check if sound volume is unchanged andi.b #$f,d0 cmp.b (env_VolumeNo,a1),d0 beq end$ move.b d0,(env_VolumeNo,a1) ; Change frequency movea.l (env_PerVolIO,a1),a1 lsl.b #2,d0 move.w d0,(ioa_Volume,a1) JSRLIB DoIO end$: ; Pop library pointer off stack and return movea.l (sp)+,a6 rts ;****** atari2600.library/A2600_AudV1 *** ; ; NAME ; A2600_AudV1 -- Set the volume for audio channel 1. (V2) ; ; SYNOPSIS ; A2600_AudV1(volume,clock,env) ; d0 d1 a1 ; ; VOID A2600_AudV1(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the volume for audio channel 1. ; ; INPUTS ; volume - A four-bit number to specify the new volume. 0 is quietest, ; 15 is loudest. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; AudV1: ; rts ; Push library pointer onto stack and load exec pointer move.l a6,-(sp) movea.l (ab_SysLib,a6),a6 ; Check if sound is on tst.w (env_SoundOn,a1) beq.s end$ ; Check if sound volume is unchanged andi.b #$f,d0 cmp.b (env_VolumeNo+1,a1),d0 beq end$ move.b d0,(env_VolumeNo+1,a1) ; Change frequency movea.l (env_PerVolIO+4,a1),a1 lsl.b #2,d0 move.w d0,(ioa_Volume,a1) JSRLIB DoIO end$: ; Pop library pointer off stack and return movea.l (sp)+,a6 rts ;****** atari2600.library/A2600_GrP0 *** ; ; NAME ; A2600_GrP0 -- Set the graphics pattern for player 0. ; ; SYNOPSIS ; A2600_GrP0(graphics,clock,env) ; d0 d1 a1 ; ; VOID A2600_GrP0(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the first player's undelayed graphics pattern, and copies the ; second player's undelayed graphics pattern to the same player's ; delayed graphics pattern. ; ; INPUTS ; graphics - Lowest byte is the new graphics pattern for player 0. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; GrP0: ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack move.l d2,-(sp) move.l a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Calculate current colour clock plus delay move.l d1,d0 add.l d1,d0 add.l d0,d1 addq.l #1,d1 ; Get update position bsr CalculateCurrentPosition ; Update first player's pattern list move.l d0,d1 moveq #P0,d0 bsr UpdatePatternList ; Update second player's pattern list moveq #P1,d0 bsr UpdatePatternList ; Store first player's new graphics move.b d2,(env_Settings+P0*4+3,a3) ; Copy second player's undelayed graphics to its delayed graphics move.b (env_Settings+P1*4+3,a3),(env_Settings+P1*4+2,a3) ; Pop preserved registers off stack and return move.l (sp)+,a3 move.l (sp)+,d2 rts ;****** atari2600.library/A2600_GrP1 *** ; ; NAME ; A2600_GrP1 -- Set the graphics pattern for player 1. ; ; SYNOPSIS ; A2600_GrP1(graphics,clock,env) ; d0 d1 a1 ; ; VOID A2600_GrP1(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the second player's undelayed graphics pattern, and copies the ; first player's undelayed graphics pattern to the same player's ; delayed graphics pattern. In addition, the ball's delayed enable ; flag is set to the same value as its undelayed enable flag. ; ; INPUTS ; graphics - Lowest byte is the new graphics pattern for player 1. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; GrP1: ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack move.l d2,-(sp) move.l a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Calculate current colour clock plus delay move.l d1,d0 add.l d1,d0 add.l d0,d1 add.l #1,d1 ; Get update position bsr CalculateCurrentPosition move.l d0,d1 ; Update ball's pattern list moveq #BL,d0 bsr UpdatePatternList ; Update first player's pattern list moveq #P0,d0 bsr UpdatePatternList ; Update second player's pattern list moveq #P1,d0 bsr UpdatePatternList ; Store second player's new graphics move.b d2,(env_Settings+P1*4+3,a3) ; Copy first player's undelayed graphics to its delayed graphics move.b (env_Settings+P0*4+3,a3),(env_Settings+P0*4+2,a3) ; Copy ball's undelayed enable flag to its delayed enable flag move.b (env_Settings+BL*4+3,a3),(env_Settings+BL*4+2,a3) ; Pop preserved registers off stack and return move.l (sp)+,a3 move.l (sp)+,d2 rts ;****** atari2600.library/A2600_EnaM0 *** ; ; NAME ; A2600_EnaM0 -- Enable or disable missile 0. ; ; SYNOPSIS ; A2600_EnaM0(mode,clock,env) ; d0 d1 a1 ; ; VOID A2600_EnaM0(ULONG,ULONG,APTR); ; ; FUNCTION ; Determines whether the first missile is displayed or not. ; ; INPUTS ; mode - If bit 1 is set then the missile is enabled. It is disabled ; otherwise. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; EnaM0: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$1d<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2/a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Calculate current colour clock move.l d1,d0 lsl.l #1,d0 add.l d0,d1 ; Get update position movea.l a3,a1 bsr CalculateCurrentPosition ; Update first missile's pattern list move.l d0,d1 moveq #M0,d0 movea.l a3,a1 bsr UpdatePatternList ; Enable or disable missile graphics lsr.l #1,d2 move.l (env_Settings+M0*4,a3),d0 bfins d2,d0{31-OBJB_UNDELAYEDENABLE:1} move.l d0,(env_Settings+M0*4,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2/a3 rts ;****** atari2600.library/A2600_EnaM1 *** ; ; NAME ; A2600_EnaM1 -- Enable or disable missile 1. ; ; SYNOPSIS ; A2600_EnaM1(mode,clock,env) ; d0 d1 a1 ; ; VOID A2600_EnaM1(ULONG,ULONG,APTR); ; ; FUNCTION ; Determines whether the second missile is displayed or not. ; ; INPUTS ; mode - If bit 1 is set then the missile is enabled. It is disabled ; otherwise. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; EnaM1: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$1e<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2/a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Calculate current colour clock move.l d1,d0 lsl.l #1,d0 add.l d0,d1 ; Get update position movea.l a3,a1 bsr CalculateCurrentPosition ; Update first missile's pattern list move.l d0,d1 moveq #M1,d0 movea.l a3,a1 bsr UpdatePatternList ; Enable or disable missile graphics lsr.l #1,d2 move.l (env_Settings+M1*4,a3),d0 bfins d2,d0{31-OBJB_UNDELAYEDENABLE:1} move.l d0,(env_Settings+M1*4,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2/a3 rts ;****** atari2600.library/A2600_EnaBl *** ; ; NAME ; A2600_EnaBl -- Enable or disable the ball. ; ; SYNOPSIS ; A2600_EnaBl(mode,clock,env) ; d0 d1 a1 ; ; VOID A2600_EnaBl(ULONG,ULONG,APTR); ; ; FUNCTION ; Determines whether the ball is displayed or not. ; ; INPUTS ; mode - If bit 1 is set then the ball is enabled. It is disabled ; otherwise. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; EnaBl: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$1f<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2/a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Calculate current colour clock move.l d1,d0 lsl.l #1,d0 add.l d0,d1 ; Get update position movea.l a3,a1 bsr CalculateCurrentPosition ; Update ball's pattern list move.l d0,d1 moveq #BL,d0 movea.l a3,a1 bsr UpdatePatternList ; Enable or disable ball graphics lsr.l #1,d2 move.l (env_Settings+BL*4,a3),d0 bfins d2,d0{31-OBJB_UNDELAYEDENABLE:1} move.l d0,(env_Settings+BL*4,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2/a3 rts ;****** atari2600.library/A2600_HMP0 *** ; ; NAME ; A2600_HMP0 -- Set the horizontal movement rate for player 0. ; ; SYNOPSIS ; A2600_HMP0(rate,clock,env) ; d0 d1 a1 ; ; VOID A2600_HMP0(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the horizontal movement rate for the first player. The player's ; horizontal position will only actually change when HMove() is ; called. ; ; INPUTS ; rate - the upper nibble of the lowest byte is a two's-complement ; value that is subtracted from the the first player's horizontal ; position on the next call to HMove(). ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; HMP0: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$20<<2,a1) ENDC ; Store player's new horizontal movement rate lsr.b #4,d0 move.w d0,(env_MotionRates+P0*2,a1) ; Return rts ;****** atari2600.library/A2600_HMP1 *** ; ; NAME ; A2600_HMP1 -- Set the horizontal movement rate for player 1. ; ; SYNOPSIS ; A2600_HMP1(rate,clock,env) ; d0 d1 a1 ; ; VOID A2600_HMP1(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the horizontal movement rate for the second player. The ; player's horizontal position will only actually change when HMove() ; is called. ; ; INPUTS ; rate - the upper nibble of the lowest byte is a two's-complement ; value that is subtracted from the the second player's horizontal ; position on the next call to HMove(). ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; HMP1: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$21<<2,a1) ENDC ; Store player's new horizontal movement rate lsr.b #4,d0 move.w d0,(env_MotionRates+P1*2,a1) ; Return rts ;****** atari2600.library/A2600_HMM0 *** ; ; NAME ; A2600_HMM0 -- Set the horizontal movement rate for missile 0. ; ; SYNOPSIS ; A2600_HMM0(rate,clock,env) ; d0 d1 a1 ; ; VOID A2600_HMM0(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the horizontal movement rate for the first missile. The ; missile's horizontal position will only actually change when HMove() ; is called. ; ; INPUTS ; rate - the upper nibble of the lowest byte is a two's-complement ; value that is subtracted from the the first missile's horizontal ; position on the next call to HMove(). ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; HMM0: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$22<<2,a1) ENDC ; Store missile's new horizontal movement rate lsr.b #4,d0 move.w d0,(env_MotionRates+M0*2,a1) ; Return rts ;****** atari2600.library/A2600_HMM1 *** ; ; NAME ; A2600_HMM1 -- Set the horizontal movement rate for missile 1. ; ; SYNOPSIS ; A2600_HMM1(rate,clock,env) ; d0 d1 a1 ; ; VOID A2600_HMM1(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the horizontal movement rate for the second missile. The ; missile's horizontal position will only actually change when HMove() ; is called. ; ; INPUTS ; rate - the upper nibble of the lowest byte is a two's-complement ; value that is subtracted from the the second missile's ; horizontal position on the next call to HMove(). ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; HMM1: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$23<<2,a1) ENDC ; Store missile's new horizontal movement rate lsr.b #4,d0 move.w d0,(env_MotionRates+M1*2,a1) ; Return rts ;****** atari2600.library/A2600_HMBl *** ; ; NAME ; A2600_HMBl -- Set the horizontal movement rate for the ball. ; ; SYNOPSIS ; A2600_HMBl(rate,clock,env) ; d0 d1 a1 ; ; VOID A2600_HMBl(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the horizontal movement rate for the ball. The ball's ; horizontal position will only actually change when HMove() is ; called. ; ; INPUTS ; rate - the upper nibble of the lowest byte is a two's-complement ; value that is subtracted from the the ball's horizontal ; position on the next call to HMove(). ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; HMBl: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$24<<2,a1) ENDC ; Store ball's new horizontal movement rate lsr.b #4,d0 move.w d0,(env_MotionRates+BL*2,a1) ; Return rts ;****** atari2600.library/A2600_VDelP0 *** ; ; NAME ; A2600_VDelP0 -- Set vertical delay mode for player 0. ; ; SYNOPSIS ; A2600_VDelP0(mode,clock,env) ; d0 d1 a1 ; ; VOID A2600_VDelP0(ULONG,ULONG,APTR); ; ; FUNCTION ; Determines whether the first player's delayed or undelayed graphics ; pattern will be used. ; ; INPUTS ; mode - Bit 0 of this specifies the vertical delay mode: 0 for off, 1 ; for on. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; VDelP0: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$25<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2/a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Calculate current colour clock move.l d1,d0 lsl.l #1,d0 add.l d0,d1 ; Get update position movea.l a3,a1 bsr CalculateCurrentPosition ; Update first player's pattern list move.l d0,d1 moveq #P0,d0 movea.l a3,a1 bsr UpdatePatternList ; Set first player's vertical delay mode move.l (env_Settings+P0*4,a3),d0 bfins d2,d0{31-OBJB_VDELAY:1} move.l d0,(env_Settings+P0*4,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2/a3 rts ;****** atari2600.library/A2600_VDelP1 *** ; ; NAME ; A2600_VDelP1 -- Set vertical delay mode for player 1. ; ; SYNOPSIS ; A2600_VDelP1(mode,clock,env) ; d0 d1 a1 ; ; VOID A2600_VDelP1(ULONG,ULONG,APTR); ; ; FUNCTION ; Determines whether the second player's delayed or undelayed graphics ; pattern will be used. ; ; INPUTS ; mode - Bit 0 of this specifies the vertical delay mode: 0 for off, 1 ; for on. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; VDelP1: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$26<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2/a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Calculate current colour clock move.l d1,d0 lsl.l #1,d0 add.l d0,d1 ; Get update position movea.l a3,a1 bsr CalculateCurrentPosition ; Update second player's pattern list move.l d0,d1 moveq #P1,d0 movea.l a3,a1 bsr UpdatePatternList ; Set second player's vertical delay mode move.l (env_Settings+P1*4,a3),d0 bfins d2,d0{31-OBJB_VDELAY:1} move.l d0,(env_Settings+P1*4,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2/a3 rts ;****** atari2600.library/A2600_VDelBl *** ; ; NAME ; A2600_VDelBl -- Set vertical delay mode for the ball. ; ; SYNOPSIS ; A2600_VDelBl(mode,clock,env) ; d0 d1 a1 ; ; VOID A2600_VDelBl(ULONG,ULONG,APTR); ; ; FUNCTION ; Determines whether the ball's delayed or undelayed enable flag will ; be used. ; ; INPUTS ; mode - Bit 0 of this specifies the vertical delay mode: 0 for off, 1 ; for on. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; VDelBl: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$27<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2/a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Calculate current colour clock move.l d1,d0 lsl.l #1,d0 add.l d0,d1 ; Get update position movea.l a3,a1 bsr CalculateCurrentPosition ; Update ball's pattern list move.l d0,d1 moveq #BL,d0 movea.l a3,a1 bsr UpdatePatternList ; Set ball's vertical delay mode move.l (env_Settings+BL*4,a3),d0 bfins d2,d0{31-OBJB_VDELAY:1} move.l d0,(env_Settings+BL*4,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2/a3 rts ;****** atari2600.library/A2600_ResMP0 *** ; ; NAME ; A2600_ResMP0 -- Lock missile 0 to its player. (V2) ; ; SYNOPSIS ; A2600_ResMP0(mode,clock,env) ; d0 d1 a1 ; ; VOID A2600_ResMP0(ULONG,ULONG,APTR); ; ; FUNCTION ; Either locks the first missile's horizontal position to the centre ; of its player or unlocks it so that it can move freely. When the ; missile is locked, its horizontal position is always the same as ; that of its player. ; ; INPUTS ; mode - Bit 1 should be set to lock the missile, cleared to unlock ; it. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; ResMP0: IFD PROFILE addq.l #1,(env_ProfileData+$28<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d3/a3,-(sp) ; Store parameters move.l d0,d2 move.l d1,d3 movea.l a1,a3 ; Load missile's existing settings move.l (env_Settings+M0*4,a3),d2 ; See if missile is being locked or unlocked btst.l #1,d0 beq unlock$ ; Check if missile is already locked btst.l #OBJB_LOCKED,d2 bne end$ ; Record missile as being locked bset.l #OBJB_LOCKED,d2 ; Get corresponding player's central position move.l (env_Settings+P0*4,a3),d1 bfextu d1{OBJO_NUMBERSIZE:OBJW_NUMBERSIZE},d0 move.b (player_centre_table.l,d0),d0 bfextu d1{OBJO_POSITION:OBJW_POSITION},d1 add.l d0,d1 cmpi.w #TV_WIDTH,d1 blo skip_wrap_around$ subi.w #TV_WIDTH,d1 skip_wrap_around$: ; Set missile's new position bfins d1,d2{OBJO_POSITION:OBJW_POSITION} bra skip_unlock$ unlock$: ; Check if missile is already unlocked btst.l #OBJB_LOCKED,d2 beq end$ ; Record missile as being unlocked bclr.l #OBJB_LOCKED,d2 skip_unlock$: ; Calculate current colour clock move.l d3,d0 add.l d0,d0 add.l d0,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition ; Update missile's pattern list move.l d0,d1 moveq #M0,d0 movea.l a3,a1 bsr UpdatePatternList ; Store new settings for missile move.l d2,(env_Settings+M0*4,a3) bra end$ end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a3 rts ;****** atari2600.library/A2600_ResMP1 *** ; ; NAME ; A2600_ResMP1 -- Lock missile 1 to its player. (V2) ; ; SYNOPSIS ; A2600_ResMP1(mode,clock,env) ; d0 d1 a1 ; ; VOID A2600_ResMP1(ULONG,ULONG,APTR); ; ; FUNCTION ; Either locks the second missile's horizontal position to the centre ; of its player or unlocks it so that it can move freely. When the ; missile is locked, its horizontal position is always the same as ; that of its player. ; ; INPUTS ; mode - Bit 1 should be set to lock the missile, cleared to unlock ; it. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; ResMP1: IFD PROFILE addq.l #1,(env_ProfileData+$29<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d3/a3,-(sp) ; Store parameters move.l d0,d2 move.l d1,d3 movea.l a1,a3 ; Load missile's existing settings move.l (env_Settings+M1*4,a3),d2 ; See if missile is being locked or unlocked btst.l #1,d0 beq unlock$ ; Check if missile is already locked btst.l #OBJB_LOCKED,d2 bne end$ ; Record missile as being locked bset.l #OBJB_LOCKED,d2 ; Get corresponding player's central position move.l (env_Settings+P1*4,a3),d1 bfextu d1{OBJO_NUMBERSIZE:OBJW_NUMBERSIZE},d0 move.b (player_centre_table.l,d0),d0 bfextu d1{OBJO_POSITION:OBJW_POSITION},d1 add.l d0,d1 cmpi.w #TV_WIDTH,d1 blo skip_wrap_around$ subi.w #TV_WIDTH,d1 skip_wrap_around$: ; Set missile's new position bfins d1,d2{OBJO_POSITION:OBJW_POSITION} bra skip_unlock$ unlock$: ; Check if missile is already unlocked btst.l #OBJB_LOCKED,d2 beq end$ ; Record missile as being unlocked bclr.l #OBJB_LOCKED,d2 skip_unlock$: ; Calculate current colour clock move.l d3,d0 add.l d0,d0 add.l d0,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition ; Update missile's pattern list move.l d0,d1 moveq #M1,d0 movea.l a3,a1 bsr UpdatePatternList ; Store new settings for missile move.l d2,(env_Settings+M1*4,a3) end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a3 rts ;****** atari2600.library/A2600_HMove *** ; ; NAME ; A2600_HMove -- Move all Atari 2600 objects horizontally. ; ; SYNOPSIS ; A2600_HMove(clock,env) ; d1 a1 ; ; VOID A2600_HMove(ULONG,APTR); ; ; FUNCTION ; Moves all objects according to their current horizontal movement ; rates. ; ; INPUTS ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ; BUGS ; Prior to V2, this function gave incorrect movement if not called ; directly after WSync(). ; ;*** ; ; HMove: ; rts IFD PROFILE addq.l #1,(env_ProfileData+$2a<<2,a1) ENDC ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Push registers that should be preserved onto stack movem.l d2-d4/a2-a4,-(sp) ; Store parameters move.l d1,d3 movea.l a1,a3 ; Get address of motion array appropriate to the current position divu.w #A2600_LINE_CYCLES/3,d1 swap.w d1 lsl.w #4+1,d1 lea.l (horizontal_motion_table.l,d1),a2 ; Calculate current colour clock move.l d3,d0 lsl.l #1,d0 add.l d0,d3 ; Get update position move.l d3,d1 movea.l a3,a1 bsr CalculateCurrentPosition move.l d0,d3 ; Initialise object loop moveq #OBJECT_COUNT-1,d2 lea.l (env_MotionRates+OBJECT_COUNT*2,a3),a4 next_object$: ; Get object's actual movement rate move.w -(a4),d4 move.w (a2,d4*2),d4 ; See if object should move beq skip_object$ ; Update object's pattern list move.l d3,d1 move.l d2,d0 movea.l a3,a1 bsr UpdatePatternList ; Adjust object's position by its motion value move.b (env_Settings+1,a3,d2*4),d1 andi.w #$ff,d1 sub.w d4,d1 bpl check_upper_bound$ add.w #TV_WIDTH,d1 bra save_position$ check_upper_bound$: cmpi.w #TV_WIDTH,d1 blo save_position$ sub.w #TV_WIDTH,d1 save_position$: ; Store object's new position move.b d1,(env_Settings+1,a3,d2*4) skip_object$: dbra d2,next_object$ ; Pop preserved registers off stack and return movem.l (sp)+,d2-d4/a2-a4 rts ;****** atari2600.library/A2600_HMClr *** ; ; NAME ; A2600_HMClr -- Reset Atari 2600 objects' horizontal movement rates. ; ; SYNOPSIS ; A2600_HMClr(clock,env) ; d1 a1 ; ; VOID A2600_HMClr(ULONG,APTR); ; ; FUNCTION ; Sets the movement rates of all objects to stationary. ; ; INPUTS ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; HMClr: IFD PROFILE addq.l #1,(env_ProfileData+$2b<<2,a1) ENDC ; Reset all objects' horizontal movement rates to (officially) ; stationary. lea.l (env_MotionRates,a1),a0 clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ ; Return rts ;****** atari2600.library/A2600_CxClr *** ; ; NAME ; A2600_CxClr -- Reset collisions between Atari 2600 objects. (V2) ; ; SYNOPSIS ; A2600_CxClr(clock,env) ; d1 a1 ; ; VOID A2600_CxClr(ULONG,APTR); ; ; FUNCTION ; Resets all emulated collision registers to a state of no collision. ; ; INPUTS ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; CxClr: rts ; Reset collision registers to no-collision while preserving the ; mysterious undocumented bits in those locations. movea.l (env_Data,a1),a0 moveq #$70,d0 loop$: move.l #$00010203,(a0,d0) move.l #$04050600,(4,a0,d0) subi.l #$10,d0 bpl loop$ ; Return rts ;****** atari2600.library/A2600_OpenAtari2600 *** ; ; NAME ; A2600_OpenAtari2600 -- Create a new Atari 2600 environment. ; ; SYNOPSIS ; env = A2600_OpenAtari2600(tag_items,orig_sp,mem_base) ; d0 a0 d0 a1 ; ; APTR A2600_OpenAtari2600(struct TagItem *,APTR,APTR); ; ; FUNCTION ; Opens a new Atari 2600 environment to emulate that machine's custom ; hardware functions. ; ; INPUTS ; tag_items - Pointer to a taglist of parameters. ; orig_sp - The program's starting stack pointer. ; mem_base - Pointer to the program's Atari 2600 memory. ; ; TAGS ; A2600TAG_ProgramName (STRPTR) - The name of the program that will ; use the environment. The string is not copied and must be ; preserved for the lifetime of the environment. ; A2600TAG_ExitFunction (FPTR) - Pointer to a function that will be ; called when the human user chooses to exit the program. This ; function must close the environment and this library, deallocate ; any of the program's own resources etc. and then set a DOS ; return code and return. ; A2600TAG_WBMsg (struct WBStartup *) - The program's Workbench ; start up message. This is used to access the program icon's Tool ; Types. (V2) ; ; RESULT ; env - A new Atari 2600 environment. ; ; SEE ALSO ; A2600_CloseAtari2600() ; ;*** ; ; OpenAtari2600: ; Push registers that should be preserved onto stack movem.l d2-d7/a2-a6,-(sp) ; Store parameters movea.l a0,a2 move.l d0,d2 movea.l a1,a4 movea.l a6,a5 ; Allocate memory for a new environment structure move.l (ab_SysLib,a5),a6 move.l #env_SIZEOF,d0 move.l #MEMF_CLEAR,d1 JSRLIB AllocMem movea.l d0,a3 tst.l d0 beq clean_up$ ; Store program's name movea.l (ab_UtilityLib,a5),a6 move.l #A2600TAG_ProgramName,d0 move.l #default_prog_name,d1 movea.l a2,a0 JSRLIB GetTagData move.l d0,(env_ProgramName,a3) ; Store original stack pointer for use when quitting move.l d2,(env_OriginalStackPtr,a3) ; Store address of Atari 2600 address space move.l a4,(env_Data,a3) ; Store address of client program's exit function move.l #A2600TAG_ExitFunction,d0 move.l #0,d1 movea.l a2,a0 JSRLIB GetTagData move.l d0,(env_ExitFunction,a3) beq clean_up$ ; Store default values for tool type variables move.w #1,(env_FrameSkipRatio,a3) move.w #DEFAULT_START_LINE,(env_StartingLineNo,a3) move.w #60,(env_IdealFrameRate,a3) move.w #DEFAULT_TV_HEIGHT,(env_TVHeight,a3) move.w #1,(env_SoundOn,a3) move.w #JOYSTICK<<8+NOCONTROLLER,(env_ControllerTypes,a3) move.l #INVALID_ID,(env_ScreenModeID,a3) ; Get WB startup message move.l #A2600TAG_WBMsg,d0 move.l #0,d1 movea.l a2,a0 JSRLIB GetTagData tst.l d0 bne wb_msg$ ; Get lock for program's directory movea.l (ab_DosLib,a5),a6 JSRLIB GetProgramDir move.l d0,(env_HomeDirLock,a3) beq no_tooltypes$ ; Get program's file name movea.l (ab_SysLib,a5),a6 move.l #256,d2 move.l d2,d0 moveq #0,d1 JSRLIB AllocMem move.l d0,(env_ProgramFileName,a3) beq no_tooltypes$ movea.l (ab_DosLib,a5),a6 move.l d0,d1 JSRLIB GetProgramName tst.l d0 beq no_tooltypes$ movea.l (env_ProgramFileName,a3),a2 bra skip_wb_msg$ wb_msg$: ; Record a workbench start for the program move.w #1,(env_WBStart,a3) ; Get directory lock and program name from start-up message movea.l d0,a0 movea.l (sm_ArgList,a0),a2 move.l (wa_Lock,a2),(env_HomeDirLock,a3) movea.l (wa_Name,a2),a2 move.l a2,(env_ProgramFileName,a3) skip_wb_msg$: ; Get program's tool types movea.l (ab_DosLib,a5),a6 move.l (env_HomeDirLock,a3),d1 JSRLIB CurrentDir move.l d0,d2 movea.l (ab_IconLib,a5),a6 movea.l a2,a0 JSRLIB GetDiskObject move.l d0,(env_DiskObject,a3) movea.l (ab_DosLib,a5),a6 move.l d2,d1 JSRLIB CurrentDir move.l (env_DiskObject,a3),d0 beq no_tooltypes$ movea.l (do_ToolTypes.w,d0.l),a2 ; Parse frame-skip tool type movea.l (ab_IconLib,a5),a6 movea.l a2,a0 movea.l #frameskip_tt_name,a1 JSRLIB FindToolType tst.l d0 beq no_frameskip_tt$ movea.l (ab_DosLib,a5),a6 move.l d0,d1 subq.l #4,sp move.l sp,d2 JSRLIB StrToLong move.l (sp)+,d0 beq no_frameskip_tt$ bmi no_frameskip_tt$ move.w d0,(env_FrameSkipRatio,a3) subq.w #1,d0 move.w d0,(env_VSyncOffAttempts,a3) no_frameskip_tt$: ; Parse starting-line tool type movea.l (ab_IconLib,a5),a6 movea.l a2,a0 movea.l #startingline_tt_name,a1 JSRLIB FindToolType tst.l d0 beq no_startingline_tt$ movea.l (ab_DosLib,a5),a6 move.l d0,d1 subq.l #4,sp move.l sp,d2 JSRLIB StrToLong move.l (sp)+,d1 bmi no_startingline_tt$ tst.l d0 bmi no_startingline_tt$ move.w d1,(env_StartingLineNo,a3) no_startingline_tt$: ; Parse TV lines tool type movea.l (ab_IconLib,a5),a6 movea.l a2,a0 movea.l #tvlines_tt_name,a1 JSRLIB FindToolType tst.l d0 beq no_tvlines_tt$ movea.l (ab_DosLib,a5),a6 move.l d0,d1 subq.l #4,sp move.l sp,d2 JSRLIB StrToLong move.l (sp)+,d0 bmi no_tvlines_tt$ beq no_tvlines_tt$ move.w d0,(env_TVHeight,a3) no_tvlines_tt$: ; Parse frame-rate tool type movea.l (ab_IconLib,a5),a6 movea.l a2,a0 movea.l #framerate_tt_name,a1 JSRLIB FindToolType tst.l d0 beq no_framerate_tt$ movea.l (ab_DosLib,a5),a6 move.l d0,d1 subq.l #4,sp move.l sp,d2 JSRLIB StrToLong move.l (sp)+,d0 beq no_framerate_tt$ bmi no_framerate_tt$ move.w d0,(env_IdealFrameRate,a3) no_framerate_tt$: ; Parse no-sound tool type movea.l (ab_IconLib,a5),a6 movea.l a2,a0 movea.l #nosound_tt_name,a1 JSRLIB FindToolType tst.l d0 beq no_nosound_tt$ clr.w (env_SoundOn,a3) no_nosound_tt$: ; Parse left and right controller tool types movea.l (ab_IconLib,a5),a6 moveq #2-1,d2 next_controller_tt$: movea.l a2,a0 movea.l (controller_tt_name_table.l,d2*4),a1 JSRLIB FindToolType tst.l d0 beq no_controller_tt$ moveq #CONTROLLER_COUNT-1,d3 movea.l d0,a4 next_controller_type$: movea.l a4,a0 movea.l (controller_tt_value_table.l,d3*4),a1 JSRLIB MatchToolValue tst.l d0 beq.s controller_not_matched$ move.b d3,(env_ControllerTypes,a3,d2) controller_not_matched$: dbra d3,next_controller_type$ no_controller_tt$: dbra d2,next_controller_tt$ ; Parse screen-mode tool type movea.l (ab_IconLib,a5),a6 movea.l a2,a0 movea.l #screenmode_tt_name,a1 JSRLIB FindToolType tst.l d0 beq no_screenmode_tt$ cmpi.w #'0x',(d0.l) bne decimal_id$ move.l d0,a0 addq.l #2,a0 subq.l #4,sp movea.l sp,a1 bsr HexToULong move.l (sp)+,d1 tst.l d0 beq no_screenmode_tt$ move.l d1,(env_ScreenModeID,a3) bra skip_decimal_id$ decimal_id$: movea.l (ab_DosLib,a5),a6 move.l d0,d1 subq.l #4,sp move.l sp,d2 JSRLIB StrToLong move.l (sp)+,d1 bmi no_screenmode_tt$ tst.l d0 bmi no_screenmode_tt$ move.l d1,(env_ScreenModeID,a3) skip_decimal_id$: no_screenmode_tt$: no_tooltypes$: ; Calculate TV height rounded-up to nearest multiple of four moveq #0,d0 move.w (env_TVHeight,a3),d0 subq.w #1,d0 lsr.w #2,d0 addq.w #1,d0 lsl.w #2,d0 move.l d0,(env_RoundedTVHeight,a3) ; Calculate the size of a screen pattern move.l (env_RoundedTVHeight,a3),d0 mulu.w #BYTES_PER_LINE,d0 move.l d0,(env_PatternSize,a3) ; Calculate the height of the intuition screen moveq #MENU_BAR_HEIGHT,d0 add.w (env_TVHeight,a3),d0 move.l d0,(env_ScreenHeight,a3) ; Check if a screen mode has already been specified in a tooltype cmpi.l #INVALID_ID,(env_ScreenModeID,a3) bne no_screen_req$ ; Make a copy of the screen mode requester tag list movea.l (ab_UtilityLib,a5),a6 lea screen_req_tags,a0 JSRLIB CloneTagItems move.l d0,(env_ScreenReqTags,a3) beq clean_up$ ; Set minimum height for screen mode move.l #ASLSM_MinHeight,d0 move.l (env_ScreenReqTags,a3),a0 JSRLIB FindTagItem move.l (env_ScreenHeight,a3),(ti_Data.w,d0.l) ; Set window title for screen mode requester move.l #ASLSM_TitleText,d0 move.l (env_ScreenReqTags,a3),a0 JSRLIB FindTagItem move.l (env_ProgramName,a3),(ti_Data.w,d0.l) ; Allocate screen mode requester movea.l (ab_AslLib,a5),a6 moveq #ASL_ScreenModeRequest,d0 move.l (env_ScreenReqTags,a3),a0 JSRLIB AllocAslRequest move.l d0,(env_ScreenReq,a3) beq clean_up$ ; Ask the user for a screen mode move.l (env_ScreenReq,a3),a2 movea.l a2,a0 suba.l a1,a1 JSRLIB AslRequest tst.l d0 beq clean_up$ ; Store screen mode move.l (sm_DisplayID,a2),(env_ScreenModeID,a3) ; Check if the icon file has been read tst.l (env_DiskObject,a3) beq no_screen_req$ ; Allocate memory for a screen mode tooltype string movea.l (ab_SysLib,a5),a6 moveq #SCREENMODE_STR_SIZE+11+1,d0 moveq #0,d1 JSRLIB AllocMem move.l d0,(env_ScreenModeString,a3) beq clean_up$ ; Create screen mode tooltype string movea.l d0,a2 movea.l #screenmode_tt_name,a0 movea.l d0,a1 moveq #SCREENMODE_STR_SIZE,d0 JSRLIB CopyMem movea.l a2,a0 adda.l #SCREENMODE_STR_SIZE,a0 move.b #'=',(a0)+ move.w #'0x',(a0)+ move.l (env_ScreenModeID,a3),d0 bsr ULongToHex ; Count tooltypes plus two movea.l ([env_DiskObject,a3],do_ToolTypes),a4 movea.l a4,a2 moveq #1,d2 count_tooltypes$: addq.l #1,d2 move.l (a2)+,d0 beq count_tooltypes_end$ movea.l a5,a6 movea.l d0,a0 movea.l #screenmode_tt_name,a1 bsr Substring tst.l d0 bne no_screen_req$ bra count_tooltypes$ count_tooltypes_end$: ; Create new tooltype array movea.l (ab_SysLib,a5),a6 move.l d2,d0 lsl.l #2,d0 moveq #0,d1 JSRLIB AllocMem move.l d0,a2 tst.l d0 beq clean_up$ movea.l a4,a0 movea.l a2,a1 move.l d2,d1 subq.l #2,d1 bra copy_tooltypes_start$ copy_tooltypes$: movea.l (a0)+,(a1)+ copy_tooltypes_start$: dbra d1,copy_tooltypes$ ; Add screen mode string onto end of array and terminate it with a ; null pointer. move.l (env_ScreenModeString,a3),(a1)+ clr.l (a1) ; Write icon file to disk movea.l (ab_DosLib,a5),a6 move.l (env_HomeDirLock,a3),d1 JSRLIB CurrentDir move.l d0,d3 movea.l (ab_IconLib,a5),a6 movea.l (env_DiskObject,a3),a1 move.l a2,(do_ToolTypes,a1) movea.l (env_ProgramFileName,a3),a0 JSRLIB PutDiskObject movea.l (ab_DosLib,a5),a6 move.l d3,d1 JSRLIB CurrentDir ; Restore original tooltype array movea.l (env_DiskObject,a3),a1 move.l a4,(do_ToolTypes,a1) ; Free memory for new tooltype array movea.l (ab_SysLib,a5),a6 move.l d2,d0 lsl.l #2,d0 movea.l a2,a1 JSRLIB FreeMem no_screen_req$: ; Check if sound should be used tst.w (env_SoundOn,a3) beq no_sound$ ; Allocate sound clr.w (env_SoundOn,a3) movea.l a5,a6 movea.l a3,a1 moveq #1,d0 bsr AllocateSound tst.l d0 beq no_sound$ move.w #1,(env_SoundOn,a3) no_sound$: ; Create a series of bitmaps to contain the display movea.l (ab_GraphicsLib,a5),a6 moveq #SCREEN_BUFFER_COUNT-1,d4 bitmap_loop$: move.l #TV_WIDTH*X_MAG,d0 move.l (env_ScreenHeight,a3),d1 move.l #SCREEN_DEPTH,d2 move.l #(BMF_CLEAR|BMF_DISPLAYABLE),d3 move.l #0,a0 JSRLIB AllocBitMap move.l d0,(env_ScreenBitMaps,a3,d4*4) beq clean_up$ dbra d4,bitmap_loop$ ; Make a copy of the screen tag list movea.l (ab_UtilityLib,a5),a6 lea screen_tags,a0 JSRLIB CloneTagItems move.l d0,(env_ScreenTags,a3) beq clean_up$ ; Set screen height move.l #SA_Height,d0 move.l (env_ScreenTags,a3),a0 JSRLIB FindTagItem movea.l d0,a0 move.l (env_ScreenHeight,a3),(ti_Data,a0) ; Set screen bitmap move.l #SA_BitMap,d0 move.l (env_ScreenTags,a3),a0 JSRLIB FindTagItem movea.l d0,a0 move.l (env_ScreenBitMaps,a3),(ti_Data,a0) ; Set screen's screen mode movea.l (ab_UtilityLib,a5),a6 move.l #SA_DisplayID,d0 move.l (env_ScreenTags,a3),a0 JSRLIB FindTagItem movea.l d0,a0 move.l (env_ScreenModeID,a3),(ti_Data,a0) ; Set screen title move.l #SA_Title,d0 move.l (env_ScreenTags,a3),a0 JSRLIB FindTagItem movea.l d0,a0 move.l (env_ProgramName,a3),(ti_Data,a0) ; Open the screen movea.l (ab_IntuitionLib,a5),a6 movea.l #0,a0 movea.l (env_ScreenTags,a3),a1 JSRLIB OpenScreenTagList move.l d0,(env_Screen,a3) beq clean_up$ ; Make a copy of the window tag list movea.l (ab_UtilityLib,a5),a6 lea window_tags,a0 JSRLIB CloneTagItems move.l d0,(env_WindowTags,a3) beq clean_up$ ; Set window's height move.l #WA_Height,d0 move.l (env_WindowTags,a3),a0 JSRLIB FindTagItem movea.l d0,a0 moveq #0,d0 move.w (env_TVHeight,a3),d0 move.l d0,(ti_Data,a0) ; Set window's screen move.l #WA_CustomScreen,d0 move.l (env_WindowTags,a3),a0 JSRLIB FindTagItem movea.l d0,a0 move.l (env_Screen,a3),(ti_Data,a0) ; Open main window movea.l ab_IntuitionLib(a5),a6 movea.l #0,a0 movea.l (env_WindowTags,a3),a1 JSRLIB OpenWindowTagList move.l d0,(env_Window,a3) beq clean_up$ ; Get window's UserPort movea.l env_Window(a3),a0 move.l wd_UserPort(a0),env_UserPort(a3) ; Create menus structure movea.l ab_GadtoolsLib(a5),a6 lea new_menus,a0 movea.l #0,a1 JSRLIB CreateMenusA move.l d0,env_Menus(a3) beq clean_up$ ; Get screen info needed for displaying menus movea.l ab_GadtoolsLib(a5),a6 movea.l env_Screen(a3),a0 movea.l #0,a1 JSRLIB GetVisualInfoA move.l d0,env_VisualInfo(a3) beq clean_up$ ; Prepare menus for display movea.l ab_GadtoolsLib(a5),a6 movea.l env_Menus(a3),a0 movea.l env_VisualInfo(a3),a1 lea.l menu_layout_tags,a2 JSRLIB LayoutMenusA tst.l d0 beq clean_up$ ; Display menus movea.l ab_IntuitionLib(a5),a6 movea.l env_Window(a3),a0 movea.l env_Menus(a3),a1 JSRLIB SetMenuStrip ; Create a series of screen buffer structures for multi-buffering movea.l (ab_IntuitionLib,a5),a6 movea.l (env_Screen,a3),a0 movea.l (env_ScreenBitMaps+0*4,a3),a1 moveq #0,d0 JSRLIB AllocScreenBuffer move.l d0,(env_ScreenBuffers+0*4,a3) beq clean_up$ movea.l (env_Screen,a3),a0 movea.l (env_ScreenBitMaps+1*4,a3),a1 moveq #SB_COPY_BITMAP,d0 JSRLIB AllocScreenBuffer move.l d0,(env_ScreenBuffers+1*4,a3) beq clean_up$ movea.l (env_Screen,a3),a0 movea.l (env_ScreenBitMaps+2*4,a3),a1 moveq #SB_COPY_BITMAP,d0 JSRLIB AllocScreenBuffer move.l d0,(env_ScreenBuffers+2*4,a3) beq clean_up$ ; Create message ports for the library to use in receiving ; information that ensures a smooth display. movea.l ab_SysLib(a5),a6 JSRLIB CreateMsgPort move.l d0,env_SafeMsgPort(a3) beq clean_up$ JSRLIB CreateMsgPort move.l d0,env_DispMsgPort(a3) beq clean_up$ ; Put message ports into multi-buffering structures moveq #SCREEN_BUFFER_COUNT-1,d2 buffer_ports_loop$: movea.l ([env_ScreenBuffers,a3,d2*4],sb_DBufInfo),a0 move.l (env_SafeMsgPort,a3),(dbi_SafeMessage+MN_REPLYPORT,a0) move.l (env_DispMsgPort,a3),(dbi_DispMessage+MN_REPLYPORT,a0) dbra d2,buffer_ports_loop$ ; Generate initial screen-buffering messages movea.l (ab_SysLib,a5),a6 movea.l ([env_ScreenBuffers,a3],sb_DBufInfo),a0 lea.l (dbi_SafeMessage,a0),a1 JSRLIB ReplyMsg movea.l ([env_ScreenBuffers,a3],sb_DBufInfo),a0 lea.l (dbi_DispMessage,a0),a1 JSRLIB ReplyMsg movea.l ([env_ScreenBuffers,a3],sb_DBufInfo),a0 lea.l (dbi_DispMessage,a0),a1 JSRLIB ReplyMsg movea.l ([env_ScreenBuffers,a3],sb_DBufInfo),a0 lea.l (dbi_DispMessage,a0),a1 JSRLIB ReplyMsg ; Allocate memory for all-pattern difference pattern moveq #0,d0 move.w (env_TVHeight,a3),d0 move.l #MEMF_CLEAR,d1 JSRLIB AllocMem move.l d0,(env_DifferencePattern,a3) beq clean_up$ ; Allocate memory for all-object difference pattern moveq #0,d0 move.w (env_TVHeight,a3),d0 move.l #MEMF_CLEAR,d1 JSRLIB AllocMem move.l d0,(env_ObjectDifferencePattern,a3) beq clean_up$ ; Allocate memory for pattern lists and initialise them moveq #PATTERN_COUNT-1,d3 pattern_list_loop$: lea.l (env_PatternLists,a3),a2 moveq #(SCREEN_BUFFER_COUNT+1)*4,d0 mulu.w d3,d0 adda.l d0,a2 moveq #SCREEN_BUFFER_COUNT,d2 inner_pattern_list_loop$: move.l #LIST_SIZE,d0 moveq #0,d1 JSRLIB AllocMem move.l d0,(a2,d2*4) beq clean_up$ movea.l d0,a1 move.l #OBJF_VBLANK,(a1)+ move.l (env_TVHeight,a3),(a1) dbra d2,inner_pattern_list_loop$ move.l (a2),d0 move.l d0,(env_PatternListPtrs,a3,d3*4) add.l #LIST_SIZE-2*8,d0 move.l d0,(env_PatternListLimits,a3,d3*4) dbra d3,pattern_list_loop$ ; Allocate memory for patterns moveq #PATTERN_COUNT-1,d2 pattern_loop$: move.l (env_PatternSize,a3),d0 move.l #MEMF_CLEAR,d1 JSRLIB AllocMem move.l d0,(env_Patterns,a3,d2*4) beq clean_up$ dbra d2,pattern_loop$ ; Allocate memory for merged patterns moveq #REDUCED_PATTERN_COUNT*(SCREEN_BUFFER_COUNT+1)-1,d2 merged_pattern_loop$: move.l (env_PatternSize,a3),d0 move.l #MEMF_CLEAR,d1 JSRLIB AllocMem move.l d0,(env_MergedPatterns,a3,d2*4) beq clean_up$ dbra d2,merged_pattern_loop$ ; Allocate memory for difference patterns moveq #REDUCED_PATTERN_COUNT-1,d2 difference_patterns_loop$: move.l (env_RoundedTVHeight,a3),d0 move.l #MEMF_CLEAR,d1 JSRLIB AllocMem move.l d0,(env_DifferencePatterns,a3,d2*4) beq clean_up$ dbra d2,difference_patterns_loop$ ; Allocate memory for summary patterns moveq #OBJECT_COUNT-1,d2 summary_loop$: move.l (env_RoundedTVHeight,a3),d0 move.l #MEMF_CLEAR,d1 JSRLIB AllocMem move.l d0,(env_SummaryPatterns,a3,d2*4) beq clean_up$ dbra d2,summary_loop$ ; Allocate memory for pattern line move.l #BYTES_PER_LINE+4*4,d0 moveq #0,d1 JSRLIB AllocMem move.l d0,(env_PatternLine,a3) beq clean_up$ ; Allocate memory for the "About" requester structure move.l #EasyStruct_SIZEOF,d0 moveq #0,d1 JSRLIB AllocMem move.l d0,(env_AboutRequester,a3) beq clean_up$ ; Fill in "About" requester structure movea.l (env_AboutRequester,a3),a0 move.l #EasyStruct_SIZEOF,(es_StructSize,a0) move.l (env_ProgramName,a3),(es_Title,a0) move.l #about_req_body_text,(es_TextFormat,a0) move.l #about_req_button_text,(es_GadgetFormat,a0) ; Set offset of part of bit planes that should be written to move.w #MENU_BAR_HEIGHT*TV_WIDTH*2/8,env_SkipMenuOffset(a3) ; Set emulated system variables to default values move.b #%11001011,([env_Data,a3],A2600_SWCHB) ; pro, colour, no select or reset move.b #%11001011,([env_Data,a3],A2600_SWCHB+$100) move.b #%11111111,([env_Data,a3],A2600_SWCHA) ; no joystick activity move.b #%11111111,([env_Data,a3],A2600_SWCHA+$100) move.w #1,(env_MouseX,a3) ; move.b #$80,([env_Data,a3],$285) ; Initialise read registers movea.l (env_Data,a3),a0 moveq #8-1,d0 read_register_loop$: move.l #$00010203,(a0)+ move.l #$04050600,(a0)+ move.l #$7f7f7f7f,(a0)+ move.l #$ffff0e0f,(a0)+ dbra d0,read_register_loop$ ; Get and store current time in milliseconds movea.l a5,a6 bsr GetTime move.l d0,(env_MillisecondCount,a3) ; Initialise plane pointers movea.l a3,a1 bsr GetHiddenBitPlanes move.l d0,(env_PlanePtrs,a3) ; Set environment pointer as return value movea.l a3,d0 bra skip_clean_up$ clean_up$: ; Deallocate environment resources and set return value to null movea.l a5,a6 movea.l a3,a1 bsr CloseAtari2600 moveq #0,d0 skip_clean_up$: ; Return new environment or null movem.l (sp)+,d2-d7/a2-a6 rts ;****** atari2600.library/A2600_CloseAtari2600 *** ; ; NAME ; A2600_CloseAtari2600 -- Close an Atari 2600 environment. ; ; SYNOPSIS ; A2600_CloseAtari2600(env) ; a1 ; ; VOID A2600_CloseAtari2600(APTR); ; ; FUNCTION ; Closes an Atari 2600 environment and all of its resources. ; ; INPUTS ; env - The Atari 2600 environment to be closed. May be NULL. ; ; RESULT ; None. ; ; SEE ALSO ; A2600_OpenAtari2600() ; ;*** ; ; CloseAtari2600: ;FIX LEAK AT BOTTOM OF THIS FUNCTION! IFD PROFILE lea.l (env_ProfileData,a1),a0 move.l a0,8 ENDC ; Push registers that should be preserved onto stack movem.l d2-d7/a2-a6,-(sp) ; Move library and environment pointers to safe registers movea.l a6,a5 movea.l a1,a3 ; See if environment is null cmpa.l #0,a3 beq end$ ; Free memory for the "About" requester structure movea.l (ab_SysLib,a5),a6 move.l #EasyStruct_SIZEOF,d0 move.l (env_AboutRequester,a3),d1 beq skip_about$ movea.l d1,a1 JSRLIB FreeMem skip_about$: ; Free memory for all-pattern difference pattern moveq #0,d0 move.w (env_TVHeight,a3),d0 movea.l (env_DifferencePattern,a3),d1 beq skip_diff$ movea.l d1,a1 JSRLIB FreeMem skip_diff$: ; Free memory for all-object difference pattern moveq #0,d0 move.w (env_TVHeight,a3),d0 movea.l (env_ObjectDifferencePattern,a3),d1 beq skip_object_diff$ movea.l d1,a1 JSRLIB FreeMem skip_object_diff$: ; Free memory for patterns moveq #PATTERN_COUNT-1,d2 pattern_loop$: move.l (env_PatternSize,a3),d0 move.l (env_Patterns,a3,d2*4),d1 beq skip_pattern$ movea.l d1,a1 JSRLIB FreeMem skip_pattern$: dbra d2,pattern_loop$ ; Free memory for merged patterns moveq #REDUCED_PATTERN_COUNT*(SCREEN_BUFFER_COUNT+1)-1,d2 merged_pattern_loop$: move.l (env_PatternSize,a3),d0 move.l (env_MergedPatterns,a3,d2*4),d1 beq skip_merged_pattern$ movea.l d1,a1 JSRLIB FreeMem skip_merged_pattern$: dbra d2,merged_pattern_loop$ ; Free memory for pattern lists moveq #PATTERN_COUNT-1,d3 pattern_list_loop$: lea.l (env_PatternLists,a3),a2 moveq #(SCREEN_BUFFER_COUNT+1)*4,d0 mulu.w d3,d0 adda.l d0,a2 moveq #SCREEN_BUFFER_COUNT,d2 inner_pattern_list_loop$: move.l #LIST_SIZE,d0 move.l #MEMF_CLEAR,d1 move.l (a2,d2*4),d1 beq skip_pattern_list$ movea.l d1,a1 JSRLIB FreeMem skip_pattern_list$: dbra d2,inner_pattern_list_loop$ dbra d3,pattern_list_loop$ ; Free memory for difference patterns moveq #REDUCED_PATTERN_COUNT-1,d2 difference_patterns_loop$: move.l (env_RoundedTVHeight,a3),d0 movea.l (env_DifferencePatterns,a3,d2*4),d1 beq skip_difference_pattern$ movea.l d1,a1 JSRLIB FreeMem skip_difference_pattern$: dbra d2,difference_patterns_loop$ ; Free memory for summary patterns moveq #OBJECT_COUNT-1,d2 summary_loop$: move.l (env_RoundedTVHeight,a3),d0 movea.l (env_SummaryPatterns,a3,d2*4),d1 beq skip_summary_pattern$ movea.l d1,a1 JSRLIB FreeMem skip_summary_pattern$: dbra d2,summary_loop$ ; Free memory for pattern line move.l #BYTES_PER_LINE+4*4,d0 movea.l (env_PatternLine,a3),d1 beq skip_pattern_line$ movea.l d1,a1 JSRLIB FreeMem skip_pattern_line$: ; See if window is open tst.l (env_Window,a3) beq no_window$ ; Remove menus movea.l ab_IntuitionLib(a5),a6 movea.l env_Window(a3),a0 JSRLIB ClearMenuStrip ; Free visual info structure movea.l ab_GadtoolsLib(a5),a6 movea.l env_VisualInfo(a3),a0 JSRLIB FreeVisualInfo ; Free menus movea.l ab_GadtoolsLib(a5),a6 movea.l env_Menus(a3),a0 JSRLIB FreeMenus ; Close main window move.l ab_IntuitionLib(a5),a6 movea.l env_Window(a3),a0 JSRLIB CloseWindow no_window$: ; Free copy of window tag list move.l (ab_UtilityLib,a5),a6 move.l (env_WindowTags,a3),a0 JSRLIB FreeTagItems ; See if the screen is open tst.l (env_Screen,a3) beq no_screen$ ; Free screen buffers as soon as they are no longer in use move.l (ab_GraphicsLib,a5),a6 JSRLIB WaitBlit move.l (ab_IntuitionLib,a5),a6 moveq #SCREEN_BUFFER_COUNT-1,d2 buffer_loop$: movea.l env_Screen(a3),a0 movea.l (env_ScreenBuffers,a3,d2*4),a1 JSRLIB FreeScreenBuffer dbra d2,buffer_loop$ ; Close the screen move.l ab_IntuitionLib(a5),a6 try_again$: movea.l env_Screen(a3),a0 JSRLIB CloseScreen ; Keep trying to close until successful cmp.l #0,d0 beq try_again$ no_screen$: ; Free copy of screen tag list move.l (ab_UtilityLib,a5),a6 move.l (env_ScreenTags,a3),a0 JSRLIB FreeTagItems ; Free bitmaps as soon as they are no longer in use move.l (ab_GraphicsLib,a5),a6 JSRLIB WaitBlit moveq #SCREEN_BUFFER_COUNT-1,d2 bitmap_loop$: movea.l (env_ScreenBitMaps,a3,d2*4),a0 JSRLIB FreeBitMap dbra d2,bitmap_loop$ ; Free double buffering message ports movea.l ab_SysLib(a5),a6 movea.l env_SafeMsgPort(a3),a0 JSRLIB DeleteMsgPort movea.l env_DispMsgPort(a3),a0 JSRLIB DeleteMsgPort ; Deallocate sound movea.l a5,a6 movea.l a3,a1 moveq #0,d0 bsr AllocateSound ; Free memory for screen mode tooltype string movea.l (ab_SysLib,a5),a6 moveq #SCREENMODE_STR_SIZE+11+1,d0 move.l (env_ScreenModeString,a3),d1 beq skip_screenmode_string$ movea.l d1,a1 JSRLIB FreeMem skip_screenmode_string$: ; Free disk object movea.l (ab_IconLib,a5),a6 move.l (env_DiskObject,a3),d0 beq skip_disk_object$ movea.l d0,a0 JSRLIB FreeDiskObject skip_disk_object$: ; Free screen mode requester movea.l (ab_AslLib,a5),a6 movea.l (env_ScreenReq,a3),a0 JSRLIB FreeAslRequest ; Free copy of screen mode requester tag list move.l (ab_UtilityLib,a5),a6 move.l (env_ScreenReqTags,a3),a0 JSRLIB FreeTagItems ; Free memory for program file name if not started from Workbench movea.l (ab_SysLib,a5),a6 tst.w (env_WBStart,a3) bne skip_prog_name$ move.l #256,d0 move.l (env_ProgramFileName,a3),d1 beq skip_prog_name$ movea.l d1,a1 JSRLIB FreeMem skip_prog_name$: ; Free environment memory IFND PROFILE movea.l a3,a1 move.l #env_SIZEOF,d0 JSRLIB FreeMem ENDC end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d7/a2-a6 rts ;****** atari2600.library/A2600_InstallROM *** ; ; NAME ; A2600_InstallROM -- Copy a ROM image into Atari 2600 address space. ; ; SYNOPSIS ; A2600_InstallROM(source,dest,size) ; a0 a1 d0 ; ; VOID A2600_InstallROM(APTR,APTR,ULONG); ; ; FUNCTION ; Just copies a block of data from one longword-aligned location to ; another. ; ; INPUTS ; source - Pointer to the source ROM image. ; dest - The destination address. ; size - The ROM image's size in bytes. ; ; RESULT ; None. ; ;*** ; ; InstallROM: ; Move ROM image into Atari 2600's address space move.l a5,-(sp) movea.l a6,a5 movea.l ab_SysLib(a5),a6 JSRLIB CopyMemQuick movea.l a5,a6 movea.l (sp)+,a5 ; Return rts ;****** atari2600.library/A2600_InTim *** ; ; NAME ; A2600_InTim -- See if the timer has timed out. ; ; SYNOPSIS ; result = A2600_InTim(clock,env) ; d0 d1 a1 ; ; ULONG A2600_InTim(ULONG,APTR); ; ; FUNCTION ; Checks if the timer has timed out. ; ; INPUTS ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; result - The number of emulated clock cycles since the timer timed ; out. ; ;*** ; ; InTim: ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Check if this timer run has timed out. move.l (env_Timer,a1),d0 sub.l d1,d0 blo.s timed_out$ ; Divide time difference by size of timer interval. move.w (env_TimerShift,a1),d1 lsr.l d1,d0 bra end$ timed_out$: ; Return the number of processor clocks since the time-out occurred. ; This value is modulo 256 since only a byte is returned. andi.l #$ff,d0 end$: ; Return rts ;****** atari2600.library/A2600_Tim1T *** ; ; NAME ; A2600_Tim1T -- Set timer in units of 1 clock cycle. ; ; SYNOPSIS ; A2600_Tim1T(units,clock,env) ; d0 d1 a1 ; ; VOID A2600_Tim1T(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the Riot chip's timer in units of 1 clock cycle. ; ; INPUTS ; units - The number of 1 clock cycle units. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; Tim1T: ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Record the clock value for time-out add.l d0,d1 move.l d1,(env_Timer,a1) ; Record the shift value for this function's interval move.w #0,(env_TimerShift,a1) ; Return rts ;****** atari2600.library/A2600_Tim8T *** ; ; NAME ; A2600_Tim8T -- Set timer in units of 8 clock cycles. ; ; SYNOPSIS ; A2600_Tim8T(units,clock,env) ; d0 d1 a1 ; ; VOID A2600_Tim8T(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the Riot chip's timer in units of 8 clock cycles. ; ; INPUTS ; units - The number of 8 clock cycle units. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; Tim8T: ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Record the clock value for time-out lsl.l #3,d0 add.l d0,d1 move.l d1,(env_Timer,a1) ; Record the shift value for this function's interval move.w #3,(env_TimerShift,a1) ; Return rts ;****** atari2600.library/A2600_Tim64T *** ; ; NAME ; A2600_Tim64T -- Set timer in units of 64 clock cycles. ; ; SYNOPSIS ; A2600_Tim64T(units,clock,env) ; d0 d1 a1 ; ; VOID A2600_Tim64T(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the Riot chip's timer in units of 64 clock cycles. ; ; INPUTS ; units - The number of 64 clock cycle units. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; Tim64T: ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Record the clock value for time-out lsl.l #6,d0 add.l d0,d1 move.l d1,(env_Timer,a1) ; Record the shift value for this function's interval move.w #6,(env_TimerShift,a1) ; Return rts ;****** atari2600.library/A2600_Tim1024T *** ; ; NAME ; A2600_Tim1024T -- Set timer in units of 1024 clock cycles. ; ; SYNOPSIS ; A2600_Tim1024T(units,clock,env) ; d0 d1 a1 ; ; VOID A2600_Tim1024T(ULONG,ULONG,APTR); ; ; FUNCTION ; Sets the Riot chip's timer in units of 1024 clock cycles. ; ; INPUTS ; units - The number of 1024 clock cycle units. ; clock - The number of emulated clock cycles since the program began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; Tim1024T: ; Correct clock parameter sub.l (env_ClockOffset,a1),d1 ; Record the clock value for time-out swap.w d0 lsr.l #6,d0 add.l d0,d1 move.l d1,(env_Timer,a1) ; Record the shift value for this function's interval move.w #10,(env_TimerShift,a1) ; Return rts ;****i* atari2600.library/NoFunction *** ; ; NAME ; NoFunction ; ; SYNOPSIS ; NoFunction() ; ;*** ; ; NoFunction: moveq #0,d0 rts ;****i* atari2600.library/AllocateSound *** ; ; NAME ; AllocateSound ; ; SYNOPSIS ; AllocateSound(on,env) ; d0 a1 ; ; FUNCTION ; Allocates or deallocates sound. ; ; INPUTS ; on - True for sound to be switched on, false for sound to be ; switched off. ; env - The Atari 2600 environment involved. ; ; RESULT ; new_state - True for on, false for off. ; ;*** ; ; AllocateSound: ; Push registers that should be preserved onto stack movem.l d2-d3/a2-a3/a5/a6,-(sp) ; Store parameters movea.l a1,a3 movea.l a6,a5 ; Find desired new state tst.l d0 beq off$ ; Open audio.device and allocate any two audio channels movea.l (ab_SysLib,a5),a6 JSRLIB CreateMsgPort move.l d0,(env_AudioMsgPort,a3) beq off$ movea.l d0,a0 move.l #ioa_SIZEOF,d0 JSRLIB CreateIORequest move.l d0,(env_AudioIO,a3) beq off$ lea.l audio_name,a0 movea.l (env_AudioIO,a3),a1 move.b #ADALLOC_MAXPREC,(LN_PRI,a1) move.w #0,(ioa_AllocKey,a1) move.l #channel_combinations,(ioa_Data,a1) move.l #6,(ioa_Length,a1) move.b #ADIOF_NOWAIT,(IO_FLAGS,a1) JSRLIB OpenDevice tst.l d0 bne off$ move.w #1,(env_AudioOpen,a3) ; Reset audio channels movea.l (env_AudioIO,a3),a1 move.w #CMD_RESET,(IO_COMMAND,a1) move.w period_table,(ioa_Period,a1) move.w #0,(ioa_Volume,a1) JSRLIB DoIO ; Turn off sound filter move.b #2,$bfe001 ; Get mask for first channel movea.l (env_AudioIO,a3),a1 move.l (IO_UNIT,a1),d0 bfffo d0{24:8},d1 moveq #0,d2 bfset.l d2{d1:1} move.l d2,(env_AudioChannelMasks,a3) ; Get mask for second channel bfclr.l d0{d1:1} bfffo d0{24:8},d1 moveq #0,d2 bfset.l d2{d1:1} move.l d2,(env_AudioChannelMasks+4,a3) ; Initialise loop for making IORequests for volume and pitch changes moveq #AUDIO_CHANNEL_COUNT-1,d2 pervol_on_loop$: ; Allocate memory for IORequest movea.l (env_AudioMsgPort,a3),a0 move.l #ioa_SIZEOF,d0 JSRLIB CreateIORequest move.l d0,(env_PerVolIO,a3,d2*4) beq off$ ; Copy the contents of the original IORequest used to open the audio ; device. movea.l (env_AudioIO,a3),a0 movea.l d0,a1 move.l #ioa_SIZEOF,d0 JSRLIB CopyMem ; Initialise IORequest for changing period and volume movea.l (env_PerVolIO,a3,d2*4),a1 move.w #ADCMD_PERVOL,(IO_COMMAND,a1) move.l (env_AudioChannelMasks,a3,d2*4),(IO_UNIT,a1) ; Loop back dbra d2,pervol_on_loop$ ; Initialise loop for making IORequests for tone type changes moveq #AUDIO_CHANNEL_COUNT*AUDIO_BUFFER_COUNT-1,d2 tone_on_loop$: ; Allocate memory for IORequest movea.l (env_AudioMsgPort,a3),a0 move.l #ioa_SIZEOF,d0 JSRLIB CreateIORequest movea.l d0,a2 move.l d0,(env_ToneTypeIO,a3,d2*4) beq off$ ; Copy the contents of the original IORequest used to open the audio ; device. movea.l (env_AudioIO,a3),a0 movea.l d0,a1 move.l #ioa_SIZEOF,d0 JSRLIB CopyMem ; Initialise IORequest for changing tone type movea.l a2,a1 move.w #CMD_WRITE,(IO_COMMAND,a1) move.l d2,d3 divu.w #AUDIO_BUFFER_COUNT,d3 move.l (env_AudioChannelMasks.w,a3,d3*4),(IO_UNIT,a1) move.w #0,(ioa_Cycles,a1) ; Start initial sound move.l (ab_Sounds,a5),(ioa_Data,a1) move.l sound_length_table,(ioa_Length,a1) JSRLIB SendIO ; Abort sound for this IORequest if it is the current one for its ; channel. swap.w d3 tst.w d3 bne on_no_abort$ movea.l a2,a1 JSRLIB AbortIO on_no_abort$: ; Loop back dbra d2,tone_on_loop$ ; Set result as on moveq #-1,d0 bra end$ off$: ; Check if audio device was opened movea.l (ab_SysLib,a5),a6 tst.w (env_AudioOpen,a3) beq skip_close_audio$ ; Initialise tone type loop moveq #AUDIO_CHANNEL_COUNT*AUDIO_BUFFER_COUNT-1,d2 tone_off_loop$: ; Check if this IORequest was allocated movea.l (env_ToneTypeIO,a3,d2*4),d0 beq skip_tone_type_io$ movea.l d0,a2 ; Cancel any use of this IORequest btst.l #0,d2 beq off_no_abort$ movea.l a2,a1 JSRLIB AbortIO off_no_abort$: movea.l a2,a1 JSRLIB WaitIO ; Delete tone type IORequest movea.l a2,a0 JSRLIB DeleteIORequest skip_tone_type_io$: ; Loop dbra d2,tone_off_loop$ ; Initialise period/volume loop moveq #AUDIO_CHANNEL_COUNT-1,d2 pervol_off_loop$: ; Delete period/volume IORequest movea.l (env_PerVolIO,a3,d2*4),a0 JSRLIB DeleteIORequest ; Loop dbra d2,pervol_off_loop$ ; Close audio.device movea.l (env_AudioIO,a3),a1 JSRLIB CloseDevice skip_close_audio$: ; Delete audio's IORequest movea.l (env_AudioIO,a3),a0 JSRLIB DeleteIORequest ; Delete audio's message port movea.l (env_AudioMsgPort,a3),a0 JSRLIB DeleteMsgPort ; Set result as off moveq #0,d0 end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a2-a3/a5/a6 rts ;****i* atari2600.library/GetHiddenBitPlanes *** ; ; NAME ; GetHiddenBitPlanes -- Get address of table of hidden bitplanes. ; ; SYNOPSIS ; bit_planes = GetHiddenBitPlanes(env) ; d0 a1 ; ; FUNCTION ; ; INPUTS ; env - The Atari 2600 environment involved. ; ; RESULT ; A table of the addresses of the currently hidden bitmap's planes. ; ;*** ; ; GetHiddenBitPlanes: ; Set result as address of bitplane list within bitmap structure movea.l (env_ScreenBitMaps+4,a1),a0 lea.l (bm_Planes,a0),a1 move.l a1,d0 ; Return rts ;****i* atari2600.library/MakePlayfieldPatternLine *** ; ; NAME ; MakePlayfieldPatternLine -- Construct the current playfield TV line. ; ; SYNOPSIS ; MakePlayfieldPatternLine(settings,env) ; d1 a1 ; ; FUNCTION ; ; INPUTS ; settings - ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; MakePlayfieldPatternLine: ; rts ; Push registers that should be preserved onto stack movem.l d2-d3/a2-a3,-(sp) ; Get playfield graphics and pattern line and transformation tables movea.l (env_PatternLine,a1),a1 movea.l a1,a3 move.l d1,d0 lea.l long_stretch_table,a0 lea.l byte_reverse_table,a2 ; Make empty pattern line if in vblank btst.l #OBJB_VBLANK,d0 beq skip_vblank$ clr.l (a1)+ clr.l (a1)+ clr.l (a1)+ clr.l (a1)+ clr.l (a1)+ bra end$ skip_vblank$: ; Fill left hand side of playfield pattern line moveq #12,d2 moveq #8,d3 bfextu d0{d2:d3},d1 move.l (a0,d1*4),(a1)+ addq.b #8,d2 bfextu d0{d2:d3},d1 move.l (a0,d1*4),(a1)+ addq.b #4,d2 bfextu d0{d2:d3},d1 move.w (2,a0,d1*4),(a1)+ ; See if copy or relection mode should be used for remainder of line btst.l #OBJB_REFLECTION,d0 bne reflected$ ; Fill right hand side of playfield pattern line in copy mode move.l (a3)+,(a1)+ move.l (a3)+,(a1)+ move.w (a3)+,(a1)+ bra skip_reflected$ reflected$: ; Fill right hand side of playfield pattern line in reflection mode moveq #24,d2 moveq #8,d3 bfextu d0{d2:d3},d1 move.b (a2,d1),d1 move.l (a0,d1*4),(a1)+ subq.b #8,d2 bfextu d0{d2:d3},d1 move.b (a2,d1),d1 move.l (a0,d1*4),(a1)+ subq.b #4,d2 bfextu d0{d2:d3},d1 move.b (a2,d1),d1 move.w (2,a0,d1*4),(a1)+ skip_reflected$: end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a2-a3 rts ;****i* atari2600.library/MakeBallPatternLine *** ; ; NAME ; MakeBallPatternLine -- Construct the current ball TV line. ; ; SYNOPSIS ; MakeBallPatternLine(settings,env) ; d1 a1 ; ; FUNCTION ; ; INPUTS ; settings - ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; MakeBallPatternLine: ; rts ; Push registers that should be preserved onto stack movem.l d2-d4/a2-a4,-(sp) ; Store parameters move.l d1,d4 movea.l a1,a3 ; Clear the line buffer movea.l (env_PatternLine,a3),a0 movea.l a0,a1 clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ ; Check if vertical blanking is on btst.l #OBJB_VBLANK,d4 bne end$ ; Get ball position and separate it into a word and a bit bfextu d4{OBJO_POSITION:OBJW_POSITION},d0 move.w d0,d1 andi.w #$f,d1 lsr.w #4,d0 ; Create a longword that contains the ball's image pattern bfextu d4{OBJO_WIDTH:OBJW_WIDTH},d3 moveq #1,d2 lsl.w d3,d2 moveq #0,d3 bfset d3{d1:d2} ; See whether undelayed or delayed enable flag should be used btst.w #OBJB_VDELAY,d4 bne delayed$ btst.l #OBJB_UNDELAYEDENABLE,d4 bra skip_delayed$ delayed$: btst.l #OBJB_DELAYEDENABLE,d4 skip_delayed$: ; Write image pattern to line buffer if ball is enabled beq disabled$ move.l d3,(a1,d0*2) disabled$: ; Wrap around graphics that extend past end of line cmpi.w #BYTES_PER_LINE/2/2,d0 blo no_wrap$ move.l (BYTES_PER_LINE,a1),(a1) no_wrap$: end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d4/a2-a4 rts ;****i* atari2600.library/MakePlayerPatternLine *** ; ; NAME ; MakePlayerPatternLine -- Construct a player 0 TV line. ; ; SYNOPSIS ; MakePlayerPatternLine(settings,env) ; d1 a1 ; ; FUNCTION ; ; INPUTS ; settings - ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; MakePlayerPatternLine: ; Push registers that should be preserved onto stack movem.l d2-d7/a2-a3,-(sp) ; Store parameters move.l d1,d6 movea.l a1,a3 ; Clear the line buffer movea.l (env_PatternLine,a3),a1 movea.l a1,a0 clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ ; Check if vertical blanking is on btst.l #OBJB_VBLANK,d6 bne end$ ; Get player's position and separate it into byte and bit ; offsets. bfextu d6{OBJO_POSITION:OBJW_POSITION},d0 move.w d0,d1 andi.w #$7,d1 lsr.w #3,d0 ; Store position's byte number move.w d0,d7 ; Prepare a register to hold graphics and see if delayed graphics ; should be used. moveq #0,d2 btst.w #OBJB_VDELAY,d6 bne delayed$ ; Get undelayed player graphics move.b d6,d2 bra undelayed$ ; Get delayed player graphics delayed$: bfextu d6{OBJO_DELAYEDGRAPHICS:OBJW_DELAYEDGRAPHICS},d2 undelayed$: ; Reverse graphics if reflection is on for this player btst.w #OBJB_REFLECTION,d6 beq no_reflect$ lea.l byte_reverse_table,a0 move.b (a0,d2),d2 no_reflect$: ; Get repetition/stretch setting bfextu d6{OBJO_NUMBERSIZE:OBJW_NUMBERSIZE},d3 ; Check if either double or quad size is specified cmpi.b #$5,d3 beq double_width$ cmpi.b #$7,d3 beq quad_width$ ; Get normal-width repetition pattern lea.l num_size_table,a0 move.b (a0,d3),d3 ; Place graphics in left byte of word lsl.w #8,d2 ; Shift graphics right by bit component of player's position lsr.w d1,d2 ; Get address at which to start writing graphics lea.l (a1,d0.w),a0 ; Initialise loop counter with the number of normal width "columns" ; to be written. moveq #5-1,d1 normal_width_loop$: ; Save graphics to player's pattern if the player should be present ; in the next word. lsr.w #1,d3 bcc no_draw$ move.w d2,(a0) no_draw$: ; Move on to next column addq.l #2,a0 dbra d1,normal_width_loop$ bra end$ double_width$: ; One emulated pixel must be added to the bit offset in double-width ; mode. addq.w #1,d1 ; Adjust byte and bit offsets if bit offset now exceeds seven btst.w #3,d1 beq double_no_adjust$ addq.w #1,d0 bclr.w #3,d1 double_no_adjust$: ; Stretch graphics byte over a word. lea.l word_stretch_table,a0 move.w (a0,d2*2),d2 ; Left-justify the graphics within their register. swap.w d2 ; Shift graphics right by bit offset. lsr.l d1,d2 ; Write the graphics to the line buffer at the appropriate offset. move.l d2,(a1,d0.w) bra end$ quad_width$: ; One emulated pixel must be added to the bit offset in quad-width ; mode. addq.w #1,d1 ; Adjust byte and bit offsets if bit offset now exceeds seven btst.w #3,d1 beq quad_no_adjust$ addq.w #1,d0 bclr.w #3,d1 quad_no_adjust$: ; Stretch graphics byte over a longword lea.l long_stretch_table,a0 move.l (a0,d2*4),d2 ; Load address within line pattern to start writing at lea.l (a1,d0.w),a0 ; Set a register to the value that will complete a 16-bit shift ; after a shift by the bit offset. moveq #16,d0 sub.w d1,d0 ; Clear temporary register to hold graphics moveq #0,d3 ; Move the left word of the graphics into the temporary register, ; rotate it right by the bit offset, and write the lower word of the ; result to the line pattern. swap.w d2 move.w d2,d3 ror.l d1,d3 move.w d3,(a0)+ ; Right-shift the wrapped-around portion of the temporary register ; so that it is right-justified within the upper word. lsr.l d0,d3 ; Move the right word of the graphics into the lower word of the ; temporary register. swap.w d2 move.w d2,d3 ; Rotate the temporary register right by the bit offset as ; before, which this time brings the unwritten portion of the left ; graphics word into the the lower half of the register. ror.l d1,d3 ; Write this combination of the left and right graphics words to the ; line pattern. move.w d3,(a0)+ ; Write the remaining portion of the right graphics word to the line ; pattern. swap.w d3 move.w d3,(a0)+ end$: ; Wrap around graphics that extend past end of line cmpi.w #10,d7 blo no_wrap$ lea.l (BYTES_PER_LINE,a1),a0 move.l (a0)+,(a1)+ move.l (a0)+,(a1)+ move.w (a0)+,(a1)+ no_wrap$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d7/a2-a3 rts ;****i* atari2600.library/MakeMissilePatternLine *** ; ; NAME ; MakeMissilePatternLine -- Construct a missile TV line. ; ; SYNOPSIS ; MakeMissilePatternLine(settings,env) ; d1 a1 ; ; FUNCTION ; ; INPUTS ; settings - ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; MakeMissilePatternLine: ; Push registers that should be preserved onto stack movem.l d2-d4/a3,-(sp) ; Store parameters move.l d1,d4 movea.l a1,a3 ; Clear the line buffer movea.l (env_PatternLine,a3),a1 movea.l a1,a0 clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ ; Check if vertical blanking is on btst.l #OBJB_VBLANK,d4 bne end$ ; Check if the missile is locked btst.l #OBJB_LOCKED,d4 bne end$ ; Get missile position and separate it into a word and a bit bfextu d4{OBJO_POSITION:OBJW_POSITION},d0 move.w d0,d1 andi.w #$f,d1 lsr.w #4,d0 ; Create a longword that contains the missile's image pattern bfextu d4{OBJO_WIDTH:OBJW_WIDTH},d3 moveq #1,d2 lsl.w d3,d2 moveq #0,d3 bfset d3{d1:d2} ; Write image pattern to line buffer if missile is enabled btst.w #OBJB_UNDELAYEDENABLE,d4 beq disabled$ move.l d3,(a1,d0*2) disabled$: ; Wrap around graphics that extend past end of line cmpi.w #BYTES_PER_LINE/2/2,d0 blo no_wrap$ move.l (BYTES_PER_LINE,a1),(a1) no_wrap$: end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d4/a3 rts ;****i* atari2600.library/MakeBitPlanePatternLine *** ; ; NAME ; MakeBitPlanePatternLine -- Make a TV line for a colour's bitplane. ; ; SYNOPSIS ; MakeBitPlanePatternLine(settings,env) ; d1 a1 ; ; FUNCTION ; ; INPUTS ; settings - ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; MakeBitPlanePatternLine: ; Get address of pattern line movea.l (env_PatternLine,a1),a0 ; See whether the line should be filled with ones or zeros btst.l #PENB_VBLANK,d1 bne zeros$ btst.l #PENB_NORMALENABLE,d1 beq zeros$ ; Set the line buffer move.l #-1,(a0)+ move.l #-1,(a0)+ move.l #-1,(a0)+ move.l #-1,(a0)+ move.l #-1,(a0)+ bra end$ zeros$: ; Clear the line buffer clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ end$: ; Return rts ;****i* atari2600.library/MakePlayfieldBitPlanePatternLine *** ; ; NAME ; MakePlayfieldBitPlanePatternLine -- Make playfield colour's TV line. ; ; SYNOPSIS ; MakePlayfieldBitPlanePatternLine(settings,env) ; d1 a1 ; ; FUNCTION ; ; INPUTS ; settings - ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; MakePlayfieldBitPlanePatternLine: ; Get address of pattern line movea.l (env_PatternLine,a1),a0 ; See whether the first half of the line should be filled with ones ; or zeros. btst.l #PENB_VBLANK,d1 bne zeros_left$ btst.l #PENB_SCOREMODE,d1 bne use_left_colour$ btst.l #PENB_NORMALENABLE,d1 bra skip_use_left_colour$ use_left_colour$: btst.l #PENB_LEFTENABLE,d1 skip_use_left_colour$: beq zeros_left$ ; Set half the line buffer move.l #-1,(a0)+ move.l #-1,(a0)+ move.w #-1,(a0)+ bra skip_zeros_left$ zeros_left$: ; Clear half the line buffer clr.l (a0)+ clr.l (a0)+ clr.w (a0)+ skip_zeros_left$: ; See whether the second half of the line should be filled with ones ; or zeros. btst.l #PENB_VBLANK,d1 bne zeros_right$ btst.l #PENB_SCOREMODE,d1 bne use_right_colour$ btst.l #PENB_NORMALENABLE,d1 bra skip_use_right_colour$ use_right_colour$: btst.l #PENB_RIGHTENABLE,d1 skip_use_right_colour$: beq zeros_right$ ; Set half the line buffer move.w #-1,(a0)+ move.l #-1,(a0)+ move.l #-1,(a0) bra skip_zeros_right$ zeros_right$: ; Clear half the line buffer clr.w (a0)+ clr.l (a0)+ clr.l (a0) skip_zeros_right$: ; Return rts ;****i* atari2600.library/MakePriorityPatternLine *** ; ; NAME ; MakePriorityPatternLine -- ; ; SYNOPSIS ; MakePriorityPatternLine(settings,env) ; d1 a1 ; ; FUNCTION ; ; INPUTS ; settings - ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; MakePriorityPatternLine: ; Get address of pattern line movea.l (env_PatternLine,a1),a0 ; See whether the line should be filled with ones or zeros btst.l #PRIB_ON,d1 beq zeros$ ; Set the line buffer move.l #-1,(a0)+ move.l #-1,(a0)+ move.l #-1,(a0)+ move.l #-1,(a0)+ move.l #-1,(a0)+ bra end$ zeros$: ; Clear the line buffer clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ end$: ; Return rts ;****i* atari2600.library/FillPatternSection *** ; ; NAME ; FillPatternSection -- Fill part of an object pattern. ; ; SYNOPSIS ; FillPatternSection(object,start_point,end_point,env) ; d0 d1 d2 a1 ; ; FUNCTION ; ; INPUTS ; object - The object whose pattern is to be updated. ; start_point - A valid display position. ; end_point - A valid display position. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; FillPatternSection: ; rts ; Push registers that should be preserved onto stack movem.l d2-d7/a2-a4,-(sp) ; Get address of starting longword in object pattern movea.l (env_Patterns,a1,d0*4),a3 move.w d1,d6 lsr.w #5,d6 lea.l (a3,d6.w*4),a3 move.l d1,d6 swap.w d6 mulu.w #BYTES_PER_LINE,d6 adda.l d6,a3 ; Load address of object's pattern line movea.l (env_PatternLine,a1),a2 ; See if the new update point is on a later line than the old one move.l d2,d4 swap.w d4 move.l d1,d3 swap.w d3 cmp.w d3,d4 bne multiple_lines$ ; See if fill starts and stops on the same longword move.w d2,d4 lsr.w #5,d4 move.w d1,d3 lsr.w #5,d3 cmp.w d3,d4 bne multiple_longwords$ ; See if start and end points are the same move.w d2,d4 sub.w d1,d4 beq end$ ; Get longword containing the bits to be inserted into pattern move.w d1,d3 lsr.w #5,d3 move.l (a2,d3.w*4),d5 ; Extract the relevant bits from the longword bfextu d5{d1:d4},d5 ; Replace bits in old longword move.l (a3),d6 bfins d5,d6{d1:d4} move.l d6,(a3) bra end$ multiple_longwords$: ; Get first longword to be used from pattern line move.w d1,d3 lsr.w #5,d3 lea.l (a2,d3.w*4),a0 move.l (a0)+,d5 ; Extract the relevant bits from the longword moveq #32,d4 move.w d1,d3 andi.w #$1f,d3 sub.w d3,d4 bfextu d5{d1:d4},d5 ; Replace bits in starting longword move.l (a3),d6 bfins d5,d6{d1:d4} move.l d6,(a3)+ ; Fill any complete longwords in the range move.w d2,d4 lsr.w #5,d4 move.w d1,d3 lsr.w #5,d3 sub.w d3,d4 subq.w #1,d4 bra loop_start$ next_longword$: move.l (a0)+,(a3)+ loop_start$: dbra d4,next_longword$ ; Fill part of ending longword move.w d2,d3 andi.w #$1f,d3 beq end$ move.l (a0),d5 bfextu d5{0:d2},d5 move.l (a3),d6 bfins d5,d6{0:d2} move.l d6,(a3) bra end$ multiple_lines$: ; Get first longword to be used from pattern line move.w d1,d3 lsr.w #5,d3 lea.l (a2,d3.w*4),a0 move.l (a0)+,d5 ; Extract the relevant bits from the longword moveq #32,d4 move.w d1,d3 andi.w #$1f,d3 sub.w d3,d4 bfextu d5{d1:d4},d5 ; Replace bits in starting longword move.l (a3),d6 bfins d5,d6{d1:d4} move.l d6,(a3)+ ; Fill the rest of the first line moveq #(TV_WIDTH>>5)-1,d3 move.w d1,d4 lsr.w #5,d4 sub.w d4,d3 bra loop_start_2$ next_longword_2$: move.l (a0)+,(a3)+ loop_start_2$: dbra d3,next_longword_2$ ; Fill any complete lines in the range move.l d2,d3 swap.w d3 move.l d1,d4 swap.w d4 sub.w d4,d3 subq.w #1,d3 bra line_loop_start$ next_line$: movea.l a2,a0 move.l (a0)+,(a3)+ move.l (a0)+,(a3)+ move.l (a0)+,(a3)+ move.l (a0)+,(a3)+ move.l (a0)+,(a3)+ line_loop_start$: dbra d3,next_line$ ; Fill complete longwords in final line of the fill move.w d2,d3 lsr.w #5,d3 movea.l a2,a0 bra loop_start_3$ next_longword_3$: move.l (a0)+,(a3)+ loop_start_3$: dbra d3,next_longword_3$ ; Fill part of ending longword andi.w #$1f,d2 beq end$ move.l (a0),d5 bfextu d5{0:d2},d5 move.l (a3),d6 bfins d5,d6{0:d2} move.l d6,(a3) end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d7/a2-a4 rts ;****i* atari2600.library/MakeSummaryPattern *** ; ; NAME ; MakeSummaryPattern -- Summarise an object's pattern. ; ; SYNOPSIS ; MakeSummaryPattern(object,env) ; d0 a1 ; ; FUNCTION ; ; INPUTS ; object - The object whose pattern is to be summarised. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; MakeSummaryPattern: ; rts ; Push registers that should be preserved onto stack movem.l d2-d3/a2-a3,-(sp) ; Store parameters move.l d0,d2 movea.l a1,a3 ; Load addresses of patterns used movea.l (env_Patterns,a3,d2*4),a0 movea.l (env_SummaryPatterns,a3,d2*4),a1 ; Initialise outer loop counter move.l (env_RoundedTVHeight,a3),d0 lsr.w #2,d0 subq.w #1,d0 next_line$: ; Initialise inner loop moveq #0,d3 move.w #BYTES_PER_LINE-1,d1 next_longword$: ; Check if longword is empty tst.l (a0)+ bne something_there$ ; Clear bit to indicate that longword is empty bclr.l d1,d3 bra skip_something_there$ something_there$: ; Set bit to indicate that longword is non-empty bset.l d1,d3 skip_something_there$: dbra d1,next_longword$ ; Store longword representing four lines move.l d3,(a1)+ dbra d0,next_line$ ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a2-a3 rts ;****i* atari2600.library/FindCollision *** ; ; NAME ; FindCollision ; ; SYNOPSIS ; FindCollision(obj_0,obj_1,result_offset,result_bit,env) ; d0 d1 d2 d3 a1 ; ; FUNCTION ; ; INPUTS ; obj_0 - The first object. ; obj_1 - The second object. ; result_offset - The offset in Atari 2600 memory where the result ; should be written. ; result_bit - The bit of the result byte that represents the ; collision. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; FindCollision: ; rts ; Push registers that should be preserved onto stack movem.l d2-d7/a2-a6,-(sp) ; Store parameters move.l d0,d6 move.l d1,d7 movea.l a1,a3 ; Load addresses of patterns used movea.l (env_SummaryPatterns,a3,d6*4),a0 movea.l (env_SummaryPatterns,a3,d7*4),a1 movea.l (env_Patterns,a3,d6*4),a4 movea.l (env_Patterns,a3,d7*4),a5 ; Move pointers on to end of each pattern adda.l (env_RoundedTVHeight,a3),a0 adda.l (env_RoundedTVHeight,a3),a1 adda.l (env_PatternSize,a3),a4 adda.l (env_PatternSize,a3),a5 ; Initialise loop counter move.l (env_RoundedTVHeight,a3),d0 lsr.w #2,d0 subq.w #1,d0 next_line$: move.l -(a0),d1 and.l -(a1),d1 bne detailed_line_search$ continue_summary_search$: suba.l #BYTES_PER_LINE<<2,a4 suba.l #BYTES_PER_LINE<<2,a5 dbra d0,next_line$ ; Set result as not found moveq #0,d5 bra store_result$ detailed_line_search$: movea.l a4,a2 movea.l a5,a6 ; Initialise loop counter move.w #BYTES_PER_LINE-1,d4 next_longword$: move.l -(a2),d1 and.l -(a6),d1 bne collision_found$ dbra d4,next_longword$ bra continue_summary_search$ collision_found$: moveq #1,d5 store_result$: ; Test whether a collision was found tst.w d5 bne store_collision$ ; Record a non-collision bclr.b d3,([env_Data,a3],d2) bclr.b d3,([env_Data,a3],d2,$10) bclr.b d3,([env_Data,a3],d2,$20) bclr.b d3,([env_Data,a3],d2,$30) bclr.b d3,([env_Data,a3],d2,$40) bclr.b d3,([env_Data,a3],d2,$50) bclr.b d3,([env_Data,a3],d2,$60) bclr.b d3,([env_Data,a3],d2,$70) bra skip_store_collision$ store_collision$: ; Record a collision bset.b d3,([env_Data,a3],d2) bset.b d3,([env_Data,a3],d2,$10) bset.b d3,([env_Data,a3],d2,$20) bset.b d3,([env_Data,a3],d2,$30) bset.b d3,([env_Data,a3],d2,$40) bset.b d3,([env_Data,a3],d2,$50) bset.b d3,([env_Data,a3],d2,$60) bset.b d3,([env_Data,a3],d2,$70) skip_store_collision$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d7/a2-a6 rts ;****i* atari2600.library/CleanUp *** ; ; NAME ; CleanUp -- Deallocate the library's resources. ; ; SYNOPSIS ; CleanUp(library,exec) ; a5 a6 ; ; FUNCTION ; ; INPUTS ; ; RESULT ; None. ; ;*** ; ; CleanUp: ; Free memory for sound 0 move.l #SOUND_0_MULTIPLE,d0 movea.l (ab_Sounds,a5),d1 beq skip_sound_0$ movea.l d1,a1 JSRLIB FreeMem skip_sound_0$: ; Free memory for sound 1 move.l #FOUR_BIT_POLY_SIZE*SOUND_1_MULTIPLE,d0 movea.l (ab_Sounds+4,a5),d1 beq skip_sound_1$ movea.l d1,a1 JSRLIB FreeMem skip_sound_1$: ; Free memory for sound 2 move.l #FIVE_BIT_POLY_SIZE*FOUR_BIT_POLY_SIZE*SOUND_2_MULTIPLE,d0 movea.l (ab_Sounds+2*4,a5),d1 beq skip_sound_2$ movea.l d1,a1 JSRLIB FreeMem skip_sound_2$: ; Free memory for sound 3 move.l #FIVE_BIT_POLY_SIZE*FOUR_BIT_POLY_SIZE*SOUND_3_MULTIPLE,d0 movea.l (ab_Sounds+3*4,a5),d1 beq skip_sound_3$ movea.l d1,a1 JSRLIB FreeMem skip_sound_3$: ; Free memory for sound 4 move.l #SOUND_4_MULTIPLE,d0 movea.l (ab_Sounds+4*4,a5),d1 beq skip_sound_4$ movea.l d1,a1 JSRLIB FreeMem skip_sound_4$: ; Free memory for sound 6 move.l #31*SOUND_6_MULTIPLE,d0 movea.l (ab_Sounds+6*4,a5),d1 beq skip_sound_6$ movea.l d1,a1 JSRLIB FreeMem skip_sound_6$: ; Free memory for sound 7 move.l #FIVE_BIT_POLY_SIZE*SOUND_7_MULTIPLE,d0 movea.l (ab_Sounds+7*4,a5),d1 beq skip_sound_7$ movea.l d1,a1 JSRLIB FreeMem skip_sound_7$: ; Free memory for sound 8 move.l #NINE_BIT_POLY_SIZE*SOUND_8_MULTIPLE,d0 movea.l (ab_Sounds+8*4,a5),d1 beq skip_sound_8$ movea.l d1,a1 JSRLIB FreeMem skip_sound_8$: ; Free memory for sound 9 move.l #FIVE_BIT_POLY_SIZE*SOUND_9_MULTIPLE,d0 movea.l (ab_Sounds+9*4,a5),d1 beq skip_sound_9$ movea.l d1,a1 JSRLIB FreeMem skip_sound_9$: ; Free memory for sound 12 move.l #SLOW_PURE_SIZE*SOUND_12_MULTIPLE,d0 movea.l (ab_Sounds+12*4,a5),d1 beq skip_sound_12$ movea.l d1,a1 JSRLIB FreeMem skip_sound_12$: ; Free memory for sound 14 move.l #93*SOUND_14_MULTIPLE,d0 movea.l (ab_Sounds+14*4,a5),d1 beq skip_sound_14$ movea.l d1,a1 JSRLIB FreeMem skip_sound_14$: ; Free memory for sound 15 move.l #FIVE_BIT_POLY_SIZE*3*SOUND_15_MULTIPLE,d0 movea.l (ab_Sounds+15*4,a5),d1 beq skip_sound_15$ movea.l d1,a1 JSRLIB FreeMem skip_sound_15$: ; Free memory for word-to-long stretch table move.l #(1<<16)*4,d0 movea.l (ab_WordToLongTable,a5),d1 beq skip_stretch_table$ movea.l d1,a1 JSRLIB FreeMem skip_stretch_table$: ; Close asl library if it's been opened move.l (ab_AslLib,a5),d0 beq skip_close_asl$ move.l d0,a1 JSRLIB CloseLibrary skip_close_asl$: ; Close dos library if it's been opened move.l (ab_DosLib,a5),d0 beq skip_close_dos$ move.l d0,a1 JSRLIB CloseLibrary skip_close_dos$: ; Close icon library if it's been opened move.l (ab_IconLib,a5),d0 beq skip_close_icon$ move.l d0,a1 JSRLIB CloseLibrary skip_close_icon$: ; Close utility library if it's been opened move.l (ab_UtilityLib,a5),d0 beq skip_close_utility$ move.l d0,a1 JSRLIB CloseLibrary skip_close_utility$: ; Close graphics library if it's been opened move.l (ab_GraphicsLib,a5),d0 beq skip_close_graphics$ move.l d0,a1 JSRLIB CloseLibrary skip_close_graphics$: ; Close gadtools library if it's been opened move.l (ab_GadtoolsLib,a5),d0 beq skip_close_gadtools$ move.l d0,a1 JSRLIB CloseLibrary skip_close_gadtools$: ; Close intuition library if it's been opened move.l (ab_IntuitionLib,a5),d0 beq skip_close_intuition$ move.l d0,a1 JSRLIB CloseLibrary skip_close_intuition$: ; Free the library's memory move.l a5,a1 moveq #0,d0 move.w (LIB_NEGSIZE,a5),d0 sub.l d0,a1 add.w (LIB_POSSIZE,a5),d0 JSRLIB FreeMem ; Return rts ;****i* atari2600.library/FinishFrame *** ; ; NAME ; FinishFrame -- Finish current frame's patterns and get collisions. ; ; SYNOPSIS ; FinishFrame(env,lib_ptr) ; a1 a6 ; ; FUNCTION ; ; INPUTS ; ; RESULT ; None. ; ;*** ; ; FinishFrame: ; Push registers that should be preserved onto stack movem.l d2-d7/a2-a6,-(sp) ; Store parameters movea.l a1,a3 movea.l a6,a5 ; Fill in patterns moveq #PATTERN_COUNT-1,d2 fill_patterns_loop$ move.l d2,d0 movea.l a3,a1 bsr FillPattern dbra d2,fill_patterns_loop$ ; Merge the patterns of associated object pairs moveq #REDUCED_OBJECT_COUNT-1,d2 object_merge_loop$: move.w d2,d0 mulu.w #SCREEN_BUFFER_COUNT+1,d0 movea.l (env_MergedPatterns,a3,d0*4),a0 movea.l (env_Patterns,a3,d2*4),a1 movea.l (env_Patterns+REDUCED_OBJECT_COUNT*4,a3,d2*4),a2 move.l (env_PatternSize,a3),d0 lsr.l #2,d0 subq.l #1,d0 merge_next_longword$: move.l (a1)+,d1 or.l (a2)+,d1 move.l d1,(a0)+ dbra d0,merge_next_longword$ dbra d2,object_merge_loop$ ; Construct summary patterns for all objects moveq #OBJECT_COUNT-1,d2 summary_loop$: move.l d2,d0 movea.l a3,a1 bsr MakeSummaryPattern dbra d2,summary_loop$ ; Find collisions between every pair of objects moveq #M0,d0 moveq #P1,d1 moveq #A2600_CXM0P,d2 moveq #7,d3 movea.l a3,a1 bsr FindCollision moveq #M0,d0 moveq #P0,d1 moveq #A2600_CXM0P,d2 moveq #6,d3 movea.l a3,a1 bsr FindCollision moveq #M1,d0 moveq #P0,d1 moveq #A2600_CXM1P,d2 moveq #7,d3 movea.l a3,a1 bsr FindCollision moveq #M1,d0 moveq #P1,d1 moveq #A2600_CXM1P,d2 moveq #6,d3 movea.l a3,a1 bsr FindCollision moveq #P0,d0 moveq #PF,d1 moveq #A2600_CXP0FB,d2 moveq #7,d3 movea.l a3,a1 bsr FindCollision moveq #P0,d0 moveq #BL,d1 moveq #A2600_CXP0FB,d2 moveq #6,d3 movea.l a3,a1 bsr FindCollision moveq #P1,d0 moveq #PF,d1 moveq #A2600_CXP1FB,d2 moveq #7,d3 movea.l a3,a1 bsr FindCollision moveq #P1,d0 moveq #BL,d1 moveq #A2600_CXP1FB,d2 moveq #6,d3 movea.l a3,a1 bsr FindCollision moveq #M0,d0 moveq #PF,d1 moveq #A2600_CXM0FB,d2 moveq #7,d3 movea.l a3,a1 bsr FindCollision moveq #M0,d0 moveq #BL,d1 moveq #A2600_CXM0FB,d2 moveq #6,d3 movea.l a3,a1 bsr FindCollision moveq #M1,d0 moveq #PF,d1 moveq #A2600_CXM1FB,d2 moveq #7,d3 movea.l a3,a1 bsr FindCollision moveq #M1,d0 moveq #BL,d1 moveq #A2600_CXM1FB,d2 moveq #6,d3 movea.l a3,a1 bsr FindCollision moveq #BL,d0 moveq #PF,d1 moveq #A2600_CXBLPF,d2 moveq #7,d3 movea.l a3,a1 bsr FindCollision moveq #P0,d0 moveq #P1,d1 moveq #A2600_CXPPMM,d2 moveq #7,d3 movea.l a3,a1 bsr FindCollision moveq #M0,d0 moveq #M1,d1 moveq #A2600_CXPPMM,d2 moveq #6,d3 movea.l a3,a1 bsr FindCollision ; Update address of bitplane table movea.l a3,a1 bsr GetHiddenBitPlanes move.l d0,env_PlanePtrs(a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2-d7/a2-a6 rts ;****i* atari2600.library/ChangeDisplay *** ; ; NAME ; ChangeDisplay -- Display newly written bitmap and hide visible one. ; ; SYNOPSIS ; ChangeDisplay(env,lib_ptr) ; a1 a6 ; ; FUNCTION ; ; INPUTS ; ; RESULT ; None. ; ;*** ; ; ChangeDisplay: ; Push registers that should be preserved onto stack movem.l d2-d7/a2-a6,-(sp) ; Store parameters movea.l a1,a3 movea.l a6,a5 ; Wait for notification that the previous frame has been displayed movea.l (ab_SysLib,a5),a6 movea.l (env_DispMsgPort,a3),a0 JSRLIB WaitPort movea.l (env_DispMsgPort,a3),a0 JSRLIB GetMsg ; Wait until there is no screen-drawing taking place movea.l (ab_GraphicsLib,a5),a6 JSRLIB WaitBlit ; Hide currently visible bitmap and display newly written bitmap movea.l (ab_IntuitionLib,a5),a6 movea.l (env_Screen,a3),a0 movea.l (env_ScreenBuffers+4,a3),a1 JSRLIB ChangeScreenBuffer tst.l d0 bne no_delay$ ; Get current time in milliseconds movea.l a5,a6 bsr GetTime move.l d0,d2 ; Stop sound if it's on tst.w (env_SoundOn,a3) beq no_sound_off$ movea.l (ab_SysLib,a5),a6 movea.l (env_AudioIO,a3),a1 move.w #CMD_STOP,(IO_COMMAND,a1) JSRLIB DoIO no_sound_off$: ; Try again to change bitmaps movea.l (ab_IntuitionLib,a5),a6 try_again$: movea.l (env_Screen,a3),a0 movea.l (env_ScreenBuffers+4,a3),a1 JSRLIB ChangeScreenBuffer tst.l d0 beq try_again$ ; Restart sound if it should be on tst.w (env_SoundOn,a3) beq no_sound_on$ movea.l (ab_SysLib,a5),a6 movea.l (env_AudioIO,a3),a1 move.w #CMD_START,(IO_COMMAND,a1) JSRLIB DoIO no_sound_on$: ; Get length of delay movea.l a5,a6 bsr GetTime sub.l d2,d0 ; Update the recorded amount of time spent waiting to change bitmaps add.l d0,(env_ScreenSwapWaitTime,a3) no_delay$: ; Rotate array of screen buffer pointers movea.l (env_ScreenBuffers+0*4,a3),a0 movea.l (env_ScreenBuffers+1*4,a3),(env_ScreenBuffers+0*4,a3) movea.l (env_ScreenBuffers+2*4,a3),(env_ScreenBuffers+1*4,a3) movea.l a0,(env_ScreenBuffers+2*4,a3) ; Rotate array of bitmap pointers movea.l (env_ScreenBitMaps+0*4,a3),a0 movea.l (env_ScreenBitMaps+1*4,a3),(env_ScreenBitMaps+0*4,a3) movea.l (env_ScreenBitMaps+2*4,a3),(env_ScreenBitMaps+1*4,a3) movea.l a0,(env_ScreenBitMaps+2*4,a3) ; Pop preserved registers off stack and return movem.l (sp)+,d2-d7/a2-a6 rts ;****i* atari2600.library/UpdateScreen *** ; ; NAME ; UpdateScreen -- Redraw areas of the screen that have changed. ; ; SYNOPSIS ; UpdateScreen(env,lib_ptr) ; a1 a6 ; ; FUNCTION ; ; INPUTS ; ; RESULT ; None. ; ;*** ; ; UpdateScreen: ; Preserve all register values movem.l d0-d7/a0-a6,-(sp) ; Make room on stack for local variables suba.l #16,sp ; Store library and environment pointers move.l a6,(12,sp) move.l a1,(8,sp) movea.l a1,a3 ; Wait for a message that means it's safe to write to the hidden ; bitmap movea.l (ab_SysLib,a6),a6 movea.l (env_SafeMsgPort,a3),a0 JSRLIB WaitPort movea.l (env_SafeMsgPort,a3),a0 JSRLIB GetMsg ; Find areas of each object pattern that have changed since the last ; time the current screen buffer was used. moveq #REDUCED_OBJECT_COUNT-1,d2 diff_loop$: movea.l a3,a1 move.l d2,d0 bsr FindDifferences dbra d2,diff_loop$ ; Find areas of each colour and priority pattern that have changed ; since the last time the current screen buffer was used. moveq #PATTERN_COUNT-OBJECT_COUNT-1,d2 colour_diff_loop$: movea.l a3,a1 move.l d2,d0 add.l #OBJECT_COUNT,d0 bsr FindColourDifferences dbra d2,colour_diff_loop$ ; Combine object and priority difference patterns movea.l (env_ObjectDifferencePattern,a3),a6 movea.l (env_DifferencePatterns+PF*4,a3),a0 movea.l (env_DifferencePatterns+P0*4,a3),a2 movea.l (env_DifferencePatterns+P1*4,a3),a4 movea.l (env_DifferencePatterns+(REDUCED_PATTERN_COUNT-1)*4,a3),a5 move.w (env_TVHeight,a3),d0 move.w d0,d1 lsr.w #2,d0 subq.w #1,d0 andi.w #3,d1 obj_diff_longword_loop$: move.l (a0)+,d2 or.l (a2)+,d2 or.l (a4)+,d2 or.l (a5)+,d2 move.l d2,(a6)+ dbra d0,obj_diff_longword_loop$ bra obj_diff_byte_loop_start$ obj_diff_byte_loop$: move.b (a0)+,d2 or.b (a2)+,d2 or.b (a4)+,d2 or.b (a5)+,d2 move.b d2,(a6)+ obj_diff_byte_loop_start$: dbra d1,obj_diff_byte_loop$ ; Initialise bit plane loop moveq #SCREEN_DEPTH-1,d2 next_plane$: ; Combine object differences with differences for this bit plane movea.l (env_DifferencePattern,a3),a6 movea.l (env_ObjectDifferencePattern,a3),a5 movea.l (env_DifferencePatterns+(REDUCED_OBJECT_COUNT+BK_COLOUR*SCREEN_DEPTH)*4,a3,d2*4),a0 movea.l (env_DifferencePatterns+(REDUCED_OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH)*4,a3,d2*4),a1 movea.l (env_DifferencePatterns+(REDUCED_OBJECT_COUNT+P0_COLOUR*SCREEN_DEPTH)*4,a3,d2*4),a2 movea.l (env_DifferencePatterns+(REDUCED_OBJECT_COUNT+P1_COLOUR*SCREEN_DEPTH)*4,a3,d2*4),a4 move.w (env_TVHeight,a3),d0 move.w d0,d1 lsr.w #2,d0 subq.w #1,d0 andi.w #3,d1 plane_diff_longword_loop$: move.l (a0)+,d4 or.l (a1)+,d4 or.l (a2)+,d4 or.l (a4)+,d4 or.l (a5)+,d4 move.l d4,(a6)+ dbra d0,plane_diff_longword_loop$ bra plane_diff_byte_loop_start$ plane_diff_byte_loop$: move.b (a0)+,d4 or.b (a1)+,d4 or.b (a2)+,d4 or.b (a4)+,d4 or.b (a5)+,d4 move.b d4,(a6)+ plane_diff_byte_loop_start$: dbra d1,plane_diff_byte_loop$ ; Load address of current bitplane movea.l ([env_PlanePtrs,a3],d2*4),a6 moveq #0,d0 move.w env_SkipMenuOffset(a3),d0 adda.l d0,a6 ; Save environment pointer and plane counter move.l d2,(4,sp) move.l a3,(8,sp) ; Load addresses of patterns movea.l (env_DifferencePattern,a3),a5 move.l (env_Patterns+(PATTERN_COUNT-1)*4,a3),a1 move.l (env_Patterns+(OBJECT_COUNT+BK_COLOUR*SCREEN_DEPTH)*4,a3,d2*4),d4 move.l (env_Patterns+(OBJECT_COUNT+PF_COLOUR*SCREEN_DEPTH)*4,a3,d2*4),d5 move.l (env_Patterns+(OBJECT_COUNT+P0_COLOUR*SCREEN_DEPTH)*4,a3,d2*4),d6 move.l (env_Patterns+(OBJECT_COUNT+P1_COLOUR*SCREEN_DEPTH)*4,a3,d2*4),d7 movea.l (env_MergedPatterns+PF*(SCREEN_BUFFER_COUNT+1)*4,a3),a0 movea.l (env_MergedPatterns+P0*(SCREEN_BUFFER_COUNT+1)*4,a3),a2 movea.l (env_MergedPatterns+P1*(SCREEN_BUFFER_COUNT+1)*4,a3),a4 ; Initialise line loop moveq #0,d2 move.w (env_TVHeight,a3),d2 subq #1,d2 movea.l ([12,sp],ab_WordToLongTable),a3 next_line$: ; Store line counter move.w d2,(sp) ; Get differences for this line move.b (a5)+,d2 bne line_start$ ; Move all pointers on by a line add.l #BYTES_PER_LINE,d4 add.l #BYTES_PER_LINE,d5 add.l #BYTES_PER_LINE,d6 add.l #BYTES_PER_LINE,d7 adda.l #BYTES_PER_LINE,a0 adda.l #BYTES_PER_LINE,a1 adda.l #BYTES_PER_LINE,a2 adda.l #BYTES_PER_LINE,a4 adda.l #BYTES_PER_LINE*X_MAG,a6 bra skip_line$ line_start$: ; Initialise longword loop swap.w d2 move.w #BYTES_PER_LINE/4-1,d2 next_longword$: ; Check if the current longword needs to be redrawn move.w d2,d0 add.w #16,d0 btst.l d0,d2 bne longword_start$ ; Move pointers on to next longword addq.l #4,a0 addq.l #4,a1 addq.l #4,a2 addq.l #4,a4 addq.l #8,a6 bra skip_longword$ longword_start$: ; Get background move.l (d4.l),d3 ; Apply playfield and ball move.l (d5.l),d1 move.l (a0),d0 and.l d0,d1 not.l d0 and.l d0,d3 or.l d1,d3 ; Apply second player and missile move.l (d7.l),d1 move.l (a4)+,d0 and.l d0,d1 not.l d0 and.l d0,d3 or.l d1,d3 ; Apply first player and missile move.l (d6.l),d1 move.l (a2)+,d0 and.l d0,d1 not.l d0 and.l d0,d3 or.l d1,d3 ; Reapply parts of playfield and ball that have priority move.l (d5.l),d1 move.l (a0)+,d0 and.l (a1)+,d0 and.l d0,d1 not.l d0 and.l d0,d3 or.l d1,d3 ; Stretch combined longword to a quadword and write to bitplane move.l d3,d0 clr.w d0 swap.w d0 move.l (a3,d0.l*4),(a6)+ andi.l #$ffff,d3 move.l (a3,d3.l*4),(a6)+ skip_longword$: ; Move colour pattern pointers on to next longword addq.l #4,d4 addq.l #4,d5 addq.l #4,d6 addq.l #4,d7 ; Loop back dbra d2,next_longword$ skip_line$: ; Restore line counter and loop back move.w (sp),d2 dbra d2,next_line$ ; Restore environment pointer and plane counter and loop back movea.l (8,sp),a3 move.l (4,sp),d2 dbra d2,next_plane$ ; "Rotate" all pattern lists and reset list pointers for next frame moveq #PATTERN_COUNT-1,d2 pattern_list_loop$: lea.l (env_PatternLists,a3),a2 moveq #(SCREEN_BUFFER_COUNT+1)*4,d0 mulu.w d2,d0 adda.l d0,a2 move.l (3*4,a2),d0 move.l (2*4,a2),(3*4,a2) move.l (1*4,a2),(2*4,a2) move.l (0*4,a2),(1*4,a2) move.l d0,(0*4,a2) move.l d0,(env_PatternListPtrs,a3,d2*4) add.l #LIST_SIZE-2*8,d0 move.l d0,(env_PatternListLimits,a3,d2*4) dbra d2,pattern_list_loop$ ; "Rotate" all merged patterns moveq #REDUCED_PATTERN_COUNT-1,d2 merged_pattern_loop$: lea.l (env_MergedPatterns,a3),a2 moveq #(SCREEN_BUFFER_COUNT+1)*4,d0 mulu.w d2,d0 adda.l d0,a2 move.l (3*4,a2),d0 move.l (2*4,a2),(3*4,a2) move.l (1*4,a2),(2*4,a2) move.l (0*4,a2),(1*4,a2) move.l d0,(0*4,a2) dbra d2,merged_pattern_loop$ ; Readjust stack pointer to remove local variable space adda.l #16,sp ; Restore all registers from stack and return movem.l (sp)+,d0-d7/a0-a6 rts ;****i* atari2600.library/GetUserInput *** ; ; NAME ; GetUserInput -- Check for user input and respond to it. ; ; SYNOPSIS ; GetUserInput() ; ; FUNCTION ; ; INPUTS ; ; RESULT ; None. ; ;*** ; ; GetUserInput: ; Push registers that should be preserved onto stack movem.l d2-d7/a2-a6,-(sp) ; Turn off Select and Reset or.b #SWCHBF_NOSELECT|SWCHBF_NORESET,([env_Data,a3],A2600_SWCHB) or.b #SWCHBF_NOSELECT|SWCHBF_NORESET,([env_Data,a3],A2600_SWCHB+$100) next_msg$: ; See if there is an incoming message movea.l ab_GadtoolsLib(a5),a6 movea.l env_UserPort(a3),a0 JSRLIB GT_GetIMsg tst.l d0 beq end$ ; Extract relevant details from message and reply to it movea.l d0,a1 move.l (im_Class,a1),d3 move.w (im_Code,a1),d2 move.w (im_Qualifier,a1),d4 move.w (im_MouseX,a1),d5 JSRLIB GT_ReplyIMsg ; Check which type of user-input event occurred cmp.l #IDCMP_MENUPICK,d3 beq menu_selection$ cmp.l #IDCMP_RAWKEY,d3 beq joystick_action$ cmp.l #IDCMP_MOUSEBUTTONS,d3 beq mouse_button_action$ cmp.l #IDCMP_MOUSEMOVE,d3 beq new_mouse_position$ ; Skip user input code if message type is not recognised bra next_msg$ menu_selection$: ; Check that this is a real menu selection cmp.w #MENUNULL,d2 beq next_msg$ ; Store MenuNumber moveq #0,d3 move.w d2,d3 ; Parse MenuNumber moveq #$1f,d0 and.w d2,d0 ; d0 is now menu number (natural meaning) lsr.w #5,d2 moveq #$3f,d1 and.w d2,d1 ; d1 is now item number lsr.w #6,d2 ; d2 is now subitem number ; See which menu contains the selected menu item cmpi.w #0,d0 beq game_menu$ cmpi.w #1,d0 beq console_menu$ bra next_msg$ game_menu$: ; See which item from this menu was picked cmpi.w #0,d1 beq about$ cmpi.w #2,d1 beq quit$ bra next_msg$ console_menu$: ; See which item from this menu was picked cmpi.w #0,d1 beq select$ cmpi.w #1,d1 beq reset$ cmpi.w #3,d1 beq colour$ cmpi.w #4,d1 beq p0_difficulty$ bra next_msg$ about$: ; Stop sound if it's on tst.w (env_SoundOn,a3) beq no_sound_off$ movea.l (ab_SysLib,a5),a6 movea.l (env_AudioIO,a3),a1 move.w #CMD_STOP,(IO_COMMAND,a1) JSRLIB DoIO no_sound_off$: ; Get current time in milliseconds movea.l a5,a6 bsr GetTime move.l d0,d1 ; Get number of milliseconds since last report sub.l (env_MillisecondCount,a3),d1 ; Compensate for time spent waiting to change bitmaps sub.l (env_ScreenSwapWaitTime,a3),d1 bne skip_nought_milliseconds$ moveq #1,d1 ; avoid divide-by-zero skip_nought_milliseconds$: ; Reset record of time spent waiting to change bitmaps clr.l (env_ScreenSwapWaitTime,a3) ; Get number of frames since last report move.l (env_FrameCount,a3),d0 sub.l (env_PrevFrameCount,a3),d0 move.l (env_FrameCount,a3),(env_PrevFrameCount,a3) ; Convert frame count to "milliframes" mulu.l #1000,d0 ; Calculate and store number of frames per second divu.l d1,d0 move.w d0,(env_FramesPerSecond,a3) ; Display the "About" requester movem.l d0-d7/a0-a6,-(sp) movea.l (env_Window,a3),a0 movea.l (env_AboutRequester,a3),a1 movea.l #0,a2 move.w (env_FrameSkipRatio,a3),-(sp) move.w (env_FramesPerSecond,a3),-(sp) move.w (env_FramesPerSecond,a3),d0 mulu.w #100,d0 mulu.w (env_FrameSkipRatio,a3),d0 divu.w (env_IdealFrameRate,a3),d0 move.w d0,-(sp) movea.l sp,a3 movea.l (ab_IntuitionLib,a5),a6 JSRLIB EasyRequestArgs add.w #6,sp movem.l (sp)+,d0-d7/a0-a6 ; Restart sound if it should be on tst.w (env_SoundOn,a3) beq no_sound_on$ movea.l (ab_SysLib,a5),a6 movea.l (env_AudioIO,a3),a1 move.w #CMD_START,(IO_COMMAND,a1) JSRLIB DoIO no_sound_on$: ; Get and store current time in milliseconds movea.l a5,a6 bsr GetTime move.l d0,(env_MillisecondCount,a3) bra next_msg$ quit$: ; Set return code to be used by exit function to "success" moveq #0,d2 ; Restore client program's original stack pointer and jump to its ; exit function which deallocates its resources and closes this ; library. movea.l (env_OriginalStackPtr,a3),sp jmp ([env_ExitFunction,a3]) select$: ; This menu option emulates the Select button from the Atari 2600 ; console. It usually selects game options before play begins. bclr.b #SWCHBB_NOSELECT,([env_Data,a3],A2600_SWCHB) bclr.b #SWCHBB_NOSELECT,([env_Data,a3],A2600_SWCHB+$100) bra next_msg$ reset$: ; This menu option emulates the Reset button from the Atari 2600 ; console. It usually starts the game's play mode. bclr.b #SWCHBB_NORESET,([env_Data,a3],A2600_SWCHB) bclr.b #SWCHBB_NORESET,([env_Data,a3],A2600_SWCHB+$100) bra next_msg$ colour$: ; Get the address of this menu item, which emulates the Colour/B&W ; switch. movea.l (ab_IntuitionLib,a5),a6 move.l d3,d0 movea.l (env_Menus,a3),a0 JSRLIB ItemAddress movea.l d0,a0 ; See whether new state is checked or unchecked move.w (mi_Flags,a0),d0 andi.w #CHECKED,d0 beq black_and_white$ bset.b #SWCHBB_COLOUR,([env_Data,a3],A2600_SWCHB) bset.b #SWCHBB_COLOUR,([env_Data,a3],A2600_SWCHB+$100) bra next_msg$ black_and_white$: bclr.b #SWCHBB_COLOUR,([env_Data,a3],A2600_SWCHB) bclr.b #SWCHBB_COLOUR,([env_Data,a3],A2600_SWCHB+$100) bra next_msg$ p0_difficulty$: ; Get the address of this menu item, which emulates the first ; player's difficulty switch. movea.l (ab_IntuitionLib,a5),a6 move.l d3,d0 movea.l (env_Menus,a3),a0 JSRLIB ItemAddress movea.l d0,a0 ; See whether new state is checked or unchecked move.w (mi_Flags,a0),d0 andi.w #CHECKED,d0 beq difficult_p0$ bclr.b #SWCHBB_P0PRO,([env_Data,a3],A2600_SWCHB) bclr.b #SWCHBB_P0PRO,([env_Data,a3],A2600_SWCHB+$100) bra next_msg$ difficult_p0$: bset.b #SWCHBB_P0PRO,([env_Data,a3],A2600_SWCHB) bset.b #SWCHBB_P0PRO,([env_Data,a3],A2600_SWCHB+$100) bra next_msg$ joystick_action$: cmpi.w #JOY_CODE,d2 bne next_msg$ cmpi.b #JOYSTICK,(env_ControllerTypes,a3) bne next_msg$ moveq #0,d0 btst.w #IEQUALIFIERB_RSHIFT,d4 bne left$ bset.b #SWCHAB_P0RIGHT,d0 left$: btst.w #IEQUALIFIERB_LSHIFT,d4 bne down$ bset.b #SWCHAB_P0LEFT,d0 down$: btst.w #IEQUALIFIERB_RALT,d4 bne up$ bset.b #SWCHAB_P0DOWN,d0 up$: btst.w #IEQUALIFIERB_LALT,d4 bne save_joystick$ bset.b #SWCHAB_P0UP,d0 save_joystick$: ori.b #$0f,d0 move.b d0,([env_Data,a3],A2600_SWCHA) move.b d0,([env_Data,a3],A2600_SWCHA+$100) btst.w #IEQUALIFIERB_LEFTBUTTON,d4 bne firing$ movea.l (env_Data,a3),a0 moveq #$70,d0 no_fire_loop$: move.b #$ff,(A2600_INPT4,a0,d0) subi.l #$10,d0 bpl no_fire_loop$ bra not_firing$ firing$: movea.l (env_Data,a3),a0 moveq #$70,d0 fire_loop$: move.b #$7f,(A2600_INPT4,a0,d0) subi.l #$10,d0 bpl fire_loop$ not_firing$: bra next_msg$ mouse_button_action$: ; Check if this is a paddles game cmpi.b #PADDLES,(env_ControllerTypes,a3) bne next_msg$ ; Record any change in state of the left mouse button movea.l (env_Data,a3),a0 cmpi.w #SELECTDOWN,d2 bne.s no_mouse_down$ move.b #$7f,d0 move.b #$7f,(A2600_SWCHA,a0) move.b #$7f,(A2600_SWCHA+$100,a0) no_mouse_down$: cmpi.w #SELECTUP,d2 bne.s no_mouse_up$ move.b #$ff,(A2600_SWCHA,a0) move.b #$ff,(A2600_SWCHA+$100,a0) no_mouse_up$: bra next_msg$ new_mouse_position$: ; Record new horizontal mouse position tst.w d5 bpl mouse_high_enough$ clr.w d5 mouse_high_enough$: cmpi.w #A2600_TV_WIDTH*X_MAG,d5 blo mouse_low_enough$ move.w #A2600_TV_WIDTH*X_MAG-1,d5 mouse_low_enough$: move.w #A2600_TV_WIDTH*X_MAG,d0 sub.w d5,d0 move.w d0,(env_MouseX,a3) bra next_msg$ end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d7/a2-a6 rts ;****i* atari2600.library/UpdatePatternList *** ; ; NAME ; UpdatePatternList -- . ; ; SYNOPSIS ; UpdatePatternList(object,position,env) ; d0 d1 a1 ; ; FUNCTION ; ; INPUTS ; object - The object whose pattern is to be updated. ; position - The current position in the pattern. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ; NOTES ; Preserves d0, d1 and a1. ; ;*** ; ; UpdatePatternList: ; rts ; Push registers that should be preserved onto stack move.l d2,-(sp) ; Check if vertical sync is on tst.w (env_VerticalSync,a1) bne end$ ; Check if new settings are different from previous settings movea.l (env_PatternListPtrs,a1,d0*4),a0 move.l (env_Settings,a1,d0*4),d2 cmp.l (a0),d2 beq.s replace$ ; Check new settings don't come into effect before or at the same ; time as old settings. cmp.l (4,a0),d1 bhi.s new_time_is_later$ move.l d1,(4,a0) bra.s end$ new_time_is_later$: ; Check if list is full cmpa.l (env_PatternListLimits,a1,d0*4),a0 bhs end$ ; Move on to next position in list addq.l #8,(env_PatternListPtrs,a1,d0*4) addq.l #8,a0 replace$: ; Store object-settings and update-point pair move.l d2,(a0)+ move.l d1,(a0) end$: ; Pop preserved registers off stack and return move.l (sp)+,d2 rts ;****i* atari2600.library/CalculateCurrentPosition *** ; ; NAME ; CalculateCurrentPosition -- . ; ; SYNOPSIS ; position = CalculateCurrentPosition(colour_clock,env) ; d0 d1 a1 ; ; FUNCTION ; ; INPUTS ; colour_clock - The number of emulated colour clock cycles since the ; previous call to WSync(). ; env - The Atari 2600 environment involved. ; ; RESULT ; position - The current position in the pattern. ; ; NOTES ; Preserves a1. ; ;*** ; ; CalculateCurrentPosition: ; Calculate current line number divu.w #A2600_LINE_CYCLES,d1 ; Calculate visible line number sub.w (env_StartingLineNo,a1),d1 ; Ensure visible line number isn't negative bhs high_enough$ moveq #0,d1 bra end$ high_enough$: ; Ensure visible line number isn't too big cmp.w (env_TVHeight,a1),d1 bmi low_enough$ move.l (env_TVHeight,a1),d1 bra end$ low_enough$: ; Calculate current horizontal position swap.w d1 move.b (horizontal_position_table.l,d1.w),d1 end$: ; Return position move.l d1,d0 rts ;****i* atari2600.library/FillPattern *** ; ; NAME ; FillPattern -- . ; ; SYNOPSIS ; FillPattern(object,env) ; d0 a1 ; ; FUNCTION ; ; INPUTS ; object - the number of the object whose pattern is to be filled. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; FillPattern: ; rts ; Push registers that should be preserved onto stack movem.l d2-d7/a2-a6,-(sp) ; Store parameters move.l d0,d5 movea.l a1,a3 ; Add final entry to current pattern list movea.l (env_PatternListPtrs,a3,d5*4),a1 addq.l #8,a1 move.l #OBJF_VBLANK,(a1)+ move.l (env_TVHeight,a3),(a1) ; Load starting address of old and new pattern lists lea.l (env_PatternLists,a3),a0 move.l d5,d0 lsl.l #4,d0 adda.l d0,a0 movea.l (a0)+,a2 movea.l (a0),a4 ; Initialise loop moveq #0,d3 loop$: ; Get the current patterns from both lists move.l (a2),d1 move.l (a4),d4 ; See whether the next change is in the old list or the new list move.l (4,a2),d6 move.l (4,a4),d7 cmp.l d7,d6 bmi use_new_element$ bne not_same$ ; Move new list on to next element addq.l #8,a2 not_same$: ; Consume an element from the old list move.l d7,d2 addq.l #8,a4 bra skip_use_new_element$ use_new_element$: ; Consume an element from the new list move.l d6,d2 addq.l #8,a2 skip_use_new_element$: ; See if the new pattern for the current section is different from ; the old one. cmp.l d4,d1 beq do_not_fill$ ; Construct the pattern line for the next section movea.l a3,a1 movea.l (pattern_line_function_table.l,d5*4),a0 jsr (a0) ; Fill in the current section of the pattern move.l d3,d1 move.l d5,d0 movea.l a3,a1 bsr FillPatternSection do_not_fill$: ; Store new base position move.l d2,d3 ; Check that new base is less than or equal to the maximum allowable cmp.l (env_TVHeight,a3),d3 bmi loop$ ; Pop preserved registers off stack and return movem.l (sp)+,d2-d7/a2-a6 rts ;****i* atari2600.library/FindColourDifferences *** ; ; NAME ; FindColourDifferences -- . ; ; SYNOPSIS ; FindColourDifferences(pattern_no,env) ; d0 a1 ; ; FUNCTION ; ; INPUTS ; pattern_no - the number of the pattern whose difference pattern is ; to be filled. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; FindColourDifferences: ; Push registers that should be preserved onto stack movem.l d2-d7/a2-a6,-(sp) ; Store parameters move.l d0,d5 movea.l a1,a3 ; Clear difference pattern movea.l (env_DifferencePatterns-REDUCED_OBJECT_COUNT*4,a3,d5*4),a0 move.w (env_TVHeight,a3),d0 move.w d0,d1 lsr.w #2,d0 andi.w #3,d1 bra longword_loop_start$ longword_loop$: clr.l (a0)+ longword_loop_start$: dbra d0,longword_loop$ bra byte_loop_start$ byte_loop$: clr.b (a0)+ byte_loop_start$: dbra d1,byte_loop$ ; Load starting address of old and new pattern lists lea.l (env_PatternLists,a3),a0 move.l d5,d0 lsl.l #4,d0 adda.l d0,a0 movea.l (a0),a2 movea.l (SCREEN_BUFFER_COUNT*4,a0),a4 ; Initialise loop moveq #0,d3 loop$: ; Get the current patterns from both lists move.l (a2),d1 move.l (a4),d4 ; See whether the next change is in the old list or the new list move.l (4,a2),d6 move.l (4,a4),d7 cmp.l d7,d6 bmi use_new_element$ bne not_same$ ; Move new list forward to next element addq.l #8,a2 not_same$: ; Consume an element from the old list move.l d7,d2 addq.l #8,a4 bra skip_use_new_element$ use_new_element$: ; Consume an element from the new list move.l d6,d2 addq.l #8,a2 skip_use_new_element$: ; See if the new pattern for the current section is different from ; the old one. cmp.l d4,d1 beq do_not_fill$ ; Fill in the current section of the difference pattern move.l d3,d1 move.l d5,d0 movea.l a3,a1 bsr FillDifferenceSection do_not_fill$: ; Store new base position move.l d2,d3 ; Check that new base is less than or equal to the maximum allowable cmp.l (env_TVHeight,a3),d3 bmi loop$ ; Pop preserved registers off stack and return movem.l (sp)+,d2-d7/a2-a6 rts ;****i* atari2600.library/FindDifferences *** ; ; NAME ; FindDifferences -- . ; ; SYNOPSIS ; FindDifferences(object,env) ; d0 a1 ; ; FUNCTION ; ; INPUTS ; object - the number of the object whose pattern is to be filled. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; FindDifferences: ; rts ; Push registers that should be preserved onto stack movem.l d2-d7/a2-a6,-(sp) ; Store parameters move.l d0,d5 movea.l a1,a3 ; Load starting address of old and new patterns lea.l (env_MergedPatterns,a3),a2 move.l d5,d0 lsl.l #4,d0 adda.l d0,a2 movea.l (a2),a1 movea.l (SCREEN_BUFFER_COUNT*4,a2),a0 ; Load address of difference pattern movea.l (env_DifferencePatterns,a3,d5*4),a2 ; Initialise line loop move.w (env_TVHeight,a3),d3 subq.w #1,d3 next_line$: ; Initialise longword loop moveq #BYTES_PER_LINE/4-1,d5 moveq #0,d2 next_longword$: ; Check if the old pattern segment is different to the new one cmpm.l (a0)+,(a1)+ beq same_pattern$ bset.l d5,d2 same_pattern$: dbra d5,next_longword$ move.b d2,(a2)+ dbra d3,next_line$ ; Pop preserved registers off stack and return movem.l (sp)+,d2-d7/a2-a6 rts ;****i* atari2600.library/FillDifferenceSection *** ; ; NAME ; FillDifferenceSection -- Fill part of an object pattern. ; ; SYNOPSIS ; FillDifferenceSection(object,start_point,end_point,env) ; d0 d1 d2 a1 ; ; FUNCTION ; ; INPUTS ; object - The object whose pattern is to be updated. ; start_point - A valid display position. ; end_point - A valid display position. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; FillDifferenceSection: ; rts ; Push registers that should be preserved onto stack movem.l d2-d3,-(sp) ; See if start and end points are the same cmp.l d1,d2 beq end$ ; Get address of starting byte in difference pattern movea.l (env_DifferencePatterns-REDUCED_OBJECT_COUNT*4,a1,d0*4),a0 move.l d1,d0 clr.w d0 swap.w d0 adda.l d0,a0 ; See if the new update point is on a later line than the old one move.l d2,d3 swap.w d3 move.l d1,d0 swap.w d0 cmp.w d0,d3 bne multiple_lines$ ; Reduce horizontal coordinates from pixels to longwords lsr.w #5,d1 lsr.w #5,d2 ; See if fill starts and stops on the same longword cmp.w d1,d2 bne multiple_longwords$ ; Set relevant bit in the line's byte moveq #4,d0 sub.w d1,d0 bset.b d0,(a0) bra end$ multiple_longwords$: ; Set bits representing longwords in the range sub.w d1,d2 addq.w #1,d2 add.w #27,d1 move.b (a0),d0 bfset.l d0{d1:d2} move.b d0,(a0) bra end$ multiple_lines$: ; Set relevant bits representing longwords on first line moveq #5,d0 lsr.w #5,d1 sub.w d1,d0 add.w #27,d1 move.b (a0),d3 bfset.l d3{d1:d0} move.b d3,(a0)+ ; Fill any complete lines in the range move.l d2,d0 swap.w d0 swap.w d1 sub.w d1,d0 subq.w #1,d0 bra line_loop_start$ next_line$: move.b #%11111,(a0)+ line_loop_start$: dbra d0,next_line$ ; Check if there are any bits to be filled in last line tst.w d2 beq.s end$ ; Set bits for part of last line in the range lsr.w #5,d2 addq.w #1,d2 move.b (a0),d0 bfset d0{27:d2} move.b d0,(a0) end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3 rts ;****i* atari2600.library/GetTime *** ; ; NAME ; GetTime -- Get current time in milliseconds. ; ; SYNOPSIS ; milliseconds = GetTime() ; d0 ; ; FUNCTION ; ; INPUTS ; ; RESULT ; milliseconds - The current time in milliseconds. ; ;*** ; ; GetTime: ; Push registers that should be preserved onto stack move.l a6,-(sp) ; Get current time in milliseconds movea.l (ab_IntuitionLib,a6),a6 subq.l #4,sp movea.l sp,a0 subq.l #4,sp movea.l sp,a1 JSRLIB CurrentTime move.l (sp)+,d0 move.l (sp)+,d1 divu.w #1000,d0 andi.l #$ffff,d0 mulu.l #1000,d1 add.l d0,d1 ; Restore preserved registers and return time in milliseconds move.l d1,d0 movea.l (sp)+,a6 rts ;****i* atari2600.library/HexToULong *** ; ; NAME ; HexToULong -- Convert a hexadecimal string to a ULONG. ; ; SYNOPSIS ; success = HexToULong(string,value) ; d0 a0 a1 ; ; FUNCTION ; ; INPUTS ; string - The string to be converted. ; value - Pointer to a ULONG in which the result should be placed. ; ; RESULT ; success - A boolean value to indicate whether a conversion could be ; made. ; ;*** ; ; HexToULong: ; Initialise loop moveq #0,d0 moveq #0,d1 ; Check for empty string tst.b (a0) beq failure$ loop$: ; Check for end of string move.b (a0)+,d1 beq success$ ; Check for lowercase hex digit cmpi.b #'f',d1 bhi.s failure$ cmpi.b #'a',d1 blo.s skip_lower$ subi.b #'a'-10,d1 bra.s add_on$ skip_lower$: ; Check for uppercase hex digit cmp.b #'F',d1 bhi.s failure$ cmp.b #'A',d1 blo.s skip_upper$ subi.b #'A'-10,d1 bra.s add_on$ skip_upper$: ; Check for decimal digit cmp.b #'9',d1 bhi.s failure$ cmp.b #'0',d1 blo.s failure$ subi.b #'0',d1 add_on$: ; Add on current digit and loop to get next digit lsl.l #4,d0 add.l d1,d0 bra loop$ failure$: ; Indicate failure moveq #0,d0 bra end$ success$: ; Store converted value and indicate success move.l d0,(a1) moveq #1,d0 end$: ; Return rts ;****i* atari2600.library/ULongToHex *** ; ; NAME ; ULongToHex -- Convert a ULONG to a hexadecimal string. ; ; SYNOPSIS ; ULongToHex(value,string) ; d0 a0 ; ; FUNCTION ; ; INPUTS ; value - The number to be converted to a string. ; string - A pointer to at least 9 bytes to store the resultant string ; in. ; ; RESULT ; None. ; ;*** ; ; ULongToHex: ; Zero is a special case tst.l d0 bne.s not_zero$ move.b #'0',(a0)+ bra end$ not_zero$: ; Initialise loop and discard leading zeros bfffo d0{0:32},d1 andi.b #~%11,d1 ror.l #4,d0 rol.l d1,d0 lsr.b #2,d1 movea.l d0,a1 move.b d1,d0 moveq #8-1,d1 sub.b d0,d1 loop$: ; Output digits move.l a1,d0 rol.l #4,d0 movea.l d0,a1 bfextu d0{0:4},d0 move.b (hex_digit_table.l,d0),(a0)+ dbra d1,loop$ end$: ; Terminate string move.b #'\0',(a0)+ ; Return rts ;****i* atari2600.library/Substring *** ; ; NAME ; Substring -- Determine if a string is a substring of another. ; ; SYNOPSIS ; found = Substring(string,substring) ; d0 a0 a1 ; ; FUNCTION ; Determines if a string is a case-insensitive substring of another. ; ; INPUTS ; string - The string to be searched. ; substring - The possible substring. ; ; RESULT ; found - A boolean value indicating whether one string was a ; substring. ; ;*** ; ; Substring: ; rts ; Push registers that should be preserved onto stack movem.l d2-d3/a2-a3/a6,-(sp) ; Store parameters movea.l a0,a2 movea.l a1,a3 ; Get length of string moveq #-1,d2 get_string_length$: addq.l #1,d2 tst.b (a0)+ bne get_string_length$ ; Get length of substring moveq #-1,d3 get_substring_length$: addq.l #1,d3 tst.b (a1)+ bne get_substring_length$ ; Check if substring is longer than string sub.l d3,d2 bmi not_found$ ; Search for the substring movea.l (ab_UtilityLib,a6),a6 search$: movea.l a2,a0 movea.l a3,a1 move.l d3,d0 JSRLIB Strnicmp tst.l d0 beq found$ addq.l #1,a2 dbra d2,search$ not_found$: moveq #0,d0 bra end$ found$: moveq #1,d0 end$: ; Pop preserved registers off stack and return movem.l (sp)+,d2-d3/a2-a3/a6 rts ;****i* atari2600.library/UpdatePaddleCharge *** ; ; NAME ; UpdatePaddleCharge -- Update the charge of the paddles. ; ; SYNOPSIS ; UpdatePaddleCharge(clock,env) ; d1 a1 ; ; FUNCTION ; Sets highest bit in each paddle register if the paddle's capacitor ; should have charged up by now. ; ; INPUTS ; clock - The number of emulated clock cycles since the frame began. ; env - The Atari 2600 environment involved. ; ; RESULT ; None. ; ;*** ; ; UpdatePaddleCharge: ; Check if this is a paddles game cmpi.b #PADDLES,(env_ControllerTypes,a1) bne end$ ; Do nothing if paddle is already charged tst.w (env_PaddlesCharged,a1) bne end$ ; Get clock cycles since last update and store clock cycles for this ; update. move.l d1,d0 sub.l (env_ClockAtPaddleUpdate,a1),d1 move.l d0,(env_ClockAtPaddleUpdate,a1) ; Check if pots are dumped to ground tst.w (env_PotsDumped,a1) bne end$ ; Add product of time and current to charge move.l #$ffff,d0 divu.w (env_MouseX,a1),d0 andi.l #$ffff,d0 mulu.l d0,d1 move.l (env_PaddleCharges,a1),d0 add.l d1,d0 move.l d0,(env_PaddleCharges,a1) ; Check if paddle has charged up cmpi.l #PADDLE_CHARGE_THRESHOLD,d0 blo end$ ; Record paddle as having charged up move.w #1,(env_PaddlesCharged,a1) movea.l (env_Data,a1),a0 moveq #$70,d0 paddle_charged_loop$: move.b #$ff,(A2600_INPT0,a0,d0) subi.l #$10,d0 bpl paddle_charged_loop$ end$: ; Return rts ; Data: ; ===== ; Static data used by library. ; data screen_tags: dc.l SA_Width,TV_WIDTH*X_MAG dc.l SA_Height,0 dc.l SA_Depth,SCREEN_DEPTH dc.l SA_DetailPen,5 dc.l SA_BlockPen,4 dc.l SA_SysFont,1 dc.l SA_Font,font_spec dc.l SA_Type,CUSTOMSCREEN|CUSTOMBITMAP dc.l SA_BitMap,0 dc.l SA_DisplayID,0 dc.l SA_ShowTitle,1 dc.l SA_Pens,pen_list dc.l SA_Colors32,colour_table dc.l SA_Title,0 dc.l TAG_END,0 pen_list: dc.w 0 ; DETAILPEN dc.w 7 ; BLOCKPEN dc.w 0 ; TEXTPEN dc.w 7 ; SHINEPEN dc.w 0 ; SHADOWPEN dc.w $0e ; FILLPEN dc.w 0 ; FILLTEXTPEN dc.w $03 ; BACKGROUNDPEN dc.w 2 ; HIGHLIGHTTEXTPEN dc.w 0 ; BARDETAILPEN dc.w 7 ; BARBLOCKPEN dc.w 0 ; BARTRIMPEN dc.w -1 ; end of list font_spec: dc.l font_name dc.w 8 dc.b FS_NORMAL dc.b FPF_ROMFONT font_name: dc.b "topaz.font",0 cnop 0,4 colour_table: ntsc_colours: dc.w 128,0 dc.l $00000000,$00000000,$00000000 dc.l $c8888888,$51111111,$22222222 ;$39999999,$39999999,$39999999 dc.l $79999999,$79999999,$79999999 dc.l $abbbbbbb,$abbbbbbb,$abbbbbbb dc.l $cddddddd,$cddddddd,$cddddddd dc.l $ffffffff,$81111111,$1eeeeeee ;$e6666666,$e6666666,$e6666666 dc.l $f2222222,$f2222222,$f2222222 dc.l $ffffffff,$ffffffff,$ffffffff dc.l $39999999,$17777777,$01111111 dc.l $83333333,$30000000,$08888888 dc.l $c8888888,$5fffffff,$24444444 dc.l $ffffffff,$91111111,$1ddddddd dc.l $ffffffff,$c5555555,$1ddddddd dc.l $ffffffff,$d8888888,$4ccccccc dc.l $ffffffff,$f4444444,$56666666 dc.l $ffffffff,$ffffffff,$98888888 dc.l $45555555,$19999999,$04444444 dc.l $faaaaaaa,$52222222,$55555555 ;$9fffffff,$24444444,$1eeeeeee dc.l $39999999,$39999999,$39999999 ;$c8888888,$51111111,$22222222 dc.l $e6666666,$e6666666,$e6666666 ;$ffffffff,$81111111,$1eeeeeee dc.l $ffffffff,$98888888,$2ccccccc dc.l $ffffffff,$c5555555,$45555555 dc.l $ffffffff,$c6666666,$6ddddddd dc.l $ffffffff,$e4444444,$a1111111 dc.l $4aaaaaaa,$17777777,$04444444 dc.l $b2222222,$1ddddddd,$17777777 dc.l $dfffffff,$25555555,$1ccccccc dc.l $9fffffff,$24444444,$1eeeeeee ;$faaaaaaa,$52222222,$55555555 dc.l $ffffffff,$70000000,$6eeeeeee dc.l $ffffffff,$8fffffff,$8fffffff dc.l $ffffffff,$abbbbbbb,$addddddd dc.l $ffffffff,$c7777777,$ceeeeeee dc.l $05555555,$05555555,$68888888 dc.l $71111111,$22222222,$72222222 dc.l $a5555555,$32222222,$a6666666 dc.l $cddddddd,$3eeeeeee,$cfffffff dc.l $eaaaaaaa,$51111111,$ebbbbbbb dc.l $feeeeeee,$6ddddddd,$ffffffff dc.l $ffffffff,$87777777,$fbbbbbbb dc.l $ffffffff,$a4444444,$ffffffff dc.l $28888888,$04444444,$79999999 dc.l $59999999,$0fffffff,$90000000 dc.l $88888888,$39999999,$aaaaaaaa dc.l $c0000000,$4aaaaaaa,$dccccccc dc.l $e0000000,$5eeeeeee,$ffffffff dc.l $f2222222,$7ccccccc,$ffffffff dc.l $ffffffff,$98888888,$ffffffff dc.l $feeeeeee,$abbbbbbb,$ffffffff dc.l $35555555,$08888888,$8aaaaaaa dc.l $50000000,$0ccccccc,$d0000000 dc.l $79999999,$45555555,$d0000000 dc.l $a2222222,$51111111,$d9999999 dc.l $beeeeeee,$60000000,$ffffffff dc.l $cccccccc,$77777777,$ffffffff dc.l $d7777777,$90000000,$ffffffff dc.l $dfffffff,$aaaaaaaa,$ffffffff dc.l $05555555,$1eeeeeee,$81111111 dc.l $08888888,$2fffffff,$caaaaaaa dc.l $44444444,$4ccccccc,$deeeeeee dc.l $5aaaaaaa,$68888888,$ffffffff dc.l $71111111,$83333333,$ffffffff dc.l $90000000,$a0000000,$ffffffff dc.l $9fffffff,$b2222222,$ffffffff dc.l $c0000000,$cbbbbbbb,$ffffffff dc.l $0ccccccc,$04444444,$8bbbbbbb dc.l $38888888,$2ddddddd,$b5555555 dc.l $58888888,$4fffffff,$daaaaaaa dc.l $6bbbbbbb,$64444444,$ffffffff dc.l $8aaaaaaa,$84444444,$ffffffff dc.l $99999999,$98888888,$ffffffff dc.l $b1111111,$aeeeeeee,$ffffffff dc.l $c0000000,$c2222222,$ffffffff dc.l $1ddddddd,$29999999,$5aaaaaaa dc.l $1ddddddd,$48888888,$92222222 dc.l $1ccccccc,$71111111,$c6666666 dc.l $48888888,$9bbbbbbb,$d9999999 dc.l $55555555,$b6666666,$ffffffff dc.l $8ccccccc,$d8888888,$ffffffff dc.l $9bbbbbbb,$dfffffff,$ffffffff dc.l $c3333333,$e9999999,$ffffffff dc.l $2fffffff,$43333333,$02222222 dc.l $44444444,$61111111,$03333333 dc.l $3eeeeeee,$94444444,$21111111 dc.l $57777777,$abbbbbbb,$3bbbbbbb dc.l $61111111,$d0000000,$70000000 dc.l $72222222,$f5555555,$84444444 dc.l $87777777,$ffffffff,$97777777 dc.l $addddddd,$ffffffff,$b6666666 dc.l $0aaaaaaa,$41111111,$08888888 dc.l $10000000,$68888888,$0ddddddd dc.l $16666666,$92222222,$12222222 dc.l $1ccccccc,$b9999999,$17777777 dc.l $21111111,$d9999999,$1bbbbbbb dc.l $6eeeeeee,$f0000000,$40000000 dc.l $83333333,$ffffffff,$5bbbbbbb dc.l $b2222222,$ffffffff,$9aaaaaaa dc.l $04444444,$41111111,$0bbbbbbb dc.l $06666666,$66666666,$11111111 dc.l $08888888,$88888888,$17777777 dc.l $0bbbbbbb,$afffffff,$1ddddddd dc.l $86666666,$d9999999,$22222222 dc.l $99999999,$f9999999,$27777777 dc.l $b7777777,$ffffffff,$5bbbbbbb dc.l $dccccccc,$ffffffff,$81111111 dc.l $02222222,$35555555,$0fffffff dc.l $0ccccccc,$4aaaaaaa,$1ccccccc dc.l $4fffffff,$74444444,$20000000 dc.l $64444444,$92222222,$28888888 dc.l $a1111111,$b0000000,$34444444 dc.l $b2222222,$d2222222,$41111111 dc.l $d6666666,$e1111111,$49999999 dc.l $f2222222,$ffffffff,$53333333 dc.l $26666666,$30000000,$01111111 dc.l $23333333,$40000000,$05555555 dc.l $80000000,$69999999,$31111111 dc.l $afffffff,$99999999,$3aaaaaaa dc.l $d5555555,$b5555555,$43333333 dc.l $e1111111,$cbbbbbbb,$38888888 dc.l $e3333333,$e5555555,$34444444 dc.l $fbbbbbbb,$ffffffff,$7ddddddd dc.l $40000000,$1aaaaaaa,$02222222 dc.l $70000000,$24444444,$08888888 dc.l $abbbbbbb,$51111111,$1fffffff dc.l $bfffffff,$77777777,$30000000 dc.l $e1111111,$93333333,$44444444 dc.l $f9999999,$addddddd,$58888888 dc.l $ffffffff,$c1111111,$60000000 dc.l $ffffffff,$cbbbbbbb,$83333333 dc.w 0 copyright_notice: dc.b "Copyright © 1999-2001 Neil Cafferkey",0 cnop 0,4 pal_colours: dc.w 128,0 dc.l $00000000,$00000000,$00000000 dc.l $24444444,$24444444,$24444444 dc.l $48888888,$48888888,$48888888 dc.l $6ddddddd,$6ddddddd,$6ddddddd dc.l $91111111,$91111111,$91111111 dc.l $b6666666,$b6666666,$b6666666 dc.l $daaaaaaa,$daaaaaaa,$daaaaaaa dc.l $ffffffff,$ffffffff,$ffffffff dc.l $00000000,$00000000,$00000000 dc.l $24444444,$24444444,$24444444 dc.l $48888888,$48888888,$48888888 dc.l $6ddddddd,$6ddddddd,$6ddddddd dc.l $91111111,$91111111,$91111111 dc.l $b6666666,$b6666666,$b6666666 dc.l $daaaaaaa,$daaaaaaa,$daaaaaaa dc.l $ffffffff,$ffffffff,$ffffffff dc.l $4aaaaaaa,$37777777,$00000000 dc.l $70000000,$58888888,$13333333 dc.l $8ccccccc,$73333333,$2aaaaaaa dc.l $a6666666,$8ddddddd,$46666666 dc.l $beeeeeee,$a7777777,$67777777 dc.l $d4444444,$c1111111,$8bbbbbbb dc.l $eaaaaaaa,$dccccccc,$b3333333 dc.l $ffffffff,$f6666666,$deeeeeee dc.l $28888888,$4aaaaaaa,$00000000 dc.l $44444444,$70000000,$0fffffff dc.l $5ccccccc,$8ccccccc,$21111111 dc.l $74444444,$a6666666,$38888888 dc.l $8ccccccc,$beeeeeee,$51111111 dc.l $a6666666,$d4444444,$6eeeeeee dc.l $c0000000,$eaaaaaaa,$8eeeeeee dc.l $dbbbbbbb,$ffffffff,$b0000000 dc.l $4aaaaaaa,$13333333,$00000000 dc.l $70000000,$28888888,$0fffffff dc.l $8ccccccc,$3ddddddd,$21111111 dc.l $a6666666,$54444444,$38888888 dc.l $beeeeeee,$6ddddddd,$51111111 dc.l $d4444444,$88888888,$6eeeeeee dc.l $eaaaaaaa,$a5555555,$8eeeeeee dc.l $ffffffff,$c4444444,$b0000000 dc.l $00000000,$4aaaaaaa,$22222222 dc.l $0fffffff,$70000000,$3bbbbbbb dc.l $21111111,$8ccccccc,$52222222 dc.l $38888888,$a6666666,$6aaaaaaa dc.l $51111111,$beeeeeee,$83333333 dc.l $6eeeeeee,$d4444444,$9ddddddd dc.l $8eeeeeee,$eaaaaaaa,$b8888888 dc.l $b0000000,$ffffffff,$d4444444 dc.l $4aaaaaaa,$00000000,$28888888 dc.l $70000000,$0fffffff,$44444444 dc.l $8ccccccc,$21111111,$5ccccccc dc.l $a6666666,$38888888,$74444444 dc.l $beeeeeee,$51111111,$8ccccccc dc.l $d4444444,$6eeeeeee,$a6666666 dc.l $eaaaaaaa,$8eeeeeee,$c0000000 dc.l $ffffffff,$b0000000,$dbbbbbbb dc.l $00000000,$40000000,$4aaaaaaa dc.l $0fffffff,$63333333,$70000000 dc.l $21111111,$7eeeeeee,$8ccccccc dc.l $38888888,$97777777,$a6666666 dc.l $51111111,$afffffff,$beeeeeee dc.l $6eeeeeee,$c7777777,$d4444444 dc.l $8eeeeeee,$deeeeeee,$eaaaaaaa dc.l $b0000000,$f4444444,$ffffffff dc.l $43333333,$00000000,$2ccccccc dc.l $65555555,$0fffffff,$4bbbbbbb dc.l $7eeeeeee,$21111111,$65555555 dc.l $95555555,$38888888,$80000000 dc.l $a6666666,$51111111,$9aaaaaaa dc.l $bfffffff,$6eeeeeee,$b7777777 dc.l $d3333333,$8eeeeeee,$d3333333 dc.l $e5555555,$b0000000,$f1111111 dc.l $00000000,$1ddddddd,$4aaaaaaa dc.l $0fffffff,$38888888,$70000000 dc.l $21111111,$53333333,$8ccccccc dc.l $38888888,$6eeeeeee,$a6666666 dc.l $51111111,$8ddddddd,$beeeeeee dc.l $6eeeeeee,$a8888888,$d4444444 dc.l $8eeeeeee,$c8888888,$eaaaaaaa dc.l $b0000000,$e9999999,$ffffffff dc.l $37777777,$00000000,$4aaaaaaa dc.l $57777777,$0fffffff,$70000000 dc.l $70000000,$21111111,$8ccccccc dc.l $89999999,$38888888,$a6666666 dc.l $a1111111,$51111111,$beeeeeee dc.l $baaaaaaa,$6eeeeeee,$d4444444 dc.l $d2222222,$8eeeeeee,$eaaaaaaa dc.l $eaaaaaaa,$b0000000,$ffffffff dc.l $00000000,$18888888,$4aaaaaaa dc.l $0fffffff,$2eeeeeee,$70000000 dc.l $21111111,$44444444,$8ccccccc dc.l $38888888,$5bbbbbbb,$a6666666 dc.l $51111111,$74444444,$beeeeeee dc.l $6eeeeeee,$8fffffff,$d4444444 dc.l $8eeeeeee,$abbbbbbb,$eaaaaaaa dc.l $b0000000,$c9999999,$ffffffff dc.l $13333333,$00000000,$4aaaaaaa dc.l $28888888,$0fffffff,$70000000 dc.l $3ddddddd,$21111111,$8ccccccc dc.l $54444444,$38888888,$a6666666 dc.l $6ddddddd,$51111111,$beeeeeee dc.l $88888888,$6eeeeeee,$d4444444 dc.l $a5555555,$8eeeeeee,$eaaaaaaa dc.l $c4444444,$b0000000,$ffffffff dc.l $00000000,$01111111,$4aaaaaaa dc.l $0fffffff,$11111111,$70000000 dc.l $21111111,$24444444,$8ccccccc dc.l $38888888,$3aaaaaaa,$a6666666 dc.l $51111111,$53333333,$beeeeeee dc.l $6eeeeeee,$70000000,$d4444444 dc.l $8eeeeeee,$8fffffff,$eaaaaaaa dc.l $b0000000,$b2222222,$ffffffff dc.l $00000000,$00000000,$00000000 dc.l $24444444,$24444444,$24444444 dc.l $48888888,$48888888,$48888888 dc.l $6ddddddd,$6ddddddd,$6ddddddd dc.l $91111111,$91111111,$91111111 dc.l $b6666666,$b6666666,$b6666666 dc.l $daaaaaaa,$daaaaaaa,$daaaaaaa dc.l $ffffffff,$ffffffff,$ffffffff dc.l $00000000,$00000000,$00000000 dc.l $24444444,$24444444,$24444444 dc.l $48888888,$48888888,$48888888 dc.l $6ddddddd,$6ddddddd,$6ddddddd dc.l $91111111,$91111111,$91111111 dc.l $b6666666,$b6666666,$b6666666 dc.l $daaaaaaa,$daaaaaaa,$daaaaaaa dc.l $ffffffff,$ffffffff,$ffffffff dc.w 0 colour_remap_table: dc.b $00,$00,$12,$12,$02,$02,$03,$03,$04,$04,$13,$13,$06,$06,$07,$07 dc.b $08,$08,$09,$09,$0a,$0a,$0b,$0b,$0c,$0c,$0d,$0d,$0e,$0e,$0f,$0f dc.b $10,$10,$1b,$1b,$01,$01,$05,$05,$14,$14,$15,$15,$16,$16,$17,$17 dc.b $18,$18,$19,$19,$1a,$1a,$11,$11,$1c,$1c,$1d,$1d,$1e,$1e,$1f,$1f dc.b $20,$20,$21,$21,$22,$22,$23,$23,$24,$24,$25,$25,$26,$26,$27,$27 dc.b $28,$28,$29,$29,$2a,$2a,$2b,$2b,$2c,$2c,$2d,$2d,$2e,$2e,$2f,$2f dc.b $30,$30,$31,$31,$32,$32,$33,$33,$34,$34,$35,$35,$36,$36,$37,$37 dc.b $38,$38,$39,$39,$3a,$3a,$3b,$3b,$3c,$3c,$3d,$3d,$3e,$3e,$3f,$3f dc.b $40,$40,$41,$41,$42,$42,$43,$43,$44,$44,$45,$45,$46,$46,$47,$47 dc.b $48,$48,$49,$49,$4a,$4a,$4b,$4b,$4c,$4c,$4d,$4d,$4e,$4e,$4f,$4f dc.b $50,$50,$51,$51,$52,$52,$53,$53,$54,$54,$55,$55,$56,$56,$57,$57 dc.b $58,$58,$59,$59,$5a,$5a,$5b,$5b,$5c,$5c,$5d,$5d,$5e,$5e,$5f,$5f dc.b $60,$60,$61,$61,$62,$62,$63,$63,$64,$64,$65,$65,$66,$66,$67,$67 dc.b $68,$68,$69,$69,$6a,$6a,$6b,$6b,$6c,$6c,$6d,$6d,$6e,$6e,$6f,$6f dc.b $70,$70,$71,$71,$72,$72,$73,$73,$74,$74,$75,$75,$76,$76,$77,$77 dc.b $78,$78,$79,$79,$7a,$7a,$7b,$7b,$7c,$7c,$7d,$7d,$7e,$7e,$7f,$7f byte_reverse_table: incbin "byte_reverse_table" cnop 0,2 word_stretch_table: incbin "word_stretch_table" cnop 0,4 long_stretch_table: incbin "long_stretch_table" cnop 0,4 nibble_stretch_table: incbin "nibble_stretch_table" nibble_reverse_table: incbin "nibble_reverse_table" num_size_table: dc.b %00000001,%00000011,%00000101,%00000111 dc.b %00010001,%00000001,%00010101,%00000001 player_centre_table: dc.b 4,4,4,4,4,8,4,16 playfield_delay_table: dc.b 4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3 dc.b 4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3 dc.b 4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3 window_tags: dc.l WA_Top,MENU_BAR_HEIGHT dc.l WA_Height,0 dc.l WA_IDCMP,IDCMP_MENUPICK|IDCMP_RAWKEY|IDCMP_MOUSEBUTTONS|IDCMP_MOUSEMOVE dc.l WA_CustomScreen,0 dc.l WA_Backdrop,1 dc.l WA_ReportMouse,1 dc.l WA_NoCareRefresh,1 dc.l WA_Borderless,1 dc.l WA_Activate,1 dc.l WA_NewLookMenus,1 dc.l TAG_END,0 menu_layout_tags: dc.l GTMN_NewLookMenus,1 dc.l TAG_END,0 new_menus: dc.b NM_TITLE,0 dc.l game_menu_name dcb.b 14,0 dc.b NM_ITEM,0 dc.l about_item_name dc.l about_item_key dcb.b 10,0 dc.b NM_ITEM,0 dc.l NM_BARLABEL dcb.b 14,0 dc.b NM_ITEM,0 dc.l quit_item_name dc.l quit_item_key dcb.b 10,0 dc.b NM_TITLE,0 dc.l console_menu_name dcb.b 14,0 dc.b NM_ITEM,0 dc.l select_item_name dc.l select_item_key dcb.b 10,0 dc.b NM_ITEM,0 dc.l reset_item_name dc.l reset_item_key dcb.b 10,0 dc.b NM_ITEM,0 dc.l NM_BARLABEL dcb.b 14,0 dc.b NM_ITEM,0 dc.l colour_item_name dc.l 0 dc.w CHECKIT|MENUTOGGLE|CHECKED dcb.b 8,0 dc.b NM_ITEM,0 dc.l easy_item_name dc.l 0 dc.w CHECKIT|MENUTOGGLE dcb.b 8,0 dc.b NM_END,0 dcb.b 18,0 game_menu_name: dc.b "Game",0 about_item_name: dc.b "About...",0 about_item_key: dc.b "?",0 quit_item_name: dc.b "Quit",0 quit_item_key: dc.b "Q",0 console_menu_name: dc.b "Control",0 select_item_name: dc.b "Select",0 select_item_key: dc.b "S",0 reset_item_name: dc.b "Reset",0 reset_item_key: dc.b "R",0 colour_item_name: dc.b "Colour",0 easy_item_name: dc.b "Easy",0 about_req_body_text: dc.b "Speed: %3u%%\n\n" dc.b "Frames per second: %3u\n\n" dc.b "Frame skip ratio: 1:%u",0 about_req_button_text: dc.b "OK",0 default_prog_name: dc.b "Atari 2600 Program",0 cnop 0,4 pattern_line_function_table: dc.l MakePlayfieldPatternLine dc.l MakePlayerPatternLine dc.l MakePlayerPatternLine dc.l MakeBallPatternLine dc.l MakeMissilePatternLine dc.l MakeMissilePatternLine dc.l MakePlayfieldBitPlanePatternLine dc.l MakePlayfieldBitPlanePatternLine dc.l MakePlayfieldBitPlanePatternLine dc.l MakePlayfieldBitPlanePatternLine dc.l MakePlayfieldBitPlanePatternLine dc.l MakePlayfieldBitPlanePatternLine dc.l MakePlayfieldBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakeBitPlanePatternLine dc.l MakePriorityPatternLine horizontal_position_table: dc.b 0,0,0,0,0,0,0,0,0,0 dc.b 0,0,0,0,0,0,0,0,0,0 dc.b 0,0,0,0,0,0,0,0,0,0 dc.b 0,0,0,0,0,0,0,0,0,0 dc.b 0,0,0,0,0,0,0,0,0,0 dc.b 0,0,0,0,0,0,0,0,0,0 dc.b 0,0,0,0,0,0,0,0,0,1 dc.b 2,3,4,5,6,7,8,9,10,11 dc.b 12,13,14,15,16,17,18,19,20,21 dc.b 22,23,24,25,26,27,28,29,30,31 dc.b 32,33,34,35,36,37,38,39,40,41 dc.b 42,43,44,45,46,47,48,49,50,51 dc.b 52,53,54,55,56,57,58,59,60,61 dc.b 62,63,64,65,66,67,68,69,70,71 dc.b 72,73,74,75,76,77,78,79,80,81 dc.b 82,83,84,85,86,87,88,89,90,91 dc.b 92,93,94,95,96,97,98,99,100,101 dc.b 102,103,104,105,106,107,108,109,110,111 dc.b 112,113,114,115,116,117,118,119,120,121 dc.b 122,123,124,125,126,127,128,129,130,131 dc.b 132,133,134,135,136,137,138,139,140,141 dc.b 142,143,144,145,146,147,148,149,150,151 dc.b 152,153,154,155,156,157,158,159 cnop 0,4 horizontal_motion_table: dc.w 0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1 dc.w 0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1 dc.w 0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1 dc.w 0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1 dc.w 0,1,2,3,4,5,6,6,-8,-7,-6,-5,-4,-3,-2,-1 dc.w 0,1,2,3,4,5,5,5,-8,-7,-6,-5,-4,-3,-2,-1 dc.w 0,1,2,3,4,5,5,5,-8,-7,-6,-5,-4,-3,-2,-1 dc.w 0,1,2,3,4,4,4,4,-8,-7,-6,-5,-4,-3,-2,-1 dc.w 0,1,2,3,3,3,3,3,-8,-7,-6,-5,-4,-3,-2,-1 dc.w 0,1,2,2,2,2,2,2,-8,-7,-6,-5,-4,-3,-2,-1 dc.w 0,1,2,2,2,2,2,2,-8,-7,-6,-5,-4,-3,-2,-1 dc.w 0,1,1,1,1,1,1,1,-8,-7,-6,-5,-4,-3,-2,-1 dc.w 0,0,0,0,0,0,0,0,-8,-7,-6,-5,-4,-3,-2,-1 dc.w -1,-1,-1,-1,-1,-1,-1,-1,-8,-7,-6,-5,-4,-3,-2,-1 dc.w -1,-1,-1,-1,-1,-1,-1,-1,-8,-7,-6,-5,-4,-3,-2,-1 dc.w -2,-2,-2,-2,-2,-2,-2,-2,-8,-7,-6,-5,-4,-3,-2,-2 dc.w -3,-3,-3,-3,-3,-3,-3,-3,-8,-7,-6,-5,-4,-3,-3,-3 dc.w -4,-4,-4,-4,-4,-4,-4,-4,-8,-7,-6,-5,-4,-4,-4,-4 dc.w -4,-4,-4,-4,-4,-4,-4,-4,-8,-7,-6,-5,-4,-4,-4,-4 dc.w -5,-5,-5,-5,-5,-5,-5,-5,-8,-7,-6,-5,-5,-5,-5,-5 dc.w -6,-6,-6,-6,-6,-6,-6,-6,-8,-7,-6,-6,-6,-6,-6,-6 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,1,2,3,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,0,1,2,3,0,0,0,0,0,0,0,0 dc.w 0,0,0,0,1,2,3,4,0,0,0,0,0,0,0,0 dc.w 0,0,0,1,2,3,4,5,0,0,0,0,0,0,0,0 dc.w 0,0,1,2,3,4,5,6,0,0,0,0,0,0,0,0 dc.w 0,0,1,2,3,4,5,6,0,0,0,0,0,0,0,0 dc.w 0,1,2,3,4,5,6,7,0,0,0,0,0,0,0,0 dc.w 1,2,3,4,5,6,7,8,0,0,0,0,0,0,0,0 dc.w 2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,1 dc.w 2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,1 dc.w 3,4,5,6,7,8,9,10,0,0,0,0,0,0,1,2 dc.w 4,5,6,7,8,9,10,11,0,0,0,0,0,1,2,3 dc.w 5,6,7,8,9,10,11,12,0,0,0,0,1,2,3,4 dc.w 5,6,7,8,9,10,11,12,0,0,0,0,1,2,3,4 dc.w 6,7,8,9,10,11,12,13,0,0,0,1,2,3,4,5 dc.w 7,8,9,10,11,12,13,14,0,0,1,2,3,4,5,6 dc.w 8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7 dc.w 8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7 dc.w 0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1 frameskip_tt_name: dc.b "FRAMESKIPRATIO",0 startingline_tt_name: dc.b "STARTLINE",0 tvlines_tt_name: dc.b "TVLINES",0 framerate_tt_name: dc.b "IDEALFRAMERATE",0 nosound_tt_name: dc.b "NOSOUND",0 cnop 0,4 controller_tt_name_table: dc.l leftcontroller_tt_name dc.l rightcontroller_tt_name leftcontroller_tt_name: dc.b "LEFTCONTROLLER",0 rightcontroller_tt_name: dc.b "RIGHTCONTROLLER",0 cnop 0,4 controller_tt_value_table: dc.l nocontroller_name dc.l joystick_name dc.l paddles_name dc.l driving_name dc.l keypad_name nocontroller_name: dc.b "NONE",0 joystick_name: dc.b "JOYSTICK",0 paddles_name: dc.b "PADDLES",0 driving_name: dc.b "DRIVING",0 keypad_name: dc.b "KEYPAD",0 screenmode_tt_name: dc.b "SCREENMODEID",0 channel_combinations: dc.b 1|2,1|4,1|8,2|4,2|8,4|8 slow_pure_pattern: dc.b 127,127,127,-128,-128,-128 div_31_pattern: dc.b 127,-128,-128,-128,-128,-128,-128,-128,-128,-128 dc.b -128,-128,-128,-128,-128,-128,-128,-128,-128, 127 dc.b 127, 127, 127, 127, 127, 127, 127, 127, 127, 127 dc.b 127 div_93_pattern: dc.b 127, 127, 127,-128,-128,-128,-128,-128,-128,-128 dc.b -128,-128,-128,-128,-128,-128,-128,-128,-128,-128 dc.b -128,-128,-128,-128,-128,-128,-128,-128,-128,-128 dc.b -128,-128,-128,-128,-128,-128,-128,-128,-128,-128 dc.b -128,-128,-128,-128,-128,-128,-128,-128,-128,-128 dc.b -128,-128,-128,-128,-128,-128,-128, 127, 127, 127 dc.b 127, 127, 127, 127, 127, 127, 127, 127, 127, 127 dc.b 127, 127, 127, 127, 127, 127, 127, 127, 127, 127 dc.b 127, 127, 127, 127, 127, 127, 127, 127, 127, 127 dc.b 127, 127, 127 four_bit_poly_pattern: dc.b 127,127,-128,127,127,127,-128,-128 dc.b -128,-128,127,-128,127,-128,-128 five_bit_poly_pattern: dc.b -128,-128, 127,-128, 127, 127,-128,-128, 127, 127 dc.b 127, 127, 127,-128,-128,-128, 127, 127,-128, 127 dc.b 127, 127,-128, 127,-128, 127,-128,-128,-128,-128 dc.b 127 nine_bit_poly_pattern: dc.b 127,-128, 127,-128, 127,-128, 127,-128, 127, 127 dc.b 127, 127, 127,-128, 127,-128, 127,-128, 127,-128 dc.b 127,-128, 127,-128,-128, 127,-128, 127,-128, 127 dc.b -128, 127, 127,-128, 127,-128, 127,-128, 127,-128 dc.b 127,-128, 127,-128,-128,-128,-128, 127,-128,-128 dc.b -128,-128, 127,-128,-128, 127,-128, 127,-128, 127 dc.b -128, 127,-128,-128, 127, 127, 127, 127,-128, 127 dc.b -128, 127,-128,-128, 127, 127, 127,-128, 127,-128 dc.b 127,-128,-128, 127,-128, 127,-128, 127,-128, 127 dc.b 127, 127,-128, 127,-128, 127,-128, 127,-128, 127 dc.b -128, 127,-128, 127,-128, 127,-128, 127,-128, 127 dc.b -128,-128, 127, 127, 127,-128, 127,-128,-128, 127 dc.b -128, 127, 127, 127,-128,-128, 127, 127,-128,-128 dc.b 127, 127,-128,-128, 127, 127,-128,-128, 127, 127 dc.b 127,-128,-128, 127, 127,-128,-128, 127, 127,-128 dc.b -128, 127, 127,-128, 127, 127,-128,-128, 127, 127 dc.b -128, 127, 127,-128,-128, 127,-128, 127,-128, 127 dc.b -128, 127,-128, 127, 127, 127,-128,-128, 127, 127 dc.b 127, 127,-128,-128, 127, 127,-128,-128,-128, 127 dc.b 127,-128,-128, 127, 127, 127,-128,-128,-128, 127 dc.b 127, 127,-128,-128, 127, 127, 127,-128,-128, 127 dc.b 127,-128, 127,-128, 127,-128, 127, 127,-128, 127 dc.b -128, 127,-128, 127, 127,-128, 127,-128,-128,-128 dc.b 127, 127, 127,-128, 127,-128, 127,-128, 127,-128 dc.b 127,-128, 127, 127,-128, 127,-128, 127, 127,-128 dc.b -128, 127,-128, 127,-128, 127,-128,-128, 127,-128 dc.b -128,-128, 127,-128, 127,-128, 127,-128,-128, 127 dc.b -128,-128,-128, 127,-128, 127,-128, 127,-128, 127 dc.b 127, 127, 127,-128, 127,-128, 127,-128,-128,-128 dc.b 127,-128,-128,-128, 127,-128, 127,-128, 127,-128 dc.b 127,-128, 127,-128, 127,-128, 127,-128, 127,-128 dc.b -128, 127, 127,-128,-128,-128, 127,-128, 127, 127 dc.b 127, 127,-128, 127,-128, 127,-128, 127,-128,-128 dc.b 127,-128, 127,-128, 127,-128, 127, 127, 127,-128 dc.b -128,-128, 127, 127, 127,-128,-128, 127, 127,-128 dc.b 127, 127, 127,-128, 127,-128, 127,-128, 127,-128 dc.b 127,-128, 127,-128, 127, 127, 127,-128, 127,-128 dc.b 127,-128,-128,-128, 127,-128,-128, 127,-128, 127 dc.b -128, 127,-128, 127,-128,-128,-128,-128,-128,-128 dc.b 127, 127,-128,-128, 127,-128, 127,-128, 127, 127 dc.b -128, 127, 127,-128,-128, 127, 127,-128,-128, 127 dc.b -128, 127,-128,-128, 127,-128, 127,-128,-128, 127 dc.b -128, 127,-128,-128,-128, 127,-128, 127,-128, 127 dc.b -128,-128, 127,-128, 127,-128, 127,-128, 127, 127 dc.b -128, 127,-128, 127,-128,-128, 127, 127, 127,-128 dc.b -128, 127, 127,-128,-128, 127, 127,-128, 127, 127 dc.b -128, 127, 127,-128,-128, 127, 127,-128, 127,-128 dc.b 127,-128,-128, 127,-128,-128, 127, 127,-128, 127 dc.b -128, 127,-128,-128, 127,-128, 127,-128,-128, 127 dc.b 127,-128, 127,-128, 127,-128, 127, 127, 127,-128 dc.b -128, 127,-128, 127,-128,-128, 127, 127,-128,-128 dc.b 127 cnop 0,4 sound_length_table: dc.l SOUND_0_MULTIPLE dc.l FOUR_BIT_POLY_SIZE*SOUND_1_MULTIPLE dc.l FIVE_BIT_POLY_SIZE*FOUR_BIT_POLY_SIZE*SOUND_2_MULTIPLE dc.l FIVE_BIT_POLY_SIZE*FOUR_BIT_POLY_SIZE*SOUND_3_MULTIPLE dc.l SOUND_4_MULTIPLE dc.l SOUND_4_MULTIPLE dc.l 31*SOUND_6_MULTIPLE dc.l FIVE_BIT_POLY_SIZE*SOUND_7_MULTIPLE dc.l NINE_BIT_POLY_SIZE*SOUND_8_MULTIPLE dc.l FIVE_BIT_POLY_SIZE*SOUND_9_MULTIPLE dc.l 31*SOUND_6_MULTIPLE dc.l SOUND_0_MULTIPLE dc.l SLOW_PURE_SIZE*SOUND_12_MULTIPLE dc.l SLOW_PURE_SIZE*SOUND_12_MULTIPLE dc.l 93*SOUND_14_MULTIPLE dc.l FIVE_BIT_POLY_SIZE*3*SOUND_15_MULTIPLE period_table: dc.w 124 dc.w SOUND_PERIOD*2 dc.w SOUND_PERIOD*3 dc.w SOUND_PERIOD*4 dc.w SOUND_PERIOD*5 dc.w SOUND_PERIOD*6 dc.w SOUND_PERIOD*7 dc.w SOUND_PERIOD*8 dc.w SOUND_PERIOD*9 dc.w SOUND_PERIOD*10 dc.w SOUND_PERIOD*11 dc.w SOUND_PERIOD*12 dc.w SOUND_PERIOD*13 dc.w SOUND_PERIOD*14 dc.w SOUND_PERIOD*15 dc.w SOUND_PERIOD*16 dc.w SOUND_PERIOD*17 dc.w SOUND_PERIOD*18 dc.w SOUND_PERIOD*19 dc.w SOUND_PERIOD*20 dc.w SOUND_PERIOD*21 dc.w SOUND_PERIOD*22 dc.w SOUND_PERIOD*23 dc.w SOUND_PERIOD*24 dc.w SOUND_PERIOD*25 dc.w SOUND_PERIOD*26 dc.w SOUND_PERIOD*27 dc.w SOUND_PERIOD*28 dc.w SOUND_PERIOD*29 dc.w SOUND_PERIOD*30 dc.w SOUND_PERIOD*31 dc.w SOUND_PERIOD*32 cnop 0,4 screen_req_tags: dc.l ASLSM_TitleText,0 dc.l ASLSM_NegativeText,screen_req_cancel_text dc.l ASLSM_PropertyFlags,DIPF_IS_DBUFFER dc.l ASLSM_PropertyMask,DIPF_IS_DBUFFER|DIPF_IS_HAM|DIPF_IS_DUALPF dc.l ASLSM_MinWidth,A2600_TV_WIDTH*X_MAG dc.l ASLSM_MinHeight,0 dc.l ASLSM_MinDepth,SCREEN_DEPTH dc.l ASLSM_MaxDepth,SCREEN_DEPTH dc.l TAG_END,0 screen_req_cancel_text: dc.b "Quit",0 hex_digit_table: dc.b '0','1','2','3','4','5','6','7' dc.b '8','9','A','B','C','D','E','F' end_of_library: end