kopia lustrzana https://github.com/hoglet67/RGBtoHDMI
854 wiersze
28 KiB
ArmAsm
854 wiersze
28 KiB
ArmAsm
.macro LINE_TIMEOUT_TEST
|
|
READ_CYCLE_COUNTER r8
|
|
subs r8, r8, r14
|
|
rsbmi r8, r8, #0
|
|
cmp r8, #LINE_TIMEOUT
|
|
// Read the GPLEV0
|
|
ldr r8, [r4]
|
|
eorgt r8, r8, #CSYNC_MASK //inverting the value after the timeout will cause the test to pass
|
|
tst r8, #CSYNC_MASK
|
|
.endm
|
|
|
|
.macro LINE_TIMEOUT_TEST_R9
|
|
READ_CYCLE_COUNTER r8
|
|
subs r8, r8, r14
|
|
rsbmi r8, r8, #0
|
|
cmp r8, #LINE_TIMEOUT
|
|
// Read the GPLEV0
|
|
ldr r8, [r4]
|
|
eorgt r8, r8, #CSYNC_MASK //inverting the value after the timeout will cause the test to pass
|
|
cmp r9, #0
|
|
tstne r8, #CSYNC_MASK
|
|
.endm
|
|
|
|
.macro WAIT_FOR_CSYNC_0
|
|
READ_CYCLE_COUNTER r14
|
|
waitlo\@:
|
|
LINE_TIMEOUT_TEST
|
|
bne waitlo\@
|
|
LINE_TIMEOUT_TEST
|
|
bne waitlo\@
|
|
.endm
|
|
|
|
.macro WAIT_FOR_CSYNC_0_R9
|
|
READ_CYCLE_COUNTER r14
|
|
waitlo9\@:
|
|
LINE_TIMEOUT_TEST_R9
|
|
bne waitlo9\@
|
|
LINE_TIMEOUT_TEST_R9
|
|
bne waitlo9\@
|
|
.endm
|
|
|
|
.macro WAIT_FOR_CSYNC_0_FAST_R9
|
|
READ_CYCLE_COUNTER r14
|
|
waitloF\@:
|
|
LINE_TIMEOUT_TEST_R9
|
|
bne waitloF\@
|
|
.endm
|
|
|
|
.macro WAIT_FOR_CSYNC_1
|
|
READ_CYCLE_COUNTER r14
|
|
waithi\@:
|
|
LINE_TIMEOUT_TEST
|
|
beq waithi\@
|
|
LINE_TIMEOUT_TEST
|
|
beq waithi\@
|
|
.endm
|
|
|
|
.macro WAIT_FOR_CSYNC_1_FAST
|
|
READ_CYCLE_COUNTER r14
|
|
waithiF\@:
|
|
LINE_TIMEOUT_TEST
|
|
beq waithiF\@
|
|
.endm
|
|
|
|
.macro SWITCH_PSYNC_TO_VSYNC
|
|
ldr r8, =GPCLR0
|
|
mov r9, #1 << VERSION_PIN
|
|
str r9, [r8] // set version = 0
|
|
.endm
|
|
|
|
.macro SWITCH_VSYNC_TO_PSYNC
|
|
ldr r8, =GPSET0
|
|
mov r9, #1 << VERSION_PIN
|
|
str r9, [r8] // set version = 1
|
|
.endm
|
|
|
|
// Wait for the next edge on psync
|
|
// if r3 bit 17 = 0 - wait for falling edge
|
|
// if r3 bit 17 = 1 - wait for rising edge
|
|
.macro WAIT_FOR_PSYNC_EDGE
|
|
wait\@:
|
|
// Read the GPLEV0
|
|
ldr r8, [r4]
|
|
eor r8, r3
|
|
tst r8, #PSYNC_MASK
|
|
bne wait\@
|
|
|
|
// Read a second time to capture stable data
|
|
// This is executed only if CPLD is V1 or V2
|
|
tst r3, #BIT_OLD_FIRMWARE_SUPPORT
|
|
ldrne r8, [r4]
|
|
eorne r8, r3
|
|
tstne r8, #PSYNC_MASK
|
|
bne wait\@
|
|
|
|
// toggle the polarity to look for the opposite edge next time
|
|
eor r8, r3 // restore r8 value
|
|
eor r3, #PSYNC_MASK
|
|
.endm
|
|
|
|
.macro WAIT_FOR_PSYNC_EDGE_FAST
|
|
waitPF\@:
|
|
// Read the GPLEV0
|
|
ldr r8, [r4]
|
|
eor r8, r3
|
|
tst r8, #PSYNC_MASK
|
|
bne waitPF\@
|
|
|
|
// toggle the polarity to look for the opposite edge next time
|
|
eor r8, r3 // restore r8 value
|
|
eor r3, #PSYNC_MASK
|
|
.endm
|
|
|
|
.macro SKIP_PSYNC
|
|
// called if 4 bits per pixel in non-fast mode so has support for old CPLV v1 & v2
|
|
WAIT_FOR_CSYNC_0_R9
|
|
READ_CYCLE_COUNTER r10
|
|
bic r3, r3, #PSYNC_MASK // wait for zero after CSYNC
|
|
// Wait for the end of hsync
|
|
WAIT_FOR_CSYNC_1
|
|
READ_CYCLE_COUNTER r14
|
|
// Calculate length of low hsync pulse (in ARM cycles = ns)
|
|
subs r10, r14, r10
|
|
rsbmi r10, r10, #0
|
|
|
|
// Start with the configured horizontal offset
|
|
// Implement half character horizontal scrolling:
|
|
// - a "short" hsync is 3.5us, leave h_offset as-is
|
|
// - a "normal" hsync is 4.0us, increment h_offset by 1
|
|
// - a "long" hsync is 4.5us, increment h_offset by 2
|
|
// So test against two thresholds inbetween these values
|
|
|
|
// old CPLD V1 & V2 code
|
|
mov r9, r7
|
|
cmp r10, #(4000 + 224)
|
|
addgt r9, r9, #1
|
|
cmp r10, #(4000 - 224)
|
|
addgt r9, r9, #1
|
|
|
|
// new CPLD V3 or later code
|
|
mov r8, r7
|
|
cmp r10, #(4000 + 224)
|
|
addlt r8, r8, #1
|
|
cmp r10, #(4000 - 224)
|
|
addlt r8, r8, #1
|
|
|
|
tst r3, #BIT_OLD_FIRMWARE_SUPPORT
|
|
movne r8, r9
|
|
|
|
tst r3, #BIT_NO_H_SCROLL
|
|
moveq r7, r8 // only allow fine sideways scrolling in bbc / electron mode (causes timing issues in ega mode)
|
|
// Skip the configured number of psync edges (modes 0..6: edges every 250ns, mode 7: edges ever 333ns)
|
|
skip_psync_loop\@:
|
|
WAIT_FOR_PSYNC_EDGE // wait for next edge of psync
|
|
subs r7, r7, #1
|
|
bne skip_psync_loop\@
|
|
.endm
|
|
|
|
.macro SKIP_PSYNC_NO_OLD_CPLD
|
|
// only called if 6 bits/pixel in non-fast mode (old CPLDs v1 & v2 don't work at 6bpp so no need for test)
|
|
WAIT_FOR_CSYNC_0_FAST_R9
|
|
READ_CYCLE_COUNTER r10
|
|
bic r3, r3, #PSYNC_MASK // wait for zero after CSYNC
|
|
// Wait for the end of hsync
|
|
WAIT_FOR_CSYNC_1_FAST
|
|
READ_CYCLE_COUNTER r14
|
|
// Calculate length of low hsync pulse (in ARM cycles = ns)
|
|
subs r10, r14, r10
|
|
rsbmi r10, r10, #0
|
|
// Calculate length of low hsync pulse (in ARM cycles = ns)
|
|
// Start with the configured horizontal offset
|
|
// Implement half character horizontal scrolling:
|
|
// - a "short" hsync is 3.5us, leave h_offset as-is
|
|
// - a "normal" hsync is 4.0us, increment h_offset by 1
|
|
// - a "long" hsync is 4.5us, increment h_offset by 2
|
|
// So test against two thresholds inbetween these values
|
|
|
|
// new CPLD code only (not called from CPLD v1 & v2)
|
|
mov r8, r7
|
|
cmp r10, #(4000 + 224)
|
|
addlt r8, r8, #1
|
|
cmp r10, #(4000 - 224)
|
|
addlt r8, r8, #1
|
|
|
|
tst r3, #BIT_NO_H_SCROLL
|
|
moveq r7, r8 // only allow fine sideways scrolling in bbc / electron mode (causes timing issues in ega mode)
|
|
// Skip the configured number of psync edges (modes 0..6: edges every 250ns, mode 7: edges ever 333ns)
|
|
skip_psync_loop_no_old\@:
|
|
WAIT_FOR_PSYNC_EDGE_FAST // wait for next edge of psync
|
|
subs r7, r7, #1
|
|
bne skip_psync_loop_no_old\@
|
|
.endm
|
|
|
|
.macro SKIP_PSYNC_NO_H_SCROLL
|
|
// only called if in fast mode (both 3 & 6 bpp) - fast mode never called from old CPLDs v1 & v2
|
|
WAIT_FOR_CSYNC_0_FAST_R9
|
|
bic r3, r3, #PSYNC_MASK // wait for zero after CSYNC
|
|
WAIT_FOR_CSYNC_1_FAST
|
|
READ_CYCLE_COUNTER r14
|
|
skip_psync_loop_no_h_scroll\@:
|
|
WAIT_FOR_PSYNC_EDGE_FAST // wait for next edge of psync
|
|
subs r7, r7, #1
|
|
bne skip_psync_loop_no_h_scroll\@
|
|
.endm
|
|
|
|
.macro CAPTURE_LOW_BITS
|
|
// Pixel 0 in GPIO 4.. 2 -> 7.. 4
|
|
// Pixel 1 in GPIO 7.. 5 -> 3.. 0
|
|
// Pixel 2 in GPIO 10.. 8 -> 15..12
|
|
// Pixel 3 in GPIO 13..11 -> 11.. 8
|
|
|
|
and r10, r8, #(7 << PIXEL_BASE)
|
|
and r9, r8, #(7 << (PIXEL_BASE + 3))
|
|
mov r10, r10, lsl #(4 - PIXEL_BASE)
|
|
orr r10, r10, r9, lsr #(3 + PIXEL_BASE)
|
|
|
|
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
|
and r8, r8, #(7 << (PIXEL_BASE + 9))
|
|
orr r10, r10, r9, lsl #(6 - PIXEL_BASE)
|
|
orr r10, r10, r8, lsr #(1 + PIXEL_BASE)
|
|
.endm
|
|
|
|
.macro CAPTURE_HIGH_BITS
|
|
// Pixel 4 in GPIO 4.. 2 -> 23..20
|
|
// Pixel 5 in GPIO 7.. 5 -> 19..16
|
|
// Pixel 6 in GPIO 10.. 8 -> 31..28
|
|
// Pixel 7 in GPIO 13..11 -> 27..24
|
|
|
|
and r9, r8, #(7 << PIXEL_BASE)
|
|
and r14, r8, #(7 << (PIXEL_BASE + 3))
|
|
orr r10, r10, r9, lsl #(20 - PIXEL_BASE)
|
|
orr r10, r10, r14, lsl #(13 - PIXEL_BASE)
|
|
|
|
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
|
and r8, r8, #(7 << (PIXEL_BASE + 9))
|
|
orr r10, r10, r9, lsl #(22 - PIXEL_BASE)
|
|
orr r10, r10, r8, lsl #(15 - PIXEL_BASE)
|
|
.endm
|
|
|
|
.macro CAPTURE_LOW_BITS_NORMAL reg
|
|
// Pixel 0 in GPIO 4.. 2 -> 7.. 4
|
|
// Pixel 1 in GPIO 7.. 5 -> 3.. 0
|
|
// Pixel 2 in GPIO 10.. 8 -> 15..12
|
|
// Pixel 3 in GPIO 13..11 -> 11.. 8
|
|
|
|
and r9, r8, #(7 << PIXEL_BASE)
|
|
and r14, r8, #(7 << (PIXEL_BASE + 3))
|
|
eor r10, \reg, r9, lsl #(4 - PIXEL_BASE)
|
|
eor r10, r10, r14, lsr #(3 + PIXEL_BASE)
|
|
|
|
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
|
and r14, r8, #(7 << (PIXEL_BASE + 9))
|
|
eor r10, r10, r9, lsl #(6 - PIXEL_BASE)
|
|
eor r10, r10, r14, lsr #(1 + PIXEL_BASE)
|
|
.endm
|
|
|
|
.macro CAPTURE_HIGH_BITS_NORMAL reg
|
|
// Pixel 4 in GPIO 4.. 2 -> 23..20
|
|
// Pixel 5 in GPIO 7.. 5 -> 19..16
|
|
// Pixel 6 in GPIO 10.. 8 -> 31..28
|
|
// Pixel 7 in GPIO 13..11 -> 27..24
|
|
|
|
and r9, r8, #(7 << PIXEL_BASE)
|
|
and r14, r8, #(7 << (PIXEL_BASE + 3))
|
|
eor r10, r10, r9, lsl #(20 - PIXEL_BASE)
|
|
eor r10, r10, r14, lsl #(13 - PIXEL_BASE)
|
|
|
|
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
|
and r14, r8, #(7 << (PIXEL_BASE + 9))
|
|
eor r10, r10, r9, lsl #(22 - PIXEL_BASE)
|
|
eor \reg, r10, r14, lsl #(15 - PIXEL_BASE)
|
|
.endm
|
|
|
|
.macro CAPTURE_BITS_DOUBLE reg reg2
|
|
// Pixel 0 in GPIO 4.. 2 -> 7.. 4 and 3.. 0
|
|
// Pixel 1 in GPIO 7.. 5 -> 15..12 and 11.. 8
|
|
// Pixel 2 in GPIO 10.. 8 -> 23..20 and 19..16
|
|
// Pixel 3 in GPIO 13..11 -> 31..28 and 27..24
|
|
|
|
and r9, r8, #(7 << PIXEL_BASE)
|
|
and r14, r8, #(7 << (PIXEL_BASE + 3))
|
|
eor r10, \reg, r9, lsl #(4 - PIXEL_BASE)
|
|
eor r10, r10, r14, lsl #(12 - (PIXEL_BASE + 3))
|
|
|
|
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
|
and r14, r8, #(7 << (PIXEL_BASE + 9))
|
|
eor r10, r10, r9, lsl #(20 - (PIXEL_BASE + 6))
|
|
eor r10, r10, r14, lsl #(28 - (PIXEL_BASE + 9))
|
|
|
|
// Pixel double
|
|
orr \reg2, r10, r10, lsr #4
|
|
.endm
|
|
|
|
.macro CAPTURE_0_BITS_WIDE reg
|
|
// Pixel 0 in GPIO 7.. 2 -> 7.. 4
|
|
// Pixel 1 in GPIO 13.. 8 -> 3.. 0
|
|
|
|
and r9, r8, #(0x07 << PIXEL_BASE)
|
|
and r14, r8, #(0x07 << (PIXEL_BASE + 6))
|
|
eor r10, \reg, r9, lsl #(4 - PIXEL_BASE)
|
|
eor r10, r10, r14, lsr #(6 + PIXEL_BASE)
|
|
.endm
|
|
|
|
.macro CAPTURE_1_BITS_WIDE
|
|
// Pixel 0 in GPIO 7.. 2 -> 15.. 12
|
|
// Pixel 1 in GPIO 13.. 8 -> 11.. 8
|
|
|
|
and r9, r8, #(0x07 << (PIXEL_BASE))
|
|
and r14, r8, #(0x07 << (PIXEL_BASE + 6))
|
|
eor r10, r10, r9, lsl #(12 - PIXEL_BASE)
|
|
eor r10, r10, r14, lsr #(2 - PIXEL_BASE)
|
|
.endm
|
|
|
|
.macro CAPTURE_2_BITS_WIDE
|
|
// Pixel 4 in GPIO 7.. 2 -> 23..20
|
|
// Pixel 5 in GPIO 13.. 8 -> 19..16
|
|
and r9, r8, #(0x07 << PIXEL_BASE)
|
|
and r14, r8, #(0x07 << (PIXEL_BASE + 6))
|
|
eor r10, r10, r9, lsl #(20 - PIXEL_BASE)
|
|
eor r10, r10, r14, lsl #(10 - PIXEL_BASE)
|
|
.endm
|
|
|
|
.macro CAPTURE_3_BITS_WIDE reg
|
|
// Pixel 6 in GPIO 7.. 2 -> 31..28
|
|
// Pixel 7 in GPIO 13..8 -> 27..24
|
|
and r9, r8, #(0x07 << PIXEL_BASE)
|
|
and r14, r8, #(0x07 << (PIXEL_BASE + 6))
|
|
eor r10, r10, r9, lsl #(28 - PIXEL_BASE)
|
|
eor \reg, r10, r14, lsl #(18 - PIXEL_BASE)
|
|
.endm
|
|
|
|
.macro CAPTURE_LOW_BITS_DOUBLE_WIDE reg
|
|
// Pixel 0 in GPIO 7.. 2 -> 7.. 4
|
|
// Pixel 1 in GPIO 13.. 8 -> 15.. 12
|
|
|
|
and r9, r8, #(0x07 << PIXEL_BASE)
|
|
and r14, r8, #(0x07 << (PIXEL_BASE + 6))
|
|
eor r10, \reg, r9, lsl #(4 - PIXEL_BASE)
|
|
eor r10, r10, r14, lsl #(2 + PIXEL_BASE)
|
|
.endm
|
|
|
|
.macro CAPTURE_HIGH_BITS_DOUBLE_WIDE reg
|
|
// Pixel 2 in GPIO 7.. 2 -> 23..20
|
|
// Pixel 3 in GPIO 13.. 8 -> 31..28
|
|
and r9, r8, #(0x07 << PIXEL_BASE)
|
|
and r14, r8, #(0x07 << (PIXEL_BASE + 6))
|
|
eor r10, r10, r9, lsl #(20 - PIXEL_BASE)
|
|
eor r10, r10, r14, lsl #(22 - PIXEL_BASE)
|
|
|
|
// Pixel double
|
|
orr \reg, r10, r10, lsr #4
|
|
.endm
|
|
|
|
.macro CAPTURE_BITS_8BPP
|
|
// Pixel 0 in GPIO 4.. 2 -> 7.. 0
|
|
// Pixel 1 in GPIO 7.. 5 -> 15.. 8
|
|
// Pixel 2 in GPIO 10.. 8 -> 23..16
|
|
// Pixel 3 in GPIO 13..11 -> 31..24
|
|
|
|
and r10, r8, #(7 << PIXEL_BASE)
|
|
and r9, r8, #(7 << (PIXEL_BASE + 3))
|
|
mov r10, r10, lsr #(PIXEL_BASE)
|
|
orr r10, r10, r9, lsl #(8 - (PIXEL_BASE + 3))
|
|
|
|
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
|
and r8, r8, #(7 << (PIXEL_BASE + 9))
|
|
orr r10, r10, r9, lsl #(16 - (PIXEL_BASE + 6))
|
|
orr r10, r10, r8, lsl #(24 - (PIXEL_BASE + 9))
|
|
.endm
|
|
|
|
.macro CAPTURE_BITS_8BPP_NORMAL reg reg2
|
|
// Pixel 0 in GPIO 4.. 2 -> 7.. 0
|
|
// Pixel 1 in GPIO 7.. 5 -> 15.. 8
|
|
// Pixel 2 in GPIO 10.. 8 -> 23..16
|
|
// Pixel 3 in GPIO 13..11 -> 31..24
|
|
|
|
and r9, r8, #(7 << PIXEL_BASE)
|
|
and r14, r8, #(7 << (PIXEL_BASE + 3))
|
|
eor r10, \reg, r9, lsr #(PIXEL_BASE)
|
|
eor r10, r10, r14, lsl #(8 - (PIXEL_BASE + 3))
|
|
|
|
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
|
and r14, r8, #(7 << (PIXEL_BASE + 9))
|
|
eor r10, r10, r9, lsl #(16 - (PIXEL_BASE + 6))
|
|
eor \reg2, r10, r14, lsl #(24 - (PIXEL_BASE + 9))
|
|
.endm
|
|
|
|
.macro CAPTURE_LOW_BITS_DOUBLE_8BPP reg reg2
|
|
// Pixel 0 in GPIO 7.. 2 -> 7.. 0
|
|
// Pixel 1 in GPIO 13.. 8 -> 23..16
|
|
|
|
and r9, r8, #(7 << PIXEL_BASE)
|
|
and r14, r8, #(7 << (PIXEL_BASE + 3))
|
|
eor r10, \reg, r9, lsr #(PIXEL_BASE)
|
|
eor r10, r10, r14, lsl #(16 - (PIXEL_BASE + 3))
|
|
// Pixel double
|
|
orr \reg2, r10, r10, lsl #8
|
|
.endm
|
|
|
|
.macro CAPTURE_HIGH_BITS_DOUBLE_8BPP reg reg2
|
|
// Pixel 2 in GPIO 7.. 2 -> 7.. 0
|
|
// Pixel 3 in GPIO 13.. 8 -> 23..16
|
|
|
|
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
|
and r14, r8, #(7 << (PIXEL_BASE + 9))
|
|
eor r10, \reg, r9, lsr #(PIXEL_BASE + 6)
|
|
eor r10, r10, r14, lsl #(16 - (PIXEL_BASE + 9))
|
|
// Pixel double
|
|
orr \reg2, r10, r10, lsl #8
|
|
.endm
|
|
|
|
.macro CAPTURE_LOW_BITS_8BPP_WIDE reg
|
|
// Pixel 0 in GPIO 7.. 2 -> 7.. 0
|
|
// Pixel 1 in GPIO 13.. 8 -> 15.. 8
|
|
|
|
and r9, r8, #(0x3f << PIXEL_BASE)
|
|
and r14, r8, #(0x3f << (PIXEL_BASE + 6))
|
|
eor r10, \reg, r9, lsr #(PIXEL_BASE)
|
|
eor r10, r10, r14, lsl #(8 - (PIXEL_BASE + 6))
|
|
.endm
|
|
|
|
.macro CAPTURE_HIGH_BITS_8BPP_WIDE reg
|
|
// Pixel 2 in GPIO 7.. 2 -> 23..16
|
|
// Pixel 3 in GPIO 13.. 8 -> 31..24
|
|
|
|
and r9, r8, #(0x3f << PIXEL_BASE)
|
|
and r14, r8, #(0x3f << (PIXEL_BASE + 6))
|
|
eor r10, r10, r9, lsl #(16 - PIXEL_BASE)
|
|
eor \reg, r10, r14, lsl #(24 - (PIXEL_BASE + 6))
|
|
.endm
|
|
|
|
.macro CAPTURE_BITS_DOUBLE_8BPP_WIDE reg reg2
|
|
// Pixel 0 in GPIO 7.. 2 -> 7.. 0
|
|
// Pixel 1 in GPIO 13.. 8 -> 23..16
|
|
|
|
and r9, r8, #(0x3f << PIXEL_BASE)
|
|
and r14, r8, #(0x3f << (PIXEL_BASE + 6))
|
|
eor r10, \reg, r9, lsr #(PIXEL_BASE)
|
|
eor r10, r10, r14, lsl #(16 - (PIXEL_BASE + 6))
|
|
// Pixel double
|
|
orr \reg2, r10, r10, lsl #8
|
|
.endm
|
|
|
|
.macro CAPTURE_LOW_BITS_TRANSLATE
|
|
// Pixel 0 in GPIO 4.. 2 -> 7.. 4
|
|
// Pixel 1 in GPIO 7.. 5 -> 3.. 0
|
|
// Pixel 2 in GPIO 10.. 8 -> 15..12
|
|
// Pixel 3 in GPIO 13..11 -> 11.. 8
|
|
|
|
and r10, r8, #(7 << PIXEL_BASE)
|
|
and r9, r8, #(7 << (PIXEL_BASE + 3))
|
|
mov r10, r10, lsl #(4 - PIXEL_BASE)
|
|
orr r10, r10, r9, lsr #(3 + PIXEL_BASE)
|
|
|
|
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
|
and r8, r8, #(7 << (PIXEL_BASE + 9))
|
|
orr r10, r10, r9, lsl #(6 - PIXEL_BASE)
|
|
orr r10, r10, r8, lsr #(1 + PIXEL_BASE)
|
|
|
|
mov r6, r6, lsl #8 // mode 0 sentinel
|
|
mov r7, r7, lsl #2 // mode 0-6 sentinel
|
|
mov r14, #0 // mode 2 translation
|
|
|
|
tst r10, #0x00000070
|
|
orrne r14, r14, #0x08
|
|
orrne r6, r6, #0x80
|
|
tst r10, #0x00000007
|
|
orrne r14, r14, #0x080000
|
|
orrne r6, r6, #0x40
|
|
tst r10, #0x00007000
|
|
orrne r14, r14, #0x04
|
|
orrne r6, r6, #0x20
|
|
tst r10, #0x00000700
|
|
orrne r14, r14, #0x040000
|
|
orrne r6, r6, #0x10
|
|
orrne r7, r7, #2
|
|
.endm
|
|
|
|
.macro CAPTURE_HIGH_BITS_TRANSLATE
|
|
// Pixel 4 in GPIO 4.. 2 -> 23..20
|
|
// Pixel 5 in GPIO 7.. 5 -> 19..16
|
|
// Pixel 6 in GPIO 10.. 8 -> 31..28
|
|
// Pixel 7 in GPIO 13..11 -> 27..24
|
|
|
|
and r9, r8, #(7 << PIXEL_BASE) // this block unoptimised to free up r14
|
|
orr r10, r10, r9, lsl #(20 - PIXEL_BASE)
|
|
and r9, r8, #(7 << (PIXEL_BASE + 3))
|
|
orr r10, r10, r9, lsl #(13 - PIXEL_BASE)
|
|
|
|
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
|
and r8, r8, #(7 << (PIXEL_BASE + 9))
|
|
orr r10, r10, r9, lsl #(22 - PIXEL_BASE)
|
|
orr r10, r10, r8, lsl #(15 - PIXEL_BASE)
|
|
|
|
tst r10, #0x00700000
|
|
orrne r14, r14, #0x02
|
|
orrne r6, r6, #0x08
|
|
tst r10, #0x00070000
|
|
orrne r14, r14, #0x020000
|
|
orrne r6, r6, #0x04
|
|
tst r10, #0x70000000
|
|
orrne r14, r14, #0x01
|
|
orrne r6, r6, #0x02
|
|
tst r10, #0x07000000
|
|
orrne r14, r14, #0x010000
|
|
orrne r6, r6, #0x01
|
|
orrne r7, r7, #1
|
|
|
|
tst r3, #BITDUP_MODE2_16COLOUR
|
|
orrne r10, r14, r14, lsl #4
|
|
orrne r10, r10, r10, lsl #8
|
|
|
|
.endm
|
|
|
|
.macro CAPTURE_LOW_BITS_TRANSLATE_8BPP
|
|
// Pixel 0 in GPIO 4.. 2 -> 7.. 0
|
|
// Pixel 1 in GPIO 7.. 5 -> 15.. 8
|
|
// Pixel 2 in GPIO 10.. 8 -> 23..16
|
|
// Pixel 3 in GPIO 13..11 -> 31..24
|
|
|
|
and r5, r8, #(7 << PIXEL_BASE)
|
|
and r9, r8, #(7 << (PIXEL_BASE + 3))
|
|
mov r5, r5, lsr #(PIXEL_BASE)
|
|
orr r5, r5, r9, lsl #(8 - (PIXEL_BASE + 3))
|
|
|
|
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
|
and r8, r8, #(7 << (PIXEL_BASE + 9))
|
|
orr r5, r5, r9, lsl #(16 - (PIXEL_BASE + 6))
|
|
orr r5, r5, r8, lsl #(24 - (PIXEL_BASE + 9))
|
|
|
|
mov r6, r6, lsl #8 // mode 0 sentinel
|
|
mov r7, r7, lsl #2 // mode 0-6 sentinel
|
|
mov r14, #0 // mode 2 translation (low byte = left pixel, high byte = right pixel
|
|
tst r5, #0x00000007
|
|
orrne r14, r14, #0x08
|
|
orrne r6, r6, #0x80
|
|
tst r5, #0x00000700
|
|
orrne r14, r14, #0x08000000
|
|
orrne r6, r6, #0x40
|
|
tst r5, #0x00070000
|
|
orrne r14, r14, #0x04
|
|
orrne r6, r6, #0x20
|
|
tst r5, #0x07000000
|
|
orrne r14, r14, #0x04000000
|
|
orrne r6, r6, #0x10
|
|
orrne r7, r7, #2
|
|
.endm
|
|
|
|
.macro CAPTURE_HIGH_BITS_TRANSLATE_8BPP
|
|
// Pixel 0 in GPIO 4.. 2 -> 7.. 0
|
|
// Pixel 1 in GPIO 7.. 5 -> 15.. 8
|
|
// Pixel 2 in GPIO 10.. 8 -> 23..16
|
|
// Pixel 3 in GPIO 13..11 -> 31..24
|
|
|
|
and r10, r8, #(7 << PIXEL_BASE)
|
|
and r9, r8, #(7 << (PIXEL_BASE + 3))
|
|
mov r10, r10, lsr #(PIXEL_BASE)
|
|
orr r10, r10, r9, lsl #(8 - (PIXEL_BASE + 3))
|
|
|
|
and r9, r8, #(7 << (PIXEL_BASE + 6))
|
|
and r8, r8, #(7 << (PIXEL_BASE + 9))
|
|
orr r10, r10, r9, lsl #(16 - (PIXEL_BASE + 6))
|
|
orr r10, r10, r8, lsl #(24 - (PIXEL_BASE + 9))
|
|
|
|
tst r10, #0x00000007
|
|
orrne r14, r14, #0x02
|
|
orrne r6, r6, #0x08
|
|
tst r10, #0x00000700
|
|
orrne r14, r14, #0x02000000
|
|
orrne r6, r6, #0x04
|
|
tst r10, #0x00070000
|
|
orrne r14, r14, #0x01
|
|
orrne r6, r6, #0x02
|
|
tst r10, #0x07000000
|
|
orrne r14, r14, #0x01000000
|
|
orrne r6, r6, #0x01
|
|
orrne r7, r7, #1
|
|
|
|
tst r3, #BITDUP_MODE2_16COLOUR
|
|
moveq r9, r5
|
|
andne r9, r14, #0xff
|
|
orrne r9, r9, r9, lsl #8
|
|
orrne r9, r9, r9, lsl #16
|
|
andne r10, r14, #0xff000000
|
|
orrne r10, r10, r10, lsr #8
|
|
orrne r10, r10, r10, lsr #16
|
|
.endm
|
|
|
|
.macro SETUP_VSYNC_DEBUG_R11
|
|
tst r3, #BIT_VSYNC_MARKER
|
|
ldrne r11, =0x11111111
|
|
moveq r11, #0
|
|
tst r3, #BIT_DEBUG
|
|
eorne r11, r11, #0x50 //magenta in leftmost
|
|
eorne r11, r11, #0x02000000 //green in rightmost
|
|
.endm
|
|
|
|
.macro SETUP_VSYNC_DEBUG_R11_DOUBLE
|
|
tst r3, #BIT_VSYNC_MARKER
|
|
ldrne r11, =0x10101010
|
|
moveq r11, #0
|
|
tst r3, #BIT_DEBUG
|
|
eorne r11, r11, #0x50 //magenta in leftmost
|
|
eorne r11, r11, #0x20000000 //green in rightmost << 4
|
|
.endm
|
|
|
|
.macro WRITE_R7_IF_LAST
|
|
cmp r1, #1
|
|
stmeqia r0, {r7}
|
|
tsteq r3, #BIT_NO_SCANLINES | BIT_OSD | BIT_NO_LINE_DOUBLE
|
|
ldreq r8, =0x88888888
|
|
orreq r7, r7, r8
|
|
cmp r1, #1
|
|
tsteq r3, #BIT_NO_LINE_DOUBLE
|
|
subeq r0, r0, r2
|
|
stmeqia r0, {r7}
|
|
.endm
|
|
|
|
.macro WRITE_R7_R10
|
|
stmia r0, {r7, r10}
|
|
tst r3, #BIT_NO_SCANLINES | BIT_OSD | BIT_NO_LINE_DOUBLE
|
|
ldreq r8, =0x88888888
|
|
orreq r7, r7, r8
|
|
orreq r10, r10, r8
|
|
tst r3, #BIT_NO_LINE_DOUBLE
|
|
subeq r0, r0, r2
|
|
stmeqia r0, {r7, r10}
|
|
addeq r0, r0, r2
|
|
add r0, r0, #8
|
|
.endm
|
|
|
|
.macro SETUP_VSYNC_DEBUG_R11_R12
|
|
tst r3, #BIT_VSYNC_MARKER
|
|
ldrne r11, =0x01010101
|
|
moveq r11, #0
|
|
movne r12, r11
|
|
moveq r12, #0
|
|
tst r3, #BIT_DEBUG
|
|
eorne r11, r11, #0x05 //magenta in leftmost
|
|
eorne r12, r12, #0x02000000 //green in rightmost
|
|
.endm
|
|
|
|
.macro SETUP_VSYNC_DEBUG_R11_R12_DOUBLE
|
|
tst r3, #BIT_VSYNC_MARKER
|
|
ldrne r11, =0x00010001
|
|
moveq r11, #0
|
|
movne r12, r11
|
|
moveq r12, #0
|
|
tst r3, #BIT_DEBUG
|
|
eorne r11, r11, #0x05 //magenta in leftmost
|
|
eorne r12, r12, #0x00020000 //green in rightmost >> 8
|
|
.endm
|
|
|
|
.macro WRITE_R5_R6_IF_LAST
|
|
cmp r1, #1
|
|
stmeqia r0, {r5, r6}
|
|
tsteq r3, #BIT_NO_SCANLINES | BIT_OSD | BIT_NO_LINE_DOUBLE
|
|
ldreq r8, =0x80808080
|
|
orreq r5, r5, r8
|
|
orreq r6, r6, r8
|
|
cmp r1, #1
|
|
tsteq r3, #BIT_NO_LINE_DOUBLE
|
|
subeq r0, r0, r2
|
|
stmeqia r0, {r5, r6}
|
|
.endm
|
|
|
|
.macro WRITE_R5_R6_R7_R10
|
|
stmia r0, {r5, r6, r7, r10}
|
|
tst r3, #BIT_NO_SCANLINES | BIT_OSD | BIT_NO_LINE_DOUBLE
|
|
ldreq r8, =0x80808080
|
|
orreq r5, r5, r8
|
|
orreq r6, r6, r8
|
|
orreq r7, r7, r8
|
|
orreq r10, r10, r8
|
|
tst r3, #BIT_NO_LINE_DOUBLE
|
|
subeq r0, r0, r2
|
|
stmeqia r0, {r5, r6, r7, r10}
|
|
addeq r0, r0, r2
|
|
add r0, r0, #16
|
|
.endm
|
|
|
|
|
|
|
|
|
|
.macro WRITE_WORD_FAST
|
|
eor r10, r10, r6 //eor in vsync and debug
|
|
str r10, [r0]
|
|
tst r3, #BIT_NO_SCANLINES | BIT_OSD | BIT_NO_LINE_DOUBLE
|
|
ldreq r8, =0x88888888
|
|
orreq r10, r10, r8
|
|
tst r3, #BIT_NO_LINE_DOUBLE
|
|
streq r10, [r0, -r2]
|
|
add r0, r0, #4
|
|
.endm
|
|
|
|
.macro WRITE_WORDS_8BPP_FAST
|
|
eor r9, r9, r5 //eor in vsync and debug
|
|
eor r10, r10, r6 //eor in vsync and debug
|
|
stmia r0, {r9, r10}
|
|
sub r0, r0, r2
|
|
tst r3, #BIT_NO_SCANLINES | BIT_OSD | BIT_NO_LINE_DOUBLE
|
|
ldreq r8, =0x80808080
|
|
orreq r9, r9, r8
|
|
orreq r10, r10, r8
|
|
tst r3, #BIT_NO_LINE_DOUBLE
|
|
stmeqia r0, {r9, r10}
|
|
add r0, r0, r2
|
|
add r0, r0, #8
|
|
.endm
|
|
|
|
.macro WRITE_WORD
|
|
tst r3, #BIT_VSYNC_MARKER
|
|
ldrne r8, =0x11111111
|
|
eorne r10, r10, r8 // eor in the VSync indicator (orr doesn't work on zx80/81 due to white screen)
|
|
tst r3, #BIT_DEBUG
|
|
eorne r10, r10, #0x50 //magenta in leftmost
|
|
eorne r10, r10, #0x02000000 //green in rightmost
|
|
str r10, [r0]
|
|
tst r3, #BIT_NO_SCANLINES | BIT_OSD | BIT_NO_LINE_DOUBLE
|
|
ldreq r8, =0x88888888
|
|
orreq r10, r10, r8
|
|
tst r3, #BIT_NO_LINE_DOUBLE
|
|
streq r10, [r0, -r2]
|
|
add r0, r0, #4
|
|
.endm
|
|
|
|
.macro WRITE_WORDS_8BPP
|
|
and r8, r3, #MASKDUP_PALETTE_HIGH_NIBBLE
|
|
mov r8, r8, lsr #(OFFSETDUP_PALETTE_HIGH_NIBBLE - 4)
|
|
orr r8, r8, r8, lsl #8
|
|
orr r8, r8, r8, lsl #16
|
|
orr r9, r9, r8
|
|
orr r10, r10, r8
|
|
tst r3, #BIT_VSYNC_MARKER
|
|
ldrne r8, =0x01010101
|
|
eorne r9, r9, r8 // eor in the VSync indicator (orr doesn't work on zx80/81 due to white screen)
|
|
eorne r10, r10, r8
|
|
tst r3, #BIT_DEBUG
|
|
eorne r9, r9, #0x05 //magenta in leftmost
|
|
eorne r10, r10, #0x02000000 //green in rightmost
|
|
stmia r0, {r9, r10}
|
|
sub r0, r0, r2
|
|
tst r3, #BIT_NO_SCANLINES | BIT_OSD | BIT_NO_LINE_DOUBLE
|
|
ldreq r8, =0x80808080
|
|
orreq r9, r9, r8
|
|
orreq r10, r10, r8
|
|
tst r3, #BIT_NO_LINE_DOUBLE
|
|
stmeqia r0, {r9, r10}
|
|
add r0, r0, r2
|
|
add r0, r0, #8
|
|
.endm
|
|
|
|
.macro SETUP_DUMMY_PARAMETERS
|
|
ldr r0, =(dummyscreen + 1024) //in case data written backwards
|
|
mov r1, #3
|
|
mov r2, #0
|
|
orr r3, r3, #BIT_VSYNC_MARKER // ensure that constants are in data cache
|
|
mov r5, #1
|
|
mov r6, #0
|
|
mov r7, #2
|
|
mov r8, #1
|
|
mov r9, #0 //force skip of wait for csync 0
|
|
.endm
|
|
|
|
// ======================================================================
|
|
// Macros
|
|
// ======================================================================
|
|
|
|
// Data Synchronisation Barrier
|
|
.macro DSB
|
|
mcr p15, 0, r0, c7, c10, 4
|
|
.endm
|
|
|
|
// Data Memory Barrier
|
|
.macro DMB
|
|
mcr p15, 0, r0, c7, c10, 5
|
|
.endm
|
|
|
|
.macro READ_CYCLE_COUNTER reg
|
|
#if defined(RPI2) || defined(RPI3)
|
|
mrc p15, 0, \reg, c9, c13, 0
|
|
#else
|
|
mrc p15, 0, \reg, c15, c12, 1
|
|
#endif
|
|
.endm
|
|
|
|
.macro CLEAR_VSYNC
|
|
// Clear the VSYNC interrupt
|
|
ldr r0, =SMICTRL
|
|
bic r3, r3, #BIT_VSYNC_MARKER
|
|
mov r7, #0
|
|
str r7, [r0]
|
|
// Don't proceed until this write is complete
|
|
DSB
|
|
.endm
|
|
|
|
.macro SHOW_VSYNC
|
|
bic r3, r3, #BIT_VSYNC_MARKER
|
|
tst r3, #(BIT_PROBE)
|
|
bne novsync\@
|
|
// Poll for the VSYNC interrupt
|
|
ldr r0, =INTPEND2
|
|
ldr r0, [r0]
|
|
tst r0, #(1<<VSYNCINT)
|
|
beq novsync\@
|
|
// Clear the VSYNC interrupt
|
|
CLEAR_VSYNC
|
|
// If the vsync indicator is enabled, mark the next line in red
|
|
tst r3, #(BIT_VSYNC)
|
|
orrne r3, r3, #BIT_VSYNC_MARKER
|
|
// Remember the line where vsync occurred
|
|
str r5, vsync_line
|
|
novsync\@:
|
|
.endm
|
|
|
|
#ifdef MULTI_BUFFER
|
|
.macro FLIP_BUFFER
|
|
// Skip the multi buffering in mode 7 and probe mode
|
|
tst r3, #(BIT_MODE7 | BIT_PROBE)
|
|
bne noflip\@
|
|
// Flip to the last completed draw buffer
|
|
// It seems the GPU delays this until the next vsync
|
|
push {r0-r3}
|
|
mov r14, r3, lsr #OFFSET_LAST_BUFFER
|
|
and r0, r14, #3
|
|
bl swapBuffer
|
|
pop {r0-r3}
|
|
noflip\@:
|
|
.endm
|
|
#endif
|
|
|
|
.macro KEY_PRESS_DETECT mask, ret, counter
|
|
ldr r5, \counter // Load the counter value
|
|
tst r8, #\mask // Is the button pressed (active low)?
|
|
movne r5, #0 // Clear the counter
|
|
addeq r5, r5, #1 // If pressed, then increment the counter valye
|
|
str r5, \counter // And always write back the counter value
|
|
|
|
cmp r5, #1 // Counter goes from 0->1 when key initially
|
|
orreq r0, #\ret // Indicate the initial press in the result
|
|
|
|
cmp r5, #32 // 32 = auto repeat delay
|
|
tstge r5, #7 // 7 = auto repeat rate
|
|
orreq r0, #\ret // Indicate the auto repeated press in the result
|
|
|
|
cmp r5, #128 // 128 = auto repeat delay
|
|
tstge r5, #3 // 3 = auto repeat rate
|
|
orreq r0, #\ret // Indicate the auto repeated press in the result
|
|
|
|
cmp r5, #256 // 256 = auto repeat delay
|
|
tstge r5, #1 // 1 = auto repeat rate
|
|
orreq r0, #\ret // Indicate the auto repeated press in the result
|
|
.endm
|