tests: add am-tests

This commit is contained in:
Zihao Yu 2020-08-23 19:54:16 +08:00
parent 8fbf7f9425
commit 0a123cc9e6
11 changed files with 405 additions and 0 deletions

3
tests/am-tests/Makefile Normal file
View file

@ -0,0 +1,3 @@
NAME = amtest
SRCS = $(shell find src/ -name "*.c")
include $(AM_HOME)/Makefile

View file

@ -0,0 +1,24 @@
#ifndef __AMUNIT_H__
#define __AMUNIT_H__
#include <am.h>
#include <klib.h>
#include <klib-macros.h>
#define IOE ({ ioe_init(); })
#define CTE(h) ({ Context *h(Event, Context *); cte_init(h); })
#define VME(f1, f2) ({ void *f1(int); void f2(void *); vme_init(f1, f2); })
#define MPE ({ mpe_init(entry); })
extern void (*entry)();
#define CASE(id, entry_, ...) \
case id: { \
void entry_(); \
entry = entry_; \
__VA_ARGS__; \
entry_(); \
break; \
}
#endif

37
tests/am-tests/src/main.c Normal file
View file

@ -0,0 +1,37 @@
#include <amtest.h>
void (*entry)() = NULL; // mp entry
static const char *tests[256] = {
['h'] = "hello",
['H'] = "display this help message",
['i'] = "interrupt/yield test",
['d'] = "scan devices",
['m'] = "multiprocessor test",
['t'] = "real-time clock test",
['k'] = "readkey test",
['v'] = "display test",
['p'] = "x86 virtual memory test",
};
int main(const char *args) {
switch (args[0]) {
CASE('h', hello);
CASE('i', hello_intr, IOE, CTE(simple_trap));
CASE('d', devscan, IOE);
CASE('m', mp_print, MPE);
CASE('t', rtc_test, IOE);
CASE('k', keyboard_test, IOE);
CASE('v', video_test, IOE);
CASE('p', vm_test, CTE(vm_handler), VME(simple_pgalloc, simple_pgfree));
case 'H':
default:
printf("Usage: make run mainargs=*\n");
for (int ch = 0; ch < 256; ch++) {
if (tests[ch]) {
printf(" %c: %s\n", ch, tests[ch]);
}
}
}
return 0;
}

View file

@ -0,0 +1,69 @@
#include <amtest.h>
static void input_test() {
printf("Input device test skipped.\n");
}
static void timer_test() {
AM_TIMER_UPTIME_T uptime;
uint32_t t0, t1;
uptime = io_read(AM_TIMER_UPTIME);
t0 = uptime.us / 1000;
for (int volatile i = 0; i < 10000000; i ++) ;
uptime = io_read(AM_TIMER_UPTIME);
t1 = uptime.us / 1000;
printf("Loop 10^7 time elapse: %d ms\n", t1 - t0);
}
static uint8_t vmem[512 << 10];
static inline gpuptr_t to_guest(void *ptr) { return ptr ? (uint8_t *)ptr - vmem : AM_GPU_NULL; }
static void video_test() {
AM_GPU_CONFIG_T info = io_read(AM_GPU_CONFIG);
int w = info.width, h = info.height;
printf("Screen size: %d x %d\n", w, h);
struct gpu_canvas *cv = (void *)vmem;
for (uint8_t *p = (void *)&cv[8]; p != vmem + sizeof(vmem); p++)
*p = rand() & 0xff;
cv[0] = (struct gpu_canvas) {
.w = -1, .h = -1, .x1 = w / 4, .y1 = 0, .w1 = w / 2, .h1 = h - 100,
.type = AM_GPU_TEXTURE,
.texture = (struct gpu_texturedesc) {
.w = 37, .h = 10,
.pixels = to_guest(&cv[8]),
},
.sibling = to_guest(NULL),
};
io_write(AM_GPU_MEMCPY, 0, vmem, sizeof(vmem));
io_write(AM_GPU_RENDER, 0);
}
static void storage_test() {
#define nbytes 512
static char buf[nbytes];
AM_DISK_CONFIG_T info = io_read(AM_DISK_CONFIG);
printf("Storage: %d blocks of %d size. Show first 512 bytes\n", info.blkcnt, info.blksz);
io_write(AM_DISK_BLKIO, false, buf, 0, nbytes / info.blksz);
for (uint32_t i = 0; i < nbytes; i += 2) {
printf("%02x%02x ", buf[i] & 0xff, buf[i+1] & 0xff);
if ((i+2) % 32 == 0) printf("\n");
}
}
void devscan() {
printf("heap = [%08x, %08x)\n", heap.start, heap.end);
input_test();
timer_test();
video_test();
storage_test();
printf("Test End!\n");
while (1);
}

