1
0
mirror of https://github.com/fumiama/c64-snake.git synced 2026-06-05 00:32:39 +08:00

初步框架

This commit is contained in:
fumiama
2021-03-30 23:18:15 +08:00
parent 8706367007
commit ece3f266ea
14 changed files with 703 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.DS_Store

37
main.asm Normal file
View File

@@ -0,0 +1,37 @@
.outfile "snake.prg"
.require "platform/c64_0.oph"
.require "platform/c64kernal.oph"
.alias go_u #1 ; 上
.alias go_d #2 ; 下
.alias go_l #4 ; 左
.alias go_r #8 ; 右
.data zp
.space d 1 ; 方向 值定义如上
.space c 1 ; 长度 最大255 最小0
.text
main:
.scope
lda #147 ;清屏
jsr chrout
rts
.scend
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; getdir 返回一个方向到d
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
getdir:
.macro
jsr chrin
sta d
.macend
.checkpc $A000 ; text段边界
.data zp ; 零页段边界
.checkpc $80
.data
.checkpc $D000 ; data段边界

42
platform/README.txt Executable file
View File

@@ -0,0 +1,42 @@
This directory holds files likely to be of use to you in developing your own
programs. The contents of each file is summarized below.
c64_0.oph: A Commodore 64 equivalent to a modern compiler's "crt0.s" - it
contains a .PRG file header, a short BASIC program that launches
the machine language program, and a prologue and epilogue that
prepare memory for your use and then clean it up again when you
are done. Memory locations $02 through $8F on the zero page are
available for your use, and the program lives at the beginning
a contiguous block of RAM from $0800 through $CFFF. The BASIC
ROM is swapped out of memory (leaving $A000-$BFFF as RAM) for
the duration of your program. BASIC's working storage on the
zero page is backed up in the RAM underneath the KERNAL ROM
while your program runs.
c64kernal.oph: A collection of standard aliases for the KERNAL routines on the
Commodore 64. Names for these routines have been chosen to match
the Commodore 64 Programmer's Reference Guide. Additional useful
constants are defined for the character codes for color changes
and case-changing.
libbasic64.oph:A still-experimental set of macros and routines for exploiting
the software floating point routines in the Commodore 64
BASIC ROM.
c64header.oph: A much simpler Commodore 64 header that does nothing but jump
directly to your code. Useful for small programs or those that
intend to interface with BASIC.
vic20.oph: A simple header for the unexpanded VIC-20. Equivalent in
behavior to c64header.oph.
vic20x.oph: A simple header like the two above, but for expanded VIC-20.
nes.oph: A somewhat skeletal collection of aliases for the PPU registers
on the Nintendo Entertainment System. These names were chosen
to match the constant names given on the NESdev Wiki.
stella.oph: A collection of aliases for the registers of the Atari 2600.
These names were taken from the "Stella Programmer's Guide" and
are in wide use amongst developers and code analysts alike.

74
platform/c64_0.oph Executable file
View File

@@ -0,0 +1,74 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Commodore 64 Basic Runtime File
;;
;; Include this at the TOP of your C64 program, and it will handle
;; hiding away the BASIC ROM and data and restoring it at the end.
;;
;; You will have a contiguous block of RAM from $0800 to $CFFF, and
;; Zero Page access from $02 to $8F in the segment "zp".
.include "c64header.oph"
.data zp ; Zero Page memory segment.
.org $0002
.text
.scope
; Cache BASIC zero page underneath the KERNAL, while also
; making RAM copies of the NMI routines
ldx #$00
* lda $00, x
sta $e000, x
inx
bne -
; Swap out the BASIC ROM for RAM
lda $01
and #$fe
ora #$06
sta $01
; Run the real program
jsr _main
; Swap out KERNAL to expose cached BASIC ZP values
; Block IRQs during this period. NMIs cannot be blocked,
; but we copied enough of the processing code into the
; RAM under the KERNAL that we can disable NMI processing
; during this period
sei ; Disable IRQs
lda #$c1 ; Defang NMIs
sta $318
lda $01 ; Swap out KERNAL
and #$fd
sta $01
; Restore BASIC zero page
ldx #$8E
* lda $e001, x
sta $01, x
dex
bne -
; Restore BASIC ROM, KERNAL, and interrupts
lda $01
ora #$07
sta $01
lda #$47 ; Restore NMI vector
sta $318
cli ; Re-enable interrupts
; Back to BASIC. We do this by clearing the keyboard
; buffer and then jumping through the warm start
; vector. This will more cleanly handle case where
; the program has somehow modified BASIC's state,
; such as running through PUCRUNCH or a onefiler.
stx $c6 ; .X is zero from previous loop
jmp ($a002)
_main:
; Program follows...
.scend

