generated from saji/ecp5-template
151 lines
3.9 KiB
C++
151 lines
3.9 KiB
C++
// Project-specific cosimuluated devices.
|
|
#pragma once
|
|
#include "tests.hpp"
|
|
#include "Vhub75e.h"
|
|
|
|
// slices the RGB values for us.
|
|
uint8_t rgb_slice(uint32_t rgb, uint8_t bit) {
|
|
if (bit > 8) {
|
|
// todo: panic
|
|
return 0;
|
|
}
|
|
uint8_t r = (rgb >> (16 + bit)) & 1;
|
|
uint8_t g = (rgb >> (8 + bit)) & 1;
|
|
uint8_t b = (rgb >> bit) & 1;
|
|
return (r << 2) & (g << 1) & (b << 1);
|
|
}
|
|
|
|
void rgb_unslice(unsigned int &rgb, uint8_t bits, uint8_t bitpos) {
|
|
if (bitpos > 7 || bits > 0b111) {
|
|
// TODO: panic.
|
|
return;
|
|
}
|
|
auto r = (bits >> 2) & 1;
|
|
auto g = (bits >> 1) & 1;
|
|
auto b = (bits >> 0) & 1;
|
|
|
|
rgb |= r << bitpos << 16;
|
|
rgb |= g << bitpos << 8;
|
|
rgb |= b << bitpos << 0;
|
|
}
|
|
|
|
class HUB75Reciever : public CosimulatedDevice {
|
|
|
|
typedef std::vector<unsigned char> row_array;
|
|
int xsize;
|
|
int ysize;
|
|
|
|
row_array row0{};
|
|
row_array row1{};
|
|
|
|
// the previous row values that were latched in.
|
|
std::vector<std::pair<row_array, row_array>> past_rows{};
|
|
// the pulse width for each output, in clock cycles.
|
|
std::vector<int> pulse_widths{};
|
|
|
|
int bit_position = 7; // the bit that is currently being shifted in
|
|
|
|
int output_period_cnt;
|
|
// if oe = 0, count clocks. when oe = 1, store value into
|
|
// pulse_widths[display_bit];
|
|
|
|
// previous latch value, used to identify when to latch.
|
|
unsigned char prev_latch = 0;
|
|
// previous display clock value, used to detect rising edge.
|
|
unsigned char prev_display_clk = 0;
|
|
|
|
unsigned char prev_clk = 0;
|
|
|
|
unsigned char prev_oe = 1; // assuming starting high.
|
|
|
|
// references to the panel driver signals.
|
|
VL_IN8(&display_clk, 0, 0);
|
|
VL_IN8(&out_enable, 0, 0);
|
|
VL_IN8(&latch, 0, 0);
|
|
VL_IN8(&rgb0, 2, 0);
|
|
VL_IN8(&rgb1, 2, 0);
|
|
VL_IN8(&clk, 0, 0);
|
|
|
|
public:
|
|
HUB75Reciever(int xsize, int ysize, const Vhub75e &dut)
|
|
: clk(dut.clk), display_clk(dut.display_clk), out_enable(dut.out_enable),
|
|
latch(dut.latch), rgb0(dut.panel_rgb0), rgb1(dut.panel_rgb1) {
|
|
this->xsize = xsize;
|
|
this->ysize = ysize;
|
|
row0.clear();
|
|
prev_oe = out_enable;
|
|
prev_display_clk = display_clk;
|
|
prev_latch = latch;
|
|
prev_clk = clk;
|
|
};
|
|
|
|
// evaluates the reciever.
|
|
virtual void tick() override {
|
|
|
|
if (prev_display_clk == 0 && display_clk == 1) {
|
|
// display clock rising edge.
|
|
row0.push_back(rgb0);
|
|
row1.push_back(rgb1);
|
|
}
|
|
|
|
if (prev_latch == 0 && latch == 1) {
|
|
// latch in the data: reverse the rows, and pu
|
|
std::reverse(row0.begin(), row0.end());
|
|
std::reverse(row1.begin(), row1.end());
|
|
past_rows.push_back(std::pair(row0, row1));
|
|
row0.clear();
|
|
row1.clear();
|
|
}
|
|
|
|
if (prev_clk == 0 && clk == 1) {
|
|
if (out_enable == 0) {
|
|
if (prev_oe == 1) {
|
|
// falling edge.
|
|
output_period_cnt = 1;
|
|
} else {
|
|
output_period_cnt++;
|
|
}
|
|
} else { // out_enable == 1
|
|
if (prev_oe == 1) {
|
|
// do nothing
|
|
}
|
|
if (prev_oe == 0) {
|
|
// rising edge
|
|
pulse_widths.push_back(output_period_cnt);
|
|
}
|
|
}
|
|
}
|
|
|
|
// update previous values
|
|
prev_display_clk = display_clk;
|
|
prev_latch = latch;
|
|
prev_oe = out_enable;
|
|
prev_clk = clk;
|
|
}
|
|
|
|
const auto &get_past_rows() { return this->past_rows; }
|
|
const std::vector<int> &get_pulse_widths() { return this->pulse_widths; }
|
|
|
|
// return the RGB version.
|
|
std::pair<std::vector<unsigned int>, std::vector<unsigned int>> transpose() {
|
|
auto r0rgb = std::vector<unsigned int>(xsize, 0);
|
|
auto r1rgb = std::vector<unsigned int>(xsize, 0);
|
|
|
|
auto bitdepth = pulse_widths.size();
|
|
|
|
// TODO: use more sophisticated slicing.
|
|
auto slice = bitdepth - 1;
|
|
for (const auto &[row0slice, row1slice] : this->past_rows) {
|
|
|
|
for (int i = 0; i < row0slice.size(); i++) {
|
|
rgb_unslice(r0rgb[i], row0slice[i], slice);
|
|
rgb_unslice(r1rgb[i], row1slice[i], slice);
|
|
}
|
|
|
|
slice--;
|
|
}
|
|
|
|
return std::pair(r0rgb, r1rgb);
|
|
}
|
|
};
|