Last active
November 24, 2019 23:57
-
-
Save ErnestoBorio/917de83ac3d121c41cb799a19720062c to your computer and use it in GitHub Desktop.
C64 Raster IRQ test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// For KickAssembler | |
#import "ptz.asm" | |
BasicUpstart2(Start) | |
.memblock "Start" | |
Start: | |
DisableInterrupts() | |
lda #%01111111 // Bitmask to clear interrupts | |
sta IRQInterrupts // Disable IRQ system interrupts | |
sta NMIInterrupts // Disable NMI system interrupts | |
ScreenControl1(_screen_on | _25_rows | _text_mode | 3) // value is vertical scroll | |
ScreenControl2(_hires_mode | _40_columns) | |
Copy #%10100 : VICMemory // Screen memory at $400, character memory at $2000 | |
Copy #BLACK : BackgroundColor | |
Copy #LIGHT_GREEN : BorderColor | |
EnableRasterInterrupts(_raster_line) | |
CopyWord(IRQRoutine, IRQVector) // Hookup the IRQ routine | |
Copy #100 : RasterLine // schedule raster interrupts at given scanline | |
// Acknowledge any pending interrupts | |
lda IRQInterrupts | |
lda NMIInterrupts | |
AcknowledgeIRQ() | |
EnableInterrupts() | |
InfiniteLoop() | |
rts | |
.memblock "IRQRoutine" | |
IRQRoutine: | |
Copy #YELLOW : BackgroundColor // lda #YELLOW; sta $D021 | |
Copy #BLACK : BackgroundColor // lda #BLACK; sta $D021 | |
AcknowledgeIRQ() // dec $D019 | |
ReturnFromIRQ() // jmp $EA81 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************ | |
* General dev | |
************************************************/ | |
// Sleeps for the specified CPU cycles inserting NOPs | |
.macro Sleep(cycles) { | |
.if (cycles <= 1) .error "Can't sleep for less than 2 cycles." | |
.var loops = floor(cycles/2) // How many 2 cycle NOPs are needed | |
.if (mod(cycles, 2) == 1) { // If cycles is odd | |
.eval loops-- // Replace one 2 cycle NOP | |
.byte NOP_ZP, $EB // With a 3 cycle NOP to sleep odd cycles (bytes $04 $EB) | |
} | |
.for (var i = 0; i < loops; i++) { | |
nop | |
} | |
} | |
.pseudocommand Copy source : target { | |
lda source | |
sta target | |
} | |
// Copies 2 bytes in consecutive addresses big, endian. | |
.macro CopyWord(data, address) { | |
lda #<data | |
sta address | |
lda #>data | |
sta address+1 | |
} | |
.macro InfiniteLoop() { | |
jmp * | |
} | |
.macro DisableInterrupts() { | |
sei | |
} | |
.macro EnableInterrupts() { | |
cli | |
} | |
// Acknowledges Raster IRQ (And possible collisions too) | |
.macro AcknowledgeIRQ() { | |
dec IRQStatus | |
} | |
// Restores registers from the stack and rti | |
.macro ReturnFromIRQ() { | |
// jmp $EA81 // This Kernal routine does the same | |
pla | |
tay | |
pla | |
tax | |
pla | |
rti | |
} | |
// Shifts A the specified many bits | |
.macro ShiftRightA(bits) { | |
.for (var i = 0; i < bits; i++) { | |
lsr | |
} | |
} | |
.macro ShiftLeftA(bits) { | |
.for (var i = 0; i < bits; i++) { | |
asl | |
} | |
} | |
/************************************************ | |
* Game dev | |
************************************************/ | |
.const IRQVector = $314 // 2 byte vector to IRQ routine | |
.const SpritePointers = $7F8 // 8 byte pointers to the sprite patterns, in multiples of $40 | |
// VIC-II | |
.const SpriteEnable = $D015 // bitmap to enable or disable sprites | |
.const BorderColor = $D020 | |
.const BackgroundColor = $D021 | |
.const SpriteX = $D000 // address of Sprite 0's X coordinate, 8 less significant bits | |
.const SpriteY = $D001 // address of Sprite 0's Y coordinate | |
.const SpriteXHighBits = $D010 // Bit 8 (most significant) of X coordinates of all 8 sprites | |
.const ScreenControl1 = $D011 // Vertical scroll, screen height, screen on, text/bitmap mode, current raster line | |
.const RasterLine = $D012 // 8 less significant bits of current raster line | |
.const ScreenControl2 = $D016 // Horizontal scroll, 38/40 columns, hires/multicolor mode | |
.const VICMemory = $D018 // Set address of character or bitmap screen data | |
.const IRQStatus = $D019 // IRQ status and acknowledgement | |
.const RasterInterrupts = $D01A // Raster, sprite collisions and lightpen interrupts | |
.const IRQInterrupts = $DC0D // IRQ system interrupts | |
.const NMIInterrupts = $DD0D // NMI system interrupts | |
.const VICBank = $DD00 // VIC Bank selector $0, $4000, $8000, $C000. Also serial bus I/O | |
// Kernal | |
.const ClearScreen = $E544 | |
.const DefaultIRQRoutine = $EA31 // jmp here to go back to flashing cursor and BASIC CLI | |
.const ReturnFromIRQ = $EA81 // Restores the stack and registers and does RTI | |
// Use these constants summed or OR'd to enable them with EnableRasterInterrupts() | |
.const _raster_line = 1 | |
.const _sprite_bg_collision = 2 | |
.const _sprite_sprite_collision = 4 | |
.const _lightpen = 8 | |
.macro EnableRasterInterrupts(mask) { | |
lda mask | |
sta RasterInterrupts | |
} | |
// Set sprite's X coordinate, 8 less significant bits | |
.pseudocommand SpriteX index : x { | |
lda x | |
ldx index | |
sta SpriteX, x | |
} | |
// Set sprite's Y coordinate | |
.pseudocommand SpriteY index : y { | |
lda y | |
ldx index | |
sta SpriteY, x | |
} | |
// Set memory address where the sprite's bitmap is | |
.macro SpriteAddress(index, address) { | |
.if (index > 7) { | |
.error "Sprite index "+ index +" out of bounds. (0..7)" | |
} | |
.if (mod(address, $40) != 0) { | |
.error "Sprite address $"+ toHexString(address) +" should be multiple of $40 (64)." | |
} | |
.var place = address / $40 | |
lda #place | |
sta SpritePointers + index | |
// .print "SpriteAddress() place: $"+ toHexString(place) | |
} | |
// Used by sprite enable and disable macros | |
.function CalculateSpriteMask(indices) { | |
.var mask = 0 | |
.for (var i=0; i < indices.size(); i++) { | |
.var index = indices.get(i) | |
.var spriteBit = 1 << index | |
.eval mask = mask | spriteBit | |
} | |
// .print "Sprite bitmask: "+ toBinaryString(mask, 8) | |
.return mask | |
} | |
// Enable sprites given in list | |
.macro SpriteEnable(indices) { | |
lda SpriteEnable | |
ora #CalculateSpriteMask(indices) | |
sta SpriteEnable | |
} | |
// Disable sprites given in list | |
.macro SpriteDisable(indices) { | |
lda #CalculateSpriteMask(indices) | |
eor #$FF | |
and SpriteEnable | |
sta SpriteEnable | |
} | |
.const _24_rows = 0 | |
.const _25_rows = %1000 | |
.const _screen_off = 0 | |
.const _screen_on = %10000 | |
.const _text_mode = 0 | |
.const _bitmap_mode = %100000 | |
.const _extended_background = %1000000 | |
// Set the Screen Control 1 register with the values above | |
.macro ScreenControl1(mask) { | |
lda #mask | |
sta ScreenControl1 // $D011 | |
} | |
.const _38_columns = 0 | |
.const _40_columns = %1000 | |
.const _multicolor_mode = %10000 | |
.const _hires_mode = 0 | |
// Set the Screen Control 2 register with the values above | |
.macro ScreenControl2(mask) { | |
lda #mask | |
sta ScreenControl2 // $D016 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment