initial commit
This commit is contained in:
commit
59f7d5db2e
|
@ -0,0 +1,71 @@
|
|||
# ##############################################################################
|
||||
|
||||
# iCEcube PCF
|
||||
|
||||
# Version: 2014.12.27052
|
||||
|
||||
# File Generated: Apr 27 2015 09:46:33
|
||||
|
||||
# Family & Device: iCE40HX1K
|
||||
|
||||
# Package: VQ100
|
||||
|
||||
# ##############################################################################
|
||||
|
||||
### Main FPGA Clock
|
||||
set_io i_Clk 15
|
||||
|
||||
### LED Pins:
|
||||
set_io o_LED_1 56
|
||||
set_io o_LED_2 57
|
||||
set_io o_LED_3 59
|
||||
set_io o_LED_4 60
|
||||
|
||||
## Push-Button Switches
|
||||
set_io i_Switch_1 53
|
||||
set_io i_Switch_2 51
|
||||
set_io i_Switch_3 54
|
||||
set_io i_Switch_4 52
|
||||
|
||||
### 7 Segment Outputs
|
||||
set_io o_Segment1_A 3
|
||||
set_io o_Segment1_B 4
|
||||
set_io o_Segment1_C 93
|
||||
set_io o_Segment1_D 91
|
||||
set_io o_Segment1_E 90
|
||||
set_io o_Segment1_F 1
|
||||
set_io o_Segment1_G 2
|
||||
set_io o_Segment2_A 100
|
||||
set_io o_Segment2_B 99
|
||||
set_io o_Segment2_C 97
|
||||
set_io o_Segment2_D 95
|
||||
set_io o_Segment2_E 94
|
||||
set_io o_Segment2_F 8
|
||||
set_io o_Segment2_G 96
|
||||
|
||||
## UART Outputs
|
||||
set_io i_UART_RX 73
|
||||
set_io o_UART_TX 74
|
||||
|
||||
## VGA Outputs
|
||||
set_io o_VGA_HSync 26
|
||||
set_io o_VGA_VSync 27
|
||||
set_io o_VGA_Red_0 36
|
||||
set_io o_VGA_Red_1 37
|
||||
set_io o_VGA_Red_2 40
|
||||
set_io o_VGA_Grn_0 29
|
||||
set_io o_VGA_Grn_1 30
|
||||
set_io o_VGA_Grn_2 33
|
||||
set_io o_VGA_Blu_0 28
|
||||
set_io o_VGA_Blu_1 41
|
||||
set_io o_VGA_Blu_2 42
|
||||
|
||||
## PMOD Signals
|
||||
set_io io_PMOD_1 65
|
||||
set_io io_PMOD_2 64
|
||||
set_io io_PMOD_3 63
|
||||
set_io io_PMOD_4 62
|
||||
set_io io_PMOD_7 78
|
||||
set_io io_PMOD_8 79
|
||||
set_io io_PMOD_9 80
|
||||
set_io io_PMOD_10 81
|
|
@ -0,0 +1,23 @@
|
|||
CONSTRAINTS = ../Go_Board_Constraints.pcf
|
||||
LED_TOGGLE = pong_runner.bin
|
||||
|
||||
install: $(LED_TOGGLE)
|
||||
iceprog $(LED_TOGGLE)
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
iverilog -o test uart_rx_test.v uart_rx.v
|
||||
vvp test
|
||||
gtkwave test.vcd
|
||||
|
||||
.SUFFIXES: .v .json .bitstream .bin
|
||||
|
||||
.v.json:
|
||||
yosys -q -p "hierarchy -top PongRunner; synth_ice40 -json $*.json" $*.v vga_sync_pulse_generator.v vga_current_beam_position.v vga_add_porches_to_output.v uart_rx.v uart_tx.v pong.v pong_ball.v pong_paddle.v debounce_filter.v
|
||||
|
||||
.json.bitstream:
|
||||
#nextpnr-ice40 --hx1k --freq 25 --pcf $(CONSTRAINTS) --json $*.json --package vq100 --asc $*.bitstream
|
||||
nextpnr-ice40 --hx1k --freq 25 --pcf $(CONSTRAINTS) --json $*.json --package vq100 --asc $*.bitstream
|
||||
|
||||
.bitstream.bin:
|
||||
icepack $*.bitstream $*.bin
|
|
@ -0,0 +1,28 @@
|
|||
# Go Board code reworking
|
||||
|
||||
This code is a reworking of the code for the [Go Board](https://nandland.com/the-go-board/)
|
||||
FPGA beginner's board.
|
||||
|
||||
The original code comes from two sources:
|
||||
|
||||
* [Nandland Go Board tutorials](https://nandland.com/download-and-install-the-fpga-tools-and-drivers/)
|
||||
* [Getting Started with FPGAs repo](https://github.com/nandland/getting-started-with-fpgas/)
|
||||
|
||||
Where possible I tried to:
|
||||
|
||||
* use more consistent variable and constant names
|
||||
* fix missing inferred wires (the Pong project had a lot of these)
|
||||
* avoid run-on lines of code
|
||||
* avoid one-liner conditional bodies, opting for `begin...end` blocks everywhere
|
||||
|
||||
All of these can be built with [Yosys](https://github.com/YosysHQ/yosys)
|
||||
and tested with [Icarus Verilog](https://github.com/steveicarus/iverilog). The `Makefile` is one I've been dragging along across all projects. It can fire off both a build-and-install to the Go Board, as well as run the test suite and open up [GTKWave](https://gtkwave.sourceforge.net/)
|
||||
so you can inspect the signals. You do not need Lattive iCECube2 and you will have a hard time
|
||||
getting it to run on modern Linux anyway!
|
||||
|
||||
`sipo_shift_register_test.sv` shows how to create your own `assert` for Icarus Verilog,
|
||||
taken from an idea from here: https://stackoverflow.com/a/13906120
|
||||
|
||||
Have fun.
|
||||
|
||||
John
|
|
@ -0,0 +1,44 @@
|
|||
module Binary_to_7_Segment(
|
||||
input i_Clk,
|
||||
input [$clog2(15)-1:0] i_Number,
|
||||
output o_SegA,
|
||||
output o_SegB,
|
||||
output o_SegC,
|
||||
output o_SegD,
|
||||
output o_SegE,
|
||||
output o_SegF,
|
||||
output o_SegG
|
||||
);
|
||||
|
||||
reg [6:0] r_HexEncoding;
|
||||
always @(posedge i_Clk) begin
|
||||
case (i_Number)
|
||||
0: r_HexEncoding <= 7'b1111110;
|
||||
1: r_HexEncoding <= 7'b0110000;
|
||||
2: r_HexEncoding <= 7'b1101101;
|
||||
3: r_HexEncoding <= 7'b1111001;
|
||||
4: r_HexEncoding <= 7'b0110011;
|
||||
5: r_HexEncoding <= 7'b1011011;
|
||||
6: r_HexEncoding <= 7'b1011111;
|
||||
7: r_HexEncoding <= 7'b1110000;
|
||||
8: r_HexEncoding <= 7'b1111111;
|
||||
9: r_HexEncoding <= 7'b1111011;
|
||||
10: r_HexEncoding <= 7'b1110111;
|
||||
11: r_HexEncoding <= 7'b0011111;
|
||||
12: r_HexEncoding <= 7'b1001110;
|
||||
13: r_HexEncoding <= 7'b0111101;
|
||||
14: r_HexEncoding <= 7'b1001111;
|
||||
15: r_HexEncoding <= 7'b1000111;
|
||||
default: r_HexEncoding <= 7'b0000000;
|
||||
endcase
|
||||
end
|
||||
|
||||
assign o_SegA = r_HexEncoding[6];
|
||||
assign o_SegB = r_HexEncoding[5];
|
||||
assign o_SegC = r_HexEncoding[4];
|
||||
assign o_SegD = r_HexEncoding[3];
|
||||
assign o_SegE = r_HexEncoding[2];
|
||||
assign o_SegF = r_HexEncoding[1];
|
||||
assign o_SegG = r_HexEncoding[0];
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,22 @@
|
|||
module Count_And_Toggle (
|
||||
input i_Clk,
|
||||
input i_Enable,
|
||||
output reg o_Toggle
|
||||
);
|
||||
parameter COUNT_LIMIT = 10;
|
||||
|
||||
reg [$clog2(COUNT_LIMIT - 1):0] r_Counter;
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
if (i_Enable == 1) begin
|
||||
if (r_Counter == COUNT_LIMIT - 1) begin
|
||||
o_Toggle <= !o_Toggle;
|
||||
r_Counter <= 0;
|
||||
end else begin
|
||||
r_Counter <= r_Counter + 1;
|
||||
end
|
||||
end else begin
|
||||
o_Toggle <= 0;
|
||||
end
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,30 @@
|
|||
module Debounce_Filter
|
||||
#(parameter DEBOUNCE_LIMIT = 20) (
|
||||
input i_Clk,
|
||||
input i_Bouncy,
|
||||
output o_Debounced
|
||||
);
|
||||
|
||||
reg [$clog2(DEBOUNCE_LIMIT)-1:0] r_Count = 0;
|
||||
reg r_State = 1'b0;
|
||||
|
||||
always @(posedge i_Clk)
|
||||
begin
|
||||
if (i_Bouncy !== r_State && r_Count < DEBOUNCE_LIMIT - 1)
|
||||
begin
|
||||
r_Count <= r_Count + 1;
|
||||
end
|
||||
else if (r_Count == DEBOUNCE_LIMIT - 1)
|
||||
begin
|
||||
r_State <= i_Bouncy;
|
||||
r_Count <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
r_Count <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
assign o_Debounced = r_State;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,19 @@
|
|||
module Debounce_Project_Top(
|
||||
input i_Clk,
|
||||
input i_Switch_1,
|
||||
output o_LED_1
|
||||
);
|
||||
wire w_Debounced_Switch;
|
||||
|
||||
Debounce_Filter #(.DEBOUNCE_LIMIT(250000)) Debounce_Inst (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Bouncy(i_Switch_1),
|
||||
.o_Debounced(w_Debounced_Switch)
|
||||
);
|
||||
|
||||
LED_Toggle_Project LED_Toggle_Inst (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Switch_1(w_Debounced_Switch),
|
||||
.o_LED_1(o_LED_1)
|
||||
);
|
||||
endmodule
|
|
@ -0,0 +1,14 @@
|
|||
module Demux_1_to_4(
|
||||
input i_Data,
|
||||
input i_Sel0,
|
||||
input i_Sel1,
|
||||
output o_Data0,
|
||||
output o_Data1,
|
||||
output o_Data2,
|
||||
output o_Data3
|
||||
);
|
||||
assign o_Data0 = i_Data & !i_Sel0 & !i_Sel1;
|
||||
assign o_Data1 = i_Data & i_Sel0 & !i_Sel1;
|
||||
assign o_Data2 = i_Data & !i_Sel0 & i_Sel1;
|
||||
assign o_Data3 = i_Data & i_Sel0 & i_Sel1;
|
||||
endmodule
|
|
@ -0,0 +1,180 @@
|
|||
module FIFO(
|
||||
input i_Clock,
|
||||
|
||||
input i_writeDataReady_Flash,
|
||||
input [WIDTH_BITS-1:0] i_writeData,
|
||||
input [$clog2(DEPTH_WORDS)-1:0] i_almostFullLevel,
|
||||
output o_almostFull,
|
||||
output o_Full,
|
||||
|
||||
input i_doRead_Flash,
|
||||
output reg o_readDataReady,
|
||||
output reg [WIDTH_BITS-1:0] o_readData,
|
||||
input [$clog2(DEPTH_WORDS)-1:0] i_almostEmptyLevel,
|
||||
output o_almostEmpty,
|
||||
output o_Empty,
|
||||
|
||||
input i_Reset_Low
|
||||
);
|
||||
parameter WIDTH_BITS = 8;
|
||||
parameter DEPTH_WORDS = 16;
|
||||
|
||||
reg [WIDTH_BITS-1:0] r_RAM [DEPTH_WORDS-1:0];
|
||||
reg [$clog2(DEPTH_WORDS)-1:0] r_writeAddress;
|
||||
reg [$clog2(DEPTH_WORDS)-1:0] r_readAddress;
|
||||
reg [$clog2(DEPTH_WORDS)-1:0] r_Count;
|
||||
|
||||
always @(posedge i_Clock or negedge i_Reset_Low) begin
|
||||
if (~i_Reset_Low) begin
|
||||
r_writeAddress <= 0;
|
||||
r_readAddress <= 0;
|
||||
r_Count <= 0;
|
||||
end else begin
|
||||
if (i_writeDataReady_Flash) begin
|
||||
r_RAM[r_writeAddress] <= i_writeData;
|
||||
|
||||
if (r_writeAddress == DEPTH_WORDS - 1) begin
|
||||
r_writeAddress <= 0;
|
||||
end else begin
|
||||
r_writeAddress <= r_writeAddress + 1;
|
||||
end
|
||||
end
|
||||
|
||||
if (i_doRead_Flash) begin
|
||||
o_readData <= r_RAM[r_readAddress];
|
||||
o_readDataReady <= i_doRead_Flash;
|
||||
|
||||
if (r_readAddress == DEPTH_WORDS - 1) begin
|
||||
r_readAddress <= 0;
|
||||
end else begin
|
||||
r_readAddress <= r_readAddress + 1;
|
||||
end
|
||||
end
|
||||
|
||||
if (i_doRead_Flash & ~i_writeDataReady_Flash) begin
|
||||
if (r_Count != 0) begin
|
||||
r_Count <= r_Count - 1;
|
||||
end
|
||||
end else if (i_writeDataReady_Flash & ~i_doRead_Flash) begin
|
||||
if (r_Count != DEPTH_WORDS) begin
|
||||
r_Count <= r_Count + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign o_Full = (
|
||||
r_Count == DEPTH_WORDS
|
||||
) || (
|
||||
r_Count == DEPTH_WORDS-1 &&
|
||||
i_writeDataReady_Flash &&
|
||||
!i_doRead_Flash
|
||||
);
|
||||
assign o_Empty = (r_Count == 0);
|
||||
|
||||
assign o_almostFull = (r_Count > DEPTH_WORDS - i_almostFullLevel);
|
||||
assign o_almostEmpty = (r_Count < i_almostEmptyLevel);
|
||||
endmodule
|
||||
|
||||
module TestFIFO();
|
||||
reg r_Clk = 0;
|
||||
|
||||
always #1 r_Clk <= !r_Clk;
|
||||
|
||||
reg r_Reset_Low = 0;
|
||||
|
||||
reg r_writeDataReady_Flash = 0;
|
||||
reg [7:0] r_writeData = 50;
|
||||
reg [3:0] r_almostFullLevel = 4;
|
||||
|
||||
wire w_almostFull;
|
||||
wire w_Full;
|
||||
|
||||
reg r_doReadFlash = 0;
|
||||
wire w_readDataReady;
|
||||
wire [7:0] w_readData;
|
||||
reg [3:0] r_almostEmptyLevel = 4;
|
||||
wire w_almostEmpty;
|
||||
wire w_Empty;
|
||||
|
||||
FIFO myFifo(
|
||||
.i_Clock(r_Clk),
|
||||
.i_Reset_Low(r_Reset_Low),
|
||||
|
||||
.i_writeDataReady_Flash(r_writeDataReady_Flash),
|
||||
.i_writeData(r_writeData),
|
||||
.i_almostFullLevel(r_almostFullLevel),
|
||||
.o_almostFull(w_almostFull),
|
||||
.o_Full(w_Full),
|
||||
|
||||
.i_doRead_Flash(r_doReadFlash),
|
||||
.o_readDataReady(w_readDataReady),
|
||||
.o_readData(w_readData),
|
||||
.i_almostEmptyLevel(r_almostEmptyLevel),
|
||||
.o_almostEmpty(w_almostEmpty),
|
||||
.o_Empty(w_Empty)
|
||||
);
|
||||
|
||||
initial begin
|
||||
$dumpfile("test.vcd");
|
||||
$dumpvars;
|
||||
|
||||
#2;
|
||||
|
||||
r_Reset_Low <= 1;
|
||||
|
||||
#2;
|
||||
|
||||
r_writeDataReady_Flash <= 1;
|
||||
|
||||
#2;
|
||||
|
||||
r_writeDataReady_Flash <= 0;
|
||||
|
||||
#2;
|
||||
|
||||
r_writeData = 69;
|
||||
r_writeDataReady_Flash <= 1;
|
||||
#2;
|
||||
r_writeDataReady_Flash <= 0;
|
||||
#2;
|
||||
|
||||
r_writeDataReady_Flash <= 1;
|
||||
#2;
|
||||
r_writeDataReady_Flash <= 0;
|
||||
#2;
|
||||
|
||||
r_writeDataReady_Flash <= 1;
|
||||
#2;
|
||||
r_writeDataReady_Flash <= 0;
|
||||
#2;
|
||||
|
||||
r_writeDataReady_Flash <= 1;
|
||||
#2;
|
||||
r_writeDataReady_Flash <= 0;
|
||||
#2;
|
||||
|
||||
r_writeDataReady_Flash <= 1;
|
||||
#2;
|
||||
r_writeDataReady_Flash <= 0;
|
||||
#2;
|
||||
|
||||
r_doReadFlash <= 1;
|
||||
|
||||
#2;
|
||||
|
||||
r_doReadFlash <= 0;
|
||||
|
||||
#2;
|
||||
|
||||
r_doReadFlash <= 1;
|
||||
|
||||
#2;
|
||||
|
||||
r_doReadFlash <= 0;
|
||||
|
||||
#2;
|
||||
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,20 @@
|
|||
module LED_Toggle_Project(
|
||||
input i_Clk,
|
||||
input i_Switch_1,
|
||||
output o_LED_1
|
||||
);
|
||||
reg r_LED_1 = 1'b0;
|
||||
reg r_Switch_1 = 1'b0;
|
||||
|
||||
always @(posedge i_Clk)
|
||||
begin
|
||||
r_Switch_1 <= i_Switch_1;
|
||||
|
||||
if (i_Switch_1 == 1'b0 && r_Switch_1 == 1'b1)
|
||||
begin
|
||||
r_LED_1 <= ~r_LED_1;
|
||||
end
|
||||
end
|
||||
|
||||
assign o_LED_1 = r_LED_1;
|
||||
endmodule
|
|
@ -0,0 +1,18 @@
|
|||
module LFSR(
|
||||
input i_Clk,
|
||||
output [SIZE-1:0] o_LFSR_Data,
|
||||
output o_LFSR_Done
|
||||
);
|
||||
parameter SIZE = 22;
|
||||
|
||||
reg [SIZE-1:0] r_LFSR;
|
||||
wire w_XNOR;
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
r_LFSR <= {r_LFSR[SIZE-2:0], w_XNOR};
|
||||
end
|
||||
|
||||
assign w_XNOR = r_LFSR[SIZE-1] ^~ r_LFSR[SIZE-2];
|
||||
assign o_LFSR_Done = (r_LFSR == 0);
|
||||
assign o_LFSR_Data = r_LFSR;
|
||||
endmodule
|
|
@ -0,0 +1,181 @@
|
|||
module Pong(
|
||||
input i_Clk,
|
||||
input i_HSync,
|
||||
input i_VSync,
|
||||
|
||||
input i_GameStart,
|
||||
|
||||
input i_Player1_Up,
|
||||
input i_Player1_Down,
|
||||
input i_Player2_Up,
|
||||
input i_Player2_Down,
|
||||
|
||||
output reg o_HSync,
|
||||
output reg o_VSync,
|
||||
output [2:0] o_Red,
|
||||
output [2:0] o_Green,
|
||||
output [2:0] o_Blue
|
||||
);
|
||||
parameter TOTAL_COLUMNS = 800;
|
||||
parameter TOTAL_ROWS = 525;
|
||||
|
||||
parameter ACTIVE_COLUMNS = 640;
|
||||
parameter ACTIVE_ROWS = 480;
|
||||
|
||||
localparam SCREEN_WIDTH_CELLS = 40;
|
||||
localparam SCREEN_HEIGHT_CELLS = 30;
|
||||
localparam SCORE_LIMIT = 9;
|
||||
localparam PADDLE_HEIGHT = 6;
|
||||
localparam PADDLE_PLAYER1_X = 0;
|
||||
localparam PADDLE_PLAYER2_X = SCREEN_WIDTH_CELLS - 1;
|
||||
|
||||
localparam STATE_IDLE = 0;
|
||||
localparam STATE_RUNNING = 1;
|
||||
localparam STATE_P1_WINNER = 2;
|
||||
localparam STATE_P2_WINNER = 3;
|
||||
localparam STATE_CLEANUP = 4;
|
||||
|
||||
reg [2:0] r_currentState = STATE_IDLE;
|
||||
|
||||
wire w_HSync, w_VSync;
|
||||
wire [9:0] w_X, w_Y;
|
||||
|
||||
wire w_P1_DoDrawPaddle, w_P2_DoDrawPaddle;
|
||||
wire [5:0] w_P1_PaddleY, w_P2_PaddleY;
|
||||
wire w_DoDrawBall, w_DrawAny;
|
||||
wire [5:0] w_BallX, w_BallY;
|
||||
wire w_IsGameActive;
|
||||
|
||||
reg [3:0] r_P1_Score = 0;
|
||||
reg [3:0] r_P2_Score = 0;
|
||||
|
||||
wire [5:0] w_CellX, w_CellY;
|
||||
|
||||
VGA_Current_Beam_Position #(
|
||||
.TOTAL_COLUMNS(TOTAL_COLUMNS),
|
||||
.TOTAL_ROWS(TOTAL_ROWS)
|
||||
) CurrentPosition (
|
||||
.i_Clk(i_Clk),
|
||||
.i_HSync(i_HSync),
|
||||
.i_VSync(i_VSync),
|
||||
.o_HSync(w_HSync),
|
||||
.o_VSync(w_VSync),
|
||||
.o_X(w_X),
|
||||
.o_Y(w_Y)
|
||||
);
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
o_HSync <= w_HSync;
|
||||
o_VSync <= w_VSync;
|
||||
end
|
||||
|
||||
// right shift 4
|
||||
assign w_CellX = w_X[9:4];
|
||||
assign w_CellY = w_Y[9:4];
|
||||
|
||||
// paddles
|
||||
|
||||
PongPaddle #(
|
||||
.X_POS_CELLS(PADDLE_PLAYER1_X),
|
||||
.SCREEN_HEIGHT_CELLS(SCREEN_HEIGHT_CELLS),
|
||||
.PADDLE_HEIGHT_CELLS(PADDLE_HEIGHT)
|
||||
) P1_Paddle (
|
||||
.i_Clk(i_Clk),
|
||||
.i_CellX(w_CellX),
|
||||
.i_CellY(w_CellY),
|
||||
.i_PaddleUp(i_Player1_Up),
|
||||
.i_PaddleDown(i_Player1_Down),
|
||||
.o_DoDrawPaddle(w_P1_DoDrawPaddle),
|
||||
.o_PaddleY(w_P1_PaddleY)
|
||||
);
|
||||
|
||||
PongPaddle #(
|
||||
.X_POS_CELLS(PADDLE_PLAYER2_X),
|
||||
.SCREEN_HEIGHT_CELLS(SCREEN_HEIGHT_CELLS),
|
||||
.PADDLE_HEIGHT_CELLS(PADDLE_HEIGHT)
|
||||
) P2_Paddle (
|
||||
.i_Clk(i_Clk),
|
||||
.i_CellX(w_CellX),
|
||||
.i_CellY(w_CellY),
|
||||
.i_PaddleUp(i_Player2_Up),
|
||||
.i_PaddleDown(i_Player2_Down),
|
||||
.o_DoDrawPaddle(w_P2_DoDrawPaddle),
|
||||
.o_PaddleY(w_P2_PaddleY)
|
||||
);
|
||||
|
||||
PongBall #(
|
||||
.SCREEN_WIDTH_CELLS(SCREEN_WIDTH_CELLS),
|
||||
.SCREEN_HEIGHT_CELLS(SCREEN_HEIGHT_CELLS)
|
||||
) Ball (
|
||||
.i_Clk(i_Clk),
|
||||
.i_IsGameActive(w_IsGameActive),
|
||||
.i_CellX(w_CellX),
|
||||
.i_CellY(w_CellY),
|
||||
.o_DoDrawBall(w_DoDrawBall),
|
||||
.o_BallX(w_BallX),
|
||||
.o_BallY(w_BallY)
|
||||
);
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
case (r_currentState)
|
||||
STATE_IDLE:
|
||||
begin
|
||||
if (i_GameStart) begin
|
||||
r_currentState <= STATE_RUNNING;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_RUNNING:
|
||||
begin
|
||||
if (
|
||||
w_BallX == 0 && (
|
||||
w_BallY < w_P1_PaddleY ||
|
||||
w_BallY > w_P1_PaddleY + PADDLE_HEIGHT
|
||||
)
|
||||
) begin
|
||||
r_currentState <= STATE_P1_WINNER;
|
||||
end else if (
|
||||
w_BallX == SCREEN_WIDTH_CELLS - 1 && (
|
||||
w_BallY < w_P2_PaddleY ||
|
||||
w_BallY > w_P2_PaddleY + PADDLE_HEIGHT
|
||||
)
|
||||
) begin
|
||||
r_currentState <= STATE_P2_WINNER;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_P1_WINNER:
|
||||
begin
|
||||
if (r_P1_Score == SCORE_LIMIT - 1) begin
|
||||
r_P1_Score <= 0;
|
||||
end else begin
|
||||
r_P1_Score <= r_P1_Score + 1;
|
||||
r_currentState <= STATE_CLEANUP;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_P2_WINNER:
|
||||
begin
|
||||
if (r_P2_Score == SCORE_LIMIT - 1) begin
|
||||
r_P2_Score <= 0;
|
||||
end else begin
|
||||
r_P2_Score <= r_P2_Score + 1;
|
||||
r_currentState <= STATE_CLEANUP;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_CLEANUP:
|
||||
begin
|
||||
r_currentState <= STATE_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
assign w_IsGameActive = (r_currentState == STATE_RUNNING) ? 1 : 0;
|
||||
|
||||
assign w_DrawAny = w_DoDrawBall | w_P1_DoDrawPaddle | w_P2_DoDrawPaddle;
|
||||
|
||||
assign o_Red = w_DrawAny ? 7 : 0;
|
||||
assign o_Green = w_DrawAny ? 7 : 0;
|
||||
assign o_Blue = w_DrawAny ? 7 : 0;
|
||||
endmodule
|
|
@ -0,0 +1,70 @@
|
|||
module PongBall (
|
||||
input i_Clk,
|
||||
input i_IsGameActive,
|
||||
input [5:0] i_CellX,
|
||||
input [5:0] i_CellY,
|
||||
|
||||
output reg o_DoDrawBall,
|
||||
output reg [5:0] o_BallX,
|
||||
output reg [5:0] o_BallY
|
||||
);
|
||||
parameter SCREEN_WIDTH_CELLS = 40;
|
||||
parameter SCREEN_HEIGHT_CELLS = 30;
|
||||
|
||||
parameter CLOCKS_PER_SECOND = 25000000;
|
||||
parameter BALL_MOVE_TIME_MS = 50;
|
||||
parameter BALL_SPEED = 1250000;
|
||||
|
||||
reg [$clog2(BALL_SPEED)-1:0] r_ballMoveCount;
|
||||
|
||||
reg [5:0] r_PrevBallX;
|
||||
reg [5:0] r_PrevBallY;
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
if (!i_IsGameActive) begin
|
||||
o_BallX <= SCREEN_WIDTH_CELLS / 2;
|
||||
o_BallY <= SCREEN_HEIGHT_CELLS / 2;
|
||||
r_PrevBallX <= SCREEN_WIDTH_CELLS / 2 + 1;
|
||||
r_PrevBallY <= SCREEN_HEIGHT_CELLS / 2 - 2;
|
||||
end else begin
|
||||
if (r_ballMoveCount < BALL_SPEED) begin
|
||||
r_ballMoveCount <= r_ballMoveCount + 1;
|
||||
end else begin
|
||||
r_ballMoveCount <= 0;
|
||||
|
||||
r_PrevBallX <= o_BallX;
|
||||
r_PrevBallY <= o_BallY;
|
||||
|
||||
if (
|
||||
// at right edge, travelling right
|
||||
(r_PrevBallX < o_BallX && o_BallX == SCREEN_WIDTH_CELLS - 1) ||
|
||||
// not at left edge
|
||||
(o_BallX < r_PrevBallX && o_BallX != 0)
|
||||
) begin
|
||||
o_BallX <= o_BallX - 1;
|
||||
end else begin
|
||||
o_BallX <= o_BallX + 1;
|
||||
end
|
||||
|
||||
if (
|
||||
// at bottom edge, travelling up
|
||||
(r_PrevBallY < o_BallY && o_BallY == SCREEN_HEIGHT_CELLS - 1) ||
|
||||
// not at left edge
|
||||
(o_BallY < r_PrevBallY && o_BallY != 0)
|
||||
) begin
|
||||
o_BallY <= o_BallY - 1;
|
||||
end else begin
|
||||
o_BallY <= o_BallY + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
if (i_CellX == o_BallX && i_CellY == o_BallY) begin
|
||||
o_DoDrawBall <= 1;
|
||||
end else begin
|
||||
o_DoDrawBall <= 0;
|
||||
end
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* Paddles maintain their own location on the screen
|
||||
*/
|
||||
module PongPaddle (
|
||||
input i_Clk,
|
||||
input [5:0] i_CellX,
|
||||
input [5:0] i_CellY,
|
||||
input i_PaddleUp,
|
||||
input i_PaddleDown,
|
||||
|
||||
output reg o_DoDrawPaddle,
|
||||
output reg [5:0] o_PaddleY
|
||||
);
|
||||
parameter X_POS_CELLS = 0;
|
||||
parameter PADDLE_HEIGHT_CELLS = 6;
|
||||
parameter SCREEN_HEIGHT_CELLS = 30;
|
||||
|
||||
parameter CLOCKS_PER_SECOND = 25000000;
|
||||
parameter PADDLE_MOVE_TIME_MS = 50;
|
||||
// omg i can't get this
|
||||
parameter integer PADDLE_SPEED = 1250000;
|
||||
|
||||
reg [$clog2(PADDLE_SPEED)-1:0] r_paddleMoveCount;
|
||||
wire w_onlyOneButtonDown = i_PaddleUp ^ i_PaddleDown;
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
// handle end of move delay
|
||||
if (w_onlyOneButtonDown) begin
|
||||
if (r_paddleMoveCount == PADDLE_SPEED) begin
|
||||
r_paddleMoveCount <= 0;
|
||||
end else begin
|
||||
r_paddleMoveCount <= r_paddleMoveCount + 1;
|
||||
end
|
||||
end
|
||||
|
||||
if (
|
||||
i_PaddleUp &&
|
||||
r_paddleMoveCount == PADDLE_SPEED &&
|
||||
o_PaddleY > 0
|
||||
) begin
|
||||
o_PaddleY <= o_PaddleY - 1;
|
||||
end else if (
|
||||
i_PaddleDown &&
|
||||
r_paddleMoveCount == PADDLE_SPEED &&
|
||||
o_PaddleY < SCREEN_HEIGHT_CELLS - PADDLE_HEIGHT_CELLS - 1
|
||||
) begin
|
||||
o_PaddleY <= o_PaddleY + 1;
|
||||
end
|
||||
|
||||
if (
|
||||
i_CellX == X_POS_CELLS &&
|
||||
i_CellY >= o_PaddleY &&
|
||||
i_CellY <= o_PaddleY + PADDLE_HEIGHT_CELLS) begin
|
||||
o_DoDrawPaddle <= 1;
|
||||
end else begin
|
||||
o_DoDrawPaddle <= 0;
|
||||
end
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,142 @@
|
|||
module PongRunner (
|
||||
input i_Clk,
|
||||
input i_UART_RX,
|
||||
|
||||
input i_Switch_1,
|
||||
input i_Switch_2,
|
||||
input i_Switch_3,
|
||||
input i_Switch_4,
|
||||
|
||||
output o_VGA_HSync,
|
||||
output o_VGA_VSync,
|
||||
output o_VGA_Red_0,
|
||||
output o_VGA_Red_1,
|
||||
output o_VGA_Red_2,
|
||||
output o_VGA_Grn_0,
|
||||
output o_VGA_Grn_1,
|
||||
output o_VGA_Grn_2,
|
||||
output o_VGA_Blu_0,
|
||||
output o_VGA_Blu_1,
|
||||
output o_VGA_Blu_2
|
||||
);
|
||||
localparam TOTAL_COLUMNS = 800;
|
||||
localparam TOTAL_ROWS = 525;
|
||||
|
||||
localparam ACTIVE_COLUMNS = 640;
|
||||
localparam ACTIVE_ROWS = 480;
|
||||
|
||||
localparam VIDEO_WIDTH = 3;
|
||||
|
||||
wire [VIDEO_WIDTH-1:0] w_Red_FromPong, w_Red_FromPorchSync;
|
||||
wire [VIDEO_WIDTH-1:0] w_Green_FromPong, w_Green_FromPorchSync;
|
||||
wire [VIDEO_WIDTH-1:0] w_Blue_FromPong, w_Blue_FromPorchSync;
|
||||
|
||||
wire w_dataReady;
|
||||
wire w_HSync_Start, w_VSync_Start;
|
||||
wire w_HSync_FromPong, w_VSync_FromPong;
|
||||
wire w_HSync_FromPorchSync, w_VSync_FromPorchSync;
|
||||
wire w_Switch_1_Debounced,
|
||||
w_Switch_2_Debounced,
|
||||
w_Switch_3_Debounced,
|
||||
w_Switch_4_Debounced;
|
||||
|
||||
UART_RX #(
|
||||
.CLOCKS_PER_SECOND(25000000),
|
||||
.BAUD_RATE(115200)
|
||||
) MyUART_RX (
|
||||
.i_Clk(i_Clk),
|
||||
.i_ReceiveBit(i_UART_RX),
|
||||
.o_DataReady(w_dataReady),
|
||||
.o_DataByte()
|
||||
);
|
||||
|
||||
VGA_Sync_Pulse_Generator #(
|
||||
.TOTAL_COLUMNS(TOTAL_COLUMNS),
|
||||
.TOTAL_ROWS(TOTAL_ROWS),
|
||||
.ACTIVE_COLUMNS(ACTIVE_COLUMNS),
|
||||
.ACTIVE_ROWS(ACTIVE_ROWS)
|
||||
) SyncGenerator (
|
||||
.i_Clk(i_Clk),
|
||||
.o_HSync(w_HSync_Start),
|
||||
.o_VSync(w_VSync_Start),
|
||||
.o_rawX(),
|
||||
.o_rawY()
|
||||
);
|
||||
|
||||
Debounce_Filter #(
|
||||
.DEBOUNCE_LIMIT(25000000 / 25000)
|
||||
) Debounce_Switch_1 (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Bouncy(i_Switch_1),
|
||||
.o_Debounced(w_Switch_1_Debounced)
|
||||
);
|
||||
|
||||
Debounce_Filter #(
|
||||
.DEBOUNCE_LIMIT(25000000 / 25000)
|
||||
) Debounce_Switch_2 (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Bouncy(i_Switch_2),
|
||||
.o_Debounced(w_Switch_2_Debounced)
|
||||
);
|
||||
|
||||
Debounce_Filter #(
|
||||
.DEBOUNCE_LIMIT(25000000 / 25000)
|
||||
) Debounce_Switch_3 (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Bouncy(i_Switch_3),
|
||||
.o_Debounced(w_Switch_3_Debounced)
|
||||
);
|
||||
|
||||
Debounce_Filter #(
|
||||
.DEBOUNCE_LIMIT(25000000 / 25000)
|
||||
) Debounce_Switch_4 (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Bouncy(i_Switch_4),
|
||||
.o_Debounced(w_Switch_4_Debounced)
|
||||
);
|
||||
|
||||
Pong #() MyPong (
|
||||
.i_Clk(i_Clk),
|
||||
.i_HSync(w_HSync_Start),
|
||||
.i_VSync(w_VSync_Start),
|
||||
.i_GameStart(w_dataReady),
|
||||
.i_Player1_Up(w_Switch_1_Debounced),
|
||||
.i_Player1_Down(w_Switch_2_Debounced),
|
||||
.i_Player2_Up(w_Switch_3_Debounced),
|
||||
.i_Player2_Down(w_Switch_4_Debounced),
|
||||
.o_HSync(w_HSync_FromPong),
|
||||
.o_VSync(w_VSync_FromPong),
|
||||
.o_Red(w_Red_FromPong),
|
||||
.o_Green(w_Green_FromPong),
|
||||
.o_Blue(w_Blue_FromPong)
|
||||
);
|
||||
|
||||
VGA_Add_Porches_To_Output #() PorchOutput (
|
||||
.i_Clk(i_Clk),
|
||||
.i_HSync(w_HSync_FromPong),
|
||||
.i_VSync(w_VSync_FromPong),
|
||||
.i_Red(w_Red_FromPong),
|
||||
.i_Green(w_Green_FromPong),
|
||||
.i_Blue(w_Blue_FromPong),
|
||||
.o_HSync(w_HSync_FromPorchSync),
|
||||
.o_VSync(w_VSync_FromPorchSync),
|
||||
.o_Red(w_Red_FromPorchSync),
|
||||
.o_Green(w_Green_FromPorchSync),
|
||||
.o_Blue(w_Blue_FromPorchSync)
|
||||
);
|
||||
|
||||
assign o_VGA_HSync = w_HSync_FromPorchSync;
|
||||
assign o_VGA_VSync = w_VSync_FromPorchSync;
|
||||
|
||||
assign o_VGA_Red_0 = w_Red_FromPorchSync[0];
|
||||
assign o_VGA_Red_1 = w_Red_FromPorchSync[1];
|
||||
assign o_VGA_Red_2 = w_Red_FromPorchSync[2];
|
||||
|
||||
assign o_VGA_Grn_0 = w_Green_FromPorchSync[0];
|
||||
assign o_VGA_Grn_1 = w_Green_FromPorchSync[1];
|
||||
assign o_VGA_Grn_2 = w_Green_FromPorchSync[2];
|
||||
|
||||
assign o_VGA_Blu_0 = w_Blue_FromPorchSync[0];
|
||||
assign o_VGA_Blu_1 = w_Blue_FromPorchSync[1];
|
||||
assign o_VGA_Blu_2 = w_Blue_FromPorchSync[2];
|
||||
endmodule
|
|
@ -0,0 +1,77 @@
|
|||
module RAM(
|
||||
input i_writeClock,
|
||||
input [$clog2(DEPTH_WORDS - 1):0] i_writeAddress,
|
||||
input [WIDTH_BITS-1:0] i_writeData,
|
||||
input i_writeDataValid,
|
||||
|
||||
input i_readClock,
|
||||
input [$clog2(DEPTH_WORDS - 1):0] i_readAddress,
|
||||
input i_doRead,
|
||||
output reg o_dataValid,
|
||||
output reg [WIDTH_BITS-1:0] o_readData
|
||||
);
|
||||
parameter WIDTH_BITS = 8;
|
||||
parameter DEPTH_WORDS = 16;
|
||||
|
||||
reg [WIDTH_BITS-1:0] r_Memory[DEPTH_WORDS-1:0];
|
||||
|
||||
always @(posedge i_writeClock) begin
|
||||
if (i_writeDataValid) begin
|
||||
r_Memory[i_writeAddress] <= i_writeData;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge i_readClock) begin
|
||||
o_readData <= r_Memory[i_readAddress];
|
||||
o_dataValid <= i_doRead;
|
||||
end
|
||||
endmodule
|
||||
|
||||
module TestRAM();
|
||||
reg r_Clk = 0;
|
||||
|
||||
always #2 r_Clk <= !r_Clk;
|
||||
|
||||
reg [4:0] r_writeAddress = 1;
|
||||
reg [7:0] r_writeData = 50;
|
||||
reg r_writeDataValid = 0;
|
||||
|
||||
reg [4:0] r_readAddress = 1;
|
||||
wire [7:0] w_readData;
|
||||
reg r_doRead = 0;
|
||||
wire w_dataValid;
|
||||
|
||||
RAM myRam (
|
||||
.i_writeClock(r_Clk),
|
||||
.i_writeAddress(r_writeAddress),
|
||||
.i_writeData(r_writeData),
|
||||
.i_writeDataValid(r_writeDataValid),
|
||||
|
||||
.i_readClock(r_Clk),
|
||||
.i_readAddress(r_readAddress),
|
||||
.i_doRead(r_doRead),
|
||||
.o_dataValid(w_dataValid),
|
||||
.o_readData(w_readData)
|
||||
);
|
||||
|
||||
initial begin
|
||||
$dumpfile("test.vcd");
|
||||
$dumpvars;
|
||||
|
||||
#2;
|
||||
|
||||
r_writeDataValid <= 1;
|
||||
|
||||
#2;
|
||||
|
||||
r_writeDataValid <= 0;
|
||||
|
||||
#2;
|
||||
|
||||
r_doRead <= 1;
|
||||
|
||||
#2;
|
||||
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,103 @@
|
|||
module Simon(
|
||||
input i_Clk,
|
||||
|
||||
input i_Switch_1,
|
||||
input i_Switch_2,
|
||||
input i_Switch_3,
|
||||
input i_Switch_4,
|
||||
|
||||
output o_LED_1,
|
||||
output o_LED_2,
|
||||
output o_LED_3,
|
||||
output o_LED_4,
|
||||
|
||||
output o_Segment2_A,
|
||||
output o_Segment2_B,
|
||||
output o_Segment2_C,
|
||||
output o_Segment2_D,
|
||||
output o_Segment2_E,
|
||||
output o_Segment2_F,
|
||||
output o_Segment2_G
|
||||
);
|
||||
localparam GAME_LIMIT = 7;
|
||||
localparam CLKS_PER_SECOND = 25000000;
|
||||
localparam integer DEBOUNCE_LIMIT = CLKS_PER_SECOND * 0.001;
|
||||
|
||||
wire w_Switch_1, w_Switch_2, w_Switch_3, w_Switch_4;
|
||||
wire [3:0] w_Score;
|
||||
wire w_Segment2_A,
|
||||
w_Segment2_B,
|
||||
w_Segment2_C,
|
||||
w_Segment2_D,
|
||||
w_Segment2_E,
|
||||
w_Segment2_F,
|
||||
w_Segment2_G;
|
||||
|
||||
Debounce_Filter #(
|
||||
.DEBOUNCE_LIMIT(DEBOUNCE_LIMIT)
|
||||
) Debounce_Switch_1 (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Bouncy(i_Switch_1),
|
||||
.o_Debounced(w_Switch_1)
|
||||
);
|
||||
|
||||
Debounce_Filter #(
|
||||
.DEBOUNCE_LIMIT(DEBOUNCE_LIMIT)
|
||||
) Debounce_Switch_2 (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Bouncy(i_Switch_2),
|
||||
.o_Debounced(w_Switch_2)
|
||||
);
|
||||
|
||||
Debounce_Filter #(
|
||||
.DEBOUNCE_LIMIT(DEBOUNCE_LIMIT)
|
||||
) Debounce_Switch_3 (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Bouncy(i_Switch_3),
|
||||
.o_Debounced(w_Switch_3)
|
||||
);
|
||||
|
||||
Debounce_Filter #(
|
||||
.DEBOUNCE_LIMIT(DEBOUNCE_LIMIT)
|
||||
) Debounce_Switch_4 (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Bouncy(i_Switch_4),
|
||||
.o_Debounced(w_Switch_4)
|
||||
);
|
||||
|
||||
Simon_Game #(
|
||||
.CLKS_PER_SECOND(CLKS_PER_SECOND),
|
||||
.GAME_LIMIT(GAME_LIMIT)
|
||||
) Simon_Game_Instance (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Switch_1(w_Switch_1),
|
||||
.i_Switch_2(w_Switch_2),
|
||||
.i_Switch_3(w_Switch_3),
|
||||
.i_Switch_4(w_Switch_4),
|
||||
.o_Score(w_Score),
|
||||
.o_LED_1(o_LED_1),
|
||||
.o_LED_2(o_LED_2),
|
||||
.o_LED_3(o_LED_3),
|
||||
.o_LED_4(o_LED_4)
|
||||
);
|
||||
|
||||
Binary_to_7_Segment Scoreboard (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Number(w_Score),
|
||||
.o_SegA(w_Segment2_A),
|
||||
.o_SegB(w_Segment2_B),
|
||||
.o_SegC(w_Segment2_C),
|
||||
.o_SegD(w_Segment2_D),
|
||||
.o_SegE(w_Segment2_E),
|
||||
.o_SegF(w_Segment2_F),
|
||||
.o_SegG(w_Segment2_G)
|
||||
);
|
||||
|
||||
assign o_Segment2_A = !w_Segment2_A;
|
||||
assign o_Segment2_B = !w_Segment2_B;
|
||||
assign o_Segment2_C = !w_Segment2_C;
|
||||
assign o_Segment2_D = !w_Segment2_D;
|
||||
assign o_Segment2_E = !w_Segment2_E;
|
||||
assign o_Segment2_F = !w_Segment2_F;
|
||||
assign o_Segment2_G = !w_Segment2_G;
|
||||
endmodule
|
|
@ -0,0 +1,208 @@
|
|||
module Simon_Game (
|
||||
input i_Clk,
|
||||
|
||||
input i_Switch_1,
|
||||
input i_Switch_2,
|
||||
input i_Switch_3,
|
||||
input i_Switch_4,
|
||||
|
||||
output reg [3:0] o_Score,
|
||||
|
||||
output o_LED_1,
|
||||
output o_LED_2,
|
||||
output o_LED_3,
|
||||
output o_LED_4
|
||||
);
|
||||
parameter CLKS_PER_SECOND = 25000000;
|
||||
parameter GAME_LIMIT = 6;
|
||||
|
||||
localparam START = 3'd0;
|
||||
localparam PATTERN_OFF = 3'd1;
|
||||
localparam PATTERN_SHOW = 3'd2;
|
||||
localparam WAIT_PLAYER = 3'd3;
|
||||
localparam INCREMENT_SCORE = 3'd4;
|
||||
localparam PLAYER_LOST = 3'd5;
|
||||
localparam PLAYER_WON = 3'd6;
|
||||
|
||||
reg [2:0] r_currentState;
|
||||
|
||||
// count and toggle results
|
||||
wire w_IncomingDelay;
|
||||
reg r_DelayCompleted;
|
||||
wire w_EnableCounter;
|
||||
|
||||
// user input handling
|
||||
reg r_Switch_1, r_Switch_2, r_Switch_3, r_Switch_4;
|
||||
reg r_Button_notDown;
|
||||
reg [1:0] r_currentButtonDown;
|
||||
|
||||
// game pattern & construction
|
||||
reg [1:0] r_LEDPattern [0:10];
|
||||
wire [21:0] w_LFSR_Data;
|
||||
reg [$clog2(GAME_LIMIT)-1:0] r_currentLEDPattern;
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
if (i_Switch_1 & i_Switch_2) begin
|
||||
r_currentState <= START;
|
||||
end else begin
|
||||
case (r_currentState)
|
||||
START:
|
||||
begin
|
||||
if (!i_Switch_1 & !i_Switch_2 & r_Button_notDown) begin
|
||||
o_Score <= 0;
|
||||
r_currentLEDPattern <= 0;
|
||||
r_currentState <= PATTERN_OFF;
|
||||
end
|
||||
end
|
||||
|
||||
PATTERN_OFF:
|
||||
begin
|
||||
if (!w_IncomingDelay & r_DelayCompleted) begin
|
||||
r_currentState <= PATTERN_SHOW;
|
||||
end
|
||||
end
|
||||
|
||||
PATTERN_SHOW:
|
||||
begin
|
||||
if (!w_IncomingDelay & r_DelayCompleted) begin
|
||||
// this limits the number of
|
||||
if (o_Score == r_currentLEDPattern) begin
|
||||
r_currentLEDPattern <= 0;
|
||||
r_currentState <= WAIT_PLAYER;
|
||||
end else begin
|
||||
r_currentLEDPattern <= r_currentLEDPattern + 1;
|
||||
r_currentState <= PATTERN_OFF;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_PLAYER:
|
||||
begin
|
||||
if (r_Button_notDown) begin
|
||||
if (
|
||||
r_LEDPattern[r_currentLEDPattern] == r_currentButtonDown &&
|
||||
o_Score == r_currentLEDPattern
|
||||
) begin
|
||||
r_currentLEDPattern <= 0;
|
||||
r_currentState <= INCREMENT_SCORE;
|
||||
end else if (
|
||||
r_LEDPattern[r_currentLEDPattern] != r_currentButtonDown
|
||||
) begin
|
||||
r_currentState <= PLAYER_LOST;
|
||||
end else begin
|
||||
r_currentLEDPattern <= r_currentLEDPattern + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
INCREMENT_SCORE:
|
||||
begin
|
||||
o_Score <= o_Score + 1;
|
||||
if (o_Score == GAME_LIMIT - 1) begin
|
||||
r_currentState <= PLAYER_WON;
|
||||
end else begin
|
||||
r_currentState <= PATTERN_OFF;
|
||||
end
|
||||
end
|
||||
|
||||
PLAYER_WON:
|
||||
begin
|
||||
o_Score <= 4'hA;
|
||||
end
|
||||
|
||||
PLAYER_LOST:
|
||||
begin
|
||||
o_Score <= 4'hF;
|
||||
end
|
||||
|
||||
default:
|
||||
begin
|
||||
r_currentState <= START;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
if (r_currentState == START) begin
|
||||
r_LEDPattern[0] <= w_LFSR_Data[1:0];
|
||||
r_LEDPattern[1] <= w_LFSR_Data[3:2];
|
||||
r_LEDPattern[2] <= w_LFSR_Data[5:4];
|
||||
r_LEDPattern[3] <= w_LFSR_Data[7:6];
|
||||
r_LEDPattern[4] <= w_LFSR_Data[9:8];
|
||||
r_LEDPattern[5] <= w_LFSR_Data[11:10];
|
||||
r_LEDPattern[6] <= w_LFSR_Data[13:12];
|
||||
r_LEDPattern[7] <= w_LFSR_Data[15:14];
|
||||
r_LEDPattern[8] <= w_LFSR_Data[17:16];
|
||||
r_LEDPattern[9] <= w_LFSR_Data[19:18];
|
||||
r_LEDPattern[10] <= w_LFSR_Data[21:20];
|
||||
end
|
||||
end
|
||||
|
||||
assign o_LED_1 = (
|
||||
(r_currentState == PATTERN_SHOW && r_LEDPattern[r_currentLEDPattern] == 0) ?
|
||||
1 :
|
||||
i_Switch_1
|
||||
);
|
||||
|
||||
assign o_LED_2 = (
|
||||
(r_currentState == PATTERN_SHOW && r_LEDPattern[r_currentLEDPattern] == 1) ?
|
||||
1 :
|
||||
i_Switch_2
|
||||
);
|
||||
|
||||
assign o_LED_3 = (
|
||||
(r_currentState == PATTERN_SHOW && r_LEDPattern[r_currentLEDPattern] == 2) ?
|
||||
1 :
|
||||
i_Switch_3
|
||||
);
|
||||
|
||||
assign o_LED_4 = (
|
||||
(r_currentState == PATTERN_SHOW && r_LEDPattern[r_currentLEDPattern] == 3) ?
|
||||
1 :
|
||||
i_Switch_4
|
||||
);
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
r_DelayCompleted <= w_IncomingDelay;
|
||||
r_Switch_1 <= i_Switch_1;
|
||||
r_Switch_2 <= i_Switch_2;
|
||||
r_Switch_3 <= i_Switch_3;
|
||||
r_Switch_4 <= i_Switch_4;
|
||||
|
||||
if (r_Switch_1 && !i_Switch_1) begin
|
||||
r_Button_notDown <= 1;
|
||||
r_currentButtonDown <= 0;
|
||||
end else if (r_Switch_2 && !i_Switch_2) begin
|
||||
r_Button_notDown <= 1;
|
||||
r_currentButtonDown <= 1;
|
||||
end else if (r_Switch_3 && !i_Switch_3) begin
|
||||
r_Button_notDown <= 1;
|
||||
r_currentButtonDown <= 2;
|
||||
end else if (r_Switch_4 && !i_Switch_4) begin
|
||||
r_Button_notDown <= 1;
|
||||
r_currentButtonDown <= 3;
|
||||
end else begin
|
||||
r_Button_notDown <= 0;
|
||||
r_currentButtonDown <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
assign w_EnableCounter = (r_currentState == PATTERN_SHOW || r_currentState == PATTERN_OFF);
|
||||
|
||||
Count_And_Toggle #(
|
||||
.COUNT_LIMIT(CLKS_PER_SECOND/4)
|
||||
) Counter (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Enable(w_EnableCounter),
|
||||
.o_Toggle(w_IncomingDelay)
|
||||
);
|
||||
|
||||
LFSR #(
|
||||
.SIZE(22)
|
||||
) MyLFSR (
|
||||
.i_Clk(i_Clk),
|
||||
.o_LFSR_Data(w_LFSR_Data),
|
||||
.o_LFSR_Done()
|
||||
);
|
||||
endmodule
|
|
@ -0,0 +1,104 @@
|
|||
module SiPo_ShiftRegister_4(
|
||||
input i_Clk,
|
||||
input i_Latch,
|
||||
input i_Data,
|
||||
input i_Reset,
|
||||
output o_Data0,
|
||||
output o_Data1,
|
||||
output o_Data2,
|
||||
output o_Data3
|
||||
);
|
||||
reg [3:0] r_Data;
|
||||
reg [3:0] r_Incoming;
|
||||
reg [2:0] r_Pos;
|
||||
reg r_didLatch;
|
||||
|
||||
always @ (posedge i_Clk & i_Reset) begin
|
||||
r_Data <= 0;
|
||||
r_Incoming <= 0;
|
||||
r_Pos <= 0;
|
||||
r_didLatch <= 0;
|
||||
end
|
||||
|
||||
always @ (posedge i_Clk) begin
|
||||
if (i_Latch & !r_didLatch) begin
|
||||
r_Incoming[0] <= i_Data;
|
||||
r_Incoming[3:1] <= r_Incoming[2:0];
|
||||
r_Pos <= r_Pos + 1;
|
||||
r_didLatch <= 1;
|
||||
end
|
||||
|
||||
if (r_didLatch & !i_Latch) begin
|
||||
r_didLatch <= 0;
|
||||
|
||||
if (r_Pos == 4) begin
|
||||
r_Data[3:0] <= r_Incoming[3:0];
|
||||
r_Incoming <= 0;
|
||||
r_Pos <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign o_Data0 = r_Data[0];
|
||||
assign o_Data1 = r_Data[1];
|
||||
assign o_Data2 = r_Data[2];
|
||||
assign o_Data3 = r_Data[3];
|
||||
endmodule
|
||||
|
||||
module Test_SIPO();
|
||||
task assert(input condition);
|
||||
if (!condition) $error;
|
||||
endtask
|
||||
|
||||
reg r_Data = 1'b0, r_Clk = 1'b0, r_Latch = 1'b0, r_Reset = 1'b0;
|
||||
wire w_Data0, w_Data1, w_Data2, w_Data3;
|
||||
|
||||
always #2 r_Clk <= !r_Clk;
|
||||
|
||||
SiPo_ShiftRegister_4 UUT(
|
||||
.i_Clk(r_Clk),
|
||||
.i_Data(r_Data),
|
||||
.i_Latch(r_Latch),
|
||||
.i_Reset(r_Reset),
|
||||
.o_Data0(w_Data0),
|
||||
.o_Data1(w_Data1),
|
||||
.o_Data2(w_Data2),
|
||||
.o_Data3(w_Data3)
|
||||
);
|
||||
|
||||
initial begin
|
||||
$dumpfile("test.vcd");
|
||||
$dumpvars;
|
||||
|
||||
r_Data <= 1'b1;
|
||||
r_Reset <= 1'b1;
|
||||
@(posedge r_Clk);
|
||||
|
||||
r_Reset <= 1'b0;
|
||||
@(posedge r_Clk);
|
||||
|
||||
r_Latch <= 1'b1;
|
||||
@(posedge r_Clk);
|
||||
r_Latch <= 1'b0;
|
||||
@(posedge r_Clk);
|
||||
|
||||
r_Data <= 0;
|
||||
r_Latch <= 1'b1;
|
||||
@(posedge r_Clk);
|
||||
r_Latch <= 1'b0;
|
||||
@(posedge r_Clk);
|
||||
r_Latch <= 1'b1;
|
||||
@(posedge r_Clk);
|
||||
r_Latch <= 1'b0;
|
||||
@(posedge r_Clk);
|
||||
r_Data <= 1;
|
||||
r_Latch <= 1'b1;
|
||||
@(posedge r_Clk);
|
||||
r_Latch <= 1'b0;
|
||||
@(posedge r_Clk);
|
||||
|
||||
#5;
|
||||
|
||||
$finish();
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,100 @@
|
|||
module UART_RX (
|
||||
input i_Clk,
|
||||
input i_ReceiveBit,
|
||||
output o_DataReady,
|
||||
output [7:0] o_DataByte
|
||||
);
|
||||
parameter CLOCKS_PER_SECOND = 25000000;
|
||||
parameter BAUD_RATE = 115200;
|
||||
localparam integer CLOCKS_PER_BIT = CLOCKS_PER_SECOND / BAUD_RATE;
|
||||
localparam integer HALF_CLOCKS_PER_BIT = (CLOCKS_PER_BIT - 1) / 2;
|
||||
|
||||
localparam IDLE = 0;
|
||||
localparam VERIFY_START_BIT = 1;
|
||||
localparam READ_DATA_BITS = 2;
|
||||
localparam WAIT_FOR_STOP_BIT = 3;
|
||||
localparam CLEANUP = 4;
|
||||
|
||||
// golang-style: lowercase is private, uppercase is public
|
||||
reg [$clog2(CLEANUP)-1:0] r_currentState = IDLE;
|
||||
|
||||
reg r_dataReady = 0;
|
||||
reg [$clog2(CLOCKS_PER_BIT)-1:0] r_clockCount = 0;
|
||||
reg [$clog2(8)-1:0] r_bitIndex = 0;
|
||||
reg [7:0] r_receivedByte = 0;
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
case (r_currentState)
|
||||
IDLE:
|
||||
begin
|
||||
r_dataReady <= 0;
|
||||
r_clockCount <= 0;
|
||||
r_bitIndex <= 0;
|
||||
|
||||
if (i_ReceiveBit == 0) begin
|
||||
r_currentState <= VERIFY_START_BIT;
|
||||
end
|
||||
end
|
||||
|
||||
// Check the middle of the start bit to make sure it's still low
|
||||
VERIFY_START_BIT:
|
||||
begin
|
||||
if (r_clockCount == HALF_CLOCKS_PER_BIT) begin
|
||||
// still low, let's go
|
||||
if (i_ReceiveBit == 0) begin
|
||||
r_clockCount <= 0;
|
||||
r_currentState <= READ_DATA_BITS;
|
||||
end else begin
|
||||
r_currentState <= IDLE;
|
||||
end
|
||||
end else begin
|
||||
r_clockCount <= r_clockCount + 1;
|
||||
end
|
||||
end
|
||||
|
||||
// note that we are still in the halfway points of the signal at this
|
||||
// point. we are sampling the very middles.
|
||||
READ_DATA_BITS:
|
||||
begin
|
||||
if (r_clockCount < CLOCKS_PER_BIT - 1) begin
|
||||
r_clockCount <= r_clockCount + 1;
|
||||
end else begin
|
||||
r_clockCount <= 0;
|
||||
r_receivedByte[r_bitIndex] <= i_ReceiveBit;
|
||||
|
||||
if (r_bitIndex == 7) begin
|
||||
r_bitIndex <= 0;
|
||||
r_currentState <= WAIT_FOR_STOP_BIT;
|
||||
end else begin
|
||||
r_bitIndex <= r_bitIndex + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_FOR_STOP_BIT:
|
||||
begin
|
||||
if (r_clockCount < CLOCKS_PER_BIT - 1) begin
|
||||
r_clockCount <= r_clockCount + 1;
|
||||
end else begin
|
||||
r_dataReady <= 1;
|
||||
r_clockCount <= 0;
|
||||
r_currentState <= CLEANUP;
|
||||
end
|
||||
end
|
||||
|
||||
CLEANUP:
|
||||
begin
|
||||
r_currentState <= IDLE;
|
||||
r_dataReady <= 0;
|
||||
end
|
||||
|
||||
default:
|
||||
begin
|
||||
r_currentState <= IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
assign o_DataByte = r_receivedByte;
|
||||
assign o_DataReady = r_dataReady;
|
||||
endmodule
|
|
@ -0,0 +1,98 @@
|
|||
module UART_TX (
|
||||
input i_Reset_Low,
|
||||
input i_Clk,
|
||||
input i_TransmitReady,
|
||||
input [7:0] i_TransmitByte,
|
||||
|
||||
output reg o_Active,
|
||||
output reg o_Output,
|
||||
output reg o_Done
|
||||
);
|
||||
parameter CLOCKS_PER_SECOND = 25000000;
|
||||
parameter BAUD_RATE = 115200;
|
||||
localparam integer CLOCKS_PER_BIT = CLOCKS_PER_SECOND / BAUD_RATE;
|
||||
|
||||
localparam IDLE = 0;
|
||||
localparam SEND_START_BIT = 1;
|
||||
localparam SEND_DATA_BITS = 2;
|
||||
localparam SEND_STOP_BIT = 3;
|
||||
|
||||
reg [$clog2(SEND_STOP_BIT)-1:0] r_currentState = IDLE;
|
||||
reg [$clog2(CLOCKS_PER_BIT)-1:0] r_clockCount = 0;
|
||||
reg [$clog2(8)-1:0] r_bitIndex = 0;
|
||||
reg [7:0] r_transmitData;
|
||||
|
||||
always @(posedge i_Clk or negedge i_Reset_Low) begin
|
||||
if (!i_Reset_Low) begin
|
||||
r_currentState <= IDLE;
|
||||
end else begin
|
||||
o_Done <= 0;
|
||||
|
||||
case (r_currentState)
|
||||
IDLE:
|
||||
begin
|
||||
// Drive line high for idle
|
||||
o_Output <= 1;
|
||||
r_clockCount <= 0;
|
||||
r_bitIndex <= 0;
|
||||
|
||||
if (i_TransmitReady) begin
|
||||
o_Active <= 1;
|
||||
r_transmitData <= i_TransmitByte;
|
||||
r_currentState <= SEND_START_BIT;
|
||||
end
|
||||
end
|
||||
|
||||
SEND_START_BIT:
|
||||
begin
|
||||
o_Output <= 0;
|
||||
|
||||
if (r_clockCount < CLOCKS_PER_BIT - 1) begin
|
||||
r_clockCount <= r_clockCount + 1;
|
||||
end else begin
|
||||
r_clockCount <= 0;
|
||||
r_currentState <= SEND_DATA_BITS;
|
||||
end
|
||||
end
|
||||
|
||||
SEND_DATA_BITS:
|
||||
begin
|
||||
o_Output <= r_transmitData[r_bitIndex];
|
||||
|
||||
if (r_clockCount < CLOCKS_PER_BIT - 1) begin
|
||||
r_clockCount <= r_clockCount + 1;
|
||||
end else begin
|
||||
r_clockCount <= 0;
|
||||
|
||||
if (r_bitIndex == 7) begin
|
||||
r_bitIndex <= 0;
|
||||
r_currentState <= SEND_STOP_BIT;
|
||||
end else begin
|
||||
r_bitIndex <= r_bitIndex + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SEND_STOP_BIT:
|
||||
begin
|
||||
o_Output <= 1;
|
||||
|
||||
if (r_clockCount < CLOCKS_PER_BIT - 1) begin
|
||||
r_clockCount <= r_clockCount + 1;
|
||||
end else begin
|
||||
o_Done <= 1;
|
||||
r_clockCount <= 0;
|
||||
r_currentState <= IDLE;
|
||||
o_Output <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
default:
|
||||
begin
|
||||
r_currentState <= IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* The output is buffered as the front/back porches are added, so watch your
|
||||
* timing for other stuff.
|
||||
*/
|
||||
module VGA_Add_Porches_To_Output(
|
||||
input i_Clk,
|
||||
input i_HSync,
|
||||
input i_VSync,
|
||||
input [VIDEO_WIDTH-1:0] i_Red,
|
||||
input [VIDEO_WIDTH-1:0] i_Green,
|
||||
input [VIDEO_WIDTH-1:0] i_Blue,
|
||||
|
||||
output reg o_HSync,
|
||||
output reg o_VSync,
|
||||
output reg [VIDEO_WIDTH-1:0] o_Red,
|
||||
output reg [VIDEO_WIDTH-1:0] o_Green,
|
||||
output reg [VIDEO_WIDTH-1:0] o_Blue
|
||||
);
|
||||
parameter VIDEO_WIDTH = 3;
|
||||
|
||||
parameter TOTAL_COLUMNS = 800;
|
||||
parameter TOTAL_ROWS = 525;
|
||||
|
||||
parameter ACTIVE_COLUMNS = 640;
|
||||
parameter ACTIVE_ROWS = 480;
|
||||
|
||||
//parameter FRONT_PORCH_COUNT_X = 18;
|
||||
parameter FRONT_PORCH_COUNT_X = 15;
|
||||
//parameter FRONT_PORCH_COUNT_Y = 10;
|
||||
parameter FRONT_PORCH_COUNT_Y = 10;
|
||||
//parameter BACK_PORCH_COUNT_X = 50;
|
||||
parameter BACK_PORCH_COUNT_X = 53;
|
||||
//parameter BACK_PORCH_COUNT_Y = 33;
|
||||
parameter BACK_PORCH_COUNT_Y = 33;
|
||||
|
||||
wire w_HSync, w_VSync;
|
||||
|
||||
wire [$clog2(TOTAL_COLUMNS)-1:0] w_X;
|
||||
wire [$clog2(TOTAL_ROWS)-1:0] w_Y;
|
||||
|
||||
reg [VIDEO_WIDTH-1:0] r_Red = 0;
|
||||
reg [VIDEO_WIDTH-1:0] r_Green = 0;
|
||||
reg [VIDEO_WIDTH-1:0] r_Blue = 0;
|
||||
|
||||
VGA_Current_Beam_Position #(
|
||||
.TOTAL_COLUMNS(TOTAL_COLUMNS),
|
||||
.TOTAL_ROWS(TOTAL_ROWS)
|
||||
) CurrentPosition (
|
||||
.i_Clk(i_Clk),
|
||||
.i_HSync(i_HSync),
|
||||
.i_VSync(i_VSync),
|
||||
.o_HSync(w_HSync),
|
||||
.o_VSync(w_VSync),
|
||||
.o_X(w_X),
|
||||
.o_Y(w_Y)
|
||||
);
|
||||
|
||||
// https://web.mit.edu/6.111/www/s2004/NEWKIT/vga.shtml
|
||||
always @(posedge i_Clk) begin
|
||||
if (
|
||||
(w_X < FRONT_PORCH_COUNT_X + ACTIVE_COLUMNS) ||
|
||||
(w_X > TOTAL_COLUMNS - BACK_PORCH_COUNT_X - 1)
|
||||
) begin
|
||||
o_HSync <= 1;
|
||||
end else begin
|
||||
o_HSync <= w_HSync;
|
||||
end
|
||||
|
||||
if (
|
||||
(w_Y < FRONT_PORCH_COUNT_Y + ACTIVE_ROWS) ||
|
||||
(w_Y > TOTAL_ROWS - BACK_PORCH_COUNT_Y - 1)
|
||||
) begin
|
||||
o_VSync <= 1;
|
||||
end else begin
|
||||
o_VSync <= w_VSync;
|
||||
end
|
||||
end
|
||||
|
||||
// The process of going through Current Beam Position and then
|
||||
// the porch alignment above delays the video signal by two clock ticks.
|
||||
// Do the same input -> wire -> output as above.
|
||||
always @(posedge i_Clk) begin
|
||||
r_Red <= i_Red;
|
||||
r_Green <= i_Green;
|
||||
r_Blue <= i_Blue;
|
||||
|
||||
o_Red <= r_Red;
|
||||
o_Green <= r_Green;
|
||||
o_Blue <= r_Blue;
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,47 @@
|
|||
// Keys off of HSync and VSync signals to get the actual electron
|
||||
// beam position
|
||||
|
||||
module VGA_Current_Beam_Position(
|
||||
input i_Clk,
|
||||
input i_HSync,
|
||||
input i_VSync,
|
||||
|
||||
output reg o_HSync = 0,
|
||||
output reg o_VSync = 0,
|
||||
|
||||
output reg [$clog2(TOTAL_COLUMNS)-1:0] o_X,
|
||||
output reg [$clog2(TOTAL_ROWS)-1:0] o_Y
|
||||
);
|
||||
parameter TOTAL_COLUMNS = 800;
|
||||
parameter TOTAL_ROWS = 525;
|
||||
|
||||
wire w_frameStart;
|
||||
|
||||
// forward these flip-flop style. use these instead of what
|
||||
// comes out of sync pulse generator!
|
||||
always @(posedge i_Clk) begin
|
||||
o_VSync <= i_VSync;
|
||||
o_HSync <= i_HSync;
|
||||
end
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
if (w_frameStart == 1) begin
|
||||
o_X <= 0;
|
||||
o_Y <= 0;
|
||||
end else begin
|
||||
if (o_X == TOTAL_COLUMNS - 1) begin
|
||||
o_X <= 0;
|
||||
if (o_Y == TOTAL_ROWS - 1) begin
|
||||
o_Y <= 0;
|
||||
end else begin
|
||||
o_Y <= o_Y + 1;
|
||||
end
|
||||
end else begin
|
||||
o_X <= o_X + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// rising vsync == new frame
|
||||
assign w_frameStart = (~o_VSync & i_VSync);
|
||||
endmodule
|
|
@ -0,0 +1,189 @@
|
|||
module VGA_Pattern_Generator(
|
||||
input i_Clk,
|
||||
input [3:0] i_Pattern,
|
||||
input i_HSync,
|
||||
input i_VSync,
|
||||
|
||||
output reg o_HSync = 0,
|
||||
output reg o_VSync = 0,
|
||||
output reg [VIDEO_WIDTH-1:0] o_Red,
|
||||
output reg [VIDEO_WIDTH-1:0] o_Green,
|
||||
output reg [VIDEO_WIDTH-1:0] o_Blue
|
||||
);
|
||||
// Go Board only supports 3 bits per channel. That's even less than the
|
||||
// Amiga!
|
||||
parameter VIDEO_WIDTH = 3;
|
||||
|
||||
parameter TOTAL_COLUMNS = 800;
|
||||
parameter TOTAL_ROWS = 525;
|
||||
|
||||
parameter ACTIVE_COLUMNS = 640;
|
||||
parameter ACTIVE_ROWS = 480;
|
||||
|
||||
localparam COLOR_BAR_WIDTH = ACTIVE_COLUMNS / 8;
|
||||
|
||||
wire w_HSync, w_VSync;
|
||||
|
||||
wire [VIDEO_WIDTH-1:0] w_Red[0:15];
|
||||
wire [VIDEO_WIDTH-1:0] w_Green[0:15];
|
||||
wire [VIDEO_WIDTH-1:0] w_Blue[0:15];
|
||||
|
||||
wire [$clog2(TOTAL_COLUMNS)-1:0] w_X;
|
||||
wire [$clog2(TOTAL_ROWS)-1:0] w_Y;
|
||||
|
||||
VGA_Current_Beam_Position #(
|
||||
.TOTAL_COLUMNS(TOTAL_COLUMNS),
|
||||
.TOTAL_ROWS(TOTAL_ROWS)
|
||||
) CurrentPosition (
|
||||
.i_Clk(i_Clk),
|
||||
.i_HSync(i_HSync),
|
||||
.i_VSync(i_VSync),
|
||||
.o_HSync(w_HSync),
|
||||
.o_VSync(w_VSync),
|
||||
.o_X(w_X),
|
||||
.o_Y(w_Y)
|
||||
);
|
||||
|
||||
// all these pattern operations take one clock tick
|
||||
// so delay sync signals by that much
|
||||
always @(posedge i_Clk) begin
|
||||
o_HSync <= w_HSync;
|
||||
o_VSync <= w_VSync;
|
||||
end
|
||||
|
||||
// none more black
|
||||
assign w_Red[0] = 0;
|
||||
assign w_Green[0] = 0;
|
||||
assign w_Blue[0] = 0;
|
||||
|
||||
// red
|
||||
assign w_Red[1] = (
|
||||
(w_X < ACTIVE_COLUMNS && w_Y < ACTIVE_ROWS) ?
|
||||
{VIDEO_WIDTH{1'b1}} :
|
||||
0
|
||||
);
|
||||
assign w_Green[1] = 0;
|
||||
assign w_Blue[1] = 0;
|
||||
|
||||
// green
|
||||
assign w_Red[2] = 0;
|
||||
assign w_Green[2] = (
|
||||
(w_X < ACTIVE_COLUMNS && w_Y < ACTIVE_ROWS) ?
|
||||
{VIDEO_WIDTH{1'b1}} :
|
||||
0
|
||||
);
|
||||
assign w_Blue[2] = 0;
|
||||
|
||||
// blue
|
||||
assign w_Red[3] = 0;
|
||||
assign w_Green[3] = 0;
|
||||
assign w_Blue[3] = (
|
||||
(w_X < ACTIVE_COLUMNS && w_Y < ACTIVE_ROWS) ?
|
||||
{VIDEO_WIDTH{1'b1}} :
|
||||
0
|
||||
);
|
||||
|
||||
// checkerboard
|
||||
// cell size is 32 pixels
|
||||
assign w_Red[4] = (w_X[5] ^ w_Y[5]) ? {VIDEO_WIDTH{1'b1}} : 0;
|
||||
assign w_Green[4] = w_Red[4];
|
||||
assign w_Blue[4] = w_Red[4];
|
||||
|
||||
wire [2:0] w_colorBarSelect;
|
||||
|
||||
// color bars
|
||||
// yes this is the hardware way to do this b/c multi/div
|
||||
assign w_colorBarSelect =
|
||||
w_X < COLOR_BAR_WIDTH ? 0 :
|
||||
w_X < COLOR_BAR_WIDTH * 2 ? 1 :
|
||||
w_X < COLOR_BAR_WIDTH * 3 ? 2 :
|
||||
w_X < COLOR_BAR_WIDTH * 4 ? 3 :
|
||||
w_X < COLOR_BAR_WIDTH * 5 ? 4 :
|
||||
w_X < COLOR_BAR_WIDTH * 6 ? 5 :
|
||||
w_X < COLOR_BAR_WIDTH * 7 ? 6 :7;
|
||||
|
||||
assign w_Red[5] = (
|
||||
w_colorBarSelect == 4 ||
|
||||
w_colorBarSelect == 5 ||
|
||||
w_colorBarSelect == 6 ||
|
||||
w_colorBarSelect == 7
|
||||
) ? {VIDEO_WIDTH{1'b1}} : 0;
|
||||
|
||||
assign w_Green[5] = (
|
||||
w_colorBarSelect == 2 ||
|
||||
w_colorBarSelect == 3 ||
|
||||
w_colorBarSelect == 6 ||
|
||||
w_colorBarSelect == 7
|
||||
) ? {VIDEO_WIDTH{1'b1}} : 0;
|
||||
|
||||
assign w_Blue[5] = (
|
||||
w_colorBarSelect == 1 ||
|
||||
w_colorBarSelect == 3 ||
|
||||
w_colorBarSelect == 5 ||
|
||||
w_colorBarSelect == 7
|
||||
) ? {VIDEO_WIDTH{1'b1}} : 0;
|
||||
|
||||
// border
|
||||
|
||||
localparam BORDER_WIDTH = 2;
|
||||
|
||||
assign w_Red[6] = (
|
||||
w_X < BORDER_WIDTH || w_X >= ACTIVE_COLUMNS - BORDER_WIDTH ||
|
||||
w_Y < BORDER_WIDTH || w_Y >= ACTIVE_ROWS - BORDER_WIDTH
|
||||
) ? {VIDEO_WIDTH{1'b1}} : 0;
|
||||
assign w_Green[6] = 0;
|
||||
assign w_Blue[6] = 0;
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
case (i_Pattern)
|
||||
0:
|
||||
begin
|
||||
o_Red <= w_Red[0];
|
||||
o_Green <= w_Green[0];
|
||||
o_Blue <= w_Blue[0];
|
||||
end
|
||||
1:
|
||||
begin
|
||||
o_Red <= w_Red[1];
|
||||
o_Green <= w_Green[1];
|
||||
o_Blue <= w_Blue[1];
|
||||
end
|
||||
2:
|
||||
begin
|
||||
o_Red <= w_Red[2];
|
||||
o_Green <= w_Green[2];
|
||||
o_Blue <= w_Blue[2];
|
||||
end
|
||||
3:
|
||||
begin
|
||||
o_Red <= w_Red[3];
|
||||
o_Green <= w_Green[3];
|
||||
o_Blue <= w_Blue[3];
|
||||
end
|
||||
4:
|
||||
begin
|
||||
o_Red <= w_Red[4];
|
||||
o_Green <= w_Green[4];
|
||||
o_Blue <= w_Blue[4];
|
||||
end
|
||||
5:
|
||||
begin
|
||||
o_Red <= w_Red[5];
|
||||
o_Green <= w_Green[5];
|
||||
o_Blue <= w_Blue[5];
|
||||
end
|
||||
6:
|
||||
begin
|
||||
o_Red <= w_Red[6];
|
||||
o_Green <= w_Green[6];
|
||||
o_Blue <= w_Blue[6];
|
||||
end
|
||||
default:
|
||||
begin
|
||||
o_Red <= w_Red[0];
|
||||
o_Green <= w_Green[0];
|
||||
o_Blue <= w_Blue[0];
|
||||
end
|
||||
endcase
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,34 @@
|
|||
// Remember, this "magically works" on the Go Board.
|
||||
// If you're using a different clock speed, you need to
|
||||
// do a different thing here.
|
||||
module VGA_Sync_Pulse_Generator (
|
||||
input i_Clk,
|
||||
output o_HSync,
|
||||
output o_VSync,
|
||||
|
||||
output reg [$clog2(TOTAL_COLUMNS)-1:0] o_rawX,
|
||||
output reg [$clog2(TOTAL_ROWS)-1:0] o_rawY
|
||||
);
|
||||
// remember overscan
|
||||
parameter ACTIVE_COLUMNS = 640;
|
||||
parameter ACTIVE_ROWS = 480;
|
||||
|
||||
parameter TOTAL_COLUMNS = 800;
|
||||
parameter TOTAL_ROWS = 525;
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
if (o_rawX == TOTAL_COLUMNS - 1) begin
|
||||
o_rawX <= 0;
|
||||
if (o_rawY == TOTAL_ROWS - 1) begin
|
||||
o_rawY <= 0;
|
||||
end else begin
|
||||
o_rawY <= o_rawY + 1;
|
||||
end
|
||||
end else begin
|
||||
o_rawX <= o_rawX + 1;
|
||||
end
|
||||
end
|
||||
|
||||
assign o_HSync = (o_rawX < ACTIVE_COLUMNS) ? 1 : 0;
|
||||
assign o_VSync = (o_rawY < ACTIVE_ROWS) ? 1 : 0;
|
||||
endmodule
|
|
@ -0,0 +1,219 @@
|
|||
module VGA_Tester(
|
||||
input i_Clk,
|
||||
|
||||
output o_VGA_HSync,
|
||||
output o_VGA_VSync,
|
||||
output o_VGA_Red_0,
|
||||
output o_VGA_Red_1,
|
||||
output o_VGA_Red_2,
|
||||
output o_VGA_Grn_0,
|
||||
output o_VGA_Grn_1,
|
||||
output o_VGA_Grn_2,
|
||||
output o_VGA_Blu_0,
|
||||
output o_VGA_Blu_1,
|
||||
output o_VGA_Blu_2,
|
||||
|
||||
input i_UART_RX,
|
||||
output o_UART_TX,
|
||||
|
||||
output o_Segment1_A,
|
||||
output o_Segment1_B,
|
||||
output o_Segment1_C,
|
||||
output o_Segment1_D,
|
||||
output o_Segment1_E,
|
||||
output o_Segment1_F,
|
||||
output o_Segment1_G,
|
||||
output o_Segment2_A,
|
||||
output o_Segment2_B,
|
||||
output o_Segment2_C,
|
||||
output o_Segment2_D,
|
||||
output o_Segment2_E,
|
||||
output o_Segment2_F,
|
||||
output o_Segment2_G
|
||||
);
|
||||
localparam TOTAL_COLUMNS = 800;
|
||||
localparam TOTAL_ROWS = 525;
|
||||
|
||||
localparam ACTIVE_COLUMNS = 640;
|
||||
localparam ACTIVE_ROWS = 480;
|
||||
|
||||
localparam VIDEO_WIDTH = 3;
|
||||
|
||||
// vga
|
||||
wire w_HSync_Start, w_VSync_Start;
|
||||
wire w_HSync_FromTestPattern, w_VSync_FromTestPattern;
|
||||
wire w_HSync_FromPorchSync, w_VSync_FromPorchSync;
|
||||
|
||||
wire [VIDEO_WIDTH-1:0] w_Red_FromTestPattern;
|
||||
wire [VIDEO_WIDTH-1:0] w_Red_FromPorchSync;
|
||||
wire [VIDEO_WIDTH-1:0] w_Green_FromTestPattern;
|
||||
wire [VIDEO_WIDTH-1:0] w_Green_FromPorchSync;
|
||||
wire [VIDEO_WIDTH-1:0] w_Blue_FromTestPattern;
|
||||
wire [VIDEO_WIDTH-1:0] w_Blue_FromPorchSync;
|
||||
|
||||
reg [3:0] r_currentPattern = 6;
|
||||
|
||||
// uart
|
||||
wire w_dataReady;
|
||||
wire [7:0] w_dataByte;
|
||||
wire w_transmitActive, w_transmitSerial;
|
||||
|
||||
wire w_segment1_A, w_segment2_A;
|
||||
wire w_segment1_B, w_segment2_B;
|
||||
wire w_segment1_C, w_segment2_C;
|
||||
wire w_segment1_D, w_segment2_D;
|
||||
wire w_segment1_E, w_segment2_E;
|
||||
wire w_segment1_F, w_segment2_F;
|
||||
wire w_segment1_G, w_segment2_G;
|
||||
|
||||
reg r_resetTransmit = 1;
|
||||
|
||||
// accept incoming data
|
||||
|
||||
UART_RX #(
|
||||
.CLOCKS_PER_SECOND(25000000),
|
||||
.BAUD_RATE(115200)
|
||||
) MyUART_RX (
|
||||
.i_Clk(i_Clk),
|
||||
.i_ReceiveBit(i_UART_RX),
|
||||
.o_DataReady(w_dataReady),
|
||||
.o_DataByte(w_dataByte)
|
||||
);
|
||||
|
||||
UART_TX #(
|
||||
.CLOCKS_PER_SECOND(25000000),
|
||||
.BAUD_RATE(115200)
|
||||
) MyUART_TX (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Reset_Low(r_resetTransmit),
|
||||
.i_TransmitReady(w_dataReady),
|
||||
.i_TransmitByte(w_dataByte),
|
||||
.o_Active(w_transmitActive),
|
||||
.o_Output(w_transmitSerial),
|
||||
.o_Done()
|
||||
);
|
||||
|
||||
assign o_UART_TX = w_transmitActive ? w_transmitSerial : 1;
|
||||
|
||||
Binary_to_7_Segment Segment_1 (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Number(w_dataByte[7:4]),
|
||||
.o_SegA(w_segment1_A),
|
||||
.o_SegB(w_segment1_B),
|
||||
.o_SegC(w_segment1_C),
|
||||
.o_SegD(w_segment1_D),
|
||||
.o_SegE(w_segment1_E),
|
||||
.o_SegF(w_segment1_F),
|
||||
.o_SegG(w_segment1_G)
|
||||
);
|
||||
|
||||
assign o_Segment1_A = !w_segment1_A;
|
||||
assign o_Segment1_B = !w_segment1_B;
|
||||
assign o_Segment1_C = !w_segment1_C;
|
||||
assign o_Segment1_D = !w_segment1_D;
|
||||
assign o_Segment1_E = !w_segment1_E;
|
||||
assign o_Segment1_F = !w_segment1_F;
|
||||
assign o_Segment1_G = !w_segment1_G;
|
||||
|
||||
Binary_to_7_Segment Segment_2 (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Number(w_dataByte[3:0]),
|
||||
.o_SegA(w_segment2_A),
|
||||
.o_SegB(w_segment2_B),
|
||||
.o_SegC(w_segment2_C),
|
||||
.o_SegD(w_segment2_D),
|
||||
.o_SegE(w_segment2_E),
|
||||
.o_SegF(w_segment2_F),
|
||||
.o_SegG(w_segment2_G)
|
||||
);
|
||||
|
||||
assign o_Segment2_A = !w_segment2_A;
|
||||
assign o_Segment2_B = !w_segment2_B;
|
||||
assign o_Segment2_C = !w_segment2_C;
|
||||
assign o_Segment2_D = !w_segment2_D;
|
||||
assign o_Segment2_E = !w_segment2_E;
|
||||
assign o_Segment2_F = !w_segment2_F;
|
||||
assign o_Segment2_G = !w_segment2_G;
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
if (w_dataReady) begin
|
||||
r_currentPattern <= w_dataByte[3:0];
|
||||
end
|
||||
end
|
||||
|
||||
// show the video
|
||||
|
||||
VGA_Sync_Pulse_Generator #(
|
||||
.TOTAL_COLUMNS(TOTAL_COLUMNS),
|
||||
.TOTAL_ROWS(TOTAL_ROWS),
|
||||
.ACTIVE_COLUMNS(ACTIVE_COLUMNS),
|
||||
.ACTIVE_ROWS(ACTIVE_ROWS)
|
||||
) SyncGenerator (
|
||||
.i_Clk(i_Clk),
|
||||
.o_HSync(w_HSync_Start),
|
||||
.o_VSync(w_VSync_Start),
|
||||
.o_rawX(),
|
||||
.o_rawY()
|
||||
);
|
||||
|
||||
VGA_Pattern_Generator #(
|
||||
.VIDEO_WIDTH(VIDEO_WIDTH),
|
||||
.TOTAL_COLUMNS(TOTAL_COLUMNS),
|
||||
.TOTAL_ROWS(TOTAL_ROWS),
|
||||
.ACTIVE_COLUMNS(ACTIVE_COLUMNS),
|
||||
.ACTIVE_ROWS(ACTIVE_ROWS)
|
||||
) PatternGenerator (
|
||||
.i_Clk(i_Clk),
|
||||
.i_Pattern(r_currentPattern),
|
||||
.i_HSync(w_HSync_Start),
|
||||
.i_VSync(w_VSync_Start),
|
||||
|
||||
.o_HSync(w_HSync_FromTestPattern),
|
||||
.i_Clk(i_Clk),
|
||||
.i_Pattern(r_currentPattern),
|
||||
.i_HSync(w_HSync_Start),
|
||||
.i_VSync(w_VSync_Start),
|
||||
|
||||
.o_HSync(w_HSync_FromTestPattern),
|
||||
.o_VSync(w_VSync_FromTestPattern),
|
||||
.o_Red(w_Red_FromTestPattern),
|
||||
.o_Green(w_Green_FromTestPattern),
|
||||
.o_Blue(w_Blue_FromTestPattern)
|
||||
);
|
||||
|
||||
VGA_Add_Porches_To_Output #(
|
||||
.VIDEO_WIDTH(VIDEO_WIDTH),
|
||||
.TOTAL_COLUMNS(TOTAL_COLUMNS),
|
||||
.TOTAL_ROWS(TOTAL_ROWS),
|
||||
.ACTIVE_COLUMNS(ACTIVE_COLUMNS),
|
||||
.ACTIVE_ROWS(ACTIVE_ROWS)
|
||||
) PorchBuilder (
|
||||
.i_Clk(i_Clk),
|
||||
.i_HSync(w_HSync_FromTestPattern),
|
||||
.i_VSync(w_VSync_FromTestPattern),
|
||||
.i_Red(w_Red_FromTestPattern),
|
||||
.i_Green(w_Green_FromTestPattern),
|
||||
.i_Blue(w_Blue_FromTestPattern),
|
||||
|
||||
.o_HSync(w_HSync_FromPorchSync),
|
||||
.o_VSync(w_VSync_FromPorchSync),
|
||||
.o_Red(w_Red_FromPorchSync),
|
||||
.o_Green(w_Green_FromPorchSync),
|
||||
.o_Blue(w_Blue_FromPorchSync)
|
||||
);
|
||||
|
||||
assign o_VGA_HSync = w_HSync_FromPorchSync;
|
||||
assign o_VGA_VSync = w_VSync_FromPorchSync;
|
||||
|
||||
assign o_VGA_Red_0 = w_Red_FromPorchSync[0];
|
||||
assign o_VGA_Red_1 = w_Red_FromPorchSync[1];
|
||||
assign o_VGA_Red_2 = w_Red_FromPorchSync[2];
|
||||
|
||||
assign o_VGA_Grn_0 = w_Green_FromPorchSync[0];
|
||||
assign o_VGA_Grn_1 = w_Green_FromPorchSync[1];
|
||||
assign o_VGA_Grn_2 = w_Green_FromPorchSync[2];
|
||||
|
||||
assign o_VGA_Blu_0 = w_Blue_FromPorchSync[0];
|
||||
assign o_VGA_Blu_1 = w_Blue_FromPorchSync[1];
|
||||
assign o_VGA_Blu_2 = w_Blue_FromPorchSync[2];
|
||||
endmodule
|
Loading…
Reference in New Issue