Author Topic: Learning FPGAs: wrong approach?  (Read 32464 times)

0 Members and 2 Guests are viewing this topic.

Offline Cerebus

  • Super Contributor
  • ***
  • Posts: 3648
  • Country: gb
Re: Learning FPGAs: wrong approach?
« Reply #25 on: June 16, 2017, 02:50:06 pm »
if you dont care about $ you can "program" fpgas in python ...

You probably think you're joking, but human madness is already past that. Xilinx marketers take python very seriously, and even "scientists" from California University believe that python is the most efficient way to program FPGAs:

https://forums.xilinx.com/t5/Xcell-Daily-Blog/Best-Short-Paper-at-FCCM-2017-gets-30x-from-Python-based-PYNQ/ba-p/765899

https://arxiv.org/pdf/1705.05209.pdf

I think you're jumping to conclusions there. The first URL is talking about using Python (running an a dedicated or soft processor on the FPGA) with pre-packaged bitstreams for the FPGA fabric. So it's just about using Python to interface to things implemented on the FPGA. Just a short way down the page you'll find this quote:

Quote
PYNQ does not currently provide or perform any high-level synthesis or porting of Python applications directly into the FPGA fabric. As a result, a developer still must use create a design using the FPGA fabric. While PYNQ does provide an Overlay framework to support interfacing with the board’s IO, any custom logic must be created and integrated by the developer.

They do indirectly reference a Python to HDL tool, but the thrust of that page (and paper) is not on programming the FPGA fabric in Python.
Anybody got a syringe I can use to squeeze the magic smoke back into this?
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 17998
  • Country: nl
    • NCT Developments
Re: Learning FPGAs: wrong approach?
« Reply #26 on: June 16, 2017, 03:10:22 pm »

You probably already have a good grasp of state machines, but if not, bone up on them because you'll be using them a lot when working with FPGAs.


A state machine is just a C switch statement inside the while(1) loop.  But, just ahead of the switch(), you need to define a default output state for every output signal you create.  Otherwise, you have to define the output state of every signal at every state.

Like this:
Code: [Select]

    process(Reset,Clk) is
    begin
        if Reset = '1' then
            state <= s0;
        elseif rising_edge(clk) then
            state <= NextState;
        end if;
    end process;


    process (state, FullEA, FetchOpnd, F, TAG, IA, CO, OFL, OVFLInd, COtemp, CSET, VSET,
                r_Button0, CCC, CondMet, BOSC_Flag, SavedSign, A_BUS(15), ShiftCount,
                SZ, ZR, DVDS, Result, Ones, OVR,
                CountShifts, ACC, IncludeEXT, EXTN, Rotate, AFR,
                BitCount, XIO_Device, XIO_Function, XIO_Modifier,
                DisplaySwitch,
                ConsoleXIOCmdBusy, ConsoleXIOCmdAck,
                PrinterXIOCmdAck, PrinterXIOCmdBusy,
                ReaderXIOCmdBusy, ReaderXIOCmdAck,
                DiskXIOCmdBusy, DiskXIOCmdAck,
                DiskReady, IAR,
                SingleStep, BreakPointActive, BreakPoint,
                PendingInterrupt, ReturnState_r, StartState) is
    begin
        A_BusCtrl <= A_BUS_NOP;
        ACC_Ctrl <= ACC_NOP;
        ACC_ShiftIn <= '0';
        Add <= '0';
        AFR_Ctrl <= AFR_NOP;
        BitCountCtrl <= BitCount_NOP;
        CI <= '0';
        CIn <= '0';
        CIX <= '0';
        CarryIndCtrl <= CARRY_IND_NOP;

        <and so on...>
       
        case state is
            when s0    => NextState <= s0a; -- use this to IPL
            when s0a  => if DiskReady = '0' then -- wait for disk to go not ready
                                      NextState <= s0b;
                                else
                                      NextState <= s0a;
                                end if;
            when s0b => if DiskReady = '1' and ColdstartHold = '0' then -- wait for disk to go ready and
                                                                                                     -- coldstart code to be copied

            <and so on>
 

There are two processes to create this FSM:  The first just changes the state according to the NextState value on every clock cycle.  In the case of a loop, the state may not actually change.  See the second process...

The second process does all the work and it is not clocked.  It is just a huge collection of combinatorial logic.

