Skip to content

Instantly share code, notes, and snippets.

@alsrgv
Last active February 20, 2023 12:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alsrgv/b08d35715854642691fed0084c6c1076 to your computer and use it in GitHub Desktop.
Save alsrgv/b08d35715854642691fed0084c6c1076 to your computer and use it in GitHub Desktop.
TMDS in C++ HLS
#include <assert.h>
#include "tmds.h"
#include "utils.h"
template<int X>
ap_uint<log2up(X)> count_ones(ap_uint<X> data) {
ap_uint<X> result = data[0];
for (int i = 1; i < 8; i++) {
#pragma HLS UNROLL
result += data[i];
}
return result;
}
template<int X>
ap_uint<X> rolling_xor(ap_uint<X> data) {
ap_uint<X> result = data[0];
for (int i = 1; i < 8; i++) {
#pragma HLS UNROLL
result[i] = result[i - 1] ^ data[i];
}
return result;
}
template<int X>
ap_uint<X> rolling_xnor(ap_uint<X> data) {
ap_uint<X> result = data[0];
for (int i = 1; i < 8; i++) {
#pragma HLS UNROLL
result[i] = result[i - 1] ^~ data[i];
}
return result;
}
void tmds_encode(bool disp_ena, ap_uint<2> control,
ap_uint<8> d_in, tmds_encoded_t& d_out) {
#pragma HLS INTERFACE ap_none port=disp_ena
#pragma HLS INTERFACE ap_none port=control
#pragma HLS INTERFACE ap_none port=d_in
#pragma HLS INTERFACE ap_none register port=d_out
#pragma HLS INTERFACE ap_ctrl_none port=return
#pragma HLS DATA_PACK variable=d_out
#pragma HLS LATENCY min=1 max=1
#pragma HLS PIPELINE
#pragma HLS INLINE recursive
static ap_int<6> disparity;
#pragma HLS RESET variable=disparity
auto ones_d_in = count_ones(d_in);
auto use_xor = ones_d_in < 4 || (ones_d_in == 4 && (d_in & 1));
auto q_m = use_xor ? rolling_xor(d_in) : rolling_xnor(d_in);
auto ones_q_m = count_ones(q_m);
auto diff_q_m = ones_q_m - (8 - ones_q_m);
bool inv_q_m;
if (disparity == 0 && ones_q_m == 4) {
// inv_q_m negates xor to preserve balance between ones and zeroes.
inv_q_m = !use_xor;
} else {
inv_q_m = (disparity > 0 && ones_q_m > 4) || (disparity < 0 && ones_q_m < 4);
}
if (disp_ena) {
// Output.
d_out.inv_q_m = inv_q_m;
d_out.use_xor = use_xor;
if (inv_q_m) {
d_out.q_m = ~q_m;
} else {
d_out.q_m = q_m;
}
// Adjust disparity.
if (inv_q_m) {
disparity -= diff_q_m - 1;
} else {
disparity += diff_q_m - 1;
}
} else {
// Output.
switch (control) {
case 0:
d_out = {true, true, 0x54};
break;
case 1:
d_out = {false, false, 0xab};
break;
case 2:
d_out = {false, true, 0x54};
break;
case 3:
d_out = {true, false, 0xab};
break;
}
// Adjust disparity.
disparity = 0;
}
}
#pragma once
#include "ap_int.h"
struct tmds_encoded_t {
bool inv_q_m;
bool use_xor;
ap_uint<8> q_m;
};
void tmds_encode(bool disp_ena, ap_uint<2> control,
ap_uint<8> d_in, tmds_encoded_t& d_out);
#include "tmds.h"
int main() {
tmds_encoded_t result;
for (int i = 0; i < 10; i++) {
tmds_encode(true, 0, 123, result);
printf("result: %x\n", result.q_m.to_int());
}
return 0;
}
constexpr int log2up(int n) {
return n < 2 ? 1 : 1 + log2up(n / 2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment