Internal change
PiperOrigin-RevId: 549214897
diff --git a/sim/kelvin_instructions.cc b/sim/kelvin_instructions.cc
index 357eb9b..dbc25d6 100644
--- a/sim/kelvin_instructions.cc
+++ b/sim/kelvin_instructions.cc
@@ -60,6 +60,8 @@
break;
}
case 1: { // Scalar log op to load an integer argument.
+ // The value is stored as an unsigned integer. The actual format will be
+ // determined with the format specifier "d" or "u".
auto data =
mpact::sim::generic::GetInstructionSource<uint32_t>(inst, 0, 0);
state->SetLogArgs(data);
diff --git a/sim/kelvin_state.cc b/sim/kelvin_state.cc
index 5fd15ca..3903548 100644
--- a/sim/kelvin_state.cc
+++ b/sim/kelvin_state.cc
@@ -3,6 +3,7 @@
#include <cstdint>
#include <iostream>
+#include <ostream>
#include <string>
#include "absl/log/check.h"
@@ -47,10 +48,25 @@
CHECK_GT(log_args_.size(), 0)
<< "Invalid program with insufficient log argurments";
if (log_args_[0].type() == typeid(uint32_t)) {
- std::cout << std::any_cast<uint32_t>(log_args_[0]);
+ switch (print_ptr[1]) {
+ case 'u':
+ std::cout << std::any_cast<uint32_t>(log_args_[0]);
+ break;
+ case 'd':
+ std::cout << static_cast<int32_t>(
+ std::any_cast<uint32_t>(log_args_[0]));
+ break;
+ default:
+ std::cerr << "incorrect format" << std::endl;
+ break;
+ }
}
if (log_args_[0].type() == typeid(std::string)) {
- std::cout << std::any_cast<std::string>(log_args_[0]);
+ if (print_ptr[1] == 's') {
+ std::cout << std::any_cast<std::string>(log_args_[0]);
+ } else {
+ std::cerr << "incorrect format" << std::endl;
+ }
}
log_args_.erase(log_args_.begin());
print_ptr += 2; // skip the format specifier too.
diff --git a/sim/test/kelvin_log_instructions_test.cc b/sim/test/kelvin_log_instructions_test.cc
index 093b610..e868a62 100644
--- a/sim/test/kelvin_log_instructions_test.cc
+++ b/sim/test/kelvin_log_instructions_test.cc
@@ -46,9 +46,9 @@
EXPECT_EQ(kHelloString, stdout_str);
}
-TEST_F(KelvinLogInstructionsTest, PrintNumer) {
- constexpr char kFormatString[] = "Hello %d\n";
- constexpr uint32_t kPrintNum = 1337;
+TEST_F(KelvinLogInstructionsTest, PrintUnsignedNumber) {
+ constexpr char kFormatString[] = "Hello %u\n";
+ constexpr uint32_t kPrintNum = 2200000000; // a number > INT32_MAX
// Initialize memory.
auto *db = state_->db_factory()->Allocate<char>(sizeof(kFormatString));
@@ -80,7 +80,44 @@
instructions[i]->Execute(nullptr);
}
const std::string stdout_str = testing::internal::GetCapturedStdout();
- EXPECT_EQ("Hello 1337\n", stdout_str);
+ EXPECT_EQ("Hello 2200000000\n", stdout_str);
+}
+
+TEST_F(KelvinLogInstructionsTest, PrintSignedNumber) {
+ constexpr char kFormatString[] = "Hello %d\n";
+ constexpr int32_t kPrintNum = -1337;
+
+ // Initialize memory.
+ auto *db = state_->db_factory()->Allocate<char>(sizeof(kFormatString));
+ for (int i = 0; i < sizeof(kFormatString); ++i) {
+ db->Set<char>(i, kFormatString[i]);
+ }
+ db->DecRef();
+
+ std::array<InstructionPtr, 2> instructions = {CreateInstruction(),
+ CreateInstruction()};
+
+ AppendRegisterOperands(instructions[0].get(), {kelvin::sim::test::kRs1Name},
+ {});
+ instructions[0]->set_semantic_function(
+ absl::bind_front(&KelvinLogInstruction, /*mode=*/1)); // scalar log
+
+ // Set the second instruction for the actual print out.
+ state_->StoreMemory(instructions[1].get(), kMemAddress, db);
+ AppendRegisterOperands(instructions[1].get(), {kelvin::sim::test::kRs2Name},
+ {});
+ instructions[1]->set_semantic_function(
+ absl::bind_front(&KelvinLogInstruction, /*mode=*/0));
+
+ SetRegisterValues<int32_t>({{kelvin::sim::test::kRs1Name, kPrintNum}});
+ SetRegisterValues<uint32_t>({{kelvin::sim::test::kRs2Name, kMemAddress}});
+
+ testing::internal::CaptureStdout();
+ for (int i = 0; i < instructions.size(); ++i) {
+ instructions[i]->Execute(nullptr);
+ }
+ const std::string stdout_str = testing::internal::GetCapturedStdout();
+ EXPECT_EQ("Hello -1337\n", stdout_str);
}
TEST_F(KelvinLogInstructionsTest, PrintCharacterStream) {