CORE VHS
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. Verilator converts the Verilog code into functionally equivalent C++ code. This is intended for development and debug purposes only and should not be deployed as part of a performance critical system.
The software hooks to the Verilator output code are conditionally compiled from the Foo.c file.
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