| // SPDX-FileCopyrightText: | |
| // 2021 Nguyen Dao | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // | |
| // SPDX-License-Identifier: Apache-2.0 | |
| module bitbang (s_clk, s_data, strobe, data, active, clk); | |
| localparam on_pattern = 16'hFAB1; | |
| localparam off_pattern = 16'hFAB0; | |
| input s_clk; | |
| input s_data; | |
| output reg strobe; | |
| output reg [31:0] data; | |
| output reg active = 1'b0; | |
| input clk; | |
| reg [3:0] s_data_sample; | |
| reg [3:0] s_clk_sample; | |
| reg [31:0] serial_data; | |
| reg [15:0] serial_control; | |
| reg local_strobe; | |
| reg old_local_strobe; | |
| always @ (posedge clk) | |
| begin : p_input_sync | |
| s_data_sample <= {s_data_sample[3-1:0],s_data}; | |
| s_clk_sample <= {s_clk_sample[3-1:0],s_clk}; | |
| end | |
| always @ (posedge clk) | |
| begin : p_in_shift | |
| // on s_clk_sample rising edge, we sample in a serial_data bit | |
| if ((s_clk_sample[3] == 1'b0) && (s_clk_sample[3-1] == 1'b1)) begin | |
| serial_data <= {serial_data[31-1:0],s_data_sample[3]}; | |
| end | |
| // on s_clk_sample faling edge, we sample in a serial_data bit | |
| if ((s_clk_sample[3] == 1'b1) && (s_clk_sample[3-1] == 1'b0)) begin | |
| serial_control <= {serial_control[15-1:0],s_data_sample[3]}; // its data again, but its sampled on the other edge | |
| end | |
| end | |
| // we could replicate the following | |
| always @ (posedge clk) | |
| begin : p_parallel_load | |
| local_strobe <= 1'b0; // will be overwritten if next conditional is true | |
| if (serial_control == on_pattern) begin// x"FAB1" then | |
| data <= serial_data; | |
| local_strobe <= 1'b1; | |
| end //else begin | |
| // data <= data; | |
| // local_strobe <= 1'b0; | |
| // end | |
| old_local_strobe <= local_strobe; | |
| strobe <= local_strobe & ~old_local_strobe; // activates strobe for one clock cycle after "FAB0" was detected | |
| end | |
| // we could replicate the following | |
| always @ (posedge clk) | |
| begin : active_FSM | |
| if (serial_control == on_pattern) begin// x"FAB1" then | |
| active <= 1'b1; | |
| end | |
| if (serial_control == off_pattern) begin// x"FAB0" then | |
| active <= 1'b0; | |
| end | |
| end | |
| // the following is just copy and past, in case we want use the bitbang interface to shift in other data (let's say to drive CPU port) | |
| // we can also read back the data by loading the parallel shift and shifting the content to an output pin | |
| //p_parallel_load2: process(clk) | |
| //begin | |
| // if clk'event and clk=1'b1 then | |
| // local_strobe <= 1'b0; // will be overwritten if next conditional is true | |
| // if serial_control = x"FAB1" then | |
| // data2 <= serial_data; | |
| // local_strobe2 <= 1'b1; | |
| // old_local_strobe2 <= local_strobe; | |
| // end if; | |
| // strobe2 <= local_strobe2 and (not old_local_strobe2) // activates strobe for one clock cycle after "FAB0" was detected | |
| // end if; | |
| //end process; | |
| endmodule |