Test firmware refactoring
This commit is contained in:
parent
f0b824ad9a
commit
d4331491a8
|
@ -1,5 +1,5 @@
|
||||||
/tests/*.o
|
/tests/*.o
|
||||||
/firmware/start.o
|
/firmware/*.o
|
||||||
/firmware/firmware.bin
|
/firmware/firmware.bin
|
||||||
/firmware/firmware.elf
|
/firmware/firmware.elf
|
||||||
/firmware/firmware.hex
|
/firmware/firmware.hex
|
||||||
|
|
8
Makefile
8
Makefile
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
TEST_OBJS = $(addsuffix .o,$(basename $(wildcard tests/*.S)))
|
TEST_OBJS = $(addsuffix .o,$(basename $(wildcard tests/*.S)))
|
||||||
|
FIRMWARE_OBJS = firmware/start.o firmware/irq.o firmware/print.o firmware/sieve.o firmware/stats.o
|
||||||
|
|
||||||
test: testbench.exe firmware/firmware.hex
|
test: testbench.exe firmware/firmware.hex
|
||||||
vvp -N testbench.exe
|
vvp -N testbench.exe
|
||||||
|
@ -22,15 +23,18 @@ firmware/firmware.bin: firmware/firmware.elf
|
||||||
riscv64-unknown-elf-objcopy -O binary $< $@
|
riscv64-unknown-elf-objcopy -O binary $< $@
|
||||||
chmod -x $@
|
chmod -x $@
|
||||||
|
|
||||||
firmware/firmware.elf: $(TEST_OBJS) firmware/sections.lds firmware/start.o firmware/sieve.c firmware/stats.c
|
firmware/firmware.elf: $(FIRMWARE_OBJS) $(TEST_OBJS) firmware/sections.lds
|
||||||
riscv64-unknown-elf-gcc -Os -m32 -march=RV32I -ffreestanding -nostdlib -o $@ \
|
riscv64-unknown-elf-gcc -Os -m32 -march=RV32I -ffreestanding -nostdlib -o $@ \
|
||||||
-Wl,-Bstatic,-T,firmware/sections.lds,-Map,firmware/firmware.map,--strip-debug \
|
-Wl,-Bstatic,-T,firmware/sections.lds,-Map,firmware/firmware.map,--strip-debug \
|
||||||
firmware/start.o firmware/sieve.c firmware/stats.c $(TEST_OBJS) -lgcc
|
$(FIRMWARE_OBJS) $(TEST_OBJS) -lgcc
|
||||||
chmod -x $@
|
chmod -x $@
|
||||||
|
|
||||||
firmware/start.o: firmware/start.S
|
firmware/start.o: firmware/start.S
|
||||||
riscv64-unknown-elf-gcc -c -m32 -o $@ $<
|
riscv64-unknown-elf-gcc -c -m32 -o $@ $<
|
||||||
|
|
||||||
|
firmware/%.o: firmware/%.c
|
||||||
|
riscv64-unknown-elf-gcc -c -Os -m32 -march=RV32I -ffreestanding -nostdlib -o $@ $<
|
||||||
|
|
||||||
tests/%.o: tests/%.S tests/riscv_test.h tests/test_macros.h
|
tests/%.o: tests/%.S tests/riscv_test.h tests/test_macros.h
|
||||||
riscv64-unknown-elf-gcc -m32 -march=RV32I -c -o $@ -DTEST_FUNC_NAME=$(notdir $(basename $<)) \
|
riscv64-unknown-elf-gcc -m32 -march=RV32I -c -o $@ -DTEST_FUNC_NAME=$(notdir $(basename $<)) \
|
||||||
-DTEST_FUNC_TXT='"$(notdir $(basename $<))"' -DTEST_FUNC_RET=$(notdir $(basename $<))_ret $<
|
-DTEST_FUNC_TXT='"$(notdir $(basename $<))"' -DTEST_FUNC_RET=$(notdir $(basename $<))_ret $<
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef FIRMWARE_H
|
||||||
|
#define FIRMWARE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
// irq.c
|
||||||
|
uint32_t *irq(uint32_t *regs, uint32_t irqs);
|
||||||
|
|
||||||
|
// print.c
|
||||||
|
void print_chr(char ch);
|
||||||
|
void print_str(const char *p);
|
||||||
|
void print_dec(int val);
|
||||||
|
void print_hex(unsigned int val);
|
||||||
|
|
||||||
|
// sieve.c
|
||||||
|
void sieve();
|
||||||
|
|
||||||
|
// stats.c
|
||||||
|
void stats();
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,111 @@
|
||||||
|
|
||||||
|
#include "firmware.h"
|
||||||
|
|
||||||
|
uint32_t *irq(uint32_t *regs, uint32_t irqs)
|
||||||
|
{
|
||||||
|
static int ext_irq_4_count = 0;
|
||||||
|
static int ext_irq_5_count = 0;
|
||||||
|
static int timer_irq_count = 0;
|
||||||
|
|
||||||
|
if ((irqs & (1<<4)) != 0) {
|
||||||
|
ext_irq_4_count++;
|
||||||
|
// print_str("[EXT-IRQ-4]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((irqs & (1<<5)) != 0) {
|
||||||
|
ext_irq_5_count++;
|
||||||
|
// print_str("[EXT-IRQ-5]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((irqs & 1) != 0) {
|
||||||
|
timer_irq_count++;
|
||||||
|
// print_str("[TIMER-IRQ]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((irqs & 6) != 0)
|
||||||
|
{
|
||||||
|
int i, k;
|
||||||
|
uint32_t pc = regs[0] - 4;
|
||||||
|
uint32_t instr = *(uint32_t*)pc;
|
||||||
|
|
||||||
|
print_str("\n");
|
||||||
|
print_str("------------------------------------------------------------\n");
|
||||||
|
|
||||||
|
if ((irqs & 2) != 0) {
|
||||||
|
if (instr == 0x00100073) {
|
||||||
|
print_str("SBREAK instruction at 0x");
|
||||||
|
print_hex(pc);
|
||||||
|
print_str("\n");
|
||||||
|
} else {
|
||||||
|
print_str("Illegal Instruction at 0x");
|
||||||
|
print_hex(pc);
|
||||||
|
print_str(": 0x");
|
||||||
|
print_hex(instr);
|
||||||
|
print_str("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((irqs & 4) != 0) {
|
||||||
|
print_str("Bus error in Instruction at 0x");
|
||||||
|
print_hex(pc);
|
||||||
|
print_str(": 0x");
|
||||||
|
print_hex(instr);
|
||||||
|
print_str("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
for (k = 0; k < 4; k++)
|
||||||
|
{
|
||||||
|
int r = i + k*8;
|
||||||
|
|
||||||
|
if (r == 0) {
|
||||||
|
print_str("pc ");
|
||||||
|
} else
|
||||||
|
if (r < 10) {
|
||||||
|
print_chr('x');
|
||||||
|
print_chr('0' + r);
|
||||||
|
print_chr(' ');
|
||||||
|
print_chr(' ');
|
||||||
|
} else
|
||||||
|
if (r < 20) {
|
||||||
|
print_chr('x');
|
||||||
|
print_chr('1');
|
||||||
|
print_chr('0' + r - 10);
|
||||||
|
print_chr(' ');
|
||||||
|
} else
|
||||||
|
if (r < 30) {
|
||||||
|
print_chr('x');
|
||||||
|
print_chr('2');
|
||||||
|
print_chr('0' + r - 20);
|
||||||
|
print_chr(' ');
|
||||||
|
} else {
|
||||||
|
print_chr('x');
|
||||||
|
print_chr('3');
|
||||||
|
print_chr('0' + r - 30);
|
||||||
|
print_chr(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
print_hex(regs[r]);
|
||||||
|
print_str(k == 3 ? "\n" : " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_str("------------------------------------------------------------\n");
|
||||||
|
|
||||||
|
print_str("Number of fast external IRQs counted: ");
|
||||||
|
print_dec(ext_irq_4_count);
|
||||||
|
print_str("\n");
|
||||||
|
|
||||||
|
print_str("Number of slow external IRQs counted: ");
|
||||||
|
print_dec(ext_irq_5_count);
|
||||||
|
print_str("\n");
|
||||||
|
|
||||||
|
print_str("Number of timer IRQs counted: ");
|
||||||
|
print_dec(timer_irq_count);
|
||||||
|
print_str("\n");
|
||||||
|
|
||||||
|
__asm__("sbreak");
|
||||||
|
}
|
||||||
|
|
||||||
|
return regs;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
|
||||||
|
#include "firmware.h"
|
||||||
|
|
||||||
|
#define OUTPORT 0x10000000
|
||||||
|
|
||||||
|
void print_chr(char ch)
|
||||||
|
{
|
||||||
|
*((volatile uint32_t*)OUTPORT) = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_str(const char *p)
|
||||||
|
{
|
||||||
|
while (*p != 0)
|
||||||
|
*((volatile uint32_t*)OUTPORT) = *(p++);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_dec(int val)
|
||||||
|
{
|
||||||
|
char buffer[10];
|
||||||
|
char *p = buffer;
|
||||||
|
while (val || p == buffer) {
|
||||||
|
*(p++) = val % 10;
|
||||||
|
val = val / 10;
|
||||||
|
}
|
||||||
|
while (p != buffer) {
|
||||||
|
*((volatile uint32_t*)OUTPORT) = '0' + *(--p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_hex(unsigned int val)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 32-4; i >= 0; i -= 4)
|
||||||
|
*((volatile uint32_t*)OUTPORT) = "0123456789ABCDEF"[(val >> i) % 16];
|
||||||
|
}
|
||||||
|
|
156
firmware/sieve.c
156
firmware/sieve.c
|
@ -1,12 +1,17 @@
|
||||||
// A simple Sieve of Eratosthenes
|
// A simple Sieve of Eratosthenes
|
||||||
|
|
||||||
#include <stdint.h>
|
#include "firmware.h"
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#define BITMAP_SIZE 64
|
#define BITMAP_SIZE 64
|
||||||
#define OUTPORT 0x10000000
|
|
||||||
|
|
||||||
static uint32_t bitmap[BITMAP_SIZE/32];
|
static uint32_t bitmap[BITMAP_SIZE/32];
|
||||||
|
static uint32_t hash;
|
||||||
|
|
||||||
|
static uint32_t mkhash(uint32_t a, uint32_t b)
|
||||||
|
{
|
||||||
|
// The XOR version of DJB2
|
||||||
|
return ((a << 5) + a) ^ b;
|
||||||
|
}
|
||||||
|
|
||||||
static void bitmap_set(int idx)
|
static void bitmap_set(int idx)
|
||||||
{
|
{
|
||||||
|
@ -18,37 +23,6 @@ static bool bitmap_get(int idx)
|
||||||
return (bitmap[idx/32] & (1 << (idx % 32))) != 0;
|
return (bitmap[idx/32] & (1 << (idx % 32))) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_chr(char ch)
|
|
||||||
{
|
|
||||||
*((volatile uint32_t*)OUTPORT) = ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_str(const char *p)
|
|
||||||
{
|
|
||||||
while (*p != 0)
|
|
||||||
*((volatile uint32_t*)OUTPORT) = *(p++);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_dec(int val)
|
|
||||||
{
|
|
||||||
char buffer[10];
|
|
||||||
char *p = buffer;
|
|
||||||
while (val || p == buffer) {
|
|
||||||
*(p++) = val % 10;
|
|
||||||
val = val / 10;
|
|
||||||
}
|
|
||||||
while (p != buffer) {
|
|
||||||
*((volatile uint32_t*)OUTPORT) = '0' + *(--p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_hex(unsigned int val)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 32-4; i >= 0; i -= 4)
|
|
||||||
*((volatile uint32_t*)OUTPORT) = "0123456789ABCDEF"[(val >> i) % 16];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_prime(int idx, int val)
|
static void print_prime(int idx, int val)
|
||||||
{
|
{
|
||||||
if (idx < 10)
|
if (idx < 10)
|
||||||
|
@ -66,12 +40,16 @@ static void print_prime(int idx, int val)
|
||||||
print_str(" prime is ");
|
print_str(" prime is ");
|
||||||
print_dec(val);
|
print_dec(val);
|
||||||
print_str(".\n");
|
print_str(".\n");
|
||||||
|
|
||||||
|
hash = mkhash(hash, idx);
|
||||||
|
hash = mkhash(hash, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sieve()
|
void sieve()
|
||||||
{
|
{
|
||||||
int i, j, k;
|
int i, j, k;
|
||||||
int idx = 1;
|
int idx = 1;
|
||||||
|
hash = 5381;
|
||||||
print_prime(idx++, 2);
|
print_prime(idx++, 2);
|
||||||
for (i = 0; i < BITMAP_SIZE; i++) {
|
for (i = 0; i < BITMAP_SIZE; i++) {
|
||||||
if (bitmap_get(i))
|
if (bitmap_get(i))
|
||||||
|
@ -86,113 +64,15 @@ void sieve()
|
||||||
bitmap_set(k);
|
bitmap_set(k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t *irq(uint32_t *regs, uint32_t irqs)
|
print_str("checksum: ");
|
||||||
{
|
print_hex(hash);
|
||||||
static int ext_irq_4_count = 0;
|
|
||||||
static int ext_irq_5_count = 0;
|
|
||||||
static int timer_irq_count = 0;
|
|
||||||
|
|
||||||
if ((irqs & (1<<4)) != 0) {
|
if (hash == 0x1772A48F) {
|
||||||
ext_irq_4_count++;
|
print_str(" OK\n");
|
||||||
// print_str("[EXT-IRQ-4]");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((irqs & (1<<5)) != 0) {
|
|
||||||
ext_irq_5_count++;
|
|
||||||
// print_str("[EXT-IRQ-5]");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((irqs & 1) != 0) {
|
|
||||||
timer_irq_count++;
|
|
||||||
// print_str("[TIMER-IRQ]");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((irqs & 6) != 0)
|
|
||||||
{
|
|
||||||
int i, k;
|
|
||||||
uint32_t pc = regs[0] - 4;
|
|
||||||
uint32_t instr = *(uint32_t*)pc;
|
|
||||||
|
|
||||||
print_str("\n");
|
|
||||||
print_str("------------------------------------------------------------\n");
|
|
||||||
|
|
||||||
if ((irqs & 2) != 0) {
|
|
||||||
if (instr == 0x00100073) {
|
|
||||||
print_str("SBREAK instruction at 0x");
|
|
||||||
print_hex(pc);
|
|
||||||
print_str("\n");
|
|
||||||
} else {
|
} else {
|
||||||
print_str("Illegal Instruction at 0x");
|
print_str(" ERROR\n");
|
||||||
print_hex(pc);
|
asm volatile ("sbreak");
|
||||||
print_str(": 0x");
|
|
||||||
print_hex(instr);
|
|
||||||
print_str("\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((irqs & 4) != 0) {
|
|
||||||
print_str("Bus error in Instruction at 0x");
|
|
||||||
print_hex(pc);
|
|
||||||
print_str(": 0x");
|
|
||||||
print_hex(instr);
|
|
||||||
print_str("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
|
||||||
for (k = 0; k < 4; k++)
|
|
||||||
{
|
|
||||||
int r = i + k*8;
|
|
||||||
|
|
||||||
if (r == 0) {
|
|
||||||
print_str("pc ");
|
|
||||||
} else
|
|
||||||
if (r < 10) {
|
|
||||||
print_chr('x');
|
|
||||||
print_chr('0' + r);
|
|
||||||
print_chr(' ');
|
|
||||||
print_chr(' ');
|
|
||||||
} else
|
|
||||||
if (r < 20) {
|
|
||||||
print_chr('x');
|
|
||||||
print_chr('1');
|
|
||||||
print_chr('0' + r - 10);
|
|
||||||
print_chr(' ');
|
|
||||||
} else
|
|
||||||
if (r < 30) {
|
|
||||||
print_chr('x');
|
|
||||||
print_chr('2');
|
|
||||||
print_chr('0' + r - 20);
|
|
||||||
print_chr(' ');
|
|
||||||
} else {
|
|
||||||
print_chr('x');
|
|
||||||
print_chr('3');
|
|
||||||
print_chr('0' + r - 30);
|
|
||||||
print_chr(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
print_hex(regs[r]);
|
|
||||||
print_str(k == 3 ? "\n" : " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
print_str("------------------------------------------------------------\n");
|
|
||||||
|
|
||||||
print_str("Number of fast external IRQs counted: ");
|
|
||||||
print_dec(ext_irq_4_count);
|
|
||||||
print_str("\n");
|
|
||||||
|
|
||||||
print_str("Number of slow external IRQs counted: ");
|
|
||||||
print_dec(ext_irq_5_count);
|
|
||||||
print_str("\n");
|
|
||||||
|
|
||||||
print_str("Number of timer IRQs counted: ");
|
|
||||||
print_dec(timer_irq_count);
|
|
||||||
print_str("\n");
|
|
||||||
|
|
||||||
__asm__("sbreak");
|
|
||||||
}
|
|
||||||
|
|
||||||
return regs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
#include <stdint.h>
|
#include "firmware.h"
|
||||||
#include <stdbool.h>
|
|
||||||
#define OUTPORT 0x10000000
|
|
||||||
|
|
||||||
static void print_str(const char *p)
|
static void stats_print_dec(int val, int digits, bool zero_pad)
|
||||||
{
|
|
||||||
while (*p != 0)
|
|
||||||
*((volatile uint32_t*)OUTPORT) = *(p++);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_dec(int val, int digits, bool zero_pad)
|
|
||||||
{
|
{
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
char *p = buffer;
|
char *p = buffer;
|
||||||
|
@ -22,7 +14,7 @@ static void print_dec(int val, int digits, bool zero_pad)
|
||||||
}
|
}
|
||||||
while (p != buffer) {
|
while (p != buffer) {
|
||||||
if (p[-1] == ' ' && p[-2] == ' ') p[-1] = '.';
|
if (p[-1] == ' ' && p[-2] == ' ') p[-1] = '.';
|
||||||
*((volatile uint32_t*)OUTPORT) = *(--p);
|
print_chr(*(--p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,13 +23,13 @@ void stats()
|
||||||
int num_cycles, num_instr;
|
int num_cycles, num_instr;
|
||||||
asm("rdcycle %0; rdinstret %1;" : "=r"(num_cycles), "=r"(num_instr));
|
asm("rdcycle %0; rdinstret %1;" : "=r"(num_cycles), "=r"(num_instr));
|
||||||
print_str("Cycle counter ........");
|
print_str("Cycle counter ........");
|
||||||
print_dec(num_cycles, 8, false);
|
stats_print_dec(num_cycles, 8, false);
|
||||||
print_str("\nInstruction counter ..");
|
print_str("\nInstruction counter ..");
|
||||||
print_dec(num_instr, 8, false);
|
stats_print_dec(num_instr, 8, false);
|
||||||
print_str("\nCPI: ");
|
print_str("\nCPI: ");
|
||||||
print_dec((num_cycles / num_instr), 0, false);
|
stats_print_dec((num_cycles / num_instr), 0, false);
|
||||||
print_str(".");
|
print_str(".");
|
||||||
print_dec(((100 * num_cycles) / num_instr) % 100, 2, true);
|
stats_print_dec(((100 * num_cycles) / num_instr) % 100, 2, true);
|
||||||
print_str("\n");
|
print_str("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue