Better decoding

This commit is contained in:
Charles Papon 2017-03-13 18:30:37 +01:00
parent e36c90af03
commit df99a0d963
4 changed files with 128 additions and 77 deletions

View File

@ -6,7 +6,7 @@ import spinal.lib._
import scala.collection.mutable
class Stageable[T <: Data](dataType : T) extends HardType[T](dataType) with Nameable{
class Stageable[T <: Data](val dataType : T) extends HardType[T](dataType) with Nameable{
setWeakName(this.getClass.getSimpleName.replace("$",""))
}

View File

@ -146,61 +146,103 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{
trait DecoderService{
def add(key : MaskedLiteral,values : Seq[(Stageable[_ <: Data],Any)])
def add(encoding :Seq[(MaskedLiteral,Seq[(Stageable[_ <: Data],Any)])])
def addDefault(key : Stageable[_ <: Data], value : Any)
def add(key : MaskedLiteral,values : Seq[(Stageable[_ <: BaseType],Any)])
def add(encoding :Seq[(MaskedLiteral,Seq[(Stageable[_ <: BaseType],Any)])])
def addDefault(key : Stageable[_ <: BaseType], value : Any)
}
case class Node(val value : BigInt,val careAbout : BigInt){
case class Masked(value : BigInt,care : BigInt){
}
class DecoderSimplePlugin extends Plugin[VexRiscv] with DecoderService {
override def add(encoding: Seq[(MaskedLiteral, Seq[(Stageable[_ <: Data], Any)])]): Unit = encoding.foreach(e => this.add(e._1,e._2))
override def add(key: MaskedLiteral, values: Seq[(Stageable[_ <: Data], Any)]): Unit = {
override def add(encoding: Seq[(MaskedLiteral, Seq[(Stageable[_ <: BaseType], Any)])]): Unit = encoding.foreach(e => this.add(e._1,e._2))
override def add(key: MaskedLiteral, values: Seq[(Stageable[_ <: BaseType], Any)]): Unit = {
require(!encodings.contains(key))
encodings(key) = values.map{case (a,b) => (a,b match{
case e : SpinalEnumElement[_] => e()
case e => e
case e : BaseType => e
})}
}
override def addDefault(key: Stageable[_ <: Data], value: Any): Unit = {
override def addDefault(key: Stageable[_ <: BaseType], value: Any): Unit = {
require(!defaults.contains(key))
defaults(key) = value match{
case e : SpinalEnumElement[_] => e()
case e : Data => e
case e : BaseType => e
}
}
val defaults = mutable.HashMap[Stageable[_ <: Data], Data]()
val encodings = mutable.HashMap[MaskedLiteral,Seq[(Stageable[_ <: Data], Any)]]()
val defaults = mutable.HashMap[Stageable[_ <: BaseType], BaseType]()
val encodings = mutable.HashMap[MaskedLiteral,Seq[(Stageable[_ <: BaseType], BaseType)]]()
override def build(pipeline: VexRiscv): Unit = {
import pipeline.decode._
import pipeline.config._
val stageables = encodings.flatMap(_._2.map(_._1)).toSet
val stageables = (encodings.flatMap(_._2.map(_._1)) ++ defaults.map(_._1)).toSet.toList
var offset = 0
var defaultValue, defaultCare = BigInt(0)
val offsetOf = mutable.HashMap[Stageable[_ <: BaseType],Int]()
stageables.foreach(e => if(defaults.contains(e.asInstanceOf[Stageable[Data]]))
insert(e.asInstanceOf[Stageable[Data]]) := defaults(e.asInstanceOf[Stageable[Data]])
else
insert(e).assignDontCare())
//Build defaults value and field offset map
stageables.foreach(e => {
defaults.get(e) match {
case Some(value) => {
value.input match {
case literal: EnumLiteral[_] => literal.fixEncoding(e.dataType.asInstanceOf[SpinalEnumCraft[_]].getEncoding)
case _ =>
}
defaultValue += value.input.asInstanceOf[Literal].getValue << offset
defaultCare += ((BigInt(1) << e.dataType.getBitsWidth) - 1) << offset
stageables.foreach(insert(_) match{
case e : Bits => println(e.getWidth)
case _ =>
})
for((key,values) <- encodings){
when(input(INSTRUCTION) === key){
for((stageable,value) <- values){
insert(stageable).assignFrom(value.asInstanceOf[AnyRef],false)
}
case _ =>
}
offsetOf(e) = offset
offset += e.dataType.getBitsWidth
})
//Build spec
val spec = encodings.map { case (key, values) =>
var decodedValue, decodedCare = BigInt(0)
for((e, literal) <- values){
literal.input match{
case literal : EnumLiteral[_] => literal.fixEncoding(e.dataType.asInstanceOf[SpinalEnumCraft[_]].getEncoding)
case _ =>
}
val offset = offsetOf(e)
decodedValue += literal.input.asInstanceOf[Literal].getValue << offset
decodedCare += ((BigInt(1) << e.dataType.getBitsWidth)-1) << offset
}
(Masked(key.value,key.careAbout),Masked(decodedValue,decodedCare))
}
// logic implementation
val decodedBits = Bits(stageables.foldLeft(0)(_ + _.dataType.getBitsWidth) bits)
val defaultBits = cloneOf(decodedBits)
// require(defaultValue == 0)
for(i <- decodedBits.range)
// if(defaultCare.testBit(i))
defaultBits(i) := Bool(defaultValue.testBit(i))
// else
// defaultBits(i).assignDontCare()
val localAnds = for((key, mapping) <- spec) yield Mux[Bits](((input(INSTRUCTION) & key.care) === (key.value & key.care)), B(mapping.value & mapping.care, decodedBits.getWidth bits) , B(0, decodedBits.getWidth bits))
decodedBits := localAnds.foldLeft(defaultBits)(_ | _)
//Unpack decodedBits and insert fields in the pipeline
offset = 0
stageables.foreach(e => {
insert(e).assignFromBits(decodedBits(offset, e.dataType.getBitsWidth bits))
offset += e.dataType.getBitsWidth
})
}
def bench(toplevel : VexRiscv): Unit ={
@ -231,7 +273,7 @@ class NoPredictionBranchPlugin extends Plugin[VexRiscv]{
val decoderService = pipeline.service(classOf[DecoderService])
val bActions = List[(Stageable[_ <: Data],Any)](
val bActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
@ -240,7 +282,7 @@ class NoPredictionBranchPlugin extends Plugin[VexRiscv]{
SRC2_USE -> True
)
val jActions = List[(Stageable[_ <: Data],Any)](
val jActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.FOUR,
SRC2_CTRL -> Src2CtrlEnum.PC,
@ -418,7 +460,7 @@ class DBusSimplePlugin extends Plugin[VexRiscv]{
val decoderService = pipeline.service(classOf[DecoderService])
val stdActions = List[(Stageable[_ <: Data],Any)](
val stdActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC_USE_SUB_LESS -> False,
@ -675,7 +717,7 @@ class IntAluPlugin extends Plugin[VexRiscv]{
import pipeline.config._
import Riscv._
val immediateActions = List[(Stageable[_ <: Data],Any)](
val immediateActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.IMI,
@ -685,7 +727,7 @@ class IntAluPlugin extends Plugin[VexRiscv]{
SRC1_USE -> True
)
val nonImmediateActions = List[(Stageable[_ <: Data],Any)](
val nonImmediateActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
@ -768,7 +810,7 @@ class FullBarrielShifterPlugin extends Plugin[VexRiscv]{
val immediateActions = List[(Stageable[_ <: Data],Any)](
val immediateActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.IMI,
@ -777,7 +819,7 @@ class FullBarrielShifterPlugin extends Plugin[VexRiscv]{
BYPASSABLE_MEMORY_STAGE -> True
)
val nonImmediateActions = List[(Stageable[_ <: Data],Any)](
val nonImmediateActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,

View File

@ -3,6 +3,7 @@
#include "verilated.h"
#include "verilated_vcd_c.h"
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <stdint.h>
@ -85,10 +86,12 @@ uint32_t regFileWriteRefArray[][2] = {
#define assertEq(x,ref) if(x != ref) {\
printf("\n*** %s is %d but should be %d ***\n\n",TEXTIFY(x),x,ref);\
error = 1;\
error = 1; \
throw std::exception();\
}
int main(int argc, char **argv, char **env) {
Verilated::randReset(2);
int i;
int clk;
int error = 0;
@ -105,58 +108,64 @@ int main(int argc, char **argv, char **env) {
// Reset
top->clk = 1;
top->reset = 1;
top->reset = 0;
top->iCmd_ready = 1;
top->dCmd_ready = 1;
for (uint32_t i = 0; i < 16; i++) {
tfp->dump(i);
top->eval();
}
top->eval();
top->reset = 1;
top->eval();
tfp->dump(0);
top->reset = 0;
top->eval();
// run simulation for 100 clock periods
for (i = 16; i < 600; i+=2) {
uint32_t iRsp_inst_next = top->iRsp_inst;
if (top->iCmd_valid) {
assert((top->iCmd_payload_pc & 3) == 0);
uint8_t* ptr = memory + top->iCmd_payload_pc;
iRsp_inst_next = (ptr[0] << 0) | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
}
try {
// run simulation for 100 clock periods
for (i = 16; i < 600; i+=2) {
if(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_valid == 1 && top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address != 0){
assertEq(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address, regFileWriteRefArray[regFileWriteRefIndex][0]);
assertEq(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data, regFileWriteRefArray[regFileWriteRefIndex][1]);
printf("%d\n",i);
regFileWriteRefIndex++;
if(regFileWriteRefIndex == sizeof(regFileWriteRefArray)/sizeof(regFileWriteRefArray[0])){
tfp->dump(i);
tfp->dump(i+1);
printf("SUCCESS\n");
break;
uint32_t iRsp_inst_next = top->iRsp_inst;
if (top->iCmd_valid) {
assertEq(top->iCmd_payload_pc & 3,0);
//printf("%d\n",top->iCmd_payload_pc);
uint8_t* ptr = memory + top->iCmd_payload_pc;
iRsp_inst_next = (ptr[0] << 0) | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
}
if(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_valid == 1 && top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address != 0){
assertEq(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address, regFileWriteRefArray[regFileWriteRefIndex][0]);
assertEq(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data, regFileWriteRefArray[regFileWriteRefIndex][1]);
printf("%d\n",i);
regFileWriteRefIndex++;
if(regFileWriteRefIndex == sizeof(regFileWriteRefArray)/sizeof(regFileWriteRefArray[0])){
tfp->dump(i);
tfp->dump(i+1);
printf("SUCCESS\n");
break;
}
}
// dump variables into VCD file and toggle clock
for (clk = 0; clk < 2; clk++) {
tfp->dump(i+ clk);
top->clk = !top->clk;
top->eval();
}
top->iRsp_inst = iRsp_inst_next;
if (Verilated::gotFinish())
exit(0);
}
if(error) {
tfp->dump(i);
tfp->dump(i+1);
break;
}
// dump variables into VCD file and toggle clock
for (clk = 0; clk < 2; clk++) {
tfp->dump(i+ clk);
top->clk = !top->clk;
top->eval();
}
top->iRsp_inst = iRsp_inst_next;
if (Verilated::gotFinish())
exit(0);
} catch (const std::exception& e) {
std::cout << e.what();
}
if(error)
tfp->dump(i);
tfp->dump(i+1);
tfp->close();
printf("done\n");
exit(0);

View File

@ -2,7 +2,7 @@ run: compile
./obj_dir/VVexRiscv
verilate:
verilator -cc ../../../../VexRiscv.v --trace -Wno-WIDTH --exe main.cpp
verilator -cc ../../../../VexRiscv.v --gdbbt --trace -Wno-WIDTH --x-assign unique --exe main.cpp
compile: verilate
make -j -C obj_dir/ -f VVexRiscv.mk VVexRiscv