diff --git a/software/apps/vista/CMakeLists.txt b/software/apps/vista/CMakeLists.txt index 8da5ec1..8e6cf56 100644 --- a/software/apps/vista/CMakeLists.txt +++ b/software/apps/vista/CMakeLists.txt @@ -13,9 +13,15 @@ target_compile_definitions(vista_boot2 PRIVATE PICO_FLASH_SPI_CLKDIV=2) pico_set_boot_stage2(vista vista_boot2) -target_compile_definitions(vista PRIVATE DVI_VERTICAL_REPEAT=1 DVI_N_TMDS_BUFFERS=5) +target_compile_definitions(vista PRIVATE + DVI_VERTICAL_REPEAT=1 + DVI_N_TMDS_BUFFERS=5 + DVI_SYMBOLS_PER_WORD=1 + ) + target_compile_definitions(vista PRIVATE PICO_STACK_SIZE=0x200) + target_link_libraries(vista pico_stdlib pico_multicore diff --git a/software/libdvi/dvi_timing.c b/software/libdvi/dvi_timing.c index 9d94ebe..ec17ff7 100644 --- a/software/libdvi/dvi_timing.c +++ b/software/libdvi/dvi_timing.c @@ -201,13 +201,17 @@ const uint32_t __dvi_const(dvi_ctrl_syms)[4] = { // Output solid red scanline if we are given NULL for tmdsbuff #if DVI_SYMBOLS_PER_WORD == 2 -static uint32_t __attribute__((aligned(8))) __dvi_const(empty_scanline_tmds)[3] = { - 0x7fd00u, // 0x00 - 0x7fd00u, // 0x00 - 0xbfa01u // 0xfc +static uint32_t __dvi_const(empty_scanline_tmds)[3] = { + 0x7fd00u, // 0x00, 0x00 + 0x7fd00u, // 0x00, 0x00 + 0xbfa01u // 0xfc, 0xfc }; #else -#error "Can't handle empty scanlines with pixel-per-word right now" +static uint32_t __attribute__((aligned(8))) __dvi_const(empty_scanline_tmds)[6] = { + 0x100u, 0x1ffu, // 0x00, 0x00 + 0x100u, 0x1ffu, // 0x00, 0x00 + 0x201u, 0x2feu // 0xfc, 0xfc +}; #endif void dvi_timing_state_init(struct dvi_timing_state *t) { @@ -259,6 +263,7 @@ void dvi_setup_scanline_for_vblank(const struct dvi_timing *t, const struct dvi_ const uint32_t *sym_no_sync = get_ctrl_sym(false, false ); dma_cb_t *synclist = dvi_lane_from_list(l, TMDS_SYNC_LANE); + // The symbol table contains each control symbol *twice*, concatenated into 20 LSBs of table word, so we can always do word-repeat. _set_data_cb(&synclist[0], &dma_cfg[TMDS_SYNC_LANE], sym_hsync_off, t->h_front_porch / DVI_SYMBOLS_PER_WORD, 2, false); _set_data_cb(&synclist[1], &dma_cfg[TMDS_SYNC_LANE], sym_hsync_on, t->h_sync_width / DVI_SYMBOLS_PER_WORD, 2, false); _set_data_cb(&synclist[2], &dma_cfg[TMDS_SYNC_LANE], sym_hsync_off, t->h_back_porch / DVI_SYMBOLS_PER_WORD, 2, true); @@ -298,7 +303,7 @@ void dvi_setup_scanline_for_active(const struct dvi_timing *t, const struct dvi_ t->h_active_pixels / DVI_SYMBOLS_PER_WORD, 0, false); } else { - // 8-byte read ring mode to repeat the correct DC-balanced symbol pair on blank scanlines + // Use read ring to repeat the correct DC-balanced symbol pair on blank scanlines (4 or 8 byte period) _set_data_cb(&cblist[target_block], &dma_cfg[i], &empty_scanline_tmds[2 * i / DVI_SYMBOLS_PER_WORD], t->h_active_pixels / DVI_SYMBOLS_PER_WORD, DVI_SYMBOLS_PER_WORD == 2 ? 2 : 3, false); } diff --git a/software/libdvi/tmds_encode.S b/software/libdvi/tmds_encode.S index dd9861b..7164f30 100644 --- a/software/libdvi/tmds_encode.S +++ b/software/libdvi/tmds_encode.S @@ -275,11 +275,9 @@ tmds_1bpp_table: // once (2 words), and write 4 at once (4 words). This gives 7 cyc/pix. // // One issue is that the TMDS data in the bottom of ACCUM1 will eventually -// overflow and affect the running disparity. At least 64 pixels will pass -// before this happens, so we just need to read out ACCUM1, mask it, and write -// it back at least once every 64 pixels. This could be done at the end of -// every unrolled loop, before the test and branch. At 16 pix/loop this is an -// additional 0.5 cyc/pix. +// overflow and affect the running disparity, but with 16 zeroes in between, +// this would take much longer than one scanline, so everything is fine if +// we clear the accumulator at the start of the scanline. // // Note that we need to use two interpolators to get the bits from both pixels // -- we are not outputting a single DC-balanced stream, but rather two @@ -355,16 +353,6 @@ tmds_1bpp_table: stmia r1!, {r4, r5, r6, r7} .endr - // Need to mask away bottoms of ACCUM1 before the TMDS data overflows into - // disparity counter. This costs 8 cycles per loop body. -#if !TMDS_FULLRES_NO_DC_BALANCE - ldr r4, [r2, #ACCUM1_OFFS] - ands r4, r3 - str r4, [r2, #ACCUM1_OFFS] - ldr r4, [r2, #ACCUM1_OFFS + INTERP1] - ands r4, r3 - str r4, [r2, #ACCUM1_OFFS + INTERP1] -#endif 2: cmp r1, ip beq 1f @@ -447,17 +435,6 @@ decl_func_y tmds_fullres_encode_loop_16bpp_y stmia r1!, {r4, r5, r6, r7} .endr - // Need to mask away bottoms of ACCUM1 before the TMDS data overflows into - // disparity counter -#if !TMDS_FULLRES_NO_DC_BALANCE - mov r5, r9 - ldr r4, [r2, #ACCUM1_OFFS] - ands r4, r5 - str r4, [r2, #ACCUM1_OFFS] - ldr r4, [r2, #ACCUM1_OFFS + INTERP1] - ands r4, r5 - str r4, [r2, #ACCUM1_OFFS + INTERP1] -#endif 2: cmp r1, ip beq 1f diff --git a/software/libdvi/tmds_table_fullres.h b/software/libdvi/tmds_table_fullres.h index 984106a..872d7ff 100644 --- a/software/libdvi/tmds_table_fullres.h +++ b/software/libdvi/tmds_table_fullres.h @@ -1,6 +1,6 @@ -// Each entry consists of a 20 bit TMDS symbol in pseudo-differential format -// (20 LSBs) and the symbol's disparity as a 6 bit signed integer (the 6 -// MSBs). There is a 6 bit gap in between them, which is actually vital for +// Each entry consists of a 10 bit TMDS symbol in pseudo-differential format +// (10 LSBs) and the symbol's disparity as a 6 bit signed integer (the 6 +// MSBs). There is a 16 bit gap in between them, which is actually vital for // the way the TMDS encode works! // // There are 128 1-word entries. The lookup index should be the concatenation @@ -8,132 +8,132 @@ // data. // Non-negative running disparity: -0xe009aaaa, -0xf805aaa5, -0x0005aa95, -0xe809aa9a, -0x000955aa, -0xf009aa5a, -0xe809aa6a, -0x0005aa65, -0xf80956aa, -0xf809a95a, -0xf009a96a, -0x0009569a, -0xe809a9aa, -0x0005a9a5, -0x0009566a, -0xf0069aa9, -0xf0095aaa, -0x0009a55a, -0xf809a56a, -0xf8095a9a, -0xf009a5aa, -0x00095a5a, -0xf8095a6a, -0xf80696a9, -0xe809a6aa, -0x0005a6a5, -0x0009596a, -0x000695a9, -0xf80959aa, -0xf00a6a96, -0xe80a6aa6, -0xf0066aa9, -0xe8096aaa, -0x00056aa5, -0x0009956a, -0xf0096a9a, -0xf80995aa, -0xf8096a5a, -0xf0096a6a, -0xf006a6a9, -0xf00996aa, -0x0009695a, -0xf809696a, -0xf806a5a9, -0xf00969aa, -0x0006a569, -0xf00a5aa6, -0xf8065aa9, -0xe8099aaa, -0x00059aa5, -0x0009656a, -0xf006a9a9, -0xf80965aa, -0xf806a969, -0x0006a959, -0x000656a9, -0xf00966aa, -0xf006aa69, -0xf806aa59, -0xf00aaa56, -0xf006aa99, -0xe80aaa96, -0xe00aaaa6, -0xe806aaa9, +0xe0000100, +0xf8000303, +0x00000307, +0xe8000104, +0x000001f0, +0xf000010c, +0xe8000108, +0x0000030b, +0xf80001e0, +0xf800011c, +0xf0000118, +0x000001e4, +0xe8000110, +0x00000313, +0x000001e8, +0xf0000241, +0xf00001c0, +0x0000013c, +0xf8000138, +0xf80001c4, +0xf0000130, +0x000001cc, +0xf80001c8, +0xf8000261, +0xe8000120, +0x00000323, +0x000001d8, +0x00000271, +0xf80001d0, +0xf0000086, +0xe8000082, +0xf0000281, +0xe8000180, +0x00000383, +0x00000178, +0xf0000184, +0xf8000170, +0xf800018c, +0xf0000188, +0xf0000221, +0xf0000160, +0x0000019c, +0xf8000198, +0xf8000231, +0xf0000190, +0x00000239, +0xf00000c2, +0xf80002c1, +0xe8000140, +0x00000343, +0x000001b8, +0xf0000211, +0xf80001b0, +0xf8000219, +0x0000021d, +0x000002e1, +0xf00001a0, +0xf0000209, +0xf800020d, +0xf000000e, +0xf0000205, +0xe8000006, +0xe0000002, +0xe8000201, // Negative running disparity: -0x28055555, -0x1009555a, -0x0809556a, -0x20055565, -0x000955aa, -0x180555a5, -0x20055595, -0x0809559a, -0x1005a955, -0x100556a5, -0x18055695, -0x0009569a, -0x20055655, -0x0809565a, -0x0009566a, -0x080a6556, -0x1805a555, -0x0009a55a, -0x10055a95, -0x1005a565, -0x18055a55, -0x00095a5a, -0x1005a595, -0x000a6956, -0x20055955, -0x0809595a, -0x0009596a, -0x000695a9, -0x1005a655, -0x08069569, -0x10069559, -0x080a9556, -0x20059555, -0x0809955a, -0x0009956a, -0x18059565, -0x10056a55, -0x100595a5, -0x18059595, -0x080a5956, -0x18056955, -0x0009695a, -0x10059695, -0x000a5a56, -0x18059655, -0x0006a569, -0x0806a559, -0x000aa556, -0x20056555, -0x0809655a, -0x0009656a, -0x080a5656, -0x10059a55, -0x000a5696, -0x0006a959, -0x000656a9, -0x18059955, -0x080a5596, -0x000a55a6, -0x080655a9, -0x080a5566, -0x10065569, -0x18065559, -0x100a5556, +0x280003ff, +0x100001fc, +0x080001f8, +0x200003fb, +0x000001f0, +0x180003f3, +0x200003f7, +0x080001f4, +0x1000031f, +0x100003e3, +0x180003e7, +0x000001e4, +0x200003ef, +0x080001ec, +0x000001e8, +0x080000be, +0x1800033f, +0x0000013c, +0x100003c7, +0x1000033b, +0x180003cf, +0x000001cc, +0x10000337, +0x0000009e, +0x200003df, +0x080001dc, +0x000001d8, +0x00000271, +0x1000032f, +0x08000279, +0x1000027d, +0x0800007e, +0x2000037f, +0x0800017c, +0x00000178, +0x1800037b, +0x1000038f, +0x10000373, +0x18000377, +0x080000de, +0x1800039f, +0x0000019c, +0x10000367, +0x000000ce, +0x1800036f, +0x00000239, +0x0800023d, +0x0000003e, +0x200003bf, +0x080001bc, +0x000001b8, +0x080000ee, +0x1000034f, +0x000000e6, +0x0000021d, +0x000002e1, +0x1800035f, +0x080000f6, +0x000000f2, +0x080002f1, +0x080000fa, +0x100002f9, +0x180002fd, +0x100000fe, diff --git a/software/libdvi/tmds_table_gen.py b/software/libdvi/tmds_table_gen.py index 97d1192..579f890 100755 --- a/software/libdvi/tmds_table_gen.py +++ b/software/libdvi/tmds_table_gen.py @@ -98,16 +98,16 @@ enc = TMDSEncode() # (two pairs of dark/light colours. Creates some fairly subtle vertical # (banding, but it's cheap. -for i in range(1 << 4): - syms = list(enc.encode((0xff if i & 1 << j else 0) ^ j & 0x01, 0, 1) for j in range(4)) - print(f"0x{syms[0] | syms[1] << 10:05x}, 0x{syms[2] | syms[3] << 10:05x}") - assert(enc.imbalance == 0) +# for i in range(1 << 4): +# syms = list(enc.encode((0xff if i & 1 << j else 0) ^ j & 0x01, 0, 1) for j in range(4)) +# print(f"0x{syms[0] | syms[1] << 10:05x}, 0x{syms[2] | syms[3] << 10:05x}") +# assert(enc.imbalance == 0) ### # Fullres table stuff: # def disptable_format(sym): -# return differentialise(sym, 10) | ((popcount(sym) * 2 - 10 & 0x3f) << 26) +# return sym | ((popcount(sym) * 2 - 10 & 0x3f) << 26) # print("// Non-negative running disparity:") # for i in range(0, 256, 4):