Better decoding
This commit is contained in:
parent
e36c90af03
commit
df99a0d963
|
@ -6,7 +6,7 @@ import spinal.lib._
|
||||||
import scala.collection.mutable
|
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("$",""))
|
setWeakName(this.getClass.getSimpleName.replace("$",""))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,61 +146,103 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{
|
||||||
|
|
||||||
|
|
||||||
trait DecoderService{
|
trait DecoderService{
|
||||||
def add(key : MaskedLiteral,values : Seq[(Stageable[_ <: Data],Any)])
|
def add(key : MaskedLiteral,values : Seq[(Stageable[_ <: BaseType],Any)])
|
||||||
def add(encoding :Seq[(MaskedLiteral,Seq[(Stageable[_ <: Data],Any)])])
|
def add(encoding :Seq[(MaskedLiteral,Seq[(Stageable[_ <: BaseType],Any)])])
|
||||||
def addDefault(key : Stageable[_ <: Data], value : 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 {
|
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(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[_ <: Data], Any)]): Unit = {
|
override def add(key: MaskedLiteral, values: Seq[(Stageable[_ <: BaseType], Any)]): Unit = {
|
||||||
require(!encodings.contains(key))
|
require(!encodings.contains(key))
|
||||||
encodings(key) = values.map{case (a,b) => (a,b match{
|
encodings(key) = values.map{case (a,b) => (a,b match{
|
||||||
case e : SpinalEnumElement[_] => e()
|
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))
|
require(!defaults.contains(key))
|
||||||
defaults(key) = value match{
|
defaults(key) = value match{
|
||||||
case e : SpinalEnumElement[_] => e()
|
case e : SpinalEnumElement[_] => e()
|
||||||
case e : Data => e
|
case e : BaseType => e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val defaults = mutable.HashMap[Stageable[_ <: Data], Data]()
|
val defaults = mutable.HashMap[Stageable[_ <: BaseType], BaseType]()
|
||||||
val encodings = mutable.HashMap[MaskedLiteral,Seq[(Stageable[_ <: Data], Any)]]()
|
val encodings = mutable.HashMap[MaskedLiteral,Seq[(Stageable[_ <: BaseType], BaseType)]]()
|
||||||
|
|
||||||
override def build(pipeline: VexRiscv): Unit = {
|
override def build(pipeline: VexRiscv): Unit = {
|
||||||
import pipeline.decode._
|
import pipeline.decode._
|
||||||
import pipeline.config._
|
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]()
|
||||||
|
|
||||||
|
//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(e => if(defaults.contains(e.asInstanceOf[Stageable[Data]]))
|
|
||||||
insert(e.asInstanceOf[Stageable[Data]]) := defaults(e.asInstanceOf[Stageable[Data]])
|
|
||||||
else
|
|
||||||
insert(e).assignDontCare())
|
|
||||||
|
|
||||||
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 ={
|
def bench(toplevel : VexRiscv): Unit ={
|
||||||
|
@ -231,7 +273,7 @@ class NoPredictionBranchPlugin extends Plugin[VexRiscv]{
|
||||||
|
|
||||||
val decoderService = pipeline.service(classOf[DecoderService])
|
val decoderService = pipeline.service(classOf[DecoderService])
|
||||||
|
|
||||||
val bActions = List[(Stageable[_ <: Data],Any)](
|
val bActions = List[(Stageable[_ <: BaseType],Any)](
|
||||||
LEGAL_INSTRUCTION -> True,
|
LEGAL_INSTRUCTION -> True,
|
||||||
SRC1_CTRL -> Src1CtrlEnum.RS,
|
SRC1_CTRL -> Src1CtrlEnum.RS,
|
||||||
SRC2_CTRL -> Src2CtrlEnum.RS,
|
SRC2_CTRL -> Src2CtrlEnum.RS,
|
||||||
|
@ -240,7 +282,7 @@ class NoPredictionBranchPlugin extends Plugin[VexRiscv]{
|
||||||
SRC2_USE -> True
|
SRC2_USE -> True
|
||||||
)
|
)
|
||||||
|
|
||||||
val jActions = List[(Stageable[_ <: Data],Any)](
|
val jActions = List[(Stageable[_ <: BaseType],Any)](
|
||||||
LEGAL_INSTRUCTION -> True,
|
LEGAL_INSTRUCTION -> True,
|
||||||
SRC1_CTRL -> Src1CtrlEnum.FOUR,
|
SRC1_CTRL -> Src1CtrlEnum.FOUR,
|
||||||
SRC2_CTRL -> Src2CtrlEnum.PC,
|
SRC2_CTRL -> Src2CtrlEnum.PC,
|
||||||
|
@ -418,7 +460,7 @@ class DBusSimplePlugin extends Plugin[VexRiscv]{
|
||||||
|
|
||||||
val decoderService = pipeline.service(classOf[DecoderService])
|
val decoderService = pipeline.service(classOf[DecoderService])
|
||||||
|
|
||||||
val stdActions = List[(Stageable[_ <: Data],Any)](
|
val stdActions = List[(Stageable[_ <: BaseType],Any)](
|
||||||
LEGAL_INSTRUCTION -> True,
|
LEGAL_INSTRUCTION -> True,
|
||||||
SRC1_CTRL -> Src1CtrlEnum.RS,
|
SRC1_CTRL -> Src1CtrlEnum.RS,
|
||||||
SRC_USE_SUB_LESS -> False,
|
SRC_USE_SUB_LESS -> False,
|
||||||
|
@ -675,7 +717,7 @@ class IntAluPlugin extends Plugin[VexRiscv]{
|
||||||
import pipeline.config._
|
import pipeline.config._
|
||||||
import Riscv._
|
import Riscv._
|
||||||
|
|
||||||
val immediateActions = List[(Stageable[_ <: Data],Any)](
|
val immediateActions = List[(Stageable[_ <: BaseType],Any)](
|
||||||
LEGAL_INSTRUCTION -> True,
|
LEGAL_INSTRUCTION -> True,
|
||||||
SRC1_CTRL -> Src1CtrlEnum.RS,
|
SRC1_CTRL -> Src1CtrlEnum.RS,
|
||||||
SRC2_CTRL -> Src2CtrlEnum.IMI,
|
SRC2_CTRL -> Src2CtrlEnum.IMI,
|
||||||
|
@ -685,7 +727,7 @@ class IntAluPlugin extends Plugin[VexRiscv]{
|
||||||
SRC1_USE -> True
|
SRC1_USE -> True
|
||||||
)
|
)
|
||||||
|
|
||||||
val nonImmediateActions = List[(Stageable[_ <: Data],Any)](
|
val nonImmediateActions = List[(Stageable[_ <: BaseType],Any)](
|
||||||
LEGAL_INSTRUCTION -> True,
|
LEGAL_INSTRUCTION -> True,
|
||||||
SRC1_CTRL -> Src1CtrlEnum.RS,
|
SRC1_CTRL -> Src1CtrlEnum.RS,
|
||||||
SRC2_CTRL -> Src2CtrlEnum.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,
|
LEGAL_INSTRUCTION -> True,
|
||||||
SRC1_CTRL -> Src1CtrlEnum.RS,
|
SRC1_CTRL -> Src1CtrlEnum.RS,
|
||||||
SRC2_CTRL -> Src2CtrlEnum.IMI,
|
SRC2_CTRL -> Src2CtrlEnum.IMI,
|
||||||
|
@ -777,7 +819,7 @@ class FullBarrielShifterPlugin extends Plugin[VexRiscv]{
|
||||||
BYPASSABLE_MEMORY_STAGE -> True
|
BYPASSABLE_MEMORY_STAGE -> True
|
||||||
)
|
)
|
||||||
|
|
||||||
val nonImmediateActions = List[(Stageable[_ <: Data],Any)](
|
val nonImmediateActions = List[(Stageable[_ <: BaseType],Any)](
|
||||||
LEGAL_INSTRUCTION -> True,
|
LEGAL_INSTRUCTION -> True,
|
||||||
SRC1_CTRL -> Src1CtrlEnum.RS,
|
SRC1_CTRL -> Src1CtrlEnum.RS,
|
||||||
SRC2_CTRL -> Src2CtrlEnum.RS,
|
SRC2_CTRL -> Src2CtrlEnum.RS,
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "verilated.h"
|
#include "verilated.h"
|
||||||
#include "verilated_vcd_c.h"
|
#include "verilated_vcd_c.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <iostream>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -85,10 +86,12 @@ uint32_t regFileWriteRefArray[][2] = {
|
||||||
|
|
||||||
#define assertEq(x,ref) if(x != ref) {\
|
#define assertEq(x,ref) if(x != ref) {\
|
||||||
printf("\n*** %s is %d but should be %d ***\n\n",TEXTIFY(x),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) {
|
int main(int argc, char **argv, char **env) {
|
||||||
|
Verilated::randReset(2);
|
||||||
int i;
|
int i;
|
||||||
int clk;
|
int clk;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
@ -105,58 +108,64 @@ int main(int argc, char **argv, char **env) {
|
||||||
|
|
||||||
// Reset
|
// Reset
|
||||||
top->clk = 1;
|
top->clk = 1;
|
||||||
top->reset = 1;
|
top->reset = 0;
|
||||||
top->iCmd_ready = 1;
|
top->iCmd_ready = 1;
|
||||||
top->dCmd_ready = 1;
|
top->dCmd_ready = 1;
|
||||||
for (uint32_t i = 0; i < 16; i++) {
|
top->eval();
|
||||||
tfp->dump(i);
|
top->reset = 1;
|
||||||
top->eval();
|
top->eval();
|
||||||
}
|
tfp->dump(0);
|
||||||
top->reset = 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;
|
try {
|
||||||
if (top->iCmd_valid) {
|
// run simulation for 100 clock periods
|
||||||
assert((top->iCmd_payload_pc & 3) == 0);
|
for (i = 16; i < 600; i+=2) {
|
||||||
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){
|
uint32_t iRsp_inst_next = top->iRsp_inst;
|
||||||
assertEq(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address, regFileWriteRefArray[regFileWriteRefIndex][0]);
|
if (top->iCmd_valid) {
|
||||||
assertEq(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data, regFileWriteRefArray[regFileWriteRefIndex][1]);
|
assertEq(top->iCmd_payload_pc & 3,0);
|
||||||
printf("%d\n",i);
|
//printf("%d\n",top->iCmd_payload_pc);
|
||||||
|
uint8_t* ptr = memory + top->iCmd_payload_pc;
|
||||||
regFileWriteRefIndex++;
|
iRsp_inst_next = (ptr[0] << 0) | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
|
||||||
if(regFileWriteRefIndex == sizeof(regFileWriteRefArray)/sizeof(regFileWriteRefArray[0])){
|
|
||||||
tfp->dump(i);
|
|
||||||
tfp->dump(i+1);
|
|
||||||
printf("SUCCESS\n");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
} catch (const std::exception& e) {
|
||||||
if(error) {
|
std::cout << e.what();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(error)
|
||||||
|
tfp->dump(i);
|
||||||
|
tfp->dump(i+1);
|
||||||
tfp->close();
|
tfp->close();
|
||||||
printf("done\n");
|
printf("done\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
|
@ -2,7 +2,7 @@ run: compile
|
||||||
./obj_dir/VVexRiscv
|
./obj_dir/VVexRiscv
|
||||||
|
|
||||||
verilate:
|
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
|
compile: verilate
|
||||||
make -j -C obj_dir/ -f VVexRiscv.mk VVexRiscv
|
make -j -C obj_dir/ -f VVexRiscv.mk VVexRiscv
|
||||||
|
|
Loading…
Reference in New Issue