feat: publish FreeRTOS C FC04 card
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
/*****************************************************************************\
|
||||
| Copyright (C) 2021-2022 Luke Wren |
|
||||
| SPDX-License-Identifier: Apache-2.0 |
|
||||
\*****************************************************************************/
|
||||
|
||||
// APB-to-APB asynchronous bridge for connecting DTM to DM, in case DTM is in
|
||||
// a different clock domain (e.g. running directly from crystal to get a
|
||||
// fixed baud reference)
|
||||
//
|
||||
// Note this module depends on the hazard3_sync_1bit module (a flop-chain
|
||||
// synchroniser) which should be reimplemented for your FPGA/process.
|
||||
|
||||
`ifndef HAZARD3_REG_KEEP_ATTRIBUTE
|
||||
`define HAZARD3_REG_KEEP_ATTRIBUTE (* keep = 1'b1 *)
|
||||
`endif
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module hazard3_apb_async_bridge #(
|
||||
parameter W_ADDR = 8,
|
||||
parameter W_DATA = 32,
|
||||
parameter N_SYNC_STAGES = 2
|
||||
) (
|
||||
// Resets assumed to be synchronised externally
|
||||
input wire clk_src,
|
||||
input wire rst_n_src,
|
||||
|
||||
input wire clk_dst,
|
||||
input wire rst_n_dst,
|
||||
|
||||
// APB port from Transport Module
|
||||
input wire src_psel,
|
||||
input wire src_penable,
|
||||
input wire src_pwrite,
|
||||
input wire [W_ADDR-1:0] src_paddr,
|
||||
input wire [W_DATA-1:0] src_pwdata,
|
||||
output wire [W_DATA-1:0] src_prdata,
|
||||
output wire src_pready,
|
||||
output wire src_pslverr,
|
||||
|
||||
// APB port to Debug Module
|
||||
output wire dst_psel,
|
||||
output wire dst_penable,
|
||||
output wire dst_pwrite,
|
||||
output wire [W_ADDR-1:0] dst_paddr,
|
||||
output wire [W_DATA-1:0] dst_pwdata,
|
||||
input wire [W_DATA-1:0] dst_prdata,
|
||||
input wire dst_pready,
|
||||
input wire dst_pslverr
|
||||
);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Clock-crossing registers
|
||||
|
||||
// We're using a modified req/ack handshake:
|
||||
//
|
||||
// - Initially both req and ack are low
|
||||
// - src asserts req high
|
||||
// - dst responds with ack high and begins transfer
|
||||
// - src deasserts req once it sees ack high
|
||||
// - dst deasserts ack once:
|
||||
// - transfer is complete *and*
|
||||
// - dst sees req deasserted
|
||||
// - Once src sees ack low, a new transfer can begin.
|
||||
//
|
||||
// A NRZI toggle handshake might be more appropriate, but can cause spurious
|
||||
// bus accesses when only one side of the link is reset.
|
||||
|
||||
`HAZARD3_REG_KEEP_ATTRIBUTE reg src_req;
|
||||
wire dst_req;
|
||||
|
||||
`HAZARD3_REG_KEEP_ATTRIBUTE reg dst_ack;
|
||||
wire src_ack;
|
||||
|
||||
// Note the launch registers are not resettable. We maintain setup/hold on
|
||||
// launch-to-capture paths thanks to the req/ack handshake. A stray reset
|
||||
// could violate this.
|
||||
//
|
||||
// The req/ack logic itself can be reset safely because the receiving domain
|
||||
// is protected from metastability by a 2FF synchroniser.
|
||||
|
||||
`HAZARD3_REG_KEEP_ATTRIBUTE reg [W_ADDR + W_DATA + 1 -1:0] src_paddr_pwdata_pwrite; // launch
|
||||
`HAZARD3_REG_KEEP_ATTRIBUTE reg [W_ADDR + W_DATA + 1 -1:0] dst_paddr_pwdata_pwrite; // capture
|
||||
|
||||
`HAZARD3_REG_KEEP_ATTRIBUTE reg [W_DATA + 1 -1:0] dst_prdata_pslverr; // launch
|
||||
`HAZARD3_REG_KEEP_ATTRIBUTE reg [W_DATA + 1 -1:0] src_prdata_pslverr; // capture
|
||||
|
||||
hazard3_sync_1bit #(
|
||||
.N_STAGES (N_SYNC_STAGES)
|
||||
) sync_req (
|
||||
.clk (clk_dst),
|
||||
.rst_n (rst_n_dst),
|
||||
.i (src_req),
|
||||
.o (dst_req)
|
||||
);
|
||||
|
||||
hazard3_sync_1bit #(
|
||||
.N_STAGES (N_SYNC_STAGES)
|
||||
) sync_ack (
|
||||
.clk (clk_src),
|
||||
.rst_n (rst_n_src),
|
||||
.i (dst_ack),
|
||||
.o (src_ack)
|
||||
);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// src state machine
|
||||
|
||||
reg src_waiting_for_downstream;
|
||||
reg src_pready_r;
|
||||
|
||||
always @ (posedge clk_src or negedge rst_n_src) begin
|
||||
if (!rst_n_src) begin
|
||||
src_req <= 1'b0;
|
||||
src_waiting_for_downstream <= 1'b0;
|
||||
src_prdata_pslverr <= {W_DATA + 1{1'b0}};
|
||||
src_pready_r <= 1'b1;
|
||||
end else if (src_waiting_for_downstream) begin
|
||||
if (src_req && src_ack) begin
|
||||
// Request was acknowledged, so deassert.
|
||||
src_req <= 1'b0;
|
||||
end else if (!(src_req || src_ack)) begin
|
||||
// Downstream transfer has finished, data is valid.
|
||||
src_pready_r <= 1'b1;
|
||||
src_waiting_for_downstream <= 1'b0;
|
||||
// Note this assignment is cross-domain (but data has been stable
|
||||
// for duration of ack synchronisation delay):
|
||||
src_prdata_pslverr <= dst_prdata_pslverr;
|
||||
end
|
||||
end else begin
|
||||
// paddr, pwdata and pwrite are all valid during the setup phase, and
|
||||
// APB defines the setup phase to always last one cycle and proceed
|
||||
// to access phase. So, we can ignore penable, and pready is ignored.
|
||||
if (src_psel) begin
|
||||
src_pready_r <= 1'b0;
|
||||
src_req <= 1'b1;
|
||||
src_waiting_for_downstream <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Bus request launch register is not resettable
|
||||
always @ (posedge clk_src) begin
|
||||
if (src_psel && !src_waiting_for_downstream)
|
||||
src_paddr_pwdata_pwrite <= {src_paddr, src_pwdata, src_pwrite};
|
||||
end
|
||||
|
||||
assign {src_prdata, src_pslverr} = src_prdata_pslverr;
|
||||
assign src_pready = src_pready_r;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// dst state machine
|
||||
|
||||
wire dst_bus_finish = dst_penable && dst_pready;
|
||||
reg dst_psel_r;
|
||||
reg dst_penable_r;
|
||||
|
||||
always @ (posedge clk_dst or negedge rst_n_dst) begin
|
||||
if (!rst_n_dst) begin
|
||||
dst_ack <= 1'b0;
|
||||
end else if (dst_req) begin
|
||||
dst_ack <= 1'b1;
|
||||
end else if (!dst_req && dst_ack && !dst_psel_r) begin
|
||||
dst_ack <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
always @ (posedge clk_dst or negedge rst_n_dst) begin
|
||||
if (!rst_n_dst) begin
|
||||
dst_psel_r <= 1'b0;
|
||||
dst_penable_r <= 1'b0;
|
||||
dst_paddr_pwdata_pwrite <= {W_ADDR + W_DATA + 1{1'b0}};
|
||||
end else if (dst_req && !dst_ack) begin
|
||||
dst_psel_r <= 1'b1;
|
||||
// Note this assignment is cross-domain. The src register has been
|
||||
// stable for the duration of the req sync delay.
|
||||
dst_paddr_pwdata_pwrite <= src_paddr_pwdata_pwrite;
|
||||
end else if (dst_psel_r && !dst_penable_r) begin
|
||||
dst_penable_r <= 1'b1;
|
||||
end else if (dst_bus_finish) begin
|
||||
dst_psel_r <= 1'b0;
|
||||
dst_penable_r <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// Bus response launch register is not resettable
|
||||
always @ (posedge clk_dst) begin
|
||||
if (dst_bus_finish)
|
||||
dst_prdata_pslverr <= {dst_prdata, dst_pslverr};
|
||||
end
|
||||
|
||||
assign dst_psel = dst_psel_r;
|
||||
assign dst_penable = dst_penable_r;
|
||||
assign {dst_paddr, dst_pwdata, dst_pwrite} = dst_paddr_pwdata_pwrite;
|
||||
|
||||
endmodule
|
||||
|
||||
`ifndef YOSYS
|
||||
`default_nettype wire
|
||||
`endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/*****************************************************************************\
|
||||
| Copyright (C) 2021-2022 Luke Wren |
|
||||
| SPDX-License-Identifier: Apache-2.0 |
|
||||
\*****************************************************************************/
|
||||
|
||||
// The output is asserted asynchronously when the input is asserted,
|
||||
// but deasserted synchronously when clocked with the input deasserted.
|
||||
// Input and output are both active-low.
|
||||
//
|
||||
// This is a baseline implementation -- you should replace it with cells
|
||||
// specific to your FPGA/process
|
||||
|
||||
`ifndef HAZARD3_REG_KEEP_ATTRIBUTE
|
||||
`define HAZARD3_REG_KEEP_ATTRIBUTE (* keep = 1'b1 *)
|
||||
`endif
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module hazard3_reset_sync #(
|
||||
parameter N_STAGES = 2 // Should be >= 2
|
||||
) (
|
||||
input wire clk,
|
||||
input wire rst_n_in,
|
||||
output wire rst_n_out
|
||||
);
|
||||
|
||||
`HAZARD3_REG_KEEP_ATTRIBUTE reg [N_STAGES-1:0] delay;
|
||||
|
||||
always @ (posedge clk or negedge rst_n_in)
|
||||
if (!rst_n_in)
|
||||
delay <= {N_STAGES{1'b0}};
|
||||
else
|
||||
delay <= {delay[N_STAGES-2:0], 1'b1};
|
||||
|
||||
assign rst_n_out = delay[N_STAGES-1];
|
||||
|
||||
endmodule
|
||||
|
||||
`ifndef YOSYS
|
||||
`default_nettype wire
|
||||
`endif
|
||||
@@ -0,0 +1,39 @@
|
||||
/*****************************************************************************\
|
||||
| Copyright (C) 2021-2022 Luke Wren |
|
||||
| SPDX-License-Identifier: Apache-2.0 |
|
||||
\*****************************************************************************/
|
||||
|
||||
// A 2FF synchronizer to mitigate metastabilities. This is a baseline
|
||||
// implementation -- you should replace it with cells specific to your
|
||||
// FPGA/process
|
||||
|
||||
`ifndef HAZARD3_REG_KEEP_ATTRIBUTE
|
||||
`define HAZARD3_REG_KEEP_ATTRIBUTE (* keep = 1'b1 *) (* async_reg *)
|
||||
`endif
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module hazard3_sync_1bit #(
|
||||
parameter N_STAGES = 2 // Should be >=2
|
||||
) (
|
||||
input wire clk,
|
||||
input wire rst_n,
|
||||
input wire i,
|
||||
output wire o
|
||||
);
|
||||
|
||||
`HAZARD3_REG_KEEP_ATTRIBUTE reg [N_STAGES-1:0] sync_flops;
|
||||
|
||||
always @ (posedge clk or negedge rst_n)
|
||||
if (!rst_n)
|
||||
sync_flops <= {N_STAGES{1'b0}};
|
||||
else
|
||||
sync_flops <= {sync_flops[N_STAGES-2:0], i};
|
||||
|
||||
assign o = sync_flops[N_STAGES-1];
|
||||
|
||||
endmodule
|
||||
|
||||
`ifndef YOSYS
|
||||
`default_nettype wire
|
||||
`endif
|
||||
Reference in New Issue
Block a user