Skip to content

Instantly share code, notes, and snippets.

@JettMonstersGoBoom
Last active November 20, 2020 05:50
Show Gist options
  • Save JettMonstersGoBoom/62a6ef6d6f60bb4d92f8a55dfd91697d to your computer and use it in GitHub Desktop.
Save JettMonstersGoBoom/62a6ef6d6f60bb4d92f8a55dfd91697d to your computer and use it in GitHub Desktop.
C64 CIA example with Kickasm
.file [name="test.prg", segments="CODE,DATA"]
.segment CODE [start=$0801]
.segment DATA [startAfter="CODE"]
// PAL
.label CPU_FREQ = $4cc8
VIC: {
.label RASTER = $d012
.label BORDER = $d020
.label BACKGROUND = $d021
}
CIA: {
// irq ctrl status bits
.label TIMER_A_UNDERFLOW = %00000001 // triggered or enable timer a Rw
.label TIMER_B_UNDERFLOW = %00000010 // triggered or enable timer b Rw
.label TOD_ALARM = %00000100 // time of day alarm
.label BYTE_RECIEVE = %00001000 // tape stuff
.label DATASET = %00010000 //
.label IRQ_GENERATED = %10000000 // irq triggered or enable Rw
// control bits
.label TIMER_START = %00000001
.label TIMER_RESTARTS = %00000000 // will restart on underflow
.label TIMER_STOPS = %00001000 // will stop
.label TIMER_RELOAD = %00010000 // reload on underflow from set values
.label TIMER_COUNTS_CYCLES = %00000000 // count cpu cycles
.label TIMER_COUNTS_EDGES = %00100000 // count edges
.label TIMER_COUNTS_A_UNDERFLOW = %01000000 // count timer a underflow
.label TIMER_COUNTS_A_UNDERFLOW_EDGES = %01100000 // both
.label TOD_50hz = %10000000 // time of day clock is 50hz
.label TOD_60hz = %00000000 // time of day clock is 60hz
}
// CIA1 causes IRQ interupt
CIA1: {
.label PORT_A = $dc00
.label PORT_B = $dc01
.label DDR_A = $dc02
.label DDR_B = $dc03
.label Timer_A = $dc04
.label Timer_A_l = $dc04
.label Timer_A_h = $dc05
.label Timer_B = $dc06
.label Timer_B_l = $dc06
.label Timer_B_h = $dc07
.label IRQCtrlStatus = $dc0d
.label Timer_A_Control = $dc0e
.label Timer_B_Control = $dc0f
}
// CIA2 causes NMI
CIA2: {
.label PORT_A = $dd00
.label PORT_B = $dd01
.label DDR_A = $dd02
.label DDR_B = $dd03
.label Timer_A = $dd04
.label Timer_A_l = $dd04
.label Timer_A_h = $dd05
.label Timer_B = $dd06
.label Timer_B_l = $dd06
.label Timer_B_h = $dd07
.label IRQCtrlStatus = $dd0d
.label Timer_A_Control = $dd0e
.label Timer_B_Control = $dd0f
}
// NOTE: doesn't get written to the prg
.segment ZP [start=$02]
result: .word 0
.segment CODE
//-------------------------------------------------------------
// This creates a basic sys line that can start your program
//-------------------------------------------------------------
BasicUpstart2(Start)
// Our code
Start:
{
// stop IRQ
sei
// set to black
lda #$00
sta VIC.BORDER
sta VIC.BACKGROUND
// clear screen
ldx #$00
!:
lda #$20
sta $0400,x
sta $0500,x
lda #$1
sta $d800,x
sta $d900,x
dex
bne !-
// set A & B for display above
lda #$01
sta $0401
lda #$02
sta $0403
// copy names to screen
ldx #$00
!:
lda irqs,x
sta $0428+8,x
lda nmis,x
sta $0428+48,x
inx
cpx #3
bne !-
//
// Disable all interrupts..
//
lda #$7f
sta CIA1.IRQCtrlStatus
sta CIA2.IRQCtrlStatus
// poll
lda CIA1.IRQCtrlStatus
lda CIA2.IRQCtrlStatus
// set IRQ to our routine
lda #<Irq
sta $0314
lda #>Irq
sta $0315
// set NMI to our routine
lda #<Nmi
sta $0318
lda #>Nmi
sta $0319
// set timer A to CPU_Frequency (irq)
lda #<CPU_FREQ
sta CIA1.Timer_A_l
lda #>CPU_FREQ
sta CIA1.Timer_A_h
// second timer
// 15 frames
lda #15
sta CIA1.Timer_B_l
lda #$00
sta CIA1.Timer_B_h
// set timer A to CPU_Frequency (nmi)
lda #<CPU_FREQ
sta CIA2.Timer_A_l
lda #>CPU_FREQ
sta CIA2.Timer_A_h
// second timer
// 50 frames
lda #50
sta CIA2.Timer_B_l
lda #$00
sta CIA2.Timer_B_h
// cia 1 irq
// trigger when timer A hits
lda #CIA.IRQ_GENERATED | CIA.TIMER_A_UNDERFLOW
sta CIA1.IRQCtrlStatus
// cia 2 nmi
// trigger when timer A hits
lda #CIA.IRQ_GENERATED | CIA.TIMER_A_UNDERFLOW
sta CIA2.IRQCtrlStatus
// wait until we're in the middle before starting timer 1
vwait:
lda VIC.RASTER
cmp #$80
bne vwait
// we want the CIA to auto reload and auto restart the timer and tell it to start here
lda #CIA.TIMER_RELOAD | CIA.TIMER_RESTARTS | CIA.TIMER_START | CIA.TIMER_COUNTS_CYCLES
sta CIA1.Timer_A_Control
// we want the CIA to auto reload and auto restart the timer and count timer A underflow ( 0 )
lda #CIA.TIMER_RELOAD | CIA.TIMER_RESTARTS | CIA.TIMER_START | CIA.TIMER_COUNTS_A_UNDERFLOW
sta CIA1.Timer_B_Control
// polling this register starts
lda CIA1.IRQCtrlStatus
lda CIA1.IRQCtrlStatus
// wait until we're a bit below before starting timer 2
vwait2:
lda VIC.RASTER
cmp #$c0
bne vwait2
// we want the CIA to auto reload and auto restart the timer and tell it to start here
lda #CIA.TIMER_RELOAD | CIA.TIMER_RESTARTS | CIA.TIMER_START | CIA.TIMER_COUNTS_CYCLES
sta CIA2.Timer_A_Control
// we want the CIA to auto reload and auto restart the timer and count timer A underflow ( 0 )
lda #CIA.TIMER_RELOAD | CIA.TIMER_RESTARTS | CIA.TIMER_START | CIA.TIMER_COUNTS_A_UNDERFLOW
sta CIA2.Timer_B_Control
// polling this register starts
lda CIA2.IRQCtrlStatus
lda CIA2.IRQCtrlStatus
cli
jmp *
rts
}
Nmi:
{
pha
// grab status bits
// we use this to offset our increment of $428 , x
// should be 1 ( timer A )
// or 3 ( timer A & B )
lda CIA2.IRQCtrlStatus
and #$7f
tax
lda $042b+40
sta VIC.BORDER
sta VIC.BACKGROUND
// we can figure out what timer here
inc $0428+40,x
pla
bit $2
bit $2
bit $2
bit $2
lda #$00
sta VIC.BORDER
sta VIC.BACKGROUND
rti
}
Irq:
{
pha
// grab status bits
// we use this to offset our increment of $400 , x
// should be 1 ( timer A )
// or 3 ( timer A & B )
lda CIA1.IRQCtrlStatus
and #$7f
tax
lda $0403+40
sta VIC.BORDER
sta VIC.BACKGROUND
// we can figure out what timer here
inc $0400+40,x
// inc $d020
pla
bit $2
bit $2
bit $2
bit $2
lda #$00
sta VIC.BORDER
sta VIC.BACKGROUND
jmp $ea81
}
irqs: .text "irq"
nmis: .text "nmi"
.segment DATA
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment