Jump to content

Photo

VHDL for a 9902

9902 vhdl

37 replies to this topic

#26 matthew180 OFFLINE  

matthew180

    River Patroller

  • 2,466 posts
  • Location:Castaic, California

Posted Fri Apr 13, 2018 4:04 PM

All: when it comes to running VHDL simulations I'm starting from absolute zero. :-o   I'd be happy to hear of tips, suggestions and perhaps pointers to tutorials for running simulations / test benches on the Altera Quartus II software. My confusion already starts at the constraints file.

 

Start slow, it will take time.  I recommend you get an FPGA devboard that has some tutorials that you can just load and blink an LED first, that is the "hello world" equivalent for FPGAs.  Getting the full end-to-end process working quickly is really important, even if you don't understand all the pieces yet.

 

I have only ever once looked at Altera's FPGA software, and that was in 2011.  For better or worse, I went with Xilinx.  I'm sure Quartus can create the TB (test bench) boiler-plate stuff, and I have to image they have some sort of simulator that lets you see the signal waveforms and such.
 
As for the constraints file, keep in mind that an FPGA is a big pile of circuits and I/O that get configured into the circuit you describe.  The constraints file is where you specify what physical I/O pins on the FPGA is connected to the specific "net names" (the term "net" comes from schematic capture and PCB layout, and is a named wire, essentially).  You can also specify electrical constraints, like that an I/O is 3.3V or 1.8V, etc.  For clock input signals (usually you have an external oscillator providing a clock input to an FPGA), you must also specify the frequency of the clock so the synthesizer can perform the proper propagation delay calculations.  You don't need a constraints file until you want to load your design onto a real FPGA.  You will need a schematic and FPGA pin-out documentation for this task.

 

My coding style is also influenced by this project: https://github.com/wfjm/w11


That is an interesting project, thanks for the link. It looks very clean and there are definitely some things in there I have not seen before (the "alias" type for example). I'm constantly looking for better ways to do HDL, to make it easier to read and manage, etc. so I'll be experimenting with some of that and maybe adopting some new methods.
 

My understanding of variables and signals in VHDL is as follows. When used for simulation, the VHDL runtime keeps an event queue with the next, current and previous state of all signals. Assigning a signal reads from the current state and writes to the next state. What is 'current' shifts continuously forward as simulated time progresses. Variables only exist inside a process block and are like regular variables. It would seem that variables keep their value from event to event (i.e. process blocks in simulation are "closures") and if one relies on this the block becomes non-synthesizable. In my "*_cmb" process block code all variables are re-initialised for each event (i.e. the process blocks are pure combinational) and this can be synthesised, or so it seems.


I try not to think or HDL in terms of "programming", or even make correlations to programming.  It was a programming mind-set that got me into trouble with the F18A HDL, and only after I stopped thinking in terms of "code", and started thinking in terms of "how would I do this with 74LS logic?", only then did I start making progress again.

 

Assigning a signal in simulation is expensive (it requires updating the event queue) and according to Gaisler some 100x slower than simply assigning a variable. Hence I keep all my intermediaries in variables, even though my designs are so small that I probably won't notice the difference.


It depends on the size of the project.  I did a simulation on an entire Joust SoC that I wrote without too much trouble.  I would be careful when adopting claims like that one.  In most cases, your simulations are so small that you won't notice.  Then again, I have never simulated a design with variable vs signals.  I just know that my simulations are typically so fast that it was not an issue.
 

My understanding is that synthesising was something that was later overlaid on the VHDL language (and is arguably a language in itself). What constructs are being recognised as what circuit seems to me to be a bit of a black art, with differences between tools and changing as technology progresses.  In effect, my *_cmb process blocks are truth tables written up like code. It would seem that toolchains have learned to recognise this (and even the 15 year old synthesiser shipped by Atmel/Microchip seems to handle it well).


You can think of synthesizing as being roughly analogous to compiling.  The synthesizer reads the HDL and infers logic, like muxes, counters, comparators, registers, memory, ROM, RAM, etc.  You should always read the output of the synthesizer carefully to make sure it found the circuits you are trying to describe with your HDL.  After all, that is what HDL is, describing hardware.  Thats why I think most people avoid the language constructs that do not correlate to hardware.

 

There is then a step where the results of synthesis are mapped to an actual device, and FPGA resources are consumed.  This is called "place and route".  From that there is another step where the bit-stream is produced.  The tools like ISE, Vivado, Quartus, etc. mash all this together, kind of like a compiler will call the linker for you.
 

Now that I have written some code I think that I did not quite understand Gaisler: I'm still writing code with each register in a separate process statement. This is not necessary: all the registers for the timer could be in a big single record, as could all the registers for the transmitter. Doing so keeps all related code together and this is perhaps easier to read and maintain. Once I have working code I will try that refactoring and see if makes sense.


There are many ways to organize your HDL, format your HDL, etc. and coming up with an organization and style that makes sense to you is the most important.  After that, try for readability and understanding.  The parallel nature of hardware makes it hard to follow when presented in a form that resembles "code".  IMO a schematic is far more superior for hardware, which is probably why schematics were invented. ;-)  Try to organize you code into blocks just like you would in real hardware.



#27 pnr OFFLINE  

pnr

    Star Raider

  • Topic Starter
  • 98 posts

Posted Fri Apr 13, 2018 4:34 PM

And here is the code with the receiver added as well. Now at 845 lines, and there are only a few small bits and bobs still to do (e.g. DSR interrupt) -- I think the total will remain well below 900.

 

Full file attached. The receiver code is very similar to the transmitter code, so I won't do a walk through.

 

I ran the code through both the Altera and the Xilinx tool chain. I manually calculate that I have 154 flip-flops in the various registers and counters. Altera reports 158 and Xilinx reports 148. Puzzling...  In any case, squeezing it into an EPM7160 CPLD will be a tight fit (it has 160 flip-flops).

 

I think I will leave the code aside for a bit and go back to it with "fresh eyes" later.

 

Attached Files



#28 pnr OFFLINE  

pnr

    Star Raider

  • Topic Starter
  • 98 posts

Posted Fri Apr 13, 2018 4:53 PM

Start slow, it will take time.  I recommend you get an FPGA devboard that has some tutorials that you can just load and blink an LED first, that is the "hello world" equivalent for FPGAs.  Getting the full end-to-end process working quickly is really important, even if you don't understand all the pieces yet.

 

I got the dev board (Spartan-6) about two years ago and it sat in a project box since then. Finally did the "blinken lights" a few weeks ago. I've been reading a lot about VHDL and synthesis in the past quarter. This is the first 'real' project.

 

I have only ever once looked at Altera's FPGA software, and that was in 2011.  For better or worse, I went with Xilinx. 

 

Perhaps I should try that a bit more. Quartus seems to insist on a constraints file before it can do simulation. Haven't really dived into it yet, but the ISE tool seems to autogenerate it. Pointers on how to get ISE to help with generating a test bench would be welcome.

 

<... much more ...>

 

Many thanks for all these helpful pointers, much appreciated!



#29 matthew180 OFFLINE  

matthew180

    River Patroller

  • 2,466 posts
  • Location:Castaic, California

Posted Fri Apr 13, 2018 5:23 PM

ISE test bench from memory:

 

1. Source -> Add New

2. Select VDHL Test Bench

3. Select your UUT VHDL file, i.e. the VHDL file in your project that you want to test.  This should *not* be your "top", unless you want to simulate the whole project.  Assuming you are doing one module per HDL file, this will be a test bench for that module.

4. Hit Ok

 

A test bench is literally another HDL file that you will add to your project.  Some people make a separate folder for the test bench HDL files.  I tend to just prefix all the test bench files with tb_ (real original I know) and put them in the same folder as the rest of my HDL.  Open the test bench file and you will see a bunch of boiler plate.  Down near the bottom you will see a comment that says something like "add stimulus here" or some such thing.  This is where you provide the inputs and read the outputs of the module.  You just set inputs to make the module work.  Something like: input_1 <= '1'; or whatever.

 

