Jump to content
  • 0

Feedback on a register file design?


CurtP

Question

Hey everyone,

I've done the initial design of a register file (16x 32-bit registers, two write ports, four read ports) in VHDL as part of a larger project, but seeing as I am a relative newcomer to HDLs, I was hoping to get some feedback on my design, any errors I may have made, or any improvements I might want to make.

Here is the VHDL:

-- Register file

-- Two write ports, four read ports.
-- For performance reasons, this register file does not check for the same 
-- register being written on both write ports in the same cycle. CPU control
-- circuitry is responsible for preventing this condition from happening.

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

use work.cpu1_globals_1.all;
use work.func_pkg.all;

entity registerFile is
    port
    (
        clk : in std_logic;
        rst : in std_logic;
        writeEnableA : in std_logic;
        writeEnableB : in std_logic;
        readSelA, readSelB, readSelC, readSelD, writeSelA, writeSelB : in std_logic_vector(3 downto 0);
        data_inA, data_inB : in std_logic_vector(DATA_WIDTH - 1 downto 0);
        data_outA, data_outB, data_outC, data_outD : out std_logic_vector(DATA_WIDTH - 1 downto 0)
    );
end registerFile;

architecture behavioral of registerFile is

    type regArray is array (0 to 15) of std_logic_vector(DATA_WIDTH - 1 downto 0);
    signal registers : regArray := (others => (others => '0'));

begin

    data_outA <= registers(to_integer(unsigned(readSelA)));
    data_outB <= registers(to_integer(unsigned(readSelB)));
    data_outC <= registers(to_integer(unsigned(readSelC)));
    data_outD <= registers(to_integer(unsigned(readSelD)));

    registerFile_main : process(clk)
    
    begin
    
        if(rising_edge(clk)) then
        
            if(rst = '1') then
        	
                registers <= (others => (others => '0'));
                
            else
                
                if(writeEnableA = '1') then
                    registers(to_integer(unsigned(writeSelA))) <= data_inA;
                end if;
            	
                if(writeEnableB = '1') then
                    registers(to_integer(unsigned(writeSelB))) <= data_inB;
                end if;
                
            end if;
            
        end if;
        
    end process;
    
end behavioral;

This design is intended for use on FPGAs, hence the use of default values for the registers.

I appreciate any feedback you might have!

Thanks,

 - Curt

Link to comment
Share on other sites

Recommended Posts

44 minutes ago, CurtP said:

I view signed and unsigned as just different ways to look at a bucket of bits.

I might go with the notion that STD_LOGIC_VECTOR is a bucket of ULOGIC bits. I've done a lot of signed and unsigned VHDL projects and I can't say that I can't support the quote above. In C abstraction is a concept to be embraced. In logic design you are responsible for any abstraction you want to imply. VHDL, like ADA is a strongly typed language and will give you lots of error messages. You can still get into trouble, even with VHDL, especially with carries, overflow, comparison etc.

Now that you've brought it up

44 minutes ago, CurtP said:

tempResult := unsigned("0" & operandA) + unsigned("0" & opB_adjusted) + unsigned'("" & (invert_opB xor tempCarry));

The ':=' implies instantaneous value assignment. It is not the same as the "<=" gets assignment. The two are not interchangeable. Confusing the two will result in "you := are_in_trouble" in a hurry. I rarely use ":=" except for simulation and special circumstances.

You should understand that VHDL was not designed for synthesis. IT is a simulation language. Most, but not all of its statements can be synthesized into logic or are supported by vendors synthesis tools. Both Altera and Xilinx will tell you what statements are supported.

Link to comment
Share on other sites

26 minutes ago, CurtP said:

I view signed and unsigned as just different ways to look at a bucket of bits. My current practice is to favor the use of std_logic_vector for moving and storing data, and converting to unsigned for arithmetic and logical operations.

You can also import just "+" and "-" from std_logic_signed as well as the conversion functions from std_logic_arith.  This way you still are required to specify signed/unsigned for "<", "*", etc...  Importing "-" from std_logic_signed will give you the unary "-", which can be used for logical induction in expressions like (-x) and (x).

Link to comment
Share on other sites

1 hour ago, xc6lx45 said:

There is no "business case" for high-end CPUs on FPGAs.
Period.

@xc6lx45,

You must like experimenting with the reaction of Africanized bee colonies to jack-hammers. I'm in a feisty mood today so what the heck...

