Refactor tests
This commit is contained in:
15
bench/programs/chenillard_minimaliste.s
Normal file
15
bench/programs/chenillard_minimaliste.s
Normal file
@@ -0,0 +1,15 @@
|
||||
.text
|
||||
ori x1, x0, 21
|
||||
ori x2, x0, 1
|
||||
addi x3, x3, 1 #Itérateur. Ne fonctionne que sur carte car x3 ne sera pas initialisé à 0 en simu.
|
||||
srl x4, x3, x1 # Compteur tous les 2 million d'itérations environ (fréquence à l'Hertz)
|
||||
and x4, x4, x2
|
||||
xor x5, x4, x6 # détection de front (x6 étant la valeur précédente de x4)
|
||||
or x6, x0, x4 # Sauvegarde de la valeur précédente
|
||||
# Le motif à afficher est dans x7.
|
||||
# On le décale de x5 (0 ou 1) position vers la gauche
|
||||
sll x7, x7, x5
|
||||
ori x7, x7, 1
|
||||
or x31, x0, x7
|
||||
# Via l'instruction de garde que rajoute l'assembleur, on réinitialise PC.
|
||||
# Donc on reboucle sur la première instruction.
|
||||
23
bench/programs/chenillard_rotation.s
Normal file
23
bench/programs/chenillard_rotation.s
Normal file
@@ -0,0 +1,23 @@
|
||||
.text
|
||||
# Le motif du chenillard (2 bits consécutifs) est mis dans x1
|
||||
# Le chenillard est sur 4 LED
|
||||
ori x1, x0, 0x3
|
||||
|
||||
boucle_infinie:
|
||||
# Durée d'attente dépend de la fréquence
|
||||
li x2, 10000000
|
||||
|
||||
boucle_attente:
|
||||
addi x2, x2, -1
|
||||
bne x2, x0, boucle_attente
|
||||
# On affiche le motif
|
||||
ori x31, x1, 0
|
||||
# On décale le motif
|
||||
sll x1, x1, 1
|
||||
# On cherche un dépassement en dehors des 4 LED
|
||||
andi x2, x1, 0x10
|
||||
beq x2, x0, boucle_infinie
|
||||
# En cas de changement, on ramène la LED qui sort sur la première LED
|
||||
andi x1, x1, 0xf
|
||||
ori x1, x1, 0x1
|
||||
j boucle_infinie
|
||||
38
bench/programs/fmnsoc.h
Normal file
38
bench/programs/fmnsoc.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef __FMNSOC_H__
|
||||
#define __FMNSOC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Leds et boutons
|
||||
// Même adresse, leds en écriture, boutons en lecture
|
||||
#define LED_LEDS 0x30000000
|
||||
#define LED_PUSHBUTTONS 0x30000000
|
||||
|
||||
// Vga sans configuration possible
|
||||
#define FRAMEBUFFER 0x80000000
|
||||
|
||||
// CLint pour le timer
|
||||
#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
|
||||
|
||||
// Vga 320x200, 8 bits par pixels
|
||||
#define DISPLAY_WIDTH 320
|
||||
#define DISPLAY_HEIGHT 240
|
||||
#define DISPLAY_SIZE (DISPLAY_WIDTH * DISPLAY_HEIGHT)
|
||||
#define DISPLAY_SCALE 1
|
||||
|
||||
#define TIMER_FREQ 10000000 // 10MHz
|
||||
#define TIMER_RATIO 200
|
||||
|
||||
void timer_set(uint32_t period, uint32_t start_value);
|
||||
void timer_wait(void);
|
||||
void timer_set_and_wait(uint32_t period, uint32_t time);
|
||||
void led_set(uint32_t value);
|
||||
uint32_t push_button_get();
|
||||
|
||||
#endif // __FMNSOC_H__
|
||||
438
bench/programs/invaders.c
Normal file
438
bench/programs/invaders.c
Normal file
@@ -0,0 +1,438 @@
|
||||
#include "fmnsoc.h"
|
||||
#include "invaders.h"
|
||||
#define N_OBJECTS 7
|
||||
|
||||
/*
|
||||
* Definition of bitmap for each line in the 8x8 pattern
|
||||
*
|
||||
* Since we have a word addressable bitmap, we need to reorder the patterns
|
||||
* so that they display correctly.
|
||||
* We do that in the definitions to avoid run time penalties.
|
||||
*/
|
||||
#define R(x) (((x & 0xf0) >> 4) | ((x & 0x0f) << 4))
|
||||
static uint8_t sprite_sship[8] = {
|
||||
R(0b00000000),
|
||||
R(0b00111100),
|
||||
R(0b01111110),
|
||||
R(0b11111111),
|
||||
R(0b11111111),
|
||||
R(0b11100111),
|
||||
R(0b11000011),
|
||||
R(0b11000011),
|
||||
};
|
||||
static uint8_t sprite_laser[8] = {
|
||||
R(0b00011000),
|
||||
R(0b00011000),
|
||||
R(0b00011000),
|
||||
R(0b00011000),
|
||||
R(0b00011000),
|
||||
R(0b00011000),
|
||||
R(0b00011000),
|
||||
R(0b00011000),
|
||||
};
|
||||
static uint8_t sprite_alien1[8] = {
|
||||
R(0b11000011),
|
||||
R(0b00111100),
|
||||
R(0b01011010),
|
||||
R(0b11111111),
|
||||
R(0b11111111),
|
||||
R(0b10000001),
|
||||
R(0b01000010),
|
||||
R(0b00100100),
|
||||
};
|
||||
static uint8_t sprite_alien2[8] = {
|
||||
R(0b11000011),
|
||||
R(0b00111100),
|
||||
R(0b01011010),
|
||||
R(0b11111111),
|
||||
R(0b11111111),
|
||||
R(0b10100101),
|
||||
R(0b10100101),
|
||||
R(0b01011010),
|
||||
};
|
||||
static uint8_t sprite_alien3[8] = {
|
||||
R(0b01000010),
|
||||
R(0b00100100),
|
||||
R(0b00111100),
|
||||
R(0b01011010),
|
||||
R(0b11111111),
|
||||
R(0b10111101),
|
||||
R(0b10000001),
|
||||
R(0b01000010),
|
||||
};
|
||||
static uint8_t sprite_alien4[8] = {
|
||||
R(0b11000011),
|
||||
R(0b00100100),
|
||||
R(0b10111101),
|
||||
R(0b11100111),
|
||||
R(0b00111100),
|
||||
R(0b00100100),
|
||||
R(0b01011010),
|
||||
R(0b10011001),
|
||||
};
|
||||
static uint8_t sprite_alien5[8] = {
|
||||
R(0b01100110),
|
||||
R(0b01111110),
|
||||
R(0b11011011),
|
||||
R(0b01111110),
|
||||
R(0b10111101),
|
||||
R(0b10100101),
|
||||
R(0b10000001),
|
||||
R(0b01100110),
|
||||
};
|
||||
// bleu, vert, rouge pour tenir dans l'uint8_t de color_t comme il faut
|
||||
static const color_t black = {0, 0, 0};
|
||||
static const color_t white = {7, 7, 3};
|
||||
static const color_t red = {0, 0, 3};
|
||||
static const color_t green = {0, 7, 0};
|
||||
static const color_t blue = {7, 0, 0};
|
||||
static const color_t magenta = {7, 0, 3};
|
||||
static const color_t cyan = {7, 7, 1};
|
||||
static const color_t yellow = {0, 7, 3};
|
||||
|
||||
/* sprite objects */
|
||||
object_t object[N_OBJECTS] = {
|
||||
/* blue spaceship */
|
||||
{1, 3, 1, 18, 23, 0, 0, sprite_sship, blue, {[0 ... 7]={0}}, 0, 0},
|
||||
/* white laser */
|
||||
{0, 1, 1, 18, 0, 0, 0, sprite_laser, white, {[0 ... 7]={0}}, 0, 0},
|
||||
/* green alien */
|
||||
{1, 4, 1, 10, 0, -1, 0, sprite_alien1, green, {[0 ... 7]={0}}, 0, 0},
|
||||
/* red alien */
|
||||
{1, 4, 1, 18, 0, -1, 0, sprite_alien2, red, {[0 ... 7]={0}}, 0, 0},
|
||||
/* magenta alien */
|
||||
{1, 4, 1, 26, 0, -1, 0, sprite_alien3, magenta, {[0 ... 7]={0}}, 0, 0},
|
||||
/* yellow alien */
|
||||
{1, 4, 1, 14, 2, -1, 0, sprite_alien4, yellow, {[0 ... 7]={0}}, 0, 0},
|
||||
/* cyan alien */
|
||||
{1, 4, 1, 22, 2, -1, 0, sprite_alien5, cyan, {[0 ... 7]={0}}, 0, 0}
|
||||
};
|
||||
|
||||
/* Tableau d'états pour la mécanique du jeu */
|
||||
state_t state[5] = {
|
||||
{0, 1, 1},
|
||||
{0, 1, 2},
|
||||
{1, 0, 3},
|
||||
{0, 1, 4},
|
||||
{-1, 0, 1}
|
||||
};
|
||||
|
||||
/*
|
||||
* Deux pointeurs vers le frame buffer pour éviter les problèmes
|
||||
* d'aliasing sur les types.
|
||||
*/
|
||||
static volatile color_t *img = (volatile color_t *)FRAMEBUFFER;
|
||||
static volatile uint32_t *framebuffer = (volatile uint32_t *)FRAMEBUFFER;
|
||||
static volatile uint32_t *led = (volatile uint32_t *)LED_LEDS;
|
||||
static volatile uint32_t *push = (volatile uint32_t *)LED_PUSHBUTTONS;
|
||||
static volatile uint64_t *timer = (volatile uint64_t *)CLINT_TIMER;
|
||||
static volatile uint64_t *timer_cmp = (volatile uint64_t *)CLINT_TIMER_CMP;
|
||||
static volatile uint32_t *timer_hi = (volatile uint32_t *)CLINT_TIMER_HI;
|
||||
static volatile uint32_t *timer_lo = (volatile uint32_t *)CLINT_TIMER_LOW;
|
||||
static volatile uint32_t *timer_cmp_hi = (volatile uint32_t *)CLINT_TIMER_CMP_HI;
|
||||
static volatile uint32_t *timer_cmp_lo = (volatile uint32_t *)CLINT_TIMER_CMP_LO;
|
||||
|
||||
uint32_t mult(uint64_t x, uint64_t y)
|
||||
{
|
||||
uint64_t res = 0;
|
||||
while (y != 0) {
|
||||
if (y % 2 == 1) {
|
||||
res += x;
|
||||
}
|
||||
x <<= 1;
|
||||
y >>= 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void timer_set(uint32_t period, uint32_t time)
|
||||
{
|
||||
uint64_t now = *timer;
|
||||
*timer_cmp = now + mult(((uint64_t)period >> 8), time);
|
||||
}
|
||||
|
||||
void timer_wait(void)
|
||||
{
|
||||
while (*timer <= *timer_cmp);
|
||||
}
|
||||
|
||||
void timer_set_and_wait(uint32_t period, uint32_t time)
|
||||
{
|
||||
timer_set(period, time);
|
||||
timer_wait();
|
||||
}
|
||||
|
||||
void led_set(uint32_t value)
|
||||
{
|
||||
*led = value;
|
||||
}
|
||||
|
||||
uint32_t push_button_get()
|
||||
{
|
||||
return *push;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* main program
|
||||
* ---------------------------------------------------------------------------
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
/* declaration of local variables */
|
||||
uint32_t i;
|
||||
uint32_t push_state, led_state, alien_state, edge_reached;
|
||||
uint32_t n_aliens;
|
||||
object_t *spaceship, *laser;
|
||||
|
||||
init:
|
||||
/* initialization stage */
|
||||
push_state = 0; /* no button pressed at beginning */
|
||||
led_state = 0; /* initial value displayed on leds */
|
||||
alien_state = 0; /* state of alien in a line */
|
||||
edge_reached = 0; /* no edge reached at beginning */
|
||||
n_aliens = N_OBJECTS - 2; /* number of displayed aliens */
|
||||
initialize();
|
||||
laser = &object[1]; /* laser is the second declared object */
|
||||
spaceship = &object[0]; /* spaceship is the first declared object */
|
||||
spaceship->x = 20; /* set spaceship at the middle */
|
||||
spaceship->y = 25; /* and bottom of the screen */
|
||||
#define MAX_X 39
|
||||
|
||||
/* display stage */
|
||||
while (1) {
|
||||
edge_reached = 0;
|
||||
|
||||
/* decrease deadline of alive objects */
|
||||
for (i = 0; i < N_OBJECTS; i++) {
|
||||
if (object[i].alive)
|
||||
object[i].deadline--;
|
||||
}
|
||||
|
||||
/* display all alive objects */
|
||||
for (i = 0; i < N_OBJECTS; i++) {
|
||||
if (object[i].alive)
|
||||
display_sprite(&object[i]);
|
||||
}
|
||||
|
||||
/* determine new positions of all alive objects */
|
||||
for (i = 0; i < N_OBJECTS; i++) {
|
||||
/* update object state when deadline is reached */
|
||||
if (object[i].alive && 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].dx;
|
||||
if (object[i].x < 0)
|
||||
object[i].x = 0;
|
||||
if (object[i].x > MAX_X)
|
||||
object[i].x = MAX_X;
|
||||
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 == MAX_X))
|
||||
edge_reached = 1;
|
||||
/* store background of the next position */
|
||||
if (i > 1 && object[i].y >= spaceship->y) {
|
||||
clear_screen(blue); /* blue screen */
|
||||
timer_set_and_wait(TIMER_FREQ, 1000);
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* test if alien is hit by an alive laser */
|
||||
if (laser->alive) {
|
||||
for (i = 2; i < N_OBJECTS; i++) {
|
||||
if (object[i].alive && laser->x == object[i].x && laser->y == object[i].y) {
|
||||
n_aliens--;
|
||||
object[i].alive = 0;
|
||||
laser->alive = 0;
|
||||
if (n_aliens == 0) {
|
||||
/* no more aliens */
|
||||
spaceship->alive = 0;
|
||||
clear_screen(yellow); /* yellow screen */
|
||||
timer_set_and_wait(TIMER_FREQ, 1000);
|
||||
clear_screen(red); /* red screen */
|
||||
} else {
|
||||
display_sprite(&object[i]);
|
||||
display_sprite(laser);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* when an alien reaches a screen edge, the group of aliens is moved */
|
||||
if (edge_reached) {
|
||||
for (i = 2; i < N_OBJECTS; i++) {
|
||||
object[i].dx = state[alien_state].dx;
|
||||
object[i].dy = state[alien_state].dy;
|
||||
}
|
||||
alien_state = state[alien_state].next_state;
|
||||
}
|
||||
|
||||
/* 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 we won, press fire to restart
|
||||
if ((n_aliens == 0)
|
||||
&& (push_state & 0x4)) {
|
||||
goto init;
|
||||
}
|
||||
if ((spaceship->deadline == 1)
|
||||
|| (n_aliens == 0)) {
|
||||
spaceship->dx = 0;
|
||||
if (push_state & 0x1)
|
||||
/* to the right */
|
||||
spaceship->dx = 1;
|
||||
if (push_state & 0x2)
|
||||
/* to the left */
|
||||
spaceship->dx = -1;
|
||||
if (push_state & 0x4) {
|
||||
/* fire a laser */
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* manage leds' state */
|
||||
led_set(led_state);
|
||||
led_state++;
|
||||
timer_set_and_wait(TIMER_FREQ, 4);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* definition of functions
|
||||
* ---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* function to read a pixel from a (x,y) position of video framebuffer */
|
||||
color_t read_pixel(uint32_t x, uint32_t y)
|
||||
{
|
||||
uint32_t real_y = y * DISPLAY_WIDTH * DISPLAY_SCALE;
|
||||
uint32_t real_x = x * DISPLAY_SCALE;
|
||||
return img[real_y + real_x];
|
||||
}
|
||||
|
||||
void write_pixel_scaling(color_t pixel, uint32_t x, uint32_t y)
|
||||
{
|
||||
for (int i = 0; i < DISPLAY_SCALE; ++i) {
|
||||
for (int j = 0; j < DISPLAY_SCALE; ++j) {
|
||||
uint32_t real_y = y * DISPLAY_SCALE + i;
|
||||
uint32_t real_x = x * DISPLAY_SCALE + j;
|
||||
|
||||
img[real_y * DISPLAY_WIDTH + real_x] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void memsetw(volatile uint32_t* dest, uint32_t c, uint32_t n)
|
||||
{
|
||||
volatile uint32_t *p = dest;
|
||||
while (n-- > 0) {
|
||||
*(volatile uint32_t *)dest++ = c;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_screen(color_t color)
|
||||
{
|
||||
pixels_t p;
|
||||
p.pixel[0] = color;
|
||||
p.pixel[1] = color;
|
||||
p.pixel[2] = color;
|
||||
p.pixel[3] = color;
|
||||
memsetw(framebuffer, p.pixels, DISPLAY_SIZE / 4);
|
||||
}
|
||||
|
||||
/* function to initialize all objects */
|
||||
void initialize()
|
||||
{
|
||||
uint32_t i, dx, dy;
|
||||
clear_screen(black); /* black screen */
|
||||
for (i = 0; i < N_OBJECTS; i++) {
|
||||
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 */
|
||||
for (dx = 0; dx < 8; dx++)
|
||||
for (dy = 0; dy < 8; dy++)
|
||||
object[i].bg[dx][dy] = black;
|
||||
}
|
||||
}
|
||||
|
||||
/* function to display the 8 pixels of a pattern line */
|
||||
void display_pattern_line(uint8_t m, uint32_t x, uint32_t y, color_t color)
|
||||
{
|
||||
for (int i = 0; i < 8; i++) {
|
||||
color_t new_color = (m & 1) == 1 ? color : black;
|
||||
m >>= 1;
|
||||
write_pixel_scaling(new_color, x + i, y);
|
||||
}
|
||||
}
|
||||
|
||||
/* function to display an 8x8 object considering the last background */
|
||||
void display_pattern(uint8_t pattern[8], uint32_t x, uint32_t y, color_t color)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
display_pattern_line(pattern[i], x, y + i, color);
|
||||
}
|
||||
|
||||
/* function to display an 8x8 object (spaceship, laser or alien) */
|
||||
void display_sprite(object_t *object)
|
||||
{
|
||||
if ((object->ax > -1 && object->ay > -1) && (object->x != object->ax || object->y != object->ay || !object->alive)) {
|
||||
for (uint32_t dx = 0; dx < 8; dx++) {
|
||||
for (uint32_t dy = 0; dy < 8; dy++) {
|
||||
write_pixel_scaling(object->bg[dx][dy], ((object->ax) << 3) + dx, ((object->ay) << 3) + dy);
|
||||
if (!object->alive)
|
||||
object->bg[dx][dy] = black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object->ax = object->x;
|
||||
object->ay = object->y;
|
||||
|
||||
if (object->alive)
|
||||
display_pattern(object->pattern, (object->x) << 3, (object->y) << 3, object->color);
|
||||
}
|
||||
49
bench/programs/invaders.h
Normal file
49
bench/programs/invaders.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef __SPRITE_H__
|
||||
#define __SPRITE_H__
|
||||
#include <stdint.h>
|
||||
|
||||
#define OBJECT_SIZE 8
|
||||
|
||||
struct color_t {
|
||||
uint8_t b:3;
|
||||
uint8_t g:3;
|
||||
uint8_t r:2;
|
||||
} __attribute__((packed));
|
||||
typedef struct color_t color_t;
|
||||
|
||||
typedef union {
|
||||
color_t pixel[4];
|
||||
uint32_t pixels;
|
||||
} pixels_t;
|
||||
|
||||
|
||||
/* Objet pour représenter les aliens, le vaisseau et le laser */
|
||||
typedef struct object_t {
|
||||
uint32_t alive;
|
||||
uint32_t period;
|
||||
uint32_t deadline;
|
||||
int x, y;
|
||||
int dx, dy;
|
||||
uint8_t *pattern;
|
||||
color_t color;
|
||||
color_t bg[OBJECT_SIZE][OBJECT_SIZE];
|
||||
int ax, ay;
|
||||
} object_t;
|
||||
|
||||
/* État pour implanter la mécanique du jeu sous forme de machine à états */
|
||||
typedef struct state_t {
|
||||
int dx;
|
||||
int dy;
|
||||
int next_state;
|
||||
} state_t;
|
||||
|
||||
/* Prototype des fonctions définies dans invaders.c */
|
||||
color_t read_pixel(uint32_t x, uint32_t y);
|
||||
void write_pixel_scaling(color_t pixel, uint32_t x, uint32_t y);
|
||||
void clear_screen(color_t color);
|
||||
void initialize(void);
|
||||
void display_pattern_line(uint8_t m, uint32_t x, uint32_t y, color_t color);
|
||||
void display_pattern(uint8_t pattern[OBJECT_SIZE], uint32_t x, uint32_t y, color_t color);
|
||||
void display_sprite(object_t *object);
|
||||
void display_timer(void);
|
||||
#endif
|
||||
Reference in New Issue
Block a user