In ISE there is a radio button at the top of the left area where your files are shown, you can select "syntheisze" or "simulation" (or something like that, I can't remember exactly).  This is a kind of mode-switch and by default it will be set to "synthesize".  Change that to "simulation" and select the test bench.  Now down below in the lower left box you should have an option to "Simulate".  Start the simulation and ISE will do some compiling, and assuming there are no errors, it will open the iSim tool (or iSimScope, or whatever it is called).

 

At the top there is a button to "play" the simulation for a designated amount of time.  Choose something like 10us and hit play.  On the left you can drill down into the signals and pick which ones you want to see.  It is a little confusing, but find the "UUT" entry in the tree and expand that.  Now you should see all the signals in your component.  Add those to the waveforms section and rerun the simulation.  Add / remove signals, change the simulation time, repeat.  You can also change how the signals are displayed, i.e. binary, decimal, hex, etc.

 

That is very brief, but it would take a rather long tutorial to step through it in detail.  I'm pretty sure there must already be some screen shots and videos out there of doing an ISE simulation.  If not, I might be able to put something together.



#30 matthew180 OFFLINE  

matthew180

    River Patroller

  • 2,466 posts
  • Location:Castaic, California

Posted Fri Apr 13, 2018 5:40 PM

I don't know if the constraints file for ISE is required to simulate.  I always just make one pretty early because they are not that hard.  The format between ISE and Vivado changed, and the Vivado format is a pain in the ass IMO.  There is a tool somewhere in ISE that you can use to make the constraints file, but I have never bother to look or try it out, I always just make it by hand.  For example say you had a board with a 50MHz oscillator and four LEDs.  Your constraints file might look like this:

# Clocks
NET "clk_50m0_net" PERIOD = 20 ns | LOC = "K3";

# LEDs
NET "led_net<0>" LOC="P11" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=SLOW;
NET "led_net<1>" LOC="N9"  | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=SLOW;
NET "led_net<2>" LOC="M9"  | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=SLOW;
NET "led_net<3>" LOC="P9"  | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=SLOW;

Your "top" HDL file would have its port map like this:

entity top is
   port (
      clk_50m0_net   : in  std_logic;
      led_net        : out std_logic_vector(0 to 3)
   );
end top;

-- Set the LEDs on
led_net <= "1111";

-- Set one LED off
led_net(2) <= '0';

And so on.  Your clock input will usually go to a DCM block to make whatever frequency you need, and get buffered for distribution around the FPGA.  You also want to make sure you always drive outputs with registers!  My example above probably won't work because led_net(2) is driven by two values, and the synthesizer will complain (rightfully so).  The LOC entries are "location" and are specific to the FPGA device you are using.  Constraints files are always device specific.  You get the location values from the datasheet.



#31 speccery OFFLINE  

speccery

    Moonsweeper

  • 324 posts

Posted Sat Apr 14, 2018 2:55 AM

And here is the code with the receiver added as well. Now at 845 lines, and there are only a few small bits and bobs still to do (e.g. DSR interrupt) -- I think the total will remain well below 900.
 
Full file attached. The receiver code is very similar to the transmitter code, so I won't do a walk through.
 
I ran the code through both the Altera and the Xilinx tool chain. I manually calculate that I have 154 flip-flops in the various registers and counters. Altera reports 158 and Xilinx reports 148. Puzzling...  In any case, squeezing it into an EPM7160 CPLD will be a tight fit (it has 160 flip-flops).
 
I think I will leave the code aside for a bit and go back to it with "fresh eyes" later.
 


I had no time yesterday to do anything, and I have a workshop this weekend; next weekend heading to Asia, so not much time at home. Ill do what I always do and take a few FPGA boards with me, Ill try to do some integration of your code - that would be fun.

The EPM7160 seems to be a very expensive chip. I took a look last week, perhaps I was looking at the wrong place, but paying nearly 200 per chip is just too much. Anyway with the experience I have now gained with the XC95144XL CPLD I will definitely lean towards real FPGAs in the future. I dont have that much time for the hobby, so when I have the time Id rather not fight against the CPLD routing...

#32 pnr OFFLINE  

pnr

    Star Raider

  • Topic Starter
  • 98 posts

Posted Sat Apr 14, 2018 3:45 AM

I had no time yesterday to do anything, and I have a workshop this weekend; next weekend heading to Asia, so not much time at home. Ill do what I always do and take a few FPGA boards with me, Ill try to do some integration of your code - that would be fun.

 

No worries: giving newly written source code a few weeks for code review is probably a good thing. It would also allow some time for me to get a test bench sorted out. Integrating working code is so much better than debugging a component and the integration at the same time.

 

 

 

The EPM7160 seems to be a very expensive chip. I took a look last week, perhaps I was looking at the wrong place, but paying nearly 200 per chip is just too much. Anyway with the experience I have now gained with the XC95144XL CPLD I will definitely lean towards real FPGAs in the future. I dont have that much time for the hobby, so when I have the time Id rather not fight against the CPLD routing...

 

I just bought two for 35 bucks, incl. shipping. Haven't tested them yet, but they look genuine. With only a few spare macrocells I think the design won't fit anyway, but attempting this will give me more insight into the efficiency of synthesis. In many ways the current state of synthesis feels like the state of C in the late 70's: the result is 30% bigger and 30% slower than hand coded stuff, but the higher abstraction level makes it worth it. Also, working around 1970's C compiler bugs very much feels like the synthesis voodoo of today: always wondering "will this particular construct translate okay?"

 

In general I agree with your point. I want to use HDL's to quickly prototype stuff, a "soft breadboard" if you like. For that I want a spacious FPGA so that even quick & dirty code will have ample room.



#33 speccery OFFLINE  

speccery

    Moonsweeper

  • 324 posts

Posted Sat Apr 14, 2018 6:25 AM

To continue on the discussion about simulation workbenches, I concur that it definitely makes sense to create one. I keep forgetting that ISE has the facility of creating a template for that, thanks matthew180 for reminding about that. I had used it, then I coded some manually, then I remembered again that the tool exists...

For pnr’s benefit it’s perhaps worth pointing out that even a very simple test bench can give you a lot of information. Normally you don’t need much more stimulus in the test bench than a clock and a reset to get started. With the TMS9902 you probably also want to include a CRU write method, so that you can initialize the design and try to send a byte.

#34 pnr OFFLINE  

pnr

    Star Raider

  • Topic Starter
  • 98 posts

Posted Sat Apr 14, 2018 7:48 AM

Matthew180's quick guidance how to start with simulations using the ISE toolchain were super helpful!

 

I'm up and running with the first tests. No need to convince me on the utility of having a test bench: I've learned the hard way that one cannot confidently maintain and refactor a serious code base without one. That is one of the hard bits of working with vintage source code: more often than not there is no test suite.



#35 matthew180 OFFLINE  

matthew180

    River Patroller

  • 2,466 posts
  • Location:Castaic, California

Posted Sat Apr 14, 2018 10:18 PM

@speccery: wow, I might never have used a test bench if I had to have written it from scratch! ;-)  I was still learning and did not understand that the test bench is just HDL too, albeit using language constructs that only work for simulation (which, of course, is the whole point of test benches...)

 

