1
0
mirror of https://github.com/aolofsson/oh.git synced 2025-01-30 02:32:53 +08:00

Merge branch 'master' of github.com:parallella/oh

Conflicts:
	docs/tapeout_checklist.md
This commit is contained in:
Andreas Olofsson 2016-06-20 21:21:07 -04:00
commit 893db9508a
147 changed files with 3677 additions and 1378 deletions

View File

@ -123,10 +123,12 @@ TBD
* Use common names: nreset, clk, din, dout, en, rd, wr, addr, etc
* Make names descriptive, avoid non-common abbreviations
* Make names as short as possible, but not shorter
* Use short named generate blocks "g0, g1, etc"
* Inside generate blocks use short "i<name>" for instance
* Use _ in constants over 4 bits (eg: 8'h1100_1100)
* One module per file
* Use ".vh" suffix for header files,
* yse ".v" for verilog source files
* Use ".v" for verilog source files
* Use `include files for constants
* Use `ifndef _CONSTANTS_V to include file only once
* No timescales in design files (only in testbench)
@ -138,6 +140,7 @@ TBD
* Avoid redundant resets
* Avoid heavily nested if, else statements
* Don't use defparams, place #(.DW(DW)) in module instantation
* With parameters, NEVER us this instantiation: "mux3 #(32) U2 (...)"
* Always use connection by name (not by order) in module instantiatoin
* Parametrize as much as possible but not more
* Place a useful comment every 5-20 lines
@ -149,6 +152,7 @@ TBD
* Don't use proprietary EDA tool pragmas (use parameters)
* Only use synthesizable constructs
* Use $signed() for arithmetic operations on signed types
.
* Allowed keywords: assign, always, input, output, wire, reg, module, endmodule, if/else, case, casez, ~,|,&,^,==, >>, <<, >, <,?,posedge, negedge, generate, for(...), begin, end, $signed,
@ -174,16 +178,9 @@ TBD
* Show how to synthesize/build..
* Show how to use..
## Design Checklist
## Tapeout Checklist
* Is the block datasheet complete and accurate?
* Is there a user guide?
* Is there a script/make file for building/testing the design?
* Is there a self testing testbench?
* Is there an auotomated synthesis script?
* Is the driver written?
* Is there a demo example?
* Is the the block Silicon and FPGA validated?
* [HERE](docs/tapeout_checklist.md)
## Recommended Reading

View File

@ -35,6 +35,8 @@ A list of some basic equations and constants I have found useful in my life as a
| Line capacitance / mm (max density) | (highly variable!) |
| Line resistance / mm (fat layer) | (copper, highly variable!) |
## Interconnects
| Rule | Value |

View File

@ -8,17 +8,23 @@
| Specification | Answer |
|--------------------------------------------|--------------------------------|
| Is there a written specification? | |
| Is the datasheet complete and accurate? | |
| Is there a user guide? | |
| What is the chip max power target? | |
| What is the chip standby power target? | |
| What is the chip yield target? | |
| What is the chip cost target? | |
| What is the max die size? | |
| What is the maximum die size? | |
| How many signal IOs? | |
| What is the highest frequency IO? | |
| Design | Answer |
|--------------------------------------------|--------------------------------|
| In Verilog 2005 used? | |
| Are all features implemented? | |
| Are all issues closed? | |
| Has design been through peer review? | |
| Has a linter been run? | |
| Is there zero use of 'casex'? | |
| Were Latches used? (If so list) | |
@ -39,7 +45,7 @@
| Any floating inputs in design? | |
| All power-gated signals isolated? | |
| All voltage domain crossings levelshifted? | |
| Is Verilog 2005 used? | |
| Verification | Answer |
|--------------------------------------------|--------------------------------|
@ -49,10 +55,15 @@
| >24hrs of random vectors? | |
| Randomized clock frequencies? | |
| Were all open issues closed? | |
| Were all features tested? | |
| Simulator support for all features? | |
| Was design emulated in an FPGA? | |
| Was design validated with application SW? | |
| Was formal equivalence run between HDL/GL? | |
| Is the firmware written? | |
| Is there a demo? | |
| Timing | Answer |
|--------------------------------------------|--------------------------------|
@ -74,6 +85,8 @@
| Clock | Answer |
|--------------------------------------------|--------------------------------|
| Percentage regs clock gated? | |
| Integrated clock gating cells used? | |
| Setup/hold verified on clock gating cells? | |
| Clock tree insertion delay? | |
| Clock tree local skew? | |
| Clock tree global skew? | |
@ -83,7 +96,6 @@
| Use of oh_fifo_cdc on all CDCs? | |
| Were custom CDCs used? (if so list) | |
| Reset | Answer |
|--------------------------------------------|--------------------------------|
| Is reset active low used? | |
@ -133,6 +145,12 @@
| Layout | Answer |
|--------------------------------------------|--------------------------------|
| Synthesis/PNR | Answer |
|--------------------------------------------|--------------------------------|
| Is the flow completely automated? | |
| Was the correct/latest version of HDL used?| |
| Are all EDA warnings/errors acceptable? | |
| The number of warnings has bee minimized? | |
| Was the correct/latest gate level used? | |
| Are all EDA warnings/errors understood? | |
| Are ECO/spare cells used? | |
@ -150,6 +168,7 @@
| Is the chip logo included | |
| Have gds layer map been manually reviewed? | |
| Has tapeout GDS been manually reviewed? | |
| XOR check between foundry/design GDSIIs | |
| DFM | Answer |
|--------------------------------------------|--------------------------------|
@ -158,6 +177,7 @@
| What is the percentage of double vias? | |
| Is yield optimizing wire spreading used? | |
| Does design include fault tolerance? | |
| Does design meet metal density rules? | |
| Test | Answer |
|--------------------------------------------|--------------------------------|
@ -187,6 +207,10 @@
| Design's lowest operating voltage? | |
| What is the longest signal on the chip? | |
| Is design sensitive to duty cycle shift? | |
| What is the max duty-cycle distortion? | |
| Does design meet EMI constraints? | |
| ERC runset checks run on GDSII? | |

View File

@ -21,6 +21,7 @@ $OH_HOME/scripts/link.sh
###############################
iverilog -g2005\
-DTARGET_SIM=1\
-DCFG_ASIC=0\
$DUT\
$OH_HOME/symlinks/dv/dv_top.v\
-y .\

View File

@ -1,50 +1,42 @@
/* verilator lint_off STMTDLY */
module dv_driver (/*AUTOARG*/
// Outputs
stim_access, stim_packet, stim_wait, stim_done,
// Inputs
clkin, clkout, nreset, start, coreid, dut_access, dut_packet,
dut_wait
);
//Parameters
parameter N = 1; // "N" packets wide
parameter AW = 32; // address width
parameter IDW = 12; // id width
parameter NAME = "none"; // north, south etc
parameter STIMS = 1; // number of stimulus
parameter MAW = 16; // 64KB memory address width
localparam PW = 2*AW+40; // packet width (derived)
//Control signals
input clkin;
input clkout;
input nreset;
input start; //starts test
input [IDW-1:0] coreid; //everything has a coreid!
//Inputs for monitoring
input [N-1:0] dut_access;
input [N*PW-1:0] dut_packet;
input [N-1:0] dut_wait;
//Stimulus to drive
output [N-1:0] stim_access;
output [N*PW-1:0] stim_packet;
output [N-1:0] stim_wait;
output stim_done;
module dv_driver #( parameter N = 1, // "N" packets wide
parameter AW = 32, // address width
parameter PW = 104, // packet width (derived)
parameter IDW = 12, // id width
parameter NAME = "none", // north, south etc
parameter STIMS = 1, // number of stimulus
parameter MAW = 16 // 64KB memory address width
)
(
//control signals
input clkin,
input clkout,
input nreset,
input start, //starts test
input [IDW-1:0] coreid, //everything has a coreid!
//inputs for monitoring
input [N-1:0] dut_access,
input [N*PW-1:0] dut_packet,
input [N-1:0] dut_wait,
//stimulus to drive
output [N-1:0] stim_access,
output [N*PW-1:0] stim_packet,
output [N-1:0] stim_wait,
output stim_done
);
//#############
//LOCAL WIRES
//#############
reg [IDW-1:0] offset;
wire [N*32-1:0] stim_count;
wire [N-1:0] stim_vec_done;
wire [N*IDW-1:0] coreid_array;
reg [IDW-1:0] offset;
wire [N*PW-1:0] mem_packet_out;
wire [N-1:0] mem_access_out;
wire [N-1:0] mem_wait_out;
/*AUTOWIRE*/
//###########################################
//STIMULUS
//###########################################
@ -126,6 +118,7 @@ module dv_driver (/*AUTOARG*/
for(j=0;j<N;j=j+1) begin : mem
ememory #(.NAME(NAME),
.IDW(IDW),
.PW(PW),
.AW(AW)
)
ememory(// Outputs

View File

@ -53,6 +53,8 @@ module dv_top();
.clk1 (clk1),
.clk2 (clk2),
.start (start),
.vdd (vdd),
.vss (vss),
// Inputs
.dut_active (dut_active),
.stim_done (stim_done));

View File

@ -32,6 +32,8 @@ module oh_clockdiv
reg clkout1_reg;
reg clkout1_shift;
reg [2:0] period;
wire
period_match;
//###########################################
//# CHANGE DETECT (count 8 periods)

View File

@ -5,34 +5,40 @@
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module oh_clockgate #(parameter DW = 1, // width of data
parameter ASIC = 0 // use ASIC lib
module oh_clockgate # (parameter ASIC = 0, // use ASIC lib
parameter PROJ = "E5" // project name (used for IP selection)
)
(
input nrst, // active low sync reset (synced to input clk)
input clk, // clock input
input se, // scan enable
input [DW-1:0] en, // enable (from positive edge FF)
output [DW-1:0] eclk// enabled clock output
);
input clk, // clock input
input te, // test enable enable
input en, // enable (from positive edge FF)
output eclk // enabled clock output
);
generate
if(ASIC)
begin : asic
asic_icg #(.PROJ(PROJ))
asic_icg (.en(en),
.te(te),
.clk(clk),
.eclk(eclk));
end
else
begin : generic
wire en_sh;
wire en_sl;
//Stable low/valid rising edge enable
assign en_sl = en | te;
wire [DW-1:0] en_sh;
wire [DW-1:0] en_sl;
//Turn on clock if in scan mode or if enabled
assign en_sl[DW-1:0] = en[DW-1:0] |
{(DW){se}} |
{(DW){~nrst}};
//making signal stable
oh_lat0 #(.DW(1)) lat0 (.out (en_sh[DW-1:0]),
.in (en_sl[DW-1:0]),
.clk (clk)
);
assign eclk[DW-1:0] = {(DW){clk}} & en_sh[DW-1:0];
//Stable high enable signal
oh_lat0 lat0 (.out (en_sh),
.in (en_sl),
.clk (clk));
assign eclk = clk & en_sh;
end
endgenerate
endmodule // oh_clockgate

View File

@ -0,0 +1,32 @@
//#############################################################################
//# Function: One hot 4:1 mux for clocks #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module oh_clockmux #(parameter PROJ = "E5", // project name
parameter ASIC = 0, // use ASIC lib
parameter N = 1) // number of clock inputs
(
input [N-1:0] en, // one hot enable, valid rising edge wrt to its clock
input [N-1:0] clkin,// free running input clocks
output clkout
);
wire [N-1:0] eclk;
//One clock gate per clock
oh_clockgate #(.PROJ(PROJ),
.ASIC(ASIC))
i_clockgate [N-1:0] (.eclk (eclk[N-1:0]),
.clk (clkin[N-1:0]),
.te (1'b0), //do something about this>
.en (en[N-1:0]));
//Or gated clocks together
assign clkout = |(eclk[N-1:0]);
endmodule // oh_clockmux

View File

@ -17,7 +17,7 @@ module oh_csa32 #(parameter DW = 1, // data width
generate
if(ASIC)
begin
begin : asic
asic_csa32 i_csa32[DW-1:0] (.s(s[DW-1:0]),
.c(c[DW-1:0]),
.in2(in2[DW-1:0]),
@ -25,7 +25,7 @@ module oh_csa32 #(parameter DW = 1, // data width
.in0(in0[DW-1:0]));
end
else
begin
begin : generic
assign s[DW-1:0] = in0[DW-1:0] ^ in1[DW-1:0] ^ in2[DW-1:0];
assign c[DW-1:0] = (in0[DW-1:0] & in1[DW-1:0]) |
(in1[DW-1:0] & in2[DW-1:0]) |

View File

@ -5,52 +5,36 @@
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module oh_dsync #(parameter DW = 1, // width of data
parameter PS = 3, // mnumber of sync stages
parameter ASIC = 0 // use asic library
module oh_dsync #(parameter PS = 2, // number of sync stages
parameter DELAY = 0, // random delay
parameter ASIC = `CFG_ASIC // use asic library
)
(
input clk, // clock
input nreset, // clock
input [DW-1:0] din, // input data
output [DW-1:0] dout // synchronized data
input clk, // clock
input nreset, // clock
input din, // input data
output dout // synchronized data
);
generate
if(ASIC)
begin
asic_dsync #(.DW(DW))
asic_dsync(.clk(clk),
.nreset(nreset),
.din(din[DW-1:0]),
.dout(dout[DW-1:0]));
begin : g0
asic_dsync asic_dsync (.clk(clk),
.nreset(nreset),
.din(din),
.dout(dout));
end
else
begin
reg [DW-1:0] sync_pipe[PS:0]; //extra cycle for DV
genvar i;
for(i=0;i<(PS+1);i=i+1)
if(i==0)
always @ (posedge clk or negedge nreset)
if(!nreset)
sync_pipe[0][DW-1:0] <= 'b0;
else
sync_pipe[0][DW-1:0] <= din[DW-1:0];
begin : g0
reg [PS:0] sync_pipe;
always @ (posedge clk or negedge nreset)
if(!nreset)
sync_pipe[PS:0] <= 1'b0;
else
always @ (posedge clk or negedge nreset)
if(!nreset)
sync_pipe[i][DW-1:0] <= 'b0;
else
sync_pipe[i][DW-1:0] <= sync_pipe[i-1][DW-1:0];
`ifdef TARGET_SIM
// randomize sync delay based on value in per bit delay register
// delay to be forced from testbench
reg [DW-1:0] delay = 0;
assign dout[DW-1:0] = (delay[DW-1:0] & sync_pipe[PS][DW-1:0]) | //extra cycle
(~delay[DW-1:0] & sync_pipe[PS-1][DW-1:0]); //default
`else
assign dout[DW-1:0] = sync_pipe[PS-1][DW-1:0];
`endif
sync_pipe[PS:0] <= {sync_pipe[PS-1:0],din};
// drive randomize delay from testbench
assign dout = (DELAY & sync_pipe[PS]) | //extra cycle
(~DELAY & sync_pipe[PS-1]); //default
end
endgenerate

View File

@ -5,25 +5,25 @@
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module oh_fifo_async # (parameter DW = 104, //FIFO width
parameter DEPTH = 32, //FIFO depth (entries)
parameter TARGET = "GENERIC",//XILINX,ALTERA,GENERIC,ASIC
module oh_fifo_async # (parameter DW = 104, // FIFO width
parameter DEPTH = 32, // FIFO depth (entries)
parameter TARGET = "GENERIC",// XILINX,ALTERA,GENERIC,ASIC
parameter PROG_FULL = (DEPTH/2),// program full threshold
parameter AW = $clog2(DEPTH) // binary read count width
)
(
input nreset, // async reset
input wr_clk, // write clock
input wr_en, // write fifo
input [DW-1:0] din, // data to write
input rd_clk, // read clock
input rd_en, // read fifo
output [DW-1:0] dout, // output data (next cycle)
output full, // fifo is full
output prog_full, // fifo reaches full threshold
output empty, // fifo is empty
output [AW-1:0] rd_count // # of valid entries in fifo
);
(
input nreset, // async reset
input wr_clk, // write clock
input wr_en, // write fifo
input [DW-1:0] din, // data to write
input rd_clk, // read clock
input rd_en, // read fifo
output [DW-1:0] dout, // output data (next cycle)
output full, // fifo is full
output prog_full, // fifo reaches full threshold
output empty, // fifo is empty
output [AW-1:0] rd_count // # of valid entries in fifo
);
//local wires
wire [AW-1:0] wr_count; // valid entries in fifo
@ -48,9 +48,28 @@ module oh_fifo_async # (parameter DW = 104, //FIFO width
.din (din[DW-1:0]),
.rd_en (rd_en));
end
else if(TARGET=="ASIC") begin : asic
oh_fifo_generic #(.DEPTH(DEPTH),
.DW(DW))
fifo_generic (
// Outputs
.full (full),
.prog_full (prog_full),
.dout (dout[DW-1:0]),
.empty (empty),
.rd_count (rd_count[AW-1:0]),
.wr_count (wr_count[AW-1:0]),
// Inputs
.nreset (nreset),
.wr_clk (wr_clk),
.rd_clk (rd_clk),
.wr_en (wr_en),
.din (din[DW-1:0]),
.rd_en (rd_en));
end
else if (TARGET=="XILINX") begin : xilinx
if((DW==104) & (DEPTH==32))
begin
begin : g104x32
fifo_async_104x32
fifo (
// Outputs

View File

@ -7,16 +7,16 @@
module oh_fifo_cdc # (parameter DW = 104, //FIFO width
parameter DEPTH = 32, //FIFO depth (entries)
parameter TARGET = "GENERIC" //XILINX,ALTERA,GENERIC,ASIC
parameter TARGET = "GENERIC" //XILINX,ALTERA,GENERIC
)
(
input nreset, // shared domain async active low reset
input clk_in, // write clock
input nreset, // shared domain async active low reset
input clk_in, // write clock
input access_in, // write access
input [DW-1:0] packet_in, // write packet
output wait_out, // write pushback
input clk_out, //read clock
output access_out, //read access
output reg access_out, //read access
output [DW-1:0] packet_out, //read packet
input wait_in, // read pushback
output prog_full, // fifo is half full
@ -24,8 +24,8 @@ module oh_fifo_cdc # (parameter DW = 104, //FIFO width
output empty // fifo is empty
);
// local variables
reg access_out;
wire wr_en;
wire rd_en;
// FIFO control logic
assign wr_en = access_in;

View File

@ -28,6 +28,8 @@ module oh_fifo_generic #(parameter DW = 104, // FIFO width
output [AW-1:0] wr_count // NOT IMPLEMENTED
);
localparam ASIC = `CFG_ASIC;
//regs
reg [AW:0] wr_addr; // extra bit for wraparound comparison
reg [AW:0] wr_addr_ahead; // extra bit for wraparound comparison
@ -38,7 +40,8 @@ module oh_fifo_generic #(parameter DW = 104, // FIFO width
wire [AW:0] wr_addr_gray_sync;
wire [AW:0] rd_addr_sync;
wire [AW:0] wr_addr_sync;
wire wr_nreset;
wire rd_nreset;
//###########################
//# Full/empty indicators
@ -64,13 +67,15 @@ module oh_fifo_generic #(parameter DW = 104, // FIFO width
//# Reset synchronizers
//###########################
oh_rsync wr_rsync (.nrst_out (wr_nreset),
.clk (wr_clk),
.nrst_in (nreset));
oh_rsync #(.ASIC(ASIC))
wr_rsync (.nrst_out (wr_nreset),
.clk (wr_clk),
.nrst_in (nreset));
oh_rsync rd_rsync (.nrst_out (rd_nreset),
.clk (rd_clk),
.nrst_in (nreset));
oh_rsync #(.ASIC(ASIC))
rd_rsync (.nrst_out (rd_nreset),
.clk (rd_clk),
.nrst_in (nreset));
//###########################
//#write side address counter
@ -99,11 +104,10 @@ module oh_fifo_generic #(parameter DW = 104, // FIFO width
.in (wr_addr[AW:0]));
// synchronize to read clock
oh_dsync #(.DW(AW+1))
wr_sync(.dout (wr_addr_gray_sync[AW:0]),
.clk (rd_clk),
.nreset(rd_nreset),
.din (wr_addr_gray[AW:0]));
oh_dsync wr_sync[AW:0] (.dout (wr_addr_gray_sync[AW:0]),
.clk (rd_clk),
.nreset(rd_nreset),
.din (wr_addr_gray[AW:0]));
//###########################
//#read side address counter
@ -125,11 +129,10 @@ module oh_fifo_generic #(parameter DW = 104, // FIFO width
.in (rd_addr[AW:0]));
//synchronize to wr clock
oh_dsync #(.DW(AW+1))
rd_sync(.dout (rd_addr_gray_sync[AW:0]),
.clk (wr_clk),
.nreset (wr_nreset),
.din (rd_addr_gray[AW:0]));
oh_dsync rd_sync[AW:0] (.dout (rd_addr_gray_sync[AW:0]),
.clk (wr_clk),
.nreset (wr_nreset),
.din (rd_addr_gray[AW:0]));
//convert back to binary (for ease of use, rd_count)
oh_gray2bin #(.DW(AW+1))

View File

@ -11,21 +11,22 @@ module oh_fifo_sync #(parameter DW = 104, //FIFO width
parameter AW = $clog2(DEPTH) //rd_count width
)
(
input clk, // clock
input nreset, // active high async reset
input [DW-1:0] din, // data to write
input wr_en, // write fifo
input rd_en, // read fifo
output [DW-1:0] dout, // output data (next cycle)
output full, // fifo full
output prog_full, // fifo is almost full
output empty, // fifo is empty
output [AW-1:0] rd_count // valid entries in fifo
input clk, // clock
input nreset, // active high async reset
input [DW-1:0] din, // data to write
input wr_en, // write fifo
input rd_en, // read fifo
output [DW-1:0] dout, // output data (next cycle)
output full, // fifo full
output prog_full, // fifo is almost full
output empty, // fifo is empty
output reg [AW-1:0] rd_count // valid entries in fifo
);
reg [AW-1:0] wr_addr;
reg [AW-1:0] rd_addr;
reg [AW-1:0] rd_count;
reg [AW-1:0] wr_addr;
reg [AW-1:0] rd_addr;
wire fifo_read;
wire fifo_write;
assign empty = (rd_count[AW-1:0] == 0);
assign prog_full = (rd_count[AW-1:0] >= PROG_FULL);

View File

@ -8,18 +8,16 @@
module oh_iddr #(parameter DW = 1 // width of data inputs
)
(
input clk, // clock
input ce, // clock enable, set to high to clock in data
input [DW-1:0] din, // data input sampled on both edges of clock
output [DW-1:0] q1, // iddr rising edge sampled data
output [DW-1:0] q2 // iddr falling edge sampled data
input clk, // clock
input ce, // clock enable, set to high to clock in data
input [DW-1:0] din, // data input sampled on both edges of clock
output reg [DW-1:0] q1, // iddr rising edge sampled data
output reg [DW-1:0] q2 // iddr falling edge sampled data
);
//regs("sl"=stable low, "sh"=stable high)
reg [DW-1:0] q1_sl;
reg [DW-1:0] q2_sh;
reg [DW-1:0] q1;
reg [DW-1:0] q2;
// rising edge sample
always @ (posedge clk)

View File

@ -7,11 +7,10 @@
module oh_lat0 #(parameter DW = 1) // data width
( input clk, // clk, latch when clk=0
input [DW-1:0] in, // input data
output [DW-1:0] out // output data (stable/latched when clk=1)
input [DW-1:0] in, // input data
output reg [DW-1:0] out // output data (stable/latched when clk=1)
);
reg [DW-1:0] out;
always @ (clk or in)
if (!clk)
out[DW-1:0] <= in[DW-1:0];

View File

@ -1,21 +1,33 @@
//#############################################################################
//# Function: Latch data when clk=1 #
//# Function: Achive high latch #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module oh_lat1 #(parameter DW = 1) // data width
module oh_lat1 #(parameter DW = 1, //data width
parameter ASIC = 0 // use ASIC lib
)
( input clk, // clk, latch when clk=1
input [DW-1:0] in, // input data
output [DW-1:0] out // output data (stable/latched when clk=0)
);
reg [DW-1:0] out;
always @ (clk or in)
if (clk)
out[DW-1:0] <= in[DW-1:0];
generate
if(ASIC)
begin : g0
asic_lat1 i_lat [DW-1:0] (.clk(clk),
.in(in[DW-1:0]),
.out(out[DW-1:0]));
end
else
begin : g0
reg [DW-1:0] out_reg;
always @ (clk or in)
if (clk)
out_reg[DW-1:0] <= in[DW-1:0];
assign out[DW-1:0] = out_reg[DW-1:0];
end
endgenerate
endmodule // oh_lat1

View File

@ -39,40 +39,38 @@ module oh_memory_dp # (parameter DW = 104, //memory width
generate
if(ASIC)
begin
begin : asic
oh_memory_ram #(.DW(DW),
.DEPTH(DEPTH))
i_sram (//read port
.rd_dout (rd_dout[DW-1:0]),
.rd_clk (rd_clk),
.rd_en (rd_en),
.rd_addr (rd_addr[AW-1:0]),
//write port
.wr_en (wr_en),
.wr_clk (wr_clk),
.wr_addr (wr_addr[AW-1:0]),
.wr_wem (wr_wem[DW-1:0]),
.wr_din (wr_din[DW-1:0]));
memory_dp (//read port
.rd_dout (rd_dout[DW-1:0]),
.rd_clk (rd_clk),
.rd_en (rd_en),
.rd_addr (rd_addr[AW-1:0]),
//write port
.wr_en (wr_en),
.wr_clk (wr_clk),
.wr_addr (wr_addr[AW-1:0]),
.wr_wem (wr_wem[DW-1:0]),
.wr_din (wr_din[DW-1:0]));
end // if (ASIC)
else
begin
begin : generic
oh_memory_ram #(.DW(DW),
.DEPTH(DEPTH))
oh_memory_ram (//read port
.rd_dout (rd_dout[DW-1:0]),
.rd_clk (rd_clk),
.rd_en (rd_en),
.rd_addr (rd_addr[AW-1:0]),
//write port
.wr_en (wr_en),
.wr_clk (wr_clk),
.wr_addr (wr_addr[AW-1:0]),
.wr_wem (wr_wem[DW-1:0]),
.wr_din (wr_din[DW-1:0]));
memory_dp (//read port
.rd_dout (rd_dout[DW-1:0]),
.rd_clk (rd_clk),
.rd_en (rd_en),
.rd_addr (rd_addr[AW-1:0]),
//write port
.wr_en (wr_en),
.wr_clk (wr_clk),
.wr_addr (wr_addr[AW-1:0]),
.wr_wem (wr_wem[DW-1:0]),
.wr_din (wr_din[DW-1:0]));
end // else: !if(ASIC)
endgenerate
endgenerate
endmodule // oh_memory_dp

View File

@ -5,26 +5,24 @@
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module oh_memory_ram # (parameter DW = 104, //memory width
parameter DEPTH = 32 //memory depth
module oh_memory_ram # (parameter DW = 104, //memory width
parameter DEPTH = 32, //memory depth
parameter AW = $clog2(DEPTH) // address width
)
(// read-port
input rd_clk,// rd clock
input rd_en, // memory access
input [AW-1:0] rd_addr, // address
output [DW-1:0] rd_dout, // data output
input rd_clk,// rd clock
input rd_en, // memory access
input [AW-1:0] rd_addr, // address
output reg [DW-1:0] rd_dout, // data output
// write-port
input wr_clk,// wr clock
input wr_en, // memory access
input [AW-1:0] wr_addr, // address
input [DW-1:0] wr_wem, // write enable vector
input [DW-1:0] wr_din // data input
input wr_clk,// wr clock
input wr_en, // memory access
input [AW-1:0] wr_addr, // address
input [DW-1:0] wr_wem, // write enable vector
input [DW-1:0] wr_din // data input
);
parameter AW = $clog2(DEPTH); // address bus width
reg [DW-1:0] ram [DEPTH-1:0];
reg [DW-1:0] rd_dout;
integer i;
//registered read port

View File

@ -1,15 +1,16 @@
//#############################################################################
//# Function: Sinle Port Memory #
//# Function: Single Port Memory #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see LICENSE file in OH! repository) #
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module oh_memory_sp # (parameter DW = 104, // memory width
parameter DEPTH = 32, // memory depth
parameter PROJ = "", // project name
parameter ASIC = 0, // use ASIC lib
parameter MCW = 8 // repair/config vector width
module oh_memory_sp # (parameter DW = 104, // memory width
parameter DEPTH = 32, // memory depth
parameter PROJ = "", // project name
parameter ASIC = 0, // use ASIC lib
parameter MCW = 8, // repair/config width
parameter AW = $clog2(DEPTH) // address bus width
)
(// memory interface (single port)
input clk, // clock
@ -34,51 +35,51 @@ module oh_memory_sp # (parameter DW = 104, // memory width
input [DW-1:0] bist_din // data input
);
parameter AW = $clog2(DEPTH); // address bus width
generate
if(ASIC)
begin
begin : g0
asic_sram_sp #(.DW(DW),
.DEPTH(DEPTH),
.PROJ(PROJ),
.MCW(MCW))
i_sram (// Outputs
.dout (dout[DW-1:0]),
// Inputs
.clk (clk),
.en (en),
.we (we),
.wem (wem[DW-1:0]),
.addr (addr[AW-1:0]),
.din (din[DW-1:0]),
.vdd (vdd),
.vddm (vddm),
.vss (vss),
.shutdown (shutdown),
.memconfig (memconfig[MCW-1:0]),
.memrepair (memrepair[MCW-1:0]),
.bist_en (bist_en),
.bist_we (bist_we),
.bist_wem (bist_wem[DW-1:0]),
.bist_addr (bist_addr[AW-1:0]),
.bist_din (bist_din[DW-1:0]));
sram_sp (// Outputs
.dout (dout[DW-1:0]),
// Inputs
.clk (clk),
.en (en),
.we (we),
.wem (wem[DW-1:0]),
.addr (addr[AW-1:0]),
.din (din[DW-1:0]),
.vdd (vdd),
.vddm (vddm),
.vss (vss),
.shutdown (shutdown),
.memconfig (memconfig[MCW-1:0]),
.memrepair (memrepair[MCW-1:0]),
.bist_en (bist_en),
.bist_we (bist_we),
.bist_wem (bist_wem[DW-1:0]),
.bist_addr (bist_addr[AW-1:0]),
.bist_din (bist_din[DW-1:0]));
end
else
begin
begin : g0
oh_memory_ram #(.DW(DW),
.DEPTH(DEPTH))
oh_memory_ram (//read port
.rd_dout (dout[DW-1:0]),
.rd_clk (clk),
.rd_addr (addr[AW-1:0]),
.rd_en (en & ~we),
//write port
.wr_clk (clk),
.wr_en (en & we),
.wr_addr (addr[AW-1:0]),
.wr_wem (wem[DW-1:0]),
.wr_din (din[DW-1:0]));
sram_sp (//read port
.rd_dout (dout[DW-1:0]),
.rd_clk (clk),
.rd_addr (addr[AW-1:0]),
.rd_en (en & ~we),
//write port
.wr_clk (clk),
.wr_en (en & we),
.wr_addr (addr[AW-1:0]),
.wr_wem (wem[DW-1:0]),
.wr_din (din[DW-1:0]));
end
endgenerate

View File

@ -5,8 +5,9 @@
//# License: MIT (see LICENSE in OH! repositpory) #
//#############################################################################
module oh_par2ser #(parameter PW = 64, // parallel packet width
parameter SW = 1 // serial packet width
module oh_par2ser #(parameter PW = 64, // parallel packet width
parameter SW = 1, // serial packet width
parameter CW = $clog2(PW/SW) // serialization factor
)
(
input clk, // sampling clock
@ -23,11 +24,11 @@ module oh_par2ser #(parameter PW = 64, // parallel packet width
output wait_out // wait output (wait in | serial wait)
);
// parameters
parameter CW = $clog2(PW/SW); // serialization factor (for counter)
// local wires
reg [PW-1:0] shiftreg;
reg [CW-1:0] count;
wire start_transfer;
wire busy;
// start serialization
assign start_transfer = load & ~wait_in & ~busy;

View File

@ -28,10 +28,10 @@ module oh_pulse2pulse (
toggle_reg <= toggle;
//metastability synchronizer
oh_dsync #(1) sync(.dout (toggle_sync),
.din (toggle),
.nreset (nrstout),
.clk (clkout));
oh_dsync sync(.dout (toggle_sync),
.din (toggle),
.nreset (nrstout),
.clk (clkout));
//toogle to pulse
always @ (posedge clkout)

View File

@ -18,7 +18,7 @@ module oh_pwr_gate #(parameter ASIC = 0 // use ASIC lib
`else
generate
if(ASIC)
begin
begin : asic
asic_pwr_header i_header (.npower(npower),
.vdd(vdd),
.vddg(vddg));

