Skip to content

Commit

Permalink
[AsmParser] Adds ISA parser
Browse files Browse the repository at this point in the history
  • Loading branch information
joaobispo committed May 2, 2024
1 parent 45e0aeb commit 64896fe
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 33 deletions.
13 changes: 11 additions & 2 deletions AsmParser/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ dependencies {
testImplementation "junit:junit:4.11"

implementation ':SpecsUtils'
implementation ':jOptions'

implementation ':jOptions'

implementation group: 'com.google.code.gson', name: 'gson', version: '2.4'
}

java {
Expand All @@ -35,11 +36,19 @@ sourceSets {
java {
srcDir 'src'
}

resources {
srcDir 'test'
}
}

test {
java {
srcDir 'test'
}

resources {
srcDir 'test'
}
}
}
98 changes: 98 additions & 0 deletions AsmParser/src/pt/up/fe/specs/asmparser/Isa32bitParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package pt.up.fe.specs.asmparser;

import com.google.gson.Gson;
import pt.up.fe.specs.asmparser.ast.FieldNode;
import pt.up.fe.specs.asmparser.ast.RuleNode;
import pt.up.fe.specs.asmparser.parser32bit.Asm32bitParser;
import pt.up.fe.specs.util.SpecsIo;

import java.util.*;

public class Isa32bitParser {

public static void main(String[] args) {
var isaParser = newInstance(SpecsIo.getResource(() -> "pt/up/fe/specs/binarytranslation/asm/parsing/asm_test.json"));

//"0110_xx_registerd(5)_1000_opcode(1)_0_imm(15)"
// 31, 1, 10925
var decoded = isaParser.parse(Long.parseLong("01100011111100010010101010101101", 2));
System.out.println(Arrays.toString(decoded));
}


private final List<Asm32bitParser> parsers;

private Isa32bitParser(List<Asm32bitParser> parsers) {
this.parsers = parsers;
}


public static Isa32bitParser newInstance(String jsonContents) {
var isa = new Gson().fromJson(jsonContents, Map.class);

//var fields = new LinkedHashSet<>((List<String>) isa.get("fields"));

// Maps a field to an index
var fieldsMap = new HashMap<String, Integer>();

// Index 0 is id of format
var fieldId = 1;
for (var field : (List<String>) isa.get("fields")) {
fieldsMap.put(field, fieldId);
fieldId++;
}

System.out.println("FIELDS MAP: " + fieldsMap);

int id = 0;
var parsers = new ArrayList<Asm32bitParser>();
for (var format : (List<String>) isa.get("formats")) {

// Parse format
var rule = new InstructionFormatParser().parse(format);

// Verify rule
verify(rule, format, fieldsMap.keySet());

// Create parser
var parser = Asm32bitParser.build(id, rule, fieldsMap);
parsers.add(parser);
id++;
}


return new Isa32bitParser(parsers);
}

private static void verify(RuleNode rule, String format, Set<String> fields) {
// Go to all fields, check they are declared
var invalidField = rule.getDescendants(FieldNode.class).stream()
.filter(node -> !fields.contains(node.getField()))
.findFirst()
.orElse(null);


if (invalidField != null) {
throw new RuntimeException("Found undeclared field '" + invalidField.getField() + "' in format rule '" + format + "'");
}

}

public int[] parse(long instruction) {
// Iterate over all parsers, looking for one that accepts the instruction
for (var parser : parsers) {
var decoded = parser.parse(instruction);

// Could not decode, skip
if (decoded == null) {
continue;
}

// Decoded, return
return decoded;
}

throw new RuntimeException("Could not decode instruction 0x" + Long.toString(instruction, 16));
}

}
3 changes: 3 additions & 0 deletions AsmParser/src/pt/up/fe/specs/asmparser/ast/FieldNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@ public FieldNode(DataStore data, Collection<? extends InstructionFormatNode> chi
super(data, children);
}

public String getField() {
return get(FIELD);
}
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,68 @@
/**
* Copyright 2024 SPeCS.
*
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
*
* <p>
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. under the License.
*/

package pt.up.fe.specs.asmparser.parser32bit;

import java.util.List;

import pt.up.fe.specs.asmparser.ast.ConstantNode;
import pt.up.fe.specs.asmparser.ast.FieldNode;
import pt.up.fe.specs.asmparser.ast.IgnoreNode;
import pt.up.fe.specs.asmparser.ast.InstructionFormatNode;
import pt.up.fe.specs.asmparser.ast.RuleNode;
import pt.up.fe.specs.asmparser.ast.*;
import pt.up.fe.specs.asmparser.parser32bit.rules.Asm32bitConstantRule;
import pt.up.fe.specs.asmparser.parser32bit.rules.Asm32bitFieldRule;
import pt.up.fe.specs.asmparser.parser32bit.rules.Asm32bitIgnoreRule;
import pt.up.fe.specs.asmparser.parser32bit.rules.Asm32bitRule;
import pt.up.fe.specs.util.exceptions.NotImplementedException;

