## Function Generator

Projects you are planning or working on with the Mojo
comeau
Posts: 21
Joined: March 5th, 2017, 6:07 pm

### Function Generator

Hey Guys,
I'm working on a Mojo analog function generator shield. Basically I want eventually use it instead of buying a (ridiculously) expensive function generator. Obviously with a stock board I'm limited by the 50MHz clock, but I'm mostly doing this for fun and learning.

Code: Select all

``````module sine #(parameter freq=2000) (
input clk,  // clock
input rst,  // reset
output [7:0] fnc
);

reg [31 : 0] counter;
reg [31 : 0] div;
reg [31 : 0] f[7:0][3:0];
initial begin
div=50000000/freq;
f[0][0]=div*169/1000;
f[0][1]=div*330/1000;
f[0][2]=div;
f[0][3]=0;
f[1][0]=div*107/1000;
f[1][1]=div*392/1000;
f[1][2]=div;
f[1][3]=0;
f[2][0]=div*061/1000;
f[2][1]=div*438/1000;
f[2][2]=div;
f[2][3]=0;
f[3][0]=div*019/1000;
f[3][1]=div*480/1000;
f[3][2]=div;
f[3][3]=0;
f[4][0]=0;
f[4][1]=div*519/1000;
f[4][2]=div*980/1000;
f[4][3]=div;
f[5][0]=0;
f[5][1]=div*561/1000;
f[5][2]=div*938/1000;
f[5][3]=div;
f[6][0]=0;
f[6][1]=div*607/1000;
f[6][2]=div*892/1000;
f[6][3]=div;
f[7][0]=0;
f[7][1]=div*669/1000;
f[7][2]=div*830/1000;
f[7][3]=div;

end
genvar i;
generate
for (i = 0; i<8;i=i+1) begin: fnc_gen_loop
assign fnc[i] = ((counter>=f[i][0])&(counter<=f[i][1]))|((counter>=f[i][2])&(counter<=f[i][3]));
end
endgenerate
/* Combinational Logic */
always @* begin

end

/* Sequential Logic */
always @(posedge clk) begin
if (rst) begin
// Add flip-flop reset values here
counter <= 31'b0;
end else if(counter==div) begin
counter<=31'd0;
end else begin
// Add flip-flop q <= d statements here
counter <= counter+1'b1;
end
end

endmodule``````
This one uses basically a look-up-table to determine where it should start and stop the signal. Ideally, it will scale pretty well with frequency, but I need more work to make sure the registers don't overflow etc.
Then the pins will go to the input of an op-amp (on the shield) that would run from the power rails of the mojo. Right now I've got it working for 8 pins and it makes a decent signal. (The sine and triangle waves look very similar at this resolution)
Attachments
small gen.jpg (718.58 KiB) Viewed 5973 times
sine.JPG (107.07 KiB) Viewed 5973 times
saw.JPG (104.31 KiB) Viewed 5973 times
Last edited by comeau on March 13th, 2017, 5:19 pm, edited 1 time in total.

comeau
Posts: 21
Joined: March 5th, 2017, 6:07 pm

### Re: Function Generator

For the record, this design does not scale well. If try to make the freq set at runtime versus compile time it makes the design much larger and you can't fit all four patterns on the chip. In fact I have not been able to fit the sine function with a variable freq on the chip at all. I will poke at it more this week.

embmicro
Posts: 834
Joined: March 24th, 2013, 12:45 pm

### Re: Function Generator

Using the / operator directly is usually not a good idea. It's super slow and takes a ton of space. You should easily be able to fit all this in the Mojo with some clever design.

You could do the line

Code: Select all

``f[0][0]=div*169/1000;``
as

Code: Select all

