demo:

https://www.bilibili.com/video/BV1tx4y1A7wZ/?vd_source=3d19a3d894313e266a040f306849e552

Contents

Chapter 1 Introduction 3

1.1 The purpose of the experiment 3

1.2 Experimental Procedure of FDE Lab 3

Chapter 2. Name Display Experiment 5

2.1 The Text Display of Name 5

2.1.1 Document Directory 5

2.1.2 Experimental Principle 6

2.1.3 Source Code Design 7

2.2 The Image Display of Name 10

2.2.1 Document Directory 10

2.1.2 Experimental Principle 10

2.2.3 Source Code Design 12

Chapter 3. Aerial Combat Game 20

3.1 Document Directory 20

3.2 Game Introduction 20

3.3 Source Code Structure 21

Chapter 4. Experiment Summary 31

4.1 Experiment Summary 31

Chapter 5. References 32

Chapter 6. Appendices 33

Chapter 1 Introduction

1.1 The purpose of the experiment

Through various experiments in FDE Lab, I gradually master the specific steps of digital circuit design, be familiar with the use of SMIMS and Wonton software, and understand the workflow of Yosys and DC, such as compiling, packing, placing, routing and generating bit files. By writing Verilog files, I am familiar with top-down design methods, test document writing and waveform viewing. The mastery of these knowledge will be of great help to the later embedded experiments.

1.2 Experimental Procedure of FDE Lab

Firstly, the design source file is written by Vivado software developed by AMD Xilinx Company. By writing testbench files, we can verify the functions of source files through behavior level simulation. In order to ensure the reliability of the design source file, we can also conduct post synthesis simulation again after synthesis steps to verify the correctness of timing and functions.

Secondly, we can compile the design source file through Yosys or DC. After the compilation is complete, we can use the FDE2019 software to complete a work flow, such as packing, placing, routing, and generating bit files. It is worth noting that the SMIMS HDLAutoAssign tool should be used to generate pin constraint files in advance during the placing and routing process.

Finally, Wonton interactive software is used to control each input and output component. When creating a new project, it is necessary to add the previously generated pin constraint file, connect the FDE development board after adding the bitstream file, and set the clock frequency after programming. After setting this up, the output component can perform a series of operations by controlling the input component.

Next, I will introduce some specific process of digital circuit design:

  • Packing

The packing step in digital circuit design is the process of grouping logical components and interconnect wires into physical entities called modules or cells.

The following are the typical steps involved in the packing step of digital circuit design:

  • Module generation: The first step is to group related components into modules. This is done based on the functionality of the components and the design hierarchy. The modules can be pre-designed blocks or they can be created during the packing step.
  • Cell generation: In this step, the modules are transformed into physical cells. Each cell contains one or more modules and associated interconnect wires. The cells are generated using a cell generation tool, which takes into account the placement of the components and the design rules specified by the manufacturer.
  • Cell placement: Once the cells are generated, they are placed on the chip or PCB. The placement takes into account the location of the input/output pins and the interconnect wires between the cells.

Overall, the packing step in digital circuit design is a critical part of the design process, as it determines the physical grouping of components and interconnect wires into cells or modules. This can have a significant impact on the performance and reliability of the circuit

  • Placing

The placement step in digital circuit design is the process of determining the physical location of each logic gate, flip-flop, and other components on a chip or printed circuit board (PCB). The goal of the placement step is to minimize the length of interconnect wires and optimize the performance of the circuit.

The following are the typical steps involved in the placement step of digital circuit design:

  • Netlist generation: The first step is to generate a netlist, which is a list of all the components in the design and their connections. This is typically done using a computer-aided design (CAD) tool.
  • Floorplanning: In this step, the designer allocates space for each component on the chip or PCB. This involves deciding on the overall size of the chip, the location of the input/output pins, and the placement of other components.
  • Placement: Once the floorplan is complete, the designer uses a placement tool to place the components on the chip or PCB. The placement tool takes into account the location of the input/output pins, the size and shape of the components, and any design rules specified by the manufacturer.

To summarize, the placement step in digital circuit design determines the physical layout of the circuit and can have a significant impact on its performance.

  • Routing

The routing step in digital circuit design is the process of determining the physical paths for interconnect wires that connect the various cells or modules of a circuit. The goal of the routing step is to minimize the total length of interconnect wires while meeting the timing, area, and power constraints of the design.

The following are the typical steps involved in the routing step of digital circuit design:

  • Routing grid generation: In this step, a routing grid is created over the cells or modules of the circuit. The routing grid is a matrix of cells that represent the physical space available for routing wires between the cells.
  • Global routing: In this step, a global router is used to determine the approximate paths for the interconnect wires between the cells. The global router takes into account the placement of the cells, the routing grid, and the design constraints.
  • Detailed routing: Once the approximate paths for the interconnect wires have been determined, a detailed router is used to refine the paths and to optimize the routing. The detailed router takes into account the specific physical characteristics of the interconnect wires, such as their width and spacing, and the design constraints.

All in all, the routing step determines the physical paths for interconnect wires that connect the various cells or modules of a circuit. This can have a significant impact on the performance, area, and power consumption of the circuit.

Chapter 2. Name Display Experiment