import java.util.List;
import java.util.Map;

public class Asm32bitParser {

private final int id;
private final List<Asm32bitRule> rules;
private final Map<String, Integer> fieldsMap;

private final int numFields;
private final int[] fieldIndexes;

private Asm32bitParser(int id, List<Asm32bitRule> rules) {
private Asm32bitParser(int id, List<Asm32bitRule> rules, Map<String, Integer> fieldsMap) {
this.id = id;
this.rules = rules;
this.numFields = (int) rules.stream()
.filter(rule -> rule.hasValue())
.count();
this.fieldsMap = fieldsMap;
this.fieldIndexes = buildFieldsIndexes(rules, fieldsMap);
this.numFields = fieldIndexes.length;
}

private int[] buildFieldsIndexes(List<Asm32bitRule> rules, Map<String, Integer> fieldsMap) {
var fieldRules = rules.stream()
.filter(rule -> rule instanceof Asm32bitFieldRule)
.map(Asm32bitFieldRule.class::cast)
.toList();

var numFields = fieldsMap != null ? fieldsMap.size() : fieldRules.size();

var fieldIndexes = new int[numFields];

// If no map, just fill with indexes from 1 to N
if (fieldsMap == null) {
for (int i = 0; i < numFields; i++) {
fieldIndexes[i] = i + 1;
}
} else {
// Iterate over all rules with fields, store the corresponding index
for (int i = 0; i < fieldRules.size(); i++) {
fieldIndexes[i] = fieldsMap.get(fieldRules.get(i).getField());
}
}

return fieldIndexes;
}

public int[] parse(long instruction) {
Expand All @@ -46,7 +71,8 @@ public int[] parse(long instruction) {
int[] decoded = new int[1 + numFields];
decoded[0] = id;

int fieldIndex = 1;
//int fieldIndex = 1;
int fieldIndex = 0;
int startIndex = 0;

// Iterate over all rules
Expand All @@ -59,8 +85,8 @@ public int[] parse(long instruction) {
}

// If rule extracts a value, store it
if (rule.hasValue()) {
decoded[fieldIndex] = res.value();
if (rule instanceof Asm32bitFieldRule) {
decoded[fieldIndexes[fieldIndex]] = res.value();
fieldIndex++;
}

Expand All @@ -72,6 +98,10 @@ public int[] parse(long instruction) {
}

public static Asm32bitParser build(int id, RuleNode rule) {
return build(id, rule, null);
}

public static Asm32bitParser build(int id, RuleNode rule, Map<String, Integer> fieldsMap) {
// Check if total bits is 32
var totalBits = rule.getTotalBits();
if (totalBits != 32) {
Expand All @@ -82,7 +112,7 @@ public static Asm32bitParser build(int id, RuleNode rule) {
.map(Asm32bitParser::convert)
.toList();

return new Asm32bitParser(id, rules);
return new Asm32bitParser(id, rules, fieldsMap);
}

private static Asm32bitRule convert(InstructionFormatNode node) {
Expand All @@ -94,8 +124,8 @@ private static Asm32bitRule convert(InstructionFormatNode node) {
return new Asm32bitIgnoreRule(node.getNumBits());
}

if (node instanceof FieldNode) {
return new Asm32bitFieldRule(node.getNumBits());
if (node instanceof FieldNode fieldNode) {
return new Asm32bitFieldRule(fieldNode.getField(), fieldNode.getNumBits());
}

throw new NotImplementedException(node.getClass());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/**
* Copyright 2024 SPeCS.
*
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
*
* <p>
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. under the License.
Expand All @@ -18,14 +18,20 @@

public class Asm32bitFieldRule implements Asm32bitRule {

private final String field;
private final int numBits;
private final long mask;

public Asm32bitFieldRule(int numBits) {
public Asm32bitFieldRule(String field, int numBits) {
this.field = field;
this.numBits = numBits;
this.mask = SpecsBits.mask(-1, numBits);
}

public String getField() {
return field;
}

@Override
public Asm32bitResult parse(long asm, int startIndex) {

Expand All @@ -40,9 +46,5 @@ public Asm32bitResult parse(long asm, int startIndex) {
return new Asm32bitResult(startIndex + numBits, (int) asmFiltered);
}

@Override
public boolean hasValue() {
return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public interface Asm32bitRule {

Asm32bitResult parse(long asm, int startIndex);

default boolean hasValue() {
return false;
}
// default boolean hasValue() {
// return false;
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,9 @@ public void test1() {
*/
}

@Test
public void testFromJson() {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"fields": [
"registerd",
"registera",
"opcode",
"imm"
],
"formats": [
"100101_0_opcode(1)_000_registerd(5)_11_registera(14)",
"0110_xx_registerd(5)_1000_opcode(1)_0_imm(15)"
]
}

0 comments on commit 64896fe

Please sign in to comment.