10
platform/c64header.oph Executable file
View File

@@ -0,0 +1,10 @@
.word $0801
.org $0801
; BASIC program that just calls our machine language code
.scope
.word _next, 10 ; Next line and current line number
.byte $9e,"2061",0 ; SYS 2061
_next: .word 0 ; End of program
.scend
; Program follows...

67
platform/c64kernal.oph Executable file
View File

@@ -0,0 +1,67 @@
; KERNAL routine aliases (C64)
.alias acptr $ffa5
.alias chkin $ffc6
.alias chkout $ffc9
.alias chrin $ffcf
.alias chrout $ffd2
.alias ciout $ffa8
.alias cint $ff81
.alias clall $ffe7
.alias close $ffc3
.alias clrchn $ffcc
.alias getin $ffe4
.alias iobase $fff3
.alias ioinit $ff84
.alias listen $ffb1
.alias load $ffd5
.alias membot $ff9c
.alias memtop $ff99
.alias open $ffc0
.alias plot $fff0
.alias ramtas $ff87
.alias rdtim $ffde
.alias readst $ffb7
.alias restor $ff8a
.alias save $ffd8
.alias scnkey $ff9f
.alias screen $ffed
.alias second $ff93
.alias setlfs $ffba
.alias setmsg $ff90
.alias setnam $ffbd
.alias settim $ffdb
.alias settmo $ffa2
.alias stop $ffe1
.alias talk $ffb4
.alias tksa $ff96
.alias udtim $ffea
.alias unlsn $ffae
.alias untlk $ffab
.alias vector $ff8d
; Character codes for the colors.
.alias color'0 144
.alias color'1 5
.alias color'2 28
.alias color'3 159
.alias color'4 156
.alias color'5 30
.alias color'6 31
.alias color'7 158
.alias color'8 129
.alias color'9 149
.alias color'10 150
.alias color'11 151
.alias color'12 152
.alias color'13 153
.alias color'14 154
.alias color'15 155
; ...and reverse video
.alias reverse'on 18
.alias reverse'off 146
; ...and character set
.alias upper'case 142
.alias lower'case 14

287
platform/libbasic64.oph Executable file
View File

