Moved calling distance to bank.

This commit is contained in:
jespergravgaard 2023-04-23 22:20:13 +02:00
parent 8b7afa4ad0
commit 606ea29132
6 changed files with 62 additions and 53 deletions

View File

@ -51,13 +51,13 @@ final public class AsmFragmentInstanceSpecBuilder {
* @param program The program
* @return the fragment instance spec factory
*/
public static AsmFragmentInstanceSpec callBanked(Procedure toProcedure, Procedure.CallingDistance callingDistance, Program program) {
public static AsmFragmentInstanceSpec callBanked(Procedure toProcedure, Bank.CallingDistance callingDistance, Program program) {
final Bank toBank = toProcedure.getBank();
AsmFragmentBindings bindings = new AsmFragmentBindings(program);
AsmFragmentSignature signature = new AsmFragmentSignature.CallBanked(
toProcedure.getCallingConvention().getShortName(),
callingDistance.toString(),
(callingDistance.equals(Procedure.CallingDistance.NEAR)?null:toBank.bankArea()));
(callingDistance.equals(Bank.CallingDistance.NEAR)?null:toBank.bankArea()));
ScopeRef codeScope = program.getScope().getRef();
bindings.bind("c1", new ConstantInteger(toBank.bankNumber()));
bindings.bind("la1", new LabelRef(toProcedure.getFullName()));

View File

@ -44,15 +44,12 @@ public class Directive {
}
/**
* Creates a new Bank which collects the necessary data to handle banking.
* For example, on the Commander X16, RAM is banked from address 0xA000 till 0xBFFF.
* Zeropage 0x00 configures this banked RAM, with a number from 0x00 till 0xff.
* So banked RAM is is a bankArea, and the bank is a configurable bank number in the bankArea.
* Bank to place code into. Used for determining call distance.
*/
static public class Bank extends Directive {
private String bankArea; // A bank area is a memory range that is banked on a target platform.
private Long bankNumber; // A bank is a number that defines a bank configuration in a bank area.
private String bankArea;
private Long bankNumber;
public Bank(String bankArea, Long bankNumber) {
super("bank" );

View File

@ -135,4 +135,39 @@ public record Bank(String bankArea, Long bankNumber) {
return "__bank(" + this.bankArea() + ", " + this.bankNumber() + ") ";
}
}
/** The bank distance between a caller and callee, which will determine the type of call needed. */
public enum CallingDistance {
/** Caller and callee are both in the same bank or in the common bank. No bank change is needed. */
NEAR,
/** Caller is in the common bank or a different banking area. A direct bank change is needed. */
CLOSE,
/** Caller and callee are different banks of the same banking area. A trampoline bank change is needed. */
FAR;
public static CallingDistance forCall(Bank from, Bank to) {
if(to.isCommon()) {
// NEAR: call to the common bank
return NEAR;
} else if(to.equals(from)) {
// NEAR: call to the same bank in the same banking area
return NEAR;
} else if(from.isCommon()) {
// CLOSE: call from common bank to any bank
return CLOSE;
} else if(!from.bankArea().equals(to.bankArea())) {
// CLOSE: from one banking area to another
return CLOSE;
} else {
// FAR: banked to different bank in same bank area
return FAR;
}
}
@Override
public String toString() {
return name().toLowerCase();
}
}
}

View File

@ -63,41 +63,6 @@ public class Procedure extends Scope {
this.bank = Objects.requireNonNull(bank);
}
/** The bank distance between a caller and callee, which will determine the type of call needed. */
public enum CallingDistance {
/** Caller and callee are both in the same bank or in the common bank. No bank change is needed. */
NEAR,
/** Caller is in the common bank or a different banking area. A direct bank change is needed. */
CLOSE,
/** Caller and callee are different banks of the same banking area. A trampoline bank change is needed. */
FAR;
public static CallingDistance forCall(Bank from, Bank to) {
if(to.isCommon()) {
// NEAR: call to the common bank
return NEAR;
} else if(to.equals(from)) {
// NEAR: call to the same bank in the same banking area
return NEAR;
} else if(from.isCommon()) {
// CLOSE: call from common bank to any bank
return CLOSE;
} else if(!from.bankArea().equals(to.bankArea())) {
// CLOSE: from one banking area to another
return CLOSE;
} else {
// FAR: banked to different bank in same bank area
return FAR;
}
}
@Override
public String toString() {
return name().toLowerCase();
}
}
/** The method for passing parameters and return value to the procedure. */
public enum CallingConvention {
/** Parameters and return value handled through PHI-transitions. */
@ -355,11 +320,23 @@ public class Procedure extends Scope {
if(o == null || getClass() != o.getClass()) return false;
if(!super.equals(o)) return false;
Procedure procedure = (Procedure) o;
return variableLengthParameterList == procedure.variableLengthParameterList && declaredInline == procedure.declaredInline && declaredIntrinsic == procedure.declaredIntrinsic && isConstructor == procedure.isConstructor && Objects.equals(procedureType, procedure.procedureType) && Objects.equals(parameterNames, procedure.parameterNames) && Objects.equals(interruptType, procedure.interruptType) && Objects.equals(comments, procedure.comments) && Objects.equals(reservedZps, procedure.reservedZps) && Objects.equals(segmentCode, procedure.segmentCode) && Objects.equals(constructorRefs, procedure.constructorRefs) && Objects.equals(definitionSource, procedure.definitionSource) && Objects.equals(bank, procedure.bank) && callingConvention == procedure.callingConvention;
return variableLengthParameterList == procedure.variableLengthParameterList &&
declaredInline == procedure.declaredInline &&
declaredIntrinsic == procedure.declaredIntrinsic &&
isConstructor == procedure.isConstructor &&
Objects.equals(procedureType, procedure.procedureType) &&
Objects.equals(parameterNames, procedure.parameterNames) &&
Objects.equals(interruptType, procedure.interruptType) &&
Objects.equals(comments, procedure.comments) &&
Objects.equals(reservedZps, procedure.reservedZps) &&
Objects.equals(segmentCode, procedure.segmentCode) &&
Objects.equals(constructorRefs, procedure.constructorRefs) &&
Objects.equals(bank, procedure.bank) &&
callingConvention == procedure.callingConvention;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), procedureType, parameterNames, variableLengthParameterList, declaredInline, declaredIntrinsic, interruptType, comments, reservedZps, segmentCode, constructorRefs, isConstructor, definitionSource, bank, callingConvention);
return Objects.hash(super.hashCode(), procedureType, parameterNames, variableLengthParameterList, declaredInline, declaredIntrinsic, interruptType, comments, reservedZps, segmentCode, constructorRefs, isConstructor, bank, callingConvention);
}
}

