Skip to content

Commit 7874b34

Browse files
committed
Partial progress towards analog waves
1 parent 0b01c1f commit 7874b34

File tree

7 files changed

+306
-110
lines changed

7 files changed

+306
-110
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ add_executable(simview
4040
wave_data.cc
4141
wavedata_tree_item.cc
4242
wavedata_tree_panel.cc
43+
wave_image.cc
4344
wave_signals_panel.cc
4445
waves_panel.cc
4546
workspace.cc

src/radix.cc

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,62 @@
11
#include "radix.h"
22
#include "absl/strings/str_format.h"
3+
#include <optional>
34

45
namespace sv {
5-
std::string FormatValue(const std::string &bin, Radix radix,
6-
bool leading_zeroes, bool drop_size) {
6+
7+
namespace {
8+
9+
int64_t SignExtend(uint64_t val, int bits) {
10+
if (val & (1ull << (bits - 1))) return val | (static_cast<uint64_t>(-1) << bits);
11+
return val;
12+
}
13+
14+
template <typename T>
15+
std::optional<T> BinStringCast(std::string_view bin) {
16+
std::optional<uint64_t> val_or = BinStringToUnsigned(bin);
17+
if (!val_or) return std::nullopt;
18+
const uint64_t val = *val_or;
19+
T t;
20+
memcpy(&t, &val, sizeof(T));
21+
return t;
22+
}
23+
24+
} // namespace
25+
26+
std::optional<uint64_t> BinStringToUnsigned(std::string_view bin) {
27+
if (bin.size() > 64) return std::nullopt;
28+
uint64_t val = 0;
29+
for (char ch : bin) {
30+
if (ch != '0' && ch != '1') return std::nullopt;
31+
val <<= 1;
32+
val |= ch == '1';
33+
}
34+
return val;
35+
}
36+
37+
std::optional<float> BinStringToFp32(std::string_view bin) { return BinStringCast<float>(bin); }
38+
39+
std::optional<double> BinStringToFp64(std::string_view bin) { return BinStringCast<double>(bin); }
40+
41+
std::optional<int64_t> BinStringToSigned(std::string_view bin) {
42+
std::optional<uint64_t> val_or = BinStringToUnsigned(bin);
43+
if (!val_or) return std::nullopt;
44+
return SignExtend(*val_or, bin.size());
45+
}
46+
47+
std::string FormatValue(const std::string &bin, Radix radix, bool leading_zeroes, bool drop_size) {
748
if (radix == Radix::kUnsignedDecimal || radix == Radix::kSignedDecimal ||
849
radix == Radix::kFloat) {
950
// These formats can use a real machine type and therefore take advantage of
1051
// printf style formatting.
11-
uint64_t val = 0;
12-
for (int i = 0; i < bin.size(); ++i) {
13-
const char ch = std::tolower(bin[bin.size() - 1 - i]);
14-
if (ch == 'z' || ch == 'x') return "x";
15-
if (bin[bin.size() - 1 - i] == '1') val |= 1ull << i;
16-
}
52+
std::optional<uint64_t> maybe_val = BinStringToUnsigned(bin);
53+
if (!maybe_val) return "x";
54+
uint64_t val = *maybe_val;
1755
if (radix == Radix::kUnsignedDecimal) {
18-
return (drop_size ? "" : absl::StrFormat("%d'd", bin.size())) +
19-
absl::StrFormat("%lu", val);
56+
return (drop_size ? "" : absl::StrFormat("%d'd", bin.size())) + absl::StrFormat("%lu", val);
2057
} else if (radix == Radix::kSignedDecimal) {
21-
return (drop_size ? "" : absl::StrFormat("%d'sd", bin.size())) +
22-
absl::StrFormat("%ld", val);
58+
int64_t sval = SignExtend(val, bin.size());
59+
return (drop_size ? "" : absl::StrFormat("%d'sd", bin.size())) + absl::StrFormat("%ld", sval);
2360
} else if (bin.size() == 32) {
2461
float f;
2562
memcpy(&f, &val, sizeof(float));

src/radix.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include <cstdint>
4+
#include <optional>
35
#include <string>
46

57
namespace sv {
@@ -12,6 +14,11 @@ enum class Radix {
1214
kFloat,
1315
};
1416

17+
std::optional<float> BinStringToFp32(std::string_view bin);
18+
std::optional<double> BinStringToFp64(std::string_view bin);
19+
std::optional<int64_t> BinStringToSigned(std::string_view bin);
20+
std::optional<uint64_t> BinStringToUnsigned(std::string_view bin);
21+
1522
// Format a string of '1' and '0' charachters into the proper representation.
1623
std::string FormatValue(const std::string &bin, Radix radix,
1724
bool leading_zeroes, bool drop_size = false);

src/wave_image.cc

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#include "wave_image.h"
2+
#include <cstdlib>
3+
4+
namespace sv {
5+
6+
void WaveImage::SetPixel(int x, int y) {
7+
if (x < 0 || x >= width_) return;
8+
if (y < 0 || y >= height_) return;
9+
buffer_[y * width_ * x] = true;
10+
}
11+
12+
void WaveImage::DrawLine(int x0, int y0, int x1, int y1) {
13+
if (x0 < 0 || x1 < 0 || x0 >= width_ || x1 >= width_) return;
14+
if (y0 < 0 || y1 < 0 || y0 >= height_ || y1 >= height_) return;
15+
// Bresenham's Line Algorithm
16+
const bool steep = std::abs(y1 - y0) > std::abs(x1 - x0);
17+
if (steep) {
18+
std::swap(x0, y0);
19+
std::swap(x1, y1);
20+
}
21+
if (x0 > x1) {
22+
std::swap(x0, x1);
23+
std::swap(y0, y1);
24+
}
25+
26+
const int dx = x1 - x0;
27+
const int dy = std::abs(y1 - y0);
28+
const int ystep = (y0 < y1) ? 1 : -1;
29+
int error = dx / 2;
30+
int y = y0;
31+
32+
for (int x = x0; x <= x1; ++x) {
33+
if (steep) {
34+
SetPixel(y, x);
35+
} else {
36+
SetPixel(x, y);
37+
}
38+
error -= dy;
39+
if (error < 0) {
40+
y += ystep;
41+
error += dx;
42+
}
43+
}
44+
}
45+
46+
uint16_t WaveImage::GetBrailleChar(int x, int y) {
47+
// Bit index as follows:
48+
// 0 3
49+
// 1 4
50+
// 2 5
51+
// 6 7
52+
// nicode value is 0x28xx, with xx being the 8-bits above.
53+
uint16_t braille = 0x2800;
54+
if (x >= width_ / 2 || y >= height_ / 4) return braille;
55+
braille |= buffer_[(4 * y + 0) * width_ + (2 * x + 0)] << 0;
56+
braille |= buffer_[(4 * y + 1) * width_ + (2 * x + 0)] << 1;
57+
braille |= buffer_[(4 * y + 2) * width_ + (2 * x + 0)] << 2;
58+
braille |= buffer_[(4 * y + 0) * width_ + (2 * x + 1)] << 3;
59+
braille |= buffer_[(4 * y + 1) * width_ + (2 * x + 1)] << 4;
60+
braille |= buffer_[(4 * y + 2) * width_ + (2 * x + 1)] << 5;
61+
braille |= buffer_[(4 * y + 3) * width_ + (2 * x + 0)] << 6;
62+
braille |= buffer_[(4 * y + 3) * width_ + (2 * x + 1)] << 7;
63+
return braille;
64+
}
65+
66+
WaveImage RenderWaves(const WaveImageConfig &cfg, const std::vector<WaveData::Sample> &wave) {
67+
68+
69+
70+
// Braille patterns are 2x4 dots, "pixels".
71+
WaveImage img(cfg.char_w * 2, cfg.char_h * 4);
72+
73+
int p0_idx = cfg.left_idx;
74+
while (p0_idx > 0 && wave[p0_idx].time > cfg.left_time) {
75+
p0_idx--;
76+
}
77+
// Draw stable signal up to the first point.
78+
if (wave[p0_idx].time > cfg.left_time) {
79+
}
80+
81+
82+
return img;
83+
}
84+
} // namespace sv

src/wave_image.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#pragma once
2+
3+
#include "radix.h"
4+
#include "wave_data.h"
5+
6+
#include <cstdint>
7+
#include <vector>
8+
9+
namespace sv {
10+
11+
class WaveImage {
12+
public:
13+
WaveImage(int w, int h) : width_(w), height_(h), buffer_(w * h) {}
14+
bool GetPixel(int x, int y) const { return buffer_[y * width_ * x]; }
15+
void DrawLine(int x0, int y0, int x1, int y1);
16+
uint16_t GetBrailleChar(int x, int y);
17+
18+
private:
19+
void SetPixel(int x, int y);
20+
const int width_;
21+
const int height_;
22+
std::vector<bool> buffer_;
23+
};
24+
25+
struct WaveImageConfig {
26+
int char_w;
27+
int char_h;
28+
// Hint indicator where the sample is that's near the left edge of the image.
29+
int left_idx = 0;
30+
uint64_t left_time;
31+
uint64_t right_time;
32+
Radix radix = Radix::kBinary;
33+
};
34+
35+
WaveImage RenderWaves(const WaveImageConfig &cfg, const std::vector<WaveData::Sample> &wave);
36+
37+
} // namespace sv

0 commit comments

Comments
 (0)