├── diagrams └── AESAccelTopLevelDiagram.png ├── .gitignore ├── src ├── main │ ├── scala │ │ ├── Configs.scala │ │ ├── Const.scala │ │ ├── CommonIO.scala │ │ ├── AES.scala │ │ ├── DMABuffer.scala │ │ ├── Decoupler.scala │ │ └── Controller.scala │ └── resources │ │ └── vsrc │ │ ├── aes.v │ │ ├── aes_sbox.v │ │ ├── aes_core.v │ │ ├── aes_inv_sbox.v │ │ ├── aes_key_mem.v │ │ ├── aes_encipher_block.v │ │ └── aes_decipher_block.v └── test │ └── scala │ ├── StandaloneBlocks.scala │ ├── TestUtils.scala │ ├── AccelTopTest.scala │ ├── DMABufferTest.scala │ └── DcplrSanityTest.scala ├── LICENSE └── README.md /diagrams/AESAccelTopLevelDiagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucb-ee290c/sp21-aes-rocc-accel/HEAD/diagrams/AESAccelTopLevelDiagram.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bloop 2 | .bsp 3 | .metals 4 | .vscode 5 | target 6 | project 7 | test_run_dir 8 | 9 | # ignore swp file 10 | .*.swp 11 | 12 | # ignore hidden file 13 | .* 14 | -------------------------------------------------------------------------------- /src/main/scala/Configs.scala: -------------------------------------------------------------------------------- 1 | package aes 2 | 3 | import chipsalliance.rocketchip.config.{Config, Parameters} 4 | import freechips.rocketchip.diplomacy.LazyModule 5 | import freechips.rocketchip.tile.{BuildRoCC, OpcodeSet} 6 | 7 | class WithAESAccel extends Config((site, here, up) => { 8 | case BuildRoCC => up(BuildRoCC) ++ Seq( 9 | (p: Parameters) => { 10 | val aes = LazyModule.apply(new AESAccel(OpcodeSet.custom0)(p)) 11 | aes 12 | } 13 | ) 14 | }) 15 | -------------------------------------------------------------------------------- /src/main/scala/Const.scala: -------------------------------------------------------------------------------- 1 | package aes 2 | 3 | import chisel3._ 4 | import chisel3.experimental.ChiselEnum 5 | 6 | // AES ISA 7 | object AESISA { 8 | val KEYSETUP128 = 0.U(7.W) 9 | val KEYSETUP256 = 1.U(7.W) 10 | val ADDRESSLOAD = 2.U(7.W) 11 | val ENCRYPTBLOCKS = 3.U(7.W) 12 | val DECRYPTBLOCKS = 4.U(7.W) 13 | val QUERYSTATUS = 5.U(7.W) 14 | } 15 | 16 | // AES address map 17 | object AESAddr { 18 | val CTRL = 8.U(8.W) 19 | val STATUS = 9.U(8.W) 20 | val CONFIG = 10.U(8.W) 21 | val KEY = 16.U(8.W) 22 | val TEXT = 32.U(8.W) 23 | val RESULT = 48.U(8.W) 24 | } 25 | 26 | // Main Controller States 27 | object CtrlState extends ChiselEnum { 28 | val sIdle, sKeySetup, sKeyExp, sWaitData, sDataSetup, sWaitStart, sAESRun, sWaitResult, sDataWrite = Value 29 | } 30 | 31 | // Memory Controller States 32 | object MemState extends ChiselEnum { 33 | val sIdle, sReadReq, sReadIntoAES, sWriteReq, sWriteIntoMem = Value 34 | } 35 | -------------------------------------------------------------------------------- /src/test/scala/StandaloneBlocks.scala: -------------------------------------------------------------------------------- 1 | package aes 2 | 3 | import chisel3._ 4 | import freechips.rocketchip.config.Parameters 5 | import freechips.rocketchip.diplomacy._ 6 | import freechips.rocketchip.tile.OpcodeSet 7 | import freechips.rocketchip.tilelink._ 8 | import freechips.rocketchip.subsystem.WithoutTLMonitors 9 | import verif.VerifTestUtils 10 | 11 | class AESAccelStandaloneBlock(beatBytes: Int)(implicit p: Parameters = new WithoutTLMonitors) extends LazyModule { 12 | val mPortParams = VerifTestUtils.getVerifTLMasterPortParameters() 13 | val sPortParams = VerifTestUtils.getVerifTLSlavePortParameters(beatBytes = beatBytes) 14 | val bParams = TLBundleParameters(mPortParams, sPortParams) 15 | 16 | // AES Accelerator 17 | val aes = LazyModule(new AESAccel(OpcodeSet.custom0)) 18 | 19 | // IO for DMA 20 | val ioOutNode = BundleBridgeSink[TLBundle]() 21 | val to_mem = InModuleBody { ioOutNode.makeIO() } 22 | 23 | ioOutNode := TLToBundleBridge(sPortParams) := aes.tlNode 24 | 25 | lazy val module = new LazyModuleImp(this) { 26 | val io = IO(chiselTypeOf(aes.module.io)) 27 | io <> aes.module.io 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, The Regents of the University of California (Regents) 4 | All Rights Reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /src/main/scala/CommonIO.scala: -------------------------------------------------------------------------------- 1 | package aes 2 | 3 | import chisel3._ 4 | import chisel3.util.Decoupled 5 | import chipsalliance.rocketchip.config.Parameters 6 | import ee290cdma.{EE290CDMAReaderReq, EE290CDMAReaderResp, EE290CDMAWriterReq} 7 | 8 | class AESCoreIO extends Bundle { 9 | val clk = Input(Clock()) 10 | val reset_n = Input(Bool()) 11 | val cs = Input(Bool()) 12 | val we = Input(Bool()) 13 | val address = Input(UInt(8.W)) 14 | val write_data = Input(UInt(32.W)) 15 | val read_data = Output(UInt(32.W)) 16 | } 17 | 18 | class DecouplerControllerIO extends Bundle { 19 | val excp_ready = Output(Bool()) 20 | val excp_valid = Input(Bool()) 21 | val interrupt = Output(Bool()) 22 | val busy = Output(Bool()) 23 | 24 | val key_ready = Output(Bool()) 25 | val key_valid = Input(Bool()) 26 | val key_size = Input(UInt(1.W)) 27 | val key_addr = Input(UInt(32.W)) 28 | 29 | val addr_ready = Output(Bool()) 30 | val addr_valid = Input(Bool()) 31 | val src_addr = Input(UInt(32.W)) 32 | val dest_addr = Input(UInt(32.W)) 33 | 34 | val start_ready = Output(Bool()) 35 | val start_valid = Input(Bool()) 36 | val op_type = Input(Bool()) 37 | val block_count = Input(UInt(32.W)) 38 | val intrpt_en = Input(Bool()) 39 | } 40 | 41 | class ControllerDMAIO (addrBits: Int, beatBytes: Int)(implicit p: Parameters) extends Bundle { 42 | val writeReq = Decoupled(new EE290CDMAWriterReq(addrBits, beatBytes)) 43 | val readReq = Decoupled(new EE290CDMAReaderReq(addrBits, 256)) // Hardcoded due to 256b key and 128b blocks 44 | val readResp = Flipped(Decoupled(new EE290CDMAReaderResp(256))) 45 | val readRespQueue = Flipped(Decoupled(UInt((beatBytes * 8).W))) 46 | val busy = Input(Bool()) 47 | } 48 | -------------------------------------------------------------------------------- /src/main/scala/AES.scala: -------------------------------------------------------------------------------- 1 | package aes 2 | 3 | import chisel3._ 4 | import chisel3.util.HasBlackBoxResource 5 | import chipsalliance.rocketchip.config.Parameters 6 | import ee290cdma.EE290CDMA 7 | import freechips.rocketchip.tile.{HasCoreParameters, LazyRoCC, LazyRoCCModuleImp, OpcodeSet} 8 | import freechips.rocketchip.diplomacy.LazyModule 9 | import freechips.rocketchip.subsystem.SystemBusKey 10 | 11 | // Blackbox (Class name must match top-level verilog file) 12 | class aes(implicit p: Parameters) extends BlackBox with HasBlackBoxResource { 13 | val io = IO(new AESCoreIO) 14 | 15 | addResource("/vsrc/aes_core.v") 16 | addResource("/vsrc/aes_decipher_block.v") 17 | addResource("/vsrc/aes_encipher_block.v") 18 | addResource("/vsrc/aes_inv_sbox.v") 19 | addResource("/vsrc/aes_key_mem.v") 20 | addResource("/vsrc/aes_sbox.v") 21 | addResource("/vsrc/aes.v") 22 | } 23 | 24 | class AESAccel(opcodes: OpcodeSet)(implicit p: Parameters) extends LazyRoCC(opcodes = opcodes, nPTWPorts = 0) { 25 | val dma = LazyModule(new EE290CDMA(p(SystemBusKey).beatBytes, 32, "AESAccelDMA")) 26 | 27 | override lazy val module = new AESAccelImp(this) 28 | override val tlNode = dma.id_node 29 | } 30 | 31 | class AESAccelImp(outer: AESAccel)(implicit p: Parameters) extends LazyRoCCModuleImp(outer) with HasCoreParameters { 32 | val beatBytes = p(SystemBusKey).beatBytes 33 | 34 | // RoCC Decoupler 35 | val dcplr = Module(new RoCCDecoupler) 36 | dcplr.io.reset := reset.asBool() 37 | dcplr.io.rocc_cmd <> io.cmd 38 | io.resp <> dcplr.io.rocc_resp 39 | io.busy := dcplr.io.rocc_busy 40 | io.interrupt := dcplr.io.rocc_intr 41 | dcplr.io.rocc_excp := io.exception 42 | 43 | // Controller 44 | val ctrl = Module(new AESController(32, beatBytes)) 45 | ctrl.io.reset := reset.asBool() 46 | ctrl.io.dcplrIO <> dcplr.io.ctrlIO 47 | 48 | // DMA Connections 49 | outer.dma.module.io.read.req <> ctrl.io.dmem.readReq 50 | outer.dma.module.io.write.req <> ctrl.io.dmem.writeReq 51 | ctrl.io.dmem.readResp <> outer.dma.module.io.read.resp 52 | ctrl.io.dmem.readRespQueue <> outer.dma.module.io.read.queue 53 | ctrl.io.dmem.busy := outer.dma.module.io.readBusy | outer.dma.module.io.writeBusy 54 | 55 | // AES Core (Black Box) 56 | val aesbb = Module(new aes) 57 | aesbb.io <> ctrl.io.aesCoreIO 58 | } 59 | -------------------------------------------------------------------------------- /src/main/scala/DMABuffer.scala: -------------------------------------------------------------------------------- 1 | package aes 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | import ee290cdma.EE290CDMAWriterReq 6 | 7 | // Takes 32bit inputs (from AES core) and writes to DMA 8 | class DMAInputBuffer (addrBits: Int = 32, beatBytes: Int) extends Module { 9 | val io = IO(new Bundle { 10 | val baseAddr = Flipped(Decoupled(UInt(addrBits.W))) 11 | val dataIn = Flipped(Decoupled(UInt(32.W))) 12 | val dmaOutput = Decoupled(new EE290CDMAWriterReq(addrBits, beatBytes)) 13 | val done = Output(Bool()) 14 | }) 15 | 16 | val bitsFilled = RegInit(0.U(log2Ceil(128 + 1).W)) 17 | val addrReg = RegInit(0.U(addrBits.W)) 18 | val wideData = RegInit(0.U(128.W)) // AES data block size is 128b 19 | // AES core outputs 32 bits at a time 20 | val dataQueue = Module(new Queue(UInt(32.W), 4)) 21 | // Signal when to start writing to DMA (ensure that all 128b of data is correctly matched to address) 22 | val startWrite = RegInit(false.B) 23 | // Delay done by a cycle to account for request to propagate to DMA 24 | val doneReg = RegInit(false.B) 25 | // Data to-be-reversed 26 | val toReverse = Wire(UInt(32.W)) 27 | // Data with bytes reversed 28 | val reverse = Wire(UInt(32.W)) 29 | 30 | // Start writing when we have an entire block of data (128b) 31 | when (bitsFilled === 128.U) { 32 | startWrite := true.B 33 | } .elsewhen (bitsFilled === 0.U) { 34 | startWrite := false.B 35 | } 36 | 37 | // NOTE: Base addr will only be set once per block in memory controller FSM 38 | when (io.baseAddr.fire()) { 39 | addrReg := io.baseAddr.bits 40 | } 41 | // NOTE: The two statements below will NEVER concurrently fire (fire conditions prevent) 42 | when (dataQueue.io.deq.fire()) { 43 | wideData := wideData | (reverse << bitsFilled).asUInt() 44 | bitsFilled := bitsFilled + 32.U 45 | } 46 | when (io.dmaOutput.fire()) { 47 | addrReg := addrReg + io.dmaOutput.bits.totalBytes 48 | wideData := wideData >> (io.dmaOutput.bits.totalBytes * 8.U) 49 | bitsFilled := bitsFilled - (io.dmaOutput.bits.totalBytes * 8.U) 50 | } 51 | 52 | io.baseAddr.ready := ~startWrite 53 | dataQueue.io.deq.ready := ~startWrite 54 | dataQueue.io.enq <> io.dataIn 55 | io.dmaOutput.valid := (bitsFilled > 0.U) & startWrite 56 | io.dmaOutput.bits.addr := addrReg 57 | io.dmaOutput.bits.data := wideData 58 | when (beatBytes.U < 16.U) { 59 | io.dmaOutput.bits.totalBytes := beatBytes.U 60 | } .otherwise { 61 | // 16 bytes == 128 bits 62 | io.dmaOutput.bits.totalBytes := 16.U 63 | } 64 | doneReg := bitsFilled === 0.U 65 | io.done := doneReg 66 | 67 | // Reversing bytes 68 | toReverse := dataQueue.io.deq.bits 69 | reverse := (toReverse(7,0) << 24).asUInt() | (toReverse(15,8) << 16).asUInt() | (toReverse(23,16) << 8).asUInt() | toReverse(31,24).asUInt() 70 | } 71 | 72 | // Outputs data from DMA in 32bit chunks (for AES core) 73 | // WARNING: Assumes that beatBytes is at most 16 (anything greater will require us to mask/truncate input data) 74 | // Currently a safe assumption as our 32b RISC-V core will have beatBytes = 4 75 | class DMAOutputBuffer (beatBytes: Int) extends Module { 76 | val io = IO(new Bundle { 77 | val dmaInput = Flipped(Decoupled(UInt((beatBytes*8).W))) 78 | val dataOut = Decoupled(UInt(32.W)) 79 | }) 80 | 81 | val bitsFilled = RegInit(0.U(log2Ceil(256 + 1).W)) 82 | val wideData = RegInit(0.U(256.W)) // Max data we will ever read at a time is 256b 83 | val dataQueue = Module(new Queue(UInt(32.W), 8)) 84 | val reverse = Wire(UInt(32.W)) // Used to carry data with bytes reversed 85 | 86 | // NOTE: These two statements will NEVER concurrently fire (fire conditions prevent) 87 | when (dataQueue.io.enq.fire()) { 88 | bitsFilled := bitsFilled - 32.U 89 | wideData := wideData >> 32 90 | } 91 | when (io.dmaInput.fire()) { 92 | bitsFilled := bitsFilled + (beatBytes * 8).U 93 | wideData := wideData | (io.dmaInput.bits << bitsFilled).asUInt() 94 | } 95 | 96 | io.dmaInput.ready := bitsFilled < 32.U 97 | io.dataOut <> dataQueue.io.deq 98 | 99 | dataQueue.io.enq.valid := bitsFilled >= 32.U 100 | dataQueue.io.enq.bits := reverse 101 | 102 | // Reversing bytes 103 | reverse := (wideData(7,0) << 24).asUInt() | (wideData(15,8) << 16).asUInt() | (wideData(23,16) << 8).asUInt() | wideData(31,24).asUInt() 104 | } 105 | -------------------------------------------------------------------------------- /src/main/scala/Decoupler.scala: -------------------------------------------------------------------------------- 1 | package aes 2 | 3 | import chisel3._ 4 | import chisel3.util.Decoupled 5 | import chipsalliance.rocketchip.config.Parameters 6 | import freechips.rocketchip.tile.RoCCCommand 7 | import freechips.rocketchip.tile.RoCCResponse 8 | 9 | class RoCCDecouplerIO(implicit p: Parameters) extends Bundle { 10 | // System Signal 11 | val reset = Input(Bool()) 12 | 13 | // RoCCCommand + Other Signals 14 | val rocc_cmd = Flipped(Decoupled(new RoCCCommand)) 15 | val rocc_resp = Decoupled(new RoCCResponse) 16 | val rocc_busy = Output(Bool()) 17 | val rocc_intr = Output(Bool()) 18 | val rocc_excp = Input(Bool()) 19 | 20 | // Controller 21 | val ctrlIO = Flipped(new DecouplerControllerIO) 22 | } 23 | 24 | class RoCCDecoupler(implicit p: Parameters) extends Module { 25 | // Internal Registers 26 | val excp_valid_reg = RegInit(false.B) 27 | val key_valid_reg = RegInit(false.B) 28 | val key_size_reg = RegInit(0.U(1.W)) 29 | val key_addr_reg = RegInit(0.U(32.W)) 30 | val addr_valid_reg = RegInit(false.B) 31 | val src_addr_reg = RegInit(0.U(32.W)) 32 | val dest_addr_reg = RegInit(0.U(32.W)) 33 | val start_valid_reg = RegInit(false.B) 34 | val op_type_reg = RegInit(0.U(1.W)) 35 | val block_count_reg = RegInit(0.U(32.W)) 36 | val intrpt_en_reg = RegInit(0.U(1.W)) 37 | val resp_rd_reg = RegInit(0.U(5.W)) 38 | val resp_data_reg = RegInit(0.U(32.W)) 39 | val resp_valid_reg = RegInit(false.B) 40 | 41 | 42 | // Helper wires 43 | val reset_wire = Wire(Bool()) 44 | val funct = Wire(UInt(7.W)) 45 | val rs1_data = Wire(UInt(32.W)) 46 | val rs2_data = Wire(UInt(32.W)) 47 | val rd = Wire(UInt(5.W)) 48 | val busy = Wire(Bool()) 49 | 50 | // IO 51 | val io = IO(new RoCCDecouplerIO) 52 | 53 | // Unwrapping RoCCCommands 54 | // Does nothing when reset 55 | when (io.rocc_cmd.fire & ~reset_wire) { 56 | when (funct === AESISA.KEYSETUP128 & ~key_valid_reg) { 57 | key_valid_reg := true.B 58 | key_size_reg := 0.U 59 | key_addr_reg := rs1_data 60 | } .elsewhen (funct === AESISA.KEYSETUP256 & ~key_valid_reg) { // Cannot overwrite valid (edgecase where ctrl reads at same time) 61 | key_valid_reg := true.B 62 | key_size_reg := 1.U 63 | key_addr_reg := rs1_data 64 | } .elsewhen (funct === AESISA.ADDRESSLOAD & ~addr_valid_reg) { 65 | addr_valid_reg := true.B 66 | src_addr_reg := rs1_data 67 | dest_addr_reg := rs2_data 68 | } .elsewhen (funct === AESISA.ENCRYPTBLOCKS & ~start_valid_reg) { 69 | start_valid_reg := true.B 70 | op_type_reg := 1.U(1.W) 71 | block_count_reg := rs1_data 72 | intrpt_en_reg := rs2_data(0) 73 | } .elsewhen (funct === AESISA.DECRYPTBLOCKS & ~start_valid_reg) { 74 | start_valid_reg := true.B 75 | op_type_reg := 0.U(1.W) 76 | block_count_reg := rs1_data 77 | intrpt_en_reg := rs2_data(0) 78 | } .elsewhen (funct === AESISA.QUERYSTATUS & ~resp_valid_reg) { 79 | resp_rd_reg := rd 80 | resp_data_reg := busy 81 | resp_valid_reg := true.B 82 | } 83 | } 84 | 85 | // When an exception is received (only ignored when io.reset is high) 86 | when (io.rocc_excp & ~io.reset) { 87 | excp_valid_reg := true.B 88 | } 89 | 90 | // When register groups "fire" (ready && valid high) 91 | // Clear all valid when reset 92 | when ((io.ctrlIO.key_ready & io.ctrlIO.key_valid) | reset_wire) { 93 | key_valid_reg := false.B 94 | } 95 | when ((io.ctrlIO.addr_ready & io.ctrlIO.addr_valid) | reset_wire) { 96 | addr_valid_reg := false.B 97 | } 98 | when ((io.ctrlIO.start_ready & io.ctrlIO.start_valid) | reset_wire) { 99 | start_valid_reg := false.B 100 | } 101 | // Only ignored when io.reset is high 102 | when ((io.ctrlIO.excp_ready & io.ctrlIO.excp_valid) | io.reset) { 103 | excp_valid_reg := false.B 104 | } 105 | 106 | // When response fires 107 | // Clear valid when reset 108 | when (io.rocc_resp.fire | reset_wire) { 109 | resp_valid_reg := false.B 110 | } 111 | 112 | // Assigning other wires/signals 113 | io.ctrlIO.excp_valid := excp_valid_reg 114 | io.ctrlIO.key_valid := key_valid_reg 115 | io.ctrlIO.key_size := key_size_reg 116 | io.ctrlIO.key_addr := key_addr_reg 117 | io.ctrlIO.addr_valid := addr_valid_reg 118 | io.ctrlIO.src_addr := src_addr_reg 119 | io.ctrlIO.dest_addr := dest_addr_reg 120 | io.ctrlIO.start_valid := start_valid_reg 121 | io.ctrlIO.op_type := op_type_reg 122 | io.ctrlIO.block_count := block_count_reg 123 | io.ctrlIO.intrpt_en := intrpt_en_reg 124 | 125 | reset_wire := io.rocc_excp | io.reset 126 | funct := io.rocc_cmd.bits.inst.funct 127 | rs1_data := io.rocc_cmd.bits.rs1 128 | rs2_data := io.rocc_cmd.bits.rs2 129 | rd := io.rocc_cmd.bits.inst.rd 130 | busy := (start_valid_reg | io.ctrlIO.busy) 131 | 132 | // Should be always ready to process instructions 133 | io.rocc_cmd.ready := true.B 134 | io.rocc_resp.valid := resp_valid_reg 135 | io.rocc_resp.bits.rd := resp_rd_reg 136 | io.rocc_resp.bits.data := resp_data_reg 137 | io.rocc_busy := busy 138 | io.rocc_intr := io.ctrlIO.interrupt 139 | } 140 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AES RoCC Accelerator/Co-Processor --- EE290C Spring 2021 2 | AES RoCC Accelerator for baremetal machines. 3 | 4 | ## Team Members 5 | Anson Tsai (TsaiAnson), Eric Wu (ericwu13), Daniel Fan (gobears) 6 | 7 | ## Table of Contents 8 | [Brief Intro](#brief-intro) 9 | 10 | [Installation Instructions](#installation-instructions) 11 | 12 | ## Brief Intro 13 | The AES RoCC Accelerator enables hardware accelerated AES block cipher operations for baremetal machines. 14 | It is built using [Secwork's open-source AES core](https://github.com/secworks/aes) and additional hardware logic for RoCC integration. 15 | The accelerator also comes with a custom software stack that can be found in the EE290C software stack repo 16 | [here](https://bwrcrepo.eecs.berkeley.edu/EE290C_EE194_tstech28/ee290c-software-stack). 17 | 18 | To add the accelerator to a rocket configuration, simply import the `aes` project (installation instructions below) and add the accelerator configuration: 19 | ``` 20 | import aes._ 21 | 22 | ... 23 | 24 | class BaremetalRocketConfig extends Config( 25 | ... 26 | new aes.WithAESAccel ++ 27 | ... 28 | ) 29 | ``` 30 | 31 | ### Top-Level Diagram and Implementation 32 | The top-level accelerator block diagram is shown below: 33 | 34 | ![diagram](https://github.com/ucberkeley-ee290c/sp21-aes-rocc-accel/blob/master/diagrams/AESAccelTopLevelDiagram.png?raw=true) 35 | 36 | For a brief description, the AES RoCC Accelerator communicates with the rocket core via RISC-V instructions transmitted on `RoCCIO` interface and connects to the memory bus via a `TileLink` interface. 37 | Accelerator instructions from the CPU are processed by the `RoCC Decoupler`, which processes instructions in a non-blocking fashion and retains important information for the `Controller`. 38 | The `Controller` is responsible for taking the information from the `RoCC Decoupler` and operating the `SecWorks AES core` by performing the necessary setup steps and initiating the core. 39 | To fetch the input data (key and text data) and write back output data (encrypted/decrypted text), the controller sends memory requests to the DMA, which interfaces with the memory bus. 40 | 41 | ### More Documentation/Spec 42 | For more information on the implementation of the accelerator, documentation can be found in the chip spec 43 | [here](https://docs.google.com/document/d/1J9azqokkR0AsUUAkwU-hotsNtb-0KX5duK7d7f_3MhI/edit?usp=sharing) (you may need to request read access). 44 | 45 | 46 | ## Requirements 47 | The AES RoCC Accelerator utilizes a DMA generator and the chisel verification library. 48 | As such, this accelerator generator must be built alongside Chipyard. 49 | 50 | ### Installing Chipyard 51 | The Chipyard repo and installation instructions can be found at: https://github.com/ucb-bar/chipyard. 52 | Note that the installation instructions below require Chipyard version 1.3.0 or later. 53 | 54 | ### Installing Chisel Verification Library 55 | Note that we start in the chipyard root directory. 56 | ``` 57 | ~/chipyard> cd tools 58 | ~/chipyard/tools> git submodule add https://github.com/TsaiAnson/verif.git 59 | ``` 60 | 61 | ### Installing the DMA Generator 62 | Note that we start in the chipyard root directory. 63 | ``` 64 | ~/chipyard> cd generators 65 | ~/chipyard/generators> git submodule add https://github.com/ucberkeley-ee290c/sp21-dma 66 | ``` 67 | 68 | 69 | ### Installing the AES RoCC Accelerator Generator 70 | Note that we start in the chipyard root directory. 71 | ``` 72 | ~/chipyard> cd generators 73 | ~/chipyard/generators> git submodule add https://github.com/ucberkeley-ee290c/sp21-aes-rocc-accel 74 | ``` 75 | 76 | ### Modifying your build.sbt 77 | Add the following snippet to the end of `chipyard/build.sbt`: 78 | ``` 79 | val directoryLayout = Seq( 80 | scalaSource in Compile := baseDirectory.value / "src", 81 | javaSource in Compile := baseDirectory.value / "resources", 82 | resourceDirectory in Compile := baseDirectory.value / "resources", 83 | scalaSource in Test := baseDirectory.value / "test", 84 | javaSource in Test := baseDirectory.value / "resources", 85 | resourceDirectory in Test := baseDirectory.value / "resources", 86 | ) 87 | 88 | val verifSettings = Seq( 89 | resolvers ++= Seq( 90 | Resolver.sonatypeRepo("snapshots"), 91 | Resolver.sonatypeRepo("releases"), 92 | Resolver.mavenLocal 93 | ), 94 | scalacOptions := Seq("-deprecation", "-unchecked", "-Xsource:2.11", "-language:reflectiveCalls"), 95 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.3.1", 96 | libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.+" % "test" 97 | ) 98 | 99 | lazy val verifCore = (project in file("./tools/verif/core")) 100 | .settings(directoryLayout) 101 | .sourceDependency(chiselRef, chiselLib) 102 | .dependsOn(rocketchip, dsptools, `rocket-dsptools`) 103 | .settings(commonSettings) 104 | .settings(verifSettings) 105 | 106 | lazy val verifTL = (project in file("./tools/verif/tilelink")) 107 | .settings(directoryLayout) 108 | .sourceDependency(chiselRef, chiselLib) 109 | .dependsOn(verifCore) 110 | .settings(commonSettings) 111 | .settings(verifSettings) 112 | 113 | lazy val verifGemmini = (project in file("./tools/verif/cosim")) 114 | .settings(directoryLayout) 115 | .sourceDependency(chiselRef, chiselLib) 116 | .dependsOn(verifCore, verifTL) 117 | .settings(commonSettings) 118 | .settings(verifSettings) 119 | .settings(libraryDependencies += "com.google.protobuf" % "protobuf-java" % "3.14.0") 120 | .settings(libraryDependencies += "com.google.protobuf" % "protobuf-java-util" % "3.14.0") 121 | 122 | lazy val dma = (project in file("generators/dma")) 123 | .sourceDependency(chiselRef, chiselLib) 124 | .dependsOn(verifCore, verifTL, verifGemmini) 125 | .settings(commonSettings) 126 | 127 | lazy val aes = (project in file("generators/aes")) 128 | .sourceDependency(chiselRef, chiselLib) 129 | .dependsOn(verifCore, verifTL, verifGemmini, dma) 130 | .settings(commonSettings) 131 | .settings(verifSettings) 132 | ``` 133 | 134 | ### Compiling and running the tests 135 | Note that we start in the chipyard root directory. 136 | ``` 137 | ~/chipyard> cd sims/verilator 138 | ~/chipyard/sims/verilator> make launch-sbt 139 | sbt:chipyardRoot> project aes 140 | sbt:aes> compile // If you just want to compile src code 141 | sbt:aes> test:compile // If you just want to compile test code 142 | sbt:aes> testOnly aes.dcplrSanityTest // Compiles all dependencies and runs test 143 | ``` 144 | -------------------------------------------------------------------------------- /src/test/scala/TestUtils.scala: -------------------------------------------------------------------------------- 1 | package aes 2 | 3 | import chisel3._ 4 | import chipsalliance.rocketchip.config.Parameters 5 | import freechips.rocketchip.tile.RoCCCommand 6 | import verif.TLMemoryModel._ 7 | import verif.VerifBundleUtils.{RoCCCommandHelper, RoCCInstructionHelper} 8 | 9 | import javax.crypto.Cipher 10 | import javax.crypto.spec.SecretKeySpec 11 | import scala.util.Random 12 | 13 | package object AESTestUtils { 14 | // Helper methods for creating a RoCCCommand 15 | def keyLoad128(addr: BigInt)(implicit p: Parameters): RoCCCommand = 16 | RoCCCommandHelper(inst = RoCCInstructionHelper(xs1 = true.B), rs1 = addr.U) 17 | def keyLoad256(addr: BigInt)(implicit p: Parameters): RoCCCommand = 18 | RoCCCommandHelper(inst = RoCCInstructionHelper(funct = 1.U, xs1 = true.B), rs1 = addr.U) 19 | def addrLoad(src: BigInt, dest: BigInt)(implicit p: Parameters): RoCCCommand = 20 | RoCCCommandHelper(inst = RoCCInstructionHelper(funct = 2.U, xs1 = true.B, xs2 = true.B), rs1 = src.U, rs2 = dest.U) 21 | def encBlock(count: Int, interrupt_en: Int)(implicit p: Parameters): RoCCCommand = 22 | RoCCCommandHelper(inst = RoCCInstructionHelper(funct = 3.U, xs1 = true.B, xs2 = true.B), rs1 = count.U, rs2 = interrupt_en.U) 23 | def decBlock(count: Int, interrupt_en: Int)(implicit p: Parameters): RoCCCommand = 24 | RoCCCommandHelper(inst = RoCCInstructionHelper(funct = 4.U, xs1 = true.B, xs2 = true.B), rs1 = count.U, rs2 = interrupt_en.U) 25 | def getStatus(rd: Int)(implicit p: Parameters): RoCCCommand = { 26 | assert(rd < 32, s"RD register must be less than 32. Given: $rd") 27 | RoCCCommandHelper(inst = RoCCInstructionHelper(funct = 5.U, xd = true.B, rd = rd.U)) 28 | } 29 | 30 | // Generates random (but legal) addresses for key, source text, dest text 31 | // Legal key address: anything beatByte aligned 32 | // Legal data address: anything beatByte aligned and != key addr, and if src/dest overlap it must directly overlap (same address, destructive) 33 | // If prevKeyAddr != -1, then use that address 34 | // (keyAddr: BigInt, srcAddr: BigInt, destAddr: BigInt) 35 | def getRandomKeyTextAddr(textBlocks: Int, destructive: Boolean, prevKeyAddr: BigInt, beatBytes: Int, r: Random): (BigInt, BigInt, BigInt) = { 36 | assert(textBlocks > 0, s"# of text block must be at least 1. Given: $textBlocks") 37 | assert(beatBytes == 16, "TEMP: beatBytes must be 16 (see accelerator test for more details)") 38 | 39 | val keyAddr = if (prevKeyAddr != -1) prevKeyAddr else BigInt(32, r) & ~(beatBytes - 1) 40 | var srcAddr = BigInt(32, r) & ~(beatBytes - 1) 41 | while (keyAddr <= srcAddr && srcAddr <= (keyAddr + 32)) { 42 | srcAddr = BigInt(32, r) & ~(beatBytes - 1) 43 | } 44 | if (destructive) { 45 | (keyAddr, srcAddr, srcAddr) 46 | } else { 47 | var destAddr = BigInt(32, r) & ~(beatBytes - 1) 48 | while ((keyAddr <= srcAddr && srcAddr <= (keyAddr + 32)) || (srcAddr <= destAddr && destAddr <= (srcAddr + textBlocks * 16))) { 49 | destAddr = BigInt(32, r) & ~(beatBytes - 1) 50 | } 51 | (keyAddr, srcAddr, destAddr) 52 | } 53 | } 54 | 55 | // Helper method for creating TLMemoryModel state with initial AES Data (key, text) 56 | // Assumes all addresses are legal (beatBytes aligned) 57 | // Assumes keyData is 256 bits, and textData is 128 bits per block 58 | // NOTE: Reverses data to mimic how it will be stored in memory 59 | def getTLMemModelState(keyAddr: BigInt, keyData: BigInt, textAddr: BigInt, textData: Seq[BigInt], beatBytes: Int): State = { 60 | assert(beatBytes == 16, "TEMP: beatBytes must be 16 (see accelerator test for more details)") 61 | 62 | var initMem: Map[WordAddr, BigInt] = Map () 63 | val keyWordAddr = keyAddr / beatBytes 64 | val keyDataRev = BigInt(keyData.toByteArray.takeRight(32).reverse.padTo(32, 0.toByte)) 65 | initMem = initMem + (keyWordAddr.toLong -> (keyDataRev & BigInt("1" * 128, 2))) 66 | initMem = initMem + ((keyWordAddr + 1).toLong -> (keyDataRev >> 128)) 67 | 68 | val txtWordAddr = textAddr / beatBytes 69 | for (i <- textData.indices) { 70 | // NOTE: Prepend 0 byte s.t. it is interpreted as a positive (bug where if the last byte is FF it will be removed due to negative interpretation) 71 | initMem = initMem + ((txtWordAddr + i).toLong -> BigInt(Array(0.toByte) ++ textData(i).toByteArray.takeRight(16).reverse.padTo(16, 0.toByte))) 72 | } 73 | 74 | State.init(initMem, beatBytes) 75 | } 76 | 77 | // Generates random stimulus for AES Accelerator 78 | // (keyAddr: BigInt, keyData (256b post-padded): BigInt, srcAddr: BigInt, textData: Seq[BigInt], destAddr: BigInt, memState: TLMemModel.State) 79 | def genAESStim(keySize: Int, textBlocks: Int, destructive: Boolean, prevKeyAddr: BigInt, beatBytes: Int, r: Random): 80 | (BigInt, BigInt, BigInt, Seq[BigInt], BigInt, State) = { 81 | assert(beatBytes == 16, "TEMP: beatBytes must be 16 (see accelerator test for more details)") 82 | 83 | // Generate Addresses 84 | val addresses = getRandomKeyTextAddr(textBlocks, destructive, prevKeyAddr, beatBytes, r) 85 | val keyAddr = addresses._1 86 | val srcAddr = addresses._2 87 | val dstAddr = addresses._3 88 | 89 | // Generate key 90 | assert(keySize == 128 || keySize == 256, s"KeySize must be 128 OR 256. Given: $keySize") 91 | var keyData: BigInt = 0 92 | if (keySize == 128) { 93 | keyData = BigInt(128, r) << 128 94 | } else { 95 | keyData = BigInt(256, r) 96 | } 97 | 98 | // Generate Source Text 99 | val srcData = Seq.fill(textBlocks)(BigInt(128, r)) 100 | 101 | // Generate State 102 | val state = getTLMemModelState(keyAddr, keyData, srcAddr, srcData, beatBytes) 103 | 104 | (keyAddr, keyData, srcAddr, srcData, dstAddr, state) 105 | } 106 | 107 | // Conditional if last block of result data has been written 108 | // InitData should be 0 unless destructive 109 | def finishedWriting(state: State, destAddr: BigInt, txtBlocks: Int, initData: BigInt, beatBytes: Int): Boolean = { 110 | assert(beatBytes == 16, "TEMP: beatBytes must be 16 (see accelerator test for more details)") 111 | 112 | // Reversing since data is stored in reverse 113 | BigInt(Array(0.toByte) ++ read(state.mem, (destAddr/beatBytes + txtBlocks*(16/beatBytes) - 1).toLong, beatBytes, -1) 114 | .toByteArray.takeRight(16).reverse) != initData 115 | } 116 | 117 | // Checks if output matches standard AES library (ECB) 118 | def checkResult(keySize: Int, key: BigInt, srcData: Seq[BigInt], dstAddr: BigInt, encrypt: Boolean, state: State, beatBytes: Int): Boolean = { 119 | assert(beatBytes == 16, "TEMP: beatBytes must be 16 (see accelerator test for more details)") 120 | 121 | val cipher = AESECBCipher(keySize, key, encrypt) 122 | // NOTE: Additional reverse to match how data will be stored in memory 123 | // NOTE: Prepending a 0 byte in front so that results are interpreted as positives 124 | val results = srcData.map(x => BigInt(Array(0.toByte) ++ cipher.doFinal(x.toByteArray.reverse.padTo(16, 0.toByte).reverse.takeRight(16)).reverse)) 125 | 126 | var matched = true 127 | for (i <- results.indices) { 128 | val actual = read(state.mem, (dstAddr/beatBytes + i).toLong, beatBytes, -1) 129 | if (actual != results(i)) { 130 | println(s"Match failed for block $i. Expected: ${results(i).toString(16).toUpperCase()} " + 131 | s"Actual: ${actual.toString(16).toUpperCase()}") 132 | matched = false 133 | } 134 | } 135 | if (!matched) println("At least one encryption/decryption operation did not match the SW model. See above log.") 136 | matched 137 | } 138 | 139 | // Function that returns a cipher object (the SW model) 140 | def AESECBCipher(keySize: Int, key: BigInt, encrypt: Boolean): Cipher = { 141 | assert(keySize == 128 || keySize == 256, s"KeySize must be 128 OR 256. Given: $keySize") 142 | 143 | val cipher: Cipher = Cipher.getInstance("AES/ECB/NoPadding") 144 | // Properly format key 145 | val fmtKey = if (keySize == 128) key >> 128 else key 146 | val keyBArr = fmtKey.toByteArray.reverse.padTo(keySize/8, 0.toByte).reverse.takeRight(keySize/8) 147 | if (encrypt) { 148 | cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBArr, "AES")) 149 | } else { 150 | cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBArr, "AES")) 151 | } 152 | cipher 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/resources/vsrc/aes.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // aes.v 4 | // -------- 5 | // Top level wrapper for the AES block cipher core. 6 | // 7 | // 8 | // Author: Joachim Strombergson 9 | // Copyright (c) 2013, 2014 Secworks Sweden AB 10 | // All rights reserved. 11 | // 12 | // Redistribution and use in source and binary forms, with or 13 | // without modification, are permitted provided that the following 14 | // conditions are met: 15 | // 16 | // 1. Redistributions of source code must retain the above copyright 17 | // notice, this list of conditions and the following disclaimer. 18 | // 19 | // 2. Redistributions in binary form must reproduce the above copyright 20 | // notice, this list of conditions and the following disclaimer in 21 | // the documentation and/or other materials provided with the 22 | // distribution. 23 | // 24 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | // 37 | //====================================================================== 38 | 39 | module aes( 40 | // Clock and reset. 41 | input wire clk, 42 | input wire reset_n, 43 | 44 | // Control. 45 | input wire cs, 46 | input wire we, 47 | 48 | // Data ports. 49 | input wire [7 : 0] address, 50 | input wire [31 : 0] write_data, 51 | output wire [31 : 0] read_data 52 | ); 53 | 54 | //---------------------------------------------------------------- 55 | // Internal constant and parameter definitions. 56 | //---------------------------------------------------------------- 57 | localparam ADDR_NAME0 = 8'h00; 58 | localparam ADDR_NAME1 = 8'h01; 59 | localparam ADDR_VERSION = 8'h02; 60 | 61 | localparam ADDR_CTRL = 8'h08; 62 | localparam CTRL_INIT_BIT = 0; 63 | localparam CTRL_NEXT_BIT = 1; 64 | 65 | localparam ADDR_STATUS = 8'h09; 66 | localparam STATUS_READY_BIT = 0; 67 | localparam STATUS_VALID_BIT = 1; 68 | 69 | localparam ADDR_CONFIG = 8'h0a; 70 | localparam CTRL_ENCDEC_BIT = 0; 71 | localparam CTRL_KEYLEN_BIT = 1; 72 | 73 | localparam ADDR_KEY0 = 8'h10; 74 | localparam ADDR_KEY7 = 8'h17; 75 | 76 | localparam ADDR_BLOCK0 = 8'h20; 77 | localparam ADDR_BLOCK3 = 8'h23; 78 | 79 | localparam ADDR_RESULT0 = 8'h30; 80 | localparam ADDR_RESULT3 = 8'h33; 81 | 82 | localparam CORE_NAME0 = 32'h61657320; // "aes " 83 | localparam CORE_NAME1 = 32'h20202020; // " " 84 | localparam CORE_VERSION = 32'h302e3630; // "0.60" 85 | 86 | 87 | //---------------------------------------------------------------- 88 | // Registers including update variables and write enable. 89 | //---------------------------------------------------------------- 90 | reg init_reg; 91 | reg init_new; 92 | 93 | reg next_reg; 94 | reg next_new; 95 | 96 | reg encdec_reg; 97 | reg keylen_reg; 98 | reg config_we; 99 | 100 | reg [31 : 0] block_reg [0 : 3]; 101 | reg block_we; 102 | 103 | reg [31 : 0] key_reg [0 : 7]; 104 | reg key_we; 105 | 106 | reg [127 : 0] result_reg; 107 | reg valid_reg; 108 | reg ready_reg; 109 | 110 | 111 | //---------------------------------------------------------------- 112 | // Wires. 113 | //---------------------------------------------------------------- 114 | reg [31 : 0] tmp_read_data; 115 | 116 | wire core_encdec; 117 | wire core_init; 118 | wire core_next; 119 | wire core_ready; 120 | wire [255 : 0] core_key; 121 | wire core_keylen; 122 | wire [127 : 0] core_block; 123 | wire [127 : 0] core_result; 124 | wire core_valid; 125 | 126 | 127 | //---------------------------------------------------------------- 128 | // Concurrent connectivity for ports etc. 129 | //---------------------------------------------------------------- 130 | assign read_data = tmp_read_data; 131 | 132 | assign core_key = {key_reg[0], key_reg[1], key_reg[2], key_reg[3], 133 | key_reg[4], key_reg[5], key_reg[6], key_reg[7]}; 134 | 135 | assign core_block = {block_reg[0], block_reg[1], 136 | block_reg[2], block_reg[3]}; 137 | assign core_init = init_reg; 138 | assign core_next = next_reg; 139 | assign core_encdec = encdec_reg; 140 | assign core_keylen = keylen_reg; 141 | 142 | 143 | //---------------------------------------------------------------- 144 | // core instantiation. 145 | //---------------------------------------------------------------- 146 | aes_core core( 147 | .clk(clk), 148 | .reset_n(reset_n), 149 | 150 | .encdec(core_encdec), 151 | .init(core_init), 152 | .next(core_next), 153 | .ready(core_ready), 154 | 155 | .key(core_key), 156 | .keylen(core_keylen), 157 | 158 | .block(core_block), 159 | .result(core_result), 160 | .result_valid(core_valid) 161 | ); 162 | 163 | 164 | //---------------------------------------------------------------- 165 | // reg_update 166 | // Update functionality for all registers in the core. 167 | // All registers are positive edge triggered with asynchronous 168 | // active low reset. 169 | //---------------------------------------------------------------- 170 | always @ (posedge clk or negedge reset_n) 171 | begin : reg_update 172 | integer i; 173 | 174 | if (!reset_n) 175 | begin 176 | for (i = 0 ; i < 4 ; i = i + 1) 177 | block_reg[i] <= 32'h0; 178 | 179 | for (i = 0 ; i < 8 ; i = i + 1) 180 | key_reg[i] <= 32'h0; 181 | 182 | init_reg <= 1'b0; 183 | next_reg <= 1'b0; 184 | encdec_reg <= 1'b0; 185 | keylen_reg <= 1'b0; 186 | 187 | result_reg <= 128'h0; 188 | valid_reg <= 1'b0; 189 | ready_reg <= 1'b0; 190 | end 191 | else 192 | begin 193 | ready_reg <= core_ready; 194 | valid_reg <= core_valid; 195 | result_reg <= core_result; 196 | init_reg <= init_new; 197 | next_reg <= next_new; 198 | 199 | if (config_we) 200 | begin 201 | encdec_reg <= write_data[CTRL_ENCDEC_BIT]; 202 | keylen_reg <= write_data[CTRL_KEYLEN_BIT]; 203 | end 204 | 205 | if (key_we) 206 | key_reg[address[2 : 0]] <= write_data; 207 | 208 | if (block_we) 209 | block_reg[address[1 : 0]] <= write_data; 210 | end 211 | end // reg_update 212 | 213 | 214 | //---------------------------------------------------------------- 215 | // api 216 | // 217 | // The interface command decoding logic. 218 | //---------------------------------------------------------------- 219 | always @* 220 | begin : api 221 | init_new = 1'b0; 222 | next_new = 1'b0; 223 | config_we = 1'b0; 224 | key_we = 1'b0; 225 | block_we = 1'b0; 226 | tmp_read_data = 32'h0; 227 | 228 | if (cs) 229 | begin 230 | if (we) 231 | begin 232 | if (address == ADDR_CTRL) 233 | begin 234 | init_new = write_data[CTRL_INIT_BIT]; 235 | next_new = write_data[CTRL_NEXT_BIT]; 236 | end 237 | 238 | if (address == ADDR_CONFIG) 239 | config_we = 1'b1; 240 | 241 | if ((address >= ADDR_KEY0) && (address <= ADDR_KEY7)) 242 | key_we = 1'b1; 243 | 244 | if ((address >= ADDR_BLOCK0) && (address <= ADDR_BLOCK3)) 245 | block_we = 1'b1; 246 | end // if (we) 247 | 248 | else 249 | begin 250 | case (address) 251 | ADDR_NAME0: tmp_read_data = CORE_NAME0; 252 | ADDR_NAME1: tmp_read_data = CORE_NAME1; 253 | ADDR_VERSION: tmp_read_data = CORE_VERSION; 254 | ADDR_CTRL: tmp_read_data = {28'h0, keylen_reg, encdec_reg, next_reg, init_reg}; 255 | ADDR_STATUS: tmp_read_data = {30'h0, valid_reg, ready_reg}; 256 | 257 | default: 258 | begin 259 | end 260 | endcase // case (address) 261 | 262 | if ((address >= ADDR_RESULT0) && (address <= ADDR_RESULT3)) 263 | tmp_read_data = result_reg[(3 - (address - ADDR_RESULT0)) * 32 +: 32]; 264 | end 265 | end 266 | end // addr_decoder 267 | endmodule // aes 268 | 269 | //====================================================================== 270 | // EOF aes.v 271 | //====================================================================== 272 | -------------------------------------------------------------------------------- /src/main/resources/vsrc/aes_sbox.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // aes_sbox.v 4 | // ---------- 5 | // The AES S-box. Basically a 256 Byte ROM. This implementation 6 | // contains four parallel S-boxes to handle a 32 bit word. 7 | // 8 | // 9 | // Author: Joachim Strombergson 10 | // Copyright (c) 2014, Secworks Sweden AB 11 | // All rights reserved. 12 | // 13 | // Redistribution and use in source and binary forms, with or 14 | // without modification, are permitted provided that the following 15 | // conditions are met: 16 | // 17 | // 1. Redistributions of source code must retain the above copyright 18 | // notice, this list of conditions and the following disclaimer. 19 | // 20 | // 2. Redistributions in binary form must reproduce the above copyright 21 | // notice, this list of conditions and the following disclaimer in 22 | // the documentation and/or other materials provided with the 23 | // distribution. 24 | // 25 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 30 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 34 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 36 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | // 38 | //====================================================================== 39 | 40 | module aes_sbox( 41 | input wire [31 : 0] sboxw, 42 | output wire [31 : 0] new_sboxw 43 | ); 44 | 45 | 46 | //---------------------------------------------------------------- 47 | // The sbox array. 48 | //---------------------------------------------------------------- 49 | wire [7 : 0] sbox [0 : 255]; 50 | 51 | 52 | //---------------------------------------------------------------- 53 | // Four parallel muxes. 54 | //---------------------------------------------------------------- 55 | assign new_sboxw[31 : 24] = sbox[sboxw[31 : 24]]; 56 | assign new_sboxw[23 : 16] = sbox[sboxw[23 : 16]]; 57 | assign new_sboxw[15 : 08] = sbox[sboxw[15 : 08]]; 58 | assign new_sboxw[07 : 00] = sbox[sboxw[07 : 00]]; 59 | 60 | 61 | //---------------------------------------------------------------- 62 | // Creating the sbox array contents. 63 | //---------------------------------------------------------------- 64 | assign sbox[8'h00] = 8'h63; 65 | assign sbox[8'h01] = 8'h7c; 66 | assign sbox[8'h02] = 8'h77; 67 | assign sbox[8'h03] = 8'h7b; 68 | assign sbox[8'h04] = 8'hf2; 69 | assign sbox[8'h05] = 8'h6b; 70 | assign sbox[8'h06] = 8'h6f; 71 | assign sbox[8'h07] = 8'hc5; 72 | assign sbox[8'h08] = 8'h30; 73 | assign sbox[8'h09] = 8'h01; 74 | assign sbox[8'h0a] = 8'h67; 75 | assign sbox[8'h0b] = 8'h2b; 76 | assign sbox[8'h0c] = 8'hfe; 77 | assign sbox[8'h0d] = 8'hd7; 78 | assign sbox[8'h0e] = 8'hab; 79 | assign sbox[8'h0f] = 8'h76; 80 | assign sbox[8'h10] = 8'hca; 81 | assign sbox[8'h11] = 8'h82; 82 | assign sbox[8'h12] = 8'hc9; 83 | assign sbox[8'h13] = 8'h7d; 84 | assign sbox[8'h14] = 8'hfa; 85 | assign sbox[8'h15] = 8'h59; 86 | assign sbox[8'h16] = 8'h47; 87 | assign sbox[8'h17] = 8'hf0; 88 | assign sbox[8'h18] = 8'had; 89 | assign sbox[8'h19] = 8'hd4; 90 | assign sbox[8'h1a] = 8'ha2; 91 | assign sbox[8'h1b] = 8'haf; 92 | assign sbox[8'h1c] = 8'h9c; 93 | assign sbox[8'h1d] = 8'ha4; 94 | assign sbox[8'h1e] = 8'h72; 95 | assign sbox[8'h1f] = 8'hc0; 96 | assign sbox[8'h20] = 8'hb7; 97 | assign sbox[8'h21] = 8'hfd; 98 | assign sbox[8'h22] = 8'h93; 99 | assign sbox[8'h23] = 8'h26; 100 | assign sbox[8'h24] = 8'h36; 101 | assign sbox[8'h25] = 8'h3f; 102 | assign sbox[8'h26] = 8'hf7; 103 | assign sbox[8'h27] = 8'hcc; 104 | assign sbox[8'h28] = 8'h34; 105 | assign sbox[8'h29] = 8'ha5; 106 | assign sbox[8'h2a] = 8'he5; 107 | assign sbox[8'h2b] = 8'hf1; 108 | assign sbox[8'h2c] = 8'h71; 109 | assign sbox[8'h2d] = 8'hd8; 110 | assign sbox[8'h2e] = 8'h31; 111 | assign sbox[8'h2f] = 8'h15; 112 | assign sbox[8'h30] = 8'h04; 113 | assign sbox[8'h31] = 8'hc7; 114 | assign sbox[8'h32] = 8'h23; 115 | assign sbox[8'h33] = 8'hc3; 116 | assign sbox[8'h34] = 8'h18; 117 | assign sbox[8'h35] = 8'h96; 118 | assign sbox[8'h36] = 8'h05; 119 | assign sbox[8'h37] = 8'h9a; 120 | assign sbox[8'h38] = 8'h07; 121 | assign sbox[8'h39] = 8'h12; 122 | assign sbox[8'h3a] = 8'h80; 123 | assign sbox[8'h3b] = 8'he2; 124 | assign sbox[8'h3c] = 8'heb; 125 | assign sbox[8'h3d] = 8'h27; 126 | assign sbox[8'h3e] = 8'hb2; 127 | assign sbox[8'h3f] = 8'h75; 128 | assign sbox[8'h40] = 8'h09; 129 | assign sbox[8'h41] = 8'h83; 130 | assign sbox[8'h42] = 8'h2c; 131 | assign sbox[8'h43] = 8'h1a; 132 | assign sbox[8'h44] = 8'h1b; 133 | assign sbox[8'h45] = 8'h6e; 134 | assign sbox[8'h46] = 8'h5a; 135 | assign sbox[8'h47] = 8'ha0; 136 | assign sbox[8'h48] = 8'h52; 137 | assign sbox[8'h49] = 8'h3b; 138 | assign sbox[8'h4a] = 8'hd6; 139 | assign sbox[8'h4b] = 8'hb3; 140 | assign sbox[8'h4c] = 8'h29; 141 | assign sbox[8'h4d] = 8'he3; 142 | assign sbox[8'h4e] = 8'h2f; 143 | assign sbox[8'h4f] = 8'h84; 144 | assign sbox[8'h50] = 8'h53; 145 | assign sbox[8'h51] = 8'hd1; 146 | assign sbox[8'h52] = 8'h00; 147 | assign sbox[8'h53] = 8'hed; 148 | assign sbox[8'h54] = 8'h20; 149 | assign sbox[8'h55] = 8'hfc; 150 | assign sbox[8'h56] = 8'hb1; 151 | assign sbox[8'h57] = 8'h5b; 152 | assign sbox[8'h58] = 8'h6a; 153 | assign sbox[8'h59] = 8'hcb; 154 | assign sbox[8'h5a] = 8'hbe; 155 | assign sbox[8'h5b] = 8'h39; 156 | assign sbox[8'h5c] = 8'h4a; 157 | assign sbox[8'h5d] = 8'h4c; 158 | assign sbox[8'h5e] = 8'h58; 159 | assign sbox[8'h5f] = 8'hcf; 160 | assign sbox[8'h60] = 8'hd0; 161 | assign sbox[8'h61] = 8'hef; 162 | assign sbox[8'h62] = 8'haa; 163 | assign sbox[8'h63] = 8'hfb; 164 | assign sbox[8'h64] = 8'h43; 165 | assign sbox[8'h65] = 8'h4d; 166 | assign sbox[8'h66] = 8'h33; 167 | assign sbox[8'h67] = 8'h85; 168 | assign sbox[8'h68] = 8'h45; 169 | assign sbox[8'h69] = 8'hf9; 170 | assign sbox[8'h6a] = 8'h02; 171 | assign sbox[8'h6b] = 8'h7f; 172 | assign sbox[8'h6c] = 8'h50; 173 | assign sbox[8'h6d] = 8'h3c; 174 | assign sbox[8'h6e] = 8'h9f; 175 | assign sbox[8'h6f] = 8'ha8; 176 | assign sbox[8'h70] = 8'h51; 177 | assign sbox[8'h71] = 8'ha3; 178 | assign sbox[8'h72] = 8'h40; 179 | assign sbox[8'h73] = 8'h8f; 180 | assign sbox[8'h74] = 8'h92; 181 | assign sbox[8'h75] = 8'h9d; 182 | assign sbox[8'h76] = 8'h38; 183 | assign sbox[8'h77] = 8'hf5; 184 | assign sbox[8'h78] = 8'hbc; 185 | assign sbox[8'h79] = 8'hb6; 186 | assign sbox[8'h7a] = 8'hda; 187 | assign sbox[8'h7b] = 8'h21; 188 | assign sbox[8'h7c] = 8'h10; 189 | assign sbox[8'h7d] = 8'hff; 190 | assign sbox[8'h7e] = 8'hf3; 191 | assign sbox[8'h7f] = 8'hd2; 192 | assign sbox[8'h80] = 8'hcd; 193 | assign sbox[8'h81] = 8'h0c; 194 | assign sbox[8'h82] = 8'h13; 195 | assign sbox[8'h83] = 8'hec; 196 | assign sbox[8'h84] = 8'h5f; 197 | assign sbox[8'h85] = 8'h97; 198 | assign sbox[8'h86] = 8'h44; 199 | assign sbox[8'h87] = 8'h17; 200 | assign sbox[8'h88] = 8'hc4; 201 | assign sbox[8'h89] = 8'ha7; 202 | assign sbox[8'h8a] = 8'h7e; 203 | assign sbox[8'h8b] = 8'h3d; 204 | assign sbox[8'h8c] = 8'h64; 205 | assign sbox[8'h8d] = 8'h5d; 206 | assign sbox[8'h8e] = 8'h19; 207 | assign sbox[8'h8f] = 8'h73; 208 | assign sbox[8'h90] = 8'h60; 209 | assign sbox[8'h91] = 8'h81; 210 | assign sbox[8'h92] = 8'h4f; 211 | assign sbox[8'h93] = 8'hdc; 212 | assign sbox[8'h94] = 8'h22; 213 | assign sbox[8'h95] = 8'h2a; 214 | assign sbox[8'h96] = 8'h90; 215 | assign sbox[8'h97] = 8'h88; 216 | assign sbox[8'h98] = 8'h46; 217 | assign sbox[8'h99] = 8'hee; 218 | assign sbox[8'h9a] = 8'hb8; 219 | assign sbox[8'h9b] = 8'h14; 220 | assign sbox[8'h9c] = 8'hde; 221 | assign sbox[8'h9d] = 8'h5e; 222 | assign sbox[8'h9e] = 8'h0b; 223 | assign sbox[8'h9f] = 8'hdb; 224 | assign sbox[8'ha0] = 8'he0; 225 | assign sbox[8'ha1] = 8'h32; 226 | assign sbox[8'ha2] = 8'h3a; 227 | assign sbox[8'ha3] = 8'h0a; 228 | assign sbox[8'ha4] = 8'h49; 229 | assign sbox[8'ha5] = 8'h06; 230 | assign sbox[8'ha6] = 8'h24; 231 | assign sbox[8'ha7] = 8'h5c; 232 | assign sbox[8'ha8] = 8'hc2; 233 | assign sbox[8'ha9] = 8'hd3; 234 | assign sbox[8'haa] = 8'hac; 235 | assign sbox[8'hab] = 8'h62; 236 | assign sbox[8'hac] = 8'h91; 237 | assign sbox[8'had] = 8'h95; 238 | assign sbox[8'hae] = 8'he4; 239 | assign sbox[8'haf] = 8'h79; 240 | assign sbox[8'hb0] = 8'he7; 241 | assign sbox[8'hb1] = 8'hc8; 242 | assign sbox[8'hb2] = 8'h37; 243 | assign sbox[8'hb3] = 8'h6d; 244 | assign sbox[8'hb4] = 8'h8d; 245 | assign sbox[8'hb5] = 8'hd5; 246 | assign sbox[8'hb6] = 8'h4e; 247 | assign sbox[8'hb7] = 8'ha9; 248 | assign sbox[8'hb8] = 8'h6c; 249 | assign sbox[8'hb9] = 8'h56; 250 | assign sbox[8'hba] = 8'hf4; 251 | assign sbox[8'hbb] = 8'hea; 252 | assign sbox[8'hbc] = 8'h65; 253 | assign sbox[8'hbd] = 8'h7a; 254 | assign sbox[8'hbe] = 8'hae; 255 | assign sbox[8'hbf] = 8'h08; 256 | assign sbox[8'hc0] = 8'hba; 257 | assign sbox[8'hc1] = 8'h78; 258 | assign sbox[8'hc2] = 8'h25; 259 | assign sbox[8'hc3] = 8'h2e; 260 | assign sbox[8'hc4] = 8'h1c; 261 | assign sbox[8'hc5] = 8'ha6; 262 | assign sbox[8'hc6] = 8'hb4; 263 | assign sbox[8'hc7] = 8'hc6; 264 | assign sbox[8'hc8] = 8'he8; 265 | assign sbox[8'hc9] = 8'hdd; 266 | assign sbox[8'hca] = 8'h74; 267 | assign sbox[8'hcb] = 8'h1f; 268 | assign sbox[8'hcc] = 8'h4b; 269 | assign sbox[8'hcd] = 8'hbd; 270 | assign sbox[8'hce] = 8'h8b; 271 | assign sbox[8'hcf] = 8'h8a; 272 | assign sbox[8'hd0] = 8'h70; 273 | assign sbox[8'hd1] = 8'h3e; 274 | assign sbox[8'hd2] = 8'hb5; 275 | assign sbox[8'hd3] = 8'h66; 276 | assign sbox[8'hd4] = 8'h48; 277 | assign sbox[8'hd5] = 8'h03; 278 | assign sbox[8'hd6] = 8'hf6; 279 | assign sbox[8'hd7] = 8'h0e; 280 | assign sbox[8'hd8] = 8'h61; 281 | assign sbox[8'hd9] = 8'h35; 282 | assign sbox[8'hda] = 8'h57; 283 | assign sbox[8'hdb] = 8'hb9; 284 | assign sbox[8'hdc] = 8'h86; 285 | assign sbox[8'hdd] = 8'hc1; 286 | assign sbox[8'hde] = 8'h1d; 287 | assign sbox[8'hdf] = 8'h9e; 288 | assign sbox[8'he0] = 8'he1; 289 | assign sbox[8'he1] = 8'hf8; 290 | assign sbox[8'he2] = 8'h98; 291 | assign sbox[8'he3] = 8'h11; 292 | assign sbox[8'he4] = 8'h69; 293 | assign sbox[8'he5] = 8'hd9; 294 | assign sbox[8'he6] = 8'h8e; 295 | assign sbox[8'he7] = 8'h94; 296 | assign sbox[8'he8] = 8'h9b; 297 | assign sbox[8'he9] = 8'h1e; 298 | assign sbox[8'hea] = 8'h87; 299 | assign sbox[8'heb] = 8'he9; 300 | assign sbox[8'hec] = 8'hce; 301 | assign sbox[8'hed] = 8'h55; 302 | assign sbox[8'hee] = 8'h28; 303 | assign sbox[8'hef] = 8'hdf; 304 | assign sbox[8'hf0] = 8'h8c; 305 | assign sbox[8'hf1] = 8'ha1; 306 | assign sbox[8'hf2] = 8'h89; 307 | assign sbox[8'hf3] = 8'h0d; 308 | assign sbox[8'hf4] = 8'hbf; 309 | assign sbox[8'hf5] = 8'he6; 310 | assign sbox[8'hf6] = 8'h42; 311 | assign sbox[8'hf7] = 8'h68; 312 | assign sbox[8'hf8] = 8'h41; 313 | assign sbox[8'hf9] = 8'h99; 314 | assign sbox[8'hfa] = 8'h2d; 315 | assign sbox[8'hfb] = 8'h0f; 316 | assign sbox[8'hfc] = 8'hb0; 317 | assign sbox[8'hfd] = 8'h54; 318 | assign sbox[8'hfe] = 8'hbb; 319 | assign sbox[8'hff] = 8'h16; 320 | 321 | endmodule // aes_sbox 322 | 323 | //====================================================================== 324 | // EOF aes_sbox.v 325 | //====================================================================== 326 | -------------------------------------------------------------------------------- /src/main/resources/vsrc/aes_core.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // aes_core.v 4 | // ---------- 5 | // The AES core. This core supports key size of 128, and 256 bits. 6 | // Most of the functionality is within the submodules. 7 | // 8 | // 9 | // Author: Joachim Strombergson 10 | // Copyright (c) 2013, 2014, Secworks Sweden AB 11 | // All rights reserved. 12 | // 13 | // Redistribution and use in source and binary forms, with or 14 | // without modification, are permitted provided that the following 15 | // conditions are met: 16 | // 17 | // 1. Redistributions of source code must retain the above copyright 18 | // notice, this list of conditions and the following disclaimer. 19 | // 20 | // 2. Redistributions in binary form must reproduce the above copyright 21 | // notice, this list of conditions and the following disclaimer in 22 | // the documentation and/or other materials provided with the 23 | // distribution. 24 | // 25 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 30 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 34 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 36 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | // 38 | //====================================================================== 39 | 40 | module aes_core( 41 | input wire clk, 42 | input wire reset_n, 43 | 44 | input wire encdec, 45 | input wire init, 46 | input wire next, 47 | output wire ready, 48 | 49 | input wire [255 : 0] key, 50 | input wire keylen, 51 | 52 | input wire [127 : 0] block, 53 | output wire [127 : 0] result, 54 | output wire result_valid 55 | ); 56 | 57 | 58 | 59 | 60 | //---------------------------------------------------------------- 61 | // Internal constant and parameter definitions. 62 | //---------------------------------------------------------------- 63 | localparam CTRL_IDLE = 2'h0; 64 | localparam CTRL_INIT = 2'h1; 65 | localparam CTRL_NEXT = 2'h2; 66 | 67 | 68 | //---------------------------------------------------------------- 69 | // Registers including update variables and write enable. 70 | //---------------------------------------------------------------- 71 | reg [1 : 0] aes_core_ctrl_reg; 72 | reg [1 : 0] aes_core_ctrl_new; 73 | reg aes_core_ctrl_we; 74 | 75 | reg result_valid_reg; 76 | reg result_valid_new; 77 | reg result_valid_we; 78 | 79 | reg ready_reg; 80 | reg ready_new; 81 | reg ready_we; 82 | 83 | 84 | //---------------------------------------------------------------- 85 | // Wires. 86 | //---------------------------------------------------------------- 87 | reg init_state; 88 | 89 | wire [127 : 0] round_key; 90 | wire key_ready; 91 | 92 | reg enc_next; 93 | wire [3 : 0] enc_round_nr; 94 | wire [127 : 0] enc_new_block; 95 | wire enc_ready; 96 | wire [31 : 0] enc_sboxw; 97 | 98 | reg dec_next; 99 | wire [3 : 0] dec_round_nr; 100 | wire [127 : 0] dec_new_block; 101 | wire dec_ready; 102 | 103 | reg [127 : 0] muxed_new_block; 104 | reg [3 : 0] muxed_round_nr; 105 | reg muxed_ready; 106 | 107 | wire [31 : 0] keymem_sboxw; 108 | 109 | reg [31 : 0] muxed_sboxw; 110 | wire [31 : 0] new_sboxw; 111 | 112 | 113 | //---------------------------------------------------------------- 114 | // Instantiations. 115 | //---------------------------------------------------------------- 116 | aes_encipher_block enc_block( 117 | .clk(clk), 118 | .reset_n(reset_n), 119 | 120 | .next(enc_next), 121 | 122 | .keylen(keylen), 123 | .round(enc_round_nr), 124 | .round_key(round_key), 125 | 126 | .sboxw(enc_sboxw), 127 | .new_sboxw(new_sboxw), 128 | 129 | .block(block), 130 | .new_block(enc_new_block), 131 | .ready(enc_ready) 132 | ); 133 | 134 | 135 | aes_decipher_block dec_block( 136 | .clk(clk), 137 | .reset_n(reset_n), 138 | 139 | .next(dec_next), 140 | 141 | .keylen(keylen), 142 | .round(dec_round_nr), 143 | .round_key(round_key), 144 | 145 | .block(block), 146 | .new_block(dec_new_block), 147 | .ready(dec_ready) 148 | ); 149 | 150 | 151 | aes_key_mem keymem( 152 | .clk(clk), 153 | .reset_n(reset_n), 154 | 155 | .key(key), 156 | .keylen(keylen), 157 | .init(init), 158 | 159 | .round(muxed_round_nr), 160 | .round_key(round_key), 161 | .ready(key_ready), 162 | 163 | .sboxw(keymem_sboxw), 164 | .new_sboxw(new_sboxw) 165 | ); 166 | 167 | 168 | aes_sbox sbox_inst(.sboxw(muxed_sboxw), .new_sboxw(new_sboxw)); 169 | 170 | 171 | //---------------------------------------------------------------- 172 | // Concurrent connectivity for ports etc. 173 | //---------------------------------------------------------------- 174 | assign ready = ready_reg; 175 | assign result = muxed_new_block; 176 | assign result_valid = result_valid_reg; 177 | 178 | 179 | //---------------------------------------------------------------- 180 | // reg_update 181 | // 182 | // Update functionality for all registers in the core. 183 | // All registers are positive edge triggered with asynchronous 184 | // active low reset. All registers have write enable. 185 | //---------------------------------------------------------------- 186 | always @ (posedge clk or negedge reset_n) 187 | begin: reg_update 188 | if (!reset_n) 189 | begin 190 | result_valid_reg <= 1'b0; 191 | ready_reg <= 1'b1; 192 | aes_core_ctrl_reg <= CTRL_IDLE; 193 | end 194 | else 195 | begin 196 | if (result_valid_we) 197 | result_valid_reg <= result_valid_new; 198 | 199 | if (ready_we) 200 | ready_reg <= ready_new; 201 | 202 | if (aes_core_ctrl_we) 203 | aes_core_ctrl_reg <= aes_core_ctrl_new; 204 | end 205 | end // reg_update 206 | 207 | 208 | //---------------------------------------------------------------- 209 | // sbox_mux 210 | // 211 | // Controls which of the encipher datapath or the key memory 212 | // that gets access to the sbox. 213 | //---------------------------------------------------------------- 214 | always @* 215 | begin : sbox_mux 216 | if (init_state) 217 | begin 218 | muxed_sboxw = keymem_sboxw; 219 | end 220 | else 221 | begin 222 | muxed_sboxw = enc_sboxw; 223 | end 224 | end // sbox_mux 225 | 226 | 227 | //---------------------------------------------------------------- 228 | // encdex_mux 229 | // 230 | // Controls which of the datapaths that get the next signal, have 231 | // access to the memory as well as the block processing result. 232 | //---------------------------------------------------------------- 233 | always @* 234 | begin : encdec_mux 235 | enc_next = 1'b0; 236 | dec_next = 1'b0; 237 | 238 | if (encdec) 239 | begin 240 | // Encipher operations 241 | enc_next = next; 242 | muxed_round_nr = enc_round_nr; 243 | muxed_new_block = enc_new_block; 244 | muxed_ready = enc_ready; 245 | end 246 | else 247 | begin 248 | // Decipher operations 249 | dec_next = next; 250 | muxed_round_nr = dec_round_nr; 251 | muxed_new_block = dec_new_block; 252 | muxed_ready = dec_ready; 253 | end 254 | end // encdec_mux 255 | 256 | 257 | //---------------------------------------------------------------- 258 | // aes_core_ctrl 259 | // 260 | // Control FSM for aes core. Basically tracks if we are in 261 | // key init, encipher or decipher modes and connects the 262 | // different submodules to shared resources and interface ports. 263 | //---------------------------------------------------------------- 264 | always @* 265 | begin : aes_core_ctrl 266 | init_state = 1'b0; 267 | ready_new = 1'b0; 268 | ready_we = 1'b0; 269 | result_valid_new = 1'b0; 270 | result_valid_we = 1'b0; 271 | aes_core_ctrl_new = CTRL_IDLE; 272 | aes_core_ctrl_we = 1'b0; 273 | 274 | case (aes_core_ctrl_reg) 275 | CTRL_IDLE: 276 | begin 277 | if (init) 278 | begin 279 | init_state = 1'b1; 280 | ready_new = 1'b0; 281 | ready_we = 1'b1; 282 | result_valid_new = 1'b0; 283 | result_valid_we = 1'b1; 284 | aes_core_ctrl_new = CTRL_INIT; 285 | aes_core_ctrl_we = 1'b1; 286 | end 287 | else if (next) 288 | begin 289 | init_state = 1'b0; 290 | ready_new = 1'b0; 291 | ready_we = 1'b1; 292 | result_valid_new = 1'b0; 293 | result_valid_we = 1'b1; 294 | aes_core_ctrl_new = CTRL_NEXT; 295 | aes_core_ctrl_we = 1'b1; 296 | end 297 | end 298 | 299 | CTRL_INIT: 300 | begin 301 | init_state = 1'b1; 302 | 303 | if (key_ready) 304 | begin 305 | ready_new = 1'b1; 306 | ready_we = 1'b1; 307 | aes_core_ctrl_new = CTRL_IDLE; 308 | aes_core_ctrl_we = 1'b1; 309 | end 310 | end 311 | 312 | CTRL_NEXT: 313 | begin 314 | init_state = 1'b0; 315 | 316 | if (muxed_ready) 317 | begin 318 | ready_new = 1'b1; 319 | ready_we = 1'b1; 320 | result_valid_new = 1'b1; 321 | result_valid_we = 1'b1; 322 | aes_core_ctrl_new = CTRL_IDLE; 323 | aes_core_ctrl_we = 1'b1; 324 | end 325 | end 326 | 327 | default: 328 | begin 329 | 330 | end 331 | endcase // case (aes_core_ctrl_reg) 332 | 333 | end // aes_core_ctrl 334 | endmodule // aes_core 335 | 336 | //====================================================================== 337 | // EOF aes_core.v 338 | //====================================================================== 339 | -------------------------------------------------------------------------------- /src/test/scala/AccelTopTest.scala: -------------------------------------------------------------------------------- 1 | package aes 2 | 3 | import AESTestUtils._ 4 | import chisel3._ 5 | import chiseltest._ 6 | import chiseltest.internal.{VerilatorBackendAnnotation, WriteVcdAnnotation} 7 | import chiseltest.experimental.TestOptionBuilder._ 8 | import org.scalatest.flatspec.AnyFlatSpec 9 | import freechips.rocketchip.config.Parameters 10 | import freechips.rocketchip.diplomacy.LazyModule 11 | import freechips.rocketchip.tile.{RoCCCommand, RoCCResponse} 12 | import verif.TLMemoryModel.{State, WordAddr, read} 13 | import verif._ 14 | 15 | 16 | class AccelTopTest extends AnyFlatSpec with ChiselScalatestTester { 17 | // Hardcoded, since only beatBytes == 16 works for now. Seems like it's a hardcoded value for the DCache 18 | val beatBytes = 16 19 | implicit val p: Parameters = VerifTestUtils.getVerifParameters(xLen = 32, beatBytes = beatBytes) // Testing for our 32b RISC-V chip 20 | val r = new scala.util.Random 21 | 22 | // Temporary storage for keys in key-reusal case 23 | var prev_key: BigInt = 0 24 | var prev_key_addr: BigInt = 0 25 | 26 | def testAccelerator(dut: AESAccelStandaloneBlock, clock: Clock, keySize: Int, encdec: Int, interrupt: Int, rounds: Int, reuse_key_en: Boolean): Boolean = { 27 | assert(keySize == 128 || keySize == 256 || keySize == -1, s"KeySize must be 128, 256, or -1 (random). Given: $keySize") 28 | assert(encdec == 0 || encdec == 1 || encdec == -1, s"ENCDEC must be 1 (encrypt), 0 (decrypt), or -1 (random). Given: $encdec") 29 | assert(interrupt == 0 || interrupt == 1 || interrupt == -1, s"INTERRUPT must be 1 (enable), 0 (disable), or -1 (random). Given: $interrupt") 30 | 31 | // RoCCCommand driver + RoCCResponse receiver 32 | val driver = new DecoupledDriverMaster[RoCCCommand](clock, dut.module.io.cmd) 33 | val txProto = new DecoupledTX(new RoCCCommand()) 34 | val monitor = new DecoupledMonitor[RoCCResponse](clock, dut.module.io.resp) 35 | val receiver = new DecoupledDriverSlave[RoCCResponse](clock, dut.module.io.resp, 0) 36 | 37 | // Mock Memory 38 | val slaveFn = new TLMemoryModel(dut.to_mem.params) 39 | val slaveModel = new TLDriverSlave(clock, dut.to_mem, slaveFn, TLMemoryModel.State.empty()) 40 | val slaveMonitor = new TLMonitor(clock, dut.to_mem) 41 | 42 | var cycleCount = 0 43 | var blocksProcessed = 0 44 | var allPass = true 45 | var actualKeySize = 128 46 | var encrypt = true 47 | var interrupt_en = 0 48 | var reuse_key = false 49 | 50 | for (i <- 0 until rounds) { 51 | // Output: (1: keyAddr, 2: keyData (256b post-padded), 3: srcAddr, 4: textData, 5: destAddr, 6: memState) 52 | val destructive = r.nextBoolean() 53 | if (keySize == -1) actualKeySize = if (r.nextBoolean()) 128 else 256 54 | else actualKeySize = keySize 55 | if (encdec == -1) encrypt = r.nextBoolean() 56 | else encrypt = encdec == 1 57 | if (interrupt == -1) interrupt_en = r.nextInt(2) 58 | 59 | val stim = genAESStim(actualKeySize, r.nextInt(10) + 1, destructive = destructive, if (reuse_key) prev_key_addr else BigInt(-1), beatBytes, r) 60 | slaveModel.state = stim._6 61 | 62 | // Randomize reuse_key (cannot reuse on first enc/dec, key expansion required) 63 | if (i != 0 && reuse_key_en) reuse_key = r.nextBoolean() 64 | if (!reuse_key) { 65 | prev_key_addr = stim._1 66 | prev_key = stim._2 67 | } 68 | 69 | // // Debug Printing 70 | // println(s"Debug: key size: $actualKeySize") 71 | // println(s"Debug: encdec: $encrypt") 72 | // println(s"Debug: $stim") 73 | // println(s"Debug: Reuse key $reuse_key") 74 | // println(s"Debug: Destructive $destructive") 75 | 76 | var inputCmd = Seq[DecoupledTX[RoCCCommand]]() 77 | // Key load instruction 78 | if (!reuse_key) { 79 | if (actualKeySize == 128) inputCmd = inputCmd :+ txProto.tx(keyLoad128(stim._1)) 80 | else inputCmd = inputCmd :+ txProto.tx(keyLoad256(stim._1)) 81 | } 82 | // Address load instruction 83 | inputCmd = inputCmd :+ txProto.tx(addrLoad(stim._3, stim._5)) 84 | // Encrypt/Decrypt instruction 85 | if (encrypt) inputCmd = inputCmd :+ txProto.tx(encBlock(stim._4.length, interrupt_en)) 86 | else inputCmd = inputCmd :+ txProto.tx(decBlock(stim._4.length, interrupt_en)) 87 | // Poll instruction 88 | inputCmd = inputCmd :+ txProto.tx(getStatus(1)) // RD hardcoded as not affected by accel. 89 | driver.push(inputCmd) 90 | 91 | // Each block takes at least 50 cycles, will auto-increment 92 | clock.step(50 * stim._4.length) 93 | cycleCount += 50 * stim._4.length 94 | 95 | // Checking busy status (should still be busy) 96 | assert(dut.module.io.busy.peek().litToBoolean, "Accelerator de-asserted busy before interrupt was raised.") 97 | 98 | // Sending additional poll instruction (should still be busy) 99 | driver.push(Seq(txProto.tx(getStatus(1)))) 100 | 101 | if (interrupt_en == 1) { 102 | while (!dut.module.io.interrupt.peek().litToBoolean) { 103 | clock.step() 104 | cycleCount += 1 105 | } 106 | clock.step() // Note: Interrupt and Busy are raised at the same time 107 | assert(!dut.module.io.busy.peek().litToBoolean, "Accelerator is still busy after interrupt was raised.") 108 | } else { 109 | val initData = if (destructive) stim._4.last else BigInt(0) 110 | while(!finishedWriting(slaveModel.state, stim._5, stim._4.length, initData, beatBytes)) { 111 | clock.step() 112 | cycleCount += 1 113 | } 114 | clock.step(5) // Few cycles delay for AccessAck to propagate back and busy to be de-asserted 115 | assert(!dut.module.io.busy.peek().litToBoolean, "Accelerator is still busy when data was written back.") 116 | } 117 | 118 | // Sending additional poll instruction (should be non-busy) 119 | driver.push(Seq(txProto.tx(getStatus(1)))) 120 | clock.step(10) 121 | 122 | // Checking data result 123 | if (reuse_key) allPass &= checkResult(actualKeySize, prev_key, stim._4, stim._5, encrypt = encrypt, slaveModel.state, beatBytes) 124 | else allPass &= checkResult(actualKeySize, stim._2, stim._4, stim._5, encrypt = encrypt, slaveModel.state, beatBytes) 125 | 126 | // Checking poll responses (first 2 should be busy, last one should be non-busy) 127 | val resp = monitor.monitoredTransactions 128 | assert(resp.size == 3, s"Accelerator responded with ${resp.size} status messages (expected 3).") 129 | assert(resp(0).data.data.litValue() == 1, s"Accelerator responded non-busy for first status query (expected busy).") 130 | assert(resp(1).data.data.litValue() == 1, s"Accelerator responded non-busy for second status query (expected busy).") 131 | assert(resp(2).data.data.litValue() == 0, s"Accelerator responded busy for third status query (expected non-busy).") 132 | monitor.clearMonitoredTransactions() 133 | 134 | blocksProcessed += stim._4.length 135 | } 136 | 137 | println(s"====== :Performance stats: ======") 138 | println(s"Blocks Processed: $blocksProcessed") 139 | println(s"Cycles Elapsed: $cycleCount") 140 | println(s"Average Cycles/Block: ${cycleCount/blocksProcessed.toDouble}") 141 | allPass 142 | } 143 | 144 | // // Elaborate to see if anything structure-wise broke 145 | // it should "elaborate the accelerator" in { 146 | // val dut = LazyModule(new AESAccelStandaloneBlock(beatBytes)) 147 | // // Requires verilator backend! (For verilog blackbox files) 148 | // test(dut.module).withAnnotations(Seq(VerilatorBackendAnnotation, WriteVcdAnnotation)) { c => 149 | // assert(true) 150 | // } 151 | // } 152 | 153 | it should "Test 128b AES Encryption" in { 154 | val dut = LazyModule(new AESAccelStandaloneBlock(beatBytes)) 155 | test(dut.module).withAnnotations(Seq(VerilatorBackendAnnotation, WriteVcdAnnotation)) { c => 156 | val result = testAccelerator(dut, c.clock, keySize = 128, encdec = 1, interrupt = -1, rounds = 20, reuse_key_en = true) 157 | assert(result) 158 | } 159 | } 160 | 161 | it should "Test 128b AES Decryption" in { 162 | val dut = LazyModule(new AESAccelStandaloneBlock(beatBytes)) 163 | test(dut.module).withAnnotations(Seq(VerilatorBackendAnnotation, WriteVcdAnnotation)) { c => 164 | val result = testAccelerator(dut, c.clock, keySize = 128, encdec = 0, interrupt = 0, rounds = 20, reuse_key_en = true) 165 | assert(result) 166 | } 167 | } 168 | 169 | it should "Test 256b AES Encryption" in { 170 | val dut = LazyModule(new AESAccelStandaloneBlock(beatBytes)) 171 | test(dut.module).withAnnotations(Seq(VerilatorBackendAnnotation, WriteVcdAnnotation)) { c => 172 | val result = testAccelerator(dut, c.clock, keySize = 256, encdec = 1, interrupt = 0, rounds = 20, reuse_key_en = true) 173 | assert(result) 174 | } 175 | } 176 | 177 | it should "Test 256b AES Decryption" in { 178 | val dut = LazyModule(new AESAccelStandaloneBlock(beatBytes)) 179 | test(dut.module).withAnnotations(Seq(VerilatorBackendAnnotation, WriteVcdAnnotation)) { c => 180 | val result = testAccelerator(dut, c.clock, keySize = 256, encdec = 0, interrupt = 0, rounds = 20, reuse_key_en = true) 181 | assert(result) 182 | } 183 | } 184 | 185 | it should "Test Mixed 128/256 AES Encryption/Decryption" in { 186 | val dut = LazyModule(new AESAccelStandaloneBlock(beatBytes)) 187 | test(dut.module).withAnnotations(Seq(VerilatorBackendAnnotation, WriteVcdAnnotation)) { c => 188 | // Cannot reuse-key as keys may be different sizes 189 | val result = testAccelerator(dut, c.clock, keySize = -1, encdec = -1, interrupt = 0, rounds = 20, reuse_key_en = false) 190 | assert(result) 191 | } 192 | } 193 | 194 | 195 | // // Debug sanity test 196 | // // 128B Key: 256'h2b7e151628aed2a6abf7158809cf4f3c00000000000000000000000000000000 197 | // // plaintext: 128'h6bc1bee22e409f96e93d7e117393172a 198 | // // ciphertext: 128'h3ad77bb40d7a3660a89ecaf32466ef97 199 | // it should "debug AES sanity check" in { 200 | // val dut = LazyModule(new AESAccelStandaloneBlock(beatBytes)) 201 | // test(dut.module).withAnnotations(Seq(VerilatorBackendAnnotation, WriteVcdAnnotation)) { c => 202 | // // RoCCCommand driver + RoCCResponse receiver 203 | // val driver = new DecoupledDriverMaster[RoCCCommand](c.clock, dut.module.io.cmd) 204 | // val txProto = new DecoupledTX(new RoCCCommand()) 205 | // val monitor = new DecoupledMonitor[RoCCResponse](c.clock, dut.module.io.resp) 206 | // val receiver = new DecoupledDriverSlave[RoCCResponse](c.clock, dut.module.io.resp, 0) 207 | // 208 | // // Mock Memory 209 | // val slaveFn = new TLMemoryModel(dut.to_mem.params) 210 | // val slaveModel = new TLDriverSlave(c.clock, dut.to_mem, slaveFn, TLMemoryModel.State.empty()) 211 | // val slaveMonitor = new TLMonitor(c.clock, dut.to_mem) 212 | // 213 | // val keyData = BigInt("2b7e151628aed2a6abf7158809cf4f3c00000000000000000000000000000000", 16) 214 | // var initMem: Map[WordAddr, BigInt] = Map () 215 | // val keyDataRev = BigInt(keyData.toByteArray.reverse) 216 | // initMem = initMem + (0.toLong -> (keyDataRev & BigInt("1" * 128, 2))) 217 | // initMem = initMem + (1.toLong -> (keyDataRev >> 128)) 218 | // val textData = BigInt("6bc1bee22e409f96e93d7e117393172a", 16) 219 | // initMem = initMem + (2.toLong -> BigInt(textData.toByteArray.reverse)) 220 | // slaveModel.state = State.init(initMem, beatBytes) 221 | // 222 | // val input = Seq( 223 | // txProto.tx(keyLoad128(0x0)), 224 | // txProto.tx(addrLoad(0x20, 0x30)), 225 | // txProto.tx(encBlock(1, 0)) 226 | // ) 227 | // driver.push(input) 228 | // c.clock.step(50) 229 | // 230 | // while(!finishedWriting(slaveModel.state, 0x30, 1, 0, beatBytes)) { 231 | // c.clock.step() 232 | // } 233 | // c.clock.step(5) // Few cycles delay for AccessAck to propagate back and busy to be de-asserted 234 | // assert(!dut.module.io.busy.peek().litToBoolean, "Accelerator is still busy when data was written back.") 235 | // 236 | // val actual = read(slaveModel.state.mem, 3.toLong, beatBytes, -1) 237 | // println(s"RESULT: ${actual.toString(16)}") 238 | // assert(actual == BigInt(Array(0.toByte) ++ BigInt("3ad77bb40d7a3660a89ecaf32466ef97", 16).toByteArray.takeRight(16).reverse)) 239 | // } 240 | // } 241 | } -------------------------------------------------------------------------------- /src/main/scala/Controller.scala: -------------------------------------------------------------------------------- 1 | package aes 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | import chipsalliance.rocketchip.config.Parameters 6 | 7 | class AESControllerIO(addrBits: Int, beatBytes: Int)(implicit p: Parameters) extends Bundle { 8 | // System 9 | val reset = Input(Bool()) 10 | 11 | // RoCC Decoupler 12 | val dcplrIO = new DecouplerControllerIO 13 | val dmem = new ControllerDMAIO(addrBits, beatBytes) 14 | 15 | // AES Core 16 | val aesCoreIO = Flipped(new AESCoreIO) 17 | 18 | // Testing Signals have been removed 19 | // See commit 82a030730220a45974db77fce7da674ba0338676 for last commit before change 20 | } 21 | 22 | class AESController(addrBits: Int, beatBytes: Int)(implicit p: Parameters) extends Module { val io = IO(new AESControllerIO(addrBits, beatBytes)) 23 | 24 | // Internal Registers 25 | val size_reg = RegInit(0.U(32.W)) 26 | val key_addr_reg = RegInit(0.U(32.W)) 27 | val key_size_reg = RegInit(0.U(1.W)) 28 | val src_addr_reg = RegInit(0.U(32.W)) 29 | val dest_addr_reg = RegInit(0.U(32.W)) 30 | val counter_reg = RegInit(0.U(4.W)) 31 | val mem_target_reg = RegInit(0.U(4.W)) 32 | val blks_remain_reg = RegInit(0.U(32.W)) 33 | val intrpt_en_reg = RegInit(false.B) 34 | val ready_check_reg = RegInit(false.B) 35 | 36 | 37 | // States (C - Controller, M - Memory) 38 | val cState = RegInit(CtrlState.sIdle) 39 | val cStateWire = WireDefault(cState) 40 | val mState = RegInit(MemState.sIdle) 41 | val mStateWire = WireDefault(mState) 42 | 43 | // Helper Wires 44 | val addrWire = Wire(UInt(32.W)) 45 | val data_wr_done = mState === MemState.sIdle 46 | val data_ld_done = mState === MemState.sIdle 47 | val enqueue_data = Reg(UInt(32.W)) 48 | 49 | // Default DecouplerIO Signals 50 | io.dcplrIO.key_ready := false.B 51 | io.dcplrIO.addr_ready := false.B 52 | io.dcplrIO.start_ready := false.B 53 | io.dcplrIO.excp_ready := true.B 54 | io.dcplrIO.interrupt := false.B 55 | 56 | // Default DMA readReq Values 57 | io.dmem.readReq.valid := false.B 58 | io.dmem.readReq.bits.addr := 0.U 59 | io.dmem.readReq.bits.totalBytes := 0.U 60 | io.dmem.readResp.ready := false.B 61 | 62 | // Default AESCoreIO Signals 63 | io.aesCoreIO.we := false.B 64 | io.aesCoreIO.cs := false.B 65 | io.aesCoreIO.write_data := 0.U 66 | io.aesCoreIO.address := 0.U 67 | 68 | 69 | // Default Queue Signals 70 | val dequeue = Module(new DMAOutputBuffer(beatBytes)) 71 | dequeue.io.dataOut.ready := mState === MemState.sReadIntoAES 72 | dequeue.io.dmaInput <> io.dmem.readRespQueue 73 | 74 | val enqueue = Module(new DMAInputBuffer(addrBits, beatBytes)) 75 | enqueue.io.dataIn.valid := false.B 76 | enqueue_data := io.aesCoreIO.read_data 77 | enqueue.io.baseAddr.bits := addrWire 78 | enqueue.io.baseAddr.valid := (mState === MemState.sWriteReq) & (counter_reg === 0.U) 79 | enqueue.io.dataIn.bits := enqueue_data 80 | io.dmem.writeReq <> enqueue.io.dmaOutput 81 | 82 | 83 | when (cState === CtrlState.sKeySetup) { 84 | addrWire := key_addr_reg 85 | } .elsewhen (cState === CtrlState.sDataSetup) { 86 | addrWire := src_addr_reg 87 | } .elsewhen (cState === CtrlState.sDataWrite) { 88 | addrWire := dest_addr_reg 89 | } .otherwise { 90 | addrWire := 0.U 91 | } 92 | 93 | // Separate state FSM w/ reset 94 | when (io.reset | io.dcplrIO.excp_valid) { 95 | cState := CtrlState.sIdle 96 | blks_remain_reg := 0.U 97 | intrpt_en_reg := false.B 98 | counter_reg := 0.U 99 | } .otherwise { 100 | cState := cStateWire 101 | } 102 | 103 | switch (cState) { 104 | is (CtrlState.sIdle) { 105 | io.dcplrIO.key_ready := true.B 106 | // wait for directly start signal 107 | io.dcplrIO.start_ready := true.B 108 | 109 | when (io.dcplrIO.key_valid) { 110 | // configure AES key length 111 | io.aesCoreIO.we := true.B 112 | io.aesCoreIO.cs := true.B 113 | io.aesCoreIO.address := AESAddr.CONFIG 114 | io.aesCoreIO.write_data := io.dcplrIO.key_size << 1.U 115 | key_size_reg := io.dcplrIO.key_size 116 | 117 | // set memory addr and start memory read 118 | key_addr_reg := io.dcplrIO.key_addr 119 | when (io.dcplrIO.key_size === 0.U) { 120 | mem_target_reg := 4.U 121 | size_reg := 16.U 122 | } .otherwise { 123 | mem_target_reg := 8.U 124 | size_reg := 32.U 125 | } 126 | 127 | mStateWire := MemState.sReadReq 128 | cStateWire := CtrlState.sKeySetup 129 | } .elsewhen (io.dcplrIO.addr_valid) { 130 | // Wait for SRC and DEST address to arrive 131 | cStateWire := CtrlState.sWaitData 132 | io.dcplrIO.addr_ready := true.B 133 | when (io.dcplrIO.addr_valid) { 134 | // Save SRC and DEST address 135 | src_addr_reg := io.dcplrIO.src_addr 136 | dest_addr_reg := io.dcplrIO.dest_addr 137 | size_reg := 16.U 138 | mStateWire := MemState.sReadReq 139 | cStateWire := CtrlState.sDataSetup 140 | mem_target_reg := 4.U 141 | } 142 | } 143 | } 144 | is (CtrlState.sKeySetup) { 145 | // wait data loading from memory 146 | cStateWire := CtrlState.sKeySetup 147 | when (data_ld_done) { 148 | // Start the Key Expansion Process 149 | io.aesCoreIO.cs := true.B 150 | io.aesCoreIO.we := true.B 151 | io.aesCoreIO.address := AESAddr.CTRL 152 | io.aesCoreIO.write_data := 1.U 153 | ready_check_reg := false.B 154 | cStateWire := CtrlState.sKeyExp 155 | } 156 | } 157 | is (CtrlState.sKeyExp) { 158 | // Waiting for Key Expansion to Complete 159 | io.aesCoreIO.cs := 1.U 160 | io.aesCoreIO.address := AESAddr.STATUS 161 | cStateWire := CtrlState.sKeyExp 162 | when(io.aesCoreIO.read_data(0) === ready_check_reg) { 163 | when (ready_check_reg === false.B) { 164 | ready_check_reg := true.B 165 | } .otherwise { 166 | ready_check_reg := false.B 167 | cStateWire := CtrlState.sWaitData 168 | } 169 | } 170 | } 171 | is (CtrlState.sWaitData) { 172 | // Wait for SRC and DEST address to arrive 173 | cStateWire := CtrlState.sWaitData 174 | io.dcplrIO.addr_ready := true.B 175 | when (io.dcplrIO.addr_valid) { 176 | // Save SRC and DEST address 177 | src_addr_reg := io.dcplrIO.src_addr 178 | dest_addr_reg := io.dcplrIO.dest_addr 179 | size_reg := 16.U 180 | mStateWire := MemState.sReadReq 181 | cStateWire := CtrlState.sDataSetup 182 | mem_target_reg := 4.U 183 | } 184 | } 185 | is (CtrlState.sDataSetup) { 186 | when (blks_remain_reg === 0.U) { // First block 187 | when (data_ld_done) { 188 | // When memory has finished loading, wait for green light 189 | cStateWire := CtrlState.sWaitStart 190 | } .otherwise { 191 | cStateWire := CtrlState.sDataSetup 192 | } 193 | } .otherwise { 194 | when (data_ld_done) { 195 | // When memory has finish loading, straight to processing 196 | cStateWire := CtrlState.sAESRun 197 | } .otherwise { 198 | cStateWire := CtrlState.sDataSetup 199 | } 200 | } 201 | } 202 | is (CtrlState.sWaitStart) { 203 | cStateWire := CtrlState.sWaitStart 204 | io.dcplrIO.start_ready := true.B 205 | when (io.dcplrIO.start_valid) { 206 | // Set ENC or DEC operation 207 | io.aesCoreIO.cs := true.B 208 | io.aesCoreIO.we := true.B 209 | io.aesCoreIO.address := AESAddr.CONFIG 210 | io.aesCoreIO.write_data := io.dcplrIO.op_type | (key_size_reg << 1.U) 211 | 212 | // set number of blocks & interrupt enable 213 | blks_remain_reg := io.dcplrIO.block_count 214 | intrpt_en_reg := io.dcplrIO.intrpt_en 215 | cStateWire := CtrlState.sAESRun 216 | } 217 | } 218 | is (CtrlState.sAESRun) { 219 | // Start the ENC/DEC process 220 | io.aesCoreIO.cs := true.B 221 | io.aesCoreIO.we := true.B 222 | io.aesCoreIO.address := AESAddr.CTRL 223 | io.aesCoreIO.write_data := 1.U << 1.U 224 | ready_check_reg := false.B 225 | cStateWire := CtrlState.sWaitResult 226 | } 227 | is (CtrlState.sWaitResult) { 228 | cStateWire := CtrlState.sWaitResult 229 | io.aesCoreIO.cs := 1.U 230 | io.aesCoreIO.address := AESAddr.STATUS 231 | when(io.aesCoreIO.read_data(0) === ready_check_reg) { 232 | when (ready_check_reg === false.B) { 233 | ready_check_reg := true.B 234 | } .otherwise { 235 | blks_remain_reg := blks_remain_reg - 1.U 236 | 237 | ready_check_reg := false.B 238 | mStateWire := MemState.sWriteIntoMem 239 | cStateWire := CtrlState.sDataWrite 240 | } 241 | } 242 | } 243 | is (CtrlState.sDataWrite) { 244 | when (mState === MemState.sWriteIntoMem) { 245 | // Read AES result out to DMA 246 | io.aesCoreIO.cs := 1.U 247 | io.aesCoreIO.address := AESAddr.RESULT + counter_reg 248 | cStateWire := CtrlState.sDataWrite 249 | } .elsewhen (data_wr_done) { 250 | when (blks_remain_reg > 0.U) { 251 | // Return to DataSetup state to read in next block 252 | src_addr_reg := src_addr_reg + 16.U 253 | dest_addr_reg := dest_addr_reg + 16.U 254 | 255 | mStateWire := MemState.sReadReq 256 | cStateWire := CtrlState.sDataSetup 257 | } .otherwise { 258 | // Completed Encryption/Decryption, Raise Interrupt 259 | // NOTE: Moved to when memory FSM finishes writeback 260 | // io.dcplrIO.interrupt := intrpt_en_reg 261 | cStateWire := CtrlState.sIdle 262 | } 263 | } .otherwise { 264 | cStateWire := CtrlState.sDataWrite 265 | } 266 | } 267 | } 268 | 269 | // Separate state FSM w/ reset 270 | when (io.reset | io.dcplrIO.excp_valid) { 271 | mState := MemState.sIdle 272 | } .otherwise { 273 | mState := mStateWire 274 | } 275 | 276 | // Memory FSM 277 | switch (mState) { 278 | is (MemState.sIdle) { 279 | counter_reg := 0.U 280 | } 281 | is (MemState.sReadReq) { 282 | // Send Memory Read Request for Key 283 | mStateWire := MemState.sReadReq 284 | io.dmem.readReq.valid := true.B 285 | io.dmem.readReq.bits.addr := addrWire 286 | io.dmem.readReq.bits.totalBytes := size_reg 287 | when (io.dmem.readReq.fire()) { 288 | mStateWire := MemState.sReadIntoAES 289 | } 290 | } 291 | is (MemState.sReadIntoAES) { 292 | mStateWire := MemState.sReadIntoAES 293 | when (counter_reg === mem_target_reg) { 294 | // Completed Memory Read 295 | mStateWire := MemState.sIdle 296 | } .otherwise { 297 | when (dequeue.io.dataOut.fire()) { // When we dequeue 298 | io.aesCoreIO.cs := true.B 299 | io.aesCoreIO.we := true.B 300 | io.aesCoreIO.write_data := dequeue.io.dataOut.bits 301 | counter_reg := counter_reg + 1.U 302 | } 303 | } 304 | when (cState === CtrlState.sKeySetup) { 305 | io.aesCoreIO.address := AESAddr.KEY + counter_reg 306 | } .elsewhen (cState === CtrlState.sDataSetup) { 307 | io.aesCoreIO.address := AESAddr.TEXT + counter_reg 308 | } 309 | } 310 | is (MemState.sWriteReq) { 311 | mStateWire := MemState.sWriteReq 312 | when (counter_reg === 4.U(4.W)) { 313 | // Completed Memory Write 314 | when (!io.dmem.busy && enqueue.io.done) { 315 | mStateWire := MemState.sIdle 316 | when (blks_remain_reg === 0.U) { 317 | io.dcplrIO.interrupt := intrpt_en_reg 318 | } 319 | } 320 | } .otherwise { 321 | // Send Write Request 322 | enqueue.io.dataIn.valid := true.B 323 | when (enqueue.io.dataIn.ready === true.B) { 324 | mStateWire := MemState.sWriteIntoMem 325 | counter_reg := counter_reg + 1.U 326 | } 327 | } 328 | } 329 | is (MemState.sWriteIntoMem) { 330 | mStateWire := MemState.sWriteReq; 331 | } 332 | } 333 | 334 | // Set static system signals 335 | io.dcplrIO.busy := (blks_remain_reg =/= 0.U(32.W)) | mState =/= MemState.sIdle 336 | io.dcplrIO.excp_ready := true.B 337 | io.aesCoreIO.clk := clock 338 | io.aesCoreIO.reset_n := ~io.reset 339 | } 340 | -------------------------------------------------------------------------------- /src/test/scala/DMABufferTest.scala: -------------------------------------------------------------------------------- 1 | package aes 2 | 3 | import chisel3._ 4 | import chisel3.util.DecoupledIO 5 | import chiseltest._ 6 | import chiseltest.experimental.TestOptionBuilder._ 7 | import chiseltest.internal.WriteVcdAnnotation 8 | import ee290cdma.EE290CDMAWriterReq 9 | import org.scalatest.flatspec.AnyFlatSpec 10 | import verif._ 11 | 12 | class DMABufferTest extends AnyFlatSpec with ChiselScalatestTester { 13 | 14 | // ---------------------------- DMA Input Buffer Tests ---------------------------- 15 | // Testing various beatByte sizes centered at 16 (128bits) for complete block write 16 | 17 | // ----------------------------------- NOTICE ------------------------------------- 18 | // This test has not been updated for the latest DMABuffer update (where it reverse 19 | // all bits to match how software stores data in memory). Tests here will FAIL. 20 | // Use the accelerator-level testbench to verify correctness 21 | 22 | it should "Test DMAInputBuffer when beatBytes == 16" in { 23 | val beatBytes = 16 24 | test(new DMAInputBuffer(32, beatBytes)).withAnnotations(Seq(WriteVcdAnnotation)) { c => 25 | val addrDriver = new DecoupledDriverMaster(c.clock, c.io.baseAddr) 26 | val inDriver = new DecoupledDriverMaster(c.clock, c.io.dataIn) 27 | val outDriver = new DecoupledDriverSlave[EE290CDMAWriterReq](c.clock, c.io.dmaOutput, 0) 28 | val outMonitor = new DecoupledMonitor[EE290CDMAWriterReq](c.clock, c.io.dmaOutput) 29 | 30 | val addrInputs = Seq.fill(25)(BigInt(32, scala.util.Random)) 31 | val resultDataBlocks = Seq.fill(25)(BigInt(128, scala.util.Random)) 32 | val mask = BigInt("1" * 32, 2) // For masking into 32bit blocks 33 | 34 | // Driving inputs 35 | for (i <- addrInputs.indices) { 36 | addrDriver.push(new DecoupledTX(UInt(32.W)).tx(addrInputs(i).U)) 37 | val dataBlock = resultDataBlocks(i) 38 | val dataInputs = Seq(dataBlock & mask, (dataBlock >> 32) & mask, (dataBlock >> 64) & mask, dataBlock >> 96) 39 | inDriver.push(dataInputs.map(x => new DecoupledTX(UInt(32.W)).tx(x.U))) 40 | c.clock.step(15) 41 | } 42 | 43 | assert(outMonitor.monitoredTransactions.nonEmpty) 44 | assert(outMonitor.monitoredTransactions.size == resultDataBlocks.size) 45 | outMonitor.monitoredTransactions 46 | .map(x => x.data.addr.litValue()) 47 | .zip(addrInputs) 48 | .foreach {case (o, e) => assert(o == e)} 49 | outMonitor.monitoredTransactions 50 | .map(x => x.data.data.litValue()) 51 | .zip(resultDataBlocks) 52 | .foreach {case (o, e) => assert(o == e)} 53 | outMonitor.monitoredTransactions 54 | .map(x => assert(x.data.totalBytes.litValue() == beatBytes)) 55 | } 56 | } 57 | 58 | it should "Test DMAInputBuffer when beatBytes == 8 (less than 16)" in { 59 | val beatBytes = 8 60 | test(new DMAInputBuffer(32, beatBytes)).withAnnotations(Seq(WriteVcdAnnotation)) { c => 61 | val addrDriver = new DecoupledDriverMaster(c.clock, c.io.baseAddr) 62 | val inDriver = new DecoupledDriverMaster(c.clock, c.io.dataIn) 63 | val outDriver = new DecoupledDriverSlave[EE290CDMAWriterReq](c.clock, c.io.dmaOutput, 0) 64 | val outMonitor = new DecoupledMonitor[EE290CDMAWriterReq](c.clock, c.io.dmaOutput) 65 | 66 | val addrInputs = Seq.fill(25)(BigInt(32, scala.util.Random)) 67 | val dataBlocks = Seq.fill(25)(BigInt(128, scala.util.Random)) 68 | 69 | // Expected results 70 | var resultAddrInputs = Seq[BigInt]() 71 | for (i <- addrInputs) { 72 | resultAddrInputs = resultAddrInputs ++ Seq(i, i + 8) 73 | } 74 | var resultDataBlocks = Seq[BigInt]() 75 | for (i <- dataBlocks) { 76 | resultDataBlocks = resultDataBlocks ++ Seq(i & BigInt("1" * 64, 2), i >> 64) 77 | } 78 | val mask = BigInt("1" * 32, 2) // For masking into 32bit blocks 79 | 80 | // Driving inputs 81 | for (i <- addrInputs.indices) { 82 | addrDriver.push(new DecoupledTX(UInt(32.W)).tx(addrInputs(i).U)) 83 | val dataBlock = dataBlocks(i) 84 | val dataInputs = Seq(dataBlock & mask, (dataBlock >> 32) & mask, (dataBlock >> 64) & mask, dataBlock >> 96) 85 | inDriver.push(dataInputs.map(x => new DecoupledTX(UInt(32.W)).tx(x.U))) 86 | c.clock.step(15) 87 | } 88 | 89 | assert(outMonitor.monitoredTransactions.nonEmpty) 90 | 91 | assert(outMonitor.monitoredTransactions.size == resultAddrInputs.size && 92 | resultAddrInputs.size == resultDataBlocks.size) 93 | outMonitor.monitoredTransactions 94 | .map(x => x.data.addr.litValue()) 95 | .zip(resultAddrInputs) 96 | .foreach {case (o, e) => assert(o == e)} 97 | 98 | outMonitor.monitoredTransactions 99 | .map(x => x.data.data.litValue()) 100 | .zip(resultDataBlocks) 101 | .foreach {case (o, e) => assert(o == e)} 102 | 103 | outMonitor.monitoredTransactions 104 | .map(x => assert(x.data.totalBytes.litValue() == beatBytes)) 105 | } 106 | } 107 | 108 | // Testing one more case for beatBytes < 16, as this is most likely the param in the actual chip 109 | it should "Test DMAInputBuffer when beatBytes == 4 (less than 16)" in { 110 | val beatBytes = 4 111 | test(new DMAInputBuffer(32, beatBytes)).withAnnotations(Seq(WriteVcdAnnotation)) { c => 112 | val addrDriver = new DecoupledDriverMaster(c.clock, c.io.baseAddr) 113 | val inDriver = new DecoupledDriverMaster(c.clock, c.io.dataIn) 114 | val outDriver = new DecoupledDriverSlave[EE290CDMAWriterReq](c.clock, c.io.dmaOutput, 0) 115 | val outMonitor = new DecoupledMonitor[EE290CDMAWriterReq](c.clock, c.io.dmaOutput) 116 | 117 | val addrInputs = Seq.fill(25)(BigInt(32, scala.util.Random)) 118 | val dataBlocks = Seq.fill(25)(BigInt(128, scala.util.Random)) 119 | 120 | // Expected results 121 | var resultAddrInputs = Seq[BigInt]() 122 | for (i <- addrInputs) { 123 | resultAddrInputs = resultAddrInputs ++ Seq(i, i + 4, i + 8, i + 12) 124 | } 125 | val mask = BigInt("1" * 32, 2) // For masking into 32bit blocks 126 | var resultDataBlocks = Seq[BigInt]() 127 | for (i <- dataBlocks) { 128 | resultDataBlocks = resultDataBlocks ++ Seq(i & mask, (i >> 32) & mask, (i >> 64) & mask, i >> 96) 129 | } 130 | 131 | // Driving inputs 132 | for (i <- addrInputs.indices) { 133 | addrDriver.push(new DecoupledTX(UInt(32.W)).tx(addrInputs(i).U)) 134 | val dataBlock = dataBlocks(i) 135 | val dataInputs = Seq(dataBlock & mask, (dataBlock >> 32) & mask, (dataBlock >> 64) & mask, dataBlock >> 96) 136 | inDriver.push(dataInputs.map(x => new DecoupledTX(UInt(32.W)).tx(x.U))) 137 | c.clock.step(15) 138 | } 139 | 140 | assert(outMonitor.monitoredTransactions.nonEmpty) 141 | 142 | assert(outMonitor.monitoredTransactions.size == resultAddrInputs.size && 143 | resultAddrInputs.size == resultDataBlocks.size) 144 | outMonitor.monitoredTransactions 145 | .map(x => x.data.addr.litValue()) 146 | .zip(resultAddrInputs) 147 | .foreach {case (o, e) => assert(o == e)} 148 | 149 | outMonitor.monitoredTransactions 150 | .map(x => x.data.data.litValue()) 151 | .zip(resultDataBlocks) 152 | .foreach {case (o, e) => assert(o == e)} 153 | 154 | outMonitor.monitoredTransactions 155 | .map(x => assert(x.data.totalBytes.litValue() == beatBytes)) 156 | } 157 | } 158 | 159 | it should "Test DMAInputBuffer when beatBytes == 32 (greater than 16)" in { 160 | val beatBytes = 32 161 | test(new DMAInputBuffer(32, beatBytes)).withAnnotations(Seq(WriteVcdAnnotation)) { c => 162 | val addrDriver = new DecoupledDriverMaster(c.clock, c.io.baseAddr) 163 | val inDriver = new DecoupledDriverMaster(c.clock, c.io.dataIn) 164 | val outDriver = new DecoupledDriverSlave[EE290CDMAWriterReq](c.clock, c.io.dmaOutput, 0) 165 | val outMonitor = new DecoupledMonitor[EE290CDMAWriterReq](c.clock, c.io.dmaOutput) 166 | 167 | val addrInputs = Seq.fill(25)(BigInt(32, scala.util.Random)) 168 | val resultDataBlocks = Seq.fill(25)(BigInt(128, scala.util.Random)) 169 | val mask = BigInt("1" * 32, 2) // For masking into 32bit blocks 170 | 171 | for (i <- addrInputs.indices) { 172 | addrDriver.push(new DecoupledTX(UInt(32.W)).tx(addrInputs(i).U)) 173 | val dataBlock = resultDataBlocks(i) 174 | val dataInputs = Seq(dataBlock & mask, (dataBlock >> 32) & mask, (dataBlock >> 64) & mask, dataBlock >> 96) 175 | inDriver.push(dataInputs.map(x => new DecoupledTX(UInt(32.W)).tx(x.U))) 176 | c.clock.step(15) 177 | } 178 | 179 | assert(outMonitor.monitoredTransactions.nonEmpty) 180 | assert(outMonitor.monitoredTransactions.size == addrInputs.size && 181 | addrInputs.size == resultDataBlocks.size) 182 | outMonitor.monitoredTransactions 183 | .map(x => x.data.addr.litValue()) 184 | .zip(addrInputs) 185 | .foreach {case (o, e) => assert(o == e)} 186 | 187 | outMonitor.monitoredTransactions 188 | .map(x => x.data.data.litValue()) 189 | .zip(resultDataBlocks) 190 | .foreach {case (o, e) => assert(o == e)} 191 | 192 | outMonitor.monitoredTransactions 193 | .map(x => assert(x.data.totalBytes.litValue() == 16)) // Max out at 16 bytes (128b) 194 | } 195 | } 196 | 197 | // ---------------------------- DMA Output Buffer Tests ---------------------------- 198 | // Testing various beatByte sizes centered at 4 (32bits) or intended DMA output size 199 | 200 | it should "Test DMAOutputBuffer when beatBytes == 4" in { 201 | val beatBytes = 4 202 | test(new DMAOutputBuffer(beatBytes)).withAnnotations(Seq(WriteVcdAnnotation)) { c => 203 | val inDriver = new DecoupledDriverMaster(c.clock, c.io.dmaInput) 204 | val outDriver = new DecoupledDriverSlave(c.clock, c.io.dataOut, 0) 205 | val outMonitor = new DecoupledMonitor(c.clock, c.io.dataOut) 206 | 207 | val inputs = Seq.fill(100)(BigInt((beatBytes * 8), scala.util.Random)) 208 | 209 | inDriver.push(inputs.map(x => new DecoupledTX(UInt((beatBytes * 8).W)).tx(x.U))) 210 | c.clock.step(inputs.length + 200) 211 | 212 | assert(outMonitor.monitoredTransactions.nonEmpty) 213 | assert(outMonitor.monitoredTransactions.size == inputs.size) 214 | outMonitor.monitoredTransactions 215 | .map(x => x.data.litValue()) 216 | .zip(inputs) 217 | .foreach {case (o, e) => assert(o == e)} 218 | } 219 | } 220 | 221 | it should "Test DMAOutputBuffer when beatBytes == 2 (less than 4)" in { 222 | val beatBytes = 2 223 | test(new DMAOutputBuffer(beatBytes)).withAnnotations(Seq(WriteVcdAnnotation)) { c => 224 | val inDriver = new DecoupledDriverMaster(c.clock, c.io.dmaInput) 225 | val outDriver = new DecoupledDriverSlave(c.clock, c.io.dataOut, 0) 226 | val outMonitor = new DecoupledMonitor(c.clock, c.io.dataOut) 227 | 228 | val inputs = Seq.fill(100)(BigInt((beatBytes * 8), scala.util.Random)) 229 | val results = inputs.grouped(2).map { case List(x,y) => (y << 16) + x}.toList 230 | println(s"Result size is ${results.size}") 231 | 232 | inDriver.push(inputs.map(x => new DecoupledTX(UInt((beatBytes * 8).W)).tx(x.U))) 233 | c.clock.step(inputs.length + 200) 234 | 235 | assert(outMonitor.monitoredTransactions.nonEmpty) 236 | assert(outMonitor.monitoredTransactions.size == results.size) 237 | outMonitor.monitoredTransactions 238 | .map(x => x.data.litValue()) 239 | .zip(results) 240 | .foreach {case (o, e) => assert(o == e)} 241 | } 242 | } 243 | 244 | it should "Test DMAOutputBuffer when beatBytes == 8 (greater than 4)" in { 245 | val beatBytes = 8 246 | test(new DMAOutputBuffer(beatBytes)).withAnnotations(Seq(WriteVcdAnnotation)) { c => 247 | val inDriver = new DecoupledDriverMaster(c.clock, c.io.dmaInput) 248 | val outDriver = new DecoupledDriverSlave(c.clock, c.io.dataOut, 0) 249 | val outMonitor = new DecoupledMonitor(c.clock, c.io.dataOut) 250 | 251 | val inputs = Seq.fill(100)(BigInt((beatBytes * 8), scala.util.Random)) 252 | var results = Seq[BigInt]() 253 | for (i <- inputs) { 254 | results = results ++ Seq(i & (BigInt("1" * 32, 2)), i >> 32) 255 | } 256 | println(s"Result size is ${results.size}") 257 | 258 | inDriver.push(inputs.map(x => new DecoupledTX(UInt((beatBytes * 8).W)).tx(x.U))) 259 | c.clock.step(inputs.length * 2 + 200) 260 | 261 | assert(outMonitor.monitoredTransactions.nonEmpty) 262 | assert(outMonitor.monitoredTransactions.size == results.size) 263 | outMonitor.monitoredTransactions 264 | .map(x => x.data.litValue()) 265 | .zip(results) 266 | .foreach {case (o, e) => assert(o == e)} 267 | } 268 | } 269 | } -------------------------------------------------------------------------------- /src/main/resources/vsrc/aes_inv_sbox.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // aes_inv_sbox.v 4 | // -------------- 5 | // The inverse AES S-box. Basically a 256 Byte ROM. 6 | // 7 | // 8 | // Copyright (c) 2013 Secworks Sweden AB 9 | // All rights reserved. 10 | // 11 | // Redistribution and use in source and binary forms, with or 12 | // without modification, are permitted provided that the following 13 | // conditions are met: 14 | // 15 | // 1. Redistributions of source code must retain the above copyright 16 | // notice, this list of conditions and the following disclaimer. 17 | // 18 | // 2. Redistributions in binary form must reproduce the above copyright 19 | // notice, this list of conditions and the following disclaimer in 20 | // the documentation and/or other materials provided with the 21 | // distribution. 22 | // 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | // 36 | //====================================================================== 37 | 38 | module aes_inv_sbox( 39 | input wire [31 : 0] sword, 40 | output wire [31 : 0] new_sword 41 | ); 42 | 43 | 44 | //---------------------------------------------------------------- 45 | // The inverse sbox array. 46 | //---------------------------------------------------------------- 47 | wire [7 : 0] inv_sbox [0 : 255]; 48 | 49 | 50 | //---------------------------------------------------------------- 51 | // Four parallel muxes. 52 | //---------------------------------------------------------------- 53 | assign new_sword[31 : 24] = inv_sbox[sword[31 : 24]]; 54 | assign new_sword[23 : 16] = inv_sbox[sword[23 : 16]]; 55 | assign new_sword[15 : 08] = inv_sbox[sword[15 : 08]]; 56 | assign new_sword[07 : 00] = inv_sbox[sword[07 : 00]]; 57 | 58 | 59 | //---------------------------------------------------------------- 60 | // Creating the contents of the array. 61 | //---------------------------------------------------------------- 62 | assign inv_sbox[8'h00] = 8'h52; 63 | assign inv_sbox[8'h01] = 8'h09; 64 | assign inv_sbox[8'h02] = 8'h6a; 65 | assign inv_sbox[8'h03] = 8'hd5; 66 | assign inv_sbox[8'h04] = 8'h30; 67 | assign inv_sbox[8'h05] = 8'h36; 68 | assign inv_sbox[8'h06] = 8'ha5; 69 | assign inv_sbox[8'h07] = 8'h38; 70 | assign inv_sbox[8'h08] = 8'hbf; 71 | assign inv_sbox[8'h09] = 8'h40; 72 | assign inv_sbox[8'h0a] = 8'ha3; 73 | assign inv_sbox[8'h0b] = 8'h9e; 74 | assign inv_sbox[8'h0c] = 8'h81; 75 | assign inv_sbox[8'h0d] = 8'hf3; 76 | assign inv_sbox[8'h0e] = 8'hd7; 77 | assign inv_sbox[8'h0f] = 8'hfb; 78 | assign inv_sbox[8'h10] = 8'h7c; 79 | assign inv_sbox[8'h11] = 8'he3; 80 | assign inv_sbox[8'h12] = 8'h39; 81 | assign inv_sbox[8'h13] = 8'h82; 82 | assign inv_sbox[8'h14] = 8'h9b; 83 | assign inv_sbox[8'h15] = 8'h2f; 84 | assign inv_sbox[8'h16] = 8'hff; 85 | assign inv_sbox[8'h17] = 8'h87; 86 | assign inv_sbox[8'h18] = 8'h34; 87 | assign inv_sbox[8'h19] = 8'h8e; 88 | assign inv_sbox[8'h1a] = 8'h43; 89 | assign inv_sbox[8'h1b] = 8'h44; 90 | assign inv_sbox[8'h1c] = 8'hc4; 91 | assign inv_sbox[8'h1d] = 8'hde; 92 | assign inv_sbox[8'h1e] = 8'he9; 93 | assign inv_sbox[8'h1f] = 8'hcb; 94 | assign inv_sbox[8'h20] = 8'h54; 95 | assign inv_sbox[8'h21] = 8'h7b; 96 | assign inv_sbox[8'h22] = 8'h94; 97 | assign inv_sbox[8'h23] = 8'h32; 98 | assign inv_sbox[8'h24] = 8'ha6; 99 | assign inv_sbox[8'h25] = 8'hc2; 100 | assign inv_sbox[8'h26] = 8'h23; 101 | assign inv_sbox[8'h27] = 8'h3d; 102 | assign inv_sbox[8'h28] = 8'hee; 103 | assign inv_sbox[8'h29] = 8'h4c; 104 | assign inv_sbox[8'h2a] = 8'h95; 105 | assign inv_sbox[8'h2b] = 8'h0b; 106 | assign inv_sbox[8'h2c] = 8'h42; 107 | assign inv_sbox[8'h2d] = 8'hfa; 108 | assign inv_sbox[8'h2e] = 8'hc3; 109 | assign inv_sbox[8'h2f] = 8'h4e; 110 | assign inv_sbox[8'h30] = 8'h08; 111 | assign inv_sbox[8'h31] = 8'h2e; 112 | assign inv_sbox[8'h32] = 8'ha1; 113 | assign inv_sbox[8'h33] = 8'h66; 114 | assign inv_sbox[8'h34] = 8'h28; 115 | assign inv_sbox[8'h35] = 8'hd9; 116 | assign inv_sbox[8'h36] = 8'h24; 117 | assign inv_sbox[8'h37] = 8'hb2; 118 | assign inv_sbox[8'h38] = 8'h76; 119 | assign inv_sbox[8'h39] = 8'h5b; 120 | assign inv_sbox[8'h3a] = 8'ha2; 121 | assign inv_sbox[8'h3b] = 8'h49; 122 | assign inv_sbox[8'h3c] = 8'h6d; 123 | assign inv_sbox[8'h3d] = 8'h8b; 124 | assign inv_sbox[8'h3e] = 8'hd1; 125 | assign inv_sbox[8'h3f] = 8'h25; 126 | assign inv_sbox[8'h40] = 8'h72; 127 | assign inv_sbox[8'h41] = 8'hf8; 128 | assign inv_sbox[8'h42] = 8'hf6; 129 | assign inv_sbox[8'h43] = 8'h64; 130 | assign inv_sbox[8'h44] = 8'h86; 131 | assign inv_sbox[8'h45] = 8'h68; 132 | assign inv_sbox[8'h46] = 8'h98; 133 | assign inv_sbox[8'h47] = 8'h16; 134 | assign inv_sbox[8'h48] = 8'hd4; 135 | assign inv_sbox[8'h49] = 8'ha4; 136 | assign inv_sbox[8'h4a] = 8'h5c; 137 | assign inv_sbox[8'h4b] = 8'hcc; 138 | assign inv_sbox[8'h4c] = 8'h5d; 139 | assign inv_sbox[8'h4d] = 8'h65; 140 | assign inv_sbox[8'h4e] = 8'hb6; 141 | assign inv_sbox[8'h4f] = 8'h92; 142 | assign inv_sbox[8'h50] = 8'h6c; 143 | assign inv_sbox[8'h51] = 8'h70; 144 | assign inv_sbox[8'h52] = 8'h48; 145 | assign inv_sbox[8'h53] = 8'h50; 146 | assign inv_sbox[8'h54] = 8'hfd; 147 | assign inv_sbox[8'h55] = 8'hed; 148 | assign inv_sbox[8'h56] = 8'hb9; 149 | assign inv_sbox[8'h57] = 8'hda; 150 | assign inv_sbox[8'h58] = 8'h5e; 151 | assign inv_sbox[8'h59] = 8'h15; 152 | assign inv_sbox[8'h5a] = 8'h46; 153 | assign inv_sbox[8'h5b] = 8'h57; 154 | assign inv_sbox[8'h5c] = 8'ha7; 155 | assign inv_sbox[8'h5d] = 8'h8d; 156 | assign inv_sbox[8'h5e] = 8'h9d; 157 | assign inv_sbox[8'h5f] = 8'h84; 158 | assign inv_sbox[8'h60] = 8'h90; 159 | assign inv_sbox[8'h61] = 8'hd8; 160 | assign inv_sbox[8'h62] = 8'hab; 161 | assign inv_sbox[8'h63] = 8'h00; 162 | assign inv_sbox[8'h64] = 8'h8c; 163 | assign inv_sbox[8'h65] = 8'hbc; 164 | assign inv_sbox[8'h66] = 8'hd3; 165 | assign inv_sbox[8'h67] = 8'h0a; 166 | assign inv_sbox[8'h68] = 8'hf7; 167 | assign inv_sbox[8'h69] = 8'he4; 168 | assign inv_sbox[8'h6a] = 8'h58; 169 | assign inv_sbox[8'h6b] = 8'h05; 170 | assign inv_sbox[8'h6c] = 8'hb8; 171 | assign inv_sbox[8'h6d] = 8'hb3; 172 | assign inv_sbox[8'h6e] = 8'h45; 173 | assign inv_sbox[8'h6f] = 8'h06; 174 | assign inv_sbox[8'h70] = 8'hd0; 175 | assign inv_sbox[8'h71] = 8'h2c; 176 | assign inv_sbox[8'h72] = 8'h1e; 177 | assign inv_sbox[8'h73] = 8'h8f; 178 | assign inv_sbox[8'h74] = 8'hca; 179 | assign inv_sbox[8'h75] = 8'h3f; 180 | assign inv_sbox[8'h76] = 8'h0f; 181 | assign inv_sbox[8'h77] = 8'h02; 182 | assign inv_sbox[8'h78] = 8'hc1; 183 | assign inv_sbox[8'h79] = 8'haf; 184 | assign inv_sbox[8'h7a] = 8'hbd; 185 | assign inv_sbox[8'h7b] = 8'h03; 186 | assign inv_sbox[8'h7c] = 8'h01; 187 | assign inv_sbox[8'h7d] = 8'h13; 188 | assign inv_sbox[8'h7e] = 8'h8a; 189 | assign inv_sbox[8'h7f] = 8'h6b; 190 | assign inv_sbox[8'h80] = 8'h3a; 191 | assign inv_sbox[8'h81] = 8'h91; 192 | assign inv_sbox[8'h82] = 8'h11; 193 | assign inv_sbox[8'h83] = 8'h41; 194 | assign inv_sbox[8'h84] = 8'h4f; 195 | assign inv_sbox[8'h85] = 8'h67; 196 | assign inv_sbox[8'h86] = 8'hdc; 197 | assign inv_sbox[8'h87] = 8'hea; 198 | assign inv_sbox[8'h88] = 8'h97; 199 | assign inv_sbox[8'h89] = 8'hf2; 200 | assign inv_sbox[8'h8a] = 8'hcf; 201 | assign inv_sbox[8'h8b] = 8'hce; 202 | assign inv_sbox[8'h8c] = 8'hf0; 203 | assign inv_sbox[8'h8d] = 8'hb4; 204 | assign inv_sbox[8'h8e] = 8'he6; 205 | assign inv_sbox[8'h8f] = 8'h73; 206 | assign inv_sbox[8'h90] = 8'h96; 207 | assign inv_sbox[8'h91] = 8'hac; 208 | assign inv_sbox[8'h92] = 8'h74; 209 | assign inv_sbox[8'h93] = 8'h22; 210 | assign inv_sbox[8'h94] = 8'he7; 211 | assign inv_sbox[8'h95] = 8'had; 212 | assign inv_sbox[8'h96] = 8'h35; 213 | assign inv_sbox[8'h97] = 8'h85; 214 | assign inv_sbox[8'h98] = 8'he2; 215 | assign inv_sbox[8'h99] = 8'hf9; 216 | assign inv_sbox[8'h9a] = 8'h37; 217 | assign inv_sbox[8'h9b] = 8'he8; 218 | assign inv_sbox[8'h9c] = 8'h1c; 219 | assign inv_sbox[8'h9d] = 8'h75; 220 | assign inv_sbox[8'h9e] = 8'hdf; 221 | assign inv_sbox[8'h9f] = 8'h6e; 222 | assign inv_sbox[8'ha0] = 8'h47; 223 | assign inv_sbox[8'ha1] = 8'hf1; 224 | assign inv_sbox[8'ha2] = 8'h1a; 225 | assign inv_sbox[8'ha3] = 8'h71; 226 | assign inv_sbox[8'ha4] = 8'h1d; 227 | assign inv_sbox[8'ha5] = 8'h29; 228 | assign inv_sbox[8'ha6] = 8'hc5; 229 | assign inv_sbox[8'ha7] = 8'h89; 230 | assign inv_sbox[8'ha8] = 8'h6f; 231 | assign inv_sbox[8'ha9] = 8'hb7; 232 | assign inv_sbox[8'haa] = 8'h62; 233 | assign inv_sbox[8'hab] = 8'h0e; 234 | assign inv_sbox[8'hac] = 8'haa; 235 | assign inv_sbox[8'had] = 8'h18; 236 | assign inv_sbox[8'hae] = 8'hbe; 237 | assign inv_sbox[8'haf] = 8'h1b; 238 | assign inv_sbox[8'hb0] = 8'hfc; 239 | assign inv_sbox[8'hb1] = 8'h56; 240 | assign inv_sbox[8'hb2] = 8'h3e; 241 | assign inv_sbox[8'hb3] = 8'h4b; 242 | assign inv_sbox[8'hb4] = 8'hc6; 243 | assign inv_sbox[8'hb5] = 8'hd2; 244 | assign inv_sbox[8'hb6] = 8'h79; 245 | assign inv_sbox[8'hb7] = 8'h20; 246 | assign inv_sbox[8'hb8] = 8'h9a; 247 | assign inv_sbox[8'hb9] = 8'hdb; 248 | assign inv_sbox[8'hba] = 8'hc0; 249 | assign inv_sbox[8'hbb] = 8'hfe; 250 | assign inv_sbox[8'hbc] = 8'h78; 251 | assign inv_sbox[8'hbd] = 8'hcd; 252 | assign inv_sbox[8'hbe] = 8'h5a; 253 | assign inv_sbox[8'hbf] = 8'hf4; 254 | assign inv_sbox[8'hc0] = 8'h1f; 255 | assign inv_sbox[8'hc1] = 8'hdd; 256 | assign inv_sbox[8'hc2] = 8'ha8; 257 | assign inv_sbox[8'hc3] = 8'h33; 258 | assign inv_sbox[8'hc4] = 8'h88; 259 | assign inv_sbox[8'hc5] = 8'h07; 260 | assign inv_sbox[8'hc6] = 8'hc7; 261 | assign inv_sbox[8'hc7] = 8'h31; 262 | assign inv_sbox[8'hc8] = 8'hb1; 263 | assign inv_sbox[8'hc9] = 8'h12; 264 | assign inv_sbox[8'hca] = 8'h10; 265 | assign inv_sbox[8'hcb] = 8'h59; 266 | assign inv_sbox[8'hcc] = 8'h27; 267 | assign inv_sbox[8'hcd] = 8'h80; 268 | assign inv_sbox[8'hce] = 8'hec; 269 | assign inv_sbox[8'hcf] = 8'h5f; 270 | assign inv_sbox[8'hd0] = 8'h60; 271 | assign inv_sbox[8'hd1] = 8'h51; 272 | assign inv_sbox[8'hd2] = 8'h7f; 273 | assign inv_sbox[8'hd3] = 8'ha9; 274 | assign inv_sbox[8'hd4] = 8'h19; 275 | assign inv_sbox[8'hd5] = 8'hb5; 276 | assign inv_sbox[8'hd6] = 8'h4a; 277 | assign inv_sbox[8'hd7] = 8'h0d; 278 | assign inv_sbox[8'hd8] = 8'h2d; 279 | assign inv_sbox[8'hd9] = 8'he5; 280 | assign inv_sbox[8'hda] = 8'h7a; 281 | assign inv_sbox[8'hdb] = 8'h9f; 282 | assign inv_sbox[8'hdc] = 8'h93; 283 | assign inv_sbox[8'hdd] = 8'hc9; 284 | assign inv_sbox[8'hde] = 8'h9c; 285 | assign inv_sbox[8'hdf] = 8'hef; 286 | assign inv_sbox[8'he0] = 8'ha0; 287 | assign inv_sbox[8'he1] = 8'he0; 288 | assign inv_sbox[8'he2] = 8'h3b; 289 | assign inv_sbox[8'he3] = 8'h4d; 290 | assign inv_sbox[8'he4] = 8'hae; 291 | assign inv_sbox[8'he5] = 8'h2a; 292 | assign inv_sbox[8'he6] = 8'hf5; 293 | assign inv_sbox[8'he7] = 8'hb0; 294 | assign inv_sbox[8'he8] = 8'hc8; 295 | assign inv_sbox[8'he9] = 8'heb; 296 | assign inv_sbox[8'hea] = 8'hbb; 297 | assign inv_sbox[8'heb] = 8'h3c; 298 | assign inv_sbox[8'hec] = 8'h83; 299 | assign inv_sbox[8'hed] = 8'h53; 300 | assign inv_sbox[8'hee] = 8'h99; 301 | assign inv_sbox[8'hef] = 8'h61; 302 | assign inv_sbox[8'hf0] = 8'h17; 303 | assign inv_sbox[8'hf1] = 8'h2b; 304 | assign inv_sbox[8'hf2] = 8'h04; 305 | assign inv_sbox[8'hf3] = 8'h7e; 306 | assign inv_sbox[8'hf4] = 8'hba; 307 | assign inv_sbox[8'hf5] = 8'h77; 308 | assign inv_sbox[8'hf6] = 8'hd6; 309 | assign inv_sbox[8'hf7] = 8'h26; 310 | assign inv_sbox[8'hf8] = 8'he1; 311 | assign inv_sbox[8'hf9] = 8'h69; 312 | assign inv_sbox[8'hfa] = 8'h14; 313 | assign inv_sbox[8'hfb] = 8'h63; 314 | assign inv_sbox[8'hfc] = 8'h55; 315 | assign inv_sbox[8'hfd] = 8'h21; 316 | assign inv_sbox[8'hfe] = 8'h0c; 317 | assign inv_sbox[8'hff] = 8'h7d; 318 | 319 | endmodule // aes_inv_sbox 320 | 321 | //====================================================================== 322 | // EOF aes_inv_sbox.v 323 | //====================================================================== 324 | -------------------------------------------------------------------------------- /src/main/resources/vsrc/aes_key_mem.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // aes_key_mem.v 4 | // ------------- 5 | // The AES key memory including round key generator. 6 | // 7 | // 8 | // Author: Joachim Strombergson 9 | // Copyright (c) 2013 Secworks Sweden AB 10 | // All rights reserved. 11 | // 12 | // Redistribution and use in source and binary forms, with or 13 | // without modification, are permitted provided that the following 14 | // conditions are met: 15 | // 16 | // 1. Redistributions of source code must retain the above copyright 17 | // notice, this list of conditions and the following disclaimer. 18 | // 19 | // 2. Redistributions in binary form must reproduce the above copyright 20 | // notice, this list of conditions and the following disclaimer in 21 | // the documentation and/or other materials provided with the 22 | // distribution. 23 | // 24 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | // 37 | //====================================================================== 38 | 39 | module aes_key_mem( 40 | input wire clk, 41 | input wire reset_n, 42 | 43 | input wire [255 : 0] key, 44 | input wire keylen, 45 | input wire init, 46 | 47 | input wire [3 : 0] round, 48 | output wire [127 : 0] round_key, 49 | output wire ready, 50 | 51 | 52 | output wire [31 : 0] sboxw, 53 | input wire [31 : 0] new_sboxw 54 | ); 55 | 56 | 57 | //---------------------------------------------------------------- 58 | // Parameters. 59 | //---------------------------------------------------------------- 60 | localparam AES_128_BIT_KEY = 1'h0; 61 | localparam AES_256_BIT_KEY = 1'h1; 62 | 63 | localparam AES_128_NUM_ROUNDS = 10; 64 | localparam AES_256_NUM_ROUNDS = 14; 65 | 66 | localparam CTRL_IDLE = 3'h0; 67 | localparam CTRL_INIT = 3'h1; 68 | localparam CTRL_GENERATE = 3'h2; 69 | localparam CTRL_DONE = 3'h3; 70 | 71 | 72 | //---------------------------------------------------------------- 73 | // Registers. 74 | //---------------------------------------------------------------- 75 | reg [127 : 0] key_mem [0 : 14]; 76 | reg [127 : 0] key_mem_new; 77 | reg key_mem_we; 78 | 79 | reg [127 : 0] prev_key0_reg; 80 | reg [127 : 0] prev_key0_new; 81 | reg prev_key0_we; 82 | 83 | reg [127 : 0] prev_key1_reg; 84 | reg [127 : 0] prev_key1_new; 85 | reg prev_key1_we; 86 | 87 | reg [3 : 0] round_ctr_reg; 88 | reg [3 : 0] round_ctr_new; 89 | reg round_ctr_rst; 90 | reg round_ctr_inc; 91 | reg round_ctr_we; 92 | 93 | reg [2 : 0] key_mem_ctrl_reg; 94 | reg [2 : 0] key_mem_ctrl_new; 95 | reg key_mem_ctrl_we; 96 | 97 | reg ready_reg; 98 | reg ready_new; 99 | reg ready_we; 100 | 101 | reg [7 : 0] rcon_reg; 102 | reg [7 : 0] rcon_new; 103 | reg rcon_we; 104 | reg rcon_set; 105 | reg rcon_next; 106 | 107 | 108 | //---------------------------------------------------------------- 109 | // Wires. 110 | //---------------------------------------------------------------- 111 | reg [31 : 0] tmp_sboxw; 112 | reg round_key_update; 113 | reg [127 : 0] tmp_round_key; 114 | 115 | 116 | //---------------------------------------------------------------- 117 | // Concurrent assignments for ports. 118 | //---------------------------------------------------------------- 119 | assign round_key = tmp_round_key; 120 | assign ready = ready_reg; 121 | assign sboxw = tmp_sboxw; 122 | 123 | 124 | //---------------------------------------------------------------- 125 | // reg_update 126 | // 127 | // Update functionality for all registers in the core. 128 | // All registers are positive edge triggered with asynchronous 129 | // active low reset. All registers have write enable. 130 | //---------------------------------------------------------------- 131 | always @ (posedge clk or negedge reset_n) 132 | begin: reg_update 133 | integer i; 134 | 135 | if (!reset_n) 136 | begin 137 | for (i = 0 ; i <= AES_256_NUM_ROUNDS ; i = i + 1) 138 | key_mem [i] <= 128'h0; 139 | 140 | ready_reg <= 1'b0; 141 | rcon_reg <= 8'h0; 142 | round_ctr_reg <= 4'h0; 143 | prev_key0_reg <= 128'h0; 144 | prev_key1_reg <= 128'h0; 145 | key_mem_ctrl_reg <= CTRL_IDLE; 146 | end 147 | else 148 | begin 149 | if (ready_we) 150 | ready_reg <= ready_new; 151 | 152 | if (rcon_we) 153 | rcon_reg <= rcon_new; 154 | 155 | if (round_ctr_we) 156 | round_ctr_reg <= round_ctr_new; 157 | 158 | if (key_mem_we) 159 | key_mem[round_ctr_reg] <= key_mem_new; 160 | 161 | if (prev_key0_we) 162 | prev_key0_reg <= prev_key0_new; 163 | 164 | if (prev_key1_we) 165 | prev_key1_reg <= prev_key1_new; 166 | 167 | if (key_mem_ctrl_we) 168 | key_mem_ctrl_reg <= key_mem_ctrl_new; 169 | end 170 | end // reg_update 171 | 172 | 173 | //---------------------------------------------------------------- 174 | // key_mem_read 175 | // 176 | // Combinational read port for the key memory. 177 | //---------------------------------------------------------------- 178 | always @* 179 | begin : key_mem_read 180 | tmp_round_key = key_mem[round]; 181 | end // key_mem_read 182 | 183 | 184 | //---------------------------------------------------------------- 185 | // round_key_gen 186 | // 187 | // The round key generator logic for AES-128 and AES-256. 188 | //---------------------------------------------------------------- 189 | always @* 190 | begin: round_key_gen 191 | reg [31 : 0] w0, w1, w2, w3, w4, w5, w6, w7; 192 | reg [31 : 0] k0, k1, k2, k3; 193 | reg [31 : 0] rconw, rotstw, tw, trw; 194 | 195 | // Default assignments. 196 | key_mem_new = 128'h0; 197 | key_mem_we = 1'b0; 198 | prev_key0_new = 128'h0; 199 | prev_key0_we = 1'b0; 200 | prev_key1_new = 128'h0; 201 | prev_key1_we = 1'b0; 202 | 203 | k0 = 32'h0; 204 | k1 = 32'h0; 205 | k2 = 32'h0; 206 | k3 = 32'h0; 207 | 208 | rcon_set = 1'b1; 209 | rcon_next = 1'b0; 210 | 211 | // Extract words and calculate intermediate values. 212 | // Perform rotation of sbox word etc. 213 | w0 = prev_key0_reg[127 : 096]; 214 | w1 = prev_key0_reg[095 : 064]; 215 | w2 = prev_key0_reg[063 : 032]; 216 | w3 = prev_key0_reg[031 : 000]; 217 | 218 | w4 = prev_key1_reg[127 : 096]; 219 | w5 = prev_key1_reg[095 : 064]; 220 | w6 = prev_key1_reg[063 : 032]; 221 | w7 = prev_key1_reg[031 : 000]; 222 | 223 | rconw = {rcon_reg, 24'h0}; 224 | tmp_sboxw = w7; 225 | rotstw = {new_sboxw[23 : 00], new_sboxw[31 : 24]}; 226 | trw = rotstw ^ rconw; 227 | tw = new_sboxw; 228 | 229 | // Generate the specific round keys. 230 | if (round_key_update) 231 | begin 232 | rcon_set = 1'b0; 233 | key_mem_we = 1'b1; 234 | case (keylen) 235 | AES_128_BIT_KEY: 236 | begin 237 | if (round_ctr_reg == 0) 238 | begin 239 | key_mem_new = key[255 : 128]; 240 | prev_key1_new = key[255 : 128]; 241 | prev_key1_we = 1'b1; 242 | rcon_next = 1'b1; 243 | end 244 | else 245 | begin 246 | k0 = w4 ^ trw; 247 | k1 = w5 ^ w4 ^ trw; 248 | k2 = w6 ^ w5 ^ w4 ^ trw; 249 | k3 = w7 ^ w6 ^ w5 ^ w4 ^ trw; 250 | 251 | key_mem_new = {k0, k1, k2, k3}; 252 | prev_key1_new = {k0, k1, k2, k3}; 253 | prev_key1_we = 1'b1; 254 | rcon_next = 1'b1; 255 | end 256 | end 257 | 258 | AES_256_BIT_KEY: 259 | begin 260 | if (round_ctr_reg == 0) 261 | begin 262 | key_mem_new = key[255 : 128]; 263 | prev_key0_new = key[255 : 128]; 264 | prev_key0_we = 1'b1; 265 | end 266 | else if (round_ctr_reg == 1) 267 | begin 268 | key_mem_new = key[127 : 0]; 269 | prev_key1_new = key[127 : 0]; 270 | prev_key1_we = 1'b1; 271 | rcon_next = 1'b1; 272 | end 273 | else 274 | begin 275 | if (round_ctr_reg[0] == 0) 276 | begin 277 | k0 = w0 ^ trw; 278 | k1 = w1 ^ w0 ^ trw; 279 | k2 = w2 ^ w1 ^ w0 ^ trw; 280 | k3 = w3 ^ w2 ^ w1 ^ w0 ^ trw; 281 | end 282 | else 283 | begin 284 | k0 = w0 ^ tw; 285 | k1 = w1 ^ w0 ^ tw; 286 | k2 = w2 ^ w1 ^ w0 ^ tw; 287 | k3 = w3 ^ w2 ^ w1 ^ w0 ^ tw; 288 | rcon_next = 1'b1; 289 | end 290 | 291 | // Store the generated round keys. 292 | key_mem_new = {k0, k1, k2, k3}; 293 | prev_key1_new = {k0, k1, k2, k3}; 294 | prev_key1_we = 1'b1; 295 | prev_key0_new = prev_key1_reg; 296 | prev_key0_we = 1'b1; 297 | end 298 | end 299 | 300 | default: 301 | begin 302 | end 303 | endcase // case (keylen) 304 | end 305 | end // round_key_gen 306 | 307 | 308 | //---------------------------------------------------------------- 309 | // rcon_logic 310 | // 311 | // Caclulates the rcon value for the different key expansion 312 | // iterations. 313 | //---------------------------------------------------------------- 314 | always @* 315 | begin : rcon_logic 316 | reg [7 : 0] tmp_rcon; 317 | rcon_new = 8'h00; 318 | rcon_we = 1'b0; 319 | 320 | tmp_rcon = {rcon_reg[6 : 0], 1'b0} ^ (8'h1b & {8{rcon_reg[7]}}); 321 | 322 | if (rcon_set) 323 | begin 324 | rcon_new = 8'h8d; 325 | rcon_we = 1'b1; 326 | end 327 | 328 | if (rcon_next) 329 | begin 330 | rcon_new = tmp_rcon[7 : 0]; 331 | rcon_we = 1'b1; 332 | end 333 | end 334 | 335 | 336 | //---------------------------------------------------------------- 337 | // round_ctr 338 | // 339 | // The round counter logic with increase and reset. 340 | //---------------------------------------------------------------- 341 | always @* 342 | begin : round_ctr 343 | round_ctr_new = 4'h0; 344 | round_ctr_we = 1'b0; 345 | 346 | if (round_ctr_rst) 347 | begin 348 | round_ctr_new = 4'h0; 349 | round_ctr_we = 1'b1; 350 | end 351 | 352 | else if (round_ctr_inc) 353 | begin 354 | round_ctr_new = round_ctr_reg + 1'b1; 355 | round_ctr_we = 1'b1; 356 | end 357 | end 358 | 359 | 360 | //---------------------------------------------------------------- 361 | // key_mem_ctrl 362 | // 363 | // 364 | // The FSM that controls the round key generation. 365 | //---------------------------------------------------------------- 366 | always @* 367 | begin: key_mem_ctrl 368 | reg [3 : 0] num_rounds; 369 | 370 | // Default assignments. 371 | ready_new = 1'b0; 372 | ready_we = 1'b0; 373 | round_key_update = 1'b0; 374 | round_ctr_rst = 1'b0; 375 | round_ctr_inc = 1'b0; 376 | key_mem_ctrl_new = CTRL_IDLE; 377 | key_mem_ctrl_we = 1'b0; 378 | 379 | if (keylen == AES_128_BIT_KEY) 380 | num_rounds = AES_128_NUM_ROUNDS; 381 | else 382 | num_rounds = AES_256_NUM_ROUNDS; 383 | 384 | case(key_mem_ctrl_reg) 385 | CTRL_IDLE: 386 | begin 387 | if (init) 388 | begin 389 | ready_new = 1'b0; 390 | ready_we = 1'b1; 391 | key_mem_ctrl_new = CTRL_INIT; 392 | key_mem_ctrl_we = 1'b1; 393 | end 394 | end 395 | 396 | CTRL_INIT: 397 | begin 398 | round_ctr_rst = 1'b1; 399 | key_mem_ctrl_new = CTRL_GENERATE; 400 | key_mem_ctrl_we = 1'b1; 401 | end 402 | 403 | CTRL_GENERATE: 404 | begin 405 | round_ctr_inc = 1'b1; 406 | round_key_update = 1'b1; 407 | if (round_ctr_reg == num_rounds) 408 | begin 409 | key_mem_ctrl_new = CTRL_DONE; 410 | key_mem_ctrl_we = 1'b1; 411 | end 412 | end 413 | 414 | CTRL_DONE: 415 | begin 416 | ready_new = 1'b1; 417 | ready_we = 1'b1; 418 | key_mem_ctrl_new = CTRL_IDLE; 419 | key_mem_ctrl_we = 1'b1; 420 | end 421 | 422 | default: 423 | begin 424 | end 425 | endcase // case (key_mem_ctrl_reg) 426 | 427 | end // key_mem_ctrl 428 | endmodule // aes_key_mem 429 | 430 | //====================================================================== 431 | // EOF aes_key_mem.v 432 | //====================================================================== 433 | -------------------------------------------------------------------------------- /src/main/resources/vsrc/aes_encipher_block.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // aes_encipher_block.v 4 | // -------------------- 5 | // The AES encipher round. A pure combinational module that implements 6 | // the initial round, main round and final round logic for 7 | // enciper operations. 8 | // 9 | // 10 | // Author: Joachim Strombergson 11 | // Copyright (c) 2013, 2014, Secworks Sweden AB 12 | // All rights reserved. 13 | // 14 | // Redistribution and use in source and binary forms, with or 15 | // without modification, are permitted provided that the following 16 | // conditions are met: 17 | // 18 | // 1. Redistributions of source code must retain the above copyright 19 | // notice, this list of conditions and the following disclaimer. 20 | // 21 | // 2. Redistributions in binary form must reproduce the above copyright 22 | // notice, this list of conditions and the following disclaimer in 23 | // the documentation and/or other materials provided with the 24 | // distribution. 25 | // 26 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 29 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 30 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 31 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 32 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 35 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 37 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | // 39 | //====================================================================== 40 | 41 | module aes_encipher_block( 42 | input wire clk, 43 | input wire reset_n, 44 | 45 | input wire next, 46 | 47 | input wire keylen, 48 | output wire [3 : 0] round, 49 | input wire [127 : 0] round_key, 50 | 51 | output wire [31 : 0] sboxw, 52 | input wire [31 : 0] new_sboxw, 53 | 54 | input wire [127 : 0] block, 55 | output wire [127 : 0] new_block, 56 | output wire ready 57 | ); 58 | 59 | 60 | //---------------------------------------------------------------- 61 | // Internal constant and parameter definitions. 62 | //---------------------------------------------------------------- 63 | localparam AES_128_BIT_KEY = 1'h0; 64 | localparam AES_256_BIT_KEY = 1'h1; 65 | 66 | localparam AES128_ROUNDS = 4'ha; 67 | localparam AES256_ROUNDS = 4'he; 68 | 69 | localparam NO_UPDATE = 3'h0; 70 | localparam INIT_UPDATE = 3'h1; 71 | localparam SBOX_UPDATE = 3'h2; 72 | localparam MAIN_UPDATE = 3'h3; 73 | localparam FINAL_UPDATE = 3'h4; 74 | 75 | localparam CTRL_IDLE = 3'h0; 76 | localparam CTRL_INIT = 3'h1; 77 | localparam CTRL_SBOX = 3'h2; 78 | localparam CTRL_MAIN = 3'h3; 79 | localparam CTRL_FINAL = 3'h4; 80 | 81 | 82 | //---------------------------------------------------------------- 83 | // Round functions with sub functions. 84 | //---------------------------------------------------------------- 85 | function [7 : 0] gm2(input [7 : 0] op); 86 | begin 87 | gm2 = {op[6 : 0], 1'b0} ^ (8'h1b & {8{op[7]}}); 88 | end 89 | endfunction // gm2 90 | 91 | function [7 : 0] gm3(input [7 : 0] op); 92 | begin 93 | gm3 = gm2(op) ^ op; 94 | end 95 | endfunction // gm3 96 | 97 | function [31 : 0] mixw(input [31 : 0] w); 98 | reg [7 : 0] b0, b1, b2, b3; 99 | reg [7 : 0] mb0, mb1, mb2, mb3; 100 | begin 101 | b0 = w[31 : 24]; 102 | b1 = w[23 : 16]; 103 | b2 = w[15 : 08]; 104 | b3 = w[07 : 00]; 105 | 106 | mb0 = gm2(b0) ^ gm3(b1) ^ b2 ^ b3; 107 | mb1 = b0 ^ gm2(b1) ^ gm3(b2) ^ b3; 108 | mb2 = b0 ^ b1 ^ gm2(b2) ^ gm3(b3); 109 | mb3 = gm3(b0) ^ b1 ^ b2 ^ gm2(b3); 110 | 111 | mixw = {mb0, mb1, mb2, mb3}; 112 | end 113 | endfunction // mixw 114 | 115 | function [127 : 0] mixcolumns(input [127 : 0] data); 116 | reg [31 : 0] w0, w1, w2, w3; 117 | reg [31 : 0] ws0, ws1, ws2, ws3; 118 | begin 119 | w0 = data[127 : 096]; 120 | w1 = data[095 : 064]; 121 | w2 = data[063 : 032]; 122 | w3 = data[031 : 000]; 123 | 124 | ws0 = mixw(w0); 125 | ws1 = mixw(w1); 126 | ws2 = mixw(w2); 127 | ws3 = mixw(w3); 128 | 129 | mixcolumns = {ws0, ws1, ws2, ws3}; 130 | end 131 | endfunction // mixcolumns 132 | 133 | function [127 : 0] shiftrows(input [127 : 0] data); 134 | reg [31 : 0] w0, w1, w2, w3; 135 | reg [31 : 0] ws0, ws1, ws2, ws3; 136 | begin 137 | w0 = data[127 : 096]; 138 | w1 = data[095 : 064]; 139 | w2 = data[063 : 032]; 140 | w3 = data[031 : 000]; 141 | 142 | ws0 = {w0[31 : 24], w1[23 : 16], w2[15 : 08], w3[07 : 00]}; 143 | ws1 = {w1[31 : 24], w2[23 : 16], w3[15 : 08], w0[07 : 00]}; 144 | ws2 = {w2[31 : 24], w3[23 : 16], w0[15 : 08], w1[07 : 00]}; 145 | ws3 = {w3[31 : 24], w0[23 : 16], w1[15 : 08], w2[07 : 00]}; 146 | 147 | shiftrows = {ws0, ws1, ws2, ws3}; 148 | end 149 | endfunction // shiftrows 150 | 151 | function [127 : 0] addroundkey(input [127 : 0] data, input [127 : 0] rkey); 152 | begin 153 | addroundkey = data ^ rkey; 154 | end 155 | endfunction // addroundkey 156 | 157 | 158 | //---------------------------------------------------------------- 159 | // Registers including update variables and write enable. 160 | //---------------------------------------------------------------- 161 | reg [1 : 0] sword_ctr_reg; 162 | reg [1 : 0] sword_ctr_new; 163 | reg sword_ctr_we; 164 | reg sword_ctr_inc; 165 | reg sword_ctr_rst; 166 | 167 | reg [3 : 0] round_ctr_reg; 168 | reg [3 : 0] round_ctr_new; 169 | reg round_ctr_we; 170 | reg round_ctr_rst; 171 | reg round_ctr_inc; 172 | 173 | reg [127 : 0] block_new; 174 | reg [31 : 0] block_w0_reg; 175 | reg [31 : 0] block_w1_reg; 176 | reg [31 : 0] block_w2_reg; 177 | reg [31 : 0] block_w3_reg; 178 | reg block_w0_we; 179 | reg block_w1_we; 180 | reg block_w2_we; 181 | reg block_w3_we; 182 | 183 | reg ready_reg; 184 | reg ready_new; 185 | reg ready_we; 186 | 187 | reg [2 : 0] enc_ctrl_reg; 188 | reg [2 : 0] enc_ctrl_new; 189 | reg enc_ctrl_we; 190 | 191 | 192 | //---------------------------------------------------------------- 193 | // Wires. 194 | //---------------------------------------------------------------- 195 | reg [2 : 0] update_type; 196 | reg [31 : 0] muxed_sboxw; 197 | 198 | 199 | //---------------------------------------------------------------- 200 | // Concurrent connectivity for ports etc. 201 | //---------------------------------------------------------------- 202 | assign round = round_ctr_reg; 203 | assign sboxw = muxed_sboxw; 204 | assign new_block = {block_w0_reg, block_w1_reg, block_w2_reg, block_w3_reg}; 205 | assign ready = ready_reg; 206 | 207 | 208 | //---------------------------------------------------------------- 209 | // reg_update 210 | // 211 | // Update functionality for all registers in the core. 212 | // All registers are positive edge triggered with asynchronous 213 | // active low reset. All registers have write enable. 214 | //---------------------------------------------------------------- 215 | always @ (posedge clk or negedge reset_n) 216 | begin: reg_update 217 | if (!reset_n) 218 | begin 219 | block_w0_reg <= 32'h0; 220 | block_w1_reg <= 32'h0; 221 | block_w2_reg <= 32'h0; 222 | block_w3_reg <= 32'h0; 223 | sword_ctr_reg <= 2'h0; 224 | round_ctr_reg <= 4'h0; 225 | ready_reg <= 1'b1; 226 | enc_ctrl_reg <= CTRL_IDLE; 227 | end 228 | else 229 | begin 230 | if (block_w0_we) 231 | block_w0_reg <= block_new[127 : 096]; 232 | 233 | if (block_w1_we) 234 | block_w1_reg <= block_new[095 : 064]; 235 | 236 | if (block_w2_we) 237 | block_w2_reg <= block_new[063 : 032]; 238 | 239 | if (block_w3_we) 240 | block_w3_reg <= block_new[031 : 000]; 241 | 242 | if (sword_ctr_we) 243 | sword_ctr_reg <= sword_ctr_new; 244 | 245 | if (round_ctr_we) 246 | round_ctr_reg <= round_ctr_new; 247 | 248 | if (ready_we) 249 | ready_reg <= ready_new; 250 | 251 | if (enc_ctrl_we) 252 | enc_ctrl_reg <= enc_ctrl_new; 253 | end 254 | end // reg_update 255 | 256 | 257 | //---------------------------------------------------------------- 258 | // round_logic 259 | // 260 | // The logic needed to implement init, main and final rounds. 261 | //---------------------------------------------------------------- 262 | always @* 263 | begin : round_logic 264 | reg [127 : 0] old_block, shiftrows_block, mixcolumns_block; 265 | reg [127 : 0] addkey_init_block, addkey_main_block, addkey_final_block; 266 | 267 | block_new = 128'h0; 268 | muxed_sboxw = 32'h0; 269 | block_w0_we = 1'b0; 270 | block_w1_we = 1'b0; 271 | block_w2_we = 1'b0; 272 | block_w3_we = 1'b0; 273 | 274 | old_block = {block_w0_reg, block_w1_reg, block_w2_reg, block_w3_reg}; 275 | shiftrows_block = shiftrows(old_block); 276 | mixcolumns_block = mixcolumns(shiftrows_block); 277 | addkey_init_block = addroundkey(block, round_key); 278 | addkey_main_block = addroundkey(mixcolumns_block, round_key); 279 | addkey_final_block = addroundkey(shiftrows_block, round_key); 280 | 281 | case (update_type) 282 | INIT_UPDATE: 283 | begin 284 | block_new = addkey_init_block; 285 | block_w0_we = 1'b1; 286 | block_w1_we = 1'b1; 287 | block_w2_we = 1'b1; 288 | block_w3_we = 1'b1; 289 | end 290 | 291 | SBOX_UPDATE: 292 | begin 293 | block_new = {new_sboxw, new_sboxw, new_sboxw, new_sboxw}; 294 | 295 | case (sword_ctr_reg) 296 | 2'h0: 297 | begin 298 | muxed_sboxw = block_w0_reg; 299 | block_w0_we = 1'b1; 300 | end 301 | 302 | 2'h1: 303 | begin 304 | muxed_sboxw = block_w1_reg; 305 | block_w1_we = 1'b1; 306 | end 307 | 308 | 2'h2: 309 | begin 310 | muxed_sboxw = block_w2_reg; 311 | block_w2_we = 1'b1; 312 | end 313 | 314 | 2'h3: 315 | begin 316 | muxed_sboxw = block_w3_reg; 317 | block_w3_we = 1'b1; 318 | end 319 | endcase // case (sbox_mux_ctrl_reg) 320 | end 321 | 322 | MAIN_UPDATE: 323 | begin 324 | block_new = addkey_main_block; 325 | block_w0_we = 1'b1; 326 | block_w1_we = 1'b1; 327 | block_w2_we = 1'b1; 328 | block_w3_we = 1'b1; 329 | end 330 | 331 | FINAL_UPDATE: 332 | begin 333 | block_new = addkey_final_block; 334 | block_w0_we = 1'b1; 335 | block_w1_we = 1'b1; 336 | block_w2_we = 1'b1; 337 | block_w3_we = 1'b1; 338 | end 339 | 340 | default: 341 | begin 342 | end 343 | endcase // case (update_type) 344 | end // round_logic 345 | 346 | 347 | //---------------------------------------------------------------- 348 | // sword_ctr 349 | // 350 | // The subbytes word counter with reset and increase logic. 351 | //---------------------------------------------------------------- 352 | always @* 353 | begin : sword_ctr 354 | sword_ctr_new = 2'h0; 355 | sword_ctr_we = 1'b0; 356 | 357 | if (sword_ctr_rst) 358 | begin 359 | sword_ctr_new = 2'h0; 360 | sword_ctr_we = 1'b1; 361 | end 362 | else if (sword_ctr_inc) 363 | begin 364 | sword_ctr_new = sword_ctr_reg + 1'b1; 365 | sword_ctr_we = 1'b1; 366 | end 367 | end // sword_ctr 368 | 369 | 370 | //---------------------------------------------------------------- 371 | // round_ctr 372 | // 373 | // The round counter with reset and increase logic. 374 | //---------------------------------------------------------------- 375 | always @* 376 | begin : round_ctr 377 | round_ctr_new = 4'h0; 378 | round_ctr_we = 1'b0; 379 | 380 | if (round_ctr_rst) 381 | begin 382 | round_ctr_new = 4'h0; 383 | round_ctr_we = 1'b1; 384 | end 385 | else if (round_ctr_inc) 386 | begin 387 | round_ctr_new = round_ctr_reg + 1'b1; 388 | round_ctr_we = 1'b1; 389 | end 390 | end // round_ctr 391 | 392 | 393 | //---------------------------------------------------------------- 394 | // encipher_ctrl 395 | // 396 | // The FSM that controls the encipher operations. 397 | //---------------------------------------------------------------- 398 | always @* 399 | begin: encipher_ctrl 400 | reg [3 : 0] num_rounds; 401 | 402 | // Default assignments. 403 | sword_ctr_inc = 1'b0; 404 | sword_ctr_rst = 1'b0; 405 | round_ctr_inc = 1'b0; 406 | round_ctr_rst = 1'b0; 407 | ready_new = 1'b0; 408 | ready_we = 1'b0; 409 | update_type = NO_UPDATE; 410 | enc_ctrl_new = CTRL_IDLE; 411 | enc_ctrl_we = 1'b0; 412 | 413 | if (keylen == AES_256_BIT_KEY) 414 | begin 415 | num_rounds = AES256_ROUNDS; 416 | end 417 | else 418 | begin 419 | num_rounds = AES128_ROUNDS; 420 | end 421 | 422 | case(enc_ctrl_reg) 423 | CTRL_IDLE: 424 | begin 425 | if (next) 426 | begin 427 | round_ctr_rst = 1'b1; 428 | ready_new = 1'b0; 429 | ready_we = 1'b1; 430 | enc_ctrl_new = CTRL_INIT; 431 | enc_ctrl_we = 1'b1; 432 | end 433 | end 434 | 435 | CTRL_INIT: 436 | begin 437 | round_ctr_inc = 1'b1; 438 | sword_ctr_rst = 1'b1; 439 | update_type = INIT_UPDATE; 440 | enc_ctrl_new = CTRL_SBOX; 441 | enc_ctrl_we = 1'b1; 442 | end 443 | 444 | CTRL_SBOX: 445 | begin 446 | sword_ctr_inc = 1'b1; 447 | update_type = SBOX_UPDATE; 448 | if (sword_ctr_reg == 2'h3) 449 | begin 450 | enc_ctrl_new = CTRL_MAIN; 451 | enc_ctrl_we = 1'b1; 452 | end 453 | end 454 | 455 | CTRL_MAIN: 456 | begin 457 | sword_ctr_rst = 1'b1; 458 | round_ctr_inc = 1'b1; 459 | if (round_ctr_reg < num_rounds) 460 | begin 461 | update_type = MAIN_UPDATE; 462 | enc_ctrl_new = CTRL_SBOX; 463 | enc_ctrl_we = 1'b1; 464 | end 465 | else 466 | begin 467 | update_type = FINAL_UPDATE; 468 | ready_new = 1'b1; 469 | ready_we = 1'b1; 470 | enc_ctrl_new = CTRL_IDLE; 471 | enc_ctrl_we = 1'b1; 472 | end 473 | end 474 | 475 | default: 476 | begin 477 | // Empty. Just here to make the synthesis tool happy. 478 | end 479 | endcase // case (enc_ctrl_reg) 480 | end // encipher_ctrl 481 | 482 | endmodule // aes_encipher_block 483 | 484 | //====================================================================== 485 | // EOF aes_encipher_block.v 486 | //====================================================================== 487 | -------------------------------------------------------------------------------- /src/main/resources/vsrc/aes_decipher_block.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // aes_decipher_block.v 4 | // -------------------- 5 | // The AES decipher round. A pure combinational module that implements 6 | // the initial round, main round and final round logic for 7 | // decciper operations. 8 | // 9 | // 10 | // Author: Joachim Strombergson 11 | // Copyright (c) 2013, 2014, Secworks Sweden AB 12 | // All rights reserved. 13 | // 14 | // Redistribution and use in source and binary forms, with or 15 | // without modification, are permitted provided that the following 16 | // conditions are met: 17 | // 18 | // 1. Redistributions of source code must retain the above copyright 19 | // notice, this list of conditions and the following disclaimer. 20 | // 21 | // 2. Redistributions in binary form must reproduce the above copyright 22 | // notice, this list of conditions and the following disclaimer in 23 | // the documentation and/or other materials provided with the 24 | // distribution. 25 | // 26 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 29 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 30 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 31 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 32 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 35 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 37 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | // 39 | //====================================================================== 40 | 41 | module aes_decipher_block( 42 | input wire clk, 43 | input wire reset_n, 44 | 45 | input wire next, 46 | 47 | input wire keylen, 48 | output wire [3 : 0] round, 49 | input wire [127 : 0] round_key, 50 | 51 | input wire [127 : 0] block, 52 | output wire [127 : 0] new_block, 53 | output wire ready 54 | ); 55 | 56 | 57 | //---------------------------------------------------------------- 58 | // Internal constant and parameter definitions. 59 | //---------------------------------------------------------------- 60 | localparam AES_128_BIT_KEY = 1'h0; 61 | localparam AES_256_BIT_KEY = 1'h1; 62 | 63 | localparam AES128_ROUNDS = 4'ha; 64 | localparam AES256_ROUNDS = 4'he; 65 | 66 | localparam NO_UPDATE = 3'h0; 67 | localparam INIT_UPDATE = 3'h1; 68 | localparam SBOX_UPDATE = 3'h2; 69 | localparam MAIN_UPDATE = 3'h3; 70 | localparam FINAL_UPDATE = 3'h4; 71 | 72 | localparam CTRL_IDLE = 3'h0; 73 | localparam CTRL_INIT = 3'h1; 74 | localparam CTRL_SBOX = 3'h2; 75 | localparam CTRL_MAIN = 3'h3; 76 | localparam CTRL_FINAL = 3'h4; 77 | 78 | 79 | //---------------------------------------------------------------- 80 | // Gaolis multiplication functions for Inverse MixColumn. 81 | //---------------------------------------------------------------- 82 | function [7 : 0] gm2(input [7 : 0] op); 83 | begin 84 | gm2 = {op[6 : 0], 1'b0} ^ (8'h1b & {8{op[7]}}); 85 | end 86 | endfunction // gm2 87 | 88 | function [7 : 0] gm3(input [7 : 0] op); 89 | begin 90 | gm3 = gm2(op) ^ op; 91 | end 92 | endfunction // gm3 93 | 94 | function [7 : 0] gm4(input [7 : 0] op); 95 | begin 96 | gm4 = gm2(gm2(op)); 97 | end 98 | endfunction // gm4 99 | 100 | function [7 : 0] gm8(input [7 : 0] op); 101 | begin 102 | gm8 = gm2(gm4(op)); 103 | end 104 | endfunction // gm8 105 | 106 | function [7 : 0] gm09(input [7 : 0] op); 107 | begin 108 | gm09 = gm8(op) ^ op; 109 | end 110 | endfunction // gm09 111 | 112 | function [7 : 0] gm11(input [7 : 0] op); 113 | begin 114 | gm11 = gm8(op) ^ gm2(op) ^ op; 115 | end 116 | endfunction // gm11 117 | 118 | function [7 : 0] gm13(input [7 : 0] op); 119 | begin 120 | gm13 = gm8(op) ^ gm4(op) ^ op; 121 | end 122 | endfunction // gm13 123 | 124 | function [7 : 0] gm14(input [7 : 0] op); 125 | begin 126 | gm14 = gm8(op) ^ gm4(op) ^ gm2(op); 127 | end 128 | endfunction // gm14 129 | 130 | function [31 : 0] inv_mixw(input [31 : 0] w); 131 | reg [7 : 0] b0, b1, b2, b3; 132 | reg [7 : 0] mb0, mb1, mb2, mb3; 133 | begin 134 | b0 = w[31 : 24]; 135 | b1 = w[23 : 16]; 136 | b2 = w[15 : 08]; 137 | b3 = w[07 : 00]; 138 | 139 | mb0 = gm14(b0) ^ gm11(b1) ^ gm13(b2) ^ gm09(b3); 140 | mb1 = gm09(b0) ^ gm14(b1) ^ gm11(b2) ^ gm13(b3); 141 | mb2 = gm13(b0) ^ gm09(b1) ^ gm14(b2) ^ gm11(b3); 142 | mb3 = gm11(b0) ^ gm13(b1) ^ gm09(b2) ^ gm14(b3); 143 | 144 | inv_mixw = {mb0, mb1, mb2, mb3}; 145 | end 146 | endfunction // mixw 147 | 148 | function [127 : 0] inv_mixcolumns(input [127 : 0] data); 149 | reg [31 : 0] w0, w1, w2, w3; 150 | reg [31 : 0] ws0, ws1, ws2, ws3; 151 | begin 152 | w0 = data[127 : 096]; 153 | w1 = data[095 : 064]; 154 | w2 = data[063 : 032]; 155 | w3 = data[031 : 000]; 156 | 157 | ws0 = inv_mixw(w0); 158 | ws1 = inv_mixw(w1); 159 | ws2 = inv_mixw(w2); 160 | ws3 = inv_mixw(w3); 161 | 162 | inv_mixcolumns = {ws0, ws1, ws2, ws3}; 163 | end 164 | endfunction // inv_mixcolumns 165 | 166 | function [127 : 0] inv_shiftrows(input [127 : 0] data); 167 | reg [31 : 0] w0, w1, w2, w3; 168 | reg [31 : 0] ws0, ws1, ws2, ws3; 169 | begin 170 | w0 = data[127 : 096]; 171 | w1 = data[095 : 064]; 172 | w2 = data[063 : 032]; 173 | w3 = data[031 : 000]; 174 | 175 | ws0 = {w0[31 : 24], w3[23 : 16], w2[15 : 08], w1[07 : 00]}; 176 | ws1 = {w1[31 : 24], w0[23 : 16], w3[15 : 08], w2[07 : 00]}; 177 | ws2 = {w2[31 : 24], w1[23 : 16], w0[15 : 08], w3[07 : 00]}; 178 | ws3 = {w3[31 : 24], w2[23 : 16], w1[15 : 08], w0[07 : 00]}; 179 | 180 | inv_shiftrows = {ws0, ws1, ws2, ws3}; 181 | end 182 | endfunction // inv_shiftrows 183 | 184 | function [127 : 0] addroundkey(input [127 : 0] data, input [127 : 0] rkey); 185 | begin 186 | addroundkey = data ^ rkey; 187 | end 188 | endfunction // addroundkey 189 | 190 | 191 | //---------------------------------------------------------------- 192 | // Registers including update variables and write enable. 193 | //---------------------------------------------------------------- 194 | reg [1 : 0] sword_ctr_reg; 195 | reg [1 : 0] sword_ctr_new; 196 | reg sword_ctr_we; 197 | reg sword_ctr_inc; 198 | reg sword_ctr_rst; 199 | 200 | reg [3 : 0] round_ctr_reg; 201 | reg [3 : 0] round_ctr_new; 202 | reg round_ctr_we; 203 | reg round_ctr_set; 204 | reg round_ctr_dec; 205 | 206 | reg [127 : 0] block_new; 207 | reg [31 : 0] block_w0_reg; 208 | reg [31 : 0] block_w1_reg; 209 | reg [31 : 0] block_w2_reg; 210 | reg [31 : 0] block_w3_reg; 211 | reg block_w0_we; 212 | reg block_w1_we; 213 | reg block_w2_we; 214 | reg block_w3_we; 215 | 216 | reg ready_reg; 217 | reg ready_new; 218 | reg ready_we; 219 | 220 | reg [2 : 0] dec_ctrl_reg; 221 | reg [2 : 0] dec_ctrl_new; 222 | reg dec_ctrl_we; 223 | 224 | 225 | //---------------------------------------------------------------- 226 | // Wires. 227 | //---------------------------------------------------------------- 228 | reg [31 : 0] tmp_sboxw; 229 | wire [31 : 0] new_sboxw; 230 | reg [2 : 0] update_type; 231 | 232 | 233 | //---------------------------------------------------------------- 234 | // Instantiations. 235 | //---------------------------------------------------------------- 236 | aes_inv_sbox inv_sbox_inst(.sword(tmp_sboxw), .new_sword(new_sboxw)); 237 | 238 | 239 | //---------------------------------------------------------------- 240 | // Concurrent connectivity for ports etc. 241 | //---------------------------------------------------------------- 242 | assign round = round_ctr_reg; 243 | assign new_block = {block_w0_reg, block_w1_reg, block_w2_reg, block_w3_reg}; 244 | assign ready = ready_reg; 245 | 246 | 247 | //---------------------------------------------------------------- 248 | // reg_update 249 | // 250 | // Update functionality for all registers in the core. 251 | // All registers are positive edge triggered with synchronous 252 | // active low reset. All registers have write enable. 253 | //---------------------------------------------------------------- 254 | always @ (posedge clk or negedge reset_n) 255 | begin: reg_update 256 | if (!reset_n) 257 | begin 258 | block_w0_reg <= 32'h0; 259 | block_w1_reg <= 32'h0; 260 | block_w2_reg <= 32'h0; 261 | block_w3_reg <= 32'h0; 262 | sword_ctr_reg <= 2'h0; 263 | round_ctr_reg <= 4'h0; 264 | ready_reg <= 1'b1; 265 | dec_ctrl_reg <= CTRL_IDLE; 266 | end 267 | else 268 | begin 269 | if (block_w0_we) 270 | block_w0_reg <= block_new[127 : 096]; 271 | 272 | if (block_w1_we) 273 | block_w1_reg <= block_new[095 : 064]; 274 | 275 | if (block_w2_we) 276 | block_w2_reg <= block_new[063 : 032]; 277 | 278 | if (block_w3_we) 279 | block_w3_reg <= block_new[031 : 000]; 280 | 281 | if (sword_ctr_we) 282 | sword_ctr_reg <= sword_ctr_new; 283 | 284 | if (round_ctr_we) 285 | round_ctr_reg <= round_ctr_new; 286 | 287 | if (ready_we) 288 | ready_reg <= ready_new; 289 | 290 | if (dec_ctrl_we) 291 | dec_ctrl_reg <= dec_ctrl_new; 292 | end 293 | end // reg_update 294 | 295 | 296 | //---------------------------------------------------------------- 297 | // round_logic 298 | // 299 | // The logic needed to implement init, main and final rounds. 300 | //---------------------------------------------------------------- 301 | always @* 302 | begin : round_logic 303 | reg [127 : 0] old_block, inv_shiftrows_block, inv_mixcolumns_block; 304 | reg [127 : 0] addkey_block; 305 | 306 | inv_shiftrows_block = 128'h0; 307 | inv_mixcolumns_block = 128'h0; 308 | addkey_block = 128'h0; 309 | block_new = 128'h0; 310 | tmp_sboxw = 32'h0; 311 | block_w0_we = 1'b0; 312 | block_w1_we = 1'b0; 313 | block_w2_we = 1'b0; 314 | block_w3_we = 1'b0; 315 | 316 | old_block = {block_w0_reg, block_w1_reg, block_w2_reg, block_w3_reg}; 317 | 318 | // Update based on update type. 319 | case (update_type) 320 | // InitRound 321 | INIT_UPDATE: 322 | begin 323 | old_block = block; 324 | addkey_block = addroundkey(old_block, round_key); 325 | inv_shiftrows_block = inv_shiftrows(addkey_block); 326 | block_new = inv_shiftrows_block; 327 | block_w0_we = 1'b1; 328 | block_w1_we = 1'b1; 329 | block_w2_we = 1'b1; 330 | block_w3_we = 1'b1; 331 | end 332 | 333 | SBOX_UPDATE: 334 | begin 335 | block_new = {new_sboxw, new_sboxw, new_sboxw, new_sboxw}; 336 | 337 | case (sword_ctr_reg) 338 | 2'h0: 339 | begin 340 | tmp_sboxw = block_w0_reg; 341 | block_w0_we = 1'b1; 342 | end 343 | 344 | 2'h1: 345 | begin 346 | tmp_sboxw = block_w1_reg; 347 | block_w1_we = 1'b1; 348 | end 349 | 350 | 2'h2: 351 | begin 352 | tmp_sboxw = block_w2_reg; 353 | block_w2_we = 1'b1; 354 | end 355 | 356 | 2'h3: 357 | begin 358 | tmp_sboxw = block_w3_reg; 359 | block_w3_we = 1'b1; 360 | end 361 | endcase // case (sbox_mux_ctrl_reg) 362 | end 363 | 364 | MAIN_UPDATE: 365 | begin 366 | addkey_block = addroundkey(old_block, round_key); 367 | inv_mixcolumns_block = inv_mixcolumns(addkey_block); 368 | inv_shiftrows_block = inv_shiftrows(inv_mixcolumns_block); 369 | block_new = inv_shiftrows_block; 370 | block_w0_we = 1'b1; 371 | block_w1_we = 1'b1; 372 | block_w2_we = 1'b1; 373 | block_w3_we = 1'b1; 374 | end 375 | 376 | FINAL_UPDATE: 377 | begin 378 | block_new = addroundkey(old_block, round_key); 379 | block_w0_we = 1'b1; 380 | block_w1_we = 1'b1; 381 | block_w2_we = 1'b1; 382 | block_w3_we = 1'b1; 383 | end 384 | 385 | default: 386 | begin 387 | end 388 | endcase // case (update_type) 389 | end // round_logic 390 | 391 | 392 | //---------------------------------------------------------------- 393 | // sword_ctr 394 | // 395 | // The subbytes word counter with reset and increase logic. 396 | //---------------------------------------------------------------- 397 | always @* 398 | begin : sword_ctr 399 | sword_ctr_new = 2'h0; 400 | sword_ctr_we = 1'b0; 401 | 402 | if (sword_ctr_rst) 403 | begin 404 | sword_ctr_new = 2'h0; 405 | sword_ctr_we = 1'b1; 406 | end 407 | else if (sword_ctr_inc) 408 | begin 409 | sword_ctr_new = sword_ctr_reg + 1'b1; 410 | sword_ctr_we = 1'b1; 411 | end 412 | end // sword_ctr 413 | 414 | 415 | //---------------------------------------------------------------- 416 | // round_ctr 417 | // 418 | // The round counter with reset and increase logic. 419 | //---------------------------------------------------------------- 420 | always @* 421 | begin : round_ctr 422 | round_ctr_new = 4'h0; 423 | round_ctr_we = 1'b0; 424 | 425 | if (round_ctr_set) 426 | begin 427 | if (keylen == AES_256_BIT_KEY) 428 | begin 429 | round_ctr_new = AES256_ROUNDS; 430 | end 431 | else 432 | begin 433 | round_ctr_new = AES128_ROUNDS; 434 | end 435 | round_ctr_we = 1'b1; 436 | end 437 | else if (round_ctr_dec) 438 | begin 439 | round_ctr_new = round_ctr_reg - 1'b1; 440 | round_ctr_we = 1'b1; 441 | end 442 | end // round_ctr 443 | 444 | 445 | //---------------------------------------------------------------- 446 | // decipher_ctrl 447 | // 448 | // The FSM that controls the decipher operations. 449 | //---------------------------------------------------------------- 450 | always @* 451 | begin: decipher_ctrl 452 | sword_ctr_inc = 1'b0; 453 | sword_ctr_rst = 1'b0; 454 | round_ctr_dec = 1'b0; 455 | round_ctr_set = 1'b0; 456 | ready_new = 1'b0; 457 | ready_we = 1'b0; 458 | update_type = NO_UPDATE; 459 | dec_ctrl_new = CTRL_IDLE; 460 | dec_ctrl_we = 1'b0; 461 | 462 | case(dec_ctrl_reg) 463 | CTRL_IDLE: 464 | begin 465 | if (next) 466 | begin 467 | round_ctr_set = 1'b1; 468 | ready_new = 1'b0; 469 | ready_we = 1'b1; 470 | dec_ctrl_new = CTRL_INIT; 471 | dec_ctrl_we = 1'b1; 472 | end 473 | end 474 | 475 | CTRL_INIT: 476 | begin 477 | sword_ctr_rst = 1'b1; 478 | update_type = INIT_UPDATE; 479 | dec_ctrl_new = CTRL_SBOX; 480 | dec_ctrl_we = 1'b1; 481 | end 482 | 483 | CTRL_SBOX: 484 | begin 485 | sword_ctr_inc = 1'b1; 486 | update_type = SBOX_UPDATE; 487 | if (sword_ctr_reg == 2'h3) 488 | begin 489 | round_ctr_dec = 1'b1; 490 | dec_ctrl_new = CTRL_MAIN; 491 | dec_ctrl_we = 1'b1; 492 | end 493 | end 494 | 495 | CTRL_MAIN: 496 | begin 497 | sword_ctr_rst = 1'b1; 498 | if (round_ctr_reg > 0) 499 | begin 500 | update_type = MAIN_UPDATE; 501 | dec_ctrl_new = CTRL_SBOX; 502 | dec_ctrl_we = 1'b1; 503 | end 504 | else 505 | begin 506 | update_type = FINAL_UPDATE; 507 | ready_new = 1'b1; 508 | ready_we = 1'b1; 509 | dec_ctrl_new = CTRL_IDLE; 510 | dec_ctrl_we = 1'b1; 511 | end 512 | end 513 | 514 | default: 515 | begin 516 | // Empty. Just here to make the synthesis tool happy. 517 | end 518 | endcase // case (dec_ctrl_reg) 519 | end // decipher_ctrl 520 | 521 | endmodule // aes_decipher_block 522 | 523 | //====================================================================== 524 | // EOF aes_decipher_block.v 525 | //====================================================================== 526 | -------------------------------------------------------------------------------- /src/test/scala/DcplrSanityTest.scala: -------------------------------------------------------------------------------- 1 | package aes 2 | 3 | import AESTestUtils._ 4 | import chisel3._ 5 | import chiseltest._ 6 | import org.scalatest.flatspec.AnyFlatSpec 7 | import freechips.rocketchip.config.Parameters 8 | import freechips.rocketchip.tile.{RoCCCommand, RoCCResponse} 9 | import verif._ 10 | 11 | import scala.util.Random 12 | 13 | /* 14 | Tests that verify basic functionality of the decoupler. 15 | */ 16 | 17 | class DcplrSanityTest extends AnyFlatSpec with ChiselScalatestTester { 18 | implicit val p: Parameters = VerifTestUtils.getVerifParameters(xLen = 32) // Testing for our 32b RISC-V chip 19 | 20 | 21 | it should "elaborate the Decoupler" in { 22 | test(new RoCCDecoupler()) { _ => 23 | assert(true) 24 | } 25 | } 26 | 27 | it should "sanity check decoupler output key" in { 28 | test(new RoCCDecoupler()) { c => 29 | // Initializing RoCCCommand driver 30 | val driver = new DecoupledDriverMaster[RoCCCommand](c.clock, c.io.rocc_cmd) 31 | val txProto = new DecoupledTX(new RoCCCommand()) 32 | 33 | // Initialize random generator (for cycle count) 34 | val r = new Random 35 | 36 | // Initialize signals 37 | c.io.reset.poke(false.B) 38 | c.io.rocc_excp.poke(false.B) 39 | c.io.ctrlIO.interrupt.poke(false.B) 40 | c.io.ctrlIO.busy.poke(false.B) 41 | c.io.ctrlIO.excp_ready.poke(false.B) 42 | c.io.ctrlIO.key_ready.poke(false.B) 43 | c.io.ctrlIO.addr_ready.poke(false.B) 44 | c.io.ctrlIO.start_ready.poke(false.B) 45 | c.clock.step() 46 | 47 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 48 | c.clock.step(r.nextInt(100)) 49 | 50 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 51 | // Checking when key ready is low 52 | var addr = r.nextInt(2 << 32) 53 | driver.push(txProto.tx(keyLoad128(addr))) 54 | c.clock.step(2) // 1 cycle for driver, 1 cycle for decoupler (total 2) 55 | 56 | assert(c.io.ctrlIO.key_valid.peek.litToBoolean) 57 | assert(c.io.ctrlIO.key_addr.peek.litValue() == addr) 58 | assert(c.io.ctrlIO.key_size.peek.litValue() == 0) 59 | c.clock.step(r.nextInt(100)) 60 | 61 | assert(c.io.ctrlIO.key_valid.peek.litToBoolean) 62 | assert(c.io.ctrlIO.key_addr.peek.litValue() == addr) 63 | assert(c.io.ctrlIO.key_size.peek.litValue() == 0) 64 | // Asserting key ready. Expect valid to go low next cycle 65 | c.io.ctrlIO.key_ready.poke(true.B) 66 | c.clock.step() 67 | 68 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 69 | c.clock.step(r.nextInt(100)) 70 | 71 | // Valid should still be low 72 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 73 | // NOTE: KEY READY SHOULD STILL BE HIGH 74 | // Checking behavior when when key ready is already high 75 | addr = r.nextInt(2 << 32) 76 | driver.push(txProto.tx(keyLoad128(addr))) 77 | c.clock.step(2) 78 | 79 | // Valid should be high for only ONE cycle 80 | assert(c.io.ctrlIO.key_valid.peek.litToBoolean) 81 | assert(c.io.ctrlIO.key_addr.peek.litValue() == addr) 82 | assert(c.io.ctrlIO.key_size.peek.litValue() == 0) 83 | c.clock.step() 84 | 85 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 86 | c.clock.step(r.nextInt(100)) 87 | 88 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 89 | 90 | c.io.ctrlIO.key_ready.poke(false.B) 91 | c.clock.step(r.nextInt(100)) 92 | 93 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 94 | // Repeating for second key load (256) 95 | addr = r.nextInt(2 << 32) 96 | driver.push(txProto.tx(keyLoad256(addr))) 97 | c.clock.step(2) 98 | 99 | assert(c.io.ctrlIO.key_valid.peek.litToBoolean) 100 | assert(c.io.ctrlIO.key_addr.peek.litValue() == addr) 101 | assert(c.io.ctrlIO.key_size.peek.litValue() == 1) 102 | c.clock.step(r.nextInt(100)) 103 | 104 | assert(c.io.ctrlIO.key_valid.peek.litToBoolean) 105 | assert(c.io.ctrlIO.key_addr.peek.litValue() == addr) 106 | assert(c.io.ctrlIO.key_size.peek.litValue() == 1) 107 | // Asserting key ready. Expect valid to go low next cycle 108 | c.io.ctrlIO.key_ready.poke(true.B) 109 | c.clock.step() 110 | 111 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 112 | c.clock.step(r.nextInt(100)) 113 | 114 | // Valid should still be low 115 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 116 | // NOTE: KEY READY SHOULD STILL BE HIGH 117 | // Checking behavior when when key ready is already high 118 | addr = r.nextInt(2 << 32) 119 | driver.push(txProto.tx(keyLoad256(addr))) 120 | c.clock.step(2) 121 | 122 | // Valid should be high for only ONE cycle 123 | assert(c.io.ctrlIO.key_valid.peek.litToBoolean) 124 | assert(c.io.ctrlIO.key_addr.peek.litValue() == addr) 125 | assert(c.io.ctrlIO.key_size.peek.litValue() == 1) 126 | c.clock.step() 127 | 128 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 129 | c.clock.step(r.nextInt(100)) 130 | 131 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 132 | 133 | c.io.ctrlIO.key_ready.poke(false.B) 134 | c.clock.step(r.nextInt(100)) 135 | } 136 | } 137 | 138 | it should "sanity check decoupler output addr" in { 139 | test(new RoCCDecoupler()) { c => 140 | // Initializing RoCCCommand driver 141 | val driver = new DecoupledDriverMaster[RoCCCommand](c.clock, c.io.rocc_cmd) 142 | val txProto = new DecoupledTX(new RoCCCommand()) 143 | 144 | // Initialize random generator (for cycle count) 145 | val r = new Random 146 | 147 | // Initialize signals 148 | c.io.reset.poke(false.B) 149 | c.io.rocc_excp.poke(false.B) 150 | c.io.ctrlIO.interrupt.poke(false.B) 151 | c.io.ctrlIO.busy.poke(false.B) 152 | c.io.ctrlIO.excp_ready.poke(false.B) 153 | c.io.ctrlIO.key_ready.poke(false.B) 154 | c.io.ctrlIO.addr_ready.poke(false.B) 155 | c.io.ctrlIO.start_ready.poke(false.B) 156 | c.clock.step() 157 | 158 | 159 | assert(!c.io.ctrlIO.addr_valid.peek.litToBoolean) 160 | c.clock.step(r.nextInt(100)) 161 | 162 | assert(!c.io.ctrlIO.addr_valid.peek.litToBoolean) 163 | // Checking when key ready is low 164 | var src = r.nextInt(2 << 32) 165 | var dest = r.nextInt(2 << 32) 166 | driver.push(txProto.tx(addrLoad(src, dest))) 167 | c.clock.step(2) // 1 cycle for driver, 1 cycle for decoupler (total 2) 168 | 169 | assert(c.io.ctrlIO.addr_valid.peek.litToBoolean) 170 | assert(c.io.ctrlIO.src_addr.peek.litValue() == src) 171 | assert(c.io.ctrlIO.dest_addr.peek.litValue() == dest) 172 | c.clock.step(r.nextInt(100)) 173 | 174 | assert(c.io.ctrlIO.addr_valid.peek.litToBoolean) 175 | assert(c.io.ctrlIO.src_addr.peek.litValue() == src) 176 | assert(c.io.ctrlIO.dest_addr.peek.litValue() == dest) 177 | assert(c.io.ctrlIO.key_size.peek.litValue() == 0) 178 | // Asserting key ready. Expect valid to go low next cycle 179 | c.io.ctrlIO.addr_ready.poke(true.B) 180 | c.clock.step() 181 | 182 | assert(!c.io.ctrlIO.addr_valid.peek.litToBoolean) 183 | c.clock.step(r.nextInt(100)) 184 | 185 | // Valid should still be low 186 | assert(!c.io.ctrlIO.addr_valid.peek.litToBoolean) 187 | // NOTE: ADDR READY SHOULD STILL BE HIGH 188 | // Checking behavior when when key ready is already high 189 | src = r.nextInt(2 << 32) 190 | dest = r.nextInt(2 << 32) 191 | driver.push(txProto.tx(addrLoad(src, dest))) 192 | c.clock.step(2) 193 | 194 | // Valid should be high for only ONE cycle 195 | assert(c.io.ctrlIO.addr_valid.peek.litToBoolean) 196 | assert(c.io.ctrlIO.src_addr.peek.litValue() == src) 197 | assert(c.io.ctrlIO.dest_addr.peek.litValue() == dest) 198 | assert(c.io.ctrlIO.key_size.peek.litValue() == 0) 199 | c.clock.step() 200 | 201 | assert(!c.io.ctrlIO.addr_valid.peek.litToBoolean) 202 | c.clock.step(r.nextInt(100)) 203 | 204 | assert(!c.io.ctrlIO.addr_valid.peek.litToBoolean) 205 | 206 | c.io.ctrlIO.addr_ready.poke(false.B) 207 | c.clock.step(r.nextInt(100)) 208 | 209 | assert(!c.io.ctrlIO.addr_valid.peek.litToBoolean) 210 | } 211 | } 212 | 213 | it should "sanity check decoupler output enc/dec" in { 214 | test(new RoCCDecoupler()) { c => 215 | // Initializing RoCCCommand driver 216 | val driver = new DecoupledDriverMaster[RoCCCommand](c.clock, c.io.rocc_cmd) 217 | val txProto = new DecoupledTX(new RoCCCommand()) 218 | 219 | // Initialize random generator (for cycle count) 220 | val r = new Random 221 | 222 | // Initialize signals 223 | c.io.reset.poke(false.B) 224 | c.io.rocc_excp.poke(false.B) 225 | c.io.ctrlIO.interrupt.poke(false.B) 226 | c.io.ctrlIO.busy.poke(false.B) 227 | c.io.ctrlIO.excp_ready.poke(false.B) 228 | c.io.ctrlIO.key_ready.poke(false.B) 229 | c.io.ctrlIO.addr_ready.poke(false.B) 230 | c.io.ctrlIO.start_ready.poke(false.B) 231 | c.clock.step() 232 | 233 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 234 | c.clock.step(r.nextInt(100)) 235 | 236 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 237 | // Checking when key ready is low 238 | var blocks = r.nextInt(2 << 32) 239 | driver.push(txProto.tx(encBlock(blocks, interrupt_en = 0))) 240 | c.clock.step(2) // 1 cycle for driver, 1 cycle for decoupler (total 2) 241 | 242 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 243 | assert(c.io.ctrlIO.block_count.peek.litValue() == blocks) 244 | assert(c.io.ctrlIO.op_type.peek.litValue() == 1) 245 | c.clock.step(r.nextInt(100)) 246 | 247 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 248 | assert(c.io.ctrlIO.block_count.peek.litValue() == blocks) 249 | assert(c.io.ctrlIO.op_type.peek.litValue() == 1) 250 | // Asserting key ready. Expect valid to go low next cycle 251 | c.io.ctrlIO.start_ready.poke(true.B) 252 | c.clock.step() 253 | 254 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 255 | c.clock.step(r.nextInt(100)) 256 | 257 | // Valid should still be low 258 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 259 | // NOTE: KEY READY SHOULD STILL BE HIGH 260 | // Checking behavior when when key ready is already high 261 | blocks = r.nextInt(2 << 32) 262 | driver.push(txProto.tx(encBlock(blocks, interrupt_en = 0))) 263 | c.clock.step(2) 264 | 265 | // Valid should be high for only ONE cycle 266 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 267 | assert(c.io.ctrlIO.block_count.peek.litValue() == blocks) 268 | assert(c.io.ctrlIO.op_type.peek.litValue() == 1) 269 | c.clock.step() 270 | 271 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 272 | c.clock.step(r.nextInt(100)) 273 | 274 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 275 | 276 | c.io.ctrlIO.start_ready.poke(false.B) 277 | c.clock.step(r.nextInt(100)) 278 | 279 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 280 | // Repeating for decryption 281 | blocks = r.nextInt(2 << 32) 282 | driver.push(txProto.tx(decBlock(blocks, interrupt_en = 0))) 283 | c.clock.step(2) 284 | 285 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 286 | assert(c.io.ctrlIO.block_count.peek.litValue() == blocks) 287 | assert(c.io.ctrlIO.op_type.peek.litValue() == 0) 288 | c.clock.step(r.nextInt(100)) 289 | 290 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 291 | assert(c.io.ctrlIO.block_count.peek.litValue() == blocks) 292 | assert(c.io.ctrlIO.op_type.peek.litValue() == 0) 293 | // Asserting key ready. Expect valid to go low next cycle 294 | c.io.ctrlIO.start_ready.poke(true.B) 295 | c.clock.step() 296 | 297 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 298 | c.clock.step(r.nextInt(100)) 299 | 300 | // Valid should still be low 301 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 302 | // NOTE: KEY READY SHOULD STILL BE HIGH 303 | // Checking behavior when when key ready is already high 304 | blocks = r.nextInt(2 << 32) 305 | driver.push(txProto.tx(decBlock(blocks, interrupt_en = 0))) 306 | c.clock.step(2) 307 | 308 | // Valid should be high for only ONE cycle 309 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 310 | assert(c.io.ctrlIO.block_count.peek.litValue() == blocks) 311 | assert(c.io.ctrlIO.op_type.peek.litValue() == 0) 312 | c.clock.step() 313 | 314 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 315 | c.clock.step(r.nextInt(100)) 316 | 317 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 318 | 319 | c.io.ctrlIO.start_ready.poke(false.B) 320 | c.clock.step(r.nextInt(100)) 321 | } 322 | } 323 | 324 | /* From decoupler perspective, busy should be high when a complete enc/dec operation has been received and not yet completed 325 | busy = start_valid | controller_busy 326 | Will need integration test to completely verify this 327 | */ 328 | it should "sanity check decoupler busy and status query" in { 329 | test(new RoCCDecoupler()) { c => 330 | // Initializing RoCCCommand driver 331 | val driver = new DecoupledDriverMaster[RoCCCommand](c.clock, c.io.rocc_cmd) 332 | val txProto = new DecoupledTX(new RoCCCommand()) 333 | val monitor = new DecoupledMonitor[RoCCResponse](c.clock, c.io.rocc_resp) 334 | val receiver = new DecoupledDriverSlave[RoCCResponse](c.clock, c.io.rocc_resp, 0) 335 | 336 | // Initialize random generator (for cycle count) 337 | val r = new Random 338 | 339 | // Initialize signals 340 | c.io.reset.poke(false.B) 341 | c.io.rocc_excp.poke(false.B) 342 | c.io.ctrlIO.interrupt.poke(false.B) 343 | c.io.ctrlIO.busy.poke(false.B) 344 | c.io.ctrlIO.excp_ready.poke(false.B) 345 | c.io.ctrlIO.key_ready.poke(false.B) 346 | c.io.ctrlIO.addr_ready.poke(false.B) 347 | c.io.ctrlIO.start_ready.poke(false.B) 348 | c.clock.step() 349 | 350 | assert(!c.io.rocc_busy.peek.litToBoolean) 351 | c.clock.step(r.nextInt(100)) 352 | 353 | assert(!c.io.rocc_busy.peek.litToBoolean) 354 | driver.push(txProto.tx(keyLoad128(r.nextInt(2 << 32)))) 355 | c.clock.step(2) 356 | 357 | assert(!c.io.rocc_busy.peek.litToBoolean) 358 | c.clock.step(r.nextInt(100)) 359 | 360 | assert(!c.io.rocc_busy.peek.litToBoolean) 361 | driver.push(txProto.tx(addrLoad(r.nextInt(2 << 32), r.nextInt(2 << 32)))) 362 | c.clock.step(2) 363 | 364 | assert(!c.io.rocc_busy.peek.litToBoolean) 365 | c.clock.step(r.nextInt(100)) 366 | 367 | assert(!c.io.rocc_busy.peek.litToBoolean) 368 | driver.push(txProto.tx(encBlock(r.nextInt(2 << 32), interrupt_en = 0))) 369 | c.clock.step(2) 370 | 371 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 372 | assert(c.io.rocc_busy.peek.litToBoolean) 373 | c.clock.step(r.nextInt(100)) 374 | 375 | assert(c.io.rocc_busy.peek.litToBoolean) 376 | c.io.ctrlIO.start_ready.poke(true.B) 377 | c.clock.step() 378 | 379 | assert(!c.io.rocc_busy.peek.litToBoolean) 380 | c.io.ctrlIO.start_ready.poke(false.B) 381 | c.clock.step(r.nextInt(100)) 382 | 383 | // Query busy status (not busy) 384 | var rd = r.nextInt(32) 385 | driver.push(txProto.tx(getStatus(rd))) 386 | c.clock.step(2) 387 | 388 | // Should be valid for one cycle 389 | assert(c.io.rocc_resp.valid.peek.litToBoolean) 390 | c.clock.step() 391 | 392 | var txns = monitor.monitoredTransactions 393 | assert(txns.size == 1) 394 | assert(!c.io.rocc_resp.valid.peek.litToBoolean) 395 | c.clock.step(r.nextInt(100)) 396 | 397 | txns = monitor.monitoredTransactions 398 | assert(txns.size == 1) // Still only one response 399 | var resp = txns.head.data 400 | assert(resp.rd.litValue() == rd) 401 | assert(resp.data.litValue() == 0) // Currently busy 402 | monitor.clearMonitoredTransactions() // Clear transactions 403 | 404 | assert(!c.io.rocc_busy.peek.litToBoolean) 405 | driver.push(txProto.tx(decBlock(r.nextInt(2 << 32), interrupt_en = 0))) 406 | c.clock.step(2) 407 | 408 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 409 | assert(c.io.rocc_busy.peek.litToBoolean) 410 | c.clock.step(r.nextInt(100)) 411 | 412 | // Query busy status (busy) 413 | rd = r.nextInt(32) 414 | driver.push(txProto.tx(getStatus(rd))) 415 | c.clock.step(2) 416 | 417 | // Should be valid for one cycle 418 | assert(c.io.rocc_resp.valid.peek.litToBoolean) 419 | c.clock.step() 420 | 421 | txns = monitor.monitoredTransactions 422 | assert(txns.size == 1) 423 | assert(!c.io.rocc_resp.valid.peek.litToBoolean) 424 | c.clock.step(r.nextInt(100)) 425 | 426 | txns = monitor.monitoredTransactions 427 | assert(txns.size == 1) // Still only one response 428 | resp = txns.head.data 429 | assert(resp.rd.litValue() == rd) 430 | assert(resp.data.litValue() == 1) // Currently busy 431 | monitor.clearMonitoredTransactions() // Clear transactions 432 | 433 | assert(c.io.rocc_busy.peek.litToBoolean) 434 | c.io.ctrlIO.start_ready.poke(true.B) 435 | c.clock.step() 436 | 437 | assert(!c.io.rocc_busy.peek.litToBoolean) 438 | c.io.ctrlIO.start_ready.poke(false.B) 439 | c.clock.step(r.nextInt(100)) 440 | 441 | assert(!c.io.rocc_busy.peek.litToBoolean) 442 | c.io.ctrlIO.busy.poke(true.B) 443 | c.clock.step() 444 | 445 | assert(c.io.rocc_busy.peek.litToBoolean) 446 | c.clock.step(r.nextInt(100)) 447 | 448 | assert(c.io.rocc_busy.peek.litToBoolean) 449 | c.io.ctrlIO.busy.poke(false.B) 450 | c.clock.step() 451 | 452 | assert(!c.io.rocc_busy.peek.litToBoolean) 453 | c.clock.step(r.nextInt(100)) 454 | 455 | assert(!c.io.rocc_busy.peek.litToBoolean) 456 | } 457 | } 458 | 459 | it should "test decoupler reset and exception when receiving instruction" in { 460 | test(new RoCCDecoupler()) { c => 461 | // Initializing RoCCCommand driver 462 | val driver = new DecoupledDriverMaster[RoCCCommand](c.clock, c.io.rocc_cmd) 463 | val txProto = new DecoupledTX(new RoCCCommand()) 464 | val monitor = new DecoupledMonitor[RoCCResponse](c.clock, c.io.rocc_resp) 465 | val receiver = new DecoupledDriverSlave[RoCCResponse](c.clock, c.io.rocc_resp, 0) 466 | 467 | // Initialize random generator (for cycle count) 468 | val r = new Random 469 | 470 | // Initialize signals 471 | c.io.reset.poke(false.B) 472 | c.io.rocc_excp.poke(false.B) 473 | c.io.ctrlIO.interrupt.poke(false.B) 474 | c.io.ctrlIO.busy.poke(false.B) 475 | c.io.ctrlIO.excp_ready.poke(false.B) 476 | c.io.ctrlIO.key_ready.poke(false.B) 477 | c.io.ctrlIO.addr_ready.poke(false.B) 478 | c.io.ctrlIO.start_ready.poke(false.B) 479 | c.clock.step() 480 | 481 | c.io.reset.poke(true.B) // First testing reset 482 | c.clock.step() 483 | 484 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 485 | driver.push(txProto.tx(keyLoad128(r.nextInt(2 << 32)))) 486 | c.clock.step(2) 487 | 488 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 489 | driver.push(txProto.tx(keyLoad256(r.nextInt(2 << 32)))) 490 | c.clock.step(2) 491 | 492 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 493 | driver.push(txProto.tx(addrLoad(r.nextInt(2 << 32), r.nextInt(2 << 32)))) 494 | c.clock.step(2) 495 | 496 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 497 | driver.push(txProto.tx(encBlock(r.nextInt(2 << 32), interrupt_en = 0))) 498 | c.clock.step(2) 499 | 500 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 501 | driver.push(txProto.tx(decBlock(r.nextInt(2 << 32), interrupt_en = 0))) 502 | c.clock.step(2) 503 | 504 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 505 | driver.push(txProto.tx(getStatus(r.nextInt(32)))) 506 | c.clock.step(2) 507 | 508 | assert(monitor.monitoredTransactions.isEmpty) 509 | c.clock.step(2) 510 | 511 | assert(monitor.monitoredTransactions.isEmpty) 512 | c.clock.step(r.nextInt(100)) 513 | 514 | c.io.reset.poke(false.B) // Testing exception 515 | c.io.rocc_excp.poke(true.B) 516 | c.clock.step() 517 | 518 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 519 | driver.push(txProto.tx(keyLoad128(r.nextInt(2 << 32)))) 520 | c.clock.step(2) 521 | 522 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 523 | driver.push(txProto.tx(keyLoad256(r.nextInt(2 << 32)))) 524 | c.clock.step(2) 525 | 526 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 527 | driver.push(txProto.tx(addrLoad(r.nextInt(2 << 32), r.nextInt(2 << 32)))) 528 | c.clock.step(2) 529 | 530 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 531 | driver.push(txProto.tx(encBlock(r.nextInt(2 << 32), interrupt_en = 0))) 532 | c.clock.step(2) 533 | 534 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 535 | driver.push(txProto.tx(decBlock(r.nextInt(2 << 32), interrupt_en = 0))) 536 | c.clock.step(2) 537 | 538 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 539 | driver.push(txProto.tx(getStatus(r.nextInt(32)))) 540 | c.clock.step(2) 541 | 542 | assert(monitor.monitoredTransactions.isEmpty) 543 | c.clock.step(2) 544 | 545 | assert(monitor.monitoredTransactions.isEmpty) 546 | } 547 | } 548 | 549 | it should "test decoupler reset and exception when idle" in { 550 | test(new RoCCDecoupler()) { c => 551 | // Initializing RoCCCommand driver 552 | val driver = new DecoupledDriverMaster[RoCCCommand](c.clock, c.io.rocc_cmd) 553 | val txProto = new DecoupledTX(new RoCCCommand()) 554 | 555 | // Initialize random generator (for cycle count) 556 | val r = new Random 557 | 558 | // Inputs 559 | val inputs = Seq( 560 | txProto.tx(keyLoad128(r.nextInt(2 << 32))), 561 | txProto.tx(addrLoad(r.nextInt(2 << 32), r.nextInt(2 << 32))), 562 | txProto.tx(encBlock(r.nextInt(2 << 32), interrupt_en = 0)), 563 | ) 564 | 565 | // Initialize signals 566 | c.io.reset.poke(false.B) 567 | c.io.rocc_excp.poke(false.B) 568 | c.io.ctrlIO.interrupt.poke(false.B) 569 | c.io.ctrlIO.busy.poke(false.B) 570 | c.io.ctrlIO.excp_ready.poke(false.B) 571 | c.io.ctrlIO.key_ready.poke(false.B) 572 | c.io.ctrlIO.addr_ready.poke(false.B) 573 | c.io.ctrlIO.start_ready.poke(false.B) 574 | c.clock.step() 575 | 576 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 577 | assert(!c.io.ctrlIO.addr_valid.peek.litToBoolean) 578 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 579 | driver.push(inputs) 580 | c.clock.step(10) 581 | 582 | assert(c.io.ctrlIO.key_valid.peek.litToBoolean) 583 | assert(c.io.ctrlIO.addr_valid.peek.litToBoolean) 584 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 585 | c.io.reset.poke(true.B) 586 | c.clock.step() 587 | 588 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 589 | assert(!c.io.ctrlIO.addr_valid.peek.litToBoolean) 590 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 591 | c.clock.step(r.nextInt(10)) 592 | 593 | c.io.reset.poke(false.B) 594 | c.clock.step() 595 | 596 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 597 | assert(!c.io.ctrlIO.addr_valid.peek.litToBoolean) 598 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 599 | // Testing exceptions 600 | driver.push(inputs) 601 | c.clock.step(10) 602 | 603 | assert(c.io.ctrlIO.key_valid.peek.litToBoolean) 604 | assert(c.io.ctrlIO.addr_valid.peek.litToBoolean) 605 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 606 | c.io.rocc_excp.poke(true.B) 607 | c.clock.step() 608 | 609 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 610 | assert(!c.io.ctrlIO.addr_valid.peek.litToBoolean) 611 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 612 | assert(c.io.ctrlIO.excp_valid.peek.litToBoolean) 613 | 614 | //Testing exception acceptance 615 | c.clock.step(r.nextInt(5)) 616 | c.io.ctrlIO.excp_ready.poke(true.B) 617 | c.clock.step() 618 | c.io.ctrlIO.excp_ready.poke(false.B) 619 | assert(!c.io.ctrlIO.excp_valid.peek.litToBoolean) 620 | c.clock.step(r.nextInt(10)) 621 | 622 | c.io.rocc_excp.poke(false.B) 623 | c.clock.step() 624 | 625 | assert(!c.io.ctrlIO.key_valid.peek.litToBoolean) 626 | assert(!c.io.ctrlIO.addr_valid.peek.litToBoolean) 627 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 628 | } 629 | } 630 | 631 | it should "sanity check decoupler output enc/dec with interrupt enable signal" in { 632 | test(new RoCCDecoupler()) { c => 633 | // Initializing RoCCCommand driver 634 | val driver = new DecoupledDriverMaster[RoCCCommand](c.clock, c.io.rocc_cmd) 635 | val txProto = new DecoupledTX(new RoCCCommand()) 636 | 637 | // Initialize random generator (for cycle count) 638 | val r = new Random 639 | 640 | // Initialize signals 641 | c.io.reset.poke(false.B) 642 | c.io.rocc_excp.poke(false.B) 643 | c.io.ctrlIO.interrupt.poke(false.B) 644 | c.io.ctrlIO.busy.poke(false.B) 645 | c.io.ctrlIO.excp_ready.poke(false.B) 646 | c.io.ctrlIO.key_ready.poke(false.B) 647 | c.io.ctrlIO.addr_ready.poke(false.B) 648 | c.io.ctrlIO.start_ready.poke(false.B) 649 | c.clock.step() 650 | 651 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 652 | c.clock.step(r.nextInt(100)) 653 | 654 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 655 | // Checking when key ready is low 656 | var blocks = r.nextInt(2 << 32) 657 | // enable interrupt signals 658 | driver.push(txProto.tx(encBlock(blocks, 1))) 659 | c.clock.step(2) // 1 cycle for driver, 1 cycle for decoupler (total 2) 660 | 661 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 662 | assert(c.io.ctrlIO.block_count.peek.litValue() == blocks) 663 | assert(c.io.ctrlIO.op_type.peek.litValue() == 1) 664 | assert(c.io.ctrlIO.intrpt_en.peek.litValue() == 1) 665 | c.clock.step(r.nextInt(100)) 666 | 667 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 668 | assert(c.io.ctrlIO.block_count.peek.litValue() == blocks) 669 | assert(c.io.ctrlIO.op_type.peek.litValue() == 1) 670 | assert(c.io.ctrlIO.intrpt_en.peek.litValue() == 1) 671 | // Asserting key ready. Expect valid to go low next cycle 672 | c.io.ctrlIO.start_ready.poke(true.B) 673 | c.clock.step() 674 | 675 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 676 | c.clock.step(r.nextInt(100)) 677 | 678 | // Valid should still be low 679 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 680 | // NOTE: KEY READY SHOULD STILL BE HIGH 681 | // Checking behavior when when key ready is already high 682 | blocks = r.nextInt(2 << 32) 683 | // disable interrupt signal 684 | driver.push(txProto.tx(encBlock(blocks, 0))) 685 | c.clock.step(2) 686 | 687 | // Valid should be high for only ONE cycle 688 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 689 | assert(c.io.ctrlIO.block_count.peek.litValue() == blocks) 690 | assert(c.io.ctrlIO.op_type.peek.litValue() == 1) 691 | assert(c.io.ctrlIO.intrpt_en.peek.litValue() == 0) 692 | c.clock.step() 693 | 694 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 695 | c.clock.step(r.nextInt(100)) 696 | 697 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 698 | 699 | c.io.ctrlIO.start_ready.poke(false.B) 700 | c.clock.step(r.nextInt(100)) 701 | 702 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 703 | // Repeating for decryption 704 | blocks = r.nextInt(2 << 32) 705 | // enable interrupt signal 706 | driver.push(txProto.tx(decBlock(blocks, 1))) 707 | c.clock.step(2) 708 | 709 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 710 | assert(c.io.ctrlIO.block_count.peek.litValue() == blocks) 711 | assert(c.io.ctrlIO.op_type.peek.litValue() == 0) 712 | assert(c.io.ctrlIO.intrpt_en.peek.litValue() == 1) 713 | c.clock.step(r.nextInt(100)) 714 | 715 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 716 | assert(c.io.ctrlIO.block_count.peek.litValue() == blocks) 717 | assert(c.io.ctrlIO.op_type.peek.litValue() == 0) 718 | assert(c.io.ctrlIO.intrpt_en.peek.litValue() == 1) 719 | // Asserting key ready. Expect valid to go low next cycle 720 | c.io.ctrlIO.start_ready.poke(true.B) 721 | c.clock.step() 722 | 723 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 724 | c.clock.step(r.nextInt(100)) 725 | 726 | // Valid should still be low 727 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 728 | // NOTE: KEY READY SHOULD STILL BE HIGH 729 | // Checking behavior when when key ready is already high 730 | blocks = r.nextInt(2 << 32) 731 | // disable interrupt signal 732 | driver.push(txProto.tx(decBlock(blocks, 0))) 733 | c.clock.step(2) 734 | 735 | // Valid should be high for only ONE cycle 736 | assert(c.io.ctrlIO.start_valid.peek.litToBoolean) 737 | assert(c.io.ctrlIO.block_count.peek.litValue() == blocks) 738 | assert(c.io.ctrlIO.op_type.peek.litValue() == 0) 739 | assert(c.io.ctrlIO.intrpt_en.peek.litValue() == 0) 740 | c.clock.step() 741 | 742 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 743 | c.clock.step(r.nextInt(100)) 744 | 745 | assert(!c.io.ctrlIO.start_valid.peek.litToBoolean) 746 | 747 | c.io.ctrlIO.start_ready.poke(false.B) 748 | c.clock.step(r.nextInt(100)) 749 | } 750 | } 751 | } 752 | --------------------------------------------------------------------------------