@@ -0,0 +1,287 @@
;;; LIBBASIC64.OPH
;;; This is a collection of routines inside the BASIC ROM that can
;;; be repurposed to do floating-point math inside your machine
;;; language programs. It is currently VERY EXPERIMENTAL. The documentation
;;; available for this is spotty at best and disassembly confirms that
;;; a lot of hidden invariants may lurk.
;;; BASIC function equivalents. These operate on FAC1 and are pretty
;;; clean overall. They take their input in FAC1 and put their output
;;; there too. While it is not *guaranteed* it is probably best to
;;; assume that these functions trash the value in FAC2.
.alias abs_fac1 $bc58
.alias atn_fac1 $e30e
.alias cos_fac1 $e264
.alias exp_fac1 $bfed
.alias int_fac1 $bccc
.alias log_fac1 $b9ea
.alias rnd_fac1 $e097
.alias sgn_fac1 $bc39
.alias sin_fac1 $e26b
.alias tan_fac1 $e2b4
;;; Getting useful information into the FACs
;; Treat the accumulator as a signed byte, load that value
;; into FAC1
.alias ld_fac1_a $bc3c
;; Load the signed 16-bit value with A as the *high* byte and
;; Y as the *low* byte into FAC1. This is backwards from pretty
;; much everything else.
.alias ld_fac1_s16 $b391
;; Load a 5-byte value from memory into FAC1.
.alias ld_fac1_mem $bba2
;; Copy FAC2 into FAC1.
.alias ld_fac1_fac2 $bbfc
;; Translate FAC1 into a string that is at $0100.
.alias fac1_to_string $bddd
;; Convert FAC1 into a 32-bit *big-endian* signed integer at
;; $62-$65 (where the mantissa usually goes in FAC1).
.alias fac1_to_s32 $bc9b
;; Store out FAC1 to $57-$5B, converting it back into the five-byte
;; floating-point format.
.alias fac1_to_57 $bbca
;; Do the same but at $5c-$60.
.alias fac1_to_5c $bbc7
;; Load a 5-byte value into FAC2.
.alias ld_fac2_mem $ba8c
;; Copy FAC1 to FAC2. FAC1 has some extra precision that is
;; rounded away when you do this.
.alias ld_fac2_fac1 $bc0c
;;; Comparison operator.
;; Like sgn_fac1, but returns the -1/0/1 in the accumulator as
;; an integer.
.alias fac1_sign $bc2b
;;; FP operators. These are all FAC2 OP FAC1 with the result in FAC1.
;;; PRECONDITIONS: All of these operations but AND and OR require you to
;;; have the contents of $61 in the accumulator. calling one of the ld_fac*
;;; routines will do that for you automatically. f_add_op also requires that
;;; $6F be set properly; only ld_fac2_mem does this.
.alias f_add_op $b86a
.alias f_subtract_op $b853
.alias f_multiply_op $ba2b
.alias f_divide_op $bb12
.alias f_pow_op $bf7b
.alias f_and_op $afe9
.alias f_or_op $afe6
;;; Memory-based FP operations. All are MEM OP FAC1. These are usually safer
;;; than the *_op routines.
.alias f_add_mem $b867
.alias f_subtract_mem $b850
.alias f_multiply_mem $ba28
.alias f_divide_mem $bb0f
;;; Useful FP constants that live in the ROM. It's plausible that ld_fac1_a
;;; or ld_fac1_s16 would be more convenient than ld_fac1_mem with f_1 or f_10,
;;; but when doing memory-based generic stuff, these will still be useful.
.alias f_0_5 $bf11 ; 0.5
.alias f_1 $b9bc ; 1.0
.alias f_pi $aea8 ; 3.1415926
.alias f_10 $baf9 ; 10.0
;;; Macros for using these routines more safely.
;; Copy 5-byte values around in memory without touching the FACs.
.macro f_move
ldx #$00
_fmvlp: lda _2,x
sta _1,x
inx
cpx #$05
bne _fmvlp
.macend
;;; These next few macros really exist just to save us the trouble of loading
;;; addresses into registers
.macro print_str
lda #<_1
ldy #>_1
jsr strout
.macend
.macro ld_fac1
lda #<_1
ldy #>_1
jsr ld_fac1_mem
.macend
.macro ld_fac2
lda #<_1
ldy #>_1
jsr ld_fac2_mem
.macend
.macro st_fac1
lda #<_1
ldy #>_1
jsr fac1_to_mem
.macend
.macro fp_load
`ld_fac1 _1
.macend
.macro fp_store
`st_fac1 _1
.macend
.macro fp_print
`ld_fac1 _1
jsr fac1out
.macend
.macro fp_read
lda #<_1
ldy #>_1
jsr ld_fac1_string
.macend
;;; Arithmetic macros. These serve mainly to make the operations work left-
;;; to-right as one generally would prefer. They also guarantee the obscure
;;; preconditions hold.
.macro fp_add
lda #<_1
ldy #>_1
jsr f_add_mem
.macend
.macro fp_subtract
jsr ld_fac2_fac1
`ld_fac1 _1
jsr f_subtract_op
.macend
.macro fp_multiply
lda #<_1
ldy #>_1
jsr f_multiply_mem
.macend
.macro fp_divide
jsr ld_fac2_fac1
`ld_fac1 _1
jsr f_divide_op
.macend
.macro fp_pow
jsr ld_fac2_fac1
`ld_fac1 _1
jsr f_pow_op
.macend
.macro fp_and
`ld_fac2 _1
jsr f_and_op
.macend
.macro fp_or
`ld_fac2 _1
jsr f_or_op
.macend
;;; Utility routine for converting the system clock to a floating point
;;; value.
ld_fac1_ti:
jsr $ffde ; RDTIM
sty $63
stx $64
sta $65
;; Once the requirements on .Y and $68 are better
;; understood, this might be exportable as
;; ld_fac1_s32, but there are still some dragons
;; lurking
ldy #$00 ; Clear out intermediary values
sta $62
sta $68
jmp $bcd5
;;; FAC1 can only be stored out to two locations. We'd prefer to be able
;;; to store anywhere. This routine is a support routine that allows that.
;;; It will normally only be called by the fp_store macro.
fac1_to_mem:
sta $fd
sty $fe
jsr fac1_to_5c
ldy #$00
* lda $5c,y
sta ($fd),y
iny
cpy #$05
bne -
rts
;;; The VAL function uses the CHRGET routine copied to the zero page to read
;;; strings in. That's a fragile operation if we don't want to confuse BASIC
;;; later, so this routine juggles the values we need to preserve. It will
;;; normally only be called by the fp_read macro.
ld_fac1_string:
ldx $7a
sta $7a
txa
pha
lda $7b
pha
sty $7b
jsr $79
jsr $bcf3
pla
sta $7b
pla
sta $7a
rts
;;; Print out the contents of FAC1.
fac1out:
ldy #$00 ; Clean out overflow
sty $68
sty $70
jsr fac1_to_string
ldy #$01
;; Skip the first character if it's not "-"
lda $100
sec
sbc #$2d
beq strout
lda #$01
;; Fall through to strout
;;; The BASIC ROM already has a STROUT routine - $ab1e - but
;;; it makes use of BASIC's own temporary string handling. We
;;; don't want it to ever touch its notion of temporary strings
;;; here, so we provide our own short routine to do this.
strout: sta $fd
sty $fe
ldy #$00
* lda ($fd),y
beq +
jsr $ffd2 ; CHROUT
iny
bne -
* rts
;;; Execute RND(-TI), seeding the random number generator the traditional way.
randomize:
jsr ld_fac1_ti
lda #$ff
sta $66 ; Force sign negative
jmp rnd_fac1 ; RND(-TI)
;;; Return RND(1), a fresh random number between 0 and 1.
rnd: lda #$01
jsr ld_fac1_a
jmp rnd_fac1

15
platform/nes.oph Executable file
View File

@@ -0,0 +1,15 @@
; NES-related headers. Unlike the C64 and Stella developers, there is
; no standard nomenclature for these registers. It's not uncommon to
; see them hardcoded.
; PPU registers have reasonably standard names, at least.
.alias PPUCTRL $2000 ; PPU Control Register #1
.alias PPUMASK $2001 ; PPU Control Register #2
.alias PPUSTATUS $2002 ; PPU Status Register
.alias OAMADDR $2003 ; SPR-RAM Address Register
.alias OAMDATA $2004 ; SPR-RAM I/O Register
.alias PPUSCROLL $2005 ; VRAM Address Register #1 (Panning control)
.alias PPUADDR $2006 ; VRAM Address Register #2 (Direct Address control)
.alias PPUDATA $2007 ; VRAM I/O Register
.alias OAMDMA $4014 ; Sprite DMA Register

127
platform/stella.oph Executable file
View File

@@ -0,0 +1,127 @@
; Register mnemonics for the Atari 2600 VCS
;
; Taken from the "Stella Programming Guide", at
; http://www.alienbill.com/2600/101/docs/stella.html
; Writable TIA addresses
.alias VSYNC $00 ; vertical sync set-clear
.alias VBLANK $01 ; vertical blank set-clear
.alias WSYNC $02 ; wait for leading edge of horizontal blank
.alias RSYNC $03 ; reset horizontal sync counter
.alias NUSIZ0 $04 ; number-size player-missile 0
.alias NUSIZ1 $05 ; number-size player-missile 1
.alias COLUP0 $06 ; color-lum player 0
.alias COLUP1 $07 ; color-lum player 1
.alias COLUPF $08 ; color-lum playfield
.alias COLUBK $09 ; color-lum background
.alias CTRLPF $0A ; control playfield ball size and collisions
.alias REFP0 $0B ; reflect player 0
.alias REFP1 $0C ; reflect player 1
.alias PF0 $0D ; playfield register byte 0
.alias PF1 $0E ; playfield register byte 1
.alias PF2 $0F ; playfield register byte 2
.alias RESP0 $10 ; reset player 0
.alias RESP1 $11 ; reset player 1
.alias RESM0 $12 ; reset missile 0
.alias RESM1 $13 ; reset missile 1
.alias RESBL $14 ; reset ball
.alias AUDC0 $15 ; audio control 0
.alias AUDC1 $16 ; audio control 1
.alias AUDF0 $17 ; audio frequency 0
.alias AUDF1 $18 ; audio frequency 1
.alias AUDV0 $19 ; audio volume 0
.alias AUDV1 $1A ; audio volume 1
.alias GRP0 $1B ; Graphics player 0
.alias GRP1 $1C ; Graphics player 1
.alias ENAM0 $1D ; Graphics enable missile 0
.alias ENAM1 $1E ; Graphics enable missile 1
.alias ENABL $1F ; Graphics enable ball
.alias HMP0 $20 ; horizontal motion player 0
.alias HMP1 $21 ; horizontal motion player 1
.alias HMM0 $22 ; horizontal motion missile 0
.alias HMM1 $23 ; horizontal motion missile 1
.alias HMBL $24 ; horizontal motion ball
.alias VDELP0 $25 ; vertical delay player 0
.alias VDELP1 $26 ; vertical delay player 1
.alias VDELBL $27 ; vertical delay ball
.alias RESMP0 $28 ; reset missile 0 to player 0
.alias RESMP1 $29 ; reset missile 1 to player 1
.alias HMOVE $2A ; apply horizontal motion
.alias HMCLR $2B ; clear horizontal motion registers
.alias CXCLR $2C ; clear collision latches
; Readable TIA addresses
.alias CXM0P $00 ; read collision missile 0 players
.alias CXM1P $01 ; read collision missile 1 players
.alias CXP0FB $02 ; read collision player 0 playfield/ball
.alias CXP1FB $03 ; read collision player 1 playfield/ball
.alias CXM0FB $04 ; read collision missile 0 playfield/ball
.alias CXM1FB $05 ; read collision missile 1 playfield/ball
.alias CXBLPF $06 ; read collision ball playfield
.alias CXPPMM $07 ; read collision player/player missile/missile
.alias INPT0 $08 ; read pot port
.alias INPT1 $09 ; read pot port
.alias INPT2 $0A ; read pot port
.alias INPT3 $0B ; read pot port
.alias INPT4 $0C ; read input
.alias INPT5 $0D ; read input
; PIA addresses
.alias SWCHA $280 ; Port A data register (read/write)
.alias SWACNT $281 ; Port A data direction register (0=input, 1=output)
.alias SWCHB $282 ; Port B - console switches (read-only)
.alias SWBCNT $283 ; Port B data direction register (hardwired to 0)
.alias INTIM $284 ; Timer output (read only)
.alias TIM1T $294 ; Set 1-clock interval (838 nsec/interval)
.alias TIM8T $295 ; Set 8-clock interval (6.7 usec/interval)
.alias TIM64T $296 ; Set 64-clock interval (53.6 usec/interval
.alias T1024T $297 ; Set 1025-clock interval (858.2 usec/interval)
; These macros are adapted from DASM's old macro.h. Credit and description are
; replicated from there.
;-------------------------------------------------------------------------------
; VERTICAL_SYNC
; Original author: Manuel Polik
; Inserts the code required for a proper 3 scanline
; vertical sync sequence
;
; Note: Alters the accumulator
;
; IN:
; OUT: A = 1
.macro vertical'sync
lda #$02
sta WSYNC
sta VSYNC
sta WSYNC
sta WSYNC
lsr
sta WSYNC
sta VSYNC
.macend
;-------------------------------------------------------------------------------
; CLEAN_START
; Original author: Andrew Davie
; Standardised start-up code, clears stack, all TIA registers and RAM to 0
; Sets stack pointer to $FF, and all registers to 0
; Sets decimal mode off, sets interrupt flag (kind of un-necessary)
; Use as very first section of code on boot (ie: at reset)
; Code written to minimise total ROM usage - uses weird 6502 knowledge :)
.macro clean'start
sei
cld
ldx #$00
txa
tay
_clear'stack:
dex
txs
pha
bne _clear'stack
.macend

