Tetris Game: CSEE4840 Embedded System Project Report
Tetris Game: CSEE4840 Embedded System Project Report
Yunfan Dong,yd2238
CSEE 4840 Project Report
Directory
Introduction .................................................................................................................................. 3
I. System Structure ............................................................................................................... 5
Tetris CPU ........................................................................................................ 6
VGA control ..................................................................................................... 7
W/R Control ..................................................................................................... 7
PS/2 control ...................................................................................................... 8
DM9000A .......................................................................................................... 8
II. Image Data and Storage use .......................................................................................... 9
Sum Up ............................................................................................................. 9
How images are Stored and Displayed ........................................................ 10
III. VGA Control and Display ............................................................................................ 13
Arrays ............................................................................................................. 14
Coordinates .................................................................................................... 15
Output Logic .................................................................................................. 16
Detailed Distinctive Sprites ........................................................................... 18
Battlefield Background ............................................................................ 18
The Columbia Relief ................................................................................ 19
Digital Clock Numbers ............................................................................. 20
Three-dimension Tiles .............................................................................. 23
IV. W/R Control ..................................................................................................................... 25
V. PS/2 Control ..................................................................................................................... 29
VI. DM9000A........................................................................................................................... 30
VII. Game Software ................................................................................................................ 31
VIII. Experiences ...................................................................................................................... 34
IX. Source Code .................................................................................................................. 36
Tetris.c: ........................................................................................................... 36
DE2_Default.V ............................................................................................... 62
2
CSEE 4840 Project Report
Introduction
the Soviet Union. It was released on June 6, 1984, while he was working
prefix tetra- (all of the game's pieces contain four segments) and tennis,
64 and IBM PC. TheTetris game is a popular use of tetrominoes, the four
3
CSEE 4840 Project Report
popular puzzles since at least 1907, and the name was given by the
the player will deal with 7 different kinds of falling blocks with random
colors. Each block contains four tiles. The aim is to eliminate as many
grow, tiles fall faster and faster, the player would probably find out that
I have also introduced ethernet connections into this game ,so that two
players can fight against each other in two separate running game clients
4
CSEE 4840 Project Report
I. System Structure
game goes on, blocks can be created as a whole and fall down as a whole
but parts of them might get eliminated. It means that lots of block data
will be written dynamically into SRAM and then output to VGA display.
The clock rate of CPU and VGA are different. So there will be a
5
CSEE 4840 Project Report
Tetris CPU
Control Logic.
6
CSEE 4840 Project Report
VGA control
reads image data from SRAM and output them into VGA Display.
W/R Control
Because VGA Display works at 25MHz and CPU works at 50MHz, there
is always a switch between VGA cycle and CPU cycle. The W/R control
makes sure that during VGA cycle, the SRAM reads. And other
times ,with rising signal of CPU clock, the SRAM writes. W/R control
also makes sure that address switch between VGA cycle and CPU cycle.
7
CSEE 4840 Project Report
PS/2 control
DM9000A
packages.
8
CSEE 4840 Project Report
Sum Up
Background 1 37.50
Name 1 0.86
Title 1 0.73
Columbia 1 8.98
Score 1 0.33
background.
9
CSEE 4840 Project Report
Dynamic part contains Tiles, Next Piece Area and Score digits.
All image data are stored in SRAM on chip (size 512 KB).
The usage of SRAM for this game is 72.65% in Single Player mode.
Under Double Player mode, the Tiles data would double. Total size is
All image data are stored as arrays either of binary or hex numbers.
The Process & Extract part is implemented with VC++ 6.0 ,by
For example, the following code is how I extract pixels from a image
of characters.
10
CSEE 4840 Project Report
lpData = gDib.FindDIBBits(hDIB);
WORD gwBytesPerLine = gDib.BytePerLine(hDIB);
unsigned ColorR,ColorG,ColorB;
double gray;
int gray_int;
Gray= new int*[v_top-v_bottom+1];
LPBITMAPINFOHEADER lpbi;
int width,height;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
//width and height
width = lpbi->biWidth;
height = lpbi->biHeight;
if((p1 = fopen("g://out1.txt","w+"))==NULL)
::AfxMessageBox("Wrong!");
int k;
for( k=0;k<v_top-v_bottom+1;k++)
Gray[k]=new int [v_right-v_left+1];
int k1,i,j;
CString s1,s2;
s1.Format("%d",width);
s2.Format("%d",height);
11
CSEE 4840 Project Report
fprintf(p1,"score[%3d] = %d'b",height-1-i,width);
for(j=0;j<=width-1; j++)
{
lOffset = gDib.PixelOffset(i, j, gwBytesPerLine);
ColorB=*(lpData + lOffset);
ColorG=*(lpData + lOffset+1);
ColorR=*(lpData + lOffset+2);
gray = (ColorG*50+ColorR*39+ColorB*11)/100;
gray_int = gray;
if(gray<50) fputc('1',p1);
else fputc('0',p1);
When arrays are generated, the data will then be processed in VGA
12
CSEE 4840 Project Report
controls the signals input into the VGA display. Most of images are
pictures are controlled by the input X, Y, FLAG and score signals which
13
CSEE 4840 Project Report
Arrays
score[ 1] = 80'b00000000000000000000000000000000000000000000000000000000000000000000000000000000;
score[ 2] = 80'b00000000000000000000000000000000000000000000000000000000000000000000000000011100;
score[ 3] = 80'b00000000000000000000000000000011100000000001000000000000000000000000000111111110;
score[ 4] = 80'b00000000000000000000000000001111110000001111100000000011111111000000011111111111;
score[ 5] = 80'b00000000011111111100000000011100110000011111100000011111111111110000111111111110;
score[ 6] = 80'b00000001111111111100000000111000110000111111100001111111111111111001111000000000;
score[ 7] = 80'b00000011111111111100000001100000110001111111110011111111100000111011110000000000;
score[ 8] = 80'b00000111100000010000000011000001100011111000110011100001100000011011000000000000;
score[ 9] = 80'b00000110000000000000000111000011100111100000110000000011000000011011100000000000;
14
CSEE 4840 Project Report
Coordinates
In order to output the image in the right place, we have two sets of
For example, for the score characters, the coordinate for the center
VGA Sync Counts and center point. The aim of relative coordinates is to
set up a mapping between VGA Sync Counts and positions in the array.
//**********************'score' characters********
score_V = (V_Cont - Y_START - 230 + 12) % 23;
score_H = (H_Cont - X_START - 320 + 40) % 79;
15
CSEE 4840 Project Report
Output Logic
Now that we have the arrays and the coordinates, we can manage
image display.
for the “score” characters image, it should be shown after the game starts,
rather than in the welcome page. We use the first bit of iFlag to judge the
conditions.
the center point of image , 40 is the half width of image, and 12 is the half
height of image.
necessary.
So, in this case, we consider whether there are RGB inputs or not,
16
CSEE 4840 Project Report
begin
if(!iRed && !iGreen && !iBlue)
begin
Cur_Color_R <= 0;
Cur_Color_G <= 800;
Cur_Color_B <= 0;
end
else
begin
Cur_Color_R <= iRed;
Cur_Color_G <= iGreen;
Cur_Color_B <= iBlue;
end
end
17
CSEE 4840 Project Report
Battlefield Background
below .
The way to implement this effect is to let 1/3 of the pixels in the area
display battle field background(dark) and 2/3 of the pixels in the area
Corresponding Codes:
if(!iRed && !iGreen && !iBlue
&&((H_Cont-X_START)%3==0)&&((V_Cont-Y_START)%3==0))
begin
Cur_Color_R <= 316;
Cur_Color_G <= 316;
Cur_Color_B <= 316;
end
else if(!iRed && !iGreen && !iBlue
&&((H_Cont-X_START)%3==1)&&((V_Cont-Y_START)%3==1))
begin
Cur_Color_R <= 280;
Cur_Color_G <= 520;
Cur_Color_B <= 720;
end
18
CSEE 4840 Project Report
The most difficult part of this relief is not to show it in the display, we
The difficult part is to extract exactly the pixels you need in a bitmap
In this picture , all the white pixels have grayscale value between 152
19
CSEE 4840 Project Report
Digital Numbers are like 7-segment hex on the DE2 board. Each Digit
contains 7 segments.
is then translated into 7-segment digits and displayed out through Score
always @ (*)
begin
if (iscoreofplayer < 10)
begin
digit1 = tdigit0 ;
digit2 = 7'b0111111 ;
digit3 = 7'b0111111 ;
end
21
CSEE 4840 Project Report
digit1 = tdigit3 ;
digit2 = 7'b1001111 ;
digit3 = 7'b0111111 ;
end
else if (iscoreofplayer < 50)
begin
digit1 = tdigit4 ;
digit2 = 7'b1100110 ;
digit3 = 7'b0111111 ;
end
else if (iscoreofplayer < 60)
begin
digit1 = tdigit5 ;
digit2 = 7'b1101101 ;
digit3 = 7'b0111111 ;
end
else if (iscoreofplayer < 70)
begin
digit1 = tdigit6 ;
digit2 = 7'b1111101 ;
digit3 = 7'b0111111 ;
end
else if (iscoreofplayer < 80)
begin
digit1 = tdigit7 ;
digit2 = 7'b0000111 ;
digit3 = 7'b0111111 ;
end
else if (iscoreofplayer < 90)
begin
digit1 = tdigit8 ;
digit2 = 7'b1111111 ;
digit3 = 7'b0111111 ;
end
22
CSEE 4840 Project Report
Three-dimension Tiles
If we use 10 bits for RGB values or even 8bits(24 bitmap color) for
So the colors are not changed little by little, colors change vastly with
bits change.
In this case ,it is difficult to find shadow colors (shadow colors are
colors that are close to but a little darker than the original color). What’s
more, there are two kinds of shadows for each three-dimension tile :
23
CSEE 4840 Project Report
shadows on the left and top, shadows on the right and bottom.
I solved the problem by traversing almost all the colors in color space,
By putting huge amounts of different blocks on the screen , and pick out
the good ones. That’s the way I finally have the 10 color types in my
/*colors :
* light blue : 86cf
* dark blue : 448f
* red : 8c66
* green : 64a6
* white : 6cee
* orange : 1fb5
* yellow : 6fd4
* purple : 98e
* brown : 5766
* pink : 8c9b
*/
24
CSEE 4840 Project Report
accelerate SRAM data access speed. The improvement space comes from
the fact that SRAM works at 50 MHz while VGA works at 25MHz.
Originally, I only used the VGA_CLK to control both the read and
write of SRAM. And when I run the program, I found it rather slow to
software ) .
CPU_CLK. That would make the read and write coding much more
25
CSEE 4840 Project Report
accelerated.:
Before Optimization
After Optimization
26
CSEE 4840 Project Report
SRAM.
// VGA Cycles
always @ (posedge VGA_CLK )
begin
trial[0] = 12'hcba;
trial[1] = 4'b1011;
trial[2] = 4'hc;
if (VGA_VS & VGA_HS)
begin
//READ
vga_addr_flag <=1;
flag <=0;
vga_addr_reg <= {Coord_X[9:1],Coord_Y[8:0]} ;
we_vga <= 1'b1;
end
//Write when syncing
else
begin
vga_addr_flag <=0;
flag <=1;
we_vga <= 1'b0;
end
end
27
CSEE 4840 Project Report
//CPU Cycles
always@(posedge CPU_CLK)
begin
if(flag)
begin
if (reset) //synch reset assumes KEY0 is held down 1/60 second
begin
//clear the screen
cpu_addr_reg <= {Coord_X[9:1],Coord_Y[8:0]} ; // [17:0]
we_cpu <= 1'b0; //write some memory
data_reg <= 16'b0; //write all zeros (black)
counter <= 9'o330 ;
counter1 <= 4'b0000 ;
end
else
begin
cpu_addr_reg <= {x_ptr[9:1],y_ptr[8:0]}; // [17:0]
we_cpu <= 1'b0; //write some memory
data_reg <= out_sram_data;
end
end
end
28
CSEE 4840 Project Report
V. PS/2 Control
Keyboard acts as the only controller of the Tetris game. Players use
four arrows and the space key (rotation) to control the tiles.
single press. The ps/2 clock works at 50 MHz, so the time is different
between a single press and a single clock cycle. The controller gets a scan
code every clock cycle when key is pressed. But within one press, we
Count adds itself by 1 when scan code from PS/2 arrives. To avoid
multi-moves , set Count to 0 once Count reaches 3. And only when Count
two factors.
Within each press 3 scan codes are delivered to the CPU, namely’
press’, ‘release’ and ‘hold’. The software will judge keyboard inputs
according to the combination of the 3 scan code and make relative moves.
29
CSEE 4840 Project Report
used an reg :
reg [7:0] history [4:1];
key inputs.
VI. DM9000A
cross-line ,via Ethernet cable. The protocol used for communicating game
messages is UDP just like Lab2. The send and receive organisms are the
same as Lab2.
30
CSEE 4840 Project Report
31
CSEE 4840 Project Report
The most fancy and yet complicated part of software for this game is
chose 12bits Color space ,RGB has 4 bits respectively. Color information
32
CSEE 4840 Project Report
33
CSEE 4840 Project Report
VIII.Experiences
game than to play one. In the developing process , the programmer is the
rule maker .
background look like a digital photo. But it turned out that it exceeds the
SRAM size. So I chose another pattern : make it clean and tidy ,rather
than fancy.
each RGB color. But it will make the game a lot slower and may exceed
the memory.
In this game I used four bits for each RGB color. So it is difficult to
find colors close to but darker than a given color (The shadow effects
need some of the pixels to display close but darker color). Because when
I finally solved this problem by traversing all the possible colors and
There are a lot more detailed difficulties : almost every final detail is
34
CSEE 4840 Project Report
macroscopic problems. I think this experience will not only help me with
later programings but also help me with any problem I meet in my life.
Finally, I want to thank Prof. Edwards for his generous helps on this
project. Without him the project would have been a much harder one.
35
CSEE 4840 Project Report
IX.Source Code
Tetris.c:
// system.h has peripheral base addresses, IRQ definitions, and cpu details
#include "system.h"
#include "sys/alt_irq.h"
#include "altera_avalon_pio_regs.h"
#include <unistd.h> //e.g. //usleep(5000000); is 5 seconds
#include <stdio.h>
#include "functions.h"
#include "altera_avalon_pio_regs.h"
#include <io.h>
#include "DM9000A.h"
#include "basic_io.h"
#include "functions.h"
#include "altera_avalon_uart_regs.h"
//DM9000
#define MAX_MSG_LENGTH 128
#define UDP_PACKET_PAYLOAD_OFFSET 42
#define UDP_PACKET_LENGTH_OFFSET 38
#define UDP_PACKET_PAYLOAD (transmit_buffer + UDP_PACKET_PAYLOAD_OFFSET)
#define STATE_INIT 0
#define STATE_CONNECTED 1
#define STATE_ME_START 2
#define STATE_HIM_START 3
#define STATE_START 4
36
CSEE 4840 Project Report
char spcount1 , spcount2 , spcount3 , spcount4 ; //space vars to calculate new positions.
every block contains 4 units.
char spcount1_r, spcount2_r , spcount3_r, spcount4_r ; //right battle area vars
int score_lines = 0 ; //score
volatile int count = 0;
volatile int othermadeline ;
//keyboard
int edgeregister = 0;
int previouscount = 0 ;
int currentcount = 0 ;
int w , cgover;
int gameover = 0 ;
int gameover_r = 0;
//KB_CODE_TYPE decode_mode;
#define UDP_PACKET_PAYLOAD_OFFSET 42
#define UDP_PACKET_LENGTH_OFFSET 38
37
CSEE 4840 Project Report
// IP Header
0x45, // version (IPv4), header length = 20 bytes
0x00, // differentiated services field
0x00,0x9C, // total length: 20 bytes for IP header +
// 8 bytes for UDP header + 128 bytes for payload
0x00, 0x00, // packet ID
0x00, // flags
0x00, // fragment offset
0x01, // time-to-live
0x11, // protocol: 11 = UDP
0xb6,0x00, // header checksum: incorrect
0xc0,0xa8,0x01,0x01, // source IP address
0xFF,0xFF,0xFF,0xFF, // destination IP address
// UDP Header
0x67,0xd9, // source port port (26585: garbage)
0x27,0x2b, // destination port (10027: garbage)
0x00,0x88, // length (136: 8 for UDP header + 128 for data)
0x00,0x00, // checksum: 0 = none
// UDP payload
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67,
0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x73, 0x67
};
38
CSEE 4840 Project Report
int i;
int sprite_num;
int curMsgChar = 0;
unsigned int packet_length;
if (receive_status == DMFE_SUCCESS) {
UDP_PACKET_PAYLOAD[curMsgChar++] = 'z';
UDP_PACKET_PAYLOAD[curMsgChar++] = 'z';
UDP_PACKET_PAYLOAD[curMsgChar++] = 0;
packet_length = UDP_PACKET_PAYLOAD_OFFSET + curMsgChar;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET] = packet_length >> 8;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET + 1] = packet_length & 0xff;
if (TransmitPacket(transmit_buffer, UDP_PACKET_PAYLOAD_OFFSET + curMsgChar
+ 1)==DMFE_SUCCESS);
if (TransmitPacket(transmit_buffer, UDP_PACKET_PAYLOAD_OFFSET + curMsgChar
+ 1)==DMFE_SUCCESS);
}
39
CSEE 4840 Project Report
STATE_CONNECTED)&&(receive_buffer[42]=='z')&&(receive_buffer[43]=='s'))
{
state = STATE_HIM_START;
printf("Player 2 is Ready,Pleas press 'enter' to start game!");
}
else if (receive_buffer[42]=='a')
{
sprite_num = receive_buffer[43];
// printf("
received :%d\n",sprite_num);
current_blk_r.c1.x = piecessprites_r[sprite_num][0] ;
current_blk_r.c1.y = piecessprites_r[sprite_num][1] ;
current_blk_r.c2.x = piecessprites_r[sprite_num][2] ;
current_blk_r.c2.y = piecessprites_r[sprite_num][3] ;
current_blk_r.c3.x = piecessprites_r[sprite_num][4] ;
current_blk_r.c3.y = piecessprites_r[sprite_num][5] ;
current_blk_r.c4.x = piecessprites_r[sprite_num][6] ;
current_blk_r.c4.y = piecessprites_r[sprite_num][7] ;
current_blk_r.type = piecessprites_r[sprite_num][8] ;
current_blk_r.state =piecessprites_r[sprite_num][9] ;
current_blk_r.color =piecessprites_r[sprite_num][10] ;
}
else if ((receive_buffer[42]=='e')&&(receive_buffer[43]=='q'))
{
current_blk1_r = current_blk_r;
}
else if ((receive_buffer[42]=='e')&&(receive_buffer[43]=='r'))
{
current_blk_r = current_blk1_r;
}
else if (receive_buffer[42]=='b')
{
sprite_num = receive_buffer[43];
// printf("
received :%d\n",sprite_num);
current_blk1_r.c1.x = piecessprites_r[sprite_num][0] ;
40
CSEE 4840 Project Report
current_blk1_r.c1.y = piecessprites_r[sprite_num][1] ;
current_blk1_r.c2.x = piecessprites_r[sprite_num][2] ;
current_blk1_r.c2.y = piecessprites_r[sprite_num][3] ;
current_blk1_r.c3.x = piecessprites_r[sprite_num][4] ;
current_blk1_r.c3.y = piecessprites_r[sprite_num][5] ;
current_blk1_r.c4.x = piecessprites_r[sprite_num][6] ;
current_blk1_r.c4.y = piecessprites_r[sprite_num][7] ;
current_blk1_r.type = piecessprites_r[sprite_num][8] ;
current_blk1_r.state =piecessprites_r[sprite_num][9] ;
current_blk1_r.color =piecessprites_r[sprite_num][10] ;
}
else if ((receive_buffer[42]=='z')&&(receive_buffer[43]=='a'))
{
draw(current_blk_r);
}
else if ((receive_buffer[42]=='z')&&(receive_buffer[43]=='p'))
{
uu_r = current_blk_r;
uu_r.c1.x = receive_buffer[44]+320; //+320 because we should display the origin
block into the right battle field
uu_r.c1.y = receive_buffer[45];
uu_r.c2.x = receive_buffer[46]+320;
uu_r.c2.y = receive_buffer[47];
uu_r.c3.x = receive_buffer[48]+320;
uu_r.c3.y = receive_buffer[49];
uu_r.c4.x = receive_buffer[50]+320;
uu_r.c4.y = receive_buffer[51];
drawpiece_tnext(current_blk_r , uu_r) ;
delay2();
delay2();
delay2();
}
} else {
printf("Received non-UDP packet\n");
}
} else {
printf("Received non-IP packet\n");
41
CSEE 4840 Project Report
}
} else {
printf("Malformed Ethernet packet\n");
}
} else {
printf("Error receiving packet\n");
}
/* Clear the DM9000A ISR: PRS, PTS, ROS, ROOS 4 bits, by RW/C1 */
dm9000a_iow(ISR, 0x3F);
int main(void)
{
//UDP packet
int curMsgChar = 0;
unsigned int packet_length;
state = 0;
printf("\n===================================================================
=============\n");
printf("* Welcome to Tetris v 1.0 ....
*\n");
printf("* Copy rights Open to All
42
CSEE 4840 Project Report
*\n");
printf("* Yunfan
Dong *\n");
printf("====================================================================
============\n");
//******************************Preparations
**************************************
printf("====================================================================
============\n");
DM9000_init(mac_address);
interrupt_number = 0;
alt_irq_register(DM9000A_IRQ, NULL, (void*)ethernet_interrupt_handler);
43
CSEE 4840 Project Report
UDP_PACKET_PAYLOAD[curMsgChar++] = 'a';
UDP_PACKET_PAYLOAD[curMsgChar++] = random;
UDP_PACKET_PAYLOAD[curMsgChar++] = 0;
packet_length = UDP_PACKET_PAYLOAD_OFFSET + curMsgChar;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET] = packet_length >> 8;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET + 1] = packet_length & 0xff;
if (TransmitPacket(transmit_buffer, UDP_PACKET_PAYLOAD_OFFSET + curMsgChar +
1)==DMFE_SUCCESS);
// printf(" Message Sent! Sprite num:%d \n",random);
current_blk1 = current_blk ;
UDP_PACKET_PAYLOAD[curMsgChar++] = 'e';
UDP_PACKET_PAYLOAD[curMsgChar++] = 'q';
UDP_PACKET_PAYLOAD[curMsgChar++] = 0;
44
CSEE 4840 Project Report
while(state!=STATE_START){
IOWR_ALTERA_AVALON_PIO_DATA(PIO_FLAG_BASE,0x02);
usleep(1000000);
IOWR_ALTERA_AVALON_PIO_DATA(PIO_FLAG_BASE,0x00);
usleep(1000000);
int cnt;
edgeregister =
IORD_ALTERA_AVALON_PIO_DATA(KEYBOARDSCANCODE_BASE);
previouscount = currentcount ;
currentcount = IORD_ALTERA_AVALON_PIO_DATA(KEYCOUNTER_BASE);
// printf("\ncurrent count:%d 0x%x ",currentcount,edgeregister);
if(currentcount>previouscount){
45
CSEE 4840 Project Report
printf("****************************************\n Initializing
Screen ......\n****************************************\nlog:\n\n");
// IOWR_ALTERA_AVALON_PIO_DATA(PIO_FLAG_BASE,0x01);
IOWR_ALTERA_AVALON_PIO_DATA(PIO_FLAG_BASE,0x05);
IOWR_ALTERA_AVALON_PIO_DATA(SCOREOFPLAYER_BASE,0);
initializescreen();
//*********************************************************************************
*********
//*********************************main loop
***********************************************
{
for (curMsgChar=MAX_MSG_LENGTH-1; curMsgChar>0; curMsgChar--) {
UDP_PACKET_PAYLOAD[curMsgChar] = 0;
}
UDP_PACKET_PAYLOAD[curMsgChar++] = 'e';
UDP_PACKET_PAYLOAD[curMsgChar++] = 'r';
UDP_PACKET_PAYLOAD[curMsgChar++] = 0;
packet_length = UDP_PACKET_PAYLOAD_OFFSET + curMsgChar;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET] = packet_length >> 8;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET + 1] = packet_length & 0xff;
if (TransmitPacket(transmit_buffer, UDP_PACKET_PAYLOAD_OFFSET + curMsgChar
+ 1)==DMFE_SUCCESS);
46
CSEE 4840 Project Report
UDP_PACKET_PAYLOAD[curMsgChar++] = 'b';
UDP_PACKET_PAYLOAD[curMsgChar++] = random;
UDP_PACKET_PAYLOAD[curMsgChar++] = 0;
packet_length = UDP_PACKET_PAYLOAD_OFFSET + curMsgChar;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET] = packet_length >> 8;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET + 1] = packet_length & 0xff;
if (TransmitPacket(transmit_buffer, UDP_PACKET_PAYLOAD_OFFSET + curMsgChar +
1)==DMFE_SUCCESS);
current_blk1.c1.x = piecessprites[random][0] ;
current_blk1.c1.y = piecessprites[random][1] ;
current_blk1.c2.x = piecessprites[random][2] ;
current_blk1.c2.y = piecessprites[random][3] ;
current_blk1.c3.x = piecessprites[random][4] ;
current_blk1.c3.y = piecessprites[random][5] ;
current_blk1.c4.x = piecessprites[random][6] ;
current_blk1.c4.y = piecessprites[random][7] ;
current_blk1.type = piecessprites[random][8] ;
current_blk1.state =piecessprites[random][9] ;
current_blk1.color =piecessprites[random][10] ;
UDP_PACKET_PAYLOAD[curMsgChar++] = 'z';
UDP_PACKET_PAYLOAD[curMsgChar++] = 'a';
UDP_PACKET_PAYLOAD[curMsgChar++] = 0;
packet_length = UDP_PACKET_PAYLOAD_OFFSET + curMsgChar;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET] = packet_length >> 8;
47
CSEE 4840 Project Report
draw(current_blk);
clearnextpiecearea();
drawnextpiece (current_blk1) ;
char collision = 0;
char collision_r = 0;
//****************************************************************************
//*****************************collision loop1*********************************
//**** parallel thread for battle area 1
while (collision != 1)
{
int response ;
for(response = 0 ; response < 30 ; response++)
{
edgeregister =
IORD_ALTERA_AVALON_PIO_DATA(KEYBOARDSCANCODE_BASE);
previouscount = currentcount ;
currentcount = IORD_ALTERA_AVALON_PIO_DATA(KEYCOUNTER_BASE);
48
CSEE 4840 Project Report
{
//if 'enter' output current grids in console (for debugging)
if(edgeregister == 0x5af05a)
{
printf("left grid\n");
for (i = 0 ; i < 20 ; i++)
{
for(j = 0 ; j < 10 ; j++)
{
49
CSEE 4840 Project Report
}
//**********'up' key pressed
else if( edgeregister == 0xe0f075 )
{
uu = rotate(current_blk);
printf("keycode: %x -- 'up'(rotate)\n" , edgeregister) ;
}
//***********'down' key pressed
else if( edgeregister == 0xe0f072 )
{
uu = movedown(current_blk);
uu = movedown(uu) ;
printf("keycode: %x -- 'down'\n" , edgeregister) ;
}
//************'spacebar' pressed
else if(edgeregister == 0x29f029)
{
printf("keycode: %x -- 'space'(to bottom)\n" , edgeregister) ;
//g1,g2,g2,g4 are relative positions in the grid, the grid is 10*20 , every grid
capable of one blk
struct coordinate g1 , g2 , g3 , g4 ;
g1 = coord_change(current_blk.c1);
g2 = coord_change(current_blk.c2);
g3 = coord_change(current_blk.c3);
g4 = coord_change(current_blk.c4);
// keep track of how many grids we move down in order to calculate exact
coordinates
spcount1 = 0 ;
spcount2 = 0 ;
spcount3 = 0 ;
spcount4 = 0 ;
// total height is 20
// x --- vertical y --- horizontal
50
CSEE 4840 Project Report
{
g1.x = g1.x + 1 ;
spcount1 = spcount1 + 1 ;
}
char min_x_down_allowed ;
min_x_down_allowed = spcount1 ;
uu = current_blk ;
uu.c1.y = uu.c1.y + 20 * min_x_down_allowed ;
uu.c2.y = uu.c2.y + 20 * min_x_down_allowed ;
uu.c3.y = uu.c3.y + 20 * min_x_down_allowed ;
uu.c4.y = uu.c4.y + 20 * min_x_down_allowed ;
51
CSEE 4840 Project Report
// check whether the corrdinates needed to be filled are occupied,if so, the move is
illegal
g1 = coord_change(uu.c1);
g2 = coord_change(uu.c2);
g3 = coord_change(uu.c3);
g4 = coord_change(uu.c4);
//left
if( (tempgrid[g1.x][g1.y] == 1) || (tempgrid[g2.x][g2.y] == 1)
||(tempgrid[g3.x][g3.y] == 1)
|| (tempgrid[g4.x][g4.y] == 1) )
{
uu = current_blk ;
}
uu = current_blk ;
}
else if (((uu.c1.y < 50) || (uu.c2.y < 50) || (uu.c3.y < 50) || (uu.c4.y < 50))
|| ((uu.c1.y > 430) || (uu.c2.y > 430) || (uu.c3.y > 430) || (uu.c4.y > 430)))
{
//the piece might go outside the top and bottom edges
// printf("333333333333333333333\n") ;
uu = current_blk ;
}
else
{
// legal move here . draw blk on new place,clear old place first
52
CSEE 4840 Project Report
UDP_PACKET_PAYLOAD[curMsgChar++] = 'z';
UDP_PACKET_PAYLOAD[curMsgChar++] = 'p';
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c1.x;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c1.y;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c2.x;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c2.y;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c3.x;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c3.y;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c4.x;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c4.y;
UDP_PACKET_PAYLOAD[curMsgChar++] = 0;
packet_length = UDP_PACKET_PAYLOAD_OFFSET + curMsgChar;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET] = packet_length >> 8;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET + 1] = packet_length
& 0xff;
if (TransmitPacket(transmit_buffer, UDP_PACKET_PAYLOAD_OFFSET
+ curMsgChar + 1)==DMFE_SUCCESS);
drawpiece_tnext(current_blk , uu) ;
current_blk = uu ;
}
delay2();
53
CSEE 4840 Project Report
max_y = current_blk.c1.y ;
//**********************************************
//****** see if there is a collision with anything on the grid
int ymax1 , tempxcoord , c1set , c2set , c3set , c4set ;
c1set = 0;
c2set = 0;
c3set = 0;
c4set = 0;
// c1 check
//left area
tempxcoord = current_blk.c1.x ;
ymax1 = current_blk.c1.y ;
if ( (current_blk.c2.y > ymax1) && (current_blk.c2.x == tempxcoord)) ymax1 =
current_blk.c2.y ;
if ( (current_blk.c3.y > ymax1) && (current_blk.c3.x == tempxcoord)) ymax1 =
current_blk.c3.y ;
if ( (current_blk.c4.y > ymax1) && (current_blk.c4.x == tempxcoord)) ymax1 =
current_blk.c4.y ;
yy1.x = tempxcoord ;
yy1.y = ymax1 + 20 ;
yyy1 = coord_change(yy1) ;
if( tempgrid[yyy1.x][yyy1.y] == 1) c1set = 1 ;
//c2 check
//left area
tempxcoord = current_blk.c2.x ;
ymax1 = current_blk.c2.y ;
54
CSEE 4840 Project Report
//c3 check
//left
tempxcoord = current_blk.c3.x ;
ymax1 = current_blk.c3.y ;
if ( (current_blk.c1.y > ymax1) && (current_blk.c1.x == tempxcoord)) ymax1 =
current_blk.c1.y ;
if ( (current_blk.c2.y > ymax1) && (current_blk.c2.x == tempxcoord)) ymax1 =
current_blk.c2.y ;
if ( (current_blk.c4.y > ymax1) && (current_blk.c4.x == tempxcoord)) ymax1 =
current_blk.c4.y ;
yy1.x = tempxcoord ;
yy1.y = ymax1 + 20 ;
yyy1 = coord_change(yy1) ;
if( tempgrid[yyy1.x][yyy1.y] == 1) c3set = 1 ;
//c4 check
//left
tempxcoord = current_blk.c4.x ;
ymax1 = current_blk.c4.y ;
if ( (current_blk.c1.y > ymax1) && (current_blk.c1.x == tempxcoord)) ymax1 =
current_blk.c1.y ;
if ( (current_blk.c2.y > ymax1) && (current_blk.c2.x == tempxcoord)) ymax1 =
current_blk.c2.y ;
if ( (current_blk.c3.y > ymax1) && (current_blk.c3.x == tempxcoord)) ymax1 =
current_blk.c3.y ;
yy1.x = tempxcoord ;
yy1.y = ymax1 + 20 ;
55
CSEE 4840 Project Report
yyy1 = coord_change(yy1) ;
if( tempgrid[yyy1.x][yyy1.y] == 1) c4set = 1 ;
///update grid
tempgrid[f1.x][f1.y] = 1 ;
tempgrid[f2.x][f2.y] = 1 ;
tempgrid[f3.x][f3.y] = 1 ;
tempgrid[f4.x][f4.y] = 1 ;
}
else if((c4set + c3set + c2set + c1set) > 0 ) // touches blks already in the grid
{
collision = 1 ;
struct coordinate f1 , f2 , f3 , f4 ;
f1 = coord_change(current_blk.c1);
f2 = coord_change(current_blk.c2);
f3 = coord_change(current_blk.c3);
f4 = coord_change(current_blk.c4);
tempgrid[f1.x][f1.y] = 1 ;
tempgrid[f2.x][f2.y] = 1 ;
tempgrid[f3.x][f3.y] = 1 ;
tempgrid[f4.x][f4.y] = 1 ;
}
else //if no collision move down and restart the collsion check loop
{
uu = movedown(current_blk);
56
CSEE 4840 Project Report
UDP_PACKET_PAYLOAD[curMsgChar++] = 'z';
UDP_PACKET_PAYLOAD[curMsgChar++] = 'p';
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c1.x;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c1.y;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c2.x;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c2.y;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c3.x;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c3.y;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c4.x;
UDP_PACKET_PAYLOAD[curMsgChar++] = uu.c4.y;
UDP_PACKET_PAYLOAD[curMsgChar++] = 0;
packet_length = UDP_PACKET_PAYLOAD_OFFSET + curMsgChar;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET] = packet_length >> 8;
transmit_buffer[UDP_PACKET_LENGTH_OFFSET + 1] = packet_length
& 0xff;
if (TransmitPacket(transmit_buffer, UDP_PACKET_PAYLOAD_OFFSET
+ curMsgChar + 1)==DMFE_SUCCESS);
drawpiece_tnext(current_blk , uu) ;
// printf("position updated!!");
//speed control
if(score_lines <3)
delay1();
else if (score_lines<6)
delay11();
else delay111();
}
///**************end of collision loop1********************
//************************************************************
//********** detect line fulfilment & update grid
57
CSEE 4840 Project Report
sum = 0 ;
///**********leftside*****************
//traverse grid
for (i = 19 ; i >= 0 ; i--)
{
for (j = 0 ; j < 10 ; j++)
{
sum = sum + tempgrid[i][j] ;
}
58
CSEE 4840 Project Report
/*
///**********right side*****************
//traverse grid
for (i = 19 ; i >= 0 ; i--)
{
for (j = 0 ; j < 10 ; j++)
{
sum = sum + tempgrid_r[i][j] ;
}
*/
59
CSEE 4840 Project Report
//******************************************************
//*****************update the score*********************
score_lines = score_lines + t ;
//*********************************************************************************
*******
//*******check differences between
//*******the the boardgrid and the tempgrid1 and draw accordingly. Then update the
//*******board grid and the tempgrid arrays
int d , s ;
for (d = 0 ; d < 20 ; d++)
{
for (s = 0 ; s < 10 ; s++)
{
if(tempgrid[d][s] == tempgrid1[d][s])
{
//do nothing
}
else
{
if(tempgrid[d][s] == 1)
{
createunit(20*s + 50 , 20*d + 50 , 0 );
tempgrid[d][s] = 0 ;
}
else
{
// createunit(20*s + 70 , 20*d + 50 , white );
tempgrid[d][s] = 1 ;
}
}
}
}
60
CSEE 4840 Project Report
/*
for (d = 0 ; d < 20 ; d++)
{
for (s = 0 ; s < 10 ; s++)
{
if(tempgrid_r[d][s] == tempgrid1_r[d][s])
{
//do nothing
}
else
{
if(tempgrid_r[d][s] == 1)
{
createunit(20*s + 70 , 20*d + 50 , 0 );
tempgrid_r[d][s] = 0 ;
}
else
{
// createunit(20*s + 70 , 20*d + 50 , white );
tempgrid_r[d][s] = 1 ;
}
}
}
}
*/
//********************************************************************************
//check if the top row of the gris is full and stop the loop. Basically game over
cgover = 0 ;
for (w = 0 ; w < 10 ; w++)
{
cgover = cgover + tempgrid[1][w] ;
}
if(cgover > 1 ) {
gameover = 1 ;
IOWR_ALTERA_AVALON_PIO_DATA(KEYCOUNTER_BASE,0);
printf("Game Over...");
}
61
CSEE 4840 Project Report
// IOWR_ALTERA_AVALON_PIO_DATA(PIO_FLAG_BASE,0x00);
finalmessage();
DE2_Default.V
module DE2_Default
(
//////////////////// Clock Input ////////////////////
CLOCK_27, // 27 MHz
CLOCK_50, // 50 MHz
EXT_CLOCK, // External Clock
//////////////////// Push Button ////////////////////
KEY, // Pushbutton[3:0]
//////////////////// DPDT Switch ////////////////////
SW, // Toggle Switch[17:0]
//////////////////// 7-SEG Dispaly ////////////////////
HEX0, // Seven Segment Digit 0
HEX1, // Seven Segment Digit 1
HEX2, // Seven Segment Digit 2
HEX3, // Seven Segment Digit 3
HEX4, // Seven Segment Digit 4
HEX5, // Seven Segment Digit 5
HEX6, // Seven Segment Digit 6
HEX7, // Seven Segment Digit 7
//////////////////////// LED ////////////////////////
LEDG, // LED Green[8:0]
LEDR, // LED Red[17:0]
//////////////////////// UART ////////////////////////
UART_TXD, // UART Transmitter
UART_RXD, // UART Receiver
//////////////////////// IRDA ////////////////////////
IRDA_TXD, // IRDA Transmitter
62
CSEE 4840 Project Report
63
CSEE 4840 Project Report
64
CSEE 4840 Project Report
);
65
CSEE 4840 Project Report
66
CSEE 4840 Project Report
67
CSEE 4840 Project Report
//////////////////////////////////////////////////////////////////////
////////////////////////////////////
//DLA state machine variables
wire reset;
reg [17:0] cpu_addr_reg; //memory address register for SRAM
reg [17:0] vga_addr_reg;
reg [15:0] data_reg; //memory data register for SRAM
reg we_vga;
reg we_cpu ; //write enable for SRAM
reg flag;
////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// LCD ON
assign LCD_ON = 1'b0;
assign LCD_BLON = 1'b0;
68
CSEE 4840 Project Report
//DM9000A Clock
reg ENET_CLK;
always@(posedge CPU_CLK) ENET_CLK=~ENET_CLK;
Reset_Delay r0 ( .iCLK(CLOCK_50),.oRESET(DLY_RST) );
VGA_Audio_PLL p1 (
.areset(~DLY_RST),.inclk0(CLOCK_27),.c0(VGA_CTRL_CLK),.c1(AUD_CTRL_CLK),.c2(V
GA_CLK) );
/***************************SDRAM
PLL****************************************************/
wire CPU_CLK ;
sdrampll pll1(CLOCK_50, DRAM_CLK , CPU_CLK);
//*********************************************************************************
**********
//*********************************************************************************
**
69
CSEE 4840 Project Report
//******************************CPU instantiation***********************************
TETRISCPU cpu1
( //DM9000A
.ENET_CMD_from_the_DM9000A (ENET_CMD),
.ENET_CS_N_from_the_DM9000A (ENET_CS_N),
.ENET_DATA_to_and_from_the_DM9000A (ENET_DATA),
.ENET_INT_to_the_DM9000A (ENET_INT),
.ENET_RD_N_from_the_DM9000A (ENET_RD_N),
.ENET_RST_N_from_the_DM9000A (ENET_RST_N),
.ENET_WR_N_from_the_DM9000A (ENET_WR_N),
.clk (CPU_CLK),
.reset_n (KEY[0]),
.in_port_to_the_keyboardscancode (keyscanreg),
.in_port_to_the_keycounter (count1),
//VGA control
.out_port_from_the_outputsramdata (out_sram_data),
.out_port_from_the_outputxcoord (x_ptr),
.out_port_from_the_outputycoord (y_ptr),
.out_port_from_the_pio_flag (out_flag),
.out_port_from_the_scoreofplayer (scoreofplayer),
.rxd_to_the_uart1 (UART_RXD),
.txd_from_the_uart1 (UART_TXD),
70
CSEE 4840 Project Report
.zs_addr_from_the_sdram (DRAM_ADDR),
.zs_ba_from_the_sdram ({DRAM_BA_1, DRAM_BA_0}),
.zs_cas_n_from_the_sdram (DRAM_CAS_N),
.zs_cke_from_the_sdram (DRAM_CKE),
.zs_cs_n_from_the_sdram (DRAM_CS_N),
.zs_dq_to_and_from_the_sdram (DRAM_DQ),
.zs_dqm_from_the_sdram ({DRAM_UDQM, DRAM_LDQM}),
.zs_ras_n_from_the_sdram (DRAM_RAS_N),
.zs_we_n_from_the_sdram (DRAM_WE_N)
);
//*********************************************************************************
**
VGA_Controller u1 (
// Host Side
.iCursor_RGB_EN(4'b0111),
.oAddress(mVGA_ADDR),
.oCoord_X(Coord_X),
.oCoord_Y(Coord_Y),
.iRed(mVGA_R),
.iGreen(mVGA_G),
.iBlue(mVGA_B),
.iFlag(out_flag[7:0]),
// .iFlag1(out_flag[1]|SW[1]),
// VGA Side
.oVGA_R(VGA_R),
.oVGA_G(VGA_G),
.oVGA_B(VGA_B),
.oVGA_H_SYNC(VGA_HS),
.oVGA_V_SYNC(VGA_VS),
.oVGA_SYNC(VGA_SYNC),
.oVGA_BLANK(VGA_BLANK),
// Control Signal
71
CSEE 4840 Project Report
.iCLK(ENET_CLK),
.iRST_N(DLY_RST),
.iscoreofplayer (scoreofplayer) );
reg vga_addr_flag;
// SRAM_control
assign SRAM_ADDR = (vga_addr_flag) ? vga_addr_reg:cpu_addr_reg;
assign SRAM_DQ = (we_vga | we_cpu)? 16'hzzzz : data_reg ;
assign SRAM_UB_N = 0; // hi byte select enabled
assign SRAM_LB_N = 0; // lo byte select enabled
assign SRAM_CE_N = 0; // chip is enabled
assign SRAM_WE_N = (we_vga | we_cpu); // write when ZERO
assign SRAM_OE_N = 0; //output enable is overidden by WE
72
CSEE 4840 Project Report
reg [11:0]trial[2:0];
// VGA Cycles
always @ (posedge ENET_CLK )
begin
trial[0] = 12'hcba;
trial[1] = 4'b1011;
trial[2] = 4'hc;
end
//CPU Cycles
always@(posedge CPU_CLK)
begin
73
CSEE 4840 Project Report
if(flag)
begin
if (reset) //synch reset assumes KEY0 is held down 1/60 second
begin
//clear the screen
cpu_addr_reg <= {Coord_X[9:1],Coord_Y[8:0]} ; // [17:0]
we_cpu <= 1'b0; //write some memory
data_reg <= 16'b0; //write all zeros (black)
counter <= 9'o330 ;
counter1 <= 4'b0000 ;
end
else
begin
cpu_addr_reg <= {x_ptr[9:1],y_ptr[8:0]}; // [17:0]
we_cpu <= 1'b0; //write some memory
data_reg <= out_sram_data;
end
end
end
//*********************************************************************************
************************
//*****************************Keyboardfiles. Source cited in the
report************************************
wire reset1 = 1'b0;
wire [7:0] scan_code;
oneshot pulser(
.pulse_out(read),
.trigger_in(scan_ready),
.clk(CLOCK_50)
);
keyboard kbd(
.keyboard_clk(PS2_CLK),
.keyboard_data(PS2_DAT),
.clock50(CLOCK_50),
.reset(reset1),
.read(read),
.scan_ready(scan_ready),
.scan_code(scan_code)
74
CSEE 4840 Project Report
);
75
CSEE 4840 Project Report
end
hex_7seg dsp6(history[4][3:0],HEX6);
hex_7seg dsp7(history[4][7:4],HEX7);
76