aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojciech Kosior <kwojtus@protonmail.com>2020-07-15 20:21:20 +0200
committerWojciech Kosior <kwojtus@protonmail.com>2020-07-15 20:21:20 +0200
commit9f366a72a63829f640fd7acf2c6cbea139e9e0ca (patch)
treeadbbbf4b89ec76f243157a87532a18f294850570
parent641105c869ddc9bf70454103e7a606bc4377933f (diff)
downloadAGH-engineering-thesis-9f366a72a63829f640fd7acf2c6cbea139e9e0ca.tar.gz
AGH-engineering-thesis-9f366a72a63829f640fd7acf2c6cbea139e9e0ca.zip
add an example of SRAM access
-rw-r--r--src/example.v845
-rw-r--r--src/letter_A.pngbin0 -> 201 bytes
-rw-r--r--src/letter_B.pngbin0 -> 200 bytes
-rw-r--r--src/letter_C.pngbin0 -> 202 bytes
-rw-r--r--src/letter_D.pngbin0 -> 206 bytes
-rw-r--r--src/letter_E.pngbin0 -> 186 bytes
-rw-r--r--src/letter_F.pngbin0 -> 184 bytes
-rw-r--r--src/mapping.pcf62
-rw-r--r--src/number_0.pngbin0 -> 211 bytes
-rw-r--r--src/number_1.pngbin0 -> 184 bytes
-rw-r--r--src/number_2.pngbin0 -> 208 bytes
-rw-r--r--src/number_3.pngbin0 -> 212 bytes
-rw-r--r--src/number_4.pngbin0 -> 198 bytes
-rw-r--r--src/number_5.pngbin0 -> 209 bytes
-rw-r--r--src/number_6.pngbin0 -> 210 bytes
-rw-r--r--src/number_7.pngbin0 -> 205 bytes
-rw-r--r--src/number_8.pngbin0 -> 202 bytes
-rw-r--r--src/number_9.pngbin0 -> 212 bytes
18 files changed, 847 insertions, 60 deletions
diff --git a/src/example.v b/src/example.v
index bf90bbe..8c3de35 100644
--- a/src/example.v
+++ b/src/example.v
@@ -1,49 +1,329 @@
`default_nettype none
-
-module vga_example(input wire clock_100mhz,
- input wire reset,
-
- output reg h_sync,
- output reg v_sync,
- output reg [2:0] vga_red,
- output reg [2:0] vga_green,
- output reg [2:0] vga_blue
+
+ module hex_print(input wire [3:0] halfbyte,
+ input wire [7:0] x,
+ input wire [15:0] y,
+
+ output wire pixel
);
-
- wire [9:0] col_next_tick;
- wire [8:0] row_next_tick;
- wire h_sync_next_tick;
- wire v_sync_next_tick;
- wire display_on_next_tick;
-
- vga vga(clock_100mhz, ~reset, h_sync_next_tick, v_sync_next_tick,
- col_next_tick, row_next_tick, display_on_next_tick);
-
- always @ (posedge clock_100mhz) begin
- h_sync <= h_sync_next_tick;
- v_sync <= v_sync_next_tick;
-
- if (display_on_next_tick) begin
- vga_red <= 3'b000;
- vga_green <= row_next_tick < 220 ? 3'b111 : 3'b000;
- vga_blue <= row_next_tick >= 220 ? 3'b111 : 3'b000;
- end
- else begin
- vga_red <= 0;
- vga_green <= 0;
- vga_blue <= 0;
- end
- end // always @ (posedge clock_100mhz)
-endmodule // vga_example
-
-module vga(input wire clock_100mhz,
- input wire reset,
-
- output reg h_sync,
- output reg v_sync,
- output reg [9:0] col,
- output reg [8:0] row,
- output reg display_on);
+ wire [0:7] number_0 [15:0];
+ wire [0:7] number_1 [15:0];
+ wire [0:7] number_2 [15:0];
+ wire [0:7] number_3 [15:0];
+ wire [0:7] number_4 [15:0];
+ wire [0:7] number_5 [15:0];
+ wire [0:7] number_6 [15:0];
+ wire [0:7] number_7 [15:0];
+ wire [0:7] number_8 [15:0];
+ wire [0:7] number_9 [15:0];
+
+ wire [0:7] letter_A [15:0];
+ wire [0:7] letter_B [15:0];
+ wire [0:7] letter_C [15:0];
+ wire [0:7] letter_D [15:0];
+ wire [0:7] letter_E [15:0];
+ wire [0:7] letter_F [15:0];
+
+ assign number_0[0] = 8'b00000000;
+ assign number_0[1] = 8'b00011000;
+ assign number_0[2] = 8'b00100100;
+ assign number_0[3] = 8'b00100100;
+ assign number_0[4] = 8'b01000110;
+ assign number_0[5] = 8'b01001010;
+ assign number_0[6] = 8'b01001010;
+ assign number_0[7] = 8'b01001010;
+ assign number_0[8] = 8'b01010010;
+ assign number_0[9] = 8'b01010010;
+ assign number_0[10] = 8'b01010010;
+ assign number_0[11] = 8'b01100010;
+ assign number_0[12] = 8'b00100100;
+ assign number_0[13] = 8'b00100100;
+ assign number_0[14] = 8'b00011000;
+ assign number_0[15] = 8'b00000000;
+
+ assign number_1[0] = 8'b00000000;
+ assign number_1[1] = 8'b00001000;
+ assign number_1[2] = 8'b00011000;
+ assign number_1[3] = 8'b00111000;
+ assign number_1[4] = 8'b00001000;
+ assign number_1[5] = 8'b00001000;
+ assign number_1[6] = 8'b00001000;
+ assign number_1[7] = 8'b00001000;
+ assign number_1[8] = 8'b00001000;
+ assign number_1[9] = 8'b00001000;
+ assign number_1[10] = 8'b00001000;
+ assign number_1[11] = 8'b00001000;
+ assign number_1[12] = 8'b00001000;
+ assign number_1[13] = 8'b00001000;
+ assign number_1[14] = 8'b00001000;
+ assign number_1[15] = 8'b00000000;
+
+ assign number_2[0] = 8'b00000000;
+ assign number_2[1] = 8'b00111000;
+ assign number_2[2] = 8'b01000100;
+ assign number_2[3] = 8'b00000010;
+ assign number_2[4] = 8'b00000010;
+ assign number_2[5] = 8'b00000010;
+ assign number_2[6] = 8'b00000010;
+ assign number_2[7] = 8'b00000100;
+ assign number_2[8] = 8'b00001000;
+ assign number_2[9] = 8'b00010000;
+ assign number_2[10] = 8'b00100000;
+ assign number_2[11] = 8'b00100000;
+ assign number_2[12] = 8'b01000000;
+ assign number_2[13] = 8'b01000000;
+ assign number_2[14] = 8'b01111110;
+ assign number_2[15] = 8'b00000000;
+
+ assign number_3[0] = 8'b00000000;
+ assign number_3[1] = 8'b00111000;
+ assign number_3[2] = 8'b01000100;
+ assign number_3[3] = 8'b00000010;
+ assign number_3[4] = 8'b00000010;
+ assign number_3[5] = 8'b00000010;
+ assign number_3[6] = 8'b00000100;
+ assign number_3[7] = 8'b00011000;
+ assign number_3[8] = 8'b00000100;
+ assign number_3[9] = 8'b00000010;
+ assign number_3[10] = 8'b00000010;
+ assign number_3[11] = 8'b00000010;
+ assign number_3[12] = 8'b00000010;
+ assign number_3[13] = 8'b01000100;
+ assign number_3[14] = 8'b00111000;
+ assign number_3[15] = 8'b00000000;
+
+ assign number_4[0] = 8'b00000000;
+ assign number_4[1] = 8'b00001000;
+ assign number_4[2] = 8'b00001000;
+ assign number_4[3] = 8'b00010000;
+ assign number_4[4] = 8'b00010000;
+ assign number_4[5] = 8'b00100000;
+ assign number_4[6] = 8'b00100000;
+ assign number_4[7] = 8'b01000100;
+ assign number_4[8] = 8'b01111110;
+ assign number_4[9] = 8'b00000100;
+ assign number_4[10] = 8'b00000100;
+ assign number_4[11] = 8'b00000100;
+ assign number_4[12] = 8'b00000100;
+ assign number_4[13] = 8'b00000100;
+ assign number_4[14] = 8'b00000100;
+ assign number_4[15] = 8'b00000000;
+
+ assign number_5[0] = 8'b00000000;
+ assign number_5[1] = 8'b01111100;
+ assign number_5[2] = 8'b01000000;
+ assign number_5[3] = 8'b01000000;
+ assign number_5[4] = 8'b01000000;
+ assign number_5[5] = 8'b01000000;
+ assign number_5[6] = 8'b01111000;
+ assign number_5[7] = 8'b00000100;
+ assign number_5[8] = 8'b00000010;
+ assign number_5[9] = 8'b00000010;
+ assign number_5[10] = 8'b00000010;
+ assign number_5[11] = 8'b00000010;
+ assign number_5[12] = 8'b00000010;
+ assign number_5[13] = 8'b01000100;
+ assign number_5[14] = 8'b00111000;
+ assign number_5[15] = 8'b00000000;
+
+ assign number_6[0] = 8'b00000000;
+ assign number_6[1] = 8'b00001100;
+ assign number_6[2] = 8'b00010000;
+ assign number_6[3] = 8'b00100000;
+ assign number_6[4] = 8'b00100000;
+ assign number_6[5] = 8'b01000000;
+ assign number_6[6] = 8'b01000000;
+ assign number_6[7] = 8'b01011000;
+ assign number_6[8] = 8'b01100100;
+ assign number_6[9] = 8'b01000010;
+ assign number_6[10] = 8'b01000010;
+ assign number_6[11] = 8'b01000010;
+ assign number_6[12] = 8'b01000010;
+ assign number_6[13] = 8'b00100100;
+ assign number_6[14] = 8'b00011000;
+ assign number_6[15] = 8'b00000000;
+
+ assign number_7[0] = 8'b00000000;
+ assign number_7[1] = 8'b01111110;
+ assign number_7[2] = 8'b00000010;
+ assign number_7[3] = 8'b00000100;
+ assign number_7[4] = 8'b00000100;
+ assign number_7[5] = 8'b00001000;
+ assign number_7[6] = 8'b00001000;
+ assign number_7[7] = 8'b00111100;
+ assign number_7[8] = 8'b00010000;
+ assign number_7[9] = 8'b00010000;
+ assign number_7[10] = 8'b00010000;
+ assign number_7[11] = 8'b00100000;
+ assign number_7[12] = 8'b00100000;
+ assign number_7[13] = 8'b00100000;
+ assign number_7[14] = 8'b00100000;
+ assign number_7[15] = 8'b00000000;
+
+ assign number_8[0] = 8'b00000000;
+ assign number_8[1] = 8'b00011000;
+ assign number_8[2] = 8'b00100100;
+ assign number_8[3] = 8'b01000010;
+ assign number_8[4] = 8'b01000010;
+ assign number_8[5] = 8'b01000010;
+ assign number_8[6] = 8'b00100100;
+ assign number_8[7] = 8'b00011000;
+ assign number_8[8] = 8'b00100100;
+ assign number_8[9] = 8'b01000010;
+ assign number_8[10] = 8'b01000010;
+ assign number_8[11] = 8'b01000010;
+ assign number_8[12] = 8'b01000010;
+ assign number_8[13] = 8'b00100100;
+ assign number_8[14] = 8'b00011000;
+ assign number_8[15] = 8'b00000000;
+
+ assign number_9[0] = 8'b00000000;
+ assign number_9[1] = 8'b00011000;
+ assign number_9[2] = 8'b00100100;
+ assign number_9[3] = 8'b01000010;
+ assign number_9[4] = 8'b01000010;
+ assign number_9[5] = 8'b01000010;
+ assign number_9[6] = 8'b01000010;
+ assign number_9[7] = 8'b00100110;
+ assign number_9[8] = 8'b00011010;
+ assign number_9[9] = 8'b00000010;
+ assign number_9[10] = 8'b00000010;
+ assign number_9[11] = 8'b00000100;
+ assign number_9[12] = 8'b00000100;
+ assign number_9[13] = 8'b00001000;
+ assign number_9[14] = 8'b00110000;
+ assign number_9[15] = 8'b00000000;
+
+ assign letter_A[0] = 8'b00000000;
+ assign letter_A[1] = 8'b00011000;
+ assign letter_A[2] = 8'b00100100;
+ assign letter_A[3] = 8'b00100100;
+ assign letter_A[4] = 8'b00100100;
+ assign letter_A[5] = 8'b01000010;
+ assign letter_A[6] = 8'b01000010;
+ assign letter_A[7] = 8'b01000010;
+ assign letter_A[8] = 8'b01111110;
+ assign letter_A[9] = 8'b01000010;
+ assign letter_A[10] = 8'b01000010;
+ assign letter_A[11] = 8'b01000010;
+ assign letter_A[12] = 8'b01000010;
+ assign letter_A[13] = 8'b01000010;
+ assign letter_A[14] = 8'b01000010;
+ assign letter_A[15] = 8'b00000000;
+
+ assign letter_B[0] = 8'b00000000;
+ assign letter_B[1] = 8'b01111000;
+ assign letter_B[2] = 8'b01000100;
+ assign letter_B[3] = 8'b01000010;
+ assign letter_B[4] = 8'b01000010;
+ assign letter_B[5] = 8'b01000010;
+ assign letter_B[6] = 8'b01000100;
+ assign letter_B[7] = 8'b01111000;
+ assign letter_B[8] = 8'b01000100;
+ assign letter_B[9] = 8'b01000010;
+ assign letter_B[10] = 8'b01000010;
+ assign letter_B[11] = 8'b01000010;
+ assign letter_B[12] = 8'b01000010;
+ assign letter_B[13] = 8'b01000100;
+ assign letter_B[14] = 8'b01111000;
+ assign letter_B[15] = 8'b00000000;
+
+ assign letter_C[0] = 8'b00000000;
+ assign letter_C[1] = 8'b00011100;
+ assign letter_C[2] = 8'b00100010;
+ assign letter_C[3] = 8'b00100000;
+ assign letter_C[4] = 8'b01000000;
+ assign letter_C[5] = 8'b01000000;
+ assign letter_C[6] = 8'b01000000;
+ assign letter_C[7] = 8'b01000000;
+ assign letter_C[8] = 8'b01000000;
+ assign letter_C[9] = 8'b01000000;
+ assign letter_C[10] = 8'b01000000;
+ assign letter_C[11] = 8'b01000000;
+ assign letter_C[12] = 8'b00100000;
+ assign letter_C[13] = 8'b00100010;
+ assign letter_C[14] = 8'b00011100;
+ assign letter_C[15] = 8'b00000000;
+
+ assign letter_D[0] = 8'b00000000;
+ assign letter_D[1] = 8'b01110000;
+ assign letter_D[2] = 8'b01001000;
+ assign letter_D[3] = 8'b01000100;
+ assign letter_D[4] = 8'b01000100;
+ assign letter_D[5] = 8'b01000010;
+ assign letter_D[6] = 8'b01000010;
+ assign letter_D[7] = 8'b01000010;
+ assign letter_D[8] = 8'b01000010;
+ assign letter_D[9] = 8'b01000010;
+ assign letter_D[10] = 8'b01000010;
+ assign letter_D[11] = 8'b01000100;
+ assign letter_D[12] = 8'b01000100;
+ assign letter_D[13] = 8'b01001000;
+ assign letter_D[14] = 8'b01110000;
+ assign letter_D[15] = 8'b00000000;
+
+ assign letter_E[0] = 8'b00000000;
+ assign letter_E[1] = 8'b01111110;
+ assign letter_E[2] = 8'b01000000;
+ assign letter_E[3] = 8'b01000000;
+ assign letter_E[4] = 8'b01000000;
+ assign letter_E[5] = 8'b01000000;
+ assign letter_E[6] = 8'b01000000;
+ assign letter_E[7] = 8'b01111000;
+ assign letter_E[8] = 8'b01000000;
+ assign letter_E[9] = 8'b01000000;
+ assign letter_E[10] = 8'b01000000;
+ assign letter_E[11] = 8'b01000000;
+ assign letter_E[12] = 8'b01000000;
+ assign letter_E[13] = 8'b01000000;
+ assign letter_E[14] = 8'b01111110;
+ assign letter_E[15] = 8'b00000000;
+
+ assign letter_F[0] = 8'b00000000;
+ assign letter_F[1] = 8'b01111110;
+ assign letter_F[2] = 8'b01000000;
+ assign letter_F[3] = 8'b01000000;
+ assign letter_F[4] = 8'b01000000;
+ assign letter_F[5] = 8'b01000000;
+ assign letter_F[6] = 8'b01000000;
+ assign letter_F[7] = 8'b01111000;
+ assign letter_F[8] = 8'b01000000;
+ assign letter_F[9] = 8'b01000000;
+ assign letter_F[10] = 8'b01000000;
+ assign letter_F[11] = 8'b01000000;
+ assign letter_F[12] = 8'b01000000;
+ assign letter_F[13] = 8'b01000000;
+ assign letter_F[14] = 8'b01000000;
+ assign letter_F[15] = 8'b00000000;
+
+ assign pixel = halfbyte == 0 ? number_0[y][x] :
+ halfbyte == 1 ? number_1[y][x] :
+ halfbyte == 2 ? number_2[y][x] :
+ halfbyte == 3 ? number_3[y][x] :
+ halfbyte == 4 ? number_4[y][x] :
+ halfbyte == 5 ? number_5[y][x] :
+ halfbyte == 6 ? number_6[y][x] :
+ halfbyte == 7 ? number_7[y][x] :
+ halfbyte == 8 ? number_8[y][x] :
+ halfbyte == 9 ? number_9[y][x] :
+ halfbyte == 10 ? letter_A[y][x] :
+ halfbyte == 11 ? letter_B[y][x] :
+ halfbyte == 12 ? letter_C[y][x] :
+ halfbyte == 13 ? letter_D[y][x] :
+ halfbyte == 14 ? letter_E[y][x] :
+ letter_F[y][x];
+endmodule
+
+module vga_timing(input wire clock_50mhz,
+ input wire reset,
+
+ output reg h_sync,
+ output reg v_sync,
+ output reg [9:0] col,
+ output reg [8:0] row,
+ output reg display_on,
+ output wire pixel_starting,
+ output wire row_starting);
parameter h_pixels = 640;
parameter v_pixels = 480;
@@ -65,14 +345,21 @@ module vga(input wire clock_100mhz,
parameter h_frame_end = h_active_video_start + h_pixels;
parameter v_frame_end = v_active_video_start + v_pixels;
- reg [9:0] h_counter;
- reg [9:0] v_counter;
+ reg [9:0] h_counter;
+ reg [9:0] v_counter;
+
+ reg divider; // 25MHz
- reg [1:0] divider; // 25MHz
+ wire display_on_next_tick;
+ assign display_on_next_tick = (h_counter < h_frame_end - 1) &&
+ (h_counter >= h_active_video_start - 1) &&
+ (v_counter < v_frame_end) &&
+ (v_counter >= v_active_video_start);
- always @ (posedge clock_100mhz) begin
+ always @ (posedge clock_50mhz) begin
if (reset) begin
- divider <= 2'b00;
+ divider <= 1'b0;
+
h_counter <= 0;
v_counter <= 0;
@@ -84,25 +371,22 @@ module vga(input wire clock_100mhz,
end // if (reset)
else begin
divider <= divider + 1;
-
- if (divider == 2'b11) begin
- display_on <= (h_counter < h_frame_end - 1) &&
- (h_counter >= h_active_video_start - 1) &&
- (v_counter < v_frame_end) &&
- (v_counter >= v_active_video_start);
+
+ if (divider == 1'b1) begin
+ display_on <= display_on_next_tick;
if (h_counter < h_frame_end - 1) begin
h_counter <= h_counter + 1;
h_sync <= h_pol ^ (h_counter < h_pulse_start - 1 || h_counter >= h_pulse_end - 1);
-
+
if (h_counter >= h_active_video_start)
col <= col + 1;
end
else begin
h_counter <= 0;
col <= 0;
-
+
if (v_counter < v_frame_end - 1) begin
v_counter <= v_counter + 1;
@@ -116,7 +400,448 @@ module vga(input wire clock_100mhz,
row <= 0;
end // else: !if(v_counter < v_frame_end - 1)
end // else: !if(h_counter < h_frame_end - 1)
- end // if (divider == 2'b11)
+ end // if (divider == 1'b1)
+ end // else: !if(reset)
+ end // always @ (posedge clock_50mhz)
+
+ assign pixel_starting = display_on && divider == 1'b0;
+ assign row_starting = pixel_starting && col == 0;
+endmodule // vga_timing
+
+module vga_pass_colors(input wire clock_50mhz,
+ input wire reset,
+
+ input wire h_sync_next_tick,
+ input wire v_sync_next_tick,
+ input wire display_on_next_tick,
+ input wire pixel_on_next_tick,
+
+ output reg h_sync,
+ output reg v_sync,
+ output reg [2:0] vga_red,
+ output reg [2:0] vga_green,
+ output reg [2:0] vga_blue
+ );
+
+ wire [8:0] color_next_tick;
+ assign color_next_tick = !display_on_next_tick ? 0 :
+ pixel_on_next_tick ? color1 : color2;
+
+ parameter color1 = {3'b010, 3'b111, 3'b101};
+ parameter color2 = {3'b000, 3'b000, 3'b111};
+
+ always @ (posedge clock_50mhz) begin
+ if (reset) begin
+ h_sync <= 0;
+ v_sync <= 0;
+ vga_red <= 0;
+ vga_green <= 0;
+ vga_blue <= 0;
+ end
+ else begin
+ h_sync <= h_sync_next_tick;
+ v_sync <= v_sync_next_tick;
+
+ vga_red <= color_next_tick[8:6];
+ vga_green <= color_next_tick[5:3];
+ vga_blue <= color_next_tick[2:0];
+ end // else: !if(reset)
+ end // always @ (posedge clock_50mhz)
+endmodule // vga_pass_colors
+
+module vga_hexmode(input wire clock_50mhz,
+ input wire reset,
+
+ input wire can_read,
+ input wire [15:0] read_data,
+
+ output wire want_to_read,
+ output wire [17:0] read_addr,
+
+ input wire [17:0] displayed_memory_base,
+
+ output wire h_sync,
+ output wire v_sync,
+ output wire [2:0] vga_red,
+ output wire [2:0] vga_green,
+ output wire [2:0] vga_blue
+ );
+ wire [9:0] col_next_tick;
+ wire [8:0] row_next_tick;
+ wire h_sync_next_tick;
+ wire v_sync_next_tick;
+ wire display_on_next_tick;
+ wire pixel_starting_next_tick;
+ wire row_starting_next_tick;
+
+ vga_timing timing(clock_50mhz, reset, h_sync_next_tick, v_sync_next_tick,
+ col_next_tick, row_next_tick, display_on_next_tick,
+ pixel_starting_next_tick, row_starting_next_tick);
+
+ parameter queue_size = 4;
+
+ /* will store 4 consecutive hex digits copied from read_data[15:0] */
+ reg [15:0] digits_queue;
+ reg [1:0] digits_in_queue;
+
+ parameter words_per_line = 20;
+ parameter lines = 30;
+ parameter words_per_screen = words_per_line * lines;
+ parameter digit_h_pixels = 8;
+ parameter digit_v_pixels = 16;
+ parameter word_digits = 4;
+
+ reg [2:0] digit_x;
+ wire [2:0] subsequent_digit_x;
+ assign subsequent_digit_x = digit_x == digit_h_pixels - 1 ? 0 : digit_x + 1;
+
+ reg [3:0] digit_y;
+ wire [3:0] subsequent_digit_y;
+ assign subsequent_digit_y = digit_y == digit_v_pixels - 1 ? 0 : digit_y + 1;
+
+ wire digit_starting_next_tick;
+ assign digit_starting_next_tick = pixel_starting_next_tick &&
+ digit_x == digit_h_pixels - 1;
+
+ wire line_starting_next_tick;
+ assign line_starting_next_tick = row_starting_next_tick &&
+ digit_y == digit_v_pixels - 1;
+
+ reg [4:0] word_in_line;
+ reg [11:0] word_idx;
+ wire [11:0] subsequent_word_idx;
+ assign subsequent_word_idx = word_idx == words_per_screen - 1 ?
+ 0 : word_idx + 1;
+
+ assign read_addr = displayed_memory_base + word_idx;
+
+ reg [3:0] current_digit;
+ wire [3:0] digit_next_tick;
+ assign digit_next_tick = digit_starting_next_tick ?
+ digits_queue[15:12] : current_digit;
+
+ wire pixel_on_next_tick;
+
+ hex_print hex_print(digit_next_tick,
+ pixel_starting_next_tick ? subsequent_digit_x : digit_x,
+ row_starting_next_tick ? subsequent_digit_y : digit_y,
+ pixel_on_next_tick);
+
+ vga_pass_colors color_pass(clock_50mhz, reset, h_sync_next_tick,
+ v_sync_next_tick, display_on_next_tick,
+ pixel_on_next_tick, h_sync, v_sync,
+ vga_red, vga_green, vga_blue);
+
+ /* 0 - waiting for read; 1 - reading; 2 - reading done */
+ reg [1:0] reading_state;
+
+ assign want_to_read = reading_state == 0 ||
+ (digit_starting_next_tick &&
+ digits_in_queue - 1 == 0);
+
+ wire reading;
+ /* If new read can start, the previous one is ignored */
+ assign reading = reading_state == 1 && !(want_to_read);
+
+ reg [11:0] word_idx_at_some_point;
+ reg [1:0] digits_in_queue_at_some_point;
+ reg [1:0] reading_state_at_some_point;
+ always @ (posedge clock_50mhz) begin
+ if (reset) begin
+ digits_queue <= 16'bxxxxxxxxxxxxxxxx;
+ digits_in_queue <= 0;
+ reading_state <= 0;
+ digit_x <= digit_h_pixels - 1;
+ digit_y <= digit_v_pixels - 1;
+ word_in_line <= 0;
+ word_idx <= 0; word_idx_at_some_point <= 0; digits_in_queue_at_some_point <= 0; reading_state_at_some_point <= 0;
+ end
+ else begin
+ if (pixel_starting_next_tick && col_next_tick == 3 && row_next_tick == 1) begin
+ word_idx_at_some_point <= word_idx;
+ digits_in_queue_at_some_point <= digits_in_queue;
+ reading_state_at_some_point <= reading_state;
+ end
+
+ if (pixel_starting_next_tick)
+ digit_x <= subsequent_digit_x;
+
+ if (digit_starting_next_tick) begin
+ current_digit <= digit_next_tick;
+
+ /*
+ * Once there's only 1 digit in the queue, word_idx shall
+ * already be pointing at the next address.
+ */
+ if (digits_in_queue - 3 == 0) begin
+ if (word_in_line == words_per_line - 1) begin
+ word_in_line <= 0;
+ if (digit_y == digit_v_pixels - 1)
+ word_idx <= subsequent_word_idx;
+ else
+ word_idx <= word_idx - (words_per_line - 1);
+ end
+ else begin
+ word_in_line <= word_in_line + 1;
+ word_idx <= subsequent_word_idx;
+ end
+ end
+
+ /*
+ * Hopefully read will always finish before we pop the next digit
+ * from the queue. But we still need to avoid multiple drivers.
+ */
+ if (!reading)
+ digits_queue <= {digits_queue[11:0], 4'bxxxx};
+ end
+
+ if (row_starting_next_tick)
+ digit_y <= subsequent_digit_y;
+
+ digits_in_queue <= digits_in_queue + (reading ? queue_size : 0) -
+ (digit_starting_next_tick ? 1 : 0);
+
+ if (want_to_read) begin
+ if (can_read)
+ reading_state <= 1;
+ else
+ reading_state <= 0;
+ end
+ else if (reading_state == 1) begin
+ reading_state <= 2;
+ digits_queue <= read_data;
+ end
+ end // else: !if(reset)
+ end // always @ (posedge clock_50mhz)
+endmodule
+
+module on_button_write(input wire clock_50mhz,
+ input wire reset,
+
+ input wire can_write,
+ output reg [15:0] write_data,
+
+ output wire want_to_write,
+ output wire [17:0] write_addr,
+
+ input wire [17:0] written_memory_base,
+ input wire but
+ );
+ /* 0 - waiting for write, 1 - writing, 2 - write complete */
+ reg [1:0] write_state;
+
+ parameter cooldown_start = 25'b111111111111111111111111;
+ reg [23:0] but_cooldown;
+
+ reg [4:0] write_idx;
+ assign write_addr = written_memory_base + write_idx;
+
+ wire button_pressed;
+ assign button_pressed = !but && !but_cooldown;
+ assign want_to_write = button_pressed || write_state == 0;
+
+ always @ (posedge clock_50mhz) begin
+ if (reset) begin
+ but_cooldown <= cooldown_start;
+ write_data <= 16'b000100000000000;
+ write_state <= 2;
+ write_idx <= 0;
+ end
+ else begin
+ if (button_pressed)
+ but_cooldown <= cooldown_start;
+ else if (but_cooldown)
+ but_cooldown <= but_cooldown - 1;
+
+ if (want_to_write) begin
+ if (can_write)
+ write_state <= 1;
+ else
+ write_state <= 0;
+ end
+ else if (write_state == 1) begin
+ write_state <= 2;
+
+ write_data <= write_data + 1;
+ write_idx <= write_idx >= 30 ? 0 : write_idx + 1;
+ end
+ end
+ end // always @ (posedge clock_50mhz)
+endmodule
+
+module dumb_write(input wire clock_50mhz,
+ input wire reset,
+
+ input wire can_write,
+ output wire [15:0] write_data,
+
+ output wire want_to_write,
+ output wire [17:0] write_addr,
+
+ input wire [17:0] written_memory_base,
+ input wire start_operating
+ );
+ reg [9:0] write_idx;
+ /* To each word we'll be writing its offset from written_memory_base */
+ assign write_data = write_idx;
+ assign write_addr = written_memory_base + write_idx;
+
+ parameter max_idx = 599;
+ reg operating;
+ assign want_to_write = operating;
+
+ reg [1:0] write_state;
+
+ always @ (posedge clock_50mhz) begin
+ if (reset) begin
+ write_idx <= 10'bxxxxxxxxxx;
+ operating <= 0;
+ end
+ else begin
+ if (start_operating && !operating) begin
+ operating <= 1;
+ write_state <= 0;
+ write_idx <= 0;
+ end
+ else if (operating) begin
+ if (can_write) begin
+ write_idx <= write_idx + 1;
+ if (write_idx == max_idx)
+ operating <= 0;
+ end
+ end
end // else: !if(reset)
- end // always @ (posedge clock_100mhz)
-endmodule // vga
+ end // always @ (posedge clock_50mhz)
+endmodule // dumb_write
+
+module top(input wire clock_100mhz,
+ input wire but1,
+ input wire but2,
+
+ output reg [17:0] sram_addr,
+ inout wire [15:0] sram_io,
+ output reg sram_cs_n,
+ output reg sram_oe_n,
+ output reg sram_we_n,
+
+ output wire h_sync,
+ output wire v_sync,
+ output wire [2:0] vga_red,
+ output wire [2:0] vga_green,
+ output wire [2:0] vga_blue,
+
+ output wire sdo,
+ input wire sdi,
+ output wire sck,
+ output wire ss_n
+ );
+ reg reset;
+ reg err_disabled;
+
+ reg clock_50mhz;
+ always @ (posedge clock_100mhz)
+ clock_50mhz <= clock_50mhz + 1;
+
+ parameter memory_base = 18'b010101010101010101;
+
+ wire vga_io_available;
+ assign vga_io_available = 1;
+ wire vga_wants_io;
+ wire [17:0] vga_io_addr;
+
+ vga_hexmode vga(clock_50mhz, reset, vga_io_available, sram_io, vga_wants_io,
+ vga_io_addr, memory_base,
+ h_sync, v_sync, vga_red, vga_green, vga_blue);
+
+ reg last_reset;
+ always @ (posedge clock_50mhz)
+ last_reset <= reset;
+
+ wire dumbwrite_io_available;
+ assign dumbwrite_io_available = vga_io_available && !vga_wants_io;
+
+ wire dumbwrite_wants_io;
+ wire [17:0] dumbwrite_io_addr;
+ wire [15:0] dumbwrite_write_data;
+
+ dumb_write dumbwrite(clock_50mhz, reset, dumbwrite_io_available, dumbwrite_write_data,
+ dumbwrite_wants_io, dumbwrite_io_addr, memory_base,
+ !reset && last_reset);
+
+ wire butwrite_io_available;
+ assign butwrite_io_available = dumbwrite_io_available && !dumbwrite_wants_io;
+
+ wire butwrite_wants_io;
+ wire [17:0] butwrite_io_addr;
+ wire [15:0] butwrite_write_data;
+
+ on_button_write butwrite(clock_50mhz, reset, butwrite_io_available,
+ butwrite_write_data, butwrite_wants_io,
+ butwrite_io_addr, memory_base, but2);
+
+ reg [15:0] write_data;
+ reg write_in_progress;
+
+ always @ (posedge clock_50mhz) begin
+ reset <= !but1 || err_disabled;
+
+ if (!but1)
+ err_disabled <= 0;
+
+ if (reset) begin
+ err_disabled <= 0;
+ write_in_progress <= 0;
+ sram_oe_n <= 1'b1;
+ sram_cs_n <= 1'b1;
+ write_data <= 16'bxxxxxxxxxxxxxxxx;
+ end
+ else begin
+ if (vga_wants_io) begin
+ write_in_progress <= 0;
+ sram_oe_n <= 1'b0;
+ sram_cs_n <= 1'b0;
+ sram_addr <= vga_io_addr;
+ end
+ else if (dumbwrite_wants_io) begin
+ write_in_progress <= 1;
+ sram_oe_n <= 1'b1;
+ sram_cs_n <= 1'b0;
+ sram_addr <= dumbwrite_io_addr;
+ write_data <= dumbwrite_write_data;
+ end
+ else if (butwrite_wants_io) begin
+ write_in_progress <= 1;
+ sram_oe_n <= 1'b1;
+ sram_cs_n <= 1'b0;
+ sram_addr <= butwrite_io_addr;
+ write_data <= butwrite_write_data;
+ if (butwrite_io_addr > memory_base + 30)
+ err_disabled <= 1;
+ end
+ else begin
+ write_in_progress <= 0;
+ sram_oe_n <= 1'b1;
+ sram_cs_n <= 1'b1;
+ end
+ end
+ end // always @ (posedge clock_50mhz)
+
+ always @ (negedge clock_100mhz) begin
+ if (reset) begin
+ sram_we_n <= 1'b1;
+ end
+ else begin
+ if (write_in_progress)
+ sram_we_n <= !sram_we_n;
+ else
+ sram_we_n <= 1'b1;
+ end
+ end
+
+ assign sram_io = sram_we_n ? 16'bzzzzzzzzzzzzzzzz : write_data;
+
+ assign sdo = sdi;
+ assign sck = 1;
+ assign ss_n = 1;
+
+endmodule // top
diff --git a/src/letter_A.png b/src/letter_A.png
new file mode 100644
index 0000000..f8787e2
--- /dev/null
+++ b/src/letter_A.png
Binary files differ
diff --git a/src/letter_B.png b/src/letter_B.png
new file mode 100644
index 0000000..6b47b03
--- /dev/null
+++ b/src/letter_B.png
Binary files differ
diff --git a/src/letter_C.png b/src/letter_C.png
new file mode 100644
index 0000000..ebc0ed6
--- /dev/null
+++ b/src/letter_C.png
Binary files differ
diff --git a/src/letter_D.png b/src/letter_D.png
new file mode 100644
index 0000000..36ce8a5
--- /dev/null
+++ b/src/letter_D.png
Binary files differ
diff --git a/src/letter_E.png b/src/letter_E.png
new file mode 100644
index 0000000..826ed78
--- /dev/null
+++ b/src/letter_E.png
Binary files differ
diff --git a/src/letter_F.png b/src/letter_F.png
new file mode 100644
index 0000000..10df13d
--- /dev/null
+++ b/src/letter_F.png
Binary files differ
diff --git a/src/mapping.pcf b/src/mapping.pcf
new file mode 100644
index 0000000..afdadc4
--- /dev/null
+++ b/src/mapping.pcf
@@ -0,0 +1,62 @@
+set_io clock_100mhz J3
+
+set_io but1 K11 # actually used as reset
+set_io but2 P13
+
+set_io h_sync J4
+set_io v_sync H2
+set_io vga_red[0] E3
+set_io vga_red[1] H5
+set_io vga_red[2] F3
+set_io vga_green[0] F2
+set_io vga_green[1] H6
+set_io vga_green[2] H3
+set_io vga_blue[0] F1
+set_io vga_blue[1] H4
+set_io vga_blue[2] G2
+
+set_io sram_addr[0] N6
+set_io sram_addr[1] T1
+set_io sram_addr[2] P4
+set_io sram_addr[3] R2
+set_io sram_addr[4] N5
+set_io sram_addr[5] T2
+set_io sram_addr[6] P5
+set_io sram_addr[7] R3
+set_io sram_addr[8] R5
+set_io sram_addr[9] T3
+set_io sram_addr[10] R4
+set_io sram_addr[11] M7
+set_io sram_addr[12] N7
+set_io sram_addr[13] P6
+set_io sram_addr[14] M8
+set_io sram_addr[15] T5
+set_io sram_addr[16] R6
+set_io sram_addr[17] P8
+
+set_io sram_io[0] T8
+set_io sram_io[1] P7
+set_io sram_io[2] N9
+set_io sram_io[3] T9
+set_io sram_io[4] M9
+set_io sram_io[5] R9
+set_io sram_io[6] K9
+set_io sram_io[7] P9
+set_io sram_io[8] R10
+set_io sram_io[9] L10
+set_io sram_io[10] P10
+set_io sram_io[11] N10
+set_io sram_io[12] T10
+set_io sram_io[13] T11
+set_io sram_io[14] T15
+set_io sram_io[15] T14
+
+set_io sram_cs_n T6
+set_io sram_oe_n L9
+set_io sram_we_n T7
+
+# SPI to on-board chip
+set_io sdo P12
+set_io sdi P11
+set_io sck R11
+set_io ss_n R12
diff --git a/src/number_0.png b/src/number_0.png
new file mode 100644
index 0000000..f8a1742
--- /dev/null
+++ b/src/number_0.png
Binary files differ
diff --git a/src/number_1.png b/src/number_1.png
new file mode 100644
index 0000000..a2b4b66
--- /dev/null
+++ b/src/number_1.png
Binary files differ
diff --git a/src/number_2.png b/src/number_2.png
new file mode 100644
index 0000000..0af34dd
--- /dev/null
+++ b/src/number_2.png
Binary files differ
diff --git a/src/number_3.png b/src/number_3.png
new file mode 100644
index 0000000..5483902
--- /dev/null
+++ b/src/number_3.png
Binary files differ
diff --git a/src/number_4.png b/src/number_4.png
new file mode 100644
index 0000000..3b6a6d4
--- /dev/null
+++ b/src/number_4.png
Binary files differ
diff --git a/src/number_5.png b/src/number_5.png
new file mode 100644
index 0000000..710cd3e
--- /dev/null
+++ b/src/number_5.png
Binary files differ
diff --git a/src/number_6.png b/src/number_6.png
new file mode 100644
index 0000000..36e8c3c
--- /dev/null
+++ b/src/number_6.png
Binary files differ
diff --git a/src/number_7.png b/src/number_7.png
new file mode 100644
index 0000000..ca13f4d
--- /dev/null
+++ b/src/number_7.png
Binary files differ
diff --git a/src/number_8.png b/src/number_8.png
new file mode 100644
index 0000000..17b1fdc
--- /dev/null
+++ b/src/number_8.png
Binary files differ
diff --git a/src/number_9.png b/src/number_9.png
new file mode 100644
index 0000000..f887222
--- /dev/null
+++ b/src/number_9.png
Binary files differ