I'm glad the info has been useful.  There is just too much information I want to say on every topic to convey everything.  Every time I write something it reminds me of something else; lots of hard-won knowledge.  I have to remember you will need to run into some of your own brick walls though, it is the only way to learn.  Thinking in terms of hardware instead of software was a big one for me, along with understanding what pipe-lining really is, what it means to "register" you input and outputs, and the importance of synchronizing asynchronous inputs.

 

 

In many ways the current state of synthesis feels like the state of C in the late 70's: the result is 30% bigger and 30% slower than hand coded stuff, but the higher abstraction level makes it worth it. Also, working around 1970's C compiler bugs very much feels like the synthesis voodoo of today: always wondering "will this particular construct translate okay?"

 

I'm curious what gives you that notion?  What kind of "hand coding" would you do in terms of HDL?  I would hate to try and write the equivalent equations for my HDL.  I'm not even sure a human could do it for a complex design.  I'm actually very impressed by the synthesizer and what it can infer from the HDL.  I have played with writing compilers for languages like C and Pascal, but an HDL compiler...  I would not even know where to begin.  Maybe it is simpler than I imagine, but I don't think so.  If it was as easy as writing compilers then I think we would see more open source HDL synthesizers.

 

I see people complain about the closed-source vendor tools a lot, but personally I'm just really happy companies like Xilinx and Altera make their tools available for free.  I would not be doing FPGA work if I would have had to pay for the tools.  They can be big and unwieldy sometimes for sure, but they tend to work.



#36 pnr OFFLINE  

pnr

    Star Raider

  • Topic Starter
  • 98 posts

Posted Sun Apr 15, 2018 7:34 AM

Well, the tests went a lot quicker than I thought. I had to spent a bit of time learning to work with the tools, but the actual tests went much better than I had anticipated.

 

The receive shift register shifted the wrong way 'round, and in the rcv/xmt state machines some timers were off by one (or more accurately: my thinking on what happens at a state transition was a bit muddled). All in all, very few changes versus the v4 source. I've also made the change to run the 9902 at the global clock speed, with just the timers running at 1Mhz. The clock divider for this is currently just /3 or /4 (as in a real 9902), but making it /50 or /100 is a trivial change.

 

All of the timer, the transmitter and the receiver (along with all the associated configuration and status bits) appear to work in simulation. Making it "FPGA proven" will be next.

 

I've also attached the source for the test bench. It is pretty basic now, but with the infrastructure done it will not be hard to make a real test suite that covers all chip modes and functions. If anybody wants to help a bit with defining test cases, I'd be much obliged.

 