View File

@ -23,14 +23,13 @@ module oh_pwr_isolate #(parameter DW = 1, // width of data inputs
`else
generate
if(ASIC)
begin
asic_iso i_iso [DW-1:0] (.vdd(vdd),
.vss(vss),
begin : asic
asic_iso i_iso [DW-1:0] (.niso(niso),
.in(in[DW-1:0]),
.out(out[DW-1:0]));
end
else
begin
begin : generic
assign out[DW-1:0] = {(DW){niso}} & in[DW-1:0];
end
endgenerate

View File

@ -5,22 +5,32 @@
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module oh_rsync #(parameter PS =2) // number of sync stages
module oh_rsync #(parameter PS = 2, // number of sync stages
parameter ASIC = `CFG_ASIC // use asic library
)
(
input clk,
input nrst_in,
output nrst_out
);
reg [PS-1:0] sync_pipe;
always @ (posedge clk or negedge nrst_in)
if(!nrst_in)
sync_pipe[PS-1:0] <= 1'b0;
else
sync_pipe[PS-1:0] <= {sync_pipe[PS-2:0],1'b1};
assign nrst_out = sync_pipe[PS-1];
generate
if(ASIC)
begin : g0
asic_rsync asic_rsync (.clk(clk),
.nrst_in(nrst_in),
.nrst_out(nrst_out));
end
else
begin :g0
reg [PS-1:0] sync_pipe;
always @ (posedge clk or negedge nrst_in)
if(!nrst_in)
sync_pipe[PS-1:0] <= 1'b0;
else
sync_pipe[PS-1:0] <= {sync_pipe[PS-2:0],1'b1};
assign nrst_out = sync_pipe[PS-1];
end
endgenerate
endmodule // oh_rsync

View File

@ -6,19 +6,17 @@
//#############################################################################
module oh_ser2par #(parameter PW = 64, // parallel packet width
parameter SW = 1 // serial packet width
parameter SW = 1, // serial packet width
parameter CW = $clog2(PW/SW) // serialization factor (for counter)
)
(
input clk, // sampling clock
input [SW-1:0] din, // serial data
output [PW-1:0] dout, // parallel data
input lsbfirst, // lsb first order
input shift // shift the shifter
input clk, // sampling clock
input [SW-1:0] din, // serial data
output reg [PW-1:0] dout, // parallel data
input lsbfirst, // lsb first order
input shift // shift the shifter
);
parameter CW = $clog2(PW/SW); // serialization factor (for counter)
reg [PW-1:0] dout;
reg [CW-1:0] count;
wire [PW-1:0] shiftdata;

View File

@ -5,40 +5,51 @@
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module oh_standby #( parameter PD = 5) //cycles to stay awake after "wakeup"
module oh_standby #( parameter PD = 5, // cycles to stay awake after "wakeup"
parameter ASIC = 1, // use ASIC lib
parameter N = 5, // number of wake up signals
parameter PROJ = "") // project name
(
input clkin, //clock input
input nreset, //sync reset
input wakeup, //wake up now!
input idle, //core is in idle
output clkout //clock output
input clkin, //clock input
input nreset,//async active low reset
input [N-1:0] wakeup, //wake up event vector
input idle, //core is in idle
output clkout //clock output
);
//Wire declarations
reg [PD-1:0] wakeup_pipe;
reg idle_reg;
wire state_change;
wire clk_en;
wire [N-1:0] wakeup_pulse;
wire wakeup_now;
// detect an idle state change (wake up on any)
always @ (posedge clk )
idle_reg <= idle;
assign state_change = (idle ^ idle_reg);
// Wake up on any external event change
oh_edge2pulse #(.DW(N))
oh_edge2pulse (.out (wakeup_pulse[N-1:0]),
.clk (clkin),
.nreset (nreset),
.in (wakeup[N-1:0]));
always @ (posedge clk)
wakeup_pipe[PD-1:0] <= {wakeup_pipe[PD-2:0],(state_change | wakeup)};
assign wakeup_now = |(wakeup_pulse[N-1:0]);
//block enable signal
assign clk_en = ~nreset | //always on during reset
wakeup | //immediate wakeup
state_change | //incoming transition
// Stay away for PD cycles
always @ (posedge clkin)
wakeup_pipe[PD-1:0] <= {wakeup_pipe[PD-2:0], wakeup_now};
// Clock enable
assign clk_en = wakeup_now | //immediate wakeup
(|wakeup_pipe[PD-1:0]) | //anything in pipe
~idle; //core not in idle
//clock gater (technology specific)
oh_clockgate clockgate (.eclk(clkout),
.clk(clk),
.en(clk_en),
.nrst(nreset),
.se(1'b0));
// Clock gating cell
oh_clockgate #(.PROJ(PROJ),
.ASIC(ASIC))
oh_clockgate (.eclk(clkout),
.clk(clkin),
.en(clk_en),
.te(1'b0));
endmodule // oh_standby

View File

@ -0,0 +1,26 @@
//#############################################################################
//# Function: Bidirectional port with output-enable #
//#############################################################################
//# Author: Ola Jeppsson #
//# SPDX-License-Identifier: MIT #
//#############################################################################
module oh_tristate #(parameter N = 1) // width of port
(
inout [N-1:0] io, // bidirectional port
input [N-1:0] oe, // output enable (1 = output, 0 = input)
output [N-1:0] in, // port as input
input [N-1:0] out // port as output
);
assign in[N-1:0] = io[N-1:0];
genvar i;
generate
for (i = 0; i < N; i = i + 1)
begin : gen_oh_tristate
assign io[i] = oe[i] ? out[i] : 1'bZ;
end
endgenerate
endmodule // oh_tristate

View File

@ -4,57 +4,38 @@
//# Author: Andreas Olofsson #
//# License: MIT (see below) #
//#############################################################################
module edma (/*AUTOARG*/
// Outputs
irq, wait_out, access_out, packet_out, reg_wait_out,
reg_access_out, reg_packet_out,
// Inputs
vdd, vss, clk, nreset, access_in, packet_in, wait_in,
reg_access_in, reg_packet_in, reg_wait_in
);
//#####################################################################
//# INTERFACE
//#####################################################################
//parameters
parameter AW = 32; // address width
localparam PW = 2*AW+40; // emesh packet width
// power
input vdd; // supply
input vss; // common ground
// reset, clk, config
input clk; // main core clock
input nreset; // async active low reset
output irq; // interrupt output
// datapath interface
input access_in; // streaming input access
input [PW-1:0] packet_in; // streaming input data
output wait_out; // pushback
output access_out; // output access (master/slave)
output [PW-1:0] packet_out; // output packet (with address)
input wait_in; // pushback
// config/fetch interface
input reg_access_in; // config register access
input [PW-1:0] reg_packet_in; // config register packet
output reg_wait_out; // pushback by register read
output reg_access_out;// config readback
output [PW-1:0] reg_packet_out;// config reacback packet
input reg_wait_in; // pushback for readback
//#####################################################################
//# BODY
//#####################################################################
module edma #( parameter AW = 32, // address width
parameter PW = 104 // packet width
)
(
// power
input vdd, // supply
input vss, // common ground
// reset, clk, config
input clk, // main core clock
input nreset, // async active low reset
output irq, // interrupt output
// datapath interface
input access_in, // streaming input access
input [PW-1:0] packet_in, // streaming input data
output wait_out, // pushback
output access_out, // output access (master/slave)
output [PW-1:0] packet_out, // output packet (with address)
input wait_in, // pushback
// config/fetch interface
input reg_access_in, // config register access
input [PW-1:0] reg_packet_in, // config register packet
output reg_wait_out, // pushback by register read
output reg_access_out,// config readback
output [PW-1:0] reg_packet_out,// config reacback packet
input reg_wait_in // pushback for readback
);
//###############
//# LOCAL WIRES
//###############
/*AUTOOUTPUT*/
/*AUTOINPUT*/
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire chainmode; // From edma_regs of edma_regs.v
@ -84,7 +65,8 @@ module edma (/*AUTOARG*/
//# DATAPATH
//##########################
edma_dp #(.AW(AW))
edma_dp #(.AW(AW),
.PW(PW))
edma_dp(/*AUTOINST*/
// Outputs
.count (count[31:0]),
@ -112,7 +94,8 @@ module edma (/*AUTOARG*/
//# CONFIG REGISTERS
//##########################
edma_regs #(.AW(AW))
edma_regs #(.AW(AW),
.PW(PW))
edma_regs (/*AUTOINST*/
// Outputs
.reg_wait_out (reg_wait_out),
@ -149,7 +132,8 @@ module edma (/*AUTOARG*/
//# STATE MACHINE
//##########################
edma_ctrl #(.AW(AW))
edma_ctrl #(.AW(AW),
.PW(PW))
edma_ctrl (/*AUTOINST*/
// Outputs
.fetch_access (fetch_access),

View File

@ -16,7 +16,7 @@ module edma_ctrl (/*AUTOARG*/
);
parameter AW = 32; // address width
localparam PW = 2*AW+40; // fetch packet width
parameter PW = 2*AW+40; // fetch packet width
parameter ID = 4'b0000; // group id for DMA regs [10:8]
// clk, reset, config
@ -54,6 +54,9 @@ module edma_ctrl (/*AUTOARG*/
wire [15:0] fetch_addr;
wire [AW-1:0] srcaddr_out;
wire [4:0] reg_addr;
wire dma_error;
wire incount_zero;
wire outcount_zero;
//###########################################
//# STATE MACHINE
@ -167,7 +170,8 @@ module edma_ctrl (/*AUTOARG*/
2'b0}; //1-0
// constructing fetch packet
emesh2packet #(.AW(AW))
emesh2packet #(.AW(AW),
.PW(PW))
e2p (//outputs
.packet_out (fetch_packet[PW-1:0]),
//inputs

View File

@ -13,8 +13,8 @@ module edma_dp (/*AUTOARG*/
packet_in, wait_in
);
parameter AW = 8; // divider counter width
localparam PW = 2*AW+40; // emesh packet width
parameter AW = 8; // divider counter width
parameter PW = 2*AW+40; // emesh packet width
// clk, reset, config
input clk; // main clock
@ -99,7 +99,8 @@ module edma_dp (/*AUTOARG*/
//################################
// parsing input packet
packet2emesh #(.AW(AW))
packet2emesh #(.AW(AW),
.PW(PW))
p2e (/*AUTOINST*/
// Outputs
.write_in (write_in),
@ -121,7 +122,8 @@ module edma_dp (/*AUTOARG*/
assign srcaddr_out[AW-1:0] = master_active ? {(AW){1'b0}} : srcaddr_in[31:0];
// constructing output packet
emesh2packet #(.AW(AW))
emesh2packet #(.AW(AW),
.PW(PW))
e2p (.packet_out (packet[PW-1:0]),
/*AUTOINST*/
// Inputs

View File

@ -19,7 +19,7 @@ module edma_regs (/*AUTOARG*/
// parameters
parameter AW = 8; // address width
localparam PW = 2*AW+40; // emesh packet width
parameter PW = 2*AW+40; // emesh packet width
parameter DEF_CFG = 0; // default config after reset
// clk, reset
@ -79,12 +79,16 @@ module edma_regs (/*AUTOARG*/
reg [31:0] status_reg;
// wires
wire [4:0] ctrlmode_out;
wire [AW-1:0] data_out;
wire [1:0] datamode_out;
wire [AW-1:0] dstaddr_out;
wire [AW-1:0] srcaddr_out;
wire write_out;
wire reg_write;
wire config_write;
wire stride_write;
wire count_write;
wire srcaddr0_write;
wire srcaddr1_write;
wire dstaddr0_write;
wire dstaddr1_write;
wire status_write;
wire irqmode;
/*AUTOINPUT*/
/*AUTOWIRE*/
@ -101,7 +105,8 @@ module edma_regs (/*AUTOARG*/
//# DECODE
//################################
packet2emesh #(.AW(AW))
packet2emesh #(.AW(AW),
.PW(PW))
p2e (.packet_in (reg_packet_in[PW-1:0]),
/*AUTOINST*/
// Outputs

View File

@ -143,11 +143,10 @@ module etx_cfg (/*AUTOARG*/
//###########################
//Synchronize to make easy regular
oh_dsync #(.DW(16))
dsync (.dout (tx_status_sync[15:0]),
.clk (clk),
.nreset (1'b1),
.din (tx_status[15:0]));
oh_dsync isync[15:0] (.dout (tx_status_sync[15:0]),
.clk (clk),
.nreset (1'b1),
.din (tx_status[15:0]));
always @ (posedge clk)
if (tx_status_write)

View File

@ -1,37 +1,34 @@
module ememory(/*AUTOARG*/
// Outputs
wait_out, access_out, packet_out,
// Inputs
clk, nreset, coreid, access_in, packet_in, wait_in
);
module ememory # (parameter AW = 32, // address width
parameter PW = 104, // packet width
parameter IDW = 12, // ID width
parameter DEPTH = 65536, // memory depth
parameter NAME = "emem", // instance name
parameter WAIT = 0, // enable random wait
parameter MON = 0 // enable monitor monitor
)
parameter AW = 32;
parameter IDW = 12;
parameter DEPTH = 65536;
parameter MAW = $clog2(DEPTH);
parameter NAME = "emem";
parameter WAIT = 0; //turns on random wait circuit
parameter MON = 0; //turns on monitor
(// clk,reset
input clk,
input nreset,
input [IDW-1:0] coreid,
// incoming read/write
input access_in,
input [PW-1:0] packet_in,
output wait_out, //pushback
// back to mesh (readback data)
output reg access_out,
output [PW-1:0] packet_out,
input wait_in //pushback
);
//derived parameters
localparam DW = AW; //always the same
localparam PW = 2*AW+40;//packet width
localparam DW = AW; //always the same
parameter MAW = $clog2(DEPTH);
//Basic Interface
input clk;
input nreset;
input [IDW-1:0] coreid;
//incoming read/write
input access_in;
input [PW-1:0] packet_in;
output wait_out; //pushback
//back to mesh (readback data)
output access_out;
output [PW-1:0] packet_out;
input wait_in; //pushback
//###############
//# LOCAL WIRES
//##############
wire [MAW-1:0] addr;
wire [63:0] din;
@ -39,39 +36,40 @@ module ememory(/*AUTOARG*/
wire en;
wire mem_rd;
reg [7:0] wen;
//State
reg access_out;
reg write_out;
reg [1:0] datamode_out;
reg [4:0] ctrlmode_out;
reg [AW-1:0] dstaddr_out;
wire [AW-1:0] srcaddr_out;
wire [AW-1:0] data_out;
reg [2:0] align_addr;
wire write_in;
wire [1:0] datamode_in;
wire [4:0] ctrlmode_in;
wire [AW-1:0] dstaddr_in;
wire [DW-1:0] data_in;
wire [AW-1:0] srcaddr_in;
wire [DW-1:0] din_aligned;
wire [63:0] dout_aligned;
wire wait_random; //TODO: make random
wire wait_all;
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [4:0] ctrlmode_in; // From p2e of packet2emesh.v
wire [AW-1:0] data_in; // From p2e of packet2emesh.v
wire [1:0] datamode_in; // From p2e of packet2emesh.v
wire [AW-1:0] dstaddr_in; // From p2e of packet2emesh.v
wire [AW-1:0] srcaddr_in; // From p2e of packet2emesh.v
wire write_in; // From p2e of packet2emesh.v
// End of automatics
packet2emesh #(.AW(AW),
.PW(PW))
p2e (/*AUTOINST*/
// Outputs
.write_in (write_in),
.datamode_in (datamode_in[1:0]),
.ctrlmode_in (ctrlmode_in[4:0]),
.dstaddr_in (dstaddr_in[AW-1:0]),
.srcaddr_in (srcaddr_in[AW-1:0]),
.data_in (data_in[AW-1:0]),
// Inputs
.packet_in (packet_in[PW-1:0]));
packet2emesh #(.AW(AW))
p2e (
.write_in (write_in),
.datamode_in (datamode_in[1:0] ),
.ctrlmode_in (ctrlmode_in[4:0]),
.dstaddr_in (dstaddr_in[AW-1:0]),
.data_in (data_in[DW-1:0]),
.srcaddr_in (srcaddr_in[AW-1:0]),
.packet_in (packet_in[PW-1:0])
);
//Access-in
assign en = access_in & ~wait_all & ~wait_all;
@ -178,7 +176,8 @@ module ememory(/*AUTOARG*/
assign data_out[31:0] = dout_aligned[31:0];
//Concatenate
emesh2packet #(.AW(AW))
emesh2packet #(.AW(AW),
.PW(PW))
e2p (
/*AUTOINST*/
// Outputs

View File

@ -1,71 +1,67 @@
/*
* ---- 32-BIT ADDRESS ----
* [1] write bit
* [2:1] datamode
* [6:3] ctrlmode
* [7] RESERVED
* [39:8] f0 = dstaddr(lo)
* [71:40] f1 = data (lo)
* [103:72] f2 = srcaddr(lo) / data (hi)
*
* ---- 64-BIT ADDRESS ----
* [0] write bit
* [2:1] datamode
* [7:3] ctrlmode
* [39:8] f0 = dstaddr(lo)
* [71:40] f1 = D0
* [103:72] f2 = D1 | srcaddr(lo)
* [135:104] f3 = D2 | srcaddr(hi)
* [167:136] f4 = D3 | dstaddr(hi)
*
*/
module emesh2packet(/*AUTOARG*/
// Outputs
packet_out,
// Inputs
write_out, datamode_out, ctrlmode_out, dstaddr_out, data_out,
srcaddr_out
);
parameter AW = 32;
parameter PW = 2*AW+40;
//#############################################################################
//# Function: Maps Emesh Signals to Packet #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module emesh2packet #(parameter AW = 32, // address width
parameter PW = 104) // packet width
(
//Emesh signal bundle
input write_out,
input [1:0] datamode_out,
input [4:0] ctrlmode_out,
input [AW-1:0] dstaddr_out,
input [AW-1:0] data_out,
input [AW-1:0] srcaddr_out,
//Output packet
output [PW-1:0] packet_out
);
//Emesh signal bundle
input write_out;
input [1:0] datamode_out;
input [4:0] ctrlmode_out;
input [AW-1:0] dstaddr_out;
input [AW-1:0] data_out;
input [AW-1:0] srcaddr_out;
//Output packet
output [PW-1:0] packet_out;
// ---- FORMAT -----
//
// [0] =write bit
// [2:1]=datamode
// [7:3]=ctrlmode
// [39:8]=dstaddr(lo)
//
// ---- 32-BIT ADDRESS ----
// [71:40] data (lo) | xxxx
// [103:72] srcaddr(lo) | data (hi)
//
// ---- 64-BIT ADDRESS ----
// [71:40] D0 | srcaddr(hi)
// [103:72] D1 | srcaddr(lo)
// [135:104] dstaddr(hi)
assign packet_out[0] = write_out;
assign packet_out[2:1] = datamode_out[1:0];
assign packet_out[7:3] = ctrlmode_out[4:0];
generate
if(AW==64)
begin : packet64
if(PW==136)
begin : p136
assign packet_out[39:8] = dstaddr_out[31:0];
assign packet_out[71:40] = data_out[31:0];
assign packet_out[103:72] = srcaddr_out[31:0];
assign packet_out[135:104] = srcaddr_out[63:32];
assign packet_out[167:136] = dstaddr_out[63:32];
assign packet_out[71:40] = data_out[31:0]; // | srcaddr_out[63:32]
assign packet_out[103:72] = srcaddr_out[31:0]; // (data_out[63:32])
assign packet_out[135:104] = dstaddr_out[63:32];
end
else if(AW==32)
begin : packet32
else if(PW==104)
begin : p104
assign packet_out[39:8] = dstaddr_out[31:0];
assign packet_out[71:40] = data_out[31:0];
assign packet_out[103:72] = srcaddr_out[31:0];
end
else if(AW==16)
begin : packet16
else if(PW==72)
begin : p72
assign packet_out[39:8] = dstaddr_out[31:0];
assign packet_out[71:40] = data_out[31:0];
end
else if(PW==40)
begin : p40
assign packet_out[23:8] = dstaddr_out[15:0];
assign packet_out[39:24] = data_out[15:0];
assign packet_out[55:40] = srcaddr_out[15:0];
end
endgenerate
endmodule // emesh2packet

View File

@ -4,8 +4,8 @@ module emesh_readback (/*AUTOARG*/
// Inputs
nreset, clk, access_in, packet_in, read_data, wait_in
);
parameter AW = 32; // address width
localparam PW = 2*AW+40; // packet width
parameter AW = 32; // address width
parameter PW = 104; // packet width
//clk, reset
input nreset; // asynchronous active low reset
@ -45,7 +45,8 @@ module emesh_readback (/*AUTOARG*/
//# Parse packet
//#######################################
packet2emesh #(.AW(AW))
packet2emesh #(.AW(AW),
.PW(PW))
p2e (/*AUTOINST*/
// Outputs
.write_in (write_in),
@ -87,7 +88,8 @@ module emesh_readback (/*AUTOARG*/
//# Convert to Packet
//#######################################
emesh2packet #(.AW(AW))
emesh2packet #(.AW(AW),
.PW(PW))
e2p (.write_out (1'b1),
/*AUTOINST*/
// Outputs

View File

@ -1,49 +1,42 @@
/*
* ---- 32-BIT ADDRESS ----
* [1] write bit
* [2:1] datamode
* [6:3] ctrlmode
* [7] RESERVED
* [39:8] f0 = dstaddr(lo)
* [71:40] f1 = data (lo)
* [103:72] f2 = srcaddr(lo) / data (hi)
*
* ---- 64-BIT ADDRESS ----
* [0] write bit
* [2:1] datamode
* [7:3] ctrlmode
* [39:8] f0 = dstaddr(lo)
* [71:40] f1 = D0
* [103:72] f2 = D1 | srcaddr(lo)
* [135:104] f3 = D2 | srcaddr(hi)
* [167:136] f4 = D3 | dstaddr(hi)
*
*/
module packet2emesh(/*AUTOARG*/
// Outputs
write_in, datamode_in, ctrlmode_in, dstaddr_in, srcaddr_in,
data_in,
// Inputs
packet_in
);
//#############################################################################
//# Function: Maps Packet to Emesh Signals #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module packet2emesh #(parameter AW = 32, // address width
parameter PW = 104) // packet width
(
//Input packet
input [PW-1:0] packet_in,
//Emesh signal bundle
output write_in, // write signal
output [1:0] datamode_in,// datasize
output [4:0] ctrlmode_in,// ctrlmode
output [AW-1:0] dstaddr_in, // read/write address
output [AW-1:0] srcaddr_in, // return address for reads
output [AW-1:0] data_in // data
);
parameter AW = 32;
parameter PW = (2*AW+40);
//Input packet
input [PW-1:0] packet_in;
//Emesh signal bundle
output write_in;
output [1:0] datamode_in;
output [4:0] ctrlmode_in;
output [AW-1:0] dstaddr_in;
output [AW-1:0] srcaddr_in;
output [AW-1:0] data_in;
// ---- FORMAT -----
//
// [0] =write bit
// [2:1]=datamode
// [7:3]=ctrlmode
// [39:8]=dstaddr(lo)
//
// ---- 32-BIT ADDRESS ----
// [71:40] data (lo) | xxxx
// [103:72] srcaddr(lo) | data (hi)
//
// ---- 64-BIT ADDRESS ----
// [71:40] D0 | srcaddr(hi)
// [103:72] D1 | srcaddr(lo)
// [135:104] dstaddr(hi)
generate
if(AW==32)
begin : packet32
if(PW==104)
begin : p104
assign write_in = packet_in[0];
assign datamode_in[1:0] = packet_in[2:1];
assign ctrlmode_in[4:0] = {1'b0,packet_in[6:3]};
@ -51,15 +44,31 @@ module packet2emesh(/*AUTOARG*/
assign srcaddr_in[31:0] = packet_in[103:72];
assign data_in[31:0] = packet_in[71:40];
end
else if(AW==64)
begin : packet64
else if(PW==136)
begin : p136
assign write_in = packet_in[0];
assign datamode_in[1:0] = packet_in[2:1];
assign ctrlmode_in[4:0] = packet_in[7:3];
assign dstaddr_in[63:0] = {packet_in[167:135],packet_in[39:8]};
assign srcaddr_in[63:0] = packet_in[135:72];
assign dstaddr_in[63:0] = {packet_in[135:104],packet_in[39:8]};
assign srcaddr_in[63:0] = {packet_in[71:40],packet_in[135:72]};
assign data_in[63:0] = packet_in[103:40];
end
else if(PW==72)
begin : p72
assign write_in = packet_in[0];
assign datamode_in[1:0] = packet_in[2:1];
assign ctrlmode_in[4:0] = packet_in[7:3];
assign dstaddr_in[31:0] = packet_in[39:8];
assign data_in[31:0] = packet_in[71:40];
end
else if(PW==40)
begin : p40
assign write_in = packet_in[0];
assign datamode_in[1:0] = packet_in[2:1];
assign ctrlmode_in[4:0] = packet_in[7:3];
assign dstaddr_in[15:0] = packet_in[23:8];
assign data_in[15:0] = packet_in[39:24];
end
else
begin : unknown
`ifdef TARGET_SIM

View File

@ -164,14 +164,11 @@ module etrace (/*AUTOARG*/
//# SYNC CFG SIGNALS TO SAMPLE CLK
//#################################
dsync #(.DW(1))
dsync(// Outputs
.dout (trace_enable),
// Inputs
.clk (trace_clk),
.din (mi_trace_enable)
);
dsync dsync(// Outputs
.dout (trace_enable),
// Inputs
.clk (trace_clk),
.din (mi_trace_enable));
//###########################
//# TIME KEEPER

View File

@ -19,7 +19,7 @@ GPIO: General Purpose Software Programmable IO
| GPIO_OUTSET | 0x4 | WR | n/a | Output = output "or" value |
| GPIO_OUTXOR | 0x5 | WR | n/a | Output = output ^ value |
| GPIO_IMASK | 0x6 | WR | H | Interrupt mask (1=mask) |
| GPIO_ITYPE | 0x7 | WR | n/a | IRQ type (1=edge,0=level) |
| GPIO_ITYPE | 0x7 | WR | n/a | IRQ type (0=edge,1=level) |
| GPIO_IPOL | 0x8 | WR | H | IRQ polarity (1=rising edge/high)|
| GPIO_ILAT | 0x9 | RD | L | IRQ Status (1=latched irq) |
| GPIO_ILATCLR | 0xA | WR | n/a | Clears ILAT(1=clear) |

View File

@ -0,0 +1,35 @@
OH GPIO controller bindings
Required properties:
- compatible: "oh,gpio"
- reg: Address and length of the register set for the device
- interrupt-parent: phandle of the parent interrupt controller.
- interrupts : Should be the port interrupt shared by all 32 pins.
- gpio-controller : Marks the device node as a GPIO controller.
- #gpio-cells : Should be two.
- first cell is the pin number
- second cell is used to specify optional parameters (unused)
- interrupt-controller: Mark the device node as an interrupt controller.
- #interrupt-cells : Should be 2.
The first cell is the GPIO number.
The second cell is used to specify flags:
bits[3:0] trigger type and level flags:
1 = rising edge triggered.
2 = falling edge triggered.
4 = active high level-sensitive.
8 = active low level-sensitive.
- ngpios: number of GPIOs this controller has
Example:
gpio0: gpio0 {
compatible = "oh,gpio";
reg = <0xe000a000 0x1000>;
interrupt-parent = <&intc>;
interrupts = <57>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
ngpios = <24>;
};

View File

@ -0,0 +1 @@
obj-m := gpio-oh.o

View File

@ -0,0 +1,14 @@
ifneq ($(KERNELRELEASE),)
# kbuild part of makefile
obj-y := gpio-oh.o
else
# normal makefile
KDIR ?= /lib/modules/`uname -r`/build
default:
$(MAKE) -C $(KDIR) M=$$PWD
clean:
rm -fr gpio-oh.mod.c *.o *.ko .*.cmd modules.order Module.symvers .tmp_versions
endif

View File

@ -0,0 +1,28 @@
# OH GPIO Linux Kernel driver
## Compilation
### Against system kernel sources
```
make
```
### Custom source path
```
make KDIR=path/to/src/linux
```
### Cross compiling (example w/ custom build-dir)
```
make -C path/to/built/linux-builddir \
M=`pwd` \
ARCH=arm \
CROSS_COMPILE=arm-linux-gnueabihf- \
LOADADDR=0x8000
```
For more flags etc, see:
https://www.kernel.org/doc/Documentation/kbuild/modules.txt

View File

@ -0,0 +1,503 @@
/*
* Open Hardware GPIO device driver
*
* Copyright (C) 2016 Parallella Foundation
* Written by Ola Jeppsson <ola@adapteva.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* The full GNU General Public License is included in this distribution in the
* file called COPYING.
*/
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/spinlock.h>
#define DRIVERNAME "oh-gpio"
#define OH_GPIO_MAX_NR_GPIOS 64
#define OH_GPIO_DIR 0x00 /* set direction of pin */
#define OH_GPIO_IN 0x08 /* input data (read only) */
#define OH_GPIO_OUT 0x10 /* output data (write only) */
#define OH_GPIO_OUTCLR 0x18 /* alias, clears specific bits in GPIO_OUT */
#define OH_GPIO_OUTSET 0x20 /* alias, sets specific bits in GPIO_OUT */
#define OH_GPIO_OUTXOR 0x28 /* alias, toggles specific bits in GPIO_OUT */
#define OH_GPIO_IMASK 0x30 /* interrupt mask */
#define OH_GPIO_ITYPE 0x38 /* interrupt type (edge=0/level=1) */
#define OH_GPIO_IPOL 0x40 /* interrupt polarity (hi/rising / low/falling) */
#define OH_GPIO_ILAT 0x48 /* latched interrupts (read only) */
#define OH_GPIO_ILATCLR 0x50 /* clear an interrupt */
struct oh_gpio {
void __iomem *base_addr;
struct gpio_chip chip;
spinlock_t lock;
};
static struct oh_gpio *to_oh_gpio(struct gpio_chip *gpio)
{
return container_of(gpio, struct oh_gpio, chip);
}
#ifdef writeq
#define oh_gpio_writeq writeq
#else
static inline void oh_gpio_writeq(u64 value, void __iomem *addr)
{
writel((u32) (value & 0xffffffff), addr);
writel((u32) (value >> 32), (u8 __iomem *) addr + 4);
}
#endif
#ifdef readq
#define oh_gpio_readq readq
#else
static inline u64 oh_gpio_readq(void __iomem *addr)
{
u64 lo, hi;
lo = readl(addr);
hi = readl((u8 __iomem *) addr + 4);
return (hi << 32 | lo);
}
#endif
static inline void oh_gpio_reg_write(u64 value, struct oh_gpio *gpio,
unsigned long offset)
{
if (gpio->chip.ngpio > 32)
oh_gpio_writeq(value, (u8 __iomem *) gpio->base_addr + offset);
else
writel((u32) value, (u8 __iomem *) gpio->base_addr + offset);
}
static inline u64 oh_gpio_reg_read(struct oh_gpio *gpio, unsigned long offset)
{
if (gpio->chip.ngpio > 32)
return oh_gpio_readq((u8 __iomem *) gpio->base_addr + offset);
else
return (u64) readl((u8 __iomem *) gpio->base_addr + offset);
}
/**
* oh_gpio_get_value - Get value of the specified pin
* @chip: gpio chip device
* @pin: gpio pin number
*
* Return: 0 if the pin is low, 1 if pin is high.
*/
static int oh_gpio_get_value(struct gpio_chip *chip, unsigned pin)
{
u64 data;
unsigned long flags;
struct oh_gpio *gpio = to_oh_gpio(chip);
spin_lock_irqsave(&gpio->lock, flags);
data = oh_gpio_reg_read(gpio, OH_GPIO_IN);
spin_unlock_irqrestore(&gpio->lock, flags);
return (data >> pin) & 1;
}
/**
* oh_gpio_set_value - Assign output value for pin
* @chip: gpio chip device
* @pin: gpio pin number
* @value: value used to modify the state of the specified pin
*/
static void oh_gpio_set_value(struct gpio_chip *chip, unsigned pin, int value)
{
u64 mask;
unsigned long flags;
struct oh_gpio *gpio = to_oh_gpio(chip);
mask = BIT_ULL(pin);
spin_lock_irqsave(&gpio->lock, flags);
if (value)
oh_gpio_reg_write(mask, gpio, OH_GPIO_OUTSET);
else
oh_gpio_reg_write(mask, gpio, OH_GPIO_OUTCLR);
spin_unlock_irqrestore(&gpio->lock, flags);
}
/**
* oh_gpio_get_direction - Get direction of pin
* @chip: gpio chip device
* @pin: gpio pin number
*
* Return: direction of pin, 0=out, 1=in
*/
static int oh_gpio_get_direction(struct gpio_chip *chip, unsigned pin)
{
u64 dir;
unsigned long flags;
struct oh_gpio *gpio = to_oh_gpio(chip);
spin_lock_irqsave(&gpio->lock, flags);
dir = oh_gpio_reg_read(gpio, OH_GPIO_DIR);
spin_unlock_irqrestore(&gpio->lock, flags);
return !((dir >> pin) & 1);
}
/**
* oh_gpio_direction_in - Set the direction of the specified GPIO pin as input
* @chip: gpio chip device
* @pin: gpio pin number
*
* Return: 0 always
*/
static int oh_gpio_direction_in(struct gpio_chip *chip, unsigned pin)
{
u64 mask, dir;
unsigned long flags;
struct oh_gpio *gpio = to_oh_gpio(chip);
mask = BIT_ULL(pin);
spin_lock_irqsave(&gpio->lock, flags);
dir = oh_gpio_reg_read(gpio, OH_GPIO_DIR);
dir &= ~mask;
oh_gpio_reg_write(dir, gpio, OH_GPIO_DIR);
spin_unlock_irqrestore(&gpio->lock, flags);
return 0;
}
/**
* oh_gpio_direction_out - Set the direction of the specified GPIO pin as output
* @chip: gpio chip device
* @pin: gpio pin number
* @value: value to be written to pin
*
* This function sets the direction of specified GPIO pin as output, and uses
* oh_gpio_set to set the specified pin value.
*
* Return: 0 always
*/
static int oh_gpio_direction_out(struct gpio_chip *chip, unsigned pin,
int value)
{
u64 mask, dir;
unsigned long flags;
struct oh_gpio *gpio = to_oh_gpio(chip);
mask = BIT_ULL(pin);
spin_lock_irqsave(&gpio->lock, flags);
dir = oh_gpio_reg_read(gpio, OH_GPIO_DIR);
dir |= mask;
oh_gpio_reg_write(dir, gpio, OH_GPIO_DIR);
spin_unlock_irqrestore(&gpio->lock, flags);
oh_gpio_set_value(chip, pin, value);
return 0;
}
/**
* oh_gpio_irq_mask - Disable interrupts for a gpio pin
* @irq_data: per irq and chip data passed down to chip functions
*
*/
static void oh_gpio_irq_mask(struct irq_data *irq_data)
{
u64 imask;
unsigned long flags;
unsigned pin;
struct oh_gpio *gpio = to_oh_gpio(irq_data_get_irq_chip_data(irq_data));
pin = irq_data->hwirq;
spin_lock_irqsave(&gpio->lock, flags);
imask = oh_gpio_reg_read(gpio, OH_GPIO_IMASK);
imask |= BIT_ULL(pin);
oh_gpio_reg_write(imask, gpio, OH_GPIO_IMASK);
spin_unlock_irqrestore(&gpio->lock, flags);
}
/**
* oh_gpio_irq_unmask - Enable interrupts for a gpio pin
* @irq_data: irq data containing irq number of gpio pin for the interrupt
* to enable
*/
static void oh_gpio_irq_unmask(struct irq_data *irq_data)
{
u64 imask;
unsigned long flags;
unsigned pin;
struct oh_gpio *gpio = to_oh_gpio(irq_data_get_irq_chip_data(irq_data));
pin = irq_data->hwirq;
spin_lock_irqsave(&gpio->lock, flags);
imask = oh_gpio_reg_read(gpio, OH_GPIO_IMASK);
imask &= ~BIT_ULL(pin);
oh_gpio_reg_write(imask, gpio, OH_GPIO_IMASK);
spin_unlock_irqrestore(&gpio->lock, flags);
}
/**
* oh_gpio_irq_ack - Clear interrupt latch of a gpio pin
* @irq_data: irq data containing irq number of gpio pin for the interrupt
* to clear
*/
static void oh_gpio_irq_ack(struct irq_data *irq_data)
{
unsigned long flags;
unsigned pin;
struct oh_gpio *gpio = to_oh_gpio(irq_data_get_irq_chip_data(irq_data));
pin = irq_data->hwirq;
spin_lock_irqsave(&gpio->lock, flags);
oh_gpio_reg_write(BIT_ULL(pin), gpio, OH_GPIO_ILATCLR);
spin_unlock_irqrestore(&gpio->lock, flags);
}
/**
* oh_gpio_irq_set_type - Set the irq type for a gpio pin
* @irq_data: irq data containing irq number of gpio pin
* @type: interrupt type that is to be set for the gpio pin
*
* Return: 0 on success, negative on error.
*/
static int oh_gpio_irq_set_type(struct irq_data *irq_data, unsigned type)
{
u64 itype, ipol, mask;
unsigned pin;
unsigned long flags;
irq_flow_handler_t handler;
struct oh_gpio *gpio = to_oh_gpio(irq_data_get_irq_chip_data(irq_data));
pin = irq_data->hwirq;
mask = BIT_ULL(pin);
spin_lock_irqsave(&gpio->lock, flags);
itype = oh_gpio_reg_read(gpio, OH_GPIO_ITYPE);
ipol = oh_gpio_reg_read(gpio, OH_GPIO_IPOL);
switch (type) {
case IRQ_TYPE_EDGE_RISING:
itype &= ~mask;
ipol |= mask;
break;
case IRQ_TYPE_EDGE_FALLING:
itype &= ~mask;
ipol &= ~mask;
break;
case IRQ_TYPE_LEVEL_HIGH:
itype |= mask;
ipol |= mask;
break;
case IRQ_TYPE_LEVEL_LOW:
itype |= mask;
ipol &= ~mask;
break;
default:
spin_unlock_irqrestore(&gpio->lock, flags);
return -EINVAL;
}
oh_gpio_reg_write(itype, gpio, OH_GPIO_ITYPE);
oh_gpio_reg_write(ipol, gpio, OH_GPIO_IPOL);
spin_unlock_irqrestore(&gpio->lock, flags);
handler = type & IRQ_TYPE_LEVEL_MASK ? handle_level_irq
: handle_edge_irq;
irq_set_handler_locked(irq_data, handler);
return 0;
}
static struct irq_chip oh_gpio_irqchip = {
.name = DRIVERNAME,
.irq_ack = oh_gpio_irq_ack,
.irq_mask = oh_gpio_irq_mask,
.irq_unmask = oh_gpio_irq_unmask,
.irq_set_type = oh_gpio_irq_set_type,
};
/**
* oh_gpio_irq_handler - IRQ handler
* @irq: oh_gpio irq number
* @devid: pointer to oh_gpio struct
*
* Reads the interrupt latch register register to get the gpio pin number(s)
* that have pending interrupts. It then calls the generic irq handlers for
* those pins irqs.
*
* Return: IRQ_HANDLED if any interrupts were handled, IRQ_NONE otherwise.
*/
static irqreturn_t oh_gpio_irq_handler(int irq, void *dev_id)
{
u64 ilat;
unsigned long flags, ilat_lo, ilat_hi;
int offset;
struct oh_gpio *gpio = dev_id;
struct irq_domain *irqdomain = gpio->chip.irqdomain;
spin_lock_irqsave(&gpio->lock, flags);
ilat = oh_gpio_reg_read(gpio, OH_GPIO_ILAT);
spin_unlock_irqrestore(&gpio->lock, flags);
if (!ilat)
return IRQ_NONE;
/* No generic 64-bit for_each_set_bit. Need to split in high/low */
ilat_lo = (unsigned long) ((ilat >> 0) & 0xffffffff);
ilat_hi = (unsigned long) ((ilat >> 32) & 0xffffffff);
for_each_set_bit(offset, &ilat_lo, 32)
generic_handle_irq(irq_find_mapping(irqdomain, offset));
for_each_set_bit(offset, &ilat_hi, 32)
generic_handle_irq(irq_find_mapping(irqdomain, 32 + offset));
return IRQ_HANDLED;
}
static const struct of_device_id oh_gpio_of_match[] = {
{ .compatible = "oh,gpio" },
{ }
};
MODULE_DEVICE_TABLE(of, oh_gpio_of_match);
/**
* oh_gpio_probe - Platform probe for a oh_gpio device
* @pdev: platform device
*
* Note: All interrupts are cleared + masked after function exits.
*
* Return: 0 on success, negative error otherwise.
*/
static int oh_gpio_probe(struct platform_device *pdev)
{
int ret, irq;
u32 ngpios;
struct oh_gpio *gpio;
struct gpio_chip *chip;
struct resource *res;
struct device_node *np = pdev->dev.of_node;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
return -ENOMEM;
platform_set_drvdata(pdev, gpio);
ret = of_property_read_u32(np, "ngpios", &ngpios);
if (ret == -ENOENT) {
dev_info(&pdev->dev,
"ngpios property missing, defaulting to %u\n",
OH_GPIO_MAX_NR_GPIOS);
ngpios = OH_GPIO_MAX_NR_GPIOS;
} else if (ret) {
dev_err(&pdev->dev, "ngpios property is not valid\n");
return ret;
}
if (ngpios > OH_GPIO_MAX_NR_GPIOS) {
dev_err(&pdev->dev,
"ngpios property is %u, max allowed is %u\n",
(unsigned) ngpios, OH_GPIO_MAX_NR_GPIOS);
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gpio->base_addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(gpio->base_addr))
return PTR_ERR(gpio->base_addr);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "invalid IRQ\n");
return irq;
}
ret = devm_request_irq(&pdev->dev, irq, oh_gpio_irq_handler, 0,
dev_name(&pdev->dev), gpio);
if (ret) {
dev_err(&pdev->dev, "could not request IRQ\n");
return ret;
}
spin_lock_init(&gpio->lock);
/* configure the gpio chip */
chip = &gpio->chip;
chip->label = "oh_gpio";
chip->owner = THIS_MODULE;
chip->dev = &pdev->dev;
chip->base = -1;
chip->ngpio = (u16) ngpios;
chip->get = oh_gpio_get_value;
chip->set = oh_gpio_set_value;
chip->get_direction = oh_gpio_get_direction;
chip->direction_input = oh_gpio_direction_in;
chip->direction_output = oh_gpio_direction_out;
/* mask / clear all interrupts */
oh_gpio_reg_write(~0ULL, gpio, OH_GPIO_IMASK);
oh_gpio_reg_write(~0ULL, gpio, OH_GPIO_ILATCLR);
/* register gpio chip */
ret = gpiochip_add(chip);
if (ret) {
dev_err(&pdev->dev, "failed to add gpio chip\n");
return ret;
}
ret = gpiochip_irqchip_add(chip, &oh_gpio_irqchip, 0,
handle_level_irq, IRQ_TYPE_NONE);
if (ret) {
dev_err(&pdev->dev, "failed to add irq chip\n");
gpiochip_remove(chip);
return ret;
}
return 0;
}
/**
* oh_gpio_remove - Driver removal function
* @pdev: platform device
*
* Return: 0 always
*/
static int oh_gpio_remove(struct platform_device *pdev)
{
struct oh_gpio *gpio = platform_get_drvdata(pdev);
gpiochip_remove(&gpio->chip);
return 0;
}
static struct platform_driver oh_gpio_driver = {
.driver = {
.name = DRIVERNAME,
.of_match_table = oh_gpio_of_match,
},
.probe = oh_gpio_probe,
.remove = oh_gpio_remove,
};
module_platform_driver(oh_gpio_driver);
MODULE_AUTHOR("Ola Jeppsson <ola@adapteva.com>");
MODULE_DESCRIPTION("OH GPIO driver");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,6 @@
the_ROM_image:
{
[bootloader]dummy.elf
./system.runs/impl_1/system_wrapper.bit
}

15
src/gpio/fpga/build.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
#clean up
rm system_wrapper.bit.bin bit2bin.bin
#package IP
vivado -mode batch -source package.tcl
#create bit stream
vivado -mode batch -source run.tcl
#xilinx stuff...
bootgen -image bit2bin.bif -split bin
cp system_wrapper.bit.bin parallella.bit.bin

BIN
src/gpio/fpga/dummy.elf Normal file

Binary file not shown.

View File

@ -0,0 +1,23 @@
# NOTE: See UG1118 for more information
set design parallella_gpio
set projdir ./
set root "../.."
set partname "xc7z020clg400-1"
set hdl_files [list \
$root/gpio/hdl \
$root/common/hdl/ \
$root/emesh/hdl \
$root/emmu/hdl \
$root/axi/hdl \
$root/emailbox/hdl \
$root/edma/hdl \
$root/elink/hdl \
$root/parallella/hdl \
]
set ip_files []
set constraints_files []

View File

@ -0,0 +1,3 @@
#STEP1: DEFINE KEY PARAMETERS
source ./ip_params.tcl
source ../../common/fpga/create_ip.tcl

12
src/gpio/fpga/run.tcl Normal file
View File

@ -0,0 +1,12 @@
#STEP1: DEFINE KEY PARAMETERS
source ./run_params.tcl
#STEP2: CREATE PROJECT AND READ IN FILES
source ../../common/fpga/system_init.tcl
#STEP 3 (OPTIONAL): EDIT system.bd in VIVADO gui, then go to STEP 4.
##...
#STEP 4: SYNTEHSIZE AND CREATE BITSTRAM
source ../../common/fpga/system_build.tcl

View File

@ -0,0 +1,22 @@
#Design name ("system" recommended)
set design system
#Project directory ("." recommended)
set projdir ./
#Device name
set partname "xc7z020clg400-1"
#Paths to all IP blocks to use in Vivado "system.bd"
set ip_repos [list "."]
#All source files
set hdl_files []
#All constraints files
set constraints_files [list \
../../parallella/fpga/parallella_io.xdc \
../../parallella/fpga/parallella_7020_io.xdc \
]

227
src/gpio/fpga/system_bd.tcl Normal file
View File

@ -0,0 +1,227 @@
################################################################
# This is a generated script based on design: system
#
# Though there are limitations about the generated script,
# the main purpose of this utility is to make learning
# IP Integrator Tcl commands easier.
################################################################
################################################################
# Check if script is running in correct Vivado version.
################################################################
set scripts_vivado_version 2015.2
set current_vivado_version [version -short]
if { [string first $scripts_vivado_version $current_vivado_version] == -1 } {
puts ""
puts "ERROR: This script was generated using Vivado <$scripts_vivado_version> and is being run in <$current_vivado_version> of Vivado. Please run the script in Vivado <$scripts_vivado_version> then open the design in Vivado <$current_vivado_version>. Upgrade the design by running \"Tools => Report => Report IP Status...\", then run write_bd_tcl to create an updated script."
return 1
}
################################################################
# START
################################################################
# To test this script, run the following commands from Vivado Tcl console:
# source system_script.tcl
# If you do not already have a project created,
# you can create a project using the following command:
# create_project project_1 myproj -part xc7z020clg400-1
# CHECKING IF PROJECT EXISTS
if { [get_projects -quiet] eq "" } {
puts "ERROR: Please open or create a project!"
return 1
}
# CHANGE DESIGN NAME HERE
set design_name system
# If you do not already have an existing IP Integrator design open,
# you can create a design using the following command:
# create_bd_design $design_name
# Creating design if needed
set errMsg ""
set nRet 0
set cur_design [current_bd_design -quiet]
set list_cells [get_bd_cells -quiet]
if { ${design_name} eq "" } {
# USE CASES:
# 1) Design_name not set
set errMsg "ERROR: Please set the variable <design_name> to a non-empty value."
set nRet 1
} elseif { ${cur_design} ne "" && ${list_cells} eq "" } {
# USE CASES:
# 2): Current design opened AND is empty AND names same.
# 3): Current design opened AND is empty AND names diff; design_name NOT in project.
# 4): Current design opened AND is empty AND names diff; design_name exists in project.
if { $cur_design ne $design_name } {
puts "INFO: Changing value of <design_name> from <$design_name> to <$cur_design> since current design is empty."
set design_name [get_property NAME $cur_design]
}
puts "INFO: Constructing design in IPI design <$cur_design>..."
} elseif { ${cur_design} ne "" && $list_cells ne "" && $cur_design eq $design_name } {
# USE CASES:
# 5) Current design opened AND has components AND same names.
set errMsg "ERROR: Design <$design_name> already exists in your project, please set the variable <design_name> to another value."
set nRet 1
} elseif { [get_files -quiet ${design_name}.bd] ne "" } {
# USE CASES:
# 6) Current opened design, has components, but diff names, design_name exists in project.
# 7) No opened design, design_name exists in project.
set errMsg "ERROR: Design <$design_name> already exists in your project, please set the variable <design_name> to another value."
set nRet 2
} else {
# USE CASES:
# 8) No opened design, design_name not in project.
# 9) Current opened design, has components, but diff names, design_name not in project.
puts "INFO: Currently there is no design <$design_name> in project, so creating one..."
create_bd_design $design_name
puts "INFO: Making design <$design_name> as current_bd_design."
current_bd_design $design_name
}
puts "INFO: Currently the variable <design_name> is equal to \"$design_name\"."
if { $nRet != 0 } {
puts $errMsg
return $nRet
}
##################################################################
# DESIGN PROCs
##################################################################
# Procedure to create entire design; Provide argument to make
# procedure reusable. If parentCell is "", will use root.
proc create_root_design { parentCell } {
if { $parentCell eq "" } {
set parentCell [get_bd_cells /]
}
# Get object for parentCell
set parentObj [get_bd_cells $parentCell]
if { $parentObj == "" } {
puts "ERROR: Unable to find parent cell <$parentCell>!"
return
}
# Make sure parentObj is hier blk
set parentType [get_property TYPE $parentObj]
if { $parentType ne "hier" } {
puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be <hier>."
return
}
# Save current instance; Restore later
set oldCurInst [current_bd_instance .]
# Set parent object as current
current_bd_instance $parentObj
# Create interface ports
# Create ports
set gpio_n [ create_bd_port -dir IO -from 23 -to 0 gpio_n ]
set gpio_p [ create_bd_port -dir IO -from 23 -to 0 gpio_p ]
# Create instance: parallella_gpio_0, and set properties
set parallella_gpio_0 [ create_bd_cell -type ip -vlnv www.parallella.org:user:parallella_gpio:1.0 parallella_gpio_0 ]
# Create instance: proc_sys_reset_0, and set properties
set proc_sys_reset_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 proc_sys_reset_0 ]
# Create instance: processing_system7_0, and set properties
set processing_system7_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 processing_system7_0 ]
set_property -dict [ list CONFIG.PCW_CORE0_FIQ_INTR {0} \
CONFIG.PCW_ENET0_ENET0_IO {MIO 16 .. 27} CONFIG.PCW_ENET0_GRP_MDIO_ENABLE {1} \
CONFIG.PCW_ENET0_PERIPHERAL_ENABLE {1} CONFIG.PCW_ENET1_PERIPHERAL_ENABLE {0} \
CONFIG.PCW_EN_CLK3_PORT {1} CONFIG.PCW_FPGA0_PERIPHERAL_FREQMHZ {100} \
CONFIG.PCW_FPGA3_PERIPHERAL_FREQMHZ {100} CONFIG.PCW_GPIO_EMIO_GPIO_ENABLE {1} \
CONFIG.PCW_GPIO_MIO_GPIO_ENABLE {1} CONFIG.PCW_GPIO_MIO_GPIO_IO {MIO} \
CONFIG.PCW_I2C0_I2C0_IO {EMIO} CONFIG.PCW_I2C0_PERIPHERAL_ENABLE {1} \
CONFIG.PCW_I2C0_RESET_ENABLE {0} CONFIG.PCW_IRQ_F2P_INTR {1} \
CONFIG.PCW_IRQ_F2P_MODE {DIRECT} CONFIG.PCW_PRESET_BANK1_VOLTAGE {LVCMOS 1.8V} \
CONFIG.PCW_QSPI_GRP_SINGLE_SS_ENABLE {1} CONFIG.PCW_QSPI_PERIPHERAL_ENABLE {1} \
CONFIG.PCW_SD1_PERIPHERAL_ENABLE {1} CONFIG.PCW_SD1_SD1_IO {MIO 10 .. 15} \
CONFIG.PCW_SDIO_PERIPHERAL_FREQMHZ {50} CONFIG.PCW_UART1_PERIPHERAL_ENABLE {1} \
CONFIG.PCW_UART1_UART1_IO {MIO 8 .. 9} CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY0 {0.434} \
CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY1 {0.398} CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY2 {0.410} \
CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY3 {0.455} CONFIG.PCW_UIPARAM_DDR_CL {9} \
CONFIG.PCW_UIPARAM_DDR_CWL {9} CONFIG.PCW_UIPARAM_DDR_DEVICE_CAPACITY {8192 MBits} \
CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_0 {0.315} CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_1 {0.391} \
CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_2 {0.374} CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_3 {0.271} \
CONFIG.PCW_UIPARAM_DDR_DRAM_WIDTH {32 Bits} CONFIG.PCW_UIPARAM_DDR_FREQ_MHZ {400.00} \
CONFIG.PCW_UIPARAM_DDR_PARTNO {Custom} CONFIG.PCW_UIPARAM_DDR_T_FAW {50} \
CONFIG.PCW_UIPARAM_DDR_T_RAS_MIN {40} CONFIG.PCW_UIPARAM_DDR_T_RC {60} \
CONFIG.PCW_UIPARAM_DDR_T_RCD {9} CONFIG.PCW_UIPARAM_DDR_T_RP {9} \
CONFIG.PCW_UIPARAM_DDR_USE_INTERNAL_VREF {1} CONFIG.PCW_USB0_PERIPHERAL_ENABLE {1} \
CONFIG.PCW_USB0_RESET_ENABLE {0} CONFIG.PCW_USB1_PERIPHERAL_ENABLE {1} \
CONFIG.PCW_USE_FABRIC_INTERRUPT {1} CONFIG.PCW_USE_M_AXI_GP1 {1} \
CONFIG.PCW_USE_S_AXI_HP0 {1} ] $processing_system7_0
# Create instance: processing_system7_0_axi_periph, and set properties
set processing_system7_0_axi_periph [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 processing_system7_0_axi_periph ]
set_property -dict [ list CONFIG.NUM_MI {1} ] $processing_system7_0_axi_periph
# Create instance: sys_concat_intc, and set properties
set sys_concat_intc [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlconcat:2.1 sys_concat_intc ]
set_property -dict [ list CONFIG.NUM_PORTS {16} ] $sys_concat_intc
# Create interface connections
connect_bd_intf_net -intf_net processing_system7_0_M_AXI_GP0 [get_bd_intf_pins processing_system7_0/M_AXI_GP0] [get_bd_intf_pins processing_system7_0_axi_periph/S00_AXI]
connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M00_AXI [get_bd_intf_pins parallella_gpio_0/s_axi] [get_bd_intf_pins processing_system7_0_axi_periph/M00_AXI]
# Create port connections
connect_bd_net -net parallella_gpio_0_constant_zero [get_bd_pins sys_concat_intc/In0] [get_bd_pins sys_concat_intc/In1] [get_bd_pins sys_concat_intc/In2] [get_bd_pins sys_concat_intc/In3] [get_bd_pins sys_concat_intc/In4] [get_bd_pins sys_concat_intc/In5] [get_bd_pins sys_concat_intc/In6] [get_bd_pins sys_concat_intc/In7] [get_bd_pins sys_concat_intc/In8] [get_bd_pins sys_concat_intc/In9] [get_bd_pins sys_concat_intc/In11] [get_bd_pins sys_concat_intc/In12] [get_bd_pins sys_concat_intc/In13] [get_bd_pins sys_concat_intc/In14] [get_bd_pins sys_concat_intc/In15]
connect_bd_net -net parallella_gpio_0_gpio_irq [get_bd_pins parallella_gpio_0/gpio_irq] [get_bd_pins sys_concat_intc/In10]
connect_bd_net -net parallella_gpio_0_gpio_n [get_bd_ports gpio_n] [get_bd_pins parallella_gpio_0/gpio_n]
connect_bd_net -net parallella_gpio_0_gpio_p [get_bd_ports gpio_p] [get_bd_pins parallella_gpio_0/gpio_p]
connect_bd_net -net proc_sys_reset_0_interconnect_aresetn [get_bd_pins proc_sys_reset_0/interconnect_aresetn] [get_bd_pins processing_system7_0_axi_periph/ARESETN]
connect_bd_net -net proc_sys_reset_0_peripheral_aresetn [get_bd_pins parallella_gpio_0/s_axi_aresetn] [get_bd_pins parallella_gpio_0/sys_nreset] [get_bd_pins proc_sys_reset_0/peripheral_aresetn] [get_bd_pins processing_system7_0_axi_periph/M00_ARESETN] [get_bd_pins processing_system7_0_axi_periph/S00_ARESETN]
connect_bd_net -net processing_system7_0_FCLK_CLK0 [get_bd_pins parallella_gpio_0/sys_clk] [get_bd_pins proc_sys_reset_0/slowest_sync_clk] [get_bd_pins processing_system7_0/FCLK_CLK0] [get_bd_pins processing_system7_0/M_AXI_GP0_ACLK] [get_bd_pins processing_system7_0/M_AXI_GP1_ACLK] [get_bd_pins processing_system7_0/S_AXI_HP0_ACLK] [get_bd_pins processing_system7_0_axi_periph/ACLK] [get_bd_pins processing_system7_0_axi_periph/M00_ACLK] [get_bd_pins processing_system7_0_axi_periph/S00_ACLK]
connect_bd_net -net processing_system7_0_FCLK_RESET0_N [get_bd_pins proc_sys_reset_0/ext_reset_in] [get_bd_pins processing_system7_0/FCLK_RESET0_N]
connect_bd_net -net sys_concat_intc_dout [get_bd_pins processing_system7_0/IRQ_F2P] [get_bd_pins sys_concat_intc/dout]
# Create address segments
create_bd_addr_seg -range 0x40000000 -offset 0x40000000 [get_bd_addr_spaces processing_system7_0/Data] [get_bd_addr_segs parallella_gpio_0/s_axi/axi_lite] SEG_parallella_gpio_0_axi_lite
# Restore current instance
current_bd_instance $oldCurInst
save_bd_design
}
# End of create_root_design()
##################################################################
# MAIN FLOW
##################################################################
create_root_design ""

View File

@ -0,0 +1,29 @@
# NOTE: See UG1118 for more information
#########################################
# VARIABLES
#########################################
set design axi_gpio
set projdir ./
set root "../.."
set partname "xc7z020clg400-1"
set hdl_files [list \
$root/gpio/hdl \
$root/common/hdl/ \
$root/emesh/hdl \
$root/emmu/hdl \
$root/axi/hdl \
$root/emailbox/hdl \
$root/edma/hdl \
$root/elink/hdl \
$root/parallella/hdl \
]
set ip_files []
set constraints_files [list \
../../parallella/fpga/parallella_io.xdc \
../../parallella/fpga/parallella_7020_io.xdc \
]

210
src/gpio/hdl/axi_gpio.v Normal file
View File

@ -0,0 +1,210 @@
//#############################################################################
//# Purpose: AXI GPIO module #
//#############################################################################
//# Author: Ola Jeppsson #
//# SPDX-License-Identifier: MIT #
//#############################################################################
module axi_gpio(/*AUTOARG*/
// Outputs
s_axi_wready, s_axi_rvalid, s_axi_rresp, s_axi_rlast, s_axi_rid,
s_axi_rdata, s_axi_bvalid, s_axi_bresp, s_axi_bid, s_axi_awready,
s_axi_arready, gpio_out, gpio_irq, gpio_dir,
// Inputs
s_axi_wvalid, s_axi_wstrb, s_axi_wlast, s_axi_wid, s_axi_wdata,
s_axi_rready, s_axi_bready, s_axi_awvalid, s_axi_awsize,
s_axi_awqos, s_axi_awprot, s_axi_awlock, s_axi_awlen, s_axi_awid,
s_axi_awcache, s_axi_awburst, s_axi_awaddr, s_axi_arvalid,
s_axi_arsize, s_axi_arqos, s_axi_arprot, s_axi_arlock, s_axi_arlen,
s_axi_arid, s_axi_aresetn, s_axi_arcache, s_axi_arburst,
s_axi_araddr, gpio_in, sys_nreset, sys_clk
);
//########################################################
// INTERFACE
//########################################################
parameter AW = 32; // address width
parameter PW = 2*AW+40; // packet width
parameter ID = 12'h810; // addr[31:20] id
parameter S_IDW = 12; // ID width for S_AXI
parameter N = 24; // number of gpio pins
//clk, reset
input sys_nreset; // active low async reset
input sys_clk; // system clock for AXI
//############################
// HOST GENERATERD
//############################
//Slave Write
wire s_wr_access;
wire [PW-1:0] s_wr_packet;
wire s_wr_wait;
//Slave Read Request
wire s_rd_access;
wire [PW-1:0] s_rd_packet;
wire s_rd_wait;
//Slave Read Response
wire s_rr_access;
wire [PW-1:0] s_rr_packet;
wire s_rr_wait;
//##############################################################
/*AUTOINPUT*/
// Beginning of automatic inputs (from unused autoinst inputs)
input [N-1:0] gpio_in; // To gpio of gpio.v
input [31:0] s_axi_araddr; // To esaxi of esaxi.v
input [1:0] s_axi_arburst; // To esaxi of esaxi.v
input [3:0] s_axi_arcache; // To esaxi of esaxi.v
input s_axi_aresetn; // To esaxi of esaxi.v
input [S_IDW-1:0] s_axi_arid; // To esaxi of esaxi.v
input [7:0] s_axi_arlen; // To esaxi of esaxi.v
input s_axi_arlock; // To esaxi of esaxi.v
input [2:0] s_axi_arprot; // To esaxi of esaxi.v
input [3:0] s_axi_arqos; // To esaxi of esaxi.v
input [2:0] s_axi_arsize; // To esaxi of esaxi.v
input s_axi_arvalid; // To esaxi of esaxi.v
input [31:0] s_axi_awaddr; // To esaxi of esaxi.v
input [1:0] s_axi_awburst; // To esaxi of esaxi.v
input [3:0] s_axi_awcache; // To esaxi of esaxi.v
input [S_IDW-1:0] s_axi_awid; // To esaxi of esaxi.v
input [7:0] s_axi_awlen; // To esaxi of esaxi.v
input s_axi_awlock; // To esaxi of esaxi.v
input [2:0] s_axi_awprot; // To esaxi of esaxi.v
input [3:0] s_axi_awqos; // To esaxi of esaxi.v
input [2:0] s_axi_awsize; // To esaxi of esaxi.v
input s_axi_awvalid; // To esaxi of esaxi.v
input s_axi_bready; // To esaxi of esaxi.v
input s_axi_rready; // To esaxi of esaxi.v
input [31:0] s_axi_wdata; // To esaxi of esaxi.v
input [S_IDW-1:0] s_axi_wid; // To esaxi of esaxi.v
input s_axi_wlast; // To esaxi of esaxi.v
input [3:0] s_axi_wstrb; // To esaxi of esaxi.v
input s_axi_wvalid; // To esaxi of esaxi.v
// End of automatics
/*AUTOOUTPUT*/
// Beginning of automatic outputs (from unused autoinst outputs)
output [N-1:0] gpio_dir; // From gpio of gpio.v
output gpio_irq; // From gpio of gpio.v
output [N-1:0] gpio_out; // From gpio of gpio.v
output s_axi_arready; // From esaxi of esaxi.v
output s_axi_awready; // From esaxi of esaxi.v
output [S_IDW-1:0] s_axi_bid; // From esaxi of esaxi.v
output [1:0] s_axi_bresp; // From esaxi of esaxi.v
output s_axi_bvalid; // From esaxi of esaxi.v
output [31:0] s_axi_rdata; // From esaxi of esaxi.v
output [S_IDW-1:0] s_axi_rid; // From esaxi of esaxi.v
output s_axi_rlast; // From esaxi of esaxi.v
output [1:0] s_axi_rresp; // From esaxi of esaxi.v
output s_axi_rvalid; // From esaxi of esaxi.v
output s_axi_wready; // From esaxi of esaxi.v
// End of automatics
/*AUTOWIRE*/
/*AUTOREG*/
wire gpio_wait_out;
wire gpio_access_out;
wire [PW-1:0] gpio_packet_out;
wire gpio_access_in;
wire [PW-1:0] gpio_packet_in;
wire gpio_wait_in;
gpio #(.AW(AW),.N(N))
gpio(
//Outputs
.wait_out (gpio_wait_out),
.access_out (gpio_access_out),
.packet_out (gpio_packet_out[PW-1:0]),
//Inputs
.nreset (sys_nreset),
.clk (sys_clk),
.access_in (gpio_access_in),
.packet_in (gpio_packet_in[PW-1:0]),
.wait_in (gpio_wait_in),
/*AUTOINST*/
// Outputs
.gpio_out (gpio_out[N-1:0]),
.gpio_dir (gpio_dir[N-1:0]),
.gpio_irq (gpio_irq),
// Inputs
.gpio_in (gpio_in[N-1:0]));
//########################################################
//AXI SLAVE
//########################################################
emesh_mux #(.N(2),.AW(AW))
mux2(// Outputs
.wait_out ({s_rd_wait, s_wr_wait}),
.access_out (gpio_access_in),
.packet_out (gpio_packet_in[PW-1:0]),
// Inputs
.access_in ({s_rd_access, s_wr_access}),
.packet_in ({s_rd_packet[PW-1:0], s_wr_packet[PW-1:0]}),
.wait_in (s_rr_wait)
);
esaxi #(.S_IDW(S_IDW))
esaxi (.s_axi_aclk (sys_clk),
.wr_access (s_wr_access),
.wr_packet (s_wr_packet[PW-1:0]),
.rr_wait (s_rr_wait),
.rd_wait (s_rd_wait),
.rr_access (gpio_access_out),
.rr_packet (gpio_packet_out[PW-1:0]),
.wr_wait (s_wr_wait),
.rd_access (s_rd_access),
.rd_packet (s_rd_packet[PW-1:0]),
/*AUTOINST*/
// Outputs
.s_axi_arready (s_axi_arready),
.s_axi_awready (s_axi_awready),
.s_axi_bid (s_axi_bid[S_IDW-1:0]),
.s_axi_bresp (s_axi_bresp[1:0]),
.s_axi_bvalid (s_axi_bvalid),
.s_axi_rid (s_axi_rid[S_IDW-1:0]),
.s_axi_rdata (s_axi_rdata[31:0]),
.s_axi_rlast (s_axi_rlast),
.s_axi_rresp (s_axi_rresp[1:0]),
.s_axi_rvalid (s_axi_rvalid),
.s_axi_wready (s_axi_wready),
// Inputs
.s_axi_aresetn (s_axi_aresetn),
.s_axi_arid (s_axi_arid[S_IDW-1:0]),
.s_axi_araddr (s_axi_araddr[31:0]),
.s_axi_arburst (s_axi_arburst[1:0]),
.s_axi_arcache (s_axi_arcache[3:0]),
.s_axi_arlock (s_axi_arlock),
.s_axi_arlen (s_axi_arlen[7:0]),
.s_axi_arprot (s_axi_arprot[2:0]),
.s_axi_arqos (s_axi_arqos[3:0]),
.s_axi_arsize (s_axi_arsize[2:0]),
.s_axi_arvalid (s_axi_arvalid),
.s_axi_awid (s_axi_awid[S_IDW-1:0]),
.s_axi_awaddr (s_axi_awaddr[31:0]),
.s_axi_awburst (s_axi_awburst[1:0]),
.s_axi_awcache (s_axi_awcache[3:0]),
.s_axi_awlock (s_axi_awlock),
.s_axi_awlen (s_axi_awlen[7:0]),
.s_axi_awprot (s_axi_awprot[2:0]),
.s_axi_awqos (s_axi_awqos[3:0]),
.s_axi_awsize (s_axi_awsize[2:0]),
.s_axi_awvalid (s_axi_awvalid),
.s_axi_bready (s_axi_bready),
.s_axi_rready (s_axi_rready),
.s_axi_wid (s_axi_wid[S_IDW-1:0]),
.s_axi_wdata (s_axi_wdata[31:0]),
.s_axi_wlast (s_axi_wlast),
.s_axi_wstrb (s_axi_wstrb[3:0]),
.s_axi_wvalid (s_axi_wvalid));
endmodule // axi_gpio
// Local Variables:
// verilog-library-directories:("." "../../axi/hdl" "../../common/hdl" "../../emesh/hdl")
// End:

View File

@ -7,41 +7,36 @@
//#############################################################################
`include "gpio_regmap.vh"
module gpio #(
parameter integer N = 24, // number of gpio pins
parameter integer AW = 32 // architecture address width
module gpio #( parameter integer N = 24, // number of gpio pins
parameter integer AW = 32, // architecture address width
parameter integer PW = 104 // packet width
)
(
input nreset, // asynchronous active low reset
input clk, // clock
input access_in, // register access
input [PW-1:0] packet_in, // data/address
output wait_out, // pushback from mesh
output access_out, // register access
output [PW-1:0] packet_out, // data/address
input wait_in, // pushback from mesh
output [N-1:0] gpio_out, // data to drive to IO pins
output [N-1:0] gpio_dir, // gpio direction(0=input)
input [N-1:0] gpio_in, // data from IO pins
output gpio_irq // OR of GPIO_ILAT register
input nreset, // asynchronous active low reset
input clk, // clock
input access_in, // register access
input [PW-1:0] packet_in, // data/address
output wait_out, // pushback from mesh
output access_out, // register access
output [PW-1:0] packet_out, // data/address
input wait_in, // pushback from mesh
output reg [N-1:0] gpio_out, // data to drive to IO pins
output reg [N-1:0] gpio_dir, // gpio direction(0=input)
input [N-1:0] gpio_in, // data from IO pins
output gpio_irq // OR of GPIO_ILAT register
);
//################################
//# wires/regs/ params
//################################
//local parameters
localparam integer PW = 2*AW+40; // packet width
//registers
reg [N-1:0] gpio_dir;
reg [N-1:0] gpio_out;
reg [N-1:0] gpio_imask;
reg [N-1:0] gpio_itype;
reg [N-1:0] gpio_ipol;
reg [N-1:0] gpio_ilat;
reg [N-1:0] gpio_in_old;
reg [AW-1:0] read_data; // read is always 32 bits
reg [N-1:0] read_data;
//wires
wire [N-1:0] ilat_clr;
@ -51,6 +46,19 @@ module gpio #(
wire [N-1:0] rising_edge;
wire [N-1:0] falling_edge;
wire [N-1:0] irq_event;
wire reg_write;
wire reg_read;
wire reg_double;
wire dir_write;
wire imask_write;
wire itype_write;
wire ipol_write;
wire ilatclr_write;
wire out_write;
wire outset_write;
wire outclr_write;
wire outxor_write;
wire outreg_write;
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
@ -66,7 +74,8 @@ module gpio #(
//# DECODE LOGIC
//################################
packet2emesh #(.AW(AW))
packet2emesh #(.AW(AW),
.PW(PW))
p2e(
/*AUTOINST*/
// Outputs
@ -85,7 +94,7 @@ module gpio #(
assign reg_wdata[N-1:0] = data_in[N-1:0];
assign dir_write = reg_write & (dstaddr_in[6:3]==`GPIO_DIR);
assign out_write = reg_write & (dstaddr_in[6:3]==`GPIO_OUT);
assign outreg_write = reg_write & (dstaddr_in[6:3]==`GPIO_OUT);
assign imask_write = reg_write & (dstaddr_in[6:3]==`GPIO_IMASK);
assign itype_write = reg_write & (dstaddr_in[6:3]==`GPIO_ITYPE);
assign ipol_write = reg_write & (dstaddr_in[6:3]==`GPIO_IPOL);
@ -94,10 +103,10 @@ module gpio #(
assign outset_write = reg_write & (dstaddr_in[6:3]==`GPIO_OUTSET);
assign outxor_write = reg_write & (dstaddr_in[6:3]==`GPIO_OUTXOR);
assign out_reg_write = out_write |
outclr_write |
outset_write |
outxor_write;
assign out_write = outreg_write |
outclr_write |
outset_write |
outxor_write;
//################################
//# GPIO_DIR
@ -113,11 +122,10 @@ module gpio #(
//# GPIO_IN
//################################
oh_dsync #(.DW(N))
dsync (.dout (gpio_in_sync[N-1:0]),
.clk (clk),
.nreset (nreset),
.din (gpio_in[N-1:0]));
oh_dsync oh_dsync[N-1:0] (.dout (gpio_in_sync[N-1:0]),
.clk (clk),
.nreset (nreset),
.din (gpio_in[N-1:0]));
always @ (posedge clk)
gpio_in_old[N-1:0] <= gpio_in_sync[N-1:0];
@ -129,7 +137,7 @@ module gpio #(
oh_mux4 #(.DW(N))
oh_mux4 (.out (out_dmux[N-1:0]),
// Inputs
.in0 (reg_wdata[N-1:0]), .sel0 (out_write),
.in0 (reg_wdata[N-1:0]), .sel0 (outreg_write),
.in1 (gpio_out[N-1:0] & ~reg_wdata[N-1:0]),.sel1 (outclr_write),
.in2 (gpio_out[N-1:0] | reg_wdata[N-1:0]), .sel2 (outset_write),
.in3 (gpio_out[N-1:0] ^ reg_wdata[N-1:0]), .sel3 (outxor_write));
@ -137,7 +145,7 @@ module gpio #(
always @ (posedge clk or negedge nreset)
if(!nreset)
gpio_out[N-1:0] <= 'b0;
else if(out_reg_write)
else if(out_write)
gpio_out[N-1:0] <= out_dmux[N-1:0];
//################################
@ -203,16 +211,17 @@ module gpio #(
always @ (posedge clk)
if(reg_read)
case(dstaddr_in[6:3])
`GPIO_IN : read_data[AW-1:0] <= gpio_in_sync[N-1:0];
`GPIO_ILAT : read_data[AW-1:0] <= gpio_ilat[N-1:0];
`GPIO_DIR : read_data[AW-1:0] <= gpio_dir[N-1:0];
`GPIO_IMASK: read_data[AW-1:0] <= gpio_imask[N-1:0];
`GPIO_IPOL : read_data[AW-1:0] <= gpio_ipol[N-1:0];
`GPIO_ITYPE: read_data[AW-1:0] <= gpio_itype[N-1:0];
default : read_data[AW-1:0] <='b0;
`GPIO_IN : read_data[N-1:0] <= gpio_in_sync[N-1:0];
`GPIO_ILAT : read_data[N-1:0] <= gpio_ilat[N-1:0];
`GPIO_DIR : read_data[N-1:0] <= gpio_dir[N-1:0];
`GPIO_IMASK: read_data[N-1:0] <= gpio_imask[N-1:0];
`GPIO_IPOL : read_data[N-1:0] <= gpio_ipol[N-1:0];
`GPIO_ITYPE: read_data[N-1:0] <= gpio_itype[N-1:0];
default : read_data[N-1:0] <='b0;
endcase // case (dstaddr_in[7:3])
emesh_readback #(.AW(AW))
emesh_readback #(.AW(AW),
.PW(PW))
emesh_readback (/*AUTOINST*/
// Outputs
.wait_out (wait_out),

View File

@ -0,0 +1,171 @@
//#############################################################################
//# Purpose: Parallella GPIO top #
//#############################################################################
//# Author: Ola Jeppsson #
//# SPDX-License-Identifier: MIT #
//#############################################################################
module parallella_gpio(/*AUTOARG*/
// Outputs
s_axi_wready, s_axi_rvalid, s_axi_rresp, s_axi_rlast, s_axi_rid,
s_axi_rdata, s_axi_bvalid, s_axi_bresp, s_axi_bid, s_axi_awready,
s_axi_arready, gpio_irq,
// Inouts
gpio_n, gpio_p,
// Inputs
s_axi_wvalid, s_axi_wstrb, s_axi_wlast, s_axi_wid, s_axi_wdata,
s_axi_rready, s_axi_bready, s_axi_awvalid, s_axi_awsize,
s_axi_awqos, s_axi_awprot, s_axi_awlock, s_axi_awlen, s_axi_awid,
s_axi_awcache, s_axi_awburst, s_axi_awaddr, s_axi_arvalid,
s_axi_arsize, s_axi_arqos, s_axi_arprot, s_axi_arlock, s_axi_arlen,
s_axi_arid, s_axi_aresetn, s_axi_arcache, s_axi_arburst,
s_axi_araddr, constant_zero, constant_one, sys_nreset, sys_clk
);
//########################################################
// INTERFACE
//########################################################
parameter AW = 32; // address width
parameter DW = 32;
parameter PW = 2*AW+40; // packet width
parameter ID = 12'h7ff; // addr[31:20] id
parameter S_IDW = 12; // ID width for S_AXI
parameter NGPIO = 24; // number of gpio pins
// constants
input constant_zero; // Always 0
input constant_one; // Always 1
//clk, reset
input sys_nreset; // active low async reset
input sys_clk; // system clock for AXI
inout [NGPIO-1:0] gpio_n; // physical gpio pins
inout [NGPIO-1:0] gpio_p; // physical gpio pins
wire [NGPIO-1:0] gpio_in; // oh gpio in
wire [NGPIO-1:0] gpio_out; // oh gpio out
wire [NGPIO-1:0] gpio_dir; // oh gpio direction
wire [NGPIO-1:0] pgpio_in; // parallella gpio in
wire [NGPIO-1:0] pgpio_out; // parallella gpio out
/*AUTOINPUT*/
// Beginning of automatic inputs (from unused autoinst inputs)
input [31:0] s_axi_araddr; // To axi_gpio of axi_gpio.v
input [1:0] s_axi_arburst; // To axi_gpio of axi_gpio.v
input [3:0] s_axi_arcache; // To axi_gpio of axi_gpio.v
input s_axi_aresetn; // To axi_gpio of axi_gpio.v
input [S_IDW-1:0] s_axi_arid; // To axi_gpio of axi_gpio.v
input [7:0] s_axi_arlen; // To axi_gpio of axi_gpio.v
input s_axi_arlock; // To axi_gpio of axi_gpio.v
input [2:0] s_axi_arprot; // To axi_gpio of axi_gpio.v
input [3:0] s_axi_arqos; // To axi_gpio of axi_gpio.v
input [2:0] s_axi_arsize; // To axi_gpio of axi_gpio.v
input s_axi_arvalid; // To axi_gpio of axi_gpio.v
input [31:0] s_axi_awaddr; // To axi_gpio of axi_gpio.v
input [1:0] s_axi_awburst; // To axi_gpio of axi_gpio.v
input [3:0] s_axi_awcache; // To axi_gpio of axi_gpio.v
input [S_IDW-1:0] s_axi_awid; // To axi_gpio of axi_gpio.v
input [7:0] s_axi_awlen; // To axi_gpio of axi_gpio.v
input s_axi_awlock; // To axi_gpio of axi_gpio.v
input [2:0] s_axi_awprot; // To axi_gpio of axi_gpio.v
input [3:0] s_axi_awqos; // To axi_gpio of axi_gpio.v
input [2:0] s_axi_awsize; // To axi_gpio of axi_gpio.v
input s_axi_awvalid; // To axi_gpio of axi_gpio.v
input s_axi_bready; // To axi_gpio of axi_gpio.v
input s_axi_rready; // To axi_gpio of axi_gpio.v
input [31:0] s_axi_wdata; // To axi_gpio of axi_gpio.v
input [S_IDW-1:0] s_axi_wid; // To axi_gpio of axi_gpio.v
input s_axi_wlast; // To axi_gpio of axi_gpio.v
input [3:0] s_axi_wstrb; // To axi_gpio of axi_gpio.v
input s_axi_wvalid; // To axi_gpio of axi_gpio.v
// End of automatics
/*AUTOOUTPUT*/
// Beginning of automatic outputs (from unused autoinst outputs)
output gpio_irq; // From axi_gpio of axi_gpio.v
output s_axi_arready; // From axi_gpio of axi_gpio.v
output s_axi_awready; // From axi_gpio of axi_gpio.v
output [S_IDW-1:0] s_axi_bid; // From axi_gpio of axi_gpio.v
output [1:0] s_axi_bresp; // From axi_gpio of axi_gpio.v
output s_axi_bvalid; // From axi_gpio of axi_gpio.v
output [31:0] s_axi_rdata; // From axi_gpio of axi_gpio.v
output [S_IDW-1:0] s_axi_rid; // From axi_gpio of axi_gpio.v
output s_axi_rlast; // From axi_gpio of axi_gpio.v
output [1:0] s_axi_rresp; // From axi_gpio of axi_gpio.v
output s_axi_rvalid; // From axi_gpio of axi_gpio.v
output s_axi_wready; // From axi_gpio of axi_gpio.v
// End of automatics
/*AUTOWIRE*/
/*AUTOREG*/
assign constant_zero = 1'b0;
assign constant_one = 1'b1;
pgpio #(.NGPIO(NGPIO),.NPS(NGPIO))
pgpio (.ps_gpio_i (gpio_in[NGPIO-1:0]),
.ps_gpio_o (gpio_out[NGPIO-1:0]),
.ps_gpio_t (~gpio_dir[NGPIO-1:0]),
/*AUTOINST*/
// Inouts
.gpio_p (gpio_p[NGPIO-1:0]),
.gpio_n (gpio_n[NGPIO-1:0]));
axi_gpio #(.S_IDW(S_IDW),.AW(AW),.N(NGPIO),.ID(ID))
axi_gpio (
.gpio_out (gpio_out[NGPIO-1:0]),
.gpio_dir (gpio_dir[NGPIO-1:0]),
.gpio_in (gpio_in[NGPIO-1:0]),
/*AUTOINST*/
// Outputs
.gpio_irq (gpio_irq),
.s_axi_arready (s_axi_arready),
.s_axi_awready (s_axi_awready),
.s_axi_bid (s_axi_bid[S_IDW-1:0]),
.s_axi_bresp (s_axi_bresp[1:0]),
.s_axi_bvalid (s_axi_bvalid),
.s_axi_rdata (s_axi_rdata[31:0]),
.s_axi_rid (s_axi_rid[S_IDW-1:0]),
.s_axi_rlast (s_axi_rlast),
.s_axi_rresp (s_axi_rresp[1:0]),
.s_axi_rvalid (s_axi_rvalid),
.s_axi_wready (s_axi_wready),
// Inputs
.sys_nreset (sys_nreset),
.sys_clk (sys_clk),
.s_axi_araddr (s_axi_araddr[31:0]),
.s_axi_arburst (s_axi_arburst[1:0]),
.s_axi_arcache (s_axi_arcache[3:0]),
.s_axi_aresetn (s_axi_aresetn),
.s_axi_arid (s_axi_arid[S_IDW-1:0]),
.s_axi_arlen (s_axi_arlen[7:0]),
.s_axi_arlock (s_axi_arlock),
.s_axi_arprot (s_axi_arprot[2:0]),
.s_axi_arqos (s_axi_arqos[3:0]),
.s_axi_arsize (s_axi_arsize[2:0]),
.s_axi_arvalid (s_axi_arvalid),
.s_axi_awaddr (s_axi_awaddr[31:0]),
.s_axi_awburst (s_axi_awburst[1:0]),
.s_axi_awcache (s_axi_awcache[3:0]),
.s_axi_awid (s_axi_awid[S_IDW-1:0]),
.s_axi_awlen (s_axi_awlen[7:0]),
.s_axi_awlock (s_axi_awlock),
.s_axi_awprot (s_axi_awprot[2:0]),
.s_axi_awqos (s_axi_awqos[3:0]),
.s_axi_awsize (s_axi_awsize[2:0]),
.s_axi_awvalid (s_axi_awvalid),
.s_axi_bready (s_axi_bready),
.s_axi_rready (s_axi_rready),
.s_axi_wdata (s_axi_wdata[31:0]),
.s_axi_wid (s_axi_wid[S_IDW-1:0]),
.s_axi_wlast (s_axi_wlast),
.s_axi_wstrb (s_axi_wstrb[3:0]),
.s_axi_wvalid (s_axi_wvalid));
endmodule // parallella_gpio
// Local Variables:
// verilog-library-directories:("." "../../axi/hdl" "../../common/hdl" "../../emesh/hdl" "../../parallella/hdl")
// End:

View File

@ -0,0 +1,8 @@
CFLAGS ?= -g
all: hello-mio
clean:
rm -f hello-mio
.PHONY: all clean

View File

View File

@ -0,0 +1,175 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdint.h>
#include <stdio.h>
#define PAGE_SHIFT 12
#define MIO_CONFIG 0 // general config
#define MIO_STATUS 1 // status
#define MIO_CLKDIV 2 // clk divider config
#define MIO_CLKPHASE 3 // clk divider config
#define MIO_ODELAY 4 // output data delay element
#define MIO_IDELAY 5 // input data delay element
#define MIO_ADDR0 6 // destination address for amode
#define MIO_ADDR1 7 // destination address for amode
#define MIO_STATUS_RX_EMPTY (1 << 0)
#define MIO_STATUS_RX_PROG_FULL (1 << 1)
#define MIO_STATUS_RX_FULL (1 << 2)
#define MIO_STATUS_TX_EMPTY (1 << 3)
#define MIO_STATUS_TX_PROG_FULL (1 << 4)
#define MIO_STATUS_TX_FULL (1 << 5)
void mio_set_clkdiv(volatile uint32_t *regs, uint32_t clkdiv)
{
uint32_t rise0, fall0, rise1, fall1;
uint32_t clkphase;
if (clkdiv > 254)
clkdiv = 254;
rise0 = 0;
fall0 = 0xff & ((clkdiv + 1) >> 1); // 180 degrees
rise1 = 0xff & ((clkdiv + 1) >> 2); // 90 degrees
fall1 = 0xff & (((clkdiv + 1) >> 2) +
((clkdiv + 1) >> 1)); // 270 degrees
regs[MIO_CLKDIV] = clkdiv;
regs[MIO_CLKPHASE] = fall1 << 24 |
rise1 << 16 |
fall0 << 8 |
rise0 << 0;
}
int main()
{
bool pass = true;
int fd;
union acme_ptr {
void *v;
volatile uint8_t *u8;
volatile uint16_t *u16;
volatile uint32_t *u32;
};
union acme_ptr wormhole, regs, mem;
fd = open("/dev/uio0", O_RDWR);
if (fd < 0) {
perror("open");
return errno;
}
/* uio_pdrv_genirq uses (offset >> PAGE_SHIFT) as index into the region
* list. Device tree snippet:
* mio: mio@7fd00000 {
* #address-cells = <1>;
* #size-cells = <1>;
* ranges;
* compatible = "oh,mio";
* reg = <0x7fc00000 0x100000>, // TX wormhole
* <0x7fd00000 0x100000>, // MIO registers
* <0x3e000000 0x100000>; // TX destination
* };
*/
wormhole.v = mmap(NULL, 0x100000, PROT_WRITE | PROT_READ, MAP_SHARED,
fd, 0 << PAGE_SHIFT);
if (wormhole.v == MAP_FAILED) {
perror("mmap wormhole");
return errno;
}
regs.v = mmap(NULL, 0x100000, PROT_WRITE | PROT_READ, MAP_SHARED,
fd, 1 << PAGE_SHIFT);
if (regs.v == MAP_FAILED) {
perror("mmap regs");
return errno;
}
mem.v = mmap(NULL, 0x100000, PROT_WRITE | PROT_READ, MAP_SHARED,
fd, 2 << PAGE_SHIFT);
if (mem.v == MAP_FAILED) {
perror("mmap mem");
return errno;
}
mio_set_clkdiv(regs.u32, 10);
// Clear memory region
unsigned i, j;
for (i = 0; i < 0x40000; i++)
mem.u32[i] = 0;
regs.u32[1] = 0;
printf("status: 0x%08x\n", regs.u32[1]);
printf("Testing pattern 1\n");
for (i = 0; i < 0x40000; i++) {
uint32_t val = (i + 1) * 0x10101010;
wormhole.u32[i] = val;
/* HACK: Pushback broken mio_wait_out <--> s_wr_wait broken */
/* FIFO depth = 32 */
while (mem.u32[i] != val) {
// for (j = 0; j < 500; j++)
asm("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop" ::: "memory");
// if (mem.u32[i] == val)
// break;
// printf("PAT1 mem[%d]: 0x%08x expected: 0x%08x. Retrying\n",
// i, mem.u32[i], val);
}
}
for (i = 0; i < 0x40000; i++) {
uint32_t val = (i + 1) * 0x10101010;
while (mem.u32[i] != val) {
printf("PAT1 mem[%d]: 0x%08x expected: 0x%08x. Retrying\n",
i, mem.u32[i], val);
usleep(50);
}
}
printf("Testing pattern 2\n");
for (i = 0; i < 0x40000; i++) {
uint32_t val = (i + 1) * 0x01010101;
wormhole.u32[i] = val;
/* HACK: Pushback broken mio_wait_out <--> s_wr_wait broken */
/* FIFO depth = 32 */
while (mem.u32[i] != val) {
// for (j = 0; j < 500; j++)
asm("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop" ::: "memory");
// if (mem.u32[i] == val)
// break;
// printf("PAT2 mem[%d]: 0x%08x expected: 0x%08x. Retrying\n",
// i, mem.u32[i], val);
}
}
for (i = 0; i < 0x40000; i++) {
uint32_t val = (i + 1) * 0x01010101;
while (mem.u32[i] != val) {
printf("PAT2 mem[%d]: 0x%08x expected: 0x%08x. Retrying\n",
i, mem.u32[i], val);
usleep(50);
}
}
munmap(wormhole.v, 0x100000);
munmap(regs.v, 0x100000);
munmap(mem.v, 0x100000);
close(fd);
/* If we reached here the test did pass */
printf(pass ? "PASS\n" : "FAIL\n");
return pass ? 0 : 1;
}

View File

@ -0,0 +1,16 @@
# OH Linux generic UIO driver
Modules and devicetree compiled for Pubuntu 2016.3.x
1. Copy `zynq-parallella-oh-mio.dtb` to SD card boot partition, name it `devicetree.dtb`.
2. Reboot Parallella
3. (OPTIONAL) Load bitstream: `sudo dd if=parallella.bit.bin of=/dev/xdevcfg`
3. Load the required modules:
```
sudo insmod uio.ko
sudo insmod uio_pdrv_genirq.ko of_id=oh,mio
sudo rmmod uio_pdrv_genirq.ko
sudo insmod uio_pdrv_genirq.ko of_id=oh,mio
chmod 777 /dev/uio0
```
4. You can now compile and run hello-mio in oh.git/src/mio/driver/hello-mio

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2016 Parallella Foundation
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/dts-v1/;
#include "zynq-parallella1.dtsi"
/ {
model = "Adapteva Parallella Board with OH MIO bitstream";
};
&amba {
mio: mio@7fd00000 {
#address-cells = <1>;
#size-cells = <1>;
ranges;
compatible = "oh,mio";
reg = <0x7fc00000 0x100000>, /* TX wormhole */
<0x7fd00000 0x100000>, /* MIO registers */
<0x3e000000 0x100000>; /* TX destination */
};
};
&usb_phy0 {
status = "okay";
};
&usb_phy1 {
status = "okay";
};
&usb0 {
status = "okay";
};
&usb1 {
status = "okay";
};
&elink0 {
status = "disabled";
};
&i2c0 {
status = "disabled";
};

View File

@ -15,8 +15,7 @@ module mio (/*AUTOARG*/
parameter NMIO = 8; // IO width
parameter AW = 32; // address width
parameter MPW = 128; // mio packet width (>PW)
localparam PW = 2*AW+40; // emesh packet width
parameter PW = 2*AW+40; // emesh packet width
parameter DEF_CFG = 0; // Default config
parameter DEF_CLK = 0; // Default clock
parameter TARGET = "GENERIC";// GENERIC,XILINX,ALTERA,GENERIC,ASIC
@ -102,6 +101,7 @@ module mio (/*AUTOARG*/
*/
mio_regs #(.AW(AW),
.PW(PW),
.DEF_CFG(DEF_CFG),
.DEF_CLK(DEF_CLK))
mio_regs (.dmode (),
@ -220,6 +220,7 @@ module mio (/*AUTOARG*/
);
*/
mio_if #(.AW(AW),
.PW(PW),
.MPW(MPW))
mio_if (
/*AUTOINST*/

View File

@ -61,7 +61,8 @@ module mio_dp (/*AUTOARG*/
/*AUTOWIRE*/
mtx #(.NMIO(NMIO),
.PW(PW))
.PW(PW),
.TARGET(TARGET))
mtx (/*AUTOINST*/
// Outputs
.tx_empty (tx_empty),
@ -83,7 +84,8 @@ module mio_dp (/*AUTOARG*/
.tx_wait (tx_wait));
mrx #(.NMIO(NMIO),
.PW(PW))
.PW(PW),
.TARGET(TARGET))
mrx (/*AUTOINST*/
// Outputs
.rx_empty (rx_empty),

View File

@ -15,7 +15,7 @@ module mio_if (/*AUTOARG*/
//parameters
parameter AW = 32; // address width
parameter PW = 2*AW +40; // emesh packet width
parameter PW = 104; // emesh packet width
parameter MPW = 128; // mio packet width (> PW)
// reset, clk, config
@ -87,7 +87,8 @@ module mio_if (/*AUTOARG*/
//#################################################
// parse packet
packet2emesh #(.AW(AW))
packet2emesh #(.AW(AW),
.PW(PW))
pe2 (.packet_in (rx_packet_in[PW-1:0]),
/*AUTOINST*/
// Outputs
@ -133,7 +134,8 @@ module mio_if (/*AUTOARG*/
srcaddr_in[AW-1:0];
//Construct outgoing packet
emesh2packet #(.AW(AW))
emesh2packet #(.AW(AW),
.PW(PW))
e2p (/*AUTOINST*/
// Outputs
.packet_out (packet_out[PW-1:0]),

View File

@ -1,70 +1,79 @@
`include "mio_regmap.vh"
module mio_regs (/*AUTOARG*/
// Outputs
wait_out, access_out, packet_out, tx_en, rx_en, ddr_mode, emode,
amode, dmode, datasize, lsbfirst, framepol, ctrlmode, dstaddr,
clkchange, clkdiv, clkphase0, clkphase1,
// Inputs
clk, nreset, access_in, packet_in, wait_in, tx_full, tx_prog_full,
tx_empty, rx_full, rx_prog_full, rx_empty
);
//#############################################################################
//# Function: MIO Configuration Registers #
//# (See README.md for complete documentation) #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see LICENSE file in this repository) #
//#############################################################################
`include "mio_regmap.vh"
module mio_regs #(parameter N = 8, // number of I/O pins
parameter AW = 32, // address width
parameter PW = 104, // packet width
parameter DEF_CFG = 0, // reset MIO_CONFIG value
parameter DEF_CLK = 0 // reset MIO_CLKDIV value
)
(
// clk,reset
input clk,
input nreset,
// register access interface
input access_in, // incoming access
input [PW-1:0] packet_in, // incoming packet
output wait_out,
output access_out, // outgoing read packet
output [PW-1:0] packet_out, // outgoing read packet
input wait_in,
// config outputs
output tx_en, // enable tx
output rx_en, // enable rx
output ddr_mode, // ddr mode for mio
output emode, // epiphany packet mode
output amode, // mio packet mode
output dmode, // mio packet mode
output [7:0] datasize, // mio datasize
output lsbfirst, // lsb shift first
output framepol, // framepolarity (0=actrive high)
output [4:0] ctrlmode, // emode ctrlmode
output [AW-1:0] dstaddr, // destination address for RX dmode
output clkchange, // indicates a clock change
output [7:0] clkdiv, // mio clk clock setting
output [15:0] clkphase0, // [7:0]=rising,[15:8]=falling
output [15:0] clkphase1, // [7:0]=rising,[15:8]=falling
// status inputs
input tx_full, //tx fifo is full (should not happen!)
input tx_prog_full, //tx fifo is nearing full
input tx_empty, //tx fifo is empty
input rx_full, //rx fifo is full (should not happen!)
input rx_prog_full, //rx fifo is nearing full
input rx_empty //rx fifo is empty
);
// parameters
parameter N = 8; // number of I/O pins
parameter AW = 32; // address width
localparam PW = 2*AW+40; // packet width
parameter DEF_CFG = 0; // reset MIO_CONFI value
parameter DEF_CLK = 0; // reset MIO_CLKDIV value
localparam DEF_RISE0 = 0; // 0 degrees
localparam DEF_FALL0 = ((DEF_CLK+8'd1)>>8'd1); // 180 degrees
localparam DEF_RISE1 = ((DEF_CLK+8'd1)>>8'd2); // 90 degrees
localparam DEF_FALL1 = ((DEF_CLK+8'd1)>>8'd2)+
((DEF_CLK+8'd1)>>8'd1); // 270 degrees
// clk,reset
input clk;
input nreset;
//##############
//# LOCAL WIRES
//##############
// registre access interface
input access_in; // incoming access
input [PW-1:0] packet_in; // incoming packet
output wait_out;
output access_out; // outgoing read packet
output [PW-1:0] packet_out; // outgoing read packet
input wait_in;
// config
output tx_en; // enable tx
output rx_en; // enable rx
output ddr_mode; // ddr mode for mio
output emode; // epiphany packet mode
output amode; // mio packet mode
output dmode; // mio packet mode
output [7:0] datasize; // mio datasize
output lsbfirst; // lsb shift first
output framepol; // framepolarity (0=actrive high)
output [4:0] ctrlmode; // emode ctrlmode
//address
output [AW-1:0] dstaddr; // destination address for RX dmode
// clock
output clkchange; // indicates a clock change
output [7:0] clkdiv; // mio clk clock setting
output [15:0] clkphase0; // [7:0]=rising,[15:8]=falling
output [15:0] clkphase1; // [7:0]=rising,[15:8]=falling
// status
input tx_full; //tx fifo is full (should not happen!)
input tx_prog_full; //tx fifo is nearing full
input tx_empty; //tx fifo is empty
input rx_full; //rx fifo is full (should not happen!)
input rx_prog_full; //rx fifo is nearing full
input rx_empty; //rx fifo is empty
//######################################################################
//# BODY
//######################################################################
reg [20:0] config_reg;
reg [15:0] status_reg;
reg [31:0] clkdiv_reg;
reg [63:0] addr_reg;
reg [31:0] clkphase_reg;
wire [7:0] status_in;
wire reg_write;
wire config_write;
wire status_write;
wire clkdiv_write;
wire clkphase_write;
wire idelay_write;
wire odelay_write;
wire addr0_write;
wire addr1_write;
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
@ -76,19 +85,12 @@ module mio_regs (/*AUTOARG*/
wire write_in; // From p2e of packet2emesh.v
// End of automatics
//regs
reg [18:0] config_reg;
reg [7:0] status_reg;
wire [7:0] status_in;
reg [31:0] clkdiv_reg;
reg [63:0] addr_reg;
reg [31:0] clkphase_reg;
//#####################################
//# DECODE
//#####################################
packet2emesh #(.AW(AW))
packet2emesh #(.AW(AW),
.PW(PW))
p2e (/*AUTOINST*/
// Outputs
.write_in (write_in),
@ -119,10 +121,10 @@ module mio_regs (/*AUTOARG*/
always @ (posedge clk or negedge nreset)
if(!nreset)
begin
config_reg[18:0] <= DEF_CFG;
config_reg[20:0] <= DEF_CFG;
end
else if(config_write)
config_reg[18:0] <= data_in[18:0];
config_reg[20:0] <= data_in[20:0];
assign tx_en = ~config_reg[0]; // tx disable
assign rx_en = ~config_reg[1]; // rx disable
@ -149,11 +151,11 @@ module mio_regs (/*AUTOARG*/
always @ (posedge clk or negedge nreset)
if(!nreset)
status_reg[7:0] <= 'b0;
status_reg[15:0] <= 'b0;
else if(status_write)
status_reg[7:0] <= data_in[7:0];
status_reg[15:0] <= data_in[7:0];
else
status_reg[7:0] <= {(status_reg[15:8] | status_in[7:0]), // sticky bits
status_reg[15:0] <= {(status_reg[15:8] | status_in[7:0]), // sticky bits
status_in[7:0]}; // immediate bits
//###############################

View File

@ -39,6 +39,9 @@ module mrx_io (/*AUTOARG*/
wire [2*NMIO-1:0] ddr_data;
reg [2*NMIO-1:0] sdr_data;
reg byte0_sel;
wire io_nreset;
wire rx_frame;
//########################################
//# CLOCK, RESET
@ -61,7 +64,7 @@ module mrx_io (/*AUTOARG*/
//########################################
always @ (posedge rx_clk or negedge io_nreset)
if(!nreset)
if(!io_nreset)
io_access <= 1'b0;
else
io_access <= rx_frame;
@ -75,8 +78,8 @@ module mrx_io (/*AUTOARG*/
.q2 (ddr_data[2*NMIO-1:NMIO]),
.clk (rx_clk),
.ce (rx_frame),
.din (rx_packet[NMIO-1:0])
);
.din (rx_packet[NMIO-1:0]));
//########################################
//# DATA (SDR)
//########################################

View File

@ -38,6 +38,9 @@ module mrx_protocol (/*AUTOARG*/
reg [2:0] mrx_state;
reg [CW-1:0] mrx_count;
reg fifo_access;
wire shift;
wire transfer_done;
//##########################
//# STATE MACHINE

View File

@ -35,21 +35,26 @@ module mtx_io (/*AUTOARG*/
//# BODYINTER
//#####################################################################
//regs
localparam ASIC = `CFG_ASIC;
//Regs
reg tx_access;
wire [NMIO-1:0] tx_packet_ddr;
reg [NMIO-1:0] tx_packet_sdr;
reg byte0_sel;
wire [2*NMIO-1:0] ddr_data;
wire io_nreset;
//########################################
//# RESET
//########################################
//synchronize reset to io_clk
oh_rsync oh_rsync(.nrst_out (io_nreset),
.clk (io_clk),
.nrst_in (nreset));
oh_rsync #(.ASIC(ASIC))
oh_rsync(.nrst_out (io_nreset),
.clk (io_clk),
.nrst_in (nreset));
//########################################
//# ACCESS (SDR)

View File

@ -3,7 +3,8 @@ module dut(/*AUTOARG*/
// Outputs
dut_active, clkout, wait_out, access_out, packet_out,
// Inputs
clk1, clk2, nreset, vdd, vss, access_in, packet_in, wait_in
reg_write, reg_addr, clk1, clk2, nreset, vdd, vss, access_in,
packet_in, wait_in
);
//##########################################################################
@ -16,9 +17,7 @@ module dut(/*AUTOARG*/
parameter M_IDW = 6;
parameter PW = 2*AW + 40;
parameter N = 1;
parameter IRQW = 10;
parameter LAW = 16;
parameter IW = 10;
//clock,reset
input clk1;
@ -49,15 +48,12 @@ module dut(/*AUTOARG*/
wire [PW-1:0] mem_packet;
/*AUTOINPUT*/
// Beginning of automatic inputs (from unused autoinst inputs)
input [5:0] reg_addr; // To pic of pic.v
input reg_write; // To pic of pic.v
// End of automatics
wire ic_flush; // From pic of pic.v
wire [IRQW-1:0] ic_ilat_reg; // From pic of pic.v
wire [IRQW-1:0] ic_imask_reg; // From pic of pic.v
wire [IRQW-1:0] ic_ipend_reg; // From pic of pic.v
wire [LAW-1:0] ic_iret_reg; // From pic of pic.v
wire ic_irq; // From pic of pic.v
wire [LAW-1:0] ic_irq_addr; // From pic of pic.v
wire [5:0] reg_addr;
// End of automatics
/*AUTOWIRE*/
@ -66,6 +62,13 @@ module dut(/*AUTOARG*/
wire [AW-1:0] data_in; // From p2e of packet2emesh.v
wire [1:0] datamode_in; // From p2e of packet2emesh.v
wire [AW-1:0] dstaddr_in; // From p2e of packet2emesh.v
wire ic_flush; // From pic of pic.v
wire [IW-1:0] ic_ilat_reg; // From pic of pic.v
wire [IW-1:0] ic_imask_reg; // From pic of pic.v
wire [IW-1:0] ic_ipend_reg; // From pic of pic.v
wire [AW-1:0] ic_iret_reg; // From pic of pic.v
wire ic_irq; // From pic of pic.v
wire [AW-1:0] ic_irq_addr; // From pic of pic.v
wire [AW-1:0] srcaddr_in; // From p2e of packet2emesh.v
wire write_in; // From p2e of packet2emesh.v
// End of automatics
@ -91,27 +94,28 @@ module dut(/*AUTOARG*/
pic #(.LAW(LAW),
.IRQW(IRQW))
pic (// Outputs
.ic_flush (ic_flush),
.ic_iret_reg (ic_iret_reg[LAW-1:0]),
.ic_imask_reg (ic_imask_reg[IRQW-1:0]),
.ic_ilat_reg (ic_ilat_reg[IRQW-1:0]),
.ic_ipend_reg (ic_ipend_reg[IRQW-1:0]),
.ic_irq (ic_irq),
.ic_irq_addr (ic_irq_addr[LAW-1:0]),
// Inputs
.clk (clk1),
.nreset (nreset),
.reg_write (reg_write),
.reg_addr (reg_addr[5:0]),
.reg_wdata (data_in[31:0]),
.ext_irq ({(IRQW){1'b0}}),
.sq_pc_next_ra ({(LAW){1'b0}}),
.de_rti_e1 (1'b0),
.sq_global_irq_en (1'b1),
.sq_ic_wait (1'b0));
pic #(.AW(AW),
.IW(IW))
pic (.reg_wdata (data_in[31:0]),
.ext_irq ({(IW){1'b0}}),
.sq_pc_next ({(AW){1'b0}}),
.de_rti (1'b0),
.sq_irq_en (1'b1),
.sq_ic_wait (1'b0),
.clk (clk1),
/*AUTOINST*/
// Outputs
.ic_iret_reg (ic_iret_reg[AW-1:0]),
.ic_imask_reg (ic_imask_reg[IW-1:0]),
.ic_ilat_reg (ic_ilat_reg[IW-1:0]),
.ic_ipend_reg (ic_ipend_reg[IW-1:0]),
.ic_flush (ic_flush),
.ic_irq (ic_irq),
.ic_irq_addr (ic_irq_addr[AW-1:0]),
// Inputs
.nreset (nreset),
.reg_write (reg_write),
.reg_addr (reg_addr[5:0]));
endmodule

View File

@ -1,90 +1,83 @@
//#############################################################################
//# Function: Programmable Interrupt Controller #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
`include "pic_regmap.vh"
//###########################################################################
//# IRQC: Simple nessted interrupt controller
//#
//############################################################################
module pic(/*AUTOARG*/
// Outputs
ic_flush, ic_iret_reg, ic_imask_reg, ic_ilat_reg, ic_ipend_reg,
ic_irq, ic_irq_addr,
// Inputs
clk, nreset, reg_write, reg_addr, reg_wdata, ext_irq,
sq_pc_next_ra, de_rti_e1, sq_global_irq_en, sq_ic_wait
);
module pic #( parameter AW = 32, // address width
parameter IW = 10, // number of interrupts supported
parameter USE = 1 // set to 0 to disable
)
(
// CLK, RESET
input clk, // main clock
input nreset, // active low async reset
// REGISTER ACCESS
input reg_write, // reg write signal
input [5:0] reg_addr, // reg addr[5:0]
input [31:0] reg_wdata, // data input
output reg [AW-1:0] ic_iret_reg, // interrupt return register
output reg [IW-1:0] ic_imask_reg, // interrupt mask register
output reg [IW-1:0] ic_ilat_reg, // latched irq signals (but not started)
output reg [IW-1:0] ic_ipend_reg, // interrrupts pending/active
// PIPELINE
input [IW-1:0] ext_irq, // interrupt signals
input [AW-1:0] sq_pc_next, //PC to save to IRET
input de_rti, //jump to IRET
input sq_irq_en, // global interrupt enable
input sq_ic_wait, // wait until it's safe to interrupt
output ic_flush, // flush pipeline
// INTERRUPT
output ic_irq, // tells core to jump to adress in irq_addr
output reg [AW-1:0] ic_irq_addr// interrupt vector
);
//#####################################################################
//# INTERFACE
//#####################################################################
//Parameters
parameter LAW = 32;
parameter IRQW = 10;
/*TODO: Implement, don't wrap whole logic, let tool synthesize!
generate
if(USE==0)
begin: off
assign ic_imask_reg = 'b0;
assign ic_ilat_reg = 'b0;
assign ic_ipend_reg = 'b0;
assign ic_irq = 'b0;
assign ic_irq_addr = 'b0;
assign ic_flush = 'b0;
end
else
begin : g0
*/
//Basic Interface
input clk; //main clock
input nreset; //active low async reset
//Sysreg Write Access
input reg_write; //write signal
input [5:0] reg_addr; //addr[5:0]
input [31:0] reg_wdata; //data input
//Control signals
input [IRQW-1:0] ext_irq; //interrupt signals
input [LAW-1:0] sq_pc_next_ra; //PC to save to IRET
input de_rti_e1; //jump to IRET
input sq_global_irq_en; //disables all interrupts
input sq_ic_wait; //wait until it's safe to interrupt (delete?)
output ic_flush; //flush pipeline to get rid if all instructions
//Register Read Outputs
output [LAW-1:0] ic_iret_reg; //interrupt return register
output [IRQW-1:0] ic_imask_reg; //interrupt mask register
output [IRQW-1:0] ic_ilat_reg; //latched ext_irq signals (but not started)
output [IRQW-1:0] ic_ipend_reg; //interrrupts pending/active
//Interrupt Vector
output ic_irq; //tells core to jump to adress in irq_addr
output [LAW-1:0] ic_irq_addr; //interrupt vector
//#####################################################################
//# BODY
//#####################################################################
//###############
//# LOCAL WIRES
//###############
//For loop integers
integer i,j,m1,m2,n1,n2,p;
//Control registers
reg [LAW-1:0] ic_iret_reg;
reg [IRQW-1:0] ic_ilat_reg;
reg [IRQW-1:0] ic_imask_reg;
reg [IRQW-1:0] ic_ipend_reg;
reg [LAW-1:0] ic_irq_addr;
integer i,j,m1,m2,n1,n2,p;
//Functions
reg [IRQW-1:0] ic_ilat_in;
reg [IRQW-1:0] ic_ilat_priority_en_n;
reg [IRQW-1:0] ic_ipend_priority_en_n;
reg [IRQW-1:0] ic_irq_shadow;
reg [IRQW-1:0] ic_irq_entry;
reg [IW-1:0] ic_ilat_in;
reg [IW-1:0] ic_ilat_priority_en_n;
reg [IW-1:0] ic_ipend_priority_en_n;
reg [IW-1:0] ic_irq_shadow;
reg [IW-1:0] ic_irq_entry;
//Wires
wire [IRQW-1:0] ic_masked_ilat;
wire [LAW-1:0] ic_ivt[IRQW-1:0];
wire [IRQW-1:0] ic_ipend_in;//changed to generate
wire [IRQW:0] ic_ipend_shifted_reg;
wire [IRQW-1:0] ic_imask_in;
wire [IRQW-1:0] ic_irq_select;
wire [IRQW-1:0] ic_global_en;
wire [IRQW-1:0] ic_event;
wire [IRQW-1:0] ic_ilat_set_data;
wire [IRQW-1:0] ic_ilat_clear_data;
wire ic_write_imask;
wire ic_write_ipend;
wire ic_write_ilat;
wire ic_write_ilatset;
wire ic_write_ilatclr;
wire ic_write_iret;
wire [IW-1:0] ic_masked_ilat;
wire [AW-1:0] ic_ivt[IW-1:0];
wire [IW-1:0] ic_ipend_in;
wire [IW:0] ic_ipend_shifted_reg;
wire [IW-1:0] ic_imask_in;
wire [IW-1:0] ic_irq_select;
wire [IW-1:0] ic_global_en;
wire [IW-1:0] ic_event;
wire [IW-1:0] ic_ilat_set_data;
wire [IW-1:0] ic_ilat_clear_data;
wire ic_write_imask;
wire ic_write_ipend;
wire ic_write_ilat;
wire ic_write_ilatset;
wire ic_write_ilatclr;
wire ic_write_iret;
//###########################
//ACCESS DECODE
@ -96,30 +89,28 @@ module pic(/*AUTOARG*/
assign ic_write_ilatclr = reg_write &(reg_addr[5:0] ==`ECORE_ILATCL);
assign ic_write_iret = reg_write & reg_addr[5:0] ==`ECORE_IRET;
//###########################
//# RISING EDGE DETECTOR
//###########################
always @ (posedge clk or negedge nreset)
if(!nreset)
ic_irq_shadow[IRQW-1:0] <= 'b0;
ic_irq_shadow[IW-1:0] <= 'b0;
else
ic_irq_shadow[IRQW-1:0] <= ext_irq[IRQW-1:0] ;
assign ic_event[IRQW-1:0] = ext_irq[IRQW-1:0] & ~ic_irq_shadow[IRQW-1:0] ;
ic_irq_shadow[IW-1:0] <= ext_irq[IW-1:0] ;
assign ic_event[IW-1:0] = ext_irq[IW-1:0] & ~ic_irq_shadow[IW-1:0] ;
//###########################
//# ILAT
//###########################
assign ic_ilat_set_data[IRQW-1:0] = reg_wdata[IRQW-1:0] |
ic_ilat_reg[IRQW-1:0];
assign ic_ilat_set_data[IW-1:0] = reg_wdata[IW-1:0] |
ic_ilat_reg[IW-1:0];
assign ic_ilat_clear_data[IRQW-1:0] = ~reg_wdata[IRQW-1:0] &
ic_ilat_reg[IRQW-1:0];
assign ic_ilat_clear_data[IW-1:0] = ~reg_wdata[IW-1:0] &
ic_ilat_reg[IW-1:0];
always @*
for(i=0;i<IRQW;i=i+1)
for(i=0;i<IW;i=i+1)
ic_ilat_in[i] =(ic_write_ilat & reg_wdata[i])| // explicit write
(ic_write_ilatset & ic_ilat_set_data[i]) | // ilatset
(ic_event[i]) | // irq signal
@ -131,32 +122,31 @@ module pic(/*AUTOARG*/
//Don't clock gate the ILAT, should always be ready to recieve
always @ (posedge clk or negedge nreset)
if (!nreset)
ic_ilat_reg[IRQW-1:0] <= 'b0;
ic_ilat_reg[IW-1:0] <= 'b0;
else
ic_ilat_reg[IRQW-1:0] <= ic_ilat_in[IRQW-1:0];
ic_ilat_reg[IW-1:0] <= ic_ilat_in[IW-1:0];
//###########################
//# IPEND
//###########################
assign ic_ipend_shifted_reg[IRQW:0] = {ic_ipend_reg[IRQW-1:0],1'b0};
assign ic_ipend_shifted_reg[IW:0] = {ic_ipend_reg[IW-1:0],1'b0};
genvar q;
generate
for(q=IRQW-1;q>=0;q=q-1) begin : gen_ipend
for(q=IW-1;q>=0;q=q-1) begin : gen_ipend
assign ic_ipend_in[q]=(ic_irq_entry[q]) |
(ic_ipend_reg[q] & ~de_rti_e1) |
(ic_ipend_reg[q] & ~de_rti) |
(|ic_ipend_shifted_reg[q:0]); //BUG?????
end
endgenerate
always @ (posedge clk or negedge nreset)
if (!nreset)
ic_ipend_reg[IRQW-1:0] <= 'b0;
ic_ipend_reg[IW-1:0] <= 'b0;
else if(ic_write_ipend)
ic_ipend_reg[IRQW-1:0] <= reg_wdata[IRQW-1:0];
ic_ipend_reg[IW-1:0] <= reg_wdata[IW-1:0];
else
ic_ipend_reg[IRQW-1:0] <= ic_ipend_in[IRQW-1:0];
ic_ipend_reg[IW-1:0] <= ic_ipend_in[IW-1:0];
//###########################
//# IMASK
@ -164,25 +154,25 @@ module pic(/*AUTOARG*/
always @ (posedge clk or negedge nreset)
if (!nreset)
ic_imask_reg[IRQW-1:0] <= 'b0;
ic_imask_reg[IW-1:0] <= 'b0;
else if(ic_write_imask)
ic_imask_reg[IRQW-1:0] <= reg_wdata[IRQW-1:0];
ic_imask_reg[IW-1:0] <= reg_wdata[IW-1:0];
//###########################
//# IRET
//###########################
always @ (posedge clk)
if(ic_flush)
ic_iret_reg[LAW-1:0] <= sq_pc_next_ra[LAW-1:0];
ic_iret_reg[AW-1:0] <= sq_pc_next[AW-1:0];
else if(ic_write_iret)
ic_iret_reg[LAW-1:0] <= reg_wdata[LAW-1:0];
ic_iret_reg[AW-1:0] <= reg_wdata[AW-1:0];
//###########################
//# IRQ VECTOR TABLE
//###########################
genvar k;
generate
for(k=0;k<IRQW;k=k+1) begin: irqs
for(k=0;k<IW;k=k+1) begin: irqs
assign ic_ivt[k]=(`IRQ_VECTOR_TABLE+4*k);
end
endgenerate
@ -190,10 +180,10 @@ module pic(/*AUTOARG*/
//mux
always @*
begin
ic_irq_addr[LAW-1:0] = {(LAW){1'b0}};
for(p=0;p<IRQW;p=p+1)
ic_irq_addr[LAW-1:0] = ic_irq_addr[LAW-1:0] |
({(LAW){ic_irq_entry[p]}} & ic_ivt[p]);
ic_irq_addr[AW-1:0] = {(AW){1'b0}};
for(p=0;p<IW;p=p+1)
ic_irq_addr[AW-1:0] = ic_irq_addr[AW-1:0] |
({(AW){ic_irq_entry[p]}} & ic_ivt[p]);
end
//###########################
@ -201,8 +191,8 @@ module pic(/*AUTOARG*/
//###########################
//Masking interrupts
assign ic_masked_ilat[IRQW-1:0] = ic_ilat_reg[IRQW-1:0] &
~{ic_imask_reg[IRQW-1:1],1'b0};
assign ic_masked_ilat[IW-1:0] = ic_ilat_reg[IW-1:0] &
~{ic_imask_reg[IW-1:1],1'b0};
//Interrupt sent to sequencer if:
//1.) no bit set in ipend for anything at that bit level or below
@ -214,7 +204,7 @@ module pic(/*AUTOARG*/
//This circuit is needed for the case when interrupts arrive simulataneously
always @*
begin
for(m1=IRQW-1;m1>0;m1=m1-1)
for(m1=IW-1;m1>0;m1=m1-1)
begin
ic_ilat_priority_en_n[m1]=1'b0;
for(m2=m1-1;m2>=0;m2=m2-1)
@ -224,11 +214,10 @@ module pic(/*AUTOARG*/
ic_ilat_priority_en_n[0]=1'b0;
end
//IPEND PRIORITY
always @*
begin
for(n1=IRQW-1;n1>=0;n1=n1-1)
for(n1=IW-1;n1>=0;n1=n1-1)
begin
ic_ipend_priority_en_n[n1]=1'b0;
for(n2=n1;n2>=0;n2=n2-1)
@ -239,23 +228,25 @@ module pic(/*AUTOARG*/
end
//Outgoing Interrupt (to sequencer)
assign ic_irq_select[IRQW-1:0]= ic_masked_ilat[IRQW-1:0] & //only if the ILAT bit is not masked by IMASK
~ic_ilat_priority_en_n[IRQW-1:0] & //only if there is no masked ilat bit <current
~ic_ipend_priority_en_n[IRQW-1:0] & //only if there is no ipend bit <=current
{(IRQW){sq_global_irq_en}}; //global vector for nested interrupts
assign ic_irq_select[IW-1:0]= ic_masked_ilat[IW-1:0] & //only if the ILAT bit is not masked by IMASK
~ic_ilat_priority_en_n[IW-1:0] & //only if there is no masked ilat bit <current
~ic_ipend_priority_en_n[IW-1:0] & //only if there is no ipend bit <=current
{(IW){sq_irq_en}}; //global vector for nested interrupts
//Pipelining interrupt to account for stall signal
//TODO: Understand this better...
always @ (posedge clk or negedge nreset)
if(!nreset)
ic_irq_entry[IRQW-1:0] <= 'b0;
ic_irq_entry[IW-1:0] <= 'b0;
else if(~sq_ic_wait)//includes fetch wait
ic_irq_entry[IRQW-1:0] <= ic_irq_select[IRQW-1:0];// & ~ic_irq_entry[IRQW-1:0] ;
ic_irq_entry[IW-1:0] <= ic_irq_select[IW-1:0];// & ~ic_irq_entry[IW-1:0] ;
assign ic_irq =|(ic_irq_entry[IRQW-1:0]);
assign ic_irq =|(ic_irq_entry[IW-1:0]);
//Flush for one cycle interrupt pulse
assign ic_flush =|(ic_irq_select[IRQW-1:0]);
assign ic_flush =|(ic_irq_select[IW-1:0]);
endmodule // pic
endmodule // interrupt_controller

View File

@ -0,0 +1,3 @@
# SPI slave clock
create_clock -name spi_s_sclk -period 10 [get_ports spi_s_sclk]

6
src/spi/fpga/bit2bin.bif Normal file
View File

@ -0,0 +1,6 @@
the_ROM_image:
{
[bootloader]dummy.elf
./system.runs/impl_1/system_wrapper.bit
}

15
src/spi/fpga/build.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
#clean up
rm system_wrapper.bit.bin bit2bin.bin
#package IP
vivado -mode batch -source package.tcl
#create bit stream
vivado -mode batch -source run.tcl
#xilinx stuff...
bootgen -image bit2bin.bif -split bin
cp system_wrapper.bit.bin parallella.bit.bin

21
src/spi/fpga/clean.sh Executable file
View File

@ -0,0 +1,21 @@
#!/bin/sh
rm -rf component.xml
rm -rf parallella.bit.bin
rm -rf parallella_spi.cache
rm -rf parallella_spi.hw
rm -rf parallella_spi.sim
rm -rf parallella_spi.xpr
rm -rf parallella_spi.zip
rm -rf reports
rm -rf results
rm -rf src
rm -rf system.cache
rm -rf system.hw
rm -rf system.runs
rm -rf system.sim
rm -rf system.srcs
rm -rf system_wrapper.bit.bin
rm -rf system.xpr
rm -rf vivado*.jou
rm -rf vivado*.log
rm -rf xgui

BIN
src/spi/fpga/dummy.elf Normal file

Binary file not shown.

View File

@ -0,0 +1,23 @@
# NOTE: See UG1118 for more information
set design parallella_spi
set projdir ./
set root "../.."
set partname "xc7z020clg400-1"
set hdl_files [list \
$root/spi/hdl \
$root/common/hdl/ \
$root/emesh/hdl \
$root/emmu/hdl \
$root/axi/hdl \
$root/emailbox/hdl \
$root/edma/hdl \
$root/elink/hdl \
$root/parallella/hdl \
]
set ip_files []
set constraints_files []

3
src/spi/fpga/package.tcl Normal file
View File

@ -0,0 +1,3 @@
#STEP1: DEFINE KEY PARAMETERS
source ./ip_params.tcl
source ../../common/fpga/create_ip.tcl

12
src/spi/fpga/run.tcl Normal file
View File

@ -0,0 +1,12 @@
#STEP1: DEFINE KEY PARAMETERS
source ./run_params.tcl
#STEP2: CREATE PROJECT AND READ IN FILES
source ../../common/fpga/system_init.tcl
#STEP 3 (OPTIONAL): EDIT system.bd in VIVADO gui, then go to STEP 4.
##...
#STEP 4: SYNTEHSIZE AND CREATE BITSTRAM
source ../../common/fpga/system_build.tcl

View File

@ -0,0 +1,23 @@
#Design name ("system" recommended)
set design system
#Project directory ("." recommended)
set projdir ./
#Device name
set partname "xc7z020clg400-1"
#Paths to all IP blocks to use in Vivado "system.bd"
set ip_repos [list "."]
#All source files
set hdl_files []
#All constraints files
set constraints_files [list \
../../parallella/fpga/parallella_io.xdc \
../../parallella/fpga/parallella_7020_io.xdc \
./axi_spi_timing.xdc \
]

227
src/spi/fpga/system_bd.tcl Normal file
View File

@ -0,0 +1,227 @@
################################################################
# This is a generated script based on design: system
#
# Though there are limitations about the generated script,
# the main purpose of this utility is to make learning
# IP Integrator Tcl commands easier.
################################################################
################################################################
# Check if script is running in correct Vivado version.
################################################################
set scripts_vivado_version 2015.2
set current_vivado_version [version -short]
if { [string first $scripts_vivado_version $current_vivado_version] == -1 } {
puts ""
puts "ERROR: This script was generated using Vivado <$scripts_vivado_version> and is being run in <$current_vivado_version> of Vivado. Please run the script in Vivado <$scripts_vivado_version> then open the design in Vivado <$current_vivado_version>. Upgrade the design by running \"Tools => Report => Report IP Status...\", then run write_bd_tcl to create an updated script."
return 1
}
################################################################
# START
################################################################
# To test this script, run the following commands from Vivado Tcl console:
# source system_script.tcl
# If you do not already have a project created,
# you can create a project using the following command:
# create_project project_1 myproj -part xc7z020clg400-1
# CHECKING IF PROJECT EXISTS
if { [get_projects -quiet] eq "" } {
puts "ERROR: Please open or create a project!"
return 1
}
# CHANGE DESIGN NAME HERE
set design_name system
# If you do not already have an existing IP Integrator design open,
# you can create a design using the following command:
# create_bd_design $design_name
# Creating design if needed
set errMsg ""
set nRet 0
set cur_design [current_bd_design -quiet]
set list_cells [get_bd_cells -quiet]
if { ${design_name} eq "" } {
# USE CASES:
# 1) Design_name not set
set errMsg "ERROR: Please set the variable <design_name> to a non-empty value."
set nRet 1
} elseif { ${cur_design} ne "" && ${list_cells} eq "" } {
# USE CASES:
# 2): Current design opened AND is empty AND names same.
# 3): Current design opened AND is empty AND names diff; design_name NOT in project.
# 4): Current design opened AND is empty AND names diff; design_name exists in project.
if { $cur_design ne $design_name } {
puts "INFO: Changing value of <design_name> from <$design_name> to <$cur_design> since current design is empty."
set design_name [get_property NAME $cur_design]
}
puts "INFO: Constructing design in IPI design <$cur_design>..."
} elseif { ${cur_design} ne "" && $list_cells ne "" && $cur_design eq $design_name } {
# USE CASES:
# 5) Current design opened AND has components AND same names.
set errMsg "ERROR: Design <$design_name> already exists in your project, please set the variable <design_name> to another value."
set nRet 1
} elseif { [get_files -quiet ${design_name}.bd] ne "" } {
# USE CASES:
# 6) Current opened design, has components, but diff names, design_name exists in project.
# 7) No opened design, design_name exists in project.
set errMsg "ERROR: Design <$design_name> already exists in your project, please set the variable <design_name> to another value."
set nRet 2
} else {
# USE CASES:
# 8) No opened design, design_name not in project.
# 9) Current opened design, has components, but diff names, design_name not in project.
puts "INFO: Currently there is no design <$design_name> in project, so creating one..."
create_bd_design $design_name
puts "INFO: Making design <$design_name> as current_bd_design."
current_bd_design $design_name
}
puts "INFO: Currently the variable <design_name> is equal to \"$design_name\"."
if { $nRet != 0 } {
puts $errMsg
return $nRet
}
##################################################################
# DESIGN PROCs
##################################################################
# Procedure to create entire design; Provide argument to make
# procedure reusable. If parentCell is "", will use root.
proc create_root_design { parentCell } {
if { $parentCell eq "" } {
set parentCell [get_bd_cells /]
}
# Get object for parentCell
set parentObj [get_bd_cells $parentCell]
if { $parentObj == "" } {
puts "ERROR: Unable to find parent cell <$parentCell>!"
return
}
# Make sure parentObj is hier blk
set parentType [get_property TYPE $parentObj]
if { $parentType ne "hier" } {
puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be <hier>."
return
}
# Save current instance; Restore later
set oldCurInst [current_bd_instance .]
# Set parent object as current
current_bd_instance $parentObj
# Create interface ports
# Create ports
set gpio_n [ create_bd_port -dir IO -from 23 -to 0 gpio_n ]
set gpio_p [ create_bd_port -dir IO -from 23 -to 0 gpio_p ]
# Create instance: parallella_spi_0, and set properties
set parallella_spi_0 [ create_bd_cell -type ip -vlnv www.parallella.org:user:parallella_spi:1.0 parallella_spi_0 ]
# Create instance: proc_sys_reset_0, and set properties
set proc_sys_reset_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 proc_sys_reset_0 ]
# Create instance: processing_system7_0, and set properties
set processing_system7_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 processing_system7_0 ]
set_property -dict [ list CONFIG.PCW_CORE0_FIQ_INTR {0} \
CONFIG.PCW_ENET0_ENET0_IO {MIO 16 .. 27} CONFIG.PCW_ENET0_GRP_MDIO_ENABLE {1} \
CONFIG.PCW_ENET0_PERIPHERAL_ENABLE {1} CONFIG.PCW_ENET1_PERIPHERAL_ENABLE {0} \
CONFIG.PCW_EN_CLK3_PORT {1} CONFIG.PCW_FPGA0_PERIPHERAL_FREQMHZ {100} \
CONFIG.PCW_FPGA3_PERIPHERAL_FREQMHZ {100} CONFIG.PCW_GPIO_EMIO_GPIO_ENABLE {1} \
CONFIG.PCW_GPIO_MIO_GPIO_ENABLE {1} CONFIG.PCW_GPIO_MIO_GPIO_IO {MIO} \
CONFIG.PCW_I2C0_I2C0_IO {EMIO} CONFIG.PCW_I2C0_PERIPHERAL_ENABLE {1} \
CONFIG.PCW_I2C0_RESET_ENABLE {0} CONFIG.PCW_IRQ_F2P_INTR {1} \
CONFIG.PCW_IRQ_F2P_MODE {DIRECT} CONFIG.PCW_PRESET_BANK1_VOLTAGE {LVCMOS 1.8V} \
CONFIG.PCW_QSPI_GRP_SINGLE_SS_ENABLE {1} CONFIG.PCW_QSPI_PERIPHERAL_ENABLE {1} \
CONFIG.PCW_SD1_PERIPHERAL_ENABLE {1} CONFIG.PCW_SD1_SD1_IO {MIO 10 .. 15} \
CONFIG.PCW_SDIO_PERIPHERAL_FREQMHZ {50} CONFIG.PCW_UART1_PERIPHERAL_ENABLE {1} \
CONFIG.PCW_UART1_UART1_IO {MIO 8 .. 9} CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY0 {0.434} \
CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY1 {0.398} CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY2 {0.410} \
CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY3 {0.455} CONFIG.PCW_UIPARAM_DDR_CL {9} \
CONFIG.PCW_UIPARAM_DDR_CWL {9} CONFIG.PCW_UIPARAM_DDR_DEVICE_CAPACITY {8192 MBits} \
CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_0 {0.315} CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_1 {0.391} \
CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_2 {0.374} CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_3 {0.271} \
CONFIG.PCW_UIPARAM_DDR_DRAM_WIDTH {32 Bits} CONFIG.PCW_UIPARAM_DDR_FREQ_MHZ {400.00} \
CONFIG.PCW_UIPARAM_DDR_PARTNO {Custom} CONFIG.PCW_UIPARAM_DDR_T_FAW {50} \
CONFIG.PCW_UIPARAM_DDR_T_RAS_MIN {40} CONFIG.PCW_UIPARAM_DDR_T_RC {60} \
CONFIG.PCW_UIPARAM_DDR_T_RCD {9} CONFIG.PCW_UIPARAM_DDR_T_RP {9} \
CONFIG.PCW_UIPARAM_DDR_USE_INTERNAL_VREF {1} CONFIG.PCW_USB0_PERIPHERAL_ENABLE {1} \
CONFIG.PCW_USB0_RESET_ENABLE {0} CONFIG.PCW_USB1_PERIPHERAL_ENABLE {1} \
CONFIG.PCW_USE_FABRIC_INTERRUPT {1} CONFIG.PCW_USE_M_AXI_GP1 {1} \
CONFIG.PCW_USE_S_AXI_HP0 {1} ] $processing_system7_0
# Create instance: processing_system7_0_axi_periph, and set properties
set processing_system7_0_axi_periph [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 processing_system7_0_axi_periph ]
set_property -dict [ list CONFIG.NUM_MI {1} ] $processing_system7_0_axi_periph
# Create instance: sys_concat_intc, and set properties
set sys_concat_intc [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlconcat:2.1 sys_concat_intc ]
set_property -dict [ list CONFIG.NUM_PORTS {16} ] $sys_concat_intc
# Create interface connections
connect_bd_intf_net -intf_net processing_system7_0_M_AXI_GP0 [get_bd_intf_pins processing_system7_0/M_AXI_GP0] [get_bd_intf_pins processing_system7_0_axi_periph/S00_AXI]
connect_bd_intf_net -intf_net processing_system7_0_axi_periph_M00_AXI [get_bd_intf_pins parallella_spi_0/s_axi] [get_bd_intf_pins processing_system7_0_axi_periph/M00_AXI]
# Create port connections
connect_bd_net -net parallella_spi_0_constant_zero [get_bd_pins sys_concat_intc/In0] [get_bd_pins sys_concat_intc/In1] [get_bd_pins sys_concat_intc/In2] [get_bd_pins sys_concat_intc/In3] [get_bd_pins sys_concat_intc/In4] [get_bd_pins sys_concat_intc/In5] [get_bd_pins sys_concat_intc/In6] [get_bd_pins sys_concat_intc/In7] [get_bd_pins sys_concat_intc/In8] [get_bd_pins sys_concat_intc/In10] [get_bd_pins sys_concat_intc/In11] [get_bd_pins sys_concat_intc/In12] [get_bd_pins sys_concat_intc/In13] [get_bd_pins sys_concat_intc/In14] [get_bd_pins sys_concat_intc/In15]
connect_bd_net -net parallella_spi_0_gpio_n [get_bd_ports gpio_n] [get_bd_pins parallella_spi_0/gpio_n]
connect_bd_net -net parallella_spi_0_gpio_p [get_bd_ports gpio_p] [get_bd_pins parallella_spi_0/gpio_p]
connect_bd_net -net parallella_spi_0_spi_irq [get_bd_pins parallella_spi_0/spi_irq] [get_bd_pins sys_concat_intc/In9]
connect_bd_net -net proc_sys_reset_0_interconnect_aresetn [get_bd_pins proc_sys_reset_0/interconnect_aresetn] [get_bd_pins processing_system7_0_axi_periph/ARESETN]
connect_bd_net -net proc_sys_reset_0_peripheral_aresetn [get_bd_pins parallella_spi_0/s_axi_aresetn] [get_bd_pins parallella_spi_0/sys_nreset] [get_bd_pins proc_sys_reset_0/peripheral_aresetn] [get_bd_pins processing_system7_0_axi_periph/M00_ARESETN] [get_bd_pins processing_system7_0_axi_periph/S00_ARESETN]
connect_bd_net -net processing_system7_0_FCLK_CLK0 [get_bd_pins parallella_spi_0/sys_clk] [get_bd_pins proc_sys_reset_0/slowest_sync_clk] [get_bd_pins processing_system7_0/FCLK_CLK0] [get_bd_pins processing_system7_0/M_AXI_GP0_ACLK] [get_bd_pins processing_system7_0/M_AXI_GP1_ACLK] [get_bd_pins processing_system7_0/S_AXI_HP0_ACLK] [get_bd_pins processing_system7_0_axi_periph/ACLK] [get_bd_pins processing_system7_0_axi_periph/M00_ACLK] [get_bd_pins processing_system7_0_axi_periph/S00_ACLK]
connect_bd_net -net processing_system7_0_FCLK_RESET0_N [get_bd_pins proc_sys_reset_0/ext_reset_in] [get_bd_pins processing_system7_0/FCLK_RESET0_N]
connect_bd_net -net sys_concat_intc_dout [get_bd_pins processing_system7_0/IRQ_F2P] [get_bd_pins sys_concat_intc/dout]
# Create address segments
create_bd_addr_seg -range 0x40000000 -offset 0x40000000 [get_bd_addr_spaces processing_system7_0/Data] [get_bd_addr_segs parallella_spi_0/s_axi/axi_lite] SEG_parallella_spi_0_axi_lite
# Restore current instance
current_bd_instance $oldCurInst
save_bd_design
}
# End of create_root_design()
##################################################################
# MAIN FLOW
##################################################################
create_root_design ""

View File

@ -0,0 +1,30 @@
# NOTE: See UG1118 for more information
#########################################
# VARIABLES
#########################################
set design axi_spi
set projdir ./
set root "../.."
set partname "xc7z020clg400-1"
set hdl_files [list \
$root/spi/hdl \
$root/common/hdl/ \
$root/emesh/hdl \
$root/emmu/hdl \
$root/axi/hdl \
$root/emailbox/hdl \
$root/edma/hdl \
$root/elink/hdl \
$root/parallella/hdl \
]
set ip_files []
set constraints_files [list \
../../parallella/fpga/parallella_io.xdc \
../../parallella/fpga/parallella_7020_io.xdc \
./axi_spi_timing.xdc \
]

223
src/spi/hdl/axi_spi.v Normal file
View File

@ -0,0 +1,223 @@
//#############################################################################
//# Purpose: AXI spi module #
//#############################################################################
//# Author: Ola Jeppsson #
//# SPDX-License-Identifier: MIT #
//#############################################################################
module axi_spi(/*AUTOARG*/
// Outputs
spi_s_miso, spi_m_ss, spi_m_sclk, spi_m_mosi, spi_irq,
s_axi_wready, s_axi_rvalid, s_axi_rresp, s_axi_rlast, s_axi_rid,
s_axi_rdata, s_axi_bvalid, s_axi_bresp, s_axi_bid, s_axi_awready,
s_axi_arready,
// Inputs
spi_s_ss, spi_s_sclk, spi_s_mosi, spi_m_miso, s_axi_wvalid,
s_axi_wstrb, s_axi_wlast, s_axi_wid, s_axi_wdata, s_axi_rready,
s_axi_bready, s_axi_awvalid, s_axi_awsize, s_axi_awqos,
s_axi_awprot, s_axi_awlock, s_axi_awlen, s_axi_awid, s_axi_awcache,
s_axi_awburst, s_axi_awaddr, s_axi_arvalid, s_axi_arsize,
s_axi_arqos, s_axi_arprot, s_axi_arlock, s_axi_arlen, s_axi_arid,
s_axi_aresetn, s_axi_arcache, s_axi_arburst, s_axi_araddr,
sys_nreset, sys_clk
);
//########################################################
// INTERFACE
//########################################################
parameter AW = 32; // address width
parameter PW = 2*AW+40; // packet width
parameter ID = 12'h810; // addr[31:20] id
parameter S_IDW = 12; // ID width for S_AXI
//clk, reset
input sys_nreset; // active low async reset
input sys_clk; // system clock for AXI
//############################
// HOST GENERATERD
//############################
//Slave Write
wire s_wr_access;
wire [PW-1:0] s_wr_packet;
wire s_wr_wait;
//Slave Read Request
wire s_rd_access;
wire [PW-1:0] s_rd_packet;
wire s_rd_wait;
//Slave Read Response
wire s_rr_access;
wire [PW-1:0] s_rr_packet;
wire s_rr_wait;
//##############################################################
/*AUTOINPUT*/
// Beginning of automatic inputs (from unused autoinst inputs)
input [31:0] s_axi_araddr; // To esaxi of esaxi.v
input [1:0] s_axi_arburst; // To esaxi of esaxi.v
input [3:0] s_axi_arcache; // To esaxi of esaxi.v
input s_axi_aresetn; // To esaxi of esaxi.v
input [S_IDW-1:0] s_axi_arid; // To esaxi of esaxi.v
input [7:0] s_axi_arlen; // To esaxi of esaxi.v
input s_axi_arlock; // To esaxi of esaxi.v
input [2:0] s_axi_arprot; // To esaxi of esaxi.v
input [3:0] s_axi_arqos; // To esaxi of esaxi.v
input [2:0] s_axi_arsize; // To esaxi of esaxi.v
input s_axi_arvalid; // To esaxi of esaxi.v
input [31:0] s_axi_awaddr; // To esaxi of esaxi.v
input [1:0] s_axi_awburst; // To esaxi of esaxi.v
input [3:0] s_axi_awcache; // To esaxi of esaxi.v
input [S_IDW-1:0] s_axi_awid; // To esaxi of esaxi.v
input [7:0] s_axi_awlen; // To esaxi of esaxi.v
input s_axi_awlock; // To esaxi of esaxi.v
input [2:0] s_axi_awprot; // To esaxi of esaxi.v
input [3:0] s_axi_awqos; // To esaxi of esaxi.v
input [2:0] s_axi_awsize; // To esaxi of esaxi.v
input s_axi_awvalid; // To esaxi of esaxi.v
input s_axi_bready; // To esaxi of esaxi.v
input s_axi_rready; // To esaxi of esaxi.v
input [31:0] s_axi_wdata; // To esaxi of esaxi.v
input [S_IDW-1:0] s_axi_wid; // To esaxi of esaxi.v
input s_axi_wlast; // To esaxi of esaxi.v
input [3:0] s_axi_wstrb; // To esaxi of esaxi.v
input s_axi_wvalid; // To esaxi of esaxi.v
input spi_m_miso; // To spi of spi.v
input spi_s_mosi; // To spi of spi.v
input spi_s_sclk; // To spi of spi.v
input spi_s_ss; // To spi of spi.v
// End of automatics
/*AUTOOUTPUT*/
// Beginning of automatic outputs (from unused autoinst outputs)
output s_axi_arready; // From esaxi of esaxi.v
output s_axi_awready; // From esaxi of esaxi.v
output [S_IDW-1:0] s_axi_bid; // From esaxi of esaxi.v
output [1:0] s_axi_bresp; // From esaxi of esaxi.v
output s_axi_bvalid; // From esaxi of esaxi.v
output [31:0] s_axi_rdata; // From esaxi of esaxi.v
output [S_IDW-1:0] s_axi_rid; // From esaxi of esaxi.v
output s_axi_rlast; // From esaxi of esaxi.v
output [1:0] s_axi_rresp; // From esaxi of esaxi.v
output s_axi_rvalid; // From esaxi of esaxi.v
output s_axi_wready; // From esaxi of esaxi.v
output spi_irq; // From spi of spi.v
output spi_m_mosi; // From spi of spi.v
output spi_m_sclk; // From spi of spi.v
output spi_m_ss; // From spi of spi.v
output spi_s_miso; // From spi of spi.v
// End of automatics
/*AUTOWIRE*/
/*AUTOREG*/
wire spi_wait_out;
wire spi_access_out;
wire [PW-1:0] spi_packet_out;
wire spi_access_in;
wire [PW-1:0] spi_packet_in;
wire spi_wait_in;
/* spi AUTO_TEMPLATE (.\([sm]_.*\) (spi_\1[]),); */
spi #(.AW(AW))
spi (
//Outputs
.hw_en (1'b1),
.wait_out (spi_wait_out),
.access_out (spi_access_out),
.packet_out (spi_packet_out[PW-1:0]),
//Inputs
.nreset (sys_nreset),
.clk (sys_clk),
.access_in (spi_access_in),
.packet_in (spi_packet_in[PW-1:0]),
.wait_in (spi_wait_in),
/*AUTOINST*/
// Outputs
.spi_irq (spi_irq),
.m_sclk (spi_m_sclk), // Templated
.m_mosi (spi_m_mosi), // Templated
.m_ss (spi_m_ss), // Templated
.s_miso (spi_s_miso), // Templated
// Inputs
.m_miso (spi_m_miso), // Templated
.s_sclk (spi_s_sclk), // Templated
.s_mosi (spi_s_mosi), // Templated
.s_ss (spi_s_ss)); // Templated
//########################################################
//AXI SLAVE
//########################################################
emesh_mux #(.N(2),.AW(AW))
mux2(// Outputs
.wait_out ({s_rd_wait, s_wr_wait}),
.access_out (spi_access_in),
.packet_out (spi_packet_in[PW-1:0]),
// Inputs
.access_in ({s_rd_access, s_wr_access}),
.packet_in ({s_rd_packet[PW-1:0], s_wr_packet[PW-1:0]}),
.wait_in (s_rr_wait)
);
esaxi #(.S_IDW(S_IDW))
esaxi (.s_axi_aclk (sys_clk),
.wr_access (s_wr_access),
.wr_packet (s_wr_packet[PW-1:0]),
.rr_wait (s_rr_wait),
.rd_wait (s_rd_wait),
.rr_access (spi_access_out),
.rr_packet (spi_packet_out[PW-1:0]),
.wr_wait (s_wr_wait),
.rd_access (s_rd_access),
.rd_packet (s_rd_packet[PW-1:0]),
/*AUTOINST*/
// Outputs
.s_axi_arready (s_axi_arready),
.s_axi_awready (s_axi_awready),
.s_axi_bid (s_axi_bid[S_IDW-1:0]),
.s_axi_bresp (s_axi_bresp[1:0]),
.s_axi_bvalid (s_axi_bvalid),
.s_axi_rid (s_axi_rid[S_IDW-1:0]),
.s_axi_rdata (s_axi_rdata[31:0]),
.s_axi_rlast (s_axi_rlast),
.s_axi_rresp (s_axi_rresp[1:0]),
.s_axi_rvalid (s_axi_rvalid),
.s_axi_wready (s_axi_wready),
// Inputs
.s_axi_aresetn (s_axi_aresetn),
.s_axi_arid (s_axi_arid[S_IDW-1:0]),
.s_axi_araddr (s_axi_araddr[31:0]),
.s_axi_arburst (s_axi_arburst[1:0]),
.s_axi_arcache (s_axi_arcache[3:0]),
.s_axi_arlock (s_axi_arlock),
.s_axi_arlen (s_axi_arlen[7:0]),
.s_axi_arprot (s_axi_arprot[2:0]),
.s_axi_arqos (s_axi_arqos[3:0]),
.s_axi_arsize (s_axi_arsize[2:0]),
.s_axi_arvalid (s_axi_arvalid),
.s_axi_awid (s_axi_awid[S_IDW-1:0]),
.s_axi_awaddr (s_axi_awaddr[31:0]),
.s_axi_awburst (s_axi_awburst[1:0]),
.s_axi_awcache (s_axi_awcache[3:0]),
.s_axi_awlock (s_axi_awlock),
.s_axi_awlen (s_axi_awlen[7:0]),
.s_axi_awprot (s_axi_awprot[2:0]),
.s_axi_awqos (s_axi_awqos[3:0]),
.s_axi_awsize (s_axi_awsize[2:0]),
.s_axi_awvalid (s_axi_awvalid),
.s_axi_bready (s_axi_bready),
.s_axi_rready (s_axi_rready),
.s_axi_wid (s_axi_wid[S_IDW-1:0]),
.s_axi_wdata (s_axi_wdata[31:0]),
.s_axi_wlast (s_axi_wlast),
.s_axi_wstrb (s_axi_wstrb[3:0]),
.s_axi_wvalid (s_axi_wvalid));
endmodule // axi_spi
// Local Variables:
// verilog-library-directories:("." "../../axi/hdl" "../../common/hdl" "../../emesh/hdl")
// End:

View File

@ -0,0 +1,202 @@
//#############################################################################
//# Purpose: Parallella SPI top #
//#############################################################################
//# Author: Ola Jeppsson #
//# SPDX-License-Identifier: MIT #
//#############################################################################
module parallella_spi(/*AUTOARG*/
// Outputs
spi_s_miso, spi_m_ss, spi_m_sclk, spi_m_mosi, spi_irq,
s_axi_wready, s_axi_rvalid, s_axi_rresp, s_axi_rlast, s_axi_rid,
s_axi_rdata, s_axi_bvalid, s_axi_bresp, s_axi_bid, s_axi_awready,
s_axi_arready,
// Inouts
gpio_n, gpio_p,
// Inputs
s_axi_wvalid, s_axi_wstrb, s_axi_wlast, s_axi_wid, s_axi_wdata,
s_axi_rready, s_axi_bready, s_axi_awvalid, s_axi_awsize,
s_axi_awqos, s_axi_awprot, s_axi_awlock, s_axi_awlen, s_axi_awid,
s_axi_awcache, s_axi_awburst, s_axi_awaddr, s_axi_arvalid,
s_axi_arsize, s_axi_arqos, s_axi_arprot, s_axi_arlock, s_axi_arlen,
s_axi_arid, s_axi_aresetn, s_axi_arcache, s_axi_arburst,
s_axi_araddr, constant_zero, constant_one, sys_nreset, sys_clk
);
//########################################################
// INTERFACE
//########################################################
parameter AW = 32; // address width
parameter DW = 32;
parameter PW = 2*AW+40; // packet width
parameter ID = 12'h7fe; // addr[31:20] id
parameter S_IDW = 12; // ID width for S_AXI
parameter NGPIO = 24; // number of gpio pins
// constants
input constant_zero; // Always 0
input constant_one; // Always 1
//clk, reset
input sys_nreset; // active low async reset
input sys_clk; // system clock for AXI
// gpio pins
inout [NGPIO-1:0] gpio_n; // physical spi pins
inout [NGPIO-1:0] gpio_p; // physical spi pins
wire [NGPIO-1:0] gpio_in; // out gpio pins
wire [NGPIO-1:0] gpio_out; // in gpio pins
wire [NGPIO-1:0] gpio_dir; // gpio pin direction
// spi
wire spi_s_miso;
wire spi_m_ss;
wire spi_m_sclk;
wire spi_m_mosi;
wire spi_s_ss;
wire spi_s_sclk;
wire spi_s_mosi;
wire spi_m_miso;
/*AUTOINPUT*/
// Beginning of automatic inputs (from unused autoinst inputs)
input [31:0] s_axi_araddr; // To axi_spi of axi_spi.v
input [1:0] s_axi_arburst; // To axi_spi of axi_spi.v
input [3:0] s_axi_arcache; // To axi_spi of axi_spi.v
input s_axi_aresetn; // To axi_spi of axi_spi.v
input [S_IDW-1:0] s_axi_arid; // To axi_spi of axi_spi.v
input [7:0] s_axi_arlen; // To axi_spi of axi_spi.v
input s_axi_arlock; // To axi_spi of axi_spi.v
input [2:0] s_axi_arprot; // To axi_spi of axi_spi.v
input [3:0] s_axi_arqos; // To axi_spi of axi_spi.v
input [2:0] s_axi_arsize; // To axi_spi of axi_spi.v
input s_axi_arvalid; // To axi_spi of axi_spi.v
input [31:0] s_axi_awaddr; // To axi_spi of axi_spi.v
input [1:0] s_axi_awburst; // To axi_spi of axi_spi.v
input [3:0] s_axi_awcache; // To axi_spi of axi_spi.v
input [S_IDW-1:0] s_axi_awid; // To axi_spi of axi_spi.v
input [7:0] s_axi_awlen; // To axi_spi of axi_spi.v
input s_axi_awlock; // To axi_spi of axi_spi.v
input [2:0] s_axi_awprot; // To axi_spi of axi_spi.v
input [3:0] s_axi_awqos; // To axi_spi of axi_spi.v
input [2:0] s_axi_awsize; // To axi_spi of axi_spi.v
input s_axi_awvalid; // To axi_spi of axi_spi.v
input s_axi_bready; // To axi_spi of axi_spi.v
input s_axi_rready; // To axi_spi of axi_spi.v
input [31:0] s_axi_wdata; // To axi_spi of axi_spi.v
input [S_IDW-1:0] s_axi_wid; // To axi_spi of axi_spi.v
input s_axi_wlast; // To axi_spi of axi_spi.v
input [3:0] s_axi_wstrb; // To axi_spi of axi_spi.v
input s_axi_wvalid; // To axi_spi of axi_spi.v
// End of automatics
/*AUTOOUTPUT*/
// Beginning of automatic outputs (from unused autoinst outputs)
output s_axi_arready; // From axi_spi of axi_spi.v
output s_axi_awready; // From axi_spi of axi_spi.v
output [S_IDW-1:0] s_axi_bid; // From axi_spi of axi_spi.v
output [1:0] s_axi_bresp; // From axi_spi of axi_spi.v
output s_axi_bvalid; // From axi_spi of axi_spi.v
output [31:0] s_axi_rdata; // From axi_spi of axi_spi.v
output [S_IDW-1:0] s_axi_rid; // From axi_spi of axi_spi.v
output s_axi_rlast; // From axi_spi of axi_spi.v
output [1:0] s_axi_rresp; // From axi_spi of axi_spi.v
output s_axi_rvalid; // From axi_spi of axi_spi.v
output s_axi_wready; // From axi_spi of axi_spi.v
output spi_irq; // From axi_spi of axi_spi.v
output spi_m_mosi; // From axi_spi of axi_spi.v
output spi_m_sclk; // From axi_spi of axi_spi.v
output spi_m_ss; // From axi_spi of axi_spi.v
output spi_s_miso; // From axi_spi of axi_spi.v
// End of automatics
/*AUTOWIRE*/
/*AUTOREG*/
assign spi_s_ss = gpio_in[10];
assign spi_s_miso = gpio_out[9];
assign spi_s_mosi = gpio_in[8];
assign spi_s_sclk = gpio_in[7]; /* Must map to a MRCC/SRCC pin */
assign spi_m_ss = gpio_out[6];
assign spi_m_miso = gpio_in[5];
assign spi_m_mosi = gpio_out[4];
assign spi_m_sclk = gpio_out[3];
/* NOTE: 0 = in, 1 = out */
assign gpio_dir[NGPIO-1:0] = {{(NGPIO-8){1'b0}}, 8'b01001011};
assign constant_zero = 1'b0;
assign constant_one = 1'b1;
pgpio #(.NGPIO(NGPIO),.NPS(NGPIO))
pgpio (.ps_gpio_i (gpio_in[NGPIO-1:0]),
.ps_gpio_o (gpio_out[NGPIO-1:0]),
.ps_gpio_t (~gpio_dir[NGPIO-1:0]),
/*AUTOINST*/
// Inouts
.gpio_p (gpio_p[NGPIO-1:0]),
.gpio_n (gpio_n[NGPIO-1:0]));
axi_spi #(.S_IDW(S_IDW),.AW(AW),.ID(ID))
axi_spi (// Outputs
.spi_irq (spi_irq),
.spi_m_mosi (spi_m_mosi),
.spi_m_sclk (spi_m_sclk),
.spi_m_ss (spi_m_ss),
.spi_s_miso (spi_s_miso),
// Inputs
.spi_m_miso (spi_m_miso),
.spi_s_mosi (spi_s_mosi),
.spi_s_sclk (spi_s_sclk),
.spi_s_ss (spi_s_ss),
/*AUTOINST*/
// Outputs
.s_axi_arready (s_axi_arready),
.s_axi_awready (s_axi_awready),
.s_axi_bid (s_axi_bid[S_IDW-1:0]),
.s_axi_bresp (s_axi_bresp[1:0]),
.s_axi_bvalid (s_axi_bvalid),
.s_axi_rdata (s_axi_rdata[31:0]),
.s_axi_rid (s_axi_rid[S_IDW-1:0]),
.s_axi_rlast (s_axi_rlast),
.s_axi_rresp (s_axi_rresp[1:0]),
.s_axi_rvalid (s_axi_rvalid),
.s_axi_wready (s_axi_wready),
// Inputs
.sys_nreset (sys_nreset),
.sys_clk (sys_clk),
.s_axi_araddr (s_axi_araddr[31:0]),
.s_axi_arburst (s_axi_arburst[1:0]),
.s_axi_arcache (s_axi_arcache[3:0]),
.s_axi_aresetn (s_axi_aresetn),
.s_axi_arid (s_axi_arid[S_IDW-1:0]),
.s_axi_arlen (s_axi_arlen[7:0]),
.s_axi_arlock (s_axi_arlock),
.s_axi_arprot (s_axi_arprot[2:0]),
.s_axi_arqos (s_axi_arqos[3:0]),
.s_axi_arsize (s_axi_arsize[2:0]),
.s_axi_arvalid (s_axi_arvalid),
.s_axi_awaddr (s_axi_awaddr[31:0]),
.s_axi_awburst (s_axi_awburst[1:0]),
.s_axi_awcache (s_axi_awcache[3:0]),
.s_axi_awid (s_axi_awid[S_IDW-1:0]),
.s_axi_awlen (s_axi_awlen[7:0]),
.s_axi_awlock (s_axi_awlock),
.s_axi_awprot (s_axi_awprot[2:0]),
.s_axi_awqos (s_axi_awqos[3:0]),
.s_axi_awsize (s_axi_awsize[2:0]),
.s_axi_awvalid (s_axi_awvalid),
.s_axi_bready (s_axi_bready),
.s_axi_rready (s_axi_rready),
.s_axi_wdata (s_axi_wdata[31:0]),
.s_axi_wid (s_axi_wid[S_IDW-1:0]),
.s_axi_wlast (s_axi_wlast),
.s_axi_wstrb (s_axi_wstrb[3:0]),
.s_axi_wvalid (s_axi_wvalid));
endmodule // parallella_spi
// Local Variables:
// verilog-library-directories:("." "../../axi/hdl" "../../common/hdl" "../../emesh/hdl" "../../parallella/hdl")
// End:

View File

@ -2,59 +2,43 @@
//# Purpose: SPI top (configurable as master or slave) #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see below) #
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module spi (/*AUTOARG*/
// Outputs
spi_irq, access_out, packet_out, wait_out, m_sclk, m_mosi, m_ss,
s_miso,
// Inputs
nreset, clk, hw_en, access_in, packet_in, wait_in, m_miso, s_sclk,
s_mosi, s_ss
);
module spi #( parameter AW = 32, // address width
parameter PW = 104, // packet size
parameter UREGS = 13 // number of user slave regs
)
(//clk, reset, irq
input nreset, // asynch active low reset
input clk, // core clock
input hw_en, // block enable pin
output spi_irq, // interrupt output
//packet from core
input access_in, // access from core
input [PW-1:0] packet_in, // packet from core
input wait_in, // pushback from io
//packet to core
output access_out, // access to core
output [PW-1:0] packet_out, // packet to core
output wait_out, // pushback from core
//master io interface
output m_sclk, // master clock
output m_mosi, // master output
output m_ss, // slave select
input m_miso, // master input
//slave io interface
input s_sclk, // slave clock
input s_mosi, // slave input
input s_ss, // slave select
output s_miso // slave output
);
//##################################################################
//# INTERFACE
//##################################################################
parameter AW = 32; // data width of fifo
parameter PW = 2*AW+40; // packet size
parameter UREGS = 13; // number of user slave regs
//clk, reset, irq
input nreset; // asynch active low reset
input clk; // core clock
input hw_en; // block enable pin
//interrupt output
output spi_irq; // interrupt output
//packet from core
input access_in; // access from core
input [PW-1:0] packet_in; // packet from core
input wait_in; // pushback from io
//packet to core
output access_out; // access to core
output [PW-1:0] packet_out; // packet to core
output wait_out; // pushback from core
//master io interface
output m_sclk; // master clock
output m_mosi; // master output
output m_ss; // slave select
input m_miso; // master input
//slave io interface
input s_sclk; // slave clock
input s_mosi; // slave input
input s_ss; // slave select
output s_miso; // slave output
//###############
//# LOCAL WIRES
//###############
/*AUTOINPUT*/
// End of automatics
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire m_access_out; // From spi_master of spi_master.v
@ -78,7 +62,8 @@ module spi (/*AUTOARG*/
);
*/
spi_master #(.AW(AW))
spi_master #(.AW(AW),
.PW(PW))
spi_master (/*AUTOINST*/
// Outputs
.sclk (m_sclk), // Templated
@ -110,6 +95,7 @@ module spi (/*AUTOARG*/
*/
spi_slave #(.AW(AW),
.PW(PW),
.UREGS(UREGS))
spi_slave (/*AUTOINST*/
// Outputs
@ -137,7 +123,8 @@ module spi (/*AUTOARG*/
assign wait_out = s_wait_out | m_wait_out;
emesh_mux #(.N(2),
.AW(AW))
.AW(AW),
.PW(PW))
emesh_mux (// Outputs
.wait_out (),
.access_out (access_out),
@ -153,27 +140,3 @@ endmodule // spi
// verilog-library-directories:("." "../hdl" "../../emesh/hdl")
// End:
//////////////////////////////////////////////////////////////////////////////
// The MIT License (MIT) //
// //
// Copyright (c) 2015-2016, Adapteva, Inc. //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software")//
// to deal in the Software without restriction, including without limitation//
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included //
// in all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS //
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF //
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. //
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY //
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT//
// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR //
// THE USE OR OTHER DEALINGS IN THE SOFTWARE. //
// //
//////////////////////////////////////////////////////////////////////////////

View File

@ -1,44 +1,38 @@
//#############################################################################
//# Purpose: SPI master (configurable) #
//# Purpose: SPI master #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see below) #
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module spi_master(/*AUTOARG*/
// Outputs
sclk, mosi, ss, wait_out, access_out, packet_out,
// Inputs
clk, nreset, hw_en, miso, access_in, packet_in, wait_in
);
//parameters
parameter DEPTH = 32; // fifo depth
parameter REGS = 16; // total regs
parameter AW = 32; // addresss width
localparam PW = (2*AW+40); // packet width
//clk,reset, cfg
input clk; // core clock
input nreset; // async active low reset
input hw_en; // hardware enable pin
//IO interface
output sclk; // spi clock
output mosi; // slave input
output ss; // slave select
input miso; // slave output
//packet to transmit
input access_in; // access from core
input [PW-1:0] packet_in; // data to core
output wait_out; // pushback from spi register
//return packet
output access_out; // readback access
output [PW-1:0] packet_out; // packet from spi register
input wait_in; // pushback by core
module spi_master # ( parameter DEPTH = 32, // fifo depth
parameter REGS = 16, // total # of regs
parameter AW = 32, // addresss width
parameter PW = 104 // packet width
)
(
//clk,reset, cfg
input clk, // core clock
input nreset, // async active low reset
input hw_en, // hardware enable pin
//IO interface
output sclk, // spi clock
output mosi, // slave input
output ss, // slave select
input miso, // slave output
//packet to transmit
input access_in, // access from core
input [PW-1:0] packet_in, // data to core
output wait_out, // pushback from spi register
//return packet
output access_out, // readback access
output [PW-1:0] packet_out, // packet from spi register
input wait_in // pushback by core
);
//###############
//# LOCAL WIRES
//###############
/*AUTOINPUT*/
/*AUTOOUTPUT*/
@ -63,7 +57,8 @@ module spi_master(/*AUTOARG*/
//# Master control registers
//#####################################################
spi_master_regs #(.AW(AW))
spi_master_regs #(.AW(AW),
.PW(PW))
spi_master_regs (/*AUTOINST*/
// Outputs
.cpol (cpol),
@ -97,6 +92,7 @@ module spi_master(/*AUTOARG*/
*/
spi_master_fifo #(.AW(AW),
.PW(PW),
.DEPTH(DEPTH))
spi_master_fifo(
/*AUTOINST*/
@ -117,7 +113,7 @@ module spi_master(/*AUTOARG*/
//# SPI IO (8 bit)
//#####################################################
spi_master_io #(.AW(AW))
spi_master_io
spi_master_io (/*AUTOINST*/
// Outputs
.spi_state (spi_state[1:0]),
@ -140,28 +136,3 @@ module spi_master(/*AUTOARG*/
endmodule // spi_master
//////////////////////////////////////////////////////////////////////////////
// The MIT License (MIT) //
// //
// Copyright (c) 2015-2016, Adapteva, Inc. //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software")//
// to deal in the Software without restriction, including without limitation//
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included //
// in all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS //
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF //
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. //
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY //
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT//
// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR //
// THE USE OR OTHER DEALINGS IN THE SOFTWARE. //
// //
//////////////////////////////////////////////////////////////////////////////

View File

@ -1,45 +1,46 @@
//#############################################################################
//# Purpose: SPI Master Transmit Fifo #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
`include "spi_regmap.vh"
module spi_master_fifo (/*AUTOARG*/
// Outputs
fifo_prog_full, wait_out, fifo_empty, fifo_dout,
// Inputs
clk, nreset, spi_en, access_in, packet_in, fifo_read
);
//#####################################################################
//# INTERFACE
//#####################################################################
module spi_master_fifo #(parameter DEPTH = 16, // fifo entries
parameter AW = 32, // address width
parameter PW = 104, // input packet width
parameter SW = 8 // io packet width
)
(
//clk,reset, cfg
input clk, // clk
input nreset, // async active low reset
input spi_en, // spi enable
output fifo_prog_full, // fifo full indicator for status
// Incoming interface
input access_in, // access by core
input [PW-1:0] packet_in, // packet from core
output wait_out, // pushback to core
// IO interface
input fifo_read, // pull a byte to IO
output fifo_empty, // fifo is empty
output [SW-1:0] fifo_dout // byte for IO
);
//parameters
parameter DEPTH = 16; // fifo entries
parameter AW = 32; // architecture address width
parameter SW = 8; // output packet width
localparam PW = 2*AW+40; // input packet width
parameter FAW = $clog2(DEPTH); // fifo address width
parameter SRW = $clog2(PW/SW); // serializer cycle count width
//clk,reset, cfg
input clk; // clk
input nreset; // async active low reset
input spi_en; // spi enable
output fifo_prog_full; // fifo full indicator for status
// Incoming interface
input access_in; // access by core
input [PW-1:0] packet_in; // packet from core
output wait_out; // pushback to core
// IO interface
input fifo_read; // pull a byte to IO
output fifo_empty; // fifo is empty
output [SW-1:0] fifo_dout; // byte for IO
//##################################
//# BODY
//##################################
localparam FAW = $clog2(DEPTH); // fifo address width
localparam SRW = $clog2(PW/SW); // serialization factor
//###############
//# LOCAL WIRES
//###############
wire [7:0] datasize;
wire [PW-1:0] tx_data;
wire [SW-1:0] fifo_din;
wire tx_write;
wire fifo_wait;
wire fifo_wr;
wire fifo_full;
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
@ -55,7 +56,8 @@ module spi_master_fifo (/*AUTOARG*/
//# DECODE
//###################################
packet2emesh #(.AW(AW))
packet2emesh #(.AW(AW),
.PW(PW))
p2e (/*AUTOINST*/
// Outputs
.write_in (write_in),

View File

@ -1,59 +1,48 @@
//#############################################################################
//# Purpose: SPI slave IO and statemachine #
//# Purpose: SPI master IO state-machine #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see below) #
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
module spi_master_io(/*AUTOARG*/
// Outputs
spi_state, fifo_read, rx_data, rx_access, sclk, mosi, ss,
// Inputs
clk, nreset, cpol, cpha, lsbfirst, clkdiv_reg, fifo_dout,
fifo_empty, miso
module spi_master_io
(
//clk, reset, cfg
input clk, // core clock
input nreset, // async active low reset
input cpol, // cpol
input cpha, // cpha
input lsbfirst, // send lsbfirst
input [7:0] clkdiv_reg, // baudrate
output reg [1:0] spi_state, // current spi tx state
// data to transmit
input [7:0] fifo_dout, // data payload
input fifo_empty, //
output fifo_read, // read new byte
// receive data (for sregs)
output [63:0] rx_data, // rx data
output rx_access, // transfer done
// IO interface
output sclk, // spi clock
output mosi, // slave input
output ss, // slave select
input miso // slave output
);
//#################################
//# INTERFACE
//#################################
//parameters
parameter REGS = 16; // total regs (16/32/64)
parameter AW = 32; // address width
localparam PW = (2*AW+40); // packet width
//clk, reset, cfg
input clk; // core clock
input nreset; // async active low reset
//cfg
input cpol; // cpol
input cpha; // cpha
input lsbfirst; // send lsbfirst
input [7:0] clkdiv_reg; // baudrate
output [1:0] spi_state; // current spi tx state
//data to transmit
input [7:0] fifo_dout; // data payload
input fifo_empty; //
output fifo_read; // read new byte
//receive data (for sregs)
output [63:0] rx_data; // rx data
output rx_access; // transfer done
//IO interface
output sclk; // spi clock
output mosi; // slave input
output ss; // slave select
input miso; // slave output
reg [1:0] spi_state;
//###############
//# LOCAL WIRES
//###############
reg fifo_empty_reg;
reg load_byte;
wire [7:0] data_out;
wire [15:0] clkphase0;
wire period_match;
wire phase_match;
wire clkout;
wire clkchange;
wire data_done;
wire spi_wait;
wire shift;
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
@ -178,35 +167,9 @@ module spi_master_io(/*AUTOARG*/
.lsbfirst (lsbfirst), // shift direction
.shift (shift)); // shift data
endmodule // spi_slave_io
endmodule // spi_master_io
// Local Variables:
// verilog-library-directories:("." "../../common/hdl" "../../emesh/hdl")
// End:
///////////////////////////////////////////////////////////////////////////////
// The MIT License (MIT) //
// //
// Copyright (c) 2015-2016, Adapteva, Inc. //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software") //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included //
// in all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS //
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF //
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. //
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY //
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT //
// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR //
// THE USE OR OTHER DEALINGS IN THE SOFTWARE. //
// //
///////////////////////////////////////////////////////////////////////////////

View File

@ -1,74 +1,65 @@
//#############################################################################
//# Purpose: SPI master (configurable) #
//# Purpose: SPI master Registers #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see below) #
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
`include "spi_regmap.vh"
module spi_master_regs (/*AUTOARG*/
// Outputs
cpol, cpha, lsbfirst, spi_en, clkdiv_reg, wait_out, access_out,
packet_out,
// Inputs
clk, nreset, hw_en, rx_data, rx_access, spi_state, fifo_prog_full,
fifo_wait, access_in, packet_in, wait_in
);
//parameters
parameter CLKDIV = 1; // default clkdiv
parameter PSIZE = 0; // default is 32 bits
parameter AW = 32; // addresss width
localparam PW = (2*AW+40); // packet width
//clk,reset, cfg
input clk; // core clock
input nreset; // async active low reset
input hw_en; // block enable pin
//io interface
input [63:0] rx_data; // rx data
input rx_access; // rx access pulse
//control
output cpol; // clk polarity (default is 0)
output cpha; // clk phase shift (default is 0)
output lsbfirst; // send lsbfirst
output spi_en; // enable transmitter
output [7:0] clkdiv_reg; // baud rate setting
input [1:0] spi_state; // transmit state
input fifo_prog_full; // fifo reached half/full
input fifo_wait; // tx transfer wait
//packet to transmit
input access_in; // access from core
input [PW-1:0] packet_in; // data to core
output wait_out; // pushback from spi master
//return packet
output access_out; // writeback from spi
output [PW-1:0] packet_out; // writeback data from spi
input wait_in; // pushback by core
//########################################################
//# BODY
//########################################################
module spi_master_regs # (parameter CLKDIV = 1, // default clkdiv
parameter AW = 32, // addresss width
parameter PW = 104 // packet width
)
(
//clk,reset, cfg
input clk, // core clock
input nreset, // async active low reset
input hw_en, // block enable pin
//io interface
input [63:0] rx_data, // rx data
input rx_access, // rx access pulse
//control
output cpol, // clk polarity (default is 0)
output cpha, // clk phase shift (default is 0)
output lsbfirst, // send lsbfirst
output spi_en, // enable transmitter
output reg [7:0] clkdiv_reg, // baud rate setting
input [1:0] spi_state, // transmit state
input fifo_prog_full, // fifo reached half/full
input fifo_wait, // tx transfer wait
//packet to transmit
input access_in, // access from core
input [PW-1:0] packet_in, // data to core
output wait_out, // pushback from spi master
//return packet
output reg access_out, // writeback from spi
output [PW-1:0] packet_out, // writeback data from spi
input wait_in // pushback by core
);
//###############
//# LOCAL WIRES
//###############
reg [7:0] config_reg;
reg [7:0] status_reg;
reg [7:0] clkdiv_reg;
reg [63:0] rx_reg;
reg [AW-1:0] reg_rdata;
reg autotran;
reg access_out;
reg [AW-1:0] dstaddr_out;
reg [4:0] ctrlmode_out;
reg [1:0] datamode_out;
wire [31:0] reg_wdata;
wire reg_write;
wire reg_read;
wire config_write;
wire status_write;
wire clkdiv_write;
wire cmd_write;
wire tx_write;
wire irq_en;
wire wait_pulse;
integer i;
wire [31:0] reg_wdata;
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
@ -84,7 +75,8 @@ module spi_master_regs (/*AUTOARG*/
//# DECODE
//####################################
packet2emesh #(.AW(AW))
packet2emesh #(.AW(AW),
.PW(PW))
pe2 (/*AUTOINST*/
// Outputs
.write_in (write_in),
@ -183,7 +175,7 @@ module spi_master_regs (/*AUTOARG*/
datamode_out[1:0] <= datamode_in[1:0];
end
//create a pulse on register reads
//create a single cycle pulse on register read
oh_edge2pulse
e2pulse (.out (wait_pulse),
.clk (clk),
@ -192,7 +184,8 @@ module spi_master_regs (/*AUTOARG*/
//TODO: fix!
assign wait_out = fifo_wait;
emesh2packet #(.AW(AW))
emesh2packet #(.AW(AW),
.PW(PW))
e2p (.write_out (1'b1),
.srcaddr_out ({(AW){1'b0}}),
.data_out (reg_rdata[AW-1:0]),

View File

@ -1,3 +1,10 @@
//#############################################################################
//# Purpose: SPI Register Map #
//#############################################################################
//# Author: Andreas Olofsson #
//# License: MIT (see LICENSE file in OH! repository) #
//#############################################################################
//8 bit registers [5:0]
`ifndef SPI_REGMAP_VH_
`define SPI_REGMAP_VH_

Some files were not shown because too many files have changed in this diff Show More