There is absolutely a place for hard CPU core based FPGA devices like the Zynq. I don't even feel the needs to support that statement. For almost all low power applications the FPGA can't compete with a commercial uC or DSP. I tend to be more sympathetic with you on soft CPU cores using FPGA resources. The exception is when you are pursuing a project that is a labour of love. Implementing a full-stack Ethernet interface in HDL makes no sense to me. There are times when post configuration programmability might push me toward a soft processor. But then I'd use an Atmel clone that someone else's software toolchain. If someone ( I can think of someone ) makes a great soft processor that is compatible with the gcc toolchain I might be interested. By and large HDLs get almost everything done that needs to be done.

BTW there's thread in another section in the Digilent forum dedicated to just this topic... which would be a better place to post your argument.

Link to comment
Share on other sites

42 minutes ago, zygot said:

I might go with the notion that STD_LOGIC_VECTOR is a bucket of ULOGIC bits. I've done a lot of signed and unsigned VHDL projects and I can't say that I can't support the quote above. In C abstraction is a concept to be embraced. In logic design you are responsible for any abstraction you want to imply. VHDL, like ADA is a strongly typed language and will give you lots of error messages. You can still get into trouble, even with VHDL, especially with carries, overflow, comparison etc.

Now that you've brought it up

The ':=' implies instantaneous value assignment. It is not the same as the "<=" gets assignment. The two are not interchangeable. Confusing the two will result in "you := are_in_trouble" in a hurry. I rarely use ":=" except for simulation and special circumstances.

You should understand that VHDL was not designed for synthesis. IT is a simulation language. Most, but not all of its statements can be synthesized into logic or are supported by vendors synthesis tools. Both Altera and Xilinx will tell you what statements are supported.

tempResult is a 33-bit variable, used for convenience within the process. Its use is appropriately expanded upon elaboration and synthesis. It isn't used to register a value between cycles. The result signal becomes tempResult(31 downto 0) and the carry flag bit on the flag signal output becomes tempResult(32). Using a simple container module for clocking and I/O, I have synthesized and verified its operation on a Spartan7 board.

Link to comment
Share on other sites

49 minutes ago, Piasa said:

You can also import just "+" and "-" from std_logic_signed as well as the conversion functions from std_logic_arith.  This way you still are required to specify signed/unsigned for "<", "*", etc...  Importing "-" from std_logic_signed will give you the unary "-", which can be used for logical induction in expressions like (-x) and (x).

Very good to know! I feel like there are a million little things I don't know about VHDL, and the worst part is that I don't know what I don't know, haha.

Link to comment
Share on other sites

6 minutes ago, CurtP said:

tempResult is a 33-bit variable, used for convenience within the process. Its use is appropriately expanded upon elaboration and synthesis. It isn't used to register a value between cycles. The result signal becomes tempResult(31 downto 0) and the carry flag bit on the flag signal output becomes tempResult(32). Using a simple container module for clocking and I/O, I have synthesized and verified its operation on a Spartan7 board.

There are a lot of things that you can do and not have problems for any given entity... if you fully understand what you are doing. There are hours or days of debugging ahead for those who don't when all of a sudden what seemed to be good practice for one project doesn't work out so well on another. Especially when entities become components in large hierarchical designs.

More advice that you should feel free to ignore. I spent the first couple of years restricting my HDL to basic constructs and still had plenty of surprises to learn about. As time wore on I became more adventurous. Not everyone need operate this way... but probably more than do. You will, no doubt , find a coding style that suits the way that you work. Using individual operators from libraries would probably not work out for me as it does Piasa.

Link to comment
Share on other sites

@zygot,

Oh, I'm around, but you guys have given me a lot of reading material to go through.  Well, that and I haven't been waiting on the synthesizer as much so I haven't been hitting reload on the Digilent forum page as often.

@CurtP,

What @zygot is trying to point out is that I've built my own CPU, the ZipCPU, as a similar labor of love.  It's not a forth machine, but a basic sixteen 32-bit register design, with two register sets of that size.  It's also small enough to fit on Digilent's CMod S6 while running a small O/S.  I'd love to offer you an example register file module, however my own register "file" never managed to get separated out from the rest of the CPU such as you are trying to do.  I struggled to find a clean way to do so, and so didn't.  If you are curious, you can search the main CPU source and look for "regset" and see how I handled it.

