kopia lustrzana https://github.com/hoglet67/RGBtoHDMI
Merge remote-tracking branch 'ian/dev' into dev
commit
33c91ae80e
|
@ -6,6 +6,7 @@
|
|||
.text
|
||||
|
||||
.global capture_line_default_4bpp
|
||||
.global inBandData
|
||||
|
||||
// The capture line function is provided the following:
|
||||
// r0 = pointer to current line in frame buffer
|
||||
|
@ -18,35 +19,130 @@
|
|||
//
|
||||
// All registers are available as scratch registers (i.e. nothing needs to be preserved)
|
||||
|
||||
inBandData:
|
||||
.space 1024, 0
|
||||
|
||||
capture_line_default_4bpp:
|
||||
|
||||
push {lr}
|
||||
|
||||
mov r6, #0
|
||||
mov r7, #0
|
||||
tst r3, #BIT_VSYNC_MARKER
|
||||
ldrne r7, =0x11111111
|
||||
adrl r11, inBandData
|
||||
mov r12, #0 // pointer to end of "HDMI" string
|
||||
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_LOW_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_HIGH_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
CONVERT_WORD_MODE0
|
||||
CONVERT_MODE0_MODE2
|
||||
WRITE_WORD
|
||||
sub r1, r1, #1
|
||||
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_LOW_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_HIGH_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
CONVERT_WORD_MODE0
|
||||
CONVERT_MODE0_MODE2
|
||||
WRITE_WORD
|
||||
sub r1, r1, #1
|
||||
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_LOW_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_HIGH_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
CONVERT_WORD_MODE0
|
||||
CONVERT_MODE0_MODE2
|
||||
WRITE_WORD
|
||||
sub r1, r1, #1
|
||||
cmp r9, #'H'
|
||||
bne loop
|
||||
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_LOW_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_HIGH_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
CONVERT_WORD_MODE0
|
||||
CONVERT_MODE0_MODE2
|
||||
WRITE_WORD
|
||||
sub r1, r1, #1
|
||||
cmp r9, #'D'
|
||||
bne loop
|
||||
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_LOW_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_HIGH_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
CONVERT_WORD_MODE0
|
||||
CONVERT_MODE0_MODE2
|
||||
WRITE_WORD
|
||||
sub r1, r1, #1
|
||||
cmp r9, #'M'
|
||||
bne loop
|
||||
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_LOW_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_HIGH_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
CONVERT_WORD_MODE0
|
||||
CONVERT_MODE0_MODE2
|
||||
WRITE_WORD
|
||||
sub r1, r1, #1
|
||||
cmp r9, #'I'
|
||||
bne loop
|
||||
|
||||
mov r12, r0 // save current screen pointer in r12 (points to end of "HDMI")
|
||||
orr r3, r3, #BIT_IN_BAND_DETECTED
|
||||
inBandLoop:
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_LOW_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
CAPTURE_HIGH_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
CONVERT_WORD_MODE0
|
||||
mov r10, #0
|
||||
WRITE_WORD
|
||||
strb r9, [r11], #1
|
||||
subs r1, r1, #1
|
||||
bne inBandLoop
|
||||
|
||||
sub r0, r12, #16
|
||||
mov r10, #0
|
||||
WRITE_WORD
|
||||
mov r10, #0
|
||||
WRITE_WORD
|
||||
mov r10, #0
|
||||
WRITE_WORD
|
||||
mov r10, #0
|
||||
WRITE_WORD
|
||||
pop {pc}
|
||||
|
||||
loop:
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
|
||||
CAPTURE_LOW_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
|
||||
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
|
||||
|
||||
CAPTURE_HIGH_BITS // input in r8, result in r10, corrupts r9/r14
|
||||
|
||||
// Orr in the VSync indicator
|
||||
|
||||
orr r10, r10, r7
|
||||
|
||||
// Line double always in Modes 0-6 regardless of interlace
|
||||
// On the multi core Pi this introduces stalling artefacts
|
||||
#ifndef HAS_MULTICORE
|
||||
tst r3, #BIT_SCANLINES
|
||||
streq r10, [r0, r2]
|
||||
strne r6, [r0, r2]
|
||||
#endif
|
||||
str r10, [r0], #4
|
||||
CONVERT_WORD_MODE0
|
||||
CONVERT_MODE0_MODE2
|
||||
WRITE_WORD
|
||||
|
||||
subs r1, r1, #1
|
||||
bne loop
|
||||
|
||||
pop {pc}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -61,7 +61,9 @@
|
|||
#define BIT_FIELD_TYPE1 0x00800000 // bit 23, indicates the field type of the previous field
|
||||
#define BIT_FIELD_TYPE1_VALID 0x01000000 // bit 24, indicates FIELD_TYPE1 is valid
|
||||
|
||||
// bits 25-31 unused
|
||||
#define BIT_MODE2_16COLOUR 0x02000000 // bit 25, if set then 16 colour mode 2 is emulated by decoding mode 0
|
||||
#define BIT_IN_BAND_DETECTED 0x04000000 // bit 26, if set if in band data is detected
|
||||
// bits 27-31 unused
|
||||
// R0 return value bits
|
||||
#define RET_SW1 0x02
|
||||
#define RET_SW2 0x04
|
||||
|
|
65
src/macros.S
65
src/macros.S
|
@ -51,3 +51,68 @@ wait\@:
|
|||
orr r10, r10, r9, lsl #(22 - PIXEL_BASE)
|
||||
orr r10, r10, r8, lsl #(15 - PIXEL_BASE)
|
||||
.endm
|
||||
|
||||
.macro CONVERT_WORD_MODE0
|
||||
// Any non-zero pixel gets converted sets a bit
|
||||
mov r9, #0
|
||||
tst r10, #0x00000070
|
||||
orrne r9, r9, #0x80
|
||||
tst r10, #0x00000007
|
||||
orrne r9, r9, #0x40
|
||||
tst r10, #0x00007000
|
||||
orrne r9, r9, #0x20
|
||||
tst r10, #0x00000700
|
||||
orrne r9, r9, #0x10
|
||||
tst r10, #0x00700000
|
||||
orrne r9, r9, #0x08
|
||||
tst r10, #0x00070000
|
||||
orrne r9, r9, #0x04
|
||||
tst r10, #0x70000000
|
||||
orrne r9, r9, #0x02
|
||||
tst r10, #0x07000000
|
||||
orrne r9, r9, #0x01
|
||||
.endm
|
||||
.macro CONVERT_MODE0_MODE2
|
||||
tst r3, #BIT_MODE2_16COLOUR
|
||||
beq standardPalette\@
|
||||
// reinterpret mode 0 bits as 16 colour mode 2
|
||||
mov r10,#0
|
||||
tst r9, #0x01
|
||||
orrne r10, r10, #0x010000
|
||||
tst r9, #0x04
|
||||
orrne r10, r10, #0x020000
|
||||
tst r9, #0x10
|
||||
orrne r10, r10, #0x040000
|
||||
tst r9, #0x40
|
||||
orrne r10, r10, #0x080000
|
||||
tst r9, #0x02
|
||||
orrne r10, r10, #0x01
|
||||
tst r9, #0x08
|
||||
orrne r10, r10, #0x02
|
||||
tst r9, #0x20
|
||||
orrne r10, r10, #0x04
|
||||
tst r9, #0x80
|
||||
orrne r10, r10, #0x08
|
||||
|
||||
orr r10, r10, r10, lsl #4
|
||||
orr r10, r10, r10, lsl #8
|
||||
standardPalette\@:
|
||||
.endm
|
||||
|
||||
.macro WRITE_WORD
|
||||
|
||||
// eor in the VSync indicator (orr doesn't work on zx80/81 due to white screen)
|
||||
eor r10, r10, r7
|
||||
tst r3, #BIT_DEBUG
|
||||
orrne r10, r10, #0x10 //red in leftmost
|
||||
orrne r10, r10, #0x02000000 //green in rightmost
|
||||
// Line double always in Modes 0-6 regardless of interlace
|
||||
// On the multi core Pi this introduces stalling artefacts
|
||||
#ifndef HAS_MULTICORE
|
||||
tst r3, #BIT_SCANLINES
|
||||
streq r10, [r0, r2]
|
||||
strne r6, [r0, r2]
|
||||
#endif
|
||||
str r10, [r0], #4
|
||||
.endm
|
||||
|
20
src/osd.c
20
src/osd.c
|
@ -731,11 +731,21 @@ void osd_update_palette() {
|
|||
int m;
|
||||
int num_colours = (capinfo->bpp == 8) ? 256 : 16;
|
||||
for (int i = 0; i < num_colours; i++) {
|
||||
int r = (i & 1) ? 255 : 0;
|
||||
int g = (i & 2) ? 255 : 0;
|
||||
int b = (i & 4) ? 255 : 0;
|
||||
int r = (i & 1) ? 255 : 0;
|
||||
int g = (i & 2) ? 255 : 0;
|
||||
int b = (i & 4) ? 255 : 0;
|
||||
|
||||
if (paletteFlags & 1) {
|
||||
|
||||
r = customPalette[i] & 0xff;
|
||||
g = (customPalette[i]>>8) & 0xff;
|
||||
b = (customPalette[i]>>16) & 0xff;
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
switch (palette) {
|
||||
case PALETTE_INVERSE:
|
||||
case PALETTE_INVERSE:
|
||||
r = 255 - r;
|
||||
g = 255 - g;
|
||||
b = 255 - b;
|
||||
|
@ -855,6 +865,7 @@ void osd_update_palette() {
|
|||
r = g = b = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (active) {
|
||||
if (i >= (num_colours >> 1)) {
|
||||
palette_data[i] = 0xFFFFFFFF;
|
||||
|
@ -868,6 +879,7 @@ void osd_update_palette() {
|
|||
if (get_debug()) {
|
||||
palette_data[i] |= 0x00101010;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Flush the previous swapBuffer() response from the GPU->ARM mailbox
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
#define ATTR_DOUBLE_SIZE (1 << 0)
|
||||
|
||||
extern int clock_error_ppm;
|
||||
extern int customPalette[];
|
||||
extern int paletteFlags;
|
||||
|
||||
|
||||
enum {
|
||||
HDMI_ORIGINAL,
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
.global vsync_line
|
||||
.global default_vsync_line
|
||||
.global lock_fail
|
||||
.global paletteFlags
|
||||
.global customPalette
|
||||
|
||||
// ======================================================================
|
||||
// Macros
|
||||
|
@ -229,6 +231,13 @@ frame:
|
|||
bl wait_for_vsync
|
||||
ldr r0, default_vsync_line
|
||||
str r0, vsync_line // default for vsync line if vsync in blanking area
|
||||
|
||||
bic r3, r3, #BIT_IN_BAND_DETECTED
|
||||
|
||||
ldr r0, paletteFlags
|
||||
tst r0, #1
|
||||
orrne r3, r3, #BIT_MODE2_16COLOUR
|
||||
biceq r3, r3, #BIT_MODE2_16COLOUR
|
||||
|
||||
// Working registers while frame is being captured
|
||||
//
|
||||
|
@ -456,7 +465,10 @@ skip_psync_loop_exit:
|
|||
blx r10
|
||||
|
||||
// Restore the state used by the outer code
|
||||
tst r3, #BIT_IN_BAND_DETECTED
|
||||
pop {r1-r5, r11}
|
||||
orrne r3, r3, #BIT_IN_BAND_DETECTED
|
||||
|
||||
|
||||
// Skip a whole line to maintain aspect ratio
|
||||
ldr r0, linecountmod10
|
||||
|
@ -468,7 +480,53 @@ skip_psync_loop_exit:
|
|||
|
||||
subs r5, r5, #1
|
||||
bne process_line_loop
|
||||
push {r0-r12, lr}
|
||||
|
||||
mov r9, #0 // palette changed flag
|
||||
mov r8, #0 // mode 2 emulation flag
|
||||
tst r3, #BIT_OSD
|
||||
bne noInBandData
|
||||
|
||||
tst r3, #BIT_IN_BAND_DETECTED
|
||||
beq noInBandData
|
||||
|
||||
adr r10, customPalette
|
||||
ldr r12, =inBandData
|
||||
ldrb r11, [r12], #1 //read 1 byte of command data
|
||||
cmp r11, #0
|
||||
beq noInBandData
|
||||
mov r11, r11, lsr #1
|
||||
mov r8, #1 // mode 2 emulation enabled
|
||||
commandloop:
|
||||
ldrb r1, [r12], #1 //read 1 byte of command data
|
||||
and r0, r1, #0x0f
|
||||
ldrb r1, [r12], #1 //read 1 byte of command data
|
||||
and r3, r1, #0xf0
|
||||
orr r0, r0, r3, lsl #4
|
||||
and r3, r1, #0x0f
|
||||
orr r0, r0, r3, lsl #16
|
||||
orr r0, r0, r0, lsl #4
|
||||
|
||||
ldr r2, [r10]
|
||||
str r0, [r10], #4
|
||||
|
||||
cmp r0, r2
|
||||
movne r9, #1
|
||||
|
||||
subs r11, r11, #1
|
||||
bne commandloop
|
||||
|
||||
noInBandData:
|
||||
|
||||
ldr r7, paletteFlags
|
||||
str r8, paletteFlags
|
||||
cmp r9, #0
|
||||
cmpeq r7, r8
|
||||
blne osd_update_palette
|
||||
|
||||
pop {r0-r12, lr}
|
||||
|
||||
|
||||
// Update the OSD in Mode 0..6
|
||||
pop {r11}
|
||||
tst r3, #BIT_MODE7
|
||||
|
@ -480,6 +538,7 @@ skip_psync_loop_exit:
|
|||
pop {r0-r12, lr}
|
||||
skip_osd_update:
|
||||
|
||||
|
||||
#ifdef MULTI_BUFFER
|
||||
// Update the last drawn buffer
|
||||
mov r0, r3, lsr #OFFSET_CURR_BUFFER
|
||||
|
@ -491,6 +550,8 @@ skip_osd_update:
|
|||
#endif
|
||||
|
||||
push {r0-r12, lr}
|
||||
|
||||
|
||||
bl recalculate_hdmi_clock_line_locked_update
|
||||
|
||||
// Returns:
|
||||
|
@ -775,3 +836,10 @@ vsync_line:
|
|||
|
||||
lock_fail:
|
||||
.word 0
|
||||
|
||||
paletteFlags:
|
||||
.word 0
|
||||
|
||||
customPalette:
|
||||
.space 1024, 0
|
||||
|
||||
|
|
|
@ -41,4 +41,6 @@ extern int lock_fail;
|
|||
|
||||
int recalculate_hdmi_clock_line_locked_update();
|
||||
|
||||
void osd_update_palette();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -459,7 +459,11 @@ static void recalculate_hdmi_clock(int vlockmode) { // use local vsyncmode, not
|
|||
double f2 = pllh_clock;
|
||||
if (vlockmode > 0) {
|
||||
f2 /= error;
|
||||
f2 /= 1.0 + ((double) (HDMI_EXACT - vlockmode)) / 1000.0;
|
||||
double divisor = 1000.0;
|
||||
if (vlockmode == HDMI_SLOW_1000PPM || vlockmode == HDMI_FAST_1000PPM) {
|
||||
divisor = 2000.0; //workaround 1000PPM actually now 500PPM
|
||||
}
|
||||
f2 /= 1.0 + ((double) (HDMI_EXACT - vlockmode)) / divisor;
|
||||
}
|
||||
|
||||
// Sanity check HDMI pixel clock
|
||||
|
@ -573,13 +577,13 @@ int recalculate_hdmi_clock_line_locked_update() {
|
|||
log_info("Locked");
|
||||
} else {
|
||||
if (difference >= target_difference) {
|
||||
if (difference < (20 + target_difference)) {
|
||||
if (difference <= 3) {
|
||||
recalculate_hdmi_clock_once(HDMI_SLOW_1000PPM);
|
||||
} else {
|
||||
recalculate_hdmi_clock_once(HDMI_SLOW_2000PPM);
|
||||
}
|
||||
} else {
|
||||
if (difference > (-20 + target_difference)) {
|
||||
if (difference >= 3) {
|
||||
recalculate_hdmi_clock_once(HDMI_FAST_1000PPM);
|
||||
} else {
|
||||
recalculate_hdmi_clock_once(HDMI_FAST_2000PPM);
|
||||
|
|
Ładowanie…
Reference in New Issue