The experiment of name display is mainly divided into two parts, respectively LED text display and LED image display. Compared to LED text display, LED image display is more complex, it needs to use more complex state machine and dynamic scanning knowledge.

2.1 The Text Display of Name

2.1.1 Document Directory

The table below shows the file directories in the Lab1 text folder.

Table.1 Related Files of the Text Display in Lab1 Text Folder

Name Specific content

ZTY_name_display2_FDE

1. Source files

2. Generated bit files

3. Yosys compiled files

4. Packed, placed, and routed files

5. Pin constraint files.

demo

1. Demo videos

2. Demo pictures

3. Waveform pictures

tb_wave

1. Testbench file

2. Waveform file

vivado_zty_word_display

1. Vivado project file

2. Vivado source files

3. Vivado simulation files

ZTY_name_display2_Wonton Wonton project files

2.1.2 Experimental Principle

The name display takes advantage of the LED text display module in Wonton. The LCD module has its display starting at the top left corner, where the first character is shown. As each character is displayed, the display address automatically moves to the next position. Once all 32 addresses (2 rows of 16 characters) are written, the character data in the initial position is overwritten in a cyclic manner. Additionally, the user manual provides the corresponding hexadecimal codes for letters, symbols, and numbers.

The component picture and the functions of the various I/O ports are shown below.

Table.2 Different Port Functions

Port Function
DB0~DB7 Input data

RS

Register select

When it is 0, the instruction register is selected

When it is 1, the data register is selected

RW

Read/Write

When it is 0, a write operation is performed

When it is 1, no operation is performed

EN Data is transferred on the falling edge of EN

RST

RESET

When it is 1, all display data is cleared and the cursor is moved to the initial position (top left corner).

Aspose.Words.edf023e3-7755-4ecb-a3b3-627145557c7f.003

Figure.2 The Time Sequence Working Mode

Each character in the LED text display adopts the encoding rule of ASCII code, and each character corresponds to a hexadecimal code.

2.1.3 Source Code Design

Part of the sequential logic code is shown here, which is the key to led text display.

Code.1 Partial Text Display of Sequential Logic Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105


*// for text led display*

always @(posedge iClk)

`    `if(oLcdRst)

`        `countlcd    <=  8'd0;

`    `else if(countlimit)

`        `countlcd    <=  countlcd;

`    `else

`        `countlcd    <=  countlcd + 1'b1;

always @(posedge iClk)

`    `if(oLcdRst)

`        `oLcdRw  <=  1'b0;

`    `else if(countlimit)

`        `oLcdRw  <=  1'b1;

assign  oLcdRst =   iRst || iButton2 ;

assign  oLcdRs  =   1'b1;