In particular, the ZipCPU register file accepts only one write to the register file per clock--not two.  I was convinced that two writes per clock would leave the CPU vulnerable to coherency problems--assuming the block RAM's even supported it.  This register set supports one write and three reads per clock.  Two of those reads are for an instruction, the third is to support the debug port.  (You are thinking about how to debug your CPU already, aren't you?)

I've also written several instructional blog's on this and similar topics.  These cover my view that you should start building a CPU by first building its peripherals, then a debug port to access and test the peripherals, before starting on the CPU itself.  Further blog articles discuss how to build a debugging port into the CPU, how to debug the CPU from that port when using a simulator as well as when online.  I've discussed pipelining strategies, and presented how the ZipCPU pipeline strategy works.  More recently, I've been working with formal methods.  I've therefore presented a demonstration of how formal methods can be used to verify that a bus component works as designed, and then offered a simple prefetch as an example.  I'm hoping to post again regarding how to build an instruction prefetch and cache, as well as how to formally verify that such a module works, but I haven't managed to clean up my code enough to present it in spite of presenting why such a proof would be so valuable.

While I didn't use formal methods to build the CPU initially, I've been finding more bugs using formal methods than I had otherwise, so you might say that I've become a believer.

As a result, I'm right now in the process of formally verifying as much of the CPU's modules as I can.  I've managed to formally verify three separate prefetch modules, including the one with a cache, the memory access components, the instruction decoder.  I've also managed to formally verify several CPU related peripheral components, such as the (yet to be integrated) MMU, counters, timers, an interrupt controller, bus arbiters, bus delay components and more.  This has been my current focus with the CPU.  Once I finish it, I'm hoping to write about how to use the ZipCPU in case others are interested (and I know they are).

I know @zygot dislikes my blog, but you might find a lot of useful information available there to describe the things you've discussed above.

Dan

Link to comment
Share on other sites

4 hours ago, Piasa said:

it looks fine.  I would normally have a different port order and have each on a different line for easy copy/paste.  I prefer to have interfaces -- readA, doutA, readB, doutB, etc...  I also place interfaces in an output, input, config, infrastructure order.  In industry the order of infrastructure, input, output, config is more common.  

For implementation, this probably infers registers.  It is possible to construct this with distributed memory, although it is more complex.  It isn't clear to me if the added complexity results in a better design at this size.

The design actually will have priority logic for data_inB if the same address is used.  This is because the last reached assignment will be used. 

Also, the logic has unregistered outputs.  Normally this isn't something that is desired.  This means critical timing paths could be due to logic in multiple modules.  Not sure if there is anything that can be done here though.

You can also add asserts for the "write to same address" case.  this can be helpful in simulation.

Thanks for all the info! My background is software, primarily C/C++, so I am still learning the stylistic conventions of VHDL and HDLs in general as I go. It helps to have other engineers point me in the right direction.

A few questions, if you don't mind:

When you say "infrastructure", are you referring to things like clock, reset, and other signals that propagate broadly through the design?

Regarding distributed memory versus registers -- you're correct that this design infers registers upon elaboration. What kinds of tradeoffs are involved in choosing which design to pursue? This register file will be the main GP registers for a superscalar design, so I want to be able to write 2 registers and read 4 registers per clock (when made possible by the pipeline), and I would like to be able to read back a written register the cycle immediately after it was written, if possible. Of course, none of these things should come at the cost of potential data corruption.

Regarding unregistered outputs -- is this because the outputs aren't in the clocked process? I had used this approach prior but noticed that this caused an extra cycle to elapse between when a register was written and when that same register's new value could be read back.

Regarding the priority for data_inB if the same address is used -- is this behavior reliable under FPGA implementation? I had assumed that it would cause some sort of contention that would lead to undefined values. I've often heard the phrase "last signal assignment wins", but wasn't sure if that was something that merely happens in simulation, or if it was a reliable implemented behavior.

Regarding the asserts -- thank you for the suggestion. Someone else also recommended this, and I will be implementing it for simulation.

 

Thanks again for all the help!

- Curt

Link to comment
Share on other sites

1 hour ago, CurtP said:

I've often heard the phrase "last signal assignment wins", but wasn't sure if that was something that merely happens in simulation, or if it was a reliable implemented behavior.

