aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2020-11-24 13:46:41 -0700
committerJosh Rahm <joshuarahm@gmail.com>2020-11-24 13:46:41 -0700
commit93b063fedfcf7409a67df035170ea5670cad22e1 (patch)
treea23321a7465d966b1ccf196ca00e65a70c9f9110 /tests
parentb040195d31df6ad759f16ea3456471897f55daa1 (diff)
downloadstm32l4-93b063fedfcf7409a67df035170ea5670cad22e1.tar.gz
stm32l4-93b063fedfcf7409a67df035170ea5670cad22e1.tar.bz2
stm32l4-93b063fedfcf7409a67df035170ea5670cad22e1.zip
Moved action to top level.
Removed old iterations of the project and moved the files from 02-usart to the root directory since that's the sole place where the action is and that subproject has outgrown its initial title.
Diffstat (limited to 'tests')
-rw-r--r--tests/metatest.c22
-rw-r--r--tests/test_dma.c189
-rw-r--r--tests/test_gpio.c194
-rw-r--r--tests/test_irq.c43
-rw-r--r--tests/test_lib.c21
-rw-r--r--tests/test_memory.c378
-rw-r--r--tests/test_spi.c11
-rw-r--r--tests/test_usart.c22
8 files changed, 880 insertions, 0 deletions
diff --git a/tests/metatest.c b/tests/metatest.c
new file mode 100644
index 0000000..1024156
--- /dev/null
+++ b/tests/metatest.c
@@ -0,0 +1,22 @@
+#include "test_harness.h"
+
+/* Tests the test harness itself. */
+
+static int my_variable;
+static int my_initialized_variable = 5;
+
+TEST(meta, clobbers_variables)
+{
+ my_variable = 6;
+ my_initialized_variable = 5;
+
+ return 0;
+}
+
+TEST(meta, variables_reset)
+{
+ ASSERT_EQ(my_variable, 0);
+ ASSERT_EQ(my_initialized_variable, 5);
+
+ return 0;
+}
diff --git a/tests/test_dma.c b/tests/test_dma.c
new file mode 100644
index 0000000..50cdb5b
--- /dev/null
+++ b/tests/test_dma.c
@@ -0,0 +1,189 @@
+#include "test_harness.h"
+#include "arch/stm32l4xxx/peripherals/dma.h"
+#include "arch/stm32l4xxx/peripherals/rcc.h"
+#include "arch/stm32l4xxx/peripherals/usart.h"
+#include "kern/dma/dma_manager.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+TEST(dma, smoke)
+{
+ dma_t* dma = &DMA1;
+ memset(dma, 0, sizeof(dma_t));
+
+ regset(dma->is_r, dma_tcif1, 1);
+ ASSERT_EQ(dma->is_r, 2);
+
+ regset(dma->is_r, dma_htif7, 1);
+ ASSERT_EQ(dma->is_r, 67108866);
+ return 0;
+}
+
+TEST(dma, cc_regset)
+{
+ dma_t* dma = &DMA1;
+ memset(dma, 0, sizeof(dma_t));
+
+ dma_channel_config_t* channel_config = &dma->channel_config[2];
+ regset(channel_config->cc_r, dma_cc_msize, DMA_SIZE_32_BITS);
+
+ ASSERT_EQ(channel_config->cc_r, 1 << 11);
+ return 0;
+}
+
+TEST(dma, correct_align)
+{
+ dma_t dma;
+
+ // Assert the DMA registers are aligned with what the spec says.
+ ASSERT_EQ((long)(&dma.csel_r) - (long)(&dma), 0xA8);
+
+ return 0;
+}
+
+TEST(dma, regset_pl)
+{
+ uint32_t reg = 0;
+
+ regset(reg, dma_cc_pl, DMA_PRIORITY_LEVEL_MEDIUM);
+
+ ASSERT_EQ(reg, (1 << 12));
+
+ ASSERT_EQ(
+ regget(reg, dma_cc_pl),
+ DMA_PRIORITY_LEVEL_MEDIUM);
+ return 0;
+}
+
+TEST(dma_peri, select_peripheral)
+{
+ dma_opts_t opts = DEFAULT_DMA_OPTS;
+ int ec;
+
+ dma_mem2p_channel_t chan =
+ select_dma_channel_mem2p(
+ DMA1_PERIPH_USART2_TX,
+ &opts,
+ &ec);
+
+ ASSERT_EQ(DMA1.channel_config[6].cpa_r, ptr2reg(&USART2.td_r));
+
+ ASSERT_EQ(
+ regget(DMA1.channel_config[6].cc_r, dma_cc_dir),
+ READ_FROM_MEMORY);
+
+ ASSERT_EQ(
+ regget(DMA1.channel_config[6].cc_r, dma_cc_minc),
+ 1);
+
+ ASSERT_EQ(
+ regget(DMA1.channel_config[6].cc_r, dma_cc_pl),
+ DMA_PRIORITY_LEVEL_MEDIUM);
+
+ ASSERT_EQ(regget(DMA1.csel_r, dma_c7s), 0x2);
+
+ ASSERT_EQ(regget(RCC.ahb1en_r, rcc_dma1en), 1);
+
+ release_dma_channel(chan.c_);
+
+ ASSERT_EQ(regget(RCC.ahb1en_r, rcc_dma1en), 0);
+ return 0;
+}
+
+TEST(dma_peri, unable_to_realloc)
+{
+ dma_opts_t opts = DEFAULT_DMA_OPTS;
+
+ int ec = 0;
+
+ dma_mem2p_channel_t chan =
+ select_dma_channel_mem2p(
+ DMA1_PERIPH_USART2_TX,
+ &opts,
+ &ec);
+
+ ASSERT_EQ(ec, 0);
+
+ select_dma_channel_p2mem(
+ DMA1_PERIPH_USART2_TX,
+ &opts,
+ &ec);
+
+ ASSERT_EQ(ec, DMA_ERROR_CHANNEL_IN_USE);
+
+ release_dma_channel(chan.c_);
+
+ chan = select_dma_channel_mem2p(
+ DMA1_PERIPH_USART2_TX,
+ &opts,
+ &ec);
+
+ ASSERT_EQ(ec, 0);
+
+ release_dma_channel(chan.c_);
+ return 0;
+}
+
+TEST(dma_peri, select_mem2mem)
+{
+ int ec = 0;
+ dma_opts_t opts = DEFAULT_DMA_OPTS;
+ dma_mem2mem_channel_t chan =
+ select_dma_channel_mem2mem(-1, &opts, &ec);
+
+ ASSERT_EQ(ec, 0);
+
+ ASSERT_EQ(chan.c_.dma, 1);
+ ASSERT_EQ(chan.c_.chan, 6);
+
+ dma_mem2mem_channel_t chan2 =
+ select_dma_channel_mem2mem(-1, &opts, &ec);
+
+ ASSERT_EQ(ec, 0);
+
+ ASSERT_EQ(chan2.c_.dma, 1);
+ ASSERT_EQ(chan2.c_.chan, 5);
+
+ release_dma_channel(chan.c_);
+
+ dma_mem2mem_channel_t chan3 =
+ select_dma_channel_mem2mem(-1, &opts, &ec);
+
+ ASSERT_EQ(chan3.c_.dma, 1);
+ ASSERT_EQ(chan3.c_.chan, 6);
+
+ release_dma_channel(chan2.c_);
+ release_dma_channel(chan3.c_);
+ return 0;
+}
+
+TEST(dma_peri, select_mem2mem_2)
+{
+ dma_opts_t opts = DEFAULT_DMA_OPTS;
+ dma_mem2mem_channel_t chans[14];
+ int ec;
+
+ for (int i = 0; i < 14; ++ i) {
+ chans[i] = select_dma_channel_mem2mem(
+ -1, &opts, &ec);
+
+ ASSERT_EQ(ec, 0);
+ }
+
+ select_dma_channel_mem2mem(-1, &opts, &ec);
+ ASSERT_EQ(ec, DMA_ERROR_CHANNEL_IN_USE);
+
+ for (int i = 0; i < 14; ++ i) {
+ if (i < 7) {
+ ASSERT_EQ(chans[i].c_.chan, 6 - i);
+ ASSERT_EQ(chans[i].c_.dma, 1);
+ } else {
+ ASSERT_EQ(chans[i].c_.chan, 6 - (i - 7));
+ ASSERT_EQ(chans[i].c_.dma, 0);
+ }
+ release_dma_channel(chans[i].c_);
+ }
+ return 0;
+}
diff --git a/tests/test_gpio.c b/tests/test_gpio.c
new file mode 100644
index 0000000..bcb953c
--- /dev/null
+++ b/tests/test_gpio.c
@@ -0,0 +1,194 @@
+#include "test_harness.h"
+
+#include "arch/stm32l4xxx/peripherals/rcc.h"
+#include "kern/gpio/gpio_manager.h"
+
+TEST(gpio_manager, smell)
+{
+ gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT;
+ int ec = 5;
+ gpio_reserved_pin_t some_pin = reserve_gpio_pin(GPIO_PIN_PA15, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_TRUE(gpio_pin_in_use(GPIO_PIN_PA15));
+
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 1);
+ release_gpio_pin(some_pin);
+
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 0);
+ return 0;
+}
+
+TEST(gpio_manager, multiplereserve)
+{
+ int ec;
+ gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT;
+ reserve_gpio_pin(GPIO_PIN_PA15, &opts, &ec);
+ ASSERT_TRUE(ec == 0);
+
+ reserve_gpio_pin(GPIO_PIN_PA15, &opts, &ec);
+ ASSERT_EQ(ec, GPIO_ERROR_IN_USE);
+
+ return 0;
+}
+
+TEST(gpio_manager, alternate)
+{
+ int ec;
+
+ /* Pretending to start the USART. */
+ gpio_enable_alternate_function(
+ GPIO_ALTERNATE_FUNCTION_USART2_TX, GPIO_PIN_PA2, &ec);
+
+ ASSERT_EQ(ec, 0);
+
+ gpio_enable_alternate_function(
+ GPIO_ALTERNATE_FUNCTION_USART2_RX, GPIO_PIN_PA15, &ec);
+
+ ASSERT_EQ(ec, 0);
+
+ gpio_port_config_t* gpioa = (gpio_port_config_t*) GPIOA_BASE;
+
+ ASSERT_EQ(regget(gpioa->mode_r, gpio_mode_n(15)), GPIO_MODE_ALTERNATE);
+ ASSERT_EQ(regget(gpioa->mode_r, gpio_mode_n(2)), GPIO_MODE_ALTERNATE);
+
+ ASSERT_EQ(regget(gpioa->af_rl, gpio_afsel_n(2)), 7);
+ ASSERT_EQ(regget(gpioa->af_rh, gpio_afsel_n(7)), 3);
+
+ return 0;
+}
+
+TEST(gpio_manager, bad_alternate)
+{
+ int ec;
+
+ /* Pretending to start the USART. */
+ gpio_enable_alternate_function(
+ GPIO_ALTERNATE_FUNCTION_USART2_RX, GPIO_PIN_PA2, &ec);
+
+ ASSERT_EQ(ec, GPIO_ERROR_INVALID_PIN_FOR_ALTERNATE_FUNCTION);
+
+ return 0;
+}
+
+TEST(gpio_manager, bad_pin)
+{
+ int ec;
+
+ /* Pretending to start the USART. */
+ gpio_enable_alternate_function(
+ GPIO_ALTERNATE_FUNCTION_USART2_RX, 99, &ec);
+
+ ASSERT_EQ(ec, GPIO_ERROR_INVALID_PIN);
+
+ return 0;
+}
+
+TEST(gpio_manager, alternate_then_reserve_fail)
+{
+ int ec;
+
+ /* Pretending to start the USART. */
+ gpio_enable_alternate_function(
+ GPIO_ALTERNATE_FUNCTION_USART2_TX, GPIO_PIN_PA2, &ec);
+
+ ASSERT_EQ(ec, 0);
+
+ gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT;
+ reserve_gpio_pin(GPIO_PIN_PA2, &opts, &ec);
+
+ ASSERT_EQ(ec, GPIO_ERROR_IN_USE);
+
+ return 0;
+}
+
+TEST(gpio_manager, get_gpio_pin_port_off)
+{
+
+ gpio_port_config_t* cfg;
+ int off;
+ get_gpio_pin_port_off(GPIO_PIN_PA5, &cfg, &off);
+
+ ASSERT_EQ(cfg, (void*)(GPIOA_BASE));
+ ASSERT_EQ(off, 5);
+
+ return 0;
+}
+
+TEST(gpio_manager, sets_gpio_settings)
+{
+ gpio_pin_opts_t opts;
+ int ec;
+
+ opts.mode = GPIO_MODE_OUTPUT;
+ opts.pull_dir = GPIO_PULL_DIR_NONE;
+ opts.output_opts.speed = GPIO_OUTPUT_SPEED_VERY_HIGH;
+ opts.output_opts.type = GPIO_OUTPUT_TYPE_PUSH_PULL;
+
+ reserve_gpio_pin(GPIO_PIN_PA2, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+
+ gpio_port_config_t* gpioa = (gpio_port_config_t*) GPIOA_BASE;
+
+ ASSERT_EQ(regget(gpioa->mode_r, gpio_mode_n(2)), GPIO_MODE_OUTPUT);
+ ASSERT_EQ(regget(gpioa->pupd_r, gpio_pupd_n(2)), GPIO_PULL_DIR_NONE);
+ ASSERT_EQ(regget(gpioa->ospeed_r, gpio_ospeed_n(2)), GPIO_OUTPUT_SPEED_VERY_HIGH);
+ ASSERT_EQ(regget(gpioa->otype_r, gpio_otype_n(2)), GPIO_OUTPUT_TYPE_PUSH_PULL);
+
+ return 0;
+}
+
+TEST(gpio_manager, gc)
+{
+ int ec;
+ gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT;
+
+ gpio_reserved_pin_t p1 = reserve_gpio_pin(GPIO_PIN_PA0, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 1);
+
+ gpio_reserved_pin_t p2 = reserve_gpio_pin(GPIO_PIN_PA1, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 1);
+
+ gpio_reserved_pin_t p3 = reserve_gpio_pin(GPIO_PIN_PA15, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 1);
+
+ gpio_reserved_pin_t p4 = reserve_gpio_pin(GPIO_PIN_PB3, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ gpio_reserved_pin_t p5 = reserve_gpio_pin(GPIO_PIN_PB1, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ gpio_reserved_pin_t p6 = reserve_gpio_pin(GPIO_PIN_PB0, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ release_gpio_pin(p1);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 1);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ release_gpio_pin(p2);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 1);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ release_gpio_pin(p3);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ release_gpio_pin(p4);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ release_gpio_pin(p5);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ release_gpio_pin(p6);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 0);
+
+ return 0;
+}
diff --git a/tests/test_irq.c b/tests/test_irq.c
new file mode 100644
index 0000000..3c4ee9c
--- /dev/null
+++ b/tests/test_irq.c
@@ -0,0 +1,43 @@
+#include "test_harness.h"
+
+#include "arch/stm32l4xxx/peripherals/irq.h"
+#include "arch/stm32l4xxx/peripherals/nvic.h"
+
+TEST(irq, nvic)
+{
+ interrupt_set_t is = { 0 };
+
+ interrupt_set_add(&is, IRQ_USART2);
+ interrupt_set_add(&is, IRQ_USART3);
+
+ enable_interrupts(&is);
+
+ ASSERT_EQ(is.irqs[1], 0xC0);
+ ASSERT_EQ(NVIC.ise_r[1], 0xC0);
+
+ return 0;
+}
+
+TEST(irq, nvic_edgecase)
+{
+ interrupt_set_t is = { 0 };
+ interrupt_set_add(&is, IRQ_WWDG_IRQ);
+ interrupt_set_add(&is, IRQ_I2C1_ER);
+
+ enable_interrupts(&is);
+
+ ASSERT_EQ(is.irqs[0], 1);
+ ASSERT_EQ(NVIC.ise_r[0], 1);
+ ASSERT_EQ(is.irqs[1], 1);
+ ASSERT_EQ(NVIC.ise_r[1], 1);
+
+ return 0;
+}
+
+TEST(irq, enable_single_interrupt)
+{
+ enable_interrupt(IRQ_USART2);
+ ASSERT_EQ(NVIC.ise_r[1], 0x40);
+
+ return 0;
+}
diff --git a/tests/test_lib.c b/tests/test_lib.c
new file mode 100644
index 0000000..33076c2
--- /dev/null
+++ b/tests/test_lib.c
@@ -0,0 +1,21 @@
+#include "test_harness.h"
+#include "kern/lib.h"
+
+TEST(lib, hexify)
+{
+ char buf[10];
+
+ hexify(0xaaaaaaaa, buf);
+ ASSERT_EQ_STR(buf, "AAAAAAAA");
+
+ hexify(0xdddddddd, buf);
+ ASSERT_EQ_STR(buf, "DDDDDDDD");
+
+ hexify(0x02468ace, buf);
+ ASSERT_EQ_STR(buf, "02468ACE");
+
+ hexify(0xdeadbeef, buf);
+ ASSERT_EQ_STR(buf, "DEADBEEF");
+
+ return 0;
+}
diff --git a/tests/test_memory.c b/tests/test_memory.c
new file mode 100644
index 0000000..04e9289
--- /dev/null
+++ b/tests/test_memory.c
@@ -0,0 +1,378 @@
+#ifndef FOR_TESTING
+#define FOR_TESTING
+#endif
+
+#include <stdlib.h>
+
+#include "arch.h"
+#include "test_harness.c"
+#include "kern/common.h"
+#include "kern/mem.h"
+
+struct TEST_STRUCT {
+ uint32_t array[3];
+};
+
+struct TEST_STRUCT2 {
+ uint32_t array[10];
+};
+
+/* Copy of the node structure. */
+typedef struct HALLOC_NODE {
+ union {
+ uint32_t header;
+ struct {
+ /* Is this memory block currently in use (hasn't been hfree'd) */
+ bool used:1;
+ /* Number of words allocated. Does not include the header. */
+ uint16_t size:12;
+ /* The location of the previous block (in WORDS from offest) */
+ uint16_t prev:12;
+ uint8_t canary:7;
+ } PACKED;
+ };
+
+ uint8_t mem[]; /* The memory to use. */
+} halloc_node_t;
+
+extern halloc_node_t* halloc_start;
+
+static void wipeout_halloc()
+{
+ memset(halloc_start, 0, 1024);
+ halloc_start = NULL;
+}
+
+
+static struct TEST_STRUCT* new_test_struct()
+{
+ struct TEST_STRUCT* ret = halloc(sizeof(struct TEST_STRUCT));
+
+ ret->array[0] = 1;
+ ret->array[1] = 2;
+ ret->array[2] = 3;
+
+ return ret;
+}
+
+static struct TEST_STRUCT2* new_test_struct2()
+{
+ struct TEST_STRUCT2* ret = halloc(sizeof(struct TEST_STRUCT2));
+
+ for (int i = 0; i < 10; ++ i) {
+ ret->array[i] = i;
+ }
+
+ return ret;
+}
+
+#define ASSERT_CHAIN(t1, t2) \
+ ASSERT_EQ(V(t1) + sizeof(*t1) + 4, V(t2))
+
+TEST(memory, halloc)
+{
+
+#define V(x) ((void*)(x))
+ struct TEST_STRUCT* test1 = new_test_struct();
+ struct TEST_STRUCT2* test2 = new_test_struct2();
+ struct TEST_STRUCT* test3 = new_test_struct();
+ struct TEST_STRUCT2* test4 = new_test_struct2();
+ struct TEST_STRUCT2* test5 = new_test_struct2();
+
+ ASSERT_TRUE(V(test1) != V(test2));
+ ASSERT_TRUE(V(test2) != V(test3));
+ ASSERT_TRUE(V(test3) != V(test1));
+ ASSERT_TRUE(V(test2) != V(test5));
+ ASSERT_TRUE(V(test4) != V(test5));
+
+ ASSERT_CHAIN(test1, test2);
+ ASSERT_CHAIN(test2, test3);
+ ASSERT_CHAIN(test3, test4);
+ ASSERT_CHAIN(test4, test5);
+
+
+ char buf[1024];
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(
+ stderr,
+ "Consistency check failed. (%s:%d)\n",
+ __FILE__,
+ __LINE__);
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+
+ wipeout_halloc();
+
+ return 0;
+}
+
+struct UNEVEN_STRUCT {
+ uint8_t arr[5];
+};
+
+struct UNEVEN_STRUCT* new_uneven_struct()
+{
+ struct UNEVEN_STRUCT* ret = halloc(sizeof(struct UNEVEN_STRUCT));
+
+ ret->arr[0] = 1;
+ ret->arr[1] = 2;
+ ret->arr[2] = 3;
+ ret->arr[3] = 4;
+ ret->arr[4] = 5;
+
+ return ret;
+}
+
+#define size_for(n) \
+ (((n) / 4) + ((n) % 4 != 0))
+
+TEST(memory, uneven_halloc)
+{
+ if (halloc_start) {
+ wipeout_halloc();
+ }
+
+ struct UNEVEN_STRUCT* test1 = new_uneven_struct();
+ struct UNEVEN_STRUCT* test2 = new_uneven_struct();
+
+ ASSERT_EQ(V(test1) + 12, test2);
+
+ wipeout_halloc();
+
+ return 0;
+}
+
+TEST(memory, halloc_free)
+{
+ if (halloc_start) {
+ wipeout_halloc();
+ }
+
+ struct TEST_STRUCT* test1 = new_test_struct();
+ struct TEST_STRUCT2* test2 = new_test_struct2();
+ struct TEST_STRUCT* test3 = new_test_struct();
+ struct TEST_STRUCT2* test4 = new_test_struct2();
+ struct TEST_STRUCT2* test5 = new_test_struct2();
+
+ hfree(test2);
+ hfree(test4);
+ hfree(test3);
+ hfree(test1);
+ hfree(test5);
+
+ ASSERT_EQ((int) halloc_start->size * 4, MAX_HEAP_SIZE - 4);
+
+ test1 = new_test_struct();
+ test2 = new_test_struct2();
+ test3 = new_test_struct();
+ test4 = new_test_struct2();
+ test5 = new_test_struct2();
+
+ hfree(test1);
+ hfree(test3);
+ hfree(test2);
+ hfree(test4);
+ hfree(test5);
+
+ ASSERT_EQ((int) halloc_start->size * 4, MAX_HEAP_SIZE - 4);
+
+ test1 = new_test_struct();
+ test2 = new_test_struct2();
+ test3 = new_test_struct();
+ test4 = new_test_struct2();
+ test5 = new_test_struct2();
+
+ hfree(test4);
+ hfree(test3);
+ hfree(test1);
+ hfree(test2);
+ hfree(test5);
+
+ ASSERT_EQ((int) halloc_start->size * 4, MAX_HEAP_SIZE - 4);
+
+ wipeout_halloc();
+
+ return 0;
+}
+
+TEST(memory, halloc_free_alloc2)
+{
+ if (halloc_start) {
+ wipeout_halloc();
+ }
+
+ struct TEST_STRUCT2* test1 = new_test_struct2();
+ struct TEST_STRUCT2* test2 = new_test_struct2();
+
+ hfree(test1);
+
+ struct TEST_STRUCT* test3 = new_test_struct();
+ struct TEST_STRUCT* test4 = new_test_struct();
+
+ ASSERT_EQ(debug_halloc_get_next_ptr(test3), V(test4));
+
+ ASSERT_EQ(
+ // There should be a free block after test4.
+ debug_halloc_get_next_ptr(debug_halloc_get_next_ptr(test4)),
+ V(test2));
+
+ ASSERT_EQ(
+ // There should be a free block after test4.
+ debug_halloc_get_prev_ptr(debug_halloc_get_prev_ptr(test2)),
+ V(test4));
+
+ char buf[1024];
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(stderr, "Consistency check failed.\n");
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+
+ return 0;
+}
+
+TEST(memory, relink_backref_after_free)
+{
+ if (halloc_start) {
+ wipeout_halloc();
+ }
+
+ struct TEST_STRUCT* test2 = new_test_struct();
+ struct TEST_STRUCT* test3 = new_test_struct();
+
+ hfree(test2);
+ hfree(test3);
+
+ char buf[1024];
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(stderr, "Consistency check failed.\n");
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+
+ return 0;
+}
+
+TEST(memory, consistency_stress)
+{
+#define NRUNS 500
+ if (halloc_start) {
+ wipeout_halloc();
+ }
+
+ int i;
+ void* allocd[NRUNS] = { 0 };
+ char buf[1024];
+
+ for (i = 0; i < NRUNS; ++ i) {
+ size_t nalloc = rand() % 20;
+ allocd[i] = halloc(nalloc);
+
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(
+ stderr,
+ "Consistency check failed. (At index=%d, %s:%d)\n",
+ i,
+ __FILE__,
+ __LINE__);
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+
+ ASSERT_TRUE(allocd[i]);
+
+ memset(allocd[i], 0xFF, nalloc);
+ size_t idx = rand() % NRUNS;
+
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(
+ stderr,
+ "Consistency check failed. (At index=%d, %s:%d)\n",
+ i,
+ __FILE__,
+ __LINE__);
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+
+ hfree(allocd[idx]);
+ allocd[idx] = NULL;
+
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(
+ stderr,
+ "Consistency check failed. (At index=%d, %s:%d)\n",
+ i,
+ __FILE__,
+ __LINE__);
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+
+ idx = rand() % NRUNS;
+ hfree(allocd[idx]);
+ allocd[idx] = NULL;
+
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(
+ stderr,
+ "Consistency check failed. (At index=%d, %s:%d)\n",
+ i,
+ __FILE__,
+ __LINE__);
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+ }
+
+ for(i = 0; i < NRUNS; ++ i) {
+ if (allocd[i]) {
+ hfree(allocd[i]);
+ }
+
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(
+ stderr,
+ "Consistency check failed. (At index=%d, %s:%d)\n",
+ i,
+ __FILE__,
+ __LINE__);
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+ }
+ ASSERT_EQ((int) halloc_start->size * 4, MAX_HEAP_SIZE - 4);
+
+ return 0;
+}
+
+TEST(memory, halloc_free_alloc)
+{
+ if (halloc_start) {
+ wipeout_halloc();
+ }
+
+ new_test_struct();
+ struct TEST_STRUCT2* test2 = new_test_struct2();
+ new_test_struct();
+ struct TEST_STRUCT2* test4 = new_test_struct2();
+ new_test_struct2();
+
+ hfree(test4);
+
+ struct TEST_STRUCT2* test6 = new_test_struct2();
+
+ // test_6 should have been allocated in test_4's spot.
+ ASSERT_EQ(test6, test4);
+
+ hfree(test2);
+ struct TEST_STRUCT* test7 = new_test_struct();
+ struct TEST_STRUCT* test8 = new_test_struct();
+
+ // Test 2 was large enough to accomodate 3 smaller structs.
+ ASSERT_EQ(V(test7), V(test2));
+ ASSERT_EQ(V(test8), V(test2) + sizeof(*test7) + 4);
+
+ return 0;
+}
diff --git a/tests/test_spi.c b/tests/test_spi.c
new file mode 100644
index 0000000..cc25d6e
--- /dev/null
+++ b/tests/test_spi.c
@@ -0,0 +1,11 @@
+#include "test_harness.h"
+
+#include "arch/stm32l4xxx/peripherals/spi.h"
+
+TEST(spi, smoke)
+{
+ __IO spi_t* spi = &SPI1;
+ spi->s_r = 1;
+
+ return 0;
+}
diff --git a/tests/test_usart.c b/tests/test_usart.c
new file mode 100644
index 0000000..b19d687
--- /dev/null
+++ b/tests/test_usart.c
@@ -0,0 +1,22 @@
+#include "test_harness.h"
+#include "arch/stm32l4xxx/peripherals/usart.h"
+
+#include <stdlib.h>
+
+TEST(usart, enable_dma)
+{
+ __IO usart_t* usart = &USART1;
+
+ usart->c_r3 = 0;
+
+ usart_enable_dma(usart, USART_ENABLE_TX);
+ ASSERT_EQ(usart->c_r3, 128);
+
+ usart_enable_dma(usart, USART_ENABLE_RX);
+ ASSERT_EQ(usart->c_r3, 192);
+
+ usart_enable_dma(usart, USART_ENABLE_DISABLED);
+ ASSERT_EQ(usart->c_r3, 0);
+
+ return 0;
+}