Skip to content

Instantly share code, notes, and snippets.

@selimslab
Created May 23, 2020 12:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save selimslab/d7fcdb0b904cb5fbfdd311438f2e7f8d to your computer and use it in GitHub Desktop.
Save selimslab/d7fcdb0b904cb5fbfdd311438f2e7f8d to your computer and use it in GitHub Desktop.
#include "headers/audio.h"
#define fifo_threshold 96 //Audio out fifo
/****************************************************************************************
* For playing the audio contained in passed array
****************************************************************************************/
void play_audio(int audio[],int audio_len)
{
int fifospace;
int play = 1;
int buffer_index = 0;
volatile int *audio_ptr = (int *) AUDIO_BASE; // Audio port address
*(audio_ptr) = 0x8; // clear write FIFOs
*(audio_ptr) = 0x0; // deactivate clearing
fifospace = *(audio_ptr + 1); // read the audio port fifospace register
while(play)
{
fifospace = *(audio_ptr + 1); // read the audio port fifospace register
if ( ((fifospace & 0x00FF0000) >> 4) >= fifo_threshold) // check WSRC, for < 75% full
{
/* store data until the audio-out FIFO is full when the audio data is not finished*/
while ( (fifospace & 0x00FF0000) && (buffer_index < audio_len) )
{
*(audio_ptr + 2) = audio[buffer_index]; //left data
*(audio_ptr + 3) = audio[buffer_index]; //right data
++buffer_index;
fifospace = *(audio_ptr + 1); // read the audio port fifospace register
}
if(buffer_index == audio_len) // end of audio data, finish playing and return to main!
{
play = 0;
}
}
}
}
#include "headers/address_map_arm.h"
#include "headers/data.h"
#include "vga.c"
#include "audio.c"
#include "interrupt.c"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#
define text_x 68# define score_x(text_x + 7)# define score_y 1
# define green 0x3F03# define yellow 0xFFE0# define red 0xF800# define brown 0x5140# define blue 0x393B
int g = 1;
int box_size = 7;
void play_audio(int[], int);
int bufferPixels[76800];
void keep_score() {
int score = 0;
int health = 100;
}
void draw_box(struct box b) {
if (!b.is_invisible)
VGA_box(b.x, b.y, b.x + b.width, b.y + b.height, b.color);
}
void draw(int image[]) {
int i, j, offset = 0;
int pixel[arr_size(image)];
for (i = 0; i < 320; i++)
for (j = 0; j < 240; j++) {
pixel[offset] = image[offset];
if (pixel[offset] != 0 & pixel[offset] != 65535) {
write_pixel(i, j, pixel[offset]);
}
offset++;
}
}
void delete_box(struct box b) {
recover_background(b.x, b.x + b.width, b.y, b.y + b.height);
}
void delete_hero() {
recover_background(osman.x, osman.x + osman.width - 1, osman.y, osman.y + osman.height - 1);
}
void init_hero() {
osman.x = 150;
osman.y = 30;
osman.alive = 1;
osman.speed_x = 0;
osman.speed_y = 0;
osman.acceleration = 4;
osman.max_speed = 20;
osman.width = 28;
osman.height = 30;
osman.score = 0;
};
void draw_boxes() {
int i;
for (i = 0; i < box_size; i++) {
int x2 = boxes[i].x + boxes[i].width;
int y2 = boxes[i].y + boxes[i].height;
if (!boxes[i].is_invisible)
VGA_box(boxes[i].x, boxes[i].y, x2, y2, boxes[i].color);
}
}
void create_boxes() {
int i;
for (i = 0; i < box_size; i++) {
struct box new_box;
new_box.width = 50;
new_box.height = 5;
if (i == 5) {
new_box.x = 130;
} else {
boxes[i].x = rand() % (vga_width - boxes[i].width);
}
new_box.y = i * 30;
new_box.is_broken = 0;
new_box.is_moving = 0;
new_box.direction = 1;
new_box.is_invisible = 0;
new_box.color = green;
boxes[i] = new_box;
}
}
void box_fall(int disposition) {
osman.score += disposition;
int i;
for (i = 0; i < box_size; i++) {
delete_box(boxes[i]);
boxes[i].y = boxes[i].y + disposition;
if (boxes[i].y >= vga_height) {
boxes[i].y = 0;
boxes[i].x = rand() % (vga_width - boxes[i].width);
boxes[i].is_invisible = 0;
int broken = rand() % 100;
if (broken < 73) {
boxes[i].is_broken = 0;
boxes[i].is_moving = 0;
boxes[i].is_invisible = 0;
boxes[i].color = green;
} else if (broken < 92) {
boxes[i].is_broken = 0;
boxes[i].is_moving = 1;
boxes[i].is_invisible = 0;
boxes[i].color = blue;
} else {
boxes[i].is_broken = 1;
boxes[i].is_moving = 0;
boxes[i].is_invisible = 0;
boxes[i].color = brown;
}
}
draw_box(boxes[i]);
}
}
int update_hero_position() {
osman.y = osman.y + osman.speed_y / 10;
if (osman.x > vga_width) {
osman.x = 0;
}
if (osman.x < 0) {
osman.x = 320 - osman.width;
}
osman.speed_y = osman.speed_y + osman.acceleration;
if (osman.speed_y > osman.max_speed) {
osman.speed_y = osman.max_speed;
}
if (osman.y > vga_height) {
return 0;
osman.y = vga_height / 3;
}
if (osman.y < vga_height / 3) {
int tmp = osman.y;
osman.y = vga_height / 3;
box_fall(vga_height / 3 - tmp + 1);
}
return 1;
}
void jump_if_necessary() {
if (osman.speed_y < 0)
return;
bool shouldJump = 0;
int i;
for (i = 0; i < box_size; i++) //jump
{
bool betweenX = (osman.x >= boxes[i].x && osman.x < boxes[i].x + boxes[i].width);
bool betweenX2 = (osman.x + osman.width >= boxes[i].x && osman.x + osman.width < boxes[i].x + boxes[i].width);
bool betweenY = (osman.y + osman.height >= boxes[i].y && osman.y + osman.height < boxes[i].y + boxes[i].height);
bool curShouldJump = ((betweenX | betweenX2) & betweenY);
if (curShouldJump & boxes[i].is_broken) {
delete_box(boxes[i]);
boxes[i].is_invisible = 1;
}
shouldJump = shouldJump | ((betweenX | betweenX2) & betweenY & (!boxes[i].is_broken));
}
if (shouldJump) {
osman.speed_y = -100;
}
}
void update_box_positions() {
int i;
for (i = 0; i < box_size; i++) //jump
{
if (boxes[i].is_moving) {
delete_box(boxes[i]);
boxes[i].x += boxes[i].direction;
}
if (boxes[i].x + boxes[i].width >= vga_width) {
boxes[i].x = vga_width - boxes[i].width;
boxes[i].direction *= -1;
}
if (boxes[i].x <= 0) {
boxes[i].x = 0;
boxes[i].direction *= -1;
}
}
}
void do_config() {
set_A9_IRQ_stack(); // initialize the stack pointer for IRQ mode
config_GIC(); // configure the general interrupt controller
config_PS2();
enable_A9_interrupts(); // enable interrupts
}
void clear_screen() {
VGA_box(0, 0, vga_width, vga_height, 0);
}
void display_score() {
/* Score message to be displayed on the VGA screen */
char text[10] = "SCORE:\0";
char score[16];
sprintf(score, "%d", osman.score);
VGA_text(text_x, score_y, text);
VGA_text(score_x, score_y, score);
}
int play() {
delete_hero(); //hero fall
update_box_positions();
draw_boxes();
int alive = update_hero_position();
jump_if_necessary();
draw_hero(osman, hero_matrix);
display_score();
return alive;
}
void game_over_func() {
/* Score message to be displayed on the VGA screen */
clear_screen();
draw(game_over);
play_audio(audio_death, arr_size(audio_death)); // play death music
}
int main(void) {
do_config();
while (1) {
start_game = 0;
osman.score = 0;
clear_screen();
init_hero();
draw(background);
create_boxes();
draw_boxes();
draw_hero(osman, hero_matrix);
play_audio(start_buffer, arr_size(start_buffer)); // play start music
int alive = 1;
while (alive) {
int k = 0;
while (k < 11999999) {
k++;
}
alive = play();
if (!alive) {
game_over_func();
long long int a = 0;
while (a < 2000000000) {
a++;
}
}
}
}
return 0;
}
#include "headers/globals.h"
void config_interrupt (int, int);
void write_bits(volatile int *, volatile int, volatile int);
void PS2_ISR(void);
// Define the exception handlers here
void __attribute__ ((interrupt)) __cs3_reset (void)
{
while(1);
}
void __attribute__ ((interrupt)) __cs3_isr_undef (void)
{
while(1);
}
void __attribute__ ((interrupt)) __cs3_isr_swi (void)
{
while(1);
}
void __attribute__ ((interrupt)) __cs3_isr_pabort (void)
{
while(1);
}
void __attribute__ ((interrupt)) __cs3_isr_dabort (void)
{
while(1);
}
void __attribute__ ((interrupt)) __cs3_isr_irq (void)
{
// Read the ICCIAR from the processor interface
int address = MPCORE_GIC_CPUIF + ICCIAR;
int int_ID = *((int *) address);
if (int_ID == PS2_IRQ) // check if interrupt is from the PS2 buttonboard
PS2_ISR();
else
while (1); // if unexpected, then halt
// Write to the End of Interrupt Register (ICCEOIR)
address = MPCORE_GIC_CPUIF + ICCEOIR;
*((int *) address) = int_ID;
return;
}
void __attribute__ ((interrupt)) __cs3_isr_fiq (void)
{
while(1);
}
/*
* Initialize the banked stack pointer register for IRQ mode
*/
void set_A9_IRQ_stack(void)
{
int stack, mode;
stack = A9_ONCHIP_END - 7; // top of A9 onchip memory, aligned to 8 bytes
/* change processor to IRQ mode with interrupts disabled */
mode = INT_DISABLE | IRQ_MODE;
asm("msr cpsr, %[ps]" : : [ps] "r" (mode));
/* set banked stack pointer */
asm("mov sp, %[ps]" : : [ps] "r" (stack));
/* go back to SVC mode before executing subroutine return! */
mode = INT_DISABLE | SVC_MODE;
asm("msr cpsr, %[ps]" : : [ps] "r" (mode));
}
/*
* Turn on interrupts in the ARM processor
*/
void enable_A9_interrupts(void)
{
int status = SVC_MODE | INT_ENABLE;
asm("msr cpsr,%[ps]" : : [ps]"r"(status));
}
/*
* Configure the Generic Interrupt Controller (GIC)
*/
void config_GIC(void)
{
int address; // used to calculate register addresses
/* enable some examples of interrupts */
config_interrupt(PS2_IRQ, CPU0);
// Set Interrupt Priority Mask Register (ICCPMR). Enable interrupts for lowest priority
address = MPCORE_GIC_CPUIF + ICCPMR;
*((int *) address) = 0xFFFF;
// Set CPU Interface Control Register (ICCICR). Enable signaling of interrupts
address = MPCORE_GIC_CPUIF + ICCICR;
*((int *) address) = ENABLE;
// Configure the Distributor Control Register (ICDDCR) to send pending interrupts to CPUs
address = MPCORE_GIC_DIST + ICDDCR;
*((int *) address) = ENABLE;
}
/*
* Configure registers in the GIC for individual interrupt IDs.
*/
void config_interrupt (int int_ID, int CPU_target)
{
int n, addr_offset, value, address;
/* Set Interrupt Processor Targets Register (ICDIPTRn) to cpu0.
* n = integer_div(int_ID / 4) * 4
* addr_offet = #ICDIPTR + n
* value = CPU_target << ((int_ID & 0x3) * 8)
*/
n = (int_ID >> 2) << 2;
addr_offset = ICDIPTR + n;
value = CPU_target << ((int_ID & 0x3) << 3);
/* Now that we know the register address and value, we need to set the correct bits in
* the GIC register, without changing the other bits */
address = MPCORE_GIC_DIST + addr_offset;
write_bits((int *) address, 0xff << ((int_ID & 0x3) << 3), value);
/* Set Interrupt Set-Enable Registers (ICDISERn).
* n = (integer_div(in_ID / 32) * 4
* addr_offset = 0x100 + n
* value = enable << (int_ID & 0x1F) */
n = (int_ID >> 5) << 2;
addr_offset = ICDISER + n;
value = 0x1 << (int_ID & 0x1f);
/* Now that we know the register address and value, we need to set the correct bits in
* the GIC register, without changing the other bits */
address = MPCORE_GIC_DIST + addr_offset;
write_bits((int *) address, 0x1 << (int_ID & 0x1f), value);
}
void write_bits(volatile int * addr, volatile int unmask, volatile int value)
{
*addr = ((~unmask) & *addr) | value;
}
/* setup the PS/2 interrupts */
void config_PS2() {
volatile int * PS2_ptr = (int *)PS2_BASE; // PS/2 port address
*(PS2_ptr) = 0xFF; /* reset */
*(PS2_ptr + 1) = 0x1; /* write to the PS/2 Control register to enable interrupts */
}
void PS2_ISR(void)
{
volatile int *PS2_ptr = (int *)PS2_BASE; // PS/2 port address
int PS2_data, RAVAIL;
volatile char button=0;
PS2_data = *(PS2_ptr); // read the Data register in the PS/2 port
RAVAIL = (PS2_data & 0xFFFF0000) >> 16; // extract the RAVAIL field
if (RAVAIL > 0)
{
/* always save the last three bytes received */
button = PS2_data & 0xFF;
int i;
if (button == (char)0x74) // right arrow--right movement of our hero
{
for(i=0;i<2;i++){
move_hero(5);
}
}
else if (button == (char)0x6b) // left arrow--left movement of our hero
{
for(i=0;i<2;i++){
move_hero(-5);
}
}
else if (button == (char)0x5a) // enter button
{
}
}
return;
}
/****************************************************************************************
* Subroutine to send a string of text to the VGA monitor
****************************************************************************************/
void VGA_text(int x, int y, char * text_ptr)
{
int offset;
volatile char * character_buffer = (char *) FPGA_CHAR_BASE; // VGA character buffer
/* assume that the text string fits on one line */
offset = (y << 7) + x;
while ( *(text_ptr) )
{
*(character_buffer + offset) = *(text_ptr); // write to the character buffer
++text_ptr;
++offset;
}
}
/****************************************************************************************
* Draw a filled rectangle on the VGA monitor
****************************************************************************************/
void VGA_box(int x1, int y1, int x2, int y2, short pixel_color)
{
int pixel_ptr, row, col;
/* assume that the box coordinates are valid */
for (row = y1; row <= y2; row++)
for (col = x1; col <= x2; ++col)
{
pixel_ptr = FPGA_ONCHIP_BASE + (row << 10) + (col << 1);
*(short *)pixel_ptr = pixel_color; // set pixel color
}
}
/****************************************************************************************
* Subroutine to show a string of HEX data on the HEX displays
****************************************************************************************/
void HEX_PS2(char b1, char b2, char b3)
{
volatile int * HEX3_HEX0_ptr = (int *) HEX3_HEX0_BASE;
volatile int * HEX5_HEX4_ptr = (int *) HEX5_HEX4_BASE;
/* SEVEN_SEGMENT_DECODE_TABLE gives the on/off settings for all segments in
* a single 7-seg display in the DE1-SoC Computer, for the hex digits 0 - F */
unsigned char seven_seg_decode_table[] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7C, 0x07,
0x7F, 0x67, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71 };
unsigned char hex_segs[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
unsigned int shift_buffer, nibble;
unsigned char code;
int i;
shift_buffer = (b1 << 16) | (b2 << 8) | b3;
for ( i = 0; i < 6; ++i )
{
nibble = shift_buffer & 0x0000000F; // character is in rightmost nibble
code = seven_seg_decode_table[nibble];
hex_segs[i] = code;
shift_buffer = shift_buffer >> 4;
}
/* drive the hex displays */
*(HEX3_HEX0_ptr) = *(int *) (hex_segs);
*(HEX5_HEX4_ptr) = *(int *) (hex_segs+4);
}
int resample_rgb(int num_bits, int color)
{
if (num_bits == 8) {
color = (((color >> 16) & 0x000000E0) | ((color >> 11) & 0x0000001C) |
((color >> 6) & 0x00000003));
color = (color << 8) | color;
} else if (num_bits == 16) {
color = (((color >> 8) & 0x0000F800) | ((color >> 5) & 0x000007E0) |
((color >> 3) & 0x0000001F));
}
return color;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment