Add theory 2

This commit is contained in:
peteraa 2019-10-17 16:28:13 +02:00
parent 63b4447084
commit ec5089de8e
6 changed files with 201 additions and 23 deletions

View file

@ -39,7 +39,8 @@ object Data {
// addr is the target address
case class PcUpdateJALR(addr: Addr) extends ExecutionEvent
case class PcUpdateJAL(addr: Addr) extends ExecutionEvent
case class PcUpdateB(addr: Addr) extends ExecutionEvent
case class PcUpdateBranch(addr: Addr) extends ExecutionEvent
case class PcUpdateNoBranch(addr: Addr) extends ExecutionEvent
case class PcUpdate(addr: Addr) extends ExecutionEvent
case class ExecutionTraceEvent(pc: Addr, event: ExecutionEvent*){ override def toString(): String = s"$pc: " + event.toList.mkString(", ") }

View file

@ -110,25 +110,10 @@ object Ops {
case class LUI(rd: Reg, imm: Imm) extends Op with UType
case class AUIPC(rd: Reg, imm: Imm) extends Op with UType
case class Store(rs2: Reg, rs1: Reg, offset: Imm, width: Int) extends Op with SType
object Store {
def sw(rs2: Int, rs1: Int, offset: Int) = Store(Reg(rs2), Reg(rs1), Imm(offset), 4)
def sh(rs2: Int, rs1: Int, offset: Int) = Store(Reg(rs2), Reg(rs1), Imm(offset), 2)
def sb(rs2: Int, rs1: Int, offset: Int) = Store(Reg(rs2), Reg(rs1), Imm(offset), 1)
}
case class Load(rd: Reg, rs1: Reg, offset: Imm, width: Int, signed: Boolean) extends Op with IType
object Load {
def lw (rd: Int, rs1: Int, offset: Int) = Load(Reg(rd), Reg(rs1), Imm(offset), 4, true)
def lh (rd: Int, rs1: Int, offset: Int) = Load(Reg(rd), Reg(rs1), Imm(offset), 2, true)
def lb (rd: Int, rs1: Int, offset: Int) = Load(Reg(rd), Reg(rs1), Imm(offset), 1, true)
def lhu(rd: Int, rs1: Int, offset: Int) = Load(Reg(rd), Reg(rs1), Imm(offset), 2, false)
def lbu(rd: Int, rs1: Int, offset: Int) = Load(Reg(rd), Reg(rs1), Imm(offset), 1, false)
}
case class JALR(rd: Reg, rs1: Reg, dst: String) extends Op with IType
case class JAL(rd: Reg, dst: String) extends Op with UType
case class SW(rs2: Reg, rs1: Reg, offset: Imm) extends Op with SType
case class LW(rd: Reg, rs1: Reg, offset: Imm) extends Op with IType
object LUI { def apply(rd: Int, imm: Int): LUI = LUI(Reg(rd), Imm(imm)) }
@ -136,6 +121,8 @@ object Ops {
object JAL{ def apply(rd: Int, dst: String): JAL = JAL(Reg(rd), dst) }
object JALR{ def apply(rd: Int, rs1: Int, dst: String): JALR = JALR(Reg(rd), Reg(rs1), dst) }
object SW { def apply(rs2: Int, rs1: Int, offset: Int): SW = SW(Reg(rs2), Reg(rs1), Imm(offset)) }
object LW { def apply(rd: Int, rs1: Int, offset: Int): LW = LW(Reg(rd), Reg(rs1), Imm(offset)) }
// This op should not be assembled, but will for the sake of simplicity be rendered as a NOP
case object DONE extends Op with IType { val rd = Reg(0); val rs1 = Reg(0) }

View file

@ -38,21 +38,19 @@ case class VM(
}
private def executeBranch(op: Branch) = {
getAddr(op.dst).map{ addr =>
val takeBranch = regs.compare(op.rs1, op.rs2, op.comp.run)
if(takeBranch){
val nextVM = copy(pc = addr)
jump(nextVM, PcUpdateB(nextVM.pc))
jump(nextVM, PcUpdateBranch(nextVM.pc))
}
else {
step(this)
step(this, PcUpdateNoBranch(this.pc + Addr(4)))
}
}
}
/**
* The weird :_* syntax is simply a way to pass a list to a varArgs function.
*

View file

@ -42,7 +42,8 @@ object PrintUtils {
// addr is the target address
case PcUpdateJALR(addr) => fansi.Color.Green(s"PC updated to ${addr.show} via JALR")
case PcUpdateJAL(addr) => fansi.Color.Magenta(s"PC updated to ${addr.show} via JAL")
case PcUpdateB(addr) => fansi.Color.Yellow(s"PC updated to ${addr.show} via Branch")
case PcUpdateBranch(addr) => fansi.Color.Yellow(s"PC updated to ${addr.show} via Branch")
case PcUpdateNoBranch(addr) => fansi.Color.Yellow(s"PC updated to ${addr.show}, skipping a Branch")
}
}

View file

@ -100,4 +100,94 @@ object TestRunner {
successful
}.toOption.getOrElse(false)
}
def profileBranching(testOptions: TestOptions): Boolean = {
val testResults = for {
lines <- fileUtils.readTest(testOptions)
program <- FiveStage.Parser.parseProgram(lines, testOptions)
(binary, (trace, finalVM)) <- program.validate.map(x => (x._1, x._2.run))
} yield {
sealed trait BranchEvent
case class Taken(addr: Int) extends BranchEvent
case class NotTaken(addr: Int) extends BranchEvent
val events: List[BranchEvent] = trace.flatMap(_.event).collect{
case PcUpdateBranch(x) => Taken(x.value)
case PcUpdateNoBranch(x) => NotTaken(x.value)
}
/**
* This is a sample profiler for a rather unrealistic branch predictor which has an unlimited amount
* of slots
*/
def OneBitInfiniteSlots(events: List[BranchEvent]): Int = {
// Helper inspects the next element of the event list. If the event is a mispredict the prediction table is updated
// to reflect this.
// As long as there are remaining events the helper calls itself recursively on the remainder
def helper(events: List[BranchEvent], predictionTable: Map[Int, Boolean]): Int = {
events match {
// Scala syntax for matching a list with a head element of some type and a tail
// `case h :: t =>`
// means we want to match a list with at least a head and a tail (tail can be Nil, so we
// essentially want to match a list with at least one element)
// h is the first element of the list, t is the remainder (which can be Nil, aka empty)
// `case Constructor(arg1, arg2) :: t => `
// means we want to match a list whose first element is of type Constructor, giving us access to its internal
// values.
// `case Constructor(arg1, arg2) :: t => if(p(arg1, arg2))`
// means we want to match a list whose first element is of type Constructor while satisfying some predicate p,
// called an if guard.
case Taken(addr) :: t if( predictionTable(addr)) => helper(t, predictionTable)
case Taken(addr) :: t if(!predictionTable(addr)) => 1 + helper(t, predictionTable.updated(addr, true))
case NotTaken(addr) :: t if(!predictionTable(addr)) => 1 + helper(t, predictionTable.updated(addr, false))
case NotTaken(addr) :: t if( predictionTable(addr)) => helper(t, predictionTable)
case _ => 0
}
}
// Initially every possible branch is set to false since the initial state of the predictor is to assume branch not taken
def initState = events.map{
case Taken(addr) => (addr, false)
case NotTaken(addr) => (addr, false)
}.toMap
helper(events, initState)
}
say(OneBitInfiniteSlots(events))
}
true
}
def profileCache(testOptions: TestOptions): Boolean = {
val testResults = for {
lines <- fileUtils.readTest(testOptions)
program <- FiveStage.Parser.parseProgram(lines, testOptions)
(binary, (trace, finalVM)) <- program.validate.map(x => (x._1, x._2.run))
} yield {
sealed trait MemoryEvent
case class Write(addr: Int) extends MemoryEvent
case class Read(addr: Int) extends MemoryEvent
val events: List[MemoryEvent] = trace.flatMap(_.event).collect{
case MemWrite(x,_) => Write(x.value)
case MemRead(x,_) => Read(x.value)
}
// Your cache here
}
true
}
}