generated from RuiFPB/65c02-template
Initial commit
This commit is contained in:
commit
3fc52b8adc
9 files changed
+325
No files matched your search
+36
@@ -0,0 +1,36 @@
|
||||
### IntelliJ IDEA ###
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
.kotlin
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
|
||||
|
||||
.idea/
|
||||
symon*.jar
|
||||
*.bin
|
||||
*.map
|
||||
@@ -0,0 +1,29 @@
|
||||
OUTPUT := example.bin
|
||||
TARGET_CPU := 65c02
|
||||
|
||||
MEM_MAP_FILE := $(OUTPUT:.bin=.map)
|
||||
|
||||
# Tool list
|
||||
CC65 := cc65
|
||||
CA65 := ca65
|
||||
LD65 := ld65
|
||||
CL65 := cl65
|
||||
|
||||
# Searches directly under src and one level under. If a file is under 2 folders
|
||||
#such as src/math/float/types.s, either one more level needs to be added, or
|
||||
#switch these to a shell find $(shell find src -name '*.s')
|
||||
C_SOURCES := $(wildcard src/*.c) $(wildcard src/*/*.s)
|
||||
ASM_SOURCES := $(wildcard src/*.s) $(wildcard src/*/*.s)
|
||||
OBJECTS := $(ASM_SOURCES:.s=.o)
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(OUTPUT)
|
||||
|
||||
$(OUTPUT): $(C_SOURCES) $(ASM_SOURCES)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CL65) -t none --cpu $(TARGET_CPU) -C computer.cfg -m $(MEM_MAP_FILE) -O -o $@ $^
|
||||
|
||||
clean:
|
||||
rm -f $(OBJECTS)
|
||||
rm -f $(OUTPUT)
|
||||
@@ -0,0 +1,4 @@
|
||||
# 65C02 Assembly Project Template
|
||||
|
||||
This template is based on the memory map for Mike42's computer/board. [Github](https://github.com/mike42/6502-computer/)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Physical Memory configuration
|
||||
MEMORY {
|
||||
ZP: start = $00, size = $0100, type = rw, file = "";
|
||||
RAM: start = $0200, size = $7d00, type = rw, file = "";
|
||||
PRG: start = $C000, size = $4000, type = ro, file = %O, fill = yes, fillval = $00;
|
||||
}
|
||||
|
||||
# In-Code Segment separators
|
||||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp;
|
||||
BSS: load = RAM, type = bss;
|
||||
CODE: load = PRG, type = ro, start = $C000;
|
||||
DATA: load = PRG, run = RAM, type = rw, define = yes;
|
||||
RODATA: load = PRG, type = ro;
|
||||
VECTORS: load = PRG, type = ro, start = $FFFA;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
.ifndef HARDWARE_INC
|
||||
HARDWARE_INC = 1
|
||||
|
||||
; CPU settings
|
||||
CPU_HZ = 1843200
|
||||
|
||||
; Serial/ACIA addresses
|
||||
SERIAL_DATA = $8400
|
||||
SERIAL_STATUS = $8401
|
||||
SERIAL_COMMAND = $8402
|
||||
SERIAL_CONTROL = $8403
|
||||
|
||||
; VIA addresses
|
||||
VIA_PORTB = $8000
|
||||
VIA_PORTA = $8001
|
||||
VIA_DDRB = $8002
|
||||
VIA_DDRA = $8003
|
||||
VIA_T1C_L = $8004
|
||||
VIA_T1C_H = $8005
|
||||
VIA_T1L_L = $8006
|
||||
VIA_T1L_H = $8007
|
||||
VIA_T2C_L = $8008
|
||||
VIA_T2C_H = $8009
|
||||
VIA_SR = $800a
|
||||
VIA_ACR = $800b
|
||||
VIA_PCR = $800c
|
||||
VIA_IFR = $800d
|
||||
VIA_IER = $800e
|
||||
VIA_PORTA_2 = $800f
|
||||
|
||||
.endif
|
||||
@@ -0,0 +1,90 @@
|
||||
; Serial port helper function
|
||||
; Serial is handled by the 65c51n (this thing has a few bugs)
|
||||
.export serial_setup, serial_recv_char, serial_print_char, serial_baud_19200, serial_baud_9600
|
||||
|
||||
.include "hardware.inc"
|
||||
|
||||
; -----------------------------
|
||||
; Active wait loop calculations
|
||||
; -----------------------------
|
||||
INNER_LOOP = 9 ; Inner loop count (sets granularity of the waiting period)
|
||||
|
||||
; cycles per outer pass: ldx(2) + innerLoop(5*INNER_LOOP-1) + dey(2) + bne(3)
|
||||
PASS_CYC = INNER_LOOP * 5 + 6
|
||||
|
||||
; passes for each 10bit frame (8N1), rounded up
|
||||
PASSES_19200 = (10 * CPU_HZ/19200 + PASS_CYC - 1) / PASS_CYC
|
||||
PASSES_9600 = (10 * CPU_HZ/9600 + PASS_CYC - 1) / PASS_CYC
|
||||
|
||||
.assert PASSES_9600 < 256, error, "CPU clock too fast for this delay; raise INNER_LOOP"
|
||||
|
||||
; ACIA control register presets: internal BAUD, 8N1
|
||||
SERIAL_CTRL_19200 = %00011111
|
||||
SERIAL_CTRL_9600 = %00011110
|
||||
; ||||````- 19200/9600 baud
|
||||
; |||`----- Receiver clock is baud rate
|
||||
; |``------ 8bit word
|
||||
; `-------- 1 stop bit
|
||||
|
||||
; -----------------------------
|
||||
; -----------------------------
|
||||
|
||||
.zeropage
|
||||
tx_passes: .res 1 ; Variable to store outer loop passes
|
||||
|
||||
.code
|
||||
serial_setup:
|
||||
; 65c51n has a few bugs. check http://forum.6502.org/viewtopic.php?f=4&t=2543&start=30#p29795
|
||||
lda #$00
|
||||
sta SERIAL_STATUS ; Write to the status register for program reset
|
||||
|
||||
lda #$0b ; %0000 1011
|
||||
sta SERIAL_COMMAND ; || |||`- Data terminal ready (DTRB low)
|
||||
; || ||`-- IRQB disabled
|
||||
; || ``--- RTSB low, transmit interrupt disabled
|
||||
; |`------ Receiver normal mode
|
||||
; `------- Parity disabled
|
||||
|
||||
jsr serial_baud_19200
|
||||
rts
|
||||
|
||||
serial_baud_19200:
|
||||
lda #SERIAL_CTRL_19200
|
||||
sta SERIAL_CONTROL
|
||||
lda #PASSES_19200
|
||||
sta tx_passes
|
||||
rts
|
||||
|
||||
serial_baud_9600:
|
||||
lda #SERIAL_CTRL_9600
|
||||
sta SERIAL_CONTROL
|
||||
lda #PASSES_9600
|
||||
sta tx_passes
|
||||
rts
|
||||
|
||||
serial_recv_char:
|
||||
lda SERIAL_STATUS ; read status
|
||||
and #$08 ; mask receive status flag
|
||||
beq serial_recv_char; if buffer is empty, loop
|
||||
lda SERIAL_DATA ; get byte
|
||||
rts
|
||||
|
||||
serial_print_char:
|
||||
sta SERIAL_DATA ; send character
|
||||
;fall through to the delay routine
|
||||
|
||||
serial_delay:
|
||||
phy ; save y reg
|
||||
phx ; save x register
|
||||
ldy tx_passes ; outer passes
|
||||
@ydelay:
|
||||
ldx #INNER_LOOP ; Init x register
|
||||
@xdelay: ; loop time was calculated above by the assembler
|
||||
dex ; decrement low index
|
||||
bne @xdelay ; loop back until x is 0
|
||||
dey ; decrement high
|
||||
bne @ydelay ; loop until y is 0
|
||||
@delay_done:
|
||||
plx ; return x
|
||||
ply ; return y
|
||||
rts
|
||||
@@ -0,0 +1 @@
|
||||
.include "hardware.inc"
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
.import serial_setup, serial_print_char, serial_recv_char
|
||||
.import copy_data
|
||||
|
||||
; ---------------
|
||||
; ZP
|
||||
; ---------------
|
||||
.zeropage
|
||||
; Zero-page variables ($0000 - $00ff)
|
||||
|
||||
; ---------------
|
||||
; BSS
|
||||
; ---------------
|
||||
.bss
|
||||
; RAM variables ($0200 - $7fff)
|
||||
|
||||
; ---------------
|
||||
; DATA
|
||||
; ---------------
|
||||
.data
|
||||
; Initialized RAM variables ($0200 - $7fff)
|
||||
|
||||
; ---------------
|
||||
; CODE
|
||||
; ---------------
|
||||
.code
|
||||
; Actual program code ($c000 - $fff9)
|
||||
reset: ; Program starts here
|
||||
; System setup
|
||||
sei ; disable interrupts while setting things up
|
||||
cld ; clear BCD mode flag (undefined on NMOS 6502, auto cleared on 65C02)
|
||||
ldx #$ff
|
||||
txs ; Reset stack pointer
|
||||
|
||||
jsr copy_data ; copy data variables from ROM to RAM
|
||||
|
||||
jsr serial_setup ; setup serial interface (65C51N). 19200 baud set as default
|
||||
|
||||
print_hello_world:
|
||||
ldx #0
|
||||
@loop:
|
||||
lda str_hello_world,x ; get char
|
||||
beq @end ; IF char is 0, done
|
||||
jsr serial_print_char ; send char to console
|
||||
inx ; increment x (next char)
|
||||
jmp @loop
|
||||
@end:
|
||||
jmp @end
|
||||
|
||||
|
||||
irq_handler: ; IRQ Handler
|
||||
rti ; Do nothing
|
||||
|
||||
nmi_handler: ; NMI handler
|
||||
rti ; Do nothing
|
||||
|
||||
|
||||
; ---------------
|
||||
; RODATA
|
||||
; ---------------
|
||||
.rodata
|
||||
; Constants
|
||||
str_hello_world: .asciiz "Hello, World!"
|
||||
|
||||
|
||||
; ---------------
|
||||
; VECTORS
|
||||
; ---------------
|
||||
.segment "VECTORS"
|
||||
; NMI, RESET and IRQ vectors
|
||||
.word nmi_handler
|
||||
.word reset
|
||||
.word irq_handler
|
||||
@@ -0,0 +1,46 @@
|
||||
.import __DATA_LOAD__, __DATA_RUN__, __DATA_SIZE__
|
||||
.export copy_data
|
||||
|
||||
.zeropage
|
||||
src: .res 2
|
||||
dst: .res 2
|
||||
|
||||
.code
|
||||
copy_data:
|
||||
; Copy data segment from ROM to final RAM location
|
||||
lda #<__DATA_LOAD__ ; get source address low byte
|
||||
sta src
|
||||
lda #>__DATA_LOAD__ ; get source address high byte
|
||||
sta src+1
|
||||
|
||||
lda #<__DATA_RUN__ ; get runtime final address low byte
|
||||
sta dst
|
||||
lda #>__DATA_RUN__ ; get runtime final address high byte
|
||||
sta dst+1
|
||||
|
||||
ldx #>__DATA_SIZE__ ; number of 256 byte pages to copy (high byte)
|
||||
beq @tail ; if no full pages to copy, skip
|
||||
ldy #0
|
||||
|
||||
@page:
|
||||
lda (src),y ; grab byte
|
||||
sta (dst),y ; store byte
|
||||
iny
|
||||
bne @page ; for 256 cycles
|
||||
inc src+1 ; increment source high byte (next memory page)
|
||||
inc dst+1 ; increment destination high byte (next memory page)
|
||||
dex ; decrement full pages counter
|
||||
bne @page ; if no more full pages, stop
|
||||
|
||||
@tail: ; copy remaining non full page
|
||||
ldy #0
|
||||
cpy #<__DATA_SIZE__ ; check if there is data to copy
|
||||
beq @done ; if no data, done
|
||||
@byte:
|
||||
lda (src),y
|
||||
sta (dst),y
|
||||
iny
|
||||
cpy #<__DATA_SIZE__ ; when y == __DATA_SIZE__, done
|
||||
bne @byte ; else, continue
|
||||
@done:
|
||||
rts
|
||||
Reference in new issue
Block a user