There's still a few tweaks and clean-up items to do in the source, but I'd say that having a VHDL 9902 for use in a Grant Searle style "soft breadboard" is 95% done (unless speccery's integration test brings up major new issues).

Attached Files



#37 pnr OFFLINE  

pnr

    Star Raider

  • Topic Starter
  • 98 posts

Posted Mon Apr 16, 2018 1:56 AM

@pnr: Your use of the "variable" type is... interesting.  [...] Admittedly it looks a little strange to me, [...].  This is all just my opinion and such, so don't take this wrong, I'm just contrasting and comparing, and trying to decide if using the variable type is something I might start trying to use more of.  Your HDL is the most use of the variable type that I have ever seen, and I wonder if it will make it equally as strange to you when you see HDL that does not use variables at all.

 

I've been thinking about this for a bit. The Free range VHDL book talks about three common coding styles: data-flow, behavioural and structural (see chapter five). I think the difference may be that you are using a style that is mostly data-flow oriented and I'm using a style that is mostly behavioural oriented. The third style, structural, is what Grant Searle is doing in his top level file: connecting up components as if it is a schematic. I'm not sure these terms for coding styles are in common use, but does that make sense?

 

The funny thing about it is that when I was reading up on VHDL in the past few months, I had decided to focus on a data-flow oriented style, as I imagined that would give me the maximum control over what the synthesiser would generate. Now that I look back on the 9902 project I see that I ended up doing mostly behavioural stuff without that ever being a conscious decision.

 

By the way, I find the explanation of process blocks in chapter 5 confusing. It explains it in terms of code being executed sequentially, and for a while I imagined that the synthesised circuit would have interlock flip-flops to enforce that in real hardware. Only much later I realised that such language refers to a context where VHDL is being executed by the simulator. The synthesiser simply does a flow analysis (like a regular optimising compiler would) and extracts the equivalent logic formulas (and where it can't the block is non-synthesiable).

 

pnr wrote: "In many ways the current state of synthesis feels like the state of C in the late 70's: the result is 30% bigger and 30% slower than hand coded stuff, but the higher abstraction level makes it worth it. Also, working around 1970's C compiler bugs very much feels like the synthesis voodoo of today: always wondering "will this particular construct translate okay?""

 

I'm curious what gives you that notion?  What kind of "hand coding" would you do in terms of HDL?  I would hate to try and write the equivalent equations for my HDL.  I'm not even sure a human could do it for a complex design.  I'm actually very impressed by the synthesizer and what it can infer from the HDL.  I have played with writing compilers for languages like C and Pascal, but an HDL compiler...  I would not even know where to begin.  Maybe it is simpler than I imagine, but I don't think so.  If it was as easy as writing compilers then I think we would see more open source HDL synthesizers.

 

I see people complain about the closed-source vendor tools a lot, but personally I'm just really happy companies like Xilinx and Altera make their tools available for free.  I would not be doing FPGA work if I would have had to pay for the tools.  They can be big and unwieldy sometimes for sure, but they tend to work.

 

I'm happy that these tools exist too, and I shouldn't look a gift horse in the mouth.

 

You raise several interesting points. Will come back with a few thoughts on that "1970's feeling" later -- I'm a tad busy this week.


Edited by pnr, Mon Apr 16, 2018 2:13 AM.


#38 pnr OFFLINE  

pnr

    Star Raider

  • Topic Starter
  • 98 posts

Posted Today, 2:02 AM

I'm doing some cleanup of the 9902 code and here's a question:

 

Take this code for the clock divider (it is around line 200 in the full source file) and let's call it version A:

   clkdiv: process(CLK, clkctr_q, ctl_q)
   variable v : std_logic_vector(1 downto 0);
   begin
      v := clkctr_q;
      if rising_edge(CLK) then
         v := v + 1;
         if ctl_q.clk4m='0' and v="10" then v:="11"; end if;
         clkctr_q <= v;
      end if;
   end process;
   bitclk <= '1' when clkctr_q="00" else '0';

And let's call this slightly modified version, version B:

   clkdiv: process(CLK, clkctr_q, ctl_q)
   variable v : std_logic_vector(1 downto 0);
   begin
      v := clkctr_q;
      if rising_edge(CLK) then
         v := v + 1;
         if ctl_q.clk4m='0' and v="10" then v:="11"; end if;
      end if;
      clkctr_q <= v;
   end process;
   bitclk <= '1' when clkctr_q="00" else '0';

The Xilinx ISE tool chain accepts both versions with a warning that "variable 'v' does not keep its value outside rising edge(CLK)". Both versions simulate okay.

 

The Altera Quartus tool chain accepts version A without warning or error, and flags version B as an error (with a similar error text). Version A simulates okay.

 

In my limited understanding of VHDL both versions should be okay and not give a warning or error. What subtle aspect of VHDL am I missing?

 

(PS of course I can rewrite it to not have a warning or error, but I'm interested to understand why this is wrong and why the two tools chains have different opinions about it).







Also tagged with one or more of these keywords: 9902, vhdl

0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users