base:agsp_any_given_screen_position
no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
Next revision | |||
— | base:agsp_any_given_screen_position [2015-04-17 04:30] – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Any Given Screen Positioning (AGSP) HSP/VSP with a line crunch ====== | ||
+ | |||
+ | A HSP (VSP/ | ||
+ | |||
+ | This code is for PAL machines. To make it work for NTSC you have to do some minor timing modifications for each scan-line. | ||
+ | |||
+ | The code is in ACME assembler format. | ||
+ | |||
+ | < | ||
+ | ; This demonstrates AGSP (any given screen position). This uses HSP (Horizontal Screen Positioning) (DMA delay) | ||
+ | ; with a stable raster plus a line crunch to scroll the screen vertically to any position. | ||
+ | |||
+ | ; Use a joystick in port two to move the screen around. | ||
+ | |||
+ | ; The top five and a bit lines are " | ||
+ | ; few lines blanked out and the screen below is moving at a fast rate then you can probably guess | ||
+ | ; it is using a similar method. | ||
+ | |||
+ | !to " | ||
+ | !cpu 6510 | ||
+ | !ct pet | ||
+ | |||
+ | ZPProcessorPortDDR = $00 | ||
+ | ProcessorPortDDRDefault = %101111 | ||
+ | ZPProcessorPort = $01 | ||
+ | ProcessorPortAllRAMWithIO = %100101 | ||
+ | CIA1InterruptControl = $dc0d | ||
+ | CIA1TimerAControl = $dc0e | ||
+ | CIA1TimerBControl = $dc0f | ||
+ | CIA2InterruptControl = $dd0d | ||
+ | CIA2TimerAControl = $dd0e | ||
+ | CIA2TimerBControl = $dd0f | ||
+ | VIC2InteruptControl = $d01a | ||
+ | VIC2InteruptStatus = $d019 | ||
+ | VIC2BorderColour = $d020 | ||
+ | VIC2ScreenColour = $d021 | ||
+ | VIC2ScreenControlV = $d011 | ||
+ | VIC2SpriteEnable = $d015 | ||
+ | VIC2Raster = $d012 | ||
+ | CIA1KeyboardColumnJoystickA = $dc00 | ||
+ | KERNALNMIServiceRoutineLo = $fffa | ||
+ | KERNALNMIServiceRoutineHi = $fffb | ||
+ | KERNALIRQServiceRoutineLo = $fffe | ||
+ | KERNALIRQServiceRoutineHi = $ffff | ||
+ | VIC2Colour_Black = 0 | ||
+ | VIC2Colour_Red = 2 | ||
+ | VIC2Colour_Green = 5 | ||
+ | |||
+ | !macro MACROAckRasterIRQ_A { | ||
+ | lda #1 | ||
+ | sta VIC2InteruptStatus ; | ||
+ | } | ||
+ | |||
+ | !macro MACROAckAllIRQs_A { | ||
+ | ; Ack any interrupts that might have happened from the CIAs | ||
+ | lda CIA1InterruptControl | ||
+ | lda CIA2InterruptControl | ||
+ | ; Ack any interrupts that have happened from the VIC2 | ||
+ | lda #$ff | ||
+ | sta VIC2InteruptStatus | ||
+ | } | ||
+ | |||
+ | |||
+ | *= $0801 | ||
+ | !byte $0b, | ||
+ | !convtab pet | ||
+ | !tx " | ||
+ | !byte $00,$00,$00 | ||
+ | |||
+ | !zn | ||
+ | .theLine = 45 | ||
+ | ; Stop interrupts, clear decimal mode and backup the previous stack entries | ||
+ | lda # | ||
+ | sei | ||
+ | cld | ||
+ | ; Grab everything on the stack | ||
+ | ldx #$ff | ||
+ | txs | ||
+ | ; Init the processor port | ||
+ | ldx # | ||
+ | stx ZPProcessorPortDDR | ||
+ | ; Set the user requested ROM state | ||
+ | sta ZPProcessorPort | ||
+ | ; Clear all CIA to known state, interrupts off. | ||
+ | lda #$7f | ||
+ | sta CIA1InterruptControl | ||
+ | sta CIA2InterruptControl | ||
+ | lda #0 | ||
+ | sta VIC2InteruptControl | ||
+ | sta CIA1TimerAControl | ||
+ | sta CIA1TimerBControl | ||
+ | sta CIA2TimerAControl | ||
+ | sta CIA2TimerBControl | ||
+ | +MACROAckAllIRQs_A | ||
+ | |||
+ | ; Setup kernal and user mode IRQ vectors to point to a blank routine | ||
+ | lda #< | ||
+ | sta KERNALIRQServiceRoutineLo | ||
+ | lda #> | ||
+ | sta KERNALIRQServiceRoutineHi | ||
+ | |||
+ | lda #< | ||
+ | sta KERNALNMIServiceRoutineLo | ||
+ | lda #> | ||
+ | sta KERNALNMIServiceRoutineHi | ||
+ | |||
+ | ; Turn off various bits in the VIC2 and SID chips | ||
+ | ; Screen, sprites and volume are disabled. | ||
+ | lda #0 | ||
+ | sta VIC2ScreenColour | ||
+ | sta VIC2BorderColour | ||
+ | sta VIC2ScreenControlV | ||
+ | sta VIC2SpriteEnable | ||
+ | |||
+ | ; Setup raster IRQ | ||
+ | lda #< | ||
+ | sta KERNALIRQServiceRoutineLo | ||
+ | lda #> | ||
+ | sta KERNALIRQServiceRoutineHi | ||
+ | lda #1 | ||
+ | sta VIC2InteruptControl | ||
+ | lda #.theLine | ||
+ | sta VIC2Raster | ||
+ | lda #$1b | ||
+ | sta VIC2ScreenControlV | ||
+ | |||
+ | lda # | ||
+ | sta VIC2BorderColour | ||
+ | |||
+ | +MACROAckAllIRQs_A | ||
+ | |||
+ | ldx #39 | ||
+ | .fs1 | ||
+ | lda #$30 | ||
+ | sta $400 + 00*40 ,x | ||
+ | sta $400 + 10*40 ,x | ||
+ | sta $400 + 20*40 ,x | ||
+ | lda #$31 | ||
+ | sta $400 + 01*40 ,x | ||
+ | sta $400 + 11*40 ,x | ||
+ | sta $400 + 21*40 ,x | ||
+ | lda #$32 | ||
+ | sta $400 + 02*40 ,x | ||
+ | sta $400 + 12*40 ,x | ||
+ | sta $400 + 22*40 ,x | ||
+ | lda #$33 | ||
+ | sta $400 + 03*40 ,x | ||
+ | sta $400 + 13*40 ,x | ||
+ | sta $400 + 23*40 ,x | ||
+ | lda #$34 | ||
+ | sta $400 + 04*40 ,x | ||
+ | sta $400 + 14*40 ,x | ||
+ | sta $400 + 24*40 ,x | ||
+ | lda #$35 | ||
+ | sta $400 + 05*40 ,x | ||
+ | sta $400 + 15*40 ,x | ||
+ | lda #$36 | ||
+ | sta $400 + 06*40 ,x | ||
+ | sta $400 + 16*40 ,x | ||
+ | lda #$37 | ||
+ | sta $400 + 07*40 ,x | ||
+ | sta $400 + 17*40 ,x | ||
+ | lda #$38 | ||
+ | sta $400 + 08*40 ,x | ||
+ | sta $400 + 18*40 ,x | ||
+ | lda #$39 | ||
+ | sta $400 + 09*40 ,x | ||
+ | sta $400 + 19*40 ,x | ||
+ | |||
+ | dex | ||
+ | bpl .fs1 | ||
+ | |||
+ | cli | ||
+ | .mainLine | ||
+ | ; Wait for the top IRQ to be triggered | ||
+ | lda .topIRQDone | ||
+ | beq .mainLine | ||
+ | |||
+ | lda #0 | ||
+ | sta .topIRQDone | ||
+ | |||
+ | lda #%00001 | ||
+ | bit CIA1KeyboardColumnJoystickA | ||
+ | bne .notUp | ||
+ | ldx .yPosOffset | ||
+ | inx | ||
+ | cpx #26 | ||
+ | bne .s1 | ||
+ | ldx #25 | ||
+ | .s1 | ||
+ | stx .yPosOffset | ||
+ | .notUp | ||
+ | lda #%00010 | ||
+ | bit CIA1KeyboardColumnJoystickA | ||
+ | bne .notDown | ||
+ | ldx .yPosOffset | ||
+ | dex | ||
+ | bpl .s2 | ||
+ | ldx #0 | ||
+ | .s2 | ||
+ | stx .yPosOffset | ||
+ | .notDown | ||
+ | ; If fire is not pressed then don't update the counter | ||
+ | lda #%01000 | ||
+ | bit CIA1KeyboardColumnJoystickA | ||
+ | bne .notLeft | ||
+ | ldx .xPosOffset | ||
+ | inx | ||
+ | cpx #40 | ||
+ | bne .o1 | ||
+ | ldx #39 | ||
+ | .o1 | ||
+ | stx .xPosOffset | ||
+ | |||
+ | .notLeft | ||
+ | lda #%00100 | ||
+ | bit CIA1KeyboardColumnJoystickA | ||
+ | bne .notRight | ||
+ | ldx .xPosOffset | ||
+ | dex | ||
+ | bpl .o2 | ||
+ | ldx #0 | ||
+ | .o2 | ||
+ | stx .xPosOffset | ||
+ | |||
+ | .notRight | ||
+ | jmp .mainLine | ||
+ | |||
+ | .topIRQDone !by 0 | ||
+ | .xPosOffset !by 0 | ||
+ | .yPosOffset !by 0 | ||
+ | |||
+ | ; Remove all possibility that the timings will change due to previous code | ||
+ | !align 255,0 | ||
+ | IrqTopOfScreen | ||
+ | ; Line 45 | ||
+ | pha | ||
+ | txa | ||
+ | pha | ||
+ | tya | ||
+ | pha | ||
+ | |||
+ | inc .topIRQDone | ||
+ | |||
+ | lda #<.irq2 | ||
+ | ldx #>.irq2 | ||
+ | |||
+ | sta KERNALIRQServiceRoutineLo | ||
+ | stx KERNALIRQServiceRoutineHi | ||
+ | inc VIC2Raster | ||
+ | +MACROAckRasterIRQ_A | ||
+ | |||
+ | ; Begin the raster stabilisation code | ||
+ | tsx | ||
+ | cli | ||
+ | ; These nops never really finish due to the raster IRQ triggering again | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | .irq2 | ||
+ | ; Line 46 | ||
+ | txs | ||
+ | |||
+ | ; Delay for a while | ||
+ | ldx #8 | ||
+ | .l1 | ||
+ | dex | ||
+ | bne .l1 | ||
+ | bit $ea | ||
+ | |||
+ | ; Final cycle wobble check. | ||
+ | lda VIC2Raster | ||
+ | cmp VIC2Raster | ||
+ | beq .start | ||
+ | .start | ||
+ | |||
+ | ; The raster is now stable | ||
+ | |||
+ | ; Line 47 | ||
+ | lda #$11 | ||
+ | sta VIC2ScreenControlV | ||
+ | |||
+ | ; Waste some time | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | bit $ea | ||
+ | |||
+ | ; Still in line 47 | ||
+ | ; Calculate a variable offset to delay by branching over nops | ||
+ | lda #39 | ||
+ | sec | ||
+ | sbc .xPosOffset | ||
+ | ; divide by 2 to get the number of nops to skip | ||
+ | lsr | ||
+ | sta .sm1+1 | ||
+ | ; Force branch always | ||
+ | clv | ||
+ | |||
+ | ; Line 48 | ||
+ | |||
+ | ; Introduce a 1 cycle extra delay depending on the least significant bit of the x offset | ||
+ | bcc .sm1 | ||
+ | .sm1 | ||
+ | bvc * | ||
+ | ; The above branches somewhere into these nops depending on the x offset position | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | |||
+ | ; Show the raster position is stable and varies as a function of x offset | ||
+ | ; If these border colour changes are removed then they need to be replaced with the same | ||
+ | ; cycle count of nops | ||
+ | inc VIC2BorderColour | ||
+ | dec VIC2BorderColour | ||
+ | |||
+ | ; Do the HSP by tweaking the VIC2ScreenControlV register at the correct time | ||
+ | lda # | ||
+ | ; lda # | ||
+ | dec VIC2ScreenControlV | ||
+ | inc VIC2ScreenControlV | ||
+ | sta VIC2ScreenControlV | ||
+ | |||
+ | ; Change the below to "!if 0" to turn off the line crunch | ||
+ | !if 1 { | ||
+ | ; Display a red border at the start of this routine | ||
+ | lda # | ||
+ | sta VIC2BorderColour | ||
+ | |||
+ | ; The number of lines to crunch | ||
+ | ldy .yPosOffset | ||
+ | beq .s3 | ||
+ | |||
+ | ; The raster line to start crunching on | ||
+ | ldx #67 | ||
+ | .crunchLoop | ||
+ | ; Load the next screen value | ||
+ | lda .table-67,x | ||
+ | ; Wait for the line... | ||
+ | cpx VIC2Raster | ||
+ | bne *-3 | ||
+ | ; Produces a one line crunch | ||
+ | ; The timing of this store is quite critical, hence why the load is done before the raster line test | ||
+ | sta VIC2ScreenControlV | ||
+ | inx | ||
+ | dey | ||
+ | bne .crunchLoop | ||
+ | |||
+ | ; Display green until the screen is enabled | ||
+ | lda # | ||
+ | sta VIC2BorderColour | ||
+ | |||
+ | .s3 | ||
+ | |||
+ | ; Turn off ECM/Bitmap to enable the screen | ||
+ | lda VIC2ScreenControlV | ||
+ | and #%00011111 | ||
+ | ; Wait for this raster line | ||
+ | ldx #67+26 | ||
+ | cpx VIC2Raster | ||
+ | bne *-3 | ||
+ | ; Enable the screen | ||
+ | sta VIC2ScreenControlV | ||
+ | |||
+ | lda # | ||
+ | sta VIC2BorderColour | ||
+ | } else { | ||
+ | lda #%00011011 | ||
+ | sta VIC2ScreenControlV | ||
+ | } | ||
+ | |||
+ | ; Restart the IRQ chain | ||
+ | lda #< | ||
+ | ldx #> | ||
+ | ldy #.theLine | ||
+ | sta KERNALIRQServiceRoutineLo | ||
+ | stx KERNALIRQServiceRoutineHi | ||
+ | sty VIC2Raster | ||
+ | +MACROAckRasterIRQ_A | ||
+ | |||
+ | ; Exit the IRQ | ||
+ | pla | ||
+ | tay | ||
+ | pla | ||
+ | tax | ||
+ | pla | ||
+ | .initIRQ | ||
+ | .initNMI | ||
+ | rti | ||
+ | |||
+ | ; With ECM + bitmap enabled to turn off the top of the screen | ||
+ | .table | ||
+ | !by %01111100 | ||
+ | !by %01111101 | ||
+ | !by %01111110 | ||
+ | !by %01111111 | ||
+ | !by %01111000 | ||
+ | !by %01111001 | ||
+ | !by %01111010 | ||
+ | !by %01111011 | ||
+ | |||
+ | !by %01111100 | ||
+ | !by %01111101 | ||
+ | !by %01111110 | ||
+ | !by %01111111 | ||
+ | !by %01111000 | ||
+ | !by %01111001 | ||
+ | !by %01111010 | ||
+ | !by %01111011 | ||
+ | |||
+ | !by %01111100 | ||
+ | !by %01111101 | ||
+ | !by %01111110 | ||
+ | !by %01111111 | ||
+ | !by %01111000 | ||
+ | !by %01111001 | ||
+ | !by %01111010 | ||
+ | !by %01111011 | ||
+ | |||
+ | !by %01111100 | ||
+ | !by %01111101 | ||
+ | !by %01111110 | ||
+ | !by %01111111 | ||
+ | !by %01111000 | ||
+ | !by %01111001 | ||
+ | !by %01111010 | ||
+ | !by %01111011 | ||
+ | </ | ||
base/agsp_any_given_screen_position.txt · Last modified: 2023-07-19 00:34 by groepaz