Skip to content

Commit

Permalink
Merge pull request #78 from TheThirdOne/rv64
Browse files Browse the repository at this point in the history
Support rv64
  • Loading branch information
TheThirdOne authored Jul 15, 2020
2 parents b3afbbe + 2faba4c commit a8b60f4
Show file tree
Hide file tree
Showing 154 changed files with 15,411 additions and 158 deletions.
19 changes: 19 additions & 0 deletions src/PseudoOps-64.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Templates that override 32 bit templates in the case that the 32 bit version doesn't work
# This needs to be here because it should have priority over the other li's
li t1,-100 ;addi RG1, x0, VL2 ;#Load Immediate : Set t1 to 12-bit immediate (sign-extended)
# This needs to be here because addi is not correct and addiw does not work in rv32
li t1,10000000 ;lui RG1, VH2 ;addiw RG1, RG1, VL2 ;#Load Immediate : Set t1 to 32-bit immediate (sign-extended)
# Please don't try to use LIX1 templates, they are pretty brittle and very specific to li
# This is a pretty complex template, but it is actually simpler than what gcc uses. gcc seems to actually optimize it per immediate.
li t1,1000000000000000 ;lui RG1, LIA2 ;addiw RG1, RG1, LIB2 ;slli RG1, RG1, 11 ;addi RG1, RG1, LIC2 ;slli RG1, RG1, 11 ;addi RG1, RG1, LID2 ;slli RG1, RG1, 10 ;addi RG1, RG1, LIE2 ;#Load Immediate : Set t1 to 64-bit immediate

fcvt.s.lu f1, t1 ; fcvt.s.lu RG1, RG2, dyn ;#Convert float from unsigned 64 bit integer: Assigns the value of t1 to f1
fcvt.s.l f1, t1 ; fcvt.s.l RG1, RG2, dyn ;#Convert float from signed 64 bit integer: Assigns the value of t1 to f1
fcvt.l.s t1, f1 ; fcvt.l.s RG1, RG2, dyn ;#Convert signed 64 bit integer from float: Assigns the value of f1 (rounded) to t1
fcvt.lu.s t1, f1 ; fcvt.lu.s RG1, RG2, dyn ;#Convert unsigned 64 bit integer from float: Assigns the value of f1 (rounded) to t1


fcvt.d.lu f1, t1 ; fcvt.d.lu RG1, RG2, dyn ;#Convert double from unsigned 64 bit integer: Assigns the value of t1 to f1
fcvt.d.l f1, t1 ; fcvt.d.l RG1, RG2, dyn ;#Convert double from signed 64 bit integer: Assigns the value of t1 to f1
fcvt.l.d t1, f1 ; fcvt.l.d RG1, RG2, dyn ;#Convert signed 64 bit integer from double: Assigns the value of f1 (rounded) to t1
fcvt.lu.d t1, f1 ; fcvt.lu.d RG1, RG2, dyn ;#Convert unsigned 64 bit integer from double: Assigns the value of f1 (rounded) to t1
1 change: 0 additions & 1 deletion src/PseudoOps.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ tail label ;auipc x6,PCH1 ;jalr x0, x6, PCL1;#TAIL call: tail call (cal

li t1,-100 ;addi RG1, x0, VL2 ;#Load Immediate : Set t1 to 12-bit immediate (sign-extended)
li t1,10000000 ;lui RG1, VH2 ;addi RG1, RG1, VL2 ;#Load Immediate : Set t1 to 32-bit immediate

la t1,label ;auipc RG1, PCH2 ; addi RG1, RG1, PCL2;#Load Address : Set t1 to label's address