Here I defined default outputs for 10 signals (although they aren't shown in the snippet of FSM code).  In the real world, there are 49 of these default outputs and 117 states.

I didn't say anything about the 'sensitivity list' that starts out as
Code: [Select]
process (state, FullEA, FetchOpnd, F, TAG, IA, CO, OFL, OVFLInd, COtemp, CSET, VSET,

This sensitivity list tells the simulator which signals to monitor to decide to actually run the process.  If there are no changes to any signals in the list, the simulator won't evaluate the process.

This list is meaningless to synthesis but the synthesizer will whine if an input signal to the process is undeclared.  But it's just whine and snivel, the output works with or without the list.
This is pretty bad coding because it is prone to creating latches. As a rule of thumb you only have 2 signals at most in the sensitivity list of a process: clock and reset. If there are other signals then it smells fishy. The problem is likely better solved using a function instead of a process.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 1838
  • Country: ca
Re: Learning FPGAs: wrong approach?
« Reply #27 on: June 16, 2017, 04:01:13 pm »
They do indirectly reference a Python to HDL tool, but the thrust of that page (and paper) is not on programming the FPGA fabric in Python.

This is all semantics.

"At a system-level the skill set necessary to integrate multiple custom IP hardware cores, interconnects, memory interfaces, and now heterogeneous processing elements
is complex. Rather than drive FPGA development from the hardware up, we consider the impact of leveraging Python to accelerate application development."

This may not look as FPGA programming to you, but it is to them. Certainly, as they say, they're only at the beginning of that road, but they're on that road.

Note that the fabric per-se doesn't even appear in their description of the pre-Python FPGA programming. For them, FPGA programming is merely integration and interconnection of IPs. They see Python as the way forward to replace the process.

 

Offline legacy

  • Super Contributor
  • ***
  • Posts: 4348
  • Country: ch
Re: Learning FPGAs: wrong approach?
« Reply #28 on: June 16, 2017, 04:15:31 pm »
Xilinx marketers take python very seriously, and even "scientists" from California University believe that python is the most efficient way to program FPGA

So, we have HDL which means Hardware Description Language, and we need to use python?
Does it make sense?

 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 6624
  • Country: us
Re: Learning FPGAs: wrong approach?
« Reply #29 on: June 16, 2017, 04:23:16 pm »

This is pretty bad coding because it is prone to creating latches. As a rule of thumb you only have 2 signals at most in the sensitivity list of a process: clock and reset. If there are other signals then it smells fishy. The problem is likely better solved using a function instead of a process.

The point of defining default output values before the case statement is to guarantee that latches are NOT inferred.  In any event, XST complains when latches are inferred.  Just fix the problem and move on.

I guess I don't see replacing a simple case structure with a multitude of functions although I have seen similar implementations.  In my implementation, I can see by looking at a particular case exactly what outputs I am setting up and it will only be a small subset of the 49 declared.  When I want to know what happens in each step of the Divide instruction, it is all in one place.  Sure, it takes 7 states but they are all written together, as neighbors, not split over several functions.  I could instead create a function for the Load Accumulator signal, for example, but that would require some kind of logic based on 18 values of the 'state' vector.  Basically, a big OR statement on the 'state' vector.  But that scatters the logic all over the place!

Actually, it wouldn't work well because my accumulator process takes 8 different values of the ACC_Ctrl signal to determine what it should do at each clock.  These need to be mutually exclusive and I can't imagine using an 'if-endif' on 8 discrete signals.

Code: [Select]
process(Reset, Clk, ACC_Ctrl)
begin
if Reset = '1' then
ACC <= (others => '0');
elsif Clk'event and Clk = '1' then
case ACC_Ctrl is
when ACC_NOP => null;
when ACC_LOAD => ACC <= A_BUS;
when ACC_AND => ACC <= ACC and A_BUS;
when ACC_OR => ACC <= ACC or A_BUS;
when ACC_EOR => ACC <= ACC xor A_BUS;
when ACC_SHIFT_LEFT => ACC <= ACC(14 downto 0) & ACC_ShiftIn;
when ACC_SHIFT_RIGHT => ACC <= ACC_ShiftIn & ACC(15 downto 1);
when ACC_XCHG => ACC <= EXTN;
when others => null;
end case;
end if;
end process;

But, yes, it is possible to create functions using the 'state' vector as one of parameters.

There's always another way...

 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 6624
  • Country: us
Re: Learning FPGAs: wrong approach?
« Reply #30 on: June 16, 2017, 04:37:20 pm »
Xilinx marketers take python very seriously, and even "scientists" from California University believe that python is the most efficient way to program FPGA

So, we have HDL which means Hardware Description Language, and we need to use python?
Does it make sense?

Not in my world!

One of my favorite quotes (in "A Compiler Generator" McKeeman, Horning & Wortman, 1970, page 11):
Quote

"It is possible by ingenuity and at the expense of clarity..[to do almost anything in any language].  However, the fact that it is possible to push a pea up a mountain with your nose does not mean that this is a sensible way of getting it there.  Each of these techniques of language extension should be used in its proper place."

Christopher Strachey
NATO Summer School in Programming (1969?)
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 1838
  • Country: ca
Re: Learning FPGAs: wrong approach?
« Reply #31 on: June 16, 2017, 04:43:29 pm »
So, we have HDL which means Hardware Description Language, and we need to use python?
Does it make sense?

It doesn't.

But you cannot explain this to The Python programmer. VHDL programming would look totally bizarre to him, because programming in Python is easy (whatever that means).

Similarly, programming by connecting individual LUTs and FFs would look bizarre to a VHDL programmer (such as yourself). If you can imagine the feeling, you know how The Python programmer would feel about the VHDL.
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 616
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Learning FPGAs: wrong approach?
« Reply #32 on: June 16, 2017, 04:58:40 pm »
So, we have HDL which means Hardware Description Language, and we need to use python?
Does it make sense?
Yes, it makes perfect sense.

“The combining of both Python software and FPGA’s performance potential is a significant step in reaching a broader community of developers, akin to Raspberry Pi and Ardiuno. This work studied the performance of common image processing pipelines in C/C++, Python, and custom hardware accelerators to better understand the performance and capabilities of a Python + FPGA development environment. The results are highly promising, with the ability to match and exceed performances from C implementations, up to 30x speedup."

This is what we were promised 20 years ago - the ability to accelerate software performance using reconfigurable hardware.  But instead we just got faster general-purpose CPUs.


 

Offline Cerebus

  • Super Contributor
  • ***
  • Posts: 3648
  • Country: gb
Re: Learning FPGAs: wrong approach?
« Reply #33 on: June 16, 2017, 06:04:26 pm »
They do indirectly reference a Python to HDL tool, but the thrust of that page (and paper) is not on programming the FPGA fabric in Python.

This is all semantics.

It's got nothing to do with semantics which is "the branch of linguistics and logic concerned with meaning". That phrase would only make sense if we were quibbling over the precise meaning of words, which we weren't.

This may not look as FPGA programming to you, but it is to them.

The article says quite explicitly what the are doing and makes it explicitly clear that does not include trying to program the FPGA fabric in Python so I can see no basis for your assertion. It is quite clear that they understand the difference between programming the FPGA fabric and building a application framework around the FPGA in Python. It doesn't fit your narrative of 'Ho, ho, look at them, they think you can program an FPGA in Python'.
Anybody got a syringe I can use to squeeze the magic smoke back into this?
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 1838
  • Country: ca
Re: Learning FPGAs: wrong approach?
« Reply #34 on: June 16, 2017, 06:28:23 pm »
It's got nothing to do with semantics which is "the branch of linguistics and logic concerned with meaning". That phrase would only make sense if we were quibbling over the precise meaning of words, which we weren't.

We are. The words are "Programming FPGA". You interpret them as "Programming fabric with VHDL or alike". The other, broader meaning is "Building applications with FPGA".

It doesn't fit your narrative of 'Ho, ho, look at them, they think you can program an FPGA in Python'.

That's not my narrative. My narrative is:

"Look. Python came to FPGAs too. The guys who are deemed to be scientists, but in fact know very little, write papers where they misinterpret their own facts and come to a wrong conclusions about Python efficiency and suitability. This false interpretation is spread and promoted by Xilinx as an established fact. Now more people will believe all this gibberish. So sad."

 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 4782
  • Country: gb
Re: Learning FPGAs: wrong approach?
« Reply #35 on: June 16, 2017, 06:28:56 pm »

So I (a software engineer with an EE degree from pre-FPGA times) have looked at various FPGAs at various times, and there always seems to be a hump that I have trouble getting over.   And I'm wondering if that's because of where I start - with the datasheet that describes the internal structure of the device.

I was in A very similar boat to you, of a certain vintage EE well before FPGAs.

I must've had a dozen false starts. I (usually) could get as far as running a demo on a dev board and getting a tool chain to work as a script monkey, but beyond that I floundered. There was still a gap between what I wanted to do, and where the tutorials finished.

This was the video that changed my understanding and got me in a position to write my own HDL:



 

Offline Cerebus

  • Super Contributor
  • ***
  • Posts: 3648
  • Country: gb
Re: Learning FPGAs: wrong approach?
« Reply #36 on: June 16, 2017, 06:58:50 pm »
It's got nothing to do with semantics which is "the branch of linguistics and logic concerned with meaning". That phrase would only make sense if we were quibbling over the precise meaning of words, which we weren't.

We are. The words are "Programming FPGA". You interpret them as "Programming fabric with VHDL or alike". The other, broader meaning is "Building applications with FPGA".

It doesn't fit your narrative of 'Ho, ho, look at them, they think you can program an FPGA in Python'.

That's not my narrative. My narrative is:

"Look. Python came to FPGAs too. The guys who are deemed to be scientists, but in fact know very little, write papers where they misinterpret their own facts and come to a wrong conclusions about Python efficiency and suitability. This false interpretation is spread and promoted by Xilinx as an established fact. Now more people will believe all this gibberish. So sad."

I think I'll just leave it at: People can follow the link and decide for themselves what the authors said and whether it agrees with my interpretation or yours.
Anybody got a syringe I can use to squeeze the magic smoke back into this?
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 6624
  • Country: us
Re: Learning FPGAs: wrong approach?
« Reply #37 on: June 16, 2017, 07:27:12 pm »
That MachX02 video is great!  I really like the Lattice Diamond toolchain.
The fact that the board has a ton of IO on pads is a real selling point.
I wonder if I just changed vendors?

Alas, no...  That device doesn't have anywhere near enough BlockRAM and I'm pretty sure it would be short of LUTs for my main project.

OTOH, as a starter board, with LOTS of IO and a compelling price, it seems like an excellent choice!
« Last Edit: June 16, 2017, 07:39:20 pm by rstofer »
 

Offline MK14

  • Super Contributor
  • ***
  • Posts: 2152
  • Country: gb
Re: Learning FPGAs: wrong approach?
« Reply #38 on: June 16, 2017, 07:45:35 pm »
That MachX02 video is great!  I really like the Lattice Diamond toolchain.
The fact that the board has a ton of IO on pads is a real selling point.
I wonder if I just changed vendors?

The amazing and really nice thing about it, is that you can buy them, as shown in the video (now the MachX03 series), for only about $25/£19 from Digikey (there are probably other sellers). It has about 6,900 LE's, so is reasonably powerful, for many things.
It even has about 8 programmable Leds + few more Leds and a few tiny dil switches, for messing with.
Most other FPGA kits, cost considerably more (there are exceptions, I know). They even have configuration storage onboard and/or within the chip, as necessary. The programmer (USB), is included as well (built into board), along with any voltage regulators, crystals etc, as needed.
I.e. It is all ready to run, as is.

But at that price, it is practicable, to design it into your FPGA powered projects. Without having to worry about soldering big pin count BGA parts, and design complicated BGA ready PCB's.

EDIT: You edited your post.
I agree, very big projects (FPGA complexity wise), would need much more powerful chips. Lattice seem to be aiming for the low end.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 6624
  • Country: us
Re: Learning FPGAs: wrong approach?
« Reply #39 on: June 16, 2017, 08:59:54 pm »
That MachX02 video is great!  I really like the Lattice Diamond toolchain.
The fact that the board has a ton of IO on pads is a real selling point.
I wonder if I just changed vendors?

The amazing and really nice thing about it, is that you can buy them, as shown in the video (now the MachX03 series), for only about $25/£19 from Digikey (there are probably other sellers). It has about 6,900 LE's, so is reasonably powerful, for many things.
It even has about 8 programmable Leds + few more Leds and a few tiny dil switches, for messing with.
Most other FPGA kits, cost considerably more (there are exceptions, I know). They even have configuration storage onboard and/or within the chip, as necessary. The programmer (USB), is included as well (built into board), along with any voltage regulators, crystals etc, as needed.
I.e. It is all ready to run, as is.

But at that price, it is practicable, to design it into your FPGA powered projects. Without having to worry about soldering big pin count BGA parts, and design complicated BGA ready PCB's.

EDIT: You edited your post.
I agree, very big projects (FPGA complexity wise), would need much more powerful chips. Lattice seem to be aiming for the low end.

One thing I believe as a newcomer:  The toolchain is more important than the device.  Assuming, of course, that the device is large enough for the project.  I really liked the presentation on Lattice Diamond.  Looking at the MachX03, I think I'll order a board just so I can play with the tools.  The toolchain looks a lot like Xilinx ISE with the added Logic Analyzer feature of Vivado.  This really might be the ultimate startup board.

I never underestimate the number of things that have to work right in order to blink LEDs.  The "HelloWorld" 'program' for FPGAs is every bit the equal of getting it running in C.

---

OK, I ordered the board direct from Lattice - they had stock.  But, damn, they don't offer anything like a reasonable shipping rate.  I'll quit whining...  Soon...
 
The following users thanked this post: MK14

Offline Mattjd

  • Regular Contributor
  • *
  • Posts: 196
  • Country: us
Re: Learning FPGAs: wrong approach?
« Reply #40 on: June 16, 2017, 09:32:50 pm »

You probably already have a good grasp of state machines, but if not, bone up on them because you'll be using them a lot when working with FPGAs.


A state machine is just a C switch statement inside the while(1) loop.  But, just ahead of the switch(), you need to define a default output state for every output signal you create.  Otherwise, you have to define the output state of every signal at every state.

Like this:
Code: [Select]

    process(Reset,Clk) is
    begin
        if Reset = '1' then
            state <= s0;
        elseif rising_edge(clk) then
            state <= NextState;
        end if;
    end process;


    process (state, FullEA, FetchOpnd, F, TAG, IA, CO, OFL, OVFLInd, COtemp, CSET, VSET,
                r_Button0, CCC, CondMet, BOSC_Flag, SavedSign, A_BUS(15), ShiftCount,
                SZ, ZR, DVDS, Result, Ones, OVR,
                CountShifts, ACC, IncludeEXT, EXTN, Rotate, AFR,
                BitCount, XIO_Device, XIO_Function, XIO_Modifier,
                DisplaySwitch,
                ConsoleXIOCmdBusy, ConsoleXIOCmdAck,
                PrinterXIOCmdAck, PrinterXIOCmdBusy,
                ReaderXIOCmdBusy, ReaderXIOCmdAck,
                DiskXIOCmdBusy, DiskXIOCmdAck,
                DiskReady, IAR,
                SingleStep, BreakPointActive, BreakPoint,
                PendingInterrupt, ReturnState_r, StartState) is
    begin
        A_BusCtrl <= A_BUS_NOP;
        ACC_Ctrl <= ACC_NOP;
        ACC_ShiftIn <= '0';
        Add <= '0';
        AFR_Ctrl <= AFR_NOP;
        BitCountCtrl <= BitCount_NOP;
        CI <= '0';
        CIn <= '0';
        CIX <= '0';
        CarryIndCtrl <= CARRY_IND_NOP;

        <and so on...>
       
        case state is
            when s0    => NextState <= s0a; -- use this to IPL
            when s0a  => if DiskReady = '0' then -- wait for disk to go not ready
                                      NextState <= s0b;
                                else
                                      NextState <= s0a;
                                end if;
            when s0b => if DiskReady = '1' and ColdstartHold = '0' then -- wait for disk to go ready and
                                                                                                     -- coldstart code to be copied

            <and so on>
 

There are two processes to create this FSM:  The first just changes the state according to the NextState value on every clock cycle.  In the case of a loop, the state may not actually change.  See the second process...

The second process does all the work and it is not clocked.  It is just a huge collection of combinatorial logic.

Here I defined default outputs for 10 signals (although they aren't shown in the snippet of FSM code).  In the real world, there are 49 of these default outputs and 117 states.

I didn't say anything about the 'sensitivity list' that starts out as
Code: [Select]
process (state, FullEA, FetchOpnd, F, TAG, IA, CO, OFL, OVFLInd, COtemp, CSET, VSET,

This sensitivity list tells the simulator which signals to monitor to decide to actually run the process.  If there are no changes to any signals in the list, the simulator won't evaluate the process.

This list is meaningless to synthesis but the synthesizer will whine if an input signal to the process is undeclared.  But it's just whine and snivel, the output works with or without the list.
This is pretty bad coding because it is prone to creating latches. As a rule of thumb you only have 2 signals at most in the sensitivity list of a process: clock and reset. If there are other signals then it smells fishy. The problem is likely better solved using a function instead of a process.

I'm guessing what Sal wrote is in Python? Explain to me why latches are bad. The overall structure of his code looks similar to what would be found a state machine written in Verilog. In Verilog to create a state machine you need a control and a datapath. The datapath has all the logic you would need for the input and output signals. The Control would be defining your States using parameters followed by 3 Always blocks, 1) For transitioning states on clock edges 2) For defining the transistions 3) For Defining the outputs for each state. Here is code I wrote to display "EXTRA CREDIT PLZ" on a Hitachi 47780, written in Verilog. I know the code is ugly, and I've been working on making my code more legible but there are striking resemblances between what I wrote and what Sal wrote. When I compile this code, Quartus infers latches, but as far as I know, they're necessary.

The Control
Code: [Select]
module LCD_SM(Clock,Reset,
  Delay45ms,Delay80ns,Delay240ns,Delay_TO,Inst_Cnt32,FinalWrite,
  Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,
  Reset40us,Reset100us,
  CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,
  EN,
  FirstWrite);

input Clock, Reset, Delay45ms, Delay80ns, Delay240ns, Delay_TO;
input [4:0] Inst_Cnt32;
input FinalWrite;

output reg Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us;
output reg CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us;
output reg EN;
output reg FirstWrite;

parameter Pwr_Up = 4'b0000;
parameter Pwr_Up_Delay = 4'b0001;
parameter Off_Pwr_Up_Delay = 4'b0010;
parameter Write_Data = 4'b0011;
parameter Data_Setup_Delay = 4'b0100;
parameter E_Pulse_Hi = 4'b0101;
parameter E_Hi_Time = 4'b0110;
parameter E_Pulse_Lo = 4'b0111;
parameter Proc_Comp_Delay = 4'b1000;
parameter Load_Next_Data = 4'b1001;
parameter End0 = 4'b1010;
parameter End1 = 4'b1011;
parameter End2 = 4'b1100;
parameter End3 = 4'b1101;
parameter End4 = 4'b1110;
parameter End5 = 4'b1111;

reg [3:0] state, next_state;

always@(posedge Clock or posedge Reset)
begin
if(Reset)
state <= Pwr_Up;
else
state <= next_state;
end

always@(state or Delay45ms or Delay80ns or Delay240ns or Delay_TO or FinalWrite) //need to add transition signals to go with state
begin
case(state)

default: next_state <= Pwr_Up;

Pwr_Up: next_state <= Pwr_Up_Delay;

Pwr_Up_Delay: if (Delay45ms)
next_state <= Off_Pwr_Up_Delay;
else
next_state <= Pwr_Up_Delay;

Off_Pwr_Up_Delay: next_state <= Write_Data;

Write_Data: next_state <= Data_Setup_Delay;

Data_Setup_Delay: if(Delay80ns)
next_state <= E_Pulse_Hi;
else
next_state <= Data_Setup_Delay;

E_Pulse_Hi: next_state <= E_Hi_Time;

E_Hi_Time: if(Delay240ns)
next_state <= E_Pulse_Lo;
else
next_state <= E_Hi_Time;

E_Pulse_Lo: next_state <= Proc_Comp_Delay;

Proc_Comp_Delay: if(Delay_TO)
next_state <= Load_Next_Data;
else
next_state <= Proc_Comp_Delay;

Load_Next_Data: if(FinalWrite)
next_state <= End0;
else
next_state <= Write_Data;

End0: next_state <= End1;

End1: next_state <= End2;

End2: next_state <= End3;

End3: next_state <= End4;

End4: next_state <= End5;

End5: next_state <= End5;

endcase
end

always@(state or Inst_Cnt32)
begin
case(state)

default:       {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000000;

Pwr_Up:          {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000000;

Pwr_Up_Delay:     {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000010000000;

Off_Pwr_Up_Delay: {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000000;

Write_Data:       {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000000;

Data_Setup_Delay: {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000100000000;

E_Pulse_Hi:       {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000001000000010;

E_Hi_Time:        {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000001000000010;

Proc_Comp_Delay:
begin
if (Inst_Cnt32 == 0)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000001;
end
else if (Inst_Cnt32 == 1)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000100000;
end
else if (Inst_Cnt32 == 2)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000100;
end
else if (Inst_Cnt32 == 3)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 4)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 5)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 6)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000010000;
end
else if (Inst_Cnt32 == 7)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 8)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 9)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 10)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 11)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 12)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 13)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 14)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 15)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 16)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 17)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 18)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 19)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 20)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 21)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 22)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 23)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 24)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 25)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 26)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 27)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 28)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 29)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 30)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 31)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else if (Inst_Cnt32 == 32)
begin
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000001000;
end
else
{Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000000;
end

Load_Next_Data: {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b011000000001001000;

End0:       {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000000;

End1:       {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000000;

End2:       {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000000;

End3:       {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000000;

End4:       {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000000;

End5:       {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000000;

endcase
end

endmodule


The Datapath
Code: [Select]
module LCD_Datapath(CE240ns,CE80ns,CE45ms,CE32,
  CE4ms,CE2ms,CE40us,CE100us,
  Clock,
  Delay45ms,Delay80ns,Delay240ns,Inst_Cnt32,Delay_TO,
  Reset45ms,Reset80ns,Reset240ns,ResetPC,
  Reset4ms,Reset2ms,Reset40us,Reset100us,
  FinalWrite,
  FirstWrite);
 
input Clock;
input Reset45ms,Reset80ns,Reset240ns,ResetPC;
input Reset4ms,Reset2ms,Reset40us,Reset100us;
input CE240ns,CE80ns,CE45ms,CE32;
input CE4ms,CE2ms,CE40us,CE100us;
input FirstWrite;

output [4:0] Inst_Cnt32;
output Delay45ms,Delay80ns,Delay240ns,Delay_TO;
output FinalWrite;

wire [4:0] Eighty_ns,TwoForty_ns;
wire [21:0] FortyFive_ms,Four_ms,Two_ms,Forty_us,Hundred_us;
wire Delay4ms,Delay2ms,Delay40us,Delay100us;
wire FirstWrite;

assign Delay_TO = Delay4ms|Delay2ms|Delay40us|Delay100us|FirstWrite;

//module Counter_22bit(Clock,Reset,CE,Counter);
Counter_22bit FortyFiveMilSec(Clock,Reset45ms,CE45ms,FortyFive_ms),
  FourMilSec(Clock,Reset4ms,CE4ms,Four_ms),
  TwoMilSec(Clock,Reset2ms,CE2ms,Two_ms),
  FortyMicSec(Clock,Reset40us,CE40us,Forty_us),
  HundredMicSec(Clock,Reset100us,CE100us,Hundred_us);


//module Counter_5bit(Clock,Reset,CE,Counter);
Counter_5bit EightyNanSec(Clock,Reset80ns,CE80ns,Eighty_ns),
TwoFourtyNanSec(Clock,Reset240ns,CE240ns,TwoForty_ns),
WriteCounter(Clock,ResetPC,CE32,Inst_Cnt32);

//module comparator_standalone(A,B,G,E,L);
comparator_5bit FinalWriteCompar(Inst_Cnt32,22,G,FinalWrite,L),
Eightyns(Eighty_ns,4,g,Delay80ns,L),
TwoFortyns(TwoForty_ns,12,g,Delay240ns,L);
comparator_22bit FortyFivems(FortyFive_ms,2250000,G,Delay45ms,L),
  Fourms(Four_ms,200000,G,Delay4ms,L),
  Twoms(Two_ms,100000,G,Delay2ms,L),
  Fortyus(Forty_us,2000,G,Delay40us,L),
  Hundredus(Hundred_us,5000,G,Delay100us,L);



endmodule
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 17998
  • Country: nl
    • NCT Developments
Re: Learning FPGAs: wrong approach?
« Reply #41 on: June 16, 2017, 10:09:40 pm »
Latches are bad because you can't control their timing and you they could oscillate before settling to a state or not get into the right state at all. The keyword is asynchronous logic. In an FPGA you want to prevent using asynchronous logic unless you really know what you are doing. The logic inside an FPGA does not receive all inputs simultaneously and most architectures use (strings of) lookup tables to create a combinatorial output so you can get a wild variety of signals at the output of a LUT.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 6624
  • Country: us
Re: Learning FPGAs: wrong approach?
« Reply #42 on: June 16, 2017, 11:01:25 pm »

Code: [Select]
Pwr_Up:          {Reset45ms,Reset80ns,Reset240ns,ResetPC,Reset4ms,Reset2ms,Reset40us,Reset100us,CE240ns,CE80ns,CE45ms,CE32,CE4ms,CE2ms,CE40us,CE100us,EN,FirstWrite} <= 18'b000000000000000000;

This type of coding eliminates the requirement to define default values for the 18 signals but it sure takes a lot of typing when only one or two signals are changing.  Furthermore, if the 8th bit is set, I have to wander through the signal list and count until I figure out which signal has been set.  It isn't immediately obvious.

I have no idea how to assign default values to individual signals in Verilog.

In some ways, your coding looks a lot like microcode.  So, you could create an array of 18 bit values and alias the bits to signal names (does Verilog have aliases?).  Then you could just index into the array as a function of state.

I like microcode and I have thought about building a CPU using that scheme.  It worked for the IBM 360 and a lot of other machines.  Microcoding brought structure to CPU design.

I have always wanted to write a meta-assembler like was used on the AMD bit slice devices.  Those were fun days!

 

Offline Cerebus

  • Super Contributor
  • ***
  • Posts: 3648
  • Country: gb
Re: Learning FPGAs: wrong approach?
« Reply #43 on: June 16, 2017, 11:02:13 pm »
I think it's not that latches are per se bad, it's that in HDL it's very easy to get a latch inferred without you realizing it. If you're looking at a device that has a data sheet that starts 'Transparent D-type latch' you choose it only when it is appropriate, whereas with case statements you have to be careful to make sure that you get what you're asking for.
Anybody got a syringe I can use to squeeze the magic smoke back into this?
 

Offline Mattjd

  • Regular Contributor
  • *
  • Posts: 196
  • Country: us
Re: Learning FPGAs: wrong approach?
« Reply #44 on: June 16, 2017, 11:31:19 pm »
for a case statement in Verilog, default is just "default" I have one in two of my always blocks, a default for state transitions and a default for state outputs. I suppose writing it could be a lot. I mean I use a combination of excel and Sublime text to do my typing. It really speeds things up. For debugging purposes I use a combination of testbenches, compilation reports, and RTL (netlist) viewer. The RTL view is nice because it creates a visual. I can easily find those output bits there.

For example



Thats from the RTL. Say I want to know what bits change from state Pwr_Up to Pwr_Up_Delay. I go into the RTL, find the State instance and select the net that belongs to Pwr_Up_Delay output, the entire net highlights and can be easily traced. That's just me.

Btw, as far as I know. One must account for the outputs and transitions for EVERY state, regardless if those outputs change or not. The "default" case (for outputs) is simply what the signals are going to be upon start up. The "default" case (for transitions) is what the initial state of the state machine is. If you forget to include a state, because the outputs dont change, you will get an error.
« Last Edit: June 16, 2017, 11:36:54 pm by Mattjd »
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 17998
  • Country: nl
    • NCT Developments
Re: Learning FPGAs: wrong approach?
« Reply #45 on: June 16, 2017, 11:44:52 pm »
I think it's not that latches are per se bad, it's that in HDL it's very easy to get a latch inferred without you realizing it. If you're looking at a device that has a data sheet that starts 'Transparent D-type latch' you choose it only when it is appropriate, whereas with case statements you have to be careful to make sure that you get what you're asking for.
One way to avoid that is not to use clock-less processes in VHDL (besides being careful with x when a else y).
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline Mattjd

  • Regular Contributor
  • *
  • Posts: 196
  • Country: us
Re: Learning FPGAs: wrong approach?
« Reply #46 on: June 16, 2017, 11:52:05 pm »
I think it's not that latches are per se bad, it's that in HDL it's very easy to get a latch inferred without you realizing it. If you're looking at a device that has a data sheet that starts 'Transparent D-type latch' you choose it only when it is appropriate, whereas with case statements you have to be careful to make sure that you get what you're asking for.

From the compilation report.

Info (10041): Inferred latch for "y[0]" at Mux_9_bit_32_to_1_behavorial.v(19)
Info (10041): Inferred latch for "y[1]" at Mux_9_bit_32_to_1_behavorial.v(19)
Info (10041): Inferred latch for "y[2]" at Mux_9_bit_32_to_1_behavorial.v(19)
Info (10041): Inferred latch for "y[3]" at Mux_9_bit_32_to_1_behavorial.v(19)
Info (10041): Inferred latch for "y[4]" at Mux_9_bit_32_to_1_behavorial.v(19)
Info (10041): Inferred latch for "y[5]" at Mux_9_bit_32_to_1_behavorial.v(19)
Info (10041): Inferred latch for "y[6]" at Mux_9_bit_32_to_1_behavorial.v(19)
Info (10041): Inferred latch for "y[7]" at Mux_9_bit_32_to_1_behavorial.v(19)
Info (10041): Inferred latch for "y[8]" at Mux_9_bit_32_to_1_behavorial.v(19)
Info (10041): Inferred latch for "y[9]" at Mux_9_bit_32_to_1_behavorial.v(19)
Info (10041): Inferred latch for "y[10]" at Mux_9_bit_32_to_1_behavorial.v(19)
Info (10041): Inferred latch for "y[11]" at Mux_9_bit_32_to_1_behavorial.v(19)
Warning (14026): LATCH primitive "Mux_9_bit_32_to_1_behavorial:MUX_DUT|y[0]" is permanently enabled
Warning (14026): LATCH primitive "Mux_9_bit_32_to_1_behavorial:MUX_DUT|y[1]" is permanently enabled
Warning (14026): LATCH primitive "Mux_9_bit_32_to_1_behavorial:MUX_DUT|y[2]" is permanently enabled
Warning (14026): LATCH primitive "Mux_9_bit_32_to_1_behavorial:MUX_DUT|y[3]" is permanently enabled
Warning (14026): LATCH primitive "Mux_9_bit_32_to_1_behavorial:MUX_DUT|y[4]" is permanently enabled
Warning (14026): LATCH primitive "Mux_9_bit_32_to_1_behavorial:MUX_DUT|y[5]" is permanently enabled
Warning (14026): LATCH primitive "Mux_9_bit_32_to_1_behavorial:MUX_DUT|y[6]" is permanently enabled
Warning (14026): LATCH primitive "Mux_9_bit_32_to_1_behavorial:MUX_DUT|y[8]" is permanently enabled


Now I want those because of how I am using the Mux. I don't know what other software is like but Quartus by Altera gives a nice detailed report of stuff like that it. It also tells you any kind of optimizations like, the removal of registers because of redundant or otherwise bad logic (basically the value of the register is always the same so Quartus removes it). With loads of other stuff.


edit: I'm not arguing about the latches, but that, in my experience, there is a load of information provided upon compilation that is sooo helpful.
« Last Edit: June 16, 2017, 11:58:51 pm by Mattjd »
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 17998
  • Country: nl
    • NCT Developments
Re: Learning FPGAs: wrong approach?
« Reply #47 on: June 17, 2017, 12:07:29 am »
IMHO Xilinx' tools output so many messages for a reasonably sized project that it all becomes useless noise.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline Mattjd

  • Regular Contributor
  • *
  • Posts: 196
  • Country: us
Re: Learning FPGAs: wrong approach?
« Reply #48 on: June 17, 2017, 12:16:51 am »
To each their own I suppose. I don't know what "reasonably sized is" but I have built a 64 bit processor on a DE0 (Cyclone III E3PC16F484C6), using the LCD I spoke of earlier as a peripheral. I even wrote a program for it, the ROM would be read, and would take keyboard input from PS/2 then send the input to the MUX that controls the output to the LCD. Had maybe 500 messages. I found going through them easy. *Shrugs*

This processor was an academic requirement of course and may very well still be considered small. It overclocked to 66 mhz. Base clock was 50 mhz. It was not pipelined, did not have a FPU and could not perform multiplication or division. Very basic processor. The clock multiplier was provided through Altera's megafunction IPs. For the RAM, I made two, one using Altera provided megafunctions, and then describing it in Verilog.

 

Online hamster_nz

  • Super Contributor
  • ***
  • Posts: 2133
  • Country: nz
Re: Learning FPGAs: wrong approach?
« Reply #49 on: June 17, 2017, 12:39:54 am »
Explain to me why latches are bad.

Latches are bad because they are ambiguous.

Code: [Select]
  signal a: std_logic := '0';
  signal b: std_logic := '0';

-- Setting up the test cases
process(clk)
  begin
    if rising_edge(clk) then
       a <= not a;
       b <= not b;
    end if;
  end if;

-- and now a latch.
process(a,b)
  begin
     if a = '1' then
      latch <= b;
     end if;
  end process;

So, if 'a' changes from 1 to 0, and and 'b' also changes from 1 to 0 at the same time, what value ends up in 'latch'?

Ambiguity is evil in digital design.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf