add new test spi_master_rd

This commit is contained in:
M0stafaRady 2022-10-03 05:36:36 -07:00
parent a00d62ebcf
commit 79f26f6b38
7 changed files with 415 additions and 1 deletions

View File

@ -36,6 +36,7 @@ from tests.gpio.gpio import *
from tests.mgmt_gpio.mgmt_gpio import *
from tests.timer.timer import *
from tests.uart.uart import *
from tests.spi_master.spi_master import *

View File

@ -104,7 +104,7 @@ caravel uut (
// make speical variables for the mprj input to assign the input without writing to the output gpios
// cocotb limitation #2587
// cocotb limitation #2587: iverilog deal with array as 1 object not multiple of objects so can't write to only 1 element
wire bin0;
wire bin0_en;
wire bin1;
@ -229,6 +229,87 @@ caravel uut (
assign mprj_io_tb[36] = (bin36_en) ? bin36 : 1'bz;
assign mprj_io_tb[37] = (bin37_en) ? bin37 : 1'bz;
// to read from mprj array with iverilog
wire bin0_monitor;
wire bin1_monitor;
wire bin2_monitor;
wire bin3_monitor;
wire bin4_monitor;
wire bin5_monitor;
wire bin6_monitor;
wire bin7_monitor;
wire bin8_monitor;
wire bin9_monitor;
wire bin10_monitor;
wire bin11_monitor;
wire bin12_monitor;
wire bin13_monitor;
wire bin14_monitor;
wire bin15_monitor;
wire bin16_monitor;
wire bin17_monitor;
wire bin18_monitor;
wire bin19_monitor;
wire bin20_monitor;
wire bin21_monitor;
wire bin22_monitor;
wire bin23_monitor;
wire bin24_monitor;
wire bin25_monitor;
wire bin26_monitor;
wire bin27_monitor;
wire bin28_monitor;
wire bin29_monitor;
wire bin30_monitor;
wire bin31_monitor;
wire bin32_monitor;
wire bin33_monitor;
wire bin34_monitor;
wire bin35_monitor;
wire bin36_monitor;
wire bin37_monitor;
assign bin0_monitor = mprj_io_tb[0];
assign bin1_monitor = mprj_io_tb[1];
assign bin2_monitor = mprj_io_tb[2];
assign bin3_monitor = mprj_io_tb[3];
assign bin4_monitor = mprj_io_tb[4];
assign bin5_monitor = mprj_io_tb[5];
assign bin6_monitor = mprj_io_tb[6];
assign bin7_monitor = mprj_io_tb[7];
assign bin8_monitor = mprj_io_tb[8];
assign bin9_monitor = mprj_io_tb[9];
assign bin10_monitor = mprj_io_tb[10];
assign bin11_monitor = mprj_io_tb[11];
assign bin12_monitor = mprj_io_tb[12];
assign bin13_monitor = mprj_io_tb[13];
assign bin14_monitor = mprj_io_tb[14];
assign bin15_monitor = mprj_io_tb[15];
assign bin16_monitor = mprj_io_tb[16];
assign bin17_monitor = mprj_io_tb[17];
assign bin18_monitor = mprj_io_tb[18];
assign bin19_monitor = mprj_io_tb[19];
assign bin20_monitor = mprj_io_tb[20];
assign bin21_monitor = mprj_io_tb[21];
assign bin22_monitor = mprj_io_tb[22];
assign bin23_monitor = mprj_io_tb[23];
assign bin24_monitor = mprj_io_tb[24];
assign bin25_monitor = mprj_io_tb[25];
assign bin26_monitor = mprj_io_tb[26];
assign bin27_monitor = mprj_io_tb[27];
assign bin28_monitor = mprj_io_tb[28];
assign bin29_monitor = mprj_io_tb[29];
assign bin30_monitor = mprj_io_tb[30];
assign bin31_monitor = mprj_io_tb[31];
assign bin32_monitor = mprj_io_tb[32];
assign bin33_monitor = mprj_io_tb[33];
assign bin34_monitor = mprj_io_tb[34];
assign bin35_monitor = mprj_io_tb[35];
assign bin36_monitor = mprj_io_tb[36];
assign bin37_monitor = mprj_io_tb[37];
endmodule
// module that has all needed macros by cocotb

View File

@ -169,5 +169,12 @@
"GL":["nightly","weekly","tape_out"],
"GL_SDF":["weekly","tape_out"],
"description":"test uart reception"}
,"spi_master_rd" :{"level":0,
"SW":true,
"RTL":["setup","nightly","weekly","tape_out"],
"GL":["nightly","weekly","tape_out"],
"GL_SDF":["weekly","tape_out"],
"description":"using SPI master for reading from external memory"}
}
}

