diff --git a/Sujet.pdf b/Sujet.pdf index 35aab09ee25abd86410640e5dbd04397de626f09..3f1222d0362a2e74c1a5e13ded8a8368fb4d15e8 100644 Binary files a/Sujet.pdf and b/Sujet.pdf differ diff --git a/tests/invader/cep_platform.h b/tests/invader/cep_platform.h new file mode 100644 index 0000000000000000000000000000000000000000..2bf145ddeea72aacbbadca87ddd129a65dd7db0f --- /dev/null +++ b/tests/invader/cep_platform.h @@ -0,0 +1,53 @@ +#ifndef __CEP_PLATFORM_H__ +#define __CEP_PLATFORM_H__ + +// Peripherals Addresses +#define PERIPHS_BASE_ADDRESS 0x30000000 +#define REG_LEDS_ADDR (PERIPHS_BASE_ADDRESS + 0x0) +#define REG_LEDS_CTRL (PERIPHS_BASE_ADDRESS + 0x4) +#define REG_PIN_ADDR (PERIPHS_BASE_ADDRESS + 0x8) +#define REG_PUSHBUTTON_CTL_ADDR (PERIPHS_BASE_ADDRESS + 0xC) + +// VRAM addresses +#define FRAME_BUFFER_CTRL_BASE_ADDRESS 0x70000000 +#define FRAME_BUFFER_CTRL_MODE_REG (FRAME_BUFFER_CTRL_BASE_ADDRESS + 0x0) +#define FRAME_BUFFER_CTRL_ADDR_REG (FRAME_BUFFER_CTRL_BASE_ADDRESS + 0x4) +#define VRAM_OFFSET 0x80000000 + +// PLIC registers addresses +#define PLIC_PENDING_1 0x0C001000 +#define PLIC_ENABLE_1 0x0c002000 +#define PLIC_IRQ_CLAIM 0x0c200004 + +// DEPRECATED: Gestion des priorités du PLIC a été retirée de la plateforme cep dans qemu +//#define PLIC_THRESHOLD 0x0c200000 +//#define PLIC_IRQ_PRIORITY_BASE 0x0c000000 +//#define PLIC_IRQ_PRIORITY_1 0x0c000004 + +// CLINT registers addresses +#define CLINT_MSIP 0x02000000 +#define CLINT_TIMER_CMP 0x02004000 +#define CLINT_TIMER_CMP_HI 0x02004004 +#define CLINT_TIMER_CMP_LO 0x02004000 +#define CLINT_TIMER 0x0200bff8 +#define CLINT_TIMER_HI 0x0200bffc +#define CLINT_TIMER_LOW 0x0200bff8 + +// VRAM sizes +#define VRAM_WIDTH 1280 +#define VRAM_HEIGTH 720 +#define PIXEL_SIZE 4 +#define VRAM_SIZE (VRAM_WIDTH * VRAM_HEIGTH * PIXEL_SIZE) + +// Push button modes +#define REG_PUSHBUTTON_MODE_POLL 0x0 +#define REG_PUSHBUTTON_MODE_INT 0x1 + +// HDMI Modes +#define HDMI_MODE_720p_60Hz 4 +#define HDMI_MODE_1080p_60Hz 19 +#define HDMI_MODE_1080p_30Hz_blk_0 32 +#define HDMI_MODE_1080p_30Hz_blk_1 33 +#define HDMI_MODE_1080p_30Hz_blk_2 34 + +#endif // __CEP_PLATFORM_H__ diff --git a/tests/invader/constants.s b/tests/invader/constants.s new file mode 100644 index 0000000000000000000000000000000000000000..d08387c2bc7b951a95ba0dc5e4147ee7fbdbf0f4 --- /dev/null +++ b/tests/invader/constants.s @@ -0,0 +1,18 @@ +# See LICENSE for license details. + +.equ MAX_HARTS, 4 +.equ SAVE_REGS, 16 +.equ STACK_SIZE, 1024 +.equ STACK_SHIFT, 10 +.equ CONTEXT_SIZE, (SAVE_REGS * REGBYTES) + +.globl _text_start +.globl _text_end +.globl _rodata_start +.globl _rodata_end +.globl _data_start +.globl _data_end +.globl _bss_start +.globl _bss_end +.global _memory_start; +.global _memory_end; diff --git a/tests/invader/crt.s b/tests/invader/crt.s new file mode 100644 index 0000000000000000000000000000000000000000..dcdf1e15619b966fe805452be4aeaf56892fb577 --- /dev/null +++ b/tests/invader/crt.s @@ -0,0 +1 @@ +.include "crtm.s" diff --git a/tests/invader/crtm.s b/tests/invader/crtm.s new file mode 100644 index 0000000000000000000000000000000000000000..158b3ce37b6d63155898f5f40916b043408ac200 --- /dev/null +++ b/tests/invader/crtm.s @@ -0,0 +1,75 @@ +# See LICENSE for license details. + +.include "macros.s" +.include "constants.s" + +# +# start of trap handler +# + +.section .text.init,"ax",@progbits +.globl _start + +_start: + # setup default trap vector + la t0, trap_vector + csrw mtvec, t0 + + # set up stack pointer based on hartid + la sp, stacks + STACK_SIZE + #li sp, 0x00008FF0 + + # jump to main + lw a0, 4(sp) # pass argc + addi a1, sp, 8 # pass argv + j libfemto_start_main + + .align 2 +trap_vector: + # Save registers. + addi sp, sp, -CONTEXT_SIZE + sxsp ra, 0 + sxsp a0, 1 + sxsp a1, 2 + sxsp a2, 3 + sxsp a3, 4 + sxsp a4, 5 + sxsp a5, 6 + sxsp a6, 7 + sxsp a7, 8 + sxsp t0, 9 + sxsp t1, 10 + sxsp t2, 11 + sxsp t3, 12 + sxsp t4, 13 + sxsp t5, 14 + sxsp t6, 15 + + # Invoke the handler. + mv a0, sp + csrr a1, mcause + csrr a2, mepc + jal trap_handler + + # Restore registers. + lxsp ra, 0 + lxsp a0, 1 + lxsp a1, 2 + lxsp a2, 3 + lxsp a3, 4 + lxsp a4, 5 + lxsp a5, 6 + lxsp a6, 7 + lxsp a7, 8 + lxsp t0, 9 + lxsp t1, 10 + lxsp t2, 11 + lxsp t3, 12 + lxsp t4, 13 + lxsp t5, 14 + lxsp t6, 15 + addi sp, sp, CONTEXT_SIZE + + # Return + mret + diff --git a/tests/invader/extended.lds b/tests/invader/extended.lds new file mode 100644 index 0000000000000000000000000000000000000000..a5347f423fb73d89b8c80613381dd9c68bb6cf81 --- /dev/null +++ b/tests/invader/extended.lds @@ -0,0 +1,54 @@ +OUTPUT_ARCH( "riscv" ) + +GROUP(-lgcc) + +ENTRY( _start ) + +MEMORY +{ + ram (wxa!ri) : ORIGIN = 0x1000, LENGTH = 32M +} + +PHDRS +{ + text PT_LOAD; + data PT_LOAD; + bss PT_LOAD; +} + +SECTIONS +{ + PROVIDE(_start = 0x1000); + .text : { + PROVIDE(_text_start = .); + *(.text.init) *(.text .text.*) + PROVIDE(_text_end = .); + } >ram AT>ram :text + + .rodata : { + PROVIDE(_rodata_start = .); + *(.rodata .rodata.*) + PROVIDE(_rodata_end = .); + } >ram AT>ram :text + + .data : { + . = ALIGN(4096); + PROVIDE(_data_start = .); + *(.sdata .sdata.*) *(.data .data.*) + PROVIDE(_data_end = .); + } >ram AT>ram :data + + .bss 0xc00000:{ + PROVIDE(stacks = .); + PROVIDE(_bss_start = .); + . = . + 0x400; + . = . + 0x100; + *(.sbss .sbss.*) *(.bss .bss.*) + *(COMMON) + . = . + 0x100; + PROVIDE(_bss_end = .); + } >ram AT>ram :bss + + PROVIDE(_memory_start = ORIGIN(ram)); + PROVIDE(_memory_end = ORIGIN(ram) + LENGTH(ram)); +} diff --git a/tests/invader/font.c b/tests/invader/font.c new file mode 100644 index 0000000000000000000000000000000000000000..937f6703219eac0e0bb8bc1d29914062511f6557 --- /dev/null +++ b/tests/invader/font.c @@ -0,0 +1,260 @@ +#include "font.h" + +char font8x8_basic[256][8] = { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space) + { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!) + { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (") + { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#) + { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($) + { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%) + { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&) + { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (') + { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (() + { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ()) + { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*) + { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,) + { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.) + { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/) + { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0) + { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1) + { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2) + { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3) + { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4) + { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5) + { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6) + { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7) + { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8) + { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;) + { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<) + { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=) + { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>) + { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?) + { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@) + { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A) + { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B) + { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C) + { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F) + { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G) + { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H) + { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I) + { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J) + { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K) + { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L) + { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M) + { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N) + { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O) + { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P) + { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q) + { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R) + { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S) + { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V) + { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W) + { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X) + { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y) + { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z) + { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([) + { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\) + { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (]) + { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_) + { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`) + { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a) + { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b) + { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c) + { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d) + { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e) + { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g) + { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h) + { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i) + { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j) + { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k) + { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l) + { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m) + { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n) + { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o) + { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q) + { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r) + { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s) + { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v) + { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w) + { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y) + { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z) + { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({) + { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|) + { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (}) + { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0080 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0081 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0082 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0083 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0084 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0085 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0086 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0087 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0088 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0089 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+008A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+008B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+008C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+008D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+008E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+008F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0090 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0091 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0092 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0093 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0094 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0095 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0096 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0097 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0098 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0099 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+009A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+009B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+009C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+009D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+009E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+009F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+00A0 (no break space) + { 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00}, // U+00A1 (inverted !) + { 0x18, 0x18, 0x7E, 0x03, 0x03, 0x7E, 0x18, 0x18}, // U+00A2 (dollarcents) + { 0x1C, 0x36, 0x26, 0x0F, 0x06, 0x67, 0x3F, 0x00}, // U+00A3 (pound sterling) + { 0x00, 0x00, 0x63, 0x3E, 0x36, 0x3E, 0x63, 0x00}, // U+00A4 (currency mark) + { 0x33, 0x33, 0x1E, 0x3F, 0x0C, 0x3F, 0x0C, 0x0C}, // U+00A5 (yen) + { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+00A6 (broken pipe) + { 0x7C, 0xC6, 0x1C, 0x36, 0x36, 0x1C, 0x33, 0x1E}, // U+00A7 (paragraph) + { 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+00A8 (diaeresis) + { 0x3C, 0x42, 0x99, 0x85, 0x85, 0x99, 0x42, 0x3C}, // U+00A9 (copyright symbol) + { 0x3C, 0x36, 0x36, 0x7C, 0x00, 0x00, 0x00, 0x00}, // U+00AA (superscript a) + { 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00}, // U+00AB (<<) + { 0x00, 0x00, 0x00, 0x3F, 0x30, 0x30, 0x00, 0x00}, // U+00AC (gun pointing left) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+00AD (soft hyphen) + { 0x3C, 0x42, 0x9D, 0xA5, 0x9D, 0xA5, 0x42, 0x3C}, // U+00AE (registered symbol) + { 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+00AF (macron) + { 0x1C, 0x36, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00}, // U+00B0 (degree) + { 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x7E, 0x00}, // U+00B1 (plusminus) + { 0x1C, 0x30, 0x18, 0x0C, 0x3C, 0x00, 0x00, 0x00}, // U+00B2 (superscript 2) + { 0x1C, 0x30, 0x18, 0x30, 0x1C, 0x00, 0x00, 0x00}, // U+00B2 (superscript 3) + { 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+00B2 (aigu) + { 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x03}, // U+00B5 (mu) + { 0xFE, 0xDB, 0xDB, 0xDE, 0xD8, 0xD8, 0xD8, 0x00}, // U+00B6 (pilcrow) + { 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00}, // U+00B7 (central dot) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x1E}, // U+00B8 (cedille) + { 0x08, 0x0C, 0x08, 0x1C, 0x00, 0x00, 0x00, 0x00}, // U+00B9 (superscript 1) + { 0x1C, 0x36, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00}, // U+00BA (superscript 0) + { 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00}, // U+00BB (>>) + { 0xC3, 0x63, 0x33, 0xBD, 0xEC, 0xF6, 0xF3, 0x03}, // U+00BC (1/4) + { 0xC3, 0x63, 0x33, 0x7B, 0xCC, 0x66, 0x33, 0xF0}, // U+00BD (1/2) + { 0x03, 0xC4, 0x63, 0xB4, 0xDB, 0xAC, 0xE6, 0x80}, // U+00BE (3/4) + { 0x0C, 0x00, 0x0C, 0x06, 0x03, 0x33, 0x1E, 0x00}, // U+00BF (inverted ?) + { 0x07, 0x00, 0x1C, 0x36, 0x63, 0x7F, 0x63, 0x00}, // U+00C0 (A grave) + { 0x70, 0x00, 0x1C, 0x36, 0x63, 0x7F, 0x63, 0x00}, // U+00C1 (A aigu) + { 0x1C, 0x36, 0x00, 0x3E, 0x63, 0x7F, 0x63, 0x00}, // U+00C2 (A circumflex) + { 0x6E, 0x3B, 0x00, 0x3E, 0x63, 0x7F, 0x63, 0x00}, // U+00C3 (A ~) + { 0x63, 0x1C, 0x36, 0x63, 0x7F, 0x63, 0x63, 0x00}, // U+00C4 (A umlaut) + { 0x0C, 0x0C, 0x00, 0x1E, 0x33, 0x3F, 0x33, 0x00}, // U+00C5 (A ring) + { 0x7C, 0x36, 0x33, 0x7F, 0x33, 0x33, 0x73, 0x00}, // U+00C6 (AE) + { 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x18, 0x30, 0x1E}, // U+00C7 (C cedille) + { 0x07, 0x00, 0x3F, 0x06, 0x1E, 0x06, 0x3F, 0x00}, // U+00C8 (E grave) + { 0x38, 0x00, 0x3F, 0x06, 0x1E, 0x06, 0x3F, 0x00}, // U+00C9 (E aigu) + { 0x0C, 0x12, 0x3F, 0x06, 0x1E, 0x06, 0x3F, 0x00}, // U+00CA (E circumflex) + { 0x36, 0x00, 0x3F, 0x06, 0x1E, 0x06, 0x3F, 0x00}, // U+00CB (E umlaut) + { 0x07, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00CC (I grave) + { 0x38, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00CD (I aigu) + { 0x0C, 0x12, 0x00, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+00CE (I circumflex) + { 0x33, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00CF (I umlaut) + { 0x3F, 0x66, 0x6F, 0x6F, 0x66, 0x66, 0x3F, 0x00}, // U+00D0 (Eth) + { 0x3F, 0x00, 0x33, 0x37, 0x3F, 0x3B, 0x33, 0x00}, // U+00D1 (N ~) + { 0x0E, 0x00, 0x18, 0x3C, 0x66, 0x3C, 0x18, 0x00}, // U+00D2 (O grave) + { 0x70, 0x00, 0x18, 0x3C, 0x66, 0x3C, 0x18, 0x00}, // U+00D3 (O aigu) + { 0x3C, 0x66, 0x18, 0x3C, 0x66, 0x3C, 0x18, 0x00}, // U+00D4 (O circumflex) + { 0x6E, 0x3B, 0x00, 0x3E, 0x63, 0x63, 0x3E, 0x00}, // U+00D5 (O ~) + { 0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00}, // U+00D6 (O umlaut) + { 0x00, 0x36, 0x1C, 0x08, 0x1C, 0x36, 0x00, 0x00}, // U+00D7 (multiplicative x) + { 0x5C, 0x36, 0x73, 0x7B, 0x6F, 0x36, 0x1D, 0x00}, // U+00D8 (O stroke) + { 0x0E, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, // U+00D9 (U grave) + { 0x70, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, // U+00DA (U aigu) + { 0x3C, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x00}, // U+00DB (U circumflex) + { 0x33, 0x00, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+00DC (U umlaut) + { 0x70, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x00}, // U+00DD (Y aigu) + { 0x0F, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+00DE (Thorn) + { 0x00, 0x1E, 0x33, 0x1F, 0x33, 0x1F, 0x03, 0x03}, // U+00DF (beta) + { 0x07, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E0 (a grave) + { 0x38, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E1 (a aigu) + { 0x7E, 0xC3, 0x3C, 0x60, 0x7C, 0x66, 0xFC, 0x00}, // U+00E2 (a circumflex) + { 0x6E, 0x3B, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E3 (a ~) + { 0x33, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E4 (a umlaut) + { 0x0C, 0x0C, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E5 (a ring) + { 0x00, 0x00, 0xFE, 0x30, 0xFE, 0x33, 0xFE, 0x00}, // U+00E6 (ae) + { 0x00, 0x00, 0x1E, 0x03, 0x03, 0x1E, 0x30, 0x1C}, // U+00E7 (c cedille) + { 0x07, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00E8 (e grave) + { 0x38, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00E9 (e aigu) + { 0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00}, // U+00EA (e circumflex) + { 0x33, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00EB (e umlaut) + { 0x07, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00EC (i grave) + { 0x1C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00ED (i augu) + { 0x3E, 0x63, 0x1C, 0x18, 0x18, 0x18, 0x3C, 0x00}, // U+00EE (i circumflex) + { 0x33, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00EF (i umlaut) + { 0x1B, 0x0E, 0x1B, 0x30, 0x3E, 0x33, 0x1E, 0x00}, // U+00F0 (eth) + { 0x00, 0x1F, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x00}, // U+00F1 (n ~) + { 0x00, 0x07, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F2 (o grave) + { 0x00, 0x38, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F3 (o aigu) + { 0x1E, 0x33, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F4 (o circumflex) + { 0x6E, 0x3B, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F5 (o ~) + { 0x00, 0x33, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F6 (o umlaut) + { 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00}, // U+00F7 (division) + { 0x00, 0x60, 0x3C, 0x76, 0x7E, 0x6E, 0x3C, 0x06}, // U+00F8 (o stroke) + { 0x00, 0x07, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00F9 (u grave) + { 0x00, 0x38, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FA (u aigu) + { 0x1E, 0x33, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FB (u circumflex) + { 0x00, 0x33, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FC (u umlaut) + { 0x00, 0x38, 0x00, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+00FD (y aigu) + { 0x00, 0x00, 0x06, 0x3E, 0x66, 0x3E, 0x06, 0x00}, // U+00FE (thorn) + { 0x00, 0x33, 0x00, 0x33, 0x33, 0x3E, 0x30, 0x1F} // U+00FF (y umlaut) +}; diff --git a/tests/invader/include/alloca.h b/tests/invader/include/alloca.h new file mode 100644 index 0000000000000000000000000000000000000000..2ae6a3e066639298d28c546c2acf906c4400964c --- /dev/null +++ b/tests/invader/include/alloca.h @@ -0,0 +1,3 @@ +#pragma once + +#define alloca(size) __builtin_alloca (size) diff --git a/tests/invader/include/arch/riscv/csr.h b/tests/invader/include/arch/riscv/csr.h new file mode 100644 index 0000000000000000000000000000000000000000..8bbc5f4b3c031723f598f92809a3af1f336a929c --- /dev/null +++ b/tests/invader/include/arch/riscv/csr.h @@ -0,0 +1,81 @@ +// See LICENSE for license details. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +int* csr_enum_array(); +const char** csr_name_array(); +long read_csr_enum(int csrenum); +void write_csr_enum(int csrenum, long value); + +enum { + csr_none, + csr_fflags, + csr_frm, + csr_fcsr, + csr_mcycle, + csr_minstret, + csr_mcycleh, + csr_minstreth, + csr_cycle, + csr_time, + csr_instret, + csr_cycleh, + csr_timeh, + csr_instreth, + csr_mvendorid, + csr_marchid, + csr_mimpid, + csr_mhartid, + csr_mstatus, + csr_misa, + csr_medeleg, + csr_mideleg, + csr_mie, + csr_mtvec, + csr_mcounteren, + csr_mscratch, + csr_mepc, + csr_mcause, + csr_mtval, + csr_mip, + csr_sstatus, + csr_sedeleg, + csr_sideleg, + csr_sie, + csr_stvec, + csr_scounteren, + csr_sscratch, + csr_sepc, + csr_scause, + csr_stval, + csr_sip, + csr_satp, + csr_pmpcfg0, + csr_pmpcfg1, + csr_pmpcfg2, + csr_pmpcfg3, + csr_pmpaddr0, + csr_pmpaddr1, + csr_pmpaddr2, + csr_pmpaddr3, + csr_pmpaddr4, + csr_pmpaddr5, + csr_pmpaddr6, + csr_pmpaddr7, + csr_pmpaddr8, + csr_pmpaddr9, + csr_pmpaddr10, + csr_pmpaddr11, + csr_pmpaddr12, + csr_pmpaddr13, + csr_pmpaddr14, + csr_pmpaddr15 +}; + +#ifdef __cplusplus +} +#endif diff --git a/tests/invader/include/arch/riscv/encoding.h b/tests/invader/include/arch/riscv/encoding.h new file mode 100644 index 0000000000000000000000000000000000000000..d592bbc72217c570ced0add5964d91dbd96eb752 --- /dev/null +++ b/tests/invader/include/arch/riscv/encoding.h @@ -0,0 +1,197 @@ +// See LICENSE for license details. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001 +#define MSTATUS_SIE 0x00000002 +#define MSTATUS_HIE 0x00000004 +#define MSTATUS_MIE 0x00000008 +#define MSTATUS_UPIE 0x00000010 +#define MSTATUS_SPIE 0x00000020 +#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_MPIE 0x00000080 +#define MSTATUS_SPP 0x00000100 +#define MSTATUS_HPP 0x00000600 +#define MSTATUS_MPP 0x00001800 +#define MSTATUS_FS 0x00006000 +#define MSTATUS_XS 0x00018000 +#define MSTATUS_MPRV 0x00020000 +#define MSTATUS_SUM 0x00040000 +#define MSTATUS_MXR 0x00080000 +#define MSTATUS_TVM 0x00100000 +#define MSTATUS_TW 0x00200000 +#define MSTATUS_TSR 0x00400000 +#define MSTATUS32_SD 0x80000000 +#define MSTATUS64_SD 0x8000000000000000 + +#define SSTATUS_UIE 0x00000001 +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_UPIE 0x00000010 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 +#define SSTATUS_FS 0x00006000 +#define SSTATUS_XS 0x00018000 +#define SSTATUS_SUM 0x00040000 +#define SSTATUS_MXR 0x00080000 +#define SSTATUS32_SD 0x80000000 +#define SSTATUS64_SD 0x8000000000000000 + +#define DCSR_XDEBUGVER (3U<<30) +#define DCSR_NDRESET (1<<29) +#define DCSR_FULLRESET (1<<28) +#define DCSR_EBREAKM (1<<15) +#define DCSR_EBREAKH (1<<14) +#define DCSR_EBREAKS (1<<13) +#define DCSR_EBREAKU (1<<12) +#define DCSR_STOPCYCLE (1<<10) +#define DCSR_STOPTIME (1<<9) +#define DCSR_CAUSE (7<<6) +#define DCSR_DEBUGINT (1<<5) +#define DCSR_HALT (1<<3) +#define DCSR_STEP (1<<2) +#define DCSR_PRV (3<<0) + +#define DCSR_CAUSE_NONE 0 +#define DCSR_CAUSE_SWBP 1 +#define DCSR_CAUSE_HWBP 2 +#define DCSR_CAUSE_DEBUGINT 3 +#define DCSR_CAUSE_STEP 4 +#define DCSR_CAUSE_HALT 5 + +#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) +#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) +#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) + +#define MCONTROL_SELECT (1<<19) +#define MCONTROL_TIMING (1<<18) +#define MCONTROL_ACTION (0x3f<<12) +#define MCONTROL_CHAIN (1<<11) +#define MCONTROL_MATCH (0xf<<7) +#define MCONTROL_M (1<<6) +#define MCONTROL_H (1<<5) +#define MCONTROL_S (1<<4) +#define MCONTROL_U (1<<3) +#define MCONTROL_EXECUTE (1<<2) +#define MCONTROL_STORE (1<<1) +#define MCONTROL_LOAD (1<<0) + +#define MCONTROL_TYPE_NONE 0 +#define MCONTROL_TYPE_MATCH 2 + +#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 +#define MCONTROL_ACTION_DEBUG_MODE 1 +#define MCONTROL_ACTION_TRACE_START 2 +#define MCONTROL_ACTION_TRACE_STOP 3 +#define MCONTROL_ACTION_TRACE_EMIT 4 + +#define MCONTROL_MATCH_EQUAL 0 +#define MCONTROL_MATCH_NAPOT 1 +#define MCONTROL_MATCH_GE 2 +#define MCONTROL_MATCH_LT 3 +#define MCONTROL_MATCH_MASK_LOW 4 +#define MCONTROL_MATCH_MASK_HIGH 5 + +#define MIP_SSIP (1 << IRQ_S_SOFT) +#define MIP_HSIP (1 << IRQ_H_SOFT) +#define MIP_MSIP (1 << IRQ_M_SOFT) +#define MIP_STIP (1 << IRQ_S_TIMER) +#define MIP_HTIP (1 << IRQ_H_TIMER) +#define MIP_MTIP (1 << IRQ_M_TIMER) +#define MIP_SEIP (1 << IRQ_S_EXT) +#define MIP_HEIP (1 << IRQ_H_EXT) +#define MIP_MEIP (1 << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +#define SPTBR32_MODE 0x80000000 +#define SPTBR32_ASID 0x7FC00000 +#define SPTBR32_PPN 0x003FFFFF +#define SPTBR64_MODE 0xF000000000000000 +#define SPTBR64_ASID 0x0FFFF00000000000 +#define SPTBR64_PPN 0x00000FFFFFFFFFFF + +#define SPTBR_MODE_OFF 0 +#define SPTBR_MODE_SV32 1 +#define SPTBR_MODE_SV39 8 +#define SPTBR_MODE_SV48 9 +#define SPTBR_MODE_SV57 10 +#define SPTBR_MODE_SV64 11 + +#define PMP_R 0x01 +#define PMP_W 0x02 +#define PMP_X 0x04 +#define PMP_A 0x18 +#define PMP_L 0x80 +#define PMP_SHIFT 2 +#define PMPCFG_COUNT 4 +#define PMPADDR_COUNT 16 + +#define PMP_OFF 0x00 +#define PMP_TOR 0x08 +#define PMP_NA4 0x10 +#define PMP_NAPOT 0x18 + +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_COP 12 +#define IRQ_HOST 13 + +#define DEFAULT_RSTVEC 0x00001000 +#define CLINT_BASE 0x02000000 +#define CLINT_SIZE 0x000c0000 +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +// page table entry (PTE) fields +#define PTE_V 0x001 // Valid +#define PTE_R 0x002 // Read +#define PTE_W 0x004 // Write +#define PTE_X 0x008 // Execute +#define PTE_U 0x010 // User +#define PTE_G 0x020 // Global +#define PTE_A 0x040 // Accessed +#define PTE_D 0x080 // Dirty +#define PTE_SOFT 0x300 // Reserved for Software + +#define PTE_PPN_SHIFT 10 + +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define RISCV_PGLEVEL_BITS 9 +# define SPTBR_MODE SPTBR64_MODE +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define SPTBR_MODE SPTBR32_MODE +#endif +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/tests/invader/include/arch/riscv/machine.h b/tests/invader/include/arch/riscv/machine.h new file mode 100644 index 0000000000000000000000000000000000000000..077a6c1e8a629fda3b5eefed0a24e1219c992c8b --- /dev/null +++ b/tests/invader/include/arch/riscv/machine.h @@ -0,0 +1,183 @@ +// See LICENSE for license details. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stddef.h> + +void arch_setup(); +void exit(int status) __attribute__((noreturn)); + +#define die(str, ...) ({ \ + printf("%s:%d: " str "\n", __FILE__, __LINE__, ##__VA_ARGS__); exit(-1); }) + +#define assert(x) ({ if (!(x)) die("assertion failed: %s", #x); }) + +#define read_const_csr(reg) ({ unsigned long __tmp; \ + asm ("csrr %0, " #reg : "=r"(__tmp)); __tmp; }) + +#define read_csr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); __tmp; }) + +#define write_csr(reg, val) ({ \ + asm volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); __tmp; }) + +static inline uintptr_t get_field(uintptr_t reg, uintptr_t mask) +{ + return ((reg & mask) / (mask & ~(mask << 1))); +} + +static inline uintptr_t set_field(uintptr_t reg, uintptr_t mask, uintptr_t val) +{ + return ((reg & ~mask) | ((val * (mask & ~(mask << 1))) & mask)); +} + +static inline unsigned long rdtime() { return read_csr(time); } +static inline unsigned long rdcycle() { return read_csr(cycle); } +static inline unsigned long rdinstret() { return read_csr(instret); } +static inline int64_t misa() { return read_const_csr(misa); } +static inline int has_ext(char ext) { return misa() & (1 << (ext - 'a')); } +static inline int xlen() { return misa() < 0 ? 64 : 32; } +static inline void wfi() { asm volatile ("wfi" ::: "memory"); } + +__attribute__((noreturn)) static inline void mret() +{ + asm volatile ("mret"); + __builtin_unreachable(); +} + + +/* + * Memory + * + * TODO - improve this API to return a list of memory segments + */ + +typedef struct memory_info +{ + uintptr_t start; + uintptr_t end; +} memory_info_t; + + +/* + * memory_probe - return memory_info + */ +memory_info_t memory_probe(); + +/* + * memory_probe_range - probe a memory address range + */ +uintptr_t memory_probe_range(uintptr_t start, uintptr_t end); + + +/* + * Physical Memory Protection + * + * PMP is optional but if implememented, enforcement must be enabled by + * default, if no PMP entries are set. This means loads, stores or fetches + * from any mode besides M mode, will fail unless explicitly allowed. + * PMP must be configured irregardless of whether it is implemented. + */ + +typedef struct pmp_info +{ + int width; + int granularity; + int count; +} pmp_info_t; + +/* + * pmp_probe - return pmp_info + */ +pmp_info_t pmp_probe(); + +/* + * pmp_entry_granularity - return PMP entry width (physical memory width) + */ +int pmp_entry_width(); + +/* + * pmp_entry_granularity - return PMP entry granularity (smallest entry size) + */ +int pmp_entry_granularity(); + +/* + * pmp_entry_count - return number of PMP entries + */ +int pmp_entry_count(); + +/* + * pmp_clear_all - set PMP to disallow mode != PRV_M physical memory accesses + */ +void pmp_clear_all(); + +/* + * pmp_allow_all - set PMP to allow mode != PRV_M physical memory accesses + */ +void pmp_allow_all(); + +/* + * pmp_entry_set - set one PMP entry + * + * - n : pmp entry number + * - prot : protection (PMP_R | PMP_W | PMP_X) + * - addr : start address + * - len : power of two length + */ +int pmp_entry_set(unsigned n, uint8_t prot, uint64_t addr, uint64_t len); + + +/* + * Privileged modes + */ + +/* + * mode_set_and_jump + * + * Set mstatus.mpp, sets mepc to passed function pointer and then issues mret + * Note: the hart will continue running on the same stack + */ +static inline void mode_set_and_jump(unsigned mode, void (*fn)(void)) +{ + assert(mode <= PRV_U); + write_csr(mstatus, set_field(read_csr(mstatus), MSTATUS_MPP, mode)); + write_csr(mepc, fn); + mret(); +} + +/* + * mode_set_and_continue + * + * Set mstatus.mpp, sets mepc to instruction after mret and then issues mret + * Note: the hart will continue running on the same stack + */ +static inline void mode_set_and_continue(unsigned mode) +{ + assert(mode <= PRV_U); + write_csr(mstatus, set_field(read_csr(mstatus), MSTATUS_MPP, mode)); + asm volatile ( + "lla t0, 1f\n" + "csrw mepc, t0\n" + "mret\n" + "1:" + ::: "t0" + ); +} + +#ifdef __cplusplus +} +#endif diff --git a/tests/invader/include/arch/riscv/pte.h b/tests/invader/include/arch/riscv/pte.h new file mode 100644 index 0000000000000000000000000000000000000000..38d7b8d4ad7999e8d07a430be1b8e0c908a1ad8d --- /dev/null +++ b/tests/invader/include/arch/riscv/pte.h @@ -0,0 +1,121 @@ +#pragma once + +enum { + PTE_SHIFT_V = 0, + PTE_SHIFT_R = 1, + PTE_SHIFT_W = 2, + PTE_SHIFT_X = 3, + PTE_SHIFT_U = 4, + PTE_SHIFT_G = 5, + PTE_SHIFT_A = 6, + PTE_SHIFT_D = 7, + PTE_SHIFT_SW1 = 8, + PTE_SHIFT_SW2 = 9, + PTE_V = 1 << PTE_SHIFT_V, + PTE_R = 1 << PTE_SHIFT_R, + PTE_W = 1 << PTE_SHIFT_W, + PTE_X = 1 << PTE_SHIFT_X, + PTE_U = 1 << PTE_SHIFT_U, + PTE_G = 1 << PTE_SHIFT_G, + PTE_A = 1 << PTE_SHIFT_A, + PTE_D = 1 << PTE_SHIFT_D, + PTE_SW1 = 1 << PTE_SHIFT_SW1, + PTE_SW2 = 1 << PTE_SHIFT_SW2 +}; + +enum { + SV32_LEVELS = 2, + SV32_LEVEL_BITS = 10, + SV32_PTE_SIZE = 4 +}; + +union sv32_va { + uint32_t val; + struct { + uint32_t pg_off : 12; + uint32_t vpn : 20; + } va; +}; + +union sv32_pa { + uint64_t val; + struct { + uint64_t pg_off : 12; + uint64_t ppn : 22; + uint64_t rsrv : 30; + } pa; +}; + +union sv32_pte { + uint32_t val; + struct { + uint32_t flags : 10; + uint32_t ppn : 22; + } pte; +}; + +enum { + SV39_LEVELS = 3, + SV39_LEVEL_BITS = 9, + SV39_PTE_SIZE = 8 +}; + +union sv39_va { + uint64_t val; + struct { + uint64_t pg_off : 12; + uint64_t vpn : 27; + uint64_t rsrv : 25; + } va; +}; + +union sv39_pa { + uint64_t val; + struct { + uint64_t pg_off : 12; + uint64_t ppn : 44; + uint64_t rsrv : 8; + } pa; +}; + +union sv39_pte { + uint64_t val; + struct { + uint64_t flags : 10; + uint64_t ppn : 44; + uint64_t rsrv : 10; + } pte; +}; + +enum { + SV48_LEVELS = 4, + SV48_LEVEL_BITS = 9, + SV48_PTE_SIZE = 8 +}; + +union sv48_va { + uint64_t val; + struct { + uint64_t pg_off : 12; + uint64_t vpn : 36; + uint64_t rsrv : 16; + } va; +}; + +union sv48_pa { + uint64_t val; + struct { + uint64_t pg_off : 12; + uint64_t ppn : 44; + uint64_t rsrv : 8; + } pa; +}; + +union sv48_pte { + uint64_t val; + struct { + uint64_t flags : 10; + uint64_t ppn : 44; + uint64_t rsrv : 10; + } pte; +}; diff --git a/tests/invader/include/arch/riscv/trap.h b/tests/invader/include/arch/riscv/trap.h new file mode 100644 index 0000000000000000000000000000000000000000..0b33ec587ae9529285cb1f8f8ceb17249ec49741 --- /dev/null +++ b/tests/invader/include/arch/riscv/trap.h @@ -0,0 +1,51 @@ +// See LICENSE for license details. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*trap_fn)(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc); +trap_fn get_trap_fn(); +void set_trap_fn(trap_fn fn); + +const char * riscv_excp_names[16]; +const char * riscv_intr_names[16]; + +enum { + cause_misaligned_fetch = 0, + cause_fault_fetch = 1, + cause_illegal_instruction = 2, + cause_breakpoint = 3, + cause_misaligned_load = 4, + cause_fault_load = 5, + cause_misaligned_store = 6, + cause_fault_store = 7, + cause_user_ecall = 8, + cause_supervisor_ecall = 9, + cause_hypervisor_ecall = 10, + cause_machine_ecall = 11, + cause_exec_page_fault = 12, + cause_load_page_fault = 13, + cause_store_page_fault = 15 +}; + +enum { + intr_u_software = 0, + intr_s_software = 1, + intr_h_software = 2, + intr_m_software = 3, + intr_u_timer = 4, + intr_s_timer = 5, + intr_h_timer = 6, + intr_m_timer = 7, + intr_u_external = 8, + intr_s_external = 9, + intr_h_external = 10, + intr_m_external = 11, +}; + +#ifdef __cplusplus +} +#endif diff --git a/tests/invader/include/auxval.h b/tests/invader/include/auxval.h new file mode 100644 index 0000000000000000000000000000000000000000..de108243640d3a8179b85cffb1dd8a54b47f3b14 --- /dev/null +++ b/tests/invader/include/auxval.h @@ -0,0 +1,34 @@ +// See LICENSE for license details. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + HART0_CLOCK_FREQ = 0x00010000, + UART0_CLOCK_FREQ = 0x00011000, + UART0_BAUD_RATE = 0x00011100, + NS16550A_UART0_CTRL_ADDR = 0x00030000, + RISCV_HTIF_BASE_ADDR = 0x00050000, + SIFIVE_CLINT_CTRL_ADDR = 0x55550000, + SIFIVE_CLIC_CRTL_ADDR = 0x55550001, + SIFIVE_TEST_CTRL_ADDR = 0x55550002, + SIFIVE_UART0_CTRL_ADDR = 0x55550010, + SIFIVE_GPIO0_CTRL_ADDR = 0x55550020, + SIFIVE_SPI0_CTRL_ADDR = 0x55550030, +}; + +typedef struct auxval { + unsigned long key; + unsigned long val; +} auxval_t; + +extern auxval_t __auxv[]; + +unsigned long getauxval(unsigned long key); + +#ifdef __cplusplus +} +#endif diff --git a/tests/invader/include/device.h b/tests/invader/include/device.h new file mode 100644 index 0000000000000000000000000000000000000000..822ab8c3f25147bfe0bb704f32b26f1931c85957 --- /dev/null +++ b/tests/invader/include/device.h @@ -0,0 +1,39 @@ +// See LICENSE for license details. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct console_device { + void (*init)(); + int (*getchar)(); + int (*putchar)(int); +} console_device_t; + +typedef struct poweroff_device { + void (*init)(); + void (*poweroff)(int); +} poweroff_device_t; + +void register_console(console_device_t *dev); +void register_poweroff(poweroff_device_t *dev); + +extern console_device_t *console_dev; +extern poweroff_device_t *poweroff_dev; + +extern console_device_t console_none; +extern console_device_t console_htif; +extern console_device_t console_ns16550a; +extern console_device_t console_sifive_uart; +extern console_device_t console_semihost; + +extern poweroff_device_t poweroff_none; +extern poweroff_device_t poweroff_htif; +extern poweroff_device_t poweroff_sifive_test; +extern poweroff_device_t poweroff_semihost; + +#ifdef __cplusplus +} +#endif diff --git a/tests/invader/include/elf.h b/tests/invader/include/elf.h new file mode 100644 index 0000000000000000000000000000000000000000..abfb892a256f9a9be1b155c7ffb3ca1d7f3ee3ac --- /dev/null +++ b/tests/invader/include/elf.h @@ -0,0 +1,545 @@ +#pragma once + +#include <stdint.h> + +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; +typedef uint8_t Elf32_Byte; + +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; +typedef uint8_t Elf64_Byte; + +enum { + AT_NULL = 0, + AT_PHDR = 3, + AT_PHENT = 4, + AT_PHNUM = 5, + AT_PAGESZ = 6, + AT_BASE = 7, + AT_FLAGS = 8, + AT_ENTRY = 9, + AT_UID = 11, + AT_EUID = 12, + AT_GID = 13, + AT_EGID = 14, + AT_CLKTCK = 17, + AT_SECURE = 23, + AT_RANDOM = 25 +}; + +typedef struct { + Elf32_Word a_type; + Elf32_Word a_val; +} Elf32_auxv; + +typedef struct { + Elf64_Word a_type; + Elf64_Word a_val; +} Elf64_auxv; + +enum { + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4, + ET_LOPROC = 0xff00, + ET_HIPROC = 0xffff +}; + +enum { + EM_NONE = 0, + EM_X86_64 = 62, + EM_RISCV = 243 +}; + +enum { + EV_NONE = 0, + EV_CURRENT = 1 +}; + +enum { + EI_MAG0 = 0, + EI_MAG1 = 1, + EI_MAG2 = 2, + EI_MAG3 = 3, + EI_CLASS = 4, + EI_DATA = 5, + EI_VERSION = 6, + EI_OSABI = 7, + EI_ABIVERSION = 8, + EI_PAD = 9, + EI_NIDENT = 16 +}; + +enum { + ELFMAG0 = 0x7f, + ELFMAG1 = 'E', + ELFMAG2 = 'L', + ELFMAG3 = 'F' +}; + +enum { + ELFCLASSNONE = 0, + ELFCLASS32 = 1, + ELFCLASS64 = 2, + ELFCLASS128 = 3 +}; + +enum { + ELFDATANONE = 0, + ELFDATA2LSB = 1, + ELFDATA2MSB = 2 +}; + +enum { + ELFOSABI_SYSV = 0, + ELFOSABI_LINUX = 3, + ELFOSABI_SOLARIS = 6, + ELFOSABI_FREEBSD = 9 +}; + +enum { + ELFABIVERSION_NONE = 0 +}; + +typedef struct { + Elf32_Byte e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct { + Elf64_Byte e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +enum { + PT_NULL = 0, + PT_LOAD = 1, + PT_DYNAMIC = 2, + PT_INTERP = 3, + PT_NOTE = 4, + PT_SHLIB = 5, + PT_PHDR = 6, + PT_TLS = 7, + PT_LOOS = 0x60000000, + PT_GNU_EH_FRAME = 0x6474e550, + PT_GNU_STACK = 0x6474e551, + PT_GNU_RELRO = 0x6474e552, + PT_HIOS = 0x6fffffff, + PT_LOPROC = 0x70000000, + PT_HIPROC = 0x7fffffff +}; + +enum { + PF_X = 0x1, + PF_W = 0x2, + PF_R = 0x4, + PF_MASKOS = 0x00FF0000, + PF_MASKPROC = 0xFF000000, +}; + +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +} Elf64_Phdr; + +enum { + SHN_UNDEF = 0, + SHN_LOPROC = 0xff00, + SHN_HIPROC = 0xff1f, + SHN_LOOS = 0xff20, + SHN_HIOS = 0xff3f, + SHN_ABS = 0xfff1, + SHN_COMMON = 0xfff2, + SHN_XINDEX = 0xffff, + SHN_HIRESERVE = 0xffff, +}; + +enum { + SHT_NULL = 0, + SHT_PROGBITS = 1, + SHT_SYMTAB = 2, + SHT_STRTAB = 3, + SHT_RELA = 4, + SHT_HASH = 5, + SHT_DYNAMIC = 6, + SHT_NOTE = 7, + SHT_NOBITS = 8, + SHT_REL = 9, + SHT_SHLIB = 10, + SHT_DYNSYM = 11, + SHT_INIT_ARRAY = 14, + SHT_FINI_ARRAY = 15, + SHT_PREINIT_ARRAY = 16, + SHT_GROUP = 17, + SHT_SYMTAB_SHNDX = 18, + SHT_LOOS = 0x60000000, + SHT_GNU_VERDEF = 0x6ffffffd, + SHT_GNU_VERNEED = 0x6ffffffe, + SHT_GNU_VERSYM = 0x6fffffff, + SHT_HIOS = 0x6fffffff, + SHT_LOPROC = 0x70000000, + SHT_HIPROC = 0x7fffffff, + SHT_LOUSER = 0x80000000, + SHT_HIUSER = 0xffffffff +}; + +enum { + SHF_WRITE = 0x1, + SHF_ALLOC = 0x2, + SHF_EXECINSTR = 0x4, + SHF_MERGE = 0x10, + SHF_STRINGS = 0x20, + SHF_INFO_LINK = 0x40, + SHF_LINK_ORDER = 0x80, + SHF_GROUP = 0x200, + SHF_TLS = 0x400, + SHF_MASKOS = 0x0F000000, + SHF_MASKPROC = 0xf0000000 +}; + +enum { + GRP_COMDAT = 0x1, + GRP_MASKOS = 0x0ff00000, + GRP_MASKPROC = 0xf0000000 +}; + +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; + + +typedef struct { + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +} Elf32_Nhdr; + +typedef struct { + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; +} Elf64_Nhdr; + +static inline const Elf32_Byte ELF32_ST_BIND(Elf32_Word i) { return i >> 4; } +static inline const Elf32_Byte ELF32_ST_TYPE(Elf32_Word i) { return i & 0xf; } +static inline const Elf32_Byte ELF32_ST_INFO(Elf32_Word b, Elf32_Word t) { return (b << 4) | (t & 0xf); } + +static inline const Elf32_Byte ELF64_ST_BIND(Elf32_Word i) { return i >> 4; } +static inline const Elf32_Byte ELF64_ST_TYPE(Elf32_Word i) { return i & 0xf; } +static inline const Elf32_Byte ELF64_ST_INFO(Elf32_Word b, Elf32_Word t) { return (b << 4) | (t & 0xf); } + +enum { + STB_LOCAL = 0, + STB_GLOBAL = 1, + STB_WEAK = 2, + STB_LOOS = 10, + STB_HIOS = 12, + STB_LOPROC = 13, + STB_HIPROC = 15 +}; + +enum { + STT_NOTYPE = 0, + STT_OBJECT = 1, + STT_FUNC = 2, + STT_SECTION = 3, + STT_FILE = 4, + STT_LOOS = 10, + STT_HIOS = 12, + STT_LOPROC = 13, + STT_HIPROC = 15 +}; + +enum { + STV_DEFAULT = 0, + STV_INTERNAL = 1, + STV_HIDDEN = 2, + STV_PROTECTED = 3 +}; + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + Elf32_Byte st_info; + Elf32_Byte st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct { + Elf64_Word st_name; + Elf64_Byte st_info; + Elf64_Byte st_other; + Elf64_Half st_shndx; + Elf64_Addr st_value; + Elf64_Xword st_size; +} Elf64_Sym; + +static inline const Elf32_Word ELF32_R_SYM(Elf32_Word i) { return i >> 8; } +static inline const Elf32_Word ELF32_R_TYPE(Elf32_Word i) { return i & 0xff; } +static inline const Elf32_Word ELF32_R_INFO(Elf32_Word s, Elf32_Word t) { return (s << 8) | (t & 0xff); } + +static inline const Elf64_Xword ELF64_R_SYM(Elf64_Xword i) { return i >> 32; } +static inline const Elf64_Xword ELF64_R_TYPE(Elf64_Xword i) { return i & 0xffffffffUL; } +static inline const Elf64_Xword ELF64_R_INFO(Elf64_Xword s, Elf64_Xword t) { return (s << 32) | (t & 0xffffffffUL); } + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct +{ + Elf64_Addr r_offset; + Elf64_Xword r_info; +} Elf64_Rel; + +typedef struct +{ + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; + +enum { + R_X86_64_NONE = 0, + R_X86_64_64 = 1, + R_X86_64_PC32 = 2, + R_X86_64_GOT32 = 3, + R_X86_64_PLT32 = 4, + R_X86_64_COPY = 5, + R_X86_64_GLOB_DAT = 6, + R_X86_64_JUMP_SLOT = 7, + R_X86_64_RELATIVE = 8, + R_X86_64_GOTPCREL = 9, + R_X86_64_32 = 10, + R_X86_64_32S = 11, + R_X86_64_16 = 12, + R_X86_64_PC16 = 13, + R_X86_64_8 = 14, + R_X86_64_PC8 = 15, + R_X86_64_DTPMOD64 = 16, + R_X86_64_DTPOFF64 = 17, + R_X86_64_TPOFF64 = 18, + R_X86_64_TLSGD = 19, + R_X86_64_TLSLD = 20, + R_X86_64_DTPOFF32 = 21, + R_X86_64_GOTTPOFF = 22, + R_X86_64_TPOFF32 = 23, + R_X86_64_PC64 = 24, + R_X86_64_GOTOFF64 = 25, + R_X86_64_GOTPC32 = 26, + R_X86_64_SIZE32 = 32, + R_X86_64_SIZE64 = 33, + R_X86_64_GOTPC32_TLSDESC = 34, + R_X86_64_TLSDESC_CALL = 35, + R_X86_64_TLSDESC = 36, + R_X86_64_IRELATIVE = 37, + R_X86_64_RELATIVE64 = 38 +}; + +enum { + R_RISCV_NONE = 0, + R_RISCV_32 = 1, + R_RISCV_64 = 2, + R_RISCV_RELATIVE = 3, + R_RISCV_COPY = 4, + R_RISCV_JUMP_SLOT = 5, + R_RISCV_TLS_DTPMOD32 = 6, + R_RISCV_TLS_DTPMOD64 = 7, + R_RISCV_TLS_DTPREL32 = 8, + R_RISCV_TLS_DTPREL64 = 9, + R_RISCV_TLS_TPREL32 = 10, + R_RISCV_TLS_TPREL64 = 11, + R_RISCV_BRANCH = 16, + R_RISCV_JAL = 17, + R_RISCV_CALL = 18, + R_RISCV_CALL_PLT = 19, + R_RISCV_GOT_HI20 = 20, + R_RISCV_TLS_GOT_HI20 = 21, + R_RISCV_TLS_GD_HI20 = 22, + R_RISCV_PCREL_HI20 = 23, + R_RISCV_PCREL_LO12_I = 24, + R_RISCV_PCREL_LO12_S = 25, + R_RISCV_HI20 = 26, + R_RISCV_LO12_I = 27, + R_RISCV_LO12_S = 28, + R_RISCV_TPREL_HI20 = 29, + R_RISCV_TPREL_LO12_I = 30, + R_RISCV_TPREL_LO12_S = 31, + R_RISCV_TPREL_ADD = 32, + R_RISCV_ADD8 = 33, + R_RISCV_ADD16 = 34, + R_RISCV_ADD32 = 35, + R_RISCV_ADD64 = 36, + R_RISCV_SUB8 = 37, + R_RISCV_SUB16 = 38, + R_RISCV_SUB32 = 39, + R_RISCV_SUB64 = 40, + R_RISCV_GNU_VTINHERIT = 41, + R_RISCV_GNU_VTENTRY = 42, + R_RISCV_ALIGN = 43, + R_RISCV_RVC_BRANCH = 44, + R_RISCV_RVC_JUMP = 45, + R_RISCV_RVC_LUI = 46, + R_RISCV_GPREL_I = 47, + R_RISCV_GPREL_S = 48, + R_RISCV_TPREL_I = 49, + R_RISCV_TPREL_S = 50, + R_RISCV_RELAX = 51, + R_RISCV_SUB6 = 52, + R_RISCV_SET6 = 53, + R_RISCV_SET8 = 54, + R_RISCV_SET16 = 55, + R_RISCV_SET32 = 56, +}; + +enum { + EF_RISCV_RVC = 0x1, + EF_RISCV_FLOAT_ABI_SINGLE = 0x2, + EF_RISCV_FLOAT_ABI_DOUBLE = 0x4, + EF_RISCV_FLOAT_ABI_QUAD = 0x6, + EF_RISCV_RVE = 0x8 +}; + +enum { + DF_ORIGIN = 1, + DF_SYMBOLIC = 2, + DF_TEXTREL = 4, + DF_BIND_NOW = 8, + DF_STATIC_TLS = 16 +}; + +enum { + DT_NULL = 0, + DT_NEEDED = 1, + DT_PLTRELSZ = 2, + DT_PLTGOT = 3, + DT_HASH = 4, + DT_STRTAB = 5, + DT_SYMTAB = 6, + DT_RELA = 7, + DT_RELASZ = 8, + DT_RELAENT = 9, + DT_STRSZ = 10, + DT_SYMENT = 11, + DT_INIT = 12, + DT_FINI = 13, + DT_SONAME = 14, + DT_RPATH = 15, + DT_SYMBOLIC = 16, + DT_REL = 17, + DT_RELSZ = 18, + DT_RELENT = 19, + DT_PLTREL = 20, + DT_DEBUG = 21, + DT_TEXTREL = 22, + DT_JMPREL = 23, + DT_BIND_NOW = 24, + DT_INIT_ARRAY = 25, + DT_FINI_ARRAY = 26, + DT_INIT_ARRAYSZ = 27, + DT_FINI_ARRAYSZ = 28, + DT_RUNPATH = 29, + DT_FLAGS = 30, + DT_LOOS = 0x60000000, + DT_HIOS = 0x6fffffff, + DT_LOPROC = 0x70000000, + DT_HIPROC = 0x7fffffff +}; + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; diff --git a/tests/invader/include/endian.h b/tests/invader/include/endian.h new file mode 100644 index 0000000000000000000000000000000000000000..8510f2939748b9b810ae07d8b9ef0bd62c88cd13 --- /dev/null +++ b/tests/invader/include/endian.h @@ -0,0 +1,95 @@ +#pragma once + +#define bswap16(x) __builtin_bswap16(x) +#define bswap32(x) __builtin_bswap32(x) +#define bswap64(x) __builtin_bswap64(x) + +#if __BYTE_ORDER == __LITTLE_ENDIAN +static inline uint16_t htobe16(uint16_t x) { return bswap16(x); } +static inline uint16_t htole16(uint16_t x) { return x; } +static inline uint16_t be16toh(uint16_t x) { return bswap16(x); } +static inline uint16_t le16toh(uint16_t x) { return x; } + +static inline uint32_t htobe32(uint32_t x) { return bswap32(x); } +static inline uint32_t htole32(uint32_t x) { return x; } +static inline uint32_t be32toh(uint32_t x) { return bswap32(x); } +static inline uint32_t le32toh(uint32_t x) { return x; } + +static inline uint64_t htobe64(uint64_t x) { return bswap64(x); } +static inline uint64_t htole64(uint64_t x) { return x; } +static inline uint64_t be64toh(uint64_t x) { return bswap64(x); } +static inline uint64_t le64toh(uint64_t x) { return x; } +#elif __BYTE_ORDER == __BIG_ENDIAN +static inline uint16_t htobe16(uint16_t x) { return x; } +static inline uint16_t htole16(uint16_t x) { return bswap16(x); } +static inline uint16_t be16toh(uint16_t x) { return x; } +static inline uint16_t le16toh(uint16_t x) { return bswap16(x); } + +static inline uint32_t htobe32(uint32_t x) { return x; } +static inline uint32_t htole32(uint32_t x) { return bswap32(x); } +static inline uint32_t be32toh(uint32_t x) { return x; } +static inline uint32_t le32toh(uint16_t x) { return bswap64(x); } + +static inline uint64_t htobe64(uint64_t x) { return x; } +static inline uint64_t htole64(uint64_t x) { return bswap64(x); } +static inline uint64_t be64toh(uint64_t x) { return x; } +static inline uint64_t le64toh(uint64_t x) { return bswap64(x); } +#endif + +#if __SIZE_WIDTH__ == 32 +#define _htobel htobe32 +#define _beltoh be32toh +#define _htolel htole32 +#define _leltoh le32toh +#endif + +#if __SIZE_WIDTH__ == 64 +#define _htobel htobe64 +#define _beltoh be64toh +#define _htolel htole64 +#define _leltoh le64toh +#endif + +#define htobe(X) _Generic((X), \ + short: htobe16, \ + unsigned short: htobe16, \ + int: htobe32, \ + unsigned int: htobe32, \ + long: _htobel, \ + unsigned long: _htobel, \ + long long: htobe64, \ + unsigned long long: htobe64 \ + )(X) + +#define betoh(X) _Generic((X), \ + short: be16toh, \ + unsigned short: be16toh, \ + int: be32toh, \ + unsigned int: be32toh, \ + long: _beltoh, \ + unsigned long: _beltoh, \ + long long: be64toh, \ + unsigned long long: be64toh \ + )(X) + +#define htole(X) _Generic((X), \ + short: htole16, \ + unsigned short: htole16, \ + int: htole32, \ + unsigned int: htole32, \ + long: _htolel, \ + unsigned long: _htolel, \ + long long: htole64, \ + unsigned long long: htole64 \ + )(X) + +#define letoh(X) _Generic((X), \ + short: le16toh, \ + unsigned short: le16toh, \ + int: le32toh, \ + unsigned int: le32toh, \ + long: _leltoh, \ + unsigned long: _leltoh, \ + long long: le64toh, \ + unsigned long long: le64toh \ + )(X) diff --git a/tests/invader/include/femto.h b/tests/invader/include/femto.h new file mode 100644 index 0000000000000000000000000000000000000000..aa8b4cf00d380a0321f909c8971f249316b8ddfb --- /dev/null +++ b/tests/invader/include/femto.h @@ -0,0 +1,14 @@ +// See LICENSE for license details. + +#pragma once + +#include <stdio.h> +#include <stdint.h> +#include <stddef.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdbits.h> +#include <string.h> + +#include "auxval.h" +#include "device.h" diff --git a/tests/invader/include/font.h b/tests/invader/include/font.h new file mode 100644 index 0000000000000000000000000000000000000000..f65d48d250503448fea06af0668b1b630b80bb0e --- /dev/null +++ b/tests/invader/include/font.h @@ -0,0 +1,28 @@ +#ifndef FONT_H +#define FONT_H +/** + * 8x8 monochrome bitmap fonts for rendering + * Author: Daniel Hepper <daniel@hepper.net> + * + * License: Public Domain + * + * Based on: + * // Summary: font8x8.h + * // 8x8 monochrome bitmap fonts for rendering + * // + * // Author: + * // Marcel Sondaar + * // International Business Machines (public domain VGA fonts) + * // + * // License: + * // Public Domain + * + * Fetched from: http://dimensionalrift.homelinux.net/combuster/mos3/?p=viewsource&file=/modules/gfx/font8_8.asm + * Fetched from github : https://github.com/dhepper/font8x8/blob/master/font8x8_basic.h + **/ + +// Constant: font8x8_basic +// Contains an 8x8 font map for unicode points U+0000 - U+007F (basic latin) +char font8x8_basic[256][8]; + +#endif diff --git a/tests/invader/include/libscreen.h b/tests/invader/include/libscreen.h new file mode 100644 index 0000000000000000000000000000000000000000..c222621680066fe7682cebfa7a37aa12e7964981 --- /dev/null +++ b/tests/invader/include/libscreen.h @@ -0,0 +1,69 @@ +#ifndef LIBSCREEN +#define LIBSCREEN + +typedef unsigned int uint; +#include "font.h" +#include "femto.h" + +#define CLINT_MSIP 0x02000000 +#define CLINT_TIMER_CMP 0x02004000 +#define CLINT_TIMER_CMP_HI 0x02004004 +#define CLINT_TIMER_CMP_LO 0x02004000 +#define CLINT_TIMER 0x0200bff8 +#define CLINT_TIMER_HI 0x0200bffc +#define CLINT_TIMER_LOW 0x0200bff8 + + + +volatile uint* IMG; +volatile uint *push; +volatile uint *timer; +volatile uint *timer_cmp; + +/* function to get the state of push buttons */ +uint push_button_get(void); + +// Timer options +#ifdef ENV_QEMU +#define TIMER_FREQ 10000000 // 10MHz +#define RATIO 500 +#else +#define TIMER_FREQ 100000000 // 100MHz +#define RATIO 200 +#endif + +/* function to set the timer to be reached in period*time/100 in the future */ +void timer_set(uint period, uint time); + +/* function to wait for timer zero value */ +void timer_wait(void); + +void timer_set_and_wait(uint period, uint time); + +#define NBCOL 1920 +#define NBROW 1080 + +uint fgcolor; +uint bgcolor; + +void draw(uint color, uint x, uint y); + +void clear_screen(uint color); + +void draw_bitmap(char* bitmap); + +void newline(); +void tab(); + +/* Counts the number of characters of current word. Will be used to break lines, if possible not in the middle of words. */ +uint num_characters_until_white(char* str); + +uint display_cur_x = 0; +uint display_cur_y = 0; +uint display_scale = 16; + +void display_uint(uint i); +void display_string(char* str); +void set_fg_color(uint color); +void set_bg_color(uint color); +#endif diff --git a/tests/invader/include/list.h b/tests/invader/include/list.h new file mode 100644 index 0000000000000000000000000000000000000000..5f4cc72eca0b0c2f81c58c78400d997b11b4aba4 --- /dev/null +++ b/tests/invader/include/list.h @@ -0,0 +1,495 @@ +/* + * Minimal Linux-like double-linked list helper functions + * + * Copyright (c) 2012-2016, Sven Eckelmann <sven@narfation.org> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> + +/** + * container_of() - Calculate address of object that contains address ptr + * @ptr: pointer to member variable + * @type: type of the structure containing ptr + * @member: name of the member variable in struct @type + * + * Return: @type pointer of object containing ptr + */ + +#define container_of(ptr, type, member) __extension__ ({ \ + const __typeof__(((type *)0)->member) *__pmember = (ptr); \ + (type *)((char *)__pmember - offsetof(type, member)); }) + +/** + * struct list_head - Head and node of a double-linked list + * @prev: pointer to the previous node in the list + * @next: pointer to the next node in the list + * + * The simple double-linked list consists of a head and nodes attached to + * this head. Both node and head share the same struct type. The list_* + * functions and macros can be used to access and modify this data structure. + * + * The @prev pointer of the list head points to the last list node of the + * list and @next points to the first list node of the list. For an empty list, + * both member variables point to the head. + * + * The list nodes are usually embedded in a container structure which holds the + * actual data. Such an container object is called entry. The helper list_entry + * can be used to calculate the object address from the address of the node. + */ +struct list_head { + struct list_head *prev; + struct list_head *next; +}; + +/** + * LIST_HEAD - Declare list head and initialize it + * @head: name of the new object + */ +#define LIST_HEAD(head) \ + struct list_head head = { &(head), &(head) } + +/** + * INIT_LIST_HEAD() - Initialize empty list head + * @head: pointer to list head + * + * This can also be used to initialize a unlinked list node. + * + * A node is usually linked inside a list, will be added to a list in + * the near future or the entry containing the node will be free'd soon. + * + * But an unlinked node may be given to a function which uses list_del(_init) + * before it ends up in a previously mentioned state. The list_del(_init) on an + * initialized node is well defined and safe. But the result of a + * list_del(_init) on an uninitialized node is undefined (unrelated memory is + * modified, crashes, ...). + */ +static __inline__ void INIT_LIST_HEAD(struct list_head *head) +{ + head->next = head; + head->prev = head; +} + +/** + * list_add() - Add a list node to the beginning of the list + * @node: pointer to the new node + * @head: pointer to the head of the list + */ +static __inline__ void list_add(struct list_head *node, + struct list_head *head) +{ + struct list_head *next = head->next; + + next->prev = node; + node->next = next; + node->prev = head; + head->next = node; +} + +/** + * list_add_tail() - Add a list node to the end of the list + * @node: pointer to the new node + * @head: pointer to the head of the list + */ +static __inline__ void list_add_tail(struct list_head *node, + struct list_head *head) +{ + struct list_head *prev = head->prev; + + prev->next = node; + node->next = head; + node->prev = prev; + head->prev = node; +} + +/** + * list_add_before() - Add a list node before another node to the list + * @new_node: pointer to the new node + * @node: pointer to the reference node in the list + * + * WARNING this functionality is not available in the Linux list implementation + */ +#define list_add_before(new_node, node) \ + list_add_tail(new_node, node) + +/** + * list_add_behind() - Add a list node behind another node to the list + * @new_node: pointer to the new node + * @node: pointer to the reference node in the list + * + * WARNING this functionality is not available in the Linux list implementation + */ +#define list_add_behind(new_node, node) \ + list_add(new_node, node) + +/** + * list_del() - Remove a list node from the list + * @node: pointer to the node + * + * The node is only removed from the list. Neither the memory of the removed + * node nor the memory of the entry containing the node is free'd. The node + * has to be handled like an uninitialized node. Accessing the next or prev + * pointer of the node is not safe. + * + * Unlinked, initialized nodes are also uninitialized after list_del. + * + * LIST_POISONING can be enabled during build-time to provoke an invalid memory + * access when the memory behind the next/prev pointer is used after a list_del. + * This only works on systems which prohibit access to the predefined memory + * addresses. + */ +static __inline__ void list_del(struct list_head *node) +{ + struct list_head *next = node->next; + struct list_head *prev = node->prev; + + next->prev = prev; + prev->next = next; + +#ifdef LIST_POISONING + node->prev = (struct list_head *)(0x00100100); + node->next = (struct list_head *)(0x00200200); +#endif +} + +/** + * list_del_init() - Remove a list node from the list and reinitialize it + * @node: pointer to the node + * + * The removed node will not end up in an uninitialized state like when using + * list_del. Instead the node is initialized again to the unlinked state. + */ +static __inline__ void list_del_init(struct list_head *node) +{ + list_del(node); + INIT_LIST_HEAD(node); +} + +/** + * list_empty() - Check if list head has no nodes attached + * @head: pointer to the head of the list + * + * Return: 0 - list is not empty !0 - list is empty + */ +static __inline__ int list_empty(const struct list_head *head) +{ + return (head->next == head); +} + +/** + * list_is_singular() - Check if list head has exactly one node attached + * @head: pointer to the head of the list + * + * Return: 0 - list is not singular !0 -list has exactly one entry + */ +static __inline__ int list_is_singular(const struct list_head *head) +{ + return (!list_empty(head) && head->prev == head->next); +} + +/** + * list_splice() - Add list nodes from a list to beginning of another list + * @list: pointer to the head of the list with the node entries + * @head: pointer to the head of the list + * + * All nodes from @list are added to to the beginning of the list of @head. + * It is similar to list_add but for multiple nodes. The @list head is not + * modified and has to be initialized to be used as a valid list head/node + * again. + */ +static __inline__ void list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *head_first = head->next; + struct list_head *list_first = list->next; + struct list_head *list_last = list->prev; + + if (list_empty(list)) + return; + + head->next = list_first; + list_first->prev = head; + + list_last->next = head_first; + head_first->prev = list_last; +} + +/** + * list_splice_tail() - Add list nodes from a list to end of another list + * @list: pointer to the head of the list with the node entries + * @head: pointer to the head of the list + * + * All nodes from @list are added to to the end of the list of @head. + * It is similar to list_add_tail but for multiple nodes. The @list head is not + * modified and has to be initialized to be used as a valid list head/node + * again. + */ +static __inline__ void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + struct list_head *head_last = head->prev; + struct list_head *list_first = list->next; + struct list_head *list_last = list->prev; + + if (list_empty(list)) + return; + + head->prev = list_last; + list_last->next = head; + + list_first->prev = head_last; + head_last->next = list_first; +} + +/** + * list_splice_init() - Move list nodes from a list to beginning of another list + * @list: pointer to the head of the list with the node entries + * @head: pointer to the head of the list + * + * All nodes from @list are added to to the beginning of the list of @head. + * It is similar to list_add but for multiple nodes. + * + * The @list head will not end up in an uninitialized state like when using + * list_splice. Instead the @list is initialized again to the an empty + * list/unlinked state. + */ +static __inline__ void list_splice_init(struct list_head *list, + struct list_head *head) +{ + list_splice(list, head); + INIT_LIST_HEAD(list); +} + +/** + * list_splice_tail_init() - Move list nodes from a list to end of another list + * @list: pointer to the head of the list with the node entries + * @head: pointer to the head of the list + * + * All nodes from @list are added to to the end of the list of @head. + * It is similar to list_add_tail but for multiple nodes. + * + * The @list head will not end up in an uninitialized state like when using + * list_splice. Instead the @list is initialized again to the an empty + * list/unlinked state. + */ +static __inline__ void list_splice_tail_init(struct list_head *list, + struct list_head *head) +{ + list_splice_tail(list, head); + INIT_LIST_HEAD(list); +} + +/** + * list_cut_position() - Move beginning of a list to another list + * @head_to: pointer to the head of the list which receives nodes + * @head_from: pointer to the head of the list + * @node: pointer to the node in which defines the cutting point + * + * All entries from the beginning of the list @head_from to (including) the + * @node is moved to @head_from. + * + * @head_to is replaced when @head_from is not empty. @node must be a real + * list node from @head_from or the behavior is undefined. + */ +static __inline__ void list_cut_position(struct list_head *head_to, + struct list_head *head_from, + struct list_head *node) +{ + struct list_head *head_from_first = head_from->next; + + if (list_empty(head_from)) + return; + + if (head_from == node) { + INIT_LIST_HEAD(head_to); + return; + } + + head_from->next = node->next; + head_from->next->prev = head_from; + + head_to->prev = node; + node->next = head_to; + head_to->next = head_from_first; + head_to->next->prev = head_to; +} + +/** + * list_move() - Move a list node to the beginning of the list + * @node: pointer to the node + * @head: pointer to the head of the list + * + * The @node is removed from its old position/node and add to the beginning of + * @head + */ +static __inline__ void list_move(struct list_head *node, struct list_head *head) +{ + list_del(node); + list_add(node, head); +} + +/** + * list_move_tail() - Move a list node to the end of the list + * @node: pointer to the node + * @head: pointer to the head of the list + * + * The @node is removed from its old position/node and add to the end of @head + */ +static __inline__ void list_move_tail(struct list_head *node, + struct list_head *head) +{ + list_del(node); + list_add_tail(node, head); +} + +/** + * list_entry() - Calculate address of entry that contains list node + * @node: pointer to list node + * @type: type of the entry containing the list node + * @member: name of the list_head member variable in struct @type + * + * Return: @type pointer of entry containing node + */ +#define list_entry(node, type, member) container_of(node, type, member) + +/** + * list_first_entry() - get first entry of the list + * @head: pointer to the head of the list + * @type: type of the entry containing the list node + * @member: name of the list_head member variable in struct @type + * + * Return: @type pointer of first entry in list + */ +#define list_first_entry(head, type, member) \ + list_entry((head)->next, type, member) + +/** + * list_last_entry() - get last entry of the list + * @head: pointer to the head of the list + * @type: type of the entry containing the list node + * @member: name of the list_head member variable in struct @type + * + * Return: @type pointer of last entry in list + */ +#define list_last_entry(head, type, member) \ + list_entry((head)->prev, type, member) + +/** + * list_for_each - iterate over list nodes + * @node: list_head pointer used as iterator + * @head: pointer to the head of the list + * + * The nodes and the head of the list must must be kept unmodified while + * iterating through it. Any modifications to the the list will cause undefined + * behavior. + */ +#define list_for_each(node, head) \ + for (node = (head)->next; \ + node != (head); \ + node = node->next) + +/** + * list_for_each_entry_t - iterate over list entries + * @entry: @type pointer used as iterator + * @head: pointer to the head of the list + * @type: type of the entries containing the list nodes + * @member: name of the list_head member variable in struct @type + * + * The nodes and the head of the list must must be kept unmodified while + * iterating through it. Any modifications to the the list will cause undefined + * behavior. + * + * WARNING this functionality is not available in the Linux list implementation + */ +#define list_for_each_entry_t(entry, head, type, member) \ + for (entry = list_entry((head)->next, type, member); \ + &entry->member != (head); \ + entry = list_entry(entry->member.next, type, member)) + +/** + * list_for_each_entry - iterate over list entries + * @entry: pointer used as iterator + * @head: pointer to the head of the list + * @member: name of the list_head member variable in struct type of @entry + * + * The nodes and the head of the list must must be kept unmodified while + * iterating through it. Any modifications to the the list will cause undefined + * behavior. + */ +#define list_for_each_entry(entry, head, member) \ + list_for_each_entry_t(entry, head, __typeof__(*entry), member) + +/** + * list_for_each_safe - iterate over list nodes and allow deletes + * @node: list_head pointer used as iterator + * @safe: list_head pointer used to store info for next entry in list + * @head: pointer to the head of the list + * + * The current node (iterator) is allowed to be removed from the list. Any + * other modifications to the the list will cause undefined behavior. + */ +#define list_for_each_safe(node, safe, head) \ + for (node = (head)->next, safe = node->next; \ + node != (head); \ + node = safe, safe = node->next) + +/** + * list_for_each_entry_safe_t - iterate over list entries and allow deletes + * @entry: @type pointer used as iterator + * @safe: @type pointer used to store info for next entry in list + * @head: pointer to the head of the list + * @type: type of the entries containing the list nodes + * @member: name of the list_head member variable in struct @type + * + * The current node (iterator) is allowed to be removed from the list. Any + * other modifications to the the list will cause undefined behavior. + * + * WARNING this functionality is not available in the Linux list implementation + */ +#define list_for_each_entry_safe_t(entry, safe, head, type, member) \ + for (entry = list_entry((head)->next, type, member), \ + safe = list_entry(entry->member.next, type, member); \ + &entry->member != (head); \ + entry = safe, \ + safe = list_entry(safe->member.next, type, member)) + +/** + * list_for_each_entry_safe - iterate over list entries and allow deletes + * @entry: pointer used as iterator + * @safe: @type pointer used to store info for next entry in list + * @head: pointer to the head of the list + * @member: name of the list_head member variable in struct type of @entry + * + * The current node (iterator) is allowed to be removed from the list. Any + * other modifications to the the list will cause undefined behavior. + */ +#define list_for_each_entry_safe(entry, safe, head, member) \ + list_for_each_entry_safe_t(entry, safe, head, __typeof__(*entry), \ + member) + +#ifdef __cplusplus +} +#endif diff --git a/tests/invader/include/stdarg.h b/tests/invader/include/stdarg.h new file mode 100644 index 0000000000000000000000000000000000000000..7383c4ae3bf7e4134a7d7d0e7cf2328ea363b080 --- /dev/null +++ b/tests/invader/include/stdarg.h @@ -0,0 +1,8 @@ +#pragma once + +typedef __builtin_va_list va_list; + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#define va_copy(d,s) __builtin_va_copy(d,s) diff --git a/tests/invader/include/stdbits.h b/tests/invader/include/stdbits.h new file mode 100644 index 0000000000000000000000000000000000000000..298538137a5267fb77690bc66496d06380edda22 --- /dev/null +++ b/tests/invader/include/stdbits.h @@ -0,0 +1,63 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +#define clz(val) ({ \ + int result; \ + switch(sizeof(val)) { \ + case 1: result = clz8(val); break; \ + case 2: result = clz16(val); break; \ + case 4: result = clz32(val); break; \ + case 8: result = clz64(val); break; \ + } \ + result; \ +}) + +#define ctz(val) ({ \ + int result; \ + switch(sizeof(val)) { \ + case 1: result = ctz8(val); break; \ + case 2: result = ctz16(val); break; \ + case 4: result = ctz32(val); break; \ + case 8: result = ctz64(val); break; \ + } \ + result; \ +}) + +int clz8(int8_t val); +int clz16(int16_t val); +int clz32(int32_t val); +int clz64(int64_t val); + +int ctz8(int8_t val); +int ctz16(int16_t val); +int ctz32(int32_t val); +int ctz64(int64_t val); + +static inline int ispow2(uintptr_t val) +{ + return val && !(val & (val-1)); +} + +static inline uintptr_t roundpow2(uintptr_t val) +{ + val--; + val |= val >> 1; + val |= val >> 2; + val |= val >> 4; + val |= val >> 8; + val |= val >> 16; +#if __SIZE_WIDTH__ == 64 + val |= val >> 32; +#endif + val++; + return val; +} + +#ifdef __cplusplus +} +#endif diff --git a/tests/invader/include/stddef.h b/tests/invader/include/stddef.h new file mode 100644 index 0000000000000000000000000000000000000000..3799f2a275a271442783bbc91e82a0caf24630dd --- /dev/null +++ b/tests/invader/include/stddef.h @@ -0,0 +1,8 @@ +#pragma once + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __SIZE_TYPE__ size_t; +typedef __WCHAR_TYPE__ wchar_t; + +#define NULL 0L +#define offsetof(type, member) __builtin_offsetof(type, member) diff --git a/tests/invader/include/stdint.h b/tests/invader/include/stdint.h new file mode 100644 index 0000000000000000000000000000000000000000..bef5c2f2ed13727244f26a9b883e040a51c01534 --- /dev/null +++ b/tests/invader/include/stdint.h @@ -0,0 +1,52 @@ +#pragma once + +typedef __INT8_TYPE__ int8_t; +typedef __INT16_TYPE__ int16_t; +typedef __INT32_TYPE__ int32_t; +typedef __INT64_TYPE__ int64_t; + +typedef __INT_FAST8_TYPE__ int_fast8_t; +typedef __INT_FAST16_TYPE__ int_fast16_t; +typedef __INT_FAST32_TYPE__ int_fast32_t; +typedef __INT_FAST64_TYPE__ int_fast64_t; + +typedef __INT_LEAST16_TYPE__ int_least16_t; +typedef __INT_LEAST32_TYPE__ int_least32_t; +typedef __INT_LEAST64_TYPE__ int_least64_t; +typedef __INT_LEAST8_TYPE__ int_least8_t; + +typedef __INTMAX_TYPE__ intmax_t; +typedef __INTPTR_TYPE__ intptr_t; + +typedef __UINT8_TYPE__ uint8_t; +typedef __UINT16_TYPE__ uint16_t; +typedef __UINT32_TYPE__ uint32_t; +typedef __UINT64_TYPE__ uint64_t; + +typedef __UINT_FAST8_TYPE__ uint_fast8_t; +typedef __UINT_FAST16_TYPE__ uint_fast16_t; +typedef __UINT_FAST32_TYPE__ uint_fast32_t; +typedef __UINT_FAST64_TYPE__ uint_fast64_t; + +typedef __UINT_LEAST8_TYPE__ uint_least8_t; +typedef __UINT_LEAST16_TYPE__ uint_least16_t; +typedef __UINT_LEAST32_TYPE__ uint_least32_t; +typedef __UINT_LEAST64_TYPE__ uint_least64_t; + +typedef __UINTMAX_TYPE__ uintmax_t; +typedef __UINTPTR_TYPE__ uintptr_t; + +#define INT8_MAX __INT8_MAX__ +#define INT16_MAX __INT16_MAX__ +#define INT32_MAX __INT32_MAX__ +#define INT64_MAX __INT64_MAX__ + +#define UINT8_MAX __UINT8_MAX__ +#define UINT16_MAX __UINT16_MAX__ +#define UINT32_MAX __UINT32_MAX__ +#define UINT64_MAX __UINT64_MAX__ + +#define INTPTR_MAX __INTPTR_MAX__ +#define UINTPTR_MAX __UINTPTR_MAX__ +#define PTRDIFF_MAX __PTRDIFF_MAX__ +#define SIZE_MAX __SIZE_MAX__ diff --git a/tests/invader/include/stdio.h b/tests/invader/include/stdio.h new file mode 100644 index 0000000000000000000000000000000000000000..f97e6e14d655647a57e6bb310b4c9834207e05ef --- /dev/null +++ b/tests/invader/include/stdio.h @@ -0,0 +1,20 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdarg.h> +#include <stddef.h> + +int getchar(void); +int printf(const char *, ...); +int putchar(int); +int puts(const char *); +int snprintf(char *, size_t, const char *, ...); +int vprintf(const char *, va_list); +int vsnprintf(char *, size_t, const char *, va_list); + +#ifdef __cplusplus +} +#endif diff --git a/tests/invader/include/stdlib.h b/tests/invader/include/stdlib.h new file mode 100644 index 0000000000000000000000000000000000000000..7552a1c4cf5440d09c2bbda02506a65e879d4bd6 --- /dev/null +++ b/tests/invader/include/stdlib.h @@ -0,0 +1,17 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> + +__attribute__((noreturn)) void abort(void); +__attribute__((noreturn)) void exit(int status); +void* malloc(size_t size); +void free(void* ptr); +void _malloc_addblock(void* addr, size_t size); + +#ifdef __cplusplus +} +#endif diff --git a/tests/invader/include/string.h b/tests/invader/include/string.h new file mode 100644 index 0000000000000000000000000000000000000000..6572d23e59556b519a1299091766d44d50737bd7 --- /dev/null +++ b/tests/invader/include/string.h @@ -0,0 +1,21 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> + +void *memchr(const void *s, int c, size_t n); +int memcmp(const void *, const void *, size_t); +void *memcpy(void *, const void *, size_t); +void *memset(void *, int, size_t); +char *strchr(const char *s, int c); +int strcmp(const char *, const char *); +size_t strlen(const char *); +int strncmp(const char *, const char *, size_t); +char *strncpy(char *, const char *, size_t); + +#ifdef __cplusplus +} +#endif diff --git a/tests/invader/invader.e b/tests/invader/invader.e new file mode 100644 index 0000000000000000000000000000000000000000..cf0fbb4dac7d64f2df35a81f42ac1bf304b57664 --- /dev/null +++ b/tests/invader/invader.e @@ -0,0 +1,475 @@ +int push_button_get(); +void timer_set_and_wait(int period, int time); +void clear_screen(int color); +int read_pixel(int x, int y, int scale); +void write_pixel_scaling(int pixel, int x, int y, int scale); +void set_bg_color(int color); +void set_fg_color(int color); +void set_display_cur_pos(int x, int y); +void display_string(char *msg); +void set_display_scale(int s); +int scale = 4; +int TIMER_FREQ = 10000000; + +void dirty_exit(){ + int x; + *(&x+1000000000) = 42; +} + +/* Etats */ + +struct etat { + int dx; + int dy; + int etat_suivant; +}; + +struct etat etats[5]; + +void init_etat(int index, int dx, int dy, int next){ + (etats[index]).dx = dx; + (etats[index]).dy = dy; + (etats[index]).etat_suivant = next; +} + +/* Objets */ + +struct Object { + int alive; + int period; + int deadline; + int x; + int y; + int dx; + int dy; + char *pattern; + int color; + int bg[64]; /* background */ + int ax; + int ay; +}; + +struct Object object[7]; + +int NOBJ = 7; + +void init_object(int index, int alive, int period, int deadline, + int x, int y, int dx, int dy, char* pattern, int color){ + (object[index]).alive = alive; + (object[index]).period = period; + (object[index]).deadline = deadline; + (object[index]).x = x; + (object[index]).y = y; + (object[index]).dx = dx; + (object[index]).dy = dy; + (object[index]).pattern = pattern; + (object[index]).color = color; +} + +/* Sprites */ + +char sprite_sship[8]; +char sprite_laser[8]; +char sprite_alien1[8]; +char sprite_alien2[8]; +char sprite_alien3[8]; +char sprite_alien4[8]; +char sprite_alien5[8]; + +void init_sprite(char* t, char a0, char a1, char a2, char a3, + char a4, char a5, char a6, char a7){ + t[0] = a0; + t[1] = a1; + t[2] = a2; + t[3] = a3; + t[4] = a4; + t[5] = a5; + t[6] = a6; + t[7] = a7; +} + +void initialize() +{ + int i; + int dx; + int dy; + clear_screen(0x333333); + i = 0; + while(i < NOBJ) { + if (i == 1) { + /* laser */ + (object[i]).alive = 0; + (object[i]).period = 1; + } else { + /* spaceship or aliens */ + (object[i]).alive = 1; + if (i == 0){ + /* spaceship */ + (object[i]).period = 3; + } + else{ + /* aliens */ + (object[i]).period = 4; + } + } + (object[i]).deadline = 1; + if (i > 1) { + /* aliens */ + if (i > 4) { + /* alien4 or alien5 */ + (object[i]).y = 3; /* 3rd line */ + (object[i]).x = 6 + (i - 4) * 8 ; + } else { + + /* alien1, alien2 or alien3 */ + (object[i]).y = 1; /* 1st line */ + (object[i]).x = 10 + (i - 2) * 8; + } + (object[i]).dx = -1; + (object[i]).dy = 0; + } + (object[i]).ax = -1; + (object[i]).ay = -1; + + /* initialization of object background considering the last one */ + int* ptr = (object[i]).bg; + dx = 0; + while (dx < 8){ + dy = 0; + while (dy < 8){ + int p = read_pixel((((object[i]).x) * 8) + dx, + (((object[i]).y) * 8) + dy, scale); + ptr[dx*8+dy] = p; + dy = dy + 1; + } + dx = dx + 1; + } + i = i + 1; + } +} + +/* function to display the 8 pixels of a pattern line */ +void display_pattern_line(int m, int x, int y, int color) +{ + int i = 0; + + while (i < 8){ + if ((m & 1) == 1){ + write_pixel_scaling(color, x + i, y, scale); + } + m = m / 2; + i = i + 1; + } +} + +/* function to display an 8x8 object considering the last background */ +void display_pattern(char* pattern, int x, int y, int color) +{ + int i = 0; + + while(i < 8){ + display_pattern_line(pattern[i], x, y + i, color); + i = i + 1; + } +} + +/* function to display an 8x8 object (spaceship, laser or alien) */ +void display_sprite(struct Object *object) +{ + int dx; int dy; + if ((object->ax > -1 && object->ay > -1) && + (object->x != object->ax || object->y != object->ay || !(*object).alive)) + { + int* ptr = object->bg; + dx = 0; + while(dx < 8) { + dy = 0; + while(dy < 8) { + write_pixel_scaling(ptr[dx*8+dy], + ((object->ax) *8) + dx, ((object->ay) *8 ) + dy, scale); + if (!object->alive){ + ptr[dx*8 + dy] = read_pixel(((object->x) *8) + dx, + ((object->y) *8) + dy, scale); + } + dy = dy + 1; + } + dx = dx + 1; + } + } + object->ax = object->x; + object->ay = object->y; + if ((*object).alive){ + display_pattern(object->pattern, (object->x) * 8, (object->y) * 8, + object->color); + } +} + +int main(int argc, char* argv) +{ + /* declaration of local variables */ + int i; + int dx; + int dy; + int push_state; + int alien_state; + int edge_reached; + int n_aliens; + struct Object *spaceship; + struct Object *laser; + + init_etat(0, 0, 1, 1); + init_etat(1, 0, 1, 2); + init_etat(2, 1, 0, 3); + init_etat(3, 0, 1, 4); + init_etat(4, -1, 0, 1); + + init_sprite(sprite_sship, 0x00, 0x3c, 0x7e, 0xff, 0xff, 0xe7, 0xc3, 0xc3); + init_sprite(sprite_laser, 231, 231, 255, 255, 126, 60, 24, 24); + init_sprite(sprite_alien1, 0xc3, 0x3c, 0x5a, 0xff, 0xff, 0x81, 0x42, 0x24); + init_sprite(sprite_alien2, 0xc3, 0x3c, 0x5a, 0xff, 0xff, 0xa5, 0xa5, 0x5a); + init_sprite(sprite_alien3, 0x42, 0x24, 0x3c, 0x5a, 0xff, 0xbd, 0x81, 0x42); + init_sprite(sprite_alien4, 0x81, 0x42, 0x3c, 0x5a, 0x5a, 0x3c, 0x42, 0x81); + init_sprite(sprite_alien5, 0x41, 0x22, 0x3e, 0x6b, 0x49, 0x7f, 0x3e, 0x55); + /* + 0x41 .#....#. + 0x22 ..#...#. + 0x3e ..#####. + 0x6b .##.#.## + 0x49 .#..#..# + 0x7f .####### + 0x3e ..#####. + 0x55 .#.#.#.# + */ + init_object(0, 1, 3, 1, 18, 32, 0, 0, sprite_sship, 0x0000FF); /* blue spaceship */ + init_object(1, 0, 1, 1, 18, 0, 0, 0, sprite_laser, 0xffc0cb); /* white laser */ + init_object(2, 1, 4, 1, 10, 1, -1, 0, sprite_alien1, 0x00FF00); /* green alien */ + init_object(3, 1, 4, 1, 18, 1, -1, 0, sprite_alien2, 0xFF0000); /* red alien */ + init_object(4, 1, 4, 1, 26, 1, -1, 0, sprite_alien3, 0xFF00FF); /* magenta alien */ + init_object(5, 1, 4, 1, 14, 3, -1, 0, sprite_alien4, 0xFFFF00); /* yellow alien */ + init_object(6, 1, 4, 1, 22, 3, -1, 0, sprite_alien5, 0x00FFFF); /* cyan alien */ + + /* initialization stage */ + push_state = 0; /* no button pressed at beginning */ + alien_state = 0; /* state of alien in a line */ + edge_reached = 0; /* no edge reached at beginning */ + n_aliens = NOBJ - 2; /* number of displayed aliens */ + spaceship = object; /* spaceship is the first declared object */ + laser = object + 1; /* laser is the second declared object */ + + + + clear_screen(0xcccccc); + set_display_scale(8); + set_bg_color(0xcccccc); + set_fg_color(0x000000); + int started = 0; + while(!started){ + char msg[60]; + i = 0; + msg[i] = 'P'; i = i + 1; + msg[i] = 'o'; i = i + 1; + msg[i] = 'u'; i = i + 1; + msg[i] = 'r'; i = i + 1; + msg[i] = ' '; i = i + 1; + msg[i] = 'c'; i = i + 1; + msg[i] = 'o'; i = i + 1; + msg[i] = 'm'; i = i + 1; + msg[i] = 'm'; i = i + 1; + msg[i] = 'e'; i = i + 1; + msg[i] = 'n'; i = i + 1; + msg[i] = 'c'; i = i + 1; + msg[i] = 'e'; i = i + 1; + msg[i] = 'r'; i = i + 1; + msg[i] = ','; i = i + 1; + msg[i] = ' '; i = i + 1; + msg[i] = 'a'; i = i + 1; + msg[i] = 'p'; i = i + 1; + msg[i] = 'p'; i = i + 1; + msg[i] = 'u'; i = i + 1; + msg[i] = 'y'; i = i + 1; + msg[i] = 'e'; i = i + 1; + msg[i] = 'z'; i = i + 1; + msg[i] = ' '; i = i + 1; + msg[i] = 's'; i = i + 1; + msg[i] = 'u'; i = i + 1; + msg[i] = 'r'; i = i + 1; + msg[i] = ' '; i = i + 1; + msg[i] = 'H'; i = i + 1; + msg[i] = 'A'; i = i + 1; + msg[i] = 'U'; i = i + 1; + msg[i] = 'T'; i = i + 1; + msg[i] = '\n'; i = i + 1; + msg[i] = '\n'; i = i + 1; + msg[i] = 'P'; i = i + 1; + msg[i] = 'o'; i = i + 1; + msg[i] = 'u'; i = i + 1; + msg[i] = 'r'; i = i + 1; + msg[i] = ' '; i = i + 1; + msg[i] = 'q'; i = i + 1; + msg[i] = 'u'; i = i + 1; + msg[i] = 'i'; i = i + 1; + msg[i] = 't'; i = i + 1; + msg[i] = 't'; i = i + 1; + msg[i] = 'e'; i = i + 1; + msg[i] = 'r'; i = i + 1; + msg[i] = ','; i = i + 1; + msg[i] = ' '; i = i + 1; + msg[i] = 'a'; i = i + 1; + msg[i] = 'p'; i = i + 1; + msg[i] = 'p'; i = i + 1; + msg[i] = 'u'; i = i + 1; + msg[i] = 'y'; i = i + 1; + msg[i] = 'e'; i = i + 1; + msg[i] = 'z'; i = i + 1; + msg[i] = ' '; i = i + 1; + msg[i] = 's'; i = i + 1; + msg[i] = 'u'; i = i + 1; + msg[i] = 'r'; i = i + 1; + msg[i] = ' '; i = i + 1; + msg[i] = 'B'; i = i + 1; + msg[i] = 'A'; i = i + 1; + msg[i] = 'S'; i = i + 1; + msg[i] = 0; i = i + 1; + + + set_display_cur_pos(10,10); + display_string(msg); + + push_state = push_button_get(); + if (push_state & 0x4) { + started = 1; + } + if (push_state & 0x8) { + dirty_exit(); + } + } + + clear_screen(0x333333); + + initialize(); + + /* display stage */ + while(1==1) { + edge_reached=0; + + /* decrease deadline of alive objects */ + i = 0; + while (i < NOBJ) { + if ((object[i]).alive == 1){ + (object[i]).deadline = (object[i]).deadline - 1; + } + i = i + 1; + } + + /* display all alive objects */ + i = 0; + while (i < NOBJ) { + if ((object[i]).alive == 1){ + display_sprite(object + i); + } + i = i + 1; + } + + /* determine new positions of all alive objects */ + i = 0; + while(i < NOBJ) { + /* update object state when deadline is reached */ + if ((object[i]).alive == 1 && (object[i]).deadline == 0) { + /* reinitialize the object deadline to period */ + (object[i]).deadline = (object[i]).period; + /* determine new position and manage screen edges */ + (object[i]).x = (object[i]).x + (object[i]).dx; + if ((object[i]).x < 0){ + (object[i]).x = 0; + } + if ((object[i]).x > 59){ + (object[i]).x = 59; + } + (object[i]).y = (object[i]).y + (object[i]).dy; + /* test if an edge of the screen was reached by an alien */ + if (i >= 2 && ((object[i]).x == 0 || (object[i]).x == 59)){ + edge_reached = 1; + } + if (i > 1 && (object[i]).y >= spaceship->y){ + // PERDU + clear_screen(0x0000FF); /* blue screen */ + timer_set_and_wait(TIMER_FREQ, 1000); + dirty_exit(); + } + } + i = i + 1; + } + /* test if alien is hit by an alive laser */ + if (laser->alive) { + i = 2; + while(i < NOBJ) { + if ((object[i]).alive && !((laser->x > (object[i]).x + 1) || (laser->x + 1 < (object[i]).x)) && + (laser->y) == (object[i]).y) { + n_aliens = n_aliens - 1; + (object[i]).alive = 0; + laser->alive = 0; + if (n_aliens == 0) { + /* no more aliens */ + spaceship->alive = 0; + clear_screen(0xFF00); /* yellow screen */ + timer_set_and_wait(TIMER_FREQ, 1000); + push_state = 0; /* no button pressed at beginning */ + alien_state = 0; /* state of alien in a line */ + edge_reached = 0; /* no edge reached at beginning */ + n_aliens = NOBJ - 2; /* number of displayed aliens */ + spaceship = object; /* spaceship is the first declared object */ + laser = object + 1; /* laser is the second declared object */ + initialize(); + } else { + display_sprite(object + i); + display_sprite(laser); + } + } + i = i + 1; + } + } + /* when an alien reaches a screen edge, the group of aliens is moved */ + if (edge_reached) { + i = 2; + while (i < NOBJ) { + (object[i]).dx = (etats[alien_state]).dx; + (object[i]).dy = (etats[alien_state]).dy; + i = i + 1; + } + alien_state = (etats[alien_state]).etat_suivant; + } + /* laser disappears when it reaches the screen top */ + if (laser->alive && laser->y == 0) { + laser->alive = 0; + display_sprite(laser); + } + /* manage push buttons */ + push_state = push_button_get(); + + if ( (spaceship->deadline == 1) + || (n_aliens == 0)) { + spaceship->dx = 0; + if (push_state & 0x1) { // right + spaceship->dx = 1; + } + if (push_state & 0x2){ // left + spaceship->dx = -1; + } + if (push_state & 0x4) { // fire + if (!laser->alive) { + laser->alive = 1; + laser->dx = 0; + laser->dy = -1; + laser->x = spaceship->x; + laser->y = spaceship->y - 1; + laser->deadline = laser->period; + } + } + if (push_state & 0x8) { + dirty_exit(); + } + } + + timer_set_and_wait(TIMER_FREQ, 4); + } +} diff --git a/tests/invader/itoa.c b/tests/invader/itoa.c new file mode 100644 index 0000000000000000000000000000000000000000..e172978434ea4bd52d4138baa98d45495b83273e --- /dev/null +++ b/tests/invader/itoa.c @@ -0,0 +1,34 @@ +#include<stdio.h> + +char * itoa(signed int i, char* buf){ + char *s = buf + 10; + *s = '\0'; + char neg = 0; + if (i < 0) { + neg = 1; + i = - i; + } + if (i == 0){ + *--s = '0'; + return s; + } + while(i > 0){ + + *--s = (i % 10) + '0'; + i = i / 10; + } + if (neg){ + *--s = '-'; + } + return s; +} + +/* int main(){ */ +/* char buf[20] = "abcdefghijklmnopqrst"; */ +/* printf("itoa(-23467) = %s\n", itoa(-23467,buf)); */ +/* printf("itoa(1238) = %s\n", itoa(1238,buf)); */ +/* printf("itoa(0) = %s\n", itoa(0,buf)); */ +/* printf("itoa(-0) = %s\n", itoa(-0,buf)); */ + +/* return 0; */ +/* } */ diff --git a/tests/invader/libfemto.a b/tests/invader/libfemto.a new file mode 100644 index 0000000000000000000000000000000000000000..b444d6e284575d5cd280a9d8048f56eb1e91f985 Binary files /dev/null and b/tests/invader/libfemto.a differ diff --git a/tests/invader/libscreen.c b/tests/invader/libscreen.c new file mode 100644 index 0000000000000000000000000000000000000000..a0defd7b546ad0dd18590d419391e9266a7bbeac --- /dev/null +++ b/tests/invader/libscreen.c @@ -0,0 +1,218 @@ +#include "femto.h" +#include "libscreen.h" +#include "cep_platform.h" + +typedef unsigned int uint; + +volatile uint* IMG = (volatile uint*) 0x80000000; +volatile uint *push = (volatile uint *)0x30000008; +volatile uint* led = (volatile uint *)REG_LEDS_ADDR; +volatile uint *timer = (volatile uint *)CLINT_TIMER; +volatile uint *timer_hi = (volatile uint *)CLINT_TIMER_HI; +volatile uint *timer_lo = (volatile uint *)CLINT_TIMER_LOW; +volatile uint *timer_cmp = (volatile uint *)CLINT_TIMER_CMP; +volatile uint *timer_cmp_hi = (volatile uint *)CLINT_TIMER_CMP_HI; +volatile uint *timer_cmp_lo = (volatile uint *)CLINT_TIMER_CMP_LO; + + + +/* function to get the state of push buttons */ +uint push_button_get(void) +{ + uint v = (*push) >> 16; + //printf("push_button_get: @ %p, v = %x, %x\n", push, *push, v); + return v; +} + + +/* function to set the value displayed on leds */ +void led_set(uint value) +{ + + *led = value; +} + +/* function to set the timer to be reached in period*time/100 in the future */ +void timer_set(uint period, uint time) +{ + uint now = *timer; + *timer_cmp = now + ((uint)period/RATIO * time); +} + +/* function to wait for timer zero value */ +void timer_wait(void) +{ + while(*timer <= *timer_cmp); +} + +void timer_set_and_wait(uint period, uint time) +{ + timer_set(period, time); + timer_wait(); +} + +void draw(uint color, uint x, uint y){ + uint pos = (y * NBCOL + x); + if (pos < 1920 * 1080){ + *(IMG + pos) = color; + } +} + +void clear_screen(uint color){ + for(uint j = 0; j < NBROW; j++){ + for(uint i = 0; i < NBCOL; i++){ + draw(color, i, j); + } + } +} + +void draw_bitmap(char* bitmap){ + + for(uint j = 0; j < 8; j++){ + for(uint i = 0; i < 8; i++){ + uint set = (bitmap[j] & (1 << i)) >> i; + //draw pixel bitmap[j][i] + for(uint jy = 0; jy < display_scale; jy++){ + for(uint ix = 0; ix < display_scale; ix++){ + uint realx = display_cur_x + i * display_scale + ix; + uint realy = display_cur_y + j * display_scale + jy; + /* pruintf("Writing at %d, %d, color = %x\n", realx, realy, color); */ + if(set){ + draw(fgcolor, realx, realy); + } + else{ + draw(bgcolor, realx, realy); + } + } + } + } + } +} + +extern char* itoa(uint, char*); + +void newline(){ + display_cur_x = 0; + display_cur_y += display_scale*10; +} +void tab(){ + display_cur_x += display_scale*8*4; +} + +/* Counts the number of characters of current word. Will be used to break lines, if possible not in the middle of words. */ +uint num_characters_until_white(char* str){ + uint i = 0; + char c; + while(c = *str++){ + if (c == ' ' || c == '\t' || c == '\n'){ + return i; + } + if (c == '.' || c == ','){ + return i + 1; + } + i++; + } + return i; +} + + + +void display_string(char* str){ + while(*str){ + uint n = num_characters_until_white(str) + 1; + // If there's not enough space on current line for whole current word, newline + if (display_cur_x + (n-1) * display_scale * 8 > 1920){ + newline(); + } + for(uint i = 0; i < n; i++){ + char c = str[i]; + if(c == '\n'){ + newline(); + } else if (c == '\t'){ + tab(); + } else { + draw_bitmap(font8x8_basic[c]); + display_cur_x+=display_scale*8; + } + // Still, if the next character wouldn't fit on the screen, break in the middle of the word. + if (display_cur_x + display_scale * 8 > 1920){ + newline(); + } + } + str = str + n; + } +} + +void display_uint(uint i){ + char buf[10], *bu; + bu = itoa(i, buf); + display_string(bu); +} + +void set_display_scale(int s){ + display_scale = s; +} +void set_display_cur_pos(int x, int y){ + display_cur_x = x; + display_cur_y = y; +} + + +void set_fg_color(uint color){ + fgcolor = color; +} +void set_bg_color(uint color){ + bgcolor = color; +} + + + +/* function to read a pixel from a (x,y) position of video framebuffer */ +uint read_pixel(uint x, uint y, uint scale) +{ + // #SCALING + //return IMG[y * DISPLAY_WIDTH + x]; + const uint pos = y * scale * NBCOL + x * scale; + if (pos < 1920*1080) + return IMG[pos]; + return -1; +} + +/* function to write a pixel in a (x,y) position of video framebuffer */ +void write_pixel(uint pixel, uint x, uint y) +{ + const uint pos = y * NBCOL + x; + if (pos < 1920*1080) + IMG[pos] = pixel; +} + +void write_pixel_scaling(uint pixel, uint x, uint y, uint scale) +{ + uint i, j; + for (i = 0; i < scale; ++i) { + for (j = 0; j < scale; ++j) { + const uint real_y = (y * scale + i); + const uint real_x = x * scale + j; + + write_pixel(pixel, real_x, real_y); + } + } + +} + +void show_pos ( int i, int x, int y){ + /* printf("show_pos %d: @ %p, v = %x\n",x, ptr, *(int*)(ptr+20)); */ + /* printf("alive = %x\n", *(int*)(ptr+ 0 )); */ + /* printf("period = %x\n", *(int*)(ptr+ 4 )); */ + /* printf("deadline = %x\n", *(int*)(ptr+ 8 )); */ + /* printf("x = %x\n", *(int*)(ptr+ 12 )); */ + /* printf("y = %x\n", *(int*)(ptr+ 16 )); */ + /* printf("dx = %x\n", *(int*)(ptr+ 20 )); */ + /* printf("dy = %x\n", *(int*)(ptr+ 24 )); */ + /* int i; */ + /* asm("\t mv %0, sp" : "=r"(i)); */ + /* printf("sp = %x\n", i); */ + /* asm("\t mv %0, s0" : "=r"(i)); */ + /* printf("s0 = %x\n", i); */ + printf("i = %d, x = %d; y = %d\n",i, x,y); +} diff --git a/tests/invader/macros.s b/tests/invader/macros.s new file mode 100644 index 0000000000000000000000000000000000000000..d987d0c1ec596dc45e95cbf0e7a9c69d5ff614b9 --- /dev/null +++ b/tests/invader/macros.s @@ -0,0 +1,23 @@ +# See LICENSE for license details. + +.equ REGBYTES, 4 + +.macro lx a, b +lw \a, \b +.endm + +.macro sx a, b +sw \a, \b +.endm + +.macro lxsp a, b +lw \a, ((\b)*REGBYTES)(sp) +.endm + +.macro sxsp a, b +sw \a, ((\b)*REGBYTES)(sp) +.endm + +.macro .ptr a +.4byte \a +.endm diff --git a/tests/invader/setup.c b/tests/invader/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..8a684ad365780ff73c6df52c38cc3c7a1d0c1412 --- /dev/null +++ b/tests/invader/setup.c @@ -0,0 +1,19 @@ +// See LICENSE for license details. + +#include "femto.h" + +auxval_t __auxv[] = { + { UART0_CLOCK_FREQ, 32000000 }, + { UART0_BAUD_RATE, 115200 }, + { SIFIVE_UART0_CTRL_ADDR, 0x10013000 }, + { SIFIVE_TEST_CTRL_ADDR, 0x100000 }, + { 0, 0 } +}; + +void arch_setup() +{ +#if defined(ENV_QEMU) + register_console(&console_sifive_uart); + register_poweroff(&poweroff_sifive_test); +#endif +}