What's going to happen here is that the synthesizer is going to generate your design and optimize out any signal assignments that cannot be reached (or that are reached but overridden by a later assignment) on a particular path through the process.  All possible paths that modify a particular signal are then strung into a MUX determining that signal's value.  There will be one such MUX for each different signal the process assigns to (and in this case each MUX will also be coupled to a register clocked by someClock).  It's not like a programming language where a series of assignments will be run in order.  So a process like:

someProc: process(someClock) is

begin
    if (rising_edge(someClock)) then
        mySignal <= oneSignal;
        mySignal <= anotherSignal;
        mySignal <= oneMoreSignal;
    end if;
end process someProc;

Will synthesize (elaborate) to a register called mySignal whose input connects to oneMoreSignal and whose clock input is connected to someClock.  oneSignal and anotherSignal won't even appear in the elaboration of someProc.

Link to comment
Share on other sites

9 minutes ago, Gau_Veldt said:

What's going to happen here is that the synthesizer is going to generate your design and optimize out any signal assignments that cannot be reached on a particular path through the process.  All possible paths that modify a particular signal are then strung into a MUX determining that signal's output.  There will be one such MUX for each different signal the process assigns to (and in this case each MUX will also be coupled to a register clocked by someClock).  It's not like a programming language where a series of assignments will be run in order.  So a process like:


someProc: process(someClock) is

begin
    if (rising_edge(someClock)) then
        mySignal <= oneSignal;
        mySignal <= anotherSignal;
        mySignal <= oneMoreSignal;
    end if;
end process someProc;

Will synthesize (elaborate) to a register called mySignal whose input connects to oneMoreSignal and whose clock input is connected to someClock.  oneSignal and anotherSignal won't even appear in the elaboration of someProc.

Thanks for the explanation!

Link to comment
Share on other sites

@CurtP,

I've been doing HDL designs and development for over 20 years and C/C++ for a lot longer. I started out as ( and still consider myself to be ) a digital engineer... (I won't be surprised if you say "what the heck is a digital engineer?"). I mention this only to say that the commentary that follows is colored heavily by one persons' experience. Take it as a disclaimer if you wish. Feel free to ignore everything that follows.

In general I'd say that a background in coding computers is an impediment to learning FPGA design. To me FPGA design is a digital design endeavour using text and computer assistance instead of schematics. You have more than a syntax issue.... you have a conceptual issue to master. I heartily encourage you to get a few good textbooks that cover the conceptual aspects of both digital design and HDL development. Do read the documentation and reference manuals provided by the FPGA vendors. You are dealing with not just writing robust behavioural source "code" but understanding how the synthesis, place and route and timing tools interpret that source "code". There are some good examples of HDL in the Project vault to help get a sense of good coding styles. Do get comfortable learning how to write simulation test benches and understanding how to use simulation as the tool that it is. All tools can provide false and confusing information if you don't understand how they work and their limitations. As your designs get more complex and demanding so will the issues that pop up and have to be mastered. To me this is an attraction. Good journey.

A friendly whistle in the wind....

Link to comment
Share on other sites

4 minutes ago, zygot said:

@CurtP,

I've been doing HDL designs and development for over 20 years and C/C++ for a lot longer. I started out as ( and still consider myself to be ) a digital engineer... (I won't be surprised if you say "what the heck is a digital engineer?"). I mention this only to say that the commentary that follows is colored heavily by one persons' experience. Take it as a disclaimer if you wish. Feel free to ignore everything that follows.

In general I'd say that a background in coding computers is an impediment to learning FPGA design. To me FPGA design is a digital design endeavour using text and computer assistance instead of schematics. You have more than a syntax issue.... you have a conceptual issue to master. I heartily encourage you to get a few good textbooks that cover the conceptual aspects of both digital design and HDL development. Do read the documentation and reference manuals provided by the FPGA vendors. You are dealing with not just writing robust behavioural source "code" but understanding how the synthesis, place and route and timing tools interpret that source "code". There are some good examples of HDL in the Project vault to help get a sense of good coding styles. Do get comfortable learning how to write simulation test benches and understanding how to use simulation as the tool that it is. All tools can provide false and confusing information if you don't understand how they work and their limitations. As your designs get more complex and demanding so will the issues that pop up and have to be mastered. To me this is an attraction. Good journey.

A friendly whistle in the wind....

Thanks for the advice! My journey into hardware design has been like drinking from a firehose of information so far, but that's part of the fun. You're correct that being accustomed to software development paradigms can be an impediment to learning hardware design. I think a lot of people see the superficial similarity between HDLs and C-style languages and assume that the process will be similar. It has been an interesting exercise to rework my thinking around describing the behavior of a circuit, rather than listing a series of concurrent operations to be performed.