lw t1,(t2) ;lw RG1,0(RG3) ;#Load Word : Set t1 to contents of effective memory word address
Expand Down
2 changes: 1 addition & 1 deletion src/jsoftfloat
4 changes: 2 additions & 2 deletions src/rars/Globals.java
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,10 @@ public static Settings getSettings() {
public static void initialize(boolean gui) {
if (!initialized) {
memory = Memory.getInstance(); //clients can use Memory.getInstance instead of Globals.memory
instructionSet = new InstructionSet();
instructionSet.populate();
symbolTable = new SymbolTable("global");
settings = new Settings(gui);
instructionSet = new InstructionSet();
instructionSet.populate();
initialized = true;
debug = false;
memory.clear(); // will establish memory configuration from setting
Expand Down
11 changes: 11 additions & 0 deletions src/rars/Launch.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package rars;

import rars.api.Program;
import rars.riscv.InstructionSet;
import rars.riscv.dump.DumpFormat;
import rars.riscv.dump.DumpFormatLoader;
import rars.riscv.hardware.*;
Expand Down Expand Up @@ -109,6 +110,7 @@ public class Launch {

private Options options;
private boolean simulate;
private boolean rv64;
private int displayFormat;
private boolean verbose; // display register name or address along with contents
private boolean assembleProject; // assemble only the given file or all files in its directory
Expand Down Expand Up @@ -374,6 +376,10 @@ private boolean parseCommandArgs(String[] args) {
options.selfModifyingCode = true;
continue;
}
if (args[i].toLowerCase().equals("rv64")) {
rv64 = true;
continue;
}
if (args[i].toLowerCase().equals("ic")) { // added 19-Jul-2012 DPS
countInstructions = true;
continue;
Expand Down Expand Up @@ -435,6 +441,10 @@ private Program runCommand() {
return null;
}

Globals.getSettings().setBooleanSettingNonPersistent(Settings.Bool.RV64_ENABLED,rv64);
InstructionSet.rv64 = rv64;
Globals.instructionSet.populate();

File mainFile = new File(filenameList.get(0)).getAbsoluteFile();// First file is "main" file
ArrayList<String> filesToAssemble;
if (assembleProject) {
Expand Down Expand Up @@ -718,6 +728,7 @@ private void displayHelp() {
out.println(" se<n> -- terminate RARS with integer exit code <n> if a simulation (run) error occurs.");
out.println(" sm -- start execution at statement with global label main, if defined");
out.println(" smc -- Self Modifying Code - Program can write and branch to either text or data segment");
out.println(" rv64 -- Enables 64 bit assembly and executables (Not fully compatible with rv32)");
out.println(" <n> -- where <n> is an integer maximum count of steps to simulate.");
out.println(" If 0, negative or not specified, there is no maximum.");
out.println(" x<reg> -- where <reg> is number or name (e.g. 5, t3, f10) of register whose ");
Expand Down
2 changes: 1 addition & 1 deletion src/rars/ProgramStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ public void buildBasicStatementFromBasicInstruction(ErrorList errors) {
basicStatementList.addValue(address);
}
this.operands[this.numOperands++] = address;
} else if (tokenType == TokenTypes.INTEGER_5 || tokenType == TokenTypes.INTEGER_12 ||
} else if (tokenType == TokenTypes.INTEGER_5 || tokenType == TokenTypes.INTEGER_6 || tokenType == TokenTypes.INTEGER_12 ||
tokenType == TokenTypes.INTEGER_20 || tokenType == TokenTypes.INTEGER_32) {

int tempNumeric = Binary.stringToInt(tokenValue);
Expand Down
6 changes: 5 additions & 1 deletion src/rars/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,11 @@ public enum Bool {
* Flag to determine whether a program can write binary code to the text or data segment and
* execute that code.
*/
SELF_MODIFYING_CODE_ENABLED("SelfModifyingCode", false);
SELF_MODIFYING_CODE_ENABLED("SelfModifyingCode", false),
/**
* Flag to determine whether a program uses rv64i instead of rv32i
*/
RV64_ENABLED("rv64Enabled", false);;

// TODO: add option for turning off user trap handling and interrupts
private String name;
Expand Down
27 changes: 24 additions & 3 deletions src/rars/assembler/Assembler.java
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@ private void executeDirective(TokenList tokens) {
}
} else if (direct == Directives.WORD || direct == Directives.HALF
|| direct == Directives.BYTE || direct == Directives.FLOAT
|| direct == Directives.DOUBLE) {
|| direct == Directives.DOUBLE || direct == Directives.DWORD ) {
this.dataDirective = direct;
if (passesDataSegmentCheck(token) && tokens.size() > 1) { // DPS
// 11/20/06, added text segment prohibition
Expand Down Expand Up @@ -804,7 +804,7 @@ private void transferGlobals() {
private void executeDirectiveContinuation(TokenList tokens) {
Directives direct = this.dataDirective;
if (direct == Directives.WORD || direct == Directives.HALF || direct == Directives.BYTE
|| direct == Directives.FLOAT || direct == Directives.DOUBLE) {
|| direct == Directives.FLOAT || direct == Directives.DOUBLE || direct == Directives.DWORD ) {
if (tokens.size() > 0) {
storeNumeric(tokens, direct, errors);
}
Expand Down Expand Up @@ -921,7 +921,28 @@ private void storeNumeric(TokenList tokens, Directives directive, ErrorList erro
private void storeInteger(Token token, Directives directive, ErrorList errors) {
int lengthInBytes = DataTypes.getLengthInBytes(directive);
if (TokenTypes.isIntegerTokenType(token.getType())) {
int value = Binary.stringToInt(token.getValue());
int value;
long longvalue;
if (TokenTypes.INTEGER_64 == token.getType()) {
longvalue = Binary.stringToLong(token.getValue());
value = (int)longvalue;
if (directive != Directives.DWORD){
errors.add(new ErrorMessage(ErrorMessage.WARNING, token.getSourceProgram(), token.getSourceLine(),
token.getStartPos(), "value " + Binary.longToHexString(longvalue)
+ " is out-of-range and truncated to " + Binary.intToHexString(value)));
}
}else{
value = Binary.stringToInt(token.getValue());
longvalue = value;
}

if (directive == Directives.DWORD){
writeToDataSegment((int)longvalue, 4, token, errors);
writeToDataSegment((int)(longvalue>>32), 4, token, errors);
return;
}


int fullvalue = value;
// DPS 4-Jan-2013. Overriding 6-Jan-2005 KENV changes.
// If value is out of range for the directive, will simply truncate
Expand Down
2 changes: 2 additions & 0 deletions src/rars/assembler/DataTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ public static int getLengthInBytes(Directives direct) {
return FLOAT_SIZE;
else if (direct == Directives.DOUBLE)
return DOUBLE_SIZE;
else if (direct == Directives.DWORD)
return 2*WORD_SIZE;
else if (direct == Directives.WORD)
return WORD_SIZE;
else if (direct == Directives.HALF)
Expand Down
4 changes: 3 additions & 1 deletion src/rars/assembler/Directives.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public final class Directives {
public static final Directives DATA = new Directives(".data", "Subsequent items stored in Data segment at next available address");
public static final Directives TEXT = new Directives(".text", "Subsequent items (instructions) stored in Text segment at next available address");
public static final Directives WORD = new Directives(".word", "Store the listed value(s) as 32 bit words on word boundary");
public static final Directives DWORD = new Directives(".dword", "Store the listed value(s) as 64 bit double-word on word boundary");
public static final Directives ASCII = new Directives(".ascii", "Store the string in the Data segment but do not add null terminator");
public static final Directives ASCIZ = new Directives(".asciz", "Store the string in the Data segment and add null terminator");
public static final Directives STRING = new Directives(".string", "Alias for .asciz");
Expand Down Expand Up @@ -162,7 +163,8 @@ public static ArrayList<Directives> getDirectiveList() {
* @return true if given directive is WORD, HALF, or BYTE, false otherwise
**/
public static boolean isIntegerDirective(Directives direct) {
return direct == Directives.WORD || direct == Directives.HALF || direct == Directives.BYTE;
return direct == Directives.DWORD || direct == Directives.WORD || direct == Directives.HALF || direct == Directives.BYTE;

}


Expand Down
14 changes: 11 additions & 3 deletions src/rars/assembler/OperandFormat.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,19 +128,27 @@ private static boolean operandTypeCheck(TokenList cand, Instruction spec, ErrorL
continue;
// TODO: this shouldn't really accept INTEGER_20, only unsigned 12 is ok
if(specType == TokenTypes.CSR_NAME &&
(candType==TokenTypes.INTEGER_5 || candType == TokenTypes.INTEGER_12
(candType==TokenTypes.INTEGER_5 || candType==TokenTypes.INTEGER_6 || candType == TokenTypes.INTEGER_12
|| candType ==TokenTypes.INTEGER_20 || candType == TokenTypes.CSR_NAME))
continue;
if ((specType == TokenTypes.INTEGER_12 && candType == TokenTypes.INTEGER_5) ||
if ((specType == TokenTypes.INTEGER_6 && candType == TokenTypes.INTEGER_5) ||
(specType == TokenTypes.INTEGER_12 && candType == TokenTypes.INTEGER_5) ||
(specType == TokenTypes.INTEGER_20 && candType == TokenTypes.INTEGER_5) ||
(specType == TokenTypes.INTEGER_12 && candType == TokenTypes.INTEGER_6) ||
(specType == TokenTypes.INTEGER_20 && candType == TokenTypes.INTEGER_6) ||
(specType == TokenTypes.INTEGER_20 && candType == TokenTypes.INTEGER_12) ||
(specType == TokenTypes.INTEGER_32 && candType == TokenTypes.INTEGER_5) ||
(specType == TokenTypes.INTEGER_32 && candType == TokenTypes.INTEGER_6) ||
(specType == TokenTypes.INTEGER_32 && candType == TokenTypes.INTEGER_12) ||
(specType == TokenTypes.INTEGER_32 && candType == TokenTypes.INTEGER_20))
continue;
if ((specType == TokenTypes.INTEGER_5 && candType == TokenTypes.INTEGER_12) ||
if ((specType == TokenTypes.INTEGER_5 && candType == TokenTypes.INTEGER_6) ||
(specType == TokenTypes.INTEGER_5 && candType == TokenTypes.INTEGER_12) ||
(specType == TokenTypes.INTEGER_5 && candType == TokenTypes.INTEGER_20) ||
(specType == TokenTypes.INTEGER_5 && candType == TokenTypes.INTEGER_32) ||
(specType == TokenTypes.INTEGER_6 && candType == TokenTypes.INTEGER_12) ||
(specType == TokenTypes.INTEGER_6 && candType == TokenTypes.INTEGER_20) ||
(specType == TokenTypes.INTEGER_6 && candType == TokenTypes.INTEGER_32) ||
(specType == TokenTypes.INTEGER_12 && candType == TokenTypes.INTEGER_20) ||
(specType == TokenTypes.INTEGER_12 && candType == TokenTypes.INTEGER_32) ||
(specType == TokenTypes.INTEGER_20 && candType == TokenTypes.INTEGER_32)) {
Expand Down
18 changes: 15 additions & 3 deletions src/rars/assembler/TokenTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public enum TokenTypes {
// TODO: merge REGISTER_NUMBER and REGISTER_NAME
REGISTER_NAME, REGISTER_NUMBER, FP_REGISTER_NAME, CSR_NAME, ROUNDING_MODE,
IDENTIFIER, LEFT_PAREN, RIGHT_PAREN,
INTEGER_5, INTEGER_12, INTEGER_20, INTEGER_32, REAL_NUMBER,
INTEGER_5, INTEGER_6, INTEGER_12, INTEGER_20, INTEGER_32, INTEGER_64, REAL_NUMBER,
QUOTED_STRING,
PLUS, MINUS, COLON,
ERROR, MACRO_PARAMETER,
Expand Down Expand Up @@ -144,6 +144,7 @@ public static TokenTypes matchTokenType(String value) {
// Classify based on # bits needed to represent in binary
// This is needed because most immediate operands limited to 16 bits
// others limited to 5 bits unsigned (shift amounts) others 32 bits.

try {

int i = Binary.stringToInt(value); // KENV 1/6/05
Expand All @@ -154,6 +155,9 @@ public static TokenTypes matchTokenType(String value) {
if (i >= 0 && i <= 31) {
return TokenTypes.INTEGER_5;
}
if (i >= 0 && i <= 64) {
return TokenTypes.INTEGER_6;
}
if (i >= DataTypes.MIN_IMMEDIATE_VALUE && i <= DataTypes.MAX_IMMEDIATE_VALUE) {
return TokenTypes.INTEGER_12;
}
Expand All @@ -165,6 +169,13 @@ public static TokenTypes matchTokenType(String value) {
// NO ACTION -- exception suppressed
}

try {
Binary.stringToLong(value);
return TokenTypes.INTEGER_64;
} catch (NumberFormatException e) {
// NO ACTION -- exception suppressed
}

// See if it is a real (fixed or floating point) number. Note that parseDouble()
// accepts integer values but if it were an integer literal we wouldn't get this far.
if (value.equals("Inf") || value.equals("NaN")) return TokenTypes.REAL_NUMBER;
Expand All @@ -178,6 +189,7 @@ public static TokenTypes matchTokenType(String value) {
}



// See if it is a directive
if (value.charAt(0) == '.' && Directives.matchDirective(value) != null) {
return TokenTypes.DIRECTIVE;
Expand Down Expand Up @@ -209,8 +221,8 @@ public static TokenTypes matchTokenType(String value) {
* @return true if type is an integer type, false otherwise.
**/
public static boolean isIntegerTokenType(TokenTypes type) {
return type == TokenTypes.INTEGER_5 || type == TokenTypes.INTEGER_12 ||
type == TokenTypes.INTEGER_20 || type == TokenTypes.INTEGER_32;
return type == TokenTypes.INTEGER_5 || type == TokenTypes.INTEGER_6 || type == TokenTypes.INTEGER_12 ||
type == TokenTypes.INTEGER_20 || type == TokenTypes.INTEGER_32 || type == TokenTypes.INTEGER_64;
}


Expand Down
38 changes: 38 additions & 0 deletions src/rars/extras/Documentation.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package rars.extras;

import rars.Globals;
import rars.Settings;
import rars.assembler.Directives;
import rars.riscv.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;

/**
* Small class for automatically generating documentation.
Expand All @@ -23,6 +25,8 @@ public static void main(String[] args){
System.out.println(createSyscallMarkdown());
System.out.println(createInstructionMarkdown(BasicInstruction.class));
System.out.println(createInstructionMarkdown(ExtendedInstruction.class));
System.out.println(createInstructionMarkdown64Only(BasicInstruction.class));
System.out.println(createInstructionMarkdown64Only(ExtendedInstruction.class));
}

public static String createDirectiveMarkdown(){
Expand Down Expand Up @@ -61,8 +65,13 @@ public static String createSyscallMarkdown(){
}

public static String createInstructionMarkdown(Class<? extends Instruction> instructionClass){
Globals.getSettings().setBooleanSettingNonPersistent(Settings.Bool.RV64_ENABLED,false);
InstructionSet.rv64 = false;
Globals.instructionSet.populate();

ArrayList<Instruction> instructionList = Globals.instructionSet.getInstructionList();
instructionList.sort(Comparator.comparing(Instruction::getExampleFormat));

StringBuilder output = new StringBuilder("| Example Usage | Description |\n|---------------|-------------|");
for (Instruction instr : instructionList) {
if (instructionClass.isInstance(instr)) {
Expand All @@ -75,4 +84,33 @@ public static String createInstructionMarkdown(Class<? extends Instruction> inst
}
return output.toString();
}
public static String createInstructionMarkdown64Only(Class<? extends Instruction> instructionClass){

Globals.getSettings().setBooleanSettingNonPersistent(Settings.Bool.RV64_ENABLED,false);
InstructionSet.rv64 = false;
Globals.instructionSet.populate();

HashSet<String> set = new HashSet<>();
for (Instruction i : Globals.instructionSet.getInstructionList()){
set.add(i.getExampleFormat());
}

Globals.getSettings().setBooleanSettingNonPersistent(Settings.Bool.RV64_ENABLED,true);
InstructionSet.rv64 = true;
Globals.instructionSet.populate();

ArrayList<Instruction> instructionList64 = Globals.instructionSet.getInstructionList();
instructionList64.sort(Comparator.comparing(Instruction::getExampleFormat));
StringBuilder output = new StringBuilder("| Example Usage | Description |\n|---------------|-------------|");
for (Instruction instr : instructionList64) {
if (instructionClass.isInstance(instr) && !set.contains(instr.getExampleFormat())) {
output.append("\n|");
output.append(instr.getExampleFormat());
output.append('|');
output.append(instr.getDescription());
output.append('|');
}
}
return output.toString();
}
}
Loading

0 comments on commit a8b60f4

Please sign in to comment.