Switch to software processing of CSYNC to find VSYNC and Odd/Even field

Change-Id: Ied519b072e75da67559f5e867b012c7b5ae74eb1
issue_1022
David Banks 2017-04-26 17:49:23 +01:00
rodzic 4335d4e531
commit 1bf8ebb272
1 zmienionych plików z 155 dodań i 86 usunięć

Wyświetl plik

@ -8,7 +8,7 @@
// At the moment, this only works with non-interlace
// video, as there is a bug in the CPLD that introduces
// line jitter with interlaced video.
// #define LINE_DOUBLE
.text
@ -19,108 +19,183 @@
// r0 = frame buffer base
// r1 = 8-pixel characters per line (normally 80, but 62.5 (63) in Mode 7
// r2 = bytes per line
// r3 = unused
//
// Working registers:
//
// r3 = field offsset
// r4 = GPLEV0
// r5 = line counter
// r6 = pixel counter
// r8 = value read from GPLEV0
// r9 = extracted pixel
// r10 = block of 8 pixels, to be written to FB
// r11 = pointer into frame buffer (start of line)
// r12 = pointer into frame buffer (moves within line)
// Note, in this version we are using HSYNC which is the inverse of CSYNC
.macro WAIT_FOR_CSYNC_0
WAIT_FOR_HSYNC_1
.endm
.macro WAIT_FOR_CSYNC_1
WAIT_FOR_HSYNC_0
.endm
.macro WAIT_FOR_HSYNC_0
wait\@:
// Read the GPLEV0
ldr r8, [r4]
tst r8, #HSYNC_MASK
bne wait\@
// Check again in case of noise
ldr r8, [r4]
tst r8, #HSYNC_MASK
bne wait\@
.endm
.macro WAIT_FOR_HSYNC_1
wait\@:
// Read the GPLEV0
ldr r8, [r4]
tst r8, #HSYNC_MASK
beq wait\@
// Check again in case of noise
ldr r8, [r4]
tst r8, #HSYNC_MASK
beq wait\@
.endm
.macro WAIT_FOR_PSYNC_0
wait\@:
// Read the GPLEV0
ldr r8, [r4]
tst r8, #PSYNC_MASK
bne wait\@
// Check again in case of noise
ldr r8, [r4]
tst r8, #PSYNC_MASK
bne wait\@
.endm
.macro WAIT_FOR_PSYNC_1
wait\@:
// Read the GPLEV0
ldr r8, [r4]
tst r8, #PSYNC_MASK
beq wait\@
// Check again in case of noise
ldr r8, [r4]
tst r8, #PSYNC_MASK
beq wait\@
.endm
rgb_to_fb:
push {r4-r12, lr}
mov r3, r2
ldr r4, =GPLEV0
frame:
// Set framebuffer address
#ifdef LINE_DOUBLE
mov r11, r0
#else
add r11, r0, r3
eor r3, r3, r2
#endif
// Wait for start of vsync
wait_for_vsync_a:
ldr r8, [r4]
tst r8, #VSYNC_MASK
beq wait_for_vsync_a
// Check again in case of noise
ldr r8, [r4]
tst r8, #VSYNC_MASK
beq wait_for_vsync_a
// Wait for end of vsync
wait_for_vsync_b:
ldr r8, [r4]
tst r8, #VSYNC_MASK
bne wait_for_vsync_b
// Check again in case of noise
ldr r8, [r4]
tst r8, #VSYNC_MASK
bne wait_for_vsync_b
// Working registers in the first half
//
// r4 = GPLEV0
// r5 = time of falling edge
// r6 = time of rising edge
// r7 = time of previous rising edge
// r8 = value read from GPLEV0
// r9 = state variable (1 = seen a long pulse
// Enable the cycle counter, and run at the ARM clock rate
mov r9, #7
mcr p15, 0, r9, c15, c12, 0
// Initialize "seen long pulse" to false (0)
mov r9, #0
// Wait for csync to be high
WAIT_FOR_CSYNC_1
vsync_loop:
// Wait for the falling edge of csync
WAIT_FOR_CSYNC_0
// Record time of the falling edge
mrc p15, 0, r5, c15, c12, 1
// Wait for the rising edge of hsync
WAIT_FOR_CSYNC_1
// Save time of previous rising edge
mov r7, r6
// Record time of the rising edge
mrc p15, 0, r6, c15, c12, 1
// Calculate length of low hsync pulse (in ARM cycles = ns)
sub r5, r6, r5
// Compare with 6us to descriminate short from long
// - normal hsync pulses are 4us
// - during vsync everything is either inverted, or clamped to zero
// - this results in hsync pulses between 9us and 128us
cmp r5, #6144
blt seen_short
// Set the state variable to indicate we are in the vsync
mov r9, #1
// Loop back to wait for the next pulse
b vsync_loop
seen_short:
// Test to see if we've seen any long pulses
cmp r9, #1
// No, so look back for the next pulse
bne vsync_loop
// Working registers in the second half
//
// r4 = GPLEV0
// r5 = line counter
// r6 = pixel counter
// r8 = value read from GPLEV0
// r9 = extracted pixel
// r10 = block of 8 pixels, to be written to FB
// r11 = pointer into frame buffer (start of line)
// r12 = pointer into frame buffer (moves within line)
// Set framebuffer address
mov r11, r0
// The odd vs even field can be distinguished by the time between
// the last two rising edges:
// odd field (first field) should be 23us
// even field (second field) should be 51us
sub r6, r6, r7
cmp r6, #32768
// For even field, increment the frame buffer pointer by one line
addge r11, r11, r2
// Skip inactive lines
mov r5, #28
loop0:
skip_line_loop:
wait_for_hsync_a:
ldr r8, [r4]
tst r8, #HSYNC_MASK
beq wait_for_hsync_a
ldr r8, [r4]
tst r8, #HSYNC_MASK
beq wait_for_hsync_a
wait_for_hsync_b:
ldr r8, [r4]
tst r8, #HSYNC_MASK
bne wait_for_hsync_b
ldr r8, [r4]
tst r8, #HSYNC_MASK
bne wait_for_hsync_b
WAIT_FOR_CSYNC_0
WAIT_FOR_CSYNC_1
subs r5, r5, #1
bne loop0
bne skip_line_loop
// Process active lines
mov r5, #256
loop1:
process_line_loop:
// Wait for active high hsync
wait_for_hsync:
ldr r8, [r4]
tst r8, #HSYNC_MASK
beq wait_for_hsync
ldr r8, [r4]
tst r8, #HSYNC_MASK
beq wait_for_hsync
// Wait for the start of hsync
WAIT_FOR_CSYNC_0
// number of 8-bit characters per line
mov r6, r1
// pointer into frame buffer
mov r12, r11
loop2:
process_chars_loop:
// Initialize 8 pixel block
mov r10, #0
// Wait for 0-1 edge on PSYNC
wait_psync_01:
ldr r8, [r4]
tst r8, #PSYNC_MASK
beq wait_psync_01
ldr r8, [r4]
tst r8, #PSYNC_MASK
beq wait_psync_01
WAIT_FOR_PSYNC_1
// Pixel 0 in GPIO 4.. 2 -> 7.. 4
// Pixel 1 in GPIO 7.. 5 -> 3.. 0
@ -140,13 +215,7 @@ wait_psync_01:
orr r10, r10, r9, lsr #3
// Wait for 1-0 edge on PSYNC
wait_psync_10:
ldr r8, [r4]
tst r8, #PSYNC_MASK
bne wait_psync_10
ldr r8, [r4]
tst r8, #PSYNC_MASK
bne wait_psync_10
WAIT_FOR_PSYNC_0
// Pixel 4 in GPIO 4.. 2 -> 23..20
// Pixel 5 in GPIO 7.. 5 -> 19..16
@ -165,19 +234,19 @@ wait_psync_10:
and r9, r8, #(7 << (PIXEL_BASE + 9))
orr r10, r10, r9, lsl #13
#ifdef LINE_DOUBLE
#ifdef LINE_DOUBLE
str r10, [r12, r2]
#endif
#endif
str r10, [r12], #4
subs r6, r6, #1
bne loop2
bne process_chars_loop
// Skip a whole line to maintain aspect ratio
add r11, r11, r2, lsl #1
subs r5, r5, #1
bne loop1
bne process_line_loop
b frame