|
@ -2,12 +2,13 @@ import logging |
|
|
import random |
|
|
import random |
|
|
import cocotb |
|
|
import cocotb |
|
|
import pprint |
|
|
import pprint |
|
|
from Vai import VaiDriver, VaiReceiver |
|
|
|
|
|
|
|
|
from Vai import VaiDriver, VaiReceiver, VaiMonitor |
|
|
from cocotb.clock import Clock |
|
|
from cocotb.clock import Clock |
|
|
|
|
|
from cocotb.queue import Queue |
|
|
from cocotb.triggers import FallingEdge, RisingEdge, Timer, ReadOnly |
|
|
from cocotb.triggers import FallingEdge, RisingEdge, Timer, ReadOnly |
|
|
from Crypto.Cipher import AES |
|
|
from Crypto.Cipher import AES |
|
|
from Crypto.Util.number import long_to_bytes, getRandomNBitInteger |
|
|
from Crypto.Util.number import long_to_bytes, getRandomNBitInteger |
|
|
import binascii |
|
|
|
|
|
|
|
|
import vsc |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Reset coroutine |
|
|
# Reset coroutine |
|
@ -17,7 +18,57 @@ async def reset_dut(reset_n, duration_ns): |
|
|
reset_n.value = 1 |
|
|
reset_n.value = 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@cocotb.test() |
|
|
|
|
|
|
|
|
# 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, 25), |
|
|
|
|
|
vsc.weight((1,2**128-2), 50), |
|
|
|
|
|
vsc.weight((2**128-1), 25)]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 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): |
|
|
async def test_aes_enc(dut): |
|
|
""" Test AES encryption """ |
|
|
""" Test AES encryption """ |
|
|
|
|
|
|
|
@ -26,10 +77,19 @@ async def test_aes_enc(dut): |
|
|
# Connect reset |
|
|
# Connect reset |
|
|
reset = dut.reset_i |
|
|
reset = dut.reset_i |
|
|
|
|
|
|
|
|
# Instantiate VAI driver & receiver |
|
|
|
|
|
_input = [dut.mode_i, dut.key_i, dut.data_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_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_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) |
|
|
# Drive input defaults (setimmediatevalue to avoid x asserts) |
|
|
dut.mode_i.setimmediatevalue(0) |
|
|
dut.mode_i.setimmediatevalue(0) |
|
@ -48,20 +108,24 @@ async def test_aes_enc(dut): |
|
|
|
|
|
|
|
|
# Test 10 AES calculations |
|
|
# Test 10 AES calculations |
|
|
for i in range(10): |
|
|
for i in range(10): |
|
|
|
|
|
# Get now random stimuli |
|
|
|
|
|
cr.randomize() |
|
|
|
|
|
_key = cr.key |
|
|
|
|
|
_data = cr.data |
|
|
await clkedge |
|
|
await clkedge |
|
|
_key = getRandomNBitInteger(128) |
|
|
|
|
|
_data = getRandomNBitInteger(128) |
|
|
|
|
|
# Drive AES inputs |
|
|
# Drive AES inputs |
|
|
await vai_driver.send([0, _key, _data]) |
|
|
await vai_driver.send([0, _key, _data]) |
|
|
# Calc reference data |
|
|
# Calc reference data |
|
|
_aes = AES.new(long_to_bytes(_key), AES.MODE_ECB) |
|
|
|
|
|
_ref = _aes.encrypt(long_to_bytes(_data)) |
|
|
|
|
|
|
|
|
_aes = AES.new(_key.to_bytes(16, 'big'), AES.MODE_ECB) |
|
|
|
|
|
_ref = _aes.encrypt(_data.to_bytes(16, 'big')) |
|
|
# Get DUT output data |
|
|
# Get DUT output data |
|
|
_rec = await vai_receiver.receive() |
|
|
_rec = await vai_receiver.receive() |
|
|
assert _rec.buff == _ref, f"Encrypt error, got {_rec.buff}, expected {_ref}" |
|
|
|
|
|
|
|
|
# Equivalence check |
|
|
|
|
|
assert _rec.buff == _ref, \ |
|
|
|
|
|
f"Encrypt error, got 0x{_rec.buff.hex()}, expected 0x{_ref.hex()}" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@cocotb.test() |
|
|
|
|
|
|
|
|
@cocotb.test(skip=False) |
|
|
async def test_aes_dec(dut): |
|
|
async def test_aes_dec(dut): |
|
|
""" Test AES decryption """ |
|
|
""" Test AES decryption """ |
|
|
|
|
|
|
|
@ -70,10 +134,19 @@ async def test_aes_dec(dut): |
|
|
# Connect reset |
|
|
# Connect reset |
|
|
reset = dut.reset_i |
|
|
reset = dut.reset_i |
|
|
|
|
|
|
|
|
# Instantiate VAI driver & receiver |
|
|
|
|
|
_input = [dut.mode_i, dut.key_i, dut.data_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_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_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) |
|
|
# Drive input defaults (setimmediatevalue to avoid x asserts) |
|
|
dut.mode_i.setimmediatevalue(0) |
|
|
dut.mode_i.setimmediatevalue(0) |
|
@ -86,20 +159,26 @@ async def test_aes_dec(dut): |
|
|
cocotb.start_soon(clock.start()) # Start the clock |
|
|
cocotb.start_soon(clock.start()) # Start the clock |
|
|
|
|
|
|
|
|
# Execution will block until reset_dut has completed |
|
|
# Execution will block until reset_dut has completed |
|
|
dut._log.info("Hold reset") |
|
|
|
|
|
await reset_dut(reset, 100) |
|
|
await reset_dut(reset, 100) |
|
|
dut._log.info("Released reset") |
|
|
dut._log.info("Released reset") |
|
|
|
|
|
|
|
|
# Test 10 AES calculations |
|
|
# Test 10 AES calculations |
|
|
for i in range(10): |
|
|
for i in range(10): |
|
|
|
|
|
# Get now random stimuli |
|
|
|
|
|
cr.randomize() |
|
|
|
|
|
_key = cr.key |
|
|
|
|
|
_data = cr.data |
|
|
await clkedge |
|
|
await clkedge |
|
|
_key = getRandomNBitInteger(128) |
|
|
|
|
|
_data = getRandomNBitInteger(128) |
|
|
|
|
|
# Drive AES inputs |
|
|
# Drive AES inputs |
|
|
await vai_driver.send([1, _key, _data]) |
|
|
await vai_driver.send([1, _key, _data]) |
|
|
# Calc reference data |
|
|
# Calc reference data |
|
|
_aes = AES.new(long_to_bytes(_key), AES.MODE_ECB) |
|
|
|
|
|
_ref = _aes.decrypt(long_to_bytes(_data)) |
|
|
|
|
|
|
|
|
_aes = AES.new(_key.to_bytes(16, 'big'), AES.MODE_ECB) |
|
|
|
|
|
_ref = _aes.decrypt(_data.to_bytes(16, 'big')) |
|
|
# Get DUT output data |
|
|
# Get DUT output data |
|
|
_rec = await vai_receiver.receive() |
|
|
_rec = await vai_receiver.receive() |
|
|
assert _rec.buff == _ref, f"Decrypt error, got {_rec.buff}, expected {_ref}" |
|
|
|
|
|
|
|
|
# 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()) |