More stuff
This commit is contained in:
parent
e47471826e
commit
11cea6b1cf
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/test
|
||||
/test.vcd
|
8
Makefile
8
Makefile
@ -1,19 +1,21 @@
|
||||
CONSTRAINTS = ../Go_Board_Constraints.pcf
|
||||
LED_TOGGLE = pong_runner.bin
|
||||
LED_TOGGLE = double_dabble_counters.bin
|
||||
|
||||
install: $(LED_TOGGLE)
|
||||
iceprog $(LED_TOGGLE)
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
iverilog -o test uart_rx_test.v uart_rx.v
|
||||
iverilog -o test image_index_to_color.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
|
||||
#yosys -q -p "hierarchy -top VGAImageRenderer_Top; synth_ice40 -json $*.json" $*.v vga_sync_pulse_generator.v vga_current_beam_position.v vga_add_porches_to_output.v image_index_to_color.v image_ram.v
|
||||
#yosys -q -p "hierarchy -top VGAImageRenderer_Top; synth_ice40 -json $*.json" $*.v vga_image_renderer.v image_ram.v image_index_to_color.v vga_sync_pulse_generator.v vga_current_beam_position.v vga_add_porches_to_output.v
|
||||
yosys -q -p "hierarchy -top DoubleDabbleCounter_Top; synth_ice40 -json $*.json" $*.v
|
||||
|
||||
.json.bitstream:
|
||||
#nextpnr-ice40 --hx1k --freq 25 --pcf $(CONSTRAINTS) --json $*.json --package vq100 --asc $*.bitstream
|
||||
|
101
build_image.rb
Executable file
101
build_image.rb
Executable file
@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'rmagick'
|
||||
|
||||
class GoBoardPixel
|
||||
GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL = 65_536 / 8
|
||||
|
||||
attr_reader :red, :green, :blue
|
||||
|
||||
def self.from_magick(red:, green:, blue:)
|
||||
new(
|
||||
red: red / GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL,
|
||||
green: green / GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL,
|
||||
blue: blue / GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL
|
||||
)
|
||||
end
|
||||
|
||||
def initialize(red:, green:, blue:)
|
||||
@red = red
|
||||
@green = green
|
||||
@blue = blue
|
||||
end
|
||||
|
||||
def distance_from_real_pixel(red:, green:, blue:)
|
||||
(red - @red * GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL)**2 +
|
||||
(green - @green * GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL)**2 +
|
||||
(blue - @blue * GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL)**2
|
||||
end
|
||||
|
||||
def distance_from_go_pixel(red:, green:, blue:)
|
||||
(red - @red)**2 +
|
||||
(green - @green)**2 +
|
||||
(blue - @blue)**2
|
||||
end
|
||||
|
||||
def eql?(other)
|
||||
red == other.red && green == other.green && blue == other.blue
|
||||
end
|
||||
|
||||
def hash
|
||||
[red, green, blue].hash
|
||||
end
|
||||
end
|
||||
|
||||
ImagePixel = Data.define(:red, :green, :blue)
|
||||
|
||||
image = Magick::Image.read(ARGV[0]).first
|
||||
image.change_geometry!('80x60^') do |cols, rows, img|
|
||||
img.resize!(cols, rows)
|
||||
end
|
||||
image.crop!(Magick::CenterGravity, 80, 60, true)
|
||||
|
||||
possible_colors = {}
|
||||
image.each_pixel do |px|
|
||||
go_px = GoBoardPixel.from_magick(red: px.red, green: px.green, blue: px.blue)
|
||||
possible_colors[go_px] ||= 0
|
||||
possible_colors[go_px] += 1
|
||||
end
|
||||
|
||||
pixels_by_usage = possible_colors.sort_by(&:last).reverse
|
||||
|
||||
go_board_palette = pixels_by_usage[0..31].map(&:first)
|
||||
color_mapping = go_board_palette.each_with_index.each_with_object({}) do |(go_px, index), obj|
|
||||
obj[go_px] = index
|
||||
end
|
||||
|
||||
pixels_by_usage[32..].map(&:first).each do |go_px|
|
||||
best_match = go_board_palette.each_with_index.map do |target_go_px, index|
|
||||
[
|
||||
target_go_px.distance_from_go_pixel(
|
||||
red: go_px.red,
|
||||
green: go_px.green,
|
||||
blue: go_px.blue,
|
||||
), index
|
||||
]
|
||||
end.sort_by(&:first).first
|
||||
|
||||
color_mapping[go_px] = best_match.last
|
||||
end
|
||||
|
||||
File.open('image_data.txt', 'w') do |fh|
|
||||
image.each_pixel do |px|
|
||||
magick_px = GoBoardPixel.from_magick(
|
||||
red: px.red, green: px.green, blue: px.blue
|
||||
)
|
||||
|
||||
fh.puts format('%05b', color_mapping[magick_px])
|
||||
end
|
||||
end
|
||||
|
||||
File.open('palette_data.txt', 'w') do |fh|
|
||||
go_board_palette.each do |color|
|
||||
fh.puts format('%09b', ((color.red << 6) + (color.green << 3) + color.blue))
|
||||
end
|
||||
end
|
||||
|
||||
# [ ] load image
|
||||
# [ ] downsample to 40x30
|
||||
# [ ] change to indexed image with go board palette
|
||||
# [ ] save out body data
|
||||
# [ ] save out palette data
|
37
double_dabble.rb
Executable file
37
double_dabble.rb
Executable file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# build double dabble in ruby so I can feel how it works
|
||||
|
||||
number = 999
|
||||
|
||||
puts "Binary: #{number.to_s(2)}"
|
||||
|
||||
binary_registers = number.to_s(2).split('').map(&:to_i)
|
||||
|
||||
scratch_size = 4 * (binary_registers.count / 3).ceil
|
||||
scratch_space = Array.new(binary_registers.count + scratch_size) { 0 }
|
||||
|
||||
binary_registers.each_with_index do |reg, i|
|
||||
scratch_space[-(binary_registers.count - i)] = reg
|
||||
end
|
||||
|
||||
pp (scratch_space.count / 4).to_i
|
||||
|
||||
binary_registers.count.times do
|
||||
(scratch_size / 4).to_i.times do |j|
|
||||
value = scratch_space[j * 4..j * 4 + 3].join.to_i(2)
|
||||
|
||||
next unless value > 4
|
||||
|
||||
value += 3
|
||||
|
||||
scratch_space[j * 4..j * 4 + 3] = value.to_s(2).split('').map(&:to_i)
|
||||
end
|
||||
|
||||
(scratch_space.count - 1).times do |j|
|
||||
scratch_space[j] = scratch_space[j + 1]
|
||||
end
|
||||
scratch_space[-1] = 0
|
||||
|
||||
pp scratch_space
|
||||
end
|
BIN
double_dabble_counters.bin
Normal file
BIN
double_dabble_counters.bin
Normal file
Binary file not shown.
136
double_dabble_counters.v
Normal file
136
double_dabble_counters.v
Normal file
@ -0,0 +1,136 @@
|
||||
module DoubleDabbleCounter_Top(
|
||||
input i_Clk,
|
||||
|
||||
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
|
||||
);
|
||||
reg [6:0] r_currentNumber = 0;
|
||||
reg [$clog2(10000000)-1:0] r_counter;
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
if (r_counter == 10000000) begin
|
||||
r_counter <= 0;
|
||||
if (r_currentNumber == 99) begin
|
||||
r_currentNumber <= 0;
|
||||
end else begin
|
||||
r_currentNumber <= r_currentNumber + 1;
|
||||
end
|
||||
end else begin
|
||||
r_counter <= r_counter + 1;
|
||||
end
|
||||
end
|
||||
|
||||
wire [8:0] w_binaryCodedNumber;
|
||||
|
||||
wire [3:0] w_decimal1, w_decimal2;
|
||||
wire [6:0] w_segment1, w_segment2;
|
||||
|
||||
IntegerToBCD integerToBCD (
|
||||
.i_BinaryNumber(r_currentNumber),
|
||||
.o_BinaryCodedDecimal(w_binaryCodedNumber)
|
||||
);
|
||||
|
||||
assign w_decimal1 = w_binaryCodedNumber[7:4];
|
||||
assign w_decimal2 = w_binaryCodedNumber[3:0];
|
||||
|
||||
BCDTo7Segment segment1 (
|
||||
.i_Clk(i_Clk),
|
||||
.i_BinaryCodedDecimal(w_decimal1),
|
||||
.o_SegmentLights(w_segment1)
|
||||
);
|
||||
|
||||
BCDTo7Segment segment2 (
|
||||
.i_Clk(i_Clk),
|
||||
.i_BinaryCodedDecimal(w_decimal2),
|
||||
.o_SegmentLights(w_segment2)
|
||||
);
|
||||
|
||||
assign o_Segment1_A = !w_segment1[6];
|
||||
assign o_Segment1_B = !w_segment1[5];
|
||||
assign o_Segment1_C = !w_segment1[4];
|
||||
assign o_Segment1_D = !w_segment1[3];
|
||||
assign o_Segment1_E = !w_segment1[2];
|
||||
assign o_Segment1_F = !w_segment1[1];
|
||||
assign o_Segment1_G = !w_segment1[0];
|
||||
|
||||
assign o_Segment2_A = !w_segment2[6];
|
||||
assign o_Segment2_B = !w_segment2[5];
|
||||
assign o_Segment2_C = !w_segment2[4];
|
||||
assign o_Segment2_D = !w_segment2[3];
|
||||
assign o_Segment2_E = !w_segment2[2];
|
||||
assign o_Segment2_F = !w_segment2[1];
|
||||
assign o_Segment2_G = !w_segment2[0];
|
||||
|
||||
// register that goes to 99
|
||||
// debounce two input buttons
|
||||
// button 1 increases
|
||||
// button 2 decreases
|
||||
|
||||
endmodule
|
||||
|
||||
module BCDTo7Segment(
|
||||
input i_Clk,
|
||||
input [3:0] i_BinaryCodedDecimal,
|
||||
output reg [6:0] o_SegmentLights
|
||||
);
|
||||
always @(posedge i_Clk) begin
|
||||
case (i_BinaryCodedDecimal)
|
||||
0: o_SegmentLights <= 7'b1111110;
|
||||
1: o_SegmentLights <= 7'b0110000;
|
||||
2: o_SegmentLights <= 7'b1101101;
|
||||
3: o_SegmentLights <= 7'b1111001;
|
||||
4: o_SegmentLights <= 7'b0110011;
|
||||
5: o_SegmentLights <= 7'b1011011;
|
||||
6: o_SegmentLights <= 7'b1011111;
|
||||
7: o_SegmentLights <= 7'b1110000;
|
||||
8: o_SegmentLights <= 7'b1111111;
|
||||
9: o_SegmentLights <= 7'b1111011;
|
||||
default: o_SegmentLights <= 7'b0000000;
|
||||
endcase
|
||||
end
|
||||
endmodule
|
||||
|
||||
/**
|
||||
* From https://github.com/AmeerAbdelhadi/Binary-to-BCD-Converter
|
||||
* This halts until the conversion is done!
|
||||
*/
|
||||
module IntegerToBCD(
|
||||
input [MAX_BIT_WIDTH-1:0] i_BinaryNumber,
|
||||
output reg [SCRATCH_AREA_WIDTH:0] o_BinaryCodedDecimal
|
||||
);
|
||||
// this is all the go board will need for the 7 segment display to go to 99
|
||||
parameter MAX_BIT_WIDTH = 7;
|
||||
|
||||
localparam SCRATCH_AREA_WIDTH = MAX_BIT_WIDTH+(MAX_BIT_WIDTH-4)/3;
|
||||
|
||||
integer i,j;
|
||||
|
||||
always @(i_BinaryNumber) begin
|
||||
for (i = 0; i <= SCRATCH_AREA_WIDTH; i = i + 1) begin
|
||||
o_BinaryCodedDecimal[i] = 0;
|
||||
end
|
||||
|
||||
o_BinaryCodedDecimal[MAX_BIT_WIDTH-1:0] = i_BinaryNumber;
|
||||
|
||||
// this does the shift-and-add in small pieces
|
||||
for (i = 0; i <= MAX_BIT_WIDTH - 4; i = i + 1) begin
|
||||
for (j = 0; j <= i / 3; j = j + 1) begin
|
||||
if (o_BinaryCodedDecimal[MAX_BIT_WIDTH-i+4*j -: 4] > 4) begin
|
||||
o_BinaryCodedDecimal[MAX_BIT_WIDTH-i+4*j -: 4] = o_BinaryCodedDecimal[MAX_BIT_WIDTH-i+4*j -: 4] + 4'd3;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
4800
image_data.txt
Normal file
4800
image_data.txt
Normal file
File diff suppressed because it is too large
Load Diff
94
image_index_to_color.v
Normal file
94
image_index_to_color.v
Normal file
@ -0,0 +1,94 @@
|
||||
module ImageIndexToColor(
|
||||
input i_Clk,
|
||||
|
||||
input [4:0] i_ColorIndex,
|
||||
|
||||
input i_DoWrite,
|
||||
input [3:0] i_WriteColorIndex,
|
||||
input [2:0] i_WriteColor_Red,
|
||||
input [2:0] i_WriteColor_Green,
|
||||
input [2:0] i_WriteColor_Blue,
|
||||
|
||||
output [2:0] o_Red,
|
||||
output [2:0] o_Green,
|
||||
output [2:0] o_Blue,
|
||||
|
||||
output reg o_WriteComplete
|
||||
);
|
||||
reg [8:0] r_colors[0:31];
|
||||
|
||||
initial begin
|
||||
$readmemb("palette_data.txt", r_colors);
|
||||
end
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
if (i_DoWrite) begin
|
||||
r_colors[i_WriteColorIndex] <= {
|
||||
i_WriteColor_Red, i_WriteColor_Green, i_WriteColor_Blue
|
||||
};
|
||||
o_WriteComplete <= i_DoWrite;
|
||||
end
|
||||
end
|
||||
|
||||
assign o_Red = r_colors[i_ColorIndex][8:6];
|
||||
assign o_Green = r_colors[i_ColorIndex][5:3];
|
||||
assign o_Blue = r_colors[i_ColorIndex][2:0];
|
||||
endmodule
|
||||
|
||||
module TestImageIndexToColor();
|
||||
reg i_Clk = 0;
|
||||
|
||||
always #2 i_Clk <= !i_Clk;
|
||||
|
||||
reg [3:0] r_colorIndex = 0;
|
||||
wire [2:0] w_Red, w_Green, w_Blue;
|
||||
wire w_writeComplete;
|
||||
|
||||
reg r_doWrite = 0;
|
||||
reg [2:0] r_WriteColor_Red = 3'b111;
|
||||
reg [2:0] r_WriteColor_Green = 3'b000;
|
||||
reg [2:0] r_WriteColor_Blue = 3'b001;
|
||||
reg [3:0] r_writeColorIndex = 0;
|
||||
|
||||
ImageIndexToColor ii2c (
|
||||
.i_Clk(i_Clk),
|
||||
|
||||
.i_ColorIndex(r_colorIndex),
|
||||
|
||||
.i_DoWrite(r_doWrite),
|
||||
.i_WriteColorIndex(r_writeColorIndex),
|
||||
.i_WriteColor_Red(r_WriteColor_Red),
|
||||
.i_WriteColor_Green(r_WriteColor_Green),
|
||||
.i_WriteColor_Blue(r_WriteColor_Blue),
|
||||
|
||||
.o_Red(w_Red),
|
||||
.o_Green(w_Green),
|
||||
.o_Blue(w_Blue),
|
||||
.o_WriteComplete(w_writeComplete)
|
||||
);
|
||||
|
||||
initial begin
|
||||
$dumpfile("test.vcd");
|
||||
$dumpvars;
|
||||
|
||||
#2;
|
||||
#2;
|
||||
|
||||
r_colorIndex = 1;
|
||||
|
||||
#2;
|
||||
#2;
|
||||
|
||||
r_doWrite = 1;
|
||||
|
||||
#2;
|
||||
#2;
|
||||
|
||||
r_colorIndex = 15;
|
||||
|
||||
#2;
|
||||
#2;
|
||||
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
92
image_ram.v
Normal file
92
image_ram.v
Normal file
@ -0,0 +1,92 @@
|
||||
module ImageRAM(
|
||||
input i_Clk,
|
||||
|
||||
input i_doRead,
|
||||
input [$clog2(WIDTH)-1:0] i_ReadX,
|
||||
input [$clog2(HEIGHT)-1:0] i_ReadY,
|
||||
|
||||
input [$clog2(WIDTH)-1:0] i_WriteX,
|
||||
input [$clog2(HEIGHT)-1:0] i_WriteY,
|
||||
input [$clog2(INDEXES)-1:0] i_WriteData,
|
||||
input i_DoWrite,
|
||||
|
||||
output reg o_ReadDataReady,
|
||||
output reg [4:0] o_ReadData,
|
||||
|
||||
output reg o_WriteComplete
|
||||
);
|
||||
parameter INDEXES = 8;
|
||||
parameter WIDTH = 80;
|
||||
parameter HEIGHT = 60;
|
||||
|
||||
reg [4:0] r_Memory[0:HEIGHT-1][0:WIDTH-1];
|
||||
|
||||
initial begin
|
||||
$readmemb("image_data.txt", r_Memory);
|
||||
end
|
||||
|
||||
// reading
|
||||
always @(posedge i_Clk) begin
|
||||
o_ReadData <= r_Memory[i_ReadY][i_ReadX];
|
||||
o_ReadDataReady <= i_doRead;
|
||||
end
|
||||
|
||||
// writing
|
||||
always @(posedge i_Clk) begin
|
||||
if (i_DoWrite) begin
|
||||
r_Memory[i_WriteY][i_WriteX] <= i_WriteData;
|
||||
o_WriteComplete <= i_DoWrite;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
module TestImageRAM();
|
||||
reg r_Clk = 0;
|
||||
always #2 r_Clk <= !r_Clk;
|
||||
|
||||
reg r_doRead = 0;
|
||||
|
||||
reg [5:0] r_readX = 0;
|
||||
reg [4:0] r_readY = 0;
|
||||
|
||||
wire w_readDataReady;
|
||||
wire [2:0] w_readData;
|
||||
|
||||
ImageRAM MyRam (
|
||||
.i_Clk(r_Clk),
|
||||
.i_doRead(r_doRead),
|
||||
.i_ReadX(r_readX),
|
||||
.i_ReadY(r_readY),
|
||||
.o_ReadDataReady(w_readDataReady),
|
||||
.o_ReadData(w_readData)
|
||||
);
|
||||
|
||||
initial begin
|
||||
$dumpfile("test.vcd");
|
||||
$dumpvars;
|
||||
|
||||
#2;
|
||||
#2;
|
||||
|
||||
r_doRead <= 1;
|
||||
|
||||
#2;
|
||||
#2;
|
||||
|
||||
r_doRead <= 0;
|
||||
r_readX <= 1;
|
||||
r_readY <= 0;
|
||||
|
||||
#2;
|
||||
#2;
|
||||
|
||||
r_doRead <= 1;
|
||||
|
||||
#2;
|
||||
#2;
|
||||
|
||||
r_doRead <= 0;
|
||||
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
2
image_ram_dat.txt
Normal file
2
image_ram_dat.txt
Normal file
@ -0,0 +1,2 @@
|
||||
011
|
||||
101
|
32
palette_data.txt
Normal file
32
palette_data.txt
Normal file
@ -0,0 +1,32 @@
|
||||
011110111
|
||||
101111111
|
||||
100110111
|
||||
100111111
|
||||
100011011
|
||||
011010010
|
||||
110011010
|
||||
111100011
|
||||
001011100
|
||||
111100100
|
||||
101011010
|
||||
010101111
|
||||
110011011
|
||||
011101110
|
||||
010001001
|
||||
111101101
|
||||
101011011
|
||||
010100101
|
||||
101100100
|
||||
000010011
|
||||
110101101
|
||||
001100110
|
||||
000011100
|
||||
110100100
|
||||
100010010
|
||||
100100100
|
||||
110100011
|
||||
101010010
|
||||
001100101
|
||||
111101100
|
||||
011011011
|
||||
010110111
|
BIN
pong_runner.bin
Normal file
BIN
pong_runner.bin
Normal file
Binary file not shown.
@ -1,6 +1,9 @@
|
||||
/**
|
||||
* The output is buffered as the front/back porches are added, so watch your
|
||||
* timing for other stuff.
|
||||
*
|
||||
* Side effects:
|
||||
* * Blanks o_<color> if within HSync/VSync
|
||||
*/
|
||||
module VGA_Add_Porches_To_Output(
|
||||
input i_Clk,
|
||||
@ -55,21 +58,23 @@ module VGA_Add_Porches_To_Output(
|
||||
.o_Y(w_Y)
|
||||
);
|
||||
|
||||
wire w_withinHPorch, w_withinVPorch, w_withinSync;
|
||||
|
||||
assign w_withinHPorch = (w_X < FRONT_PORCH_COUNT_X + ACTIVE_COLUMNS) ||
|
||||
(w_X > TOTAL_COLUMNS - BACK_PORCH_COUNT_X - 1);
|
||||
assign w_withinVPorch = (w_Y < FRONT_PORCH_COUNT_Y + ACTIVE_ROWS) ||
|
||||
(w_Y > TOTAL_ROWS - BACK_PORCH_COUNT_Y - 1);
|
||||
assign w_withinSync = (w_X > ACTIVE_COLUMNS) || (w_Y > ACTIVE_COLUMNS);
|
||||
|
||||
// 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
|
||||
if (w_withinHPorch) 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
|
||||
if (w_withinVPorch) begin
|
||||
o_VSync <= 1;
|
||||
end else begin
|
||||
o_VSync <= w_VSync;
|
||||
@ -84,8 +89,15 @@ module VGA_Add_Porches_To_Output(
|
||||
r_Green <= i_Green;
|
||||
r_Blue <= i_Blue;
|
||||
|
||||
o_Red <= r_Red;
|
||||
o_Green <= r_Green;
|
||||
o_Blue <= r_Blue;
|
||||
// Ensure we never deliver color data during hsync/vsync
|
||||
if (w_withinSync) begin
|
||||
o_Red <= 0;
|
||||
o_Green <= 0;
|
||||
o_Blue <= 0;
|
||||
end else begin
|
||||
o_Red <= r_Red;
|
||||
o_Green <= r_Green;
|
||||
o_Blue <= r_Blue;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
@ -10,11 +10,16 @@ module VGA_Current_Beam_Position(
|
||||
output reg o_VSync = 0,
|
||||
|
||||
output reg [$clog2(TOTAL_COLUMNS)-1:0] o_X,
|
||||
output reg [$clog2(TOTAL_ROWS)-1:0] o_Y
|
||||
output reg [$clog2(TOTAL_ROWS)-1:0] o_Y,
|
||||
|
||||
output o_IsActiveArea
|
||||
);
|
||||
parameter TOTAL_COLUMNS = 800;
|
||||
parameter TOTAL_ROWS = 525;
|
||||
|
||||
parameter ACTIVE_COLUMNS = 640;
|
||||
parameter ACTIVE_ROWS = 480;
|
||||
|
||||
wire w_frameStart;
|
||||
|
||||
// forward these flip-flop style. use these instead of what
|
||||
@ -44,4 +49,5 @@ module VGA_Current_Beam_Position(
|
||||
|
||||
// rising vsync == new frame
|
||||
assign w_frameStart = (~o_VSync & i_VSync);
|
||||
assign o_IsActiveArea = (o_X < ACTIVE_COLUMNS && o_Y < ACTIVE_COLUMNS);
|
||||
endmodule
|
||||
|
BIN
vga_image_renderer.bin
Normal file
BIN
vga_image_renderer.bin
Normal file
Binary file not shown.
81
vga_image_renderer.v
Normal file
81
vga_image_renderer.v
Normal file
@ -0,0 +1,81 @@
|
||||
module VGAImageRenderer(
|
||||
input i_Clk,
|
||||
input i_HSync,
|
||||
input i_VSync,
|
||||
|
||||
output o_HSync,
|
||||
output o_VSync,
|
||||
output [2:0] o_Red,
|
||||
output [2:0] o_Green,
|
||||
output [2:0] o_Blue
|
||||
);
|
||||
// sync signals
|
||||
wire w_HSync_FromCurrentPos, w_VSync_FromCurrentPos;
|
||||
wire w_IsActiveArea;
|
||||
|
||||
// screen location
|
||||
wire [9:0] w_X, w_Y;
|
||||
wire [6:0] w_CellX;
|
||||
wire [5:0] w_CellY;
|
||||
|
||||
// ram reading
|
||||
reg r_doImageRAMRead = 1;
|
||||
reg r_doImageRAMWrite = 0;
|
||||
wire w_imageRAMReadDataReady;
|
||||
wire [4:0] w_imageRAMReadData;
|
||||
|
||||
wire [2:0] w_Red, w_Green, w_Blue;
|
||||
|
||||
VGA_Current_Beam_Position currentPos (
|
||||
.i_Clk(i_Clk),
|
||||
.i_HSync(i_HSync),
|
||||
.i_VSync(i_VSync),
|
||||
|
||||
.o_HSync(w_HSync_FromCurrentPos),
|
||||
.o_VSync(w_VSync_FromCurrentPos),
|
||||
.o_X(w_X),
|
||||
.o_Y(w_Y),
|
||||
.o_IsActiveArea(w_IsActiveArea)
|
||||
);
|
||||
|
||||
assign w_CellX = w_X[9:3];
|
||||
assign w_CellY = w_Y[9:3];
|
||||
|
||||
// takes a tick, so add one to HSync/VSync
|
||||
ImageRAM imageRam (
|
||||
.i_Clk(i_Clk),
|
||||
.i_ReadX(w_CellX),
|
||||
.i_ReadY(w_CellY),
|
||||
.i_doRead(r_doImageRAMRead),
|
||||
.o_ReadDataReady(w_imageRAMReadDataReady),
|
||||
.o_ReadData(w_imageRAMReadData),
|
||||
|
||||
.i_WriteX(),
|
||||
.i_WriteY(),
|
||||
.i_WriteData(),
|
||||
.i_DoWrite(r_doImageRAMWrite),
|
||||
.o_WriteComplete()
|
||||
);
|
||||
|
||||
ImageIndexToColor palette (
|
||||
.i_Clk(i_Clk),
|
||||
.i_ColorIndex(w_imageRAMReadData),
|
||||
.o_Red(w_Red),
|
||||
.o_Green(w_Green),
|
||||
.o_Blue(w_Blue),
|
||||
|
||||
.i_DoWrite(r_doImageRAMWrite),
|
||||
.i_WriteColorIndex(),
|
||||
.i_WriteColor_Red(),
|
||||
.i_WriteColor_Green(),
|
||||
.i_WriteColor_Blue(),
|
||||
.o_WriteComplete()
|
||||
);
|
||||
|
||||
assign o_Red = w_IsActiveArea ? w_Red : 0;
|
||||
assign o_Green = w_IsActiveArea ? w_Green : 0;
|
||||
assign o_Blue = w_IsActiveArea ? w_Blue : 0;
|
||||
|
||||
assign o_HSync = w_HSync_FromCurrentPos;
|
||||
assign o_VSync = w_VSync_FromCurrentPos;
|
||||
endmodule
|
BIN
vga_image_renderer_top.bin
Normal file
BIN
vga_image_renderer_top.bin
Normal file
Binary file not shown.
202
vga_image_renderer_top.v
Normal file
202
vga_image_renderer_top.v
Normal file
@ -0,0 +1,202 @@
|
||||
module VGAImageRenderer_Top(
|
||||
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
|
||||
);
|
||||
localparam TOTAL_COLUMNS = 800;
|
||||
localparam TOTAL_ROWS = 525;
|
||||
|
||||
localparam ACTIVE_COLUMNS = 640;
|
||||
localparam ACTIVE_ROWS = 480;
|
||||
|
||||
localparam VIDEO_WIDTH = 3;
|
||||
|
||||
wire w_HSync_FromPulseGenerator, w_VSync_FromPulseGenerator;
|
||||
wire w_HSync_FromImageRenderer, w_VSync_FromImageRenderer;
|
||||
wire w_HSync_FromPorchSync, w_VSync_FromPorchSync;
|
||||
|
||||
wire [2:0] w_Red_FromImageRenderer, w_Green_FromImageRenderer, w_Blue_FromImageRenderer;
|
||||
wire [2:0] w_Red_FromPorchSync, w_Green_FromPorchSync, w_Blue_FromPorchSync;
|
||||
|
||||
VGA_Sync_Pulse_Generator #(
|
||||
.TOTAL_COLUMNS(TOTAL_COLUMNS),
|
||||
.TOTAL_ROWS(TOTAL_ROWS),
|
||||
.ACTIVE_COLUMNS(ACTIVE_COLUMNS),
|
||||
.ACTIVE_ROWS(ACTIVE_ROWS)
|
||||
) pulseGenerator (
|
||||
.i_Clk(i_Clk),
|
||||
|
||||
.o_HSync(w_HSync_FromPulseGenerator),
|
||||
.o_VSync(w_VSync_FromPulseGenerator),
|
||||
|
||||
.o_rawX(),
|
||||
.o_rawX()
|
||||
);
|
||||
|
||||
VGAImageRenderer imageRenderer (
|
||||
.i_Clk(i_Clk),
|
||||
|
||||
.i_HSync(w_HSync_FromPulseGenerator),
|
||||
.i_VSync(w_VSync_FromPulseGenerator),
|
||||
|
||||
.o_HSync(w_HSync_FromImageRenderer),
|
||||
.o_VSync(w_VSync_FromImageRenderer),
|
||||
.o_Red(w_Red_FromImageRenderer),
|
||||
.o_Green(w_Green_FromImageRenderer),
|
||||
.o_Blue(w_Blue_FromImageRenderer)
|
||||
);
|
||||
|
||||
wire w_HSync_FromImageDimmer, w_VSync_FromImageDimmer;
|
||||
wire [2:0] w_Red_FromImageDimmer, w_Green_FromImageDimmer, w_Blue_FromImageDimmer;
|
||||
|
||||
ImageMovingSpotlight imageDimmer (
|
||||
.i_Clk(i_Clk),
|
||||
|
||||
.i_HSync(w_HSync_FromImageRenderer),
|
||||
.i_VSync(w_VSync_FromImageRenderer),
|
||||
.i_Red(w_Red_FromImageRenderer),
|
||||
.i_Green(w_Green_FromImageRenderer),
|
||||
.i_Blue(w_Blue_FromImageRenderer),
|
||||
|
||||
.o_HSync(w_HSync_FromImageDimmer),
|
||||
.o_VSync(w_VSync_FromImageDimmer),
|
||||
.o_Red(w_Red_FromImageDimmer),
|
||||
.o_Green(w_Green_FromImageDimmer),
|
||||
.o_Blue(w_Blue_FromImageDimmer)
|
||||
);
|
||||
|
||||
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)
|
||||
) PorchOutput (
|
||||
.i_Clk(i_Clk),
|
||||
|
||||
.i_HSync(w_HSync_FromImageDimmer),
|
||||
.i_VSync(w_VSync_FromImageDimmer),
|
||||
.i_Red(w_Red_FromImageDimmer),
|
||||
.i_Green(w_Green_FromImageDimmer),
|
||||
.i_Blue(w_Blue_FromImageDimmer),
|
||||
|
||||
.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
|
||||
|
||||
module ImageMovingSpotlight(
|
||||
input i_Clk,
|
||||
input i_HSync,
|
||||
input i_VSync,
|
||||
input [2:0] i_Red,
|
||||
input [2:0] i_Green,
|
||||
input [2:0] i_Blue,
|
||||
|
||||
output reg o_HSync,
|
||||
output reg o_VSync,
|
||||
output reg [2:0] o_Red,
|
||||
output reg [2:0] o_Green,
|
||||
output reg [2:0] o_Blue
|
||||
);
|
||||
parameter VIDEO_WIDTH = 3;
|
||||
parameter TOTAL_COLUMNS = 800;
|
||||
parameter TOTAL_ROWS = 525;
|
||||
|
||||
wire w_HSync, w_VSync;
|
||||
|
||||
wire [$clog2(TOTAL_COLUMNS)-1:0] w_X;
|
||||
wire [$clog2(TOTAL_ROWS)-1:0] w_Y;
|
||||
reg [$clog2(12500000)-1:0] r_counter = 0;
|
||||
|
||||
reg [VIDEO_WIDTH-1:0] r_Red = 0;
|
||||
reg [VIDEO_WIDTH-1:0] r_Green = 0;
|
||||
reg [VIDEO_WIDTH-1:0] r_Blue = 0;
|
||||
|
||||
reg [$clog2(TOTAL_COLUMNS)-1:0] r_currentX = 4;
|
||||
reg [$clog2(TOTAL_ROWS)-1:0] r_currentY = 3;
|
||||
|
||||
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)
|
||||
);
|
||||
|
||||
wire [6:0] w_CellX;
|
||||
wire [5:0] w_CellY;
|
||||
|
||||
assign w_CellX = w_X[9:3];
|
||||
assign w_CellY = w_Y[9:3];
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
if (r_counter == 25000000/16) begin
|
||||
r_counter <= 0;
|
||||
|
||||
if (r_currentX == 80 - 1) begin
|
||||
r_currentX <= 0;
|
||||
end else begin
|
||||
r_currentX <= r_currentX + 1;
|
||||
end
|
||||
end else begin
|
||||
r_counter <= r_counter + 1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge i_Clk) begin
|
||||
o_HSync <= w_HSync;
|
||||
o_VSync <= w_VSync;
|
||||
|
||||
// if the pointer is right on the square, white
|
||||
// if the pointer is within a square, brighten by {[0, 1], 1}
|
||||
// otherwise return the current red
|
||||
|
||||
o_Red <= r_Red;
|
||||
o_Green <= r_Green;
|
||||
o_Blue <= r_Blue;
|
||||
|
||||
r_Red <= (r_currentX == w_CellX && r_currentY == w_CellY) ? 7 : i_Red;
|
||||
r_Green <= (r_currentX == w_CellX && r_currentY == w_CellY) ? 7 : i_Green;
|
||||
r_Blue <= (r_currentX == w_CellX && r_currentY == w_CellY) ? 7 : i_Blue;
|
||||
/*
|
||||
(r_currentX > 0 && w_X == r_currentX - 1 && r_currentY == w_Y) ? {i_Red[0:1], 1} :
|
||||
(r_currentX < TOTAL_COLUMNS - 2 && w_X == r_currentX + 1 && r_currentY == w_Y) ? {i_Red[0:1], 1} :
|
||||
(r_currentY > 0 && w_Y == r_currentY - 1 && r_currentX == w_X) ? {i_Red[0:1], 1} :
|
||||
(r_currentY < TOTAL_ROWS - 2 && w_Y == r_currentY + 1 && r_currentX == w_X) ? {i_Red[0:1], 1} : i_Red;
|
||||
*/
|
||||
end
|
||||
endmodule
|
@ -168,12 +168,6 @@ module VGA_Tester(
|
||||
.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),
|
||||
|
Loading…
Reference in New Issue
Block a user