Template
Overhaul the template.
- DATA and RODATA segments added to computer.cfg - RAM memory configuration now starts at to not overwrite the cpu stack - hardware.inc added to handle hardware related constants - constants removed from via.s - constants removed from serial.s - serial_delay from serial.s is now dynamic, dependant on CPU_HZ and baud rate - serial_baud_* functions added to setup 19200 and 9600 baud - mem_copy.s added. data copy functions are to be implemented here - copy_data (mem_copy.s) implemented to copy the DATA segment from ROM to RAM - propper system setup in main.s - Makefile now generates a .map file with the memory map information
This commit is contained in:
1 parent
a8caf9db75
commit
3801459e1e
8 files changed
+202
-73
No files matched your search
@@ -31,3 +31,6 @@ bin/
|
|||||||
|
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
|
symon*.jar
|
||||||
|
*.bin
|
||||||
|
*.map
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
OUTPUT := example.bin
|
OUTPUT := example.bin
|
||||||
TARGET_CPU := 65c02
|
TARGET_CPU := 65c02
|
||||||
|
|
||||||
|
MEM_MAP_FILE := $(OUTPUT:.bin=.map)
|
||||||
|
|
||||||
# Tool list
|
# Tool list
|
||||||
CC65 := cc65
|
CC65 := cc65
|
||||||
CA65 := ca65
|
CA65 := ca65
|
||||||
@@ -20,7 +22,7 @@ all: $(OUTPUT)
|
|||||||
|
|
||||||
$(OUTPUT): $(C_SOURCES) $(ASM_SOURCES)
|
$(OUTPUT): $(C_SOURCES) $(ASM_SOURCES)
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(CL65) -t none --cpu $(TARGET_CPU) -C computer.cfg -O -o $@ $^
|
$(CL65) -t none --cpu $(TARGET_CPU) -C computer.cfg -m $(MEM_MAP_FILE) -O -o $@ $^
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJECTS)
|
rm -f $(OBJECTS)
|
||||||
|
|||||||
+3
-1
@@ -1,7 +1,7 @@
|
|||||||
# Physical Memory configuration
|
# Physical Memory configuration
|
||||||
MEMORY {
|
MEMORY {
|
||||||
ZP: start = $00, size = $0100, type = rw, file = "";
|
ZP: start = $00, size = $0100, type = rw, file = "";
|
||||||
RAM: start = $0100, size = $7e00, type = rw, file = "";
|
RAM: start = $0200, size = $7d00, type = rw, file = "";
|
||||||
PRG: start = $C000, size = $4000, type = ro, file = %O, fill = yes, fillval = $00;
|
PRG: start = $C000, size = $4000, type = ro, file = %O, fill = yes, fillval = $00;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10,5 +10,7 @@ SEGMENTS {
|
|||||||
ZEROPAGE: load = ZP, type = zp;
|
ZEROPAGE: load = ZP, type = zp;
|
||||||
BSS: load = RAM, type = bss;
|
BSS: load = RAM, type = bss;
|
||||||
CODE: load = PRG, type = ro, start = $C000;
|
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;
|
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
|
||||||
+59
-29
@@ -1,14 +1,38 @@
|
|||||||
; Serial port helper function
|
; Serial port helper function
|
||||||
; Serial is handled by the 65c51n (this thing has a few bugs)
|
; Serial is handled by the 65c51n (this thing has a few bugs)
|
||||||
.export serial_setup
|
.export serial_setup, serial_recv_char, serial_print_char, serial_baud_19200, serial_baud_9600
|
||||||
.export serial_recv_char
|
|
||||||
.export serial_print_char
|
|
||||||
|
|
||||||
SERIAL_DATA = $8400
|
.include "hardware.inc"
|
||||||
SERIAL_STATUS = $8401
|
|
||||||
SERIAL_COMMAND = $8402
|
|
||||||
SERIAL_CONTROL = $8403
|
|
||||||
|
|
||||||
|
; -----------------------------
|
||||||
|
; 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:
|
serial_setup:
|
||||||
; 65c51n has a few bugs. check http://forum.6502.org/viewtopic.php?f=4&t=2543&start=30#p29795
|
; 65c51n has a few bugs. check http://forum.6502.org/viewtopic.php?f=4&t=2543&start=30#p29795
|
||||||
lda #$00
|
lda #$00
|
||||||
@@ -21,19 +45,21 @@ serial_setup:
|
|||||||
; |`------ Receiver normal mode
|
; |`------ Receiver normal mode
|
||||||
; `------- Parity disabled
|
; `------- Parity disabled
|
||||||
|
|
||||||
lda #$1f ; %0001 1111
|
jsr serial_baud_19200
|
||||||
sta SERIAL_CONTROL ; |||| ````- 19200 baud
|
|
||||||
; |||`------ Receiver clock is baud rate
|
|
||||||
; |``------- 8bit word
|
|
||||||
; `--------- 1 stop bit
|
|
||||||
rts
|
rts
|
||||||
|
|
||||||
serial_print_char:
|
serial_baud_19200:
|
||||||
pha ; Save A to stack (character)
|
lda #SERIAL_CTRL_19200
|
||||||
lda SERIAL_STATUS ; read status register and ignore the value
|
sta SERIAL_CONTROL
|
||||||
pla ; return character from stack
|
lda #PASSES_19200
|
||||||
sta SERIAL_DATA ; send character
|
sta tx_passes
|
||||||
jsr serial_delay ; comment out for older 6551/65c51
|
rts
|
||||||
|
|
||||||
|
serial_baud_9600:
|
||||||
|
lda #SERIAL_CTRL_9600
|
||||||
|
sta SERIAL_CONTROL
|
||||||
|
lda #PASSES_9600
|
||||||
|
sta tx_passes
|
||||||
rts
|
rts
|
||||||
|
|
||||||
serial_recv_char:
|
serial_recv_char:
|
||||||
@@ -43,18 +69,22 @@ serial_recv_char:
|
|||||||
lda SERIAL_DATA ; get byte
|
lda SERIAL_DATA ; get byte
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
serial_print_char:
|
||||||
|
sta SERIAL_DATA ; send character
|
||||||
|
;fall through to the delay routine
|
||||||
|
|
||||||
serial_delay:
|
serial_delay:
|
||||||
phy ; save y reg
|
phy ; save y reg
|
||||||
phx ; save x register
|
phx ; save x register
|
||||||
ldy #6 ; delay value (clock rate in mhz 2 clock cycles)
|
ldy tx_passes ; outer passes
|
||||||
@ydelay:
|
@ydelay:
|
||||||
ldx #$68 ; Init x register
|
ldx #INNER_LOOP ; Init x register
|
||||||
@xdelay:
|
@xdelay: ; loop time was calculated above by the assembler
|
||||||
dex ; decrement low index
|
dex ; decrement low index
|
||||||
bne @xdelay ; loop back until x is 0
|
bne @xdelay ; loop back until x is 0
|
||||||
dey ; decrement high
|
dey ; decrement high
|
||||||
bne @ydelay ; loop until y is 0
|
bne @ydelay ; loop until y is 0
|
||||||
@delay_done:
|
@delay_done:
|
||||||
plx ; return x
|
plx ; return x
|
||||||
ply ; return y
|
ply ; return y
|
||||||
rts
|
rts
|
||||||
+1
-18
@@ -1,18 +1 @@
|
|||||||
; Addresses for the VIA 65c22
|
.include "hardware.inc"
|
||||||
|
|
||||||
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
|
|
||||||
+56
-24
@@ -1,40 +1,72 @@
|
|||||||
.import serial_setup
|
.import serial_setup, serial_print_char, serial_recv_char
|
||||||
.import serial_print_char
|
.import copy_data
|
||||||
|
|
||||||
.segment "ZEROPAGE"
|
; ---------------
|
||||||
|
; ZP
|
||||||
|
; ---------------
|
||||||
|
.zeropage
|
||||||
; Zero-page variables ($0000 - $00ff)
|
; Zero-page variables ($0000 - $00ff)
|
||||||
|
|
||||||
.segment "BSS"
|
; ---------------
|
||||||
; RAM variables ($0100 - $7fff)
|
; BSS
|
||||||
|
; ---------------
|
||||||
|
.bss
|
||||||
|
; RAM variables ($0200 - $7fff)
|
||||||
|
|
||||||
.segment "CODE"
|
; ---------------
|
||||||
|
; DATA
|
||||||
|
; ---------------
|
||||||
|
.data
|
||||||
|
; Initialized RAM variables ($0200 - $7fff)
|
||||||
|
|
||||||
|
; ---------------
|
||||||
|
; CODE
|
||||||
|
; ---------------
|
||||||
|
.code
|
||||||
; Actual program code ($c000 - $fff9)
|
; 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
|
||||||
|
|
||||||
reset: ; Program starts here
|
jsr copy_data ; copy data variables from ROM to RAM
|
||||||
jsr serial_setup
|
|
||||||
|
|
||||||
|
jsr serial_setup ; setup serial interface (65C51N). 19200 baud set as default
|
||||||
|
|
||||||
|
print_hello_world:
|
||||||
ldx #0
|
ldx #0
|
||||||
hello_world_loop:
|
@loop:
|
||||||
lda str_hello_world,x ; get char
|
lda str_hello_world,x ; get char
|
||||||
beq hello_world_end ; IF char is 0, done
|
beq @end ; IF char is 0, done
|
||||||
jsr serial_print_char ; send char to console
|
jsr serial_print_char ; send char to console
|
||||||
inx ; increment x (next char)
|
inx ; increment x (next char)
|
||||||
jmp hello_world_loop
|
jmp @loop
|
||||||
hello_world_end:
|
@end:
|
||||||
jmp hello_world_end
|
jmp @end
|
||||||
|
|
||||||
|
|
||||||
irq: ; IRQ Handler
|
irq_handler: ; IRQ Handler
|
||||||
rti ; Do nothing
|
rti ; Do nothing
|
||||||
|
|
||||||
nmi: ; NMI handler
|
nmi_handler: ; NMI handler
|
||||||
rti ; Do nothing
|
rti ; Do nothing
|
||||||
|
|
||||||
str_hello_world:
|
|
||||||
.asciiz "Hello, World!"
|
|
||||||
|
|
||||||
|
; ---------------
|
||||||
|
; RODATA
|
||||||
|
; ---------------
|
||||||
|
.rodata
|
||||||
|
; Constants
|
||||||
|
str_hello_world: .asciiz "Hello, World!"
|
||||||
|
|
||||||
|
|
||||||
|
; ---------------
|
||||||
|
; VECTORS
|
||||||
|
; ---------------
|
||||||
.segment "VECTORS"
|
.segment "VECTORS"
|
||||||
; NMI, RESET and IRQ vectors
|
; NMI, RESET and IRQ vectors
|
||||||
.word nmi
|
.word nmi_handler
|
||||||
.word reset
|
.word reset
|
||||||
.word irq
|
.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