assign  countlimit = (countlcd == 8'd255);

assign  oLcdEn = ~countlcd[2];

always @(countlcd[3] or countlcd[4] or countlcd[5] or countlcd[6] or countlcd[7] )

`    `case(countlcd[7:3])

`        `5'd0    :   oLcdData    <=  WORD0 ;

`        `5'd1    :   oLcdData    <=  WORD1 ;

`        `5'd2    :   oLcdData    <=  WORD2 ;

`        `5'd3    :   oLcdData    <=  WORD3 ;

`        `5'd4    :   oLcdData    <=  WORD4 ;

`        `5'd5    :   oLcdData    <=  WORD5 ;

`        `5'd6    :   oLcdData    <=  WORD6 ;

`        `5'd7    :   oLcdData    <=  WORD7 ;

`        `5'd8    :   oLcdData    <=  WORD8 ;

`        `5'd9    :   oLcdData    <=  WORD9 ;

`        `5'd10   :   oLcdData    <=  WORD10;

`        `5'd11   :   oLcdData    <=  WORD11;

`        `5'd12   :   oLcdData    <=  WORD12;

`        `5'd13   :   oLcdData    <=  WORD13;

`        `5'd14   :   oLcdData    <=  WORD14;

`        `5'd15   :   oLcdData    <=  WORD15;

`        `5'd16    :   oLcdData    <=  WORD16 ;

`        `5'd17    :   oLcdData    <=  WORD17 ;

`        `5'd18    :   oLcdData    <=  WORD18 ;

`        `5'd19    :   oLcdData    <=  WORD19 ;

`        `5'd20    :   oLcdData    <=  WORD20 ;

`        `5'd21    :   oLcdData    <=  WORD21 ;

`        `5'd22    :   oLcdData    <=  WORD22 ;

`        `5'd23    :   oLcdData    <=  WORD23 ;

`        `5'd24    :   oLcdData    <=  WORD24 ;

`        `5'd25    :   oLcdData    <=  WORD25 ;

`        `5'd26   :   oLcdData    <=  WORD26;

`        `5'd27   :   oLcdData    <=  WORD27;

`        `5'd28   :   oLcdData    <=  WORD28;

`        `5'd29   :   oLcdData    <=  WORD29;

`        `5'd30   :   oLcdData    <=  WORD30;

`        `5'd31   :   oLcdData    <=  WORD31;

`    `endcase

The code consists of a series of always blocks and assign statements. The first always block is triggered on the positive edge of the input clock signal (iClk). It includes an if-else statement that checks the state of the oLcdRst signal, which is used to reset the LED display. If the oLcdRst signal is high, then the countlcd variable is set to 0. If the countlimit condition is met, then the countlcd variable is not updated. Otherwise, the countlcd variable is incremented by 1.

The second always block is also triggered on the positive edge of the input clock signal (iClk). It updates the oLcdRw signal, which is used to control the read/write operations of the LED display. If the oLcdRst signal is high, then the oLcdRw signal is set to 0 (write operation). If the countlimit condition is met, then the oLcdRw signal is set to 1 (no operation).

The assign statements are used to assign values to various signals. The oLcdRst signal is assigned the logical OR of the iRst and iButton2 signals. The oLcdRs signal is always set to 1, indicating that the data being transferred is a character data. The countlimit signal is assigned based on the value of the countlcd variable. It is set to 1 when the countlcd variable is equal to 255. The oLcdEn signal is assigned the complement of the bit at position 2 in the countlcd variable.

The final always block is triggered by changes in the countlcd variable. It uses a case statement to assign values to the oLcdData signal based on the value of the countlcd variable. The oLcdData signal represents the data being transferred to the LED display.

2.2 The Image Display of Name

2.2.1 Document Directory

The table below shows the file directories in the Lab1 image folder.

Table.3 Related Files of the Text Display in Lab1 Image Folder

Name Specific content

ZTY_name_display_FDE

1. Source files

2. Generated bit files

3. Yosys compiled files

4. Packed, placed, and routed files

5. Pin constraint files.

demo

1. Demo videos

2. Demo pictures

3. Waveform pictures

tb_simulation

1. Testbench file

2. Waveform file

vivado_zty_image_display

1.Vivado project file

2.Vivado source files

3.Vivado simulation files

ZTY_name_display_Wonton Wonton project files

2.1.2 Experimental Principle

The LED image display uses LED image display in the Wonton software, as shown in the figure below.

Figure.5 LED Image Display

The port of this component is defined as shown in the following table.

Port Function
DB0~DB7 Data input

DI

Register selection port

0: Enter command mode (select command register)

1: Enter data mode (select data bits register)

RW

Read/Write

0: write data

1: No operation

EN Enable signal. Data incoming port on negedge
CS1 Left half screen
CS2 Right half screen
RST Clear the data in the display and mem

Table.4 the Port of this Component

The device has an overall pixel resolution of 128x64, which is divided into two 64x64 screens. Each screen is made up of eight 64x8 small screens, with x and y-axis address coordinates shown in the provided figure. When data is written to the memory (MEM), the Y-coordinate automatically moves to the next position, and resets to 0 when Y=63.

For generating specific text pixels, the pctolcd2002 software is used. The displayed text and pixel generation for this experiment are shown in the figure.

To display a word, both the left and right screens are divided into 8-bit x 8 pixels on the x-axis and 64 pixels on the y-axis. An 8-bit x 64 MEM is built into the LED, so 8 pages need to be lit. Each page is illuminated for 68 clock cycles, with the start display address set in cycle 1, the page set in cycle 2, and the Y address set in cycle 3. Cycles 4 to 67 load data into MEM (with one row of data (1 x 8) loaded in each cycle), and cycle 68 illuminates that segment of the screen. Therefore, to display each word, 68 x 8 = 544 cycles are required.

2.2.3 Source Code Design

  • Generate Current Display

Code.2 Generate Current Display

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47


always @(posedge clock)

begin

`  `if(input\_rst)

`    `current\_display <= 0;

`else

`  `begin

`    `if(current\_state == 2 || current\_state == 5 || current\_state == 8)

`        `current\_display <= 0;

`    `else

`    `begin

`        `if(count\_clock == 68

`        `||count\_clock == 136

`        `||count\_clock == 204

`        `||count\_clock == 272

`        `||count\_clock == 340

`        `||count\_clock == 408

`        `||count\_clock == 476

`        `||count\_clock == 544

`        `)

`            `current\_display <= current\_display + 1;

`    `end

`  `end

end

This code is describing the functionality of an always block that is triggered on the positive edge of a clock signal. It first checks whether an input reset signal is active, and if so, sets the “current_display” variable to 0. Otherwise, it proceeds with additional checks.

If the current state is 2, 5, or 8, “current_display” is set to 0. However, if the count_clock value matches one of the specified clock cycle values (68, 136, 204, 272, 340, 408, 476, or 544), “current_display” is incremented by 1.

Essentially, this code is responsible for updating the “current_display” variable based on certain conditions related to the current state and clock cycle count.

  • Generate Count Clock

Code.3 Generate Count Clock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
always @(posedge clock)

begin

`  `if(input\_rst)

`        `count\_clock <= 0;

`else begin

`    `if((current\_state == 0 && count\_clock == 544)

`    `|| (current\_state == 1 && count\_clock == 544)

`    `|| (current\_state == 2 && count\_clock == 500)

`    `|| (current\_state == 3 && count\_clock == 544)

`    `|| (current\_state == 4 && count\_clock == 544)

`    `|| (current\_state == 5 && count\_clock == 500)

`    `|| (current\_state == 6 && count\_clock == 544)

`    `|| (current\_state == 7 && count\_clock == 544)

`    `|| (current\_state == 8 && count\_clock == 500)

`    `)

`        `count\_clock <= 1;

`    `else

`        `count\_clock <= count\_clock + 1;

`  `end

End

This code is describing the functionality of an always block that is triggered on the positive edge of a clock signal. It first checks whether an input reset signal is active, and if so, sets the “current_state” variable to 0. Otherwise, it proceeds with additional checks.

If the current state is 0 and the count_clock value is equal to 544, “current_state” is incremented by 1. This same logic is applied for each of the following states: 1, 2, 3, 4, 5, 6, and 7. However, if the current state is 8 and the count_clock value is equal to 500, “current_state” is set back to 0.

Essentially, this code is responsible for updating the “current_state” variable based on certain conditions related to the current state and clock cycle count. These conditions are used to control the timing and sequencing of the LED display in the overall system.

  • Generate Current State

Code.4 Generate Current State

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53


always @(posedge clock)

begin

`  `if(input\_rst)

`    `current\_state <= 0;

`else

`  `begin

`    `if(current\_state == 0 && count\_clock == 544)

`        `current\_state <= current\_state + 1;

`    `if(current\_state == 1 && count\_clock == 544)

`        `current\_state <= current\_state + 1;

`    `if(current\_state == 2 && count\_clock == 500)

`        `current\_state <= current\_state + 1;

`    `if(current\_state == 3 && count\_clock == 544)

`        `current\_state <= current\_state + 1;

`    `if(current\_state == 4 && count\_clock == 544)

`        `current\_state <= current\_state + 1;

`    `if(current\_state == 5 && count\_clock == 500)

`        `current\_state <= current\_state + 1;

`    `if(current\_state == 6 && count\_clock == 544)

`        `current\_state <= current\_state + 1;

`    `if(current\_state == 7 && count\_clock == 544)

`        `current\_state <= current\_state + 1;

`    `if(current\_state == 8 && count\_clock == 500)

`        `current\_state <= 0;

`  `end

end

This code is describing the functionality of an always block that is triggered on the positive edge of a clock signal. It first checks whether an input reset signal is active, and if so, sets the “current_state” variable to 0. Otherwise, it proceeds with additional checks.

If the current state is 0 and the count_clock value is equal to 544, “current_state” is incremented by 1. This same logic is applied for each of the following states: 1, 2, 3, 4, 5, 6, and 7. However, if the current state is 8 and the count_clock value is equal to 500, “current_state” is set back to 0.

  • Generate Current DI

Code.5 Generate Current DI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
always @(posedge clock)

begin

`  `if(input\_rst)

`    `current\_di <= 0;

`else

`  `begin

`    `if(count\_clock == 0

`    `||count\_clock == 67

`    `||count\_clock == 135

`    `||count\_clock == 203

`    `||count\_clock == 271

`    `||count\_clock == 339

`    `||count\_clock == 407

`    `||count\_clock == 475

`    `||count\_clock == 543

`    `)

`        `current\_di <= 0;

`    `if(count\_clock == 3

`    `||count\_clock == 71

`    `||count\_clock == 139

`    `||count\_clock == 207

`    `||count\_clock == 275

`    `||count\_clock == 343

`    `||count\_clock == 411

`    `||count\_clock == 479

`    `)

`        `current\_di <= 1;

`  `end

end

This code is describing an always block that is triggered on the positive edge of a clock signal. It first checks whether an input reset signal is active, and if so, sets the “current_di” variable to 0. Otherwise, it proceeds with additional checks.

If the “count_clock” value is equal to 0, 67, 135, 203, 271, 339, 407, 475, or 543, “current_di” is set to 0. If the “count_clock” value is equal to 3, 71, 139, 207, 275, 343, 411, or 479, “current_di” is set to 1.

  • Generate r_cs

Code.6 Generate r_cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73


always @(posedge clock)

begin

`  `case(current\_state)

`  `'d0:begin

`      `r\_cs1 <= 1;

`      `r\_cs2 <= 0;end

`  `'d1:begin

`      `r\_cs1 <= 0;

`      `r\_cs2 <= 1;end

`  `'d2:begin

`      `r\_cs1 <= 0;

`      `r\_cs2 <= 0;end

`  `'d3:begin

`      `r\_cs1 <= 1;

`      `r\_cs2 <= 0;end

`  `'d4:begin

`      `r\_cs1 <= 0;

`      `r\_cs2 <= 1;end

`  `'d5:begin

`      `r\_cs1 <= 0;

`      `r\_cs2 <= 0;end

`  `'d6:begin

`      `r\_cs1 <= 1;

`      `r\_cs2 <= 0;end

`  `'d7:begin

`      `r\_cs1 <= 0;

`      `r\_cs2 <= 1;end

`  `'d8:begin

`      `r\_cs1 <= 0;

`      `r\_cs2 <= 0;end

`  `default:begin

`      `r\_cs1 <= 0;

`      `r\_cs2 <= 0;

`  `end

`  `endcase

end

This code uses a case statement to determine the appropriate chip select signal to activate for the current state. The signals r_cs1 and r_cs2 are assigned different values based on the current state. This code is used to control the display of specific text on the two-screen LCD display.

  • Generate Data

Code.7 Generate Data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117


always @(posedge clock)

begin

`    `if(input\_rst)

`        `r\_db =  0;

`    `else

`    `begin

`    `if(count\_clock == 68

`    `||count\_clock == 136

`    `||count\_clock == 204

`    `||count\_clock == 272

`    `||count\_clock == 340

`    `||count\_clock == 408

`    `||count\_clock == 476

`    `||count\_clock == 544

`    `)

`        `r\_db =  8'b00111110;

`    `else if(count\_clock == 1

`    `||count\_clock == 69

`    `||count\_clock == 137

`    `||count\_clock == 205

`    `||count\_clock == 273

`    `||count\_clock == 341

`    `||count\_clock == 409

`    `||count\_clock == 477

`    `)

`        `r\_db =  8'b11000000;

`    `else if(count\_clock == 2

`    `||count\_clock == 70

`    `||count\_clock == 138

`    `||count\_clock == 206

`    `||count\_clock == 274

`    `||count\_clock == 342

`    `||count\_clock == 410

`    `||count\_clock == 478

`    `)

`        `r\_db =  {5'b10111, current\_display};

`    `else if(count\_clock == 3

`    `||count\_clock == 71

`    `||count\_clock == 139

`    `||count\_clock == 207

`    `||count\_clock == 275

`    `||count\_clock == 343

`    `||count\_clock == 411

`    `||count\_clock == 479

`    `)

`        `r\_db =  8'b01000000;

`    `else

`    `case(current\_state)

`    `0:begin

`        `case(count\_clock)

'd4: r\_db = 'h0;

` `'d5: r\_db = 'h0;

` `'d6: r\_db = 'h0;

` `'d7: r\_db = 'h0;

` `'d8: r\_db = 'h0;

` `'d9: r\_db = 'h0;

` `'d10: r\_db = 'h0;

**······//leave out the data because it is very large**

The code checks for a reset signal and sets the value of “r_db” accordingly. If the reset signal is not asserted, the code checks the value of “count_clock” and sets “r_db” to a specific value based on its value and the current state of the circuit.

The code uses a case statement to set the value of “r_db” based on the current state of the circuit and the value of “count_clock”. If “count_clock” is not equal to any of the specified values, the code falls through to the default case. The values assigned to “r_db” in each case are expressed in hexadecimal notation.

Chapter 3. Aerial Combat Game

  1. Document Directory

    The table below shows the file directories in the Lab2 aerial combat folder.

Table.5 Related Files of the Text Display in Lab1 Image Folder

Name Specific content

aerial_combat_FDE_yosys

1.Source files

2.Generated bit files

3.Yosys compiled files

4.Packed, placed, and routed files

5.Pin constraint files.

demo

1.Demo videos

2.Waveform pictures and files

tb_simulation

1.Testbench file

2.Waveform file

vivado_project_plane

1.Vivado project file

2.Vivado source files

3.Vivado simulation files

aerial_combat_Wonton Wonton project files
  1. Game Introduction

The whole game is implemented through Wonton software. The game is mainly divided into the following parts, respectively is the control of the start of the game switch, the control of the aircraft movement and shooting button, the game interface display, the score of the seven sections of the digital tube display and LED display.

Here are the rules of the game:

1. Enemy plane is falling from the top of the screen, and our plane is at the bottom at first.

2. The up, down, left and right movements of the aircraft are controlled by the four buttons.

3. The button in the middle controls the aircraft to shoot upward. When the bullet hits the enemy aircraft, the bullet and the enemy aircraft disappear from the current position and the enemy aircraft refreshes from the top of the screen.

4. The initial score is 1 point. Bonus points are awarded after hitting an enemy plane, for a total of 8 points. The higher the score, the more leds are lit below.When all the LED lights are on, that is, after shooting down 8 enemy aircraft, the game is won.

5. If our plane collides with the enemy plane, the game fails.

  1. Source Code Structure

The overall framework of the game, shown here, is designed from the top down.

First of all, the top layer of the entire game becomes the bridge between the various modules of data transmission. The input of the top module is the clock signal, reset signal and signal related to mobile shooting, and the output is the row selection signal and column selection signal of the LED16*16 array, as well as the signal of the control LED and seven segment tube.

The clock_divider module is used to divide the clock frequency. Since dynamic scanning of the LED matrix and game running require different clock frequencies, the clock_divier module generates a clk_out signal that is slower than the original clk signal and feeds it to the game_logic module, LED_score_display module and seven_segment module. The dynamically scanned display module still uses the clk signal with the original faster frequency.

The game control module controls the game. The game control module includes control of aircraft and bullet movement, collision determination and game_matrix update. game_matrix is equivalent to a RAM that is flushed every clock cycle. The game_matrix data will be fed to the dynamically scanned display module, which is used to generate row selection signals and column selection signals to control the LED matrix. In addition, the game control module also generates scores, which are fed to the LED_score_display module and the seven_segment module to generate the final score.

In general, the overall design framework adopts the MVC(Model-View-Controller) design pattern. The game_marix matrix stores information about aircraft and bullet models. Dynamic scanning of LED matrix, seven sections of digital tube and LED display game interface and score effect.Finally through game_logic module we can control the game.

  • Clock_divider

Code.7 Clock_divider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41


module **clk\_divider** (

`    `input wire clk,

`    `input wire rst\_n,

`    `output reg clk\_out

);

`    `reg [23:0] counter = 24'd0;

`    `always @(posedge clk or negedge rst\_n) begin

`        `if (!rst\_n) begin

`            `counter <= 24'd0;

`            `clk\_out <= 0;

`        `end else begin

`            `if (counter == 24'd10) begin

`                `counter <= 24'd0;

`                `clk\_out <= ~clk\_out;

`            `end else begin

`                `counter <= counter + 1;

`            `end

`        `end

`    `end

endmodule

This code describes a clock divider module. The module takes an input clock signal and produces an output clock signal that is divided by a factor of 10.

The code uses an “always” block that is triggered by a positive edge of the input clock signal or a negative edge of the reset signal. Inside the “always” block, the code checks the value of the reset signal. If the reset signal is asserted, the counter and output clock signals are reset to 0. If the reset signal is not asserted, the code increments the counter by 1 on each clock cycle. When the counter reaches a value of 10, the counter is reset to 0 and the output clock signal is toggled.

  • Display

Code.8 Display module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51


module **display** (

`    `input wire clk,

`    `input wire rst\_n,

`    `input wire [255:0] game\_matrix,

`    `output reg [15:0] row\_sel,

`    `output reg [15:0] col\_sel

);

`    `reg [3:0] row\_counter = 4'd0;

`    `always @(posedge clk or negedge rst\_n) begin

`        `if (!rst\_n) begin

`            `row\_counter <= 4'd0;

`            `row\_sel <= 16'h0001;

`            `col\_sel <= 16'h0000;

`        `end else begin

`            `if (row\_counter == 4'd15) begin

`                `row\_counter <= 4'd0;

`                `row\_sel <= 16'h0001;

`            `end else begin

`                `row\_counter <= row\_counter + 1;

`                `row\_sel <= row\_sel << 1;

`            `end

`            `col\_sel <= game\_matrix[16\*row\_counter +: 16];

`        `end

`    `end

endmodule

This code defines a module for a display driver that generates output signals to drive a display based on an input game matrix. The module takes an input game matrix represented as a 256-bit signal, an input clock signal, and a reset signal. The module produces two 16-bit output signals, row_sel and col_sel, which are used to drive the row and column select lines of the display.

The row_sel output signal is generated by shifting a binary value to select one row of the display at a time. The row counter is used to keep track of which row is currently being selected. When the row counter reaches a value of 15, it is reset to 0 and the row_sel signal is set to its initial value.The col_sel output signal is generated by selecting the corresponding 16-bit value from the game matrix for the current row being displayed. The value is updated on each clock cycle.

  • LED_score_display

Code.9 LED_score_display

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51


module **LED\_score\_display**(

input wire clk,

input wire rst\_n,

input wire [7:0]score,

output reg [7:0]LED

`    `);



`    `always@(posedge clk or negedge rst\_n)begin

`    `if(!rst\_n)begin

`    `LED<=8'b00000000;

`    `end else begin

`    `case(score)

`    `8'd0:begin LED<=8'b00000000; end

`    `8'd1:begin LED<=8'b00000001; end

`    `8'd2:begin LED<=8'b00000011; end

`    `8'd3:begin LED<=8'b00000111; end

`    `8'd4:begin LED<=8'b00001111; end

`    `8'd5:begin LED<=8'b00011111; end

`    `8'd6:begin LED<=8'b00111111; end

`    `8'd7:begin LED<=8'b01111111; end

`    `8'd8:begin LED<=8'b11111111; end

`    `default:begin LED<=8'b00000000; end

`    `endcase

`    `end

`    `end

endmodule

This code defines a module for a LED score display that takes an input score value and produces an 8-bit output signal that drives an eight-segment LED display. The output signal is updated on each positive edge of the input clock signal or negative edge of the reset signal.

If the reset signal is asserted, the output signal is set to 0. Otherwise, a case statement is used to set the output signal based on the input score value. The case statement checks the input score value and sets the output signal to a binary value that represents the corresponding LED display pattern. If the input score is not equal to any of the specified values, the output signal is set to 0.

  • Seven_segment_display

Code.10 Seven_segment_display

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
module **seven\_segment\_display**(

input wire clk,

input wire rst\_n,

input wire [7:0]score,

output reg [7:0]seven\_segment *//abcdefgh*

`    `);



`    `always@(posedge clk or negedge rst\_n)begin

`    `if(!rst\_n)begin

`    `seven\_segment<=8'b00000000;

`    `end else begin

`    `case(score)

`    `8'd0:begin seven\_segment<=8'b11111100; end

`    `8'd1:begin seven\_segment<=8'b01100000; end

`    `8'd2:begin seven\_segment<=8'b11011010; end

`    `8'd3:begin seven\_segment<=8'b11110010; end

`    `8'd4:begin seven\_segment<=8'b01100110; end

`    `8'd5:begin seven\_segment<=8'b10110110; end

`    `8'd6:begin seven\_segment<=8'b10111110; end

`    `8'd7:begin seven\_segment<=8'b11100000; end

`    `8'd8:begin seven\_segment<=8'b11111110; end

`    `default:begin seven\_segment<=8'b00000000; end

`    `endcase

`    `end

`    `end


endmodule

This code defines a module for a seven-segment LED display that takes an input score value and produces an 8-bit output signal that drives the display. The output signal is updated on each positive edge of the input clock signal or negative edge of the reset signal.

If the reset signal is asserted, the output signal is set to a binary value that turns off all the segments. Otherwise, a case statement is used to set the output signal based on the input score value. The case statement checks the input score value and sets the output signal to a binary value that represents the corresponding display pattern for the number. If the input score is not equal to any of the specified values, the output signal is set to a binary value that turns off all the segments.

  • Game_logic

Code.11 Game_logic

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277


module **game\_logic** (

`    `input wire clk,

`    `input wire rst\_n,

`    `input wire up,

`    `input wire down,

`    `input wire left,

`    `input wire right,

`    `input wire shoot,

`    `output reg [255:0] game\_matrix,

`    `output reg [7:0] score

);

`    `reg [7:0] plane\_position = 8'hF7;

`    `reg [7:0] bullet\_position = 8'h00;

`    `reg [7:0] enemy\_position = 8'h00;

`    `reg shoot\_reg = 0;

`    `reg [15:0] enemy\_counter = 16'd0;

`    `reg [15:0] bullet\_counter = 16'd0;

`    `reg up\_reg=0;

`    `reg down\_reg=0;

`    `reg left\_reg=0;

`    `reg right\_reg=0;

`    `reg crash;

`    `reg game\_over;



`    `always @(posedge clk or negedge rst\_n) begin

`        `if (!rst\_n) begin

`            `plane\_position <= 8'hF7;

`            `bullet\_position <= 8'h00;

`            `enemy\_position <= 8'h00;

`            `shoot\_reg <= 0;

`            `up\_reg<=0;

`            `game\_over<=0;

`            `crash<=0;

`            `down\_reg<=0;

`            `left\_reg<=0;

`            `right\_reg<=0;

`            `enemy\_counter <= 16'd0;

`            `bullet\_counter <= 16'd0;

`            `game\_matrix <= 256'b0;

`            `score <= 8'h00;

`        `end else begin

` `//control the movement of the plane

`            `if(up&&!up\_reg)begin

`            `up\_reg<=1;

`            `if (up && plane\_position[7:4] > 4'b0000) begin

`                `plane\_position <= plane\_position - 8'b00100000;

`            `end

`            `end else if (!up)begin

`            `up\_reg<=0;

`            `end



`            `if(down&&!down\_reg)begin

`            `down\_reg<=1;

`            `if (down && plane\_position[7:4] < 4'b1110) begin

`                `plane\_position <= plane\_position + 8'h10;

`            `end

`             `end else if (!down)begin

`            `down\_reg<=0;

`            `end



`            `if(left&&!left\_reg)begin

`            `left\_reg<=1;

`            `if (left && plane\_position[3:0] > 4'b0000) begin

`                `plane\_position <= plane\_position - 8'h01;

`            `end

`            `end else if (!left)begin

`            `left\_reg<=0;

`            `end



`             `if(right&&!right\_reg)begin

`            `right\_reg<=1;

`            `if (right && plane\_position[3:0] < 4'b1110) begin

`                `plane\_position <= plane\_position + 8'h01;

`            `end

`             `end else if (!right)begin

`            `right\_reg<=0;

`            `End

` `//control the shot of the bullet

`            `if (shoot && !shoot\_reg) begin

`                `shoot\_reg <= 1;

`                `bullet\_position <= plane\_position - 8'h10;

`            `end else if (!shoot) begin

`                `shoot\_reg <= 0;

`            `End

` `//use bullet\_counter to determine the speed

`            `if (bullet\_position != 8'h00) begin

`                `bullet\_counter <= bullet\_counter + 1;

`                `if (bullet\_counter == 16'd1) begin

`                    `bullet\_counter <= 16'd0;

`                    `if (bullet\_position[7:4] != 4'b0000) begin

`                        `bullet\_position <= bullet\_position - 8'h10;

`                    `end else begin

`                        `bullet\_position <= 8'h00;

`                    `end

`                `end

`            `End

` `//control the movement of the enemy

` `//use enemy\_counter to determine the speed

`            `enemy\_counter <= enemy\_counter + 1;

`            `if (enemy\_counter == 16'd1) begin

`                `enemy\_counter <= 16'd0;

`                `if (enemy\_position[7:4] < 4'b1110) begin

`                    `enemy\_position <= enemy\_position + 8'h10;

`                `end else begin

`                  `enemy\_position <= {4'b0000, enemy\_position[3:0]} + 8'h01;

`                `end

`            `End

//determine whether the bullet hits the enemy or not

`            `if (bullet\_position == enemy\_position||bullet\_position==(enemy\_position+8'h01)) begin

`                `score <= score + 8'h01;

`                `enemy\_position <= {4'b0000, enemy\_position[3:0]} + 8'h01;

`                `bullet\_position <= 8'h00;

`            `end*      

//determine whether the plane crash with the enemy

crash<=(plane\_position==enemy\_position)||((plane\_position-8'h10)==enemy\_position)||((plane\_position-8'h01)==enemy\_position)||((plane\_position+8'h01)==enemy\_position)||(plane\_position==(enemy\_position+8'h01))||((plane\_position-8'h10)==(enemy\_position+8'h01))||((plane\_position-8'h01)==(enemy\_position+8'h01))||((plane\_position+8'h01)==(enemy\_position+8'h01));

//refresh the game matrix

`         `if(crash)begin

`           `game\_matrix <= 256'b1;

`           `game\_over<=1;

`           `end

`          `else if(game\_over==0)begin  

`            `game\_matrix <= 256'b0;



`            `game\_matrix[plane\_position] <= 1;

`            `game\_matrix[plane\_position - 8'h10] <= 1;

`            `game\_matrix[plane\_position - 8'h01] <= 1;

`            `game\_matrix[plane\_position + 8'h01] <= 1;



`            `game\_matrix[enemy\_position] <= 1;

`            `game\_matrix[enemy\_position+8'h01] <= 1;



`            `if (bullet\_position != 8'h00) begin

`                `game\_matrix[bullet\_position] <= 1;

`            `end

`        `end

`    `end

`    `end

endmodule

This code defines a module for a game logic that takes several input signals representing the player’s movements and actions, and generates two output signals: a game matrix that represents the state of the game world, and a score value that represents the player’s score. The output signals are updated on each positive edge of the input clock signal or negative edge of the reset signal.

The module contains several registers that represent the positions of the player, enemy, and bullet, as well as several flags that represent the player’s actions and the game status. The logic of the module is implemented using several if-else statements and a case statement that update the position of the player, bullet, and enemy, and check for collisions and other game events.

The output game matrix is a 256-bit binary vector that represents the state of the game world, with each bit corresponding to a pixel on the game screen. The matrix is updated on each clock cycle to reflect the current position of the player, enemy, and bullet, as well as any collisions that occur.

The output score value is an 8-bit binary number that represents the player’s score, which is incremented each time the player shoots down an enemy.

Overall, this module implements the game logic for a simple shooting game that allows the player to move their character and shoot down enemy planes, while avoiding collisions and other obstacles.

Chapter 5. References

1.Principle of dynamic scanning

https://blog.csdn.net/qq_55203246/article/details/124155818

2. Electronic Design tutorial:16 *16 LED Matrix Driver

https://blog.csdn.net/geek_monkey/article/details/107622595

3.The Case statement in Verilog

https://blog.csdn.net/CLL_caicai/article/details/104395480

4.Verilog assigns a value to the array collective

https://blog.csdn.net/weixin\_34532284/article/details/112821125

5.The problem of std:bad_alloc

https://blog.csdn.net/WhereYouSink/article/details/103299432

Chapter 6. Appendices

Code.12 LED Text Display Testbench

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47


module **tb\_word\_display**();

reg clk;

reg rst;

wire oLcdEn;

wire oLcdRs;

wire  oLcdRw;

wire [7:0]  oLcdData;

wire oLcdRst;

lab0 display(

.iClk(clk),

.iRst(rst),

.oLcdEn(oLcdEn),

.oLcdRs(oLcdRs),

.oLcdRw(oLcdRw),

.oLcdData(oLcdData),

.oLcdRst(oLcdRst)

);

initial begin

#0 clk=0; rst=1;

#2 rst=0;

end

always #1 clk=~clk;

endmodule

Code.13 LED Image Display Testbench

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55


module **tb\_zty\_image\_display**();

reg clk;

reg input\_rst;

wire [7:0] db;

wire di;

wire rw;

wire en;

wire cs1;

wire cs2;

wire rst;

namedisplay display1(

.clock(clk),

.input\_rst(input\_rst),

.db(db),

.di(di),

.rw(rw),

.en(en),

.cs1(cs1),

.cs2(cs2),

.rst(rst)

);

initial begin

#0 clk=0; input\_rst=1;

#2 input\_rst=0;

end

always #1 clk=~clk;

endmodule

Code.14 Aerial Combat Testbench

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99


module **tb**();

reg clk;

reg rst\_n;

reg up;

reg down;

reg left;

reg right;

reg shoot;

wire [15:0] row\_sel;

wire [15:0] col\_sel;

wire[7:0]LED;

wire[7:0]seven\_segment;

top\_module top(

.clk(clk),

.rst\_n(rst\_n),

.up(up),

.down(down),

.left(left),

.right(right),

.shoot(shoot),

.row\_sel(row\_sel),

.col\_sel(col\_sel),

.LED(LED),

.seven\_segment(seven\_segment)

);

initial begin

#0 rst\_n=0;

clk=0;

left=0;

up=0;

right=0;

down=0;

shoot=0;

#40 rst\_n=1;

#40 left=1;

#40 left=0;

#40 up=1;

#40 up=0;

#40 shoot=1;

#40 shoot=0;

#40 right=1;

#40 right=0;

#40 left=1;

#40 left=0;

#40 shoot=1;

#40 shoot=0;

end

always #1 clk=~clk;

endmodule