I think one advantage I have going in is that digital logic and integrated circuits have been a fascination of mine since I was a kid. Long before I ever even knew about HDLs, I was pouring over Intel technical docs, and reading about the theory of machine design. Of course, once you dive in to actually designing a circuit, you quickly realize how much you -don't- know. But again, all part of the fun!

I have spent some time reading through Xilinx's guidelines for synthesis, but I haven't invested in any actual books on hardware design. Are there any particular ones that you recommend?

Thanks again,

- Curt

Link to comment
Share on other sites

19 minutes ago, Gau_Veldt said:

What's going to happen here is that the synthesizer is going to generate your design and optimize out any signal assignments that cannot be reached on a particular path through the process.  All possible paths that modify a particular signal are then strung into a MUX determining that signal's value. 

No, I'm uncomfortable with what this text is implying or stating.

The synthesis tool tries to interpret your source text and implement it using the resources of the target device. The simulator does the same. How  the simulator and synthesis tool interpret what you intend from your source is not always the same. I know this form experience. The synthesis tool might infer a latch where you don't intend to have one ( this is not generally a good thing ). The synthesis tool will try to infer certain logic elements like latches, counters, state machine and replace your code with "code" optimised for a particular FPGA device. You have some control over this behavior in the settings for the Vivado synthesis tool. The reality is that you can write crappy code and be lucky to end up with reasonably functional results because modern synthesis tools are pretty smart. What the synthesis tool can't do is replace flawed concepts or correct basic deficiencies in the design. This is why I encourage you to do the basic work of learning FPGA development from reliable sources. You might find a path to one immediate problem on a user's forum but don't mistake that success as learning the mastery of FPGA development.   

Link to comment
Share on other sites

I have found the schematic views of elaboration/synthesis/implementation to be very helpful for improving my understanding of VHDL and my target FPGA. It's one thing to see simulation results on a scope, but it's another to see the actual hardware that the tools generate from your VHDL. I try to ask myself as I go "what hardware will this create?", and am picking up best practices bit by bit. For every functional unit of a design that I create, I make sure to walk through the elaborated schematic and understand what each part is doing. I find that making small changes to the VHDL and seeing how it impacts the elaborated design is very useful.

Link to comment
Share on other sites

5 minutes ago, CurtP said:

Thanks for the advice! My journey into hardware design has been like drinking from a firehose of information so far, but that's part of the fun. You're correct that being accustomed to software development paradigms can be an impediment to learning hardware design. I think a lot of people see the superficial similarity between HDLs and C-style languages and assume that the process will be similar.

You are wise and entering this with "eyes wide open"; I am confident that you will be successful and be rewarded for your efforts.

As to textbooks, all of mine are currently boxed up as I am about to relocate.... Ashenden's VHDL textbook is a standard reference, though my copy is a bit dated. Sorry, the titles or authors of other books don't come to mind.

Altera's Quartus reference manual has some excellent guidance on how to write text syntax that their synthesis tool understand. They also have an excellent "cookbook" of coding syntax for various structures like registers, counters, state machines, etc. Of course imitating good coding styles is not the same as understanding why they are good. Both Altera and Xilinx offer application notes as well example designs with source code. The material can be daunting, even for seasoned professionals, so don't get discouraged by the learning curve.

Of course, sometimes you run into a problem that just doesn't get solved after hours of effort and this forum might help with that. The tools are not perfect and can be an impediment on their own.

Link to comment
Share on other sites

9 minutes ago, CurtP said:

I have found the schematic views of elaboration/synthesis/implementation to be very helpful for improving my understanding of VHDL and my target FPGA. It's one thing to see simulation results on a scope, but it's another to see the actual hardware that the tools generate from your VHDL. I try to ask myself as I go "what hardware will this create?", and am picking up best practices bit by bit. For every functional unit of a design that I create, I make sure to walk through the elaborated schematic and understand what each part is doing. I find that making small changes to the VHDL and seeing how it impacts the elaborated design is very useful.

Your instincts are very good.. it's great to not have to give advise because the audience has already figured it out for them self.. Insight is hard to come by and can be as important as textbook knowledge. The RTL view of post-route logic ( not the board design schematic ) is a good way to verify that what you want is what you got... and can help resolve confusion. Sometimes you just have to rework your logic to get what you want from the synthesis tool. I still create play projects just for the purpose of understanding the nuances of a particular design/syntax strategy and see what the simulator says and how the bitstream behaves in real hardware.