View File

@ -0,0 +1,87 @@
import random
import cocotb
from cocotb.triggers import FallingEdge,RisingEdge,ClockCycles,Timer
import cocotb.log
from tests.common_functions.test_functions import *
from tests.bitbang.bitbang_functions import *
#VIP for SPI
"""
support commands
00000000 -> No operation
00000011 -> Read in streaming mode
"""
async def SPI_VIP(csb,clk,SDI,SDO,mem):
while True:
await FallingEdge(csb)
cocotb.log.info (f"[SPI_VIP] CSB is asserted operation has begin ")
op = await cocotb.start(SPI_op(clk,SDI,SDO,mem))
await csb_watcher(csb,op)
cocotb.log.info (f"[SPI_VIP] CSB is deasserted operation has been killed")
# cocotb.scheduler.add
# watch the csb and when it's diable kill the SPI_op thread
async def csb_watcher(csb,thread):
cocotb.log.info (f"[csb_watcher] start CSB watching")
await RisingEdge(csb)
thread.kill()
# detect command and address and apply the command
async def SPI_op(clk,SDI,SDO,mem):
address =''
command =''
await RisingEdge(clk)
# command
for i in range(8):
command = command + SDI.value.binstr
await RisingEdge(clk)
cocotb.log.info (f"[SPI_VIP] [SPI_op] command = {command}")
# address
address =''
for i in range(8*3): # address is 3 parts each part are 8 bits
address = address + SDI.value.binstr
if i != 23: # skip last cycle wait
await RisingEdge(clk)
cocotb.log.info (f"[SPI_VIP] [SPI_op] address = {address}")
address = int(address,2)
#data
if command == "10000000" and False: # not sure about the read command
for i in range(8):
data_in += SDI
await RisingEdge(clk)
elif command == "00000011":
await FallingEdge(clk)
while True:
data = bin(mem[address])[2:].zfill(8)
for i in range(8):
SDO[0].value = 1 # enable
SDO[1].value = int(data[i],2) # bin
cocotb.log.debug (f"[SPI_VIP] [SPI_op] SDO = {data[i]} ")
await FallingEdge(clk)
SDO[0].value = 0 # enable
cocotb.log.info (f"[SPI_VIP] [SPI_op] finish reading address {hex(address) } data = {hex(int(data,2))} ")
address +=1
def read_mem (file_name):
with open(file_name, 'r') as file:
lines = file.readlines()
mem = dict()
for line in lines:
if line[0] == "@":
address = int(line[1:],16)
cocotb.log.debug (f" found line = {line} address = {hex(address)} ")
else:
line_no_space = line.strip().replace(' ','')
for i in range (0,len(line_no_space),2):
cocotb.log.debug (f" i = {i} ine_no_space[{i}:{i+2}] = {line_no_space[i:i+2]} address = {hex(address)}")
mem[address] = int(line_no_space[i:i+2],16)
address +=1
cocotb.log.debug (f" found line = {line} line_no_space = {line_no_space} size = {len(line_no_space)}")
cocotb.log.info (f"[read_mem] SPI mem = {mem}")
return mem

View File

