base:double_screen_horizontal_scroller
no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | base:double_screen_horizontal_scroller [2015-04-17 04:31] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ==== Horizontal Double Screen Bitmap Scroller ==== | ||
+ | == Done with VSP == | ||
+ | {{: | ||
+ | < | ||
+ | // | ||
+ | // Horizontal Double Screen Bitmap Scroller, done with VSP | ||
+ | // For the C64pixels.com Double Screen Pixeling Compo | ||
+ | // Code: Cruzer/CML, April 2011 | ||
+ | // Based on a routine from Codebase64 by Martin Piper | ||
+ | // Can be used/ | ||
+ | // Asm: KickAss 3.15 | ||
+ | // Tab: 16 chars | ||
+ | // | ||
+ | // Picture size: 80x25 chars, in either multicolor or hires bitmap. | ||
+ | // Gfx can be imported either as two c64 pics or a PNG file. | ||
+ | // C64 pics: | ||
+ | // - Set importMode = C64_MODE | ||
+ | // - Save pics as " | ||
+ | // - For multicolor pics use Koala format | ||
+ | // - For hires pics use Topaz Hires Editor format (starts with color screen, followed by bitmap at a $400 offset) | ||
+ | // - Set c64FileType to " | ||
+ | // PNG: | ||
+ | // - Set importMode = PNG_MODE | ||
+ | // - Save pic as " | ||
+ | // - Size: 640x201 (only the lower 200 lines are used for gfx) | ||
+ | // - The upper line is used for defining the c64 palette, with hires or multicolor sized pixels depending on the mode | ||
+ | // - The pixel to the right of the palette defines the background color | ||
+ | // For both formats: | ||
+ | // - Set multiColorMode = true/false | ||
+ | // - Set borderColor manually or leave it as -1 to make it the same as the bg color | ||
+ | // - Adjust sineLength for slower/ | ||
+ | // | ||
+ | // Code info: | ||
+ | // VSP can only push the screen 40 chars, so with extended borders the visible pic could only be 78 chars wide. | ||
+ | // To get full double screen size I added an extra displaced bitmap screen for the two last chars. | ||
+ | // When switching to/from this, the d800 colors need to be moved, since they can't be bank switched. | ||
+ | // This would of course have been easier with linecrunch, but I wasn't in the mood for finding out whether it was | ||
+ | // possible while keeping the gfx 25 chars high. | ||
+ | // | ||
+ | //params... | ||
+ | .enum {PNG_MODE, C64_MODE} | ||
+ | .const importMode = PNG_MODE | ||
+ | .const multiColorMode = true | ||
+ | .const c64FileType = " | ||
+ | .const sineAmp = $150 | ||
+ | .const sineLength = $cc | ||
+ | .var borderColor = -1 | ||
+ | // | ||
+ | // | ||
+ | .const pnt0 = $02 //2 | ||
+ | .const pnt1 = $04 //2 | ||
+ | .const xPos = $06 //1 | ||
+ | .const yPos = $07 //1 | ||
+ | .const xPosChr = $08 //1 | ||
+ | .const source = $09 //2 | ||
+ | .const target = $0b //3 | ||
+ | .const srcPos = $0e //1 | ||
+ | .const destPos = $0f //1 | ||
+ | .const destPosBitmap = $10 //2 | ||
+ | .const dir = $12 //1 | ||
+ | .const d16 = $13 //1 | ||
+ | .const dmaDelay = $14 //1 | ||
+ | // | ||
+ | //memory... | ||
+ | .const basic = $0801 //080f | ||
+ | .const tune = $1000 //1fff | ||
+ | .const main = $2000 //3fff | ||
+ | .const sineLo = $4400 //47ff | ||
+ | .const sineHi = $4800 //4bff | ||
+ | .const bitmapLut = $4c00 //8bff | ||
+ | .const screen = $8c00 //8fff | ||
+ | .const screenLut = $9000 //97ff | ||
+ | .const d800Lut = $9800 //9fff | ||
+ | .const bitmap = $a000 //bfff | ||
+ | .const bitmap2 = $c000 //dfff | ||
+ | .const screen2 = $e000 //e3ff | ||
+ | // | ||
+ | .const unused = $fff6 | ||
+ | .const border = unused | ||
+ | .const irqLine = $2d | ||
+ | .const ProcessorPortDDRDefault = %00101111 | ||
+ | .const ProcessorPortAllRAMWithIO = %00100101 | ||
+ | .const CIA1InterruptControl = $dc0d | ||
+ | .const CIA1TimerAControl = $dc0e | ||
+ | .const CIA1TimerBControl = $dc0f | ||
+ | .const CIA2InterruptControl = $dd0d | ||
+ | .const CIA2TimerAControl = $dd0e | ||
+ | .const CIA2TimerBControl = $dd0f | ||
+ | .const VIC2InteruptControl = $d01a | ||
+ | .const VIC2InteruptStatus = $d019 | ||
+ | .var bgColor | ||
+ | // | ||
+ | //general scripts... | ||
+ | .function _16bit_nextArgument(arg) { | ||
+ | .if (arg.getType()==AT_IMMEDIATE) .return CmdArgument(arg.getType(), | ||
+ | .return CmdArgument(arg.getType(), | ||
+ | } | ||
+ | |||
+ | .pseudocommand mb arg1;arg2 { //move byte | ||
+ | lda arg1 | ||
+ | sta arg2 | ||
+ | } | ||
+ | |||
+ | .pseudocommand mw src;tar { //move word | ||
+ | lda src | ||
+ | sta tar | ||
+ | |||
+ | .if (src.getType() == AT_IZEROPAGEY) { | ||
+ | iny | ||
+ | lda src | ||
+ | } else { | ||
+ | lda _16bit_nextArgument(src) | ||
+ | } | ||
+ | |||
+ | .if (tar.getType() == AT_IZEROPAGEY) { | ||
+ | .if (src.getType() != AT_IZEROPAGEY) iny | ||
+ | sta tar | ||
+ | } else { | ||
+ | sta _16bit_nextArgument(tar) | ||
+ | } | ||
+ | } | ||
+ | // | ||
+ | //scripting for png import... | ||
+ | |||
+ | .function getC64Color(xPos, | ||
+ | .if (multiColorMode) .eval xPos = xPos*2 | ||
+ | .var rgb = pic.getPixel(xPos, | ||
+ | .var c64Color = rgb2c64.get(rgb) | ||
+ | .return c64Color | ||
+ | } | ||
+ | |||
+ | .var charWidth = 8 | ||
+ | .var numBlockColors = 2 | ||
+ | .if (multiColorMode) { | ||
+ | .eval charWidth = 4 | ||
+ | .eval numBlockColors = 3 | ||
+ | } | ||
+ | |||
+ | .function getBlockColors(chrX, | ||
+ | .var colorCounts = List() | ||
+ | .for (var i=0; i<16; i++) .eval colorCounts.add(0) | ||
+ | .for (var pixY=0; pixY<8; pixY++) { | ||
+ | .for (var pixX=0; pixX< | ||
+ | .var c64Color = getC64Color(chrX*charWidth + pixX, chrY*8 + pixY, pic, rgb2c64) | ||
+ | .eval colorCounts.set(c64Color, | ||
+ | }} | ||
+ | .if (multiColorMode) .eval colorCounts.set(bgColor, | ||
+ | .for (var i=0; i<16; i++) .eval colorCounts.set(i, | ||
+ | .eval colorCounts.sort() | ||
+ | .eval colorCounts.reverse() | ||
+ | .var blockColors = List() | ||
+ | .for (var i=0; i<16; i++) .eval blockColors.add(0) | ||
+ | .for (var i=0; i< | ||
+ | .var c64Color = colorCounts.get(i) & $0f | ||
+ | .eval blockColors.set(c64Color, | ||
+ | } | ||
+ | .return blockColors | ||
+ | } | ||
+ | |||
+ | .function getBlock(chrX, | ||
+ | .var blockColors = getBlockColors(chrX, | ||
+ | .var blockData = List() | ||
+ | .for (var pixY=0; pixY<8; pixY++) { | ||
+ | .var bitmapByte = 0 | ||
+ | .for (var pixX=0; pixX< | ||
+ | .var c64Color = getC64Color(chrX*charWidth + pixX, chrY*8 + pixY, pic, rgb2c64) | ||
+ | .var multiColor = blockColors.get(c64Color) | ||
+ | .if (multiColorMode) .eval bitmapByte = bitmapByte | [multiColor << [6 - pixX*2]] | ||
+ | .if (!multiColorMode) .eval bitmapByte = bitmapByte | [[[multiColor-1]^1] << [7 - pixX]] | ||
+ | } | ||
+ | .eval blockData.add(bitmapByte) | ||
+ | } | ||
+ | .for (var multiColor=1; | ||
+ | .var c64Color = 0 | ||
+ | .for (var i=1; i<16; i++) { | ||
+ | .if (blockColors.get(i) == multiColor) .eval c64Color = i | ||
+ | } | ||
+ | .eval blockData.add(c64Color) | ||
+ | } | ||
+ | .return blockData | ||
+ | } | ||
+ | |||
+ | .var bitmapData = List() | ||
+ | .var screenData = List() | ||
+ | .var d800Data = List() | ||
+ | |||
+ | .function parseDoublePic(pic, | ||
+ | .for (var picNo=0; picNo<2; picNo++) { | ||
+ | .for (var chrY=0; chrY<25; chrY++) { | ||
+ | .for (var chrX=0; chrX<40; chrX++) { | ||
+ | .var block = getBlock(chrX+picNo*40, | ||
+ | .for (var i=0; i<8; i++) .eval bitmapData.add(block.get(i)) | ||
+ | .var scrColor = [block.get(8) << 4] | [block.get(9) & $f] | ||
+ | .eval screenData.add(scrColor) | ||
+ | .if (multiColorMode) .eval d800Data.add(block.get(10)) | ||
+ | }}} | ||
+ | } | ||
+ | |||
+ | .function initPalette(pngPic) { | ||
+ | .var rgb2c64 = Hashtable() | ||
+ | .for (var i=0; i<16; i++) { | ||
+ | .var xPos = i | ||
+ | .if (multiColorMode) .eval xPos = i*2 | ||
+ | .var rgb = pngPic.getPixel(xPos, | ||
+ | .eval rgb2c64.put(rgb, | ||
+ | } | ||
+ | .var bgRgb = pngPic.getPixel(32, | ||
+ | .eval bgColor = rgb2c64.get(bgRgb) | ||
+ | .if (borderColor == -1) .eval borderColor = bgColor | ||
+ | .return rgb2c64 | ||
+ | } | ||
+ | |||
+ | .if (importMode == PNG_MODE) { | ||
+ | .var pngPic = LoadPicture(" | ||
+ | .var rgb2c64 = initPalette(pngPic) | ||
+ | .eval parseDoublePic(pngPic, | ||
+ | } | ||
+ | // | ||
+ | //scripting for c64 file import... | ||
+ | |||
+ | .const KOALA_PRG = " | ||
+ | .const KOALA_P00 = " | ||
+ | .const HIRES_PRG = " | ||
+ | .const HIRES_P00 = " | ||
+ | .var c64Pics = List() | ||
+ | .if (importMode == C64_MODE) { | ||
+ | .if (multiColorMode && c64FileType == " | ||
+ | .eval c64Pics.add(LoadBinary(" | ||
+ | .eval c64Pics.add(LoadBinary(" | ||
+ | } | ||
+ | .if (multiColorMode && c64FileType == " | ||
+ | .eval c64Pics.add(LoadBinary(" | ||
+ | .eval c64Pics.add(LoadBinary(" | ||
+ | } | ||
+ | .if (!multiColorMode && c64FileType == " | ||
+ | .eval c64Pics.add(LoadBinary(" | ||
+ | .eval c64Pics.add(LoadBinary(" | ||
+ | } | ||
+ | .if (!multiColorMode && c64FileType == " | ||
+ | .eval c64Pics.add(LoadBinary(" | ||
+ | .eval c64Pics.add(LoadBinary(" | ||
+ | } | ||
+ | .if (multiColorMode) .eval bgColor = c64Pics.get(0).getBackgroundColor() | ||
+ | .if (!multiColorMode) .eval bgColor = 0 | ||
+ | .if (borderColor == -1) .eval borderColor = bgColor | ||
+ | } | ||
+ | // | ||
+ | //generate look-up tables with bitmap data... | ||
+ | |||
+ | .pc = bitmapLut " | ||
+ | .for (var yPos=0; yPos< | ||
+ | .for (var pic=0; pic<2; pic++) { | ||
+ | .for (var xPos=0; xPos<40; xPos++) { | ||
+ | .if (importMode == C64_MODE) { | ||
+ | .by c64Pics.get(pic).getBitmap([yPos>> | ||
+ | } | ||
+ | .if (importMode == PNG_MODE) { | ||
+ | .by bitmapData.get([yPos>> | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | .pc = screenLut " | ||
+ | .for (var yPos=0; yPos<25; yPos++) { | ||
+ | .for (var pic=0; pic<2; pic++) { | ||
+ | .for (var xPos=0; xPos<40; xPos++) { | ||
+ | .if (importMode == C64_MODE) { | ||
+ | .by c64Pics.get(pic).getScreen(yPos*40 + xPos) | ||
+ | } | ||
+ | .if (importMode == PNG_MODE) { | ||
+ | .by screenData.get(yPos*40 + xPos + pic*1000) | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | .if (multiColorMode) { | ||
+ | .pc = d800Lut " | ||
+ | .for (var yPos=0; yPos<25; yPos++) { | ||
+ | .for (var pic=0; pic<2; pic++) { | ||
+ | .for (var xPos=0; xPos<40; xPos++) { | ||
+ | .if (importMode == C64_MODE) { | ||
+ | .by c64Pics.get(pic).getD800(yPos*40 + xPos) | ||
+ | } | ||
+ | .if (importMode == PNG_MODE) { | ||
+ | .by d800Data.get(yPos*40 + xPos + pic*1000) | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | // | ||
+ | .pc = basic " | ||
+ | : | ||
+ | |||
+ | .var sineValues = List() | ||
+ | .for (var i=0; i< | ||
+ | .var val = sineAmp/2 * sin(i/ | ||
+ | .eval val = sineAmp/2 + val * 0.999999999 | ||
+ | .eval sineValues.add(floor(val)) | ||
+ | } | ||
+ | |||
+ | .pc = sineLo " | ||
+ | .var d016mc = $00 | ||
+ | .if (multiColorMode) .eval d016mc = $10 | ||
+ | .fill sineLength, [sineValues.get(i) & 7] | d016mc | ||
+ | |||
+ | .pc = sineHi " | ||
+ | .fill sineLength, sineValues.get(i) >> 3 | ||
+ | // | ||
+ | .pc = main " | ||
+ | sei | ||
+ | cld | ||
+ | ldx #$ff | ||
+ | txs | ||
+ | jsr init | ||
+ | cli | ||
+ | // | ||
+ | { | ||
+ | mainLoop: | ||
+ | !: lda topIRQDone | ||
+ | beq !- | ||
+ | :mb #0; topIRQDone | ||
+ | |||
+ | lda $d011 | ||
+ | bpl *-3 | ||
+ | inc border | ||
+ | |||
+ | jsr setScrollParams | ||
+ | .if (multiColorMode) jsr updateD800 | ||
+ | jsr updateBitmap | ||
+ | jsr incCnt | ||
+ | |||
+ | :mb #0; border | ||
+ | jmp mainLoop | ||
+ | } | ||
+ | // | ||
+ | .align $100 | ||
+ | topIrq: | ||
+ | // | ||
+ | |||
+ | //@ line 45 | ||
+ | pha | ||
+ | txa | ||
+ | pha | ||
+ | tya | ||
+ | pha | ||
+ | |||
+ | inc topIRQDone | ||
+ | |||
+ | :mw #irq2; $fffe | ||
+ | inc $d012 | ||
+ | |||
+ | :mb #1; VIC2InteruptStatus // | ||
+ | |||
+ | 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 | ||
+ | |||
+ | ldx #9 | ||
+ | !: dex | ||
+ | bne !- | ||
+ | |||
+ | //final cycle wobble check | ||
+ | lda #irqLine+1 | ||
+ | cmp $d012 | ||
+ | beq *+2 | ||
+ | |||
+ | //the raster is now stable! \o/ | ||
+ | |||
+ | //@ line 47 | ||
+ | :mb #$31; $d011 | ||
+ | |||
+ | //waste more cycles | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | |||
+ | //still @ line 47 | ||
+ | |||
+ | lda dmaDelay | ||
+ | lsr //divide by 2 to get the number of nops to skip | ||
+ | sta branch+1 | ||
+ | clv //force branch always | ||
+ | |||
+ | //@ line 48 | ||
+ | |||
+ | bcc branch //1 cycle extra delay depending on the least significant bit of the x offset | ||
+ | branch: bvc * //branch somewhere into the 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 raster position | ||
+ | inc border | ||
+ | dec border | ||
+ | |||
+ | //do the VSP by tweaking d011 at the correct time | ||
+ | lda #$3b | ||
+ | dec $d011 | ||
+ | inc $d011 | ||
+ | sta $d011 | ||
+ | |||
+ | ldx extraScreenOn | ||
+ | :mb d018s,x; $d018 | ||
+ | :mb dd00s,x; $dd00 | ||
+ | :mb d16; $d016 | ||
+ | |||
+ | //restart the IRQ chain | ||
+ | :mw #topIrq; $fffe | ||
+ | :mb #irqLine; $d012 | ||
+ | :mb #1; VIC2InteruptStatus // | ||
+ | |||
+ | pla | ||
+ | tay | ||
+ | pla | ||
+ | tax | ||
+ | pla | ||
+ | interruptReturn: | ||
+ | rti | ||
+ | |||
+ | d018s: .by $38,$80 | ||
+ | dd00s: .by $95,$94 | ||
+ | extraScreenOn: | ||
+ | topIRQDone: | ||
+ | // | ||
+ | incCnt: | ||
+ | inc cnt+0 | ||
+ | bne !+ | ||
+ | inc cnt+1 | ||
+ | !: lda cnt+0 | ||
+ | cmp #< | ||
+ | bne !+ | ||
+ | lda cnt+1 | ||
+ | cmp #> | ||
+ | bne !+ | ||
+ | :mw #0; cnt | ||
+ | !: rts | ||
+ | |||
+ | cnt: .wo sineLength/ | ||
+ | // | ||
+ | setScrollParams: | ||
+ | :mb #0; pnt0+0 | ||
+ | lda cnt+1 | ||
+ | clc | ||
+ | adc #>sineLo | ||
+ | sta pnt0+1 | ||
+ | |||
+ | ldy cnt+0 | ||
+ | :mb (pnt0),y; d16 | ||
+ | |||
+ | lda cnt+1 | ||
+ | clc | ||
+ | adc #>sineHi | ||
+ | sta pnt0+1 | ||
+ | |||
+ | ldx #0 | ||
+ | lda (pnt0),y | ||
+ | cmp xPosChr | ||
+ | beq !+ | ||
+ | ldx #1 | ||
+ | cmp xPosChr | ||
+ | bpl !+ | ||
+ | ldx #-1 | ||
+ | !: sta xPosChr | ||
+ | stx dir | ||
+ | |||
+ | ldy #0 | ||
+ | lda #39 | ||
+ | sec | ||
+ | sbc xPosChr | ||
+ | bcs !+ | ||
+ | adc #40 | ||
+ | iny | ||
+ | !: sta dmaDelay | ||
+ | sty extraScreenOn | ||
+ | |||
+ | rts | ||
+ | // | ||
+ | updateD800: | ||
+ | .if (multiColorMode) { | ||
+ | ldy extraScreenOn | ||
+ | cpy extraScreenOn+1 | ||
+ | beq !+ | ||
+ | cpy #1 | ||
+ | beq extra | ||
+ | jsr moveD800Normal | ||
+ | jmp !+ | ||
+ | extra: jsr moveD800Extra | ||
+ | !: | ||
+ | :mb extraScreenOn; | ||
+ | rts | ||
+ | } | ||
+ | // | ||
+ | updateBitmap: | ||
+ | { | ||
+ | lda dir | ||
+ | bne !+ | ||
+ | //no char-pos change | ||
+ | rts | ||
+ | !: | ||
+ | lda extraScreenOn | ||
+ | beq !+ | ||
+ | //no bitmap update needed for extra screen | ||
+ | rts | ||
+ | !: | ||
+ | lda xPosChr | ||
+ | ldx dir | ||
+ | bmi !+ | ||
+ | clc | ||
+ | adc #39 | ||
+ | !: sta srcPos | ||
+ | |||
+ | lda #81 | ||
+ | sec | ||
+ | sbc srcPos | ||
+ | sta srcPos | ||
+ | tax | ||
+ | |||
+ | lda #40 | ||
+ | ldy dir | ||
+ | bpl !+ | ||
+ | lda #79 | ||
+ | !: sec | ||
+ | sbc xPosChr | ||
+ | sta destPos | ||
+ | tay | ||
+ | |||
+ | .for (var i=0; i<24; i++) { | ||
+ | lda screenLut-1 + i*80,x | ||
+ | sta screen + i*40,y | ||
+ | lda d800Lut-1 + i*80,x | ||
+ | sta $d800 + i*40,y | ||
+ | } | ||
+ | |||
+ | //special case for lowest line, which needs to wrap to top of screen when it scrolls far enough | ||
+ | cpy #64 | ||
+ | bpl wrap | ||
+ | normal: | ||
+ | lda screenLut-1 + 24*80,x | ||
+ | sta screen + 24*40,y | ||
+ | lda d800Lut-1 + 24*80,x | ||
+ | sta $d800 + 24*40,y | ||
+ | jmp done | ||
+ | wrap: | ||
+ | lda screenLut-1 + 24*80,x | ||
+ | sta screen-$400 + 24*40,y | ||
+ | lda d800Lut-1 + 24*80,x | ||
+ | sta $d800-$400 + 24*40,y | ||
+ | done: | ||
+ | |||
+ | :mb destPos; destPosBitmap+0 | ||
+ | lda #0 | ||
+ | asl destPosBitmap+0 | ||
+ | rol | ||
+ | asl destPosBitmap+0 | ||
+ | rol | ||
+ | asl destPosBitmap+0 | ||
+ | rol | ||
+ | sta destPosBitmap+1 | ||
+ | |||
+ | ldy destPosBitmap+0 | ||
+ | lda destPosBitmap+1 | ||
+ | bne !+ | ||
+ | jmp storeBitmap0 | ||
+ | !: cmp #1 | ||
+ | bne !+ | ||
+ | jmp storeBitmap1 | ||
+ | !: jmp storeBitmap2 | ||
+ | } | ||
+ | // | ||
+ | .macro storeBitmap(offset) { | ||
+ | .for (var i=0; i<200; i++) { | ||
+ | lda bitmapLut - 1 + i*80,x | ||
+ | .var target = bitmap + offset + [i&7] + [[i>> | ||
+ | .if (offset == $200 && i >= 192) .eval target = target - $2000 //wrapping | ||
+ | sta target,y | ||
+ | } | ||
+ | rts | ||
+ | } | ||
+ | storeBitmap0: | ||
+ | storeBitmap1: | ||
+ | storeBitmap2: | ||
+ | // | ||
+ | //move d800 data when switching between normal/ | ||
+ | .macro moveD800(srcOffset, | ||
+ | .for (var yPos=0; yPos<25; yPos++) { | ||
+ | .if (yPos < 24) { | ||
+ | ldx #9 | ||
+ | !: | ||
+ | .for (var xPos=0; xPos<40; xPos=xPos+10) { | ||
+ | lda d800Lut + xPos + yPos*80 + srcOffset,x | ||
+ | sta $d800 + [[xPos + yPos*40 + tarOffset] & $3ff],x | ||
+ | } | ||
+ | dex | ||
+ | bpl !- | ||
+ | } else { | ||
+ | //avoid loops for lowest line to make it wrappable... | ||
+ | .for (var xPos=0; xPos<40; xPos++) { | ||
+ | lda d800Lut + xPos + yPos*80 + srcOffset | ||
+ | sta $d800 + [[xPos + yPos*40 + tarOffset] & $3ff] | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | rts | ||
+ | } | ||
+ | moveD800Normal: | ||
+ | moveD800Extra: | ||
+ | // | ||
+ | init: | ||
+ | :mb #$0b; $d011 | ||
+ | :mb #$00; $d015 | ||
+ | :mb # | ||
+ | :mb #bgColor; $d021 | ||
+ | |||
+ | jsr clearInterrupts | ||
+ | jsr initGfx | ||
+ | jsr setScrollParams | ||
+ | jsr initInterrupts | ||
+ | |||
+ | rts | ||
+ | // | ||
+ | clearInterrupts: | ||
+ | :mb # | ||
+ | :mb # | ||
+ | // 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 | ||
+ | |||
+ | // Ack any interrupts that might have happened from the CIAs | ||
+ | lda CIA1InterruptControl | ||
+ | lda CIA2InterruptControl | ||
+ | // Ack any interrupts that have happened from the VIC2 | ||
+ | :mb #$ff; VIC2InteruptStatus | ||
+ | |||
+ | // Setup kernal and user mode IRQ vectors to point to a blank routine | ||
+ | :mw # | ||
+ | :mw # | ||
+ | |||
+ | rts | ||
+ | // | ||
+ | initInterrupts: | ||
+ | // Setup raster IRQ | ||
+ | :mw #topIrq; $fffe | ||
+ | :mb #1; VIC2InteruptControl | ||
+ | :mb #irqLine; $d012 | ||
+ | :mb #$3b; $d011 | ||
+ | |||
+ | // Ack any interrupts that might have happened from the CIAs | ||
+ | lda CIA1InterruptControl | ||
+ | lda CIA2InterruptControl | ||
+ | // Ack any interrupts that have happened from the VIC2 | ||
+ | :mb #$ff; VIC2InteruptStatus | ||
+ | |||
+ | rts | ||
+ | // | ||
+ | initGfx: | ||
+ | //init bitmap screens, color screens and d800 | ||
+ | |||
+ | :mw # | ||
+ | :mw #$08; target | ||
+ | :mb #> | ||
+ | jsr initBitmap | ||
+ | |||
+ | :mw # | ||
+ | :mw #$01; target | ||
+ | :mb #> | ||
+ | jsr initScreen | ||
+ | |||
+ | .if (multiColorMode) jsr moveD800Extra | ||
+ | |||
+ | :mb #$34; $01 | ||
+ | |||
+ | :mw #bitmapLut; source | ||
+ | :mw #$138; target | ||
+ | :mb #> | ||
+ | jsr initBitmap | ||
+ | |||
+ | :mw #screenLut; source | ||
+ | :mw #$27; target | ||
+ | :mb #> | ||
+ | jsr initScreen | ||
+ | |||
+ | :mb #$35; $01 | ||
+ | |||
+ | rts | ||
+ | // | ||
+ | initBitmap: | ||
+ | { | ||
+ | :mb #0; yPos | ||
+ | yLoop: | ||
+ | :mw source; pnt0 | ||
+ | |||
+ | :mb target+0; pnt1+0 | ||
+ | lda target+1 | ||
+ | ora target+2 | ||
+ | sta pnt1+1 | ||
+ | |||
+ | :mb #0; xPos | ||
+ | xLoop: | ||
+ | ldy #0 | ||
+ | :mb (pnt0),y; (pnt1),y | ||
+ | |||
+ | inc pnt0+0 | ||
+ | bne !+ | ||
+ | inc pnt0+1 | ||
+ | !: | ||
+ | lda #8 | ||
+ | clc | ||
+ | adc pnt1+0 | ||
+ | sta pnt1+0 | ||
+ | lda pnt1+1 | ||
+ | adc #$00 | ||
+ | and #$1f | ||
+ | ora target+2 | ||
+ | sta pnt1+1 | ||
+ | |||
+ | inc xPos | ||
+ | lda xPos | ||
+ | cmp #40 | ||
+ | bne xLoop | ||
+ | |||
+ | lda #80 | ||
+ | clc | ||
+ | adc source+0 | ||
+ | sta source+0 | ||
+ | bcc !+ | ||
+ | inc source+1 | ||
+ | !: | ||
+ | lda #1 | ||
+ | clc | ||
+ | adc target+0 | ||
+ | sta target+0 | ||
+ | bcc !+ | ||
+ | inc target+1 | ||
+ | !: | ||
+ | lda yPos | ||
+ | and #$07 | ||
+ | cmp #$07 | ||
+ | bne !+ | ||
+ | |||
+ | lda #<$138 | ||
+ | clc | ||
+ | adc target+0 | ||
+ | sta target+0 | ||
+ | lda #>$138 | ||
+ | adc target+1 | ||
+ | and #$1f | ||
+ | sta target+1 | ||
+ | !: | ||
+ | inc yPos | ||
+ | lda yPos | ||
+ | cmp #200 | ||
+ | beq !+ | ||
+ | jmp yLoop | ||
+ | !: | ||
+ | rts | ||
+ | } | ||
+ | // | ||
+ | initScreen: | ||
+ | { | ||
+ | :mb #0; yPos | ||
+ | yLoop: | ||
+ | :mw source; pnt0 | ||
+ | |||
+ | :mb target+0; pnt1+0 | ||
+ | lda target+1 | ||
+ | ora target+2 | ||
+ | sta pnt1+1 | ||
+ | |||
+ | :mb #0; xPos | ||
+ | xLoop: | ||
+ | ldy #0 | ||
+ | :mb (pnt0),y; (pnt1),y | ||
+ | |||
+ | inc pnt0+0 | ||
+ | bne !+ | ||
+ | inc pnt0+1 | ||
+ | !: | ||
+ | lda #1 | ||
+ | clc | ||
+ | adc pnt1+0 | ||
+ | sta pnt1+0 | ||
+ | lda pnt1+1 | ||
+ | adc #$00 | ||
+ | and #$03 | ||
+ | ora target+2 | ||
+ | sta pnt1+1 | ||
+ | |||
+ | inc xPos | ||
+ | lda xPos | ||
+ | cmp #40 | ||
+ | bne xLoop | ||
+ | |||
+ | lda #80 | ||
+ | clc | ||
+ | adc source+0 | ||
+ | sta source+0 | ||
+ | bcc !+ | ||
+ | inc source+1 | ||
+ | !: | ||
+ | lda #40 | ||
+ | clc | ||
+ | adc target+0 | ||
+ | sta target+0 | ||
+ | bcc !+ | ||
+ | inc target+1 | ||
+ | !: | ||
+ | inc yPos | ||
+ | lda yPos | ||
+ | cmp #25 | ||
+ | beq !+ | ||
+ | jmp yLoop | ||
+ | !: | ||
+ | rts | ||
+ | } | ||
+ | // | ||
+ | </ |
base/double_screen_horizontal_scroller.txt · Last modified: 2015-04-17 04:31 by 127.0.0.1