Link to comment
Share on other sites

The "priority logic" is quite an important concept to understand.

In this example, it means that if both ports write to the same register, it is guaranteed that port B gets the final word, or "priority".

If this is the desired outcome, case closed. You need priority logic.

Now, often such "special cases" can be ruled out. They may never happen in a properly working design. If two parties try to write the same register at the same time, something has gone horribly wrong. Now what should your circuit do?

This is an almost philosophical argument. Without claiming to be the sole authority (ask your boss...), I'd make a strong point for the following:

Given "impossible" input, the circuit should output "undefined" signals.
Three reasons:

1) It is faster and smaller in implementation because logic can be reduced further. The lower layers of FPGA hell have you waiting for Vivado to tell after seven eternities that it was unable to close timing and / or ran out of space. Again. And again.
2) Simulation results will be nicely green when OK and ugly red when something has gone wrong (or a part of the circuit is idle). In the upper layers of FPGA hell you'll realize that you sampled one clock cycle too late, but the signal was usually still correct. Usually.
3) You don't implement logic that will never be tested (because the conditions that trigger it are impossible at the time of writing). Imagine you work with code that looks like it will do something, only to realize after much head-scratching that what looked like a feature was never completed but just a half-*ssed attempt to make it "robust" against stray alpha particles from outer space.

Personally, I "clear" every single FF bit after its useful life has ended (e.g. local bits and pieces in a state machine) by setting it to undefined.
 

 

Link to comment
Share on other sites

@xc6lx45

I'm scratching my head about how to respond to what you've contributed.... nope can't come up with anything.

I will reveal a secret; shhh... this is just between us. If you look down into the Vivado installation directory you can discover a lot of useful and accurate information. As an example in the ..//data/vhdl/src/ieee_2008 directory you can find the file std_logic_1164.vhdl that is the IEEE extension to VHDL that defines the states of STD_ULOGIC as:

  type STD_ULOGIC is ( 'U',             -- Uninitialized
                       'X',             -- Forcing  Unknown
                       '0',             -- Forcing  0
                       '1',             -- Forcing  1
                       'Z',             -- High Impedance   
                       'W',             -- Weak     Unknown
                       'L',             -- Weak     0       
                       'H',             -- Weak     1       
                       '-'              -- Don't care
                       );

You can also find the same basic information in a good textbook along with helpful and reliable commentary. ModelSim puts useful information onto your computer as well.

Don't take my word ( or anyone else's for that matter ) on any topic posted here as truth. Find the oases of reliably helpful information and remember where to go to when the desert has you seeing things that aren't there. 

 

 

Link to comment
Share on other sites

2 hours ago, zygot said:

You are wise and entering this with "eyes wide open"; I am confident that you will be successful and be rewarded for your efforts.

 

2 hours ago, zygot said:

Your instincts are very good.. it's great to not have to give advise because the audience has already figured it out for them self.. Insight is hard to come by and can be as important as textbook knowledge.

Thank you for the kind words and encouragement!


The first big project I'm working on is.. (wait for it).. a general purpose CPU. Cliche, yes, I know. But I see it as a labor of love, an opportunity to learn many principles of machine design at once, and just something I've been really curious to do for a long time. I'm sure the world doesn't need yet another new ISA, but it's still fun to create one. And I'll be open-sourcing the final product, for whoever might find it useful.

One of my design goals (or I suppose you could call it a meta-design goal) is to prioritize the use of easy-to-read, behavioral VHDL so that people who read through the source can intuitively learn the ins and outs of how a CPU really works. I've looked at a lot of other CPU designs and found that it's often difficult to quickly discern what a portion of the code is actually doing and why, because of heavy use of structural and combinational syntax, which while generally more efficient, isn't as intuitive for a human to parse beyond a certain level of complexity (at least not for me).

So will it be the best/fastest/most technically competent CPU? No. But you wouldn't get that without going the ASIC route anyway (and having a lot more resources and expertise than I do). But I do think I can make a CPU that also serves as a learning aid for others curious about the inner-workings of CPUs.

Anyhow, I digress. Thanks again!

- Curt

 

 

Link to comment
Share on other sites

2 hours ago, zygot said:

