// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "riscv/riscv_csr.h"

#include <cstdint>
#include <string>
#include <utility>

#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "mpact/sim/generic/data_buffer.h"

namespace mpact {
namespace sim {
namespace riscv {

void RiscVCsrWriteDb::SetDataBuffer(generic::DataBuffer *db) {
  auto db_size = db->size<uint8_t>();
  if (db_size == 4) {
    csr_->Write(db->Get<uint32_t>(0));
    return;
  }
  if (db_size == 8) {
    csr_->Write(db->Get<uint64_t>(0));
    return;
  }
  LOG(ERROR) << "Attempted to write CSR with width != 32 or 64";
}

void RiscVCsrClearBitsDb::SetDataBuffer(generic::DataBuffer *db) {
  auto db_size = db->size<uint8_t>();
  if (db_size == 4) {
    csr_->ClearBits(db->Get<uint32_t>(0));
    return;
  }
  if (db_size == 8) {
    csr_->ClearBits(db->Get<uint64_t>(0));
    return;
  }
  LOG(ERROR) << "Attempted to clear CSR with width != 32 or 64";
}

void RiscVCsrSetBitsDb::SetDataBuffer(generic::DataBuffer *db) {
  auto db_size = db->size<uint8_t>();
  if (db_size == 4) {
    csr_->SetBits(db->Get<uint32_t>(0));
    return;
  }
  if (db_size == 8) {
    csr_->SetBits(db->Get<uint64_t>(0));
    return;
  }
  LOG(ERROR) << "Attempted to set CSR with width != 32 or 64";
}

absl::Status RiscVCsrSet::AddCsr(RiscVCsrInterface *csr) {
  if (csr == nullptr) {
    return absl::InvalidArgumentError("csr is nullptr");
  }
  auto index_ptr = csr_index_map_.find(csr->index());
  auto name_ptr = csr_name_map_.find(csr->name());
  if (index_ptr != csr_index_map_.end()) {
    return absl::AlreadyExistsError(absl::StrCat(
        "CSR 0x", absl::Hex(csr->index()), " already added to CSR set"));
  }
  if (name_ptr != csr_name_map_.end()) {
    return absl::AlreadyExistsError(
        absl::StrCat("'", csr->name(), "'", " already added to CSR set"));
  }

  csr_index_map_.insert(std::make_pair(csr->index(), csr));
  csr_name_map_.insert(std::make_pair(csr->name(), csr));
  return absl::OkStatus();
}

absl::StatusOr<RiscVCsrInterface *> RiscVCsrSet::GetCsr(
    absl::string_view name) {
  auto name_ptr = csr_name_map_.find(name);
  if (name_ptr == csr_name_map_.end()) {
    return absl::NotFoundError(absl::StrCat("No such CSR: '", name, "'"));
  }
  return name_ptr->second;
}

absl::StatusOr<RiscVCsrInterface *> RiscVCsrSet::GetCsr(uint64_t index) {
  auto index_ptr = csr_index_map_.find(index);
  if (index_ptr == csr_index_map_.end()) {
    return absl::NotFoundError(absl::StrCat("No such CSR index: ", index));
  }
  return index_ptr->second;
}

absl::Status RiscVCsrSet::RemoveCsr(uint64_t csr_index) {
  auto index_ptr = csr_index_map_.find(csr_index);
  if (index_ptr == csr_index_map_.end()) {
    return absl::NotFoundError(
        absl::StrCat("CSR 0x", absl::Hex(csr_index), " not found"));
  }
  auto name_ptr = csr_name_map_.find(index_ptr->second->name());
  csr_index_map_.erase(index_ptr);
  csr_name_map_.erase(name_ptr);
  return absl::OkStatus();
}

RiscVCsrSourceOperand::RiscVCsrSourceOperand(RiscVCsrInterface *csr,
                                             std::string op_name)
    : csr_(csr), op_name_(op_name) {}

RiscVCsrSourceOperand::RiscVCsrSourceOperand(RiscVCsrInterface *csr)
    : RiscVCsrSourceOperand(csr, csr->name()) {}

bool RiscVCsrSourceOperand::AsBool(int i) {
  return static_cast<bool>(csr_->AsUint32());
}
int8_t RiscVCsrSourceOperand::AsInt8(int i) {
  return static_cast<int8_t>(csr_->AsUint32());
}
uint8_t RiscVCsrSourceOperand::AsUint8(int i) {
  return static_cast<uint8_t>(csr_->AsUint32());
}
int16_t RiscVCsrSourceOperand::AsInt16(int i) {
  return static_cast<int16_t>(csr_->AsUint32());
}
uint16_t RiscVCsrSourceOperand::AsUint16(int i) {
  return static_cast<uint16_t>(csr_->AsUint32());
}
int32_t RiscVCsrSourceOperand::AsInt32(int i) {
  return static_cast<int32_t>(csr_->AsUint32());
}
uint32_t RiscVCsrSourceOperand::AsUint32(int i) {
  return static_cast<uint32_t>(csr_->AsUint32());
}
int64_t RiscVCsrSourceOperand::AsInt64(int i) {
  return static_cast<int64_t>(csr_->AsUint64());
}
uint64_t RiscVCsrSourceOperand::AsUint64(int i) {
  return static_cast<uint64_t>(csr_->AsUint64());
}

// Implementation of the destination op templated class methods.
RiscVCsrDestinationOperand::RiscVCsrDestinationOperand(
    RiscVCsrInterface *csr, generic::DataBufferDestination *db_dest,
    int latency, std::string op_name)
    : csr_(csr),
      db_dest_(db_dest),
      db_factory_(csr_->state()->db_factory()),
      latency_(latency),
      delay_line_(csr_->state()->data_buffer_delay_line()),
      op_name_(op_name) {}

RiscVCsrDestinationOperand::RiscVCsrDestinationOperand(
    RiscVCsrInterface *csr, generic::DataBufferDestination *db_dest,
    int latency)
    : RiscVCsrDestinationOperand(csr, db_dest, latency, csr->name()) {}

void RiscVCsrDestinationOperand::InitializeDataBuffer(generic::DataBuffer *db) {
  db->set_destination(db_dest_);
  db->set_latency(latency_);
  db->set_delay_line(delay_line_);
}

generic::DataBuffer *RiscVCsrDestinationOperand::CopyDataBuffer() {
  generic::DataBuffer *db = db_factory_->Allocate(csr_->size());
  if (csr_->size() == 4) {
    db->Set<uint32_t>(0, csr_->AsUint32());
  } else if (csr_->size() == 8) {
    db->Set<uint64_t>(0, csr_->AsUint64());
  }
  InitializeDataBuffer(db);
  return db;
}

generic::DataBuffer *RiscVCsrDestinationOperand::AllocateDataBuffer() {
  generic::DataBuffer *db = db_factory_->Allocate(csr_->size());
  InitializeDataBuffer(db);
  return db;
}

}  // namespace riscv
}  // namespace sim
}  // namespace mpact
