From 3801459e1e822db07d93f56b0de276ab9d24f3f7 Mon Sep 17 00:00:00 2001 From: RuiFPB Date: Tue, 29 Sep 2026 12:13:24 +0100 Subject: [PATCH] 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 --- .gitignore | 5 ++- Makefile | 4 +- computer.cfg | 4 +- src/hardware/hardware.inc | 31 ++++++++++++++ src/hardware/serial.s | 88 ++++++++++++++++++++++++++------------- src/hardware/via.s | 19 +-------- src/main.s | 80 ++++++++++++++++++++++++----------- src/mem_copy.s | 46 ++++++++++++++++++++ 8 files changed, 203 insertions(+), 74 deletions(-) create mode 100644 src/hardware/hardware.inc create mode 100644 src/mem_copy.s diff --git a/.gitignore b/.gitignore index 93e0b6d..f5eab68 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,7 @@ bin/ .DS_Store -.idea/ \ No newline at end of file +.idea/ +symon*.jar +*.bin +*.map \ No newline at end of file diff --git a/Makefile b/Makefile index fee836d..9bc07d0 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ OUTPUT := example.bin TARGET_CPU := 65c02 +MEM_MAP_FILE := $(OUTPUT:.bin=.map) + # Tool list CC65 := cc65 CA65 := ca65 @@ -20,7 +22,7 @@ all: $(OUTPUT) $(OUTPUT): $(C_SOURCES) $(ASM_SOURCES) @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: rm -f $(OBJECTS) diff --git a/computer.cfg b/computer.cfg index d7e60b7..c93fa5c 100644 --- a/computer.cfg +++ b/computer.cfg @@ -1,7 +1,7 @@ # Physical Memory configuration MEMORY { 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; } @@ -10,5 +10,7 @@ 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; } \ No newline at end of file diff --git a/src/hardware/hardware.inc b/src/hardware/hardware.inc new file mode 100644 index 0000000..131d024 --- /dev/null +++ b/src/hardware/hardware.inc @@ -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 \ No newline at end of file diff --git a/src/hardware/serial.s b/src/hardware/serial.s index cbc858d..392e1c5 100644 --- a/src/hardware/serial.s +++ b/src/hardware/serial.s @@ -1,14 +1,38 @@ ; Serial port helper function ; Serial is handled by the 65c51n (this thing has a few bugs) -.export serial_setup -.export serial_recv_char -.export serial_print_char +.export serial_setup, serial_recv_char, serial_print_char, serial_baud_19200, serial_baud_9600 -SERIAL_DATA = $8400 -SERIAL_STATUS = $8401 -SERIAL_COMMAND = $8402 -SERIAL_CONTROL = $8403 +.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 @@ -21,19 +45,21 @@ serial_setup: ; |`------ Receiver normal mode ; `------- Parity disabled - lda #$1f ; %0001 1111 - sta SERIAL_CONTROL ; |||| ````- 19200 baud - ; |||`------ Receiver clock is baud rate - ; |``------- 8bit word - ; `--------- 1 stop bit + jsr serial_baud_19200 rts -serial_print_char: - pha ; Save A to stack (character) - lda SERIAL_STATUS ; read status register and ignore the value - pla ; return character from stack - sta SERIAL_DATA ; send character - jsr serial_delay ; comment out for older 6551/65c51 +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: @@ -43,18 +69,22 @@ serial_recv_char: 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 #6 ; delay value (clock rate in mhz 2 clock cycles) + phy ; save y reg + phx ; save x register + ldy tx_passes ; outer passes @ydelay: - ldx #$68 ; Init x register -@xdelay: - dex ; decrement low index - bne @xdelay ; loop back until x is 0 - dey ; decrement high - bne @ydelay ; loop until y is 0 + 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 + plx ; return x + ply ; return y rts diff --git a/src/hardware/via.s b/src/hardware/via.s index b31819a..f87e278 100644 --- a/src/hardware/via.s +++ b/src/hardware/via.s @@ -1,18 +1 @@ -; Addresses for the VIA 65c22 - -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 \ No newline at end of file +.include "hardware.inc" \ No newline at end of file diff --git a/src/main.s b/src/main.s index e85d4e4..ab2f3bf 100644 --- a/src/main.s +++ b/src/main.s @@ -1,40 +1,72 @@ -.import serial_setup -.import serial_print_char +.import serial_setup, serial_print_char, serial_recv_char +.import copy_data -.segment "ZEROPAGE" +; --------------- +; ZP +; --------------- +.zeropage ; 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) +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 serial_setup + 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 -hello_world_loop: - lda str_hello_world,x ; get char - beq hello_world_end ; IF char is 0, done - jsr serial_print_char ; send char to console - inx ; increment x (next char) - jmp hello_world_loop -hello_world_end: - jmp hello_world_end +@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: ; IRQ Handler - rti ; Do nothing +irq_handler: ; IRQ Handler + rti ; Do nothing -nmi: ; NMI handler - rti ; Do nothing +nmi_handler: ; NMI handler + rti ; Do nothing -str_hello_world: -.asciiz "Hello, World!" +; --------------- +; RODATA +; --------------- +.rodata +; Constants +str_hello_world: .asciiz "Hello, World!" + + +; --------------- +; VECTORS +; --------------- .segment "VECTORS" ; NMI, RESET and IRQ vectors -.word nmi +.word nmi_handler .word reset -.word irq \ No newline at end of file +.word irq_handler \ No newline at end of file diff --git a/src/mem_copy.s b/src/mem_copy.s new file mode 100644 index 0000000..dfe06c2 --- /dev/null +++ b/src/mem_copy.s @@ -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 \ No newline at end of file