From 5ce83907ad100fcd1b70e263228706f12f6c30a8 Mon Sep 17 00:00:00 2001 From: IanSB Date: Tue, 28 Jul 2020 05:38:35 +0100 Subject: [PATCH] Further updates to 16BPP support --- src/CMakeLists.txt | 8 +- ...apture_line_default_eightbits_8bpp_16bpp.S | 14 +- ...line_default_eightbits_double_8bpp_16bpp.S | 36 +- src/capture_line_default_sixbits_8bpp_16bpp.S | 157 ++++ ...e_line_default_sixbits_double_8bpp_16bpp.S | 131 ++++ src/capture_line_fast_eightbits_8bpp_16bpp.S | 49 +- src/capture_line_fast_sixbits_8bpp_16bpp.S | 152 ++++ src/capture_line_ntsc_sixbits_8bpp.S | 697 ++++++++++++++++++ src/cpld.h | 6 +- src/cpld_atom.c | 2 +- src/cpld_rgb.c | 42 +- src/cpld_yuv.c | 2 +- src/geometry.c | 38 +- src/macros.S | 115 +-- src/osd.c | 13 +- src/rgb_to_fb.S | 55 +- src/rgb_to_hdmi.c | 49 +- 17 files changed, 1394 insertions(+), 172 deletions(-) create mode 100644 src/capture_line_default_sixbits_8bpp_16bpp.S create mode 100644 src/capture_line_default_sixbits_double_8bpp_16bpp.S create mode 100644 src/capture_line_fast_sixbits_8bpp_16bpp.S create mode 100644 src/capture_line_ntsc_sixbits_8bpp.S diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4df7f7fb..cc3c32f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -69,10 +69,10 @@ file( GLOB core_files capture_line_fast_4bpp_8bpp.S capture_line_oddeven_4bpp_8bpp.S capture_line_half_4bpp_8bpp.S - capture_line_default_sixbits_4bpp_8bpp.S - capture_line_default_sixbits_double_4bpp_8bpp.S - capture_line_ntsc_sixbits_4bpp_8bpp.S - capture_line_fast_sixbits_4bpp_8bpp.S + capture_line_default_sixbits_8bpp_16bpp.S + capture_line_default_sixbits_double_8bpp_16bpp.S + capture_line_ntsc_sixbits_8bpp.S + capture_line_fast_sixbits_8bpp_16bpp.S capture_line_default_eightbits_8bpp_16bpp.S capture_line_default_eightbits_double_8bpp_16bpp.S capture_line_fast_eightbits_8bpp_16bpp.S diff --git a/src/capture_line_default_eightbits_8bpp_16bpp.S b/src/capture_line_default_eightbits_8bpp_16bpp.S index 17f9cfb1..37de0629 100644 --- a/src/capture_line_default_eightbits_8bpp_16bpp.S +++ b/src/capture_line_default_eightbits_8bpp_16bpp.S @@ -6,7 +6,7 @@ .text .global capture_line_default_eightbits_8bpp -.global capture_line_default_twelvebits_16bpp +.global capture_line_default_eightbits_16bpp // The capture line function is provided the following: // r0 = pointer to current line in frame buffer @@ -31,7 +31,7 @@ capture_line_default_eightbits_8bpp: SETUP_VSYNC_DEBUG_R11_R12 SKIP_PSYNC_NO_OLD_CPLD push {r14} - SETUP_MASK_R14 + SETUP_EIGHT_BITS_MASK_R14 loop_8bpp: WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 CAPTURE_EIGHT_BITS_8BPP_0 r11 // input in r8 @@ -89,13 +89,13 @@ preload_capture_line_default_eightbits_8bpp: .ltorg // *** 16 bit *** - b preload_capture_line_default_twelvebits_16bpp -capture_line_default_twelvebits_16bpp: + b preload_capture_line_default_eightbits_16bpp +capture_line_default_eightbits_16bpp: push {lr} SETUP_VSYNC_DEBUG_R11_R12_DOUBLE SKIP_PSYNC_NO_OLD_CPLD push {r14} - SETUP_MASK_R14 + SETUP_TWELVE_BITS_MASK_R14 loop_16bpp: WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 CAPTURE_TWELVE_BITS_16BPP_LO r11 // input in r8 @@ -123,6 +123,6 @@ loop_16bpp: pop {r0, pc} -preload_capture_line_default_twelvebits_16bpp: +preload_capture_line_default_eightbits_16bpp: SETUP_DUMMY_PARAMETERS - b capture_line_default_twelvebits_16bpp + b capture_line_default_eightbits_16bpp diff --git a/src/capture_line_default_eightbits_double_8bpp_16bpp.S b/src/capture_line_default_eightbits_double_8bpp_16bpp.S index 8b6bc572..2b1d2971 100644 --- a/src/capture_line_default_eightbits_double_8bpp_16bpp.S +++ b/src/capture_line_default_eightbits_double_8bpp_16bpp.S @@ -6,7 +6,7 @@ .text .global capture_line_default_eightbits_double_8bpp -.global capture_line_default_twelvebits_double_16bpp +.global capture_line_default_eightbits_double_16bpp // The capture line function is provided the following: // r0 = pointer to current line in frame buffer @@ -31,7 +31,7 @@ capture_line_default_eightbits_double_8bpp: SETUP_VSYNC_DEBUG_R11_R12_DOUBLE SKIP_PSYNC_NO_OLD_CPLD push {r14} - SETUP_MASK_R14 + SETUP_EIGHT_BITS_MASK_R14 loop_8bpp: WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 CAPTURE_EIGHT_BITS_DOUBLE_8BPP_LO r11 // input in r8 @@ -66,37 +66,35 @@ loop_8bpp: preload_capture_line_default_eightbits_double_8bpp: SETUP_DUMMY_PARAMETERS b capture_line_default_eightbits_double_8bpp - - - + .ltorg // *** 16 bit *** - b preload_capture_line_default_twelvebits_double_16bpp -capture_line_default_twelvebits_double_16bpp: + b preload_capture_line_default_eightbits_double_16bpp +capture_line_default_eightbits_double_16bpp: push {lr} SETUP_VSYNC_DEBUG_R11_R12_DOUBLE SKIP_PSYNC_NO_OLD_CPLD push {r14} - SETUP_MASK_R14 + SETUP_TWELVE_BITS_MASK_R14 loop_16bpp: - WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 - CAPTURE_TWELVE_BITS_16BPP r5 // input in r8 - WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 - CAPTURE_TWELVE_BITS_16BPP r6 // input in r8 - WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 - CAPTURE_TWELVE_BITS_16BPP r7 // input in r8 - WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 - CAPTURE_TWELVE_BITS_16BPP r10 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_DOUBLE_16BPP r11 r5 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_DOUBLE_16BPP r12 r6 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_DOUBLE_16BPP r11 r7 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_DOUBLE_16BPP r12 r10 // input in r8 WRITE_R5_R6_R7_R10 - + subs r1, r1, #1 bne loop_16bpp pop {r0, pc} -preload_capture_line_default_twelvebits_double_16bpp: +preload_capture_line_default_eightbits_double_16bpp: SETUP_DUMMY_PARAMETERS - b capture_line_default_twelvebits_double_16bpp + b capture_line_default_eightbits_double_16bpp diff --git a/src/capture_line_default_sixbits_8bpp_16bpp.S b/src/capture_line_default_sixbits_8bpp_16bpp.S new file mode 100644 index 00000000..2f16db88 --- /dev/null +++ b/src/capture_line_default_sixbits_8bpp_16bpp.S @@ -0,0 +1,157 @@ +#include "rpi-base.h" +#include "defs.h" + +#include "macros.S" + +.text + +.global capture_line_default_sixbits_8bpp +.global capture_line_default_sixbits_16bpp + +// The capture line function is provided the following: +// r0 = pointer to current line in frame buffer +// r1 = number of complete psync cycles to capture (=param_chars_per_line) +// r2 = frame buffer line pitch in bytes (=param_fb_pitch) +// r3 = flags register +// r4 = GPLEV0 constant +// r5 = line number count down to 0 (initial value =param_nlines) +// r6 = scan line count modulo 10 +// r7 = number of psyncs to skip +// r8 = frame buffer height (=param_fb_height) +// +// All registers are available as scratch registers (i.e. nothing needs to be preserved) + +// 4bpp not currently used but left in in case + + b preload_capture_line_default_sixbits +capture_line_default_sixbits_4bpp: + push {lr} + SETUP_VSYNC_DEBUG_R11 + SKIP_PSYNC_NO_OLD_CPLD + push {r14} +loop: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_0_BITS_WIDE r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_1_BITS_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_2_BITS_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_3_BITS_WIDE r7 // input in r8 + + WRITE_R7_IF_LAST + cmp r1, #1 + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_0_BITS_WIDE r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_1_BITS_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_2_BITS_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_3_BITS_WIDE r10 // input in r8 + + WRITE_R7_R10 + + subs r1, r1, #2 + bne loop + + pop {r0, pc} + + .ltorg + +preload_capture_line_default_sixbits: + SETUP_DUMMY_PARAMETERS + b capture_line_default_sixbits_4bpp + + .ltorg + + // *** 8 bit *** + + b preload_capture_line_default_sixbits_8bpp +capture_line_default_sixbits_8bpp: + push {lr} + SETUP_VSYNC_DEBUG_R11_R12 + SKIP_PSYNC_NO_OLD_CPLD + push {r14} +loop_8bpp: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_LOW_BITS_8BPP_WIDE r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_HIGH_BITS_8BPP_WIDE r5 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_LOW_BITS_8BPP_WIDE r12 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_HIGH_BITS_8BPP_WIDE r6 // input in r8 + + WRITE_R5_R6_IF_LAST + cmp r1, #1 + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_LOW_BITS_8BPP_WIDE r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_HIGH_BITS_8BPP_WIDE r7 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_LOW_BITS_8BPP_WIDE r12 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_HIGH_BITS_8BPP_WIDE r10 // input in r8 + + WRITE_R5_R6_R7_R10 + + subs r1, r1, #2 + bne loop_8bpp + + pop {r0, pc} + + +preload_capture_line_default_sixbits_8bpp: + SETUP_DUMMY_PARAMETERS + b capture_line_default_sixbits_8bpp + + + .ltorg + + // *** 16 bit *** + + b preload_capture_line_default_sixbits_16bpp +capture_line_default_sixbits_16bpp: + push {lr} + SETUP_VSYNC_DEBUG_R11_R12 + SKIP_PSYNC_NO_OLD_CPLD + push {r14} + SETUP_TWELVE_BITS_MASK_R14 +loop_16bpp: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_LO r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_HI r5 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_LO r12 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_HI r6 // input in r8 + + WRITE_R5_R6_IF_LAST + cmp r1, #1 + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_LO r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_HI r7 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_LO r12 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_HI r10 // input in r8 + + WRITE_R5_R6_R7_R10 + + subs r1, r1, #2 + bne loop_16bpp + + pop {r0, pc} + +preload_capture_line_default_sixbits_16bpp: + SETUP_DUMMY_PARAMETERS + b capture_line_default_sixbits_16bpp diff --git a/src/capture_line_default_sixbits_double_8bpp_16bpp.S b/src/capture_line_default_sixbits_double_8bpp_16bpp.S new file mode 100644 index 00000000..bb0e30ed --- /dev/null +++ b/src/capture_line_default_sixbits_double_8bpp_16bpp.S @@ -0,0 +1,131 @@ +#include "rpi-base.h" +#include "defs.h" + +#include "macros.S" + +.text + +.global capture_line_default_sixbits_double_8bpp +.global capture_line_default_sixbits_double_16bpp + +// The capture line function is provided the following: +// r0 = pointer to current line in frame buffer +// r1 = number of complete psync cycles to capture (=param_chars_per_line) +// r2 = frame buffer line pitch in bytes (=param_fb_pitch) +// r3 = flags register +// r4 = GPLEV0 constant +// r5 = line number count down to 0 (initial value =param_nlines) +// r6 = scan line count modulo 10 +// r7 = number of psyncs to skip +// r8 = frame buffer height (=param_fb_height) +// +// All registers are available as scratch registers (i.e. nothing needs to be preserved) + +// 4bpp not currently used but left in in case + + b preload_capture_line_default_sixbits_double +capture_line_default_sixbits_double_4bpp: + push {lr} + SETUP_VSYNC_DEBUG_R11_DOUBLE + SKIP_PSYNC_NO_OLD_CPLD + push {r14} +loop: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_LOW_BITS_DOUBLE_WIDE r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_HIGH_BITS_DOUBLE_WIDE r7 // input in r8 + + WRITE_R7_IF_LAST + cmp r1, #1 + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_LOW_BITS_DOUBLE_WIDE r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_HIGH_BITS_DOUBLE_WIDE r10 // input in r8 + + WRITE_R7_R10 + + subs r1, r1, #2 + bne loop + + pop {r0, pc} + + +preload_capture_line_default_sixbits_double: + SETUP_DUMMY_PARAMETERS + b capture_line_default_sixbits_double_4bpp + + .ltorg + + // *** 8 bit *** + + b preload_capture_line_default_sixbits_double_8bpp +capture_line_default_sixbits_double_8bpp: + push {lr} + SETUP_VSYNC_DEBUG_R11_R12_DOUBLE + SKIP_PSYNC_NO_OLD_CPLD + push {r14} +loop_8bpp: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_BITS_DOUBLE_8BPP_WIDE r11 r5 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_BITS_DOUBLE_8BPP_WIDE r12 r6 // input in r8 + + WRITE_R5_R6_IF_LAST + cmp r1, #1 + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_BITS_DOUBLE_8BPP_WIDE r11 r7 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_BITS_DOUBLE_8BPP_WIDE r12 r10 // input in r8 + + WRITE_R5_R6_R7_R10 + + subs r1, r1, #2 + bne loop_8bpp + + pop {r0, pc} + + +preload_capture_line_default_sixbits_double_8bpp: + SETUP_DUMMY_PARAMETERS + b capture_line_default_sixbits_double_8bpp + .ltorg + + // *** 16 bit *** + + b preload_capture_line_default_sixbits_double_16bpp +capture_line_default_sixbits_double_16bpp: + push {lr} + SETUP_VSYNC_DEBUG_R11_R12_DOUBLE + SKIP_PSYNC_NO_OLD_CPLD + push {r14} + SETUP_TWELVE_BITS_MASK_R14 +loop_16bpp: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_DOUBLE_16BPP r11 r5 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_DOUBLE_16BPP r12 r6 // input in r8 + + WRITE_R5_R6_IF_LAST + cmp r1, #1 + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_DOUBLE_16BPP r11 r7 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_DOUBLE_16BPP r12 r10 // input in r8 + + WRITE_R5_R6_R7_R10 + + subs r1, r1, #2 + bne loop_16bpp + + pop {r0, pc} + + +preload_capture_line_default_sixbits_double_16bpp: + SETUP_DUMMY_PARAMETERS + b capture_line_default_sixbits_double_16bpp diff --git a/src/capture_line_fast_eightbits_8bpp_16bpp.S b/src/capture_line_fast_eightbits_8bpp_16bpp.S index e5743eaa..b5df1c17 100644 --- a/src/capture_line_fast_eightbits_8bpp_16bpp.S +++ b/src/capture_line_fast_eightbits_8bpp_16bpp.S @@ -6,6 +6,7 @@ .text .global capture_line_fast_eightbits_8bpp +.global capture_line_fast_eightbits_16bpp // The capture line function is provided the following: // r0 = pointer to current line in frame buffer @@ -31,7 +32,7 @@ capture_line_fast_eightbits_8bpp: SETUP_VSYNC_DEBUG_R11_R12 SKIP_PSYNC_NO_H_SCROLL push {r14} - SETUP_MASK_R14 + SETUP_EIGHT_BITS_MASK_R14 loop_8bpp: WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 CAPTURE_EIGHT_BITS_8BPP_0 r11 // input in r8 @@ -86,31 +87,31 @@ preload_capture_line_fast_eightbits_8bpp: .ltorg // *** 16 bit *** - b preload_capture_line_fast_twelvebits_16bpp -capture_line_fast_twelvebits_16bpp: + b preload_capture_line_fast_eightbits_16bpp +capture_line_fast_eightbits_16bpp: push {lr} - SETUP_VSYNC_DEBUG_R11_R12_DOUBLE - SKIP_PSYNC_NO_OLD_CPLD + SETUP_VSYNC_DEBUG_R11_R12 + SKIP_PSYNC_NO_H_SCROLL push {r14} - SETUP_MASK_R14 + SETUP_TWELVE_BITS_MASK_R14 loop_16bpp: - WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 - CAPTURE_TWELVE_BITS_16BPP_LO r11 // input in r8 - WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 - CAPTURE_TWELVE_BITS_16BPP_HI r5 // input in r8 - WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 - CAPTURE_TWELVE_BITS_16BPP_LO r12 // input in r8 - WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 - CAPTURE_TWELVE_BITS_16BPP_HI r6 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_LO r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_HI r5 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_LO r12 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_HI r6 // input in r8 - WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 - CAPTURE_TWELVE_BITS_16BPP_LO r11 // input in r8 - WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 - CAPTURE_TWELVE_BITS_16BPP_HI r7 // input in r8 - WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 - CAPTURE_TWELVE_BITS_16BPP_LO r12 // input in r8 - WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 - CAPTURE_TWELVE_BITS_16BPP_HI r10 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_LO r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_HI r7 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_LO r12 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_HI r10 // input in r8 stmia r0!, {r5, r6, r7, r10} @@ -120,6 +121,6 @@ loop_16bpp: pop {r0, pc} -preload_capture_line_fast_twelvebits_16bpp: +preload_capture_line_fast_eightbits_16bpp: SETUP_DUMMY_PARAMETERS - b capture_line_fast_twelvebits_16bpp + b capture_line_fast_eightbits_16bpp diff --git a/src/capture_line_fast_sixbits_8bpp_16bpp.S b/src/capture_line_fast_sixbits_8bpp_16bpp.S new file mode 100644 index 00000000..1381effd --- /dev/null +++ b/src/capture_line_fast_sixbits_8bpp_16bpp.S @@ -0,0 +1,152 @@ +#include "rpi-base.h" +#include "defs.h" + +#include "macros.S" + +.text + +.global capture_line_fast_sixbits_8bpp +.global capture_line_fast_sixbits_16bpp + +// The capture line function is provided the following: +// r0 = pointer to current line in frame buffer +// r1 = number of complete psync cycles to capture (=param_chars_per_line) +// r2 = frame buffer line pitch in bytes (=param_fb_pitch) +// r3 = flags register +// r4 = GPLEV0 constant +// r5 = line number count down to 0 (initial value =param_nlines) +// r6 = scan line count modulo 10 +// r7 = number of psyncs to skip +// r8 = frame buffer height (=param_fb_height) +// +// All registers are available as scratch registers (i.e. nothing needs to be preserved) + + +// 4bpp not currently used but left in in case + + b preload_capture_line_fast_sixbits +capture_line_fast_sixbits_4bpp: + push {lr} + SETUP_VSYNC_DEBUG_R11 + SKIP_PSYNC_NO_H_SCROLL + push {r14} +loop: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_0_BITS_WIDE r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_1_BITS_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_2_BITS_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_3_BITS_WIDE r7 // input in r8 + + cmp r1, #1 + stmeqia r0, {r7} + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_0_BITS_WIDE r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_1_BITS_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_2_BITS_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_3_BITS_WIDE r10 // input in r8 + + stmia r0!, {r7, r10} + subs r1, r1, #2 + bne loop + + pop {r0, pc} + +preload_capture_line_fast_sixbits: + SETUP_DUMMY_PARAMETERS + b capture_line_fast_sixbits_4bpp + + .ltorg + + // *** 8 bit *** + + b preload_capture_line_fast_sixbits_8bpp +capture_line_fast_sixbits_8bpp: + push {lr} + SETUP_VSYNC_DEBUG_R11_R12 + SKIP_PSYNC_NO_H_SCROLL + push {r14} +loop_8bpp: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_LOW_BITS_8BPP_WIDE r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_HIGH_BITS_8BPP_WIDE r5 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_LOW_BITS_8BPP_WIDE r12 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_HIGH_BITS_8BPP_WIDE r6 // input in r8 + + cmp r1, #1 + stmeqia r0, {r5, r6} + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_LOW_BITS_8BPP_WIDE r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_HIGH_BITS_8BPP_WIDE r7 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_LOW_BITS_8BPP_WIDE r12 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_HIGH_BITS_8BPP_WIDE r10 // input in r8 + + stmia r0!, {r5, r6, r7, r10} + subs r1, r1, #2 + bne loop_8bpp + + pop {r0, pc} + +preload_capture_line_fast_sixbits_8bpp: + SETUP_DUMMY_PARAMETERS + b capture_line_fast_sixbits_8bpp + + + .ltorg + + // *** 16 bit *** + + b preload_capture_line_fast_sixbits_16bpp +capture_line_fast_sixbits_16bpp: + push {lr} + SETUP_VSYNC_DEBUG_R11_R12 + SKIP_PSYNC_NO_H_SCROLL + push {r14} + SETUP_TWELVE_BITS_MASK_R14 +loop_16bpp: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_LO r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_HI r5 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_LO r12 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_HI r6 // input in r8 + + cmp r1, #1 + stmeqia r0, {r5, r6} + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_LO r11 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_HI r7 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_LO r12 // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + CAPTURE_TWELVE_BITS_16BPP_HI r10 // input in r8 + + stmia r0!, {r5, r6, r7, r10} + subs r1, r1, #2 + bne loop_16bpp + + pop {r0, pc} + +preload_capture_line_fast_sixbits_16bpp: + SETUP_DUMMY_PARAMETERS + b capture_line_fast_sixbits_16bpp diff --git a/src/capture_line_ntsc_sixbits_8bpp.S b/src/capture_line_ntsc_sixbits_8bpp.S new file mode 100644 index 00000000..0e3b7ebe --- /dev/null +++ b/src/capture_line_ntsc_sixbits_8bpp.S @@ -0,0 +1,697 @@ +#include "rpi-base.h" +#include "defs.h" + +#include "macros.S" + +.macro SKIP_PSYNC_NO_OLD_CPLD_NTSC + // 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_SKIP_HSYNC + READ_CYCLE_COUNTER r10 + ldr r12, =ntsc_status + 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 + ldr r12, [r12] // ntsc_status now in r12, low 2 bits ntsc phase, next bit is ntsccolour, next bit is burst detect + // 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, r9, lsr #16 //HSYNC_SCROLL_HI + addlt r8, r8, #1 + orrgt r3, r3, #BIT_INHIBIT_MODE_DETECT + bic r9, r9, #0xff000000 + bic r9, r9, #0x00ff0000 + cmp r10, r9 //HSYNC_SCROLL_LO + addlt r8, r8, #1 + orrlt r3, r3, #BIT_INHIBIT_MODE_DETECT + 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) + mov r11, #0 +skip_psync_loop_no_old\@: + WAIT_FOR_PSYNC_EDGE_FAST // wait for next edge of psync + and r10, r8, #(0x10 << PIXEL_BASE) + orr r11, r11, r10 + and r10, r8, #(0x10 << (PIXEL_BASE + 6)) + orr r11, r11, r10 + subs r7, r7, #1 + bne skip_psync_loop_no_old\@ + cmp r11, #0 + movne r11, #8 //burst detected +.endm + + +.macro NTSC_CAPTURE_BITS_8BPP_MONO + // 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 + mov r11, r11, lsr #4 + and r9, r8, #(7 << PIXEL_BASE) + and r14, r8, #(7 << (PIXEL_BASE + 3)) + + cmp r9, #(0x07 << PIXEL_BASE) + cmpne r9, #(0x02 << PIXEL_BASE) + orreq r11, r11, #0x10000000 + + cmp r14, #(0x07 << (PIXEL_BASE + 3)) + cmpne r14, #(0x02 << (PIXEL_BASE + 3)) + orreq r11, r11, #0x20000000 + + and r9, r8, #(7 << (PIXEL_BASE + 6)) + and r14, r8, #(7 << (PIXEL_BASE + 9)) + + cmp r9, #(0x07 << (PIXEL_BASE + 6)) + cmpne r9, #(0x02 << (PIXEL_BASE + 6)) + orreq r11, r11, #0x40000000 + + cmp r14, #(0x07 << (PIXEL_BASE + 9)) + cmpne r14, #(0x02 << (PIXEL_BASE + 9)) + orreq r11, r11, #0x80000000 +.endm + +.macro NTSC_CAPTURE_BITS_8BPP_MONO_WIDE + // Pixel 0 in GPIO 7.. 2 -> 7.. 0 + // Pixel 1 in GPIO 13.. 8 -> 15.. 8 + mov r11, r11, lsr #2 + + and r9, r8, #(0x07 << PIXEL_BASE) + and r14, r8, #(0x07 << (PIXEL_BASE + 6)) + + cmp r9, #(0x07 << PIXEL_BASE) + cmpne r9, #(0x02 << PIXEL_BASE) + orreq r11, r11, #0x40000000 + + cmp r14, #(0x07 << (PIXEL_BASE + 6)) + cmpne r14, #(0x02 << (PIXEL_BASE + 6)) + orreq r11, r11, #0x80000000 +.endm + +.macro NO_BURST_NTSC_DECODE reg + and r8, r12, #3 //shift pixels by low 2 bits of NTSC phase + mov r14, r11, lsr r8 + mov \reg, #0 + tst r14, #0x01000000 + orrne \reg, \reg, #0x2f + tst r14, #0x02000000 + orrne \reg, \reg, #0x2f00 + tst r14, #0x04000000 + orrne \reg, \reg, #0x2f0000 + tst r14, #0x08000000 + orrne \reg, \reg, #0x2f000000 +.endm + +.macro NTSC_DECODE reg + and r8, r12, #3 //shift pixels by low 2 bits of NTSC phase + mov r14, r11, lsr r8 + + and r9, r14, #0x0e000000 + and r8, r14, #0x10000000 + mov \reg, r9 + orr \reg, \reg, r8, lsr #4 + and r9, r14, #0x0f000000 + orr \reg, \reg, r9, lsr #8 + and r9, r14, #0x07000000 + and r8, r14, #0x00800000 + orr r9, r8, lsl #4 + orr \reg, \reg, r9, lsr #16 + and r9, r14, #0x03000000 + and r8, r14, #0x00c00000 + orr r9, r8, lsl #4 + orr \reg, \reg, r9, lsr #24 + + mov r8, #0 + mov r9, #0 + tst r14, #0x00400000 + addne r8, r8, #1 + tst r14, #0x00800000 + addne r9, r9, #1 + tst r14, #0x01000000 + addne r9, r9, #1 + tst r14, #0x02000000 + addne r9, r9, #1 + add r8, r8, r9 + cmp r8, #3 + movge r8, #3 + subs r8, r8, #1 + orrpl \reg, \reg, r8, lsl #4 + + tst r14, #0x04000000 + addne r9, r9, #1 + cmp r9, #3 + movge r9, #3 + subs r9, r9, #1 + orrpl \reg, \reg, r9, lsl #12 + + mov r8, #0 + mov r9, #0 + tst r14, #0x01000000 + addne r8, r8, #1 + tst r14, #0x02000000 + addne r9, r9, #1 + tst r14, #0x04000000 + addne r9, r9, #1 + tst r14, #0x08000000 + addne r9, r9, #1 + add r8, r8, r9 + cmp r8, #3 + movge r8, #3 + subs r8, r8, #1 + orrpl \reg, \reg, r8, lsl #20 + + tst r14, #0x10000000 + addne r9, r9, #1 + cmp r9, #3 + movge r9, #3 + subs r9, r9, #1 + orrpl \reg, \reg, r9, lsl #28 +.endm + +.macro NTSC_DECODE_CGA reg + tst r12, #0xf0000000 + bne not_white\@ + NTSC_DECODE \reg + b done_white\@ +not_white\@: + and r8, r12, #3 //shift pixels by low 2 bits of NTSC phase + mov r14, r11, lsr r8 + + and r9, r14, #0x0e000000 + and r8, r14, #0x10000000 + mov \reg, r9 + orr \reg, \reg, r8, lsr #4 + and r9, r14, #0x0f000000 + orr \reg, \reg, r9, lsr #8 + and r9, r14, #0x07000000 + and r8, r14, #0x00800000 + orr r9, r8, lsl #4 + orr \reg, \reg, r9, lsr #16 + and r9, r14, #0x03000000 + and r8, r14, #0x00c00000 + orr r9, r8, lsl #4 + orr \reg, \reg, r9, lsr #24 + + and r8, r12, #0xf0000000 + cmp r8, #0x10000000 + orreq \reg, \reg, #0x30000000 + orreq \reg, \reg, #0x00300000 + orreq \reg, \reg, #0x00003000 + orreq \reg, \reg, #0x00000030 + + cmp r8, #0x20000000 + orreq \reg, \reg, #0x40000000 + orreq \reg, \reg, #0x00400000 + orreq \reg, \reg, #0x00004000 + orreq \reg, \reg, #0x00000040 +done_white\@: +.endm + +.macro NTSC_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 + mov r11, r11, lsr #4 + bic r12, #0xf0000000 + + and r9, r8, #(0x07 << PIXEL_BASE) + + cmp r9, #(0x01 << PIXEL_BASE) //red? + cmpne r9, #(0x03 << PIXEL_BASE) //yellow? + orreq r11, r11, #0x10000000 + cmpne r9, #(0x02 << PIXEL_BASE) //green? + orreq r12, #0x10000000 //palette 0 + + cmp r9, #(0x05 << PIXEL_BASE) //magenta? + orreq r11, r11, #0x10000000 + cmpne r9, #(0x06 << PIXEL_BASE) //cyan? + orreq r12, #0x20000000 //palette 1 + + cmp r9, #(0x07 << PIXEL_BASE) //white? + orreq r11, r11, #0x10000000 + + + and r9, r8, #(0x07 << (PIXEL_BASE + 3)) + + cmp r9, #(0x02 << (PIXEL_BASE + 3)) //green? + cmpne r9, #(0x03 << (PIXEL_BASE + 3)) //yellow? + orreq r11, r11, #0x20000000 + cmpne r9, #(0x01 << (PIXEL_BASE + 3)) //red? + orreq r12, #0x10000000 //palette 0 + + cmp r9, #(0x06 << (PIXEL_BASE + 3)) //cyan? + orreq r11, r11, #0x20000000 + cmpne r9, #(0x05 << (PIXEL_BASE + 3)) //magenta? + orreq r12, #0x20000000 //palette 1 + + cmp r9, #(0x07 << (PIXEL_BASE + 3)) //white? + orreq r11, r11, #0x20000000 + + + and r9, r8, #(0x07 << (PIXEL_BASE + 6)) + + cmp r9, #(0x01 << (PIXEL_BASE + 6)) //red? + cmpne r9, #(0x03 << (PIXEL_BASE + 6)) //yellow? + orreq r11, r11, #0x40000000 + cmpne r9, #(0x02 << (PIXEL_BASE + 6)) //green? + orreq r12, #0x10000000 //palette 0 + + cmp r9, #(0x05 << (PIXEL_BASE + 6)) //magenta? + orreq r11, r11, #0x40000000 + cmpne r9, #(0x06 << (PIXEL_BASE + 6)) //cyan? + orreq r12, #0x20000000 //palette 1 + + cmp r9, #(0x07 << (PIXEL_BASE + 6)) //white? + orreq r11, r11, #0x40000000 + + + and r9, r8, #(0x07 << (PIXEL_BASE + 9)) + + cmp r9, #(0x02 << (PIXEL_BASE + 9)) //green? + cmpne r9, #(0x03 << (PIXEL_BASE + 9)) //yellow? + orreq r11, r11, #0x80000000 + cmpne r9, #(0x01 << (PIXEL_BASE + 9)) //red? + orreq r12, #0x10000000 //palette 0 + + cmp r9, #(0x06 << (PIXEL_BASE + 9)) //cyan? + orreq r11, r11, #0x80000000 + cmpne r9, #(0x05 << (PIXEL_BASE + 9)) //magenta? + orreq r12, #0x20000000 //palette 1 + + cmp r9, #(0x07 << (PIXEL_BASE + 9)) //white? + orreq r11, r11, #0x80000000 + +.endm + + +.macro NTSC_CAPTURE_BITS_8BPP_WIDE + // Pixel 0 in GPIO 7.. 2 -> 7.. 0 + // Pixel 1 in GPIO 13.. 8 -> 15.. 8 + mov r11, r11, lsr #2 + bic r12, #0xf0000000 + + and r9, r8, #(0x07 << PIXEL_BASE) + + cmp r9, #(0x01 << PIXEL_BASE) //red? + cmpne r9, #(0x03 << PIXEL_BASE) //yellow? + orreq r11, r11, #0x40000000 + cmpne r9, #(0x02 << PIXEL_BASE) //green? + orreq r12, #0x10000000 //palette 0 + + cmp r9, #(0x05 << PIXEL_BASE) //magenta? + orreq r11, r11, #0x40000000 + cmpne r9, #(0x06 << PIXEL_BASE) //cyan? + orreq r12, #0x20000000 //palette 1 + + cmp r9, #(0x07 << PIXEL_BASE) //white? + orreq r11, r11, #0x40000000 + + + and r9, r8, #(0x07 << (PIXEL_BASE + 6)) + + cmp r9, #(0x02 << (PIXEL_BASE + 6)) //green? + cmpne r9, #(0x03 << (PIXEL_BASE + 6)) //yellow? + orreq r11, r11, #0x80000000 + cmpne r9, #(0x01 << (PIXEL_BASE + 6)) //red? + orreq r12, #0x10000000 //palette 0 + + cmp r9, #(0x06 << (PIXEL_BASE + 6)) //cyan? + orreq r11, r11, #0x80000000 + cmpne r9, #(0x05 << (PIXEL_BASE + 6)) //magenta? + orreq r12, #0x20000000 //palette 1 + + cmp r9, #(0x07 << (PIXEL_BASE + 6)) //white? + orreq r11, r11, #0x80000000 +.endm + + +.macro NO_NTSC_DECODE + WAIT_FOR_PSYNC_EDGE + NTSC_CAPTURE_BITS_8BPP +loop_8bpp_mono_auto_noburst\@: + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP // input in r8 + NO_BURST_NTSC_DECODE r5 + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP // input in r8 + NO_BURST_NTSC_DECODE r6 + + WRITE_R5_R6_IF_LAST + cmp r1, #1 + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP // input in r8 + NO_BURST_NTSC_DECODE r7 + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP // input in r8 + NO_BURST_NTSC_DECODE r10 + + WRITE_R5_R6_R7_R10 + subs r1, r1, #2 + bne loop_8bpp_mono_auto_noburst\@ + ldr r0, =ntsc_status + str r12, [r0] + pop {r0, pc} + .ltorg +.endm + +.macro NO_NTSC_DECODE_6BIT + WAIT_FOR_PSYNC_EDGE_FAST + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE + WAIT_FOR_PSYNC_EDGE_FAST + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE +loop_8bpp_mono6_auto_noburst\@: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + NO_BURST_NTSC_DECODE r5 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + NO_BURST_NTSC_DECODE r6 + + WRITE_R5_R6_IF_LAST + cmp r1, #1 + ldreq r0, =ntsc_status + streq r12, [r0] + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + NO_BURST_NTSC_DECODE r7 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + NO_BURST_NTSC_DECODE r10 + + WRITE_R5_R6_R7_R10 + + subs r1, r1, #2 + bne loop_8bpp_mono6_auto_noburst\@ + ldr r0, =ntsc_status + str r12, [r0] + pop {r0, pc} + .ltorg +.endm + +.text +.global capture_line_ntsc_8bpp_cga +.global capture_line_ntsc_8bpp_mono +.global capture_line_ntsc_sixbits_8bpp_cga +.global capture_line_ntsc_sixbits_8bpp_mono +.global capture_line_ntsc_sixbits_8bpp_mono_auto + + +// The capture line function is provided the following: +// r0 = pointer to current line in frame buffer +// r1 = number of complete psync cycles to capture (=param_chars_per_line) +// r2 = frame buffer line pitch in bytes (=param_fb_pitch) +// r3 = flags register +// r4 = GPLEV0 constant +// r5 = line number count down to 0 (initial value =param_nlines) +// r6 = scan line count modulo 10 +// r7 = number of psyncs to skip +// r8 = frame buffer height (=param_fb_height) +// +// All registers are available as scratch registers (i.e. nothing needs to be preserved) + + .ltorg + +.align 6 + // *** 8 bit *** + + b preload_capture_line_ntsc_8bpp_cga +capture_line_ntsc_8bpp_cga: + push {lr} + SKIP_PSYNC_NO_OLD_CPLD_NTSC // returns r11 = 8 if burst detected + mov r11, #0 + push {r14} + WAIT_FOR_PSYNC_EDGE + NTSC_CAPTURE_BITS_8BPP +loop_8bpp3: + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP // input in r8 + NTSC_DECODE_CGA r5 + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP // input in r8 + NTSC_DECODE_CGA r6 + + WRITE_R5_R6_IF_LAST + cmp r1, #1 + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP // input in r8 + NTSC_DECODE_CGA r7 + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP // input in r8 + NTSC_DECODE_CGA r10 + + WRITE_R5_R6_R7_R10 + + subs r1, r1, #2 + bne loop_8bpp3 + pop {r0, pc} + .ltorg + +preload_capture_line_ntsc_8bpp_cga: + SETUP_DUMMY_PARAMETERS + b capture_line_ntsc_8bpp_cga + + +.align 6 + b preload_capture_line_ntsc_8bpp_mono +capture_line_ntsc_8bpp_mono: + push {lr} + SKIP_PSYNC_NO_OLD_CPLD_NTSC // returns r11 = 8 if burst detected + mov r11, #0 + tst r12, #4 + push {r14} + beq no_ntsc_8bpp_mono + WAIT_FOR_PSYNC_EDGE + NTSC_CAPTURE_BITS_8BPP_MONO +loop_8bpp_mono3: + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO // input in r8 + NTSC_DECODE r5 + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO // input in r8 + NTSC_DECODE r6 + + WRITE_R5_R6_IF_LAST + cmp r1, #1 + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO // input in r8 + NTSC_DECODE r7 + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO // input in r8 + NTSC_DECODE r10 + + WRITE_R5_R6_R7_R10 + + subs r1, r1, #2 + bne loop_8bpp_mono3 + + pop {r0, pc} + .ltorg +no_ntsc_8bpp_mono: + NO_NTSC_DECODE + +preload_capture_line_ntsc_8bpp_mono: + SETUP_DUMMY_PARAMETERS + b capture_line_ntsc_8bpp_mono + + +//*************************************************************************************** + + +.align 6 + b preload_capture_line_ntsc_sixbits_8bpp_cga +capture_line_ntsc_sixbits_8bpp_cga: + push {lr} + SKIP_PSYNC_NO_OLD_CPLD_NTSC // returns r11 = 8 if burst detected + mov r11, #0 + push {r14} + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_WIDE // input in r8 +loop_8bpp6: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_WIDE // input in r8 + NTSC_DECODE_CGA r5 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_WIDE // input in r8 + NTSC_DECODE_CGA r6 + + WRITE_R5_R6_IF_LAST + cmp r1, #1 + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_WIDE // input in r8 + NTSC_DECODE_CGA r7 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_WIDE // input in r8 + NTSC_DECODE_CGA r10 + + WRITE_R5_R6_R7_R10 + + subs r1, r1, #2 + bne loop_8bpp6 + + pop {r0, pc} + .ltorg + +preload_capture_line_ntsc_sixbits_8bpp_cga: + SETUP_DUMMY_PARAMETERS + b capture_line_ntsc_sixbits_8bpp_cga + + + // *** 8 bit mono *** +.align 6 + b preload_capture_line_ntsc_sixbits_8bpp_mono +capture_line_ntsc_sixbits_8bpp_mono: + push {lr} + SKIP_PSYNC_NO_OLD_CPLD_NTSC // returns r11 = 8 if burst detected + mov r11, #0 + tst r12, #4 + push {r14} + beq no_ntsc_sixbits_8bpp_mono + WAIT_FOR_PSYNC_EDGE_FAST + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE + WAIT_FOR_PSYNC_EDGE_FAST + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE +loop_8bpp_mono6: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + NTSC_DECODE r5 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + NTSC_DECODE r6 + + WRITE_R5_R6_IF_LAST + cmp r1, #1 + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + NTSC_DECODE r7 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + NTSC_DECODE r10 + + WRITE_R5_R6_R7_R10 + + subs r1, r1, #2 + bne loop_8bpp_mono6 + + pop {r0, pc} + .ltorg +no_ntsc_sixbits_8bpp_mono: + NO_NTSC_DECODE_6BIT +preload_capture_line_ntsc_sixbits_8bpp_mono: + SETUP_DUMMY_PARAMETERS + b capture_line_ntsc_sixbits_8bpp_mono + + // *** 8 bit mono auto *** +.align 6 + b preload_capture_line_ntsc_sixbits_8bpp_mono_auto +capture_line_ntsc_sixbits_8bpp_mono_auto: + push {lr} + SKIP_PSYNC_NO_OLD_CPLD_NTSC // returns r11 = 0 if burst detected, 8 if not detected + eor r9, r11, r12 + eor r9, #8 //invert result so following tests can cascade + tst r9, #8 + bicne r12, r12, #0xff00 + addeq r12, r12, #0x0100 + andeq r9, r12, #0xff00 + cmpeq r9, #0x6400 //if burst state changed for 100 lines then change artifact colour state + biceq r12, r12, #4+8 + orreq r12, r12, r11, lsr #1 + orreq r12, r12, r11 + mov r11, #0 + push {r14} + tst r12, #4 + beq no_ntsc_sixbits_8bpp_mono_auto + WAIT_FOR_PSYNC_EDGE_FAST + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE + WAIT_FOR_PSYNC_EDGE_FAST + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE +loop_8bpp_mono6_auto: + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + NTSC_DECODE r5 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + NTSC_DECODE r6 + + WRITE_R5_R6_IF_LAST + cmp r1, #1 + ldreq r0, =ntsc_status + streq r12, [r0] + popeq {r0, pc} + + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + NTSC_DECODE r7 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + WAIT_FOR_PSYNC_EDGE_FAST // expects GPLEV0 in r4, result in r8 + NTSC_CAPTURE_BITS_8BPP_MONO_WIDE // input in r8 + NTSC_DECODE r10 + + WRITE_R5_R6_R7_R10 + + subs r1, r1, #2 + bne loop_8bpp_mono6_auto + ldr r0, =ntsc_status + str r12, [r0] + pop {r0, pc} + .ltorg +no_ntsc_sixbits_8bpp_mono_auto: + NO_NTSC_DECODE_6BIT + +preload_capture_line_ntsc_sixbits_8bpp_mono_auto: + SETUP_DUMMY_PARAMETERS + b capture_line_ntsc_sixbits_8bpp_mono_auto diff --git a/src/cpld.h b/src/cpld.h index 15ec5844..b46164a3 100644 --- a/src/cpld.h +++ b/src/cpld.h @@ -60,8 +60,8 @@ extern cpld_t *cpld; extern capture_info_t *capinfo; enum { - WIDTH_3, - WIDTH_6, - WIDTH_8 + SAMPLE_WIDTH_3, + SAMPLE_WIDTH_6, + SAMPLE_WIDTH_8 }; #endif diff --git a/src/cpld_atom.c b/src/cpld_atom.c index ca58274d..d770af2b 100644 --- a/src/cpld_atom.c +++ b/src/cpld_atom.c @@ -189,7 +189,7 @@ static void cpld_update_capture_info(capture_info_t *capinfo) { // Update the capture info stucture, if one was passed in if (capinfo) { // Update the sample width - capinfo->sample_width = WIDTH_6; + capinfo->sample_width = SAMPLE_WIDTH_6; // Update the line capture function capinfo->capture_line = capture_line_normal_6bpp_table; } diff --git a/src/cpld_rgb.c b/src/cpld_rgb.c index 0c5bf11b..c5f995e2 100644 --- a/src/cpld_rgb.c +++ b/src/cpld_rgb.c @@ -138,7 +138,8 @@ enum { RGB_RATE_3, RGB_RATE_6, RGB_RATE_6_LEVEL_4, - RGB_RATE_8 + RGB_RATE_8, + NUM_RGB_RATE }; static const char *rate_names[] = { @@ -153,10 +154,8 @@ static const char *eight_bit_rate_names[] = { "6 Bits Per Pixel", "6 Bits (4 Level)", "8 Bits Per Pixel" - }; - static const char *cpld_setup_names[] = { "Normal", "Set Delay" @@ -205,7 +204,7 @@ static param_t params[] = { { CLAMPTYPE, "Clamp Type", "clamptype", 0, 4, 1 }, //end of hidden block { MUX, "Sync on G/V", "input_mux", 0, 1, 1 }, - { RATE, "Sample Mode", "sample_mode", 0, 3, 1 }, + { RATE, "Sample Mode", "sample_mode", 0, NUM_RGB_RATE-1, 1 }, { TERMINATE, "75R Termination", "termination", 0, NUM_RGB_TERM-1, 1 }, { COUPLING, "G Coupling", "coupling", 0, NUM_RGB_COUPLING-1, 1 }, { DAC_A, "DAC-A: G Hi", "dac_a", 0, 255, 1 }, @@ -900,18 +899,33 @@ static void cpld_update_capture_info(capture_info_t *capinfo) { // Update the capture info stucture, if one was passed in if (capinfo) { // Update the sample width - if (supports_8bit) { - capinfo->sample_width = config->rate; - if (capinfo->sample_width >= RGB_RATE_6_LEVEL_4) { - capinfo->sample_width--; //4 level analog option is actually 6bpp - } - } else { - capinfo->sample_width = (config->rate == RGB_RATE_6); // 1 = 6bpp, everything else 3bpp + + switch(config->rate) { + case RGB_RATE_3: + capinfo->sample_width = SAMPLE_WIDTH_3; + break; + case RGB_RATE_6: + capinfo->sample_width = SAMPLE_WIDTH_6; + break; + case RGB_RATE_6_LEVEL_4: + if (supports_8bit) { + capinfo->sample_width = SAMPLE_WIDTH_6; + } else { + capinfo->sample_width = SAMPLE_WIDTH_3; + } + break; + case RGB_RATE_8: + if (supports_8bit) { + capinfo->sample_width = SAMPLE_WIDTH_8; + } else { + capinfo->sample_width = SAMPLE_WIDTH_3; + } + break; } // Update the line capture function switch (capinfo->sample_width) { - case 0: + case SAMPLE_WIDTH_3: switch (capinfo->px_sampling) { case PS_NORMAL: capinfo->capture_line = capture_line_normal_3bpp_table; @@ -930,10 +944,10 @@ static void cpld_update_capture_info(capture_info_t *capinfo) { break; } break; - case 1 : + case SAMPLE_WIDTH_6 : capinfo->capture_line = capture_line_normal_6bpp_table; break; - case 2 : + case SAMPLE_WIDTH_8 : capinfo->capture_line = capture_line_normal_8bpp_table; break; } diff --git a/src/cpld_yuv.c b/src/cpld_yuv.c index cdc3c952..5396030e 100644 --- a/src/cpld_yuv.c +++ b/src/cpld_yuv.c @@ -661,7 +661,7 @@ static void cpld_update_capture_info(capture_info_t *capinfo) { // Update the capture info stucture, if one was passed in if (capinfo) { // Update the sample width - capinfo->sample_width = WIDTH_6; + capinfo->sample_width = SAMPLE_WIDTH_6; // Update the line capture function capinfo->capture_line = capture_line_normal_6bpp_table; } diff --git a/src/geometry.c b/src/geometry.c index 1be7134f..6c850713 100644 --- a/src/geometry.c +++ b/src/geometry.c @@ -399,10 +399,10 @@ void geometry_get_fb_params(capture_info_t *capinfo) { } if (capinfo->video_type == VIDEO_TELETEXT) { capinfo->bpp = 4; //force 4bpp for teletext - } else if (capinfo->sample_width >= WIDTH_8 && capinfo->bpp == 4) { - capinfo->bpp = 8; //force at least 8bpp in 8 bit modes - } else if (capinfo->bpp == 16 && capinfo->sample_width < WIDTH_8) { - capinfo->bpp = 8; //force 8bpp in 3 and 6 bit modes if 16 bpp set + } else if (capinfo->sample_width >= SAMPLE_WIDTH_6 && capinfo->bpp == 4) { + capinfo->bpp = 8; //force at least 8bpp in >=6 bit modes as no capture loops for >=6 bit capture into 4bpp buffer + } else if (capinfo->sample_width == SAMPLE_WIDTH_3 && capinfo->bpp > 8) { + capinfo->bpp = 8; //force 8bpp in 3 bit modes as no capture loops for 3 bit capture into 16bpp buffer } #ifdef INHIBIT_DOUBLE_HEIGHT @@ -482,10 +482,15 @@ void geometry_get_fb_params(capture_info_t *capinfo) { int double_width = (capinfo->sizex2 & 2) >> 1; int double_height = capinfo->sizex2 & 1; - if ((geometry_min_h_width << double_width) > h_size43) { - double_width = 0; + if (capinfo->sample_width == SAMPLE_WIDTH_6 && capinfo->bpp == 16) { //special double rate 6 bpp mode + if (((geometry_min_h_width >> 1) << double_width) > h_size43) { + double_width = 0; + } + } else { + if ((geometry_min_h_width << double_width) > h_size43) { + double_width = 0; + } } - if ((geometry_min_v_height << double_height) > v_size43) { double_height = 0; } @@ -698,7 +703,24 @@ void geometry_get_fb_params(capture_info_t *capinfo) { capinfo->width &= 0xfffffffe; capinfo->height &= 0xfffffffe; - int pitchinchars = ((capinfo->pitch << (capinfo->bpp == 4 ? 1 : 0)) >> 3); + int pitchinchars = capinfo->pitch; + + switch(capinfo->bpp) { + case 4: + pitchinchars >>= 2; + break; + case 8: + pitchinchars >>= 3; + break; + case 16: + if (capinfo->sample_width == SAMPLE_WIDTH_6) { //special double rate 6 bpp mode + pitchinchars >>= 3; + } else { + pitchinchars >>= 4; + } + break; + } + if (capinfo->chars_per_line > pitchinchars) { //log_info("Clipping capture width to pitch: %d, %d", capinfo->chars_per_line, pitchinchars); capinfo->chars_per_line = pitchinchars; diff --git a/src/macros.S b/src/macros.S index 4b2c2aa8..da9e4f7c 100644 --- a/src/macros.S +++ b/src/macros.S @@ -486,7 +486,41 @@ wait_wr\@: orr \reg2, r10, r10, lsl #8 .endm -.macro SETUP_MASK_R14 + +.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 SETUP_EIGHT_BITS_MASK_R14 tst r3, #BIT_OSD movne r14, #(0x7f << PIXEL_BASE) moveq r14, #(0xff << PIXEL_BASE) @@ -535,69 +569,54 @@ wait_wr\@: orr \reg, r10, r10, lsl #8 .endm -.macro CAPTURE_TWELVE_BITS_16BPP reg - // Pixel 0 in GPIO 9.. 2 -> 7.. 0 - and r10, r8, #0x0f << PIXEL_BASE - mov r10, r10, lsr #(PIXEL_BASE - 1) - and r14, r8, #0x0f << (PIXEL_BASE + 4) - orr r10, r10, r14, lsl #(PIXEL_BASE + 1) - and r9, r8, #0x0f << (PIXEL_BASE + 8) - orr r10, r10, r9, lsl #(PIXEL_BASE + 2) - orr \reg, r10, r10, lsl #16 + +.macro SETUP_TWELVE_BITS_MASK_R14 + mov r14, #(0x0e << PIXEL_BASE) + orr r14, r14, #(0x0e << (PIXEL_BASE + 4)) + orr r14, r14, #(0x0e << (PIXEL_BASE + 8)) .endm + .macro CAPTURE_TWELVE_BITS_16BPP_LO reg - // Pixel 0 in GPIO 9.. 2 -> 7.. 0 + // Pixel in GPIO 13.. 2 -> 15.. 0 + and r9, r8, #0x0f << PIXEL_BASE eor r10, \reg, r9, lsr #(PIXEL_BASE - 1) - and r14, r8, #0x0f << (PIXEL_BASE + 4) - eor r10, r10, r14, lsl #(PIXEL_BASE + 1) + and r9, r8, #0x0f << (PIXEL_BASE + 4) + eor r10, r10, r9, lsl #(3 - PIXEL_BASE) and r9, r8, #0x0f << (PIXEL_BASE + 8) - eor r10, r10, r9, lsl #(PIXEL_BASE + 2) + eor r10, r10, r9, lsl #(4 - PIXEL_BASE) .endm .macro CAPTURE_TWELVE_BITS_16BPP_HI reg - // Pixel 0 in GPIO 9.. 2 -> 7.. 0 + // Pixel in GPIO 13.. 2 -> 31.. 16 + and r9, r8, #0x0f << PIXEL_BASE - eor r10, r10, r9, lsl #(16 - PIXEL_BASE + 1) - and r14, r8, #0x0f << (PIXEL_BASE + 4) - eor r10, r10, r14, lsl #(16 + PIXEL_BASE + 1) + eor r10, r10, r9, lsl #(16 - (PIXEL_BASE - 1)) + and r9, r8, #0x0f << (PIXEL_BASE + 4) + eor r10, r10, r9, lsl #(16 + (3 - PIXEL_BASE)) and r9, r8, #0x0f << (PIXEL_BASE + 8) - eor \reg, r10, r9, lsl #(16 + PIXEL_BASE + 2) + eor \reg, r10, r9, lsl #(16 + (4 - PIXEL_BASE)) + tst r3, #BIT_OSD + movne \reg, \reg, lsr #1 + .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)) +.macro CAPTURE_TWELVE_BITS_DOUBLE_16BPP reg reg2 + // Pixel in GPIO 13.. 2 -> 15.. 0 + and r9, r8, #0x0f << PIXEL_BASE + eor r10, \reg, r9, lsr #(PIXEL_BASE - 1) + and r9, r8, #0x0f << (PIXEL_BASE + 4) + eor r10, r10, r9, lsl #(3 - PIXEL_BASE) + and r9, r8, #0x0f << (PIXEL_BASE + 8) + eor r10, r10, r9, lsl #(4 - PIXEL_BASE) // Pixel double - orr \reg2, r10, r10, lsl #8 + orr \reg2, r10, r10, lsl #16 + tst r3, #BIT_OSD + movne \reg2, \reg2, lsr #1 .endm + .macro CAPTURE_LOW_BITS_TRANSLATE // Pixel 0 in GPIO 4.. 2 -> 7.. 4 // Pixel 1 in GPIO 7.. 5 -> 3.. 0 diff --git a/src/osd.c b/src/osd.c index e038c069..729521c1 100644 --- a/src/osd.c +++ b/src/osd.c @@ -1447,7 +1447,9 @@ static void redraw_menu() { i++; } } - osd_update((uint32_t *) (capinfo->fb + capinfo->pitch * capinfo->height * get_current_display_buffer() + capinfo->pitch * capinfo->v_adjust + capinfo->h_adjust), capinfo->pitch); + if ((capinfo->bpp) != 16) { + osd_update((uint32_t *) (capinfo->fb + capinfo->pitch * capinfo->height * get_current_display_buffer() + capinfo->pitch * capinfo->v_adjust + capinfo->h_adjust), capinfo->pitch); + } } static int get_key_down_duration(int key) { @@ -2847,7 +2849,7 @@ void generate_palettes() { void osd_update_palette() { - if (capinfo->bpp != 16) { + if (capinfo->bpp < 16) { int r = 0; int g = 0; int b = 0; @@ -4151,7 +4153,6 @@ void osd_init() { // ======= 16 bits/pixel tables for 8x8 font====== - // Normal size // aaaaaaaa bbbbbbbb if (j < 2) { @@ -4317,7 +4318,7 @@ void osd_update(uint32_t *osd_base, int bytes_per_line) { return; } // SAA5050 character data is 12x20 - int bufferCharWidth = capinfo->width / 12; // SAA5050 character data is 12x20 + int bufferCharWidth = (capinfo->width / 12) - 2; // SAA5050 character data is 12x20 uint32_t *line_ptr = osd_base; int words_per_line = bytes_per_line >> 2; @@ -4552,7 +4553,7 @@ void osd_update_fast(uint32_t *osd_base, int bytes_per_line) { return; } // SAA5050 character data is 12x20 - int bufferCharWidth = capinfo->width / 12; // SAA5050 character data is 12x20 + int bufferCharWidth = (capinfo->width / 12) - 2; // SAA5050 character data is 12x20 uint32_t *line_ptr = osd_base; int words_per_line = bytes_per_line >> 2; @@ -4568,7 +4569,7 @@ void osd_update_fast(uint32_t *osd_base, int bytes_per_line) { break; } - if (((capinfo->sizex2 & 1) && capinfo->nlines > FONT_THRESHOLD * 10) && (bufferCharWidth >= LINELEN) && allow1220font) { // if frame buffer is large enough and not 8bpp use SAA5050 font + if (((capinfo->sizex2 & 1) && capinfo->nlines > FONT_THRESHOLD * 10) && (bufferCharWidth > LINELEN) && allow1220font) { // if frame buffer is large enough and not 8bpp use SAA5050 font for (int line = 0; line <= osd_hwm; line++) { int attr = attributes[line]; int len = (attr & ATTR_DOUBLE_SIZE) ? (LINELEN >> 1) : LINELEN; diff --git a/src/rgb_to_fb.S b/src/rgb_to_fb.S index 4a307839..1c84e3e2 100644 --- a/src/rgb_to_fb.S +++ b/src/rgb_to_fb.S @@ -1782,57 +1782,56 @@ capture_line_normal_3bpp_table: .word capture_line_fast_8bpp capture_line_normal_6bpp_table: - .word capture_line_default_sixbits_4bpp + .word capture_line_default_sixbits_16bpp .word capture_line_default_sixbits_8bpp - .word capture_line_default_sixbits_4bpp // placeholder inband - .word capture_line_default_sixbits_8bpp // placeholder inband - .word capture_line_default_sixbits_4bpp + .word capture_line_default_sixbits_16bpp // placeholder inband + .word capture_line_default_sixbits_8bpp // placeholder inband + .word capture_line_default_sixbits_16bpp .word capture_line_ntsc_sixbits_8bpp_cga - .word capture_line_default_sixbits_4bpp + .word capture_line_default_sixbits_16bpp .word capture_line_ntsc_sixbits_8bpp_mono - .word capture_line_default_sixbits_4bpp + .word capture_line_default_sixbits_16bpp .word capture_line_ntsc_sixbits_8bpp_mono_auto - .word capture_line_default_sixbits_double_4bpp + .word capture_line_default_sixbits_double_16bpp .word capture_line_default_sixbits_double_8bpp - .word capture_line_default_sixbits_double_4bpp // placeholder inband - .word capture_line_default_sixbits_double_8bpp // placeholder inband - .word capture_line_default_sixbits_double_4bpp // placeholder ntsc - .word capture_line_default_sixbits_double_8bpp // placeholder ntsc - .word capture_line_default_sixbits_double_4bpp // placeholder ntsc - .word capture_line_default_sixbits_double_8bpp // placeholder ntsc - .word capture_line_default_sixbits_double_4bpp // placeholder ntsc - .word capture_line_default_sixbits_double_8bpp // placeholder ntsc + .word capture_line_default_sixbits_double_16bpp // placeholder inband + .word capture_line_default_sixbits_double_8bpp // placeholder inband + .word capture_line_default_sixbits_double_16bpp // placeholder ntsc + .word capture_line_default_sixbits_double_8bpp // placeholder ntsc + .word capture_line_default_sixbits_double_16bpp // placeholder ntsc + .word capture_line_default_sixbits_double_8bpp // placeholder ntsc + .word capture_line_default_sixbits_double_16bpp // placeholder ntsc + .word capture_line_default_sixbits_double_8bpp // placeholder ntsc - .word capture_line_fast_sixbits_4bpp + .word capture_line_fast_sixbits_16bpp .word capture_line_fast_sixbits_8bpp - capture_line_normal_8bpp_table: - .word capture_line_default_twelvebits_16bpp + .word capture_line_default_eightbits_16bpp .word capture_line_default_eightbits_8bpp - .word capture_line_default_twelvebits_16bpp + .word capture_line_default_eightbits_16bpp .word capture_line_default_eightbits_8bpp - .word capture_line_default_twelvebits_16bpp + .word capture_line_default_eightbits_16bpp .word capture_line_default_eightbits_8bpp - .word capture_line_default_twelvebits_16bpp + .word capture_line_default_eightbits_16bpp .word capture_line_default_eightbits_8bpp - .word capture_line_default_twelvebits_16bpp + .word capture_line_default_eightbits_16bpp .word capture_line_default_eightbits_8bpp - .word capture_line_default_twelvebits_double_16bpp + .word capture_line_default_eightbits_double_16bpp .word capture_line_default_eightbits_double_8bpp - .word capture_line_default_twelvebits_double_16bpp + .word capture_line_default_eightbits_double_16bpp .word capture_line_default_eightbits_double_8bpp - .word capture_line_default_twelvebits_double_16bpp + .word capture_line_default_eightbits_double_16bpp .word capture_line_default_eightbits_double_8bpp - .word capture_line_default_twelvebits_double_16bpp + .word capture_line_default_eightbits_double_16bpp .word capture_line_default_eightbits_double_8bpp - .word capture_line_default_twelvebits_double_16bpp + .word capture_line_default_eightbits_double_16bpp .word capture_line_default_eightbits_double_8bpp - .word capture_line_default_twelvebits_16bpp + .word capture_line_fast_eightbits_16bpp .word capture_line_fast_eightbits_8bpp diff --git a/src/rgb_to_hdmi.c b/src/rgb_to_hdmi.c index e69bd646..062f369c 100644 --- a/src/rgb_to_hdmi.c +++ b/src/rgb_to_hdmi.c @@ -376,6 +376,11 @@ static int last_height = -1; // or the RPI_PropertyGet seems to return garbage log_info("Width or Height differ from last FB: Setting dummy 64x64 framebuffer"); } + int adjusted_width = capinfo->width; + + if (capinfo->sample_width == SAMPLE_WIDTH_6 && capinfo->bpp == 16) { //special double rate 6 bpp mode + adjusted_width >>= 1; + } /* work out if overscan needed */ @@ -388,7 +393,7 @@ static int last_height = -1; if (get_gscaling() == GSCALING_INTEGER) { if (!((capinfo->video_type == VIDEO_TELETEXT && get_m7scaling() == SCALING_UNEVEN) ||(capinfo->video_type != VIDEO_TELETEXT && get_normalscaling() == SCALING_UNEVEN))) { - int width = capinfo->width >> ((capinfo->sizex2 & 2) >> 1); + int width = adjusted_width >> ((capinfo->sizex2 & 2) >> 1); int hscale = h_size / width; h_overscan = h_size - (hscale * width); } @@ -417,13 +422,16 @@ static int last_height = -1; /* Initialise a framebuffer... */ RPI_PropertyInit(); RPI_PropertyAddTag(TAG_ALLOCATE_BUFFER, 0x02000000); - RPI_PropertyAddTag(TAG_SET_PHYSICAL_SIZE, capinfo->width, capinfo->height); + RPI_PropertyAddTag(TAG_SET_PHYSICAL_SIZE, adjusted_width, capinfo->height); #ifdef MULTI_BUFFER - RPI_PropertyAddTag(TAG_SET_VIRTUAL_SIZE, capinfo->width, capinfo->height * NBUFFERS); + RPI_PropertyAddTag(TAG_SET_VIRTUAL_SIZE, adjusted_width, capinfo->height * NBUFFERS); #else - RPI_PropertyAddTag(TAG_SET_VIRTUAL_SIZE, capinfo->width, capinfo->height); + RPI_PropertyAddTag(TAG_SET_VIRTUAL_SIZE, adjusted_width, capinfo->height); #endif RPI_PropertyAddTag(TAG_SET_DEPTH, capinfo->bpp); + //if (capinfo->bpp >= 16) { + // RPI_PropertyAddTag( TAG_SET_PIXEL_ORDER, 1); + //} RPI_PropertyAddTag(TAG_SET_OVERSCAN, top_overscan, bottom_overscan, left_overscan, right_overscan); RPI_PropertyAddTag(TAG_GET_PITCH); RPI_PropertyAddTag(TAG_GET_PHYSICAL_SIZE); @@ -440,7 +448,7 @@ static int last_height = -1; int width = mp->data.buffer_32[0]; int height = mp->data.buffer_32[1]; log_info("Size: %dx%d (requested %dx%d)", width, height, capinfo->width, capinfo->height); - if (width != capinfo->width || height != capinfo->height) { + if (width != adjusted_width || height != capinfo->height) { log_info("Invalid frame buffer dimensions - maybe HDMI not connected - rebooting"); delay_in_arm_cycles_cpu_adjust(1000000000); reboot(); @@ -471,6 +479,8 @@ static int last_height = -1; // I was hoping it would then be possible to page flip just by modifying the structure // in-place. Unfortunately that didn't work, but the code might be useful in the future. + +// THIS CALL IS NOT USED AND HAS NOT BEEN UPDATED static void init_framebuffer(capture_info_t *capinfo) { static int last_width = -1; static int last_height = -1; @@ -2358,9 +2368,13 @@ void calculate_fb_adjustment() { capinfo->h_adjust <<= 3; break; case 16: - capinfo->h_adjust <<= 4; + if (capinfo->sample_width == SAMPLE_WIDTH_6) { //special double rate 6 bpp mode + capinfo->h_adjust <<= 3; + } else { + capinfo->h_adjust <<= 4; + } break; - } + } //log_info("adjust=%d, %d", capinfo->h_adjust, capinfo->v_adjust); } @@ -2705,6 +2719,7 @@ void rgb_to_hdmi_main() { ncapture = osd_key(OSD_SW3); } + cpld->update_capture_info(capinfo); geometry_get_fb_params(capinfo); capinfo->palette_control = paletteControl; if (capinfo->palette_control == PALETTECONTROL_NTSCARTIFACT_CGA && ntsccolour == 0) { @@ -2729,7 +2744,7 @@ void rgb_to_hdmi_main() { || capinfo->video_type != last_capinfo.video_type || capinfo->px_sampling != last_capinfo.px_sampling || profile != last_profile || last_subprofile != subprofile || cpld->get_divider() != last_divider || (result & RET_SYNC_TIMING_CHANGED); - if (active_size_changed) { + if (active_size_changed || fb_size_changed) { clear = BIT_CLEAR; } @@ -2757,6 +2772,21 @@ void force_reinit() { int show_detected_status(int line) { char message[80]; + int adjusted_width = capinfo->width; + int pitch = capinfo->pitch; + switch(capinfo->bpp) { + case 4: + pitch <<= 1; + break; + case 8: + break; + case 16: + pitch >>= 1; + if (capinfo->sample_width == SAMPLE_WIDTH_6) { //special double rate 6 bpp mode + adjusted_width >>= 1; + } + break; + } sprintf(message, " Pixel clock: %d Hz", adjusted_clock); osd_set(line++, 0, message); sprintf(message, " CPLD clock: %d Hz", adjusted_clock * cpld->get_divider()); @@ -2783,7 +2813,8 @@ int show_detected_status(int line) { osd_set(line++, 0, message); sprintf(message, " H & V range: %d-%d x %d-%d", capinfo->h_offset, capinfo->h_offset + (capinfo->chars_per_line << (3 - double_width)) - 1, capinfo->v_offset, capinfo->v_offset + capinfo->nlines - 1); osd_set(line++, 0, message); - sprintf(message, " Frame Buffer: %d x %d (%d x %d)", capinfo->width, capinfo->height, capinfo->pitch << (capinfo->bpp == 4 ? 1 : 0), capinfo->height); + + sprintf(message, " Frame Buffer: %d x %d (%d x %d)", adjusted_width, capinfo->height, pitch, capinfo->height); osd_set(line++, 0, message); int h_size = get_hdisplay(); int v_size = get_vdisplay();