View File

@ -111,7 +111,7 @@ public class CParser {
*/
public static final String PRAGMA_BANK = "bank";
/**
* #pragma nobank Changes the current bank to the default/common bank.
* #pragma nobank Changes the current bank to the default/common/shared bank.
*/
public static final String PRAGMA_NOBANK = "nobank";

View File

@ -900,15 +900,15 @@ public class Pass4CodeGeneration {
genBlockPhiTransition(asm, block, callSuccessor, block.getScope());
}
}
final Procedure.CallingDistance callingDistance = Procedure.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
if(Procedure.CallingDistance.NEAR.equals(callingDistance)) {
final Bank.CallingDistance callingDistance = Bank.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
if(Bank.CallingDistance.NEAR.equals(callingDistance)) {
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
} else {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked(toProcedure, callingDistance, program), program);
}
} else if (Procedure.CallingConvention.STACK_CALL.equals(toProcedure.getCallingConvention())) {
final Procedure.CallingDistance callingDistance = Procedure.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
if(Procedure.CallingDistance.NEAR.equals(callingDistance)) {
final Bank.CallingDistance callingDistance = Bank.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
if(Bank.CallingDistance.NEAR.equals(callingDistance)) {
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
} else {
throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));
@ -921,11 +921,11 @@ public class Pass4CodeGeneration {
ProgramScope scope = getScope();
Procedure toProcedure = scope.getProcedure(procedureRef);
Procedure fromProcedure = block.getProcedure(this.program);
final Procedure.CallingDistance callingDistance = Procedure.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
if(Procedure.CallingDistance.NEAR.equals(callingDistance)) {
final Bank.CallingDistance callingDistance = Bank.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
if(Bank.CallingDistance.NEAR.equals(callingDistance)) {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program);
} else {
throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));
throw new CompileError("Call procedure not supported in banked mode " + toProcedure.toString(program));
}
RValue procedureRVal = call.getProcedureRVal();
if (!(procedureRVal instanceof ProcedureRef)) {