TDT4255/src/test/scala/TestUtils.scala
2020-06-29 16:17:24 +02:00

170 lines
6.7 KiB
Scala

package FiveStage
import fileUtils._
import Data._
import PrintUtils._
object TestUtils {
implicit class OptionBackport(t: Option.type){
def when[T](b: Boolean)(t: => T) = if(b) Some(t) else None
}
/**
* Generate and serialize BTrees for the test runner
*/
def generateBTree: Unit = {
import cats._
import cats.implicits._
case class AnnotatedNode(value: Int, index: Int, left: Option[AnnotatedNode], right: Option[AnnotatedNode]){
def find(key: Int): Unit = {
say(s"at $index (${(4 + (index << 2)).hs})-> ${value.hs}, looking for ${key.hs}")
if(value == key)
say("found it")
else if(key < value)
left.map{x => say("going left\n"); x.find(key)}.getOrElse("gave up")
else
right.map{x => say("going right\n"); x.find(key)}.getOrElse("gave up")
}
}
def printAnnoTree(tree: AnnotatedNode, depth: Int): String = {
val ls = tree.left.map(n => printAnnoTree(n, depth + 2)).getOrElse("left empty")
val rs = tree.right.map(n => printAnnoTree(n, depth + 2)).getOrElse("right empty")
val pads = "|".padTo(2, ' ')*depth
s"${tree.value.hs} at ${tree.index.hs}\n$pads$ls\n$pads$rs"
}
case class Node(value: Int, left: Option[Node], right: Option[Node]){
def append(v: Int): Node = if(v < value)
copy(left = left.map(_.append(v)).orElse(Some(Node(v))))
else
copy(right = right.map(_.append(v)).orElse(Some(Node(v))))
}
object Node {
def apply(v: Int): Node = Node(v, None, None)
}
def annotate(n: Int, root: Node): (AnnotatedNode, Int) = {
(root.left, root.right) match {
case (None, None) => {
(AnnotatedNode(root.value, n, None, None), n + 1)
}
case (Some(node), None) => {
val (annotated, next) = annotate(n+1, node)
(AnnotatedNode(root.value, n, Some(annotated), None), next)
}
case (None, Some(node)) => {
val (annotated, next) = annotate(n+1, node)
(AnnotatedNode(root.value, n, None, Some(annotated)), next)
}
case (Some(left), Some(right)) => {
val (leftAnno, leftNext) = annotate(n+1, left)
val (rightAnno, rightNext) = annotate(leftNext, right)
(AnnotatedNode(root.value, n, Some(leftAnno), Some(rightAnno)), rightNext)
}
}
}
def foldAnno(root: Option[AnnotatedNode]): List[Int] = {
root.map{ root =>
val leftIndex = root.left.map(_.index).getOrElse(0)
val hasLeft = root.left.map(_ => 1).getOrElse(0)
val rightIndex = root.right.map(_.index).getOrElse(0)
val hasRight = root.right.map(_ => 1).getOrElse(0)
val entry = hasLeft + (leftIndex << 1) + (hasRight << 8) + (rightIndex << 9) + (root.value << 16)
// say(s"with leftIndex: ${leftIndex.hs}, rightIndex: ${rightIndex.hs}, value: ${root.value.hs} we got ${entry.hs}")
entry :: foldAnno(root.left) ::: foldAnno(root.right)
}.getOrElse(Nil)
}
import scala.util.Random
val r = new scala.util.Random(0xF01D1EF7)
def randInt = r.nextInt(1000)
val seed = (0 to 100).map(_ => randInt).toList
val btree = seed.foldLeft(Node(randInt, None, None)){ case(acc, n) => acc.append(n)}
val annoTree = annotate(0, btree)
say(foldAnno(Some(annoTree._1)).zipWithIndex.map{case(m, idx) => s"#memset ${(4 + (idx*4)).hs}, ${m.hs}"}.mkStringN)
}
/**
* Generates a random program filled with hazards
*/
def generateHazardsForward(steps: Int) : Unit = {
val r = new scala.util.Random(0xF01D1EF7)
// val r = new scala.util.Random(0xF01D1EF8)
import Ops._
val active = List(1, 2, 3)
val initVM = {
val init = VM.init
val init1 = init.copy(regs = (init.regs + (Reg(1) -> 123))._2)
val init2 = init.copy(regs = (init1.regs + (Reg(2) -> -40))._2)
val init3 = init.copy(regs = (init2.regs + (Reg(3) -> 0xFFEE))._2)
init3
}
def generateInstruction: (Int, (String, Op)) = {
val rd = active.shuffle(r).head
val rs1 = active.shuffle(r).head
val rs2 = active.shuffle(r).head
val imm = r.nextInt(1024) - 512
val shift = r.nextInt(32) - 16
val choices = List(
(s"add ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.add(rd, rs1, rs2)),
(s"sub ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.sub(rd, rs1, rs2)),
(s"or ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.or(rd, rs1, rs2)),
(s"xor ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.xor(rd, rs1, rs2)),
(s"and ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.and(rd, rs1, rs2)),
(s"sll ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.sll(rd, rs1, rs2)),
(s"srl ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.srl(rd, rs1, rs2)),
(s"sra ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.sra(rd, rs1, rs2)),
(s"slt ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.slt(rd, rs1, rs2)),
(s"sltu ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.sltu(rd, rs1, rs2)),
(s"addi ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.add(rd, rs1, imm)),
(s"ori ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.or(rd, rs1, imm)),
(s"xori ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.xor(rd, rs1, imm)),
(s"andi ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.and(rd, rs1, imm)),
(s"slli ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(math.abs(shift).toInt % 32).show}", ArithImmShift.sll(rd, rs1, math.abs(shift).toInt % 32)),
(s"srli ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(math.abs(shift).toInt % 32).show}", ArithImmShift.srl(rd, rs1, math.abs(shift).toInt % 32)),
(s"srai ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(math.abs(shift).toInt % 32).show}", ArithImmShift.sra(rd, rs1, math.abs(shift).toInt % 32)),
(s"slti ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.slt(rd, rs1, imm)),
(s"sltiu ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.sltu(rd, rs1, imm)))
(rd, choices.shuffle(r).head)
}
def helper(attempts: Int, steps: Int, vm: VM): Unit = {
if((attempts > 10) || (steps == 0))
()
else{
val (nextRd, (nS, nextOp)) = generateInstruction
val withOp = vm.copy(imem = vm.imem + (vm.pc -> nextOp))
val nextVmE = withOp.stepInstruction
val nextVm = nextVmE.toOption.get.run._2
if(nextVm.regs.repr(Reg(nextRd)) == 0)
helper(attempts + 1, steps, vm)
else {
say(nS)
helper(0, steps - 1, nextVm)
}
}
}
helper(0, steps, initVM)
}
}