aboutsummaryrefslogtreecommitdiffstats
path: root/atk16_fpga/top.v
blob: 6fcbddddc4a5d4bf92785bb2cac6e5fec5c47b33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Top-level module for the iCE40 HX8K FPGA.
// This module instantiates the UART transmitter and sends the bytes for
// "Hello" and a newline character, then stops.
module top (
    input  SYSCLK,     // 100 MHz system clock
    input  SERIAL_RX,   // UART receive input
    output SERIAL_TX,   // UART transmit output
    output LED1,
    output LED2
);

    // State machine states.
    localparam RX_START = 0;
    localparam WAIT_RX_DONE = 1;
    localparam START_TX = 2;
    localparam TX_IN_PROG = 3;
    localparam WAIT_TX_DONE = 4;
    localparam HANDLE_RX_DATA = 5;
    localparam SEND_STRING_WELCOME = 6;
    localparam SEND_STRING_HELP = 7;
    localparam SEND_STRING_PROGRAM_READY = 8;
    localparam RECEIVE_PROGRAM_DATA = 9;

    reg [7:0] state = SEND_STRING_WELCOME;

    // SEND_WELCOME data
    `STR_welcome
    reg [7:0] welcome_index = 0;

    // SEND_STRING_HELP data
    `STR_help
    reg [7:0] help_index = 0;

    // SEND_STRING_PROGRAM_READY data
    `STR_program_ready
    reg [7:0] program_ready_index = 0;

    // Synchronous state machine with reset.
    always @(posedge SYSCLK) begin
        case (state)
            // STATES FOR RX
            RX_START: begin
                if (!rx_done) begin
                    state <= WAIT_RX_DONE;
                end
            end

            WAIT_RX_DONE: begin
                if (rx_done) begin
                    state <= state_after_rx;
                end
            end

            // STATES FOR TX
            START_TX: begin
                if (!tx_busy) begin
                    start_tx <= 1'b1;  // trigger transmission
                    state <= TX_IN_PROG;
                end
            end

            // After issuing the start pulse, wait for tx_busy to go high.
            TX_IN_PROG: begin
                start_tx <= 1'b0;  // ensure pulse is only one cycle.
                state <= WAIT_TX_DONE;
            end

            // Wait for the transmitter to finish sending the byte.
            WAIT_TX_DONE: begin
                if (!tx_busy) begin
                    state <= state_after_tx;
                end
            end

            // STATES FOR PROCESSING DATA
            HANDLE_RX_DATA: begin
                if (data_rx == cmd_program) begin
                    state <= SEND_STRING_PROGRAM_READY;
                end else if (data_rx == cmd_help) begin
                    state <= SEND_STRING_HELP;
                end else begin
                    state <= RX_START;
                end
            end

            SEND_STRING_WELCOME: begin
                if (welcome_index < 8'd`LEN_welcome) begin
                    data_tx <= str_welcome[welcome_index];
                    welcome_index <= welcome_index + 1;
                    state <= START_TX;
                    state_after_tx <= SEND_STRING_WELCOME;
                end else begin
                    welcome_index <= 0;
                    state <= RX_START;
                    state_after_tx <= RX_START;
                end
            end

            SEND_STRING_HELP: begin
                if (help_index < 8'd`LEN_help) begin
                    data_tx <= str_help[help_index];
                    help_index <= help_index + 1;
                    state <= START_TX;
                    state_after_tx <= SEND_STRING_HELP;
                end else begin
                    help_index <= 0;
                    state <= RX_START;
                    state_after_tx <= RX_START;
                end
            end

            SEND_STRING_PROGRAM_READY: begin
                if (program_ready_index < 8'd`LEN_program_ready) begin
                    data_tx <= str_program_ready[program_ready_index];
                    program_ready_index <= program_ready_index + 1;
                    state <= START_TX;
                    state_after_tx <= SEND_STRING_PROGRAM_READY;
                end else begin
                    program_ready_index <= 0;
                    state <= RECEIVE_PROGRAM_DATA;
                    state_after_tx <= RX_START;
                end
            end

            RECEIVE_PROGRAM_DATA: begin
                // TODO write data to flash
                state <= RX_START;
                state_after_rx <= RECEIVE_PROGRAM_DATA;
            end

            default: state <= RX_START;
        endcase

    end

    // One-cycle pulse to trigger transmission.
    reg        start_tx = 1'b0;
    // Data byte to be transmitted.
    reg  [7:0] data_tx = 8'b0;
    // Busy flag from the transmitter.
    wire       tx_busy;
    // State to transition to after TX done.
    reg  [7:0] state_after_tx = RX_START;

    reg  [7:0] cmd_help = 8'd104;  // h
    reg  [7:0] cmd_program = 8'd112;  // p

    // Instantiate the UART transmitter.
    uart_tx uart_inst (
        .clk  (SYSCLK),
        .start(start_tx),   // One-cycle pulse to start transmission.
        .data (data_tx),
        .tx   (SERIAL_TX),
        .busy (tx_busy)
    );

    wire [7:0] data_rx;
    wire rx_done;
    reg [7:0] state_after_rx = HANDLE_RX_DATA;

    uart_rx uart_rx_inst (
        .clk (SYSCLK),
        .rx  (SERIAL_RX),
        .data(data_rx),
        .done(rx_done)
    );

    assign LED1 = data_rx == cmd_program;
    assign LED2 = LED1;

endmodule