Page 1 of 2

Function Generator

Posted: March 6th, 2017, 7:22 pm
by comeau
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)

Re: Function Generator

Posted: March 13th, 2017, 5:17 pm
by comeau
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.

Re: Function Generator

Posted: March 15th, 2017, 11:49 am
by embmicro
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.

Re: Function Generator

Posted: March 15th, 2017, 9:37 pm
by comeau
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 [5 : 0] f_add1;
  reg [1 : 0 ] f_add2;
  wire[8 : 0] sine_data;
  reg [34 : 0] f[63:0][3:0]; //f max 26' by 9' = 35'
  
  sine_rom s_data_inst (.clk(clk),.addr1(f_add1),.addr2(f_add2),.data(sine_data));


  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;
      f_add1 = 63'b0;
      f_add2 = 3'b0;
    end else if(counter==div) begin
      counter<=31'd0;
    end else begin
      // Add flip-flop q <= d statements here
      if(f_add1>6'd63) f_add1=6'b0;
      if(f_add2>2'd2) f_add2=2'd0;
      f[f_add1][f_add2]<=sine_data*div/511;
      f_add1 = f_add1+1'b1;
      f_add2 = f_add2+1'b1;
      counter <= counter+1'b1;
    end
  end
  
endmodule

Code: Select all

module sine_rom (
    input clk,
    input [5:0] addr1,
    input [1:0] addr2,
    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_d = sine_rom[addr1][addr2];
     data_q <= data_d;
  end
  
endmodule

Re: Function Generator

Posted: March 17th, 2017, 11:01 am
by embmicro
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.

Re: Function Generator

Posted: March 17th, 2017, 6:10 pm
by comeau
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.

To answer your questions:
-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.

Re: Function Generator

Posted: March 20th, 2017, 11:40 am
by embmicro
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.

PROJECT SUCCESS

Posted: March 20th, 2017, 7:08 pm
by comeau
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.

Hardware

Posted: March 20th, 2017, 8:43 pm
by comeau
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.

Code

Posted: March 20th, 2017, 8:57 pm
by comeau
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,
    // AVR ADC channel select
    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 [5:0] on_addr_d, on_addr_q;
  reg [5:0] off_addr_d, off_addr_q;
  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
    off_addr_d = off_addr_q +1;
    on_addr_d = on_addr_q +1;
    next_on=f_on[on_addr_q]*div>>9;
    next_off=f_off[off_addr_q]*div>>9;
  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}};
      on_addr_q <= 0;
      off_addr_q <= 0;
      aclk=~aclk;
    end else begin
      if((counter==next_on)&(counter==next_off)) begin
        fnc_d = fnc_q;
        on_addr_q <= on_addr_d;
        off_addr_q <= off_addr_d;
      end else if(counter==next_on) begin
        fnc_d = (fnc_q<<1)+1;
        on_addr_q <= on_addr_d;
      end else if(counter==next_off) begin
        fnc_d = fnc_q>>1;
        off_addr_q <= off_addr_d;
      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 [3:0] addr_d, addr_q;
  reg [1:0] mode_q=0, mode_d;
  reg [31:0] freq_q=32'd2147483, freq_d;
  
  transmit_rom message_rom (
    .clk(clk),
    .addr(addr_q),
    .data(tx_data),
    .mess(state_q)
  );
  assign mode = mode_q;
  assign freq = freq_q;
  always @(*) begin
    state_d = state_q; // default values
    addr_d = addr_q;   // needed to prevent latches
    mode_d = mode_q;
    freq_d = freq_q;
    new_tx_data = 1'b0;
    
    case (state_q)
      IDLE: begin
        addr_d = 4'd0;
        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;
      addr_d = addr_q + 1'b1;
      if (addr_q == MESSAGE_LEN-1)
        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
    addr_q <= addr_d;
  end
  
endmodule

Code: Select all

module transmit_rom (
    input clk,
    input [3:0] mess,
    input [3:0] addr,
    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
    if (addr > 4'd13)
      data_d = " ";
    else
      data_d = rom_data[addr][mess];
  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;