// EXAMPLE KICK ASSEMBLER FILE // // 6502 Decoder for 8BitDiff // // Copyright 2015 Carl-Henrik Skårstedt. All rights reserved. // https://github.com/sakrac/8BitDiff/ // // 8BDIFF FORMAT // ------------- // 4 bits: size of offset bit sizes // 4 bits: size of length bit sizes // 1 byte length bit sizes // 1 byte offset bit sizes // 2 bytes size of injected bytes (8 bit specific) // injected bytes // loop until end of inject buffer: // bit: 0=inject, 1=source or target // length bit cnt+length bits // if source or target: // buffer offset bit cnt + buffer offset bits // sign of offset (not instead of negate) // bit: 0=source, 1=target // repeat loop // // target/source/inject source pointers start // at the start of each buffer. // any pointer is set to the end of the run after // copy and the offset increments/decrements for source // for a negative offset, invert the number, don't negate. // // USAGE // ----- // Use the 8BDIFF tool (https://github.com/sakrac/8BitDiff) // to generate a patch between two files. Load the // original file and the patch file and assign them as parameters: // z8BDiff = Address of patch // z8BSrc = Address of original data // z8BDst = Address to decode updated data // jsr Patch_8BDiff // .label zParam8B = $f0 // 6 bytes .label zWork8B = $f6 // 10 bytes // input (will be changed) .label z8BDiff = zParam8B // start of diff .label z8BSrc = z8BDiff+2 // start of source .label z8BDst = z8BSrc+2 // start of destination // work (will be changed) .label z8BOff = zWork8B // 2 bytes current instruction offset .label z8BTemp = z8BOff // 1 byte temporary address .label z8BLen = z8BOff+2 // 2 bytes current instruction length .label z8BOffsSize = z8BLen+2 // 1 byte hot many bits to read for offset .label z8BLenSize = z8BOffsSize+1 // 1 byte how many bits to read for length .label z8BInj = z8BLenSize+1 // 2 bytes current injection address .label z8BTrg = z8BInj+2 // start of target 2 bytes .label z8BInjSize = z8BTrg // 2 bytes size of injection buffer .label z8BInjEnd = z8BDiff // 2 bytes keeps track of end condition // macro for reading one bit .macro GetBit() { asl bne !BitOk+ jsr GetByte !BitOk: } Patch_8BDiff: ldy #0 // clear Y lda (z8BDiff),y // first byte is prefix length bits | offset bits<<4 tax lsr lsr lsr lsr sta z8BOffsSize txa and #$0f sta z8BLenSize inc z8BDiff bne NotLastByte inc z8BDiff+1 NotLastByte: lda z8BDiff // store off address to length bit sizes sta GetLenBits+1 lda z8BDiff+1 sta GetLenBits+2 ldx z8BLenSize // prefix bits for length jsr BitX // A = 1< force fetch NextInstruction: :GetBit() // bit is 0 => inject, otherwise source or target buffer bcs SrcTrg ldx z8BInj // check if complete cpx z8BInjEnd bcc NotEnd ldx z8BInj+1 cpx z8BInjEnd+1 bcc NotEnd rts // patching is complete, return to caller NotEnd: jsr GetLen // number of bytes to inject y = 0 here pha // save bit shift byte ldx #z8BInj // use inject buffer bne MoveToDest // always branch! // PC will not cross this line SrcTrg: jsr GetLen // number of bytes to copy jsr GetOffs // offset in buffer, y = 0 here :GetBit() // check sign bit bcc PositiveOffs pha lda #$ff // apply negativity to offset eor z8BOff sta z8BOff lda #$ff eor z8BOff+1 sta z8BOff+1 pla PositiveOffs: :GetBit() ldx #z8BSrc // use source buffer bcc Src ldx #z8BTrg // use target buffer Src: pha // save bit shift byte clc lda z8BOff // apply offset to current buffer adc $00,x sta $00,x lda z8BOff+1 adc $01,x sta $01,x MoveToDest: stx BufferCopyTrg+1 // x = zero page source buffer to copy from PageCopy: // copy pages (256 bytes) at a time dec z8BLen+1 bmi PageCopyDone jsr BufferCopy // y is 0 here so copy 256 bytes inc $01,x inc z8BDst+1 bne PageCopy // PC will not cross this line PageCopyDone: ldy z8BLen // get remaining number of bytes in y beq NoLowLength jsr BufferCopy lda z8BLen // apply remainder of bytes to buffer jsr ApplyOffsetA lda z8BLen ldx #z8BDst // apply remainder of bytes to destination jsr ApplyOffsetA NoLowLength: pla // retrieve bit shift byte to parse next bit bne NextInstruction // PC will not cross this line // BufferCopy copies bytes forward from 0 to y (256 if y is 0) BufferCopy: sty BufferCopyLength+1 ldy #0 BufferCopyTrg: lda (z8BInj),y sta (z8BDst),y iny BufferCopyLength: cpy #0 bne BufferCopyTrg // Y returns unchanged rts // Gets Y number of bits and return the value in Y GetLenOffBits: :GetBit() rol z8BTemp dey bne GetLenOffBits ldy z8BTemp rts // Gets the next length GetLen: ldy #0 sty z8BTemp ldy z8BLenSize jsr GetLenOffBits pha // save bit shift byte GetLenBits: lda $1234,y ldx #z8BLen // X is the zero page address to store in GetLenOffValue: tay lda #0 // clear target indirect address sta $00,x sta $01,x pla // retrieve bit shift byte GetLenOffLoop: :GetBit() rol $00,x rol $01,x dey bne GetLenOffLoop // y returns 0 rts // Gets the next buffer offset GetOffs: ldy #0 sty z8BTemp ldy z8BOffsSize jsr GetLenOffBits pha // save bit shift byte GetOffsBits: lda $1234,y ldx #z8BOff // X is the zero page address to store in bne GetLenOffValue // Gets one byte of bits and returns top bit in C GetByte: sec DiffPtr: lda $1234 rol inc DiffPtr+1 bne DiffPage inc DiffPtr+2 DiffPage: rts // Returns 1<