``f[0][0]=(div*8'd173) >> 10;``
Basically if you can write your fractions as x/2^n you can multiply by x then shift right by n bits. Making n bigger will make the approximation better but result in larger multiplications.

If you need to do division (I don't think you should have to), coregen's divider is probably smaller than the / divider as it can be setup to take multiple cycles. See https://www.xilinx.com/support/document ... iv_gen.pdf for all the tradeoffs you can make.

You can change the 50MHz to a faster clock using some special resources in the FPGA. The easiest way is to use coregen's clock wizard (https://embeddedmicro.com/tutorials/moj ... -generator) to do this. Just remember that higher clocks will make it harder to meet timing.

comeau
Posts: 21
Joined: March 5th, 2017, 6:07 pm

### Re: Function Generator

Thanks for the divider tip. I have a python script that makes the table and it uses base two to be more efficient so this will be super simple to implement. I'm building the hardware right now and it is looking pretty good. The switching is causing a little too much noise on higher frequency but an adjustable low pass filter seems to work pretty good.

By biggest hurdle right now is when I try to change the frequency from a parameter to an adjustable value. This means the FPGA has to calculate the division values on the fly and I'm having a hard time making a efficient (fit-able) version. My thought process was to store the constant and then use math functions to multiply into a new table, but I am doing it horribly wrong. Let me post some fail-code to illustrate my ineptitude. Basically my idea was the first couple hundred clock cycles are random garbage while it calculates what it should be doing and lock into a known state, but I have a horrible resource mismanagement somewhere and can't even build this.

Code: Select all

``````module sine (
input clk,  // clock
input rst,  // reset
input [25 : 0] freq,
output [63:0] fnc
);

reg [25 : 0] div; //div max is 26'
reg [25 : 0] counter; //therefore countermax is 26'
reg [1 : 0 ] f_add2;
wire[8 : 0] sine_data;
reg [34 : 0] f[63:0][3:0]; //f max 26' by 9' = 35'

genvar i;
generate
for (i = 0; i<(64);i=i+1) begin: fnc_gen_loop
assign fnc[i] = ( (counter>=f[i][0]) & (counter<=f[i][1]) ) | (counter>=f[i][2]);
//assign fnc[i+1] = fnc[i];
end
endgenerate
/* Combinational Logic */
always @* begin
div=50000000/freq; //div max is 26bits
end

/* Sequential Logic */
always @(posedge clk) begin
if (rst) begin
// Add flip-flop reset values here
counter <= 31'b0;
end else if(counter==div) begin
counter<=31'd0;
end else begin
// Add flip-flop q <= d statements here
counter <= counter+1'b1;
end
end

endmodule``````

Code: Select all

``````module sine_rom (
input clk,
output [8:0] data
);

reg [8 : 0] sine_rom [63:0][2:0];
initial begin
//Begin ROM, scaling factor 511
sine_rom[0][0]=113;sine_rom[0][1]=142;sine_rom[0][2]=511;
sine_rom[1][0]=103;sine_rom[1][1]=153;sine_rom[1][2]=511;
sine_rom[2][0]=95;sine_rom[2][1]=160;sine_rom[2][2]=511;
sine_rom[3][0]=89;sine_rom[3][1]=166;sine_rom[3][2]=511;
sine_rom[4][0]=84;sine_rom[4][1]=171;sine_rom[4][2]=511;
sine_rom[5][0]=79;sine_rom[5][1]=176;sine_rom[5][2]=511;
sine_rom[6][0]=75;sine_rom[6][1]=181;sine_rom[6][2]=511;
sine_rom[7][0]=71;sine_rom[7][1]=185;sine_rom[7][2]=511;
sine_rom[8][0]=67;sine_rom[8][1]=188;sine_rom[8][2]=511;
sine_rom[9][0]=63;sine_rom[9][1]=192;sine_rom[9][2]=511;
sine_rom[10][0]=60;sine_rom[10][1]=196;sine_rom[10][2]=511;
sine_rom[11][0]=57;sine_rom[11][1]=199;sine_rom[11][2]=511;
sine_rom[12][0]=53;sine_rom[12][1]=202;sine_rom[12][2]=511;
sine_rom[13][0]=50;sine_rom[13][1]=205;sine_rom[13][2]=511;
sine_rom[14][0]=47;sine_rom[14][1]=208;sine_rom[14][2]=511;
sine_rom[15][0]=44;sine_rom[15][1]=211;sine_rom[15][2]=511;
sine_rom[16][0]=41;sine_rom[16][1]=214;sine_rom[16][2]=511;
sine_rom[17][0]=38;sine_rom[17][1]=217;sine_rom[17][2]=511;
sine_rom[18][0]=35;sine_rom[18][1]=220;sine_rom[18][2]=511;
sine_rom[19][0]=33;sine_rom[19][1]=223;sine_rom[19][2]=511;
sine_rom[20][0]=30;sine_rom[20][1]=226;sine_rom[20][2]=511;
sine_rom[21][0]=27;sine_rom[21][1]=228;sine_rom[21][2]=511;
sine_rom[22][0]=25;sine_rom[22][1]=231;sine_rom[22][2]=511;
sine_rom[23][0]=22;sine_rom[23][1]=234;sine_rom[23][2]=511;
sine_rom[24][0]=19;sine_rom[24][1]=236;sine_rom[24][2]=511;
sine_rom[25][0]=17;sine_rom[25][1]=239;sine_rom[25][2]=511;
sine_rom[26][0]=14;sine_rom[26][1]=241;sine_rom[26][2]=511;
sine_rom[27][0]=11;sine_rom[27][1]=244;sine_rom[27][2]=511;
sine_rom[28][0]=9;sine_rom[28][1]=247;sine_rom[28][2]=511;
sine_rom[29][0]=6;sine_rom[29][1]=249;sine_rom[29][2]=511;
sine_rom[30][0]=4;sine_rom[30][1]=252;sine_rom[30][2]=511;
sine_rom[31][0]=1;sine_rom[31][1]=254;sine_rom[31][2]=511;
sine_rom[32][0]=0;sine_rom[32][1]=257;sine_rom[32][2]=510;
sine_rom[33][0]=0;sine_rom[33][1]=259;sine_rom[33][2]=507;
sine_rom[34][0]=0;sine_rom[34][1]=262;sine_rom[34][2]=505;
sine_rom[35][0]=0;sine_rom[35][1]=264;sine_rom[35][2]=502;
sine_rom[36][0]=0;sine_rom[36][1]=267;sine_rom[36][2]=500;
sine_rom[37][0]=0;sine_rom[37][1]=270;sine_rom[37][2]=497;
sine_rom[38][0]=0;sine_rom[38][1]=272;sine_rom[38][2]=494;
sine_rom[39][0]=0;sine_rom[39][1]=275;sine_rom[39][2]=492;
sine_rom[40][0]=0;sine_rom[40][1]=277;sine_rom[40][2]=489;
sine_rom[41][0]=0;sine_rom[41][1]=280;sine_rom[41][2]=486;
sine_rom[42][0]=0;sine_rom[42][1]=283;sine_rom[42][2]=484;
sine_rom[43][0]=0;sine_rom[43][1]=285;sine_rom[43][2]=481;
sine_rom[44][0]=0;sine_rom[44][1]=288;sine_rom[44][2]=478;
sine_rom[45][0]=0;sine_rom[45][1]=291;sine_rom[45][2]=476;
sine_rom[46][0]=0;sine_rom[46][1]=294;sine_rom[46][2]=473;
sine_rom[47][0]=0;sine_rom[47][1]=297;sine_rom[47][2]=470;
sine_rom[48][0]=0;sine_rom[48][1]=300;sine_rom[48][2]=467;
sine_rom[49][0]=0;sine_rom[49][1]=303;sine_rom[49][2]=464;
sine_rom[50][0]=0;sine_rom[50][1]=306;sine_rom[50][2]=461;
sine_rom[51][0]=0;sine_rom[51][1]=309;sine_rom[51][2]=458;
sine_rom[52][0]=0;sine_rom[52][1]=312;sine_rom[52][2]=454;
sine_rom[53][0]=0;sine_rom[53][1]=315;sine_rom[53][2]=451;
sine_rom[54][0]=0;sine_rom[54][1]=319;sine_rom[54][2]=448;
sine_rom[55][0]=0;sine_rom[55][1]=323;sine_rom[55][2]=444;
sine_rom[56][0]=0;sine_rom[56][1]=326;sine_rom[56][2]=440;
sine_rom[57][0]=0;sine_rom[57][1]=330;sine_rom[57][2]=436;
sine_rom[58][0]=0;sine_rom[58][1]=335;sine_rom[58][2]=432;
sine_rom[59][0]=0;sine_rom[59][1]=340;sine_rom[59][2]=427;
sine_rom[60][0]=0;sine_rom[60][1]=345;sine_rom[60][2]=422;
sine_rom[61][0]=0;sine_rom[61][1]=351;sine_rom[61][2]=416;
sine_rom[62][0]=0;sine_rom[62][1]=358;sine_rom[62][2]=408;
sine_rom[63][0]=0;sine_rom[63][1]=369;sine_rom[63][2]=398;
//End ROM
end
reg [8:0] data_d, data_q;

assign data = data_q;

always @(*) begin

end

always @(posedge clk) begin
if (addr1 > 6'd63) data_d = 0;
else if (addr2 > 2'd2) data_d = 0;
else
data_q <= data_d;
end

endmodule``````

embmicro
Posts: 834
Joined: March 24th, 2013, 12:45 pm

### Re: Function Generator

Where are the frequency values coming from? Can you instead specify 1/freq? If you can then you can use fixed point to represent it then a simple multiply and shift will effectively divide by freq. For example, using eight bits 10000000 would be the value 1 and 01000000 would be 0.5. By multiplying by this then shifting right 7 places you can effectively divide by freq.

Also this line

Code: Select all

``f[f_add1][f_add2]<=sine_data*div/511;``
would be better written as

Code: Select all

``f[f_add1][f_add2]<=(sine_data*div) >> 9;``
This will divide by 512 instead of 511 (likely close enough) but where did 511 come from? Can you change your math to make this 512?

How are you adjusting your frequency? I'm confused what f is supposed to hold, what the three entries in your sine rom are for, and what fnc is supposed to hold.

The way I would do this is to make a rom that holds a LUT for the sin function, maybe even with some simple interpolation if necessary. You could use a CORDIC to do actual sin calculations too if you don't have too much else in your design. There are a lot of trade offs to make with the core generator that drastically affect the resource usage. Then have a counter that steps through the ROM and outputs the values. To change the frequency you simply change the delay between steps. I'd feed the module that steps through the rom the number of cycles to delay between steps. I'd then have a separate module that would calculate the number of cycles to delay between steps for a given frequency if required. If you are controlling this from a PC, I'd do these calculations PC side.

You should really never use / unless it is with constants and you know the tools can just replace it.

comeau
Posts: 21
Joined: March 5th, 2017, 6:07 pm

### Re: Function Generator

Lolz. I told you it was a fail before you read it. I appreciate all your help. Yeah I'm gonna try sorting this out this weekend. Thanks for all the help. Right now my Mojo is pumping out a 20MHz wave, so I'm pretty happy. Obviously I need to fix my code very badly, but I'm encouraged.

-The frequency values are coming from mojo_top via another modules that selects the function to generate: sine, saw, square or triangle. The other patterns are working alright. Ideally it will eventually come from a serial usb interface.
-The divide by 511 is based on 511 being the maximum possible 9 bit value. So I was trying to maximize my registers while still making 100% possible. Obviously your way is wayy better.
-f holds the sine switching data. The 32 least significant bits are initially off and turn on at f[x][0]. Then they turn off at f[x][1]. The 32 MSBs are initially on because f[x][0]=0, switch off at f[x][1] and on again at f[x][2]. These are the x intercepts of the equation sin(x*2*pi)+(1/64+2/64*(32-(b+1))) where b is the bit number 0 to 63. This function divides the sin function into 64 equal steps with a 1/64 offset to place the channel in the middle of the range vice top or bottom. (There are 64 total channels with y intercepts from -63/64 to 63/64)
-fnc is the output configuration, basically it is a coordinated pwm and can be seen for the saw function in the o-scope screen shot in my first post.
-Originally freq was a parameter and so the / was not costing me anything that I noticed.

The delay data is actually what I'm holding in the rom. So I'm not 100% how to do what you are saying. Every f value is a point on counter that a channel should switch. The rom is itself the delay.
So fnc gets output to 64 different pins to generate the (I must say sexy) 64 step 3.3Vpp sine wave. That 3.3V gets fed into an opamp where it is amplified and a DC offset can be applied. Basically making my mojo into a swanky benchtop function generator. That's the goal at least.

embmicro
Posts: 834
Joined: March 24th, 2013, 12:45 pm

### Re: Function Generator

Basically what I'm trying to say is that you use a ROM that holds the first quarter of a sine wave. You can then use some logic to flip and negate it to reproduce a full cycle. Then using that module as a sine calculator, you use a counter to be the X input to the function. To change the frequency you simply change the rate that you step through the sine function. You'll likely need to delay multiple clock cycles per step unless you want a really fast frequency then you'll make multiple steps per cycle.

To do this I'd use a counter that has a programmable increment. Say your LUT has 16 bits of precision (14 bit address + 2 bits for the region), then you could have a 32 bit counter. The 16MSBs would be the address (X value) for your sine LUT. The 16LSBs would allow you to delay multiple cycles between each step. By setting the counter step to 1<<16 you'd step once per clock cycle. Anything less would be multiple cycles per step and anything more would be multiple steps per cycle. The frequency would be proportional to 1 over the counter step size.

"I was trying to maximize my registers while still making 100% possible." Usually it is better to use an extra bit to hold the 100% state instead of a division. So use 10 bits and a max of 512 in this case. It kind of seems wasteful, but the extra bit is much cheaper than a non-power of 2 division.

comeau
Posts: 21
Joined: March 5th, 2017, 6:07 pm

### PROJECT SUCCESS

Soooo.
Pretty, it is not.
Technically correct, meh.
As good I as I expected it to be? What is?
However. I have successfully wrote the code for:
1-20Mhz+ square wave
1-700KHz Saw and Triangle Wave
1-250KHz Sine wave.

All four waves are selectable and adjustable via serial connection with my PC!!

Why the maximum limits? The (completely terrible and Justin face-palm inducing) algorithms just don't maintain the wave shape above those limit.
It should be noted that at some point during synthesis, the toolchain strongly suggested I reconsider. I, of course, ignored it.
Photos and "code" to follow.

comeau
Posts: 21
Joined: March 5th, 2017, 6:07 pm

### Hardware

Hardware
So what I did was place 64 1k ohm resistors from the I/O ports of my Mojo converging to a common header. This basically makes a voltage divider so that every individual pin will drive voltage about 1/64*3V3. Is this smart? Meh I put some diode protection to prevent over voltage and I sized the diodes for 3.3mA at 3V3. It meets the maximum per pin current limit, but I feel like I'm probably exceeding the chip maximum.
This then goes to the non-inverting input of an opamp. The inverting input is set by a 10K potentiometer to set the DC offset (in theory).
The opamp is driven by a +/-12V external supply (again in theory).
The second potentiometer you see is designed to set the feedback resistance and therefore the gain of the opamp. It works... ish.
The Mojo board itself is powered from the 5V of the usb and regulated down. The USB also supplies the serial data for wave selection and frequency adjustment.

Here is where it all goes south. The opamp doesn't work. Here is why. In order to have a UART, my computer ground and the Mojo ground have to match. Easy, the USB port does this. However, the power supply fluctuates a lot so the opamp doesn't reliably work unless it is referenced to the power supply. So the solution seems easy, connect the power supply ground to the mojo, right? NOO!!!!! As it turns out, my power supply ground is 8V above my USB ground. This means that if I had connected it, there would be a low resistance path for flow and I would be pumping several dozen watts of energy into my laptop. This is bad. SOoo.. Long story short, the opamp doesn't work because I don't have a reliable +/- 12V supply. Either that or I blew up the opamp, which is very possible.

Also, I want to put out that through hole resistors and point-to-point soldering are absolutely horrible in this project because of the amount of inductance introduced. I did it because it was cheap and easy, but expect a lot of higher frequency noise.
Attachments
small_ps.jpg (1.03 MiB) Viewed 5673 times
small_board.jpg (1.04 MiB) Viewed 5673 times
small_actual.jpg (925.59 KiB) Viewed 5673 times

comeau
Posts: 21
Joined: March 5th, 2017, 6:07 pm

### Code

I coded this project in Verilog. Thanks for the help. I learned a lot. I'm sure my code still completely sucks, but it was a learning experience to be sure. The hardest part was the sine wave. I actually made about five python scripts to figure out what I should do for values. Really the only thing I have good to say about my code is, well, it works!
Also, please note that the UART interface code was shamelessly stolen from the examples.

Code: Select all

``````module mojo_top(
// 50MHz clock input
input clk,
// Input from reset button (active low)
input rst_n,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output[7:0]led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy, // AVR Rx buffer full
output [63:0]fnc
);

wire rst = ~rst_n; // make reset active high

assign led = 8'b0;

wire [7:0] tx_data;
wire new_tx_data;
wire tx_busy;
wire [7:0] rx_data;
wire new_rx_data;
wire [1:0] mode;
wire [31:0] freq;
wire dclk;
clk_wiz_v3_6 cgclk (.CLK_IN1(clk),.CLK_OUT1(dclk),.RESET(rst));

avr_interface #(.CLK_FREQ(100000000)) avr_interface (
.clk(dclk),
.rst(rst),
.cclk(cclk),
.spi_miso(spi_miso),
.spi_mosi(spi_mosi),
.spi_sck(spi_sck),
.spi_ss(spi_ss),
.spi_channel(spi_channel),
.tx(avr_rx), // FPGA tx goes to AVR rx
.rx(avr_tx),
.channel(4'd15), // invalid channel disables the ADC
.new_sample(),
.sample(),
.sample_channel(),
.tx_data(tx_data),
.new_tx_data(new_tx_data),
.tx_busy(tx_busy),
.tx_block(avr_rx_busy),
.rx_data(rx_data),
.new_rx_data(new_rx_data)
);

user_interface mode_selector (
.clk(dclk),
.rst(rst),
.tx_data(tx_data),
.new_tx_data(new_tx_data),
.tx_busy(tx_busy),
.rx_data(rx_data),
.new_rx_data(new_rx_data),
.freq(freq),
.mode(mode)
);

gen_driver gen_driver (
.clk(dclk),
.rst(rst),
.mode(mode),
.freq(freq),
.out(fnc)
);
endmodule
``````

Code: Select all

``````module gen_driver #(parameter duty=50)(
input clk,  // clock
input rst,  // reset
input [1:0] mode,
input [31:0] freq,
output [63:0] out
);
parameter clk_freq=27'd100_000_000;
wire [63:0] saw_out;
wire [63: 0] sine_out;
wire [63: 0] square_out;
wire [63: 0] triangle_out;
reg [63 : 0] gen_out;
wire [26 : 0] div;
reg [58 : 0] div_q,div_d;
//reg [26:0] counter_r;
//wire [26 :0] counter;
//assign counter=counter_r;
assign out=gen_out;
assign div=div_q;
square square_fnc (.clk(clk),.rst(rst),.div(div),.fnc(square_out));
sine sine_fnc (.clk(clk),.rst(rst),.div(div),.fnc(sine_out));
triangle triangle_fnc (.clk(clk),.rst(rst),.div(div),.fnc(triangle_out));
saw saw_fnc (.clk(clk),.rst(rst),.div(div),.fnc(saw_out));

/* Combinational Logic */
always @* begin
div_d<=div_q;
div_d<=clk_freq*freq>>32;
case(mode)
2'b00:gen_out<=square_out;
2'b01:gen_out<=sine_out;
2'b10:gen_out<=triangle_out;
2'b11:gen_out<=saw_out;
endcase
end

/* Sequential Logic */
always @(posedge clk) begin
if (rst) begin
// Add flip-flop reset values here
//counter_r<=27'b0;
//end else if(counter_r==div) begin
//counter_r<=27'b0;
end else begin
// Add flip-flop q <= d statements here
div_q<=div_d;
//counter_r<=counter_r+1'b1;
end
end

endmodule``````

Code: Select all

``````module saw (
input clk,  // clock
input rst,  // reset
input [26 : 0] div,
output [63:0] fnc
);

//parameter clk_freq=27'd100_000_000;
//reg [26 : 0] div;
reg [26 : 0] counter; //therefore countermax is 26'
reg [20 : 0] min_div;
reg [63 : 0] fnc_d,fnc_q;
assign fnc=fnc_q;

initial begin
//div=clk_freq/freq; //div max is 26bits
end

/* Combinational Logic */
always @* begin
min_div=div>>6;
fnc_d = (fnc_q<<1)+1;
end

/* Sequential Logic */
always @(posedge clk) begin
if (rst) begin
// Add flip-flop reset values here
counter <= 27'b0;
fnc_q <= 64'b0;
end else if(counter>=min_div) begin
counter <= 27'd0;
fnc_q <= fnc_d;
end else if(fnc_q[63]==1) begin
fnc_q <=64'b0;
end else begin
// Add flip-flop q <= d statements here
counter <= counter+1'b1;

end
end

endmodule``````

Code: Select all

``````module sine #(
parameter freq = 2000
) (
input clk,  // clock
input rst,  // reset
input [26 : 0] div,
output [63:0] fnc
);

reg [26 : 0] counter; //therefore countermax is 26'
reg [8 : 0] f_on[63:0]; //f max 26' by 9' = 35'
reg [8 : 0] f_off[63:0];
reg [35:0] next_on,next_off;
reg [63 : 0] fnc_d,fnc_q;
reg aclk;
//assign fnc={&fnc_q,next_off[0],off_addr_q[0],next_on[0],on_addr_q[0],aclk,(counter==next_off),(counter==next_on)}; //This is for a quick and dirty debug on my logic analyzer, ignore
assign fnc=fnc_q;
initial begin

fnc_q = {32{1'b1}};
f_on[0]=1;f_on[1]=4;f_on[2]=6;f_on[3]=9;f_on[4]=11;
f_on[5]=14;f_on[6]=17;f_on[7]=19;f_on[8]=22;f_on[9]=25;
f_on[10]=27;f_on[11]=30;f_on[12]=33;f_on[13]=35;f_on[14]=38;
f_on[15]=41;f_on[16]=44;f_on[17]=47;f_on[18]=50;f_on[19]=53;
f_on[20]=57;f_on[21]=60;f_on[22]=64;f_on[23]=67;f_on[24]=71;
f_on[25]=75;f_on[26]=80;f_on[27]=84;f_on[28]=90;f_on[29]=96;
f_on[30]=103;f_on[31]=114;f_on[32]=398;f_on[33]=409;f_on[34]=416;
f_on[35]=422;f_on[36]=428;f_on[37]=432;f_on[38]=437;f_on[39]=441;
f_on[40]=445;f_on[41]=448;f_on[42]=452;f_on[43]=455;f_on[44]=459;
f_on[45]=462;f_on[46]=465;f_on[47]=468;f_on[48]=471;f_on[49]=474;
f_on[50]=477;f_on[51]=479;f_on[52]=482;f_on[53]=485;f_on[54]=487;
f_on[55]=490;f_on[56]=493;f_on[57]=495;f_on[58]=498;f_on[59]=501;
f_on[60]=503;f_on[61]=506;f_on[62]=508;f_on[63]=511;

f_off[0]=142;f_off[1]=153;f_off[2]=160;f_off[3]=166;f_off[4]=172;
f_off[5]=176;f_off[6]=181;f_off[7]=185;f_off[8]=189;f_off[9]=192;
f_off[10]=196;f_off[11]=199;f_off[12]=203;f_off[13]=206;f_off[14]=209;
f_off[15]=212;f_off[16]=215;f_off[17]=218;f_off[18]=221;f_off[19]=223;
f_off[20]=226;f_off[21]=229;f_off[22]=231;f_off[23]=234;f_off[24]=237;
f_off[25]=239;f_off[26]=242;f_off[27]=245;f_off[28]=247;f_off[29]=250;
f_off[30]=252;f_off[31]=255;f_off[32]=257;f_off[33]=260;f_off[34]=262;
f_off[35]=265;f_off[36]=267;f_off[37]=270;f_off[38]=273;f_off[39]=275;
f_off[40]=278;f_off[41]=281;f_off[42]=283;f_off[43]=286;f_off[44]=289;
f_off[45]=291;f_off[46]=294;f_off[47]=297;f_off[48]=300;f_off[49]=303;
f_off[50]=306;f_off[51]=309;f_off[52]=313;f_off[53]=316;f_off[54]=320;
f_off[55]=323;f_off[56]=327;f_off[57]=331;f_off[58]=336;f_off[59]=340;
f_off[60]=346;f_off[61]=352;f_off[62]=359;f_off[63]=370;
next_on=f_on[0]*div>>9;
next_off=f_off[0]*div>>9;
end

/* Combinational Logic */
always @* begin
end

/* Sequential Logic */
always @(posedge clk) begin
if (rst) begin
// Add flip-flop reset values here
counter <= 27'b0;
fnc_q = {32{1'b1}};
end else if(counter>=div) begin
counter<=27'd0;
fnc_q = {32{1'b1}};
aclk=~aclk;
end else begin
if((counter==next_on)&(counter==next_off)) begin
fnc_d = fnc_q;
end else if(counter==next_on) begin
fnc_d = (fnc_q<<1)+1;
end else if(counter==next_off) begin
fnc_d = fnc_q>>1;
end else fnc_d = fnc_q;
counter <= counter+1'b1;
fnc_q = fnc_d;
end
end

endmodule``````

Code: Select all

``````module square #(parameter duty=2) (
input clk,  // clock
input rst,  // reset
input [26:0] div, //Fraction
output [63:0] fnc
);

reg [26 : 0] counter; //therefore countermax is 26'
reg [32 : 0] f; //f max is 26' by 7' = 33'
//reg [63 : 0] div; //max is 27 by 20 = 37'

initial begin

end

assign fnc[63:0] = {64{(counter>=f)}};

/* Combinational Logic */
always @* begin
f=div*duty>>2; //I forgot to implement the duty cycle, it's locked at 50%
end

/* Sequential Logic */
always @(posedge clk) begin
if (rst) begin
// Add flip-flop reset values here
counter <= 27'b0;
end else if(counter>=div) begin
counter<=27'd0;
end else begin
// Add flip-flop q <= d statements here
counter <= counter+1'b1;
end
end

endmodule``````

Code: Select all

``````module triangle (
input clk,  // clock
input rst,  // reset
input [26 : 0] div,
output [63:0] fnc
);

//parameter clk_freq=27'd100_000_000;
//reg [26 : 0] div;
reg [26 : 0] counter; //therefore countermax is 26'
reg [26 : 0] min_div; //Sets delay in cycles for each increment
reg [63 : 0] fnc_d,fnc_q; //Accumulates fnc
reg s_d=1,s_q=0; //Switches accumulate/decrement fnc_ff
assign fnc[63:0]=fnc_q; //Output wire to 64pin bus

initial begin
//div=clk_freq/freq; //div max is 26bits
end

/* Combinational Logic */
always @* begin
s_d=~s_q; //1'ff
min_div=(div>>7);
if(s_q) fnc_d = (fnc_q<<1)+1; //True, increment by 1 bit
else fnc_d = fnc_q>>1; //False, decrement by 1 bit.=
end

/* Sequential Logic */
always @(posedge clk) begin
if (rst) begin
// Add flip-flop reset values here
counter <= 27'b0;
fnc_q <= 64'b0;
end else if(counter==min_div) begin //Counter reaches a minor div, reset counter, increment fnc_ff
counter <= 27'd0;
fnc_q <= fnc_d;
end else counter <= counter+1'b1;
if(&fnc_q&&s_q) s_q <= s_d;  //Decrement
else if(~|fnc_q&&~s_q) s_q <=s_d; //increment
begin
// Add flip-flop q <= d statements here
end
end

endmodule``````

Code: Select all

``````module user_interface (
input clk,
input rst,
output [7:0] tx_data,
output reg new_tx_data,
input tx_busy,
input [7:0] rx_data,
input new_rx_data,
output [31:0] freq,
output [1:0] mode
);

localparam STATE_SIZE = 15;
localparam IDLE = 0,
SQUARE_WAVE = 1,
SINE_WAVE = 2,
TRIANGLE_WAVE = 3,
SAW_WAVE = 4,
UP_FREQ = 5,
DOWN_FREQ = 6,
RESET_FREQ = 7,
SET_1 = 8,
SET_10 = 9,
SET_100 = 10,
SET_1_000 = 11,
SET_10_000 = 12,
SET_100_000 = 13,
SET_1_000_000 =14,
SET_10_000_000 = 15;

localparam MESSAGE_LEN = 14;

reg [STATE_SIZE-1:0] state_d, state_q;

reg [1:0] mode_q=0, mode_d;
reg [31:0] freq_q=32'd2147483, freq_d;

transmit_rom message_rom (
.clk(clk),
.data(tx_data),
.mess(state_q)
);
assign mode = mode_q;
assign freq = freq_q;
always @(*) begin
state_d = state_q; // default values
mode_d = mode_q;
freq_d = freq_q;
new_tx_data = 1'b0;

case (state_q)
IDLE: begin
if (new_rx_data && rx_data == "s")
state_d = SQUARE_WAVE;
if (new_rx_data && rx_data == "i")
state_d = SINE_WAVE;
if (new_rx_data && rx_data == "t")
state_d = TRIANGLE_WAVE;
if (new_rx_data && rx_data == "a")
state_d = SAW_WAVE;
if (new_rx_data && rx_data == "u")
state_d = UP_FREQ;
if (new_rx_data && rx_data == "d")
state_d = DOWN_FREQ;
if (new_rx_data && rx_data == "r")
state_d = RESET_FREQ;
if (new_rx_data && rx_data == "1")
state_d = SET_1;
if (new_rx_data && rx_data == "2")
state_d = SET_10;
if (new_rx_data && rx_data == "3")
state_d = SET_100;
if (new_rx_data && rx_data == "4")
state_d = SET_1_000;
if (new_rx_data && rx_data == "5")
state_d = SET_10_000;
if (new_rx_data && rx_data == "6")
state_d = SET_100_000;
if (new_rx_data && rx_data == "7")
state_d = SET_1_000_000;
if (new_rx_data && rx_data == "8")
state_d = SET_10_000_000;
end
SQUARE_WAVE: begin
mode_d = 2'b00;
end
SINE_WAVE: begin
mode_d = 2'b01;
end
TRIANGLE_WAVE: begin
mode_d = 2'b10;
end
SAW_WAVE: begin
mode_d = 2'b11;
end
UP_FREQ: begin
if ((addr_q == MESSAGE_LEN-1)&(!tx_busy)) freq_d = freq_q>>1;
end
DOWN_FREQ: begin
if ((addr_q == MESSAGE_LEN-1)&(!tx_busy)) freq_d = freq_q<<1;
end
RESET_FREQ: begin
freq_d = 32'd2147483;
end
SET_1: begin
freq_d = 32'd4294967296;
end
SET_10: begin
freq_d = 32'd429496729;
end
SET_100: begin
freq_d = 32'd42949672;
end
SET_1_000: begin
freq_d = 32'd4294967;
end
SET_10_000: begin
freq_d = 32'd429496;
end
SET_100_000: begin
freq_d = 32'd42949;
end
SET_1_000_000: begin
freq_d = 32'd4294;
end
SET_10_000_000: begin
freq_d = 32'd429;
end
default: state_d = IDLE;
endcase
if ((!tx_busy)&(state_d!=IDLE)) begin
new_tx_data = 1'b1;
state_d = IDLE;
end
end

always @(posedge clk) begin
if (rst) begin
state_q <= IDLE;
mode_q<=2'b00;
freq_q<=32'd2147483;
end else begin
state_q <= state_d;
mode_q <= mode_d;
freq_q <= freq_d;
end
end

endmodule``````

Code: Select all

``````module transmit_rom (
input clk,
input [3:0] mess,
output [7:0] data
);

wire [7:0] rom_data [13:0][15:0];

assign rom_data[0][1] = " ";
assign rom_data[1][1] = "S";
assign rom_data[2][1] = "q";
assign rom_data[3][1] = "u";
assign rom_data[4][1] = "a";
assign rom_data[5][1] = "r";
assign rom_data[6][1] = "e";
assign rom_data[7][1] = " ";
assign rom_data[8][1] = "W";
assign rom_data[9][1] = "a";
assign rom_data[10][1] = "v";
assign rom_data[11][1] = "e";
assign rom_data[12][1] = "\n";
assign rom_data[13][1] = "\r";
assign rom_data[0][2] = " ";
assign rom_data[1][2] = "S";
assign rom_data[2][2] = "i";
assign rom_data[3][2] = "n";
assign rom_data[4][2] = "e";
assign rom_data[5][2] = " ";
assign rom_data[6][2] = "W";
assign rom_data[7][2] = "a";
assign rom_data[8][2] = "v";
assign rom_data[9][2] = "e";
assign rom_data[10][2] = " ";
assign rom_data[11][2] = " ";
assign rom_data[12][2] = "\n";
assign rom_data[13][2] = "\r";
assign rom_data[0][3]= " ";
assign rom_data[1][3] = "T";
assign rom_data[2][3] = "r";
assign rom_data[3][3] = "i";
assign rom_data[4][3] = " ";
assign rom_data[5][3] = "W";
assign rom_data[6][3] = "a";
assign rom_data[7][3] = "v";
assign rom_data[8][3] = "e";
assign rom_data[9][3] = " ";
assign rom_data[10][3] = " ";
assign rom_data[11][3] = " ";
assign rom_data[12][3] = "\n";
assign rom_data[13][3] = "\r";
assign rom_data[0][4] = " ";
assign rom_data[1][4] = "S";
assign rom_data[2][4] = "a";
assign rom_data[3][4] = "w";
assign rom_data[4][4] = " ";
assign rom_data[5][4] = "W";
assign rom_data[6][4] = "a";
assign rom_data[7][4] = "v";
assign rom_data[8][4] = "e";
assign rom_data[9][4] = " ";
assign rom_data[10][4] = " ";
assign rom_data[11][4] = " ";
assign rom_data[12][4] = "\n";
assign rom_data[13][4] = "\r";
assign rom_data[0][5] = " ";
assign rom_data[1][5] = "R";
assign rom_data[2][5] = "a";
assign rom_data[3][5] = "i";
assign rom_data[4][5] = "s";
assign rom_data[5][5] = "e";
assign rom_data[6][5] = " ";
assign rom_data[7][5] = "F";
assign rom_data[8][5] = "r";
assign rom_data[9][5] = "e";
assign rom_data[10][5] = "q";
assign rom_data[11][5] = " ";
assign rom_data[12][5] = "\n";
assign rom_data[13][5] = "\r";
assign rom_data[0][6] = " ";
assign rom_data[1][6] = "L";
assign rom_data[2][6] = "o";
assign rom_data[3][6] = "w";
assign rom_data[4][6] = "e";
assign rom_data[5][6] = "r";
assign rom_data[6][6] = " ";
assign rom_data[7][6] = "F";
assign rom_data[8][6] = "r";
assign rom_data[9][6] = "e";
assign rom_data[10][6] = "q";
assign rom_data[11][6] = " ";
assign rom_data[12][6] = "\n";
assign rom_data[13][6] = "\r";
assign rom_data[0][7] = " ";
assign rom_data[1][7] = "R";
assign rom_data[2][7] = "s";
assign rom_data[3][7] = "t";
assign rom_data[4][7] = " ";
assign rom_data[5][7] = "f";
assign rom_data[6][7] = "=";
assign rom_data[7][7] = "2";
assign rom_data[8][7] = "k";
assign rom_data[9][7] = "H";
assign rom_data[10][7] = "a";
assign rom_data[11][7] = " ";
assign rom_data[12][7] = "\n";
assign rom_data[13][7] = "\r";
assign rom_data[0][8] = " ";
assign rom_data[1][8] = "S";
assign rom_data[2][8] = "e";
assign rom_data[3][8] = "t";
assign rom_data[4][8] = " ";
assign rom_data[5][8] = "f";
assign rom_data[6][8] = "=";
assign rom_data[7][8] = "1";
assign rom_data[8][8] = "H";
assign rom_data[9][8] = "z";
assign rom_data[10][8] = " ";
assign rom_data[11][8] = " ";
assign rom_data[12][8] = "\n";
assign rom_data[13][8] = "\r";
assign rom_data[0][9] = " ";
assign rom_data[1][9] = "S";
assign rom_data[2][9] = "e";
assign rom_data[3][9] = "t";
assign rom_data[4][9] = " ";
assign rom_data[5][9] = "f";
assign rom_data[6][9] = "=";
assign rom_data[7][9] = "1";
assign rom_data[8][9] = "0";
assign rom_data[9][9] = "H";
assign rom_data[10][9] = "z";
assign rom_data[11][9] = " ";
assign rom_data[12][9] = "\n";
assign rom_data[13][9] = "\r";
assign rom_data[0][10] = " ";
assign rom_data[1][10] = "S";
assign rom_data[2][10] = "e";
assign rom_data[3][10] = "t";
assign rom_data[4][10] = " ";
assign rom_data[5][10] = "f";
assign rom_data[6][10] = "=";
assign rom_data[7][10] = "1";
assign rom_data[8][10] = "0";
assign rom_data[9][10] = "0";
assign rom_data[10][10] = "H";
assign rom_data[11][10] = "z";
assign rom_data[12][10] = "\n";
assign rom_data[13][10] = "\r";
assign rom_data[0][11] = " ";
assign rom_data[1][11] = "S";
assign rom_data[2][11] = "e";
assign rom_data[3][11] = "t";
assign rom_data[4][11] = " ";
assign rom_data[5][11] = "f";
assign rom_data[6][11] = "=";
assign rom_data[7][11] = "1";
assign rom_data[8][11] = "k";
assign rom_data[9][11] = "H";
assign rom_data[10][11] = "z";
assign rom_data[11][11] = " ";
assign rom_data[12][11] = "\n";
assign rom_data[13][11] = "\r";
assign rom_data[0][12] = " ";
assign rom_data[1][12] = "S";
assign rom_data[2][12] = "e";
assign rom_data[3][12] = "t";
assign rom_data[4][12] = " ";
assign rom_data[5][12] = "f";
assign rom_data[6][12] = "=";
assign rom_data[7][12] = "1";
assign rom_data[8][12] = "0";
assign rom_data[9][12] = "k";
assign rom_data[10][12] = "H";
assign rom_data[11][12] = "z";
assign rom_data[12][12] = "\n";
assign rom_data[13][12] = "\r";
assign rom_data[0][13] = " ";
assign rom_data[1][13] = "S";
assign rom_data[2][13] = "e";
assign rom_data[3][13] = "t";
assign rom_data[4][13] = "f";
assign rom_data[5][13] = "=";
assign rom_data[6][13] = "1";
assign rom_data[7][13] = "0";
assign rom_data[8][13] = "0";
assign rom_data[9][13] = "k";
assign rom_data[10][13] = "H";
assign rom_data[11][13] = "z";
assign rom_data[12][13] = "\n";
assign rom_data[13][13] = "\r";
assign rom_data[0][14] = " ";
assign rom_data[1][14] = "S";
assign rom_data[2][14] = "e";
assign rom_data[3][14] = "t";
assign rom_data[4][14] = " ";
assign rom_data[5][14] = "f";
assign rom_data[6][14] = "=";
assign rom_data[7][14] = "1";
assign rom_data[8][14] = "M";
assign rom_data[9][14] = "H";
assign rom_data[10][14] = "z";
assign rom_data[11][14] = " ";
assign rom_data[12][14] = "\n";
assign rom_data[13][14] = "\r";
assign rom_data[0][15] = " ";
assign rom_data[1][15] = "S";
assign rom_data[2][15] = "e";
assign rom_data[3][15] = "t";
assign rom_data[4][15] = " ";
assign rom_data[5][15] = "f";
assign rom_data[6][15] = "=";
assign rom_data[7][15] = "1";
assign rom_data[8][15] = "0";
assign rom_data[9][15] = "M";
assign rom_data[10][15] = "H";
assign rom_data[11][15] = "z";
assign rom_data[12][15] = "\n";
assign rom_data[13][15] = "\r";
reg [7:0] data_d, data_q;

assign data = data_q;

always @(*) begin
data_d = " ";
else
end

always @(posedge clk) begin
data_q <= data_d;
end

endmodule``````

Code: Select all

``````NET "clk" TNM_NET = clk;
TIMESPEC TS_clk = PERIOD "clk" 50 MHz HIGH 50%;

NET "clk" LOC = P56 | IOSTANDARD = LVTTL;
NET "rst_n" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;
NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;
NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;
NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

NET "fnc<0>" LOC = P51 | IOSTANDARD = LVTTL;
NET "fnc<1>" LOC = P41 | IOSTANDARD = LVTTL;
NET "fnc<2>" LOC = P35 | IOSTANDARD = LVTTL;
NET "fnc<3>" LOC = P33 | IOSTANDARD = LVTTL;
NET "fnc<4>" LOC = P30 | IOSTANDARD = LVTTL;
NET "fnc<5>" LOC = P27 | IOSTANDARD = LVTTL;
NET "fnc<6>" LOC = P24 | IOSTANDARD = LVTTL;
NET "fnc<7>" LOC = P22 | IOSTANDARD = LVTTL;

NET "fnc<8>" LOC = P17 | IOSTANDARD = LVTTL;
NET "fnc<9>" LOC = P15 | IOSTANDARD = LVTTL;
NET "fnc<10>" LOC = P12 | IOSTANDARD = LVTTL;
NET "fnc<11>" LOC = P10 | IOSTANDARD = LVTTL;
NET "fnc<12>" LOC = P8 | IOSTANDARD = LVTTL;
NET "fnc<13>" LOC = P6 | IOSTANDARD = LVTTL;
NET "fnc<14>" LOC = P2 | IOSTANDARD = LVTTL;
NET "fnc<15>" LOC = P50 | IOSTANDARD = LVTTL;

NET "fnc<16>" LOC = P40 | IOSTANDARD = LVTTL;
NET "fnc<17>" LOC = P34 | IOSTANDARD = LVTTL;
NET "fnc<18>" LOC = P32 | IOSTANDARD = LVTTL;
NET "fnc<19>" LOC = P29 | IOSTANDARD = LVTTL;
NET "fnc<20>" LOC = P26 | IOSTANDARD = LVTTL;
NET "fnc<21>" LOC = P23 | IOSTANDARD = LVTTL;
NET "fnc<22>" LOC = P21 | IOSTANDARD = LVTTL;
NET "fnc<23>" LOC = P16 | IOSTANDARD = LVTTL;

NET "fnc<24>" LOC = P14 | IOSTANDARD = LVTTL;
NET "fnc<25>" LOC = P11 | IOSTANDARD = LVTTL;
NET "fnc<26>" LOC = P9 | IOSTANDARD = LVTTL;
NET "fnc<27>" LOC = P7 | IOSTANDARD = LVTTL;
NET "fnc<28>" LOC = P5 | IOSTANDARD = LVTTL;
NET "fnc<29>" LOC = P1 | IOSTANDARD = LVTTL;
NET "fnc<30>" LOC = P143 | IOSTANDARD = LVTTL;
NET "fnc<31>" LOC = P141 | IOSTANDARD = LVTTL;

NET "fnc<32>" LOC = P57 | IOSTANDARD = LVTTL;
NET "fnc<33>" LOC = P66 | IOSTANDARD = LVTTL;
NET "fnc<34>" LOC = P74 | IOSTANDARD = LVTTL;
NET "fnc<35>" LOC = P78 | IOSTANDARD = LVTTL;
NET "fnc<36>" LOC = P80 | IOSTANDARD = LVTTL;
NET "fnc<37>" LOC = P82 | IOSTANDARD = LVTTL;
NET "fnc<38>" LOC = P84 | IOSTANDARD = LVTTL;
NET "fnc<39>" LOC = P87 | IOSTANDARD = LVTTL;

NET "fnc<40>" LOC = P92 | IOSTANDARD = LVTTL;
NET "fnc<41>" LOC = P94 | IOSTANDARD = LVTTL;
NET "fnc<42>" LOC = P97 | IOSTANDARD = LVTTL;
NET "fnc<43>" LOC = P99 | IOSTANDARD = LVTTL;
NET "fnc<44>" LOC = P101 | IOSTANDARD = LVTTL;
NET "fnc<45>" LOC = P104 | IOSTANDARD = LVTTL;
NET "fnc<46>" LOC = P111 | IOSTANDARD = LVTTL;
NET "fnc<47>" LOC = P114 | IOSTANDARD = LVTTL;

NET "fnc<48>" LOC = P58 | IOSTANDARD = LVTTL;
NET "fnc<49>" LOC = P67 | IOSTANDARD = LVTTL;
NET "fnc<50>" LOC = P75 | IOSTANDARD = LVTTL;
NET "fnc<51>" LOC = P79 | IOSTANDARD = LVTTL;
NET "fnc<52>" LOC = P81 | IOSTANDARD = LVTTL;
NET "fnc<53>" LOC = P83 | IOSTANDARD = LVTTL;
NET "fnc<54>" LOC = P85 | IOSTANDARD = LVTTL;
NET "fnc<55>" LOC = P88 | IOSTANDARD = LVTTL;

NET "fnc<56>" LOC = P93 | IOSTANDARD = LVTTL;
NET "fnc<57>" LOC = P95 | IOSTANDARD = LVTTL;
NET "fnc<58>" LOC = P98 | IOSTANDARD = LVTTL;
NET "fnc<59>" LOC = P100 | IOSTANDARD = LVTTL;
NET "fnc<60>" LOC = P102 | IOSTANDARD = LVTTL;
NET "fnc<61>" LOC = P105 | IOSTANDARD = LVTTL;
NET "fnc<62>" LOC = P112 | IOSTANDARD = LVTTL;
NET "fnc<63>" LOC = P115 | IOSTANDARD = LVTTL;``````