|
|
- import logging
- import cocotb
- from Vai import VaiDriver, VaiReceiver, VaiMonitor
- from cocotb.clock import Clock
- from cocotb.queue import Queue
- from cocotb.triggers import RisingEdge, Timer
- from Crypto.Cipher import AES
- import vsc
-
-
- # Reset coroutine
- async def reset_dut(reset_n, duration_ns):
- reset_n.value = 0
- await Timer(duration_ns, units="ns")
- reset_n.value = 1
-
-
- # Stimuli model class
- @vsc.randobj
- class constraints():
- def __init__(self):
- self.key = vsc.rand_bit_t(128)
- self.data = vsc.rand_bit_t(128)
-
- @vsc.constraint
- def c(self):
- self.data >= 0 and self.data <= 2**128-1
- vsc.dist(self.key, [
- vsc.weight(0, 15),
- vsc.weight((1,2**128-2), 70),
- vsc.weight((2**128-1), 15)])
-
-
- # Stimuli covergroup
- @vsc.covergroup
- class covergroup():
- def __init__(self):
- self.with_sample(
- mode = vsc.bit_t(1),
- key = vsc.bit_t(128)
- )
-
- self.enc = vsc.coverpoint(self.mode, bins=dict(
- enc = vsc.bin(0)))
-
- self.dec = vsc.coverpoint(self.mode, bins=dict(
- dec = vsc.bin(1)))
-
- self.key0 = vsc.coverpoint(self.key, bins=dict(
- key0 = vsc.bin(0)))
-
- self.keyF = vsc.coverpoint(self.key, bins=dict(
- keyF = vsc.bin(2**128-1)))
-
- self.encXkey0 = vsc.cross([self.enc, self.key0])
- self.encXkeyF = vsc.cross([self.enc, self.keyF])
-
- self.decXkey0 = vsc.cross([self.dec, self.key0])
- self.decXkeyF = vsc.cross([self.dec, self.keyF])
-
-
- async def cg_sample(cg, queue):
- while True:
- _data = await queue.get()
- cg.sample(_data[0].value, _data[1].value)
-
-
- @cocotb.test(skip=False)
- async def test_aes_enc(dut):
- """ Test AES encryption """
-
- clkedge = RisingEdge(dut.clk_i)
-
- # Connect reset
- reset = dut.reset_i
-
- _input = [dut.mode_i, dut.key_i, dut.data_i]
- _output = dut.data_o
- # DUT input side
- vai_driver = VaiDriver(dut.clk_i, _input, dut.valid_i, dut.accept_o)
- vai_in_queue = cocotb.queue.Queue()
- vai_in_monitor = VaiMonitor(dut.clk_i, _input, dut.valid_i, dut.accept_o, vai_in_queue)
- # DUT output side
- vai_receiver = VaiReceiver(dut.clk_i, dut.data_o, dut.valid_o, dut.accept_i)
- vai_out_monitor = VaiMonitor(dut.clk_i, _output, dut.valid_o, dut.accept_i)
-
- cr = constraints()
- cg = covergroup()
- cocotb.start_soon(cg_sample(cg, vai_in_queue))
-
- # Drive input defaults (setimmediatevalue to avoid x asserts)
- dut.mode_i.setimmediatevalue(0)
- dut.key_i.setimmediatevalue(0)
- dut.data_i.setimmediatevalue(0)
- dut.valid_i.setimmediatevalue(0)
- dut.accept_i.setimmediatevalue(0)
-
- clock = Clock(dut.clk_i, 10, units="ns") # Create a 10 ns period clock
- cocotb.start_soon(clock.start()) # Start the clock
-
- # Execution will block until reset_dut has completed
- dut._log.info("Hold reset")
- await reset_dut(reset, 100)
- dut._log.info("Released reset")
-
- # Test 10 AES calculations
- for i in range(20):
- # Get now random stimuli
- cr.randomize()
- _key = cr.key
- _data = cr.data
- await clkedge
- # Drive AES inputs
- await vai_driver.send([0, _key, _data])
- # Calc reference data
- _aes = AES.new(_key.to_bytes(16, 'big'), AES.MODE_ECB)
- _ref = _aes.encrypt(_data.to_bytes(16, 'big'))
- # Get DUT output data
- _rec = await vai_receiver.receive()
- # Equivalence check
- assert _rec.buff == _ref, \
- f"Encrypt error, got 0x{_rec.buff.hex()}, expected 0x{_ref.hex()}"
-
-
- @cocotb.test(skip=False)
- async def test_aes_dec(dut):
- """ Test AES decryption """
-
- clkedge = RisingEdge(dut.clk_i)
-
- # Connect reset
- reset = dut.reset_i
-
- _input = [dut.mode_i, dut.key_i, dut.data_i]
- _output = dut.data_o
- # DUT input side
- vai_driver = VaiDriver(dut.clk_i, _input, dut.valid_i, dut.accept_o)
- vai_in_queue = cocotb.queue.Queue()
- vai_in_monitor = VaiMonitor(dut.clk_i, _input, dut.valid_i, dut.accept_o, vai_in_queue)
- # DUT output side
- vai_receiver = VaiReceiver(dut.clk_i, dut.data_o, dut.valid_o, dut.accept_i)
- vai_out_monitor = VaiMonitor(dut.clk_i, _output, dut.valid_o, dut.accept_i)
-
- cr = constraints()
- cg = covergroup()
- cocotb.start_soon(cg_sample(cg, vai_in_queue))
-
- # Drive input defaults (setimmediatevalue to avoid x asserts)
- dut.mode_i.setimmediatevalue(0)
- dut.key_i.setimmediatevalue(0)
- dut.data_i.setimmediatevalue(0)
- dut.valid_i.setimmediatevalue(0)
- dut.accept_i.setimmediatevalue(0)
-
- clock = Clock(dut.clk_i, 10, units="ns") # Create a 10 ns period clock
- cocotb.start_soon(clock.start()) # Start the clock
-
- # Execution will block until reset_dut has completed
- await reset_dut(reset, 100)
- dut._log.info("Released reset")
-
- # Test 10 AES calculations
- for i in range(20):
- # Get now random stimuli
- cr.randomize()
- _key = cr.key
- _data = cr.data
- await clkedge
- # Drive AES inputs
- await vai_driver.send([1, _key, _data])
- # Calc reference data
- _aes = AES.new(_key.to_bytes(16, 'big'), AES.MODE_ECB)
- _ref = _aes.decrypt(_data.to_bytes(16, 'big'))
- # Get DUT output data
- _rec = await vai_receiver.receive()
- # Equivalence check
- assert _rec.buff == _ref, \
- f"Decrypt error, got 0x{_rec.buff.hex()}, expected 0x{_ref.hex()}"
-
- with open('results/tb_aes_fcover.txt', 'w', encoding='utf-8') as f:
- f.write(vsc.get_coverage_report())
|