Compare commits

...

2 Commits

Author SHA1 Message Date
Kyle J Cardoza 0630e22e06 More work on hardware init. 2024-06-13 00:31:20 -04:00
Kyle J Cardoza 34a91aa205 Cleanup 2024-06-10 18:39:17 -04:00
11 changed files with 306 additions and 144 deletions

View File

@ -12,12 +12,7 @@ ASFLAGS := -I include \
MPFLAGS := -p SST39LF040@PLCC32
SOURCES := src/memory.s \
src/boot.s \
src/irq.s \
src/led.s \
src/vera.s \
src/main.s
SOURCES := $(wildcard src/*.s)
INCLUDES := $(wildcard include/*.i)

View File

@ -1,20 +1,20 @@
AUTO_INC_NONE = $000000
AUTO_INC_1 = $100000
AUTO_INC_2 = $200000
AUTO_INC_4 = $300000
AUTO_INC_8 = $400000
AUTO_INC_16 = $500000
AUTO_INC_32 = $600000
AUTO_INC_64 = $700000
AUTO_INC_128 = $800000
AUTO_INC_256 = $900000
AUTO_INC_512 = $A00000
AUTO_INC_40 = $B00000
AUTO_INC_80 = $C00000
AUTO_INC_160 = $D00000
AUTO_INC_320 = $E00000
AUTO_INC_640 = $F00000
AUTO_INC_NONE = $00
AUTO_INC_1 = $01
AUTO_INC_2 = $02
AUTO_INC_4 = $03
AUTO_INC_8 = $04
AUTO_INC_16 = $05
AUTO_INC_32 = $06
AUTO_INC_64 = $07
AUTO_INC_128 = $08
AUTO_INC_256 = $09
AUTO_INC_512 = $0A
AUTO_INC_40 = $0B
AUTO_INC_80 = $0C
AUTO_INC_160 = $0D
AUTO_INC_320 = $0E
AUTO_INC_640 = $0F
DISABLED = 0
ENABLED = 1
@ -117,13 +117,7 @@ VERA_SPRITE_ATTR_BASE = $1FC00
; vpoke
; writes an immediate byte to a given register
vpoke .macro reg, value
php
rep #$20
.al
pha
sep #$20
.as
.save_registers
lda #\value
sta \reg
@ -134,27 +128,61 @@ vpoke .macro reg, value
plp
.endmacro
; vera_address_set - sets the address registers to the passed in value
vera_address_set .macro addr
php
rep #$20
.al
; vera_address_select - selects the active VERA address register
; Selecting 0 means that the address registers control the address
; accessed by VERA_DATA0, while selecting 1 means controlling the
; address for VERA_DATA1.
vera_address_select .macro value
pha
sep #$20
.as
lda #(\value & %00000001)
tsb VERA_CTRL
lda #\addr & $ff
pla
.endmacro
; vera_address_set - sets the address registers to the passed in value
vera_address_set .macro addr
pha
lda #>\addr
sta VERA_ADDRx_L
lda #(\addr >> 8) & $ff
lda #<\addr
sta VERA_ADDRx_M
lda #(\addr >> 16) & $ff
lda #`\addr
sta VERA_ADDRx_H
rep #$20
.al
pla
plp
.endmacro
.endmacro
; vera_address_incr - set the VERA address auto-increment.
vera_address_incr .macro increment
pha
; Clear the top four bits of ADDRx_H (increment value and decrement bit)
lda #%11111000
trb VERA_ADDRx_H
; Set the new value
lda #\increment << 4
tsb VERA_ADDRx_H
pla
.endmacro
; vera_address_decr - set the VERA address auto-decrement.
vera_address_decr .macro decrement
pha
; Clear the top five bits of ADDRx_H
lda #%11110000
trb VERA_ADDRx_H
; Set the new value (and the decrement bit)
lda #(\increment << 4) | %00001000
tsb VERA_ADDRx_H
pla
.endmacro

View File

@ -2,16 +2,15 @@ PD0 = $00DF00
PD1 = $00DF01
PD2 = $00DF02
PD3 = $00DF03
PD4 = $00DF20
PD5 = $00DF21
PD6 = $00DF22
PD7 = $00DF23
PDD0 = $00DF04
PDD1 = $00DF05
PDD2 = $00DF06
PDD3 = $00DF07
PD4 = $00DF20
PD5 = $00DF21
PD6 = $00DF22
PD7 = $00DF23
PDD4 = $00DF24
PDD5 = $00DF25
PDD6 = $00DF26
@ -93,13 +92,13 @@ w65c265s_sram_off .macro
; Disable the on-CPU ROM
w65c265s_rom_off .macro
lda #%10000000
lda #1 << 7
tsb BCR
.endmacro
; Enable the on-CPU ROM
w65c265s_rom_on .macro
lda #%10000000
lda #1 << 7
trb BCR
.endmacro

View File

@ -45,21 +45,20 @@ restore_registers .macro
.long_i
.endmacro
; Copies up to 64KB (aligned to bank boundaries)
memcpy .macro dest, src, count
.save_registers
.long_a
.long_i
ldx #<>src
ldy #<>dest
lda #count - 1
ldx #<>\src
ldy #<>\dest
lda #\count - 1
.if dest > src
mvp #`src, #`dest
.if \dest > \src
mvp #`\src, #`\dest
.else
mvn #`src, #`dest
mvn #`\src, #`\dest
.endif
.restore_registers
.short_a
.long_i
.endmacro

View File

@ -7,10 +7,25 @@
w65c265s_init .proc
; Disable standard interrupts
sei
.short_a
.long_i
; We reset the VERA at boot. So P4.2 is an output, held
; low until later in the boot sequence.
lda #1 << 2
trb PD4
tsb PDD4
; Now we delay a while.
ldy #$0FFF
delay_y
dey
bne delay_y
; Set stack to $001FF
ldx #$01FF
txs
; Set data bank to 0
lda #0
pha
@ -22,13 +37,13 @@ w65c265s_init .proc
pld
.dpage $0000
; Set stack to $001FF
ldx #$01FF
txs
; Enable all used chip select lines.
; Enable all the in-use chip select lines.
lda #%11110011
sta PCS7
stz UIER
stz TIER
stz EIER
; Jump to entry point.
jml main

48
src/controller.s Normal file
View File

@ -0,0 +1,48 @@
.section kernel
; The controller ports are mapped to GPIO pins:
;
; CLK: P5.0
; LATCH: P5.1
; DATA0: P5.2
; DATA1: P5.3
;
; The protocol supports gamepads, mice, and keyboards.
;
; Gamepads are the simplest. They report two bytes each,
; which is sufficient to represent all the buttons on the
; pads.
;
; Mice report four bytes. The most significant bit is delivered
; first:
;
; 76543210 First byte
; ++++++++- Always zero: 00000000
;
; 76543210 Second byte
; ||||++++- Signature: 0001
; ||++----- Current sensitivity (0: low; 1: medium; 2: high)
; |+------- Left button (1: pressed)
; +-------- Right button (1: pressed)
;
; 76543210 Third byte
; |+++++++- Vertical displacement since last read
; +-------- Direction (1: up; 0: down)
;
; 76543210 Fourth byte
; |+++++++- Horizontal displacement since last read
; +-------- Direction (1: left; 0: right)
;
; Keyboards report two bytes:
;
; 76543210 First byte
; |+++++++- Keyboard scan code
; +-------- Ctrl key state (1: up; 0: down)
;
; 76543210 Second byte
; ||||++++- Signature: 0011
; |||+----- Shift key state (1: up; 0: down)
; |+------- Option key state (1: up; 0: down)
; +-------- Command key state (1: up; 0: down)
.endsection kernel

105
src/irq.s
View File

@ -1,7 +1,28 @@
; The code in this sections irq_vectors and irq_handlers will be copied
; to RAM, to fill the IRQ vector table and IRQ handler routines. As an
; optimization, we reserve the right to use trampoline code to move the
; bulk of the IRQ handling code out of bank 0.
.section irq_handlers
.logical $008100
.logical $00FE00
empty_irq_handler .proc
rti
.endproc
virq_handler .proc
phb
phd
.long_a
.long_i
pha
phx
phy
jmp irq_exit
.endproc
cop_handler .proc
phb
phd
.long_a
@ -33,38 +54,54 @@ irq_exit .proc
.section irq_vectors
.logical $00FF80
.addr empty_irq_handler ; Timer 0 (Native Mode)
.addr empty_irq_handler ; Timer 1 (Native Mode)
.addr empty_irq_handler ; Timer 2 (Native Mode)
.addr empty_irq_handler ; Timer 3 (Native Mode)
.addr empty_irq_handler ; Timer 4 (Native Mode)
.addr empty_irq_handler ; Timer 5 (Native Mode)
.addr empty_irq_handler ; Timer 6 (Native Mode)
.addr empty_irq_handler ; Timer 7 (Native Mode)
.addr empty_irq_handler ; PE56 (Native Mode)
.addr empty_irq_handler ; NE57 (Native Mode)
.addr empty_irq_handler ; PE60 (Native Mode)
.addr empty_irq_handler ; PE62 (Native Mode)
.addr empty_irq_handler ; NE64 (Native Mode)
.addr empty_irq_handler ; NE66 (Native Mode)
.addr empty_irq_handler ; PIB (Native Mode)
.addr empty_irq_handler ; IRQ (Native Mode)
.addr empty_irq_handler ; UART0 RX (Native Mode)
.addr empty_irq_handler ; UART0 TX (Native Mode)
.addr empty_irq_handler ; UART1 RX (Native Mode)
.addr empty_irq_handler ; UART1 TX (Native Mode)
.addr empty_irq_handler ; UART2 RX (Native Mode)
.addr empty_irq_handler ; UART2 TX (Native Mode)
.addr empty_irq_handler ; UART3 RX (Native Mode)
.addr empty_irq_handler ; UART3 TX (Native Mode)
.addr empty_irq_handler ; RESERVED
.addr empty_irq_handler ; RESERVED
.addr empty_irq_handler ; COP (Native Mode)
.addr empty_irq_handler ; BRK (Native Mode)
.addr empty_irq_handler ; ABORT (Native Mode)
.addr nmi_handler ; NMI (Native Mode)
.addr empty_irq_handler ; RESERVED
.addr empty_irq_handler ; RESERVED
.addr <>empty_irq_handler ; Timer 0 (Native Mode)
.addr <>empty_irq_handler ; Timer 1 (Native Mode)
.addr <>empty_irq_handler ; Timer 2 (Native Mode)
.addr <>empty_irq_handler ; Timer 3 (Native Mode)
.addr <>empty_irq_handler ; Timer 4 (Native Mode)
.addr <>empty_irq_handler ; Timer 5 (Native Mode)
.addr <>empty_irq_handler ; Timer 6 (Native Mode)
.addr <>empty_irq_handler ; Timer 7 (Native Mode)
.addr <>empty_irq_handler ; PE56 (Native Mode)
.addr <>empty_irq_handler ; NE57 (Native Mode)
.addr <>empty_irq_handler ; PE60 (Native Mode)
.addr <>empty_irq_handler ; PE62 (Native Mode)
.addr <>virq_handler ; NE64/VERA IRQ (Native Mode)
.addr <>empty_irq_handler ; NE66 (Native Mode)
.addr <>empty_irq_handler ; PIB (Native Mode)
.addr <>empty_irq_handler ; IRQ (Native Mode)
.addr <>empty_irq_handler ; UART0 RX (Native Mode)
.addr <>empty_irq_handler ; UART0 TX (Native Mode)
.addr <>empty_irq_handler ; UART1 RX (Native Mode)
.addr <>empty_irq_handler ; UART1 TX (Native Mode)
.addr <>empty_irq_handler ; UART2 RX (Native Mode)
.addr <>empty_irq_handler ; UART2 TX (Native Mode)
.addr <>empty_irq_handler ; UART3 RX (Native Mode)
.addr <>empty_irq_handler ; UART3 TX (Native Mode)
.addr <>empty_irq_handler ; RESERVED
.addr <>empty_irq_handler ; RESERVED
.addr <>cop_handler ; COP (Native Mode)
.addr <>empty_irq_handler ; BRK (Native Mode)
.addr <>empty_irq_handler ; ABORT (Native Mode)
.addr <>nmi_handler ; NMI (Native Mode)
.addr <>empty_irq_handler ; RESERVED
.addr <>empty_irq_handler ; RESERVED
.fill 64, $EA
.endlogical
.endsection irq_vectors
.endsection irq_vectors
.section kernel
; Copy the IRQ vectors and handlers into RAM
irq_init .proc
.save_registers
.memcpy $00FE00, $00FE00, $200
.restore_registers
rtl
.endproc
.endsection kernel

View File

@ -2,16 +2,18 @@
led_init .proc
.save_registers
.short_a
.long_i
; Set P5.4 and P5.5 as output
lda #%00110000
trb PDD5
tsb PDD5
trb PD5
; Set P6.1 as output
lda #%00000010
trb PDD6
tsb PDD6
trb PD6
.restore_registers
rtl
@ -19,8 +21,6 @@ led_init .proc
led_red_on .proc
.save_registers
.short_a
.long_i
lda #%00010000
tsb PD5
@ -31,8 +31,6 @@ led_red_on .proc
led_red_off .proc
.save_registers
.short_a
.long_i
lda #%00010000
trb PD5
@ -43,8 +41,6 @@ led_red_off .proc
led_green_on .proc
.save_registers
.short_a
.long_i
lda #%00100000
tsb PD5
@ -55,10 +51,8 @@ led_green_on .proc
led_green_off .proc
.save_registers
.short_a
.long_i
lda #%00100000code
lda #%00100000
trb PD5
.restore_registers
@ -67,8 +61,6 @@ led_green_off .proc
led_blue_on .proc
.save_registers
.short_a
.long_i
lda #%00000010
tsb PD6
@ -79,8 +71,6 @@ led_blue_on .proc
led_blue_off .proc
.save_registers
.short_a
.long_i
lda #%00000010
trb PD6
@ -91,8 +81,6 @@ led_blue_off .proc
led_blink_red .proc
.save_registers
.short_a
.long_i
jsl led_red_on
@ -101,14 +89,15 @@ led_blink_red .proc
jsl led_red_off
ldx #02
jsl delay
.restore_registers
rtl
.endproc
led_blink_green .proc
.save_registers
.short_a
.long_i
jsl led_green_on
@ -117,14 +106,15 @@ led_blink_green .proc
jsl led_green_off
ldx #02
jsl delay
.restore_registers
rtl
.endproc
led_blink_blue .proc
.save_registers
.short_a
.long_i
jsl led_blue_on
@ -133,6 +123,9 @@ led_blink_blue .proc
jsl led_blue_off
ldx #02
jsl delay
.restore_registers
rtl
.endproc

View File

@ -1,43 +1,38 @@
.section kernel
main .proc
.page $FFFF
.short_a
.long_i
.fclk_start
.fclk_select
.w65c265s_rom_off
; Disable secondary interrupt sources
stz UIER
stz TIER
stz EIER
jsl irq_init
; Disable all timers
stz TER
; Disable /CS4; This frees the RAM from $008000-$00FDFF for
; user code. $00FE00-$00FFFF is for the IRQ vectors and
; trampolines.
lda #1 << 4
trb PCS7
.fclk_select
; Enable the /NMI input with BCR6 = 1
lda #1 << 6
tsb BCR
jsl led_init
jsl led_blink_red
; Initialize the VERA
jsl vera_init
idle:
wai
jsl led_blink_red
jsl led_blink_green
jsl led_blink_blue
bra idle
.endpage
.endproc
; Delay X times.
delay .proc
.save_registers
.short_a
.long_i
phy
loop_x
ldy #$FFFF

View File

@ -29,10 +29,10 @@
.dsection boot
.cerror * > $C08100
.fill $C08100 - *, $EA
* = $C08100
.fill $C0FE00 - *, $EA
* = $C0FE00
.dsection irq_handlers
.cerror * > $C08200
.cerror * > $C0FF80
.fill $C0FF80 - *, $EA
* = $C0FF80

View File

@ -1,10 +1,63 @@
.section kernel
vera_init .proc
pha
.save_registers
pla
jsl vera_reset
.restore_registers
rtl
.endproc
.endsection kernel
; Resetting the VERA seems to be causing a crash, possibly due to it putting
; noise on the address and/or data bus while it boots. So, we copy a little
; routine into the 512 bytes of RAM on the CPU, jump to that, and do the
; reset from there with the external address/data buses disabled temporarily.
vera_reset .proc
.save_registers
; Copy the routine to low memory
.memcpy $000100, vera_reset_low, size(vera_reset_low)
; Call the copied routine
jsl $000100
.restore_registers
rtl
.endproc
; This is the routine that gets copied to on-CPU SRAM.
vera_reset_low .proc
.logical $000100
.save_registers
; If we get this far, we are in the CPU's on-chip SRAM, so the next step
; is to disable the external address bus with BCR0 = 0
lda #%00000001
trb BCR
; Now we let the FPGA configure itself by bringing its reset line high
; with P4.2 = 1
lda #1 << 2
tsb PD4
; Now we delay a while as the FPGA re-combobulates itself.
ldx #150; Value dialed in by manual testing.
delay_x
ldy #$FFFF
delay_y
dey
bne delay_y
dex
bne delay_x
; Before we return, we re-enable the external address bus with BCR0 = 1
lda #%00000001
tsb BCR
.restore_registers
rtl
.endlogical
.endproc
.endsection kernel