0000000f EDGEL 00000018 EDGER 00000015 EDGEB 00000005 MOVEINC 00000006 DANGER 0000013a COPYR 00000021 NXTPCX 0000000b NXTPCY 00000004 LVLROW 00000002 LVLCOL 0000023e LVLLOC 00000007 LINROW 00000002 LINCOL 0000027a LINLOC 00000004 NXTROW 0000000f NXTCOL 0000024b NXTLOC 00000020 VBLANK 00000021 COLSTK 00000028 CS0 00000029 CS1 0000002a CS2 0000002b CS3 0000002c CB 00000100 ISRVEC 00000137 TMPPC 00000137 TMPPC.C 00000138 TMPPC.X 00000139 TMPPC.Y 0000013a TMPPC.N 0000013b CURPC 0000013b CURPC.C 0000013c CURPC.X 0000013d CURPC.Y 0000013e CURPC.N 00000140 PXQ_L0 00000141 PXQ_L1 00000142 PXQ_XY 00000170 VOLSV 00000173 PAUSED 000001a0 OVRFLO 000001a1 WASDOWN 000001a2 WASHAND 000001a8 SLEVEL 000001a9 LEVEL 000001aa SFXPRIO 000001ab SCRPOS 000001ac SCRDIG 000001ad SHOWNXT 000001ae NXTPC 000001af REPEAT 000001b0 LHAND 000001b1 LHKPD 000001b2 MUTE 000001b3 CSAVE 000001c0 TSKDQ 000001e0 XSAVE 000001e1 YSAVE 000001eb DIDNXT 000001ec HEIGHT 000001ed TSKACT 000001ee TSKQHD 000001ef TSKQTL 000001f0 PSG0 000001fe CTRL0 000001ff CTRL1 00000004 MAXTSK 00000320 TSKQ 00000330 TSKTBL 00000340 SNDSTRM 00000348 PREVBL 0000034a HANDFN 0000034b SCRCOL 0000034c WTIMER 0000034d REGSV 00000352 PSCORL 00000353 PSCORH 00000354 DSCORL 00000355 DSCORH 00000356 LINES 00000358 MSCORE 0000035d TMP 0000035e RANDLO 0000035f RANDHI 00000333 SPEED 00003000 GROM 00003800 GRAM 00005000 ROMHDR 00005030 START 0000610f T1TLE 00005014 SNDTBL 00005014 SNDTBL.bip 00005ceb BIP 00005016 SNDTBL.byump 00005cf2 BYUMP 00005018 SNDTBL.bomb 00005cc1 BOMB 0000501a SNDTBL.bomb4 00005d0b BOMB4 0000501c SNDTBL.boom2 00005ce0 BOOM2 0000501e SNDTBL.ding3 00005cff DING3 00005020 SNDTBL.title 00005d44 NUTMARCH 00005022 SNDTBL.game 0000631a CHINDNCE 00005024 SNDTBL.over 00006d9c BEHAPPY 00005026 SNDTBL.silence 00005cdb SILENCE 00000000 FXBIP 00000004 FXBOMB 00000006 FXBOMB4 00000008 FXBOOM2 0000000a FXDING3 00000002 FXBYUMP 0000000c M_TITLE 0000000e M_GAME 00000010 M_OVER 00000012 FX_OFF 00005028 TITLE 00005bd5 FILLZERO 0000505f INIT 00005057 @@spin 0000505e STUB 0000506b INIT.randok 000050cb MAINISR 00005235 DOFACE 00005086 INIT.gromcopy 000050b1 LOADFONT 00006e77 FONT 00005090 INIT.loop 00005714 TITLESCREEN 00005180 MAINLOOP 000050a9 INIT.soundtest 000057a8 INGAME 0000597b GAMEOVER 0000587e SOUNDTEST 000050b6 LOADFONT.gramlo 000050ca LOADFONT.gramdo 000050c1 LOADFONT.charlo 000050d0 MAINISR.rl0 00005bdb SNDPRIO 00005bf0 DOSNDSTREAM 000050e9 MAINISR.slowmus 0000534a DRAINPXQ 00005133 MAINISR.notasks 000050f9 MAINISR.taskloo 00005127 MAINISR.nexttas 0000510a MAINISR.noreini 0000510d MAINISR.q 0000512e MAINISR.overflo 00005133 MAINISR.wtimer 0000513a MAINISR.expired 00005145 MAINISR.pausing 00005171 MAINISR.waithan 0000516f MAINISR.waitpre 0000517c MAINISR.waitdon 00005173 MAINISR.waitloo 00005187 MAINLOOP.loop 000051a0 MAINLOOP.bktsk 00005abc NEXTRAND 000059f4 SCANHAND 0000cf00 EC_LOC 00000069 EC_MAG 0000cf01 EC_POLL 000051b2 QTASK 000051c9 QTASK.overflow 000051d0 SCHEDEXIT 000051da STOPALLTASKS 000051d9 SCHEDEXIT.exit 000051ee STARTTASK 000051fd STOPTASK 00005204 RETRIGGERTASK 00005209 RETRIGGERTASK.c 0000520d WAIT 00005211 WAIT.loop 00005216 SLEEP 00005216 SPAWN 0000522b SLEEP.wake 0000527a DOFACE.loadface 00005bd6 FILLMEM 00006f82 FACE 00005251 DOFACE.f_oloop 00005253 DOFACE.f_iloop 00005bd1 DRAWSTRING3 0000528b DOFACE.shunt 00006ee0 FACEFONT 0000528e MSKTBL 00005292 CLRTBL 0000529a PIXCALC 000052ab PUTPIXEL 000052b0 PUTPIXELR 000052bb PIXELCLIP 000052cb PIXELCLIP.offsc 000052cd GETPIXELS 000052ce GETPIXELS.chain 000052f3 GETPIXEL 000052da PUTPIXELS 000052db PUTPIXELS.chain 000052eb GETPIXELSC 000052f8 GETPIXELR 0000530a PUTPIXELSCQ 0000533b PUTPIXELSCQ.ins 00005327 PUTPIXELSCQ.che 00005321 PUTPIXELSCQ.dra 0000533c PUTPIXELSCQ.ins 0000532b PUTPIXELSCQ.not 0000532c PUTPIXELSCQ.not 0000532f PUTPIXELSCQ.rlo 00005346 PUTPIXELSCQ.sty 00005345 PUTPIXELSCQ.stx 0000536d DRAINPXQ.leave 00005359 DRAINPXQ.pixloo 0000536f COMMITPXQ 0000537a COMMITPXQ.leave 0000537c PIECE 00000000 PIECE.up0 00000002 PIECE.dn0 00000001 PIECE.lf0 00000003 PIECE.rt0 00000000 PIECE.up1 00000008 PIECE.dn1 00000004 PIECE.lf1 0000000c PIECE.rt1 00000000 PIECE.up2 00000020 PIECE.dn2 00000010 PIECE.lf2 00000030 PIECE.rt2 00000000 PIECE.up3 00000080 PIECE.dn3 00000040 PIECE.lf3 000000c0 PIECE.rt3 00000200 PIECE.dn4 00000100 PIECE.lf4 00000300 PIECE.rt4 0000537c PIECE.p0r0 0000537d PIECE.p0r1 0000537e PIECE.p0r2 0000537f PIECE.p0r3 00005380 PIECE.p1r0 00005381 PIECE.p1r1 00005382 PIECE.p1r2 00005383 PIECE.p1r3 00005384 PIECE.p2r0 00005385 PIECE.p2r1 00005386 PIECE.p2r2 00005387 PIECE.p2r3 00005388 PIECE.p3r0 00005389 PIECE.p3r1 0000538a PIECE.p3r2 0000538b PIECE.p3r3 0000538c PIECE.p4r0 0000538d PIECE.p4r1 0000538e PIECE.p4r2 0000538f PIECE.p4r3 00005390 PIECE.p5r0 00005391 PIECE.p5r1 00005392 PIECE.p5r2 00005393 PIECE.p5r3 00005394 PIECE.p6r0 00005395 PIECE.p6r1 00005396 PIECE.p6r2 00005397 PIECE.p6r3 00005398 PUTPIECEREC 00005399 PUTPIECEREC.NC 0000539d GETPIECEREC 0000539e GETPIECEREC.NC 000053a9 DRAWPIECE 00000130 DRAWPIECE.colsv 00000131 DRAWPIECE.pvxsv 00000132 DRAWPIECE.pvysv 00000133 DRAWPIECE.pnrsv 00000134 DRAWPIECE.pcwsv 00000135 DRAWPIECE.cntsv 00000136 DRAWPIECE.miny 000053ac TESTPIECE 000053ba DRAWPIECE.loop 000053c9 DRAWPIECE.xaxis 000053ca DRAWPIECE.cont 000053e7 DRAWPIECE.draw 000053d3 DRAWPIECE.test 000053f9 DRAWPIECE.notok 000053ea DRAWPIECE.pixel 00005402 GETPIECECOLOR 00005409 GETPIECECOLOR.c 00005410 PICKPIECE 00005411 PICKPIECE.chain 00005411 PICKPIECE.randl 00005abe NEXTRANDX 000056ac NEXTCLEAR 0000542f PICKPIECE.nosho 000056a8 NEXTSHOW 00005441 CLEARWELL 000001e2 CLEARWELL.bot 00005445 CLEARWELL.welll 00005471 CLEARWELL.retur 0000544b CLEARWELL.randl 00005466 CLEARWELL.nukei 00005461 CLEARWELL.filli 0000547a NUKELINE 00005526 DOSCORE.nukeit 00005472 SCOREDROP 000001e2 SCOREDROP.trip 000001e3 SCOREDROP.full 00005482 SCOREDROP.dosco 00005491 SCOREDROP.nuke 00005486 SCOREDROP.score 000054a2 SCOREDROP.sloop 0000549a SCOREDROP.floop 000054a8 SCOREDROP.sdone 000054b4 SCOREDROP.retur 00005c67 PLAY.sfxp 000054b6 SCORETABLE 000054ba DOSCORE 000001e2 DOSCORE.bot 000001e3 DOSCORE.top 000001e6 DOSCORE.clr 000054c1 DOSCORE.rowok 0000550c DOSCORE.done 000054dc DOSCORE.hmm 000054e5 DOSCORE.scorelo 000054ee DOSCORE.notnuke 000054f9 DOSCORE.scan 00005514 DOSCORE.collaps 0000558b UPDATESTATS 0000552c DOSCORE.nosfx 0000552e DOSCORE.xloop 00005533 DOSCORE.yloop 00005559 UPDATESCORE 00005566 UPDATESCORE.nex 00005570 UPDATESCORE.doi 0000556b UPDATESCORE.uho 0000556f UPDATESCORE.ret 0000557f UPDATESCORE.dis 0000557c UPDATESCORE.add 00005b49 DEC32B 000055a9 UPDATESTATS.ini 000055c3 UPDATESTATS.sam 000055a2 UPDATESTATS.nex 000055ad UPDATESTATS.ski 000055b3 UPDATESTATS.spe 000055ca SPDTBL 00005afc DEC16A 000055de MARQUEE 000055ea MARQUEE.loop 000055ef MARQUEE.ok 000055f8 ANIDROP 00005600 ANIDROP.active 00005605 MUTETOGGLE 0000561f MUTETOGGLE.unmu 00005614 MUTETOGGLE.notc 00005619 MUTETOGGLE.notb 0000561e MUTETOGGLE.nota 00005624 ROTPIECE_CW 00005626 ROTPIECE_CCW 00005630 GRAVITY 00005634 MVPIECE 000056a7 GRAVITY.return 0000565f GRAVITY.check 0000564e GRAVITY.not_lef 00005658 GRAVITY.is_righ 0000565a GRAVITY.not_dow 0000569f GRAVITY.cantmov 0000569c GRAVITY.nothand 00005c66 PLAY.sfx 0000569c GRAVITY.notdown 000056d2 PLACEPIECE 000056b7 NEXTSHOW.clear 000056c3 NEXTTOGGLE 000056cd NEXTTOGGLE.turn 000056c8 NEXTTOGGLE.turn 000056de PLACEPIECE.acti 000056f8 PLACEPIECE.notg 000056fe PLACEPIECE.nott 00005708 PLACEPIECE.didn 00005bd2 DRAWSTRING4 00005bb6 DRAWSTRING5 00005c69 PLAY.mus 00005795 GAMEHAND 00005795 GAMEHAND.kp0 00005796 GAMEHAND.kp1 00005797 GAMEHAND.kp2 00005798 GAMEHAND.kp3 00005799 GAMEHAND.kp4 0000579a GAMEHAND.kp5 0000579b GAMEHAND.kp6 0000579c GAMEHAND.kp7 0000579d GAMEHAND.kp8 0000579e GAMEHAND.kp9 0000579f GAMEHAND.kpC 000057a0 GAMEHAND.kpE 000057a1 GAMEHAND.dsU 000057a2 GAMEHAND.dsL 000057a3 GAMEHAND.dsR 000057a4 GAMEHAND.dsD 000057a5 GAMEHAND.acT 000057a6 GAMEHAND.acL 000057a7 GAMEHAND.acR 000057bd INGAME.csloop 000057ce INGAME.botloop 000057dc INGAME.npxloop 000057ed INGAME.npyloop 00005864 TLA 0000586b TESTHAND 0000586b TESTHAND.kp0 0000586c TESTHAND.kp1 0000596a SOUNDTEST.sfx 0000586d TESTHAND.kp2 0000586e TESTHAND.kp3 0000586f TESTHAND.kp4 00005870 TESTHAND.kp5 00005871 TESTHAND.kp6 00005872 TESTHAND.kp7 0000596f SOUNDTEST.mus 00005873 TESTHAND.kp8 00005874 TESTHAND.kp9 00005875 TESTHAND.kpC 00005960 SOUNDTEST.soff 00005876 TESTHAND.kpE 00005966 SOUNDTEST.moff 00005877 TESTHAND.dsU 00005878 TESTHAND.dsL 00005879 TESTHAND.dsR 0000587a TESTHAND.dsD 0000587b TESTHAND.acT 00005974 SOUNDTEST.spd 0000587c TESTHAND.acL 0000587d TESTHAND.acR 00005bbd DRAWSTRING2 00005c63 PLAY.sfxn 00005c61 PLAY.musn 00005991 GAMEOVER.spin 000059be SETLEVEL 000059c7 SETLEVEL.got_le 000059c5 SETLEVEL.defaul 000059cb HANDTASK 000059d2 KEYREPEAT 000059e1 PADTBL 000059ed ACTTBL 000059f0 DSCTBL 00000005 DBOUT 00000078 DBIN 00000060 DB80 000059f4 SCANHAND.starto 000059f9 SCANHAND.dbnoth 00005abb SCANHAND.nothin 00005a0b SCANHAND.input 00005ab4 SCANHAND.noinpu 00005a10 SCANHAND.deboun 00005a12 SCANHAND.oloop 00005a19 SCANHAND.iloop 00005a21 SCANHAND.notsam 00005a2d SCANHAND.ok 00005a67 SCANHAND.nopad 00005a3b SCANHAND.kloop 00005a43 SCANHAND.gotpad 00005a47 SCANHAND.kpdloo 00005a50 SCANHAND.kpnots 00005a62 SCANHAND.dispat 00005a58 SCANHAND.notrep 00005a61 SCANHAND.repeat 00005a94 SCANHAND.noacti 00005a6f SCANHAND.hmm 00005a82 SCANHAND.actloo 00005a8a SCANHAND.gotact 00005a93 SCANHAND.notact 00005a9d SCANHAND.disclo 00005aa6 SCANHAND.gotdis 00005ac2 NEXTRAND.loop 00005aca NEXTRAND.nocarr 00005ad2 POW10 00005ad2 POW10_9 00005ad4 POW10_8 00005ad6 POW10_7 00005ad8 POW10_6 00005ada POW10_5 00005adc POW10_4 00005ade POW10_3 00005ae0 POW10_2 00005ae2 POW10_1 00005ae4 POW10_0 00005ae6 NPW10 00005ae6 NPW10_9 00005ae8 NPW10_8 00005aea NPW10_7 00005aec NPW10_6 00005aee NPW10_5 00005af0 NPW10_4 00005af2 NPW10_3 00005af4 NPW10_2 00005af6 NPW10_1 00005af8 NPW10_0 00005afa DEC16 00000110 DEC16.so 00000111 DEC16.fw 00005aff DEC16B 00005b00 DEC16C 00005b0b DEC16.digitlp 00005b0e DEC16.divloop 00005b19 DEC16.disp 00005b24 DEC16.blank 00005b2e DEC16.ok 00005b3b DEC16.iter 00005b33 DEC16.drawit 00005b43 DEC32 00000110 DEC32.so 00000111 DEC32.fw 0000035d DEC32.fmt 00005b45 DEC32A 00005b54 DEC32.digitlp 00005b57 DEC32.divlp 00005b58 DEC32.divlpb 00005b79 DEC32.nxtdigit 00005b77 DEC32.donemult 00005b6f DEC32.mult 00005b94 DEC32.noextra 00005b97 DEC32Z 00005ba6 DEC32Z.dozero 00005ba1 DEC16Z 00005bb5 DEC32Z.nodisp 00005bac DEC32Z.loop 00005bb6 DRAWSTRING 00005bb9 DRAWSTRING1 00005bc1 DRAWSTRING.tloo 00005be4 SNDPRIO.inactiv 00005bed SNDPRIO.notmute 00005bfb DOSNDSTREAM.ina 00005bfd DOSNDSTREAM.nex 00005bfc DOSNDSTREAM.bac 00005c0d DOSNDSTREAM.not 00005c13 DOSNDSTREAM.pre 00005c1d DOSNDSTREAM.not 00005c4f DOSNDSTREAM.zer 00005c28 DOSNDSTREAM.loo 00005c46 DOSNDSTREAM.nor 00005c2a DOSNDSTREAM.rea 00005c38 DOSNDSTREAM.fin 00005c40 DOSNDSTREAM.nol 00005c44 DOSNDSTREAM.was 00005c45 DOSNDSTREAM.ret 00005c51 DOSNDSTREAM.zlo 00005c54 DOSNDSTREAM.noz 00005c5b DOSNDSTREAM.zli 00005c61 PLAY 00005c6b PLAY.go2 00005c6a PLAY.go 00005c75 PLAY.notmusic 00005cae PLAY.notbusy 00005c84 PLAY.music 00005cbe PLAY.noplay 00005c82 PLAY.play 00005c92 PLAY.no_chan_en 00005c9b PLAY.no_vol_a 00005ca4 PLAY.no_vol_b 00005cac PLAY.no_vol_c 00005cb3 PLAY.dorecord 00005cd6 BOOM 0000610c NUTMARCH.loop 00000320 ball 00000320 ball.x 00000321 ball.y 00000322 ball.xv 00000323 ball.yv 00000120 pad0 00000120 pad0.y 00000121 pad0.ai 00000122 pad1 00000122 pad1.y 00000123 pad1.ai 0000035e rnd 0000035e rnd.lo 0000035f rnd.hi 00000113 BIPT 00006117 pong 00000110 pong.scor0 00000111 pong.scor1 00000112 pong.start 00000350 pong.wait 00006125 pong.ok 0000630a ISRSPIN 0000612f pong.init 0000615a pong.pfloop 0000619a pong.mainisr 00006289 pong.padpos 000061bd pong.notwait 000061b0 pong.clearscore 0000622d pong.done 0000623b pong.badball 000061df pong.not_bounce 000061e3 pong.did_bounce 000061eb pong.not_bounce 000062e1 _BIP 000061f6 pong.check_left 000061fa pong.check 00006202 pong.maybe_hit 00006225 pong.not_hit 0000620b pong.upper_half 00006211 pong.hit 00006222 pong.bip_lo 00006238 pong.bip_skip 00006253 pong.doscore 00006278 pong.fix 0000625b pong.p1score 000062ef _SCORE 0000626c pong.again 000062b4 pong.nopadpress 000062a4 pong.notpaddown 0000629e pong.domoveup 000062ad pong.padok 000062a3 pong.badpadpos 000062a3 pong.padposdone 000062a8 pong.domovedown 000062d4 pong.moveup 000062da pong.movedown 000062fa _SCORE.notgameo 00006303 _SCORE.notten 00006314 ISRSPIN.spinloo 00006317 ISRSPIN.loop 00006853 CHINDNCE.loop 00006856 NUT3 00006d99 CHINDNCE.loop2 ;;==========================================================================;; ;; Joe Zbiciak's 4-TRIS, A "Falling Tetrominoes" Game for Intellivision. ;; ;; Copyright 2000, Joe Zbiciak, im14u2c@primenet.com. ;; ;; http://www.primenet.com/~im14u2c/intv/ ;; ;;==========================================================================;; ;* ======================================================================== *; ;* 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., 675 Mass Ave, Cambridge, MA 02139, USA. *; ;* ======================================================================== *; ;* Copyright (c) 2000, Joseph Zbiciak *; ;* ======================================================================== *; ROMW 16 ; Just for the heck of it. 0x5000 ORG $5000 ; Standard Mattel cartridge memory map ;------------------------------------------------------------------------------ ; Magic Constants ;------------------------------------------------------------------------------ 0xf EDGEL EQU 15 ; Left edge column 0x18 EDGER EQU 24 ; Right edge column 0x15 EDGEB EQU 21 ; Bottom edge row 0x5 MOVEINC EQU 5 ; Per-downward-move score increment 0x6 DANGER EQU 6 ; Trigger point at which music goes 2x 0x13a COPYR EQU $13A ; Character # for Copyright circle-C 0x21 NXTPCX EQU 33 ; X coord where next piece is shown 0xb NXTPCY EQU 11 ; Y coord where next piece is shown 0x4 LVLROW EQU 4 ; Row 'Level' banner is displayed on 0x2 LVLCOL EQU 2 ; Column 'Level' banner is displayed on 0x23e LVLLOC EQU $200 + 20*(LVLROW - 1) + LVLCOL 0x7 LINROW EQU 7 ; Row 'Lines' banner is displayed on 0x2 LINCOL EQU 2 ; Column 'Lines' banner is displayed on 0x27a LINLOC EQU $200 + 20*(LINROW - 1) + LINCOL 0x4 NXTROW EQU (NXTPCY - 3)/2 ; Row 'Next' banner is displayed on 0xf NXTCOL EQU (NXTPCX - 3)/2 ; Column 'Next' banner is displayed on 0x24b NXTLOC EQU $200 + 20*(NXTROW - 1) + NXTCOL ;------------------------------------------------------------------------------ ; Magic memory locations ;------------------------------------------------------------------------------ 0x20 VBLANK EQU $20 ; Vertical-blank Handshake 0x21 COLSTK EQU $21 ; Color-stack/FGBG switch 0x28 CS0 EQU $28 ; Color Stack 0 0x29 CS1 EQU $29 ; Color Stack 1 0x2a CS2 EQU $2A ; Color Stack 2 0x2b CS3 EQU $2B ; Color Stack 3 0x2c CB EQU $2C ; Color for border 0x100 ISRVEC EQU $100 ; ISR jump vector ; $130 .. $136 ; Save area used by DRAWPIECE/TESTPIECE 0x137 TMPPC STRUCT $137 ; Temporary storage 0x137 @@C EQU $ + 0 ; (R0) Color of current piece UNUSED 0x138 @@X EQU $ + 1 ; (R1) Pivot X coordinate for current piece 0x139 @@Y EQU $ + 2 ; (R2) Pivot Y coordinate for current piece 0x13a @@N EQU $ + 3 ; (R3) Piece number for current piece. ENDS 0x13b CURPC STRUCT $13B ; Current active piece 0x13b @@C EQU $ + 0 ; (R0) Color of current piece 0x13c @@X EQU $ + 1 ; (R1) Pivot X coordinate for current piece 0x13d @@Y EQU $ + 2 ; (R2) Pivot Y coordinate for current piece 0x13e @@N EQU $ + 3 ; (R3) Piece number for current piece. ENDS 0x140 PXQ_L0 EQU $140 ; Putpixel Queue length -- not committed 0x141 PXQ_L1 EQU $141 ; Putpixel Queue length -- committed 0x142 PXQ_XY EQU $142 ;..$161 ; Putpixel Queue XY data, interleaved. 0x170 VOLSV EQU $170 ;..$172 ; Volume save-area during pause 0x173 PAUSED EQU $173 ; Flag saying we paused. 0x1a0 OVRFLO EQU $1A0 ; Number of overflows observed 0x1a1 WASDOWN EQU $1A1 ; Flag: This movement was 'down' 0x1a2 WASHAND EQU $1A2 ; Flag: This movement was 'hand' 0x1a8 SLEVEL EQU $1A8 ; Current game level number 0x1a9 LEVEL EQU $1A9 ; Current game level number 0x1aa SFXPRIO EQU $1AA ; Priority of currently playing sound 0x1ab SCRPOS EQU $1AB ; Position onscreen to display the score 0x1ac SCRDIG EQU $1AC ; 10 - Number of digits to display in score 0x1ad SHOWNXT EQU $1AD ; Show next piece 0x1ae NXTPC EQU $1AE ; Next Piece 0x1af REPEAT EQU $1AF ; Flag: Set to keypress we're repeating 0x1b0 LHAND EQU $1B0 ; Last hand-controller input 0x1b1 LHKPD EQU $1B1 ; Last input was pad if non-zero 0x1b2 MUTE EQU $1B2 ; Last input was pad if non-zero 0x1b3 CSAVE EQU $1B3 ; Global 'c' save area 0x1c0 TSKDQ EQU $1C0 ;..$1DF ; $1C0..$1DF: Task data queue 0x1e0 XSAVE EQU $1E0 ; Global 'x' save area 0x1e1 YSAVE EQU $1E1 ; Global 'y' save area ;$1E2 .. $1E6, reserved 0x1eb DIDNXT EQU $1EB ; Next Piece was displayed some time this piece 0x1ec HEIGHT EQU $1EC ; Height of blocks in well. 0x1ed TSKACT EQU $1ED ; Number of highest numbered task + 1 0x1ee TSKQHD EQU $1EE ; Head pointer for task queue (0..15) 0x1ef TSKQTL EQU $1EF ; Tail pointer for task queue (0..15) 0x1f0 PSG0 EQU $1F0 ;..$1FD ; PSG base address 0x1fe CTRL0 EQU $1FE ; Right hand controller 0x1ff CTRL1 EQU $1FF ; Left hand controller 0x4 MAXTSK EQU 4 ; Right now allow 4 active tasks 0x320 TSKQ EQU $320 ;..$32F ; $320..$32F: Task queue 0x330 TSKTBL EQU $330 ;..$33F ; $330..$33F: Task table (four tasks) 0x340 SNDSTRM EQU $340 ;..$347 ; $340..$347: Sound stream table 0x348 PREVBL EQU $348 ; Pre-VBLANK routine address 0x34a HANDFN EQU $34A ; Keypad dispatch function table. 0x34b SCRCOL EQU $34B ; Color that score is displayed in 0x34c WTIMER EQU $34C ; Countdown timer for WAIT 0x34d REGSV EQU $34D ;..$351 ; $34D..$351: Register save area for SLEEP 0x352 PSCORL EQU $352 ; Player's score (lo 16 bits) 0x353 PSCORH EQU $353 ; Player's score (hi 16 bits) 0x354 DSCORL EQU $354 ; Displayed score (lo 16 bits) 0x355 DSCORH EQU $355 ; Displayed score (hi 16 bits) 0x356 LINES EQU $356 ; Number of lines cleared so far 0x358 MSCORE EQU $358 ; Total of per-move scores 0x35d TMP EQU $35D 0x35e RANDLO EQU $35E ; Low word of random number generator 0x35f RANDHI EQU $35F ; High word of random number generator 0x333 SPEED EQU TSKTBL + 3 ; Piece movement speed (IN TASK TABLE!) 0x3000 GROM EQU $3000 0x3800 GRAM EQU $3800 ;------------------------------------------------------------------------------ 0x5000 ROMHDR: 5000 0000 0000 WORD $0000 ; Movable object data (ignored) 5002 0001 0000 DECLE $01,$00 ; RTAB (ignored) 5004 0030 0050 WORD START ; Program start address (ignored) 5006 0000 0000 WORD $0000 ; Background graphics 5008 0002 0050 WORD ROMHDR + 2 ; Card table -- stored above in header. :-) 500a 000f 0061 WORD T1TLE ; Title string: '4-TRIS' 500c 03c0 DECLE $3C0 ; run title code, clicks off, INTY2 on, no ECS 500d 0000 DECLE $00 ; -> to STIC $32 500e 0000 DECLE $00 ; 0 = color stack, 1 = f/b mode 500f 0000 0000 0000 DECLE 0, 0, 0, 0 ; color stack elements 1 - 4 5012 0000 5013 0000 DECLE $00 ; border color ;------------------------------------------------------------------------------ ;;==========================================================================;; ;; SNDTBL ;; ;; Contains pointers and parameters for all sound effects and music. ;; ;;==========================================================================;; 0x5014 SNDTBL PROC 5014 5ceb 2744 @@bip DECLE BIP, $2744 ; Played when player moves a piece 5016 5cf2 2744 @@byump DECLE BYUMP, $2744 ; Played when the player places a piece 5018 5cc1 27cc @@bomb DECLE BOMB, $27CC ; Played when clearing a line 501a 5d0b 3fff @@bomb4 DECLE BOMB4, $3FFF ; Played when clearing FOUR lines 501c 5ce0 3fff @@boom2 DECLE BOOM2, $3FFF ; Played when well overflows 501e 5cff 35ee @@ding3 DECLE DING3, $35EE ; Played to signal changing level 5020 5d44 3fff @@title DECLE NUTMARCH, $3FFF ; Title screen music 5022 631a 3fff @@game DECLE CHINDNCE, $3FFF ; In-game music 5024 6d9c 3fff @@over DECLE BEHAPPY, $3FFF ; Game-over music 0x5026 @@silence 5026 5cdb 3fff DECLE SILENCE, $3FFF ; Silence! ENDP 0x0 FXBIP EQU SNDTBL.bip - SNDTBL 0x4 FXBOMB EQU SNDTBL.bomb - SNDTBL 0x6 FXBOMB4 EQU SNDTBL.bomb4 - SNDTBL 0x8 FXBOOM2 EQU SNDTBL.boom2 - SNDTBL 0xa FXDING3 EQU SNDTBL.ding3 - SNDTBL 0x2 FXBYUMP EQU SNDTBL.byump - SNDTBL 0xc M_TITLE EQU SNDTBL.title - SNDTBL 0xe M_GAME EQU SNDTBL.game - SNDTBL 0x10 M_OVER EQU SNDTBL.over - SNDTBL 0x12 FX_OFF EQU SNDTBL.silence - SNDTBL ;;==========================================================================;; ;; TITLE / START ;; ;; ;; ;; This contains the title string and the startup code. We pre-empt the ;; ;; EXEC's initialization sequence by setting the "Special Copyright" bit ;; ;; in location $500C. This causes the code at 'START' to run before the ;; ;; built-in title screen is completely displayed. ;; ;; ;; ;; The Startup code does very little. Mainly, it sets the Interrupt ;; ;; Service Routine vector to point to our _real_ initialization routine, ;; ;; INIT. This is done because we can only get to GRAM and STIC registers ;; ;; during the vertical retrace, and vertical retrace is signaled by an ;; ;; interrupt. (Actually, we can have access to GRAM/STIC for longer ;; ;; if we don't hit the STIC 'handshake' at location $20, but then the ;; ;; display blanks. During INIT, the display does blank briefly.) ;; ;;==========================================================================;; 5028 0064 002a 002d TITLE: BYTE 100, "*-TRIS", 0 ; Title: 4-TRIS, Copyright 2000 502b 0054 0052 0049 0053 0000 ; Intercept/preempt EXEC initialization and just do our own. ; We call no EXEC routines in this game. 0x5030 START: 5030 0282 01ff MVI $1FF, R2 5032 0382 01fe AND $1FE, R2 5034 01e4 CLRR R4 ; Prepare to zero all system RAM, PSG0,& STIC. 5035 02b9 0020 MVII #$20, R1 ; $00...$1F. (The STIC) 5037 0004 015a 03d5 JSRD R5, FILLZERO 503a 02fc 0008 ADDI #8, R4 ; $28...$32. (The rest of the STIC) 503c 02b9 000b MVII #11, R1 503e 0004 0158 03d5 CALL FILLZERO 5041 02bc 00f0 MVII #$F0, R4 ; $F0...$35D. We spare the rand seed values 5043 02b9 026d MVII #$26D, R1 ; in $35E..$35F to add some randomness. 5045 0004 0158 03d5 CALL FILLZERO 5048 001a COMR R2 5049 0242 01b0 MVO R2, LHAND ; Set up initial hand-controller state 504b 02b8 505f MVII #INIT, R0 ; Our initialization routine 504d 02bc 0100 MVII #ISRVEC, R4 ; ISR vector 504f 0260 MVO@ R0, R4 ; Write low half 5050 0040 SWAP R0 ; 5051 0260 MVO@ R0, R4 ; Write high half 5052 0280 035e MVI RANDLO, R0 ; Get whatever garbage data is in memory in the 5054 0281 035f MVI RANDHI, R1 ; random number generator fields 5056 00bd MOVR PC, R5 ; Loop starting at the next instruction. 0x5057 @@spin: 5057 0008 INCR R0 ; Seed random number generator while 5058 0011 DECR R1 ; we wait for our first interrupt. 5059 0240 035e MVO R0, RANDLO 505b 0241 035f MVO R1, RANDHI 505d 0002 EIS ; This falls through to STUB which causes ; our loop (saves a couple DECLEs.) ;;==========================================================================;; ;; STUB ;; ;; Null routine used in dispatchers where no behavior is defined/desired. ;; ;;==========================================================================;; 505e 00af STUB: JR R5 ; Stub routine ;;==========================================================================;; ;; INIT ;; ;; Initializes the ISR, etc. Gets everything ready to run. ;; ;; This is called via the ISR dispatcher, so it's safe to bang GRAM from ;; ;; here, too. ;; ;; ;; ;; -- Zero out memory to get started ;; ;; -- Set up variables that need to be set up here and there ;; ;; -- Set up GRAM image ;; ;; -- Drop into the main game state-machine. ;; ;;==========================================================================;; 0x505f INIT: PROC 505f 0003 DIS 5060 02be 02f0 MVII #$2F0, R6 ; Reset the stack pointer 5062 0281 0021 MVI COLSTK, R1 ; Force display to color-stack mode ; Make sure random number generator is non-zero. 5064 00b8 MOVR PC, R0 ; The PC is guaranteed to be non-zero. 5065 03c0 035e XOR RANDLO, R0 5067 0204 0002 BEQ @@randok ; If the XOR result is zero, we're ok, 5069 0240 035e MVO R0, RANDLO ; otherwise make RANDLO non-zero. 0x506b @@randok: ; Stub out all of the task hooks 506b 02b8 505e MVII #STUB, R0 ; Prepare to stub out some hooks. 506d 0240 0348 MVO R0, PREVBL ; Initial pre-VBL task is NULL 506f 02b8 50cb MVII #MAINISR, R0 ; Point ISR vector to our ISR 5071 0240 0100 MVO R0, ISRVEC ; store low half of ISR vector 5073 0040 SWAP R0 ; 5074 0240 0101 MVO R0, ISRVEC+1 ; store high half of ISR vector ; Do the face? 5076 02b8 00d9 MVII #$D9, R0 5078 0340 01fe CMP $1FE, R0 507a 0204 01b9 BEQ DOFACE 507c 0340 01ff CMP $1FF, R0 507e 0204 01b5 BEQ DOFACE ; Default the GRAM image to be same as GROM. 5080 02bd 3000 MVII #GROM, R5 ; Point R5 at GROM 5082 02bc 3800 MVII #GRAM, R4 ; Point R4 at GRAM 5084 02b8 0200 MVII #$200, R0 0x5086 @@gromcopy: 5086 02a9 MVI@ R5, R1 5087 0261 MVO@ R1, R4 5088 0010 DECR R0 5089 022c 0004 BNEQ @@gromcopy ; Copy our GRAM font into GRAM overtop of default. 508b 0004 0150 00b1 CALL LOADFONT 508e 6e77 DECLE FONT ; Ok, everything's ready to roll now. 508f 0002 EIS ;;==================================================================;; ;; Game phases: ;; ;; -- Title screen ;; ;; -- (optional) Sound Test ;; ;; -- In Game ;; ;; -- Game over ;; ;; ;; ;; The INIT code cycles between these gae phases by first ;; ;; calling the subroutine which sets up the tasks for a given ;; ;; game phase, and then calling the main event loop which ;; ;; runs the game. This assumes that all tasks are stopped when ;; ;; the MAINLOOP exits. Calling SCHEDEXIT accomplishes a clean ;; ;; exit from MAINLOOP by scheduling an exit while stopping all ;; ;; other tasks. (Neat, eh?) ;; ;;==================================================================;; 0x5090 @@loop: 5090 0004 0154 0314 CALL TITLESCREEN ; Set up 'Title Screen' 5093 0004 0150 0180 CALL MAINLOOP ; Do title screen. 5096 0280 01a8 MVI SLEVEL, R0 ; If starting level == 0, do 'Sound Test' 5098 0080 TSTR R0 5099 0204 000e BEQ @@soundtest 509b 0004 0154 03a8 CALL INGAME ; Set up 'In Game' 509e 0004 0150 0180 CALL MAINLOOP ; Do the Game. 50a1 0004 0158 017b CALL GAMEOVER ; Set up the 'Game Over' sequence. 50a4 0004 0150 0180 CALL MAINLOOP ; Let it run. 50a7 0220 0018 B @@loop ; Start over at the title screen. 0x50a9 @@soundtest: 50a9 0004 0158 007e CALL SOUNDTEST ; Sound-test requested. Set that up. 50ac 0004 0150 0180 CALL MAINLOOP ; Run the sound-test. 50af 0220 0020 B @@loop ; Go back to title screen when done. ENDP ;;==========================================================================;; ;; LOADFONT -- Load a compressed FONT into GRAM. ;; ;; ;; ;; Note: This should be called only when the STIC is already in CPU- ;; ;; controlled mode, such as from an interrupt handler. Loading a large ;; ;; font may cause the screen to blank for one or more frames. ;; ;; ;; ;; Font data is broken up into spans of characters that are copied ;; ;; into GRAM. Each span is defined as follows. ;; ;; ;; ;; Span Header: 2 Decles ;; ;; DECLE Skip Length (in bytes of GRAM memory) ;; ;; DECLE Span Length (in bytes of GRAM memory) ;; ;; Span Data -- up to Span Length Decles. ;; ;; ;; ;; Span Data is run-length encoded using the upper two bits of the ;; ;; decle to specify the run length. Valid run lengths are 0..3, ;; ;; with 0 meaning "just copy this byte to the GRAM", and 3 meaning ;; ;; "copy this byte to GRAM and make three more copies in the locations ;; ;; afterwards". To see what I mean, look at the font data in ;; ;; "font.asm". ;; ;; ;; ;; The run length encoding does not change the value used for ;; ;; 'span length'. The span length is always given in terms of ;; ;; # of GRAM locations, and not number of decles in the FONT data. ;; ;; ;; ;; The font is terminated with a span of length 0. ;; ;; ;; ;; INPUTS: ;; ;; R5 -- Points to word (1 decle in 16-bit ROM) containing ptr to font ;; ;; info. Code returns after this word. ;; ;; ;; ;; OUTPUTS: ;; ;; R0, R1, R4, R5 trashed. ;; ;; GRAM is updated according to the font specification. ;; ;; ;; ;;==========================================================================;; 0x50b1 LOADFONT PROC 50b1 02a8 MVI@ R5, R0 50b2 0275 PSHR R5 50b3 0085 MOVR R0, R5 50b4 02bc 3800 MVII #GRAM, R4 ; Point R4 at GRAM 0x50b6 @@gramloop: 50b6 02a8 MVI@ R5, R0 ; Get skip & span len. (in GRAM bytes) 50b7 0080 TSTR R0 ; Quit if skip/span == 0. 50b8 0204 0010 BEQ @@gramdone 50ba 0081 MOVR R0, R1 50bb 03b8 07f8 ANDI #$7F8, R0 ; Extract span length. 50bd 01c1 XORR R0, R1 ; Clear away span bits from word 50be 0041 SWAP R1 ; Extrack skip value. 50bf 00cc ADDR R1, R4 ; Skip our output pointer. 50c0 0060 SLR R0, 1 ; Divide count by 2. 0x50c1 @@charloop: 50c1 02a9 MVI@ R5, R1 ; Get two bytes 50c2 0261 MVO@ R1, R4 ; Put the first byte 50c3 0041 SWAP R1 ; Put the other byte into position 50c4 0261 MVO@ R1, R4 ; Put the second byte 50c5 0010 DECR R0 ; Sheesh, do I have to spell this out? 50c6 022c 0006 BNEQ @@charloop ; inner loop 50c8 0220 0013 B @@gramloop ; outer loop 0x50ca @@gramdone: 50ca 02b7 PULR PC ENDP ;;==========================================================================;; ;; MAINISR ;; ;; This is the main interrupt service routine. It has to perform the ;; ;; following tasks: ;; ;; ;; ;; -- Run any miscellaneous "pre-VBLANK" task requested by main program. ;; ;; -- Hit the vertical blank handshake to keep screen enabled. ;; ;; -- Update any active sound streams. ;; ;; -- Drain and pixels queued up in the Pixel Queue. ;; ;; -- Count down task timers and schedule tasks when timers expire. ;; ;; -- Count down the 'busy-wait' timer if it is set. ;; ;; -- Detect a "Pause" request and pause the game if needed. ;; ;; ;; ;; This particular program currently does not sequence GRAM at all after ;; ;; the initial bootup. Therefore, we can hit the VBLANK handshake almost ;; ;; immediately after entering the ISR. We do support a pre-VBLANK ;; ;; routine though for other purposes, such as setting color-stack regs. ;; ;; ;; ;; Our code does not rely on any EXEC routines at all, except the ISR ;; ;; dispatch routine which saves and restores all the registers. (On a ;; ;; real Intellivision, we have no choice. On an emulator, that routine ;; ;; can be replaced with a separate non-EXEC routine which performs a ;; ;; similar dispatch, if we want to distribute this program without an ;; ;; EXEC ROM image but with an emulator.) ;; ;; ;; ;;==========================================================================;; 0x50cb MAINISR PROC 50cb 0275 PSHR R5 ; Save return address ;; Call out to user-defined pre-VBLANK routine. ;; This routine should point to the stub if no routine is to ;; be called. (simplifies the code w/out really slowing it down.) 50cc 02bd 50d0 MVII #@@rl0, R5 ; Point to @@rl0 50ce 0287 0348 MVI PREVBL, PC ; Call subroutine 0x50d0 @@rl0: ;; Hit the VBLANK handshake now 50d0 0240 0020 MVO R0, $20 ; Allow STIC to display this frame. ;; Update sound streams. All sound streams update at 60Hz. ;; Stream #0 can update at "60Hz * 2" if double-speed mode is on. 50d2 0004 0158 03db CALL SNDPRIO ; Make sure music & sfx play nice ; Update music 50d5 0004 0158 03f0 CALL DOSNDSTREAM ; Update the sound stream 50d8 0340 DECLE SNDSTRM ; Point to the music stream ; Update sfx 50d9 0004 0158 03f0 CALL DOSNDSTREAM ; Update the sound stream 50dc 0344 DECLE SNDSTRM+4 ; Point to the sfx stream ; If well is too tall, play music fast. 50dd 02b8 0006 MVII #DANGER, R0 50df 0340 01ec CMP HEIGHT, R0 50e1 0205 0006 BLT @@slowmusic 50e3 02bc 0340 MVII #SNDSTRM, R4 50e5 0004 0158 03f0 CALL DOSNDSTREAM ; Update the sound stream 50e8 0340 DECLE SNDSTRM ; Point to the music stream 0x50e9 @@slowmusic: 50e9 02b9 035f MVII #RANDHI,R1 50eb 0282 0341 MVI SNDSTRM+1, R2 50ed 03ca XOR@ R1, R2 50ee 024a MVO@ R2, R1 ; Throw some bits into the random bucket ;; Drain any pixels that were queued and committed. 50ef 0004 0150 034a CALL DRAINPXQ ;; Count down task timers and schedule tasks. We have up to MAXTSK ;; active tasks at one time. We decrement all counters by two. ;; -- If the count is initially <= 0, the task is inactive and ;; is skipped. ;; -- If the count goes to zero, the task is triggered and its ;; count is reinitialized. ;; -- If the count goes negative, the task is triggered and its ;; count is not reinitialized. ;; This allows us to have one-shot and repeating tasks pretty ;; easily. Repeating tasks clear bit 0 of their period count, ;; and one-shot tasks set bit 0. ;; ;; When tasks are triggered, their procedure address is written ;; to the task queue which is drained by the non-ISR main task. ;; The task queue is a small circular buffer in 16-bit memory with ;; head and tail pointers in 8-bit memory. The circular buffer is ;; 16 entries large. I hope this is enough. Overflow can cause ;; strange effects. ;; ;; Task control table entry layout: ;; ;; Word 0: Function Ptr ;; Word 1: Instance data ;; Word 2: Current down-count ;; Word 3: Reinit count 50f2 0280 01ed MVI TSKACT, R0 ; Iterate over active tasks 50f4 0080 TSTR R0 50f5 0204 003c BEQ @@notasks 50f7 02bb 0332 MVII #TSKTBL+2, R3 ; Point to the task control table 0x50f9 @@taskloop: 50f9 0299 MVI@ R3, R1 ; Get tasks's current tick count 50fa 0089 TSTR R1 ; Is it <= 0? 50fb 0206 002a BLE @@nexttask ; ... yes? Skip it. 50fd 008a MOVR R1, R2 50fe 02c2 035e ADD RANDLO, R2 5100 0242 035e MVO R2, RANDLO ; Throw some bits into the random bucket 5102 0339 0002 SUBI #2, R1 ; Count it down. 5104 020c 0004 BNEQ @@noreinit ; If it went to zero, reinit count 5106 000b INCR R3 5107 0299 MVI@ R3, R1 ; Get new period for task 5108 0013 DECR R3 5109 0112 SUBR R2, R2 ; Z = 1, S = 0 (causes the BGT to not be taken) 0x510a @@noreinit: 510a 0259 MVO@ R1, R3 ; Store new period. 510b 020e 001a BGT @@nexttask ; If this count didn't expire, ... ; ... go to the next task 0x510d @@q: ; Schedule this task by adding it to the task queue 510d 009c MOVR R3, R4 510e 033c 0002 SUBI #2, R4 5110 02a2 MVI@ R4, R2 ; Get task function pointer 5111 0281 01ee MVI TSKQHD, R1 ; Get task queue head 5113 0009 INCR R1 ; Move to next slot 5114 03b9 000f ANDI #$F, R1 ; Stay within 16-entry circ buffer 5116 0341 01ef CMP TSKQTL, R1 5118 0204 0014 BEQ @@overflow ; Drop this task if queue overflows. (!) 511a 008d MOVR R1, R5 511b 00cd ADDR R1, R5 ; R5 is for task data queue 511c 02fd 01c0 ADDI #TSKDQ, R5 ; Point to task data queue 511e 0241 01ee MVO R1, TSKQHD ; Store updated task queue head 5120 02f9 0320 ADDI #TSKQ, R1 ; Point to actual task queue 5122 024a MVO@ R2, R1 ; Store the function pointer 5123 02a2 MVI@ R4, R2 ; Get task instance data 5124 026a MVO@ R2, R5 ; Store low half of instance data 5125 0042 SWAP R2, 1 5126 026a MVO@ R2, R5 ; Store high half of instance data 0x5127 @@nexttask: 5127 02fb 0004 ADDI #4, R3 ; Point to next task struct 5129 0010 DECR R0 512a 022c 0032 BNEQ @@taskloop ; Loop until done with all tasks 512c 0200 0005 B @@notasks 0x512e @@overflow: 512e 0280 01a0 MVI OVRFLO, R0 5130 0008 INCR R0 5131 0240 01a0 MVO R0, OVRFLO 0x5133 @@notasks: 0x5133 @@wtimer: ;; Count down the wait-timer, if there is one 5133 0285 034c MVI WTIMER, R5 5135 0015 DECR R5 5136 020b 0002 BMI @@expired 5138 0245 034c MVO R5, WTIMER 0x513a @@expired: ;; Check to see if the user has requested a pause. 513a 02b8 005a MVII #$5A, R0 ; Keypad 1 + Keypad 9 513c 0340 01fe CMP $1FE, R0 ; Pause on first controller? 513e 0204 0005 BEQ @@pausing 5140 0340 01ff CMP $1FF, R0 ; Pause on second controller? 5142 0204 0001 BEQ @@pausing 5144 02b7 PULR PC ; Return 0x5145 @@pausing: 5145 0003 DIS ; Disable interrupts while paused. ; Grab PSG volume settings aside and force volume to zero. 5146 02ba 0170 MVII #VOLSV, R2 5148 02bb 01fb MVII #$1FB, R3 514a 0095 MOVR R2, R5 514b 009c MOVR R3, R4 514c 0244 0173 MVO R4, PAUSED ; Set 'we paused' flag 514e 02a0 MVI@ R4, R0 ; Channel a 514f 0268 MVO@ R0, R5 5150 02a0 MVI@ R4, R0 ; Channel b 5151 0268 MVO@ R0, R5 5152 02a0 MVI@ R4, R0 ; Channel c 5153 0268 MVO@ R0, R5 5154 01c9 CLRR R1 5155 009c MOVR R3, R4 5156 0261 MVO@ R1, R4 5157 0261 MVO@ R1, R4 5158 0261 MVO@ R1, R4 5159 0006 CLRC 515a 0004 0150 0171 CALL @@waithand ; Wait for both controllers to be released. 515d 0007 SETC 515e 0004 0150 0171 CALL @@waithand ; Wait for either controller to be pressed 5161 0006 CLRC 5162 0004 0150 0171 CALL @@waithand ; Wait for both controllers to be released. 5165 009d MOVR R3, R5 5166 0094 MOVR R2, R4 5167 02a0 MVI@ R4, R0 ; Channel a 5168 0268 MVO@ R0, R5 5169 02a0 MVI@ R4, R0 ; Channel b 516a 0268 MVO@ R0, R5 516b 02a0 MVI@ R4, R0 ; Channel c 516c 0268 MVO@ R0, R5 516d 0002 EIS 516e 02b7 PULR PC 0x516f @@waitpress: 516f 020c 000b BNEQ @@waitdone 0x5171 @@waithand: 5171 02b9 0064 MVII #100, R1 ; Debounce factor 0x5173 @@waitloop: 5173 02bc 01fe MVII #$1FE, R4 5175 0001 SDBD 5176 02a0 MVI@ R4, R0 5177 0018 COMR R0 5178 0221 000a BC @@waitpress 517a 022c 000a BNEQ @@waithand 0x517c @@waitdone: 517c 0011 DECR R1 517d 022c 000b BNEQ @@waitloop 517f 00af JR R5 ENDP ;;==========================================================================;; ;; MAINLOOP ;; ;; The main loop runs asynchronously from the MAINISR, running tasks as ;; ;; they get scheduled. There is also a background task that runs when ;; ;; nothing else is in the queue. ;; ;; ;; ;; -- Grab task from task queue, if any ;; ;; -- run that task ;; ;; -- look for next task ;; ;; -- run background task once if no tasks available ;; ;; ;; ;; The background task scans hand controllers. I do this because ;; ;; hand-controller scanning could be fairly expensive. Also, scanning ;; ;; hand controllers may cause new tasks to get scheduled (eg. the triggers ;; ;; for various hand controller events) and I don't want to overrun the ;; ;; task queue. ;; ;; ;; ;; The background task also updates the random number generator state. I ;; ;; do this to make the random numbers a bit more random since the game ;; ;; loading varies according to what's going on. ;; ;;==========================================================================;; 0x5180 MAINLOOP PROC 5180 0275 PSHR R5 ; Save return address, since any ; task is allowed to exit the main ; game loop, say, when switching ; between game phases. ; ; There are three game phases: ; -- Title Screen ; -- In Game ; -- Game Over. 5181 02b9 0015 MVII #EDGEB, R1 ; Set the well height so that music 5183 0241 01ec MVO R1, HEIGHT ; plays correctly 5185 0241 01b2 MVO R1, MUTE ; Also, un-mute music. 0x5187 @@loop: 5187 00bd MOVR PC, R5 ; Set our return address to @@loop 5188 0015 DECR R5 ; This is 2 decles vs. 4 for SDBD/MVII ; Run next scheduled task from queue 5189 0003 DIS ; Shut off interrupts 518a 0281 01ef MVI TSKQTL, R1 ; Get the tail of the queue 518c 0341 01ee CMP TSKQHD, R1 ; Are there tasks in the queue? 518e 0204 0010 BEQ @@bktsk ; No: Do background task 5190 0009 INCR R1 ; Pop task from queue by 5191 03b9 000f ANDI #$F, R1 ; ... moving the queue tail 5193 0241 01ef MVO R1, TSKQTL ; Store new task-queue tail 5195 008c MOVR R1, R4 5196 00e4 ADDR R4, R4 5197 02fc 01c0 ADDI #TSKDQ, R4 5199 0001 SDBD 519a 02a2 MVI@ R4, R2 ; Load instance data for task 519b 02f9 0320 ADDI #TSKQ, R1 ; Point to task queue 519d 0288 MVI@ R1, R0 ; Get function pointer from queue ; Dispatch to user's task. Make sure interrupts are enabled again 519e 0002 EIS ; Done with critical section 519f 0087 JR R0 ; Jump to subroutine ; Note that this implicitly loops back to @@oloop here 0x51a0 @@bktsk: 51a0 0002 EIS ; Done with critical section 51a1 0004 0158 02bc CALL NEXTRAND ; Update random number state 51a4 0004 0158 01f4 CALL SCANHAND ; Scan the hand controllers. 0xcf00 EC_LOC EQU $CF00 0x69 EC_MAG EQU $69 0xcf01 EC_POLL EQU $CF01 51a7 0280 cf00 MVI EC_LOC, R0 51a9 0378 0069 CMPI #EC_MAG,R0 51ab 022c 0025 BNEQ @@loop 51ad 0004 01cc 0301 CALL EC_POLL 51b0 0220 002a B @@loop ; Run around the inner loop ENDP ;;==========================================================================;; ;; QTASK ;; ;; Add a task to the task queue. ;; ;; NOTE: CALL THIS WITH INTERRUPTS OFF!!!! (eg. use JSRD). Interrupts ;; ;; will be enabled before return. ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Task function pointer ;; ;; R1 -- Task instance data ;; ;; R5 -- Return address. ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- intact. ;; ;; R1 -- swapped ;; ;; R2, R4 -- trashed. ;; ;;==========================================================================;; 0x51b2 QTASK PROC 51b2 0282 01ee MVI TSKQHD, R2 ; Get head of task queue 51b4 000a INCR R2 ; Move to next queue slot 51b5 03ba 000f ANDI #$F, R2 ; Stay in circular buffer 51b7 0342 01ef CMP TSKQTL, R2 ; Are we overflowing the queue? 51b9 0204 000e BEQ @@overflow ; Yes ... don't overflow it! 51bb 0242 01ee MVO R2, TSKQHD ; Store new task queue head 51bd 0094 MOVR R2, R4 ; Generate instance data pointer 51be 00d4 ADDR R2, R4 ; (remember mult by two for data ptr) 51bf 02fa 0320 ADDI #TSKQ, R2 ; Point into task queue 51c1 0250 MVO@ R0, R2 ; Store function pointer to task q ; moved addi for STIC interruptibility fix 51c2 02fc 01c0 ADDI #TSKDQ, R4 ; Point into task data queue 51c4 0261 MVO@ R1, R4 ; Store instance data to data q 51c5 0041 SWAP R1 ; .... cont'd 51c6 0261 MVO@ R1, R4 ; .... cont'd 51c7 0002 EIS ; Re-enable ints after crit section 51c8 00af JR R5 ; Return. 0x51c9 @@overflow: 51c9 0282 01a0 MVI OVRFLO, R2 51cb 000a INCR R2 51cc 0242 01a0 MVO R2, OVRFLO 51ce 0002 EIS ; Re-enable ints after crit section 51cf 00af JR R5 ; Return. ENDP ;;==========================================================================;; ;; SCHEDEXIT ;; ;; Flushes the task queue and schedules the exit task. ;; ;; ;; ;; INPUTS: ;; ;; R5 -- Return address. ;; ;;==========================================================================;; 0x51d0 SCHEDEXIT: PROC 51d0 0275 PSHR R5 ; Push return address. 51d1 0004 0152 01da JSRD R5,STOPALLTASKS ; Flush the pending task queue 51d4 02b8 51d9 MVII #@@exit, R0 ; Schedule the exit task ... 51d6 02b5 PULR R5 51d7 0220 0026 B QTASK ; ... and chain the return. 51d9 02b7 @@exit: PULR PC ENDP ;;==========================================================================;; ;; STOPALLTASKS ;; ;; Stops all tasks by setting the task count to zero and by ;; ;; flushing the task queue (sets head/tail to 0). Returns old task count. ;; ;; NOTE: CALL THIS WITH INTERRUPTS OFF!!!! (eg. use JSRD) Interrupts ;; ;; are NOT re-enabled by this function. ;; ;; ;; ;; INPUTS: ;; ;; R5 -- Return address ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- Previous TSKACT ;; ;; R1 -- Cleared ;; ;; All tasks stopped. ;; ;;==========================================================================;; 0x51da STOPALLTASKS PROC 51da 0280 01ed MVI TSKACT, R0 51dc 01c9 CLRR R1 51dd 0241 01ed MVO R1, TSKACT 51df 0241 01ee MVO R1, TSKQHD 51e1 0241 01ef MVO R1, TSKQTL 51e3 0011 DECR R1 51e4 0241 0332 MVO R1, TSKTBL+2 ; period == -1 for task 0 51e6 0241 0336 MVO R1, TSKTBL+6 ; period == -1 for task 1 51e8 0241 033a MVO R1, TSKTBL+10 ; period == -1 for task 2 51ea 0034 NOP ; (interruptible, for STIC) 51eb 0241 033e MVO R1, TSKTBL+14 ; period == -1 for task 3 51ed 00af JR R5 ENDP ;;==========================================================================;; ;; STARTTASK ;; ;; Puts a task into a task slot for general timer-based scheduling ;; ;; ;; ;; INPUTS: ;; ;; R5 -- Invocation record: ;; ;; DECLE -- Task number ;; ;; DECLE -- Task function pointer ;; ;; DECLE -- Task initial period * 2. If bit 0==1, this is one-shot task. ;; ;; DECLE -- Task period re-init. Useful if first delay!=recurring delay. ;; ;; R2 -- Task instance data (optional) ;; ;; ;; ;; OUTPUTS: ;; ;; Task record is set up. (User still needs to update TSKACT to make ;; ;; the task records active, if necessary.) ;; ;; ;; ;; Registers R0, R4 are trashed. ;; ;;==========================================================================;; 0x51ee STARTTASK PROC 51ee 02a8 MVI@ R5, R0 51ef 004c SLL R0, 2 ; R0 = R0 * 4 (four words/entry) 51f0 02bc 0330 MVII #TSKTBL,R4 ; R4 = &TSKTBL[0] 51f2 00c4 ADDR R0, R4 ; R4 = &TSKTBL[n] 51f3 0003 DIS ; Entering critical section. 51f4 02a8 MVI@ R5, R0 ; Get Function pointer 51f5 0260 MVO@ R0, R4 ; ... and write it 51f6 0262 MVO@ R2, R4 ; Write task instance data 51f7 02a8 MVI@ R5, R0 ; Get task period 51f8 0260 MVO@ R0, R4 ; ... and write it 51f9 02a8 MVI@ R5, R0 ; Get task period reinit 51fa 0260 MVO@ R0, R4 ; ... and write it 51fb 0002 EIS 51fc 00af JR R5 ENDP ;;==========================================================================;; ;; STOPTASK ;; ;; Stops a given task by setting its period to -1. Task can be ;; ;; retriggered/restarted by calling RETRIGGERTASK. ;; ;; ;; ;; INPUTS: ;; ;; R3 -- Task number. ;; ;; ;; ;; OUTPUTS: ;; ;; Task is disabled. ;; ;; R0 == -1, R3 points to task delay count. ;; ;;==========================================================================;; 0x51fd STOPTASK PROC 51fd 004f SLL R3, 2 ; R3 = R3 * 4 (four words/entry) 51fe 02fb 0332 ADDI #TSKTBL+2, R3 ; R3 = &TSKTBL[n].delay 5200 01c0 CLRR R0 5201 0010 DECR R0 ; R0 == -1. 5202 0258 MVO@ R0, R3 ; TSKTBL[n].delay = -1 5203 00af JR R5 ENDP ;;==========================================================================;; ;; RETRIGGERTASK ;; ;; Restarts a task by copying its delay re-init field to its delay field. ;; ;; Can be used on one-shot tasks or tasks which have been stopped with ;; ;; 'StopTask'. ;; ;; ;; ;; INPUTS: ;; ;; R3 -- Task number. ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- Task delay ;; ;; R3 -- points to task delay count ;; ;;==========================================================================;; 0x5204 RETRIGGERTASK: PROC 5204 004f SLL R3, 2 ; R3 = R3 * 4 (four words/entry) 5205 02fb 0333 ADDI #TSKTBL+3, R3 ; R3 = &TSKTBL[n].reload 5207 0003 DIS 5208 0298 MVI@ R3, R0 ; Get reload value 0x5209 @@chain: 5209 0013 DECR R3 ; Offset 2 is delay count 520a 0258 MVO@ R0, R3 520b 0002 EIS 520c 00af JR R5 ENDP ;;==========================================================================;; ;; WAIT ;; ;; Busy-waits for the number of ticks specified in R0. ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Number of ticks to wait ;; ;; R5 -- Return address ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- cleared ;; ;;==========================================================================;; 0x520d WAIT PROC 520d 02a8 MVI@ R5, R0 520e 0240 034c MVO R0, WTIMER 5210 01c0 CLRR R0 0x5211 @@loop: 5211 0340 034c CMP WTIMER, R0 5213 022c 0003 BNEQ @@loop 5215 00af JR R5 ENDP ;;==========================================================================;; ;; SLEEP ;; ;; Causes a one-shot process to sleep by scheduling a second one-shot ;; ;; process to reawake it. This is VERY DIFFICULT TO USE, and can be ;; ;; used by ONE PROCESS ONLY at a time. ;; ;; ;; ;; SPAWN ;; ;; Same as sleep, only the sleeping task isn't a one-shot. It keeps ;; ;; retriggering automatically at the designated interval, or can be ;; ;; retriggered manually if the period is odd. ;; ;; ;; ;; INPUTS: ;; ;; R5 -- Invocation record, in following format: ;; ;; Period/sleep time 1 Decle (Must be ODD for SLEEP) ;; ;; Process # to use 1 Decle ;; ;; Top of Stack -- Return address from _this_ process back to scheduler. ;; ;; Task will wake at address after invocation record. ;; ;; ;; ;; OUTPUTS: ;; ;; R0, R1, R2, R3, R4 restored ;; ;; R5 points to your return address ;; ;; Top of stack has return address for scheduler ;; ;;==========================================================================;; 0x5216 SLEEP: PROC 0x5216 SPAWN: 5216 0244 0351 MVO R4, REGSV+4 ; Save R4 5218 02bc 034d MVII #REGSV, R4 521a 0260 MVO@ R0, R4 ; Save R0 521b 0261 MVO@ R1, R4 ; Save R1 521c 0262 MVO@ R2, R4 ; Save R2 521d 0263 MVO@ R3, R4 ; Save R3 521e 02aa MVI@ R5, R2 ; Get sleep time 521f 02ab MVI@ R5, R3 ; Get PID 5220 004f SLL R3, 2 ; R3 = R3 * 4 (four words/entry) 5221 02bc 0330 MVII #TSKTBL,R4 ; R4 = &TSKTBL[0] 5223 00dc ADDR R3, R4 ; R4 = &TSKTBL[n] 5224 02b8 522b MVII #@@wake,R0 5226 0260 MVO@ R0, R4 ; Address to wake up at 5227 0265 MVO@ R5, R4 ; Instance data (R2 restore) 5228 0262 MVO@ R2, R4 5229 0262 MVO@ R2, R4 522a 02b7 PULR PC 0x522b @@wake: 522b 0275 PSHR R5 ; Remember return address 522c 0095 MOVR R2, R5 522d 02bc 034d MVII #REGSV, R4 ; Point to register save area 522f 02a0 MVI@ R4, R0 ; Restore R0 5230 02a1 MVI@ R4, R1 ; Restore R1 5231 02a2 MVI@ R4, R2 ; Restore R2 5232 02a3 MVI@ R4, R3 ; Restore R3 5233 02a4 MVI@ R4, R4 ; Restore R4 5234 00af JR R5 ; Go there ENDP ;;==========================================================================;; ;; DOFACE ;; ;;==========================================================================;; 0x5235 DOFACE PROC 5235 0003 DIS 5236 02be 02f0 MVII #$2F0, SP 5238 02b8 527a MVII #@@loadface, R0 523a 0240 0348 MVO R0, PREVBL 523c 0040 SWAP R0 523d 0240 0349 MVO R0, PREVBL+1 523f 01c0 CLRR R0 5240 02b9 00f0 MVII #$F0, R1 5242 02bc 0200 MVII #$200, R4 5244 0004 0158 03d6 CALL FILLMEM 5247 02bc 021c MVII #$200 + 8 + 20, R4 5249 02bd 6f82 MVII #FACE, R5 524b 02b8 0009 MVII #9, R0 524d 0240 002c MVO R0, CB 524f 0240 0028 MVO R0, CS0 0x5251 @@f_oloop: 5251 02ba 0006 MVII #6, R2 0x5253 @@f_iloop: 5253 02a9 MVI@ R5, R1 5254 0261 MVO@ R1, R4 5255 0012 DECR R2 5256 022c 0004 BNEQ @@f_iloop 5258 02fc 000e ADDI #14, R4 525a 0010 DECR R0 525b 022c 000b BNEQ @@f_oloop 525d 0004 0158 03d1 CALL DRAWSTRING3 5260 0000 02c8 DECLE 0, $200 + 20*10 ;01234567890123456789 5262 004a 006f 0065 BYTE $4A, $6F, $65, $20, $5A, $62, $69, $63, $69, $61, $6B 5265 0020 005a 0062 0069 0063 0069 0061 006b 526d 0020 0073 0061 BYTE $20, $73, $61, $79, $73, $20, $48, $49, $21, $0A, $00 5270 0079 0073 0020 0048 0049 0021 000a 0000 5278 0002 EIS 5279 0017 DECR PC 0x527a @@loadface: 527a 02b8 528b MVII #@@shunt, R0 527c 0240 0348 MVO R0, PREVBL 527e 0040 SWAP R0 527f 0240 0349 MVO R0, PREVBL+1 5281 02b8 0009 MVII #9, R0 5283 0240 0028 MVO R0, CS0 5285 0240 002c MVO R0, CB 5287 0004 0150 00b1 CALL LOADFONT 528a 6ee0 DECLE FACEFONT 0x528b @@shunt: 528b 0240 0020 MVO R0, $20 528d 02b7 PULR PC ENDP ;;==========================================================================;; ;; Colored squares pixel-manipulation routines. ;; ;; J. Zbiciak, July 1999 ;; ;;==========================================================================;; ; Data tables for pixel routines 0x528e MSKTBL: 528e 0007 0038 01c0 DECLE $0007, $0038, $01C0, $2600 5291 2600 0x5292 CLRTBL: 5292 0000 0249 0492 DECLE $0000, $0249, $0492, $06DB 5295 06db 5296 2124 236d 25b6 DECLE $2124, $236D, $25B6, $27FF 5299 27ff ;;==========================================================================;; ;; PIXCALC -- Pixel Calculation: Convert x,y into addr,mask ;; ;; ;; ;; INPUTS: ;; ;; R1 -- X coordinate ;; ;; R2 -- Y coordinate ;; ;; R5 -- Return address ;; ;; ;; ;; OUTPUTS: ;; ;; R1 -- Pixel mask ;; ;; R2 -- Address in display memory. ;; ;; R3, R4 -- Clobbered. ;; ;;==========================================================================;; 0x529a PIXCALC PROC 529a 004a SLL R2, 1 ; y' = y << 1 529b 0094 MOVR R2, R4 ; mskidx = y << 1 529c 03bc 0002 ANDI #2, R4 ; mskidx = (y << 1) & 2 529e 0122 SUBR R4, R2 ; y' = (y & ~1) << 1 529f 0093 MOVR R2, R3 ; save y' 52a0 004e SLL R2, 2 ; y'' = (y & ~1) << 3 52a1 00da ADDR R3, R2 ; y''' = y' + y'' = (y >> 1) * 20 52a2 0079 SARC R1, 1 ; c = x & 1; x' = x >> 1 52a3 002c ADCR R4 ; mskidx = ((y << 1) & 2) + (x & 1) 52a4 00ca ADDR R1, R2 ; ofs = x' + y''' = (x >> 1) + (y >> 1) * 20 52a5 02fa 0200 ADDI #$200, R2 ; ptr = ofs + $200 = &BACKTAB[ofs] ==> R2 52a7 02fc 528e ADDI #MSKTBL,R4 ; mskptr = MSKTBL + mskidx' = &MSKTBL[mskidx] 52a9 02a1 MVI@ R4, R1 ; mask = *mskptr ==> R1 52aa 00af JR R5 ; return ENDP ;;==========================================================================;; ;; PUTPIXEL -- Put pixel at x, y coordinates with color 'c' (0-7) ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Color ;; ;; R1 -- X coordinate ;; ;; R2 -- Y coordinate ;; ;; R5 -- Return address ;; ;; ;; ;; OUTPUTS: ;; ;; R1 -- Word stored at R2 ;; ;; R2 -- Display memory address ;; ;; R0, R3, R4, R5 -- Clobbered. ;; ;;==========================================================================;; 0x52ab PUTPIXEL PROC 52ab 0275 PSHR R5 ; Save return address 52ac 02bd 52b1 MVII #PUTPIXELR+1,R5 ; Return to actual pixel draw below 52ae 0220 0015 B PIXCALC ; Convert x,y into mask,addr ;;==========================================================================;; ;; PUTPIXELR -- Put pixel 'raw': accepts address, mask, and color ;; ;; (Alternate entry point for PUTPIXEL.) ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Color ;; ;; R1 -- Pixel mask ;; ;; R2 -- Display memory address ;; ;; ;; ;; OUTPUTS: ;; ;; R1 -- Word stored at R2 ;; ;; R2 -- Display memory address ;; ;; R0,R5 -- Clobbered. ;; ;;==========================================================================;; 0x52b0 PUTPIXELR: 52b0 0275 PSHR R5 ; Save return address 52b1 0085 MOVR R0, R5 52b2 02fd 5292 ADDI #CLRTBL,R5 ; clrptr = CLRTBL + c' = &CLRTBL[c] 52b4 02a8 MVI@ R5, R0 ; color = CLRTBL[c] 52b5 0188 ANDR R1, R0 ; color = color & mask (select desired pix) 52b6 0019 COMR R1 ; invert mask 52b7 0391 AND@ R2, R1 ; pix = BACKTAB & ~mask (clear pixel) 52b8 00c1 ADDR R0, R1 ; pix' = pix + color (merge pixels) 52b9 0251 MVO@ R1, R2 ; BACKTAB[ofs] = pix' (write pixels) 52ba 02b7 PULR PC ; return. ENDP ;;==========================================================================;; ;; PIXELCLIP ;; ;; Returns with C==1 if pixel is onscreen ;; ;; ;; ;; INPUTS: ;; ;; R1 -- X coordinate ;; ;; R2 -- Y coordinate ;; ;; R5 -- Return address ;; ;; ;; ;; OUTPUTS: ;; ;; Carry == 1 if onscreen, 0 if offscreen. ;; ;;==========================================================================;; 0x52bb PIXELCLIP PROC 52bb 0089 TSTR R1 ; Off left? 52bc 020b 000d BMI @@offscr ; Yes: Set carry and exit 52be 0092 TSTR R2 ; Off top? 52bf 020b 000a BMI @@offscr ; Yes: Set carry and exit 52c1 0379 0027 CMPI #39, R1 ; Off right? 52c3 020e 0006 BGT @@offscr ; Yes: Set carry and exit 52c5 037a 0017 CMPI #23, R2 ; Off bottom? 52c7 020e 0002 BGT @@offscr ; Yes: Set carry and exit 52c9 0007 SETC ; No to all: Clear carry and exit 52ca 00af JR R5 0x52cb @@offscr 52cb 0006 CLRC 52cc 00af JR R5 ENDP ;;==========================================================================;; ;; GETPIXELS -- Calls GETPIXEL, but saves/restores X, Y ;; ;; ;; ;; INPUTS: ;; ;; R1 -- X coordinate ;; ;; R2 -- Y coordinate ;; ;; R5 -- Return addr. ;; ;; ;; ;; OUTPUTS ;; ;; R0 -- Color ;; ;; R1 -- X coordinate ;; ;; R2 -- Y coordinate ;; ;; R3, R4, R5 -- Clobbered. ;; ;;==========================================================================;; 0x52cd GETPIXELS PROC 52cd 0275 PSHR R5 0x52ce @@chain: 52ce 0241 01e0 MVO R1, XSAVE 52d0 0242 01e1 MVO R2, YSAVE 52d2 0004 0150 02f3 CALL GETPIXEL 52d5 0281 01e0 MVI XSAVE, R1 52d7 0282 01e1 MVI YSAVE, R2 52d9 02b7 PULR PC ENDP ;;==========================================================================;; ;; PUTPIXELS -- Calls PUTPIXEL, but saves/restores X, Y ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Color ;; ;; R1 -- X coordinate ;; ;; R2 -- Y coordinate ;; ;; R5 -- Return addr. ;; ;; ;; ;; OUTPUTS ;; ;; R0 -- Color ;; ;; R1 -- X coordinate ;; ;; R2 -- Y coordinate ;; ;; R3, R4, R5 -- Clobbered. ;; ;;==========================================================================;; 0x52da PUTPIXELS PROC 52da 0275 PSHR R5 0x52db @@chain: 52db 0241 01e0 MVO R1, XSAVE 52dd 0242 01e1 MVO R2, YSAVE 52df 0240 01b3 MVO R0, CSAVE 52e1 0004 0150 02ab CALL PUTPIXEL 52e4 0280 01b3 MVI CSAVE, R0 52e6 0281 01e0 MVI XSAVE, R1 52e8 0282 01e1 MVI YSAVE, R2 52ea 02b7 PULR PC ENDP ;;==========================================================================;; ;; GETPIXELSC ;; ;; Calls GETPIXELS or returns R0 unchanged if pixel is off screen ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Color to return if off-screen ;; ;; R1 -- X coordinate ;; ;; R2 -- Y coordinate ;; ;; R5 -- Return addr. ;; ;; ;; ;; OUTPUTS ;; ;; R0 -- Color ;; ;; R1 -- X coordinate ;; ;; R2 -- Y coordinate ;; ;; R3, R4, R5 -- Clobbered. ;; ;;==========================================================================;; 0x52eb GETPIXELSC PROC 52eb 0275 PSHR R5 ; Save return address 52ec 0004 0150 02bb CALL PIXELCLIP ; See if pixel is onscreen 52ef 002f ADCR PC ; If it is, then skip the return 52f0 02b7 PULR PC ; Otherwise return. 52f1 0220 0024 B GETPIXELS.chain ; If onscreen chain over to GETPIXELS ENDP ;;==========================================================================;; ;; GETPIXEL -- Get pixel at x, y address ;; ;; ;; ;; INPUTS: ;; ;; R1 -- X coordinate ;; ;; R2 -- Y coordinate ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- Color ;; ;; R2 -- Display memory address ;; ;; R1, R3, R4, R5 -- Clobbered. ;; ;;==========================================================================;; 0x52f3 GETPIXEL PROC 52f3 0275 PSHR R5 ; Save return address 52f4 02bd 52f9 MVII #GETPIXELR+1,R5 ; Return to actual pixel read below 52f6 0220 005d B PIXCALC ; Convert x,y into mask,addr ;;==========================================================================;; ;; GETPIXELR -- Get pixel 'raw': accepts address, mask ;; ;; (Alternate entry point for getpixel) ;; ;; INPUTS: ;; ;; R1 -- Pixel mask ;; ;; R2 -- Display memory address ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- Color ;; ;; R2 -- Display memory address ;; ;; R1, R5 -- Clobbered. ;; ;;==========================================================================;; 0x52f8 GETPIXELR: 52f8 0275 PSHR R5 ; Save return address 52f9 0290 MVI@ R2, R0 ; pix = BACKTAB[ofs] 52fa 0188 ANDR R1, R0 ; pix' = pix & mask 52fb 0081 MOVR R0, R1 ; 52fc 0040 SWAP R0, 1 ; 52fd 03b8 0020 ANDI #$20, R0 ; 52ff 00c8 ADDR R1, R0 ; merge oddball bit from lower right pixel 5300 004d SLL R1, 2 ; 5301 0041 SWAP R1, 1 ; 5302 00c8 ADDR R1, R0 ; Fold upper, lower pairs of pixels 5303 0081 MOVR R0, R1 ; 5304 0060 SLR R0, 1 ; 5305 0064 SLR R0, 2 ; 5306 00c8 ADDR R1, R0 ; Fold left, right pixels 5307 03b8 0007 ANDI #7, R0 ; Select remaining pixel 5309 02b7 PULR PC ; return ENDP ;;==========================================================================;; ;; PUTPIXELSCQ ;; ;; ;; ;; Queues a pixel for display if it's onscreen. This routine does not ;; ;; draw the pixel directly, but rather puts it in a queue of pixels that ;; ;; are waiting to be drawn. This queue is emptied during the interrupt ;; ;; service routine after the queue is "committed" for display with a call ;; ;; to COMMITPXQ. ;; ;; ;; ;; The pixel queue serves as a mechanism for reducing/eliminating the ;; ;; flicker associated with redrawing a game piece. Without the queue, ;; ;; piece movements could result in a significant amount of flicker. ;; ;; To further reduce flicker, the queue insert routine attempts to ;; ;; optimize multiple 'PUTPIXELs' to the same location, with the last ;; ;; PUTPIXEL taking precedence. ;; ;; ;; ;; Because this queue is intended for drawing game pieces only, it is ;; ;; not very large. No checking is performed for queue overflow, either. ;; ;; Also, because double-buffering is not performed, this routine will ;; ;; block if there is a committed pixel queue waiting to be drawn. ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Color ;; ;; R1 -- X coordinate ;; ;; R2 -- Y coordinate ;; ;; ;; ;; OUTPUTS ;; ;; R0 -- Color ;; ;; R1 -- X coordinate ;; ;; R2 -- Y coordinate ;; ;; R3, R4, R5 -- Clobbered. ;; ;;==========================================================================;; 0x530a PUTPIXELSCQ PROC 530a 0275 PSHR R5 ; Save return address 530b 0004 0150 02bb CALL PIXELCLIP ; See if pixel is onscreen 530e 002f ADCR PC ; If it is, then skip the return 530f 02b7 PULR PC ; Otherwise return. ; Merge Y coordinate and color up-front, since we store ; them merged in the queue. 5310 0083 MOVR R0, R3 ; Work on a copy of our color 5311 0043 SWAP R3 5312 0067 SLR R3, 2 5313 0063 SLR R3, 1 ; R3 = color << 5 5314 01da XORR R3, R2 ; Put color in bits 5..7 of R2 5315 0003 DIS ; Critical section: Queue management. ; First, check to see if any pixels are queued at all. If there ; aren't any, just jump straight to the queue-insert. 5316 0283 0140 MVI PXQ_L0, R3 5318 009b TSTR R3 5319 0204 0020 BEQ @@insert_eis ; Next, check to see if there are any committed pixels waiting ; to be drawn in the pixel queue. Wait until the queue is drained. 531b 01db CLRR R3 531c 0343 0141 CMP PXQ_L1, R3 ; If there are no committed pixels, we 531e 0002 EIS ; Interrupts can be enabled now. 531f 0204 0006 BEQ @@check ; still need to check for redundant pixels. 0x5321 @@drain: 5321 0343 0141 CMP PXQ_L1, R3 ; Otherwise, let the queue drain and jump 5323 022c 0003 BNEQ @@drain ; straight to the insert since it's empty 5325 0200 0015 B @@insert 0x5327 @@check: ; If we reach here, we have a non-empty pixel queue, and no ; committed pixels. Step through the queue to see if we have ; any redundant pixels. 5327 02bc 0141 MVII #PXQ_XY - 1, R4 ; Point at start of Queue minus 1 5329 0283 0140 MVI PXQ_L0, R3 ; Get queue length 532b 000c @@notx: INCR R4 ; Where we branch when X didn't match. 532c 0013 @@noty: DECR R3 ; Decrement loop count 532d 020b 000d BMI @@insert ; Get out of here when it expires. 0x532f @@rloop: 532f 0361 CMP@ R4, R1 ; Compare X coords 5330 022c 0006 BNEQ @@notx ; X miscompared. 5332 0095 MOVR R2, R5 5333 03e5 XOR@ R4, R5 5334 03bd 001f ANDI #$1F, R5 ; Cmp Y coords (lower 5 bits of queue entry) 5336 022c 000b BNEQ @@noty ; Y miscompared ; If we get here, the coordinates match, so just update the color ; and exit the queue insertion process entirely. 5338 0014 DECR R4 5339 0200 000b B @@styc ; Store Y coordinate and color, and leave 0x533b @@insert_eis: 533b 0002 EIS 0x533c @@insert: ; If we get here, then this is not a duplicate pixel, so we need ; to extend the queue. Warning: No bounds checking is done here. 533c 0283 0140 MVI PXQ_L0, R3 533e 009c MOVR R3, R4 ; Copy the old queue length to R4 533f 00dc ADDR R3, R4 ; Multiply it by 2 5340 000b INCR R3 5341 0243 0140 MVO R3, PXQ_L0 5343 02fc 0142 ADDI #PXQ_XY, R4 ; Point R4 at pixel queue 5345 0261 @@stx: MVO@ R1, R4 ; Store the X coordinate 5346 0262 @@styc: MVO@ R2, R4 ; Store the Y coordinate and color 5347 03ba 001f ANDI #$1F, R2 ; Strip the color from the Y + color. 5349 02b7 PULR PC ; Return. ENDP ;;==========================================================================;; ;; DRAINPXQ ;; ;; Drains the pixel queue (intended to be called from an ISR). ;; ;; ;; ;; INPUTS: ;; ;; R5 -- Return address ;; ;; Pixels in the committed pixel queue ;; ;; ;; ;; OUTPUTS: ;; ;; R0..R5 clobbered. ;; ;;==========================================================================;; 0x534a DRAINPXQ PROC 534a 0275 PSHR R5 534b 0003 DIS ; Critical section: Grab committed pixels. 534c 0283 0141 MVI PXQ_L1, R3 534e 009b TSTR R3 534f 0204 001c BEQ @@leave 5351 01c9 CLRR R1 5352 0241 0140 MVO R1, PXQ_L0 ; Clear count of queued pixels. 5354 0241 0141 MVO R1, PXQ_L1 ; Clear count of comitted pixels. 5356 0002 EIS 5357 02bc 0142 MVII #PXQ_XY, R4 0x5359 @@pixloop: 5359 02a1 MVI@ R4, R1 ; Get X coordinate 535a 02a2 MVI@ R4, R2 ; Get Y coordinate and color 535b 0090 MOVR R2, R0 ; Separate Y coordinate and color 535c 004c SLL R0, 2 535d 0048 SLL R0, 1 535e 0040 SWAP R0 ; Color is now in 3 lsbs. 535f 03b8 0007 ANDI #$7, R0 ; Mask away undesired bits in color 5361 03ba 001f ANDI #$1F, R2 ; Mask away undesired bits in Y coord. 5363 0273 PSHR R3 5364 0274 PSHR R4 5365 0004 0150 02ab CALL PUTPIXEL ; Display the pixel 5368 02b4 PULR R4 5369 02b3 PULR R3 536a 0013 DECR R3 ; Decrement our loop count 536b 022c 0013 BNEQ @@pixloop ; Keep looping until we've displayed them all 0x536d @@leave: 536d 0002 EIS 536e 02b7 PULR PC ENDP ;;==========================================================================;; ;; COMMITPXQ ;; ;; Commits queued pixels in the pixel queue to be displayed. ;; ;; ;; ;; INPUTS: ;; ;; R5 -- Return address ;; ;; Pixels in the pixel queue. ;; ;; ;; ;; OUTPUTS: ;; ;; Pixels are committed for display. ;; ;;==========================================================================;; 0x536f COMMITPXQ PROC 536f 0275 PSHR R5 ; Save return address on stack. 5370 0003 DIS ; Disable interrupts (critical section) 5371 0285 0141 MVI PXQ_L1, R5 ; See if there are already committed pixels 5373 00ad TSTR R5 ; ... waiting to be drawn. (oops!) 5374 020c 0004 BNEQ @@leave ; Yes.. then leave. 5376 0285 0140 MVI PXQ_L0, R5 ; No? Get our count of non-committed pixels. 5378 0245 0141 MVO R5, PXQ_L1 ; Store it to our count of committed pixels. 0x537a @@leave: 537a 0002 EIS ; Done with critical section. 537b 02b7 PULR PC ; Return to caller ENDP ;;==========================================================================;; ;; PIECE ;; ;; The Piece Shape Table ;; ;; ;; ;; Shape encoding for the game pieces ;; ;; ;; ;; The game pieces are encoded as a series of moves from the "center ;; ;; point". Blocks are placed _after_ each move. All pieces are ;; ;; composed of four moves except piece 6 (the T) which requires 5 ;; ;; moves, and piece 5 which uses an extra move so that it is centered ;; ;; in the "next piece" box. ;; ;; ;; ;; Each move is encoded in two bits. The LS bit specifies the axis ;; ;; (up/down or left/right), and the MS bit specifies the sign of ;; ;; the direction on that axis (1==+1 and 0==-1). Moves are processed ;; ;; from the LS bit pair up to the MS bit pair. This encoding allows ;; ;; each piece to be described in exactly one decle. ;; ;; ;; ;; NOTE: The fifth move may NOT be "up". The rotation code ;; ;; distiguishes between four-move and five-move pieces by whether the ;; ;; upper two bits are zero. If they're both zero, it's a four-move ;; ;; piece, otherwise the two bits specify the fifth move. (Recall that ;; ;; 00 corresponds to "up".) ;; ;; ;; ;; Right now, rotations are performed in a brute-force manner: We ;; ;; just encode all of the rotations in our data set here. It's ;; ;; seems to be alot cheaper than writing the code to rotation code, ;; ;; although I can't be sure unless I do them both. At the very least, ;; ;; the brute-force approach is alot easier. ;; ;; ;; ;; Notation: pXrY is "Piece #X, Rotation #Y". X == 0..6, Y == 0..3. ;; ;; ;; ;; up#, dn#, lf# and rt# indicate a movement in a direction ;; ;; on a given move number. ;; ;; ;; ;; Pieces are shown in the comments in their initial ;; ;; orientation. The block marked with %% is the "pivot" ;; ;; block. ;; ;;==========================================================================;; 0x537c PIECE PROC ; handy constants for defining the moves. 0x0 @@up0 EQU 0000000000b 0x2 @@dn0 EQU 0000000010b 0x1 @@lf0 EQU 0000000001b 0x3 @@rt0 EQU 0000000011b 0x0 @@up1 EQU 0000000000b 0x8 @@dn1 EQU 0000001000b 0x4 @@lf1 EQU 0000000100b 0xc @@rt1 EQU 0000001100b 0x0 @@up2 EQU 0000000000b 0x20 @@dn2 EQU 0000100000b 0x10 @@lf2 EQU 0000010000b 0x30 @@rt2 EQU 0000110000b 0x0 @@up3 EQU 0000000000b 0x80 @@dn3 EQU 0010000000b 0x40 @@lf3 EQU 0001000000b 0xc0 @@rt3 EQU 0011000000b ;;up4 not allowed 0x200 @@dn4 EQU 1000000000b 0x100 @@lf4 EQU 0100000000b 0x300 @@rt4 EQU 1100000000b ; Piece 0: The Long Bar ; ; ### ; ### ; %%% ; %%% ; ### ; ### ; ### ; ### ; 537c 00a8 @@p0r0 BYTE @@up0 + @@dn1 + @@dn2 + @@dn3 537d 00fd @@p0r1 BYTE @@lf0 + @@rt1 + @@rt2 + @@rt3 537e 00a8 @@p0r2 BYTE @@up0 + @@dn1 + @@dn2 + @@dn3 537f 00fd @@p0r3 BYTE @@lf0 + @@rt1 + @@rt2 + @@rt3 ; Piece 1: The Square Block ; ; ###%%% ; ###%%% ; ###### ; ###### ; 5380 00c6 @@p1r0 BYTE @@dn0 + @@lf1 + @@up2 + @@rt3 5381 00c6 @@p1r1 BYTE @@dn0 + @@lf1 + @@up2 + @@rt3 5382 00c6 @@p1r2 BYTE @@dn0 + @@lf1 + @@up2 + @@rt3 5383 00c6 @@p1r3 BYTE @@dn0 + @@lf1 + @@up2 + @@rt3 ; Piece 2: The L shape ; ; ###%%%### ; ###%%%### ; ### ; ### ; 5384 0097 @@p2r0 BYTE @@rt0 + @@lf1 + @@lf2 + @@dn3 5385 0042 @@p2r1 BYTE @@dn0 + @@up1 + @@up2 + @@lf3 5386 003d @@p2r2 BYTE @@lf0 + @@rt1 + @@rt2 + @@up3 5387 00e8 @@p2r3 BYTE @@up0 + @@dn1 + @@dn2 + @@rt3 ; Piece 3: The Reverse-L shape ; ; ###%%%### ; ###%%%### ; ### ; ### ; 5388 00bd @@p3r0 BYTE @@lf0 + @@rt1 + @@rt2 + @@dn3 5389 0068 @@p3r1 BYTE @@up0 + @@dn1 + @@dn2 + @@lf3 538a 0017 @@p3r2 BYTE @@rt0 + @@lf1 + @@lf2 + @@up3 538b 00c2 @@p3r3 BYTE @@dn0 + @@up1 + @@up2 + @@rt3 ; Piece 4: The S shape ; ; %%%### ; %%%### ; ###### ; ###### ; 538c 0067 @@p4r0 BYTE @@rt0 + @@lf1 + @@dn2 + @@lf3 538d 00b8 @@p4r1 BYTE @@up0 + @@dn1 + @@rt2 + @@dn3 538e 0067 @@p4r2 BYTE @@rt0 + @@lf1 + @@dn2 + @@lf3 538f 00b8 @@p4r3 BYTE @@up0 + @@dn1 + @@rt2 + @@dn3 ; Piece 5: The Z shape ; ; ###SSS Note: SSS brick is the actual starting brick. ; ###SSS ; %%%### ; %%%### ; 5390 011e @@p5r0 DECLE @@dn0 + @@rt1 + @@lf2 + @@up3 + @@lf4 5391 0262 @@p5r1 DECLE @@dn0 + @@up1 + @@dn2 + @@lf3 + @@dn4 5392 011e @@p5r2 DECLE @@dn0 + @@rt1 + @@lf2 + @@up3 + @@lf4 5393 0262 @@p5r3 DECLE @@dn0 + @@up1 + @@dn2 + @@lf3 + @@dn4 ; Piece 6: The T shape ; ; ###%%%### ; ###%%%### ; ### ; ### ; 5394 032d @@p6r0 DECLE @@lf0 + @@rt1 + @@dn2 + @@up3 + @@rt4 5395 02d8 @@p6r1 DECLE @@up0 + @@dn1 + @@lf2 + @@rt3 + @@dn4 5396 038d @@p6r2 DECLE @@lf0 + @@rt1 + @@up2 + @@dn3 + @@rt4 5397 0278 @@p6r3 DECLE @@up0 + @@dn1 + @@rt2 + @@lf3 + @@dn4 ENDP ;;==========================================================================;; ;; PUTPIECEREC ;; ;; Writes a piece record to memory. ;; ;; ;; ;; PUTPIECEREC.NC ;; ;; Writes a piece record to memory, except color. ;; ;; ;; ;; INPUTS: ;; ;; R0 -- piece color ;; ;; R1 -- X coord of pivot ;; ;; R2 -- Y coord of pivot ;; ;; R3 -- piece number/rotation ;; ;; R4 -- Address of piece information record (+1 if PUTPIECEREC.NC) ;; ;; R5 -- Return address ;; ;; ;; ;; OUTPUTS: ;; ;; R0..R3, R5 -- not modified ;; ;; R4 -- points just past end of of piece information record ;; ;;==========================================================================;; 0x5398 PUTPIECEREC PROC 5398 0260 MVO@ R0, R4 ; Put piece color 0x5399 @@NC: 5399 0261 MVO@ R1, R4 ; Put piece pivot X coordinate 539a 0262 MVO@ R2, R4 ; Put piece pivot Y coordinate 539b 0263 MVO@ R3, R4 ; Put piece number/rotation 539c 00af JR R5 ; Return ENDP ;;==========================================================================;; ;; GETPIECEREC ;; ;; Reads a piece record from memory. ;; ;; ;; ;; GETPIECEREC.NC ;; ;; Reads a piece record from memory, except color. ;; ;; ;; ;; INPUTS: ;; ;; R4 -- Address of piece information record (+1 if GETPIECEREC.NC) ;; ;; R5 -- Return address ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- piece color (unless GETPIECEREC.NC) ;; ;; R1 -- X coord of pivot ;; ;; R2 -- Y coord of pivot ;; ;; R3 -- piece number/rotation ;; ;;==========================================================================;; 0x539d GETPIECEREC PROC 539d 02a0 MVI@ R4, R0 ; Get piece color 0x539e @@NC: 539e 02a1 MVI@ R4, R1 ; Get piece pivot X coordinate 539f 02a2 MVI@ R4, R2 ; Get piece pivot Y coordinate ; Sign-extend R1 and R2 since they're in 8-bit RAM. 53a0 02bb 007f MVII #$7F, R3 ; Generate constant $FF80 53a2 001b COMR R3 ; R3 is "magic sign-extend constant" 53a3 00d9 ADDR R3, R1 ; Propogate sign-bit info to upper-half 53a4 01d9 XORR R3, R1 ; R1 is fully sign-extended here. 53a5 00da ADDR R3, R2 ; Propogate sign-bit info to upper-half 53a6 01da XORR R3, R2 ; R2 is fully sign-extended here. 53a7 02a3 MVI@ R4, R3 ; Get piece number/rotation 53a8 00af JR R5 ; Return ENDP ;;==========================================================================;; ;; DRAWPIECE ;; ;; Draws a piece on the screen in the desired color (0..7). ;; ;; ;; ;; TESTPIECE ;; ;; Determines if a piece can be drawn in a given location by tracing its ;; ;; path and doing GETPIXELSC calls. ;; ;; ;; ;; INPUTS: ;; ;; R0 -- If DRAWPIECE, color of piece to draw (0..7) ;; ;; R1 -- X coordinate of pivot ;; ;; R2 -- Y coordinate of pivot ;; ;; R3 -- Piece number ;; ;; R5 -- Return address ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- If TESTPIECE, Zero == OK, non-zero == not OK; else, trashed. ;; ;; R4 -- Minimum Y coordinate ;; ;; R5 trashed. ;; ;; ;; ;; $130..$135 used for temporary storage. ;; ;;==========================================================================;; 0x53a9 DRAWPIECE PROC 0x130 @@colsv EQU $130 ; Piece color save area 0x131 @@pvxsv EQU $131 ; Pivot X coordinate save area 0x132 @@pvysv EQU $132 ; Pivot Y coordinate save area 0x133 @@pnrsv EQU $133 ; Piece number/rotation save area 0x134 @@pcwsv EQU $134 ; Loop count save area 0x135 @@cntsv EQU $135 ; Loop count save area 0x136 @@miny EQU $136 53a9 00c0 ADDR R0, R0 ; Shift color left by 1 53aa 0008 INCR R0 ; Set the LSB on the color 53ab 000f INCR PC ; Skip the CLRR R0 0x53ac TESTPIECE: 53ac 01c0 CLRR R0 ; Start with color = 0, LSB = 0 53ad 0275 PSHR R5 ; Save return address 53ae 02bc 0130 MVII #@@colsv, R4 ; Point R4 at save area 53b0 0004 0150 0398 CALL PUTPIECEREC 53b3 0242 0136 MVO R2, @@miny ; Start with Min Y == pivot point ; Convert piece number to control word. 53b5 02fb 537c ADDI #PIECE, R3 ; Point into PIECE array entry for piece 53b7 029b MVI@ R3, R3 ; Get the piece control word 53b8 02bc 0003 MVII #3, R4 ; At least four moves in piece 0x53ba @@loop: 53ba 0098 MOVR R3, R0 ; Copy Piece Control Word 53bb 03b8 0002 ANDI #2, R0 ; Get sign for move (set == +1, clear == -1) 53bd 0010 DECR R0 ; R0 is either +1/-1 according to move 53be 007f SARC R3, 2 ; Shift move away from PCW. Carry==axis 53bf 0201 0008 BC @@xaxis ; Carry Clear == Y-Axis, Carry Set == X-Axis 53c1 00c2 ADDR R0, R2 ; Add move to Y axis ; See if this Y coordinate is our new min-Y coord 53c2 0342 0136 CMP @@miny, R2 53c4 020d 0004 BGE @@cont 53c6 0242 0136 MVO R2, @@miny 53c8 000f INCR PC ; Skip add-to-X (next instruction) 0x53c9 @@xaxis: 53c9 00c1 ADDR R0, R1 ; Add move to X axis 0x53ca @@cont: ; Note, at most 8 bits remain in PCW here, so we save in 8-bit loc. 53ca 0243 0134 MVO R3, @@pcwsv ; Save remaining Piece Control Word (max 8 bit) 53cc 0244 0135 MVO R4, @@cntsv ; Save our loop trip count 53ce 0280 0130 MVI @@colsv, R0 ; Get saved color 53d0 0078 SARC R0, 1 ; If bit-0 set, this is DRAW, else TEST 53d1 0201 0014 BC @@draw ; 0x53d3 @@test: ; Note R0 should be 0 here. This treats off-screen pixels as black, ; which is what we want. 53d3 0379 000f CMPI #EDGEL, R1 ; Are we off left? 53d5 0205 0022 BLT @@notok ; Yes: Bad! 53d7 0379 0018 CMPI #EDGER, R1 ; Are we off left? 53d9 020e 001e BGT @@notok ; Yes: Bad! 53db 0004 0150 02eb CALL GETPIXELSC ; Get pixel, with clipping. 53de 0378 0007 CMPI #7, R0 ; Ignore color 7, since we use that 53e0 0204 0008 BEQ @@pixelok ; for the active piece. 53e2 0080 TSTR R0 ; Otherwise, make sure it's black. 53e3 0204 0005 BEQ @@pixelok ; 53e5 0200 0012 B @@notok ; Didn't pass the tests? It's not ok then. 0x53e7 @@draw: 53e7 0004 0150 030a CALL PUTPIXELSCQ ; Put the pixel on the screen, with clipping. 0x53ea @@pixelok: 53ea 0283 0134 MVI @@pcwsv, R3 ; Get our saved piece number 53ec 0284 0135 MVI @@cntsv, R4 ; Get our loop trip count. 53ee 0014 DECR R4 53ef 0223 0036 BPL @@loop ; Loop as long as R4 > 0 53f1 01e4 CLRR R4 53f2 009b TSTR R3 ; See if this is a 5-move piece. 53f3 022c 003a BNEQ @@loop ; Loop one last time if it is. 53f5 0280 0130 MVI @@colsv, R0 ; Restore color register (if TESTPIECE is ok, 53f7 0060 SLR R0, 1 ; ...OR if this is DRAWPIECE). 53f8 000f INCR PC ; (skip the MOVR.) 0x53f9 @@notok: ; Else, skip the restore if TESTPIECE and 53f9 00b8 MOVR PC, R0 ; ...pixel is not ok, so force R0 non-zero 53fa 02bc 0131 MVII #@@pvxsv, R4 ; Point to save area + 1 53fc 0004 0150 039e CALL GETPIECEREC.NC 53ff 0284 0136 MVI @@miny, R4 ; Get minimum Y value into R4 5401 02b7 PULR PC ; Return to the caller ENDP ;;==========================================================================;; ;; GETPIECECOLOR ;; ;; Gets Piece Color, given the piece number/rotation. ;; ;; ;; ;; INPUTS: ;; ;; R3 -- Piece number/rot. Bits 0..1 are rotation, Bits 2..4 are piece # ;; ;; R5 -- Return address ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- Piece color ;; ;;==========================================================================;; 0x5402 GETPIECECOLOR PROC 5402 0273 PSHR R3 ; Save R3 so that it's not clobbered 5403 0067 SLR R3, 2 ; Generate index into color table 5404 02fb 5409 ADDI #@@color,R3 ; R3 = PCCOLOR[piece] 5406 0298 MVI@ R3, R0 ; Get the piece color into R0 5407 02b3 PULR R3 ; Restore R3 5408 00af JR R5 ; Return. 5409 0002 0001 0003 @@color BYTE $2, $1, $3, $4, $5, $6, $1 540c 0004 0005 0006 0001 ENDP ;;==========================================================================;; ;; PICKPIECE ;; ;; Grabs the 'next piece' and makes it the current piece. Then picks a ;; ;; new 'next piece'. ;; ;;==========================================================================;; 0x5410 PICKPIECE PROC 5410 0275 PSHR R5 0x5411 @@chain: 0x5411 @@randloop: 5411 02ba 0004 MVII #4, R2 ; Generate some new random bits 5413 0004 0158 02be CALL NEXTRANDX 5416 03b8 001c ANDI #$1C, R0 ; Mask to [0..7] * 4 5418 0224 0008 BEQ @@randloop ; If it comes up 0, try again 541a 0338 0004 SUBI #4, R0 ; Make into piece #0..#6 541c 0004 0154 02ac CALL NEXTCLEAR ; Clear previous 'next-piece' 541f 0283 01ae MVI NXTPC, R3 ; Get previous 'next-piece'. 5421 0240 01ae MVO R0, NXTPC ; Save new 'next-piece'. 5423 0281 01ad MVI SHOWNXT, R1 ; Are we showing next piece? 5425 0241 01eb MVO R1, DIDNXT ; Initialize our "showed next piece" flag 5427 0089 TSTR R1 5428 0204 0005 BEQ @@noshow 542a 0273 PSHR R3 ; Save R3 -- new current piece number 542b 0004 0154 02a8 CALL NEXTSHOW ; Show next piece 542e 02b3 PULR R3 ; Restore R3 0x542f @@noshow: 542f 0004 0154 0002 CALL GETPIECECOLOR ; Get the current piece's color. 5432 0240 0029 MVO R0, CS1 ; Force color-stack to piece's color 5434 0240 002b MVO R0, CS3 ; Force color-stack to piece's color 5436 02b9 0014 MVII #EDGEL+5, R1 ; Start out in middle of well... 5438 02ba 0003 MVII #3, R2 ; ...just a little off top of screen 543a 001a COMR R2 ; (Y = -3) 543b 02bc 013b MVII #CURPC.C, R4 ; Write to "current piece" record. 543d 0004 0150 0398 CALL PUTPIECEREC ; Make this the current piece. 5440 02b7 PULR PC ; Return. ENDP ;;==========================================================================;; ;; CLEARWELL ;; ;; Clears the well in a dramatic fashion ;; ;;==========================================================================;; 0x5441 CLEARWELL PROC 0x1e2 @@bot EQU $1E2 5441 0275 PSHR R5 5442 01c0 CLRR R0 5443 0240 013b MVO R0, CURPC.C ; make sure current piece number is cleared. 0x5445 @@wellloop: 5445 02bb 0015 MVII #EDGEB, R3 5447 0343 01ec CMP HEIGHT, R3 ; R3 has actual well height. 5449 0206 0026 BLE @@return ; Do nothing if well is empty. 0x544b @@randloop: 544b 02ba 0005 MVII #5, R2 544d 0004 0158 02be CALL NEXTRANDX ; Get a random number (advance by 5 bits) 5450 03b8 001f ANDI #31, R0 5452 02c0 01ec ADD HEIGHT, R0 5454 0158 CMPR R3, R0 ; Make sure it's less than the well height. 5455 022d 000b BGE @@randloop 5457 0082 MOVR R0, R2 5458 02b9 0010 MVII #EDGEL+1, R1 545a 0004 0150 02cd CALL GETPIXELS 545d 0378 0007 CMPI #7, R0 545f 0204 0005 BEQ @@nukeit 0x5461 @@fillit: 5461 0004 0154 007a CALL NUKELINE 5464 0220 0020 B @@wellloop 0x5466 @@nukeit: 5466 0242 01e2 MVO R2, @@bot 5468 0004 0150 020d CALL WAIT ; Wait a few ticks 546b 0002 DECLE 2 ; 546c 02bd 5445 MVII #@@wellloop, R5 546e 0275 PSHR R5 546f 0200 00b5 B DOSCORE.nukeit ; Nuke the line, collapsing the well. ; This will return to @@wellloop 0x5471 @@return: 5471 02b7 PULR PC ; Return. ENDP ;;==========================================================================;; ;; SCOREDROP ;; ;; Loops over a four line window and marks rows for deletion. ;; ;; Returns line-clearing score in R0 and leaves lines to be cleared set ;; ;; to color #7. ;; ;; ;;