module command_parser ( input bit clock , input bit resetn , output bit uart_ready , input bit uart_valid , input bit [7:0] uart_data , input bit echo_ready , output bit echo_valid , output bit [7:0] echo_data , input bit command_ready , output bit command_valid , output bit [23:0] command_address , output bit command_write , output bit [15:0] command_data ); bit input_byte_valid; bit [7:0] input_byte; enum { READ_ADDRESS_OR_COMMAND , READ_DATA_1 , READ_DATA_2 , READ_DATA_3 , READ_DATA_4 } state; always @(posedge clock) begin if (!resetn) begin uart_ready = 0; command_valid = 0; command_address = 0; command_write = 0; command_data = 0; input_byte_valid = 0; input_byte = 0; state = state.first; end else begin if (echo_ready) echo_valid = 0; if (command_ready) command_valid = 0; if (uart_ready && uart_valid) begin echo_valid = 1; echo_data = uart_data; input_byte_valid = 1; input_byte = uart_data; end if (!command_valid && input_byte_valid) begin case (state) READ_ADDRESS_OR_COMMAND: begin if (input_byte >= "0" && input_byte <= "9") begin command_address = command_address << 4; command_address[3:0] = input_byte - "0"; end else if (input_byte >= "a" && input_byte <= "f") begin command_address = command_address << 4; command_address[3:0] = input_byte - "a" + 10; end else if (input_byte >= "A" && input_byte <= "F") begin command_address = command_address << 4; command_address[3:0] = input_byte - "A" + 10; end else if (input_byte == "?") begin command_valid = 1; command_write = 0; command_data = 0; end else if (input_byte == "=") begin command_write = 1; command_data = 0; state = READ_DATA_1; end end READ_DATA_1, READ_DATA_2, READ_DATA_3, READ_DATA_4: begin if (input_byte >= "0" && input_byte <= "9") begin command_data = command_data << 4; command_data[3:0] = input_byte - "0"; state = state.next; end else if (input_byte >= "a" && input_byte <= "f") begin command_data = command_data << 4; command_data[3:0] = input_byte - "a" + 10; state = state.next; end else if (input_byte >= "A" && input_byte <= "F") begin command_data = command_data << 4; command_data[3:0] = input_byte - "A" + 10; state = state.next; end else begin state = state.first; end command_valid = state == state.first; end endcase input_byte_valid = 0; end uart_ready = !echo_valid && !input_byte_valid; end end endmodule module echo_arbiter ( input bit clock , input bit resetn , output bit in0_ready , input bit in0_valid , input bit [7:0] in0_data , output bit in1_ready , input bit in1_valid , input bit [7:0] in1_data , input bit out_ready , output bit out_valid , output bit [7:0] out_data ); bit in0_hold_valid; bit [7:0] in0_hold; bit in1_hold_valid; bit [7:0] in1_hold; always @(posedge clock) begin if (!resetn) begin in0_ready = 0; in1_ready = 0; out_valid = 0; out_data = 0; in0_hold_valid = 0; in0_hold = 0; in1_hold_valid = 0; in1_hold = 0; end else begin if (out_ready) out_valid = 0; if (in0_ready && in0_valid) begin in0_hold_valid = 1; in0_hold = in0_data; end if (in1_ready && in1_valid) begin in1_hold_valid = 1; in1_hold = in1_data; end if (!out_valid) begin if (in0_hold_valid) begin out_valid = 1; out_data = in0_hold; in0_hold_valid = 0; end else if (in1_hold_valid) begin out_valid = 1; out_data = in1_hold; in1_hold_valid = 0; end end in0_ready = !in0_hold_valid; in1_ready = !in1_hold_valid; end end endmodule module ram_controller ( input bit clock , input bit resetn , output bit command_ready , input bit command_valid , input bit [23:0] command_address , input bit command_write , input bit [15:0] command_data , input bit result_ready , output bit result_valid , output bit [15:0] result_data , output bit ram_resetn , output bit [1:0] ram_csn , output bit ram_clkp , output bit ram_clkn , output bit ram_rwds_oe , input bit ram_rwds_in , output bit ram_rwds_out , output bit ram_data_oe , input bit [7:0] ram_data_in , output bit [7:0] ram_data_out ); assign ram_clkn = !ram_clkp; bit valid; bit [23:0] address; bit write; bit [15:0] data; int reset_counter; bit slow; enum { SEND_COMMAND_1 , SEND_COMMAND_2 , SEND_COMMAND_3 , SEND_COMMAND_4 , SEND_COMMAND_5 , SEND_COMMAND_6 , LAT2_CYC1 , LAT2_CYC2 , LAT2_CYC3 , LAT2_CYC4 , LAT2_CYC5 , LAT2_CYC6 , LAT1_CYC1 , LAT1_CYC2 , LAT1_CYC3 , LAT1_CYC4 // Latency blocks are 6 cycle, but they start in the SEND_COMMAND_5 cycle, so block 1 is only 4 real cycles //, LAT1_CYC5 //, LAT1_CYC6 , DATA_1 , DATA_2 } state; always @(posedge clock) begin if (!resetn || reset_counter != 0) begin command_ready = 0; result_valid = 0; result_data = 0; ram_resetn = 0; ram_csn[0] = 1; ram_csn[1] = 1; ram_clkp = 0; ram_rwds_oe = 0; ram_rwds_out = 0; ram_data_oe = 0; ram_data_out = 0; valid = 0; address = 0; write = 0; data = 0; if (!resetn) reset_counter = 5; // Spec wants >= 100ns of reset else reset_counter = reset_counter - 1; slow = 0; state = state.first; end else begin ram_resetn = 1; ram_rwds_oe = 0; ram_data_oe = 0; if (result_ready) result_valid = 0; if (command_ready && command_valid) begin valid = 1; address = command_address; write = command_write; data = command_data; state = state.first; end if (!valid) begin ram_csn[0] = 1; ram_csn[1] = 1; ram_clkp = 0; end else begin case (state) SEND_COMMAND_1: begin ram_clkp = 0; ram_csn[address[23]] = 0; ram_data_oe = 1; ram_data_out = {!write, 1'b0, 1'b0, 5'b0}; // R/W# AS BURST RESERVED state = state.next; end SEND_COMMAND_2: begin ram_clkp = 1; ram_data_oe = 1; ram_data_out = {4'b0, address[22:19]}; // RESERVED ROW state = state.next; end SEND_COMMAND_3: begin ram_clkp = 0; ram_data_oe = 1; ram_data_out = {address[18:11]}; // ROW state = state.next; end SEND_COMMAND_4: begin ram_clkp = 1; ram_data_oe = 1; ram_data_out = {address[10:9], address[8:3]}; // ROW UPPERCOL slow = ram_rwds_in; // Sort of arbitrarily capturing RWDS in the middle of the command string state = state.next; end SEND_COMMAND_5: begin ram_clkp = 0; ram_data_oe = 1; ram_data_out = {8'b0}; // RESERVED state = state.next; end SEND_COMMAND_6: begin ram_clkp = 1; ram_data_oe = 1; ram_data_out = {5'b0, address[2:0]}; // RESERVED LOWERCOL if (slow) state = LAT2_CYC1; else state = LAT1_CYC1; end LAT2_CYC1, LAT2_CYC2, LAT2_CYC3, LAT2_CYC4, LAT2_CYC5, LAT2_CYC6, LAT1_CYC1, LAT1_CYC2, LAT1_CYC3, LAT1_CYC4: begin ram_clkp = !ram_clkp; state = state.next; end DATA_1, DATA_2: begin ram_clkp = !ram_clkp; if (write) begin ram_rwds_oe = 1; ram_rwds_out = 1; ram_data_oe = 1; ram_data_out = data[7:0]; data = data >> 8; state = state.next; end else if (ram_rwds_in) begin data = data << 8; data[7:0] = ram_data_in; state = state.next; end if (state == state.first) begin valid = 0; if (!write) begin result_valid = 1; result_data = data; end end end endcase end command_ready = !valid && !result_valid; end end endmodule module result_printer ( input bit clock , input bit resetn , output bit result_ready , input bit result_valid , input bit [15:0] result_data , input bit echo_ready , output bit echo_valid , output bit [7:0] echo_data ); bit hold_valid; bit [15:0] hold; enum { DIGIT_1 , DIGIT_2 , DIGIT_3 , DIGIT_4 } state; always @(posedge clock) begin if (!resetn) begin result_ready = 0; echo_valid = 0; echo_data = 0; hold_valid = 0; hold = 0; state = state.first; end else begin if (echo_ready) echo_valid = 0; if (result_ready && result_valid) begin hold_valid = 1; hold = result_data; end if (hold_valid && !echo_valid) begin echo_valid = 1; echo_data = hold[15:12]; hold = hold << 4; if (echo_data < 10) echo_data = echo_data + "0"; else echo_data = echo_data + "A" - 10; state = state.next; if (state == state.first) hold_valid = 0; end result_ready = !hold_valid; end end endmodule module top ( input bit clock , input bit resetn , output bit ram_resetn , output bit [1:0] ram_csn , output bit ram_clkp , output bit ram_clkn , inout bit ram_rwds , inout bit [7:0] ram_data ); bit rx_ready; bit rx_valid; bit [7:0] rx_data; bit tx_ready; bit tx_valid; bit [7:0] tx_data; alt_jtag_atlantic #( .INSTANCE_ID(0) , .LOG2_RXFIFO_DEPTH(6) , .LOG2_TXFIFO_DEPTH(6) , .SLD_AUTO_INSTANCE_INDEX("NO") ) jtag ( .clk(clock) , .rst_n(resetn) , .r_dat(tx_data) , .r_val(tx_valid) , .r_ena(tx_ready) , .t_dat(rx_data) , .t_dav(rx_ready) , .t_ena(rx_valid) ); bit echo_in0_ready; bit echo_in0_valid; bit [7:0] echo_in0_data; bit echo_in1_ready; bit echo_in1_valid; bit [7:0] echo_in1_data; echo_arbiter arb ( .clock(clock) , .resetn(resetn) , .in0_ready(echo_in0_ready) , .in0_valid(echo_in0_valid) , .in0_data(echo_in0_data) , .in1_ready(echo_in1_ready) , .in1_valid(echo_in1_valid) , .in1_data(echo_in1_data) , .out_ready(tx_ready) , .out_valid(tx_valid) , .out_data(tx_data) ); bit command_ready; bit command_valid; bit [23:0] command_address; bit command_write; bit [15:0] command_data; command_parser parser ( .clock(clock) , .resetn(resetn) , .uart_ready(rx_ready) , .uart_valid(rx_valid) , .uart_data(rx_data) , .echo_ready(echo_in0_ready) , .echo_valid(echo_in0_valid) , .echo_data(echo_in0_data) , .command_ready(command_ready) , .command_valid(command_valid) , .command_address(command_address) , .command_write(command_write) , .command_data(command_data) ); bit result_ready; bit result_valid; bit [15:0] result_data; bit ram_rwds_oe; bit ram_rwds_out; assign ram_rwds = ram_rwds_oe ? ram_rwds_out : 'bZ; bit ram_data_oe; bit [7:0] ram_data_out; assign ram_data = ram_data_oe ? ram_data_out : 'bZ; ram_controller ram ( .clock(clock) , .resetn(resetn) , .command_ready(command_ready) , .command_valid(command_valid) , .command_address(command_address) , .command_write(command_write) , .command_data(command_data) , .result_ready(result_ready) , .result_valid(result_valid) , .result_data(result_data) , .ram_resetn(ram_resetn) , .ram_csn(ram_csn) , .ram_clkp(ram_clkp) , .ram_clkn(ram_clkn) , .ram_rwds_oe(ram_rwds_oe) , .ram_rwds_in(ram_rwds) , .ram_rwds_out(ram_rwds_out) , .ram_data_oe(ram_data_oe) , .ram_data_in(ram_data) , .ram_data_out(ram_data_out) ); result_printer print ( .clock(clock) , .resetn(resetn) , .result_ready(result_ready) , .result_valid(result_valid) , .result_data(result_data) , .echo_ready(echo_in1_ready) , .echo_valid(echo_in1_valid) , .echo_data(echo_in1_data) ); endmodule