@xc6lx45

I'm scratching my head about how to respond to what you've contributed.... nope can't come up with anything....

 

Hi Zygot,

you also disagreed with what Gau_Veldt wrote so clearly we're not on the same page.

For me, Gau_Veldt's statement is 100.0 % accurate, in a sense that it would hold up in court (note, he wrote "synthesis", not "optimization"). The synthesis process will do exactly that.

Priority decoders - and why to avoid them for performance reasons - is a basic textbook topic.
It strips levels away from combinational logic. It's obvious once you get it.
And it has little to do with the language, but the resulting physical logic.

Link to comment
Share on other sites

>> a general purpose CPU

2 hours ago, CurtP said:

The first big project I'm working on is.. (wait for it).. a general purpose CPU.

CurtP,

you could have a look at J1:
http://www.excamera.com/files/j1demo/verilog/j1.v

It's a beautiful design. Not that I'd propose Forth for any real-world work but it's perfect for a simple hardware implementation. It might even make make "business sense" in Picoblaze territory.
There is a VHDL port, too, but possibly not as concise.

 

 

 

Link to comment
Share on other sites

A CPU? Hello @D@n... are you there? D@N?

I am not al all surprised that you would select such a project. This is not a trivial project. Fortunately others are like minded.... such as D@N. A solid grasp of the fundamentals would be a good prerequisite to my mind. D@N is likely a good deal more optimistic about this. I recently spent a few weeks working on a simple controller and found it challenging... though I was going for something quite efficient and scalable in terms of capability and speed. It's a naturally great project. I'd suggest a few less challenging projects to belt out as preparation ( assuming that you want to do this from scratch ). BTW the Ashenden text uses a CPU example to illustrate his concepts. My design was completely from scratch.

 

Link to comment
Share on other sites

@CurtP,

I've been following this thread much the same way as people who watch soaps... or fireworks.... the thread is throbbing with excitement.

So, I don't know if you're a genius or agog with ideas that will never be built and debugged, or someone who just wants to get to the part where tomatoes get plucked from the garden. I understand; inquiring minds want to know. I've got my own afflictions in that regard. The following comments have nothing to do with CPU design, or the excitement of discussing interesting aspects of any particular project. I'm just putting the discussion into the context of a guy who started a thread wanting feedback on a rather simple logical structure.

If I were going to build a personal manned rocket I'd want to attempt and succeed at smaller projects before strapping myself into a piece of home-built hardware and pushing the big red button. But then I'm just a pedestrian engineer. Along with succeeding at smaller but increasingly complex projects you gain a lot of skill at understanding the basic but peripheral knowledge and skills in using the tools that are needed to accomplish a complex project. This includes the Vivado tools, the languages, the bugs in the tools, best practice in implementing complex logic elements, timing, constraints, etc. I do realize that your goals and choice as to how you get there has to be your decision alone.

Were you to start a project vault project with an end goal of achieving a unique CPU with unique objectives this might be very popular and instructive to a wide audience. I'm thinking of a project consisting of a series of smaller projects culminating in one big flourish. It would produce not just code and techniques but convey the development complexities in an incremental and natural manner. I'm not saying that this is necessarily a good idea or something that you ever though about doing.... just interesting and it sure would expose a lot of those peripheral issues and strategies. My suggestion admittedly is asking a lot of you. You may have no intention of publishing any of your hard work. It would be a unique project, interesting to a lot of people and instructive to many more.

Mostly, don't let anything that I say restrain your ambition or enthusiasm.

Link to comment
Share on other sites

@xc6lx45,

9 hours ago, xc6lx45 said:

Given "impossible" input, the circuit should output "undefined" signals.
 

I had never heard of anyone actually using this practice before.

Some time ago, I was given this article which appears to describe the practice you are recommending above.  The individual who had given it to me suggested that ARM got themselves in a lot of trouble (i.e. stuff not working that should have) by using this practice.

While I'm not familiar with all the details, I did find the article fascinating--and now more so in light of your suggestion.

Dan

Link to comment
Share on other sites

I think in this case the priority logic is hard to remove in a way that isn't worse.

Some (or all?) synthesis tools will ignore 'x' and '-' and instead replace them with '0'.  This can add some extra logic to do something you specifically didn't care about.

 

Also, I agree that small sandbox designs can be really fun and informative.  IMO, devs tend to underestimate the FPGA in some ways which results in excessive pre-optimization.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...