@ -0,0 +1,55 @@
import random
import cocotb
from cocotb.triggers import FallingEdge,RisingEdge,ClockCycles,Timer
import cocotb.log
from cpu import RiskV
from defsParser import Regs
from cocotb.result import TestSuccess
from tests.common_functions.test_functions import *
from tests.spi_master.SPI_VIP import read_mem ,SPI_VIP
from caravel import GPIO_MODE
bit_time_ns = 0
reg = Regs()
@cocotb.test()
@repot_test
async def spi_master_rd(dut):
""" the firmware is configured to always send clk to spi so I can't insert alot of logics reading values
the method of testing used can't work if 2 addresses Consecutive have the same address
"""
caravelEnv,clock = await test_configure(dut,timeout_cycles=214842)
cpu = RiskV(dut)
cpu.cpu_force_reset()
cpu.cpu_release_reset()
cocotb.log.info (f"[TEST] start spi_master_rd test")
file_name = f"{os.getenv('CARAVEL_VERILOG_PATH')}/dv/cocotb/tests/spi_master/test_data"
mem = read_mem(file_name)
await cocotb.start(SPI_VIP(dut.bin33_monitor,dut.bin32_monitor,dut.bin35_monitor,(dut.bin34_en,dut.bin34),mem)) # fork for SPI
addresses_to_read = (0x04,0x05,0x06,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf) # the addresses that the firmware read from mem file
await wait_reg2(cpu,caravelEnv,0XAA)
cocotb.log.info (f"[TEST] GPIO configuration finished ans start reading from mememory")
val =0
for address in addresses_to_read:
# await wait_reg2(cpu,caravelEnv,0x55) # value is ready to be read
#wait until value change
while True:
if val != cpu.read_debug_reg1():
break
await ClockCycles(caravelEnv.clk,100)
expected_val = mem[address]
val = cpu.read_debug_reg1()
if val == expected_val:
cocotb.log.info(f"[TEST] correct read of value {hex(val)} from address {hex(address)} ")
else:
cocotb.log.error(f"[TEST] wrong read from address {hex(address)} expected value = {hex(expected_val)} value {hex(val)} ")
# cpu.write_debug_reg2_backdoor(0xCC)
await ClockCycles(caravelEnv.clk,1000)

View File

@ -0,0 +1,180 @@
/*
* SPDX-FileCopyrightText: 2020 Efabless Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#include <defs.h>
#include <csr.h>
// --------------------------------------------------------
/*
* SPI master Test
* - Enables SPI master
* - Uses SPI master to talk to external SPI module
*/
void spi_write(char c)
{
reg_spimaster_wdata = (unsigned long) c;
// reg_spimaster_wdata = c;
// spi_master_control_length_write(8);
// spi_master_control_start_write(1);
// reg_spimaster_control = 0x0800;
reg_spimaster_control = 0x0801;
}
char spi_read()
{
// reg_spimaster_wdata = c;
// spi_master_control_length_write(8);
// spi_master_control_start_write(1);
// reg_spimaster_control = 0x0800;
// spi_write(0x00);
// reg_spimaster_rdata = 0x00;
// reg_spimaster_control = 0x0801;
spi_write(0x00);
while (reg_spimaster_status != 1);
return reg_spimaster_rdata;
}
void main()
{
int i;
uint32_t value;
reg_wb_enable =1; // for enable writing to reg_debug_1 and reg_debug_2
reg_debug_1 = 0x0;
reg_debug_2 = 0x0;
// For SPI operation, GPIO 1 should be an input, and GPIOs 2 to 4
// should be outputs.
reg_mprj_io_34 = GPIO_MODE_MGMT_STD_INPUT_NOPULL; // SDI
reg_mprj_io_35 = GPIO_MODE_MGMT_STD_BIDIRECTIONAL; // SDO
reg_mprj_io_33 = GPIO_MODE_MGMT_STD_OUTPUT; // CSB
reg_mprj_io_32 = GPIO_MODE_MGMT_STD_OUTPUT; // SCK
/* Apply configuration */
reg_mprj_xfer = 1;
while (reg_mprj_xfer == 1);
reg_debug_2 =0xAA;
reg_spi_enable = 1;
// For SPI operation, GPIO 1 should be an input, and GPIOs 2 to 4
// should be outputs.
// Start test
// Enable SPI master
// SPI master configuration bits:
// bits 7-0: Clock prescaler value (default 2)
// bit 8: MSB/LSB first (0 = MSB first, 1 = LSB first)
// bit 9: CSB sense (0 = inverted, 1 = noninverted)
// bit 10: SCK sense (0 = noninverted, 1 = inverted)
// bit 11: mode (0 = read/write opposite edges, 1 = same edges)
// bit 12: stream (1 = CSB ends transmission)
// bit 13: enable (1 = enabled)
// bit 14: IRQ enable (1 = enabled)
// bit 15: (unused)
reg_spimaster_cs = 0x10001; // sel=0, manual CS
spi_write(0x03); // Write 0x03 (read mode)
spi_write(0x00); // Write 0x00 (start address high byte)
spi_write(0x00); // Write 0x00 (start address middle byte)
spi_write(0x04); // Write 0x04 (start address low byte)
value = spi_read(); // 0x93
reg_debug_1 = value;
// reg_debug_2 =0x55; // value is ready to be read
// while (reg_debug_2 != 0xCC) // testbench has read the value
value = spi_read(); // 0x01
reg_debug_1 = value;
// reg_debug_2 =0x55; // value is ready to be read
// while (reg_debug_2 != 0xCC) // testbench has read the value
value = spi_read(); // 0x00
reg_debug_1 = value;
// reg_debug_2 =0x55; // value is ready to be read
// while (reg_debug_2 != 0xCC) // testbench has read the value
reg_spimaster_cs = 0x0000; // release CS
reg_spimaster_cs = 0x10001; // sel=0, manual CS
spi_write(0x03); // Write 0x03 (read mode)
spi_write(0x00); // Write 0x00 (start address high byte)
spi_write(0x00); // Write 0x00 (start address middle byte)
spi_write(0x08); // Write 0x08 (start address low byte)
value = spi_read(); // 0x13
if (value == 0x13)
reg_debug_1 = value;
// reg_debug_2 =0x55; // value is ready to be read
// while (reg_debug_2 != 0xCC) // testbench has read the value
value = spi_read(); // 0x02
reg_debug_1 = value;
// reg_debug_2 =0x55; // value is ready to be read
// while (reg_debug_2 != 0xCC) // testbench has read the value
reg_spimaster_cs = 0x0000; // release CS
reg_spimaster_cs = 0x10001; // sel=0, manual CS
spi_write(0x03); // Write 0x03 (read mode)
spi_write(0x00); // Write 0x00 (start address high byte)
spi_write(0x00); // Write 0x00 (start address middle byte)
spi_write(0x0a); // Write 0x0a (start address low byte)
value = spi_read(); // 0x63
reg_debug_1 = value;
// reg_debug_2 =0x55; // value is ready to be read
// while (reg_debug_2 != 0xCC) // testbench has read the value
value = spi_read(); // 0x57
reg_debug_1 = value;
// reg_debug_2 =0x55; // value is ready to be read
// while (reg_debug_2 != 0xCC) // testbench has read the value
value = spi_read(); // 0xb5
reg_debug_1 = value;
// reg_debug_2 =0x55; // value is ready to be read
// while (reg_debug_2 != 0xCC) // testbench has read the value
value = spi_read(); // 0x00
reg_debug_1 = value;
// reg_debug_2 =0x55; // value is ready to be read
// while (reg_debug_2 != 0xCC) // testbench has read the value
value = spi_read();// 0x23
reg_debug_1 = value;
// reg_debug_2 =0x55; // value is ready to be read
// while (reg_debug_2 != 0xCC) // testbench has read the value
value = spi_read(); // 0x20
reg_debug_1 = value;
// reg_debug_2 =0x55; // value is ready to be read
// while (reg_debug_2 != 0xCC) // testbench has read the value
reg_spimaster_cs = 0x0000; // release CS
reg_spimaster_cs = 0x10001; // sel=0, manual CS
}

View File

@ -0,0 +1,3 @@
@00000000
6F 00 00 0B 93 01 00 00 13 02 63 57 b5 00 23 20
13 00 00 00 13 00 00 00 13 00 00 00 13 00 00 00