mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-06-03 07:29:37 +00:00
291 lines
6.6 KiB
NASM
291 lines
6.6 KiB
NASM
// Example program for the Commander X16
|
|
// Displays raster bars in the border
|
|
.cpu _65c02
|
|
// Commander X16 PRG executable file
|
|
.file [name="cx16-rasterbars.prg", type="prg", segments="Program"]
|
|
.segmentdef Program [segments="Basic, Code, Data"]
|
|
.segmentdef Basic [start=$0801]
|
|
.segmentdef Code [start=$80d]
|
|
.segmentdef Data [startAfter="Code"]
|
|
.segment Basic
|
|
:BasicUpstart(__start)
|
|
.const VERA_DCSEL = 2
|
|
.const VERA_LINE = 2
|
|
.const isr_vsync = $314
|
|
.const SIZEOF_CHAR = 1
|
|
/// $0314 (RAM) IRQ vector - The vector used when the KERNAL serves IRQ interrupts
|
|
.label KERNEL_IRQ = $314
|
|
/// $9F25 CTRL Control
|
|
/// Bit 7: Reset
|
|
/// Bit 1: DCSEL
|
|
/// Bit 2: ADDRSEL
|
|
.label VERA_CTRL = $9f25
|
|
/// $9F26 IEN Interrupt Enable
|
|
/// Bit 7: IRQ line (8)
|
|
/// Bit 3: AFLOW
|
|
/// Bit 2: SPRCOL
|
|
/// Bit 1: LINE
|
|
/// Bit 0: VSYNC
|
|
.label VERA_IEN = $9f26
|
|
/// $9F27 ISR Interrupt Status
|
|
/// Interrupts will be generated for the interrupt sources set in the lower 4 bits of IEN. ISR will indicate the interrupts that have occurred.
|
|
/// Writing a 1 to one of the lower 3 bits in ISR will clear that interrupt status. AFLOW can only be cleared by filling the audio FIFO for at least 1/4.
|
|
/// Bit 4-7: Sprite Collisions. This field indicates which groups of sprites have collided.
|
|
/// Bit 3: AFLOW
|
|
/// Bit 2: SPRCOL
|
|
/// Bit 1: LINE
|
|
/// Bit 0: VSYNC
|
|
.label VERA_ISR = $9f27
|
|
/// $9F28 IRQLINE_L IRQ line (7:0)
|
|
/// IRQ_LINE specifies at which line the LINE interrupt will be generated.
|
|
/// Note that bit 8 of this value is present in the IEN register.
|
|
/// For interlaced modes the interrupt will be generated each field and the bit 0 of IRQ_LINE is ignored.
|
|
.label VERA_IRQLINE_L = $9f28
|
|
/// $9F2C DC_BORDER (DCSEL=0) Border Color
|
|
.label VERA_DC_BORDER = $9f2c
|
|
/// $9F29 DC_HSTART (DCSEL=1) Active Display H-Start (9:2)
|
|
.label VERA_DC_HSTART = $9f29
|
|
/// $9F2A DC_HSTOP (DCSEL=1) Active Display H-Stop (9:2)
|
|
.label VERA_DC_HSTOP = $9f2a
|
|
/// $9F2B DC_VSTART (DCSEL=1) Active Display V-Start (8:1)
|
|
.label VERA_DC_VSTART = $9f2b
|
|
/// $9F2C DC_VSTOP (DCSEL=1) Active Display V-Stop (8:1)
|
|
.label VERA_DC_VSTOP = $9f2c
|
|
.label BRAM = 0
|
|
.label BROM = 1
|
|
// The horizontal start
|
|
.label hstart = 6
|
|
// The horizontal stop
|
|
.label hstop = 7
|
|
// The vertical start
|
|
.label vstart = 8
|
|
// The vertical stop
|
|
.label vstop = 9
|
|
// The countdown
|
|
.label cnt = 5
|
|
// The sin idx
|
|
.label sin_idx = $a
|
|
.segment Code
|
|
__start: {
|
|
// __export volatile __address(0x00) unsigned char BRAM = 0
|
|
lda #0
|
|
sta.z BRAM
|
|
// __export volatile __address(0x01) unsigned char BROM = 4
|
|
lda #4
|
|
sta.z BROM
|
|
// volatile char hstart = 0/4
|
|
lda #0
|
|
sta.z hstart
|
|
// volatile char hstop = 640/4
|
|
lda #$280/4
|
|
sta.z hstop
|
|
// volatile char vstart = 0/2
|
|
lda #0
|
|
sta.z vstart
|
|
// volatile char vstop = 480/2
|
|
lda #$1e0/2
|
|
sta.z vstop
|
|
// volatile char cnt = 2
|
|
lda #2
|
|
sta.z cnt
|
|
// volatile char sin_idx = 100
|
|
lda #$64
|
|
sta.z sin_idx
|
|
jsr main
|
|
rts
|
|
}
|
|
// LINE Interrupt Routine
|
|
irq_line: {
|
|
.label idx = 4
|
|
.label bar = 2
|
|
// *VERA_CTRL |= VERA_DCSEL
|
|
// Update the border
|
|
lda #VERA_DCSEL
|
|
ora VERA_CTRL
|
|
sta VERA_CTRL
|
|
// *VERA_DC_HSTART = hstart
|
|
lda.z hstart
|
|
sta VERA_DC_HSTART
|
|
// *VERA_DC_HSTOP = hstop
|
|
lda.z hstop
|
|
sta VERA_DC_HSTOP
|
|
// *VERA_DC_VSTART = vstart
|
|
lda.z vstart
|
|
sta VERA_DC_VSTART
|
|
// *VERA_DC_VSTOP = vstop
|
|
lda.z vstop
|
|
sta VERA_DC_VSTOP
|
|
// *VERA_CTRL &= ~VERA_DCSEL
|
|
// Show color raster bars in the border
|
|
lda #VERA_DCSEL^$ff
|
|
and VERA_CTRL
|
|
sta VERA_CTRL
|
|
ldx #0
|
|
__b2:
|
|
// for(char l=0;l!=230;l++)
|
|
cpx #$e6
|
|
bne __b3
|
|
// if(--cnt==0)
|
|
dec.z cnt
|
|
lda.z cnt
|
|
bne __b1
|
|
// cnt = 2
|
|
lda #2
|
|
sta.z cnt
|
|
// if(hstart<=320/4)
|
|
lda.z hstart
|
|
cmp #$140/4+1
|
|
bcs __b1
|
|
// hstart++;
|
|
inc.z hstart
|
|
// hstop--;
|
|
dec.z hstop
|
|
// vstart++;
|
|
inc.z vstart
|
|
// vstop--;
|
|
dec.z vstop
|
|
__b1:
|
|
// memset(BARS, 0, sizeof(BARS))
|
|
// Animate the bars
|
|
jsr memset
|
|
// char idx = sin_idx--
|
|
lda.z sin_idx
|
|
sta.z idx
|
|
dec.z sin_idx
|
|
ldx #0
|
|
__b13:
|
|
// for(char b=0;b<8;b++)
|
|
cpx #8
|
|
bcc __b14
|
|
// *VERA_ISR = VERA_LINE
|
|
// Reset the LINE interrupt
|
|
lda #VERA_LINE
|
|
sta VERA_ISR
|
|
// }
|
|
jmp $e049
|
|
__b14:
|
|
// char * bar = BARS + SIN[idx]
|
|
ldy.z idx
|
|
lda SIN,y
|
|
clc
|
|
adc #<BARS
|
|
sta.z bar
|
|
lda #>BARS
|
|
adc #0
|
|
sta.z bar+1
|
|
ldy #0
|
|
__b16:
|
|
// for(char i=0;i<sizeof(BAR);i++)
|
|
cpy #$20*SIZEOF_CHAR
|
|
bcc __b17
|
|
// idx += 13
|
|
lda #$d
|
|
clc
|
|
adc.z idx
|
|
sta.z idx
|
|
// for(char b=0;b<8;b++)
|
|
inx
|
|
jmp __b13
|
|
__b17:
|
|
// bar[i] = BAR[i]
|
|
lda BAR,y
|
|
sta (bar),y
|
|
// for(char i=0;i<sizeof(BAR);i++)
|
|
iny
|
|
jmp __b16
|
|
__b3:
|
|
// *VERA_DC_BORDER = BARS[l]
|
|
lda BARS,x
|
|
sta VERA_DC_BORDER
|
|
lda #0
|
|
__b5:
|
|
// for(char i=0;i<24;i++)
|
|
cmp #$18
|
|
bcc __b6
|
|
// *VERA_DC_BORDER = 0
|
|
// Wait exactly long enough to go to the next raster line
|
|
lda #0
|
|
sta VERA_DC_BORDER
|
|
__b8:
|
|
// for(char i=0;i<23;i++)
|
|
cmp #$17
|
|
bcc __b9
|
|
// asm
|
|
// Wait exactly long enough to go to the next raster line
|
|
nop
|
|
nop
|
|
// for(char l=0;l!=230;l++)
|
|
inx
|
|
jmp __b2
|
|
__b9:
|
|
// for(char i=0;i<23;i++)
|
|
inc
|
|
jmp __b8
|
|
__b6:
|
|
// for(char i=0;i<24;i++)
|
|
inc
|
|
jmp __b5
|
|
}
|
|
main: {
|
|
// asm
|
|
sei
|
|
// *KERNEL_IRQ = &irq_line
|
|
lda #<irq_line
|
|
sta KERNEL_IRQ
|
|
lda #>irq_line
|
|
sta KERNEL_IRQ+1
|
|
// *VERA_IEN = VERA_LINE
|
|
lda #VERA_LINE
|
|
sta VERA_IEN
|
|
// *VERA_IRQLINE_L = 5
|
|
lda #5
|
|
sta VERA_IRQLINE_L
|
|
// asm
|
|
cli
|
|
__b1:
|
|
jmp __b1
|
|
}
|
|
// Copies the character c (an unsigned char) to the first num characters of the object pointed to by the argument str.
|
|
// void * memset(void *str, char c, unsigned int num)
|
|
memset: {
|
|
.const num = $e6*SIZEOF_CHAR
|
|
.const c = 0
|
|
.label str = BARS
|
|
.label end = str+num
|
|
.label dst = 2
|
|
lda #<str
|
|
sta.z dst
|
|
lda #>str
|
|
sta.z dst+1
|
|
__b1:
|
|
// for(char* dst = str; dst!=end; dst++)
|
|
lda.z dst+1
|
|
cmp #>end
|
|
bne __b2
|
|
lda.z dst
|
|
cmp #<end
|
|
bne __b2
|
|
// }
|
|
rts
|
|
__b2:
|
|
// *dst = c
|
|
lda #c
|
|
ldy #0
|
|
sta (dst),y
|
|
// for(char* dst = str; dst!=end; dst++)
|
|
inc.z dst
|
|
bne !+
|
|
inc.z dst+1
|
|
!:
|
|
jmp __b1
|
|
}
|
|
.segment Data
|
|
.align $100
|
|
SIN:
|
|
.fill 256, 99+99*sin(i*2*PI/256)
|
|
|
|
.align $100
|
|
BARS: .fill $e6, 0
|
|
.align $100
|
|
BAR: .byte $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $1a, $1b, $1c, $1d, $1e, $1f, $1f, $1e, $1d, $1c, $1b, $1a, $19, $18, $17, $16, $15, $14, $13, $12, $11, $10
|