User Tools

Site Tools


base:flexible_32_sprite_multiplexer_2

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"

; 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

Create as "stdlib.asm"

; 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
base/flexible_32_sprite_multiplexer_2.txt · Last modified: 2015-04-17 04:31 (external edit)