diff --git a/src/armc-start.S b/src/armc-start.S index 937ebd93..6a89b5e7 100644 --- a/src/armc-start.S +++ b/src/armc-start.S @@ -132,10 +132,6 @@ _reset_: #endif // BL _enable_l1_cache - - - - #ifdef HAS_MULTICORE #ifdef KERNEL_OLD @@ -257,7 +253,7 @@ _reset_continue: // initialise the ro data section (most things that have the const // declaration) and initialise the bss section variables to 0 (generally // known as automatics). It'll then call main - + b _cstartup @@ -424,7 +420,7 @@ _data_memory_barrier: mov pc, lr #ifdef USE_MULTICORE -+.section ".text._init_core" +.section ".text._init_core" _init_core: // On a Raspberry Pi 2 we enter in HYP mode, and need to force a switch to supervisor mode mrs r0, cpsr @@ -508,7 +504,7 @@ _spin_core: bl RPI_AuxMiniUartWrite #endif _spin_core1: - wfi + wfe b _spin_core1 .section ".text._get_core" diff --git a/src/capture_line_mode7_4bpp.S b/src/capture_line_mode7_4bpp.S index d5a49e54..4b9a49af 100644 --- a/src/capture_line_mode7_4bpp.S +++ b/src/capture_line_mode7_4bpp.S @@ -20,6 +20,8 @@ // // All registers are available as scratch registers (i.e. nothing needs to be preserved) + .align 6 + .ltorg b preload_capture_line_mode7_4bpp // entry point for preloading cache capture_line_mode7_4bpp: @@ -27,29 +29,18 @@ capture_line_mode7_4bpp: // by Ian Bradbury (IanB on stardot). Many thanks Ian. // push {lr} - mov r5, r8 - SKIP_PSYNC - push {r14} + add r11, r0, r8 // offset to second buffer used for comparison not for display + mov r12, r0 // pointer to the line in the frame buffer tst r3, #BIT_CALIBRATE bne process_chars_7_none - ands r8, r3, #MASK_INTERLACE beq process_chars_7_none // DEINTERLACE_NONE - - mov r9, r8, lsr #OFFSET_INTERLACE // put interlace setting in R9 0-6 - - cmp r9, #1 //DEINTERLACE_BOB + mov r8, r8, lsr #OFFSET_INTERLACE // put interlace setting in R9 0-6 + cmp r8, #1 //DEINTERLACE_BOB beq process_chars_7_bob - tst r3, #BIT_FIELD_TYPE // test odd or even field - - add r11, r0, r5 // offset to second buffer used for comparison not for display - rsbeq r2, r2,#0 // negate R2 offset if odd field to write to line above (restored to original value on exit) - - mov r12, r0 // pointer to the line in the frame buffer - - cmp r9, #6 //DEINTERLACE_ADV + cmp r8, #6 //DEINTERLACE_ADV beq process_chars_7_advanced // Simple motion adaptive deinterlace @@ -69,6 +60,8 @@ capture_line_mode7_4bpp: // r11 = pointer into comparison buffer (moves within line) // r12 = pixel value from comparison buffer + SKIP_PSYNC + push {r14} mov r5, #0 mov r6, #0 mov r7, #0 @@ -79,7 +72,7 @@ capture_line_mode7_4bpp: eorne r7, r7, #0x02000000 //green in rightmost process_chars_loop_7_simple: -#if defined(RPI2) || defined(RPI3) || defined(RPI4) +#ifdef USE_ALT_DEINTERLACE_CODE WAIT_FOR_PSYNC_EDGE ldr r5, [r0] // preload old pixel value from video buffer CAPTURE_LOW_BITS @@ -145,8 +138,13 @@ process_chars_loop_7_simple: bne process_chars_loop_7_simple pop {r0, pc} + .align 6 + .ltorg process_chars_7_none: // No deinterlace + + SKIP_PSYNC + push {r14} mov r7, #0 tst r3, #BIT_VSYNC_MARKER ldrne r7, =0x11111111 // the VSync indicator @@ -174,8 +172,12 @@ process_chars_loop_7_none: bne process_chars_loop_7_none pop {r0, pc} + .align 6 + .ltorg process_chars_7_bob: // Simple bob deinterlace + SKIP_PSYNC + push {r14} mov r5, #0 mov r6, #0 mov r7, #0 @@ -187,19 +189,19 @@ process_chars_7_bob: ldr r11, =0x77777777 // mask to extract OSD process_chars_loop_7_bob: WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 -#if defined(RPI2) || defined(RPI3) || defined(RPI4) +#ifdef USE_ALT_DEINTERLACE_CODE ldr r6, [r0, r2] // preload old pixel value from other field of video buffer CAPTURE_LOW_BITS // input in r8, result in r10, corrupts r9/r14 - WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 - ldr r5, [r0] // preload old pixel value from video buffer + WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 + ldr r5, [r0] // preload old pixel value from video buffer #else tst r3, #BIT_OSD ldrne r6, [r0, r2] // preload old pixel value from other field of video buffer CAPTURE_LOW_BITS // input in r8, result in r10, corrupts r9/r14 WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8 - tst r3, #BIT_OSD - ldrne r5, [r0] // preload old pixel value from video buffer -#endif + tst r3, #BIT_OSD + ldrne r5, [r0] // preload old pixel value from video buffer +#endif CAPTURE_HIGH_BITS // input in r8, result in r10, corrupts r9/r14 eor r10, r10, r7 // EOR in the VSync indicator bic r9, r5, r11 @@ -213,6 +215,9 @@ process_chars_loop_7_bob: subs r1, r1, #1 bne process_chars_loop_7_bob pop {r0, pc} + + .align 6 + .ltorg // all 6 osd buffers must be sequential osdbuffer3: .word 0 @@ -224,6 +229,8 @@ osdbufferA3: .word 0 charline: .word 0 +r1save: + .word 0 process_chars_7_advanced: // Advanced deinterlace @@ -244,22 +251,52 @@ process_chars_7_advanced: // r11 = pointer into comparison buffer (moves within line) // r12 = pointer into frame buffer (moves within line) // r14 = misc - str r6, charline +#ifdef USE_MULTICORE + ldr r8, =line_buffer + ldr r10, =read_pointer + str r8, [r10], #4 + str r8, [r10], #4 //write_pointer + str r3, [r10], #4 //r3copy + str r4, [r10], #4 //r4copy + str r9, [r10], #4 //r9copy + str r1, [r10], #4 //capture_count + str r7, [r10] //skip_count + dmb // wait until memory written + sev // wake up core +waitforskip: + ldr r7, [r10] + cmp r7, #0 + bne waitforskip + READ_CYCLE_COUNTER r14 +#else + SKIP_PSYNC +#endif + push {r14} process_chars_loop_7_advanced: - - WAIT_FOR_PSYNC_EDGE_FAST - push {r1} - CAPTURE_LOW_BITS +#ifdef USE_MULTICORE + str r1, r1save + CAPTURE_FROM_CORE1 tst r3, #BIT_OSD ldmneia r12, {r5, r6, r7} // preload current field old screen values (three words) if OSD on moveq r5,#0 moveq r6,#0 - moveq r7,#0 + moveq r7,#0 + ldr r1, =0x77777777 // osd bitmask +#else + WAIT_FOR_PSYNC_EDGE_FAST + str r1, r1save + CAPTURE_LOW_BITS + tst r3, #BIT_OSD + ldmneia r12, {r5, r6, r7} // preload current field old screen values (three words) if OSD on + moveq r5,#0 + moveq r6,#0 + moveq r7,#0 ldr r1, =0x77777777 // osd bitmask WAIT_FOR_PSYNC_EDGE_FAST CAPTURE_HIGH_BITS +#endif str r10, [r11] // save new value in comparison buffer mov r0, r10 // save left pixel data for later @@ -286,6 +323,17 @@ process_chars_loop_7_advanced: ldreq r6, [r14, #4] // always load middle word as sometimes half has to be written back to screen during deinterlace moveq r5,#0 moveq r7,#0 + +#ifdef USE_MULTICORE + adr r14, osdbufferA1 + bic r5, r5, r1 // extract OSD bits + bic r7, r7, r1 // extract OSD bits + stmia r14, {r5, r6, r7} // save for later in osdbufferA1 but don't extract OSD bits on r6 as might need half old pixel data + mov r1, r10 + CAPTURE_FROM_CORE1 + add r14, r11, r2 // r14 points to other field + ldmia r14, {r5, r6, r7} // preload other field old values from comparison buffer (3 words) +#else WAIT_FOR_PSYNC_EDGE_FAST adr r14, osdbufferA1 bic r5, r5, r1 // extract OSD bits @@ -294,10 +342,10 @@ process_chars_loop_7_advanced: mov r1, r10 add r14, r11, r2 // r14 points to other field CAPTURE_LOW_BITS - ldmia r14, {r5, r6, r7} // preload other field old values from comparison buffer (3 words) + ldmia r14, {r5, r6, r7} // preload other field old values from comparison buffer (3 words) WAIT_FOR_PSYNC_EDGE_FAST CAPTURE_HIGH_BITS - +#endif // r0 = left 8 pixels of 1st char // r10 bottom half = right 4 pixels of 1st char // r5 = left 8 pixels of 1st char from other field comparison buffer @@ -422,12 +470,14 @@ deinterlace1: nodeinterlace1: mov r0, r10 // save middle word in r0 - +#ifdef USE_MULTICORE + CAPTURE_FROM_CORE1 +#else WAIT_FOR_PSYNC_EDGE_FAST CAPTURE_LOW_BITS WAIT_FOR_PSYNC_EDGE_FAST CAPTURE_HIGH_BITS - +#endif // deinterlace 2nd char here // all the above code is repeated for the 2nd character but is slightly different @@ -557,18 +607,26 @@ deinterlace2: nodeinterlace2: - pop {r1} + ldr r1, r1save add r11, r11, #12 add r12, r12, #12 subs r1, r1, #3 + cmp r1, #0 bgt process_chars_loop_7_advanced pop {r0, pc} preload_capture_line_mode7_4bpp: + adr r0, rounding_lookup + ldr r1, =rounding_end +preload_loop: + ldr r2,[r0], #4 + cmp r0, r1 + blt preload_loop SETUP_DUMMY_PARAMETERS b capture_line_mode7_4bpp // Insert the current literal pool, otherwise constants are to far away and you get a build error + .align 6 .ltorg rounding_lookup: @@ -5216,3 +5274,4 @@ rounding_lookup: .byte 0x00 .byte 0x00 .byte 0x00 +rounding_end: diff --git a/src/cpld_rgb.c b/src/cpld_rgb.c index 12c45394..4ac2eb6a 100644 --- a/src/cpld_rgb.c +++ b/src/cpld_rgb.c @@ -261,7 +261,7 @@ static void write_config(config_t *config) { // delay = 1 : use BCDEFA // delay = 2 : use CDEFAB // etc - int offset = (supports_delay && mode7) ? (i + config->full_px_delay) % NUM_OFFSETS : i; + int offset = (supports_delay && capinfo->video_type == VIDEO_TELETEXT) ? (i + config->full_px_delay) % NUM_OFFSETS : i; sp |= (config->sp_offset[i] & 7) << (offset * 3); } if (config->half_px_delay) { @@ -553,7 +553,7 @@ static void cpld_calibrate(capture_info_t *capinfo, int elk) { } // If the min metric is at the limit, make use of the half pixel delay - if (mode7 && min_metric > 0 && (min_i <= 1 || min_i >= 6)) { + if (capinfo->video_type == VIDEO_TELETEXT && min_metric > 0 && (min_i <= 1 || min_i >= 6)) { log_info("Enabling half pixel delay"); config->half_px_delay = 1; min_i ^= 4; @@ -575,7 +575,7 @@ static void cpld_calibrate(capture_info_t *capinfo, int elk) { write_config(config); // If the metric is non zero, there is scope for further optimization in mode7 - if (mode7 && min_metric > 0) { + if (capinfo->video_type == VIDEO_TELETEXT && min_metric > 0) { log_info("Optimizing calibration"); for (int i = 0; i < NUM_OFFSETS; i++) { // Start with current value of the sample point i @@ -609,7 +609,7 @@ static void cpld_calibrate(capture_info_t *capinfo, int elk) { // Determine mode 7 alignment if (supports_delay) { signed int new_full_px_delay; - if (mode7) { + if (capinfo->video_type == VIDEO_TELETEXT) { new_full_px_delay = analyze_mode7_alignment(capinfo); } else { new_full_px_delay = analyze_default_alignment(capinfo); @@ -652,6 +652,8 @@ static void update_param_range() { // Divider = 0 gives 6 clocks per pixel // Divider = 1 gives 8 clocks per pixel RPI_SetGpioValue(MODE7_PIN, config->divider == 8); + + } static void cpld_set_mode(int mode) { @@ -711,7 +713,6 @@ static void cpld_update_capture_info(capture_info_t *capinfo) { // Update the sample width capinfo->sample_width = (config->rate == 1); // 1 = 6bpp, everything else 3bpp // Update the line capture function - if (!mode7) { if (capinfo->sample_width) { switch (capinfo->px_sampling) { case PS_NORMAL: @@ -749,13 +750,16 @@ static void cpld_update_capture_info(capture_info_t *capinfo) { break; } } - } else { - capinfo->capture_line = capture_line_mode7_3bpp_table; - } } } static param_t *cpld_get_params() { + params[A_OFFSET].hidden = !mode7; + params[B_OFFSET].hidden = !mode7; + params[C_OFFSET].hidden = !mode7; + params[D_OFFSET].hidden = !mode7; + params[E_OFFSET].hidden = !mode7; + params[F_OFFSET].hidden = !mode7; return params; } diff --git a/src/defs.h b/src/defs.h index def88c50..75927e7b 100644 --- a/src/defs.h +++ b/src/defs.h @@ -71,7 +71,9 @@ #define BIT_NO_H_SCROLL 0x04000000 // bit 26, if set then smooth H scrolling disabled #define BIT_ELK 0x08000000 // bit 27, indicates we are an Electron #define BIT_NO_AUTOSWITCH 0x10000000 // bit 28, if set then autoselect enabled - // bit 29+ unused +#define BIT_TELETEXT 0x20000000 // bit 29, if set then teletext enabled +#define BIT_NO_SKIP_HSYNC 0x40000000 // bit 30 clear if hsync is ignored (used by cache preload) +#define BIT_INHIBIT_MODE_DETECT 0x80000000 // bit 31 inhibit mode detection if sideways scrolling // R0 return value bits #define RET_SW1 0x02 @@ -98,10 +100,14 @@ // Pi 2/3 Multicore options #if defined(RPI2) || defined(RPI3) || defined(RPI4) - // Indicate the platform has multiple cores -#define HAS_MULTICORE +#define HAS_MULTICORE // puts unused cores to sleep +#endif +#if defined(RPI2) || defined(RPI3) // Pi4 may not need these +#define USE_MULTICORE // makes Advanced Motion deinterlace use 2nd core +#define USE_ALT_DEINTERLACE_CODE // uses re-ordered code for bob and simple motion deinterlace +#define USE_CACHED_COMPARISON_BUFFER // uses cached memory for the comparison buffer with simple & advanced motion deinterlace #endif #ifdef __ASSEMBLER__ @@ -137,8 +143,9 @@ #define O_SYNCTYPE 60 #define O_DETSYNCTYPE 64 #define O_VSYNCTYPE 68 -#define O_BORDER 72 -#define O_CAPTURE_LINE 76 +#define O_VIDEOTYPE 72 +#define O_BORDER 76 +#define O_CAPTURE_LINE 80 #else @@ -161,6 +168,7 @@ typedef struct { int sync_type; // expected sync type and polarity int detected_sync_type; // detected sync type and polarity int vsync_type; // expected vertical sync type + int video_type; // expected video type / progressive / interlaced (teletext) int border; // border logical colour int (*capture_line)(); // the capture line function to use int px_sampling; // whether to sample normally, sub-sample or pixel double @@ -243,8 +251,20 @@ typedef struct { #define FRAME_MINIMUM 10000000 // 10ms #define FRAME_TIMEOUT 24000000 // 24ms which is over a frame / field @ 50Hz (20ms) #define LINE_MINIMUM 20000 // 20uS -//#define LINE_TIMEOUT 74000 // 74uS -#define LINE_TIMEOUT 74*1024 +#define HSYNC_SCROLL_LO (4000 - 250) +#define HSYNC_SCROLL_HI (4000 + 250) + + +#if defined(RPI4) +#define LINE_TIMEOUT (100 * 1500/1000 * 1024) +#elif defined(RPI3) +#define LINE_TIMEOUT (100 * 1200/1000 * 1024) +#elif defined(RPI2) +#define LINE_TIMEOUT (100 * 1000/1000 * 1024) +#else +#define LINE_TIMEOUT (100 * 1024) +#endif + #if defined(RPI4) #define CRYSTAL 54 diff --git a/src/geometry.c b/src/geometry.c index 41461310..7dd88c37 100644 --- a/src/geometry.c +++ b/src/geometry.c @@ -46,6 +46,12 @@ static const char *fb_sizex2_names[] = { "Double Height+Width", }; +static const char *deint_names[] = { + "Progressive", + "Interlaced Teletext" +}; + + static param_t params[] = { { SETUP_MODE, "Setup Mode", "setup_mode", 0,NUM_SETUP-1, 1 }, { H_OFFSET, "H Offset", "h_offset", 0, 512, 4 }, @@ -64,6 +70,7 @@ static param_t params[] = { { LINES_FRAME, "Lines per Frame", "lines_per_frame", 250, 1200, 1 }, { SYNC_TYPE, "Sync Type", "sync_type", 0, NUM_SYNC-1, 1 }, { VSYNC_TYPE, "V Sync Type", "vsync_type", 0,NUM_VSYNC-1, 1 }, + { VIDEO_TYPE, "Video Type", "video_type", 0,NUM_VIDEO-1, 1 }, { PX_SAMPLING, "Pixel Sampling", "pixel_sampling", 0, NUM_PS-1, 1 }, { -1, NULL, NULL, 0, 0, 0 } }; @@ -86,6 +93,7 @@ typedef struct { int lines_per_frame; // number of lines per frame int sync_type; // sync type and polarity int vsync_type; // vsync type auto/interlaced/non-interlaced + int video_type; // deinterlace type off/teletext int px_sampling; // pixel sampling mode } geometry_t; @@ -120,6 +128,7 @@ void geometry_init(int version) { mode7_geometry.lines_per_frame = 625; mode7_geometry.sync_type = SYNC_COMP; mode7_geometry.vsync_type = VSYNC_AUTO; + mode7_geometry.video_type = VIDEO_TELETEXT; mode7_geometry.px_sampling = PS_NORMAL; default_geometry.setup_mode = 0; @@ -138,6 +147,7 @@ void geometry_init(int version) { default_geometry.lines_per_frame = 625; default_geometry.sync_type = SYNC_COMP; default_geometry.vsync_type = VSYNC_AUTO; + default_geometry.video_type = VIDEO_PROG; default_geometry.px_sampling = PS_NORMAL; int firmware_support = cpld->old_firmware_support(); @@ -199,8 +209,10 @@ int geometry_get_value(int num) { return geometry->lines_per_frame; case SYNC_TYPE: return geometry->sync_type; - case VSYNC_TYPE: + case VSYNC_TYPE: return geometry->vsync_type; + case VIDEO_TYPE: + return geometry->video_type; case PX_SAMPLING: if (use_px_sampling == 0) { geometry->px_sampling = 0; @@ -226,6 +238,9 @@ const char *geometry_get_value_string(int num) { if (num == FB_SIZEX2) { return fb_sizex2_names[geometry_get_value(num)]; } + if (num == VIDEO_TYPE) { + return deint_names[geometry_get_value(num)]; + } return NULL; } @@ -288,6 +303,9 @@ void geometry_set_value(int num, int value) { case VSYNC_TYPE: geometry->vsync_type = value; break; + case VIDEO_TYPE: + geometry->video_type = value; + break; case PX_SAMPLING: if (use_px_sampling == 0) { geometry->px_sampling = 0; @@ -373,6 +391,21 @@ void geometry_get_fb_params(capture_info_t *capinfo) { geometry_max_v_height = geometry_min_v_height; } +#if defined(RPI2) || defined(RPI3) //clip capture size to avoid glitches on RPI2 & RPI3 (not needed on RPI4) + if (geometry_min_h_width > 704 && geometry_min_v_height > 272 && geometry_min_v_height < 300) { + geometry_min_v_height = 272; + } + if (geometry_min_h_width > 704) { + geometry_min_h_width = 704; + } + if (geometry_max_h_width > 704 && geometry_max_v_height > 272 && geometry_max_v_height < 300) { + geometry_max_v_height = 272; + } + if (geometry_max_h_width > 704) { + geometry_max_h_width = 704; + } +#endif + if (use_px_sampling != 0) { capinfo->px_sampling = geometry->px_sampling; } else { @@ -382,6 +415,7 @@ void geometry_get_fb_params(capture_info_t *capinfo) { capinfo->bpp = geometry->fb_bpp; capinfo->sync_type = geometry->sync_type; capinfo->vsync_type = geometry->vsync_type; + capinfo->video_type = geometry->video_type; if (geometry->setup_mode == SETUP_NORMAL) { capinfo->border = get_border(); @@ -449,10 +483,10 @@ void geometry_get_fb_params(capture_info_t *capinfo) { } int h_size43_adj = h_size43; - if ((mode7 && m7scaling == M7_UNEVEN) - || (!mode7 && normalscaling == NORMAL_UNEVEN && geometry->h_aspect == 3 && geometry->v_aspect == 2)) { + if ((capinfo->video_type == VIDEO_TELETEXT && m7scaling == SCALING_UNEVEN) + || (capinfo->video_type != VIDEO_TELETEXT && normalscaling == SCALING_UNEVEN && geometry->h_aspect == 3 && (geometry->v_aspect == 2 || geometry->v_aspect == 4))) { h_size43_adj = h_size43 * 3 / 4; - if (h_aspect !=0 && v_aspect !=0) { + if (h_aspect == 3 && (v_aspect == 2 || v_aspect == 4)) { h_aspect--; } } @@ -559,8 +593,8 @@ void geometry_get_fb_params(capture_info_t *capinfo) { capinfo->width = adjusted_width + hborder; capinfo->height = adjusted_height + vborder; - if ((mode7 && m7scaling == M7_UNEVEN) // workaround mode 7 width so it looks like other modes - ||(!mode7 && normalscaling == NORMAL_UNEVEN && geometry->h_aspect == 3 && geometry->v_aspect == 2)) { + if ((capinfo->video_type == VIDEO_TELETEXT && m7scaling == SCALING_UNEVEN) // workaround mode 7 width so it looks like other modes + ||(capinfo->video_type != VIDEO_TELETEXT && normalscaling == SCALING_UNEVEN && geometry->h_aspect == 3 && (geometry->v_aspect == 2 || geometry->v_aspect == 4))) { capinfo->width = capinfo->width * 3 / 4; } @@ -599,7 +633,7 @@ void geometry_get_fb_params(capture_info_t *capinfo) { //log_info("Clipping capture height to %d", capinfo->nlines); } - if (mode7) { + if (capinfo->video_type == VIDEO_TELETEXT) { capvscale >>= 1; } else { if (osd_active()) { diff --git a/src/geometry.h b/src/geometry.h index 352719d1..4314dacc 100644 --- a/src/geometry.h +++ b/src/geometry.h @@ -32,6 +32,12 @@ enum { NUM_VSYNC }; +enum { + VIDEO_PROG, + VIDEO_TELETEXT, + NUM_VIDEO +}; + enum { SETUP_MODE, H_OFFSET, @@ -50,6 +56,7 @@ enum { LINES_FRAME, SYNC_TYPE, VSYNC_TYPE, + VIDEO_TYPE, PX_SAMPLING }; diff --git a/src/macros.S b/src/macros.S index 098e34fa..58d43b0b 100644 --- a/src/macros.S +++ b/src/macros.S @@ -9,7 +9,7 @@ tst r8, #CSYNC_MASK .endm -.macro LINE_TIMEOUT_TEST_R9 +.macro LINE_TIMEOUT_TEST_SKIP_HSYNC READ_CYCLE_COUNTER r8 subs r8, r8, r14 rsbmi r8, r8, #0 @@ -17,7 +17,7 @@ // 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 + tst r3, #BIT_NO_SKIP_HSYNC tstne r8, #CSYNC_MASK .endm @@ -30,19 +30,19 @@ waitlo\@: bne waitlo\@ .endm -.macro WAIT_FOR_CSYNC_0_R9 +.macro WAIT_FOR_CSYNC_0_SKIP_HSYNC READ_CYCLE_COUNTER r14 waitlo9\@: - LINE_TIMEOUT_TEST_R9 + LINE_TIMEOUT_TEST_SKIP_HSYNC bne waitlo9\@ - LINE_TIMEOUT_TEST_R9 + LINE_TIMEOUT_TEST_SKIP_HSYNC bne waitlo9\@ .endm -.macro WAIT_FOR_CSYNC_0_FAST_R9 +.macro WAIT_FOR_CSYNC_0_FAST_SKIP_HSYNC READ_CYCLE_COUNTER r14 waitloF\@: - LINE_TIMEOUT_TEST_R9 + LINE_TIMEOUT_TEST_SKIP_HSYNC bne waitloF\@ .endm @@ -113,7 +113,7 @@ waitPF\@: .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 + WAIT_FOR_CSYNC_0_SKIP_HSYNC READ_CYCLE_COUNTER r10 bic r3, r3, #PSYNC_MASK // wait for zero after CSYNC // Wait for the end of hsync @@ -129,24 +129,32 @@ waitPF\@: // - 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 + bic r3, #BIT_INHIBIT_MODE_DETECT + mov r8, r7 + tst r3, #BIT_OLD_FIRMWARE_SUPPORT + beq notoldfirmwarescroll\@ // old CPLD V1 & V2 code - mov r9, r7 - cmp r10, #(4000 + 224) - addgt r9, r9, #1 - cmp r10, #(4000 - 224) - addgt r9, r9, #1 - + cmp r10, r9, lsr #16 //HSYNC_SCROLL_HI + addgt r8, r8, #1 + orrgt r3, r3, #BIT_INHIBIT_MODE_DETECT + bic r9, r9, #0xff000000 + bic r9, r9, #0x00ff0000 + cmp r10, r9 //HSYNC_SCROLL_LO + addgt r8, r8, #1 + orrlt r3, r3, #BIT_INHIBIT_MODE_DETECT + b doneoldfirmwarescroll\@ +notoldfirmwarescroll\@: // new CPLD V3 or later code - mov r8, r7 - cmp r10, #(4000 + 224) + cmp r10, r9, lsr #16 //HSYNC_SCROLL_HI addlt r8, r8, #1 - cmp r10, #(4000 - 224) + 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 - - tst r3, #BIT_OLD_FIRMWARE_SUPPORT - movne r8, r9 - + orrlt r3, r3, #BIT_INHIBIT_MODE_DETECT +doneoldfirmwarescroll\@: 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) @@ -158,7 +166,7 @@ skip_psync_loop\@: .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 + WAIT_FOR_CSYNC_0_FAST_SKIP_HSYNC READ_CYCLE_COUNTER r10 bic r3, r3, #PSYNC_MASK // wait for zero after CSYNC // Wait for the end of hsync @@ -177,11 +185,14 @@ skip_psync_loop\@: // new CPLD code only (not called from CPLD v1 & v2) mov r8, r7 - cmp r10, #(4000 + 224) + cmp r10, r9, lsr #16 //HSYNC_SCROLL_HI addlt r8, r8, #1 - cmp r10, #(4000 - 224) + 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) @@ -193,7 +204,7 @@ skip_psync_loop_no_old\@: .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 + WAIT_FOR_CSYNC_0_FAST_SKIP_HSYNC bic r3, r3, #PSYNC_MASK // wait for zero after CSYNC WAIT_FOR_CSYNC_1_FAST READ_CYCLE_COUNTER r14 @@ -203,6 +214,19 @@ skip_psync_loop_no_h_scroll\@: bne skip_psync_loop_no_h_scroll\@ .endm +#ifdef USE_MULTICORE +.macro CAPTURE_FROM_CORE1 + ldr r9, =read_pointer + ldr r8, [r9] //r8 is now read pointer and r9 points to write_pointer +wait_wr\@: + ldr r10, [r9, #4] //r10 is now write pointer + cmp r8, r10 + bge wait_wr\@ + ldr r10, [r8], #4 //r10 is now pixel quad + str r8, [r9] //save updated read pointer +.endm +#endif + .macro CAPTURE_LOW_BITS // Pixel 0 in GPIO 4.. 2 -> 7.. 4 // Pixel 1 in GPIO 7.. 5 -> 3.. 0 @@ -755,10 +779,11 @@ skip_psync_loop_no_h_scroll\@: mov r1, #3 mov r2, #0 orr r3, r3, #BIT_VSYNC_MARKER // ensure that constants are in data cache + bic r3, r3, #BIT_NO_SKIP_HSYNC mov r5, #1 mov r6, #0 mov r7, #2 - mov r8, #0 + mov r8, #256 mov r9, #0 //force skip of wait for csync 0 .endm @@ -816,7 +841,7 @@ novsync\@: #ifdef MULTI_BUFFER .macro FLIP_BUFFER // Skip the multi buffering in mode 7 and probe mode - tst r3, #(BIT_MODE7 | BIT_PROBE) + tst r3, #(BIT_TELETEXT | BIT_PROBE) bne noflip\@ // Flip to the last completed draw buffer // It seems the GPU delays this until the next vsync diff --git a/src/osd.c b/src/osd.c index 95244e6c..6aa6dc43 100644 --- a/src/osd.c +++ b/src/osd.c @@ -205,14 +205,9 @@ static const char *fontsize_names[] = { "Auto 12x20 8bpp" }; -static const char *m7scaling_names[] = { - "Uneven (3:2 to 4:3)", - "Even" -}; - -static const char *normalscaling_names[] = { +static const char *even_scaling_names[] = { "Even", - "Uneven (3:2 to 4:3)" + "Uneven (3:2>>4:3)" }; // ============================================================= @@ -260,9 +255,9 @@ static param_t features[] = { { F_SUBPROFILE, "Sub-Profile", "subprofile", 0, 0, 1 }, { F_PALETTE, "Palette", "palette", 0, 0, 1 }, { F_PALETTECONTROL, "Palette Control", "palette_control", 0, NUM_CONTROLS - 1, 1 }, - { F_DEINTERLACE, "Mode7 Deinterlace", "mode7_deinterlace", 0, NUM_DEINTERLACES - 1, 1 }, - { F_M7SCALING, "Mode 7 Integer", "mode7_scaling", 0, NUM_M7SCALINGS - 1, 1 }, - { F_NORMALSCALING, "Normal Integer", "normal_scaling", 0, NUM_NORMSCALINGS - 1, 1 }, + { F_DEINTERLACE,"Teletext Deinterlace", "teletext_deinterlace", 0, NUM_DEINTERLACES - 1, 1 }, + { F_M7SCALING, "Teletext Scaling", "teletext_scaling", 0, NUM_ESCALINGS - 1, 1 }, + { F_NORMALSCALING,"Progressive Scaling", "progressive_scaling", 0, NUM_ESCALINGS - 1, 1 }, { F_COLOUR, "Output Colour", "output_colour", 0, NUM_COLOURS - 1, 1 }, { F_INVERT, "Output Invert", "output_invert", 0, NUM_INVERT - 1, 1 }, { F_SCANLINES, "Scanlines", "scanlines", 0, 1, 1 }, @@ -1048,9 +1043,9 @@ static const char *get_param_string(param_menu_item_t *param_item) { case F_DEINTERLACE: return deinterlace_names[value]; case F_M7SCALING: - return m7scaling_names[value]; + return even_scaling_names[value]; case F_NORMALSCALING: - return normalscaling_names[value]; + return even_scaling_names[value]; case F_VLOCKMODE: return vlockmode_names[value]; case F_VLOCKSPEED: @@ -1108,16 +1103,19 @@ static void info_system_summary(int line) { NDIV = (gpioreg[PLLD_CTRL] & 0x3ff) << ANA1_PREDIV; FRAC = gpioreg[PLLD_FRAC] << ANA1_PREDIV; int clockD = (double) (CRYSTAL * ((double)NDIV + ((double)FRAC) / ((double)(1 << 20))) + 0.5); - int armclock = clockB / gpioreg[PLLB_ARM]; - sprintf(message, " CPU Clock: %d Mhz", armclock); + sprintf(message, " PLLA: %4d Mhz", clockA); osd_set(line++, 0, message); - sprintf(message, " PLLA: %d Mhz", clockA); + sprintf(message, " PLLB: %4d Mhz", clockB); osd_set(line++, 0, message); - sprintf(message, " PLLB: %d Mhz", clockB); + sprintf(message, " PLLC: %4d Mhz", clockC); osd_set(line++, 0, message); - sprintf(message, " PLLC: %d Mhz", clockC); + sprintf(message, " PLLD: %4d Mhz", clockD); osd_set(line++, 0, message); - sprintf(message, " PLLD: %d Mhz", clockD); + sprintf(message, " CPU Clock: %4d Mhz", get_clock_rate(ARM_CLK_ID)/1000000); + osd_set(line++, 0, message); + sprintf(message, " CORE Clock: %4d Mhz", get_clock_rate(CORE_CLK_ID)/1000000); + osd_set(line++, 0, message); + sprintf(message, " SDRAM Clock: %4d Mhz", get_clock_rate(SDRAM_CLK_ID)/1000000); osd_set(line++, 0, message); sprintf(message, " Core Temp: %6.2f C", get_temp()); osd_set(line++, 0, message); diff --git a/src/osd.h b/src/osd.h index 27c4f199..eeae81d2 100644 --- a/src/osd.h +++ b/src/osd.h @@ -143,15 +143,9 @@ enum { }; enum { - M7_UNEVEN, - M7_EVEN, - NUM_M7SCALINGS -}; - -enum { - NORMAL_EVEN, - NORMAL_UNEVEN, - NUM_NORMSCALINGS + SCALING_EVEN, + SCALING_UNEVEN, + NUM_ESCALINGS }; void osd_init(); diff --git a/src/rgb_to_fb.S b/src/rgb_to_fb.S index 2d5d4c87..6089c33c 100644 --- a/src/rgb_to_fb.S +++ b/src/rgb_to_fb.S @@ -43,10 +43,14 @@ .global frame_minimum .global line_minimum .global frame_timeout +.global hsync_scroll .global line_timeout - -.global capture_line_mode7_3bpp_table +#ifdef USE_MULTICORE +.global run_core +.global read_pointer +.global line_buffer +#endif .global capture_line_normal_3bpp_table .global capture_line_odd_3bpp_table @@ -103,6 +107,11 @@ rgb_to_fb: str r2, param_detected_sync_type ldr r2, [r0, #O_VSYNCTYPE] str r2, param_vsync_type + ldr r2, [r0, #O_VIDEOTYPE] + str r2, param_video_type + cmp r2, #0 + biceq r1, r1, #BIT_TELETEXT + orrne r1, r1, #BIT_TELETEXT ldr r2, [r0, #O_BORDER] str r2, param_border ldr r2, [r0, #O_FB_BASE] @@ -137,7 +146,7 @@ rgb_to_fb: add r2, r10 str r2, param_framebuffer3 // Default to displaying buffer 0 in Mode 7 (or on probe) - tst r1, #(BIT_MODE7 | BIT_PROBE) // options currently in r1! + tst r1, #(BIT_TELETEXT | BIT_PROBE) // options currently in r1! beq skip_swap push {r0-r3} mov r0, #0 @@ -167,7 +176,7 @@ skip_swap: // In Mode 7 (or on probe) write to buffer 0, display buffer 0 bic r3, r3, #(MASK_LAST_BUFFER | MASK_CURR_BUFFER) #ifdef MULTI_BUFFER - tst r3, #(BIT_MODE7 | BIT_PROBE) + tst r3, #(BIT_TELETEXT | BIT_PROBE) // In modes 0..6, restore the previous buffer state ldreq r10, buffer_state orreq r3, r3, r10 @@ -212,6 +221,9 @@ skip_swap: ldr r9, param_capture_line ldr r8, [r9, r7, lsl #2] + tst r3, #BIT_TELETEXT + ldrne r8, =capture_line_mode7_4bpp + ldr r10, param_border tst r10, #0x80 ldrne r8, =capture_line_null @@ -259,7 +271,7 @@ frame: // else draw to the "spare" buffer mov r0, #0 #ifdef MULTI_BUFFER - tst r3, #(BIT_MODE7 | BIT_PROBE) + tst r3, #(BIT_TELETEXT | BIT_PROBE) bne buffer_chosen // Draw to the buffers cyclically, i.e. pick the one // after the last completed buffer, modulo @@ -355,7 +367,8 @@ skip_switch_test: tst r3, #BIT_MODE_DETECT // Have we been told to exit on mode change beq skip_mode_test - + tst r3, #BIT_INHIBIT_MODE_DETECT + bne skip_mode_test tst r3, #BIT_MODE7 moveq r5, #0 // Modes 0-6 movne r5, #1 // Mode 7 @@ -417,7 +430,7 @@ no_sync_loss: // Save a copy of the frame buffer base push {r11} -#if defined(RPI2) || defined(RPI3) || defined(RPI4) +#if defined(USE_CACHED_COMPARISON_BUFFER) ldr r5, =dummyscreen sub r5, r5, r11 // put comparison buffer in cached memory #else @@ -434,11 +447,12 @@ no_sync_loss: // In Mode 0..6, reduce the number of active lines by one for the even frame // In Mode 7, increment the frame buffer pointer by one line for the even field - tst r3, #(BIT_NO_LINE_DOUBLE | BIT_MODE7) + tst r3, #BIT_NO_LINE_DOUBLE + tsteq r3, #BIT_TELETEXT addeq r11, r11, r2 tst r3, #BIT_ELK bne is_elk - tst r3, #BIT_MODE7 + tst r3, #BIT_TELETEXT beq fixupmodes tst r3, #BIT_FIELD_TYPE addeq r11, r11, r2 @@ -498,17 +512,19 @@ process_line_loop: // r6 = scan line count modulo 10 // r7 = number of psyncs to skip // r8 = frame buffer height (=param_fb_height) - // r9 = 1 is normal operation, 0 = skip wait for csync 0 (used during cache preload to avoid waiting for line sync) + // r9 = hsync scroll limits // All registers are available as scratch registers (i.e. nothing needs to be preserved) // Setup parameters // Load the address of the capture_line function into r12 ldr r12, capture_address mov r0, r11 + orr r3, r3, #BIT_NO_SKIP_HSYNC ldr r6, linecountmod10 ldr r7, param_h_offset ldr r8, video_offset - mov r9, #1 + ldr r9, hsync_scroll + // Call capture line function blx r12 // exits with h sync timestamp in r0 @@ -536,7 +552,8 @@ process_line_loop: subs r5, r5, #1 bne process_line_loop - + tst r3, #BIT_INHIBIT_MODE_DETECT + bicne r3, #BIT_MODE7 pop {r11} skip_all_lines: @@ -661,7 +678,7 @@ noInBandData: tst r3, #BIT_CLEAR bne force_osd_update - tst r3, #BIT_MODE7 + tst r3, #BIT_TELETEXT bne skip_osd_update force_osd_update: push {r1-r5, r11} @@ -1160,6 +1177,9 @@ param_detected_sync_type: param_vsync_type: .word 0 +param_video_type: + .word 0 + param_border: .word 0 @@ -1238,10 +1258,76 @@ line_minimum: .word 20000 frame_timeout: .word 24000000 +hsync_scroll: + .word (4000 - 224) | ((4000 + 224) << 16) line_timeout: - .word 74000000 + .word 100000000 + + .align 6 .ltorg + +#ifdef USE_MULTICORE + +read_pointer: + .word 0 +write_pointer: + .word 0 +r3copy: + .word 0 +r4copy: + .word 0 +r9copy: + .word 0 +capture_count: + .word 0 +skip_count: + .word 0 +run_core: + bl enable_MMU_and_IDCaches + bl _enable_unaligned_access + bl _init_cycle_counter +run_core_loop: + wfe // put core to sleep until an event + ldr r11, capture_count + cmp r11, #0 + beq run_core_loop // go back to sleep if capture count not valid + ldr r7, skip_count + cmp r7, #0 + beq run_core_loop // go back to sleep if skip count not valid + ldr r3, r3copy + ldr r4, r4copy + ldr r9, r9copy + SKIP_PSYNC + mov r7, #0 + str r7, skip_count + ldr r12, write_pointer +core_capture: + WAIT_FOR_PSYNC_EDGE + CAPTURE_LOW_BITS + WAIT_FOR_PSYNC_EDGE + CAPTURE_HIGH_BITS + mov r6, r10 + WAIT_FOR_PSYNC_EDGE + CAPTURE_LOW_BITS + WAIT_FOR_PSYNC_EDGE + CAPTURE_HIGH_BITS + mov r7, r10 + WAIT_FOR_PSYNC_EDGE + CAPTURE_LOW_BITS + WAIT_FOR_PSYNC_EDGE + CAPTURE_HIGH_BITS + stmia r12!, {r6,r7,r10} + str r12, write_pointer + sub r11, r11, #3 + cmp r11, #0 + bgt core_capture + str r12, write_pointer + mov r11, #0 + str r11, capture_count + b run_core_loop +#endif + // ====================================================================== // CLEAR_SCREEN // ====================================================================== @@ -1484,24 +1570,6 @@ capture_line_normal_6bpp_table: .word capture_line_fast_sixbits_4bpp .word capture_line_fast_sixbits_8bpp -capture_line_mode7_3bpp_table: - .word capture_line_mode7_4bpp - .word capture_line_mode7_4bpp - .word capture_line_mode7_4bpp - .word capture_line_mode7_4bpp - .word capture_line_mode7_4bpp - .word capture_line_mode7_4bpp - - .word capture_line_mode7_4bpp - .word capture_line_mode7_4bpp - .word capture_line_mode7_4bpp - .word capture_line_mode7_4bpp - .word capture_line_mode7_4bpp - .word capture_line_mode7_4bpp - - .word capture_line_mode7_4bpp - .word capture_line_mode7_4bpp - // tables below are deprecated and will be removed in future @@ -1620,6 +1688,11 @@ sw2counter2: sw3counter2: .word 0 + .ltorg + .align 6 +line_buffer: + .space 1920, 0 + .align 6 dummyscreen: // used by capture preload .space 1920*1080, 0 \ No newline at end of file diff --git a/src/rgb_to_fb.h b/src/rgb_to_fb.h index 04a596a6..0bb2e225 100644 --- a/src/rgb_to_fb.h +++ b/src/rgb_to_fb.h @@ -68,6 +68,7 @@ extern int hsync_threshold; extern int frame_minimum; extern int line_minimum; extern int frame_timeout; +extern int hsync_scroll; extern int line_timeout; extern int dummyscreen; diff --git a/src/rgb_to_hdmi.c b/src/rgb_to_hdmi.c index d886826f..f69a5da7 100644 --- a/src/rgb_to_hdmi.c +++ b/src/rgb_to_hdmi.c @@ -360,8 +360,8 @@ static int last_height = -1; v_overscan = 0; if (get_gscaling() == SCALING_INTEGER) { - if (!((mode7 && get_m7scaling() == M7_UNEVEN) - ||(!mode7 && get_normalscaling() == NORMAL_UNEVEN))) { + 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); if ((h_size - (h_size / width * width)) != 0) { h_overscan = (h_size - (h_size / capinfo->width * capinfo->width)); @@ -428,7 +428,7 @@ static int last_height = -1; } // On the Pi 2/3 the mailbox returns the address with bits 31..30 set, which is wrong capinfo->fb = (unsigned char *)(((unsigned int) capinfo->fb) & 0x3fffffff); - log_info("Framebuffer address masked: %8.8X", (unsigned int)capinfo->fb); + //log_info("Framebuffer address masked: %8.8X", (unsigned int)capinfo->fb); // Initialize the palette osd_update_palette(); } @@ -691,7 +691,7 @@ int cpu_adjust(double cycles) { return (int) (cycles * cpuspeed / 1000); } -static int calibrate_sampling_clock() { +static int calibrate_sampling_clock(int profile_changed) { int a = 13; static unsigned int old_pll_freq = 0; static unsigned int old_clock = 0; @@ -722,7 +722,9 @@ static int calibrate_sampling_clock() { log_info(" Clock error = %d PPM", clock_error_ppm); unsigned int new_clock; - + if (profile_changed) { + old_clock = clkinfo.clock * cpld->get_divider(); + } if ((clkinfo.clock_ppm > 0 && abs(clock_error_ppm) > clkinfo.clock_ppm) || (sync_detected == 0)) { if (old_clock > 0 && sub_profiles_available(profile) == 0) { log_warn("PPM error too large, using previous clock"); @@ -1183,11 +1185,7 @@ static void init_hardware() { log_debug("Setting up divisor"); init_gpclk(GPCLK_SOURCE, DEFAULT_GPCLK_DIVISOR); log_debug("Done setting up divisor"); - int ANA1_PREDIV = (gpioreg[PLLB_ANA1] >> 14) & 1; - int NDIV = (gpioreg[PLLB_CTRL] & 0x3ff) << ANA1_PREDIV; - int FRAC = gpioreg[PLLB_FRAC] << ANA1_PREDIV; - int clockB = (double) (CRYSTAL * ((double)NDIV + ((double)FRAC) / ((double)(1 << 20))) + 0.5); - cpuspeed = clockB / gpioreg[PLLB_ARM]; + cpuspeed = get_clock_rate(ARM_CLK_ID)/1000000; log_info("CPU speed detected as: %d Mhz", cpuspeed); field_type_threshold = FIELD_TYPE_THRESHOLD * cpuspeed / 1000; @@ -1199,7 +1197,8 @@ static void init_hardware() { frame_minimum = (int)((double)FRAME_MINIMUM * cpuspeed / 1000); frame_timeout = (int)((double)FRAME_TIMEOUT * cpuspeed / 1000); line_minimum = LINE_MINIMUM * cpuspeed / 1000; - line_timeout = LINE_TIMEOUT * cpuspeed / 1000; + hsync_scroll = (HSYNC_SCROLL_LO * cpuspeed / 1000) | ((HSYNC_SCROLL_HI * cpuspeed / 1000) << 16); + line_timeout = LINE_TIMEOUT * cpuspeed / 1000; //not currently used // Initialize the cpld after the gpclk generator has been started cpld_init(); @@ -1272,10 +1271,10 @@ static int extra_flags() { if (autoswitch != AUTOSWITCH_MODE7) { extra |= BIT_NO_H_SCROLL; } - if (autoswitch != AUTOSWITCH_PC) { + if (autoswitch != AUTOSWITCH_PC || !sub_profiles_available(profile)) { extra |= BIT_NO_AUTOSWITCH; } - if (!scanlines || ((capinfo->sizex2 & 1) == 0) || mode7 || osd_active()) { + if (!scanlines || ((capinfo->sizex2 & 1) == 0) || (capinfo->video_type == VIDEO_TELETEXT) || osd_active()) { extra |= BIT_NO_SCANLINES; } if (osd_active()) { @@ -1287,7 +1286,8 @@ return extra; #ifdef HAS_MULTICORE static void start_core(int core, func_ptr func) { printf("starting core %d\r\n", core); - *(unsigned int *)(0x4000008C + 0x10 * core) = (unsigned int) func; + *(unsigned int *)(0x4000008c + 0x10 * core) = (unsigned int) func; + asm ( "sev" ); } #endif @@ -1340,7 +1340,7 @@ int *diff_N_frames_by_sample(capture_info_t *capinfo, int n, int mode7, int elk) geometry_get_fb_params(capinfo); // required as calibration sets delay to 0 and the 2 high bits of that adjust the h offset // In mode 0..6, capture one field // In mode 7, capture two fields - capinfo->ncapture = mode7 ? 2 : 1; + capinfo->ncapture = (capinfo->video_type == VIDEO_TELETEXT) ? 2 : 1; #ifdef INSTRUMENT_CAL t = _get_cycle_counter(); @@ -1388,29 +1388,29 @@ int *diff_N_frames_by_sample(capture_info_t *capinfo, int n, int mode7, int elk) if (line >= 0) { if (elk) { // Eliminate cursor lines in 32 row modes (0,1,2,4,5) - if (!mode7 && (line % 8) == 5) { + if (capinfo->video_type != VIDEO_TELETEXT && (line % 8) == 5) { skip = 1; } // Eliminate cursor lines in 25 row modes (3, 6) - if (!mode7 && (line % 10) == 3) { + if (capinfo->video_type != VIDEO_TELETEXT && (line % 10) == 3) { skip = 1; } // Eliminate cursor lines in mode 7 // (this case is untested as I don't have a Jafa board) - if (mode7 && (line % 10) == 7) { + if (capinfo->video_type == VIDEO_TELETEXT && (line % 10) == 7) { skip = 1; } } else { // Eliminate cursor lines in 32 row modes (0,1,2,4,5) - if (!mode7 && (line % 8) == 7) { + if (capinfo->video_type != VIDEO_TELETEXT && (line % 8) == 7) { skip = 1; } // Eliminate cursor lines in 25 row modes (3, 6) - if (!mode7 && (line % 10) >= 5 && (line % 10) <= 7) { + if (capinfo->video_type != VIDEO_TELETEXT && (line % 10) >= 5 && (line % 10) <= 7) { skip = 1; } // Eliminate cursor lines in mode 7 - if (mode7 && (line % 10) == 7) { + if (capinfo->video_type == VIDEO_TELETEXT && (line % 10) == 7) { skip = 1; } } @@ -1491,7 +1491,7 @@ int *diff_N_frames_by_sample(capture_info_t *capinfo, int n, int mode7, int elk) #define MODE7_CHAR_WIDTH 12 signed int analyze_mode7_alignment(capture_info_t *capinfo) { - if (autoswitch != AUTOSWITCH_MODE7) { + if (capinfo->video_type != VIDEO_TELETEXT) { return -1; } @@ -1696,7 +1696,7 @@ int total_N_frames(capture_info_t *capinfo, int n, int mode7, int elk) { // In mode 0..6, capture one field // In mode 7, capture two fields - capinfo->ncapture = mode7 ? 2 : 1; + capinfo->ncapture = capinfo->video_type == VIDEO_TELETEXT ? 2 : 1; for (int i = 0; i < n; i++) { int total = 0; @@ -1756,7 +1756,7 @@ void swapBuffer(int buffer) { #endif int get_current_display_buffer() { - if (mode7) { + if (capinfo->video_type == VIDEO_TELETEXT) { return 0; } else { return current_display_buffer; @@ -2000,7 +2000,12 @@ int get_debug() { return debug; } int get_lines_per_vsync() { + if (sync_detected && lines_per_vsync > 220) { return lines_per_vsync; + } else { + return 1000; + } + } void set_autoswitch(int value) { @@ -2024,7 +2029,7 @@ void set_autoswitch(int value) { autoswitch = value; } - hsync_threshold = (autoswitch == AUTOSWITCH_MODE7) ? BBC_HSYNC_THRESHOLD : OTHER_HSYNC_THRESHOLD; + hsync_threshold = (autoswitch == AUTOSWITCH_MODE7 || capinfo->video_type == VIDEO_TELETEXT) ? BBC_HSYNC_THRESHOLD : OTHER_HSYNC_THRESHOLD; } int get_autoswitch() { @@ -2033,14 +2038,14 @@ int get_autoswitch() { void action_calibrate_clocks() { // re-measure vsync and set the core/sampling clocks - calibrate_sampling_clock(); + calibrate_sampling_clock(0); // set the hdmi clock property to match exactly set_vlockmode(HDMI_EXACT); } void action_calibrate_auto() { // re-measure vsync and set the core/sampling clocks - calibrate_sampling_clock(); + calibrate_sampling_clock(0); // During calibration we do our best to auto-delect an Electron log_debug("Elk mode = %d", elk_mode); for (int c = 0; c < NUM_CAL_PASSES; c++) { @@ -2069,7 +2074,7 @@ void calculate_fb_adjustment() { //log_info("adjust=%d, %d", capinfo->h_adjust, capinfo->v_adjust); } -void setup_profile() { +void setup_profile(int profile_changed) { // Switch the the approriate capinfo structure instance capinfo = mode7 ? &mode7_capinfo : &default_capinfo; @@ -2085,12 +2090,12 @@ void setup_profile() { geometry_get_fb_params(capinfo); - if (autoswitch != AUTOSWITCH_PC) { - capinfo->detected_sync_type = cpld->analyse(capinfo->sync_type); - log_info("Polarity state set from profile = %s (%s)", sync_names[capinfo->detected_sync_type & SYNC_BIT_MASK], mixed_names[(capinfo->detected_sync_type & SYNC_BIT_MIXED_SYNC) ? 1 : 0]); - } else { + if (autoswitch == AUTOSWITCH_PC && sub_profiles_available(profile)) { capinfo->detected_sync_type = cpld->analyse(-1); log_info("Detected polarity state = %s (%s)", sync_names[capinfo->detected_sync_type & SYNC_BIT_MASK], mixed_names[(capinfo->detected_sync_type & SYNC_BIT_MIXED_SYNC) ? 1 : 0]); + } else { + capinfo->detected_sync_type = cpld->analyse(capinfo->sync_type); + log_info("Polarity state set from profile = %s (%s)", sync_names[capinfo->detected_sync_type & SYNC_BIT_MASK], mixed_names[(capinfo->detected_sync_type & SYNC_BIT_MIXED_SYNC) ? 1 : 0]); } cpld->update_capture_info(capinfo); @@ -2098,13 +2103,13 @@ void setup_profile() { rgb_to_fb(capinfo, extra_flags() | BIT_PROBE); // dummy mode7 probe to setup sync type from capinfo - // Measure the frame time and set the sampling clock - calibrate_sampling_clock(); + // Measure the frame time and set the sampling clock + calibrate_sampling_clock(profile_changed); // force recalculation of the HDMI clock (if the vlockmode property requires this) recalculate_hdmi_clock_line_locked_update(GENLOCK_FORCE); - if (autoswitch == AUTOSWITCH_PC) { // set window around expected time from sub-profile + if (autoswitch == AUTOSWITCH_PC && sub_profiles_available(profile)) { // set window around expected time from sub-profile double line_time = (double) clkinfo.line_len * 1000000000 / (double) clkinfo.clock; int window = (int) ((double) clkinfo.clock_ppm * line_time / 1000000); hsync_comparison_lo = (line_time - window) * cpuspeed / 1000; @@ -2121,6 +2126,8 @@ void setup_profile() { } log_info("Window: H = %d to %d, V = %d to %d, S = %s", hsync_comparison_lo * 1000 / cpuspeed, hsync_comparison_hi * 1000 / cpuspeed, (int)((double)vsync_comparison_lo * 1000 / cpuspeed), (int)((double)vsync_comparison_hi * 1000 / cpuspeed), sync_names[capinfo->sync_type]); + + hsync_threshold = (autoswitch == AUTOSWITCH_MODE7 || capinfo->video_type == VIDEO_TELETEXT) ? BBC_HSYNC_THRESHOLD : OTHER_HSYNC_THRESHOLD; } void set_status_message(char *msg) { strcpy(status, msg); @@ -2148,7 +2155,7 @@ void rgb_to_hdmi_main() { // Setup defaults (these may be overridden by the CPLD) default_capinfo.capture_line = capture_line_normal_3bpp_table; - mode7_capinfo.capture_line = capture_line_mode7_3bpp_table; + mode7_capinfo.capture_line = capture_line_normal_3bpp_table; capinfo = &default_capinfo; capinfo->v_adjust = 0; capinfo->h_adjust = 0; @@ -2201,15 +2208,17 @@ void rgb_to_hdmi_main() { while (1) { log_info("-----------------------LOOP------------------------"); - setup_profile(); + setup_profile(profile != last_profile || last_subprofile != subprofile); - if ((autoswitch == AUTOSWITCH_PC) && ((result & RET_SYNC_TIMING_CHANGED) || profile != last_profile || last_subprofile != subprofile)) { + if ((autoswitch == AUTOSWITCH_PC) && sub_profiles_available(profile) && ((result & RET_SYNC_TIMING_CHANGED) || profile != last_profile || last_subprofile != subprofile)) { int new_sub_profile = autoswitch_detect(one_line_time_ns, lines_per_frame, capinfo->detected_sync_type & SYNC_BIT_MASK); if (new_sub_profile >= 0) { set_subprofile(new_sub_profile); process_sub_profile(get_profile(), new_sub_profile); - setup_profile(); + setup_profile(1); + set_status_message(""); } else { + set_status_message("Auto Switch: No profile matched"); log_info("Autoswitch: No profile matched"); } } @@ -2219,6 +2228,7 @@ void rgb_to_hdmi_main() { log_debug("Setting up frame buffer"); init_framebuffer(capinfo); log_debug("Done setting up frame buffer"); + //log_info("Peripheral base = %08X", PERIPHERAL_BASE); log_info("RAM benchmark: Main memory = %d nS, Screen memory = %d nS", (int) ((double) benchmarkRAM(dummyscreen) * 1000 / cpuspeed), (int) ((double) benchmarkRAM((int) capinfo->fb) * 1000 / cpuspeed)); osd_refresh(); @@ -2286,7 +2296,7 @@ void rgb_to_hdmi_main() { flags |= deinterlace << OFFSET_INTERLACE; #ifdef MULTI_BUFFER - if (!mode7 && osd_active() && (nbuffers == 0)) { + if (capinfo->video_type != VIDEO_TELETEXT && osd_active() && (nbuffers == 0)) { flags |= 2 << OFFSET_NBUFFERS; } else { flags |= nbuffers << OFFSET_NBUFFERS; @@ -2318,6 +2328,10 @@ void rgb_to_hdmi_main() { if (result & RET_SYNC_TIMING_CHANGED) { log_info("Timing exceeds window: H = %d, V = %d, Lines = %d, VSync = %d", hsync_period * 1000 / cpuspeed, (int)((double)vsync_period * 1000 / cpuspeed), (int) (((double)vsync_period/hsync_period) + 0.5), (result & RET_VSYNC_POLARITY_CHANGED) ? 1 : 0); } + if (result & RET_INTERLACE_CHANGED) { + log_info("Interlaced changed"); + } + clear = 0; // Possibly the size or offset has been adjusted, so update current capinfo @@ -2345,8 +2359,13 @@ void rgb_to_hdmi_main() { last_mode7 = mode7; mode7 = result & BIT_MODE7 & (autoswitch == AUTOSWITCH_MODE7); + + if (mode7 != last_mode7) { + log_info("Mode changed %d", mode7); + } + mode_changed = mode7 != last_mode7 || capinfo->vsync_type != last_capinfo.vsync_type || capinfo->sync_type != last_capinfo.sync_type || capinfo->border != last_capinfo.border - || capinfo->px_sampling != last_capinfo.px_sampling || paletteControl != last_paletteControl + || capinfo->video_type != last_capinfo.video_type|| capinfo->px_sampling != last_capinfo.px_sampling || paletteControl != last_paletteControl || profile != last_profile || last_subprofile != subprofile || (result & RET_SYNC_TIMING_CHANGED); if (active_size_changed) { @@ -2357,7 +2376,7 @@ void rgb_to_hdmi_main() { target_difference = 0; resync_count = 0; // Measure the frame time and set the sampling clock - calibrate_sampling_clock(); + calibrate_sampling_clock(0); // Force recalculation of the HDMI clock (if the vlockmode property requires this) recalculate_hdmi_clock_line_locked_update(GENLOCK_FORCE); } @@ -2446,11 +2465,13 @@ void kernel_main(unsigned int r0, unsigned int r1, unsigned int atags) #ifdef HAS_MULTICORE int i; - printf("main running on core %u\r\n", _get_core()); - for (i = 0; i < 10000000; i++); +#ifdef USE_MULTICORE + start_core(1, _init_core); +#else start_core(1, _spin_core); +#endif for (i = 0; i < 10000000; i++); start_core(2, _spin_core); for (i = 0; i < 10000000; i++);