The test suite for the nRF51 GPIO peripheral for now only tests initial state. Additionally a set of tests testing an implementation detail of the model are included.
Signed-off-by: Steffen Görtz <cont...@steffen-goertz.de> Reviewed-by: Stefan Hajnoczi <stefa...@redhat.com> --- tests/microbit-test.c | 137 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 131 insertions(+), 6 deletions(-) diff --git a/tests/microbit-test.c b/tests/microbit-test.c index 743f831466..acdb9d1c02 100644 --- a/tests/microbit-test.c +++ b/tests/microbit-test.c @@ -20,14 +20,17 @@ #include "hw/arm/nrf51.h" #include "hw/nvram/nrf51_nvm.h" +#include "hw/gpio/nrf51_gpio.h" #define FLASH_SIZE (256 * NRF51_PAGE_SIZE) static void fill_and_erase(hwaddr base, hwaddr size, uint32_t address_reg) { + uint64_t i; + /* Fill memory */ writel(NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x01); - for (hwaddr i = 0; i < size; i++) { + for (i = 0; i < size; i++) { writeb(base + i, i); g_assert_cmpuint(readb(base + i), ==, i & 0xFF); } @@ -39,7 +42,7 @@ static void fill_and_erase(hwaddr base, hwaddr size, uint32_t address_reg) writel(NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00); /* Check memory */ - for (hwaddr i = 0; i < size; i++) { + for (i = 0; i < size; i++) { g_assert_cmpuint(readb(base + i), ==, 0xFF); } } @@ -47,6 +50,7 @@ static void fill_and_erase(hwaddr base, hwaddr size, uint32_t address_reg) static void test_nrf51_nvmc(void) { uint32_t value; + uint64_t i; /* Test always ready */ value = readl(NRF51_NVMC_BASE + NRF51_NVMC_READY); g_assert_cmpuint(value & 0x01, ==, 0x01); @@ -69,7 +73,7 @@ static void test_nrf51_nvmc(void) /* Erase all */ writel(NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x01); - for (hwaddr i = 0; i < FLASH_SIZE / 4; i++) { + for (i = 0; i < FLASH_SIZE / 4; i++) { writel(NRF51_FLASH_BASE + i * 4, i); g_assert_cmpuint(readl(NRF51_FLASH_BASE + i * 4), ==, i); } @@ -79,13 +83,13 @@ static void test_nrf51_nvmc(void) writel(NRF51_NVMC_BASE + NRF51_NVMC_ERASEALL, 0x01); writel(NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00); - for (hwaddr i = 0; i < FLASH_SIZE / 4; i++) { + for (i = 0; i < FLASH_SIZE / 4; i++) { g_assert_cmpuint(readl(NRF51_FLASH_BASE + i * 4), ==, 0xFFFFFFFF); } /* Erase UICR */ writel(NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x01); - for (hwaddr i = 0; i < NRF51_UICR_SIZE / 4; i++) { + for (i = 0; i < NRF51_UICR_SIZE / 4; i++) { writel(NRF51_UICR_BASE + i * 4, i); g_assert_cmpuint(readl(NRF51_UICR_BASE + i * 4), ==, i); } @@ -95,11 +99,131 @@ static void test_nrf51_nvmc(void) writel(NRF51_NVMC_BASE + NRF51_NVMC_ERASEUICR, 0x01); writel(NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00); - for (hwaddr i = 0; i < NRF51_UICR_SIZE / 4; i++) { + for (i = 0; i < NRF51_UICR_SIZE / 4; i++) { g_assert_cmpuint(readl(NRF51_UICR_BASE + i * 4), ==, 0xFFFFFFFF); } } +static void test_nrf51_gpio(void) +{ + size_t i; + uint32_t actual, expected; + + struct { + hwaddr addr; + uint32_t expected; + } reset_state[] = { + {NRF51_GPIO_REG_OUT, 0x00000000}, {NRF51_GPIO_REG_OUTSET, 0x00000000}, + {NRF51_GPIO_REG_OUTCLR, 0x00000000}, {NRF51_GPIO_REG_IN, 0x00000000}, + {NRF51_GPIO_REG_DIR, 0x00000000}, {NRF51_GPIO_REG_DIRSET, 0x00000000}, + {NRF51_GPIO_REG_DIRCLR, 0x00000000} + }; + + /* Check reset state */ + for (i = 0; i < ARRAY_SIZE(reset_state); i++) { + expected = reset_state[i].expected; + actual = readl(NRF51_GPIO_BASE + reset_state[i].addr); + g_assert_cmpuint(actual, ==, expected); + } + + for (i = 0; i < NRF51_GPIO_PINS; i++) { + expected = 0x00000002; + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START + i * 4); + g_assert_cmpuint(actual, ==, expected); + } + + /* Check dir bit consistency between dir and cnf */ + /* Check set via DIRSET */ + expected = 0x80000001; + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRSET, expected); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR); + g_assert_cmpuint(actual, ==, expected); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01; + g_assert_cmpuint(actual, ==, 0x01); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01; + g_assert_cmpuint(actual, ==, 0x01); + + /* Check clear via DIRCLR */ + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRCLR, 0x80000001); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR); + g_assert_cmpuint(actual, ==, 0x00000000); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01; + g_assert_cmpuint(actual, ==, 0x00); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01; + g_assert_cmpuint(actual, ==, 0x00); + + /* Check set via DIR */ + expected = 0x80000001; + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, expected); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR); + g_assert_cmpuint(actual, ==, expected); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01; + g_assert_cmpuint(actual, ==, 0x01); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01; + g_assert_cmpuint(actual, ==, 0x01); + + /* Reset DIR */ + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, 0x00000000); + + /* Check Input propagates */ + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x00); + set_irq_in("/machine/nrf51", "unnamed-gpio-in", 0, 0); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; + g_assert_cmpuint(actual, ==, 0x00); + set_irq_in("/machine/nrf51", "unnamed-gpio-in", 0, 1); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; + g_assert_cmpuint(actual, ==, 0x01); + set_irq_in("/machine/nrf51", "unnamed-gpio-in", 0, -1); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; + g_assert_cmpuint(actual, ==, 0x01); + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02); + + /* Check pull-up working */ + set_irq_in("/machine/nrf51", "unnamed-gpio-in", 0, 0); + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; + g_assert_cmpuint(actual, ==, 0x00); + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b1110); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; + g_assert_cmpuint(actual, ==, 0x01); + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02); + + /* Check pull-down working */ + set_irq_in("/machine/nrf51", "unnamed-gpio-in", 0, 1); + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; + g_assert_cmpuint(actual, ==, 0x01); + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0110); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; + g_assert_cmpuint(actual, ==, 0x00); + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02); + set_irq_in("/machine/nrf51", "unnamed-gpio-in", 0, -1); + + /* Check Output propagates */ + irq_intercept_out("/machine/nrf51"); + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0011); + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01); + g_assert_true(get_irq(0)); + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01); + g_assert_false(get_irq(0)); + + /* Check self-stimulation */ + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01); + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; + g_assert_cmpuint(actual, ==, 0x01); + + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01); + actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; + g_assert_cmpuint(actual, ==, 0x00); + + /* Check short-circuit - generates an guest_error which must be checked + manually as long as qtest can not scan qemu_log messages */ + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01); + writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01); + set_irq_in("/machine/nrf51", "unnamed-gpio-in", 0, 0); +} + int main(int argc, char **argv) { int ret; @@ -109,6 +233,7 @@ int main(int argc, char **argv) global_qtest = qtest_initf("-machine microbit"); qtest_add_func("/microbit/nrf51/nvmc", test_nrf51_nvmc); + qtest_add_func("/microbit/nrf51/gpio", test_nrf51_gpio); ret = g_test_run(); -- 2.19.1