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

Support rv64 #78

Merged
merged 23 commits into from
Jul 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
41bf15e
Elongate registers and CSRs to 64 bits
TheThirdOne Jun 10, 2020
cd86550
Convert most instructions to rv64 compatable versions.
TheThirdOne Jun 13, 2020
c57464d
Add all new instructions for rv64m - new shifts as stubs
TheThirdOne Jun 13, 2020
c8a9f42
Add ArithmeticW to regularize the rv64 variants
TheThirdOne Jun 13, 2020
11b976f
Update load and store instuctions for rv64
TheThirdOne Jun 13, 2020
0ee10ac
Add a setting for rv64 mode.
TheThirdOne Jun 16, 2020
0ad1414
Update all instructions to use the new rv64 only system
TheThirdOne Jun 16, 2020
a41cc5e
Add SXXIWs
TheThirdOne Jun 16, 2020
e6d5232
Split SXXIs into 32 and 64 bit versions
TheThirdOne Jun 16, 2020
d76774d
Widen GUI register panel when 64 bit mode is active
TheThirdOne Jun 17, 2020
1cc4d0d
Instructions now switch between 32 and 64 bit semantics
TheThirdOne Jun 18, 2020
aa20f6c
Add a tokentype for 6 bit integers
TheThirdOne Jun 18, 2020
d5b240c
Allow 64 bit numbers for li and .dword
TheThirdOne Jun 18, 2020
504eac9
Fix bug that made tons of 32 bit tests break
TheThirdOne Jun 18, 2020
d050877
Fix bugs revealed by testing
TheThirdOne Jun 20, 2020
4af5de1
Add rv64F and rv64d instructions
TheThirdOne Jun 21, 2020
21f3a45
Remove erroneous import
TheThirdOne Jun 21, 2020
af804a5
Fix .dword replicating the low bits instead of sign-extending
TheThirdOne Jun 23, 2020
b34eaf9
Add tests from riscv-tests/rv64ui
TheThirdOne Jun 26, 2020
ee095d5
Fix mulhu for rv64, jalr from binary and jalr when both registers are…
TheThirdOne Jul 2, 2020
21bf74e
Add rv64 cli option
TheThirdOne Jul 8, 2020
ca1fb58
Update descriptions on 64 bit instructions
TheThirdOne Jul 10, 2020
2faba4c
Add separate 64 bit instruction table to documentation
TheThirdOne Jul 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -121,7 +121,6 @@ tail label ;auipc x6,PCH1 ;jalr x0, x6, PCL1;#TAIL call: tail call (call

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