User Tools

Site Tools


base:flexible_32_sprite_multiplexer_2

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

base:flexible_32_sprite_multiplexer_2 [2015-04-17 04:31] (current)
Line 1: Line 1:
 +===== Flexible 32 Sprite Multiplexer - Version 2 =====
 +
 +The original code is from [[Flexible 32 Sprite Multiplexer]]
 +
 +This code has been converted to ACME.
 +Compared to the previous version this has had various small tweaks, a bug fix (the interrupt was not always saving X for the RTI in all execution paths) and optimisations mostly shown by the "​MPi:"​ comments.
 +
 +There are two source files in two sections below. Assemble RasterTest.asm and you can easily load the resulting prg in an emulator and it will start. The standard library file (stdlib.asm) is also included in the section below which has lots of handy definitions for zero page, kernal, VIC and SID.
 +
 +=== Create as "​RasterTest.asm"​ ===
 +<​code>​
 +; Change list
 +; Original code from http://​codebase64.org/​doku.php?​id=base:​flexible_32_sprite_multiplexer
 +; 25th October 2007 - Martin Piper
 +; Conversion to ACME plus various tweaks, bug fix (the interrupt was not always saving X for the RTI in all execution paths) and optimisations mostly shown by the "​MPi:"​ comments.
 +; 26th October 2007 - Martin Piper
 +; Fixed a slight bug where if one particular sprite was the very last one to be drawn it wouldn'​t end the IRQ chain correctly.
 +; Added a test for sprite Y pos = $ff and then it then finishes rendering all further sprites. This is a quick way to disable a sprite from being rendered.
 +; Added some extra documentation comments.
 +
 +; TODO
 +; Tidy this so the multiplexor is in a separate file and make a bit modular.
 +
 +!source "​stdlib.asm"​
 +!to "​RasterTest.prg",​ cbm
 +!sl "​RasterTest.map"​
 +!cpu 6502
 +!ct pet
 +
 +; This starts at $0801 so that doing a LOAD"​*",​8 will still work with the default $0801 BASIC start address.
 +*= BASICSTART
 +!byte $0c,​$08,​$0a,​$00,​$9e ;​ Line 10 SYS
 +!convtab pet
 +!tx "​2304"​ ;​ Address for sys start in text
 +!byte $00,​$00,​$00,​$00
 +!byte $00,​$00,​$00,​$00 ;​ And a few more zeros for the sake of paranoia and safety.
 +
 +!macro SpriteLine .v {
 + !by .v>>​16,​ (.v>>​8)&​255,​ .v&255
 +}
 +
 +; Some sprite data high up in memory
 +*=$3f00
 +!by 255,​255,​255,​255,​255,​255,​255,​255
 +!by 255,​255,​255,​255,​255,​255,​255,​255
 +!by 255,​255,​255,​255,​255,​255,​255,​255
 +!by 255,​255,​255,​255,​255,​255,​255,​255
 +!by 255,​255,​255,​255,​255,​255,​255,​255
 +!by 255,​255,​255,​255,​255,​255,​255,​255
 +!by 255,​255,​255,​255,​255,​255,​255,​255
 +!by 255,​255,​255,​255,​255,​255,​255,​255
 +
 ++SpriteLine %........................
 ++SpriteLine %.#​......................
 ++SpriteLine %.##​.....................
 ++SpriteLine %.###​....................
 ++SpriteLine %.####​...................
 ++SpriteLine %.#####​..................
 ++SpriteLine %.######​.................
 ++SpriteLine %.#######​................
 ++SpriteLine %.########​...............
 ++SpriteLine %.#########​..............
 ++SpriteLine %.########​...............
 ++SpriteLine %.######​.................
 ++SpriteLine %.######​.................
 ++SpriteLine %.##​..##​.................
 ++SpriteLine %.#​....##​................
 ++SpriteLine %......##​................
 ++SpriteLine %.......##​...............
 ++SpriteLine %.......##​...............
 ++SpriteLine %........##​..............
 ++SpriteLine %........##​..............
 ++SpriteLine %........................
 +!byte 0
 +
 ++SpriteLine %########################​
 ++SpriteLine %########################​
 ++SpriteLine %###​..................###​
 ++SpriteLine %###​..................###​
 ++SpriteLine %###​..................###​
 ++SpriteLine %###​..................###​
 ++SpriteLine %###​..................###​
 ++SpriteLine %###​..................###​
 ++SpriteLine %###​.......###​........###​
 ++SpriteLine %###​......#####​.......###​
 ++SpriteLine %###​......#####​.......###​
 ++SpriteLine %###​......#####​.......###​
 ++SpriteLine %###​.......###​........###​
 ++SpriteLine %###​..................###​
 ++SpriteLine %###​..................###​
 ++SpriteLine %###​..................###​
 ++SpriteLine %###​..................###​
 ++SpriteLine %###​..................###​
 ++SpriteLine %###​..................###​
 ++SpriteLine %########################​
 ++SpriteLine %########################​
 +!byte 0
 +
 ++SpriteLine %########################​
 ++SpriteLine %########################​
 ++SpriteLine %####​.......##​.......####​
 ++SpriteLine %###​.#​......##​......#​.###​
 ++SpriteLine %###​..#​.....##​.....#​..###​
 ++SpriteLine %###​...#​....##​....#​...###​
 ++SpriteLine %###​....#​...##​...#​....###​
 ++SpriteLine %###​.....#​..##​..#​.....###​
 ++SpriteLine %###​......######​......###​
 ++SpriteLine %###​......#####​.......###​
 ++SpriteLine %########################​
 ++SpriteLine %###​......#####​.......###​
 ++SpriteLine %###​......#####​.......###​
 ++SpriteLine %###​.....#​..#​..#​......###​
 ++SpriteLine %###​....#​...#​...#​.....###​
 ++SpriteLine %###​...#​....#​....#​....###​
 ++SpriteLine %###​..#​.....#​.....#​...###​
 ++SpriteLine %###​.#​......#​......#​..###​
 ++SpriteLine %####​.......#​.......#​.###​
 ++SpriteLine %########################​
 ++SpriteLine %########################​
 +!byte 0
 +
 +*=$0900
 +
 +; MPi: Uncomment this line to enable border colour debug display.
 +; The sprite display IRQs will show different colours depending on how many sprites they have updated in the current band.
 +; This is useful for showing how many sprites are updated on average per band.
 +;​Multiplexor_DebugBorder
 +
 +; Define various zeropage working variables
 +.VarBase = $02
 +
 +Multiplex_areg = .VarBase+$000
 +Multiplex_xreg = .VarBase+$001
 +Multiplex_yreg = .VarBase+$002
 +
 +Multiplex_abuf = .VarBase+$003
 +Multiplex_xbuf = .VarBase+$004
 +Multiplex_ybuf = .VarBase+$005
 +
 +Multiplex_iobuf = .VarBase+$006
 +
 +Multiplex_flag = .VarBase+$007
 +
 +Multiplex_buffer = .VarBase+$008
 +
 +Multiplex_MaxSpr = .VarBase+$009
 +Multiplex_counter = .VarBase+$00a
 +
 +Multiplex_counterx1 = .VarBase+$00b
 +Multiplex_counterx2 = .VarBase+$00c
 +
 +Multiplex_countery1 = .VarBase+$00d
 +Multiplex_countery2 = .VarBase+$00e
 +
 +Multiplex_xdif = .VarBase+$00f
 +Multiplex_ydif = .VarBase+$010
 +
 +Multiplex_xspeed = .VarBase+$011
 +Multiplex_yspeed = .VarBase+$012
 +
 +Multiplex_xoffset = .VarBase+$13
 +Multiplex_yoffset = .VarBase+$14
 +
 +jumplo = .VarBase+$15
 +jumphi = .VarBase+$16
 +
 +Multiplex_bal = .VarBase+$17
 +Multiplex_bah = .VarBase+$18
 +
 +Multiplex_oldlo = .VarBase+$19
 +Multiplex_oldhi = .VarBase+$1a
 +
 +
 +; Memory
 +Multiplex_indextable = $e0 ; $20 long
 +Multiplex_spritepointer = SPRITEFRAME
 +
 +; Must be <= 32 otherwise Multiplex_indextable goes splat
 +Multiplex_items = 32
 +
 +;​--------------------------------------
 +;macros
 +
 +;​--------------------------------------
 +!zn {
 +Start
 + sei
 + cld
 + lda #$35 ; RAM visible at $A000-$BFFF and $E000-$FFFF I/O area visible at $D000-$DFFF.
 + sta ZPProcessorPort
 +
 + ldx #$ff
 + txs
 + inx
 +
 + stx VIC2ScreenColour
 + stx CIA1TimerAControl
 + stx VIC2BorderColour
 +
 + inx
 + stx VIC2InteruptControl
 +
 + lda #$1b
 + sta VIC2ScreenControlV
 +
 + lda #$00
 + sta VIC2SpriteDoubleHeight
 + sta VIC2SpritePriority
 + sta VIC2SpriteDoubleWidth
 + sta VIC2SpriteMulticolour
 +
 + lda #<​Multiplex_maininter
 + sta KERNALIRQServiceRoutineLo
 + lda #>​Multiplex_maininter
 + sta KERNALIRQServiceRoutineHi
 +
 + lda #$7f
 + sta CIA1InterruptControl
 +
 + lda #0
 + sta VIC2Raster
 +
 +
 +
 + ldx #$02
 + lda #$80
 +.3 sta $00,x
 + inx
 + bne .3
 +
 + lda #32 ; MPi: Increase to 32 sprites from the original 24 sprite demo
 + sta Multiplex_MaxSpr
 +
 + lda #$40
 + sta Multiplex_xoffset
 +
 + lda #$00
 + sta Multiplex_yoffset
 +
 + lda #$ff
 + sta Multiplex_xspeed
 +
 + lda #$01
 + sta Multiplex_yspeed
 +
 + lda #$0a
 + sta Multiplex_xdif
 + lda #$10
 + sta Multiplex_ydif
 +
 + jsr Multiplex_initsort
 +
 + ; MPi: Just to prove all IRQs save all registers. These characters should never flicker or change from ABC in the top left of the screen.
 + lda #1
 + ldx #2
 + ldy #3
 +.2 cli
 + sta SCREENRAM
 + stx SCREENRAM+1
 + sty SCREENRAM+2
 + ; MPi: Inc'​ing these three store variables should not alter the "​ABC"​ printed by the bit above.
 + ; In the previous version this code block would show how reg X was not being preserved by the IRQ because the middle character ("​B"​) would update.
 + ; This is because as the IRQ exits it would sometimes do an extra "ldx Multiplex_xreg"​ without always doing the corresponding "stx Multiplex_xreg"​ on entry.
 + inc Multiplex_areg
 + inc Multiplex_xreg
 + inc Multiplex_yreg
 + jmp .2
 +}
 +
 +;​--------------------------------------
 +!zn {
 +; The main top interrupt that draws the first line of sprites and then figures out what next to plot
 +Multiplex_maininter
 + sta Multiplex_areg
 + stx Multiplex_xreg
 + sty Multiplex_yreg
 +
 +!ifdef Multiplexor_DebugBorder {
 +inc VIC2BorderColour
 +}
 +
 + ldx Multiplex_MaxSpr
 + cpx #$09
 + bcs .morethan8
 +
 + lda #​$4c ;​ Set jmp $0000
 + sta .switch
 +
 + lda .activatetab,​x
 + sta VIC2SpriteEnable
 +
 + lda .jumplo,x
 + sta jumplo
 + lda .jumphi,x
 + sta jumphi
 + lda #$00
 + sta VIC2SpriteXMSB
 + jmp (jumplo)
 +
 +.morethan8 lda #$ff
 + sta VIC2SpriteEnable
 + lda #$08
 + sta Multiplex_counter
 +
 + lda #​$2c ;​ Set bit $0000
 + sta .switch
 + lda #$00
 +
 +;​--------------------------------------
 +.dospr7 ldy Multiplex_indextable+7
 + ldx Multiplex_YTable,​y
 + stx VIC2Sprite7Y
 + ldx Multiplex_XPosLo,​y
 + stx VIC2Sprite7X
 + ldx Multiplex_SpriteFrame,​y
 + stx Multiplex_spritepointer+7
 + ldx Multiplex_Colour,​y
 + stx VIC2Sprite7Colour
 + ldx Multiplex_XPosHi,​y
 + beq .dospr6
 + lda #$80
 +;​--------------------------------------
 +.dospr6 ldy Multiplex_indextable+6
 + ldx Multiplex_YTable,​y
 + stx VIC2Sprite6Y
 + ldx Multiplex_XPosLo,​y
 + stx VIC2Sprite6X
 + ldx Multiplex_SpriteFrame,​y
 + stx Multiplex_spritepointer+6
 + ldx Multiplex_Colour,​y
 + stx VIC2Sprite6Colour
 + ldx Multiplex_XPosHi,​y
 + beq .dospr5
 + ora #$40
 +;​--------------------------------------
 +.dospr5 ldy Multiplex_indextable+5
 + ldx Multiplex_YTable,​y
 + stx VIC2Sprite5Y
 + ldx Multiplex_XPosLo,​y
 + stx VIC2Sprite5X
 + ldx Multiplex_SpriteFrame,​y
 + stx Multiplex_spritepointer+5
 + ldx Multiplex_Colour,​y
 + stx VIC2Sprite5Colour
 + ldx Multiplex_XPosHi,​y
 + beq .dospr4
 + ora #$20
 +;​--------------------------------------
 +.dospr4 ldy Multiplex_indextable+4
 + ldx Multiplex_YTable,​y
 + stx VIC2Sprite4Y
 + ldx Multiplex_XPosLo,​y
 + stx VIC2Sprite4X
 + ldx Multiplex_SpriteFrame,​y
 + stx Multiplex_spritepointer+4
 + ldx Multiplex_Colour,​y
 + stx VIC2Sprite4Colour
 + ldx Multiplex_XPosHi,​y
 + beq .dospr3
 + ora #$10
 +;​--------------------------------------
 +.dospr3 ldy Multiplex_indextable+3
 + ldx Multiplex_YTable,​y
 + stx VIC2Sprite3Y
 + ldx Multiplex_XPosLo,​y
 + stx VIC2Sprite3X
 + ldx Multiplex_SpriteFrame,​y
 + stx Multiplex_spritepointer+3
 + ldx Multiplex_Colour,​y
 + stx VIC2Sprite3Colour
 + ldx Multiplex_XPosHi,​y
 + beq .dospr2
 + ora #$08
 +;​--------------------------------------
 +.dospr2 ldy Multiplex_indextable+2
 + ldx Multiplex_YTable,​y
 + stx VIC2Sprite2Y
 + ldx Multiplex_XPosLo,​y
 + stx VIC2Sprite2X
 + ldx Multiplex_SpriteFrame,​y
 + stx Multiplex_spritepointer+2
 + ldx Multiplex_Colour,​y
 + stx VIC2Sprite2Colour
 + ldx Multiplex_XPosHi,​y
 + beq .dospr1
 + ora #$04
 +;​--------------------------------------
 +.dospr1 ldy Multiplex_indextable+1
 + ldx Multiplex_YTable,​y
 + stx VIC2Sprite1Y
 + ldx Multiplex_XPosLo,​y
 + stx VIC2Sprite1X
 + ldx Multiplex_SpriteFrame,​y
 + stx Multiplex_spritepointer+1
 + ldx Multiplex_Colour,​y
 + stx VIC2Sprite1Colour
 + ldx Multiplex_XPosHi,​y
 + beq .dospr0
 + ora #$02
 +;​--------------------------------------
 +.dospr0 ldy Multiplex_indextable
 + ldx Multiplex_YTable,​y
 + stx VIC2Sprite0Y
 + ldx Multiplex_XPosLo,​y
 + stx VIC2Sprite0X
 + ldx Multiplex_SpriteFrame,​y
 + stx Multiplex_spritepointer
 + ldx Multiplex_Colour,​y
 + stx VIC2Sprite0Colour
 +
 +!ifdef Multiplexor_DebugBorder {
 + inc VIC2BorderColour
 +}
 + ldx Multiplex_XPosHi,​y
 + beq .over
 + ora #$01
 +.over sta VIC2SpriteXMSB
 +.switch jmp Multiplex_exitinter ;​ Self modifying for jmp or bit
 +
 + clc
 +
 + ; MPi: During heavy use (>24 sprites) on average the interrupt updates at least two new sprites and quite often three or four sprites. (Enable Multiplexor_DebugBorder to see this.)
 + ; Armed with this information there is an average time saving by having reg x maintain Multiplex_counter and being able to do
 + ; "ldy Multiplex_indextable,​x"​ instead of "lda Multiplex_indextable,​y : tay" even taking into account the extra interrupt x register store and restore.
 + ; This is because the "ldx Multiplex_counter : inx : stx Multiplex_counter"​ doesn'​t always need to be done every sprite and can be optimised to be just "​inx"​.
 + ; However Under light use (<16 sprites) the average interrupt updates one sprites but the extra overhead for the extra interrupt x store and restore is small compared to the savings mentioned above.
 + ; Basically the theory being optimise for heavy use since heavy use is where the optimisation is more appreciated.
 +
 + ldx Multiplex_counter
 +
 + ; MPi: From here until the Multiplex_exitinter the sprite plotting code has been reworked to use an extra register (x) and include the optimisations described above.
 +
 +;​--------------------------------------
 +; MPi: Calculate with this current raster position and the bottom of the last sprite Y pos
 +; Is it better to start a new raster IRQ at the new position or shall we update the sprite now?
 +.nextspr0 lda VIC2Sprite0Y
 + adc #$17
 + sbc VIC2Raster
 + bcc .blit0 ; MPi: Process the sprite now not later
 + cmp #$03
 + bcs .next0
 + lda #$03
 +.next0 clc ;​ MPi: Process the sprite later next raster IRQ
 + adc VIC2Raster
 + sta VIC2Raster
 +
 + lda #<​Multiplex_inter0
 + sta KERNALIRQServiceRoutineLo
 + lda #>​Multiplex_inter0
 + sta KERNALIRQServiceRoutineHi
 +
 + inc VIC2InteruptStatus
 + lda CIA1InterruptControl
 +
 +!ifdef Multiplexor_DebugBorder {
 + lda #3 : sta VIC2BorderColour
 +}
 + stx Multiplex_counter
 + lda Multiplex_areg
 + ldx Multiplex_xreg
 + ldy Multiplex_yreg
 + rti
 +
 +; MPi: Each Multiplex_interX is entered by each subsequent raster IRQ
 +Multiplex_inter0 sta Multiplex_areg
 + stx Multiplex_xreg
 + sty Multiplex_yreg
 + ldx Multiplex_counter
 +
 +; MPi: Each .blitX can also entered by a raster IRQ processing more than one sprite in this band if it is calculated it is better to follow on rather than create a new raster IRQ.
 +.blit0 ldy Multiplex_indextable,​x
 +
 +!ifdef Multiplexor_DebugBorder {
 + inc VIC2BorderColour
 +}
 +
 + lda Multiplex_YTable,​y
 + cmp #​$ff ;​ Don't display any sprites once this is reached
 + beq .intExitInter0
 + sta VIC2Sprite0Y
 + lda Multiplex_XPosLo,​y
 + sta VIC2Sprite0X
 + lda Multiplex_SpriteFrame,​y
 + sta Multiplex_spritepointer
 + lda Multiplex_Colour,​y
 + sta VIC2Sprite0Colour
 +
 + lda Multiplex_XPosHi,​y
 + beq .no0
 + lda #$01
 + ora VIC2SpriteXMSB
 + bne .yes0
 +.no0 lda #$fe
 + and VIC2SpriteXMSB
 +.yes0 sta VIC2SpriteXMSB
 +
 + inx
 +
 + cpx Multiplex_MaxSpr
 + bne .nextspr1
 +.intExitInter0 jmp Multiplex_exitinter
 +
 +;​--------------------------------------
 +.nextspr1 lda VIC2Sprite1Y
 + adc #$17
 + sbc VIC2Raster
 + bcc .blit1
 + cmp #$03
 + bcs .next1
 + lda #$03
 +.next1 clc
 + adc VIC2Raster
 + sta VIC2Raster
 +
 + lda #<​Multiplex_inter1
 + sta KERNALIRQServiceRoutineLo
 + lda #>​Multiplex_inter1
 + sta KERNALIRQServiceRoutineHi
 +
 + inc VIC2InteruptStatus
 + lda CIA1InterruptControl
 +
 +!ifdef Multiplexor_DebugBorder {
 + lda #3 : sta VIC2BorderColour
 +}
 + stx Multiplex_counter
 + lda Multiplex_areg
 + ldx Multiplex_xreg
 + ldy Multiplex_yreg
 + rti
 +
 +Multiplex_inter1 sta Multiplex_areg
 + stx Multiplex_xreg
 + sty Multiplex_yreg
 + ldx Multiplex_counter
 +
 +.blit1 ldy Multiplex_indextable,​x
 +
 +!ifdef Multiplexor_DebugBorder {
 + inc VIC2BorderColour
 +}
 +
 + lda Multiplex_YTable,​y
 + cmp #​$ff ;​ Don't display any sprites once this is reached
 + beq .intExitInter1
 + sta VIC2Sprite1Y
 + lda Multiplex_XPosLo,​y
 + sta VIC2Sprite1X
 + lda Multiplex_SpriteFrame,​y
 + sta Multiplex_spritepointer+1
 + lda Multiplex_Colour,​y
 + sta VIC2Sprite1Colour
 +
 + lda Multiplex_XPosHi,​y
 + beq .no1
 + lda #$02
 + ora VIC2SpriteXMSB
 + bne .yes1
 +.no1 lda #$fd
 + and VIC2SpriteXMSB
 +.yes1 sta VIC2SpriteXMSB
 +
 + inx
 +
 + cpx Multiplex_MaxSpr
 + bne .nextspr2
 +.intExitInter1 jmp Multiplex_exitinter
 +
 +;​--------------------------------------
 +.nextspr2 lda VIC2Sprite2Y
 + adc #$17
 + sbc VIC2Raster
 + bcc .blit2
 + cmp #$03
 + bcs .next2
 + lda #$03
 +.next2 clc
 + adc VIC2Raster
 + sta VIC2Raster
 +
 + lda #<​Multiplex_inter2
 + sta KERNALIRQServiceRoutineLo
 + lda #>​Multiplex_inter2
 + sta KERNALIRQServiceRoutineHi
 +
 + inc VIC2InteruptStatus
 + lda CIA1InterruptControl
 +
 +!ifdef Multiplexor_DebugBorder {
 + lda #3 : sta VIC2BorderColour
 +}
 + stx Multiplex_counter
 + lda Multiplex_areg
 + ldx Multiplex_xreg
 + ldy Multiplex_yreg
 + rti
 +
 +Multiplex_inter2 sta Multiplex_areg
 + stx Multiplex_xreg
 + sty Multiplex_yreg
 + ldx Multiplex_counter
 +
 +.blit2 ldy Multiplex_indextable,​x
 +
 +!ifdef Multiplexor_DebugBorder {
 + inc VIC2BorderColour
 +}
 +
 + lda Multiplex_YTable,​y
 + cmp #​$ff ;​ Don't display any sprites once this is reached
 + beq .intExitInter2
 + sta VIC2Sprite2Y
 + lda Multiplex_XPosLo,​y
 + sta VIC2Sprite2X
 + lda Multiplex_SpriteFrame,​y
 + sta Multiplex_spritepointer+2
 + lda Multiplex_Colour,​y
 + sta VIC2Sprite2Colour
 +
 + lda Multiplex_XPosHi,​y
 + beq .no2
 + lda #$04
 + ora VIC2SpriteXMSB
 + bne .yes2
 +.no2 lda #$fb
 + and VIC2SpriteXMSB
 +.yes2 sta VIC2SpriteXMSB
 +
 + inx
 +
 + cpx Multiplex_MaxSpr
 + bne .nextspr3
 +.intExitInter2 jmp Multiplex_exitinter
 +
 +;​--------------------------------------
 +.nextspr3 lda VIC2Sprite3Y
 + adc #$17
 + sbc VIC2Raster
 + bcc .blit3
 + cmp #$03
 + bcs .next3
 + lda #$03
 +.next3 clc
 + adc VIC2Raster
 + sta VIC2Raster
 +
 + lda #<​Multiplex_inter3
 + sta KERNALIRQServiceRoutineLo
 + lda #>​Multiplex_inter3
 + sta KERNALIRQServiceRoutineHi
 +
 + inc VIC2InteruptStatus
 + lda CIA1InterruptControl
 +
 +!ifdef Multiplexor_DebugBorder {
 + lda #3 : sta VIC2BorderColour
 +}
 + stx Multiplex_counter
 + lda Multiplex_areg
 + ldx Multiplex_xreg
 + ldy Multiplex_yreg
 + rti
 +
 +Multiplex_inter3 sta Multiplex_areg
 + stx Multiplex_xreg
 + sty Multiplex_yreg
 + ldx Multiplex_counter
 +
 +.blit3 ldy Multiplex_indextable,​x
 +
 +!ifdef Multiplexor_DebugBorder {
 + inc VIC2BorderColour
 +}
 +
 + lda Multiplex_YTable,​y
 + cmp #​$ff ;​ Don't display any sprites once this is reached
 + beq .intExitInter3
 + sta VIC2Sprite3Y
 + lda Multiplex_XPosLo,​y
 + sta VIC2Sprite3X
 + lda Multiplex_SpriteFrame,​y
 + sta Multiplex_spritepointer+3
 + lda Multiplex_Colour,​y
 + sta VIC2Sprite3Colour
 +
 + lda Multiplex_XPosHi,​y
 + beq .no3
 + lda #$08
 + ora VIC2SpriteXMSB
 + bne .yes3
 +.no3 lda #$f7
 + and VIC2SpriteXMSB
 +.yes3 sta VIC2SpriteXMSB
 +
 + inx
 +
 + cpx Multiplex_MaxSpr
 + bne .nextspr4
 +.intExitInter3 jmp Multiplex_exitinter
 +
 +;​--------------------------------------
 +.nextspr4 lda VIC2Sprite4Y
 + adc #$17
 + sbc VIC2Raster
 + bcc .blit4
 + cmp #$03
 + bcs .next4
 + lda #$03
 +.next4 clc
 + adc VIC2Raster
 + sta VIC2Raster
 +
 + lda #<​Multiplex_inter4
 + sta KERNALIRQServiceRoutineLo
 + lda #>​Multiplex_inter4
 + sta KERNALIRQServiceRoutineHi
 +
 + inc VIC2InteruptStatus
 + lda CIA1InterruptControl
 +
 +!ifdef Multiplexor_DebugBorder {
 + lda #3 : sta VIC2BorderColour
 +}
 + stx Multiplex_counter
 + lda Multiplex_areg
 + ldx Multiplex_xreg
 + ldy Multiplex_yreg
 + rti
 +
 +Multiplex_inter4 sta Multiplex_areg
 + stx Multiplex_xreg
 + sty Multiplex_yreg
 + ldx Multiplex_counter
 +
 +.blit4 ldy Multiplex_indextable,​x
 +
 +!ifdef Multiplexor_DebugBorder {
 + inc VIC2BorderColour
 +}
 +
 + lda Multiplex_YTable,​y
 + cmp #​$ff ;​ Don't display any sprites once this is reached
 + beq .intExitInter4
 + sta VIC2Sprite4Y
 + lda Multiplex_XPosLo,​y
 + sta VIC2Sprite4X
 + lda Multiplex_SpriteFrame,​y
 + sta Multiplex_spritepointer+4
 + lda Multiplex_Colour,​y
 + sta VIC2Sprite4Colour
 +
 + lda Multiplex_XPosHi,​y
 + beq .no4
 + lda #$10
 + ora VIC2SpriteXMSB
 + bne .yes4
 +.no4 lda #$ef
 + and VIC2SpriteXMSB
 +.yes4 sta VIC2SpriteXMSB
 +
 + inx
 +
 + cpx Multiplex_MaxSpr
 + bne .nextspr5
 +.intExitInter4 jmp Multiplex_exitinter
 +
 +;​--------------------------------------
 +.nextspr5 lda VIC2Sprite5Y
 + adc #$17
 + sbc VIC2Raster
 + bcc .blit5
 + cmp #$03
 + bcs .next5
 + lda #$03
 +.next5 clc
 + adc VIC2Raster
 + sta VIC2Raster
 +
 + lda #<​Multiplex_inter5
 + sta KERNALIRQServiceRoutineLo
 + lda #>​Multiplex_inter5
 + sta KERNALIRQServiceRoutineHi
 +
 + inc VIC2InteruptStatus
 + lda CIA1InterruptControl
 +
 +!ifdef Multiplexor_DebugBorder {
 + lda #3 : sta VIC2BorderColour
 +}
 + stx Multiplex_counter
 + lda Multiplex_areg
 + ldx Multiplex_xreg
 + ldy Multiplex_yreg
 + rti
 +
 +Multiplex_inter5 sta Multiplex_areg
 + stx Multiplex_xreg
 + sty Multiplex_yreg
 + ldx Multiplex_counter
 +
 +.blit5 ldy Multiplex_indextable,​x
 +
 +!ifdef Multiplexor_DebugBorder {
 + inc VIC2BorderColour
 +}
 +
 + lda Multiplex_YTable,​y
 + cmp #​$ff ;​ Don't display any sprites once this is reached
 + beq .intExitInter5
 + sta VIC2Sprite5Y
 + lda Multiplex_XPosLo,​y
 + sta VIC2Sprite5X
 + lda Multiplex_SpriteFrame,​y
 + sta Multiplex_spritepointer+5
 + lda Multiplex_Colour,​y
 + sta VIC2Sprite5Colour
 +
 + lda Multiplex_XPosHi,​y
 + beq .no5
 + lda #$20
 + ora VIC2SpriteXMSB
 + bne .yes5
 +.no5 lda #$df
 + and VIC2SpriteXMSB
 +.yes5 sta VIC2SpriteXMSB
 +
 + inx
 +
 + cpx Multiplex_MaxSpr
 + bne .nextspr6
 +.intExitInter5 jmp Multiplex_exitinter
 +
 +;​--------------------------------------
 +.nextspr6 lda VIC2Sprite6Y
 + adc #$17
 + sbc VIC2Raster
 + bcc .blit6
 + cmp #$03
 + bcs .next6
 + lda #$03
 +.next6 clc
 + adc VIC2Raster
 + sta VIC2Raster
 +
 + lda #<​Multiplex_inter6
 + sta KERNALIRQServiceRoutineLo
 + lda #>​Multiplex_inter6
 + sta KERNALIRQServiceRoutineHi
 +
 + inc VIC2InteruptStatus
 + lda CIA1InterruptControl
 +
 +!ifdef Multiplexor_DebugBorder {
 + lda #3 : sta VIC2BorderColour
 +}
 + stx Multiplex_counter
 + lda Multiplex_areg
 + ldx Multiplex_xreg
 + ldy Multiplex_yreg
 + rti
 +
 +Multiplex_inter6 sta Multiplex_areg
 + stx Multiplex_xreg
 + sty Multiplex_yreg
 + ldx Multiplex_counter
 +
 +.blit6 ldy Multiplex_indextable,​x
 +
 +!ifdef Multiplexor_DebugBorder {
 + inc VIC2BorderColour
 +}
 +
 + lda Multiplex_YTable,​y
 + cmp #​$ff ;​ Don't display any sprites once this is reached
 + beq .intExitInter6
 + sta VIC2Sprite6Y
 + lda Multiplex_XPosLo,​y
 + sta VIC2Sprite6X
 + lda Multiplex_SpriteFrame,​y
 + sta Multiplex_spritepointer+6
 + lda Multiplex_Colour,​y
 + sta VIC2Sprite6Colour
 +
 + lda Multiplex_XPosHi,​y
 + beq .no6
 + lda #$40
 + ora VIC2SpriteXMSB
 + bne .yes6
 +.no6 lda #$bf
 + and VIC2SpriteXMSB
 +.yes6 sta VIC2SpriteXMSB
 +
 + inx
 +
 + cpx Multiplex_MaxSpr
 + bne .nextspr7
 +.intExitInter6 jmp Multiplex_exitinter
 +
 +;​--------------------------------------
 +.nextspr7 lda VIC2Sprite7Y
 + adc #$17
 + sbc VIC2Raster
 + bcc .blit7
 + cmp #$03
 + bcs .next7
 + lda #$03
 +.next7 clc
 + adc VIC2Raster
 + sta VIC2Raster
 +
 + lda #<​Multiplex_inter7
 + sta KERNALIRQServiceRoutineLo
 + lda #>​Multiplex_inter7
 + sta KERNALIRQServiceRoutineHi
 +
 + inc VIC2InteruptStatus
 + lda CIA1InterruptControl
 +
 +!ifdef Multiplexor_DebugBorder {
 + lda #3 : sta VIC2BorderColour
 +}
 + stx Multiplex_counter
 + lda Multiplex_areg
 + ldx Multiplex_xreg
 + ldy Multiplex_yreg
 + rti
 +
 +Multiplex_inter7 sta Multiplex_areg
 + stx Multiplex_xreg
 + sty Multiplex_yreg
 + ldx Multiplex_counter
 +
 +.blit7 ldy Multiplex_indextable,​x
 +
 +!ifdef Multiplexor_DebugBorder {
 + inc VIC2BorderColour
 +}
 +
 + lda Multiplex_YTable,​y
 + cmp #​$ff ;​ Don't display any sprites once this is reached
 + beq Multiplex_exitinter
 + sta VIC2Sprite7Y
 + lda Multiplex_XPosLo,​y
 + sta VIC2Sprite7X
 + lda Multiplex_SpriteFrame,​y
 + sta Multiplex_spritepointer+7
 + lda Multiplex_Colour,​y
 + sta VIC2Sprite7Colour
 +
 + lda Multiplex_XPosHi,​y
 + beq .no7
 + lda #$80
 + ora VIC2SpriteXMSB
 + bne .yes7
 +.no7 lda #$7f
 + and VIC2SpriteXMSB
 +.yes7 sta VIC2SpriteXMSB
 +
 + inx
 +
 + cpx Multiplex_MaxSpr
 + beq Multiplex_exitinter
 + jmp .nextspr0
 +
 +.jumplo !by <​Multiplex_exitinter,<​.dospr0,<​.dospr1,<​.dospr2
 + !by <​.dospr3,<​.dospr4,<​.dospr5,<​.dospr6
 + !by <.dospr7
 +
 +.jumphi !by >​Multiplex_exitinter,>​.dospr0,>​.dospr1,>​.dospr2
 + !by >​.dospr3,>​.dospr4,>​.dospr5,>​.dospr6
 + !by >.dospr7
 +
 +.activatetab !by $00,​$01,​$03,​$07,​$0f,​$1f,​$3f,​$7f,​$ff
 +}
 +
 +;​--------------------------------------
 +!zn {
 +; The last interrupt that displays sprites gets to this exit routine.
 +Multiplex_exitinter
 +!ifdef Multiplexor_DebugBorder {
 + inc VIC2BorderColour
 +}
 + lda #$ef
 + cmp CIA1KeyboardRowsJoystickB
 + beq .over
 +
 +!ifdef Multiplexor_DebugBorder {
 + inc VIC2BorderColour
 + lda #1
 + sta VIC2BorderColour
 +}
 + ; Because we are exiting the current screen of sprites to display we can move the sprites and sort them.
 + jsr move
 +
 +.over
 +
 +!ifdef Multiplexor_DebugBorder {
 + inc VIC2BorderColour
 + lda #2
 + sta VIC2BorderColour
 +}
 + ; MPi: Even without any sprite move being called this still calls the sort to demonstrate just how quick the sort is.
 + ; The sort (red border area at the bottom of the screen) is actually on average much quicker than the move loop (the white area above the red).
 + ; This runs the sort using the previous results of the sort as a starting point to work from.
 + ; It's called the "Ocean method"​ since it was commonly used in Ocean games.
 + jsr Multiplex_sort
 +!ifdef Multiplexor_DebugBorder {
 + lda #0
 + sta VIC2BorderColour
 +}
 +
 + ; Start the main interrupt back at the top of the screen again
 + lda #<​Multiplex_maininter
 + sta KERNALIRQServiceRoutineLo
 + lda #>​Multiplex_maininter
 + sta KERNALIRQServiceRoutineHi
 +
 + ; MPi: First raster at the top of the first sprite minus a small amount of raster time to allow the first lot of sprite to be displayed
 + ldy Multiplex_indextable
 + lda Multiplex_YTable,​y
 + sec
 + sbc #8
 + bcs .storeRaster
 + lda #0 ; MPi: Don't go up beyond the top line
 +.storeRaster
 + sta VIC2Raster
 +
 + inc VIC2InteruptStatus
 + lda CIA1InterruptControl
 +
 +!ifdef Multiplexor_DebugBorder {
 + lda #3 : sta VIC2BorderColour
 +}
 +
 + lda Multiplex_areg
 + ldx Multiplex_xreg
 + ldy Multiplex_yreg
 + rti
 +}
 +
 +;​--------------------------------------
 +!zn {
 +Multiplex_initsort
 + ldx Multiplex_MaxSpr
 + dex
 +.1 txa
 + sta Multiplex_indextable,​x
 + dex
 + bpl .1
 +
 + lda #<​sortstart
 + sta Multiplex_bal
 + lda #>​sortstart
 + sta Multiplex_bah
 +
 + ldy #$00
 +.2 lda Multiplex_bal
 + sta Multiplex_sortlo,​y
 + lda Multiplex_bah
 + sta Multiplex_sorthi,​y
 +
 + lda Multiplex_bal
 + clc
 + adc #18
 + sta Multiplex_bal
 + bcc .over
 + inc Multiplex_bah
 +.over iny
 + cpy #​Multiplex_items-1
 + bne .2
 + rts
 +}
 +
 +;​--------------------------------------
 +!zn {
 +Multiplex_sort
 + lda Multiplex_MaxSpr
 + cmp #$02
 + bcc .exit
 + sbc #$02
 + tay
 + lda Multiplex_sortlo,​y
 + sta Multiplex_bal
 + lda Multiplex_sorthi,​y
 + sta Multiplex_bah
 + ldy #$00
 + lda #$60
 + sta (Multiplex_bal),​y
 + jsr .over0
 + ldy #$00
 + lda #$a4
 + sta (Multiplex_bal),​y
 +.exit rts
 +
 +.over0 ldy Multiplex_indextable+1
 +.back0 ldx Multiplex_indextable
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over1
 + stx Multiplex_indextable+1
 + sty Multiplex_indextable
 +
 +sortstart
 +.over1 ldy Multiplex_indextable+2
 +.back1 ldx Multiplex_indextable+1
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over2
 + stx Multiplex_indextable+2
 + sty Multiplex_indextable+1
 + bcc .back0
 +
 +.over2 ldy Multiplex_indextable+3
 +.back2 ldx Multiplex_indextable+2
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over3
 + stx Multiplex_indextable+3
 + sty Multiplex_indextable+2
 + bcc .back1
 +
 +.over3 ldy Multiplex_indextable+4
 +.back3 ldx Multiplex_indextable+3
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over4
 + stx Multiplex_indextable+4
 + sty Multiplex_indextable+3
 + bcc .back2
 +
 +.over4 ldy Multiplex_indextable+5
 +.back4 ldx Multiplex_indextable+4
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over5
 + stx Multiplex_indextable+5
 + sty Multiplex_indextable+4
 + bcc .back3
 +
 +.over5 ldy Multiplex_indextable+6
 +.back5 ldx Multiplex_indextable+5
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over6
 + stx Multiplex_indextable+6
 + sty Multiplex_indextable+5
 + bcc .back4
 +
 +.over6 ldy Multiplex_indextable+7
 +.back6 ldx Multiplex_indextable+6
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over7
 + stx Multiplex_indextable+7
 + sty Multiplex_indextable+6
 + bcc .back5
 +
 +.over7 ldy Multiplex_indextable+8
 +.back7 ldx Multiplex_indextable+7
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over8
 + stx Multiplex_indextable+8
 + sty Multiplex_indextable+7
 + bcc .back6
 +
 +.over8 ldy Multiplex_indextable+9
 +.back8 ldx Multiplex_indextable+8
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over9
 + stx Multiplex_indextable+9
 + sty Multiplex_indextable+8
 + bcc .back7
 +
 +.over9 ldy Multiplex_indextable+10
 +.back9 ldx Multiplex_indextable+9
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over10
 + stx Multiplex_indextable+10
 + sty Multiplex_indextable+9
 + bcc .back8
 +
 +.over10 ldy Multiplex_indextable+11
 +.back10 ldx Multiplex_indextable+10
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over11
 + stx Multiplex_indextable+11
 + sty Multiplex_indextable+10
 + bcc .back9
 +
 +;​-------------------
 +.over11 ldy Multiplex_indextable+12
 +.back11 ldx Multiplex_indextable+11
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over12
 + stx Multiplex_indextable+12
 + sty Multiplex_indextable+11
 + bcc .back10
 +
 +.over12 ldy Multiplex_indextable+13
 +.back12 ldx Multiplex_indextable+12
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over13
 + stx Multiplex_indextable+13
 + sty Multiplex_indextable+12
 + bcc .back11
 +
 +.over13 ldy Multiplex_indextable+14
 +.back13 ldx Multiplex_indextable+13
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over14
 + stx Multiplex_indextable+14
 + sty Multiplex_indextable+13
 + bcc .back12
 +
 +.over14 ldy Multiplex_indextable+15
 +.back14 ldx Multiplex_indextable+14
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over15
 + stx Multiplex_indextable+15
 + sty Multiplex_indextable+14
 + bcc .back13
 +
 +.over15 ldy Multiplex_indextable+16
 +.back15 ldx Multiplex_indextable+15
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over16
 + stx Multiplex_indextable+16
 + sty Multiplex_indextable+15
 + bcc .back14
 +
 +.over16 ldy Multiplex_indextable+17
 +.back16 ldx Multiplex_indextable+16
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over17
 + stx Multiplex_indextable+17
 + sty Multiplex_indextable+16
 + bcc .back15
 +
 +.over17 ldy Multiplex_indextable+18
 +.back17 ldx Multiplex_indextable+17
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over18
 + stx Multiplex_indextable+18
 + sty Multiplex_indextable+17
 + bcc .back16
 +
 +.over18 ldy Multiplex_indextable+19
 +.back18 ldx Multiplex_indextable+18
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over19
 + stx Multiplex_indextable+19
 + sty Multiplex_indextable+18
 + bcc .back17
 +
 +.over19 ldy Multiplex_indextable+20
 +.back19 ldx Multiplex_indextable+19
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over20
 + stx Multiplex_indextable+20
 + sty Multiplex_indextable+19
 + bcc .back18
 +
 +.over20 ldy Multiplex_indextable+21
 +.back20 ldx Multiplex_indextable+20
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over21
 + stx Multiplex_indextable+21
 + sty Multiplex_indextable+20
 + bcc .back19
 +;​-------------------
 +.over21 ldy Multiplex_indextable+22
 +.back21 ldx Multiplex_indextable+21
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over22
 + stx Multiplex_indextable+22
 + sty Multiplex_indextable+21
 + bcc .back20
 +
 +.over22 ldy Multiplex_indextable+23
 +.back22 ldx Multiplex_indextable+22
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over23
 + stx Multiplex_indextable+23
 + sty Multiplex_indextable+22
 + bcc .back21
 +
 +.over23 ldy Multiplex_indextable+24
 +.back23 ldx Multiplex_indextable+23
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over24
 + stx Multiplex_indextable+24
 + sty Multiplex_indextable+23
 + bcc .back22
 +
 +.over24 ldy Multiplex_indextable+25
 +.back24 ldx Multiplex_indextable+24
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over25
 + stx Multiplex_indextable+25
 + sty Multiplex_indextable+24
 + bcc .back23
 +
 +.over25 ldy Multiplex_indextable+26
 +.back25 ldx Multiplex_indextable+25
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over26
 + stx Multiplex_indextable+26
 + sty Multiplex_indextable+25
 + bcc .back24
 +
 +.over26 ldy Multiplex_indextable+27
 +.back26 ldx Multiplex_indextable+26
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over27
 + stx Multiplex_indextable+27
 + sty Multiplex_indextable+26
 + bcc .back25
 +
 +.over27 ldy Multiplex_indextable+28
 +.back27 ldx Multiplex_indextable+27
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over28
 + stx Multiplex_indextable+28
 + sty Multiplex_indextable+27
 + bcc .back26
 +
 +.over28 ldy Multiplex_indextable+29
 +.back28 ldx Multiplex_indextable+28
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over29
 + stx Multiplex_indextable+29
 + sty Multiplex_indextable+28
 + bcc .back27
 +
 +.over29 ldy Multiplex_indextable+30
 +.back29 ldx Multiplex_indextable+29
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over30
 + stx Multiplex_indextable+30
 + sty Multiplex_indextable+29
 + bcc .back28
 +
 +.over30 ldy Multiplex_indextable+31
 +.back30 ldx Multiplex_indextable+30
 + lda Multiplex_YTable,​y
 + cmp Multiplex_YTable,​x
 + bcs .over31
 + stx Multiplex_indextable+31
 + sty Multiplex_indextable+30
 + bcc .back29
 +.over31 ldy Multiplex_indextable
 + rts
 +}
 +
 +!align 255, 0
 +;​--------------------------------------
 +Multiplex_YTable
 + !by $34,​$38,​$3c,​$40,​$44,​$48,​$4c,​$50
 + !by $74,​$78,​$7c,​$80,​$84,​$88,​$8c,​$90
 + !by $60,​$60,​$75,​$75,​$a4,​$a8,​$ac,​$b0
 + !by $54,​$58,​$5c,​$60,​$64,​$68,​$6c,​$70
 +
 +Multiplex_XPosLo
 + !by $20,​$40,​$60,​$80,​$a0,​$c0,​$e0,​$ff
 + !by $20,​$40,​$60,​$80,​$a0,​$c0,​$e0,​$ff
 + !by $80,​$98,​$80,​$98,​$a0,​$c0,​$e0,​$ff
 + !by $20,​$40,​$60,​$80,​$a0,​$c0,​$e0,​$ff
 +
 +Multiplex_XPosHi
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 +
 +Multiplex_Colour
 + !by $01,​$02,​$03,​$04,​$05,​$06,​$07,​$08
 + !by $09,​$0a,​$0b,​$0c,​$0d,​$0e,​$0f,​$01
 + !by $01,​$02,​$03,​$04,​$05,​$06,​$07,​$08
 + !by $09,​$0a,​$0b,​$0c,​$0d,​$0e,​$0f,​$01
 +
 +Multiplex_SpriteFrame
 + !by $ff,​$fe,​$fd,​$fc,​$ff,​$fe,​$fd,​$fc
 + !by $ff,​$fe,​$fd,​$fc,​$ff,​$fe,​$fd,​$fc
 + !by $ff,​$fe,​$fd,​$fc,​$ff,​$fe,​$fd,​$fc
 + !by $ff,​$fe,​$fd,​$fc,​$ff,​$fe,​$fd,​$fc
 +
 +Multiplex_sortlo !fill Multiplex_items-1
 +Multiplex_sorthi !fill Multiplex_items-1
 +
 +!align 255, 0
 +;​--------------------------------------
 +!zn {
 +move
 + ldy Multiplex_MaxSpr
 + dey
 + bmi .exit
 +
 +.1 lda Multiplex_counterx2
 + clc
 + adc Multiplex_xdif
 + sta Multiplex_counterx2
 + clc
 + adc Multiplex_counterx1
 + tax
 + lda sinx,x
 + sta Multiplex_XPosLo,​y
 + lda sinxhi,x
 + sta Multiplex_XPosHi,​y
 +
 + lda Multiplex_countery2
 + clc
 + adc Multiplex_ydif
 + sta Multiplex_countery2
 + clc
 + adc Multiplex_countery1
 + tax
 + lda siny,x
 + sta Multiplex_YTable,​y
 +
 + dey
 + bpl .1
 +
 +
 +.exit
 +
 + ; MPi: When uncommented this demonstrates that when a sprite has a Y coord of $ff then the multiplexor will sort them to the end of the list and will stop plotting sprites.
 +; lda #$ff
 +; sta Multiplex_YTable + 7
 +; sta Multiplex_YTable + 17
 +; sta Multiplex_YTable + 27
 +; sta Multiplex_YTable + 18
 +; sta Multiplex_YTable + 19
 +; sta Multiplex_YTable + 20
 +; sta Multiplex_YTable + 21
 +; sta Multiplex_YTable + 22
 +; sta Multiplex_YTable + 23
 +
 +
 + ; MPi: When uncommented demonstrate how only modifying some sprite Y values each frame and keeping others constant results in a faster sort time.
 +; lda #50
 +; sta Multiplex_YTable + 4
 +; sta Multiplex_YTable + 5
 +; sta Multiplex_YTable + 6
 +; sta Multiplex_YTable + 7
 +; lda #80
 +; sta Multiplex_YTable + 16
 +; sta Multiplex_YTable + 17
 +; sta Multiplex_YTable + 18
 +; sta Multiplex_YTable + 19
 +; lda #110
 +; sta Multiplex_YTable + 20
 +; sta Multiplex_YTable + 21
 +; sta Multiplex_YTable + 22
 +; sta Multiplex_YTable + 23
 +; lda #140
 +; sta Multiplex_YTable + 24
 +; sta Multiplex_YTable + 25
 +; sta Multiplex_YTable + 26
 +; sta Multiplex_YTable + 27
 +; lda #170
 +; sta Multiplex_YTable + 0
 +; sta Multiplex_YTable + 1
 +; sta Multiplex_YTable + 2
 +; sta Multiplex_YTable + 3
 +; lda #200
 +; sta Multiplex_YTable + 8
 +; sta Multiplex_YTable + 9
 +; sta Multiplex_YTable + 10
 +; sta Multiplex_YTable + 11
 +; lda #230
 +; sta Multiplex_YTable + 12
 +; sta Multiplex_YTable + 13
 +; sta Multiplex_YTable + 14
 +; sta Multiplex_YTable + 15
 +
 +
 + lda Multiplex_xoffset
 + sta Multiplex_counterx2
 + lda Multiplex_yoffset
 + sta Multiplex_countery2
 +
 + lda Multiplex_counterx1
 + clc
 + adc Multiplex_xspeed
 + sta Multiplex_counterx1
 +
 + lda Multiplex_countery1
 + clc
 + adc Multiplex_yspeed
 + sta Multiplex_countery1
 +
 + rts
 +}
 +
 +!align 255, 0
 +sinx
 + !by $af,​$b2,​$b6,​$b9,​$bd,​$c1,​$c4,​$c8,​$cb,​$cf,​$d2,​$d6,​$d9,​$dd,​$e0,​$e3
 + !by $e7,​$ea,​$ed,​$f1,​$f4,​$f7,​$fa,​$fd,​$00,​$03,​$06,​$09,​$0b,​$0e,​$11,​$13
 + !by $16,​$18,​$1b,​$1d,​$1f,​$21,​$24,​$26,​$28,​$2a,​$2b,​$2d,​$2f,​$30,​$32,​$33
 + !by $35,​$36,​$37,​$38,​$39,​$3a,​$3b,​$3c,​$3c,​$3d,​$3d,​$3e,​$3e,​$3e,​$3e,​$3e
 + !by $3e,​$3e,​$3e,​$3e,​$3d,​$3d,​$3c,​$3c,​$3b,​$3a,​$39,​$38,​$37,​$36,​$35,​$33
 + !by $32,​$30,​$2f,​$2d,​$2b,​$2a,​$28,​$26,​$24,​$21,​$1f,​$1d,​$1b,​$18,​$16,​$13
 + !by $11,​$0e,​$0b,​$09,​$06,​$03,​$00,​$fd,​$fa,​$f7,​$f4,​$f1,​$ed,​$ea,​$e7,​$e3
 + !by $e0,​$dd,​$d9,​$d6,​$d2,​$cf,​$cb,​$c8,​$c4,​$c1,​$bd,​$b9,​$b6,​$b2,​$af,​$ab
 + !by $a7,​$a4,​$a0,​$9d,​$99,​$95,​$92,​$8e,​$8b,​$87,​$84,​$80,​$7d,​$79,​$76,​$73
 + !by $6f,​$6c,​$69,​$65,​$62,​$5f,​$5c,​$59,​$56,​$53,​$50,​$4d,​$4b,​$48,​$45,​$43
 + !by $40,​$3e,​$3b,​$39,​$37,​$35,​$32,​$30,​$2e,​$2c,​$2b,​$29,​$27,​$26,​$24,​$23
 + !by $21,​$20,​$1f,​$1e,​$1d,​$1c,​$1b,​$1a,​$1a,​$19,​$19,​$18,​$18,​$18,​$18,​$18
 + !by $18,​$18,​$18,​$18,​$19,​$19,​$1a,​$1a,​$1b,​$1c,​$1d,​$1e,​$1f,​$20,​$21,​$23
 + !by $24,​$26,​$27,​$29,​$2b,​$2c,​$2e,​$30,​$32,​$35,​$37,​$39,​$3b,​$3e,​$40,​$43
 + !by $45,​$48,​$4b,​$4d,​$50,​$53,​$56,​$59,​$5c,​$5f,​$62,​$65,​$69,​$6c,​$6f,​$73
 + !by $76,​$79,​$7d,​$80,​$84,​$87,​$8b,​$8e,​$92,​$95,​$99,​$9d,​$a0,​$a4,​$a7,​$ab
 +
 +sinxhi
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01
 + !by $01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01
 + !by $01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01
 + !by $01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01
 + !by $01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01,​$01
 + !by $01,​$01,​$01,​$01,​$01,​$01,​$01,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 + !by $00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00,​$00
 +
 +siny
 + !by $8d,​$8f,​$92,​$94,​$96,​$98,​$9a,​$9c,​$9f,​$a1,​$a3,​$a5,​$a7,​$a9,​$ab,​$ad
 + !by $af,​$b1,​$b3,​$b5,​$b7,​$b9,​$bb,​$bc,​$be,​$c0,​$c2,​$c3,​$c5,​$c7,​$c8,​$ca
 + !by $cb,​$cd,​$ce,​$d0,​$d1,​$d2,​$d4,​$d5,​$d6,​$d7,​$d8,​$d9,​$da,​$db,​$dc,​$dd
 + !by $de,​$df,​$e0,​$e0,​$e1,​$e1,​$e2,​$e2,​$e3,​$e3,​$e3,​$e4,​$e4,​$e4,​$e4,​$e4
 + !by $e4,​$e4,​$e4,​$e4,​$e3,​$e3,​$e3,​$e2,​$e2,​$e1,​$e1,​$e0,​$e0,​$df,​$de,​$dd
 + !by $dc,​$db,​$da,​$d9,​$d8,​$d7,​$d6,​$d5,​$d4,​$d2,​$d1,​$d0,​$ce,​$cd,​$cb,​$ca
 + !by $c8,​$c7,​$c5,​$c3,​$c2,​$c0,​$be,​$bc,​$bb,​$b9,​$b7,​$b5,​$b3,​$b1,​$af,​$ad
 + !by $ab,​$a9,​$a7,​$a5,​$a3,​$a1,​$9f,​$9c,​$9a,​$98,​$96,​$94,​$92,​$8f,​$8d,​$8b
 + !by $89,​$87,​$84,​$82,​$80,​$7e,​$7c,​$7a,​$77,​$75,​$73,​$71,​$6f,​$6d,​$6b,​$69
 + !by $67,​$65,​$63,​$61,​$5f,​$5d,​$5b,​$5a,​$58,​$56,​$54,​$53,​$51,​$4f,​$4e,​$4c
 + !by $4b,​$49,​$48,​$46,​$45,​$44,​$42,​$41,​$40,​$3f,​$3e,​$3d,​$3c,​$3b,​$3a,​$39
 + !by $38,​$37,​$36,​$36,​$35,​$35,​$34,​$34,​$33,​$33,​$33,​$32,​$32,​$32,​$32,​$32
 + !by $32,​$32,​$32,​$32,​$33,​$33,​$33,​$34,​$34,​$35,​$35,​$36,​$36,​$37,​$38,​$39
 + !by $3a,​$3b,​$3c,​$3d,​$3e,​$3f,​$40,​$41,​$42,​$44,​$45,​$46,​$48,​$49,​$4b,​$4c
 + !by $4e,​$4f,​$51,​$53,​$54,​$56,​$58,​$5a,​$5b,​$5d,​$5f,​$61,​$63,​$65,​$67,​$69
 + !by $6b,​$6d,​$6f,​$71,​$73,​$75,​$77,​$7a,​$7c,​$7e,​$80,​$82,​$84,​$87,​$89,​$8b
 + !by $ff
 +</​code>​
 +
 +=== Create as "​stdlib.asm"​ ===
 +<​code>​
 +; Zero page
 +
 +; Each enabled bit sets read and write on the processor port (ZPProcessorPort) otherwise the value can just be read.
 +; Default: $2F, %101111
 +ZPProcessorPortDDR = $00
 +
 +; Bits 0-2: Configuration for memory areas $A000-$BFFF,​ $D000-$DFFF and $E000-$FFFF. Values:
 +; %x00: RAM visible in all three areas.
 +; %x01: RAM visible at $A000-$BFFF and $E000-$FFFF.
 +; %x10: RAM visible at $A000-$BFFF;​ KERNAL ROM visible at $E000-$FFFF.
 +; %x11: BASIC ROM visible at $A000-$BFFF;​ KERNAL ROM visible at $E000-$FFFF.
 +; %0xx: Character ROM visible at $D000-$DFFF. (Except for the value %000, see above.)
 +; %1xx: I/O area visible at $D000-$DFFF. (Except for the value %100, see above.)
 +; Bit 3: Datasette output signal level.
 +; Bit 4: Datasette button status; 0 = One or more of PLAY, RECORD, F.FWD or REW pressed; 1 = No button is pressed.
 +; Bit 5: Datasette motor control; 0 = On; 1 = Off.
 +; Default: $37, %110111
 +ZPProcessorPort = $01
 +
 +; $02 - $06 are unused (apparently).
 +
 +; $07 - $2a are only really used during BASIC execution.
 +
 +; By default contains $0801
 +ZPStartBasicLo = $2b
 +ZPStartBasicHi = $2c
 +
 +ZPStartVariableLo = $2d
 +ZPStartVariableHi = $2e
 +
 +ZPStartArrayVariableLo = $2f
 +ZPStartArrayVariableHi = $30
 +
 +ZPEndArrayVariableLo = $31
 +ZPEndArrayVariableHi = $32
 +
 +ZPStartStringVariableLo = $33
 +ZPStartStringVariableHi = $34
 +
 +ZPCurrentStringVariableLo = $35
 +ZPCurrentStringVariableHi = $36
 +
 +ZPEndBasicLo = $37
 +ZPEndBasicHi = $38
 +
 +; $39 - $72 are only really used during BASIC execution.
 +
 +; $73 - $8a
 +ZPChrGet = $73
 +
 +; $8b - $8f are only really used during BASIC execution.
 +
 +; Also used for datasette status
 +ZPSTVariable = $90
 +
 +ZPStopKeyIndicator = $91
 +ZPDatasetteTiming = $92
 +ZPLoadVerify = $93
 +ZPSerialBusCacheStatus = $94
 +ZPSerialBusCache = $95
 +ZPDatasetteEndOfTape = $96
 +ZPRS232XYTemp = $97
 +ZPNumFilesOpen = $98
 +ZPCurrentInputDevice = $99
 +ZPCurrentOutputDevice = $9a
 +ZPDatasetteParity = $9b
 +ZPDatasetteByteReady = $9c
 +ZPDisplaySystemErrorSwitch = $9d
 +ZPRS232OutByte = $9e
 +ZPDatasetteNameWriteCount = $9f
 +ZPTimeOfDay = $a0 ; $a0 - a2
 +ZPEOISerialBusSwitch = $a3
 +ZPSerialBusBuffer = $a4
 +ZPSerialBusBitCounter = $a5
 +ZPDatasetteBufferOffset = $a6
 +ZPRS232BusBuffer = $a7
 +ZPRS232BusBitCounter = $a8
 +ZPRS232StopBitSwitch = $a9
 +ZPRS232ByteBuffer = $aa
 +ZPRS232Parity = $ab
 +ZPAddressToSave = $ac ; $ac - ad
 +ZPAddressToLoad = $ae ; $ae - af
 +
 +; $b0 - $b1 unknown
 +
 +ZPDatasetteBufferLo = $b2
 +ZPDatasetteBufferHo = $b3
 +ZPRS232BitCounter = $b4
 +ZPRS232BitBuffer = $b5
 +
 +; $b7 - $c4 Various file operation working area
 +
 +ZPPrevKeyPressed = $c5
 +ZPKeyBufferLength = $c6
 +
 +; $c7 - $ca Various cursor operations
 +
 +ZPCurrentKeyPressed = $cb
 +
 +; $cc - $f6 Various cursor, screen and keyboard conversion tables
 +
 +; $f7 - $fa RS232 input and output buffers
 +
 +; $fb - $fe unused
 +
 +ProcessorStack = $0100 ; $0100 - $01ff
 +
 +; $0200 - $0292 Various keyboard buffers and buffers used by BASIC
 +
 +; $0293 - $02ff RS232 and datasette control and buffers
 +
 +; $0300 - $0312 Used by BASIC
 +
 +; $0313 unused
 +
 +DefaultIRQServiceRoutine = $ea31
 +MinimalIRQServiceRoutine = $ea81
 +IRQServiceRoutineLo = $0314
 +IRQServiceRoutineHi = $0315
 +
 +; Default = $fe66
 +BRKServiceRoutineLo = $0316
 +BRKServiceRoutineHi = $0317
 +
 +DefaultNMIServiceRoutine = $fe47
 +NMIServiceRoutineLo = $0318
 +NMIServiceRoutineHo = $0319
 +
 +; $031a - $0333 Various vectors for standard routines like open, close, load, save etc
 +
 +; Default $f4a5
 +LoadRoutineLo = $0330
 +LoadRoutineHi = $0331
 +
 +; Default $f5ed
 +SaveRoutineLo = $0332
 +SaveRoutineHi = $0333
 +
 +; $0334 - $033b unused
 +
 +; $033c - $03fb Datasette buffer
 +
 +; $03fc - $03ff unused
 +
 +
 +
 +; Special memory sections
 +
 +BASICSTART= $0801 ; Default is memory PEEK(43) = 1 and PEEK(44) = 8
 +SCREENRAM = $0400
 +SPRITEFRAME = $07f8
 +BASICROM ​ = $A000
 +VIC       = $D000
 +SID       = $D400
 +COLORRAM ​ = $D800
 +COLOURRAM = $D800
 +CIA1      = $DC00
 +CIA2      = $DD00
 +KERNALROM = $E000
 +
 +; KERNAL routines
 +
 +ACPTR   = $FFA5
 +CHKIN   = $FFC6
 +CHKOUT ​ = $FFC9
 +CHRIN   = $FFCF
 +CHROUT ​ = $FFD2
 +CIOUT   = $FFA8
 +CINT    = $FF81
 +CLALL   = $FFE7
 +CLOSE   = $FFC3
 +CLRCHN ​ = $FFCC
 +GETIN   = $FFE4
 +IOBASE ​ = $FFF3
 +IOINIT ​ = $FF84
 +LISTEN ​ = $FFB1
 +LOAD    = $FFD5
 +MEMBOT ​ = $FF9C
 +MEMTOP ​ = $FF99
 +OPEN    = $FFC0
 +PLOT    = $FFF0
 +RAMTAS ​ = $FF87
 +RDTIM   = $FFDE
 +READST ​ = $FFB7
 +RESTOR ​ = $FF8A
 +SAVE    = $FFD8
 +SCNKEY ​ = $FF9F
 +SCREEN ​ = $FFED
 +SECOND ​ = $FF93
 +SETLFS ​ = $FFBA
 +SETMSG ​ = $FF90
 +SETNAM ​ = $FFBD
 +SETTIM ​ = $FFDB
 +SETTMO ​ = $FFA2
 +STOP    = $FFE1
 +TALK    = $FFB4
 +TKSA    = $FF96
 +UDTIM   = $FFEA
 +UNLSN   = $FFAE
 +UNTLK   = $FFAB
 +VECTOR ​ = $FF8D
 +
 +; KERNAL Vectors
 +
 +; Default = $fe43
 +KERNALNMIServiceRoutineLo = $fffa
 +KERNALNMIServiceRoutineHo = $fffb
 +
 +; Default = $fce2
 +KERNALColdStartResetLo = $fffc
 +KERNALColdStartResetHi = $fffd
 +
 +; Default = $ff48
 +KERNALIRQServiceRoutineLo = $fffe
 +KERNALIRQServiceRoutineHi = $ffff
 +
 +; Specific locations within the custom chips
 +
 +; VIC II Video chip
 +VIC2Sprite0X = $d000
 +VIC2Sprite0Y = $d001
 +VIC2Sprite1X = $d002
 +VIC2Sprite1Y = $d003
 +VIC2Sprite2X = $d004
 +VIC2Sprite2Y = $d005
 +VIC2Sprite3X = $d006
 +VIC2Sprite3Y = $d007
 +VIC2Sprite4X = $d008
 +VIC2Sprite4Y = $d009
 +VIC2Sprite5X = $d00a
 +VIC2Sprite5Y = $d00b
 +VIC2Sprite6X = $d00c
 +VIC2Sprite6Y = $d00d
 +VIC2Sprite7X = $d00e
 +VIC2Sprite7Y = $d00f
 +
 +; Each bit is the X MSB for each sprite.
 +VIC2SpriteXMSB = $d010
 +
 +; Bits 0-2 Vertical scroll.
 +; 3 Screen height 0 = 24 rows last line 246 (f6) : 1 = 25 rows last line $fa (250)
 +; 4 0 = Screen off 1 = Screen on
 +; 5 0 = Text mode 1 = Bitmap mode
 +; 6 1 = Extended background mode on
 +; 7 Read: Current raster line position bit 9. Write: Bit 9 of raster line position to generate next interrupt.
 +; Default: $1b, %00011011
 +VIC2ScreenControlV = $d011
 +
 +; Read: Current raster line position.
 +; Write: Raster line position to generate next interrupt.
 +VIC2Raster = $d012
 +VIC2LightPenX = $d013
 +VIC2LightPenY = $d014
 +VIC2SpriteEnable = $d015
 +
 +; Bits 0-2 Horizontal scroll.
 +; 3 Screen width 0 = 38 columns 1 = 40 columns
 +; 4 1 = Multicolour on
 +; 5-7 Unused
 +; Default: $c8, %11001000
 +VIC2ScreenControlH = $d016
 +
 +; Each bit sets the double height enable for each sprite.
 +VIC2SpriteDoubleHeight = $d017
 +
 +; In text mode:
 +; Bits 1-3 Character memory location * $0800 (2048) inside current VIC bank selected by $dd00.
 +; In VIC bank 0 and 2 bits %010 and %011 select character ROM except in ULTIMAX mode.
 +; In bitmap mode:
 +; Bit 3 Bitmap memory location * $2000 (8192) inside current VIC bank selected by $dd00.
 +; Bits 4-7 Screen memory location * $1000 (1024) ​ inside current VIC bank selected by $dd00.
 +VIC2MemorySetup = $d018
 +
 +; Read:
 +; Bit 0: 1 = Current raster line is equal to the raster line which is set to generate an interrupt.
 +; Bit 1: 1 = Sprite-background collision event.
 +; Bit 2: 1 = Sprite-sprite collision event.
 +; Bit 3: 1 = Light pen signal received.
 +; Bit 7: 1 = An event that might generate an interrupt happened.
 +; Write:
 +; Bit 0: 0 = Ack raster interrupt.
 +; Bit 1: 0 = Ack sprite-background collision interrupt.
 +; Bit 2: 0 = Ack sprite-sprite collision interrupt.
 +; Bit 3: 0 = Ack light pen signal interrupt.
 +VIC2InteruptStatus = $d019
 +
 +; Bit 0: 1 = Raster interrupt enabled.
 +; Bit 1: 1 = Sprite-background interrupt enabled.
 +; Bit 2: 1 = Sprite-sprite interrupt enabled.
 +; Bit 3: 1 = Light pen interrupt enabled.
 +VIC2InteruptControl = $d01a
 +
 +; Each bit sets the sprite background priority for each sprite.
 +; 0 = Sprite drawn in front of screen contents.
 +; 1 = Sprite drawn behind of screen contents.
 +VIC2SpritePriority = $d01b
 +
 +; Each bit sets multicolour for each sprite.
 +; 0 = Sprite is single colour.
 +; 1 = Sprite is multicolour.
 +VIC2SpriteMulticolour = $d01c
 +
 +; Each bit sets the double width enable for each sprite.
 +VIC2SpriteDoubleWidth = $d01d
 +
 +; Read: For each set bit X the sprite X collided with another sprite.
 +; Write: For each set bit X allow further sprite-sprite collisions.
 +VIC2SpriteSpriteCollision = $d01e
 +
 +; Read: For each set bit X the sprite X collided with the background.
 +; Write: For each set bit X allow further sprite-background collisions.
 +VIC2SpriteBackgroundCollision = $d01f
 +
 +VIC2BorderColour = $d020
 +VIC2ScreenColour = $d021
 +
 +VIC2ExtraBackgroundColour1 = $d022
 +VIC2ExtraBackgroundColour2 = $d023
 +VIC2ExtraBackgroundColour3 = $d024
 +
 +VIC2ExtraSpriteColour1 = $d025
 +VIC2ExtraSpriteColour2 = $d025
 +
 +VIC2Sprite0Colour = $d027
 +VIC2Sprite1Colour = $d028
 +VIC2Sprite2Colour = $d029
 +VIC2Sprite3Colour = $d02a
 +VIC2Sprite4Colour = $d02b
 +VIC2Sprite5Colour = $d02c
 +VIC2Sprite6Colour = $d02d
 +VIC2Sprite7Colour = $d02e
 +
 +
 +; SID Audio chip
 +
 +SIDVoice1FreqLo = $d400 ; Write only
 +SIDVoice1FreqHi = $d401 ; Write only
 +SIDVoice1PulseWidthLo = $d402 ; Write only
 +SIDVoice1PulseWidthHi = $d403 ; Write only
 +
 +; Bit 0: 0 = Voice off, release cycle. 1 = Voice on do attack-decay-sustain.
 +; Bit 1: 1 = Synchronization enable.
 +; Bit 2: 1 = Ting modulation enable.
 +; Bit 3: 1 = Disable voice.
 +; Bit 4: 1 = Triangle waveform enable.
 +; Bit 5: 1 = Saw waveform enable.
 +; Bit 6: 1 = Rectangle waveform enable.
 +; Bit 7: 1 = Noise waveform enable.
 +SIDVoice1Control = $d404 ; Write only
 +
 +; Bits 0-3 Decay length:
 +; %0000, 0: 6 ms.
 +; %0001, 1: 24 ms.
 +; %0010, 2: 48 ms.
 +; %0011, 3: 72 ms.
 +; %0100, 4: 114 ms.
 +; %0101, 5: 168 ms.
 +; %0110, 6: 204 ms.
 +; %0111, 7: 240 ms.
 +; %1000, 8: 300 ms.
 +; %1001, 9: 750 ms.
 +; %1010, 10: 1.5 s.
 +; %1011, 11: 2.4 s.
 +; %1100, 12: 3 s.
 +; %1101, 13: 9 s.
 +; %1110, 14: 15 s.
 +; %1111, 15: 24 s.
 +; Bits 4-7 Decay length:
 +; %0000, 0: 2 ms.
 +; %0001, 1: 8 ms.
 +; %0010, 2: 16 ms.
 +; %0011, 3: 24 ms.
 +; %0100, 4: 38 ms.
 +; %0101, 5: 56 ms.
 +; %0110, 6: 68 ms.
 +; %0111, 7: 80 ms.
 +; %1000, 8: 100 ms.
 +; %1001, 9: 250 ms.
 +; %1010, 10: 500 ms.
 +; %1011, 11: 800 ms.
 +; %1100, 12: 1 s.
 +; %1101, 13: 3 s.
 +; %1110, 14: 5 s.
 +; %1111, 15: 8 s.
 +SIDVoice1AttackDecay = $d405 ; Write only
 +
 +; Bits 0-3 Release length.
 +; %0000, 0: 6 ms.
 +; %0001, 1: 24 ms.
 +; %0010, 2: 48 ms.
 +; %0011, 3: 72 ms.
 +; %0100, 4: 114 ms.
 +; %0101, 5: 168 ms.
 +; %0110, 6: 204 ms.
 +; %0111, 7: 240 ms.
 +; %1000, 8: 300 ms.
 +; %1001, 9: 750 ms.
 +; %1010, 10: 1.5 s.
 +; %1011, 11: 2.4 s.
 +; %1100, 12: 3 s.
 +; %1101, 13: 9 s.
 +; %1110, 14: 15 s.
 +; %1111, 15: 24 s.
 +; Bits #4-#7: Sustain volume.
 +SIDVoice1SustainRelease = $d406 ; Write only
 +
 +SIDVoice2FreqLo = $d407 ; Write only
 +SIDVoice2FreqHi = $d408 ; Write only
 +SIDVoice2PulseWidthLo = $d409 ; Write only
 +SIDVoice2PulseWidthHi = $d40a ; Write only
 +SIDVoice2Control = $d40b ; Write only
 +SIDVoice2AttackDecay = $d40c ; Write only
 +SIDVoice2SustainRelease = $d40d ; Write only
 +
 +SIDVoice3FreqLo = $d40e ; Write only
 +SIDVoice3FreqHi = $d40f ; Write only
 +SIDVoice3PulseWidthLo = $d410 ; Write only
 +SIDVoice3PulseWidthHi = $d411 ; Write only
 +SIDVoice3Control = $d412 ; Write only
 +SIDVoice3AttackDecay = $d413 ; Write only
 +SIDVoice3SustainRelease = $d414 ; Write only
 +
 +SIDFilterCutoffFreqLo = $d415 ; Write only
 +SIDFilterCutoffFreqHi = $d416 ; Write only
 +
 +; Bit 0: 1 = Voice #1 filtered.
 +; Bit 1: 1 = Voice #2 filtered.
 +; Bit 2: 1 = Voice #3 filtered.
 +; Bit 3: 1 = External voice filtered.
 +; Bits 4-7: Filter resonance.
 +SIDFilterControl = $d417 ; Write only
 +
 +; Bits 0-3: Volume.
 +; Bit 4: 1 = Low pass filter enabled.
 +; Bit 5: 1 = Band pass filter enabled.
 +; Bit 6: 1 = High pass filter enabled.
 +; Bit 7: 1 = Voice #3 disabled.
 +SIDVolumeFilter = $d418 ; Write only
 +
 +; Paddle is selected by memory address $dd00
 +SIDPaddleX = $d419 ; Read only
 +
 +; Paddle is selected by memory address $dd00
 +SIDPaddleY = $d41a ; Read only
 +
 +SIDVoice3WaveformOutput = $d41b ; Read only
 +SIDVoice3ADSROutput = $d41c ; Read only
 +
 +
 +
 +; CIA1
 +
 +; Port A read:
 +; Bit 0: 0 = Port 2 joystick up pressed.
 +; Bit 1: 0 = Port 2 joystick down pressed.
 +; Bit 2: 0 = Port 2 joystick right pressed.
 +; Bit 3: 0 = Port 2 joystick left pressed.
 +; Bit 4: 0 = Port 2 joystick fire pressed.
 +; Write:
 +; Bit x: 0 = Select keyboard matrix column x.
 +; Bits 6-7: Paddle selection; %01 = Paddle #1; %10 = Paddle #2.
 +CIA1KeyboardColumnJoystickA = $dc00
 +
 +; Port B, keyboard matrix rows and joystick #1. Bits:
 +; Bit x: 0 = A key is currently being pressed in keyboard matrix row #x, in the column selected at memory address $DC00.
 +; Bit 0: 0 = Port 1 joystick up pressed.
 +; Bit 1: 0 = Port 1 joystick down pressed.
 +; Bit 2: 0 = Port 1 joystick right pressed.
 +; Bit 3: 0 = Port 1 joystick left pressed.
 +; Bit 4: 0 = Port 1 joystick fire pressed.
 +CIA1KeyboardRowsJoystickB = $dc01
 +
 +; Each enabled bit sets read and write on CIA1KeyboardColumnJoystickA otherwise the value can just be read.
 +CIA1PortADDR = $dc02
 +
 +; Each enabled bit sets read and write on CIA1KeyboardRowsJoystickB otherwise the value can just be read.
 +CIA1PortBDDR = $dc03
 +
 +CIA1TimerALo = $dc04
 +CIA1TimerAHi = $dc05
 +
 +CIA1TimerBLo = $dc06
 +CIA1TimerBHi = $dc07
 +
 +CIA1ToD10thSecsBCD = $dc08
 +CIA1ToDSecsBCD = $dc09
 +CIA1ToDMinsBCD = $dc0a
 +CIA1ToDHoursBCD = $dc0b
 +CIA1SerialShift = $dc0c
 +
 +; Interrupt control and status register.
 +; Read bits:
 +; Bit 0: 1 = Timer A underflow occurred.
 +; Bit 1: 1 = Timer B underflow occurred.
 +; Bit 2: 1 = TOD is equal to alarm time.
 +; Bit 3: 1 = A complete byte has been received into or sent from serial shift register.
 +; Bit 4: Signal level on FLAG pin, datasette input.
 +; Bit 7: An interrupt has been generated.
 +; Write bits:
 +; Bit 0: 1 = Enable interrupts generated by timer A underflow.
 +; Bit 1: 1 = Enable interrupts generated by timer B underflow.
 +; Bit 2: 1 = Enable TOD alarm interrupt.
 +; Bit 3: 1 = Enable interrupts generated by a byte having been received/​sent via serial shift register.
 +; Bit 4: 1 = Enable interrupts generated by positive edge on FLAG pin.
 +; Bit 7: Fill bit; bits 0-6, that are set to 1, get their values from this bit; bits 0-6, that are set to 0, are left unchanged.
 +CIA1InterruptControl = $dc0d
 +
 +; Timer A control register. Bits:
 +; Bit 0: 0 = Stop timer; 1 = Start timer.
 +; Bit 1: 1 = Indicate timer underflow on port B bit 6.
 +; Bit 2: 0 = Upon timer underflow, invert port B bit 6; 1 = upon timer underflow, generate a positive edge on port B bit 6 for 1 system cycle. ​
 +; Bit 3: 0 = Timer restarts upon underflow; 1 = Timer stops upon underflow.
 +; Bit 4: 1 = Load start value into timer.
 +; Bit 5: 0 = Timer counts system cycles; 1 = Timer counts positive edges on CNT pin.
 +; Bit 6: Serial shift register direction; 0 = Input, read; 1 = Output, write.
 +; Bit 7: TOD speed; 0 = 60 Hz; 1 = 50 Hz.
 +CIA1TimerAControl = $dc0e
 +
 +; Timer B control register. Bits:
 +; Bit 0: 0 = Stop timer; 1 = Start timer.
 +; Bit 1: 1 = Indicate timer underflow on port B bit 7.
 +; Bit 2: 0 = Upon timer underflow, invert port B bit 7; 1 = upon timer underflow, generate a positive edge on port B bit 7 for 1 system cycle.
 +; Bit 3: 0 = Timer restarts upon underflow; 1 = Timer stops upon underflow.
 +; Bit 4: 1 = Load start value into timer.
 +; Bits 5-6: %00 = Timer counts system cycles; %01 = Timer counts positive edges on CNT pin; %10 = Timer counts underflows of timer A; %11 = Timer counts underflows of timer A occurring along with a positive edge on CNT pin.
 +; Bit 7: 0 = Writing into TOD registers sets TOD; 1 = Writing into TOD registers sets alarm time.
 +CIA1TimerBControl = $dc0f
 +
 +
 +; CIA2. Mostly the same as CIA1 except for VIC bank, no datasette, RS232 and generates NMI instead of IRQ.
 +
 +; Bits 0-1: VIC bank. Values:
 +; %00, 0: Bank 3, $C000-$FFFF,​ 49152-65535.
 +; %01, 1: Bank 2, $8000-$BFFF,​ 32768-49151.
 +; %10, 2: Bank 1, $4000-$7FFF,​ 16384-32767.
 +; %11, 3: Bank 0, $0000-$3FFF,​ 0-16383.
 +; Bit 2: RS232 TXD line, output bit.
 +; Bit 3: Serial bus ATN OUT; 0 = High; 1 = Low.
 +; Bit 4: Serial bus CLOCK OUT; 0 = High; 1 = Low.
 +; Bit 5: Serial bus DATA OUT; 0 = High; 1 = Low.
 +; Bit 6: Serial bus CLOCK IN; 0 = High; 1 = Low.
 +; Bit 7: Serial bus DATA IN; 0 = High; 1 = Low.
 +CIA2PortASerialBusVICBank = $dd00
 +
 +
 +; Read bits:
 +; Bit 0: RS232 RXD line, input bit.
 +; Bit 3: RS232 RI line.
 +; Bit 4: RS232 DCD line.
 +; Bit 5: User port H pin.
 +; Bit 6: RS232 CTS line; 1 = Sender is ready to send.
 +; Bit 7: RS232 DSR line; 1 = Receiver is ready to receive.
 +; Write bits:
 +; Bit 1: RS232 RTS line. 1 = Sender is ready to send.
 +; Bit 2: RS232 DTR line. 1 = Receiver is ready to receive.
 +; Bit 3: RS232 RI line.
 +; Bit 4: RS232 DCD line.
 +; Bit 5: User port H pin.
 +CIA2PortBRS232 = $dd01
 +
 +; Each enabled bit sets read and write on CIA2PortASerialBusVICBank otherwise the value can just be read.
 +CIA2PortADDR = $dd02
 +
 +; Each enabled bit sets read and write on CIA2PortBRS232 otherwise the value can just be read.
 +CIA2PortBDDR = $dd03
 +
 +CIA2TimerALo = $dd04
 +CIA2TimerAHi = $dd05
 +
 +CIA2TimerBLo = $dd06
 +CIA2TimerBHi = $dd07
 +
 +CIA2ToD10thSecsBCD = $dd08
 +CIA2ToDSecsBCD = $dd09
 +CIA2ToDMinsBCD = $dd0a
 +CIA2ToDHoursBCD = $dd0b
 +CIA2SerialShift = $dd0c
 +
 +; Non-maskable interrupt control and status register.
 +; Read bits:
 +; Bit 0: 1 = Timer A underflow occurred.
 +; Bit 1: 1 = Timer B underflow occurred.
 +; Bit 2: 1 = TOD is equal to alarm time.
 +; Bit 3: 1 = A complete byte has been received into or sent from serial shift register.
 +; Bit 4: Signal level on FLAG pin.
 +; Bit 7: An non-maskable interrupt has been generated.
 +; Write bits:
 +; Bit 0: 1 = Enable non-maskable interrupts generated by timer A underflow.
 +; Bit 1: 1 = Enable non-maskable interrupts generated by timer B underflow.
 +; Bit 2: 1 = Enable TOD alarm non-maskable interrupt.
 +; Bit 3: 1 = Enable non-maskable interrupts generated by a byte having been received/​sent via serial shift register.
 +; Bit 4: 1 = Enable non-maskable interrupts generated by positive edge on FLAG pin.
 +; Bit 7: Fill bit; bits 0-6, that are set to 1, get their values from this bit; bits 0-6, that are set to 0, are left unchanged.
 +CIA2InterruptControl = $dd0d
 +
 +; Timer A control register. Bits:
 +; Bit 0: 0 = Stop timer; 1 = Start timer.
 +; Bit 1: 1 = Indicate timer underflow on port B bit 6.
 +; Bit 2: 0 = Upon timer underflow, invert port B bit 6; 1 = upon timer underflow, generate a positive edge on port B bit 6 for 1 system cycle. ​
 +; Bit 3: 0 = Timer restarts upon underflow; 1 = Timer stops upon underflow.
 +; Bit 4: 1 = Load start value into timer.
 +; Bit 5: 0 = Timer counts system cycles; 1 = Timer counts positive edges on CNT pin.
 +; Bit 6: Serial shift register direction; 0 = Input, read; 1 = Output, write.
 +; Bit 7: TOD speed; 0 = 60 Hz; 1 = 50 Hz.
 +CIA2TimerAControl = $dd0e
 +
 +; Timer B control register. Bits:
 +; Bit 0: 0 = Stop timer; 1 = Start timer.
 +; Bit 1: 1 = Indicate timer underflow on port B bit 7.
 +; Bit 2: 0 = Upon timer underflow, invert port B bit 7; 1 = upon timer underflow, generate a positive edge on port B bit 7 for 1 system cycle.
 +; Bit 3: 0 = Timer restarts upon underflow; 1 = Timer stops upon underflow.
 +; Bit 4: 1 = Load start value into timer.
 +; Bits 5-6: %00 = Timer counts system cycles; %01 = Timer counts positive edges on CNT pin; %10 = Timer counts underflows of timer A; %11 = Timer counts underflows of timer A occurring along with a positive edge on CNT pin.
 +; Bit 7: 0 = Writing into TOD registers sets TOD; 1 = Writing into TOD registers sets alarm time.
 +CIA2TimerBControl = $dd0f
 +</​code>​
  
base/flexible_32_sprite_multiplexer_2.txt ยท Last modified: 2015-04-17 04:31 (external edit)