Commit 6f821d5f authored by Jens Korinth's avatar Jens Korinth
Browse files

Finish draft for TaPaSCo status core configurations

* Status contains complete configuration, including kernel ids, memory
  slots and some basic sanity checking
* json package contains JSON SerDes functionality
parent 0ddba2f3
package de.tu_darmstadt.cs.esa.tapasco.tapasco_status
import de.tu_darmstadt.cs.esa.tapasco.Implicits._
import SlotConfig._
import Slot._
import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
package object json {
......@@ -10,7 +11,7 @@ package object json {
case JsNumber(n) => JsSuccess(SlotId(n.toInt))
case _ => JsError(Seq(JsPath() -> Seq(JsonValidationError("validation.error.expected.jsnumber"))))
}
def writes(sz: SlotId): JsValue = writes(sz.id)
def writes(id: SlotId): JsValue = Json.toJson(id: Int)
}
implicit object KernelIdFormats extends Format[KernelId] {
......@@ -18,7 +19,7 @@ package object json {
case JsNumber(n) => JsSuccess(KernelId(n.toInt))
case _ => JsError(Seq(JsPath() -> Seq(JsonValidationError("validation.error.expected.jsnumber"))))
}
def writes(sz: KernelId): JsValue = writes(sz.id)
def writes(id: KernelId): JsValue = Json.toJson(id: Int)
}
implicit object SizeFormats extends Format[Size] {
......@@ -26,18 +27,125 @@ package object json {
case JsNumber(n) => JsSuccess(Size(n.toInt))
case _ => JsError(Seq(JsPath() -> Seq(JsonValidationError("validation.error.expected.jsnumber"))))
}
def writes(sz: Size): JsValue = writes(sz.size)
def writes(sz: Size): JsValue = Json.toJson(sz: Int)
}
implicit val kernelWrite: Writes[Kernel] = (
implicit val kernelWrites: Writes[Kernel] = (
(JsPath \ "Type").write[String] ~
(JsPath \ "SlotId").write[SlotId] ~
(JsPath \ "Kernel").write[KernelId]
) (unlift(Kernel.unapply _ andThen (_ map ("Kernel" +: _))))
implicit val memoryWrite: Writes[Memory] = (
val kernelReads: Reads[Slot] = (
(JsPath \ "Type").read[String] (verifying[String](_.toLowerCase equals "kernel")) ~>
(JsPath \ "SlotId").read[SlotId] ~
(JsPath \ "Kernel").read[KernelId]
) (Kernel.apply _)
implicit val memoryWrites: Writes[Memory] = (
(JsPath \ "Type").write[String] ~
(JsPath \ "SlotId").write[SlotId] ~
(JsPath \ "Memory").write[Size]
(JsPath \ "Bytes").write[Size]
) (unlift(Memory.unapply _ andThen (_ map ("Memory" +: _))))
val memoryReads: Reads[Slot] = (
(JsPath \ "Type").read[String] (verifying[String](_.toLowerCase equals "memory")) ~>
(JsPath \ "SlotId").read[SlotId] ~
(JsPath \ "Bytes").read[Size]
) (Memory.apply _)
implicit val slotReads: Reads[Slot] = kernelReads | memoryReads
implicit object SlotWrites extends Writes[Slot] {
def writes(c: Slot): JsValue = c match {
case k: Kernel => kernelWrites.writes(k)
case m: Memory => memoryWrites.writes(m)
}
}
implicit val versionWrites: Writes[Versions.Version] = (
(JsPath \ "Software").write[String] ~
(JsPath \ "Year").write[Int] ~
(JsPath \ "Release").write[Int]
) (_.unapply)
val tapascoVersionReads: Reads[Versions.Version] = (
(JsPath \ "Software").read[String] (verifying[String](_.toLowerCase contains "tapasco")) ~>
(JsPath \ "Year").read[Int] ~
(JsPath \ "Release").read[Int]
) (Versions.Tapasco.apply _)
val vivadoVersionReads: Reads[Versions.Version] = (
(JsPath \ "Software").read[String] (verifying[String](_.toLowerCase contains "vivado")) ~>
(JsPath \ "Year").read[Int] ~
(JsPath \ "Release").read[Int]
) (Versions.Vivado.apply _)
implicit val versionReads: Reads[Versions.Version] = tapascoVersionReads | vivadoVersionReads
implicit object VersionsFormat extends Format[Versions] {
private def tapascoVersion(vs: Seq[Versions.Version]): Versions.Tapasco = vs match {
case t +: tt => t match {
case v: Versions.Tapasco => v
case _ => tapascoVersion(tt)
}
case _ => throw new IllegalArgumentException("TaPaSCo version not found in JSON")
}
private def vivadoVersion(vs: Seq[Versions.Version]): Versions.Vivado = vs match {
case t +: tt => t match {
case v: Versions.Vivado => v
case _ => vivadoVersion(tt)
}
case _ => throw new IllegalArgumentException("Vivado version not found in JSON")
}
def reads(json: JsValue): JsResult[Versions] = json match {
case vs: JsArray => Json.fromJson[Seq[Versions.Version]](vs) map (vs => Versions(tapascoVersion(vs), vivadoVersion(vs)))
case _ => JsError(Seq(JsPath() -> Seq(JsonValidationError("validation.error.expected.jsarray"))))
}
def writes(v: Versions): JsValue = Json.toJson(Seq(v.vivado, v.tapasco))
}
implicit val freqWrites: Writes[Clocks.Frequency] = (
(JsPath \ "Domain").write[String] ~
(JsPath \ "Frequency").write[Double]
) (_.unapply)
val hostFreqReads: Reads[Clocks.Frequency] = (
(JsPath \ "Domain").read[String] (verifying[String](_.toLowerCase equals "host")) ~>
(JsPath \ "Frequency").read[Double]
) fmap (Clocks.HostFreq.apply _)
val designFreqReads: Reads[Clocks.Frequency] = (
(JsPath \ "Domain").read[String] (verifying[String](_.toLowerCase equals "design")) ~>
(JsPath \ "Frequency").read[Double]
) fmap (Clocks.DesignFreq.apply _)
val memFreqReads: Reads[Clocks.Frequency] = (
(JsPath \ "Domain").read[String] (verifying[String](_.toLowerCase equals "memory")) ~>
(JsPath \ "Frequency").read[Double]
) fmap (Clocks.MemFreq.apply _)
implicit val freqReads: Reads[Clocks.Frequency] = hostFreqReads | designFreqReads | memFreqReads
implicit object ClocksFormat extends Format[Clocks] {
def reads(json: JsValue): JsResult[Clocks] = json match {
case cs: JsArray => Json.fromJson[Seq[Clocks.Frequency]](cs) map ((clocks: Seq[Clocks.Frequency]) => for {
hf <- (clocks collectFirst { case h: Clocks.HostFreq => h })
df <- (clocks collectFirst { case d: Clocks.DesignFreq => d })
mf <- (clocks collectFirst { case m: Clocks.MemFreq => m })
} yield Clocks(hf, df, mf)) map (_.get)
case _ => JsError(Seq(JsPath() -> Seq(JsonValidationError("validation.error.expected.jsarray"))))
}
def writes(c: Clocks): JsValue = Json.toJson(Seq(c.host, c.design, c.memory))
}
implicit val statusFormat: Format[Status] = (
(JsPath \ "Composition").format[Seq[Slot]] ~
(JsPath \ "Timestamp").format[Int] ~
(JsPath \ "Interrupt Controllers").format[Int] ~
(JsPath \ "Versions").format[Versions] ~
(JsPath \ "Clocks").format[Clocks]
) (Status.apply _, unlift(Status.unapply _))
}
package de.tu_darmstadt.cs.esa.tapasco
import scala.language.implicitConversions
import org.scalactic.anyvals.PosInt
package object tapasco_status {
final val NUM_SLOTS = 128
......@@ -18,18 +17,58 @@ package object tapasco_status {
require ((size & (~size + 1)) == size, s"memory size $size invalid, must be a power of 2")
}
sealed trait SlotConfig
object SlotConfig {
final case class Kernel(slot: SlotId, kernel: KernelId) extends SlotConfig
final case class Memory(slot: SlotId, size: Size) extends SlotConfig
final case class Versions(tapasco: Versions.Tapasco, vivado: Versions.Vivado)
object Versions {
sealed trait Version {
require(year > 0, s"year $year is invalid, must be > 0")
require(release > 0, s"release $release is invalid, must be > 0")
def year: Int
def release: Int
def toHex: String = "0x%04x%04x".format(year, release)
def unapply: (String, Int, Int)
}
final case class Tapasco(year: Int, release: Int) extends Version {
def unapply = ("TaPaSCo", year, release)
}
final case class Vivado(year: Int, release: Int) extends Version {
def unapply = ("Vivado", year, release)
}
}
final case class Status(config: Set[SlotConfig]) {
require (config.nonEmpty, "a status configuration must not be empty")
final case class Clocks(host: Clocks.HostFreq, design: Clocks.DesignFreq, memory: Clocks.MemFreq)
object Clocks {
sealed trait Frequency {
require(frequency > 0, "frequency $frequency is invalid, must be > 0")
def frequency: Double
def unapply: (String, Double)
}
final case class HostFreq(frequency: Double) extends Frequency {
def unapply = ("Host", frequency)
}
final case class DesignFreq(frequency: Double) extends Frequency {
def unapply = ("Design", frequency)
}
final case class MemFreq(frequency: Double) extends Frequency {
def unapply = ("Memory", frequency)
}
}
sealed trait Slot {
def slot: SlotId
}
object Slot {
final case class Kernel(slot: SlotId, kernel: KernelId) extends Slot
final case class Memory(slot: SlotId, size: Size) extends Slot
}
object Status {
def apply(s: SlotConfig, ss: SlotConfig*): Status = Status((s +: ss).toSet)
final case class Status(config: Seq[Slot],
timestamp: Int,
interruptControllers: Int,
versions: Versions,
clocks: Clocks) {
require (config.nonEmpty, "a status configuration must not be empty")
require ((config map (_.slot)).toSet.size == config.length, "slot ids must be unique")
}
implicit def intToSlot(i: Int): SlotId = SlotId(i)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment