Split up atomic operations more, inlining them in translator.
This commit is contained in:
@@ -329,11 +329,13 @@ public class R5CPU implements Steppable, RealTimeCounter, InterruptController {
|
||||
}
|
||||
|
||||
private void requestTraceTranslation(final MemoryMappedDevice device, final int instOffset, final int instEnd, final int toPC, final int inst) {
|
||||
// if (tracesRequested.add(pc)) {
|
||||
// translatorDataExchange.translatorRequests.add(new TranslatorJob(this, pc, device, instOffset, instEnd, toPC, inst));
|
||||
//
|
||||
// translators.submit(this::runTranslator);
|
||||
// }
|
||||
/*
|
||||
if (tracesRequested.add(pc)) {
|
||||
translatorDataExchange.translatorRequests.add(new TranslatorJob(this, pc, device, instOffset, instEnd, toPC, inst));
|
||||
|
||||
translators.submit(this::runTranslator);
|
||||
}
|
||||
/*/
|
||||
|
||||
if (!tracesRequested.contains(pc)) {
|
||||
final int hotTraceIndex = (pc >> 1) & (HOT_TRACE_COUNT - 1);
|
||||
@@ -350,6 +352,7 @@ public class R5CPU implements Steppable, RealTimeCounter, InterruptController {
|
||||
translators.submit(this::runTranslator);
|
||||
}
|
||||
}
|
||||
//*/
|
||||
}
|
||||
|
||||
private void invokeTrace(final Trace trace) throws R5Exception, MemoryAccessException {
|
||||
@@ -1541,8 +1544,6 @@ public class R5CPU implements Steppable, RealTimeCounter, InterruptController {
|
||||
private void amo32(final int inst, final int rd, final int rs1) throws R5Exception, MemoryAccessException {
|
||||
final int rs2 = BitUtils.getField(inst, 20, 24, 0);
|
||||
final int funct5 = inst >>> 27; // inst[31:27], not sign-extended
|
||||
final int address = x[rs1];
|
||||
final int result;
|
||||
switch (funct5) {
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// 8.2 Load-Reserved/Store-Conditional Instructions
|
||||
@@ -1550,84 +1551,51 @@ public class R5CPU implements Steppable, RealTimeCounter, InterruptController {
|
||||
if (rs2 != 0) {
|
||||
throw new R5IllegalInstructionException(inst);
|
||||
}
|
||||
result = load32(address);
|
||||
reservation_set = address;
|
||||
|
||||
lr_w(rd, rs1);
|
||||
break;
|
||||
}
|
||||
case 0b00011: { // SC.W
|
||||
if (address == reservation_set) {
|
||||
store32(address, x[rs2]);
|
||||
result = 0;
|
||||
} else {
|
||||
result = 1;
|
||||
}
|
||||
reservation_set = -1; // Always invalidate as per spec.
|
||||
sc_w(rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// 8.4 Atomic Memory Operations
|
||||
case 0b00001: // AMOSWAP.W
|
||||
case 0b00000: // AMOADD.W
|
||||
case 0b00100: // AMOXOR.W
|
||||
case 0b01100: // AMOAND.W
|
||||
case 0b01000: // AMOOR.W
|
||||
case 0b10000: // AMOMIN.W
|
||||
case 0b10100: // AMOMAX.W
|
||||
case 0b11000: // AMOMINU.W
|
||||
case 0b00001: { // AMOSWAP.W
|
||||
amoswap_w(rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b00000: { // AMOADD.W
|
||||
amoadd_w(rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b00100: { // AMOXOR.W
|
||||
amoxor_w(rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b01100: { // AMOAND.W
|
||||
amoand_w(rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b01000: { // AMOOR.W
|
||||
amoor_w(rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b10000: { // AMOMIN.W
|
||||
amomin_w(rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b10100: { // AMOMAX.W
|
||||
amomax_w(rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b11000: { // AMOMINU.W
|
||||
amominu_w(rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b11100: { // AMOMAXU.W
|
||||
// Grab operands, load left-hand from memory, right-hand from register.
|
||||
final int a = load32(address);
|
||||
final int b = x[rs2];
|
||||
|
||||
// Perform atomic operation.
|
||||
final int c;
|
||||
switch (funct5) {
|
||||
case 0b00001: { // AMOSWAP.W
|
||||
c = b;
|
||||
break;
|
||||
}
|
||||
case 0b00000: { // AMOADD.W
|
||||
c = a + b;
|
||||
break;
|
||||
}
|
||||
case 0b00100: { // AMOXOR.W
|
||||
c = a ^ b;
|
||||
break;
|
||||
}
|
||||
case 0b01100: { // AMOAND.W
|
||||
c = a & b;
|
||||
break;
|
||||
}
|
||||
case 0b01000: { // AMOOR.W
|
||||
c = a | b;
|
||||
break;
|
||||
}
|
||||
case 0b10000: { // AMOMIN.W
|
||||
c = Math.min(a, b);
|
||||
break;
|
||||
}
|
||||
case 0b10100: { // AMOMAX.W
|
||||
c = Math.max(a, b);
|
||||
break;
|
||||
}
|
||||
case 0b11000: { // AMOMINU.W
|
||||
c = (int) Math.min(Integer.toUnsignedLong(a), Integer.toUnsignedLong(b));
|
||||
break;
|
||||
}
|
||||
case 0b11100: { // AMOMAXU.W
|
||||
c = (int) Math.max(Integer.toUnsignedLong(a), Integer.toUnsignedLong(b));
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
throw new R5IllegalInstructionException(inst);
|
||||
}
|
||||
}
|
||||
|
||||
// Store value read from memory in register, write result back to memory.
|
||||
result = a;
|
||||
store32(address, c);
|
||||
amomaxu_w(rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1635,12 +1603,145 @@ public class R5CPU implements Steppable, RealTimeCounter, InterruptController {
|
||||
throw new R5IllegalInstructionException(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void lr_w(final int rd, final int rs1) throws MemoryAccessException {
|
||||
final int result;
|
||||
final int address = x[rs1];
|
||||
result = load32(address);
|
||||
reservation_set = address;
|
||||
|
||||
if (rd != 0) {
|
||||
x[rd] = result;
|
||||
}
|
||||
}
|
||||
|
||||
private void sc_w(final int rd, final int rs1, final int rs2) throws MemoryAccessException {
|
||||
final int result;
|
||||
final int address = x[rs1];
|
||||
if (address == reservation_set) {
|
||||
store32(address, x[rs2]);
|
||||
result = 0;
|
||||
} else {
|
||||
result = 1;
|
||||
}
|
||||
|
||||
reservation_set = -1; // Always invalidate as per spec.
|
||||
|
||||
if (rd != 0) {
|
||||
x[rd] = result;
|
||||
}
|
||||
}
|
||||
|
||||
private void amoswap_w(final int rd, final int rs1, final int rs2) throws MemoryAccessException {
|
||||
final int address = x[rs1];
|
||||
final int a = load32(address);
|
||||
final int b = x[rs2];
|
||||
|
||||
store32(address, b);
|
||||
|
||||
if (rd != 0) {
|
||||
x[rd] = a;
|
||||
}
|
||||
}
|
||||
|
||||
private void amoadd_w(final int rd, final int rs1, final int rs2) throws MemoryAccessException {
|
||||
final int address = x[rs1];
|
||||
final int a = load32(address);
|
||||
final int b = x[rs2];
|
||||
|
||||
store32(address, a + b);
|
||||
|
||||
if (rd != 0) {
|
||||
x[rd] = a;
|
||||
}
|
||||
}
|
||||
|
||||
private void amoxor_w(final int rd, final int rs1, final int rs2) throws MemoryAccessException {
|
||||
final int address = x[rs1];
|
||||
final int a = load32(address);
|
||||
final int b = x[rs2];
|
||||
|
||||
store32(address, a ^ b);
|
||||
|
||||
if (rd != 0) {
|
||||
x[rd] = a;
|
||||
}
|
||||
}
|
||||
|
||||
private void amoand_w(final int rd, final int rs1, final int rs2) throws MemoryAccessException {
|
||||
final int address = x[rs1];
|
||||
final int a = load32(address);
|
||||
final int b = x[rs2];
|
||||
|
||||
store32(address, a & b);
|
||||
|
||||
if (rd != 0) {
|
||||
x[rd] = a;
|
||||
}
|
||||
}
|
||||
|
||||
private void amoor_w(final int rd, final int rs1, final int rs2) throws MemoryAccessException {
|
||||
final int address = x[rs1];
|
||||
final int a = load32(address);
|
||||
final int b = x[rs2];
|
||||
|
||||
store32(address, a | b);
|
||||
|
||||
if (rd != 0) {
|
||||
x[rd] = a;
|
||||
}
|
||||
}
|
||||
|
||||
private void amomin_w(final int rd, final int rs1, final int rs2) throws MemoryAccessException {
|
||||
final int address = x[rs1];
|
||||
final int a = load32(address);
|
||||
final int b = x[rs2];
|
||||
|
||||
store32(address, Math.min(a, b));
|
||||
|
||||
if (rd != 0) {
|
||||
x[rd] = a;
|
||||
}
|
||||
}
|
||||
|
||||
private void amomax_w(final int rd, final int rs1, final int rs2) throws MemoryAccessException {
|
||||
final int address = x[rs1];
|
||||
final int a = load32(address);
|
||||
final int b = x[rs2];
|
||||
|
||||
final int c = Math.max(a, b);
|
||||
store32(address, c);
|
||||
|
||||
if (rd != 0) {
|
||||
x[rd] = a;
|
||||
}
|
||||
}
|
||||
|
||||
private void amominu_w(final int rd, final int rs1, final int rs2) throws MemoryAccessException {
|
||||
final int address = x[rs1];
|
||||
final int a = load32(address);
|
||||
final int b = x[rs2];
|
||||
|
||||
store32(address, (int) Math.min(Integer.toUnsignedLong(a), Integer.toUnsignedLong(b)));
|
||||
|
||||
if (rd != 0) {
|
||||
x[rd] = a;
|
||||
}
|
||||
}
|
||||
|
||||
private void amomaxu_w(final int rd, final int rs1, final int rs2) throws MemoryAccessException {
|
||||
final int address = x[rs1];
|
||||
final int a = load32(address);
|
||||
final int b = x[rs2];
|
||||
|
||||
store32(address, (int) Math.max(Integer.toUnsignedLong(a), Integer.toUnsignedLong(b)));
|
||||
|
||||
if (rd != 0) {
|
||||
x[rd] = a;
|
||||
}
|
||||
}
|
||||
|
||||
private void c_addi4spn(final int inst, final int rd) throws R5Exception {
|
||||
final int imm = BitUtils.getField(inst, 11, 12, 4) |
|
||||
BitUtils.getField(inst, 7, 10, 6) |
|
||||
|
||||
@@ -46,6 +46,9 @@ public final class Translator {
|
||||
// Local for holding current cycles. Saves the GETFIELD for each increment.
|
||||
private static final int MCYCLE_LOCAL_INDEX = 3; // long, length = 2
|
||||
|
||||
// We remap locals of inlined methods to start here.
|
||||
private static final int INLINED_LOCALS_START = 5;
|
||||
|
||||
// Cached opcode implementations by name for faster lookup in generation.
|
||||
private static final Map<String, OpcodeMethod> OPCODE_METHODS = new HashMap<>();
|
||||
|
||||
@@ -547,7 +550,63 @@ public final class Translator {
|
||||
case 0b0101111: { // AMO
|
||||
final int funct3 = BitUtils.getField(inst, 12, 14, 0);
|
||||
if (funct3 == 0b010) { // 32 bit
|
||||
invokeOp("amo32", inst, rd, rs1);
|
||||
final int rs2 = BitUtils.getField(inst, 20, 24, 0);
|
||||
final int funct5 = inst >>> 27;
|
||||
switch (funct5) {
|
||||
case 0b00010: { // LR.W
|
||||
if (rs2 != 0) {
|
||||
throw new R5IllegalInstructionException(inst);
|
||||
}
|
||||
|
||||
invokeOp("lr_w", rd, rs1);
|
||||
break;
|
||||
}
|
||||
case 0b00011: { // SC.W
|
||||
invokeOp("sc_w", rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0b00001: { // AMOSWAP.W
|
||||
invokeOp("amoswap_w", rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b00000: { // AMOADD.W
|
||||
invokeOp("amoadd_w", rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b00100: { // AMOXOR.W
|
||||
invokeOp("amoxor_w", rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b01100: { // AMOAND.W
|
||||
invokeOp("amoand_w", rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b01000: { // AMOOR.W
|
||||
invokeOp("amoor_w", rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b10000: { // AMOMIN.W
|
||||
invokeOp("amomin_w", rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b10100: { // AMOMAX.W
|
||||
invokeOp("amomax_w", rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b11000: { // AMOMINU.W
|
||||
invokeOp("amominu_w", rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
case 0b11100: { // AMOMAXU.W
|
||||
invokeOp("amomaxu_w", rd, rs1, rs2);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
throw new R5IllegalInstructionException(inst);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new R5IllegalInstructionException(inst);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user