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; 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; int reset_counter; 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; slow = 0; state = state.first; if (!resetn) reset_counter = 5; // Spec wants >= 100ns of reset else reset_counter = reset_counter - 1; 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 end endcase if (state == state.first) begin valid = 0; if (!write) begin // We know that this is safe because we don't accept commands unless we have result bandwidth result_valid = 1; result_data = data; end end end command_ready = !valid && !result_valid; end end endmodule