View file

@ -0,0 +1,7 @@
#include <amtest.h>
void hello() {
for (int i = 0; i < 10; i ++) {
putstr("Hello, AM World @ " __ISA__ "\n");
}
}

View file

@ -0,0 +1,26 @@
#include <amtest.h>
Context *simple_trap(Event ev, Context *ctx) {
switch(ev.event) {
case EVENT_IRQ_TIMER:
printf("t"); break;
case EVENT_IRQ_IODEV:
printf("d"); break;
case EVENT_YIELD:
printf("y"); break;
default:
break;
}
return ctx;
}
void hello_intr() {
printf("Hello, AM World @ " __ISA__ "\n");
printf(" t = timer, d = device, y = yield\n");
io_read(AM_INPUT_CONFIG);
iset(1);
while (1) {
for (volatile int i = 0; i < 10000000; i++) ;
yield();
}
}

View file

@ -0,0 +1,35 @@
#include <amtest.h>
#define NAMEINIT(key) [ AM_KEY_##key ] = #key,
static const char *names[] = {
AM_KEYS(NAMEINIT)
};
static bool has_uart, has_kbd;
static void drain_keys() {
if (has_uart) {
while (1) {
char ch = io_read(AM_UART_RX).data;
if (ch == -1) break;
printf("Got (uart): %c (%d)\n", ch, ch & 0xff);
}
}
if (has_kbd) {
while (1) {
AM_INPUT_KEYBRD_T ev = io_read(AM_INPUT_KEYBRD);
if (ev.keycode == AM_KEY_NONE) break;
printf("Got (kbd): %s (%d) %s\n", names[ev.keycode], ev.keycode, ev.keydown ? "DOWN" : "UP");
}
}
}
void keyboard_test() {
printf("Try to press any key (uart or keyboard)...\n");
has_uart = io_read(AM_UART_CONFIG).present;
has_kbd = io_read(AM_INPUT_CONFIG).present;
while (1) {
drain_keys();
}
}

View file

@ -0,0 +1,7 @@
#include <amtest.h>
void mp_print() {
while (1) {
printf("%d", cpu_current());
}
}

View file

@ -0,0 +1,17 @@
#include <amtest.h>
void rtc_test() {
AM_TIMER_RTC_T rtc;
int sec = 1;
while (1) {
while(io_read(AM_TIMER_UPTIME).us / 1000000 < sec) ;
rtc = io_read(AM_TIMER_RTC);
printf("%d-%d-%d %02d:%02d:%02d GMT (", rtc.year, rtc.month, rtc.day, rtc.hour, rtc.minute, rtc.second);
if (sec == 1) {
printf("%d second).\n", sec);
} else {
printf("%d seconds).\n", sec);
}
sec ++;
}
}

View file

