blob: 6f9164ee39fd45b195364a05f3d099903ccd8ce5 [file] [log] [blame]
Brian Silverman4787a6e2018-10-06 16:00:54 -07001#include "motors/print/itm.h"
2
Austin Schuh7fe04492022-01-02 13:37:21 -08003#include <cstring>
4
5#include "absl/types/span.h"
Brian Silverman4787a6e2018-10-06 16:00:54 -07006#include "motors/core/itm.h"
7
8namespace frc971 {
9namespace motors {
10namespace {
11
Austin Schuh7fe04492022-01-02 13:37:21 -080012template <int kPort>
13void WriteToPort(absl::Span<const char> buffer) {
Brian Silverman4787a6e2018-10-06 16:00:54 -070014 // This ignores memory barriers etc, because it will be called by
15 // CreatePrinting which must be called before any interrupts are enabled. That
16 // means the only thing we need to worry about is actually getting it
17 // initialized with a minimal number of cycles.
18 static bool is_initialized = false;
19 if (__builtin_expect(!is_initialized, false)) {
20 is_initialized = true;
21 itm::Initialize();
22 }
23
24 const char *next_address = buffer.data();
25 int remaining_bytes = buffer.size();
26
27 // Write small chunks to make the address even.
28 if (remaining_bytes >= 1 && (reinterpret_cast<uintptr_t>(next_address) & 1)) {
29 uint8_t value;
30 memcpy(&value, next_address, 1);
31 itm::Write8(kPort, value);
32 next_address += 1;
33 remaining_bytes -= 1;
34 }
35 if (remaining_bytes >= 2 && (reinterpret_cast<uintptr_t>(next_address) & 2)) {
36 uint16_t value;
37 memcpy(&value, next_address, 2);
38 itm::Write16(kPort, value);
39 next_address += 2;
40 remaining_bytes -= 2;
41 }
42
43 // Write big chunks while we can.
44 while (remaining_bytes >= 4) {
45 uint32_t value;
46 memcpy(&value, next_address, 4);
47 itm::Write32(kPort, value);
48 next_address += 4;
49 remaining_bytes -= 4;
50 }
51
52 // Write out any remaining uneven bytes on the end.
53 if (remaining_bytes >= 2) {
54 uint16_t value;
55 memcpy(&value, next_address, 2);
56 itm::Write16(kPort, value);
57 next_address += 2;
58 remaining_bytes -= 2;
59 }
60 if (remaining_bytes >= 1) {
61 uint8_t value;
62 memcpy(&value, next_address, 1);
63 itm::Write8(kPort, value);
64 next_address += 1;
65 remaining_bytes -= 1;
66 }
67}
68
69} // namespace
70
71::std::unique_ptr<PrintingImplementation> CreatePrinting(
72 const PrintingParameters & /*parameters*/) {
73 return ::std::unique_ptr<PrintingImplementation>(new ItmPrinting());
74}
75
76extern "C" int _write(const int /*file*/, char *const ptr, const int len) {
Austin Schuh7fe04492022-01-02 13:37:21 -080077 WriteToPort<0>(absl::Span<const char>(ptr, len));
Brian Silverman4787a6e2018-10-06 16:00:54 -070078 return len;
79}
80
81ItmPrinting::ItmPrinting() {
82 // Make sure we run the one-time initialization. It's important to do it here
83 // to ensure it's complete before interrupts are enabled, because it's not
84 // interrupt-safe.
85 _write(0, nullptr, 0);
86}
87
Austin Schuh7fe04492022-01-02 13:37:21 -080088int ItmPrinting::WriteStdout(absl::Span<const char> buffer) {
Brian Silverman4787a6e2018-10-06 16:00:54 -070089 WriteToPort<0>(buffer);
90 return buffer.size();
91}
92
Austin Schuh7fe04492022-01-02 13:37:21 -080093int ItmPrinting::WriteDebug(absl::Span<const char> buffer) {
Brian Silverman4787a6e2018-10-06 16:00:54 -070094 WriteToPort<1>(buffer);
95 return buffer.size();
96}
97
98} // namespace motors
99} // namespace frc971