Improve multi Pi support, add Video type option in geometry for teletext only modes and hide offsets when not in mode 7

pull/135/head
IanSB 2020-02-02 02:56:16 +00:00
rodzic d714ba2092
commit 9f54331075
12 zmienionych plików z 426 dodań i 194 usunięć

Wyświetl plik

@ -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"

Wyświetl plik

@ -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:

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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()) {

Wyświetl plik

@ -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
};

Wyświetl plik

@ -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

Wyświetl plik

@ -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);

Wyświetl plik

@ -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();

Wyświetl plik

@ -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 <nbuffers + 1>
@ -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

Wyświetl plik

@ -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;

Wyświetl plik

@ -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++);