********************************************************************* * * Isometric demo * * For the TI-99/4A Home Computer * * Created by Rasmus Moustgaard in 2015 * rasmus.moustgaard@gmail.com * DEF START ** * Misc memory addresses VDPRD EQU >8800 * VDP read data VDPSTA EQU >8802 * VDP status VDPWD EQU >8C00 * VDP write data VDPWA EQU >8C02 * VDP set read/write address RNDSD EQU >83C0 * Random number seed SOUND EQU >8400 * Sound ** * VDP Memory Map NAMETB EQU >1800 * Name table base COLRTB EQU >2000 * Color table base SPRATB EQU >1B00 * Sprite attribute table base PTRNTB EQU >0000 * Pattern table base SPRPTB EQU >3800 * Sprite pattern table base ** * Scratch pad WRKSP EQU >8300 * Workspace R0LB EQU WRKSP+1 * R0 low byte reqd for VDP routines R1LB EQU WRKSP+3 R2LB EQU WRKSP+5 R3LB EQU WRKSP+7 R4LB EQU WRKSP+9 R5LB EQU WRKSP+11 R6LB EQU WRKSP+13 R7LB EQU WRKSP+15 R8LB EQU WRKSP+17 R9LB EQU WRKSP+19 STACK EQU >8320 SEVEN EQU STACK+16 XINC EQU SEVEN+2 YINC EQU XINC+2 ZINC EQU YINC+2 MAPPOS EQU ZINC+2 MAPX EQU MAPPOS+2 MAPY EQU MAPX+2 MAPZ EQU MAPY+2 XPOS EQU MAPZ+2 YPOS EQU XPOS+2 ZPOS EQU YPOS+2 XOFFS EQU ZPOS+2 YOFFS EQU XOFFS+2 ZOFFS EQU YOFFS+2 ** * Constants SCRBUF EQU >2000 * CPU RAM screen buffer (6K) XORG EQU 128 YORG EQU 48 XSIZE EQU 32 YSIZE EQU 28 BSIZE EQU XSIZE/8*YSIZE MAPSZX EQU 8 MAPSZY EQU 8 MAPSZZ EQU 4 XINCR EQU 16 YINCR EQU 8 ZINCR EQU 11 SPRBW EQU 10 * Sprite buffer width SPRBH EQU 80 * Sprite buffer height SPRBSZ EQU SPRBW*SPRBH * Sprite buffer size ******************************************************************************** * * Main program * AORG >A000 START LIMI 0 LWPI WRKSP LI R10,STACK * Setup constants LI R0,7 MOV R0,@SEVEN LI R0,XINCR MOV R0,@XINC LI R0,YINCR MOV R0,@YINC LI R0,ZINCR MOV R0,@ZINC * Graphics mode BL @GMODE * Cear buffer * BL @CLRB BL @FILLB * Display map BL @DSPMAP * Copy buffer BL @CPYB * Initialize sprites BL @INISPR * Main loop LOOP BL @VSYNC * Mask sprite BL @SPRMSK * Display sprite BL @VSYNC BL @DSPSPR * Read joystick BL @JOYST * Check for quit BL @CKQUIT * Loop JMP LOOP ********************************************************************* * * Wait for vertical retrace (CRU) * VSYNC CLR R12 VSYNC1 TB 2 * Test CRU bit for VDP interrupt JEQ VSYNC1 MOVB @VDPSTA,R0 B *R11 *// VSYNC ********************************************************************* * * Read joystick * JOYST MOV R11,*R10+ * Push return address onto the stack LI R12,>0024 * CRU address of the column decoder LI R0,>0600 * Column 6, i.e joystick #1 LDCR R0,3 * Select it LI R12,>0006 * Base CRU address for joystick 1 * Init variables CLR R0 * Fire flag CLR R1 * DX CLR R2 * DY * Fire button TB 0 JEQ JOYST0 SETO R0 * Left JOYST0 TB 1 JEQ JOYST1 MOV @YPOS,R3 CI R3,62 JGT JOYST2 LI R2,1 JMP JOYST2 * Right JOYST1 TB 2 JEQ JOYST2 MOV @YPOS,R3 CI R3,1 JLT JOYST2 SETO R2 * Down JOYST2 TB 3 JEQ JOYST3 MOV @XPOS,R3 CI R3,62 JGT JOYST4 LI R1,1 JMP JOYST4 * Up JOYST3 TB 4 JEQ JOYST4 MOV @XPOS,R3 CI R3,1 JLT JOYST4 SETO R1 * Move sprite JOYST4 MOV R1,R3 MOV R2,R4 A R1,@XPOS A R2,@YPOS BL @MAPADR MOV @MAPPOS,R5 MOVB *R5,R6 JEQ JOYST5 S R3,@XPOS S R4,@YPOS * Return JOYST5 DECT R10 * Pop return address off the stack MOV *R10,R11 B *R11 *// JOYST ********************************************************************* * * Check for quit * CKQUIT CLR R1 * Test column 0 LI R12,>0024 * Address for column selection LDCR R1,3 * Select column LI R12,>0006 * Address to read rows STCR R1,8 ANDI R1,>1100 JEQ QUIT B *R11 * Quit QUIT BLWP @>0000 ********************************************************************* * * Display map * DSPMAP MOV R11,*R10+ * Push return address onto the stack LI R0,MAP00 MOV R0,@MAPPOS MOV @XPOS0,@XPOS * Init x position LI R0,XSIZE/2 S R0,@XPOS MOV @YPOS0,@YPOS * Init y position CLR @MAPZ * z index DSPMA1 CLR @MAPY * y index MOV @XPOS,@XPOS2 * Save x position MOV @YPOS,@YPOS2 * Save y position DSPMA2 CLR @MAPX * x index MOV @XPOS,@XPOS1 * Save x position MOV @YPOS,@YPOS1 * Save y position DSPMA3 MOV @XPOS,R0 * x coordinate MOV @YPOS,R1 * y coordinate LI R2,XSIZE/8 * Width in bytes (of 8 pixels) LI R3,YSIZE * Height in pixels MOV @MAPPOS,R5 * Get map address CLR R4 MOVB *R5,@R4LB * Get map block index JEQ DSPMA4 * Zero means empty DEC R4 * Index of non-empty block MPY @BSIZE0,R4 * Multiply by block size MOV R5,R4 * Duplicate result AI R4,PATTS * Add patterns base address AI R5,MASKS * Add masks base address BL @SFTSPR * Display block * BL @BLOCK * Display block DSPMA4 INC @MAPPOS * Next map position A @XINC,@XPOS * Move x position A @YINC,@YPOS * Move y position MOV @MAPX,R0 * Get x index INC R0 * Increment x index MOV R0,@MAPX * Write it back CI R0,MAPSZX * Check if done JNE DSPMA3 * x loop MOV @XPOS1,@XPOS * Restore x position MOV @YPOS1,@YPOS * Restore y position S @XINC,@XPOS * Move x position A @YINC,@YPOS * Move y position MOV @MAPY,R0 * Get y index INC R0 * Increment y index MOV R0,@MAPY * Write it back CI R0,MAPSZY * Check if done JNE DSPMA2 * y loop MOV @XPOS2,@XPOS * Restore x position MOV @YPOS2,@YPOS * Restore y position S @ZINC,@YPOS * Move y position MOV @MAPZ,R0 * Get z index INC R0 * Increment y index MOV R0,@MAPZ * Write it back CI R0,MAPSZZ * Check if done JNE DSPMA1 * z loop * Return DECT R10 * Pop return address off the stack MOV *R10,R11 B *R11 *// DSPMAP ********************************************************************* * * Display a block at an even byte address (i.e. x mod 8 = 0) * The pattern must be provided as a natural bitmap of R3 lines of * 8 * R2 pixels where a line extends all the way across the sprite. * * R0 x coordinate * R1 y coordinate * R2 Width in bytes (of 8 pixels) * R3 Height in pixels * R4 Pattern address * R5 Mask address * BLOCK MOV R11,*R10+ * Push return address onto the stack BL @SCRADR * R6 = byte offset, R7 = bit offset AI R6,SCRBUF * Add screen buffer offset * Line loop BLOCK2 MOV R2,R12 * Save the width BLOCK3 MOV R6,R7 * Save the destination address CLR R8 * Pattern register CLR R9 * Mask register * Byte loop MOV R12,R2 * Restore width BLOCK4 MOVB *R4+,R8 * Get pattern byte MOVB *R5+,R9 * Get mask byte MOVB *R6,R1 * Get existing screen buffer byte SZCB R9,R1 * Remove bits not set in mask SOCB R8,R1 * Set pattern bits MOVB R1,*R6 * Write byte back AI R6,8 * Next byte in line DEC R2 JNE BLOCK4 * Next line MOV R7,R6 * Restore destination address COC @SEVEN,R6 * Check for last character row JEQ BLOCK6 INC R6 * Next row within character JMP BLOCK7 BLOCK6 AI R6,256-7 * First row of next character BLOCK7 DEC R3 JNE BLOCK3 * Return DECT R10 * Pop return address off the stack MOV *R10,R11 B *R11 *// SFTSPR ********************************************************************* * * Display a soft sprite at any position * The pattern must be provided as a natural bitmap of R3 lines of * 8 * R2 pixels where a line extends all the way across the sprite. * * R0 x coordinate * R1 y coordinate * R2 Width in bytes (of 8 pixels) * R3 Height in pixels * R4 Pattern address * R5 Mask address * SFTSPR MOV R11,*R10+ * Push return address onto the stack BL @SCRADR * R6 = byte offset, R7 = bit offset AI R6,SCRBUF * Add screen buffer offset * Setup shift instructions LI R1,8 * 8 S R7,R1 * 8 - bit offset SLA R1,4 * Move into place for SLA instruction MOV @SLAX,R0 * Get op code for SLA Rx,0 SOC R1,R0 * Set shift MOV R0,@SLAX1 * Write into program MOV @SLAY,R0 * Get op code for SLA Ry,0 SOC R1,R0 * Set shift MOV R0,@SLAY1 * Write into program * 2nd group of shifts MOV R7,R1 * Bit offset JEQ SFTSP1 * Check if shift would be zero SLA R1,4 * Move into place for SLA instruction MOV @SLAX,R0 * Get op code for SLA Rx,0 SOC R1,R0 * Set shift MOV R0,@SLAX2 * Write into program MOV @SLAY,R0 * Get op code for SLA Ry,0 SOC R1,R0 * Set shift MOV R0,@SLAY2 * Write into program JMP SFTSP2 * Replace shifts with nops SFTSP1 MOV @NOOP,R0 MOV R0,@SLAX2 MOV R0,@SLAY2 * Line loop SFTSP2 MOV R2,R12 * Save the width SFTSP3 MOV R6,R7 * Save the destination address CLR R8 * Pattern register CLR R9 * Mask register * Byte loop MOV R12,R2 * Restore width SFTSP4 MOVB *R4+,@R8LB * Get pattern byte in LSB MOVB *R5+,@R9LB * Get mask byte in LSB SLAX1 SLA R8,0 * Shift (8 - bit offset) bits into MSB SLAY1 SLA R9,0 * Actual shift values will be inserted MOVB *R6,R1 * Get existing screen buffer byte SZCB R9,R1 * Remove bits not set in mask SOCB R8,R1 * Set pattern bits MOVB R1,*R6 * Write byte back AI R6,8 * Next byte in line DEC R2 JEQ SFTSP5 SLAX2 SLA R8,0 * Shift (bit offset) bits into MSB SLAY2 SLA R9,0 * Actual shift values will be inserted JMP SFTSP4 * Final byte SFTSP5 SWPB R8 SWPB R9 MOVB *R6,R1 * Get existing screen buffer byte SZCB R9,R1 * Remove bits not set in mask SOCB R8,R1 * Set pattern bits MOVB R1,*R6 * Write byte back * Next line MOV R7,R6 * Restore destination address COC @SEVEN,R6 * Check for last character row JEQ SFTSP6 INC R6 * Next row within character JMP SFTSP7 SFTSP6 AI R6,256-7 * First row of next character SFTSP7 DEC R3 JNE SFTSP3 * Return DECT R10 * Pop return address off the stack MOV *R10,R11 B *R11 * Instructions SLAX SLA R8,0 SLAY SLA R9,0 NOOP NOP *// SFTSPR ********************************************************************* * * Calculate the map address corresponding to the current * sprite position specified by @XPOS, @YPOS, @ZPOS. * * On return: * @MAPPOS contains the map address * @MAPX, @MAPY, @MAPZ contain the map indexes. * @XOFFS, @YOFFS, @ZOFFS contain the sprite offsets from map block origin. * R0-R2 are modified. * MAPADR * z CLR R0 MOV @ZPOS,R1 * z DIV @ZINC,R0 * z div 11 MOV R0,@MAPZ * z index = z div 11 MOV R1,@ZOFFS * z offset = z mod 11 SLA R0,6 * (z div 11) * 64 (selects map floor) * y MOV @YPOS,R1 * y MOV R1,R2 * Make a copy SRL R1,3 * y div 8 MOV R1,@MAPY * y index = y div 8 SLA R1,3 * (y div 8) * 8 (selects map row) A R1,R0 * (z div 11) * 64 + (y div 8) * 8 ANDI R2,7 * y mod 8 MOV R2,@YOFFS * y offset = y mod 8 * x MOV @XPOS,R1 * x MOV R1,R2 * Make a copy SRL R1,3 * x div 8 (selects block within row) MOV R1,@MAPX * x index = x div 8 A R1,R0 * (z div 11) * 64 + (y div 8) * 8 + (x div 8) ANDI R2,7 * x mod 8 MOV R2,@XOFFS * x offset = x mod 8 * Finalize address AI R0,MAP01 * Map offset is from ground floor MOV R0,@MAPPOS * Store it * Return B *R11 *// MAPADR ********************************************************************* * * Calculate screen address and bit mask from coordinates * Based on E/A manual page 336 * * R0 x value * R1 y value * * On return: * R6 Set to byte offset * R7 Set to bit offset * SCRADR MOV R1,R6 * 00000000yyyyyyyy SLA R6,5 * 000yyyyyyyy00000 SOC R1,R6 * 000yyyyy???yyyyy ANDI R6,>FF07 * 000yyyyy00000yyy MOV R0,R7 * 00000000xxxxxxxx ANDI R7,7 * 0000000000000xxx A R0,R6 * 000yyyyyxxxxx??? S R7,R6 * 000yyyyyxxxxxyyy * Return B *R11 *// SCRDDR ********************************************************************* * * Clear CPU RAM screen buffer * CLRB LI R0,SCRBUF LI R2,>1800/8 CLRB1 CLR *R0+ CLR *R0+ CLR *R0+ CLR *R0+ DEC R2 JNE CLRB1 B *R11 CLRBE *// CLRB ********************************************************************* * * Fill CPU RAM screen buffer * FILLB LI R0,SCRBUF LI R2,>1800/8 FILLB1 SETO *R0+ SETO *R0+ SETO *R0+ SETO *R0+ DEC R2 JNE FILLB1 B *R11 FILLBE *// FILLB ********************************************************************* * * Copy CPU RAM screen buffer to VDP RAM * CPYB CLR R0 LI R1,SCRBUF MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address ORI R0,>4000 * Set read/write bits 14 and 15 to write (01) MOVB R0,@VDPWA * Send high byte of VDP RAM write address LI R0,VDPWD LI R2,>1800/8 CPYB1 MOVB *R1+,*R0 * Write byte to VDP RAM MOVB *R1+,*R0 * Write byte to VDP RAM MOVB *R1+,*R0 * Write byte to VDP RAM MOVB *R1+,*R0 * Write byte to VDP RAM MOVB *R1+,*R0 * Write byte to VDP RAM MOVB *R1+,*R0 * Write byte to VDP RAM MOVB *R1+,*R0 * Write byte to VDP RAM MOVB *R1+,*R0 * Write byte to VDP RAM DEC R2 * Byte counter JNE CPYB1 * Check if done B *R11 CPYBE *// CPYBE ********************************************************************************* * * Display sprite * DSPSPR MOV R11,*R10+ * Push return address onto the stack * x pos MOV @XPOS,R1 * x S @YPOS,R1 * x - y SLA R1,1 * 2(x - y) A @XPOS0,R1 * 2(x - y) + x0 AI R1,-8 * Center sprite CI R1,32 * Check if early clock should be set JLT DSPSP3 CLR R4 * Clear flag JMP DSPSP4 DSPSP3 SETO R4 * Set flag AI R1,32 * Adjust x for EC * y pos DSPSP4 MOV @XPOS,R2 * x A @YPOS,R2 * x + y S @ZPOS,R2 * x + y - z A @YPOS0,R2 * x + y - z + y0 AI R2,-32 * Top of sprite * Combine x and y MOV R2,R3 * Get y SWPB R3 * Move to MSB SOC R1,R3 * Combine with x * Write to CPU RAM buffer LI R0,SPRATT LI R2,>0080 * Early clock bit ABS R4 * Check if early clock should be set JNE DSPSP1 * No early clock MOV R3,*R0+ * Write y and x SZC R2,*R0+ * Clear EC MOV R3,*R0+ * Write y and x SZC R2,*R0+ * Clear EC AI R3,>1000 * Adjust y for 2nd sprite MOV R3,*R0+ * Write y and x SZC R2,*R0+ * Clear EC MOV R3,*R0+ * Write y and x SZC R2,*R0+ * Clear EC JMP DSPSP2 * Early clock DSPSP1 MOV R3,*R0+ * Write y and x SOC R2,*R0+ * Set EC MOV R3,*R0+ * Write y and x SOC R2,*R0+ * Set EC AI R3,>1000 * Adjust y for 2nd sprite MOV R3,*R0+ * Write y and x SOC R2,*R0+ * Set EC MOV R3,*R0+ * Write y and x SOC R2,*R0+ * Set EC * Write to VDP DSPSP2 LI R0,SPRATB LI R1,SPRATT LI R2,64 BL @VMBW * Apply mask to pattern and write to VDP LI R0,SPRPTB * Setup VDP write address BL @VWAD LI R0,SPR1 LI R1,SBSPAD * Address of mask in sprite buffer BL @SPRPAT LI R0,SPR2 LI R1,SBSPAD * Address of mask in sprite buffer BL @SPRPAT LI R0,SPR3 LI R1,16*SPRBW+SBSPAD * Address of mask in sprite buffer BL @SPRPAT LI R0,SPR4 LI R1,16*SPRBW+SBSPAD * Address of mask in sprite buffer BL @SPRPAT * Return DECT R10 * Pop return address off the stack MOV *R10,R11 B *R11 *// DSPSPR ********************************************************************************* * * Apply mask to sprite pattern and write to VDP * * R0 contains sprite pattern address * R1 contains sprite mask address (in sprite buffer) * VDP write address must already be set up * SPRPAT LI R6,VDPWD LI R3,2 * Column counter SPRPA1 MOV R1,R5 LI R2,16 * Line counter SPRPA2 MOVB *R0+,R4 * Get pattern byte SZCB *R1,R4 * Apply mask MOVB R4,*R6 * Upload to VDP AI R1,SPRBW * Next line DEC R2 JNE SPRPA2 * Line loop MOV R5,R1 * Restore mask address INC R1 * Next column DEC R3 JNE SPRPA1 * Column loop * Return B *R11 *// SPRPAT ********************************************************************************* * * Create sprite mask * * Clear the sprite area marked with 0s on the first figure. * Then draw the areas of the surrounding block masks as on the second figure. * The result is a mask that can be used to remove hidden areas from the * sprite patterns before copying them to the VDP. * * .......... .......... * .......... .......... * .......... ......11.. * ....00.... ....01111. 01 * ....00.... ..110011.. 00 * ....00.... .11110.... 10 * ....00.... ..1100.... 00 * .......... .......11. * .......... ......1111 * .......... .......11. * SPRMSK MOV R11,*R10+ * Push return address onto the stack * Clear sprite area LI R0,SBSPAD LI R2,32 SPRMS1 CLR *R0 * Clear 16 pixels AI R0,SPRBW DEC R2 JNE SPRMS1 * Get the map address of the block where the sprite is located BL @MAPADR * Address in @MAPADR * Calculate sprite offset from block origin in screen coordinates MOV @XOFFS,R0 * x mod 8 S @YOFFS,R0 * (x mod 8) - (y mod 8) SLA R0,1 * dx = 2 * ((x mod 8) - (y mod 8)) * AI R0,16 MOV R0,@XOFFS1 MOV @XOFFS,R1 * x mod 8 A @YOFFS,R1 * (x mod 8) + (y mod 8) S @ZOFFS,R1 * dy = (x mod 8) + (y mod 8) - (z mod 11) MOV R1,@YOFFS1 * Draw masks LI R12,BMLIST SPRMS3 MOV *R12+,R13 * Get x offset JLT SPRMS2 * List ends with -1 MOV *R12+,R14 * Get y offset MOV *R12+,R15 * Get z offset MOV R12,@BMLPTR * Check x bounds LI R0,7 S @MAPX,R0 S R13,R0 JLT SPRMS3 * Check y bounds LI R0,7 S @MAPY,R0 S R14,R0 JLT SPRMS3 * Check z bounds LI R0,2 S @MAPZ,R0 S R15,R0 JLT SPRMS3 * Bounds ok LI R0,24 LI R1,60-16 MOV @MAPPOS,R5 * x offset MOV R13,R13 JEQ SPRMS5 SPRMS4 AI R0,XINCR AI R1,YINCR INC R5 DEC R13 JNE SPRMS4 * y offset SPRMS5 MOV R14,R14 JEQ SPRMS7 SPRMS6 AI R0,-XINCR AI R1,YINCR AI R5,8 DEC R14 JNE SPRMS6 * z offset SPRMS7 MOV R15,R15 JEQ SPRMS9 SPRMS8 AI R1,-ZINCR AI R5,64 DEC R15 JNE SPRMS8 * Calculate mask address SPRMS9 CLR R4 MOVB *R5,@R4LB * Get map block index JEQ SPRMS3 DEC R4 * Index of non-empty block MPY @BSIZE0,R4 * Multiply by block size AI R5,MASKS * Add masks base address * Draw mask S @XOFFS1,R0 S @YOFFS1,R1 BL @BLCMSK * Next block mask MOV @BMLPTR,R12 JMP SPRMS3 * Return SPRMS2 DECT R10 * Pop return address off the stack MOV *R10,R11 B *R11 * List of block masks to draw specified as index offsets from base (x,y,z) BMLPTR DATA 0 BMLIST DATA 0,1,0 DATA 1,1,0 DATA 1,0,0 * Level 1 DATA 0,1,1 DATA 1,1,1 DATA 1,0,1 DATA 2,1,1 DATA 2,2,1 DATA 1,2,1 * Level 2 DATA 0,1,2 DATA 1,1,2 DATA 1,0,2 DATA 2,1,2 DATA 2,2,2 DATA 1,2,2 DATA -1 *// SPRMSK ********************************************************************* * * Display a block mask in the sprite buffer * The buffer is structured as a natural bitmap SPRBW bytes wide * and SPRBH lines high. Mask is also a natural bitmap. * * R0 x coordinate * R1 y coordinate * R5 Mask address * BLCMSK MOV R11,*R10+ * Push return address onto the stack * Calculate dest address MOV R0,R6 * x SRL R6,3 * x div 8 LI R2,SPRBW * Buffer width MPY R2,R1 * R2 = y * width A R2,R6 * R6 = byte offset AI R6,SPRBUF * Add sprite buffer base MOV R0,R7 * x ANDI R7,7 * R7 = x mod 8 = bit offset LI R2,XSIZE/8 * Width in bytes (of 8 pixels) LI R3,YSIZE * Height in pixels * Setup shift instructions LI R1,8 * 8 S R7,R1 * 8 - bit offset SLA R1,4 * Move into place for SLA instruction MOV @SLAY,R0 * Get op code for SLA Ry,0 SOC R1,R0 * Set shift MOV R0,@SLAY1M * Write into program * 2nd shift MOV R7,R1 * Bit offset JEQ BLCMS1 * Check if shift would be zero SLA R1,4 * Move into place for SLA instruction MOV @SLAY,R0 * Get op code for SLA Ry,0 SOC R1,R0 * Set shift MOV R0,@SLAY2M * Write into program JMP BLCMS2 * Replace shift with nop BLCMS1 MOV @NOOP,R0 MOV R0,@SLAY2M * Line loop BLCMS2 MOV R2,R12 * Save the width BLCMS3 MOV R6,R7 * Save the destination address CLR R9 * Mask register * Byte loop MOV R12,R2 * Restore width BLCMS4 MOVB *R5+,@R9LB * Get mask byte in LSB SLAY1M SLA R9,0 * Actual shift values will be inserted SOCB R9,*R6+ * Set mask bits DEC R2 JEQ BLCMS5 SLAY2M SLA R9,0 * Actual shift values will be inserted JMP BLCMS4 * Final byte BLCMS5 SWPB R9 SOCB R9,*R6 * Set mask bits * Next line MOV R7,R6 * Restore destination address AI R6,SPRBW DEC R3 JNE BLCMS3 * Return DECT R10 * Pop return address off the stack MOV *R10,R11 B *R11 *// BLCMSK ********************************************************************************* * * Initialize sprite * INISPR MOV R11,*R10+ * Push return address onto the stack LI R0,SPRPTB LI R1,SPR1 LI R2,128 BL @VMBW LI R0,SPRATB LI R1,SPRATT LI R2,33 BL @VMBW LI R0,36 MOV R0,@XPOS LI R0,36 MOV R0,@YPOS LI R0,0 MOV R0,@ZPOS * Return DECT R10 * Pop return address off the stack MOV *R10,R11 B *R11 *// INISPR ********************************************************************************* * * Set graphics mode * GMODE MOV R11,*R10+ * Push return address onto the stack CLR R0 LI R1,VREGS LI R2,8 GMODE1 MOVB *R1+,@R0LB BL @VWTR * Set register AI R0,>0100 DEC R2 JNE GMODE1 * Initialize Name Table LI R0,NAMETB LI R2,>300-1 CLR R1 BL @VSBW NTINIT AI R1,>0100 MOVB R1,@VDPWD DEC R2 JNE NTINIT * Initialize the Pattern Table LI R0,PTRNTB LI R1,>FF00 LI R2,>1800 BL @VSMW * Initialize the Color Table LI R0,COLRTB LI R1,>F100 * White pixels on black background LI R2,>1800 BL @VSMW * Disable sprites LI R0,SPRATB LI R1,>D000 BL @VSBW * Return DECT R10 * Pop return address off the stack MOV *R10,R11 B *R11 VREGS BYTE >02 * Graphics II mode BYTE >E2 * 16K, display on, interrupt enabled BYTE >06 * NAMETB = >1800 BYTE >FF * COLRTB = >2000 BYTE >03 * PTRNTB = >0000 BYTE >36 * SPRATB = >1B00 BYTE >07 * SPRPTB = >3800 BYTE >0F * Backdrop color *// GMODE ********************************************************************* * * VDP Set Read Address * * R0 Address to set VDP address counter to * VRAD MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address ANDI R0,>3FFF * Make sure the two MSbits are 00 for read MOVB R0,@VDPWA * Send high byte of VDP RAM write address B *R11 *// VRAD ********************************************************************* * * VDP Set Write Address * * R0 Address to set VDP address counter to * VWAD MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address ORI R0,>4000 * Set the two MSbits to 01 for write MOVB R0,@VDPWA * Send high byte of VDP RAM write address ANDI R0,>3FFF * Restore R0 top two MSbits B *R11 *// VWAD / VRAD ********************************************************************* * * VDP Single Byte Write * * R0 Write address in VDP RAM * R1 MSB of R1 sent to VDP RAM * * R0 is modified, but can be restored with: ANDI R0,>3FFF * VSBW MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address ORI R0,>4000 * Set read/write bits 14 and 15 to write (01) MOVB R0,@VDPWA * Send high byte of VDP RAM write address MOVB R1,@VDPWD * Write byte to VDP RAM B *R11 *// VSBW ********************************************************************* * * VDP Single Byte Multiple Write * * R0 Starting write address in VDP RAM * R1 MSB of R1 sent to VDP RAM * R2 Number of times to write the MSB byte of R1 to VDP RAM * * R0 is modified, but can be restored with: ANDI R0,>3FFF * VSMW MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address ORI R0,>4000 * Set read/write bits 14 and 15 to write (01) MOVB R0,@VDPWA * Send high byte of VDP RAM write address VSMWLP MOVB R1,@VDPWD * Write byte to VDP RAM DEC R2 * Byte counter JNE VSMWLP * Check if done B *R11 *// VSMW ********************************************************************* * * VDP Multiple Byte Write * * R0 Starting write address in VDP RAM * R1 Starting read address in CPU RAM * R2 Number of bytes to send to the VDP RAM * * R0 is modified, but can be restored with: ANDI R0,>3FFF * VMBW MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address ORI R0,>4000 * Set read/write bits 14 and 15 to write (01) MOVB R0,@VDPWA * Send high byte of VDP RAM write address VMBWLP MOVB *R1+,@VDPWD * Write byte to VDP RAM DEC R2 * Byte counter JNE VMBWLP * Check if done B *R11 *// VMBW ********************************************************************* * * VDP Single Byte Read * * R0 Read address in VDP RAM * R1 MSB of R1 set to byte from VDP RAM * VSBR MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address MOVB R0,@VDPWA * Send high byte of VDP RAM write address MOVB @VDPRD,R1 * Read byte from VDP RAM B *R11 *// VSBR ********************************************************************* * * VDP Multiple Byte Read * * R0 Starting read address in VDP RAM * R1 Starting write address in CPU RAM * R2 Number of bytes to read from VDP RAM * VMBR MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address MOVB R0,@VDPWA * Send high byte of VDP RAM write address VMBRLP MOVB @VDPRD,*R1+ * Read byte from VDP RAM DEC R2 * Byte counter JNE VMBRLP * Check if finished B *R11 *// VMBR ********************************************************************* * * VDP Write To Register * * R0 MSB VDP register to write to * R0 LSB Value to write * VWTR MOVB @R0LB,@VDPWA * Send low byte (value) to write to VDP register ORI R0,>8000 * Set up a VDP register write operation (10) MOVB R0,@VDPWA * Send high byte (address) of VDP register B *R11 *// VWTR ********************************************************************* * Global variables and data * XPOS0 DATA XORG YPOS0 DATA YORG XPOS1 DATA 0 YPOS1 DATA 0 XPOS2 DATA 0 YPOS2 DATA 0 XOFFS1 DATA 0 YOFFS1 DATA 0 BSIZE0 DATA BSIZE * Sprite patterns SPR1 DATA >0102,>0404,>0808,>1010 * Color 1 DATA >2020,>4040,>8080,>8080 DATA >80C0,>60A0,>50B0,>58A8 DATA >54AC,>56AA,>55AB,>55AB SPR2 DATA >0001,>0303,>0707,>0F0F * Color 5 DATA >1F1F,>3F3F,>7F7F,>7F7F DATA >0000,>8040,>A040,>A050 DATA >A850,>A854,>AA54,>AA54 SPR3 DATA >8080,>8080,>4040,>2020 * Color 1 DATA >1010,>0808,>0404,>0201 DATA >55AB,>55AB,>56AA,>54AC DATA >58A8,>50B0,>60A0,>4080 SPR4 DATA >7F7F,>7F7F,>3F3F,>1F1F * Color 4 DATA >0F0F,>0707,>0303,>0100 DATA >AA54,>AA54,>A854,>A850 DATA >A050,>A040,>8040,>8000 * Sprite attributes SPRATT BYTE >C0,>00,>00,>01 BYTE >C0,>00,>04,>05 BYTE >C0,>00,>08,>01 BYTE >C0,>00,>0C,>04 BYTE >D0 * Block patterns PATTS BOXPAT DATA >0000,>0000,>0001,>8000 DATA >0007,>E000,>001F,>F800 DATA >007F,>FE00,>01FF,>FF80 DATA >07FF,>FFE0,>1FFF,>FFF8 DATA >7FFF,>FFFE,>1FFF,>FFFA DATA >67FF,>FFE4,>79FF,>FF8A DATA >7E7F,>FE54,>7F9F,>F8AA DATA >7FE7,>E554,>7FF9,>8AAA DATA >7FFE,>5554,>7FFF,>AAAA DATA >7FFF,>5554,>7FFF,>AAAA DATA >1FFF,>5550,>07FF,>AAA0 DATA >01FF,>5500,>007F,>AA00 DATA >001F,>5000,>0007,>A000 DATA >0001,>0000,>0000,>0000 SPHPAT DATA >0000,>0000,>0007,>E000 DATA >001F,>F800,>007F,>FE00 DATA >00FF,>FF00,>01FF,>FF80 DATA >01E7,>FF80,>03DB,>FFC0 DATA >03DB,>FFC0,>07E7,>FFE0 DATA >07FF,>FFE0,>07FF,>FFA0 DATA >07FF,>FF60,>07FF,>FFA0 DATA >07FF,>FF60,>03FF,>FEC0 DATA >03FF,>FB40,>01FF,>F680 DATA >01FF,>FC80,>00FF,>E900 DATA >007F,>5600,>001E,>B800 DATA >0007,>E000,>0000,>0000 DATA >0000,>0000,>0000,>0000 DATA >0000,>0000,>0000,>0000 PYRPAT DATA >0000,>0000,>0000,>0000 DATA >0000,>0000,>0000,>0000 DATA >0000,>0000,>0001,>8000 DATA >0002,>4000,>0006,>A000 DATA >000E,>5000,>001E,>A800 DATA >003E,>5400,>007E,>AA00 DATA >00FE,>5500,>01FE,>AA80 DATA >03FE,>5540,>07FE,>AAA0 DATA >0FFE,>5550,>1FFE,>AAA8 DATA >3FFE,>5554,>7FFE,>AAAA DATA >1FFE,>5550,>07FE,>AAA0 DATA >01FE,>5500,>007E,>AA00 DATA >001E,>5000,>0006,>A000 DATA >0001,>0000,>0000,>0000 RM1PAT DATA >0000,>0000,>0000,>8000 DATA >0001,>E000,>0003,>F800 DATA >0007,>FE00,>0007,>FF80 DATA >000F,>FFE0,>001F,>FFF8 DATA >003F,>FFFC,>007F,>FFFA DATA >007F,>FFF4,>00FF,>FFEA DATA >01FF,>FFF4,>03FF,>FFEA DATA >07FF,>FFD4,>07FF,>FFAA DATA >0FFF,>FF54,>1FFF,>FEAA DATA >3FFF,>FD54,>7FFF,>FAAA DATA >1FFF,>F550,>07FF,>EAA0 DATA >01FF,>F500,>007F,>EA00 DATA >001F,>D000,>0007,>A000 DATA >0001,>8000,>0000,>0000 * Block masks MASKS BOXMSK DATA >0001,>8000,>0007,>E000 DATA >001F,>F800,>007F,>FE00 DATA >01FF,>FF80,>07FF,>FFE0 DATA >1FFF,>FFF8,>7FFF,>FFFE DATA >FFFF,>FFFF,>FFFF,>FFFF DATA >FFFF,>FFFF,>FFFF,>FFFF DATA >FFFF,>FFFF,>FFFF,>FFFF DATA >FFFF,>FFFF,>FFFF,>FFFF DATA >FFFF,>FFFF,>FFFF,>FFFF DATA >FFFF,>FFFF,>FFFF,>FFFF DATA >7FFF,>FFFE,>1FFF,>FFF8 DATA >07FF,>FFE0,>01FF,>FF80 DATA >007F,>FE00,>001F,>F800 DATA >0007,>E000,>0001,>8000 SPHMSK DATA >0007,>E000,>001F,>F800 DATA >007F,>FE00,>00FF,>FF00 DATA >01FF,>FF80,>03FF,>FFC0 DATA >03FF,>FFC0,>07FF,>FFE0 DATA >07FF,>FFE0,>0FFF,>FFF0 DATA >0FFF,>FFF0,>0FFF,>FFF0 DATA >0FFF,>FFF0,>0FFF,>FFF0 DATA >0FFF,>FFF0,>07FF,>FFE0 DATA >07FF,>FFE0,>03FF,>FFC0 DATA >03FF,>FFC0,>01FF,>FF80 DATA >00FF,>FF00,>007F,>FE00 DATA >001F,>F800,>0007,>E000 DATA >0000,>0000,>0000,>0000 DATA >0000,>0000,>0000,>0000 PYRMSK DATA >0000,>0000,>0000,>0000 DATA >0000,>0000,>0000,>0000 DATA >0001,>8000,>0003,>C000 DATA >0007,>E000,>000F,>F000 DATA >001F,>F800,>003F,>FC00 DATA >007F,>FE00,>00FF,>FF00 DATA >01FF,>FF80,>03FF,>FFC0 DATA >07FF,>FFE0,>0FFF,>FFF0 DATA >1FFF,>FFF8,>3FFF,>FFFC DATA >7FFF,>FFFE,>FFFF,>FFFF DATA >7FFF,>FFFE,>1FFF,>FFF8 DATA >07FF,>FFE0,>01FF,>FF80 DATA >007F,>FE00,>001F,>F800 DATA >0007,>E000,>0001,>8000 RM1MSK DATA >0000,>8000,>0001,>E000 DATA >0003,>F800,>0007,>FE00 DATA >000F,>FF80,>000F,>FFE0 DATA >001F,>FFF8,>003F,>FFFE DATA >007F,>FFFF,>00FF,>FFFF DATA >00FF,>FFFF,>01FF,>FFFF DATA >03FF,>FFFF,>07FF,>FFFF DATA >0FFF,>FFFF,>0FFF,>FFFF DATA >1FFF,>FFFF,>3FFF,>FFFF DATA >7FFF,>FFFF,>FFFF,>FFFF DATA >7FFF,>FFFE,>1FFF,>FFF8 DATA >07FF,>FFE0,>01FF,>FF80 DATA >007F,>FE00,>001F,>F800 DATA >0007,>E000,>0001,>8000 * Maps MAP00 DATA >0000,>0000,>0101,>0101 ; DATA >0000,>0000,>0101,>0101 ; DATA >0000,>0000,>0101,>0101 ; DATA >0000,>0000,>0101,>0101 ; DATA >0101,>0101,>0101,>0101 ; DATA >0101,>0101,>0101,>0101 ; DATA >0101,>0101,>0101,>0101 ; DATA >0101,>0101,>0101,>0101 ; MAP01 DATA >0101,>0101,>0101,>0101 ; DATA >0101,>0101,>0004,>0000 ; DATA >0101,>0101,>0000,>0001 ; DATA >0101,>0101,>0000,>0000 ; DATA >0100,>0000,>0000,>0001 ; DATA >0100,>0002,>0000,>0000 ; DATA >0100,>0000,>0000,>0001 ; DATA >0100,>0001,>0100,>0300 ; MAP02 DATA >0101,>0101,>0100,>0000 ; DATA >0101,>0004,>0000,>0000 ; DATA >0100,>0000,>0000,>0000 ; DATA >0000,>0001,>0000,>0000 ; DATA >0000,>0000,>0000,>0001 ; DATA >0300,>0000,>0000,>0000 ; DATA >0000,>0000,>0000,>0001 ; DATA >0300,>0001,>0100,>0000 ; MAP03 DATA >0101,>0200,>0000,>0000 ; DATA >0100,>0000,>0000,>0000 ; DATA >0400,>0000,>0000,>0000 ; DATA >0000,>0000,>0000,>0000 ; DATA >0000,>0000,>0000,>0000 ; DATA >0000,>0000,>0000,>0000 ; DATA >0000,>0000,>0000,>0002 ; DATA >0000,>0000,>0000,>0000 ; * Buffer for sprite masking SPRBUF BSS 24*SPRBW SPRBU1 BSS 32*SPRBW BSS 24*SPRBW SBSPAD EQU SPRBU1+4 END START