CORE ICE
The Core class in nxm.ice.lib provides the standard framework for developing a Java callable Core. The wrappers for each hardware implementation are auto-generated by the inner class definitions in the Java reference class.
The Foo.v code contains the Verilog implementation of the Core. It is used for both the VHS and ICE implementations. The Xilinx ISE or Xflow can be used to generate the bit file to be loaded into the ICE processor module. The Xilinx script provided in the ICE Toolkit's -soc zip file option uses the xflow process to automate compilation of designs.
For example:
unix> alias xi $ICEROOT/code/soc/xilinx unix> xi make v6m hhu 1 USER
will compile the cores defined in the $ICEROOT/code/soc/v6m/mdefs.h file's PE_USER branch and create the download file $ICEROOT/dat/icev6m_hhu.prm which can be loaded into the processor module by resetting the card with the PMFPGA=u flag. The hh in the signature is automatic for processor modules mounted on PIC5 and later cards.
Example
Here is an example Verilog implementation of the noop function contained in the file noopengine.v:
/*
Noop FPGA Core
*/
module noopengine (sclk,srst, scs,saddr, swr,swrbus, srd,srdbus, sack,
ioclk, istat,iena,isel,ibus, ostat,oena,osel,obus, test);
parameter PORT=1; // engine index
parameter IBW=64; // I/O bus width - 32b in processor modules, 64b in main boards (PIC5)
parameter SBW=32; // System bus width - always 32
localparam DBW=32; // Data bus width (internal core use)
input sclk; // system clock
input srst; // system reset
input scs; // system select (qualifies swr and srd for this core)
input swr; // register write
input srd; // register read
input [31:0] saddr; // register address
input [31:0] swrbus; // register data
output [31:0] srdbus; // register data
output sack; // acknowledge
input ioclk; // I/O data bus clock
output istat; // istat - ready to accept 64 by burst
input iena; // input enable (one cycle early) (continuous 64 byte burst)
input [7:0] isel; // input channel selection
input [IBW-1:0] ibus; // input data bus
output ostat; // ostat - ready to provide 64 byte burst
input oena; // output enable (one cycle early) (continuous 64 byte burst)
output [7:0] osel; // output channel selection
output [IBW-1:0] obus;// output data bus
output [7:0] test; // 8 test signals for scope probes
wire L=0, H=1;
assign sack=H;
assign osel=0; // single channel core
// system register address resolution - with pipeline
wire [7:0] sb; swrbank #(0,8) swb (sclk,scs,swr,saddr,sb);
wire swrsys = sb[0]; // system register (required)
wire swrdec = sb[1]; // decimation register (optional)
wire swrgain = sb[2]; // gain register (optional)
wire swrfreq = sb[3]; // freq register (optional
wire swrflag = sb[7]; // flag register (optional)
// system registers - written to by pic_cport() host control software
reg [31:0] system,dec,gain;
always @(posedge sclk) begin
if (srst) system <= 0; else if (swrsys) system <= swrbus;
if (srst) dec <= 0; else if (swrdec) dec <= swrbus;
end
wire enable = system[0]; // core enable
wire dir = system[1]; // direction ? output:input
wire reduce = system[2]; // reduction ? enable:disable
wire [3:0] ifmt = system[11:8]; // input format bit[2:0]? 0=16b 1=8b 2=4b 3=1b 4=32b bit[3]?complex:real
wire [3:0] ofmt = system[15:12]; // output format bit[2:0]? 0=16b 1=8b 2=4b 3=1b 4=32b bit[3]?complex:real
wire reset = !enable; // core reset (at boot or disabled)
wire vena,wena,vstat,wstat;
wire [DBW-1:0] vbus,wbus;
reg ival; always @(posedge ioclk) ival <= iena; // handle iena early
// this reformats any input type to output format 4'h8 = complex 16b
fifoNxMfmt #(IBW,DBW) fi (ioclk,reset, ifmt,istat,ival,ibus, sclk,reset, 4'h8, vstat,vena,vbus);
// example function - replace with call to user verilog or vhdl here
noop inst (sclk,reset,reduce,dec, vstat,vena,vbus, wstat,wena,wbus);
// this reformats the 4'h8 = complex 16b to any output type
fifoNxMfmti #(IBW,DBW) fo (ioclk,reset, ofmt,ostat,oena,obus, sclk,reset, 4'h8, wstat,wena,wbus);
spram #(2,32,0) rs (sclk,scs, saddr[10:2],swr, swrbus,srdbus); // example readback 2kB ram
assign test = {oena,ostat,iena,istat,wena,vena,dir,reset}; // example test probe
endmodule
The above code is the ICE system interface and dataflow engine. It handles the system register interface, as well as the dataflow buffering and reformatting. The specific functional code should be kept separate to allow the function to migrate easily to other frameworks. The following block contains the decimation function handled by the Noop core:
module noop (clk,reset,reduce,dec, vstat,vena,vbus, wstat,wena,wbus);
input clk,reset,reduce;
input [31:0] dec;
input vstat,wstat;
output vena,wena;
input [31:0] vbus;
output [31:0] wbus;
// example noop with dec = decimation-1
reg [9:0] count;
reg vena,vval;
wire zero = (count==0);
wire load = (vena && zero);
always @(posedge clk) begin
if (reset) count <= 0; else if (load) count <= dec[9:0]; else if (vena) count <= count-1;
vena <= vstat && wstat && !reset;
vval <= vena && (zero || !reduce);
end
assign wena = vval;
assign wbus = vbus;
endmodule