Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding f and d extesion #36

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open

adding f and d extesion #36

wants to merge 7 commits into from

Conversation

lzhu-pub
Copy link
Collaborator

@lzhu-pub lzhu-pub commented Jan 2, 2025

I am pretty sure there are logical mistakes about types. But eyeballing and scrutinizing can only carry me as far as it is now.

@@ -54,7 +54,12 @@ namespace atlas

uint32_t getOpcodeSize() const { return opcode_size_; }

sparta::Register* getRs1()
uint64_t getRM()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method can be made const

return opcode_info_->getSpecialField(mavis::OpcodeInfo::SpecialField::RM);
}

sparta::Register*& getRs1()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious is there's any advantage in returning a reference pointer...

@@ -31,7 +31,7 @@ namespace atlas
static_assert(sizeof(RV) >= sizeof(SIZE));

using Op =
typename std::conditional<std::is_same_v<RV, RV64>,
typename std::conditional<std::is_same<RV, RV64>::value,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the change?

Copy link
Contributor

@lzhu-mips lzhu-mips Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think value is more compliant with the rest of the code with type. Could use is_same_v as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. I suggest fixing the other code. ;)

const uint64_t rs2_val = inst->getRs2()->dmiRead<uint64_t>();
const uint64_t rs3_val = inst->getRs3()->dmiRead<uint64_t>();
const uint64_t product = f64_mul(float64_t{rs1_val}, float64_t{rs2_val}).v;
inst->getRd()->write(f64_add(float64_t{product ^ 1UL << 63}, float64_t{rs3_val}).v);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest () around the binary operations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious... softfloat doesn't have an madd operations? The way this is implemented might lose some precision.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no it doesn't provide madd. I think there is no surprise it's going to lose precison anyway when the product is big enough.

const uint64_t rs2_val = inst->getRs2()->dmiRead<uint64_t>();
const uint64_t rs3_val = inst->getRs3()->dmiRead<uint64_t>();
const uint64_t product = f64_mul(float64_t{rs1_val}, float64_t{rs2_val}).v;
inst->getRd()->write(f64_sub(float64_t{product ^ 1UL << 63}, float64_t{rs3_val}).v);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest () around the binary operations.

const T imm = inst->hasImmediate() ? inst->getSignExtendedImmediate<T, IMM_SIZE>() : 0;
const T vaddr = rs1_val + imm;
state->getTranslationState()->makeTranslationRequest(vaddr, sizeof(T));
return nullptr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this function a simple placeholder? If it always returns nullptr, then why return anything?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kathlenemagnus might have better answer for this. But the work done here is makeTranslationRequest, then at somewhere later getTranslationResult would return the translated PA.

Comment on lines 37 to 38
using S = uint32_t;
using D = uint64_t;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes me nervous to see in a header file and in the global atlas namespace. Are these types just for convenience?

Copy link
Contributor

@lzhu-mips lzhu-mips Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's for clarity. S = single precision. D = double precision. so when using the template, it won't be confused with RV64 vs RV32, which are again, uint32_t and uint64_t.
theoretically, every extension could have its own namespace.

Comment on lines 43 to 44
static_assert(std::is_same<RV, RV64>::value || std::is_same<RV, RV32>::value);
static_assert(std::is_same<SIZE, S>::value || std::is_same<SIZE, D>::value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::is_same_v

using D = uint64_t;

template <typename RV, typename SIZE>
ActionGroup* float_ls_handler(atlas::AtlasState* state, bool load)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the parameter load be a template parameter?

const AtlasInstPtr & inst = state->getCurrentInst();
const RV paddr = state->getTranslationState()->getTranslationResult().getPaddr();

if (load)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If load is a template parameters, this can be if constexpr

///////////////////////////////////////////////////////////////////////
const AtlasInstPtr & inst = state->getCurrentInst();
const uint64_t rs1_val = inst->getRs1()->dmiRead<uint64_t>();
inst->getRd()->write(rs1_val & 0x0000FFFF);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we define this mask in AtlasTypes.hpp? I'd prefer to avoid using any hard-coded values.

// END OF SPIKE CODE
///////////////////////////////////////////////////////////////////////
const AtlasInstPtr & inst = state->getCurrentInst();
const uint32_t rs1_val = inst->getRs1()->dmiRead<uint64_t>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use the register macros defined here: https://github.com/sparcians/atlas/blob/main/arch/register_macros.hpp

@colby-nyce how do you recommend we use the register read and write macros in the instruction handler? Currently they take a string (the register name), but we don't have a method in AtlasInst to get the operand names for integer and floating point registers. We could add a method to AtlasInst to get the register number. Something like getRs1Number.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, I have only used / felt the macros to be useful when writing to CSRs so we can deal with the bitmasks automatically. But I don't see the point in using the macros for rs1/rs2/rd. What would the call site look like and how is it better than what we are using today with getRs1/dmiRead directly?

If you want to use the macros, I would probably want to add new macros like READ_RS1_VAL, READ_RD_VAL, WRITE_RD_VAL, etc.

typedef READ_RS1_VAL state->getCurrentInst()->getRs1()->dmiRead<uint64_t>()
...

But that isn't giving any real added value like with CSRs and bitmasks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we needed the macros to control treating x0 as read-only. Is that true? Or is that handled in the Sparta register class?

If we only want to use the macros for the CSRs, then we should remove the integer and floating point macros.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants