test: add noisy, max_iter, and back-to-back cocotb tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,3 +6,6 @@ from user_proj_tests.counter_la_reset.counter_la_reset import counter_la_reset
|
||||
from user_proj_tests.counter_la_clk.counter_la_clk import counter_la_clk
|
||||
from gpio_test.gpio_test import gpio_test
|
||||
from ldpc_tests.ldpc_basic.ldpc_basic import ldpc_basic
|
||||
from ldpc_tests.ldpc_noisy.ldpc_noisy import ldpc_noisy
|
||||
from ldpc_tests.ldpc_max_iter.ldpc_max_iter import ldpc_max_iter
|
||||
from ldpc_tests.ldpc_back_to_back.ldpc_back_to_back import ldpc_back_to_back
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
// SPDX-FileCopyrightText: 2024 LDPC Optical Project
|
||||
|
||||
// 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
|
||||
|
||||
/*
|
||||
* LDPC Back-to-Back Decode Test Firmware
|
||||
*
|
||||
* Runs on PicoRV32 inside Caravel. Exercises the LDPC decoder with two
|
||||
* sequential decodes to verify no state leakage between runs:
|
||||
* 1. First decode: all-zero codeword (LLRs=+31), check decoded=0
|
||||
* 2. Second decode: noisy correctable codeword (test vector 0),
|
||||
* check decoded matches expected
|
||||
* 3. Signals pass (0xAB) only if BOTH decodes are correct
|
||||
*/
|
||||
|
||||
#include <firmware_apis.h>
|
||||
|
||||
// LDPC register word offsets (byte_addr / 4)
|
||||
#define LDPC_CTRL 0 // 0x00
|
||||
#define LDPC_STATUS 1 // 0x04
|
||||
#define LDPC_LLR_BASE 4 // 0x10
|
||||
#define LDPC_DECODED 20 // 0x50
|
||||
#define LDPC_VERSION 21 // 0x54
|
||||
|
||||
#define LLR_WORD_COUNT 52 // 260 LLRs / 5 per word, rounded up
|
||||
|
||||
// CTRL register fields
|
||||
#define CTRL_START (1 << 0)
|
||||
#define CTRL_EARLY_TERM (1 << 1)
|
||||
#define CTRL_MAX_ITER(n) (((n) & 0x1F) << 8)
|
||||
|
||||
// STATUS register fields
|
||||
#define STATUS_BUSY (1 << 0)
|
||||
#define STATUS_CONVERGED (1 << 1)
|
||||
#define STATUS_ITER_MASK (0x1F << 8)
|
||||
#define STATUS_SYN_MASK (0xFF << 16)
|
||||
|
||||
// Expected values
|
||||
#define EXPECTED_VERSION 0x1D010001
|
||||
#define PASS_SIGNATURE 0xAB
|
||||
#define FAIL_SIGNATURE 0xFF
|
||||
|
||||
// All-zero codeword: every LLR = +31 (6'b011111 = 0x1F)
|
||||
// Pack 5x 0x1F per word:
|
||||
// (0x1F << 0) | (0x1F << 6) | (0x1F << 12) | (0x1F << 18) | (0x1F << 24)
|
||||
// = 0x1F7DF7DF
|
||||
#define ALL_ZERO_LLR_WORD 0x1F7DF7DF
|
||||
|
||||
// Test vector 0: noisy but correctable codeword
|
||||
// Expected decoded word: 0x3FD74222
|
||||
#define EXPECTED_DECODED_VEC0 0x3FD74222
|
||||
|
||||
static const unsigned int noisy_llr_words[LLR_WORD_COUNT] = {
|
||||
0x1F7DF81F, 0x20C9F7E0, 0x207CC7DF, 0x1F82081F, 0x328207E0, 0x20820820, 0x208207CC, 0x1F81F7DF,
|
||||
0x1F7F27DF, 0x1F7CC81F, 0x0C81F81F, 0x207E07F2, 0x1F820820, 0x207DF7CC, 0x1F81F7E0, 0x2082081F,
|
||||
0x0C31F81F, 0x2081F7DF, 0x1FCA081F, 0x20820820, 0x1F7DF7DF, 0x207E07E0, 0x208207CC, 0x1F8207DF,
|
||||
0x0C7DF7DF, 0x2030C820, 0x207DF7E0, 0x1F82081F, 0x203207DF, 0x20832820, 0x2081F820, 0x20820832,
|
||||
0x1F82081F, 0x207E081F, 0x207DF820, 0x1F7E0320, 0x1F7E07E0, 0x1F81F820, 0x20CA07CC, 0x0C81F7E0,
|
||||
0x1F820820, 0x1FCA07DF, 0x1F7E080C, 0x208207F2, 0x207E081F, 0x20820820, 0x207E07DF, 0x2082081F,
|
||||
0x1F7E07DF, 0x1F7DF7E0, 0x207DF820, 0x00000020
|
||||
};
|
||||
|
||||
void main(){
|
||||
unsigned int status;
|
||||
unsigned int decoded;
|
||||
unsigned int version;
|
||||
int pass = 1;
|
||||
|
||||
// --- Setup management GPIO for synchronization ---
|
||||
ManagmentGpio_outputEnable();
|
||||
ManagmentGpio_write(0);
|
||||
enableHkSpi(0);
|
||||
|
||||
// Configure all GPIOs as management standard output (driven by firmware)
|
||||
GPIOs_configureAll(GPIO_MODE_MGMT_STD_OUTPUT);
|
||||
GPIOs_loadConfigs();
|
||||
|
||||
// Clear GPIO output
|
||||
GPIOs_writeLow(0x00000000);
|
||||
|
||||
// Enable Wishbone interface to user project
|
||||
User_enableIF();
|
||||
|
||||
// Signal firmware ready
|
||||
ManagmentGpio_write(1);
|
||||
|
||||
// --- Step 1: Read and verify VERSION register ---
|
||||
version = USER_readWord(LDPC_VERSION);
|
||||
if (version != EXPECTED_VERSION) {
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
// ===== DECODE 1: All-zero codeword =====
|
||||
|
||||
// Write all-zero LLRs (+31 confidence in bit=0)
|
||||
for (int i = 0; i < LLR_WORD_COUNT - 1; i++) {
|
||||
USER_writeWord(ALL_ZERO_LLR_WORD, LDPC_LLR_BASE + i);
|
||||
}
|
||||
// Last word: only LLR[255] = +31, remaining slots zero
|
||||
USER_writeWord(0x0000001F, LDPC_LLR_BASE + LLR_WORD_COUNT - 1);
|
||||
|
||||
// Start decode: start=1, early_term_en=1, max_iter=30
|
||||
USER_writeWord(CTRL_START | CTRL_EARLY_TERM | CTRL_MAX_ITER(30), LDPC_CTRL);
|
||||
|
||||
// Poll until done
|
||||
do {
|
||||
status = USER_readWord(LDPC_STATUS);
|
||||
} while (status & STATUS_BUSY);
|
||||
|
||||
// Check converged
|
||||
if (!(status & STATUS_CONVERGED)) {
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
// Check syndrome weight = 0
|
||||
if ((status & STATUS_SYN_MASK) != 0) {
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
// Check decoded = 0 (all-zero codeword)
|
||||
decoded = USER_readWord(LDPC_DECODED);
|
||||
if (decoded != 0x00000000) {
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
// ===== DECODE 2: Noisy correctable codeword =====
|
||||
|
||||
// Write noisy LLRs
|
||||
for (int i = 0; i < LLR_WORD_COUNT; i++) {
|
||||
USER_writeWord(noisy_llr_words[i], LDPC_LLR_BASE + i);
|
||||
}
|
||||
|
||||
// Start decode: start=1, early_term_en=1, max_iter=30
|
||||
USER_writeWord(CTRL_START | CTRL_EARLY_TERM | CTRL_MAX_ITER(30), LDPC_CTRL);
|
||||
|
||||
// Poll until done
|
||||
do {
|
||||
status = USER_readWord(LDPC_STATUS);
|
||||
} while (status & STATUS_BUSY);
|
||||
|
||||
// Check converged
|
||||
if (!(status & STATUS_CONVERGED)) {
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
// Check syndrome weight = 0
|
||||
if ((status & STATUS_SYN_MASK) != 0) {
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
// Check decoded matches expected
|
||||
decoded = USER_readWord(LDPC_DECODED);
|
||||
if (decoded != EXPECTED_DECODED_VEC0) {
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
// --- Signal result via GPIO[7:0] ---
|
||||
if (pass) {
|
||||
GPIOs_writeLow(PASS_SIGNATURE); // 0xAB = pass (both decodes correct)
|
||||
} else {
|
||||
GPIOs_writeLow(FAIL_SIGNATURE); // 0xFF = fail
|
||||
}
|
||||
|
||||
// Signal test complete via management GPIO
|
||||
ManagmentGpio_write(0);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
# SPDX-FileCopyrightText: 2024 LDPC Optical Project
|
||||
|
||||
# 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
|
||||
|
||||
"""
|
||||
LDPC Back-to-Back Decode Test - cocotb Monitor
|
||||
|
||||
Tests the LDPC decoder with two sequential decodes to verify no state
|
||||
leakage between runs. Firmware:
|
||||
1. First decode: all-zero codeword, check converged=1, decoded=0
|
||||
2. Second decode: noisy correctable codeword, check converged=1,
|
||||
decoded matches expected
|
||||
3. Signals pass (0xAB) only if BOTH decodes are correct
|
||||
|
||||
The cocotb monitor waits for the management GPIO to signal firmware ready,
|
||||
then waits for the management GPIO to drop (test complete), and reads
|
||||
GPIO[7:0] for the pass/fail result.
|
||||
"""
|
||||
|
||||
from caravel_cocotb.caravel_interfaces import test_configure
|
||||
from caravel_cocotb.caravel_interfaces import report_test
|
||||
import cocotb
|
||||
|
||||
PASS_SIGNATURE = 0xAB
|
||||
FAIL_SIGNATURE = 0xFF
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
@report_test
|
||||
async def ldpc_back_to_back(dut):
|
||||
caravelEnv = await test_configure(dut, timeout_cycles=500000)
|
||||
|
||||
cocotb.log.info("[TEST] Starting LDPC back-to-back decode test")
|
||||
|
||||
# Release CSB to allow GPIO to function
|
||||
await caravelEnv.release_csb()
|
||||
|
||||
# Wait for firmware to signal ready (mgmt_gpio = 1)
|
||||
cocotb.log.info("[TEST] Waiting for firmware ready (mgmt_gpio=1)...")
|
||||
await caravelEnv.wait_mgmt_gpio(1)
|
||||
cocotb.log.info("[TEST] Firmware ready, back-to-back decodes in progress...")
|
||||
|
||||
# Wait for firmware to signal test complete (mgmt_gpio = 0)
|
||||
await caravelEnv.wait_mgmt_gpio(0)
|
||||
cocotb.log.info("[TEST] Firmware signaled test complete")
|
||||
|
||||
# Read GPIO[7:0] for pass/fail result
|
||||
gpio_val = caravelEnv.monitor_gpio(7, 0)
|
||||
|
||||
if not gpio_val.is_resolvable:
|
||||
cocotb.log.error(
|
||||
f"[TEST] FAIL - GPIO[7:0] is unresolvable: {gpio_val.binstr}"
|
||||
)
|
||||
assert False, "GPIO[7:0] has X/Z values"
|
||||
|
||||
result = gpio_val.integer
|
||||
cocotb.log.info(f"[TEST] GPIO[7:0] = 0x{result:02X}")
|
||||
|
||||
if result == PASS_SIGNATURE:
|
||||
cocotb.log.info(
|
||||
"[TEST] PASS - Both back-to-back decodes correct (0xAB)"
|
||||
)
|
||||
elif result == FAIL_SIGNATURE:
|
||||
cocotb.log.error(
|
||||
"[TEST] FAIL - Back-to-back decode test failed (0xFF)"
|
||||
)
|
||||
assert False, "Firmware reported LDPC back-to-back decode failure"
|
||||
else:
|
||||
cocotb.log.error(
|
||||
f"[TEST] FAIL - Unexpected GPIO value: 0x{result:02X}"
|
||||
)
|
||||
assert False, f"Unexpected GPIO result: 0x{result:02X}"
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
# SPDX-FileCopyrightText: 2024 LDPC Optical Project
|
||||
|
||||
# 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
|
||||
|
||||
Tests:
|
||||
- {name: ldpc_back_to_back, sim: RTL}
|
||||
139
verilog/dv/cocotb/ldpc_tests/ldpc_max_iter/ldpc_max_iter.c
Normal file
139
verilog/dv/cocotb/ldpc_tests/ldpc_max_iter/ldpc_max_iter.c
Normal file
@@ -0,0 +1,139 @@
|
||||
// SPDX-FileCopyrightText: 2024 LDPC Optical Project
|
||||
|
||||
// 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
|
||||
|
||||
/*
|
||||
* LDPC Max Iteration Test Firmware
|
||||
*
|
||||
* Runs on PicoRV32 inside Caravel. Exercises the LDPC decoder with an
|
||||
* uncorrectable codeword to verify it hits max iterations:
|
||||
* 1. Writes uncorrectable noisy LLRs (test vector 11)
|
||||
* 2. Starts decode with early termination, max_iter=30
|
||||
* 3. Checks converged=0 (not converged), iterations_used=30 (hit max)
|
||||
* 4. Signals pass (0xAB) or fail (0xFF) on GPIO[7:0]
|
||||
*/
|
||||
|
||||
#include <firmware_apis.h>
|
||||
|
||||
// LDPC register word offsets (byte_addr / 4)
|
||||
#define LDPC_CTRL 0 // 0x00
|
||||
#define LDPC_STATUS 1 // 0x04
|
||||
#define LDPC_LLR_BASE 4 // 0x10
|
||||
#define LDPC_DECODED 20 // 0x50
|
||||
#define LDPC_VERSION 21 // 0x54
|
||||
|
||||
#define LLR_WORD_COUNT 52 // 260 LLRs / 5 per word, rounded up
|
||||
|
||||
// CTRL register fields
|
||||
#define CTRL_START (1 << 0)
|
||||
#define CTRL_EARLY_TERM (1 << 1)
|
||||
#define CTRL_MAX_ITER(n) (((n) & 0x1F) << 8)
|
||||
|
||||
// STATUS register fields
|
||||
#define STATUS_BUSY (1 << 0)
|
||||
#define STATUS_CONVERGED (1 << 1)
|
||||
#define STATUS_ITER_MASK (0x1F << 8)
|
||||
#define STATUS_SYN_MASK (0xFF << 16)
|
||||
|
||||
// Expected values
|
||||
#define EXPECTED_VERSION 0x1D010001
|
||||
#define PASS_SIGNATURE 0xAB
|
||||
#define FAIL_SIGNATURE 0xFF
|
||||
|
||||
// Test vector 11: uncorrectable codeword (too many errors)
|
||||
// Expected: converged=False, iterations=30, syndrome_weight=67
|
||||
static const unsigned int uncorrectable_llr_words[LLR_WORD_COUNT] = {
|
||||
0x0C30C80C, 0x0C30C30C, 0x2730C820, 0x0C80C30C, 0x0C32730C, 0x0C30C9E7, 0x0CE8C33A, 0x0C9CC320,
|
||||
0x2032030C, 0x0C32030C, 0x0C30C9E0, 0x209CC320, 0x0C9E730C, 0x0C33A9CC, 0x3A80C30C, 0x0C30C80C,
|
||||
0x279CC320, 0x0CEA080C, 0x0C30C9CC, 0x279E0320, 0x2730C30C, 0x0CE8C30C, 0x0C80C9CC, 0x0C9CC30C,
|
||||
0x3AE8CEA0, 0x20E8C320, 0x0C33A80C, 0x0CEBA33A, 0x0C30C9CC, 0x27EA0E8C, 0x0C30CEBA, 0x0CE8C30C,
|
||||
0x0CEA7EA7, 0x0C30C30C, 0x0C83A327, 0x0CEBA30C, 0x0C83AEA0, 0x2033A80C, 0x0C80C30C, 0x0C30C30C,
|
||||
0x0C82730C, 0x3A30C33A, 0x3A820E8C, 0x0C30C320, 0x0C30C9E7, 0x279CC320, 0x2080C30C, 0x27320327,
|
||||
0x3A32083A, 0x0C33A80C, 0x0C9CC30C, 0x0000000C
|
||||
};
|
||||
|
||||
void main(){
|
||||
unsigned int status;
|
||||
unsigned int version;
|
||||
unsigned int iter_used;
|
||||
int pass = 1;
|
||||
|
||||
// --- Setup management GPIO for synchronization ---
|
||||
ManagmentGpio_outputEnable();
|
||||
ManagmentGpio_write(0);
|
||||
enableHkSpi(0);
|
||||
|
||||
// Configure all GPIOs as management standard output (driven by firmware)
|
||||
GPIOs_configureAll(GPIO_MODE_MGMT_STD_OUTPUT);
|
||||
GPIOs_loadConfigs();
|
||||
|
||||
// Clear GPIO output
|
||||
GPIOs_writeLow(0x00000000);
|
||||
|
||||
// Enable Wishbone interface to user project
|
||||
User_enableIF();
|
||||
|
||||
// Signal firmware ready
|
||||
ManagmentGpio_write(1);
|
||||
|
||||
// --- Step 1: Read and verify VERSION register ---
|
||||
version = USER_readWord(LDPC_VERSION);
|
||||
if (version != EXPECTED_VERSION) {
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
// --- Step 2: Write uncorrectable noisy LLRs ---
|
||||
for (int i = 0; i < LLR_WORD_COUNT; i++) {
|
||||
USER_writeWord(uncorrectable_llr_words[i], LDPC_LLR_BASE + i);
|
||||
}
|
||||
|
||||
// --- Step 3: Start decode ---
|
||||
// start=1, early_term_en=1, max_iter=30
|
||||
USER_writeWord(CTRL_START | CTRL_EARLY_TERM | CTRL_MAX_ITER(30), LDPC_CTRL);
|
||||
|
||||
// --- Step 4: Poll STATUS until not busy ---
|
||||
do {
|
||||
status = USER_readWord(LDPC_STATUS);
|
||||
} while (status & STATUS_BUSY);
|
||||
|
||||
// --- Step 5: Check results ---
|
||||
// Should NOT have converged
|
||||
if (status & STATUS_CONVERGED) {
|
||||
pass = 0; // Unexpectedly converged
|
||||
}
|
||||
|
||||
// Should have used all 30 iterations
|
||||
iter_used = (status & STATUS_ITER_MASK) >> 8;
|
||||
if (iter_used != 30) {
|
||||
pass = 0; // Did not hit max iterations
|
||||
}
|
||||
|
||||
// Syndrome weight should be non-zero (not converged)
|
||||
if ((status & STATUS_SYN_MASK) == 0) {
|
||||
pass = 0; // Syndrome weight unexpectedly zero
|
||||
}
|
||||
|
||||
// --- Step 6: Signal result via GPIO[7:0] ---
|
||||
if (pass) {
|
||||
GPIOs_writeLow(PASS_SIGNATURE); // 0xAB = pass
|
||||
} else {
|
||||
GPIOs_writeLow(FAIL_SIGNATURE); // 0xFF = fail
|
||||
}
|
||||
|
||||
// Signal test complete via management GPIO
|
||||
ManagmentGpio_write(0);
|
||||
|
||||
return;
|
||||
}
|
||||
84
verilog/dv/cocotb/ldpc_tests/ldpc_max_iter/ldpc_max_iter.py
Normal file
84
verilog/dv/cocotb/ldpc_tests/ldpc_max_iter/ldpc_max_iter.py
Normal file
@@ -0,0 +1,84 @@
|
||||
# SPDX-FileCopyrightText: 2024 LDPC Optical Project
|
||||
|
||||
# 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
|
||||
|
||||
"""
|
||||
LDPC Max Iteration Test - cocotb Monitor
|
||||
|
||||
Tests the LDPC decoder with an uncorrectable codeword. Firmware:
|
||||
1. Verifies the VERSION register
|
||||
2. Loads uncorrectable noisy LLRs (test vector 11)
|
||||
3. Runs a decode with early termination, max_iter=30
|
||||
4. Checks converged=0, iterations_used=30, syndrome_weight>0
|
||||
5. Signals pass (0xAB) or fail (0xFF) on GPIO[7:0]
|
||||
|
||||
The cocotb monitor waits for the management GPIO to signal firmware ready,
|
||||
then waits for the management GPIO to drop (test complete), and reads
|
||||
GPIO[7:0] for the pass/fail result.
|
||||
"""
|
||||
|
||||
from caravel_cocotb.caravel_interfaces import test_configure
|
||||
from caravel_cocotb.caravel_interfaces import report_test
|
||||
import cocotb
|
||||
|
||||
PASS_SIGNATURE = 0xAB
|
||||
FAIL_SIGNATURE = 0xFF
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
@report_test
|
||||
async def ldpc_max_iter(dut):
|
||||
caravelEnv = await test_configure(dut, timeout_cycles=300000)
|
||||
|
||||
cocotb.log.info("[TEST] Starting LDPC max iteration test")
|
||||
|
||||
# Release CSB to allow GPIO to function
|
||||
await caravelEnv.release_csb()
|
||||
|
||||
# Wait for firmware to signal ready (mgmt_gpio = 1)
|
||||
cocotb.log.info("[TEST] Waiting for firmware ready (mgmt_gpio=1)...")
|
||||
await caravelEnv.wait_mgmt_gpio(1)
|
||||
cocotb.log.info("[TEST] Firmware ready, decode in progress...")
|
||||
|
||||
# Wait for firmware to signal test complete (mgmt_gpio = 0)
|
||||
await caravelEnv.wait_mgmt_gpio(0)
|
||||
cocotb.log.info("[TEST] Firmware signaled test complete")
|
||||
|
||||
# Read GPIO[7:0] for pass/fail result
|
||||
gpio_val = caravelEnv.monitor_gpio(7, 0)
|
||||
|
||||
if not gpio_val.is_resolvable:
|
||||
cocotb.log.error(
|
||||
f"[TEST] FAIL - GPIO[7:0] is unresolvable: {gpio_val.binstr}"
|
||||
)
|
||||
assert False, "GPIO[7:0] has X/Z values"
|
||||
|
||||
result = gpio_val.integer
|
||||
cocotb.log.info(f"[TEST] GPIO[7:0] = 0x{result:02X}")
|
||||
|
||||
if result == PASS_SIGNATURE:
|
||||
cocotb.log.info(
|
||||
"[TEST] PASS - Firmware confirmed max iteration behavior (0xAB)"
|
||||
)
|
||||
elif result == FAIL_SIGNATURE:
|
||||
cocotb.log.error(
|
||||
"[TEST] FAIL - Firmware reported max iteration test failure (0xFF)"
|
||||
)
|
||||
assert False, "Firmware reported LDPC max iteration test failure"
|
||||
else:
|
||||
cocotb.log.error(
|
||||
f"[TEST] FAIL - Unexpected GPIO value: 0x{result:02X}"
|
||||
)
|
||||
assert False, f"Unexpected GPIO result: 0x{result:02X}"
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
# SPDX-FileCopyrightText: 2024 LDPC Optical Project
|
||||
|
||||
# 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
|
||||
|
||||
Tests:
|
||||
- {name: ldpc_max_iter, sim: RTL}
|
||||
141
verilog/dv/cocotb/ldpc_tests/ldpc_noisy/ldpc_noisy.c
Normal file
141
verilog/dv/cocotb/ldpc_tests/ldpc_noisy/ldpc_noisy.c
Normal file
@@ -0,0 +1,141 @@
|
||||
// SPDX-FileCopyrightText: 2024 LDPC Optical Project
|
||||
|
||||
// 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
|
||||
|
||||
/*
|
||||
* LDPC Noisy Decode Test Firmware
|
||||
*
|
||||
* Runs on PicoRV32 inside Caravel. Exercises the LDPC decoder with a noisy
|
||||
* but correctable codeword:
|
||||
* 1. Writes noisy LLRs (test vector 0 from gen_firmware_vectors.py)
|
||||
* 2. Starts decode with early termination, max_iter=30
|
||||
* 3. Checks converged=1, syndrome_weight=0, decoded matches expected
|
||||
* 4. Signals pass (0xAB) or fail (0xFF) on GPIO[7:0]
|
||||
*/
|
||||
|
||||
#include <firmware_apis.h>
|
||||
|
||||
// LDPC register word offsets (byte_addr / 4)
|
||||
#define LDPC_CTRL 0 // 0x00
|
||||
#define LDPC_STATUS 1 // 0x04
|
||||
#define LDPC_LLR_BASE 4 // 0x10
|
||||
#define LDPC_DECODED 20 // 0x50
|
||||
#define LDPC_VERSION 21 // 0x54
|
||||
|
||||
#define LLR_WORD_COUNT 52 // 260 LLRs / 5 per word, rounded up
|
||||
|
||||
// CTRL register fields
|
||||
#define CTRL_START (1 << 0)
|
||||
#define CTRL_EARLY_TERM (1 << 1)
|
||||
#define CTRL_MAX_ITER(n) (((n) & 0x1F) << 8)
|
||||
|
||||
// STATUS register fields
|
||||
#define STATUS_BUSY (1 << 0)
|
||||
#define STATUS_CONVERGED (1 << 1)
|
||||
#define STATUS_ITER_MASK (0x1F << 8)
|
||||
#define STATUS_SYN_MASK (0xFF << 16)
|
||||
|
||||
// Expected values
|
||||
#define EXPECTED_VERSION 0x1D010001
|
||||
#define PASS_SIGNATURE 0xAB
|
||||
#define FAIL_SIGNATURE 0xFF
|
||||
|
||||
// Test vector 0: noisy but correctable codeword
|
||||
// Expected decoded word: 0x3FD74222
|
||||
#define EXPECTED_DECODED 0x3FD74222
|
||||
|
||||
static const unsigned int noisy_llr_words[LLR_WORD_COUNT] = {
|
||||
0x1F7DF81F, 0x20C9F7E0, 0x207CC7DF, 0x1F82081F, 0x328207E0, 0x20820820, 0x208207CC, 0x1F81F7DF,
|
||||
0x1F7F27DF, 0x1F7CC81F, 0x0C81F81F, 0x207E07F2, 0x1F820820, 0x207DF7CC, 0x1F81F7E0, 0x2082081F,
|
||||
0x0C31F81F, 0x2081F7DF, 0x1FCA081F, 0x20820820, 0x1F7DF7DF, 0x207E07E0, 0x208207CC, 0x1F8207DF,
|
||||
0x0C7DF7DF, 0x2030C820, 0x207DF7E0, 0x1F82081F, 0x203207DF, 0x20832820, 0x2081F820, 0x20820832,
|
||||
0x1F82081F, 0x207E081F, 0x207DF820, 0x1F7E0320, 0x1F7E07E0, 0x1F81F820, 0x20CA07CC, 0x0C81F7E0,
|
||||
0x1F820820, 0x1FCA07DF, 0x1F7E080C, 0x208207F2, 0x207E081F, 0x20820820, 0x207E07DF, 0x2082081F,
|
||||
0x1F7E07DF, 0x1F7DF7E0, 0x207DF820, 0x00000020
|
||||
};
|
||||
|
||||
void main(){
|
||||
unsigned int status;
|
||||
unsigned int decoded;
|
||||
unsigned int version;
|
||||
int pass = 1;
|
||||
|
||||
// --- Setup management GPIO for synchronization ---
|
||||
ManagmentGpio_outputEnable();
|
||||
ManagmentGpio_write(0);
|
||||
enableHkSpi(0);
|
||||
|
||||
// Configure all GPIOs as management standard output (driven by firmware)
|
||||
GPIOs_configureAll(GPIO_MODE_MGMT_STD_OUTPUT);
|
||||
GPIOs_loadConfigs();
|
||||
|
||||
// Clear GPIO output
|
||||
GPIOs_writeLow(0x00000000);
|
||||
|
||||
// Enable Wishbone interface to user project
|
||||
User_enableIF();
|
||||
|
||||
// Signal firmware ready
|
||||
ManagmentGpio_write(1);
|
||||
|
||||
// --- Step 1: Read and verify VERSION register ---
|
||||
version = USER_readWord(LDPC_VERSION);
|
||||
if (version != EXPECTED_VERSION) {
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
// --- Step 2: Write noisy LLRs ---
|
||||
for (int i = 0; i < LLR_WORD_COUNT; i++) {
|
||||
USER_writeWord(noisy_llr_words[i], LDPC_LLR_BASE + i);
|
||||
}
|
||||
|
||||
// --- Step 3: Start decode ---
|
||||
// start=1, early_term_en=1, max_iter=30
|
||||
USER_writeWord(CTRL_START | CTRL_EARLY_TERM | CTRL_MAX_ITER(30), LDPC_CTRL);
|
||||
|
||||
// --- Step 4: Poll STATUS until not busy ---
|
||||
do {
|
||||
status = USER_readWord(LDPC_STATUS);
|
||||
} while (status & STATUS_BUSY);
|
||||
|
||||
// --- Step 5: Check results ---
|
||||
// Check converged (bit 1)
|
||||
if (!(status & STATUS_CONVERGED)) {
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
// Check syndrome weight = 0 (bits [23:16])
|
||||
if ((status & STATUS_SYN_MASK) != 0) {
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
// Read decoded info bits
|
||||
decoded = USER_readWord(LDPC_DECODED);
|
||||
if (decoded != EXPECTED_DECODED) {
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
// --- Step 6: Signal result via GPIO[7:0] ---
|
||||
if (pass) {
|
||||
GPIOs_writeLow(PASS_SIGNATURE); // 0xAB = pass
|
||||
} else {
|
||||
GPIOs_writeLow(FAIL_SIGNATURE); // 0xFF = fail
|
||||
}
|
||||
|
||||
// Signal test complete via management GPIO
|
||||
ManagmentGpio_write(0);
|
||||
|
||||
return;
|
||||
}
|
||||
82
verilog/dv/cocotb/ldpc_tests/ldpc_noisy/ldpc_noisy.py
Normal file
82
verilog/dv/cocotb/ldpc_tests/ldpc_noisy/ldpc_noisy.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# SPDX-FileCopyrightText: 2024 LDPC Optical Project
|
||||
|
||||
# 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
|
||||
|
||||
"""
|
||||
LDPC Noisy Decode Test - cocotb Monitor
|
||||
|
||||
Tests the LDPC decoder with a noisy but correctable codeword. Firmware:
|
||||
1. Verifies the VERSION register
|
||||
2. Loads noisy LLRs (test vector 0)
|
||||
3. Runs a decode with early termination, max_iter=30
|
||||
4. Checks converged=1, syndrome_weight=0, decoded matches expected
|
||||
5. Signals pass (0xAB) or fail (0xFF) on GPIO[7:0]
|
||||
|
||||
The cocotb monitor waits for the management GPIO to signal firmware ready,
|
||||
then waits for the management GPIO to drop (test complete), and reads
|
||||
GPIO[7:0] for the pass/fail result.
|
||||
"""
|
||||
|
||||
from caravel_cocotb.caravel_interfaces import test_configure
|
||||
from caravel_cocotb.caravel_interfaces import report_test
|
||||
import cocotb
|
||||
|
||||
PASS_SIGNATURE = 0xAB
|
||||
FAIL_SIGNATURE = 0xFF
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
@report_test
|
||||
async def ldpc_noisy(dut):
|
||||
caravelEnv = await test_configure(dut, timeout_cycles=300000)
|
||||
|
||||
cocotb.log.info("[TEST] Starting LDPC noisy decode test")
|
||||
|
||||
# Release CSB to allow GPIO to function
|
||||
await caravelEnv.release_csb()
|
||||
|
||||
# Wait for firmware to signal ready (mgmt_gpio = 1)
|
||||
cocotb.log.info("[TEST] Waiting for firmware ready (mgmt_gpio=1)...")
|
||||
await caravelEnv.wait_mgmt_gpio(1)
|
||||
cocotb.log.info("[TEST] Firmware ready, decode in progress...")
|
||||
|
||||
# Wait for firmware to signal test complete (mgmt_gpio = 0)
|
||||
await caravelEnv.wait_mgmt_gpio(0)
|
||||
cocotb.log.info("[TEST] Firmware signaled test complete")
|
||||
|
||||
# Read GPIO[7:0] for pass/fail result
|
||||
gpio_val = caravelEnv.monitor_gpio(7, 0)
|
||||
|
||||
if not gpio_val.is_resolvable:
|
||||
cocotb.log.error(
|
||||
f"[TEST] FAIL - GPIO[7:0] is unresolvable: {gpio_val.binstr}"
|
||||
)
|
||||
assert False, "GPIO[7:0] has X/Z values"
|
||||
|
||||
result = gpio_val.integer
|
||||
cocotb.log.info(f"[TEST] GPIO[7:0] = 0x{result:02X}")
|
||||
|
||||
if result == PASS_SIGNATURE:
|
||||
cocotb.log.info("[TEST] PASS - Firmware reported noisy decode success (0xAB)")
|
||||
elif result == FAIL_SIGNATURE:
|
||||
cocotb.log.error(
|
||||
"[TEST] FAIL - Firmware reported noisy decode failure (0xFF)"
|
||||
)
|
||||
assert False, "Firmware reported LDPC noisy decode failure"
|
||||
else:
|
||||
cocotb.log.error(
|
||||
f"[TEST] FAIL - Unexpected GPIO value: 0x{result:02X}"
|
||||
)
|
||||
assert False, f"Unexpected GPIO result: 0x{result:02X}"
|
||||
19
verilog/dv/cocotb/ldpc_tests/ldpc_noisy/ldpc_noisy.yaml
Normal file
19
verilog/dv/cocotb/ldpc_tests/ldpc_noisy/ldpc_noisy.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
# SPDX-FileCopyrightText: 2024 LDPC Optical Project
|
||||
|
||||
# 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
|
||||
|
||||
Tests:
|
||||
- {name: ldpc_noisy, sim: RTL}
|
||||
Reference in New Issue
Block a user