@ -0,0 +1,90 @@
#include <amtest.h>
#define FPS 30
#define N 32
static inline uint32_t pixel(uint8_t r, uint8_t g, uint8_t b) {
return (r << 16) | (g << 8) | b;
}
static inline uint8_t R(uint32_t p) { return p >> 16; }
static inline uint8_t G(uint32_t p) { return p >> 8; }
static inline uint8_t B(uint32_t p) { return p; }
static uint32_t canvas[N][N];
static int used[N][N];
static uint32_t color_buf[32 * 32];
void redraw() {
int w = io_read(AM_GPU_CONFIG).width / N;
int h = io_read(AM_GPU_CONFIG).height / N;
int block_size = w * h;
assert((uint32_t)block_size <= LENGTH(color_buf));
int x, y, k;
for (y = 0; y < N; y ++) {
for (x = 0; x < N; x ++) {
for (k = 0; k < block_size; k ++) {
color_buf[k] = canvas[y][x];
}
io_write(AM_GPU_FBDRAW, x * w, y * h, color_buf, w, h, false);
}
}
io_write(AM_GPU_FBDRAW, 0, 0, NULL, 0, 0, true);
}
static uint32_t p(int tsc) {
int b = tsc & 0xff;
return pixel(b * 6, b * 7, b);
}
void update() {
static int tsc = 0;
static int dx[4] = {0, 1, 0, -1};
static int dy[4] = {1, 0, -1, 0};
tsc ++;
for (int i = 0; i < N; i ++)
for (int j = 0; j < N; j ++) {
used[i][j] = 0;
}
int init = tsc * 1;
canvas[0][0] = p(init); used[0][0] = 1;
int x = 0, y = 0, d = 0;
for (int step = 1; step < N * N; step ++) {
for (int t = 0; t < 4; t ++) {
int x1 = x + dx[d], y1 = y + dy[d];
if (x1 >= 0 && x1 < N && y1 >= 0 && y1 < N && !used[x1][y1]) {
x = x1; y = y1;
used[x][y] = 1;
canvas[x][y] = p(init + step / 2);
break;
}
d = (d + 1) % 4;
}
}
}
void video_test() {
unsigned long last = 0;
unsigned long fps_last = 0;
int fps = 0;
while (1) {
unsigned long upt = io_read(AM_TIMER_UPTIME).us / 1000;
if (upt - last > 1000 / FPS) {
update();
redraw();
last = upt;
fps ++;
}
if (upt - fps_last > 1000) {
// display fps every 1s
printf("%d: FPS = %d\n", upt, fps);
fps_last = upt;
fps = 0;
}
}
}

View file

@ -0,0 +1,90 @@
#include <amtest.h>
static Context *uctx;
static AddrSpace prot;
static uintptr_t st = 0;
static int first_trap = 1;
void *simple_pgalloc(int size) {
if (st == 0) { st = (uintptr_t)heap.start; }
while (st % size != 0) st++;
void *ret = (void *)st;
st += size;
return ret;
}
void simple_pgfree(void *ptr) {
}
Context* vm_handler(Event ev, Context *ctx) {
switch (ev.event) {
case EVENT_YIELD:
break;
case EVENT_IRQ_TIMER:
case EVENT_IRQ_IODEV:
printf("==== interrupt (%s) ====\n", ev.msg);
break;
case EVENT_PAGEFAULT:
printf("PF: %x %s%s%s\n",
ev.ref,
(ev.cause & MMAP_NONE) ? "[not present]" : "",
(ev.cause & MMAP_READ) ? "[read fail]" : "",
(ev.cause & MMAP_WRITE) ? "[write fail]" : "");
break;
case EVENT_SYSCALL:
iset(1);
for (int volatile i = 0; i < 1000000; i++) ;
printf("%d ", ctx->GPRx);
break;
default:
assert(0);
}
if (first_trap) {
first_trap = 0;
return uctx;
} else {
return ctx;
}
}
uint8_t code[] = {
#ifdef __ARCH_NATIVE
0x31, 0xc0, // xor %eax, %eax
0x83, 0xc0, 0x01, // add $1, %eax
0xff, 0x14, 0x25, 0x00, 0x00, 0x10, 0x00, // call *0x100000
0xeb, 0xf4, // jmp 2
#else
0x31, 0xc0, // xor %eax, %eax
0x8d, 0xb6, // lea 0(%esi), %esi
0x00, 0x00, 0x00, 0x00,
0x83, 0xc0, 0x01, // add $1, %eax
0xcd, 0x80, // int $0x80
0xeb, 0xf9, // jmp 8
#endif
};
void vm_test() {
if (!strncmp(__ISA__, "x86", 3) == 0 &&
!strcmp(__ISA__, "native") == 0) {
printf("Not supported architecture.\n");
return;
}
protect(&prot);
printf("Protected address space: [%p, %p)\n", prot.area.start, prot.area.end);
uint8_t *ptr = (void*)((uintptr_t)(prot.area.start) +
((uintptr_t)(prot.area.end) - (uintptr_t)(prot.area.start)) / 2);
void *pg = simple_pgalloc(prot.pgsize);
memcpy(pg, code, sizeof(code));
map(&prot, ptr, pg, MMAP_WRITE | MMAP_READ);
printf("Code copied to %p (physical %p) execute\n", ptr, pg);
static uint8_t stack[4096];
uctx = ucontext(&prot, RANGE(stack, stack + sizeof(stack)), ptr);
iset(1);
yield();
}