| // SPDX-FileCopyrightText: |
| // 2022 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 |