5
platform/vic20.oph Executable file
View File

@@ -0,0 +1,5 @@
;;; Minimal header file for unexpanded VIC-20.
;;; It translates to 10 SYS4109.
.word $1001
.org $1001
.byte $0b,$10,$0a,$00,$9e,$34,$31,$30,$39,$00,$00,$00

5
platform/vic20x.oph Executable file
View File

@@ -0,0 +1,5 @@
;;; Minimal header file for expanded VIC-20.
;;; It translates to 10 SYS4621.
.word $1201
.org $1201
.byte $0b,$12,$0a,$00,$9e,$34,$36,$32,$31,$00,$00,$00

33
printinput.asm Normal file
View File

@@ -0,0 +1,33 @@
.outfile "printinput.prg"
.require "platform/c64header.oph"
.require "platform/c64kernal.oph"
.data
.org $C000
.space _na 1 ; a的临时存放处
.text
main:
* jsr getin
beq skip
jsr printbyte
lda #13 ; 换行
jsr chrout
skip:
jmp -
printbyte:
sta _na
txa
pha
ldx #7 ; 打印8bit
* lda #$30 ; a = '0'
asl _na ; 左移一位溢出到c
bcc + ; if(c == 0) goto 下一个星号
adc #0 ; else a = a + c + 0
* jsr chrout ; putchar(a)
dex ; x--
bne -- ; if(x != 0) goto 上两个星号
pla
tax
rts

BIN
printinput.prg Normal file

Binary file not shown.

BIN
snake.prg Normal file

Binary file not shown.