From 9f366a72a63829f640fd7acf2c6cbea139e9e0ca Mon Sep 17 00:00:00 2001 From: Wojciech Kosior Date: Wed, 15 Jul 2020 20:21:20 +0200 Subject: add an example of SRAM access --- src/example.v | 845 +++++++++++++++++++++++++++++++++++++++++++++++++++---- src/letter_A.png | Bin 0 -> 201 bytes src/letter_B.png | Bin 0 -> 200 bytes src/letter_C.png | Bin 0 -> 202 bytes src/letter_D.png | Bin 0 -> 206 bytes src/letter_E.png | Bin 0 -> 186 bytes src/letter_F.png | Bin 0 -> 184 bytes src/mapping.pcf | 62 ++++ src/number_0.png | Bin 0 -> 211 bytes src/number_1.png | Bin 0 -> 184 bytes src/number_2.png | Bin 0 -> 208 bytes src/number_3.png | Bin 0 -> 212 bytes src/number_4.png | Bin 0 -> 198 bytes src/number_5.png | Bin 0 -> 209 bytes src/number_6.png | Bin 0 -> 210 bytes src/number_7.png | Bin 0 -> 205 bytes src/number_8.png | Bin 0 -> 202 bytes src/number_9.png | Bin 0 -> 212 bytes 18 files changed, 847 insertions(+), 60 deletions(-) create mode 100644 src/letter_A.png create mode 100644 src/letter_B.png create mode 100644 src/letter_C.png create mode 100644 src/letter_D.png create mode 100644 src/letter_E.png create mode 100644 src/letter_F.png create mode 100644 src/mapping.pcf create mode 100644 src/number_0.png create mode 100644 src/number_1.png create mode 100644 src/number_2.png create mode 100644 src/number_3.png create mode 100644 src/number_4.png create mode 100644 src/number_5.png create mode 100644 src/number_6.png create mode 100644 src/number_7.png create mode 100644 src/number_8.png create mode 100644 src/number_9.png 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 Binary files /dev/null and b/src/letter_A.png differ diff --git a/src/letter_B.png b/src/letter_B.png new file mode 100644 index 0000000..6b47b03 Binary files /dev/null and b/src/letter_B.png differ diff --git a/src/letter_C.png b/src/letter_C.png new file mode 100644 index 0000000..ebc0ed6 Binary files /dev/null and b/src/letter_C.png differ diff --git a/src/letter_D.png b/src/letter_D.png new file mode 100644 index 0000000..36ce8a5 Binary files /dev/null and b/src/letter_D.png differ diff --git a/src/letter_E.png b/src/letter_E.png new file mode 100644 index 0000000..826ed78 Binary files /dev/null and b/src/letter_E.png differ diff --git a/src/letter_F.png b/src/letter_F.png new file mode 100644 index 0000000..10df13d Binary files /dev/null and b/src/letter_F.png 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 Binary files /dev/null and b/src/number_0.png differ diff --git a/src/number_1.png b/src/number_1.png new file mode 100644 index 0000000..a2b4b66 Binary files /dev/null and b/src/number_1.png differ diff --git a/src/number_2.png b/src/number_2.png new file mode 100644 index 0000000..0af34dd Binary files /dev/null and b/src/number_2.png differ diff --git a/src/number_3.png b/src/number_3.png new file mode 100644 index 0000000..5483902 Binary files /dev/null and b/src/number_3.png differ diff --git a/src/number_4.png b/src/number_4.png new file mode 100644 index 0000000..3b6a6d4 Binary files /dev/null and b/src/number_4.png differ diff --git a/src/number_5.png b/src/number_5.png new file mode 100644 index 0000000..710cd3e Binary files /dev/null and b/src/number_5.png differ diff --git a/src/number_6.png b/src/number_6.png new file mode 100644 index 0000000..36e8c3c Binary files /dev/null and b/src/number_6.png differ diff --git a/src/number_7.png b/src/number_7.png new file mode 100644 index 0000000..ca13f4d Binary files /dev/null and b/src/number_7.png differ diff --git a/src/number_8.png b/src/number_8.png new file mode 100644 index 0000000..17b1fdc Binary files /dev/null and b/src/number_8.png differ diff --git a/src/number_9.png b/src/number_9.png new file mode 100644 index 0000000..f887222 Binary files /dev/null and b/src/number_9.png differ -- cgit v1.2.3